Browse Source

Remove generic debug tests. (#65)

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
Tim Newsome 10 years ago
committed by Andrew Waterman
parent
commit
de9ebf704e
  1. 3
      Makefile.in
  2. 47
      tests/checksum.c
  3. 27
      tests/debug.c
  4. 225
      tests/gdbserver.py
  5. 38
      tests/mprv.S
  6. 43
      tests/regs.s
  7. 92
      tests/standalone.lds
  8. 12
      tests/start.S

3
Makefile.in

@ -121,8 +121,7 @@ INSTALL_EXE := $(INSTALL) -m 555
STOW := @stow@
# Tests
bintests = $(src_dir)/tests/gdbserver.py \
$(src_dir)/tests/ebreak.py
bintests = $(src_dir)/tests/ebreak.py
#-------------------------------------------------------------------------
# Include subproject makefile fragments

47
tests/checksum.c

@ -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);
}

27
tests/debug.c

@ -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);
}
}

225
tests/gdbserver.py

@ -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()

38
tests/mprv.S

@ -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

43
tests/regs.s

@ -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

92
tests/standalone.lds

@ -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 = .;
}

12
tests/start.S

@ -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…
Cancel
Save