Browse Source
They live in riscv-tests/debug now, since they also test gdb, and can be used to test other targets besides spike.pull/67/head
committed by
Andrew Waterman
8 changed files with 1 additions and 486 deletions
@ -1,47 +0,0 @@ |
|||
#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); |
|||
} |
|||
@ -1,27 +0,0 @@ |
|||
#include <stdio.h> |
|||
|
|||
char c = 'x'; |
|||
|
|||
void print_row(int length) |
|||
{ |
|||
for (int x=0; x<length; x++) { |
|||
printf("%c", c); |
|||
} |
|||
printf("\n"); |
|||
} |
|||
|
|||
int main() |
|||
{ |
|||
volatile int i = 42; |
|||
const char *text = "constant\n"; |
|||
int threshold = 7; |
|||
|
|||
// Wait for the debugger to get us out of this loop.
|
|||
while (i) |
|||
; |
|||
|
|||
printf("%s", text); |
|||
for (int y=0; y < 10; y++) { |
|||
print_row(y); |
|||
} |
|||
} |
|||
@ -1,225 +0,0 @@ |
|||
#!/usr/bin/python |
|||
|
|||
import os |
|||
import testlib |
|||
import unittest |
|||
import tempfile |
|||
import time |
|||
import random |
|||
import binascii |
|||
|
|||
class DeleteSpike(unittest.TestCase): |
|||
def tearDown(self): |
|||
del self.spike |
|||
|
|||
class InstantHaltTest(DeleteSpike): |
|||
def setUp(self): |
|||
self.binary = testlib.compile("debug.c") |
|||
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.spike.port) |
|||
|
|||
def test_instant_halt(self): |
|||
self.assertEqual(0x1000, self.gdb.p("$pc")) |
|||
# For some reason instret resets to 0. |
|||
self.assertLess(self.gdb.p("$instret"), 8) |
|||
self.gdb.command("stepi") |
|||
self.assertNotEqual(0x1000, self.gdb.p("$pc")) |
|||
|
|||
def test_change_pc(self): |
|||
"""Change the PC right as we come out of reset.""" |
|||
# 0x13 is nop |
|||
self.gdb.command("p *((int*) 0x80000000)=0x13") |
|||
self.gdb.command("p *((int*) 0x80000004)=0x13") |
|||
self.gdb.command("p *((int*) 0x80000008)=0x13") |
|||
self.gdb.command("p $pc=0x80000000") |
|||
self.gdb.command("stepi") |
|||
self.assertEqual(0x80000004, self.gdb.p("$pc")) |
|||
self.gdb.command("stepi") |
|||
self.assertEqual(0x80000008, self.gdb.p("$pc")) |
|||
|
|||
class DebugTest(DeleteSpike): |
|||
def setUp(self): |
|||
self.binary = testlib.compile("debug.c") |
|||
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.spike.port) |
|||
|
|||
def test_turbostep(self): |
|||
"""Single step a bunch of times.""" |
|||
self.gdb.command("p i=0"); |
|||
last_pc = None |
|||
for _ in range(100): |
|||
self.gdb.command("stepi") |
|||
pc = self.gdb.command("p $pc") |
|||
self.assertNotEqual(last_pc, pc) |
|||
last_pc = pc |
|||
|
|||
def test_exit(self): |
|||
self.gdb.command("p i=0"); |
|||
output = self.gdb.command("c") |
|||
self.assertIn("Continuing", output) |
|||
self.assertIn("Remote connection closed", output) |
|||
|
|||
def test_breakpoint(self): |
|||
self.gdb.command("p i=0"); |
|||
self.gdb.command("b print_row") |
|||
# The breakpoint should be hit exactly 10 times. |
|||
for i in range(10): |
|||
output = self.gdb.command("c") |
|||
self.assertIn("Continuing", output) |
|||
self.assertIn("length=%d" % i, output) |
|||
self.assertIn("Breakpoint 1", output) |
|||
output = self.gdb.command("c") |
|||
self.assertIn("Continuing", output) |
|||
self.assertIn("Remote connection closed", output) |
|||
|
|||
def test_registers(self): |
|||
self.gdb.command("p i=0"); |
|||
# Try both forms to test gdb. |
|||
for cmd in ("info all-registers", "info registers all"): |
|||
output = self.gdb.command(cmd) |
|||
self.assertNotIn("Could not", output) |
|||
for reg in ('zero', 'ra', 'sp', 'gp', 'tp'): |
|||
self.assertIn(reg, output) |
|||
# mcpuid is one of the few registers that should have the high bit set |
|||
# (for rv64). |
|||
# Leave this commented out until gdb and spike agree on the encoding of |
|||
# mcpuid (which is going to be renamed to misa in any case). |
|||
#self.assertRegexpMatches(output, ".*mcpuid *0x80") |
|||
|
|||
# The instret register should always be changing. |
|||
last_instret = None |
|||
for _ in range(5): |
|||
instret = self.gdb.p("$instret") |
|||
self.assertNotEqual(instret, last_instret) |
|||
last_instret = instret |
|||
self.gdb.command("stepi") |
|||
|
|||
def test_interrupt(self): |
|||
"""Sending gdb ^C while the program is running should cause it to halt.""" |
|||
self.gdb.c(wait=False) |
|||
time.sleep(0.1) |
|||
self.gdb.interrupt() |
|||
self.gdb.command("p i=123"); |
|||
self.gdb.c(wait=False) |
|||
time.sleep(0.1) |
|||
self.gdb.interrupt() |
|||
self.gdb.command("p i=0"); |
|||
output = self.gdb.c() |
|||
self.assertIn("Continuing", output) |
|||
self.assertIn("Remote connection closed", output) |
|||
|
|||
class RegsTest(DeleteSpike): |
|||
def setUp(self): |
|||
self.binary = testlib.compile("regs.s") |
|||
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.spike.port) |
|||
|
|||
def test_write_gprs(self): |
|||
# Note a0 is missing from this list since it's used to hold the |
|||
# address. |
|||
regs = ("ra", "sp", "gp", "tp", "t0", "t1", "t2", "fp", "s1", |
|||
"a1", "a2", "a3", "a4", "a5", "a6", "a7", "s2", "s3", "s4", |
|||
"s5", "s6", "s7", "s8", "s9", "s10", "s11", "t3", "t4", "t5", |
|||
"t6") |
|||
|
|||
self.gdb.command("p $pc=write_regs") |
|||
for i, r in enumerate(regs): |
|||
self.gdb.command("p $%s=%d" % (r, (0xdeadbeef<<i)+17)) |
|||
self.gdb.command("p $a0=data") |
|||
self.gdb.command("b all_done") |
|||
output = self.gdb.command("c") |
|||
self.assertIn("Breakpoint 1", output) |
|||
|
|||
# Just to get this data in the log. |
|||
self.gdb.command("x/30gx data") |
|||
self.gdb.command("info registers") |
|||
for n in range(len(regs)): |
|||
self.assertEqual(self.gdb.x("data+%d" % (8*n), 'g'), |
|||
(0xdeadbeef<<n)+17) |
|||
|
|||
def test_write_csrs(self): |
|||
# As much a test of gdb as of the simulator. |
|||
self.gdb.p("$mscratch=0") |
|||
self.gdb.stepi() |
|||
self.assertEqual(self.gdb.p("$mscratch"), 0) |
|||
self.gdb.p("$mscratch=123") |
|||
self.gdb.stepi() |
|||
self.assertEqual(self.gdb.p("$mscratch"), 123) |
|||
|
|||
self.gdb.command("p $fflags=9") |
|||
self.gdb.command("p $pc=write_regs") |
|||
self.gdb.command("p $a0=data") |
|||
self.gdb.command("b all_done") |
|||
self.gdb.command("c") |
|||
|
|||
self.assertEqual(9, self.gdb.p("$fflags")) |
|||
self.assertEqual(9, self.gdb.p("$x1")) |
|||
self.assertEqual(9, self.gdb.p("$csr1")) |
|||
|
|||
class DownloadTest(DeleteSpike): |
|||
def setUp(self): |
|||
length = 2**20 |
|||
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 i in range(length / 16): |
|||
fd.write(" /* 0x%04x */ " % (i * 16)); |
|||
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(DeleteSpike): |
|||
def setUp(self): |
|||
self.binary = testlib.compile("mprv.S", "-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) |
|||
self.gdb.command("load") |
|||
|
|||
def test_mprv(self): |
|||
"""Test that the debugger can access memory when MPRV is set.""" |
|||
self.gdb.c(wait=False) |
|||
self.gdb.interrupt() |
|||
output = self.gdb.command("p/x *(int*)(((char*)&data)-0x80000000)") |
|||
self.assertIn("0xbead", output) |
|||
|
|||
if __name__ == '__main__': |
|||
# TROUBLESHOOTING TIPS |
|||
# If a particular test fails, run just that one test, eg.: |
|||
# ./tests/gdbserver.py MprvTest.test_mprv |
|||
# Then inspect gdb.log and spike.log to see what happened in more detail. |
|||
unittest.main() |
|||
@ -1,38 +0,0 @@ |
|||
#include "../riscv/encoding.h" |
|||
#define PGSHIFT 12 |
|||
|
|||
.global _start |
|||
|
|||
.section .text |
|||
_start: |
|||
# Set up a page table entry that maps 0x0... to 0x8... |
|||
la t0, page_table |
|||
srli t0, t0, PGSHIFT |
|||
csrw CSR_SPTBR, t0 |
|||
|
|||
# update mstatus |
|||
csrr t1, CSR_MSTATUS |
|||
li t0, (MSTATUS_MPRV | (VM_SV39 << 24)) |
|||
#li t0, ((VM_SV39 << 24)) |
|||
or t1, t0, t1 |
|||
csrw CSR_MSTATUS, t1 |
|||
|
|||
la t0, (loop - 0x80000000) |
|||
csrw CSR_MEPC, t0 |
|||
|
|||
# Exit supervisor mode, entering user mode at loop. |
|||
mret |
|||
|
|||
loop: |
|||
la t0, data |
|||
lw t1, 0(t0) |
|||
j loop |
|||
|
|||
.section .data |
|||
data: |
|||
.word 0xbead |
|||
|
|||
.balign 0x1000 |
|||
page_table: |
|||
.word ((0x80000000 >> 2) | PTE_V | PTE_U | PTE_R | PTE_W | PTE_X) |
|||
.word 0 |
|||
@ -1,43 +0,0 @@ |
|||
.global main |
|||
main: |
|||
j main |
|||
|
|||
write_regs: |
|||
sd x1, 0(a0) |
|||
sd x2, 8(a0) |
|||
sd x3, 16(a0) |
|||
sd x4, 24(a0) |
|||
sd x5, 32(a0) |
|||
sd x6, 40(a0) |
|||
sd x7, 48(a0) |
|||
sd x8, 56(a0) |
|||
sd x9, 64(a0) |
|||
sd x11, 72(a0) |
|||
sd x12, 80(a0) |
|||
sd x13, 88(a0) |
|||
sd x14, 96(a0) |
|||
sd x15, 104(a0) |
|||
sd x16, 112(a0) |
|||
sd x17, 120(a0) |
|||
sd x18, 128(a0) |
|||
sd x19, 136(a0) |
|||
sd x20, 144(a0) |
|||
sd x21, 152(a0) |
|||
sd x22, 160(a0) |
|||
sd x23, 168(a0) |
|||
sd x24, 176(a0) |
|||
sd x25, 184(a0) |
|||
sd x26, 192(a0) |
|||
sd x27, 200(a0) |
|||
sd x28, 208(a0) |
|||
sd x29, 216(a0) |
|||
sd x30, 224(a0) |
|||
sd x31, 232(a0) |
|||
|
|||
csrr x1, 1 # fflags |
|||
|
|||
all_done: |
|||
j all_done |
|||
|
|||
data: |
|||
.fill 64, 8, 0 |
|||
@ -1,92 +0,0 @@ |
|||
OUTPUT_ARCH( "riscv" ) |
|||
|
|||
ENTRY( _start ) |
|||
|
|||
SECTIONS |
|||
{ |
|||
|
|||
/*--------------------------------------------------------------------*/ |
|||
/* Code and read-only segment */ |
|||
/*--------------------------------------------------------------------*/ |
|||
|
|||
/* Begining of code and text segment */ |
|||
/* Leave some space for pk's data structures, which includes tohost/fromhost |
|||
* which are special addresses we ought to leave alone. */ |
|||
. = 0x80010000; |
|||
_ftext = .; |
|||
PROVIDE( eprol = . ); |
|||
|
|||
.text : |
|||
{ |
|||
*(.text.init) |
|||
} |
|||
|
|||
/* text: Program code section */ |
|||
.text : |
|||
{ |
|||
*(.text) |
|||
*(.text.*) |
|||
*(.gnu.linkonce.t.*) |
|||
} |
|||
|
|||
/* rodata: Read-only data */ |
|||
.rodata : |
|||
{ |
|||
*(.rdata) |
|||
*(.rodata) |
|||
*(.rodata.*) |
|||
*(.gnu.linkonce.r.*) |
|||
} |
|||
|
|||
/* End of code and read-only segment */ |
|||
PROVIDE( etext = . ); |
|||
_etext = .; |
|||
|
|||
/*--------------------------------------------------------------------*/ |
|||
/* Initialized data segment */ |
|||
/*--------------------------------------------------------------------*/ |
|||
|
|||
/* Start of initialized data segment */ |
|||
. = ALIGN(16); |
|||
_fdata = .; |
|||
|
|||
/* data: Writable data */ |
|||
.data : |
|||
{ |
|||
*(.data) |
|||
*(.data.*) |
|||
*(.srodata*) |
|||
*(.gnu.linkonce.d.*) |
|||
*(.comment) |
|||
} |
|||
|
|||
/* End of initialized data segment */ |
|||
. = ALIGN(4); |
|||
PROVIDE( edata = . ); |
|||
_edata = .; |
|||
|
|||
/*--------------------------------------------------------------------*/ |
|||
/* Uninitialized data segment */ |
|||
/*--------------------------------------------------------------------*/ |
|||
|
|||
/* Start of uninitialized data segment */ |
|||
. = .; |
|||
_fbss = .; |
|||
|
|||
/* sbss: Uninitialized writeable small data section */ |
|||
. = .; |
|||
|
|||
/* bss: Uninitialized writeable data section */ |
|||
. = .; |
|||
_bss_start = .; |
|||
.bss : |
|||
{ |
|||
*(.bss) |
|||
*(.bss.*) |
|||
*(.sbss*) |
|||
*(.gnu.linkonce.b.*) |
|||
*(COMMON) |
|||
} |
|||
|
|||
_end = .; |
|||
} |
|||
@ -1,12 +0,0 @@ |
|||
.global _start |
|||
|
|||
_start: |
|||
la sp, stack_end |
|||
jal main |
|||
done: |
|||
j done |
|||
|
|||
.data |
|||
stack: |
|||
.fill 4096, 1, 0 |
|||
stack_end: |
|||
Loading…
Reference in new issue