Contents

Rocket RISC-V processor - Debugging a program

The idea is to debug a simple program on an emulated Rocket. The procedure is well defined on the officiel Rocket repository. This post basically summarizes the needed steps.

Generating the emulator

Let’s say you have a default rocket-chip repository. You need to add a Remote Bit-Bang client in the emulator by modifying src/main/scala/system/Configs.scala:

1
2
3
4
5
@@ -86,3 +86,4 @@ class MMIOPortOnlyConfig extends Config(
 
 class BaseFPGAConfig extends Config(new BaseConfig ++ new WithCoherentBusTopology)
 class DefaultFPGAConfig extends Config(new WithNSmallCores(1) ++ new BaseFPGAConfig)
+class DefaultConfigRBB extends Config(new WithJtagDTMSystem ++ new WithNBigCores(1) ++ new WithCoherentBusTopology ++ new BaseConfig)

Building the emulator

1
2
rocket-chip$ cd emulator
emulator$ CONFIG=freechips.rocketchip.system.DefaultConfigRBB make

Compiling a test program

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
char text[] = "Vafgehpgvba frgf jnag gb or serr!";

// Don't use the stack, because sp isn't set up.
volatile int wait = 1;

int main()
{
    while (wait)
        ;

    // Doesn't actually go on the stack, because there are lots of GPRs.
    int i = 0;
    while (text[i]) {
        char lower = text[i] | 32;
        if (lower >= 'a' && lower <= 'm')
            text[i] += 13;
        else if (lower > 'm' && lower <= 'z')
            text[i] -= 13;
        i++;
    }

    while (!wait)
        ;
}

This C code (which performs a ROT13 transformation) can be saved in a hello_world.c file. In order to compile it, it is assumed to the same settings as for riscv-tests. In this case, it is assumed we modified this C code and that debug symbols were added in the Makefile.

1
2
3
4
5
6
@@ -28,7 +28,7 @@ custom = \
 
 RISCV_PREFIX ?= riscv$(XLEN)-unknown-elf-
 RISCV_GCC ?= $(RISCV_PREFIX)gcc
-RISCV_GCC_OPTS ?= -DPREALLOCATE=1 -mcmodel=medany -static -std=gnu99 -O2 -ffast-math -fno-common -fno-builtin-printf -fno-tree-loop-distribute-patterns
+RISCV_GCC_OPTS ?= -DPREALLOCATE=1 -mcmodel=medany -static -std=gnu99 -O2 -ffast-math -fno-common -fno-builtin-printf -fno-tree-loop-distribute-patterns -g -0g

Then:

1
2
3
4
$ pwd                                  
~/riscv-tests/benchmarks_custom
$ make clean
$ make

It will generate an hello_world.riscv binary ready to be debugged.

Launching the emulator

Three terminals are needed:

1. The emulator

1
2
3
4
$ ./emulator-freechips.rocketchip.system-DefaultConfigRBB +jtag_rbb_enable=1 --rbb-port=9823 helloworld
This emulator compiled with JTAG Remote Bitbang client. To enable, use +jtag_rbb_enable=1.
Listening on port 9823
Attempting to accept client socket

2. The on-chip debugger

A configuration file cemulator.cfg is needed:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
interface remote_bitbang
remote_bitbang_host localhost
remote_bitbang_port 9823

set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5

set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME riscv -chain-position $_TARGETNAME

gdb_report_data_abort enable

init
halt

Note: You may need to modify bitbang_port if the emulator in step 1 gives you another number.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
$ /opt/riscv_rocket/bin/./openocd -f cemulator.cfg                                                                                  
Open On-Chip Debugger 0.10.0+dev-00849-gcbb15587d (2023-04-07-15:22)
Licensed under GNU GPL v2
For bug reports, read
	http://openocd.org/doc/doxygen/bugs.html
Info : only one transport option; autoselect 'jtag'
Info : Initializing remote_bitbang driver
Info : Connecting to localhost:9823
Info : remote_bitbang driver initialized
Info : This adapter doesn't support configurable speed
Info : JTAG tap: riscv.cpu tap/device found: 0x00000001 (mfg: 0x000 (<invalid>), part: 0x0000, ver: 0x0)
Info : datacount=2 progbufsize=16
Info : Disabling abstract command reads from CSRs.
Info : Examined RISC-V core; found 1 harts
Info :  hart 0: XLEN=64, misa=0x800000000094112d
Info : Listening on port 3333 for gdb connections
Info : Listening on port 6666 for tcl connections
Info : Listening on port 4444 for telnet connections
Info : accepting 'gdb' connection on tcp/3333

Note: it is assumed the toolchain was compiled from the rocket-tools repository.

3. The GDB debugger

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
$ riscv64-unknown-elf-gdb ~/riscv-tests/benchmarks_custom/hello_world.riscv
GNU gdb (GDB) 8.3.50.20190920-git
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Type "show copying" and "show warranty" for details.
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv64-unknown-elf".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
    <http://www.gnu.org/software/gdb/documentation/>.

For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ~/riscv-tests/benchmarks_custom/hello_world.riscv...
(gdb) set remotetimeout 2000
(gdb) target remote localhost:3333
Remote debugging using localhost:3333
0x000000008000237a in syscall (which=64, arg0=1, arg2=12, arg1=2147494400) at ./common/syscalls.c:28
28	  while (fromhost == 0)
(gdb) load
Loading section .text.init, size 0x1c2 lma 0x80000000
Loading section .tohost, size 0x48 lma 0x80001000
Loading section .text, size 0x734 lma 0x80002000
Loading section .text.startup, size 0x80 lma 0x80002734
Loading section .rodata, size 0x158 lma 0x800027b4
Loading section .rodata.str1.8, size 0x41 lma 0x80002910
Loading section .data, size 0x22 lma 0x80002958
Loading section .sdata, size 0x4 lma 0x8000297c
Start address 0x0000000080000000, load size 2941
Transfer rate: 18 bytes/sec, 367 bytes/write.
(gdb) print wait
$1 = 1
(gdb) print wait=0
$2 = 0
(gdb) print text
$3 = "Vafgehpgvba frgf jnag gb or serr!"
(gdb) c
Continuing.
keep_alive() was not invoked in the 1000ms timelimit. GDB alive packet not sent! (2277). Workaround: increase "set remotetimeout" in GDB
keep_alive() was not invoked in the 1000ms timelimit. GDB alive packet not sent! (2729). Workaround: increase "set remotetimeout" in GDB
^C
Program received signal SIGINT, Interrupt.
main () at ./hello_world/hello_world.c:22
22	    while (!wait)
(gdb) print wait
$4 = 0
(gdb) print text
$5 = "Instruction sets want to be free!"
(gdb) 

The session should finally look like:

../img/rocket-debug.png

References