It passes, but it's slow.
return false;
}
+ if (gs.read_debug_ram(DEBUG_RAM_SIZE / 4 - 1)) {
+ fprintf(stderr, "Exception happened while writing to 0x%lx -> 0x%lx\n",
+ vaddr, paddr);
+ }
+
offset += access_size;
if (offset >= length) {
gs.send_packet("OK");
return handle_halt_reason(packet);
case 'g':
return handle_general_registers_read(packet);
- case 'k':
- return handle_kill(packet);
+// case 'k':
+// return handle_kill(packet);
case 'm':
return handle_memory_read(packet);
// case 'M':
--- /dev/null
+#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);
+}
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)
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"))
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."""
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
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)
#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
OUTPUT_ARCH( "riscv" )
-ENTRY( main )
+ENTRY( _start )
SECTIONS
{
--- /dev/null
+ .global _start
+
+_start:
+ la sp, stack_end
+ jal main
+done:
+ j done
+
+ .data
+stack:
+ .fill 4096, 1, 0
+stack_end:
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):
"""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):