bump env
[riscv-tests.git] / debug / targets.py
index 1f4b176144a84ba89da5ce34ebb989eebe30f775..63994db87cd252b98839c23ade1597a198b839ae 100644 (file)
@@ -5,35 +5,83 @@ import tempfile
 
 import testlib
 
+class Hart(object):
+    # XLEN of the hart. May be overridden with --32 or --64 command line
+    # options.
+    xlen = 0
+
+    # Will be autodetected (by running ExamineTarget) if left unset. Set to
+    # save a little time.
+    misa = None
+
+    # Path to linker script relative to the .py file where the target is
+    # defined. Defaults to <name>.lds.
+    link_script_path = None
+
+    # Implements dmode in tdata1 as described in the spec. Harts that need
+    # this value set to False are not compliant with the spec (but still usable
+    # as long as running code doesn't try to mess with triggers set by an
+    # external debugger).
+    honors_tdata1_hmode = True
+
+    # Address where a r/w/x block of RAM starts, together with its size.
+    ram = None
+    ram_size = None
+
+    # Number of instruction triggers the hart supports.
+    instruction_hardware_breakpoint_count = 0
+
+    # Defaults to target-<index>
+    name = None
+
+    # When reset, the PC must be at one of the values listed here.
+    # This is a list because on some boards the reset vector depends on
+    # jumpers.
+    reset_vectors = []
+
+    def extensionSupported(self, letter):
+        # target.misa is set by testlib.ExamineTarget
+        if self.misa:
+            return self.misa & (1 << (ord(letter.upper()) - ord('A')))
+        else:
+            return False
+
 class Target(object):
     # pylint: disable=too-many-instance-attributes
 
+    # List of Hart object instances, one for each hart in the target.
+    harts = []
+
     # Name of the target. Defaults to the name of the class.
     name = None
 
-    # XLEN of the target. May be overridden with --32 or --64 command line
-    # options.
-    xlen = 0
-
     # GDB remotetimeout setting.
     timeout_sec = 2
 
+    # Timeout waiting for the server to start up. This is different than the
+    # GDB timeout, which is how long GDB waits for commands to execute.
+    # The server_timeout is how long this script waits for the server to be
+    # ready for GDB connections.
+    server_timeout_sec = 60
+
     # Path to OpenOCD configuration file relative to the .py file where the
     # target is defined. Defaults to <name>.cfg.
     openocd_config_path = None
 
-    # Path to linker script relative to the .py file where the target is
-    # defined. Defaults to <name>.lds.
-    link_script_path = None
+    # List of commands that should be executed in gdb after connecting but
+    # before starting the test.
+    gdb_setup = []
 
-    # Will be autodetected (by running ExamineTarget) if left unset. Set to
-    # save a little time.
-    misa = None
+    # Supports mtime at 0x2004000
+    supports_clint_mtime = True
+
+    # Implements custom debug registers like spike does. It seems unlikely any
+    # hardware will every do that.
+    implements_custom_test = False
 
     # Internal variables:
     directory = None
     temporary_files = []
-    temporary_binary = None
 
     def __init__(self, path, parsed):
         # Path to module.
@@ -41,7 +89,8 @@ class Target(object):
         self.directory = os.path.dirname(path)
         self.server_cmd = parsed.server_cmd
         self.sim_cmd = parsed.sim_cmd
-        self.isolate = parsed.isolate
+        self.temporary_binary = None
+        Target.isolate = parsed.isolate
         if not self.name:
             self.name = type(self).__name__
         # Default OpenOCD config file to <name>.cfg
@@ -49,11 +98,17 @@ class Target(object):
             self.openocd_config_path = "%s.cfg" % self.name
         self.openocd_config_path = os.path.join(self.directory,
                 self.openocd_config_path)
-        # Default link script to <name>.lds
-        if not self.link_script_path:
-            self.link_script_path = "%s.lds" % self.name
-        self.link_script_path = os.path.join(self.directory,
-                self.link_script_path)
+        for i, hart in enumerate(self.harts):
+            hart.index = i
+            if not hasattr(hart, 'id'):
+                hart.id = i
+            if not hart.name:
+                hart.name = "%s-%d" % (self.name, i)
+            # Default link script to <name>.lds
+            if not hart.link_script_path:
+                hart.link_script_path = "%s.lds" % self.name
+            hart.link_script_path = os.path.join(self.directory,
+                    hart.link_script_path)
 
     def create(self):
         """Create the target out of thin air, eg. start a simulator."""
