blob: 509ebf5cd643b75122eba676954652fa7b7652a3 [file]
# Copyright lowRISC contributors.
# Licensed under the Apache License, Version 2.0, see LICENSE for details.
# SPDX-License-Identifier: Apache-2.0
from riscvmodel.insn import isa # type: ignore
from .isa import (InstructionBNAFType,
InstructionBNAIType,
InstructionBNAMType,
InstructionBNANType,
InstructionBNAQType,
InstructionBNAType,
InstructionBNCSType,
InstructionBNCType,
InstructionBNISType,
InstructionBNIType,
InstructionBNMVRType,
InstructionBNMVType,
InstructionBNRType,
InstructionBNSType,
InstructionLIType,
InstructionLType,
ShiftReg)
from .model import OTBNModel
from .variant import RV32IXotbn
@isa("loop", RV32IXotbn, opcode=0b1111011, funct2=0b00)
class InstructionLOOP(InstructionLType):
"""
Loop (indirect)
Repeat a sequence of code multiple times. The number of iterations is a GPR
value. The length of the loop is given as immediate.
Alternative assembly notation: The size of the loop body is given by the
number of instructions in the parentheses.
LOOP <grs> (
# loop body
)
"""
def execute(self, model: OTBNModel) -> None:
assert self.rs1 is not None
model.state.loop_start(int(model.state.intreg[self.rs1]),
int(self.bodysize))
@isa("loopi", RV32IXotbn, opcode=0b1111011, funct2=0b01)
class InstructionLOOPI(InstructionLIType):
"""
Loop Immediate
Repeat a sequence of code multiple times. The number of iterations is given
as an immediate, as is the length of the loop. The number of iterations must
be larger than zero.
Alternative assembly notation. The size of the loop body is given by the
number of instructions in the parentheses.
LOOPI <iterations> (
# loop body
)
"""
def execute(self, model: OTBNModel) -> None:
model.state.loop_start(int(self.iter), int(self.bodysize))
@isa("bn.add", RV32IXotbn, opcode=0b0101011, funct3=0b000)
class InstructionBNADD(InstructionBNAFType):
"""
Add
Adds two WDR values, writes the result to the destination WDR and updates
flags. The content of the second source WDR can be shifted by an immediate
before it is consumed by the operation.
"""
def execute(self, model: OTBNModel) -> None:
a = int(model.state.wreg[self.wrs1].unsigned())
b_shifted = ShiftReg(int(model.state.wreg[self.wrs2].unsigned()),
self.shift_type, self.shift_bytes)
(result, flags) = model.add_with_carry(a, b_shifted, 0)
model.state.wreg[self.wrd] = result
model.state.flags[self.fg] = flags
@isa("bn.addc", RV32IXotbn, opcode=0b0101011, funct3=0b010)
class InstructionBNADDC(InstructionBNAFType):
def execute(self, model: OTBNModel) -> None:
a = int(model.state.wreg[self.wrs1].unsigned())
b_shifted = ShiftReg(int(model.state.wreg[self.wrs2].unsigned()),
self.shift_type, self.shift_bytes)
(result, flags) = model.add_with_carry(a, b_shifted,
model.state.flags[self.fg].C)
model.state.wreg[self.wrd] = result
model.state.flags[self.fg] = flags
@isa("bn.addi", RV32IXotbn, opcode=0b0101011, funct3=0b100, funct30=0)
class InstructionBNADDI(InstructionBNAIType):
def execute(self, model: OTBNModel) -> None:
a = int(model.state.wreg[self.wrs1].unsigned())
b = int(self.imm)
(result, flags) = model.add_with_carry(a, b, 0)
model.state.wreg[self.wrd] = result
model.state.flags[self.fg] = flags
@isa("bn.addm", RV32IXotbn, opcode=0b0101011, funct3=0b101, funct30=0)
class InstructionBNADDM(InstructionBNAMType):
def execute(self, model: OTBNModel) -> None:
a = int(model.state.wreg[self.wrs1].unsigned())
b = int(model.state.wreg[self.wrs2].unsigned())
(result, _) = model.add_with_carry(a, b, 0)
if result >= int(model.state.mod):
result -= int(model.state.mod)
model.state.wreg[self.wrd] = result
@isa("bn.mulqacc", RV32IXotbn, opcode=0b0111011)
class InstructionBNMULQACC(InstructionBNAQType):
"""
Quarter-word Multiply and Accumulate
Multiplies two WLEN/4 WDR values and adds the result to an accumulator after
shifting it. Optionally shifts some/all of the resulting accumulator value
out to a destination WDR.
"""
def execute(self, model: OTBNModel) -> None:
assert self.wrs1 is not None
assert self.wrs2 is not None
assert self.wrs1_qwsel is not None
assert self.wrs2_qwsel is not None
assert self.acc_shift_imm is not None
a_qw = model.get_wr_quarterword(self.wrs1, self.wrs1_qwsel)
b_qw = model.get_wr_quarterword(self.wrs2, self.wrs2_qwsel)
mul_res = a_qw * b_qw
acc = int(model.state.single_regs['acc'])
if (self.zero_acc):
acc = 0
acc += (mul_res << (self.acc_shift_imm * 64))
if self.wb_variant > 0:
if self.wb_variant == 1:
model.state.wreg[self.wrd].set(acc)
elif self.wb_variant >= 2:
# set_wr_halfword expects 0 in upper 128 bits
acc_lower = acc & ((1 << 128) - 1)
model.set_wr_halfword(self.wrd, acc_lower, self.wrd_hwsel)
acc = acc >> 128
model.state.single_regs['acc'].update(acc)
@isa("bn.sub", RV32IXotbn, opcode=0b0101011, funct3=0b001)
class InstructionBNSUB(InstructionBNAFType):
def execute(self, model: OTBNModel) -> None:
a = int(model.state.wreg[self.wrs1])
b_shifted = ShiftReg(int(model.state.wreg[self.wrs2]), self.shift_type,
self.shift_bytes)
(result, flags) = model.add_with_carry(a, -b_shifted, 0)
model.state.wreg[self.wrd] = result
model.state.flags[self.fg] = flags
@isa("bn.subb", RV32IXotbn, opcode=0b0101011, funct3=0b011)
class InstructionBNSUBB(InstructionBNAFType):
def execute(self, model: OTBNModel) -> None:
a = int(model.state.wreg[self.wrs1])
b_shifted = ShiftReg(int(model.state.wreg[self.wrs2]), self.shift_type,
self.shift_bytes)
(result,
flags) = model.add_with_carry(a, -b_shifted,
1 - model.state.flags[self.fg].C)
model.state.wreg[self.wrd] = result
model.state.flags[self.fg] = flags
@isa("bn.subi", RV32IXotbn, opcode=0b0101011, funct3=0b100, funct30=1)
class InstructionBNSUBI(InstructionBNAIType):
def execute(self, model: OTBNModel) -> None:
a = int(model.state.wreg[self.wrs1])
b = int(self.imm)
(result, flags) = model.add_with_carry(a, -b, 0)
model.state.wreg[self.wrd] = result
model.state.flags[self.fg] = flags
@isa("bn.subm", RV32IXotbn, opcode=0b0101011, funct3=0b101, funct30=1)
class InstructionBNSUBM(InstructionBNAMType):
def execute(self, model: OTBNModel) -> None:
a = int(model.state.wreg[self.wrs1])
b = int(model.state.wreg[self.wrs2])
result, _ = model.add_with_carry(a, -b, 0)
if result >= model.state.mod:
result -= model.state.mod
model.state.wreg[self.wrd] = result
@isa("bn.and", RV32IXotbn, opcode=0b0101011, funct3=0b110, funct31=0)
class InstructionBNAND(InstructionBNAType):
"""
Bitwise AND
Performs a bitwise and operation. Takes the values stored in registers
referenced by wrs1 and wrs2 and stores the result in the register referenced
by wrd. The content of the second source register can be shifted by an
immediate before it is consumed by the operation.
"""
def execute(self, model: OTBNModel) -> None:
assert self.shift_type is not None
b_shifted = ShiftReg(model.state.wreg[self.wrs2],
self.shift_type, self.shift_bytes)
a = model.state.wreg[self.wrs1]
model.state.wreg[self.wrd] = a & b_shifted
@isa("bn.or", RV32IXotbn, opcode=0b0101011, funct3=0b110, funct31=1)
class InstructionBNOR(InstructionBNAType):
"""
Bitwise OR
Performs a bitwise or operation. Takes the values stored in WDRs referenced
by wrs1 and wrs2 and stores the result in the WDR referenced by wrd. The
content of the second source WDR can be shifted by an immediate before it is
consumed by the operation.
"""
def execute(self, model: OTBNModel) -> None:
assert self.shift_type is not None
b_shifted = ShiftReg(model.state.wreg[self.wrs2],
self.shift_type, self.shift_bytes)
a = model.state.wreg[self.wrs1]
model.state.wreg[self.wrd] = a | b_shifted
@isa("bn.not", RV32IXotbn, opcode=0b0101011, funct3=0b111, funct31=0)
class InstructionBNNOT(InstructionBNANType):
"""
Bitwise NOT
Negates the value in <wrs>, storing the result into <wrd>. The source value
can be shifted by an immediate before it is consumed by the operation.
"""
def execute(self, model: OTBNModel) -> None:
b_shifted = model.state.wreg[self.wrs1]
model.state.wreg[self.wrd] = ~b_shifted
@isa("bn.xor", RV32IXotbn, opcode=0b0101011, funct3=0b111, funct31=1)
class InstructionBNXOR(InstructionBNAType):
"""
Bitwise XOR.
Performs a bitwise xor operation. Takes the values stored in WDRs referenced
by wrs1 and wrs2 and stores the result in the WDR referenced by wrd. The
content of the second source WDR can be shifted by an immediate before it is
consumed by the operation.
"""
def execute(self, model: OTBNModel) -> None:
b_shifted = model.state.wreg[self.wrs2]
a = model.state.wreg[self.wrs1]
model.state.wreg[self.wrd] = a ^ b_shifted
@isa("bn.rshi", RV32IXotbn, opcode=0b1111011, funct2=0b11)
class InstructionBNRSHI(InstructionBNRType):
def execute(self, model: OTBNModel) -> None:
a = int(model.state.wreg[self.wrs1])
b = int(model.state.wreg[self.wrs2])
shift_bit = int(self.imm)
model.state.wreg[self.wrd] = (((a << 256) | b) >> shift_bit) & (
(1 << 256) - 1)
@isa("bn.sel", RV32IXotbn, opcode=0b0001011, funct3=0b000)
class InstructionBNSEL(InstructionBNSType):
def execute(self, model: OTBNModel) -> None:
# self.flag gives a number (0-3), which we need to convert to a flag
# name for use with BitflagRegister.
assert self.flag is not None
assert 0 <= self.flag <= 3
flag_name = ['C', 'L', 'M', 'Z'][self.flag]
flag_is_set = model.state.flags[self.fg].get(flag_name)
val = model.state.wreg[self.wrs1 if flag_is_set else self.wrs2]
model.state.wreg[self.wrd] = val
@isa("bn.cmp", RV32IXotbn, opcode=0b0001011, funct3=0b001)
class InstructionBNCMP(InstructionBNCType):
def execute(self, model: OTBNModel) -> None:
a = int(model.state.wreg[self.wrs1])
b_shifted = ShiftReg(int(model.state.wreg[self.wrs2]), self.shift_type,
self.shift_bytes)
(_, flags) = model.add_with_carry(a, -b_shifted, 0)
model.state.flags[self.fg] = flags
@isa("bn.cmpb", RV32IXotbn, opcode=0b0001011, funct3=0b011)
class InstructionBNCMPB(InstructionBNCType):
def execute(self, model: OTBNModel) -> None:
a = int(model.state.wreg[self.wrs1])
b_shifted = ShiftReg(int(model.state.wreg[self.wrs2]), self.shift_type,
self.shift_bytes)
(_, flags) = model.add_with_carry(a, -b_shifted,
1 - model.state.flags[self.fg].C)
model.state.flags[self.fg] = flags
@isa("bn.lid", RV32IXotbn, opcode=0b0001011, funct3=0b100)
class InstructionBNLID(InstructionBNIType):
"""
Load Word (indirect source, indirect destination)
Calculates a byte memory address by adding the offset to the value in the
GPR grs1. The value from this memory address is then copied into the WDR
pointed to by the value in GPR grd.
After the operation, either the value in the GPR grs1, or the value in grd
can be optionally incremented.
If grs1_inc is set, the value in grs1 is incremented by the value WLEN/8
(one word). If grd_inc is set, the value in grd is incremented by the value
1.
"""
def execute(self, model: OTBNModel) -> None:
assert self.rs is not None
assert self.rd is not None
addr = int(model.state.intreg[self.rs] + int(self.imm))
wrd = int(model.state.intreg[self.rd])
word = model.load_wlen_word_from_memory(addr)
model.state.wreg[wrd] = word
@isa("bn.sid", RV32IXotbn, opcode=0b0001011, funct3=0b101)
class InstructionBNSID(InstructionBNISType):
"""
Store Word (indirect source, indirect destination)
Calculates a byte memory address by adding the offset to the value in the
GPR grs1. The value from the WDR pointed to by grs2 is then copied into the
memory.
After the operation, either the value in the GPR grs1, or the value in grs2
can be optionally incremented.
If grs1_inc is set, the value in grs1 is incremented by the value WLEN/8
(one word). If grs2_inc is set, the value in grs2 is incremented by the
value 1.
"""
def execute(self, model: OTBNModel) -> None:
assert self.rs2 is not None
assert self.rs1 is not None
addr = int(model.state.intreg[self.rs2] + int(self.imm))
wrs = int(model.state.intreg[self.rs1])
word = int(model.state.wreg[wrs])
model.store_wlen_word_to_memory(addr, word)
@isa("bn.mov", RV32IXotbn, opcode=0b0001011, funct3=0b110, funct31=0)
class InstructionBNMOV(InstructionBNMVType):
def execute(self, model: OTBNModel) -> None:
model.state.wreg[self.wrd] = model.state.wreg[self.wrs]
@isa("bn.movr", RV32IXotbn, opcode=0b0001011, funct3=0b110, funct31=1)
class InstructionBNMOVR(InstructionBNMVRType):
def execute(self, model: OTBNModel) -> None:
assert self.rd is not None
assert self.rs is not None
wrd = int(model.state.intreg[self.rd])
wrs = int(model.state.intreg[self.rs])
model.state.wreg[wrd] = model.state.wreg[wrs]
if self.rd_inc:
model.state.intreg[self.rd] += 1
if self.rs_inc:
model.state.intreg[self.rs] += 1
@isa("bn.wsrrs", RV32IXotbn, opcode=0b0001011, funct3=0b111, funct31=0)
class InstructionBNWSRRS(InstructionBNCSType):
"""
Atomic Read and Set Bits in WSR
"""
def execute(self, model: OTBNModel) -> None:
csr = model.state.wcsr_read(self.wsr)
model.state.wreg[self.wrd] = model.state.wreg[self.wrs] & csr
@isa("bn.wsrrw", RV32IXotbn, opcode=0b0001011, funct3=0b111, funct31=1)
class InstructionBNWSRRW(InstructionBNCSType):
def execute(self, model: OTBNModel) -> None:
index = int(self.wsr)
old_val = model.state.wcsr_read(index)
new_val = model.state.wreg[self.wrs]
model.state.wcsr_write(index, new_val)
model.state.wreg[self.wrd] = old_val