debug: Fix the XLEN command line check
[riscv-tests.git] / debug / targets.py
1 import importlib
2 import os.path
3 import sys
4 import tempfile
5
6 import testlib
7
8 class Hart(object):
9 # XLEN of the hart. May be overridden with --32 or --64 command line
10 # options.
11 xlen = 0
12
13 # Will be autodetected (by running ExamineTarget) if left unset. Set to
14 # save a little time.
15 misa = None
16
17 # Path to linker script relative to the .py file where the target is
18 # defined. Defaults to <name>.lds.
19 link_script_path = None
20
21 # Implements dmode in tdata1 as described in the spec. Harts that need
22 # this value set to False are not compliant with the spec (but still usable
23 # as long as running code doesn't try to mess with triggers set by an
24 # external debugger).
25 honors_tdata1_hmode = True
26
27 # Address where a r/w/x block of RAM starts, together with its size.
28 ram = None
29 ram_size = None
30
31 # Number of instruction triggers the hart supports.
32 instruction_hardware_breakpoint_count = 0
33
34 # Defaults to target-<index>
35 name = None
36
37 # When reset, the PC must be at one of the values listed here.
38 # This is a list because on some boards the reset vector depends on
39 # jumpers.
40 reset_vectors = []
41
42 def extensionSupported(self, letter):
43 # target.misa is set by testlib.ExamineTarget
44 if self.misa:
45 return self.misa & (1 << (ord(letter.upper()) - ord('A')))
46 else:
47 return False
48
49 class Target(object):
50 # pylint: disable=too-many-instance-attributes
51
52 # List of Hart object instances, one for each hart in the target.
53 harts = []
54
55 # Name of the target. Defaults to the name of the class.
56 name = None
57
58 # GDB remotetimeout setting.
59 timeout_sec = 2
60
61 # Timeout waiting for the server to start up. This is different than the
62 # GDB timeout, which is how long GDB waits for commands to execute.
63 # The server_timeout is how long this script waits for the server to be
64 # ready for GDB connections.
65 server_timeout_sec = 60
66
67 # Path to OpenOCD configuration file relative to the .py file where the
68 # target is defined. Defaults to <name>.cfg.
69 openocd_config_path = None
70
71 # List of commands that should be executed in gdb after connecting but
72 # before starting the test.
73 gdb_setup = []
74
75 # Supports mtime at 0x2004000
76 supports_clint_mtime = True
77
78 # Internal variables:
79 directory = None
80 temporary_files = []
81
82 def __init__(self, path, parsed):
83 # Path to module.
84 self.path = path
85 self.directory = os.path.dirname(path)
86 self.server_cmd = parsed.server_cmd
87 self.sim_cmd = parsed.sim_cmd
88 self.temporary_binary = None
89 Target.isolate = parsed.isolate
90 if not self.name:
91 self.name = type(self).__name__
92 # Default OpenOCD config file to <name>.cfg
93 if not self.openocd_config_path:
94 self.openocd_config_path = "%s.cfg" % self.name
95 self.openocd_config_path = os.path.join(self.directory,
96 self.openocd_config_path)
97 for i, hart in enumerate(self.harts):
98 hart.index = i
99 if not hasattr(hart, 'id'):
100 hart.id = i
101 if not hart.name:
102 hart.name = "%s-%d" % (self.name, i)
103 # Default link script to <name>.lds
104 if not hart.link_script_path:
105 hart.link_script_path = "%s.lds" % self.name
106 hart.link_script_path = os.path.join(self.directory,
107 hart.link_script_path)
108
109 def create(self):
110 """Create the target out of thin air, eg. start a simulator."""
111 pass
112
113 def server(self):
114 """Start the debug server that gdb connects to, eg. OpenOCD."""
115 return testlib.Openocd(server_cmd=self.server_cmd,
116 config=self.openocd_config_path,
117 timeout=self.server_timeout_sec)
118
119 def compile(self, hart, *sources):
120 binary_name = "%s_%s-%d" % (
121 self.name,
122 os.path.basename(os.path.splitext(sources[0])[0]),
123 hart.xlen)
124 if Target.isolate:
125 self.temporary_binary = tempfile.NamedTemporaryFile(
126 prefix=binary_name + "_")
127 binary_name = self.temporary_binary.name
128 Target.temporary_files.append(self.temporary_binary)
129 march = "rv%dima" % hart.xlen
130 for letter in "fdc":
131 if hart.extensionSupported(letter):
132 march += letter
133 testlib.compile(sources +
134 ("programs/entry.S", "programs/init.c",
135 "-DNHARTS=%d" % len(self.harts),
136 "-I", "../env",
137 "-march=%s" % march,
138 "-T", hart.link_script_path,
139 "-nostartfiles",
140 "-mcmodel=medany",
141 "-DXLEN=%d" % hart.xlen,
142 "-o", binary_name),
143 xlen=hart.xlen)
144 return binary_name
145
146 def add_target_options(parser):
147 parser.add_argument("target", help=".py file that contains definition for "
148 "the target to test with.")
149 parser.add_argument("--sim_cmd",
150 help="The command to use to start the actual target (e.g. "
151 "simulation)", default="spike")
152 parser.add_argument("--server_cmd",
153 help="The command to use to start the debug server (e.g. OpenOCD)")
154
155 xlen_group = parser.add_mutually_exclusive_group()
156 xlen_group.add_argument("--32", action="store_const", const=32, dest="xlen", default=0,
157 help="Force the target to be 32-bit.")
158 xlen_group.add_argument("--64", action="store_const", const=64, dest="xlen", default=0,
159 help="Force the target to be 64-bit.")
160
161 parser.add_argument("--isolate", action="store_true",
162 help="Try to run in such a way that multiple instances can run at "
163 "the same time. This may make it harder to debug a failure if it "
164 "does occur.")
165
166 def target(parsed):
167 directory = os.path.dirname(parsed.target)
168 filename = os.path.basename(parsed.target)
169 module_name = os.path.splitext(filename)[0]
170
171 sys.path.append(directory)
172 module = importlib.import_module(module_name)
173 found = []
174 for name in dir(module):
175 definition = getattr(module, name)
176 if isinstance(definition, type) and issubclass(definition, Target):
177 found.append(definition)
178 assert len(found) == 1, "%s does not define exactly one subclass of " \
179 "targets.Target" % parsed.target
180
181 t = found[0](parsed.target, parsed)
182 assert t.harts, "%s doesn't have any harts defined!" % t.name
183 if (parsed.xlen > 0):
184 for h in t.harts :
185 if (h.xlen == 0):
186 h.xlen = parsed.xlen
187 elif (h.xlen != parsed.xlen):
188 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))
189
190 return t