@@ -62,41 +117,36 @@ class Target(object):
     def server(self):
         """Start the debug server that gdb connects to, eg. OpenOCD."""
         return testlib.Openocd(server_cmd=self.server_cmd,
-                config=self.openocd_config_path)
+                config=self.openocd_config_path,
+                timeout=self.server_timeout_sec)
 
-    def compile(self, *sources):
+    def compile(self, hart, *sources):
         binary_name = "%s_%s-%d" % (
                 self.name,
                 os.path.basename(os.path.splitext(sources[0])[0]),
-                self.xlen)
-        if self.isolate:
+                hart.xlen)
+        if Target.isolate:
             self.temporary_binary = tempfile.NamedTemporaryFile(
                     prefix=binary_name + "_")
             binary_name = self.temporary_binary.name
             Target.temporary_files.append(self.temporary_binary)
-        march = "rv%dima" % self.xlen
+        march = "rv%dima" % hart.xlen
         for letter in "fdc":
-            if self.extensionSupported(letter):
+            if hart.extensionSupported(letter):
                 march += letter
         testlib.compile(sources +
                 ("programs/entry.S", "programs/init.c",
+                    "-DNHARTS=%d" % len(self.harts),
                     "-I", "../env",
                     "-march=%s" % march,
-                    "-T", self.link_script_path,
+                    "-T", hart.link_script_path,
                     "-nostartfiles",
                     "-mcmodel=medany",
-                    "-DXLEN=%d" % self.xlen,
+                    "-DXLEN=%d" % hart.xlen,
                     "-o", binary_name),
-                xlen=self.xlen)
+                xlen=hart.xlen)
         return binary_name
 
-    def extensionSupported(self, letter):
-        # target.misa is set by testlib.ExamineTarget
-        if self.misa:
-            return self.misa & (1 << (ord(letter.upper()) - ord('A')))
-        else:
-            return False
-
 def add_target_options(parser):
     parser.add_argument("target", help=".py file that contains definition for "
             "the target to test with.")
@@ -107,10 +157,10 @@ def add_target_options(parser):
             help="The command to use to start the debug server (e.g. OpenOCD)")
 
     xlen_group = parser.add_mutually_exclusive_group()
-    xlen_group.add_argument("--32", action="store_const", const=32, dest="xlen",
-            help="Force the target to be 32-bit.")
-    xlen_group.add_argument("--64", action="store_const", const=64, dest="xlen",
-            help="Force the target to be 64-bit.")
+    xlen_group.add_argument("--32", action="store_const", const=32,
+            dest="xlen", default=0, help="Force the target to be 32-bit.")
+    xlen_group.add_argument("--64", action="store_const", const=64,
+            dest="xlen", default=0, help="Force the target to be 64-bit.")
 
     parser.add_argument("--isolate", action="store_true",
             help="Try to run in such a way that multiple instances can run at "
@@ -127,9 +177,20 @@ def target(parsed):
     found = []
     for name in dir(module):
         definition = getattr(module, name)
-        if type(definition) == type and issubclass(definition, Target):
+        if isinstance(definition, type) and issubclass(definition, Target):
             found.append(definition)
     assert len(found) == 1, "%s does not define exactly one subclass of " \
             "targets.Target" % parsed.target
 
-    return found[0](parsed.target, parsed)
+    t = found[0](parsed.target, parsed)
+    assert t.harts, "%s doesn't have any harts defined!" % t.name
+    if parsed.xlen > 0:
+        for h in t.harts:
+            if h.xlen == 0:
+                h.xlen = parsed.xlen
+            elif h.xlen != parsed.xlen:
+                raise Exception("The target hart specified an XLEN of %d, but "\
+                        "the command line specified an XLEN of %d. They must "\
+                        "match." % (h.xlen, parsed.xlen))
+
+    return t