| # Copyright lowRISC contributors. |
| # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| # SPDX-License-Identifier: Apache-2.0 |
| |
| from typing import Dict |
| |
| from .state import OTBNState |
| from .isa import (OTBNInsn, RV32RegReg, RV32RegImm, RV32ImmShift, |
| insn_for_mnemonic, logical_byte_shift) |
| |
| |
| class ADD(RV32RegReg): |
| insn = insn_for_mnemonic('add', 3) |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| val2 = state.gprs.get_reg(self.grs2).read_unsigned() |
| result = (val1 + val2) & ((1 << 32) - 1) |
| state.gprs.get_reg(self.grd).write_unsigned(result) |
| |
| |
| class ADDI(RV32RegImm): |
| insn = insn_for_mnemonic('addi', 3) |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| result = (val1 + self.imm) & ((1 << 32) - 1) |
| state.gprs.get_reg(self.grd).write_unsigned(result) |
| |
| |
| class LUI(OTBNInsn): |
| insn = insn_for_mnemonic('lui', 2) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.grd = op_vals['grd'] |
| self.imm = op_vals['imm'] |
| |
| def execute(self, state: OTBNState) -> None: |
| state.gprs.get_reg(self.grd).write_unsigned(self.imm << 12) |
| |
| |
| class SUB(RV32RegReg): |
| insn = insn_for_mnemonic('sub', 3) |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| val2 = state.gprs.get_reg(self.grs2).read_unsigned() |
| result = (val1 - val2) & ((1 << 32) - 1) |
| state.gprs.get_reg(self.grd).write_unsigned(result) |
| |
| |
| class SLL(RV32RegReg): |
| insn = insn_for_mnemonic('sll', 3) |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| val2 = state.gprs.get_reg(self.grs2).read_unsigned() & 0x1f |
| result = (val1 << val2) & ((1 << 32) - 1) |
| state.gprs.get_reg(self.grd).write_unsigned(result) |
| |
| |
| class SLLI(RV32ImmShift): |
| insn = insn_for_mnemonic('slli', 3) |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| result = (val1 << self.shamt) & ((1 << 32) - 1) |
| state.gprs.get_reg(self.grd).write_unsigned(result) |
| |
| |
| class SRL(RV32RegReg): |
| insn = insn_for_mnemonic('srl', 3) |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| val2 = state.gprs.get_reg(self.grs2).read_unsigned() & 0x1f |
| result = val1 >> val2 |
| state.gprs.get_reg(self.grd).write_unsigned(result) |
| |
| |
| class SRLI(RV32ImmShift): |
| insn = insn_for_mnemonic('srli', 3) |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| result = val1 >> self.shamt |
| state.gprs.get_reg(self.grd).write_unsigned(result) |
| |
| |
| class SRA(RV32RegReg): |
| insn = insn_for_mnemonic('sra', 3) |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_signed() |
| val2 = state.gprs.get_reg(self.grs2).read_unsigned() & 0x1f |
| result = val1 >> val2 |
| state.gprs.get_reg(self.grd).write_signed(result) |
| |
| |
| class SRAI(RV32ImmShift): |
| insn = insn_for_mnemonic('srai', 3) |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_signed() |
| val2 = self.shamt |
| result = val1 >> val2 |
| state.gprs.get_reg(self.grd).write_signed(result) |
| |
| |
| class AND(RV32RegReg): |
| insn = insn_for_mnemonic('and', 3) |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| val2 = state.gprs.get_reg(self.grs2).read_unsigned() |
| result = val1 & val2 |
| state.gprs.get_reg(self.grd).write_unsigned(result) |
| |
| |
| class ANDI(RV32RegImm): |
| insn = insn_for_mnemonic('andi', 3) |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| val2 = self.imm |
| result = val1 & val2 |
| state.gprs.get_reg(self.grd).write_unsigned(result) |
| |
| |
| class OR(RV32RegReg): |
| insn = insn_for_mnemonic('or', 3) |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| val2 = state.gprs.get_reg(self.grs2).read_unsigned() |
| result = val1 | val2 |
| state.gprs.get_reg(self.grd).write_unsigned(result) |
| |
| |
| class ORI(RV32RegImm): |
| insn = insn_for_mnemonic('ori', 3) |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| val2 = self.imm |
| result = val1 | val2 |
| state.gprs.get_reg(self.grd).write_unsigned(result) |
| |
| |
| class XOR(RV32RegReg): |
| insn = insn_for_mnemonic('xor', 3) |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| val2 = state.gprs.get_reg(self.grs2).read_unsigned() |
| result = val1 ^ val2 |
| state.gprs.get_reg(self.grd).write_unsigned(result) |
| |
| |
| class XORI(RV32RegImm): |
| insn = insn_for_mnemonic('xori', 3) |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| val2 = self.imm |
| result = val1 ^ val2 |
| state.gprs.get_reg(self.grd).write_unsigned(result) |
| |
| |
| class LW(OTBNInsn): |
| insn = insn_for_mnemonic('lw', 3) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.grd = op_vals['grd'] |
| self.offset = op_vals['offset'] |
| self.grs1 = op_vals['grs1'] |
| |
| def execute(self, state: OTBNState) -> None: |
| base = state.gprs.get_reg(self.grs1).read_unsigned() |
| addr = (base + self.offset) & ((1 << 32) - 1) |
| result = state.dmem.load_u32(addr) |
| state.gprs.get_reg(self.grd).write_unsigned(result) |
| |
| |
| class SW(OTBNInsn): |
| insn = insn_for_mnemonic('sw', 3) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.grs2 = op_vals['grs2'] |
| self.offset = op_vals['offset'] |
| self.grs1 = op_vals['grs1'] |
| |
| def execute(self, state: OTBNState) -> None: |
| base = state.gprs.get_reg(self.grs1).read_unsigned() |
| addr = (base + self.offset) & ((1 << 32) - 1) |
| value = state.gprs.get_reg(self.grs2).read_unsigned() |
| state.dmem.store_u32(addr, value) |
| |
| |
| class BEQ(OTBNInsn): |
| insn = insn_for_mnemonic('beq', 3) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.grs1 = op_vals['grs1'] |
| self.grs2 = op_vals['grs2'] |
| self.offset = op_vals['offset'] |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| val2 = state.gprs.get_reg(self.grs2).read_unsigned() |
| if val1 == val2: |
| state.pc_next = self.offset |
| |
| |
| class BNE(OTBNInsn): |
| insn = insn_for_mnemonic('bne', 3) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.grs1 = op_vals['grs1'] |
| self.grs2 = op_vals['grs2'] |
| self.offset = op_vals['offset'] |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| val2 = state.gprs.get_reg(self.grs2).read_unsigned() |
| if val1 != val2: |
| state.pc_next = self.offset |
| |
| |
| class JAL(OTBNInsn): |
| insn = insn_for_mnemonic('jal', 2) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.grd = op_vals['grd'] |
| self.offset = op_vals['offset'] |
| |
| def execute(self, state: OTBNState) -> None: |
| link_pc = (state.pc + 4) & ((1 << 32) - 1) |
| state.gprs.get_reg(self.grd).write_unsigned(link_pc) |
| state.pc_next = self.offset |
| |
| |
| class JALR(OTBNInsn): |
| insn = insn_for_mnemonic('jalr', 3) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.grd = op_vals['grd'] |
| self.grs1 = op_vals['grs1'] |
| self.offset = op_vals['offset'] |
| |
| def execute(self, state: OTBNState) -> None: |
| val1 = state.gprs.get_reg(self.grs1).read_unsigned() |
| link_pc = (state.pc + 4) & ((1 << 32) - 1) |
| |
| state.gprs.get_reg(self.grd).write_unsigned(link_pc) |
| state.pc_next = (val1 + self.offset) & ((1 << 32) - 1) |
| |
| |
| class CSRRS(OTBNInsn): |
| insn = insn_for_mnemonic('csrrs', 3) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.grd = op_vals['grd'] |
| self.csr = op_vals['csr'] |
| self.grs1 = op_vals['grs1'] |
| |
| def execute(self, state: OTBNState) -> None: |
| old_val = state.read_csr(self.csr) |
| bits_to_set = state.gprs.get_reg(self.grs1).read_unsigned() |
| new_val = old_val | bits_to_set |
| |
| state.gprs.get_reg(self.grd).write_unsigned(old_val) |
| state.write_csr(self.csr, new_val) |
| |
| |
| class CSRRW(OTBNInsn): |
| insn = insn_for_mnemonic('csrrw', 3) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.grd = op_vals['grd'] |
| self.csr = op_vals['csr'] |
| self.grs1 = op_vals['grs1'] |
| |
| def execute(self, state: OTBNState) -> None: |
| if self.grd == 0: |
| return |
| |
| old_val = state.read_csr(self.csr) |
| new_val = state.gprs.get_reg(self.grs1).read_unsigned() |
| |
| state.gprs.get_reg(self.grd).write_unsigned(old_val) |
| state.write_csr(self.csr, new_val) |
| |
| |
| class ECALL(OTBNInsn): |
| insn = insn_for_mnemonic('ecall', 0) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| pass |
| |
| def execute(self, state: OTBNState) -> None: |
| # INTR_STATE is the interrupt state register. Bit 0 (which is being |
| # set) is the 'done' flag. |
| state.ext_regs.set_bits('INTR_STATE', 1 << 0) |
| # STATUS is a status register. Bit 0 (being cleared) is the 'busy' flag |
| state.ext_regs.clear_bits('STATUS', 1 << 0) |
| |
| # As well as the external register, clear an internal 'running' flag to |
| # tell the simulation to stop. |
| state.running = False |
| |
| |
| class LOOP(OTBNInsn): |
| insn = insn_for_mnemonic('loop', 2) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.grs = op_vals['grs'] |
| self.bodysize = op_vals['bodysize'] |
| |
| def execute(self, state: OTBNState) -> None: |
| num_iters = state.gprs.get_reg(self.grs).read_unsigned() |
| state.loop_start(num_iters, self.bodysize) |
| |
| |
| class LOOPI(OTBNInsn): |
| insn = insn_for_mnemonic('loopi', 2) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.iterations = op_vals['iterations'] |
| self.bodysize = op_vals['bodysize'] |
| |
| def execute(self, state: OTBNState) -> None: |
| state.loop_start(self.iterations, self.bodysize) |
| |
| |
| class BNADD(OTBNInsn): |
| insn = insn_for_mnemonic('bn.add', 6) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs2 = op_vals['wrs2'] |
| self.shift_type = op_vals['shift_type'] |
| self.shift_bytes = op_vals['shift_bytes'] |
| self.flag_group = op_vals['flag_group'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a = state.wdrs.get_reg(self.wrs1).read_unsigned() |
| b = state.wdrs.get_reg(self.wrs2).read_unsigned() |
| b_shifted = logical_byte_shift(b, self.shift_type, self.shift_bytes) |
| |
| (result, flags) = state.add_with_carry(a, b_shifted, 0) |
| state.wdrs.get_reg(self.wrd).write_unsigned(result) |
| state.set_flags(self.flag_group, flags) |
| |
| |
| class BNADDC(OTBNInsn): |
| insn = insn_for_mnemonic('bn.addc', 6) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs2 = op_vals['wrs2'] |
| self.shift_type = op_vals['shift_type'] |
| self.shift_bytes = op_vals['shift_bytes'] |
| self.flag_group = op_vals['flag_group'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a = state.wdrs.get_reg(self.wrs1).read_unsigned() |
| b = state.wdrs.get_reg(self.wrs2).read_unsigned() |
| b_shifted = logical_byte_shift(b, self.shift_type, self.shift_bytes) |
| |
| carry = int(state.csrs.flags[self.flag_group].C) |
| (result, flags) = state.add_with_carry(a, b_shifted, carry) |
| state.wdrs.get_reg(self.wrd).write_unsigned(result) |
| state.set_flags(self.flag_group, flags) |
| |
| |
| class BNADDI(OTBNInsn): |
| insn = insn_for_mnemonic('bn.addi', 4) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wrs = op_vals['wrs'] |
| self.imm = op_vals['imm'] |
| self.flag_group = op_vals['flag_group'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a = state.wdrs.get_reg(self.wrs).read_unsigned() |
| b = self.imm |
| |
| (result, flags) = state.add_with_carry(a, b, 0) |
| state.wdrs.get_reg(self.wrd).write_unsigned(result) |
| state.set_flags(self.flag_group, flags) |
| |
| |
| class BNADDM(OTBNInsn): |
| insn = insn_for_mnemonic('bn.addm', 3) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs2 = op_vals['wrs2'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a = state.wdrs.get_reg(self.wrs1).read_unsigned() |
| b = state.wdrs.get_reg(self.wrs2).read_unsigned() |
| result = a + b |
| |
| mod_val = state.wsrs.MOD.read_unsigned() |
| if result >= mod_val: |
| result -= mod_val |
| |
| result = result & ((1 << 256) - 1) |
| state.wdrs.get_reg(self.wrd).write_unsigned(result) |
| |
| |
| class BNMULQACC(OTBNInsn): |
| insn = insn_for_mnemonic('bn.mulqacc', 6) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.zero_acc = op_vals['zero_acc'] |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs1_qwsel = op_vals['wrs1_qwsel'] |
| self.wrs2 = op_vals['wrs2'] |
| self.wrs2_qwsel = op_vals['wrs2_qwsel'] |
| self.acc_shift_imm = op_vals['acc_shift_imm'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a_qw = state.get_quarter_word_unsigned(self.wrs1, self.wrs1_qwsel) |
| b_qw = state.get_quarter_word_unsigned(self.wrs2, self.wrs2_qwsel) |
| |
| mul_res = a_qw * b_qw |
| |
| acc = state.wsrs.ACC.read_unsigned() |
| if self.zero_acc: |
| acc = 0 |
| |
| acc += (mul_res << self.acc_shift_imm) |
| |
| truncated = acc & ((1 << 256) - 1) |
| state.wsrs.ACC.write_unsigned(truncated) |
| |
| |
| class BNMULQACCWO(OTBNInsn): |
| insn = insn_for_mnemonic('bn.mulqacc.wo', 7) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.zero_acc = op_vals['zero_acc'] |
| self.wrd = op_vals['wrd'] |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs1_qwsel = op_vals['wrs1_qwsel'] |
| self.wrs2 = op_vals['wrs2'] |
| self.wrs2_qwsel = op_vals['wrs2_qwsel'] |
| self.acc_shift_imm = op_vals['acc_shift_imm'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a_qw = state.get_quarter_word_unsigned(self.wrs1, self.wrs1_qwsel) |
| b_qw = state.get_quarter_word_unsigned(self.wrs2, self.wrs2_qwsel) |
| |
| mul_res = a_qw * b_qw |
| |
| acc = state.wsrs.ACC.read_unsigned() |
| if self.zero_acc: |
| acc = 0 |
| |
| acc += (mul_res << self.acc_shift_imm) |
| |
| truncated = acc & ((1 << 256) - 1) |
| state.wdrs.get_reg(self.wrd).write_unsigned(truncated) |
| state.wsrs.ACC.write_unsigned(truncated) |
| |
| |
| class BNMULQACCSO(OTBNInsn): |
| insn = insn_for_mnemonic('bn.mulqacc.so', 8) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.zero_acc = op_vals['zero_acc'] |
| self.wrd = op_vals['wrd'] |
| self.wrd_hwsel = op_vals['wrd_hwsel'] |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs1_qwsel = op_vals['wrs1_qwsel'] |
| self.wrs2 = op_vals['wrs2'] |
| self.wrs2_qwsel = op_vals['wrs2_qwsel'] |
| self.acc_shift_imm = op_vals['acc_shift_imm'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a_qw = state.get_quarter_word_unsigned(self.wrs1, self.wrs1_qwsel) |
| b_qw = state.get_quarter_word_unsigned(self.wrs2, self.wrs2_qwsel) |
| |
| mul_res = a_qw * b_qw |
| |
| acc = state.wsrs.ACC.read_unsigned() |
| if self.zero_acc: |
| acc = 0 |
| |
| acc += (mul_res << self.acc_shift_imm) |
| |
| lo_part = acc & ((1 << 128) - 1) |
| hi_part = acc >> 128 |
| |
| state.set_half_word_unsigned(self.wrd, self.wrd_hwsel, lo_part) |
| state.wsrs.ACC.write_unsigned(hi_part) |
| |
| |
| class BNSUB(OTBNInsn): |
| insn = insn_for_mnemonic('bn.sub', 6) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs2 = op_vals['wrs2'] |
| self.shift_type = op_vals['shift_type'] |
| self.shift_bytes = op_vals['shift_bytes'] |
| self.flag_group = op_vals['flag_group'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a = state.wdrs.get_reg(self.wrs1).read_unsigned() |
| b = state.wdrs.get_reg(self.wrs2).read_unsigned() |
| b_shifted = logical_byte_shift(b, self.shift_type, self.shift_bytes) |
| |
| (result, flags) = state.sub_with_borrow(a, b_shifted, 0) |
| state.wdrs.get_reg(self.wrd).write_unsigned(result) |
| state.set_flags(self.flag_group, flags) |
| |
| |
| class BNSUBB(OTBNInsn): |
| insn = insn_for_mnemonic('bn.subb', 6) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs2 = op_vals['wrs2'] |
| self.shift_type = op_vals['shift_type'] |
| self.shift_bytes = op_vals['shift_bytes'] |
| self.flag_group = op_vals['flag_group'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a = state.wdrs.get_reg(self.wrs1).read_unsigned() |
| b = state.wdrs.get_reg(self.wrs2).read_unsigned() |
| b_shifted = logical_byte_shift(b, self.shift_type, self.shift_bytes) |
| borrow = int(state.csrs.flags[self.flag_group].C) |
| |
| (result, flags) = state.sub_with_borrow(a, b_shifted, borrow) |
| state.wdrs.get_reg(self.wrd).write_unsigned(result) |
| state.set_flags(self.flag_group, flags) |
| |
| |
| class BNSUBI(OTBNInsn): |
| insn = insn_for_mnemonic('bn.subi', 4) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wrs = op_vals['wrs'] |
| self.imm = op_vals['imm'] |
| self.flag_group = op_vals['flag_group'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a = state.wdrs.get_reg(self.wrs).read_unsigned() |
| b = self.imm |
| |
| (result, flags) = state.sub_with_borrow(a, b, 0) |
| state.wdrs.get_reg(self.wrd).write_unsigned(result) |
| state.set_flags(self.flag_group, flags) |
| |
| |
| class BNSUBM(OTBNInsn): |
| insn = insn_for_mnemonic('bn.subm', 3) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs2 = op_vals['wrs2'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a = state.wdrs.get_reg(self.wrs1).read_unsigned() |
| b = state.wdrs.get_reg(self.wrs2).read_unsigned() |
| |
| (ures, _) = state.sub_with_borrow(a, b, 0) |
| |
| mod_val = state.wsrs.MOD.read_unsigned() |
| |
| # sub_with_borrow returns an unsigned result (in 2's complement), so |
| # the result is negative if the top bit is set. |
| is_negative = bool(ures >> 255) |
| if is_negative: |
| result = (ures + mod_val) & ((1 << 256) - 1) |
| else: |
| result = ures |
| |
| state.wdrs.get_reg(self.wrd).write_unsigned(result) |
| |
| |
| class BNAND(OTBNInsn): |
| insn = insn_for_mnemonic('bn.and', 6) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs2 = op_vals['wrs2'] |
| self.shift_type = op_vals['shift_type'] |
| self.shift_bytes = op_vals['shift_bytes'] |
| self.flag_group = op_vals['flag_group'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a = state.wdrs.get_reg(self.wrs1).read_unsigned() |
| b = state.wdrs.get_reg(self.wrs2).read_unsigned() |
| b_shifted = logical_byte_shift(b, self.shift_type, self.shift_bytes) |
| |
| result = a & b_shifted |
| state.wdrs.get_reg(self.wrd).write_unsigned(result) |
| state.set_mlz_flags(self.flag_group, result) |
| |
| |
| class BNOR(OTBNInsn): |
| insn = insn_for_mnemonic('bn.or', 6) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs2 = op_vals['wrs2'] |
| self.shift_type = op_vals['shift_type'] |
| self.shift_bytes = op_vals['shift_bytes'] |
| self.flag_group = op_vals['flag_group'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a = state.wdrs.get_reg(self.wrs1).read_unsigned() |
| b = state.wdrs.get_reg(self.wrs2).read_unsigned() |
| b_shifted = logical_byte_shift(b, self.shift_type, self.shift_bytes) |
| |
| result = a | b_shifted |
| state.wdrs.get_reg(self.wrd).write_unsigned(result) |
| state.set_mlz_flags(self.flag_group, result) |
| |
| |
| class BNNOT(OTBNInsn): |
| insn = insn_for_mnemonic('bn.not', 5) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wrs = op_vals['wrs'] |
| self.shift_type = op_vals['shift_type'] |
| self.shift_bytes = op_vals['shift_bytes'] |
| self.flag_group = op_vals['flag_group'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a = state.wdrs.get_reg(self.wrs).read_unsigned() |
| a_shifted = logical_byte_shift(a, self.shift_type, self.shift_bytes) |
| |
| result = a_shifted ^ ((1 << 256) - 1) |
| state.wdrs.get_reg(self.wrd).write_unsigned(result) |
| state.set_mlz_flags(self.flag_group, result) |
| |
| |
| class BNXOR(OTBNInsn): |
| insn = insn_for_mnemonic('bn.xor', 6) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs2 = op_vals['wrs2'] |
| self.shift_type = op_vals['shift_type'] |
| self.shift_bytes = op_vals['shift_bytes'] |
| self.flag_group = op_vals['flag_group'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a = state.wdrs.get_reg(self.wrs1).read_unsigned() |
| b = state.wdrs.get_reg(self.wrs2).read_unsigned() |
| b_shifted = logical_byte_shift(b, self.shift_type, self.shift_bytes) |
| |
| result = a ^ b_shifted |
| state.wdrs.get_reg(self.wrd).write_unsigned(result) |
| state.set_mlz_flags(self.flag_group, result) |
| |
| |
| class BNRSHI(OTBNInsn): |
| insn = insn_for_mnemonic('bn.rshi', 4) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs2 = op_vals['wrs2'] |
| self.imm = op_vals['imm'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a = state.wdrs.get_reg(self.wrs1).read_unsigned() |
| b = state.wdrs.get_reg(self.wrs2).read_unsigned() |
| |
| result = (((a << 256) | b) >> self.imm) & ((1 << 256) - 1) |
| state.wdrs.get_reg(self.wrd).write_unsigned(result) |
| |
| |
| class BNRSEL(OTBNInsn): |
| insn = insn_for_mnemonic('bn.sel', 5) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs2 = op_vals['wrs2'] |
| self.flag_group = op_vals['flag_group'] |
| self.flag = op_vals['flag'] |
| |
| def execute(self, state: OTBNState) -> None: |
| flag_is_set = state.csrs.flags[self.flag_group].get_by_idx(self.flag) |
| wrs = self.wrs1 if flag_is_set else self.wrs2 |
| value = state.wdrs.get_reg(wrs).read_unsigned() |
| state.wdrs.get_reg(self.wrd).write_unsigned(value) |
| |
| |
| class BNCMP(OTBNInsn): |
| insn = insn_for_mnemonic('bn.cmp', 5) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs2 = op_vals['wrs2'] |
| self.shift_type = op_vals['shift_type'] |
| self.shift_bytes = op_vals['shift_bytes'] |
| self.flag_group = op_vals['flag_group'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a = state.wdrs.get_reg(self.wrs1).read_unsigned() |
| b = state.wdrs.get_reg(self.wrs2).read_unsigned() |
| b_shifted = logical_byte_shift(b, self.shift_type, self.shift_bytes) |
| |
| (_, flags) = state.sub_with_borrow(a, b_shifted, 0) |
| state.set_flags(self.flag_group, flags) |
| |
| |
| class BNCMPB(OTBNInsn): |
| insn = insn_for_mnemonic('bn.cmpb', 5) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrs1 = op_vals['wrs1'] |
| self.wrs2 = op_vals['wrs2'] |
| self.shift_type = op_vals['shift_type'] |
| self.shift_bytes = op_vals['shift_bytes'] |
| self.flag_group = op_vals['flag_group'] |
| |
| def execute(self, state: OTBNState) -> None: |
| a = state.wdrs.get_reg(self.wrs1).read_unsigned() |
| b = state.wdrs.get_reg(self.wrs2).read_unsigned() |
| b_shifted = logical_byte_shift(b, self.shift_type, self.shift_bytes) |
| borrow = int(state.csrs.flags[self.flag_group].C) |
| |
| (_, flags) = state.sub_with_borrow(a, b_shifted, borrow) |
| state.set_flags(self.flag_group, flags) |
| |
| |
| class BNLID(OTBNInsn): |
| insn = insn_for_mnemonic('bn.lid', 5) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.grd = op_vals['grd'] |
| self.grd_inc = op_vals['grd_inc'] |
| self.offset = op_vals['offset'] |
| self.grs1 = op_vals['grs1'] |
| self.grs1_inc = op_vals['grs1_inc'] |
| |
| def execute(self, state: OTBNState) -> None: |
| grs1_val = state.gprs.get_reg(self.grs1).read_unsigned() |
| addr = (grs1_val + self.offset) & ((1 << 32) - 1) |
| grd_val = state.gprs.get_reg(self.grd).read_unsigned() |
| |
| wrd = grd_val & 0x1f |
| value = state.dmem.load_u256(addr) |
| state.wdrs.get_reg(wrd).write_unsigned(value) |
| |
| if self.grd_inc: |
| new_grd_val = (grd_val + 1) & ((1 << 32) - 1) |
| state.gprs.get_reg(self.grd).write_unsigned(new_grd_val) |
| |
| if self.grs1_inc: |
| new_grs1_val = (grs1_val + 1) & ((1 << 32) - 1) |
| state.gprs.get_reg(self.grs1).write_unsigned(new_grs1_val) |
| |
| |
| class BNSID(OTBNInsn): |
| insn = insn_for_mnemonic('bn.sid', 5) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.grs2 = op_vals['grs2'] |
| self.grs2_inc = op_vals['grs2_inc'] |
| self.offset = op_vals['offset'] |
| self.grs1 = op_vals['grs1'] |
| self.grs1_inc = op_vals['grs1_inc'] |
| |
| def execute(self, state: OTBNState) -> None: |
| grs1_val = state.gprs.get_reg(self.grs1).read_unsigned() |
| addr = (grs1_val + self.offset) & ((1 << 32) - 1) |
| |
| grs2_val = state.gprs.get_reg(self.grs2).read_unsigned() |
| wrs = grs2_val & 0x1f |
| wrs_val = state.wdrs.get_reg(wrs).read_unsigned() |
| |
| state.dmem.store_u256(addr, wrs_val) |
| |
| if self.grs1_inc: |
| new_grs1_val = (grs1_val + 1) & ((1 << 32) - 1) |
| state.gprs.get_reg(self.grs1).write_unsigned(new_grs1_val) |
| |
| if self.grs2_inc: |
| new_grs2_val = (grs2_val + 1) & ((1 << 32) - 1) |
| state.gprs.get_reg(self.grs2).write_unsigned(new_grs2_val) |
| |
| |
| class BNMOV(OTBNInsn): |
| insn = insn_for_mnemonic('bn.mov', 2) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wrs = op_vals['wrs'] |
| |
| def execute(self, state: OTBNState) -> None: |
| value = state.wdrs.get_reg(self.wrs).read_unsigned() |
| state.wdrs.get_reg(self.wrd).write_unsigned(value) |
| |
| |
| class BNMOVR(OTBNInsn): |
| insn = insn_for_mnemonic('bn.movr', 4) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.grd = op_vals['grd'] |
| self.grd_inc = op_vals['grd_inc'] |
| self.grs = op_vals['grs'] |
| self.grs_inc = op_vals['grs_inc'] |
| |
| def execute(self, state: OTBNState) -> None: |
| grd_val = state.gprs.get_reg(self.grd).read_unsigned() |
| grs_val = state.gprs.get_reg(self.grs).read_unsigned() |
| |
| wrd = grd_val & 0x1f |
| wrs = grs_val & 0x1f |
| |
| value = state.wdrs.get_reg(wrs).read_unsigned() |
| state.wdrs.get_reg(wrd).write_unsigned(value) |
| |
| if self.grd_inc: |
| new_grd_val = (grd_val + 1) & ((1 << 32) - 1) |
| state.gprs.get_reg(self.grd).write_unsigned(new_grd_val) |
| |
| if self.grs_inc: |
| new_grs_val = (grs_val + 1) & ((1 << 32) - 1) |
| state.gprs.get_reg(self.grs).write_unsigned(new_grs_val) |
| |
| |
| class BNWSRRS(OTBNInsn): |
| insn = insn_for_mnemonic('bn.wsrrs', 3) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wsr = op_vals['wsr'] |
| self.wrs = op_vals['wrs'] |
| |
| def execute(self, state: OTBNState) -> None: |
| old_val = state.wsrs.read_at_idx(self.wsr) |
| bits_to_set = state.wdrs.get_reg(self.wrs).read_unsigned() |
| new_val = old_val | bits_to_set |
| |
| state.wdrs.get_reg(self.wrd).write_unsigned(old_val) |
| state.wsrs.write_at_idx(self.wsr, new_val) |
| |
| |
| class BNWSRRW(OTBNInsn): |
| insn = insn_for_mnemonic('bn.wsrrw', 3) |
| |
| def __init__(self, op_vals: Dict[str, int]): |
| super().__init__(op_vals) |
| self.wrd = op_vals['wrd'] |
| self.wsr = op_vals['wsr'] |
| self.wrs = op_vals['wrs'] |
| |
| def execute(self, state: OTBNState) -> None: |
| old_val = state.wsrs.read_at_idx(self.wsr) |
| new_val = state.wdrs.get_reg(self.wrs).read_unsigned() |
| |
| state.wdrs.get_reg(self.wrd).write_unsigned(old_val) |
| state.wsrs.write_at_idx(self.wsr, new_val) |
| |
| |
| INSN_CLASSES = [ |
| ADD, ADDI, LUI, SUB, SLL, SLLI, SRL, SRLI, SRA, SRAI, |
| AND, ANDI, OR, ORI, XOR, XORI, |
| LW, SW, |
| BEQ, BNE, JAL, JALR, |
| CSRRS, CSRRW, |
| ECALL, |
| LOOP, LOOPI, |
| |
| BNADD, BNADDC, BNADDI, BNADDM, |
| BNMULQACC, BNMULQACCWO, BNMULQACCSO, |
| BNSUB, BNSUBB, BNSUBI, BNSUBM, |
| BNAND, BNOR, BNNOT, BNXOR, |
| BNRSHI, |
| BNRSEL, |
| BNCMP, BNCMPB, |
| BNLID, BNSID, |
| BNMOV, BNMOVR, |
| BNWSRRS, BNWSRRW |
| ] |