Skip to content

Commit

Permalink
Merge pull request #2348 from silabs-krdosvik/clic-minhv-test
Browse files Browse the repository at this point in the history
added mepc minhv misalignement test
  • Loading branch information
silabs-hfegran authored Jan 12, 2024
2 parents 0ce80b0 + 4a67254 commit f8c0fce
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,8 @@ Added assertion for formal coverage",Assertion Check,"ENV capability, not specif
[clic_assert].a_mret_mie_mpie"
CLIC 0.9-draft 4/11/2023,Return from handler,mret,"""If the hart is currently running at some privilege mode x, an MRET or SRET instruction that changes the privilege mode to a mode less privileged than x also sets xintthresh = 0.""","Use ""mret"" to enter U-mode.
Check that ""mintthresh"" is written to zero upon executing the mret.",Assertion Check,"ENV capability, not specific test",Assertion Coverage,A: uvmt_cv32e40s_tb.dut_wrap.cv32e40s_wrapper_i.core_i.clic_assert_i.gen_clic_assertions.a_mret_umode_clear_mintthresh
CLIC 0.9-draft 12/19/2023,Return from handler,mret minhv=1,"""If the xinhv bit is set, the hart resumes the trap handler memory access to retrieve the function pointer for vectoring with permissions corresponding to the previous privilege mode. The trap handler function address is obtained from the current privilege mode’s xepc with the low bits of the address cleared to force the access to be naturally aligned to an XLEN/8-byte table entry.""","Run mret when minhv is set. Check that the next instruction to be executed is the address pointed to by the mepc, and check that mepc gets naturally aligned to XLEN/8 byte.",Self Checking Test,Directed Self-Checking,Testcase,"DTC: clic :: mret_with_minhv
clic ::mret_with_minhv_and_unaligned_mepc"
CLIC 0.9-draft 4/11/2023,Return from debug mode,dret,"""Likewise, if the RISC-V debug specification is implemented and the hart is currently running at some privilege mode x, a DRET instruction that changes the privilege mode to a mode less privileged than x also sets xintthresh = 0.""","Use ""dret"" to enter U-mode.
Check that ""mintthresh"" is written to zero upon executing the dret.",Assertion Check,"ENV capability, not specific test",Assertion Coverage,Requirement removed
CLIC 8675ec,WFI,Wakeup conditions,"A pending-and-enabled interrupt i causes the hart to resume execution if interrupt i
Expand Down
11 changes: 11 additions & 0 deletions cv32e40s/docs/VerifPlans/Simulation/interrupts/CV32E40SX_CLIC.json
Original file line number Diff line number Diff line change
Expand Up @@ -791,6 +791,17 @@
"Coverage Method": "Assertion Coverage",
"Link to Coverage": "A: uvmt_cv32e40s_tb.dut_wrap.cv32e40s_wrapper_i.core_i.clic_assert_i.gen_clic_assertions.a_mret_umode_clear_mintthresh"
},
{
"Requirement Location": "CLIC 0.9-draft 12/19/2023",
"Feature": "Return from handler",
"Sub Feature": "mret minhv=1",
"Feature Description": "\"If the xinhv bit is set, the hart resumes the trap handler memory access to retrieve the function pointer for vectoring with permissions corresponding to the previous privilege mode. The trap handler function address is obtained from the current privilege mode\u2019s xepc with the low bits of the address cleared to force the access to be naturally aligned to an XLEN/8-byte table entry.\"",
"Verification Goal": "Run mret when minhv is set. Check that the next instruction to be executed is the address pointed to by the mepc, and check that mepc gets naturally aligned to XLEN/8 byte.",
"Pass/Fail Criteria": "Self Checking Test",
"Test Type": "Directed Self-Checking",
"Coverage Method": "Testcase",
"Link to Coverage": "DTC: clic :: mret_with_minhv\nclic ::mret_with_minhv_and_unaligned_mepc"
},
{
"Requirement Location": "CLIC 0.9-draft 4/11/2023",
"Feature": "Return from debug mode",
Expand Down
Binary file modified cv32e40s/docs/VerifPlans/Simulation/interrupts/CV32E40SX_CLIC.xlsx
Binary file not shown.
86 changes: 85 additions & 1 deletion cv32e40s/tests/programs/custom/clic/clic.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

// MUST be 31 or less (bit position-1 in result array determines test pass/fail
// status, thus we are limited to 31 tests with this construct.
#define NUM_TESTS 24
#define NUM_TESTS 25
// Set which test index to start testing at (for quickly running specific tests during development)
#define START_TEST_IDX 0
// Abort test at first self-check fail, useful for debugging.
Expand Down Expand Up @@ -220,6 +220,8 @@ volatile uint32_t * volatile g_asserted_irq_lvl;
volatile uint32_t * volatile g_irq_handler_reported_error;
volatile uint32_t * volatile g_mepc_triggered;
volatile uint32_t * volatile g_recovery_enable;
volatile uint32_t * volatile g_checker;

// ---------------------------------------------------------------
// Test prototypes - should match
// uint32_t <name>(uint32_t index, uint8_t report_name)
Expand Down Expand Up @@ -250,6 +252,7 @@ uint32_t mret_with_minhv(uint32_t index, uint8_t report_name);
uint32_t mintthresh_higher(uint32_t index, uint8_t report_name);
uint32_t mintthresh_lower(uint32_t index, uint8_t report_name);
uint32_t mintthresh_equal(uint32_t index, uint8_t report_name);
uint32_t mret_with_minhv_and_unaligned_mepc(uint32_t index, uint8_t report_name);

// ---------------------------------------------------------------
// Generic test template:
Expand Down Expand Up @@ -377,6 +380,7 @@ int main(int argc, char **argv){
g_irq_handler_reported_error = calloc(1, sizeof(uint32_t));
g_mepc_triggered = calloc(1, sizeof(uint32_t));
g_recovery_enable = calloc(1, sizeof(uint32_t));
g_checker = calloc(1, sizeof(uint32_t));

// Add function pointers to new tests here
tests[0] = mcause_mstatus_mirror_init;
Expand All @@ -403,6 +407,7 @@ int main(int argc, char **argv){
tests[21] = mintthresh_lower;
tests[22] = mintthresh_higher;
tests[23] = mintthresh_equal;
tests[24] = mret_with_minhv_and_unaligned_mepc;

// Run all tests in list above
cvprintf(V_LOW, "\nCLIC Test start\n\n");
Expand All @@ -420,6 +425,7 @@ int main(int argc, char **argv){
free((void *)g_irq_handler_reported_error);
free((void *)g_mepc_triggered );
free((void *)g_recovery_enable );
free((void *)g_checker );
return retval; // Nonzero for failing tests
}

Expand Down Expand Up @@ -3052,6 +3058,7 @@ uint32_t mret_with_minhv(uint32_t index, uint8_t report_name) {
mret
addi %[check_val], zero, 42
jal zero, 2f
.align 4
1: .word(2f)
.space 0x100, 0x0
2: addi %[result], %[check_val], 0
Expand Down Expand Up @@ -3326,6 +3333,73 @@ uint32_t mintthresh_equal(uint32_t index, uint8_t report_name) {
return 0;
}


uint32_t mret_with_minhv_and_unaligned_mepc(uint32_t index, uint8_t report_name) {
volatile uint8_t test_fail = 0;
volatile mcause_t mcause = { 0 };
volatile uint32_t result = 0;
volatile uint32_t all_set = 0xFFFFFFFF;

SET_FUNC_INFO
if (report_name) {
cvprintf(V_LOW, "\"%s\"", name);
return 0;
}

*g_special_handler_idx = 7;

__asm__ volatile ( R"(
csrrs %[rd1], mcause, zero
)":[rd1] "=r"(mcause.raw)
::);

mcause.clic.minhv = 1;
mcause.clic.mpp = 0x3;
mcause.clic.mpie = 0;

*g_checker = 0;

__asm__ volatile (R"(
csrrw zero, mcause, %[mcause]
la t0, 1f
lw t1, (t0)
csrrw zero, mepc, t0
# Store instruction mepc aims to execute in mscratch register.
csrrw zero, mscratch, t1
mret

# Write 0xFFFF_FFFF to where g_checker points.
lw t2, g_checker
sw %[all_set], 0(t2)

jal zero, 2f
.align 4
.byte(0xFF)
.byte(0xFF)
1: .word(2f)
.space 0x100, 0x0

2:
# Fetch the value g_checker points to.
lw t2, g_checker
lw t2, 0(t2)

addi %[result], t2, 0

)":[result] "=r"(result)
:[mcause] "r"(mcause.raw), [all_set] "r"(all_set)
:"t0", "t1", "t2");

test_fail += (result != 0);

if (test_fail) {
cvprintf(V_LOW, "\nTest: \"%s\" FAIL!\n", name);
return index + 1;
}
cvprintf(V_MEDIUM, "\nTest: \"%s\" OK!\n", name);
return 0;
}

// -----------------------------------------------------------------------------
// Note that the following interrupt/exception handler is not generic and specific
// to this test.
Expand Down Expand Up @@ -3408,6 +3482,16 @@ __attribute__((interrupt("machine"))) void u_sw_irq_handler(void) {
case 6:
*g_irq_handler_reported_error = 1;
vp_assert_irq(0, 0);
*g_special_handler_idx = 0;
return;
break;
case 7:
*g_special_handler_idx = 0;
//Write mscratch value to mepc
__asm__ volatile ( R"(
csrrw t0, mscratch, zero
csrrw zero, mepc, t0
)"::: "t0");
return;
break;
}
Expand Down

0 comments on commit f8c0fce

Please sign in to comment.