Test debugging code with interrupts.
authorTim Newsome <tim@sifive.com>
Wed, 13 Sep 2017 01:48:44 +0000 (18:48 -0700)
committerTim Newsome <tim@sifive.com>
Thu, 14 Sep 2017 19:32:59 +0000 (12:32 -0700)
debug/gdbserver.py
debug/programs/entry.S
debug/programs/init.c
debug/programs/interrupt.c [new file with mode: 0644]
debug/targets.py

index 21eea4ed521b2da90c18e301b06838784eb4c20d..9fedbcab96cf9e6dc6172d00ff1ffa79d968f480 100755 (executable)
@@ -419,6 +419,49 @@ class UserInterrupt(DebugTest):
         self.gdb.p("i=0")
         self.exit()
 
+class InterruptTest(GdbSingleHartTest):
+    compile_args = ("programs/interrupt.c",)
+
+    def early_applicable(self):
+        return self.target.supports_clint_mtime
+
+    def setup(self):
+        self.gdb.load()
+
+    def test(self):
+        self.gdb.b("main")
+        output = self.gdb.c()
+        assertIn(" main ", output)
+        self.gdb.b("trap_entry")
+        output = self.gdb.c()
+        assertIn(" trap_entry ", output)
+        assertEqual(self.gdb.p("$mip") & 0x80, 0x80)
+        assertEqual(self.gdb.p("interrupt_count"), 0)
+        # You'd expect local to still be 0, but it looks like spike doesn't
+        # jump to the interrupt handler immediately after the write to
+        # mtimecmp.
+        assertLess(self.gdb.p("local"), 1000)
+        self.gdb.command("delete breakpoints")
+        for _ in range(10):
+            self.gdb.c(wait=False)
+            time.sleep(2)
+            self.gdb.interrupt()
+            interrupt_count = self.gdb.p("interrupt_count")
+            local = self.gdb.p("local")
+            if interrupt_count > 1000 and \
+                    local > 1000:
+                return
+
+        assertGreater(interrupt_count, 1000)
+        assertGreater(local, 1000)
+
+    def postMortem(self):
+        GdbSingleHartTest.postMortem(self)
+        self.gdb.p("*((long long*) 0x200bff8)")
+        self.gdb.p("*((long long*) 0x2004000)")
+        self.gdb.p("interrupt_count")
+        self.gdb.p("local")
+
 class MulticoreRegTest(GdbTest):
     compile_args = ("programs/infinite_loop.S", "-DMULTICORE")
 
index a2ea955a2707ed93d1283b066d801fc46ac2d398..97b62a33f2070f4ecefa5657944a14f769264ea0 100755 (executable)
@@ -1,8 +1,6 @@
 #include "encoding.h"
 
-// Enough stack to store every register in case a trap handler is executed,
-// plus 33 more values.
-#define STACK_SIZE (64 * XLEN / 8)
+#define STACK_SIZE (74 * XLEN / 8)
 
 #if XLEN == 64
 # define LREG ld
index 9933c23a72705be76deef9a670ff053b853384a8..8b047de591405c7a4ce180bbcc358012d5948545 100644 (file)
@@ -17,7 +17,7 @@ void enable_timer_interrupts()
     set_csr(mstatus, MSTATUS_MIE);
 }
 
-void handle_trap(unsigned int mcause, unsigned int mepc, unsigned int sp)
+void handle_trap(unsigned int mcause, void *mepc, void *sp)
 {
     unsigned hartid = csr_read(mhartid);
     if (trap_handler[hartid]) {
diff --git a/debug/programs/interrupt.c b/debug/programs/interrupt.c
new file mode 100644 (file)
index 0000000..c2dd5ec
--- /dev/null
@@ -0,0 +1,32 @@
+#include "init.h"
+#include "encoding.h"
+
+static volatile unsigned interrupt_count;
+static volatile unsigned local;
+
+static unsigned delta = 0x100;
+void *increment_count(unsigned hartid, unsigned mcause, void *mepc, void *sp)
+{
+    interrupt_count++;
+    // There is no guarantee that the interrupt is cleared immediately when
+    // MTIMECMP is written, so stick around here until that happens.
+    while (csr_read(mip) & MIP_MTIP) {
+        MTIMECMP[hartid] = MTIME + delta;
+    }
+    return mepc;
+}
+
+int main()
+{
+    interrupt_count = 0;
+    local = 0;
+    unsigned hartid = csr_read(mhartid);
+
+    set_trap_handler(increment_count);
+    MTIMECMP[hartid] = MTIME - 1;
+    enable_timer_interrupts();
+
+    while (1) {
+        local++;
+    }
+}
index db8d917c7b9f2a2132acd4c026f4edecf53d2500..d661d14a59a4638a3ef2924e142c75699d99ac2e 100644 (file)
@@ -67,6 +67,9 @@ class Target(object):
     # before starting the test.
     gdb_setup = []
 
+    # Supports mtime at 0x2004000
+    supports_clint_mtime = True
+
     # Internal variables:
     directory = None
     temporary_files = []