Add vtype CSR.
Change-Id: I4ebbadcf0b76d3477f22e682da1b844375fbd4ce
diff --git a/hdl/chisel/src/kelvin/rvv/RvvInterface.scala b/hdl/chisel/src/kelvin/rvv/RvvInterface.scala
index 0b12ae5..befb80f 100644
--- a/hdl/chisel/src/kelvin/rvv/RvvInterface.scala
+++ b/hdl/chisel/src/kelvin/rvv/RvvInterface.scala
@@ -26,6 +26,14 @@
val xrm = Output(UInt(2.W))
val sew = Output(UInt(3.W))
val lmul = Output(UInt(3.W))
+
+ /**
+ * 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)
+ }
}
class Lsu2Rvv(p: Parameters) extends Bundle {
diff --git a/hdl/chisel/src/kelvin/scalar/Csr.scala b/hdl/chisel/src/kelvin/scalar/Csr.scala
index f702a97..00b303a 100644
--- a/hdl/chisel/src/kelvin/scalar/Csr.scala
+++ b/hdl/chisel/src/kelvin/scalar/Csr.scala
@@ -22,6 +22,7 @@
// To Csr from RvvCore
val vstart = Input(UInt(log2Ceil(p.rvvVlen).W))
val vl = Input(UInt(log2Ceil(p.rvvVlen).W))
+ val vtype = Input(UInt(32.W))
val vxrm = Input(UInt(2.W))
val vxsat = Input(Bool())
// From Csr to RvvCore
@@ -74,6 +75,7 @@
val MCYCLEH = Value(0xB80.U(12.W))
val MINSTRETH = Value(0xB82.U(12.W))
val VL = Value(0xC20.U(12.W))
+ val VTYPE = Value(0xC21.U(12.W))
val VLENB = Value(0xC22.U(12.W))
val MVENDORID = Value(0xF11.U(12.W))
val MARCHID = Value(0xF12.U(12.W))
@@ -302,6 +304,7 @@
val fcsrEn = csr_address === CsrAddress.FCSR
val vstartEn = Option.when(p.enableRvv) { csr_address === CsrAddress.VSTART }
val vlEn = Option.when(p.enableRvv) { csr_address === CsrAddress.VL }
+ val vtypeEn = Option.when(p.enableRvv) { csr_address === CsrAddress.VTYPE }
val vxrmEn = Option.when(p.enableRvv) { csr_address === CsrAddress.VXRM }
val vxsatEn = Option.when(p.enableRvv) { csr_address === CsrAddress.VXSAT }
val mstatusEn = csr_address === CsrAddress.MSTATUS
@@ -413,6 +416,7 @@
Seq(
vstartEn.get -> io.rvv.get.vstart,
vlEn.get -> io.rvv.get.vl,
+ vtypeEn.get -> io.rvv.get.vtype,
vxrmEn.get -> io.rvv.get.vxrm,
vxsatEn.get -> io.rvv.get.vxsat,
vlenbEn.get -> 16.U(32.W), // Vector length in Bytes
diff --git a/hdl/chisel/src/kelvin/scalar/SCore.scala b/hdl/chisel/src/kelvin/scalar/SCore.scala
index 33bae21..999992a 100644
--- a/hdl/chisel/src/kelvin/scalar/SCore.scala
+++ b/hdl/chisel/src/kelvin/scalar/SCore.scala
@@ -449,6 +449,7 @@
io.rvvcore.get.csr.vxsat_write <> csr.io.rvv.get.vxsat_write
csr.io.rvv.get.vstart := io.rvvcore.get.csr.vstart
csr.io.rvv.get.vl := io.rvvcore.get.configState.bits.vl
+ csr.io.rvv.get.vtype := io.rvvcore.get.configState.bits.vtype
csr.io.rvv.get.vxrm := io.rvvcore.get.csr.vxrm
csr.io.rvv.get.vxsat := io.rvvcore.get.csr.vxsat
}
diff --git a/tests/cocotb/BUILD b/tests/cocotb/BUILD
index 6855246..f900f79 100644
--- a/tests/cocotb/BUILD
+++ b/tests/cocotb/BUILD
@@ -157,6 +157,7 @@
"core_mini_rvv_load",
"core_mini_rvv_add",
"core_mini_vstart_store",
+ "core_mini_vcsr_test",
]
# END_TESTCASES_FOR_rvv_assembly_cocotb_test
@@ -235,12 +236,6 @@
verilator_model = ":core_mini_debug_axi_model",
)
-RVV_TEST_BINARY_TARGETS = [
- "//tests/cocotb/rvv:rvv_load.elf",
- "//tests/cocotb/rvv:rvv_add.elf",
- "//tests/cocotb/rvv:vstart_store.elf",
-]
-
cocotb_test_suite(
name = "rvv_assembly_cocotb_test",
simulators = [
@@ -259,10 +254,10 @@
requirement("tqdm"),
"@bazel_tools//tools/python/runfiles",
],
- "data": RVV_TEST_BINARY_TARGETS,
+ "data": ["//tests/cocotb/rvv:rvv_assem_tests"],
"size": "large",
},
- vcs_data = RVV_TEST_BINARY_TARGETS + [":coverage_exclude.cfg"],
+ vcs_data = ["//tests/cocotb/rvv:rvv_assem_tests"] + [":coverage_exclude.cfg"],
vcs_build_args = VCS_BUILD_ARGS,
vcs_test_args = VCS_TEST_ARGS,
vcs_defines = VCS_DEFINES,
diff --git a/tests/cocotb/rvv/BUILD b/tests/cocotb/rvv/BUILD
index b53ebe7..09fee67 100644
--- a/tests/cocotb/rvv/BUILD
+++ b/tests/cocotb/rvv/BUILD
@@ -29,5 +29,18 @@
"vstart_store": {
"srcs": ["vstart_store.S"],
},
+ "vcsr_test": {
+ "srcs": ["vcsr_test.cc"],
+ },
},
)
+
+filegroup(
+ name = "rvv_assem_tests",
+ srcs = [
+ "rvv_add.elf",
+ "rvv_load.elf",
+ "vstart_store.elf",
+ "vcsr_test.elf",
+ ],
+)
\ No newline at end of file
diff --git a/tests/cocotb/rvv/vcsr_test.cc b/tests/cocotb/rvv/vcsr_test.cc
new file mode 100644
index 0000000..a2612c5
--- /dev/null
+++ b/tests/cocotb/rvv/vcsr_test.cc
@@ -0,0 +1,32 @@
+// Copyright 2025 Google LLC
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <riscv_vector.h>
+#include <stdint.h>
+
+uint32_t vma __attribute__((section(".data"))) = 0;
+uint32_t vta __attribute__((section(".data"))) = 0;
+uint32_t sew __attribute__((section(".data"))) = 0;
+uint32_t lmul __attribute__((section(".data"))) = 0;
+uint32_t vl __attribute__((section(".data"))) = 16;
+uint32_t vtype __attribute__((section(".data"))) = ~0;
+
+int main(int argc, char **argv) {
+ uint32_t vtype_to_write = (vma << 7) | (vta << 6) | (sew << 3) | lmul;
+ asm volatile("vsetvl x0, %0, %1": : "r"(vl), "r"(vtype_to_write));
+ uint32_t vtype_to_read;
+ asm volatile("csrr %0, vtype" : "=r"(vtype_to_read));
+ vtype = vtype_to_read;
+ return 0;
+}
diff --git a/tests/cocotb/rvv_assembly_cocotb_test.py b/tests/cocotb/rvv_assembly_cocotb_test.py
index e436fca..4e3d70c 100644
--- a/tests/cocotb/rvv_assembly_cocotb_test.py
+++ b/tests/cocotb/rvv_assembly_cocotb_test.py
@@ -1,6 +1,5 @@
import cocotb
import numpy as np
-import argparse
from kelvin_test_utils.core_mini_axi_interface import CoreMiniAxiInterface
from bazel_tools.tools.python.runfiles import runfiles
@@ -139,10 +138,74 @@
# vstart is 4, so first 4 elements are skipped.
# 12 elements are stored.
- print(f"input_data={input_data}", flush=True)
- print(f"output_data={output_data}", flush=True)
assert np.array_equal(output_data[0:4], np.zeros(4, dtype=np.uint8))
assert np.array_equal(output_data[4:], input_data[4:])
await core_mini_axi.raise_irq()
await core_mini_axi.wait_for_halted()
+
+
+@cocotb.test()
+async def core_mini_vcsr_test(dut):
+ """Testbench to test vstart store.
+ """
+ # Test bench setup
+ core_mini_axi = CoreMiniAxiInterface(dut)
+ await core_mini_axi.init()
+ await core_mini_axi.reset()
+ cocotb.start_soon(core_mini_axi.clock.start())
+ r = runfiles.Create()
+
+ elf_path = r.Rlocation("kelvin_hw/tests/cocotb/rvv/vcsr_test.elf")
+ if not elf_path:
+ raise ValueError("elf_path must consist a valid path")
+ with open(elf_path, "rb") as f:
+ entry_point = await core_mini_axi.load_elf(f)
+ vma_addr = core_mini_axi.lookup_symbol(f, "vma")
+ vta_addr = core_mini_axi.lookup_symbol(f, "vta")
+ sew_addr = core_mini_axi.lookup_symbol(f, "sew")
+ lmul_addr = core_mini_axi.lookup_symbol(f, "lmul")
+ vl_addr = core_mini_axi.lookup_symbol(f, "vl")
+ vtype_addr = core_mini_axi.lookup_symbol(f, "vtype")
+
+ SEWS = [
+ 0b000, # SEW8
+ 0b001, # SEW16
+ 0b010, # SEW32
+ ]
+
+ LMULS = [
+ 0b101, # LMUL1/8
+ 0b110, # LMUL1/4
+ 0b111, # LMUL1/2
+ 0b000, # LMUL1
+ 0b001, # LMUL2
+ 0b010, # LMUL4
+ 0b011, # LMUL8
+ ]
+
+ for ma in range(2):
+ for ta in range(2):
+ for sew in SEWS:
+ for lmul in LMULS:
+ 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)
+ await core_mini_axi.write_word(lmul_addr, lmul)
+ # TODO(derekjchow): Pick random VL
+ await core_mini_axi.write_word(vl_addr, 1)
+
+ await core_mini_axi.execute_from(entry_point)
+ await core_mini_axi.wait_for_halted()
+
+ 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)