Make the debug tests aware of multicore.
[riscv-tests.git] / debug / gdbserver.py
index cbb1299ad9ecafc009df6c486a8e656f49fde011..092f0181907f31db82b9806c2e574bbfdef7c381 100755 (executable)
@@ -12,7 +12,7 @@ import targets
 import testlib
 from testlib import assertEqual, assertNotEqual, assertIn, assertNotIn
 from testlib import assertGreater, assertRegexpMatches, assertLess
 import testlib
 from testlib import assertEqual, assertNotEqual, assertIn, assertNotIn
 from testlib import assertGreater, assertRegexpMatches, assertLess
-from testlib import GdbTest
+from testlib import GdbTest, GdbSingleHartTest
 
 MSTATUS_UIE = 0x00000001
 MSTATUS_SIE = 0x00000002
 
 MSTATUS_UIE = 0x00000001
 MSTATUS_SIE = 0x00000002
@@ -66,8 +66,8 @@ def readable_binary_string(s):
 
 class SimpleRegisterTest(GdbTest):
     def check_reg(self, name):
 
 class SimpleRegisterTest(GdbTest):
     def check_reg(self, name):
-        a = random.randrange(1<<self.target.xlen)
-        b = random.randrange(1<<self.target.xlen)
+        a = random.randrange(1<<self.hart.xlen)
+        b = random.randrange(1<<self.hart.xlen)
         self.gdb.p("$%s=0x%x" % (name, a))
         self.gdb.stepi()
         assertEqual(self.gdb.p("$%s" % name), a)
         self.gdb.p("$%s=0x%x" % (name, a))
         self.gdb.stepi()
         assertEqual(self.gdb.p("$%s" % name), a)
@@ -77,12 +77,12 @@ class SimpleRegisterTest(GdbTest):
 
     def setup(self):
         # 0x13 is nop
 
     def setup(self):
         # 0x13 is nop
-        self.gdb.command("p *((int*) 0x%x)=0x13" % self.target.ram)
-        self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 4))
-        self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 8))
-        self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 12))
-        self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 16))
-        self.gdb.p("$pc=0x%x" % self.target.ram)
+        self.gdb.command("p *((int*) 0x%x)=0x13" % self.hart.ram)
+        self.gdb.command("p *((int*) 0x%x)=0x13" % (self.hart.ram + 4))
+        self.gdb.command("p *((int*) 0x%x)=0x13" % (self.hart.ram + 8))
+        self.gdb.command("p *((int*) 0x%x)=0x13" % (self.hart.ram + 12))
+        self.gdb.command("p *((int*) 0x%x)=0x13" % (self.hart.ram + 16))
+        self.gdb.p("$pc=0x%x" % self.hart.ram)
 
 class SimpleS0Test(SimpleRegisterTest):
     def test(self):
 
 class SimpleS0Test(SimpleRegisterTest):
     def test(self):
@@ -114,7 +114,8 @@ class SimpleF18Test(SimpleRegisterTest):
         assertLess(abs(float(self.gdb.p_raw("$%s" % name)) - b), .001)
 
     def early_applicable(self):
         assertLess(abs(float(self.gdb.p_raw("$%s" % name)) - b), .001)
 
     def early_applicable(self):
-        return self.target.extensionSupported('F')
+        print repr(self.hart)
+        return self.hart.extensionSupported('F')
 
     def test(self):
         self.check_reg("f18")
 
     def test(self):
         self.check_reg("f18")
@@ -157,7 +158,7 @@ class MemTest64(SimpleMemoryTest):
 #            assert False, "Read should have failed."
 #        except testlib.CannotAccess as e:
 #            assertEqual(e.address, 0xdeadbeef)
 #            assert False, "Read should have failed."
 #        except testlib.CannotAccess as e:
 #            assertEqual(e.address, 0xdeadbeef)
-#        self.gdb.p("*((int*)0x%x)" % self.target.ram)
+#        self.gdb.p("*((int*)0x%x)" % self.hart.ram)
 #
 #class MemTestWriteInvalid(SimpleMemoryTest):
 #    def test(self):
 #
 #class MemTestWriteInvalid(SimpleMemoryTest):
 #    def test(self):
