aboutsummaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2016-05-10 10:03:28 -0700
committerTim Newsome <tim@sifive.com>2016-05-23 12:12:12 -0700
commit9baa8a015cddc294d53d72ce57a8ca2f5c832c64 (patch)
tree15ff76cbf5aa58d6554c79172301f722e9bdb00f /tests
parent5b2c9df0b3db0d504ef2fb2a68f18f91cfcc5966 (diff)
downloadspike-9baa8a015cddc294d53d72ce57a8ca2f5c832c64.zip
spike-9baa8a015cddc294d53d72ce57a8ca2f5c832c64.tar.gz
spike-9baa8a015cddc294d53d72ce57a8ca2f5c832c64.tar.bz2
Write test for downloading a mostly random program
It passes, but it's slow.
Diffstat (limited to 'tests')
-rw-r--r--tests/checksum.c47
-rwxr-xr-xtests/ebreak.py4
-rwxr-xr-xtests/gdbserver.py72
-rw-r--r--tests/mprv.S4
-rw-r--r--tests/standalone.lds2
-rw-r--r--tests/start.S12
-rw-r--r--tests/testlib.py57
7 files changed, 144 insertions, 54 deletions
diff --git a/tests/checksum.c b/tests/checksum.c
new file mode 100644
index 0000000..36152fc
--- /dev/null
+++ b/tests/checksum.c
@@ -0,0 +1,47 @@
+#include <stdint.h>
+
+// CRC code from http://www.hackersdelight.org/hdcodetxt/crc.c.txt
+
+// Reverses (reflects) bits in a 32-bit word.
+unsigned reverse(unsigned x) {
+ x = ((x & 0x55555555) << 1) | ((x >> 1) & 0x55555555);
+ x = ((x & 0x33333333) << 2) | ((x >> 2) & 0x33333333);
+ x = ((x & 0x0F0F0F0F) << 4) | ((x >> 4) & 0x0F0F0F0F);
+ x = (x << 24) | ((x & 0xFF00) << 8) |
+ ((x >> 8) & 0xFF00) | (x >> 24);
+ return x;
+}
+
+// ----------------------------- crc32a --------------------------------
+
+/* This is the basic CRC algorithm with no optimizations. It follows the
+logic circuit as closely as possible. */
+
+unsigned int crc32a(uint8_t *message, unsigned int size) {
+ int i, j;
+ unsigned int byte, crc;
+
+ i = 0;
+ crc = 0xFFFFFFFF;
+ while (i < size) {
+ byte = message[i]; // Get next byte.
+ byte = reverse(byte); // 32-bit reversal.
+ for (j = 0; j <= 7; j++) { // Do eight times.
+ if ((int)(crc ^ byte) < 0)
+ crc = (crc << 1) ^ 0x04C11DB7;
+ else crc = crc << 1;
+ byte = byte << 1; // Ready next msg bit.
+ }
+ i = i + 1;
+ }
+ return reverse(~crc);
+}
+
+extern uint8_t *data;
+extern uint32_t length;
+
+uint32_t main()
+{
+ /* Compute a simple checksum. */
+ return crc32a(data, length);
+}
diff --git a/tests/ebreak.py b/tests/ebreak.py
index 4b41f7d..dd7e658 100755
--- a/tests/ebreak.py
+++ b/tests/ebreak.py
@@ -12,13 +12,13 @@ class EbreakTest(unittest.TestCase):
def test_noport(self):
"""Make sure that we can run past ebreak when --gdb-port isn't used."""
- spike = testlib.spike(self.binary, with_gdb=False, timeout=10)
+ spike = testlib.Spike(self.binary, with_gdb=False, timeout=10)
result = spike.wait()
self.assertEqual(result, 0)
def test_nogdb(self):
"""Make sure that we can run past ebreak when gdb isn't attached."""
- spike, port = testlib.spike(self.binary, timeout=10)
+ spike = testlib.Spike(self.binary, timeout=10)
result = spike.wait()
self.assertEqual(result, 0)
diff --git a/tests/gdbserver.py b/tests/gdbserver.py
index 6ca9af6..5be6574 100755
--- a/tests/gdbserver.py
+++ b/tests/gdbserver.py
@@ -5,18 +5,16 @@ import testlib
import unittest
import tempfile
import time
+import random
+import binascii
class InstantHaltTest(unittest.TestCase):
def setUp(self):
self.binary = testlib.compile("debug.c")
- self.spike, self.port = testlib.spike(self.binary, halted=True)
+ self.spike = testlib.Spike(self.binary, halted=True)
self.gdb = testlib.Gdb()
self.gdb.command("file %s" % self.binary)
- self.gdb.command("target extended-remote localhost:%d" % self.port)
-
- def tearDown(self):
- self.spike.kill()
- self.spike.wait()
+ self.gdb.command("target extended-remote localhost:%d" % self.spike.port)
def test_instant_halt(self):
self.assertEqual(0x1000, self.gdb.p("$pc"))
@@ -40,14 +38,10 @@ class InstantHaltTest(unittest.TestCase):
class DebugTest(unittest.TestCase):
def setUp(self):
self.binary = testlib.compile("debug.c")
- self.spike, self.port = testlib.spike(self.binary, halted=False)
+ self.spike = testlib.Spike(self.binary, halted=False)
self.gdb = testlib.Gdb()
self.gdb.command("file %s" % self.binary)
- self.gdb.command("target extended-remote localhost:%d" % self.port)
-
- def tearDown(self):
- self.spike.kill()
- self.spike.wait()
+ self.gdb.command("target extended-remote localhost:%d" % self.spike.port)
def test_turbostep(self):
"""Single step a bunch of times."""
@@ -117,14 +111,10 @@ class DebugTest(unittest.TestCase):
class RegsTest(unittest.TestCase):
def setUp(self):
self.binary = testlib.compile("regs.s")
- self.spike, self.port = testlib.spike(self.binary, halted=False)
+ self.spike = testlib.Spike(self.binary, halted=False)
self.gdb = testlib.Gdb()
self.gdb.command("file %s" % self.binary)
- self.gdb.command("target extended-remote localhost:%d" % self.port)
-
- def tearDown(self):
- self.spike.kill()
- self.spike.wait()
+ self.gdb.command("target extended-remote localhost:%d" % self.spike.port)
def test_write_gprs(self):
# Note a0 is missing from this list since it's used to hold the
@@ -168,20 +158,54 @@ class RegsTest(unittest.TestCase):
self.assertEqual(9, self.gdb.p("$x1"))
self.assertEqual(9, self.gdb.p("$csr1"))
+class DownloadTest(unittest.TestCase):
+ def setUp(self):
+ length = 2**16
+ fd = file("data.c", "w")
+ fd.write("#include <stdint.h>\n")
+ fd.write("uint32_t length = %d;\n" % length)
+ fd.write("uint8_t d[%d] = {\n" % length)
+ self.crc = 0
+ for _ in range(length / 16):
+ fd.write(" ");
+ for _ in range(16):
+ value = random.randrange(1<<8)
+ fd.write("%d, " % value)
+ self.crc = binascii.crc32("%c" % value, self.crc)
+ fd.write("\n");
+ fd.write("};\n");
+ fd.write("uint8_t *data = &d[0];\n");
+ fd.close()
+
+ self.binary = testlib.compile("checksum.c", "data.c", "start.S",
+ "-mcmodel=medany",
+ "-T", "standalone.lds",
+ "-nostartfiles"
+ )
+ self.spike = testlib.Spike(None, halted=True)
+ self.gdb = testlib.Gdb()
+ self.gdb.command("file %s" % self.binary)
+ self.gdb.command("target extended-remote localhost:%d" % self.spike.port)
+
+ def test_download(self):
+ output = self.gdb.command("load")
+ self.assertNotIn("failed", output)
+ self.assertIn("Transfer rate", output)
+ self.gdb.command("b done")
+ self.gdb.c()
+ result = self.gdb.p("$a0")
+ self.assertEqual(self.crc, result)
+
class MprvTest(unittest.TestCase):
def setUp(self):
self.binary = testlib.compile("mprv.S", "-T", "standalone.lds",
"-nostartfiles")
- self.spike, self.port = testlib.spike(None, halted=True)
+ self.spike = testlib.Spike(None, halted=True)
self.gdb = testlib.Gdb()
self.gdb.command("file %s" % self.binary)
- self.gdb.command("target extended-remote localhost:%d" % self.port)
+ self.gdb.command("target extended-remote localhost:%d" % self.spike.port)
self.gdb.command("load")
- def tearDown(self):
- self.spike.kill()
- self.spike.wait()
-
def test_mprv(self):
"""Test that the debugger can access memory when MPRV is set."""
self.gdb.c(wait=False)
diff --git a/tests/mprv.S b/tests/mprv.S
index 114918a..df346b3 100644
--- a/tests/mprv.S
+++ b/tests/mprv.S
@@ -1,10 +1,10 @@
#include "../riscv/encoding.h"
#define PGSHIFT 12
- .global main
+ .global _start
.section .text
-main:
+_start:
# Set up a page table entry that maps 0x0... to 0x8...
la t0, page_table
srli t0, t0, PGSHIFT
diff --git a/tests/standalone.lds b/tests/standalone.lds
index 6705cfd..9b1bab1 100644
--- a/tests/standalone.lds
+++ b/tests/standalone.lds
@@ -1,6 +1,6 @@
OUTPUT_ARCH( "riscv" )
-ENTRY( main )
+ENTRY( _start )
SECTIONS
{
diff --git a/tests/start.S b/tests/start.S
new file mode 100644
index 0000000..76c37bb
--- /dev/null
+++ b/tests/start.S
@@ -0,0 +1,12 @@
+ .global _start
+
+_start:
+ la sp, stack_end
+ jal main
+done:
+ j done
+
+ .data
+stack:
+ .fill 4096, 1, 0
+stack_end:
diff --git a/tests/testlib.py b/tests/testlib.py
index 3cba8c7..d5e8d79 100644
--- a/tests/testlib.py
+++ b/tests/testlib.py
@@ -40,28 +40,35 @@ def unused_port():
s.close()
return port
-def spike(binary, halted=False, with_gdb=True, timeout=None):
- """Launch spike. Return tuple of its process and the port it's running on."""
- cmd = []
- if timeout:
- cmd += ["timeout", str(timeout)]
-
- cmd += [find_file("spike")]
- if halted:
- cmd.append('-H')
- if with_gdb:
- port = unused_port()
- cmd += ['--gdb-port', str(port)]
- cmd.append('pk')
- if binary:
- cmd.append(binary)
- logfile = open("spike.log", "w")
- process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=logfile,
- stderr=logfile)
- if with_gdb:
- return process, port
- else:
- return process
+class Spike(object):
+ def __init__(self, binary, halted=False, with_gdb=True, timeout=None):
+ """Launch spike. Return tuple of its process and the port it's running on."""
+ cmd = []
+ if timeout:
+ cmd += ["timeout", str(timeout)]
+
+ cmd += [find_file("spike")]
+ if halted:
+ cmd.append('-H')
+ if with_gdb:
+ self.port = unused_port()
+ cmd += ['--gdb-port', str(self.port)]
+ cmd.append('pk')
+ if binary:
+ cmd.append(binary)
+ logfile = open("spike.log", "w")
+ self.process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=logfile,
+ stderr=logfile)
+
+ def __del__(self):
+ try:
+ self.process.kill()
+ self.process.wait()
+ except OSError:
+ pass
+
+ def wait(self, *args, **kwargs):
+ return self.process.wait(*args, **kwargs)
class Gdb(object):
def __init__(self):
@@ -78,10 +85,10 @@ class Gdb(object):
"""Wait for prompt."""
self.child.expect("\(gdb\)")
- def command(self, command):
+ def command(self, command, timeout=-1):
self.child.sendline(command)
- self.child.expect("\n")
- self.child.expect("\(gdb\)")
+ self.child.expect("\n", timeout=timeout)
+ self.child.expect("\(gdb\)", timeout=timeout)
return self.child.before.strip()
def c(self, wait=True):