+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, cmd, run, isolate):
- self.cmd = cmd
- self.run = run
- 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."""
+ # 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(cmd=self.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" % (
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,
def extensionSupported(self, letter):
# target.misa is set by testlib.ExamineTarget
- return self.misa & (1 << (ord(letter.upper()) - ord('A')))
-
-class SpikeTarget(Target):
- # pylint: disable=abstract-method
- directory = "spike"
- ram = 0x80010000
- ram_size = 5 * 1024 * 1024
- instruction_hardware_breakpoint_count = 4
- reset_vector = 0x1000
-
-class Spike64Target(SpikeTarget):
- name = "spike64"
- xlen = 64
- use_fpu = True
-
- def server(self):
- return testlib.Spike(self.cmd, halted=True)
-
-class Spike32Target(SpikeTarget):
- name = "spike32"
- xlen = 32
-
- def server(self):
- return testlib.Spike(self.cmd, halted=True, xlen=32)
-
-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 = 240
- 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(simv=self.run, 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 = 240
- 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(simv=self.run, debug=False)
-
-targets = [
- Spike32Target,
- Spike64Target,
- FreedomE300Target,
- FreedomU500Target,
- FreedomE300SimTarget,
- FreedomU500SimTarget,
- HiFive1Target]
+ if self.misa:
+ return self.misa & (1 << (ord(letter.upper()) - ord('A')))
+ else:
+ return False
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("--run",
+ 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)")
- parser.add_argument("--cmd",
- help="The command to use to start the debug server.")
+ "simulation)", default="spike")
+ parser.add_argument("--server_cmd",
+ 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="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)