@@ -168,7 +169,7 @@ class MemTest64(SimpleMemoryTest):
 #            assert False, "Write should have failed."
 #        except testlib.CannotAccess as e:
 #            assertEqual(e.address, 0xdeadbeef)
 #            assert False, "Write should have failed."
 #        except testlib.CannotAccess as e:
 #            assertEqual(e.address, 0xdeadbeef)
-#        self.gdb.p("*((int*)0x%x)=6874742" % self.target.ram)
+#        self.gdb.p("*((int*)0x%x)=6874742" % self.hart.ram)
 
 class MemTestBlock(GdbTest):
     def test(self):
 
 class MemTestBlock(GdbTest):
     def test(self):
@@ -183,9 +184,9 @@ class MemTestBlock(GdbTest):
             a.write(ihex_line(i * line_length, 0, line_data))
         a.flush()
 
             a.write(ihex_line(i * line_length, 0, line_data))
         a.flush()
 
-        self.gdb.command("restore %s 0x%x" % (a.name, self.target.ram))
+        self.gdb.command("restore %s 0x%x" % (a.name, self.hart.ram))
         for offset in range(0, length, 19*4) + [length-4]:
         for offset in range(0, length, 19*4) + [length-4]:
-            value = self.gdb.p("*((int*)0x%x)" % (self.target.ram + offset))
+            value = self.gdb.p("*((int*)0x%x)" % (self.hart.ram + offset))
             written = ord(data[offset]) | \
                     (ord(data[offset+1]) << 8) | \
                     (ord(data[offset+2]) << 16) | \
             written = ord(data[offset]) | \
                     (ord(data[offset+1]) << 8) | \
                     (ord(data[offset+2]) << 16) | \
@@ -194,7 +195,7 @@ class MemTestBlock(GdbTest):
 
         b = tempfile.NamedTemporaryFile(suffix=".ihex")
         self.gdb.command("dump ihex memory %s 0x%x 0x%x" % (b.name,
 
         b = tempfile.NamedTemporaryFile(suffix=".ihex")
         self.gdb.command("dump ihex memory %s 0x%x 0x%x" % (b.name,
-            self.target.ram, self.target.ram + length))
+            self.hart.ram, self.hart.ram + length))
         for line in b:
             record_type, address, line_data = ihex_parse(line)
             if record_type == 0:
         for line in b:
             record_type, address, line_data = ihex_parse(line)
             if record_type == 0:
@@ -213,7 +214,7 @@ class InstantHaltTest(GdbTest):
             self.gdb.thread(t)
             pcs.append(self.gdb.p("$pc"))
         for pc in pcs:
             self.gdb.thread(t)
             pcs.append(self.gdb.p("$pc"))
         for pc in pcs:
