diff --git a/coreblocks/arch/isa.py b/coreblocks/arch/isa.py index 39ce1abfa..ffe204ba0 100644 --- a/coreblocks/arch/isa.py +++ b/coreblocks/arch/isa.py @@ -57,6 +57,8 @@ class Extension(enum.IntFlag): ZICNTR = auto() #: Enables hardware performance counters ZIHPM = auto() + #: Integer conditional operations + ZICOND = auto() #: Misaligned atomic operations ZAM = auto() #: Half precision floating-point operations (16-bit) diff --git a/coreblocks/arch/isa_consts.py b/coreblocks/arch/isa_consts.py index abb95cca2..a472239cd 100644 --- a/coreblocks/arch/isa_consts.py +++ b/coreblocks/arch/isa_consts.py @@ -53,9 +53,9 @@ class Funct3(IntEnum, shape=3): W = SLT = CSRRS = MULHSU = SH1ADD = CLMULR = _EBREAKPOINT = 0b010 D = SLTU = CSRRC = MULHU = CLMULH = _EINSTRPAGEFAULT = 0b011 BLT = BU = XOR = DIV = DIVW = SH2ADD = MIN = XNOR = ZEXTH = 0b100 - BGE = HU = SR = CSRRWI = DIVU = DIVUW = BEXT = ORCB = REV8 = ROR = MINU = 0b101 + BGE = HU = SR = CSRRWI = DIVU = DIVUW = BEXT = ORCB = REV8 = ROR = MINU = CZEROEQZ = 0b101 BLTU = OR = CSRRSI = REM = REMW = SH3ADD = MAX = ORN = 0b110 - BGEU = AND = CSRRCI = REMU = REMUW = ANDN = MAXU = 0b111 + BGEU = AND = CSRRCI = REMU = REMUW = ANDN = MAXU = CZERONEZ = 0b111 class Funct7(IntEnum, shape=7): @@ -67,6 +67,7 @@ class Funct7(IntEnum, shape=7): BINV = REV8 = 0b0110100 BSET = ORCB = 0b0010100 MAX = MIN = CLMUL = 0b0000101 + CZERO = 0b0000111 ROL = ROR = SEXTB = SEXTH = CPOP = CLZ = CTZ = 0b0110000 ZEXTH = 0b0000100 SFENCEVMA = 0b0001001 diff --git a/coreblocks/arch/optypes.py b/coreblocks/arch/optypes.py index 4b7bb12aa..e4756359c 100644 --- a/coreblocks/arch/optypes.py +++ b/coreblocks/arch/optypes.py @@ -50,6 +50,7 @@ class OpType(IntEnum): CLMUL = auto() SRET = auto() SFENCEVMA = auto() + CZERO = auto() #: Internal Coreblocks OpType, specifing that instruction caused Exception before FU execution EXCEPTION = auto() @@ -154,6 +155,9 @@ def is_jalr(val: ValueLike) -> Value: OpType.SRET, OpType.SFENCEVMA, ], + Extension.ZICOND: [ + OpType.CZERO, + ], } diff --git a/coreblocks/frontend/decoder/instr_description.py b/coreblocks/frontend/decoder/instr_description.py index d5758c250..26f7e7b14 100644 --- a/coreblocks/frontend/decoder/instr_description.py +++ b/coreblocks/frontend/decoder/instr_description.py @@ -204,4 +204,8 @@ class Encoding: Opcode.SYSTEM, Funct3.PRIV, Funct7.SFENCEVMA, rd_zero=True, instr_type_override=InstrType.R ), # sfence.vma ], + OpType.CZERO: [ + Encoding(Opcode.OP, Funct3.CZEROEQZ, Funct7.CZERO), + Encoding(Opcode.OP, Funct3.CZERONEZ, Funct7.CZERO), + ], } diff --git a/coreblocks/func_blocks/fu/alu.py b/coreblocks/func_blocks/fu/alu.py index 1b359586f..61dc5964c 100644 --- a/coreblocks/func_blocks/fu/alu.py +++ b/coreblocks/func_blocks/fu/alu.py @@ -21,9 +21,10 @@ class AluFn(DecoderManager): - def __init__(self, zba_enable=False, zbb_enable=False) -> None: + def __init__(self, zba_enable=False, zbb_enable=False, zicond_enable=False) -> None: self.zba_enable = zba_enable self.zbb_enable = zbb_enable + self.zicond_enable = zicond_enable class Fn(IntFlag): ADD = auto() # Addition @@ -60,6 +61,10 @@ class Fn(IntFlag): ORCB = auto() # Bitwise or combine REV8 = auto() # Reverse byte ordering + # ZICOND extension + CZEROEQZ = auto() # Move zero if condition if equal to zero + CZERONEZ = auto() # Move zero if condition is nonzero + def get_instructions(self) -> Sequence[tuple]: return ( [ @@ -95,6 +100,11 @@ def get_instructions(self) -> Sequence[tuple]: (self.Fn.CPOP, OpType.UNARY_BIT_MANIPULATION_5, Funct3.CPOP), ] * self.zbb_enable + + [ + (self.Fn.CZEROEQZ, OpType.CZERO, Funct3.CZEROEQZ), + (self.Fn.CZERONEZ, OpType.CZERO, Funct3.CZERONEZ), + ] + * self.zicond_enable ) @@ -114,6 +124,7 @@ class Alu(Elaboratable): def __init__(self, gen_params: GenParams, alu_fn=AluFn()): self.zba_enable = alu_fn.zba_enable self.zbb_enable = alu_fn.zbb_enable + self.zicond_enable = alu_fn.zicond_enable self.gen_params = gen_params self.fn = alu_fn.get_function() @@ -206,6 +217,19 @@ def _or(s: Value) -> Value: for i in range(en): j = en - i - 1 m.d.comb += self.out[i * 8 : (i + 1) * 8].eq(self.in1[j * 8 : (j + 1) * 8]) + + if self.zicond_enable: + czero_cases = [ + (AluFn.Fn.CZERONEZ, lambda is_zero: self.in1 if is_zero else 0), + (AluFn.Fn.CZEROEQZ, lambda is_zero: 0 if is_zero else self.in1), + ] + for fn, output_fn in czero_cases: + with OneHotCase(fn): + with m.If(self.in2.any()): + m.d.comb += self.out.eq(output_fn(False)) + with m.Else(): + m.d.comb += self.out.eq(output_fn(True)) + return m @@ -254,10 +278,11 @@ def _(arg): class ALUComponent(FunctionalComponentParams): - def __init__(self, zba_enable=False, zbb_enable=False): + def __init__(self, zba_enable=False, zbb_enable=False, zicond_enable=False): self.zba_enable = zba_enable self.zbb_enable = zbb_enable - self.alu_fn = AluFn(zba_enable=zba_enable, zbb_enable=zbb_enable) + self.zicond_enable = zicond_enable + self.alu_fn = AluFn(zba_enable=zba_enable, zbb_enable=zbb_enable, zicond_enable=zicond_enable) def get_module(self, gen_params: GenParams) -> FuncUnit: return AluFuncUnit(gen_params, self.alu_fn) diff --git a/coreblocks/params/configurations.py b/coreblocks/params/configurations.py index d779f0388..c7727e335 100644 --- a/coreblocks/params/configurations.py +++ b/coreblocks/params/configurations.py @@ -180,7 +180,7 @@ def replace(self, **kwargs) -> Self: func_units_config=( RSBlockComponent( [ - ALUComponent(zba_enable=True, zbb_enable=True), + ALUComponent(zba_enable=True, zbb_enable=True, zicond_enable=True), ShiftUnitComponent(zbb_enable=True), ZbcComponent(), ZbsComponent(), diff --git a/test/frontend/test_instr_decoder.py b/test/frontend/test_instr_decoder.py index f7fc44c30..f7e82125c 100644 --- a/test/frontend/test_instr_decoder.py +++ b/test/frontend/test_instr_decoder.py @@ -170,11 +170,24 @@ def __init__( op=OpType.UNARY_BIT_MANIPULATION_1, ), ] + DECODER_TESTS_ZICOND = [ + # CZERO RS2 RS1 EQZ RD OP + # nez 0b0000111 00000 00000 111 00000 0110011 + # eqz 0b0000111 00000 00000 101 00000 0110011 + # CZERO.NEZ + InstrTest(0x0E007033, Opcode.OP, Funct3.CZERONEZ, Funct7.CZERO, rd=0, rs1=0, rs2=0, op=OpType.CZERO), + # CZERO.EQZ + InstrTest(0x0E005033, Opcode.OP, Funct3.CZEROEQZ, Funct7.CZERO, rd=0, rs1=0, rs2=0, op=OpType.CZERO), + ] def setup_method(self): self.gen_params = GenParams( test_core_config.replace( - _implied_extensions=Extension.G | Extension.XINTMACHINEMODE | Extension.XINTSUPERVISOR | Extension.ZBB + _implied_extensions=Extension.G + | Extension.XINTMACHINEMODE + | Extension.XINTSUPERVISOR + | Extension.ZBB + | Extension.ZICOND ) ) self.decoder = InstrDecoder(self.gen_params) @@ -263,6 +276,9 @@ def test_xintsupervisor(self): def test_zbb(self): self.do_test(self.DECODER_TESTS_ZBB) + def test_zicond(self): + self.do_test(self.DECODER_TESTS_ZICOND) + class TestDecoderEExtLegal(TestCaseWithSimulator): E_TEST = [ diff --git a/test/func_blocks/fu/test_alu.py b/test/func_blocks/fu/test_alu.py index 2b1233862..57ffb63bc 100644 --- a/test/func_blocks/fu/test_alu.py +++ b/test/func_blocks/fu/test_alu.py @@ -7,7 +7,7 @@ class TestAluUnit(FunctionalUnitTestCase[AluFn.Fn]): - func_unit = ALUComponent(zba_enable=True, zbb_enable=True) + func_unit = ALUComponent(zba_enable=True, zbb_enable=True, zicond_enable=True) zero_imm = False ops = { @@ -36,6 +36,8 @@ class TestAluUnit(FunctionalUnitTestCase[AluFn.Fn]): AluFn.Fn.CLZ: ExecFn(OpType.UNARY_BIT_MANIPULATION_3, Funct3.CLZ), AluFn.Fn.CTZ: ExecFn(OpType.UNARY_BIT_MANIPULATION_4, Funct3.CTZ), AluFn.Fn.CPOP: ExecFn(OpType.UNARY_BIT_MANIPULATION_5, Funct3.CPOP), + AluFn.Fn.CZERONEZ: ExecFn(OpType.CZERO, Funct3.CZERONEZ, Funct7.CZERO), + AluFn.Fn.CZEROEQZ: ExecFn(OpType.CZERO, Funct3.CZEROEQZ, Funct7.CZERO), } @staticmethod @@ -118,6 +120,16 @@ def compute_result(i1: int, i2: int, i_imm: int, pc: int, fn: AluFn.Fn, xlen: in while (i1 & 1) == 0: res += 1 i1 >>= 1 + case AluFn.Fn.CZEROEQZ: + if i2 == 0: + res = 0 + else: + res = i1 + case AluFn.Fn.CZERONEZ: + if i2 == 0: + res = i1 + else: + res = 0 return {"result": res & mask} diff --git a/test/params/test_configurations.py b/test/params/test_configurations.py index dcfac4eb4..a82cba1f8 100644 --- a/test/params/test_configurations.py +++ b/test/params/test_configurations.py @@ -24,9 +24,9 @@ class ISAStrTest: ), ISAStrTest( full_core_config, - "rv32imcbzicsr_zifencei_xintmachinemode", - "rv32imcbzicsr_zifencei_xintmachinemode", - "rv32imcbzicsr_zifencei_xintmachinemode", + "rv32imcbzicsr_zifencei_zicond_xintmachinemode", + "rv32imcbzicsr_zifencei_zicond_xintmachinemode", + "rv32imcbzicsr_zifencei_zicond_xintmachinemode", ), ISAStrTest(tiny_core_config, "rv32e", "rv32e", "rv32e"), ISAStrTest(test_core_config, "rv32", "rv32", "rv32i"),