From 3a5ca22f5cc6044ae6cdfb2874f62b3e6a9878ad Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 29 Sep 2016 11:42:41 -0700 Subject: [PATCH] Update dmode test to match spec. M-mode writes to triggers with dmode set are now ignored instead of raising an exception. Also added -f/--fail-fast option to gdbserver. --- debug/gdbserver.py | 61 ++++++++++++++++++++++------ debug/programs/trigger.S | 86 +++++++++++++++++++++++++--------------- 2 files changed, 101 insertions(+), 46 deletions(-) diff --git a/debug/gdbserver.py b/debug/gdbserver.py index 4e8cb5b..81aafa3 100755 --- a/debug/gdbserver.py +++ b/debug/gdbserver.py @@ -175,7 +175,9 @@ class TestFailed(Exception): Exception.__init__(self) self.message = message -def run_all_tests(target, tests): +def run_all_tests(target, tests, fail_fast): + good_results = set(('pass', 'not_applicable')) + results = {} module = sys.modules[__name__] for name in dir(module): @@ -185,11 +187,11 @@ def run_all_tests(target, tests): instance = definition(target) result = instance.run() results.setdefault(result, []).append(name) + if result not in good_results and fail_fast: + break print ":" * 40 - good_results = set(('pass', 'not_applicable')) - result = 0 for key, value in results.iteritems(): print "%d tests returned %s" % (len(value), key) @@ -592,17 +594,47 @@ class TriggerStoreAddressInstant(TriggerTest): assertEqual(self.gdb.p("$a0"), self.gdb.p("&data")) class TriggerDmode(TriggerTest): + def check_triggers(self, tdata1_lsbs, tdata2): + dmode = 1 << (self.target.xlen-5) + + triggers = [] + + if self.target.xlen == 32: + xlen_type = 'int' + elif self.target.xlen == 64: + xlen_type = 'long long' + else: + raise NotImplementedError + + dmode_count = 0 + i = 0 + for i in range(16): + tdata1 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i)) + if tdata1 == 0: + break + tdata2 = self.gdb.p("((%s *)&data)[%d]" % (xlen_type, 2*i+1)) + + if tdata1 & dmode: + dmode_count += 1 + else: + assertEqual(tdata1 & 0xffff, tdata1_lsbs) + assertEqual(tdata2, tdata2) + + assertGreater(i, 1) + assertEqual(dmode_count, 1) + + return triggers + def test(self): - return 'not_applicable' - # pylint: disable=unreachable - # Temporarily not applicable until spike is fixed to match the spec - # change. - self.gdb.command("hbreak handle_trap") - self.gdb.p("$pc=write_valid") + self.gdb.command("hbreak write_load_trigger") + self.gdb.b("clear_triggers") + self.gdb.p("$pc=write_store_trigger") output = self.gdb.c() - assertIn("handle_trap", output) - assertIn("mcause=2", output) - assertIn("mepc=%d" % self.gdb.p("&write_invalid_illegal"), output) + assertIn("write_load_trigger", output) + self.check_triggers((1<<6) | (1<<1), 0xdeadbee0) + output = self.gdb.c() + assertIn("clear_triggers", output) + self.check_triggers((1<<6) | (1<<0), 0xfeedac00) class RegsTest(GdbTest): compile_args = ("programs/regs.S", ) @@ -893,6 +925,9 @@ def main(): "the same time. This may make it harder to debug a failure if it " "does occur.") + parser.add_argument("--fail-fast", "-f", action="store_true", + help="Exit as soon as any test fails.") + parser.add_argument("test", nargs='*', help="Run only tests that are named here.") @@ -904,7 +939,7 @@ def main(): if parsed.xlen: target.xlen = parsed.xlen - return run_all_tests(target, parsed.test) + return run_all_tests(target, parsed.test, parsed.fail_fast) # TROUBLESHOOTING TIPS # If a particular test fails, run just that one test, eg.: diff --git a/debug/programs/trigger.S b/debug/programs/trigger.S index ebfce1c..1efafc7 100644 --- a/debug/programs/trigger.S +++ b/debug/programs/trigger.S @@ -1,5 +1,15 @@ #include "../../env/encoding.h" +#ifdef __riscv64 +# define LREG ld +# define SREG sd +# define REGBYTES 8 +#else +# define LREG lw +# define SREG sw +# define REGBYTES 4 +#endif + #undef MCONTROL_TYPE #undef MCONTROL_DMODE #ifdef __riscv64 @@ -36,49 +46,59 @@ write_loop: j main_exit -write_valid: +write_store_trigger: + li a0, (1<<6) | (1<<1) + li a1, 0xdeadbee0 + jal write_triggers + la a0, data + jal read_triggers + +write_load_trigger: + li a0, (1<<6) | (1<<0) + li a1, 0xfeedac00 + jal write_triggers + la a0, data + jal read_triggers + +// Clear triggers so the next test can use them. +clear_triggers: + li a0, 0 + jal write_triggers + +main_exit: + li a0, 0 + j _exit + +write_triggers: + // a0: value to write to each tdata1 + // a1: value to write to each tdata2 li t0, 0 - li t2, MCONTROL_DMODE - li t3, MCONTROL_TYPE -write_valid_loop: +2: csrw CSR_TSELECT, t0 csrr t1, CSR_TSELECT - bne t0, t1, main_exit + bne t0, t1, 1f addi t0, t0, 1 - csrr t1, CSR_TDATA1 - and t4, t1, t3 - beqz t4, main_error # type is 0 - and t1, t1, t2 - bnez t1, write_valid_loop - # Found an entry with dmode=0 - csrw CSR_TDATA1, zero # this should succeed + csrw CSR_TDATA2, a1 + csrw CSR_TDATA1, a0 + j 2b +1: ret -write_invalid: +read_triggers: + // a0: address where data should be written li t0, 0 - li t2, MCONTROL_DMODE - li t3, MCONTROL_TYPE -write_invalid_loop: +2: csrw CSR_TSELECT, t0 csrr t1, CSR_TSELECT - bne t0, t1, main_exit + bne t0, t1, 1f addi t0, t0, 1 csrr t1, CSR_TDATA1 - and t4, t1, t3 - beqz t4, main_error # type is 0 - and t1, t1, t2 - beqz t1, write_invalid_loop - # Found an entry with dmode=1 -write_invalid_illegal: - csrw CSR_TDATA1, zero # this should fail - - -main_exit: - li a0, 0 - j _exit - -main_error: - li a0, 1 - j _exit + SREG t1, 0(a0) + csrr t1, CSR_TDATA2 + SREG t1, REGBYTES(a0) + addi a0, a0, 2*REGBYTES + j 2b +1: SREG zero, 0(a0) + ret .data data: .word 0x40 -- 2.30.2