-            assertEqual(self.target.reset_vector, pc)
+            assertEqual(self.hart.reset_vector, pc)
         # mcycle and minstret have no defined reset value.
         mstatus = self.gdb.p("$mstatus")
         assertEqual(mstatus & (MSTATUS_MIE | MSTATUS_MPRV |
         # mcycle and minstret have no defined reset value.
         mstatus = self.gdb.p("$mstatus")
         assertEqual(mstatus & (MSTATUS_MIE | MSTATUS_MPRV |
@@ -225,16 +226,16 @@ class InstantChangePc(GdbTest):
         # 0x13 is nop
         self.gdb.command("monitor reset halt")
         self.gdb.command("flushregs")
         # 0x13 is nop
         self.gdb.command("monitor reset halt")
         self.gdb.command("flushregs")
-        self.gdb.command("p *((int*) 0x%x)=0x13" % self.target.ram)
-        self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 4))
-        self.gdb.command("p *((int*) 0x%x)=0x13" % (self.target.ram + 8))
-        self.gdb.p("$pc=0x%x" % self.target.ram)
+        self.gdb.command("p *((int*) 0x%x)=0x13" % self.hart.ram)
+        self.gdb.command("p *((int*) 0x%x)=0x13" % (self.hart.ram + 4))
+        self.gdb.command("p *((int*) 0x%x)=0x13" % (self.hart.ram + 8))
+        self.gdb.p("$pc=0x%x" % self.hart.ram)
         self.gdb.stepi()
         self.gdb.stepi()
-        assertEqual((self.target.ram + 4), self.gdb.p("$pc"))
+        assertEqual((self.hart.ram + 4), self.gdb.p("$pc"))
         self.gdb.stepi()
         self.gdb.stepi()
-        assertEqual((self.target.ram + 8), self.gdb.p("$pc"))
+        assertEqual((self.hart.ram + 8), self.gdb.p("$pc"))
 
 
-class DebugTest(GdbTest):
+class DebugTest(GdbSingleHartTest):
     # Include malloc so that gdb can make function calls. I suspect this malloc
     # will silently blow through the memory set aside for it, so be careful.
     compile_args = ("programs/debug.c", "programs/checksum.c",
     # Include malloc so that gdb can make function calls. I suspect this malloc
     # will silently blow through the memory set aside for it, so be careful.
     compile_args = ("programs/debug.c", "programs/checksum.c",
@@ -325,10 +326,10 @@ class DebugBreakpoint(DebugTest):
 
 class Hwbp1(DebugTest):
     def test(self):
 
 class Hwbp1(DebugTest):
     def test(self):
-        if self.target.instruction_hardware_breakpoint_count < 1:
+        if self.hart.instruction_hardware_breakpoint_count < 1:
             return 'not_applicable'
 
             return 'not_applicable'
 
-        if not self.target.honors_tdata1_hmode:
+        if not self.hart.honors_tdata1_hmode:
             # Run to main before setting the breakpoint, because startup code
             # will otherwise clear the trigger that we set.
             self.gdb.b("main")
             # Run to main before setting the breakpoint, because startup code
             # will otherwise clear the trigger that we set.
             self.gdb.b("main")
@@ -345,7 +346,7 @@ class Hwbp1(DebugTest):
 
 class Hwbp2(DebugTest):
     def test(self):
 
 class Hwbp2(DebugTest):
     def test(self):
-        if self.target.instruction_hardware_breakpoint_count < 2:
+        if self.hart.instruction_hardware_breakpoint_count < 2:
             return 'not_applicable'
 
         self.gdb.hbreak("main")
             return 'not_applicable'
 
         self.gdb.hbreak("main")
@@ -418,16 +419,15 @@ class UserInterrupt(DebugTest):
 class MulticoreTest(GdbTest):
     compile_args = ("programs/infinite_loop.S", )
 
 class MulticoreTest(GdbTest):
     compile_args = ("programs/infinite_loop.S", )
 
+    def early_applicable(self):
+        return len(self.target.harts) > 1
+
     def setup(self):
         self.gdb.load()
 
     def test(self):
     def setup(self):
         self.gdb.load()
 
     def test(self):
-        threads = self.gdb.threads()
-        if len(threads) < 2:
-            return 'not_applicable'
-
-        for t in threads:
-            self.gdb.thread(t)
+        for hart in self.target.harts:
+            self.gdb.select_hart(hart)
             self.gdb.p("$pc=_start")
 
         # Run to main
             self.gdb.p("$pc=_start")
 
         # Run to main
@@ -456,18 +456,19 @@ class MulticoreTest(GdbTest):
         # Confirmed that we read different register values for different harts.
         # Write a new value to x1, and run through the add sequence again.
 
         # Confirmed that we read different register values for different harts.
         # Write a new value to x1, and run through the add sequence again.
 
-        for t in threads:
-            self.gdb.thread(t)
-            self.gdb.p("$x1=0x%x" % (int(t.id) * 0x800))
+        for hart in self.target.harts:
+            self.gdb.select_hart(hart)
+            self.gdb.p("$x1=0x%x" % (hart.index * 0x800))
             self.gdb.p("$pc=main_post_csrr")
         self.gdb.c()
         for t in self.gdb.threads():
             assertIn("main_end", t.frame)
             self.gdb.p("$pc=main_post_csrr")
         self.gdb.c()
         for t in self.gdb.threads():
             assertIn("main_end", t.frame)
+        for hart in self.target.harts:
             # Check register values.
             # Check register values.
-            self.gdb.thread(t)
+            self.gdb.select_hart(hart)
             for n in range(1, 32):
                 value = self.gdb.p("$x%d" % n)
             for n in range(1, 32):
                 value = self.gdb.p("$x%d" % n)
-                assertEqual(value, int(t.id) * 0x800 + n - 1)
+                assertEqual(value, hart.index * 0x800 + n - 1)
 
 class StepTest(GdbTest):
     compile_args = ("programs/step.S", )
 
 class StepTest(GdbTest):
     compile_args = ("programs/step.S", )
@@ -479,7 +480,7 @@ class StepTest(GdbTest):
 
     def test(self):
         main_address = self.gdb.p("$pc")
 
     def test(self):
         main_address = self.gdb.p("$pc")
-        if self.target.extensionSupported("c"):
+        if self.hart.extensionSupported("c"):
             sequence = (4, 8, 0xc, 0xe, 0x14, 0x18, 0x22, 0x1c, 0x24, 0x24)
         else:
             sequence = (4, 8, 0xc, 0x10, 0x18, 0x1c, 0x28, 0x20, 0x2c, 0x2c)
             sequence = (4, 8, 0xc, 0xe, 0x14, 0x18, 0x22, 0x1c, 0x24, 0x24)
         else:
             sequence = (4, 8, 0xc, 0x10, 0x18, 0x1c, 0x28, 0x20, 0x2c, 0x2c)
@@ -558,16 +559,16 @@ class TriggerStoreAddressInstant(TriggerTest):
 
 class TriggerDmode(TriggerTest):
     def early_applicable(self):
 
 class TriggerDmode(TriggerTest):
     def early_applicable(self):
-        return self.target.honors_tdata1_hmode
+        return self.hart.honors_tdata1_hmode
 
     def check_triggers(self, tdata1_lsbs, tdata2):
 
     def check_triggers(self, tdata1_lsbs, tdata2):
-        dmode = 1 << (self.target.xlen-5)
+        dmode = 1 << (self.hart.xlen-5)
 
         triggers = []
 
 
         triggers = []
 
-        if self.target.xlen == 32:
+        if self.hart.xlen == 32:
             xlen_type = 'int'
             xlen_type = 'int'
-        elif self.target.xlen == 64:
+        elif self.hart.xlen == 64:
             xlen_type = 'long long'
         else:
             raise NotImplementedError
             xlen_type = 'long long'
         else:
             raise NotImplementedError
@@ -627,7 +628,7 @@ class WriteGprs(RegsTest):
         self.gdb.command("info registers")
         for n in range(len(regs)):
             assertEqual(self.gdb.x("data+%d" % (8*n), 'g'),
         self.gdb.command("info registers")
         for n in range(len(regs)):
             assertEqual(self.gdb.x("data+%d" % (8*n), 'g'),
-                    ((0xdeadbeef<<n)+17) & ((1<<self.target.xlen)-1))
+                    ((0xdeadbeef<<n)+17) & ((1<<self.hart.xlen)-1))
 
 class WriteCsrs(RegsTest):
     def test(self):
 
 class WriteCsrs(RegsTest):
     def test(self):
@@ -651,7 +652,7 @@ class WriteCsrs(RegsTest):
 class DownloadTest(GdbTest):
     def setup(self):
         # pylint: disable=attribute-defined-outside-init
 class DownloadTest(GdbTest):
     def setup(self):
         # pylint: disable=attribute-defined-outside-init
-        length = min(2**10, self.target.ram_size - 2048)
+        length = min(2**10, self.hart.ram_size - 2048)
         self.download_c = tempfile.NamedTemporaryFile(prefix="download_",
                 suffix=".c", delete=False)
         self.download_c.write("#include <stdint.h>\n")
         self.download_c = tempfile.NamedTemporaryFile(prefix="download_",
                 suffix=".c", delete=False)
         self.download_c.write("#include <stdint.h>\n")
@@ -677,7 +678,7 @@ class DownloadTest(GdbTest):
         if self.crc < 0:
             self.crc += 2**32
 
         if self.crc < 0:
             self.crc += 2**32
 
-        self.binary = self.target.compile(self.download_c.name,
+        self.binary = self.hart.compile(self.download_c.name,
                 "programs/checksum.c")
         self.gdb.command("file %s" % self.binary)
 
                 "programs/checksum.c")
         self.gdb.command("file %s" % self.binary)
 
@@ -708,7 +709,7 @@ class DownloadTest(GdbTest):
 #        # pylint: disable=attribute-defined-outside-init
 #        self.gdb.load()
 #
 #        # pylint: disable=attribute-defined-outside-init
 #        self.gdb.load()
 #
-#        misa = self.target.misa
+#        misa = self.hart.misa
 #        self.supported = set()
 #        if misa & (1<<20):
 #            self.supported.add(0)
 #        self.supported = set()
 #        if misa & (1<<20):
 #            self.supported.add(0)