blob: 0cb097d1c8648fb5d4e24f0c7733e3982a60442a [file] [log] [blame]
# 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, Iterator, Optional
from .constants import ErrBits
from .flags import FlagReg
from .isa import (OTBNInsn, RV32RegReg, RV32RegImm,
RV32ImmShift, insn_for_mnemonic, logical_byte_shift,
extract_quarter_word)
from .state import OTBNState
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()
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
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()
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
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, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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()
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
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
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
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()
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
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
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
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()
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
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
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
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
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
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()
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
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.to_2s_complement(self.imm)
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
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()
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
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.to_2s_complement(self.imm)
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
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()
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
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.to_2s_complement(self.imm)
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
result = val1 ^ val2
state.gprs.get_reg(self.grd).write_unsigned(result)
class LW(OTBNInsn):
insn = insn_for_mnemonic('lw', 3)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, op_vals)
self.grd = op_vals['grd']
self.offset = op_vals['offset']
self.grs1 = op_vals['grs1']
def execute(self, state: OTBNState) -> Optional[Iterator[None]]:
# LW executes over two cycles. On the first cycle, we read the base
# address, compute the load address and check it for correctness, then
# perform the load itself, returning the result.
#
# On the second cycle, we write the result to the destination register.
base = state.gprs.get_reg(self.grs1).read_unsigned()
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
addr = (base + self.offset) & ((1 << 32) - 1)
if not state.dmem.is_valid_32b_addr(addr):
state.stop_at_end_of_cycle(ErrBits.BAD_DATA_ADDR)
return
result = state.dmem.load_u32(addr)
# Stall for a single cycle for memory to respond
yield
if result is None:
state.stop_at_end_of_cycle(ErrBits.DMEM_INTG_VIOLATION)
return
state.gprs.get_reg(self.grd).write_unsigned(result)
class SW(OTBNInsn):
insn = insn_for_mnemonic('sw', 3)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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()
bad_grs1 = state.gprs.call_stack_err and (self.grs1 == 1)
saw_err = False
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
saw_err = True
if not state.dmem.is_valid_32b_addr(addr) and not bad_grs1:
state.stop_at_end_of_cycle(ErrBits.BAD_DATA_ADDR)
saw_err = True
if saw_err:
return
state.dmem.store_u32(addr, value)
class BEQ(OTBNInsn):
insn = insn_for_mnemonic('beq', 3)
affects_control = True
has_fetch_stall = True
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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 state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
tgt_pc = self.offset & ((1 << 32) - 1)
if val1 == val2:
if not state.is_pc_valid(tgt_pc):
state.stop_at_end_of_cycle(ErrBits.BAD_INSN_ADDR)
else:
state.set_next_pc(tgt_pc)
class BNE(OTBNInsn):
insn = insn_for_mnemonic('bne', 3)
affects_control = True
has_fetch_stall = True
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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 state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
tgt_pc = self.offset & ((1 << 32) - 1)
if val1 != val2:
if not state.is_pc_valid(tgt_pc):
state.stop_at_end_of_cycle(ErrBits.BAD_INSN_ADDR)
else:
state.set_next_pc(tgt_pc)
class JAL(OTBNInsn):
insn = insn_for_mnemonic('jal', 2)
affects_control = True
has_fetch_stall = True
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, op_vals)
self.grd = op_vals['grd']
self.offset = op_vals['offset']
def execute(self, state: OTBNState) -> None:
mask32 = ((1 << 32) - 1)
link_pc = (state.pc + 4) & mask32
state.gprs.get_reg(self.grd).write_unsigned(link_pc)
next_pc = self.offset & mask32
if not state.is_pc_valid(next_pc):
state.stop_at_end_of_cycle(ErrBits.BAD_INSN_ADDR)
else:
state.set_next_pc(next_pc)
class JALR(OTBNInsn):
insn = insn_for_mnemonic('jalr', 3)
affects_control = True
has_fetch_stall = True
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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()
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
mask32 = ((1 << 32) - 1)
link_pc = (state.pc + 4) & mask32
state.gprs.get_reg(self.grd).write_unsigned(link_pc)
next_pc = (val1 + self.offset) & mask32
if not state.is_pc_valid(next_pc):
state.stop_at_end_of_cycle(ErrBits.BAD_INSN_ADDR)
else:
state.set_next_pc(next_pc)
class CSRRS(OTBNInsn):
insn = insn_for_mnemonic('csrrs', 3)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, op_vals)
self.grd = op_vals['grd']
self.csr = op_vals['csr']
self.grs1 = op_vals['grs1']
def execute(self, state: OTBNState) -> Optional[Iterator[None]]:
if not state.csrs.check_idx(self.csr):
# Invalid CSR index. Stop with an illegal instruction error.
state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
return
bits_to_set = state.gprs.get_reg(self.grs1).read_unsigned()
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
if self.csr == 0xfc0:
# A read from RND. If a RND value is not available, request_value()
# initiates or continues an EDN request and returns False. If a RND
# value is available, it returns True.
while not state.wsrs.RND.request_value():
# There's a pending EDN request. Stall for a cycle.
yield
# At this point, the CSR is ready. Read, update and write back to grs1.
old_val = state.read_csr(self.csr)
new_val = old_val | bits_to_set
state.gprs.get_reg(self.grd).write_unsigned(old_val)
if self.grs1 != 0:
state.write_csr(self.csr, new_val)
class CSRRW(OTBNInsn):
insn = insn_for_mnemonic('csrrw', 3)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, op_vals)
self.grd = op_vals['grd']
self.csr = op_vals['csr']
self.grs1 = op_vals['grs1']
def execute(self, state: OTBNState) -> Optional[Iterator[None]]:
if not state.csrs.check_idx(self.csr):
# Invalid CSR index. Stop with an illegal instruction error.
state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
return
new_val = state.gprs.get_reg(self.grs1).read_unsigned()
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
if self.csr == 0xfc0 and self.grd != 0:
# A read from RND. If a RND value is not available, request_value()
# initiates or continues an EDN request and returns False. If a RND
# value is available, it returns True.
while not state.wsrs.RND.request_value():
# There's a pending EDN request. Stall for a cycle.
yield
# At this point, the CSR is either ready or unneeded. Read it if
# necessary and write to grd, then overwrite with new_val.
if self.grd != 0:
old_val = state.read_csr(self.csr)
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 execute(self, state: OTBNState) -> None:
# Set INTR_STATE.done and STATUS, reflecting the fact we've stopped.
state.stop_at_end_of_cycle(err_bits=0)
class LOOP(OTBNInsn):
insn = insn_for_mnemonic('loop', 2)
affects_control = True
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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()
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
return
if num_iters == 0:
state.stop_at_end_of_cycle(ErrBits.LOOP)
else:
state.loop_start(num_iters, self.bodysize)
class LOOPI(OTBNInsn):
insn = insn_for_mnemonic('loopi', 2)
affects_control = True
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, op_vals)
self.iterations = op_vals['iterations']
self.bodysize = op_vals['bodysize']
def execute(self, state: OTBNState) -> None:
if self.iterations == 0:
state.stop_at_end_of_cycle(ErrBits.LOOP)
else:
state.loop_start(self.iterations, self.bodysize)
class BNADD(OTBNInsn):
insn = insn_for_mnemonic('bn.add', 6)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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_bits'] // 8
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)
full_result = a + b_shifted
mask256 = (1 << 256) - 1
masked_result = full_result & mask256
carry_flag = bool((full_result >> 256) & 1)
flags = FlagReg.mlz_for_result(carry_flag, masked_result)
state.wdrs.get_reg(self.wrd).write_unsigned(masked_result)
state.set_flags(self.flag_group, flags)
class BNADDC(OTBNInsn):
insn = insn_for_mnemonic('bn.addc', 6)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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_bits'] // 8
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)
full_result = a + b_shifted + carry
mask256 = (1 << 256) - 1
masked_result = full_result & mask256
carry_flag = bool((full_result >> 256) & 1)
flags = FlagReg.mlz_for_result(carry_flag, masked_result)
state.wdrs.get_reg(self.wrd).write_unsigned(masked_result)
state.set_flags(self.flag_group, flags)
class BNADDI(OTBNInsn):
insn = insn_for_mnemonic('bn.addi', 4)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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
full_result = a + b
mask256 = (1 << 256) - 1
masked_result = full_result & mask256
carry_flag = bool((full_result >> 256) & 1)
flags = FlagReg.mlz_for_result(carry_flag, masked_result)
state.wdrs.get_reg(self.wrd).write_unsigned(masked_result)
state.set_flags(self.flag_group, flags)
class BNADDM(OTBNInsn):
insn = insn_for_mnemonic('bn.addm', 3)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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 = state.wdrs.get_reg(self.wrs1).read_unsigned()
b = state.wdrs.get_reg(self.wrs2).read_unsigned()
a_qw = extract_quarter_word(a, self.wrs1_qwsel)
b_qw = extract_quarter_word(b, 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', 8)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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']
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()
a_qw = extract_quarter_word(a, self.wrs1_qwsel)
b_qw = extract_quarter_word(b, 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)
state.set_mlz_flags(self.flag_group, truncated)
class BNMULQACCSO(OTBNInsn):
insn = insn_for_mnemonic('bn.mulqacc.so', 9)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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']
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()
a_qw = extract_quarter_word(a, self.wrs1_qwsel)
b_qw = extract_quarter_word(b, 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)
# Split the result into low and high parts
lo_part = truncated & ((1 << 128) - 1)
hi_part = truncated >> 128
# Shift out the low part of the result
hw_shift = 128 * self.wrd_hwsel
hw_mask = ((1 << 128) - 1) << hw_shift
old_wrd = state.wdrs.get_reg(self.wrd).read_unsigned()
new_wrd = (old_wrd & ~hw_mask) | (lo_part << hw_shift)
state.wdrs.get_reg(self.wrd).write_unsigned(new_wrd)
# Write back the high part of the result
state.wsrs.ACC.write_unsigned(hi_part)
old_flags = state.csrs.flags[self.flag_group]
if self.wrd_hwsel:
new_flags = FlagReg(C=old_flags.C,
M=bool((lo_part >> 127) & 1),
L=old_flags.L,
Z=old_flags.Z and lo_part == 0)
else:
new_flags = FlagReg(C=old_flags.C,
M=old_flags.M,
L=bool(lo_part & 1),
Z=lo_part == 0)
state.set_flags(self.flag_group, new_flags)
class BNSUB(OTBNInsn):
insn = insn_for_mnemonic('bn.sub', 6)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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_bits'] // 8
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)
full_result = a - b_shifted
mask256 = (1 << 256) - 1
masked_result = full_result & mask256
carry_flag = bool((full_result >> 256) & 1)
flags = FlagReg.mlz_for_result(carry_flag, masked_result)
state.wdrs.get_reg(self.wrd).write_unsigned(masked_result)
state.set_flags(self.flag_group, flags)
class BNSUBB(OTBNInsn):
insn = insn_for_mnemonic('bn.subb', 6)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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_bits'] // 8
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)
full_result = a - b_shifted - borrow
mask256 = (1 << 256) - 1
masked_result = full_result & mask256
carry_flag = bool((full_result >> 256) & 1)
flags = FlagReg.mlz_for_result(carry_flag, masked_result)
state.wdrs.get_reg(self.wrd).write_unsigned(masked_result)
state.set_flags(self.flag_group, flags)
class BNSUBI(OTBNInsn):
insn = insn_for_mnemonic('bn.subi', 4)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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
full_result = a - b
mask256 = (1 << 256) - 1
masked_result = full_result & mask256
carry_flag = bool((full_result >> 256) & 1)
flags = FlagReg.mlz_for_result(carry_flag, masked_result)
state.wdrs.get_reg(self.wrd).write_unsigned(masked_result)
state.set_flags(self.flag_group, flags)
class BNSUBM(OTBNInsn):
insn = insn_for_mnemonic('bn.subm', 3)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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()
mod_val = state.wsrs.MOD.read_unsigned()
diff = a - b
if diff < 0:
diff += mod_val
result = diff & ((1 << 256) - 1)
state.wdrs.get_reg(self.wrd).write_unsigned(result)
class BNAND(OTBNInsn):
insn = insn_for_mnemonic('bn.and', 6)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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_bits'] // 8
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, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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_bits'] // 8
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, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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_bits'] // 8
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, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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_bits'] // 8
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, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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 BNSEL(OTBNInsn):
insn = insn_for_mnemonic('bn.sel', 5)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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_bits'] // 8
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)
full_result = a - b_shifted
mask256 = (1 << 256) - 1
masked_result = full_result & mask256
carry_flag = bool((full_result >> 256) & 1)
flags = FlagReg.mlz_for_result(carry_flag, masked_result)
state.set_flags(self.flag_group, flags)
class BNCMPB(OTBNInsn):
insn = insn_for_mnemonic('bn.cmpb', 5)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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_bits'] // 8
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)
full_result = a - b_shifted - borrow
mask256 = (1 << 256) - 1
masked_result = full_result & mask256
carry_flag = bool((full_result >> 256) & 1)
flags = FlagReg.mlz_for_result(carry_flag, masked_result)
state.set_flags(self.flag_group, flags)
class BNLID(OTBNInsn):
insn = insn_for_mnemonic('bn.lid', 5)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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) -> Optional[Iterator[None]]:
# BN.LID executes over two cycles. On the first cycle, we read the base
# address, compute the load address and check it for correctness,
# increment any GPRs, then perform the load itself. On the second
# cycle, update the WDR with the result.
if self.grs1_inc and self.grd_inc:
state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
return
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()
bad_grs1 = state.gprs.call_stack_err and (self.grs1 == 1)
bad_grd = state.gprs.call_stack_err and (self.grd == 1)
saw_err = False
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
saw_err = True
if grd_val > 31 and not bad_grd:
state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
saw_err = True
if not state.dmem.is_valid_256b_addr(addr) and not bad_grs1:
state.stop_at_end_of_cycle(ErrBits.BAD_DATA_ADDR)
saw_err = True
if saw_err:
return
wrd = grd_val & 0x1f
value = state.dmem.load_u256(addr)
if self.grd_inc:
new_grd_val = grd_val + 1
state.gprs.get_reg(self.grd).write_unsigned(new_grd_val)
if self.grs1_inc:
new_grs1_val = (grs1_val + 32) & ((1 << 32) - 1)
state.gprs.get_reg(self.grs1).write_unsigned(new_grs1_val)
# Stall for a single cycle for memory to respond
yield
if value is None:
state.stop_at_end_of_cycle(ErrBits.DMEM_INTG_VIOLATION)
return
state.wdrs.get_reg(wrd).write_unsigned(value)
class BNSID(OTBNInsn):
insn = insn_for_mnemonic('bn.sid', 5)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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) -> Optional[Iterator[None]]:
if self.grs1_inc and self.grs2_inc:
state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
return
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()
bad_grs1 = state.gprs.call_stack_err and (self.grs1 == 1)
bad_grs2 = state.gprs.call_stack_err and (self.grs2 == 1)
saw_err = False
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
saw_err = True
if grs2_val > 31 and not bad_grs2:
state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
saw_err = True
if not state.dmem.is_valid_256b_addr(addr) and not bad_grs1:
state.stop_at_end_of_cycle(ErrBits.BAD_DATA_ADDR)
saw_err = True
if saw_err:
return
if self.grs1_inc:
new_grs1_val = (grs1_val + 32) & ((1 << 32) - 1)
state.gprs.get_reg(self.grs1).write_unsigned(new_grs1_val)
if self.grs2_inc:
new_grs2_val = grs2_val + 1
state.gprs.get_reg(self.grs2).write_unsigned(new_grs2_val)
yield
wrs = grs2_val & 0x1f
wrs_val = state.wdrs.get_reg(wrs).read_unsigned()
state.dmem.store_u256(addr, wrs_val)
class BNMOV(OTBNInsn):
insn = insn_for_mnemonic('bn.mov', 2)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, 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) -> Optional[Iterator[None]]:
if self.grs_inc and self.grd_inc:
state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
return
grd_val = state.gprs.get_reg(self.grd).read_unsigned()
grs_val = state.gprs.get_reg(self.grs).read_unsigned()
bad_grs = state.gprs.call_stack_err and (self.grs == 1)
bad_grd = state.gprs.call_stack_err and (self.grd == 1)
saw_err = False
if state.gprs.call_stack_err:
state.stop_at_end_of_cycle(ErrBits.CALL_STACK)
saw_err = True
if grd_val > 31 and not bad_grd:
state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
saw_err = True
if grs_val > 31 and not bad_grs:
state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
saw_err = True
if saw_err:
return
wrd = grd_val & 0x1f
wrs = grs_val & 0x1f
if self.grd_inc:
new_grd_val = grd_val + 1
state.gprs.get_reg(self.grd).write_unsigned(new_grd_val)
if self.grs_inc:
new_grs_val = grs_val + 1
state.gprs.get_reg(self.grs).write_unsigned(new_grs_val)
yield
value = state.wdrs.get_reg(wrs).read_unsigned()
state.wdrs.get_reg(wrd).write_unsigned(value)
class BNWSRR(OTBNInsn):
insn = insn_for_mnemonic('bn.wsrr', 2)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, op_vals)
self.wrd = op_vals['wrd']
self.wsr = op_vals['wsr']
def execute(self, state: OTBNState) -> Optional[Iterator[None]]:
# The first, and possibly only, cycle of execution.
if not state.wsrs.check_idx(self.wsr):
# Invalid WSR index. Stop with an illegal instruction error.
state.stop_at_end_of_cycle(ErrBits.ILLEGAL_INSN)
return
if self.wsr == 0x1:
# A read from RND. If a RND value is not available, request_value()
# initiates or continues an EDN request and returns False. If a RND
# value is available, it returns True.
while not state.wsrs.RND.request_value():
# There's a pending EDN request. Stall for a cycle.
yield
# At this point, the WSR is ready. Does it have a valid value? (It
# might not if this is a sideload key register and keymgr hasn't
# provided us with a value). If not, fail with a KEY_INVALID error.
if not state.wsrs.has_value_at_idx(self.wsr):
state.stop_at_end_of_cycle(ErrBits.KEY_INVALID)
return
# The WSR is ready and has a value. Read it.
val = state.wsrs.read_at_idx(self.wsr)
state.wdrs.get_reg(self.wrd).write_unsigned(val)
class BNWSRW(OTBNInsn):
insn = insn_for_mnemonic('bn.wsrw', 2)
def __init__(self, raw: int, op_vals: Dict[str, int]):
super().__init__(raw, op_vals)
self.wsr = op_vals['wsr']
self.wrs = op_vals['wrs']
def execute(self, state: OTBNState) -> None:
val = state.wdrs.get_reg(self.wrs).read_unsigned()
state.wsrs.write_at_idx(self.wsr, 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,
BNSEL,
BNCMP, BNCMPB,
BNLID, BNSID,
BNMOV, BNMOVR,
BNWSRR, BNWSRW
]