aboutsummaryrefslogtreecommitdiff
path: root/isa/rv64mi/pmpaddr.S
diff options
context:
space:
mode:
Diffstat (limited to 'isa/rv64mi/pmpaddr.S')
-rw-r--r--isa/rv64mi/pmpaddr.S154
1 files changed, 154 insertions, 0 deletions
diff --git a/isa/rv64mi/pmpaddr.S b/isa/rv64mi/pmpaddr.S
new file mode 100644
index 0000000..29413af
--- /dev/null
+++ b/isa/rv64mi/pmpaddr.S
@@ -0,0 +1,154 @@
+# See LICENSE for license details.
+
+#*****************************************************************************
+# pmpaddr.S
+#-----------------------------------------------------------------------------
+#
+# Test edge cases around the pmpaddr[G-1] bit which sometimes reads as zero
+# but is always writable and retains its state. Also test CSRC and CSRS
+# modifications to other bits result in a correct read-modify-write.
+#
+# This test auto-detects G but assumes PMP is available. It supports a
+# maximum G of XLEN-1. There's no minimum but if G is 0 then the G-1 bit
+# does not exist and this test trivially passes.
+
+#include "riscv_test.h"
+#include "test_macros.h"
+
+RVTEST_RV64M
+RVTEST_CODE_BEGIN
+
+ li TESTNUM, 1
+
+ # Software may determine the PMP granularity by writing zero to pmpcfg0,
+ # then writing all ones to pmpaddr0, then reading back pmpaddr0.
+ # If G is the index of the least-significant bit set, the PMP granularity
+ # is 2^(G+2) bytes.
+ csrw pmpcfg0, zero
+ li t0, -1
+ csrw pmpaddr0, t0
+ csrr t0, pmpaddr0
+
+ # Isolate the least significant bit.
+
+ neg t1, t0
+ and a7, t0, t1
+
+ # a7 now contains only the lowest 1 that was set in pmpaddr0.
+
+ # If a7 is 0 then G is >=XLEN which this test does not support.
+ beqz a7, fail
+ # Shift so the G-1 bit is set.
+ srl a7, a7, 1
+ # If no bits are set now then G is 0, which trivially passes.
+ beqz a7, pass
+
+#define PMPADDR_Gm1_MASK a7
+#define PMPCFG_A_MASK (0x3 << 3)
+ # Ok now we can begin the main test!
+
+# Set pmpaddr0[G-1] to `value` (1 or 0).
+.macro set_pmpaddr_bit value
+.if \value
+ csrs pmpaddr0, PMPADDR_Gm1_MASK
+.else
+ csrc pmpaddr0, PMPADDR_Gm1_MASK
+.endif
+.endm
+
+# Switch pmpcfg0 to OFF mode so pmpaddr0[G-1] reads as 0.
+.macro set_mode_off
+ csrc pmpcfg0, PMPCFG_A_MASK
+.endm
+
+# Switch pmpcfg0 to NAPOT mode so pmpaddr0[G-1] reads normally.
+.macro set_mode_napot
+ csrs pmpcfg0, PMPCFG_A_MASK
+.endm
+
+# Check that pmpaddr9[G] is set or unset depending on expected_value.
+.macro check_pmpaddr_bit expected_value
+ # Note when gas 2.43 is common we can use \+ instead of \@ which
+ # gives more sensible numbers. \@ still works but it gives 4, 6,
+ # 8, 10, 15... instead of 0, 1, 2, 3.
+ li TESTNUM, (2 + \@)
+ csrr t6, pmpaddr0
+ and t6, t6, PMPADDR_Gm1_MASK
+.if \expected_value
+ beqz t6, fail
+.else
+ bnez t6, fail
+.endif
+.endm
+
+.macro check_pmpaddr_bit_clear
+ csrr t6, pmpaddr0
+ and t6, t6, PMPADDR_Gm1_MASK
+ bnez t6, fail
+.endm
+
+ # Initialise pmpaddr and pmpcfg.
+
+ # M bit is writable in NAPOT mode.
+ set_mode_napot
+ # Clear it, it should read 0.
+ set_pmpaddr_bit 0
+ check_pmpaddr_bit 0
+ # Set it, it shouldn't read 0.
+ set_pmpaddr_bit 1
+ check_pmpaddr_bit 1
+ # M bit is writable but reads as 0 in OFF mode.
+ set_mode_off
+ # Should read as 0.
+ check_pmpaddr_bit 0
+ # Switch back to NAPOT. The 1 should be readable again.
+ set_mode_napot
+ check_pmpaddr_bit 1
+
+ # Test writing the bit while it is read-as-zero.
+ set_pmpaddr_bit 0
+ set_mode_off
+ set_pmpaddr_bit 1
+ set_mode_napot
+ check_pmpaddr_bit 1
+
+ # Test modifying a *different* bit while its underlying
+ # value is 1 but it reads as 0. Since csrs and csrc are
+ # read-modify-write they reads-as value will be written
+ # to the underlying value.
+ set_mode_off
+ # A csrs or csrc from the zero register does not have
+ # any side effects.
+ csrc pmpaddr0, zero
+ csrs pmpaddr0, zero
+ set_mode_napot
+ check_pmpaddr_bit 1
+
+ set_mode_off
+ # Set other bits. This should result in M being cleared
+ # since it currently reads as 0.
+ not t0, PMPADDR_Gm1_MASK
+ csrs pmpaddr0, t0
+ set_mode_napot
+ check_pmpaddr_bit 0
+
+ j pass
+
+ TEST_PASSFAIL
+
+ .align 2
+ .global mtvec_handler
+mtvec_handler:
+ # We aren't expecting any exceptions unless PMP is not supported
+ # in which case this test is also not supported. There's no
+ # way to probe for PMP support so we can't just pass in this case.
+ j fail
+
+RVTEST_CODE_END
+
+ .data
+RVTEST_DATA_BEGIN
+
+ TEST_DATA
+
+RVTEST_DATA_END