aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2016-12-27 11:34:50 -0800
committerTim Newsome <tim@sifive.com>2016-12-27 11:34:50 -0800
commit4ec77dde62f8c14df9403abf7b10a2455ea72125 (patch)
treece54ad127f65f392c149d66d1caf84c677d8daec
parentb986817eebe9bd810be371dc84ee94e8f654de42 (diff)
downloadriscv-tests-4ec77dde62f8c14df9403abf7b10a2455ea72125.zip
riscv-tests-4ec77dde62f8c14df9403abf7b10a2455ea72125.tar.gz
riscv-tests-4ec77dde62f8c14df9403abf7b10a2455ea72125.tar.bz2
Use compressed code if the target supports it.
The main change was to read misa before running any other test. If misa indicates C is supported, then use compressed code. This required changing some tests, mostly to ensure correct alignment. The single step test also needs to know the correct addresses to step through in compressed code. Only print at most 1000 lines from each log file.
-rwxr-xr-xdebug/gdbserver.py59
-rwxr-xr-xdebug/openocd.py2
-rw-r--r--debug/programs/step.S8
-rw-r--r--debug/programs/trigger.S1
-rw-r--r--debug/targets.py7
-rw-r--r--debug/testlib.py93
6 files changed, 109 insertions, 61 deletions
diff --git a/debug/gdbserver.py b/debug/gdbserver.py
index 323d32c..9dfea39 100755
--- a/debug/gdbserver.py
+++ b/debug/gdbserver.py
@@ -11,6 +11,7 @@ import targets
import testlib
from testlib import assertEqual, assertNotEqual, assertIn
from testlib import assertGreater, assertTrue, assertRegexpMatches, assertLess
+from testlib import GdbTest
MSTATUS_UIE = 0x00000001
MSTATUS_SIE = 0x00000002
@@ -34,30 +35,6 @@ MSTATUS64_SD = 0x8000000000000000
# pylint: disable=abstract-method
-def gdb(
- target=None,
- port=None,
- binary=None
- ):
-
- g = None
- if parsed.gdb:
- g = testlib.Gdb(parsed.gdb)
- else:
- g = testlib.Gdb()
-
- if binary:
- g.command("file %s" % binary)
- if target:
- g.command("set arch riscv:rv%d" % target.xlen)
- g.command("set remotetimeout %d" % target.timeout_sec)
- if port:
- g.command("target extended-remote localhost:%d" % port)
-
- g.p("$priv=3")
-
- return g
-
def ihex_line(address, record_type, data):
assert len(data) < 128
line = ":%02X%04X%02X" % (len(data), address, record_type)
@@ -86,20 +63,6 @@ def ihex_parse(line):
def readable_binary_string(s):
return "".join("%02x" % ord(c) for c in s)
-class GdbTest(testlib.BaseTest):
- def __init__(self, target):
- testlib.BaseTest.__init__(self, target)
- self.gdb = None
-
- def classSetup(self):
- testlib.BaseTest.classSetup(self)
- self.logs.append("gdb.log")
- self.gdb = gdb(self.target, self.server.port, self.binary)
-
- def classTeardown(self):
- del self.gdb
- testlib.BaseTest.classTeardown(self)
-
class SimpleRegisterTest(GdbTest):
def check_reg(self, name):
a = random.randrange(1<<self.target.xlen)
@@ -145,10 +108,10 @@ class SimpleF18Test(SimpleRegisterTest):
self.gdb.stepi()
assertLess(abs(float(self.gdb.p_raw("$%s" % name)) - b), .001)
+ def early_applicable(self):
+ return self.target.extensionSupported('F')
+
def test(self):
- misa = self.gdb.p("$misa")
- if not misa & (1<<(ord('F')-ord('A'))):
- return 'not_applicable'
self.check_reg("f18")
class SimpleMemoryTest(GdbTest):
@@ -440,10 +403,14 @@ class StepTest(GdbTest):
def test(self):
main_address = self.gdb.p("$pc")
- for expected in (4, 8, 0xc, 0x10, 0x18, 0x1c, 0x28, 0x20, 0x2c, 0x2c):
+ if self.target.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)
+ for expected in sequence:
self.gdb.stepi()
pc = self.gdb.p("$pc")
- assertEqual("%x" % pc, "%x" % (expected + main_address))
+ assertEqual("%x" % (pc - main_address), "%x" % expected)
class TriggerTest(GdbTest):
compile_args = ("programs/trigger.S", )
@@ -656,7 +623,7 @@ class PrivTest(GdbTest):
# pylint: disable=attribute-defined-outside-init
self.gdb.load()
- misa = self.gdb.p("$misa")
+ misa = self.target.misa
self.supported = set()
if misa & (1<<20):
self.supported.add(0)
@@ -710,8 +677,6 @@ def main():
./gdbserver.py --freedom-e300 --cmd "$HOME/SiFive/openocd/src/openocd -s $HOME/SiFive/openocd/tcl -d" Simple
""")
targets.add_target_options(parser)
- parser.add_argument("--gdb",
- help="The command to use to start gdb.")
testlib.add_test_run_options(parser)
@@ -725,7 +690,7 @@ def main():
module = sys.modules[__name__]
- return testlib.run_all_tests(module, target, parsed.test, parsed.fail_fast)
+ return testlib.run_all_tests(module, target, parsed)
# TROUBLESHOOTING TIPS
# If a particular test fails, run just that one test, eg.:
diff --git a/debug/openocd.py b/debug/openocd.py
index 0ab8810..50c6f3c 100755
--- a/debug/openocd.py
+++ b/debug/openocd.py
@@ -79,7 +79,7 @@ def main():
module = sys.modules[__name__]
- return testlib.run_all_tests(module, target, parsed.test, parsed.fail_fast)
+ return testlib.run_all_tests(module, target, parsed)
if __name__ == '__main__':
sys.exit(main())
diff --git a/debug/programs/step.S b/debug/programs/step.S
index 6601548..3e7b42e 100644
--- a/debug/programs/step.S
+++ b/debug/programs/step.S
@@ -11,14 +11,18 @@ main:
nop // 0x14
one:
beq zero, t0, one // 0x18
- jal two // 0x1c
+ // Use t0 instead of ra to force a 32-bit opcode in C mode. Otherwise
+ // 32-bit and 64-bit binaries end up with different instructions (I
+ // didn't pursue this).
+ jal t0, two // 0x1c
three:
.word 0 // 0x20
nop // 0x24
two:
- ret // 0x28
+ jr t0 // 0x28
+ .align 2
trap_entry:
j trap_entry // 0x2c
diff --git a/debug/programs/trigger.S b/debug/programs/trigger.S
index d87b71e..ac5a2f8 100644
--- a/debug/programs/trigger.S
+++ b/debug/programs/trigger.S
@@ -101,6 +101,7 @@ read_triggers:
ret
.data
+ .align 3
data: .word 0x40
.word 0x41
.word 0x42
diff --git a/debug/targets.py b/debug/targets.py
index c431a67..bcebc0b 100644
--- a/debug/targets.py
+++ b/debug/targets.py
@@ -12,6 +12,7 @@ class Target(object):
temporary_binary = None
openocd_config = []
use_fpu = False
+ misa = None
def __init__(self, cmd, run, isolate):
self.cmd = cmd
@@ -42,6 +43,8 @@ class Target(object):
march = "rv%dima" % self.xlen
if self.use_fpu:
march += "fd"
+ if self.extensionSupported("c"):
+ march += "c"
testlib.compile(sources +
("programs/entry.S", "programs/init.c",
"-I", "../env",
@@ -54,6 +57,10 @@ class Target(object):
xlen=self.xlen)
return binary_name
+ 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"
diff --git a/debug/testlib.py b/debug/testlib.py
index ac1d771..a762174 100644
--- a/debug/testlib.py
+++ b/debug/testlib.py
@@ -327,23 +327,31 @@ class Gdb(object):
assert "Hardware assisted breakpoint" in output
return output
-def run_all_tests(module, target, tests, fail_fast):
+def run_all_tests(module, target, parsed):
good_results = set(('pass', 'not_applicable'))
start = time.time()
results = {}
count = 0
+
+ global gdb_cmd # pylint: disable=global-statement
+ gdb_cmd = parsed.gdb
+
+ todo = [("ExamineTarget", ExamineTarget)]
for name in dir(module):
definition = getattr(module, name)
if type(definition) == type and hasattr(definition, 'test') and \
- (not tests or any(test in name for test in tests)):
- instance = definition(target)
- result = instance.run()
- results.setdefault(result, []).append(name)
- count += 1
- if result not in good_results and fail_fast:
- break
+ (not parsed.test or any(test in name for test in parsed.test)):
+ todo.append((name, definition))
+
+ for name, definition in todo:
+ instance = definition(target)
+ result = instance.run()
+ results.setdefault(result, []).append(name)
+ count += 1
+ if result not in good_results and parsed.fail_fast:
+ break
header("ran %d tests in %.0fs" % (count, time.time() - start), dash=':')
@@ -362,6 +370,8 @@ def add_test_run_options(parser):
help="Exit as soon as any test fails.")
parser.add_argument("test", nargs='*',
help="Run only tests that are named here.")
+ parser.add_argument("--gdb",
+ help="The command to use to start gdb.")
def header(title, dash='-'):
if title:
@@ -372,9 +382,21 @@ def header(title, dash='-'):
else:
print dash * 40
+def print_log(path):
+ header(path)
+ lines = open(path, "r").readlines()
+ if len(lines) > 1000:
+ for l in lines[:500]:
+ sys.stdout.write(l)
+ print "..."
+ for l in lines[-500:]:
+ sys.stdout.write(l)
+ else:
+ for l in lines:
+ sys.stdout.write(l)
+
class BaseTest(object):
compiled = {}
- logs = []
def __init__(self, target):
self.target = target
@@ -382,6 +404,7 @@ class BaseTest(object):
self.target_process = None
self.binary = None
self.start = 0
+ self.logs = []
def early_applicable(self):
"""Return a false value if the test has determined it cannot run
@@ -450,8 +473,7 @@ class BaseTest(object):
header("Traceback")
traceback.print_exc(file=sys.stdout)
for log in self.logs:
- header(log)
- print open(log, "r").read()
+ print_log(log)
print "/" * 40
return result
@@ -463,6 +485,55 @@ class BaseTest(object):
print "%s in %.2fs" % (result, time.time() - self.start)
return result
+gdb_cmd = None
+class GdbTest(BaseTest):
+ def __init__(self, target):
+ BaseTest.__init__(self, target)
+ self.gdb = None
+
+ def classSetup(self):
+ BaseTest.classSetup(self)
+ self.logs.append("gdb.log")
+
+ if gdb_cmd:
+ self.gdb = Gdb(gdb_cmd)
+ else:
+ self.gdb = Gdb()
+
+ if self.binary:
+ self.gdb.command("file %s" % self.binary)
+ if self.target:
+ self.gdb.command("set arch riscv:rv%d" % self.target.xlen)
+ self.gdb.command("set remotetimeout %d" % self.target.timeout_sec)
+ if self.server.port:
+ self.gdb.command(
+ "target extended-remote localhost:%d" % self.server.port)
+
+ self.gdb.p("$priv=3")
+
+ def classTeardown(self):
+ del self.gdb
+ BaseTest.classTeardown(self)
+
+class ExamineTarget(GdbTest):
+ def test(self):
+ self.target.misa = self.gdb.p("$misa")
+
+ txt = "RV"
+ if (self.target.misa >> 30) == 1:
+ txt += "32"
+ elif (self.target.misa >> 62) == 2:
+ txt += "64"
+ elif (self.target.misa >> 126) == 3:
+ txt += "128"
+ else:
+ txt += "??"
+
+ for i in range(26):
+ if self.target.misa & (1<<i):
+ txt += chr(i + ord('A'))
+ print txt,
+
class TestFailed(Exception):
def __init__(self, message):
Exception.__init__(self)