Update dmode test to match spec.
authorTim Newsome <tim@sifive.com>
Thu, 29 Sep 2016 18:42:41 +0000 (11:42 -0700)
committerTim Newsome <tim@sifive.com>
Thu, 29 Sep 2016 18:42:41 +0000 (11:42 -0700)
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
debug/programs/trigger.S

index 4e8cb5bbbbae3b3196800a893a6bcb02070fd176..81aafa345a1e60c2d24163bb742de0e50ad48906 100755 (executable)
@@ -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.:
index ebfce1ca4ffdf94ba5135759f612bf13db6b4163..1efafc7d4da2360dbbdf6bdbf1479c148c33d548 100644 (file)
@@ -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