Add back code to clean up triggers in entry.S
[riscv-tests.git] / debug / targets.py
index 525561e5130e29150313d059935d58628c407bed..296b0a95f72929c621b334da11954a8b45dab7ca 100644 (file)
@@ -1,35 +1,78 @@
+import importlib
 import os.path
+import sys
 import tempfile
 
 import testlib
 
 class Target(object):
-    name = "name"
+    # pylint: disable=too-many-instance-attributes
+
+    # 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
-    directory = None
+
+    # GDB remotetimeout setting.
     timeout_sec = 2
-    temporary_files = []
-    temporary_binary = None
-    openocd_config = []
-    use_fpu = False
+
+    # 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
+
+    # Will be autodetected (by running ExamineTarget) if left unset. Set to
+    # save a little time.
     misa = None
 
-    def __init__(self, server_cmd, sim_cmd, isolate):
-        self.server_cmd = server_cmd
-        self.sim_cmd = sim_cmd
-        self.isolate = isolate
+    # List of commands that should be executed in gdb after connecting but
+    # before starting the test.
+    gdb_setup = []
 
-    def target(self):
-        """Start the target, eg. a simulator."""
+    # Implements dmode in tdata1 as described in the spec. Targets 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
+
+    # Internal variables:
+    directory = None
+    temporary_files = []
+    temporary_binary = None
+
+    def __init__(self, path, parsed):
+        # Path to module.
+        self.path = path
+        self.directory = os.path.dirname(path)
+        self.server_cmd = parsed.server_cmd
+        self.sim_cmd = parsed.sim_cmd
+        self.isolate = parsed.isolate
+        if not self.name:
+            self.name = type(self).__name__
+        # Default OpenOCD config file to <name>.cfg
+        if not self.openocd_config_path:
+            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)
+
+    def create(self):
+        """Create the target out of thin air, eg. start a simulator."""
         pass
 
     def server(self):
         """Start the debug server that gdb connects to, eg. OpenOCD."""
-        if self.openocd_config:
-            return testlib.Openocd(server_cmd=self.server_cmd,
-                    config=self.openocd_config)
-        else:
-            raise NotImplementedError
+        return testlib.Openocd(server_cmd=self.server_cmd,
+                config=self.openocd_config_path)
 
     def compile(self, *sources):
         binary_name = "%s_%s-%d" % (
@@ -42,15 +85,14 @@ class Target(object):
             binary_name = self.temporary_binary.name
             Target.temporary_files.append(self.temporary_binary)
         march = "rv%dima" % self.xlen
-        if self.use_fpu:
-            march += "fd"
-        if self.extensionSupported("c"):
-            march += "c"
+        for letter in "fdc":
+            if self.extensionSupported(letter):
+                march += letter
         testlib.compile(sources +
                 ("programs/entry.S", "programs/init.c",
                     "-I", "../env",
                     "-march=%s" % march,
-                    "-T", "targets/%s/link.lds" % (self.directory or self.name),
+                    "-T", self.link_script_path,
                     "-nostartfiles",
                     "-mcmodel=medany",
                     "-DXLEN=%d" % self.xlen,
@@ -65,98 +107,12 @@ class Target(object):
         else:
             return False
 
-class SpikeTarget(Target):
-    # pylint: disable=abstract-method
-    instruction_hardware_breakpoint_count = 4
-    reset_vector = 0x1000
-
-class Spike64Target(SpikeTarget):
-    name = "spike64"
-    directory = name
-    xlen = 64
-    use_fpu = True
-    # Would like to use 0x7fffffffffff0000 because it crosses the 0x8000...
-    # boundary, but spike doesn't support that in the code where it generates
-    # the reset vector.
-    ram = 0x1212340000
-    ram_size = 0x10000000
-    openocd_config = "targets/%s/openocd.cfg" % directory
-
-    def target(self):
-        return testlib.Spike(self)
-
-class Spike32Target(SpikeTarget):
-    name = "spike32"
-    directory = name
-    xlen = 32
-    ram = 0x10000000
-    ram_size = 0x10000000
-    openocd_config = "targets/%s/openocd.cfg" % directory
-
-    def target(self):
-        return testlib.Spike(self)
-
-class FreedomE300Target(Target):
-    name = "freedom-e300"
-    xlen = 32
-    ram = 0x80000000
-    ram_size = 16 * 1024
-    instruction_hardware_breakpoint_count = 2
-    openocd_config = "targets/%s/openocd.cfg" % name
-
-class HiFive1Target(FreedomE300Target):
-    name = "HiFive1"
-    openocd_config = "targets/%s/openocd.cfg" % name
-
-class FreedomE300SimTarget(Target):
-    name = "freedom-e300-sim"
-    xlen = 32
-    timeout_sec = 6000
-    ram = 0x80000000
-    ram_size = 256 * 1024 * 1024
-    instruction_hardware_breakpoint_count = 2
-    openocd_config = "targets/%s/openocd.cfg" % name
-
-    def target(self):
-        return testlib.VcsSim(sim_cmd=self.sim_cmd, debug=False)
-
-class FreedomU500Target(Target):
-    name = "freedom-u500"
-    xlen = 64
-    ram = 0x80000000
-    ram_size = 16 * 1024
-    instruction_hardware_breakpoint_count = 2
-    openocd_config = "targets/%s/openocd.cfg" % name
-
-class FreedomU500SimTarget(Target):
-    name = "freedom-u500-sim"
-    xlen = 64
-    timeout_sec = 6000
-    ram = 0x80000000
-    ram_size = 256 * 1024 * 1024
-    instruction_hardware_breakpoint_count = 2
-    openocd_config = "targets/%s/openocd.cfg" % name
-
-    def target(self):
-        return testlib.VcsSim(sim_cmd=self.sim_cmd, debug=False)
-
-targets = [
-        Spike32Target,
-        Spike64Target,
-        FreedomE300Target,
-        FreedomU500Target,
-        FreedomE300SimTarget,
-        FreedomU500SimTarget,
-        HiFive1Target]
-
 def add_target_options(parser):
-    group = parser.add_mutually_exclusive_group(required=True)
-    for t in targets:
-        group.add_argument("--%s" % t.name, action="store_const", const=t,
-                dest="target")
+    parser.add_argument("target", help=".py file that contains definition for "
+            "the target to test with.")
     parser.add_argument("--sim_cmd",
             help="The command to use to start the actual target (e.g. "
-            "simulation)")
+            "simulation)", default="spike")
     parser.add_argument("--server_cmd",
             help="The command to use to start the debug server (e.g. OpenOCD)")
 
@@ -170,3 +126,20 @@ def add_target_options(parser):
             help="Try to run in such a way that multiple instances can run at "
             "the same time. This may make it harder to debug a failure if it "
             "does occur.")
+
+def target(parsed):
+    directory = os.path.dirname(parsed.target)
+    filename = os.path.basename(parsed.target)
+    module_name = os.path.splitext(filename)[0]
+
+    sys.path.append(directory)
+    module = importlib.import_module(module_name)
+    found = []
+    for name in dir(module):
+        definition = getattr(module, name)
+        if type(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)