Add vstart check for additional instructions
These follow the reduction instructions. Related functions are renamed
to reflect the change.
Change-Id: Ibed09dd9cb1cbc09f33003e5f923fc5a98f0bbef
diff --git a/hdl/chisel/src/kelvin/rvv/RvvDecode.scala b/hdl/chisel/src/kelvin/rvv/RvvDecode.scala
index 1a85a16..7967a5e 100644
--- a/hdl/chisel/src/kelvin/rvv/RvvDecode.scala
+++ b/hdl/chisel/src/kelvin/rvv/RvvDecode.scala
@@ -41,13 +41,19 @@
bits(24, 19)
}
+ def vs1(): UInt = {
+ bits(12, 8)
+ }
+
def funct3(): UInt = {
bits(7, 5)
}
- // If this instruction is a "reduction" instruction, that requires vstart=0
- def isReduction(): Bool = {
+ // These instructions need to trap when vstart is not zero. This includes
+ // all reduction instructions.
+ def requireZeroVstart(): Bool = {
(opcode === RvvCompressedOpcode.RVVALU) && (funct3() === "b010".U) &&
+ // OPMVV
MuxLookup(funct6(), false.B)(Seq(
"b000000".U -> true.B, // vredsum
"b000001".U -> true.B, // vredand
@@ -57,6 +63,17 @@
"b000101".U -> true.B, // vredmin
"b000110".U -> true.B, // vredmaxu
"b000111".U -> true.B, // vredmax
+ "b010000".U -> MuxLookup(vs1(), false.B)(Seq( // VWXUNARY0
+ "b10000".U -> true.B, // vcpop
+ "b10001".U -> true.B, // vfirst
+ )),
+ "b010100".U -> MuxLookup(vs1(), false.B)(Seq( // VMUNARY0
+ "b00001".U -> true.B, // vmsbf
+ "b00010".U -> true.B, // vmsof
+ "b00011".U -> true.B, // vmsif
+ "b10000".U -> true.B, // viota
+ )),
+ "b010111".U -> true.B, // vcompress
"b110000".U -> true.B, // vwredsumu
"b110001".U -> true.B, // vwredsum
))
diff --git a/hdl/chisel/src/kelvin/scalar/Decode.scala b/hdl/chisel/src/kelvin/scalar/Decode.scala
index 5553453..02402c8 100644
--- a/hdl/chisel/src/kelvin/scalar/Decode.scala
+++ b/hdl/chisel/src/kelvin/scalar/Decode.scala
@@ -460,15 +460,16 @@
}
// ---------------------------------------------------------------------------
- // Rvv reduction
- // Don't allow reduction instructions to execute if vstart != 0
- val rvvReductionInterlock = if (p.enableRvv) {
+ // Rvv Vstart
+ // If an instruction requires vstart == 0, don't allow that instruction to
+ // execute when vstart != 0
+ val rvvVstartInterlock = if (p.enableRvv) {
(0 until p.instructionLanes).map(i => {
- val invalidReduction =
+ val invalidVstart =
decodedInsts(i).rvv.get.valid &&
- decodedInsts(i).rvv.get.bits.isReduction() &&
+ decodedInsts(i).rvv.get.bits.requireZeroVstart() &&
(configInvalid(i) || (io.rvvState.get.bits.vstart =/= 0.U))
- !invalidReduction
+ !invalidVstart
})
} else {
Seq.fill(p.instructionLanes)(true.B)
@@ -543,7 +544,7 @@
!fence(i) && // Don't dispatch if fence interlocked
slot0Interlock(i) && // Special instructions execute out of slot 0 only
rvvConfigInterlock(i) && // Rvv interlock rules
- rvvReductionInterlock(i) && // Don't dispatch reduction if vstart != 0
+ rvvVstartInterlock(i) && // Don't dispatch illegal vstart != 0
// rvvLsuInterlock(i) && // Dispatch only one Rvv LsuOp
lsuInterlock(i) && // Ensure lsu instructions can be dispatched into queue
rvvInterlock(i) && // Ensure rvv instructions can be dispatched into queue
@@ -771,11 +772,11 @@
for (i <- 0 until p.instructionLanes) {
io.rvvFault.get(i) := (if (i == 0) {
// Return fault if vstart != 0
- val isReduction = decodedInsts(i).rvv.get.valid &&
- decodedInsts(0).rvv.get.bits.isReduction()
+ val requireZeroVstart = decodedInsts(i).rvv.get.valid &&
+ decodedInsts(0).rvv.get.bits.requireZeroVstart()
val vStartNotZero = io.rvvState.get.valid &&
(io.rvvState.get.bits.vstart =/= 0.U)
- io.inst(0).valid && isReduction && vStartNotZero
+ io.inst(0).valid && requireZeroVstart && vStartNotZero
} else {
false.B
})
diff --git a/tests/cocotb/BUILD b/tests/cocotb/BUILD
index f900f79..464c935 100644
--- a/tests/cocotb/BUILD
+++ b/tests/cocotb/BUILD
@@ -158,6 +158,13 @@
"core_mini_rvv_add",
"core_mini_vstart_store",
"core_mini_vcsr_test",
+ "core_mini_viota_test",
+ "core_mini_vfirst_test",
+ "core_mini_vcpop_test",
+ "core_mini_vcompress_test",
+ "core_mini_vmsbf_test",
+ "core_mini_vmsof_test",
+ "core_mini_vmsif_test",
]
# END_TESTCASES_FOR_rvv_assembly_cocotb_test
diff --git a/tests/cocotb/rvv/BUILD b/tests/cocotb/rvv/BUILD
index 09fee67..9320989 100644
--- a/tests/cocotb/rvv/BUILD
+++ b/tests/cocotb/rvv/BUILD
@@ -32,6 +32,27 @@
"vcsr_test": {
"srcs": ["vcsr_test.cc"],
},
+ "viota_test": {
+ "srcs": ["viota_test.cc"],
+ },
+ "vfirst_test": {
+ "srcs": ["vfirst_test.cc"],
+ },
+ "vcpop_test": {
+ "srcs": ["vcpop_test.cc"],
+ },
+ "vcompress_test": {
+ "srcs": ["vcompress_test.cc"],
+ },
+ "vmsbf_test": {
+ "srcs": ["vmsbf_test.cc"],
+ },
+ "vmsof_test": {
+ "srcs": ["vmsof_test.cc"],
+ },
+ "vmsif_test": {
+ "srcs": ["vmsif_test.cc"],
+ },
},
)
@@ -42,5 +63,12 @@
"rvv_load.elf",
"vstart_store.elf",
"vcsr_test.elf",
+ "viota_test.elf",
+ "vfirst_test.elf",
+ "vcpop_test.elf",
+ "vcompress_test.elf",
+ "vmsbf_test.elf",
+ "vmsof_test.elf",
+ "vmsif_test.elf",
],
)
\ No newline at end of file
diff --git a/tests/cocotb/rvv/vcompress_test.cc b/tests/cocotb/rvv/vcompress_test.cc
new file mode 100644
index 0000000..be376d9
--- /dev/null
+++ b/tests/cocotb/rvv/vcompress_test.cc
@@ -0,0 +1,68 @@
+// 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 vstart __attribute__((section(".data"))) = 0;
+
+uint8_t mask_data[16] __attribute__((section(".data")));
+uint8_t input_data[8*16] __attribute__((section(".data")));
+uint8_t result[8*16] __attribute__((section(".data")));
+
+uint32_t faulted __attribute__((section(".data"))) = 0;
+uint32_t mcause __attribute__((section(".data"))) = 0;
+
+// Fault handler to log fault
+extern "C" {
+void kelvin_exception_handler() {
+ faulted = 1;
+ uint32_t local_mcause;
+ asm volatile("csrr %0, mcause" : "=r"(local_mcause));
+ mcause = local_mcause;
+
+ asm volatile("ebreak");
+ while (1) {}
+}
+}
+
+int main(int argc, char **argv) {
+ // Load mask data
+ asm volatile("vsetivli x0, 16, e8, m1, ta, ma");
+ asm volatile("vle8.v v0, (%0)" : : "r"(mask_data));
+
+ // Load input (just load entire array)
+ asm volatile("vsetivli x0, 16, e8, m8, ta, ma");
+ asm volatile("vle8.v v8, (%0)" : : "r"(input_data));
+
+ // Set configuration state
+ 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 local_vstart = vstart;
+ asm volatile("csrw vstart, %0" : : "r"(local_vstart));
+
+ // Run vcompress
+ asm volatile("vcompress.vm v16, v8, v0");
+
+ // Store result (entire array)
+ asm volatile("vsetivli x0, 16, e8, m8, ta, ma");
+ asm volatile("vse8.v v16, (%0)" : : "r"(result));
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tests/cocotb/rvv/vcpop_test.cc b/tests/cocotb/rvv/vcpop_test.cc
new file mode 100644
index 0000000..8cded24
--- /dev/null
+++ b/tests/cocotb/rvv/vcpop_test.cc
@@ -0,0 +1,61 @@
+// 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 vstart __attribute__((section(".data"))) = 0;
+
+uint8_t mask_data[16] __attribute__((section(".data")));
+uint32_t result __attribute__((section(".data")));
+
+uint32_t faulted __attribute__((section(".data"))) = 0;
+uint32_t mcause __attribute__((section(".data"))) = 0;
+
+// Fault handler to log fault
+extern "C" {
+void kelvin_exception_handler() {
+ faulted = 1;
+ uint32_t local_mcause;
+ asm volatile("csrr %0, mcause" : "=r"(local_mcause));
+ mcause = local_mcause;
+
+ asm volatile("ebreak");
+ while (1) {}
+}
+}
+
+int main(int argc, char **argv) {
+ // Load mask data
+ asm volatile("vsetivli x0, 16, e8, m1, ta, ma");
+ asm volatile("vle8.v v0, (%0)" : : "r"(mask_data));
+
+ // Set configuration state
+ 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 local_vstart = vstart;
+ asm volatile("csrw vstart, %0" : : "r"(local_vstart));
+
+ // Run vcpop
+ uint32_t local_result;
+ asm volatile("vcpop.m %0, v0" : "=r"(local_result));
+ result = local_result;
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tests/cocotb/rvv/vfirst_test.cc b/tests/cocotb/rvv/vfirst_test.cc
new file mode 100644
index 0000000..6ca8081
--- /dev/null
+++ b/tests/cocotb/rvv/vfirst_test.cc
@@ -0,0 +1,61 @@
+// 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 vstart __attribute__((section(".data"))) = 0;
+
+uint8_t mask_data[16] __attribute__((section(".data")));
+uint32_t result __attribute__((section(".data")));
+
+uint32_t faulted __attribute__((section(".data"))) = 0;
+uint32_t mcause __attribute__((section(".data"))) = 0;
+
+// Fault handler to log fault
+extern "C" {
+void kelvin_exception_handler() {
+ faulted = 1;
+ uint32_t local_mcause;
+ asm volatile("csrr %0, mcause" : "=r"(local_mcause));
+ mcause = local_mcause;
+
+ asm volatile("ebreak");
+ while (1) {}
+}
+}
+
+int main(int argc, char **argv) {
+ // Load mask data
+ asm volatile("vsetivli x0, 16, e8, m1, ta, ma");
+ asm volatile("vle8.v v0, (%0)" : : "r"(mask_data));
+
+ // Set configuration state
+ 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 local_vstart = vstart;
+ asm volatile("csrw vstart, %0" : : "r"(local_vstart));
+
+ // Run vfirst
+ uint32_t local_result;
+ asm volatile("vfirst.m %0, v0" : "=r"(local_result));
+ result = local_result;
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tests/cocotb/rvv/viota_test.cc b/tests/cocotb/rvv/viota_test.cc
new file mode 100644
index 0000000..c9a3639
--- /dev/null
+++ b/tests/cocotb/rvv/viota_test.cc
@@ -0,0 +1,62 @@
+// 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 vstart __attribute__((section(".data"))) = 0;
+
+uint8_t mask_data[16] __attribute__((section(".data")));
+uint8_t result[16*8] __attribute__((section(".data")));
+
+uint32_t faulted __attribute__((section(".data"))) = 0;
+uint32_t mcause __attribute__((section(".data"))) = 0;
+
+// Fault handler to log fault
+extern "C" {
+void kelvin_exception_handler() {
+ faulted = 1;
+ uint32_t local_mcause;
+ asm volatile("csrr %0, mcause" : "=r"(local_mcause));
+ mcause = local_mcause;
+
+ asm volatile("ebreak");
+ while (1) {}
+}
+}
+
+int main(int argc, char **argv) {
+ // Load mask data
+ asm volatile("vsetivli x0, 16, e8, m1, ta, ma");
+ asm volatile("vle8.v v0, (%0)" : : "r"(mask_data));
+
+ // Set configuration state
+ 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 local_vstart = vstart;
+ asm volatile("csrw vstart, %0" : : "r"(local_vstart));
+
+ // Run viota
+ asm volatile("viota.m v8, v0");
+
+ // Store result
+ asm volatile("vse8.v v8, (%0)" : : "r"(result));
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tests/cocotb/rvv/vmsbf_test.cc b/tests/cocotb/rvv/vmsbf_test.cc
new file mode 100644
index 0000000..e0f1e25
--- /dev/null
+++ b/tests/cocotb/rvv/vmsbf_test.cc
@@ -0,0 +1,63 @@
+// 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 vstart __attribute__((section(".data"))) = 0;
+
+uint8_t input_data[16] __attribute__((section(".data")));
+uint8_t result[16] __attribute__((section(".data")));
+
+uint32_t faulted __attribute__((section(".data"))) = 0;
+uint32_t mcause __attribute__((section(".data"))) = 0;
+
+// Fault handler to log fault
+extern "C" {
+void kelvin_exception_handler() {
+ faulted = 1;
+ uint32_t local_mcause;
+ asm volatile("csrr %0, mcause" : "=r"(local_mcause));
+ mcause = local_mcause;
+
+ asm volatile("ebreak");
+ while (1) {}
+}
+}
+
+int main(int argc, char **argv) {
+ // Load input data
+ asm volatile("vsetivli x0, 16, e8, m1, ta, ma");
+ asm volatile("vle8.v v0, (%0)" : : "r"(input_data));
+
+ // Set configuration state
+ 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 local_vstart = vstart;
+ asm volatile("csrw vstart, %0" : : "r"(local_vstart));
+
+ // Run vmsbf
+ asm volatile("vmsbf.m v8, v0");
+
+ // Store result (entire array)
+ asm volatile("vsetivli x0, 16, e8, m8, ta, ma");
+ asm volatile("vse8.v v8, (%0)" : : "r"(result));
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tests/cocotb/rvv/vmsif_test.cc b/tests/cocotb/rvv/vmsif_test.cc
new file mode 100644
index 0000000..36f014f
--- /dev/null
+++ b/tests/cocotb/rvv/vmsif_test.cc
@@ -0,0 +1,63 @@
+// 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 vstart __attribute__((section(".data"))) = 0;
+
+uint8_t input_data[16] __attribute__((section(".data")));
+uint8_t result[16] __attribute__((section(".data")));
+
+uint32_t faulted __attribute__((section(".data"))) = 0;
+uint32_t mcause __attribute__((section(".data"))) = 0;
+
+// Fault handler to log fault
+extern "C" {
+void kelvin_exception_handler() {
+ faulted = 1;
+ uint32_t local_mcause;
+ asm volatile("csrr %0, mcause" : "=r"(local_mcause));
+ mcause = local_mcause;
+
+ asm volatile("ebreak");
+ while (1) {}
+}
+}
+
+int main(int argc, char **argv) {
+ // Load input data
+ asm volatile("vsetivli x0, 16, e8, m1, ta, ma");
+ asm volatile("vle8.v v0, (%0)" : : "r"(input_data));
+
+ // Set configuration state
+ 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 local_vstart = vstart;
+ asm volatile("csrw vstart, %0" : : "r"(local_vstart));
+
+ // Run vmsif
+ asm volatile("vmsif.m v8, v0");
+
+ // Store result (entire array)
+ asm volatile("vsetivli x0, 16, e8, m8, ta, ma");
+ asm volatile("vse8.v v8, (%0)" : : "r"(result));
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tests/cocotb/rvv/vmsof_test.cc b/tests/cocotb/rvv/vmsof_test.cc
new file mode 100644
index 0000000..40bf342
--- /dev/null
+++ b/tests/cocotb/rvv/vmsof_test.cc
@@ -0,0 +1,63 @@
+// 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 vstart __attribute__((section(".data"))) = 0;
+
+uint8_t input_data[16] __attribute__((section(".data")));
+uint8_t result[16] __attribute__((section(".data")));
+
+uint32_t faulted __attribute__((section(".data"))) = 0;
+uint32_t mcause __attribute__((section(".data"))) = 0;
+
+// Fault handler to log fault
+extern "C" {
+void kelvin_exception_handler() {
+ faulted = 1;
+ uint32_t local_mcause;
+ asm volatile("csrr %0, mcause" : "=r"(local_mcause));
+ mcause = local_mcause;
+
+ asm volatile("ebreak");
+ while (1) {}
+}
+}
+
+int main(int argc, char **argv) {
+ // Load input data
+ asm volatile("vsetivli x0, 16, e8, m1, ta, ma");
+ asm volatile("vle8.v v0, (%0)" : : "r"(input_data));
+
+ // Set configuration state
+ 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 local_vstart = vstart;
+ asm volatile("csrw vstart, %0" : : "r"(local_vstart));
+
+ // Run vmsof
+ asm volatile("vmsof.m v8, v0");
+
+ // Store result (entire array)
+ asm volatile("vsetivli x0, 16, e8, m8, ta, ma");
+ asm volatile("vse8.v v8, (%0)" : : "r"(result));
+
+ return 0;
+}
\ No newline at end of file
diff --git a/tests/cocotb/rvv_assembly_cocotb_test.py b/tests/cocotb/rvv_assembly_cocotb_test.py
index 4e3d70c..0c366a0 100644
--- a/tests/cocotb/rvv_assembly_cocotb_test.py
+++ b/tests/cocotb/rvv_assembly_cocotb_test.py
@@ -3,6 +3,22 @@
from kelvin_test_utils.core_mini_axi_interface import CoreMiniAxiInterface
from bazel_tools.tools.python.runfiles import runfiles
+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
+]
+
@cocotb.test()
async def core_mini_rvv_load(dut):
"""Testbench to test RVV load intrinsics.
@@ -147,8 +163,7 @@
@cocotb.test()
async def core_mini_vcsr_test(dut):
- """Testbench to test vstart store.
- """
+ """Testbench to test vcsr is set correctly."""
# Test bench setup
core_mini_axi = CoreMiniAxiInterface(dut)
await core_mini_axi.init()
@@ -168,22 +183,6 @@
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:
@@ -209,3 +208,98 @@
assert (ta == ta_result)
assert (sew == sew_result)
assert (lmul == lmul_result)
+
+
+async def test_vstart_not_zero_failure(dut, binary):
+ 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(binary)
+ 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")
+ vstart_addr = core_mini_axi.lookup_symbol(f, "vstart")
+ faulted_addr = core_mini_axi.lookup_symbol(f, "faulted")
+ mcause_addr = core_mini_axi.lookup_symbol(f, "mcause")
+
+ for ma in range(2):
+ for ta in range(2):
+ for sew in SEWS:
+ for lmul in LMULS:
+ vl = 4 # TODO(derekjchow): Pick random VL
+ vstart = 1 # Non-zero to trigger failure
+
+ 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)
+ await core_mini_axi.write_word(vl_addr, vl)
+ await core_mini_axi.write_word(vstart_addr, vstart)
+
+ await core_mini_axi.execute_from(entry_point)
+ await core_mini_axi.wait_for_halted()
+
+ faulted_result = (
+ await core_mini_axi.read_word(faulted_addr)).view(np.uint32)[0]
+ assert (faulted_result == 1)
+ mcause_result = (
+ await core_mini_axi.read_word(mcause_addr)).view(np.uint32)[0]
+ assert (mcause_result == 0x2)
+
+
+@cocotb.test()
+async def core_mini_viota_test(dut):
+ """Testbench to test vstart!=0 viota."""
+ await test_vstart_not_zero_failure(
+ dut, "kelvin_hw/tests/cocotb/rvv/viota_test.elf")
+
+
+@cocotb.test()
+async def core_mini_vfirst_test(dut):
+ """Testbench to test vstart!=0 vfirst."""
+ await test_vstart_not_zero_failure(
+ dut, "kelvin_hw/tests/cocotb/rvv/vfirst_test.elf")
+
+
+@cocotb.test()
+async def core_mini_vcpop_test(dut):
+ """Testbench to test vstart!=0 vcpop."""
+ await test_vstart_not_zero_failure(
+ dut, "kelvin_hw/tests/cocotb/rvv/vcpop_test.elf")
+
+
+@cocotb.test()
+async def core_mini_vcompress_test(dut):
+ """Testbench to test vstart!=0 vcompress."""
+ await test_vstart_not_zero_failure(
+ dut, "kelvin_hw/tests/cocotb/rvv/vcompress_test.elf")
+
+
+@cocotb.test()
+async def core_mini_vmsbf_test(dut):
+ """Testbench to test vstart!=0 vmsbf."""
+ await test_vstart_not_zero_failure(
+ dut, "kelvin_hw/tests/cocotb/rvv/vmsbf_test.elf")
+
+
+@cocotb.test()
+async def core_mini_vmsof_test(dut):
+ """Testbench to test vstart!=0 vmsof."""
+ await test_vstart_not_zero_failure(
+ dut, "kelvin_hw/tests/cocotb/rvv/vmsof_test.elf")
+
+
+@cocotb.test()
+async def core_mini_vmsif_test(dut):
+ """Testbench to test vstart!=0 vmsbf."""
+ await test_vstart_not_zero_failure(
+ dut, "kelvin_hw/tests/cocotb/rvv/vmsif_test.elf")
\ No newline at end of file