Set vill based on sew and lmul. Change-Id: I7a4bec14380c910ca147bc372f942648da9d47c9
diff --git a/hdl/chisel/src/kelvin/rvv/RvvCore.scala b/hdl/chisel/src/kelvin/rvv/RvvCore.scala index c80defe..cde9738 100644 --- a/hdl/chisel/src/kelvin/rvv/RvvCore.scala +++ b/hdl/chisel/src/kelvin/rvv/RvvCore.scala
@@ -113,6 +113,7 @@ | output [1:0] configXrm, | output [2:0] configSew, | output [2:0] configLmul, + | output configVill, | output logic rvv_idle, | output logic [3:0] queue_capacity, |""".stripMargin.replaceAll("VSTART_LEN", (log2Ceil(vlen) - 1).toString) @@ -133,6 +134,7 @@ | output rd_rob2rt_o_GENI_vector_csr_xrm, | output rd_rob2rt_o_GENI_vector_csr_sew, | output rd_rob2rt_o_GENI_vector_csr_lmul, + | output rd_rob2rt_o_GENI_vector_csr_vill, | output [15:0] rd_rob2rt_o_GENI_vxsaturate,""".stripMargin.replaceAll("GENI", i.toString) } @@ -308,6 +310,7 @@ | assign rd_rob2rt_o_GENI_vector_csr_xrm = rd_rob2rt_o[GENI].vector_csr.xrm; | assign rd_rob2rt_o_GENI_vector_csr_sew = rd_rob2rt_o[GENI].vector_csr.sew; | assign rd_rob2rt_o_GENI_vector_csr_lmul = rd_rob2rt_o[GENI].vector_csr.lmul; + | assign rd_rob2rt_o_GENI_vector_csr_vill = rd_rob2rt_o[GENI].vector_csr.vill; | assign rd_rob2rt_o_GENI_vxsaturate = rd_rob2rt_o[GENI].vxsaturate; |""".stripMargin.replaceAll("GENI", i.toString) } @@ -331,6 +334,7 @@ coreInstantiation += " assign configXrm = config_state.xrm;\n" coreInstantiation += " assign configSew = config_state.sew;\n" coreInstantiation += " assign configLmul = config_state.lmul;\n" + coreInstantiation += " assign configVill = config_state.vill;\n" moduleInterface + coreInstantiation + "endmodule\n" } @@ -378,6 +382,7 @@ val configXrm = Output(UInt(2.W)) val configSew = Output(UInt(3.W)) val configLmul = Output(UInt(3.W)) + val configVill = Output(Bool()) val rvv_idle = Output(Bool()) val queue_capacity = Output(UInt(4.W)) }) @@ -488,6 +493,7 @@ io.configState.bits.xrm := rvvCoreWrapper.io.configXrm io.configState.bits.sew := rvvCoreWrapper.io.configSew io.configState.bits.lmul := rvvCoreWrapper.io.configLmul + io.configState.bits.vill := rvvCoreWrapper.io.configVill io.rvv_idle := rvvCoreWrapper.io.rvv_idle io.queue_capacity := rvvCoreWrapper.io.queue_capacity
diff --git a/hdl/chisel/src/kelvin/rvv/RvvInterface.scala b/hdl/chisel/src/kelvin/rvv/RvvInterface.scala index 86ebc2c..d606cd6 100644 --- a/hdl/chisel/src/kelvin/rvv/RvvInterface.scala +++ b/hdl/chisel/src/kelvin/rvv/RvvInterface.scala
@@ -26,13 +26,14 @@ val xrm = Output(UInt(2.W)) val sew = Output(UInt(3.W)) val lmul = Output(UInt(3.W)) + val vill = Output(Bool()) /** * Construct the vtype CSR value. * See section 3.4 of the RISC-V Vector Specification v1.0. */ def vtype: UInt = { - Cat(0.U(24.W), ma, ta, sew, lmul) + Cat(vill, 0.U(23.W), ma, ta, sew, lmul) } }
diff --git a/hdl/verilog/rvv/design/RvvFrontEnd.sv b/hdl/verilog/rvv/design/RvvFrontEnd.sv index 3946b56..facb7d3 100644 --- a/hdl/verilog/rvv/design/RvvFrontEnd.sv +++ b/hdl/verilog/rvv/design/RvvFrontEnd.sv
@@ -139,7 +139,6 @@ (inst_q[i].opcode == RVV) && (inst_q[i].bits[7:5] == 3'b111)) begin if (inst_q[i].bits[24] == 0) begin // vsetvli - inst_config_state[i+1].vill = 0; inst_config_state[i+1].vl = reg_read_data_i[2*i]; inst_config_state[i+1].lmul = RVVLMUL'(inst_q[i].bits[15:13]); inst_config_state[i+1].sew = RVVSEW'(inst_q[i].bits[18:16]); @@ -147,7 +146,6 @@ inst_config_state[i+1].ma = inst_q[i].bits[20]; is_setvl[i] = 1; end else if (inst_q[i].bits[24:23] == 2'b11) begin // vsetivli - inst_config_state[i+1].vill = 0; inst_config_state[i+1].vl = {{(`VL_WIDTH - 5){1'b0}}, inst_q[i].bits[12:8]}; inst_config_state[i+1].lmul = RVVLMUL'(inst_q[i].bits[15:13]); @@ -156,7 +154,6 @@ inst_config_state[i+1].ma = inst_q[i].bits[20]; is_setvl[i] = 1; end else if (inst_q[i].bits[24:23] == 2'b10) begin // vsetvl - inst_config_state[i+1].vill = 0; inst_config_state[i+1].vl = reg_read_data_i[2*i]; inst_config_state[i+1].lmul = RVVLMUL'(reg_read_data_i[(2*i) + 1][2:0]); @@ -167,6 +164,35 @@ is_setvl[i] = 1; end end + + // Compute legality of vtype. + if (is_setvl[i]) begin + unique case (inst_config_state[i+1].sew) + SEW8: + unique case(inst_config_state[i+1].lmul) + LMULRESERVED: inst_config_state[i+1].vill = 1; + LMUL1_8: inst_config_state[i+1].vill = 1; + default: inst_config_state[i+1].vill = 0; + endcase + SEW16: + unique case(inst_config_state[i+1].lmul) + LMULRESERVED: inst_config_state[i+1].vill = 1; + LMUL1_8: inst_config_state[i+1].vill = 1; + LMUL1_4: inst_config_state[i+1].vill = 1; + default: inst_config_state[i+1].vill = 0; + endcase + SEW32: + unique case(inst_config_state[i+1].lmul) + LMULRESERVED: inst_config_state[i+1].vill = 1; + LMUL1_8: inst_config_state[i+1].vill = 1; + LMUL1_4: inst_config_state[i+1].vill = 1; + LMUL1_2: inst_config_state[i+1].vill = 1; + default: inst_config_state[i+1].vill = 0; + endcase + default: inst_config_state[i+1].vill = 1; + endcase + end + end end
diff --git a/tests/cocotb/rvv_assembly_cocotb_test.py b/tests/cocotb/rvv_assembly_cocotb_test.py index 8af90c7..c2e1aa8 100644 --- a/tests/cocotb/rvv_assembly_cocotb_test.py +++ b/tests/cocotb/rvv_assembly_cocotb_test.py
@@ -1,5 +1,7 @@ import cocotb +import itertools import numpy as np +import tqdm from kelvin_test_utils.core_mini_axi_interface import CoreMiniAxiInterface from kelvin_test_utils.sim_test_fixture import Fixture from bazel_tools.tools.python.runfiles import runfiles @@ -10,7 +12,9 @@ 0b010, # SEW32 ] +# See 3.4.2. Vector Register Grouping of RVV Spec LMULS = [ + 0b100, # Reserved 0b101, # LMUL1/8 0b110, # LMUL1/4 0b111, # LMUL1/2 @@ -20,6 +24,26 @@ 0b011, # LMUL8 ] +def _illegal_vtype(sew, lmul): + # SEW must be SEW8,16,32. Others are illegal + if not ((sew == 0b000) or (sew == 0b001) or (sew == 0b010)): + return True + + # Reserved or LMUL=1/8 always illegal + if (lmul == 0b100) or (lmul == 0b101): + return True + + # LMUL=1/4 is illegal for SEW16 and SEW32 + if (sew != 0b000) and (lmul == 0b110): + return True + + # LMUL=1/2 is illegal for SEW32 + if (sew == 0b010) and (lmul == 0b111): + return True + + return False + + @cocotb.test() async def core_mini_rvv_load(dut): """Testbench to test RVV load intrinsics. @@ -184,10 +208,12 @@ vl_addr = core_mini_axi.lookup_symbol(f, "vl") vtype_addr = core_mini_axi.lookup_symbol(f, "vtype") - for ma in range(2): - for ta in range(2): - for sew in SEWS: - for lmul in LMULS: + combined_loops = itertools.product(range(2), range(2), SEWS, LMULS) + total_loops = 2 * 2 * len(SEWS) * len(LMULS) + with tqdm.tqdm(combined_loops, total=total_loops) as t: + for ma, ta, sew, lmul in t: + t.set_postfix( + {'ma': ma, 'ta': ta, 'sew': bin(sew), 'lmul': bin(lmul) }) await core_mini_axi.write_word(vma_addr, ma) await core_mini_axi.write_word(vta_addr, ta) await core_mini_axi.write_word(sew_addr, sew) @@ -200,15 +226,24 @@ vtype_result = ( await core_mini_axi.read_word(vtype_addr)).view(np.uint32)[0] - ma_result = (vtype_result & (1 << 7)) >> 7 - ta_result = (vtype_result & (1 << 6)) >> 6 - sew_result = (vtype_result & (0b111 << 3)) >> 3 - lmul_result = (vtype_result & 0b111) - assert (ma == ma_result) - assert (ta == ta_result) - assert (sew == sew_result) - assert (lmul == lmul_result) + # Check if vtype is legal + expected_illegal = _illegal_vtype(sew, lmul) + result_illegal = (vtype_result & (1 << 31)) >> 31 + assert (expected_illegal == result_illegal) + + if expected_illegal: + ma_result = (vtype_result & (1 << 7)) >> 7 + ta_result = (vtype_result & (1 << 6)) >> 6 + sew_result = (vtype_result & (0b111 << 3)) >> 3 + lmul_result = (vtype_result & 0b111) + + assert (ma == ma_result) + assert (ta == ta_result) + assert (sew == sew_result) + assert (lmul == lmul_result) + + async def test_vstart_not_zero_failure(dut, binary):