1 |
69 |
zero_gravi |
<<<
|
2 |
|
|
:sectnums:
|
3 |
|
|
== Debugging using the On-Chip Debugger
|
4 |
|
|
|
5 |
|
|
The NEORV32 on-chip debugger allows _online_ in-system debugging via an external JTAG access port from a
|
6 |
|
|
host machine. The general flow is independent of the host machine's operating system. However, this tutorial uses
|
7 |
|
|
Windows and Linux (Ubuntu on Windows) in parallel.
|
8 |
|
|
|
9 |
|
|
[TIP]
|
10 |
|
|
See datasheet section https://stnolting.github.io/neorv32/#_on_chip_debugger_ocd[On Chip Debugger (OCD)]
|
11 |
|
|
for more information.
|
12 |
|
|
|
13 |
|
|
[NOTE]
|
14 |
|
|
This tutorial uses `gdb` to **directly upload an executable** to the processor. If you are using the default
|
15 |
|
|
processor setup _with_ internal instruction memory (IMEM) make sure it is implemented as RAM
|
16 |
|
|
(_INT_BOOTLOADER_EN_ generic = true).
|
17 |
|
|
|
18 |
|
|
[IMPORTANT]
|
19 |
|
|
The on-chip debugger is only implemented if the _ON_CHIP_DEBUGGER_EN_ generic is set _true_. Furthermore, it requires
|
20 |
|
|
the `Zicsr` and `Zifencei` CPU extension to be implemented (top generics _CPU_EXTENSION_RISCV_Zicsr_
|
21 |
|
|
and _CPU_EXTENSION_RISCV_Zifencei_ = true).
|
22 |
|
|
|
23 |
|
|
|
24 |
|
|
:sectnums:
|
25 |
|
|
=== Hardware Requirements
|
26 |
|
|
|
27 |
|
|
Make sure the on-chip debugger of your NEORV32 setups is implemented (_ON_CHIP_DEBUGGER_EN_ generic = true).
|
28 |
|
|
Connect a JTAG adapter to the NEORV32 `jtag_*` interface signals. If you do not have a full-scale JTAG adapter, you can
|
29 |
|
|
also use a FTDI-based adapter like the "FT2232H-56Q Mini Module", which is a simple and inexpensive FTDI breakout board.
|
30 |
|
|
|
31 |
|
|
.JTAG pin mapping
|
32 |
|
|
[cols="^3,^2,^2"]
|
33 |
|
|
[options="header",grid="rows"]
|
34 |
|
|
|=======================
|
35 |
|
|
| NEORV32 top signal | JTAG signal | FTDI port
|
36 |
|
|
| `jtag_tck_i` | TCK | D0
|
37 |
|
|
| `jtag_tdi_i` | TDI | D1
|
38 |
|
|
| `jtag_tdo_o` | TDO | D2
|
39 |
|
|
| `jtag_tms_i` | TMS | D3
|
40 |
|
|
| `jtag_trst_i` | TRST | D4
|
41 |
|
|
|=======================
|
42 |
|
|
|
43 |
|
|
[TIP]
|
44 |
|
|
The low-active JTAG _test reset_ (TRST) signals is _optional_ as a reset can also be triggered via the TAP controller.
|
45 |
|
|
If TRST is not used make sure to pull the signal _high_.
|
46 |
|
|
|
47 |
|
|
|
48 |
|
|
:sectnums:
|
49 |
|
|
=== OpenOCD
|
50 |
|
|
|
51 |
|
|
The NEORV32 on-chip debugger can be accessed using the https://github.com/riscv/riscv-openocd[RISC-V port of OpenOCD].
|
52 |
|
|
Prebuilt binaries can be obtained - for example - from https://www.sifive.com/software[SiFive]. A pre-configured
|
53 |
|
|
OpenOCD configuration file (`sw/openocd/openocd_neorv32.cfg`) is available that allows easy access to the NEORV32 CPU.
|
54 |
|
|
|
55 |
|
|
[NOTE]
|
56 |
|
|
You might need to adapt `ftdi_vid_pid`, `ftdi_channel` and `ftdi_layout_init` in `sw/openocd/openocd_neorv32.cfg`
|
57 |
|
|
according to your interface chip and your operating system.
|
58 |
|
|
|
59 |
|
|
[TIP]
|
60 |
|
|
If you want to modify the JTAG clock speed (via `adapter speed` in `sw/openocd/openocd_neorv32.cfg`) make sure to meet
|
61 |
|
|
the clock requirements noted in https://stnolting.github.io/neorv32/#_debug_module_dm[Documentation: Debug Transport Module (DTM)].
|
62 |
|
|
|
63 |
|
|
To access the processor using OpenOCD, open a terminal and start OpenOCD with the pre-configured configuration file.
|
64 |
|
|
|
65 |
|
|
.Connecting via OpenOCD (on Windows)
|
66 |
|
|
[source, bash]
|
67 |
|
|
--------------------------
|
68 |
|
|
N:\Projects\neorv32\sw\openocd>openocd -f openocd_neorv32.cfg
|
69 |
|
|
Open On-Chip Debugger 0.11.0-rc1+dev (SiFive OpenOCD 0.10.0-2020.12.1)
|
70 |
|
|
Licensed under GNU GPL v2
|
71 |
|
|
For bug reports:
|
72 |
|
|
https://github.com/sifive/freedom-tools/issues
|
73 |
|
|
1
|
74 |
|
|
Info : Listening on port 6666 for tcl connections
|
75 |
|
|
Info : Listening on port 4444 for telnet connections
|
76 |
|
|
Info : clock speed 1000 kHz
|
77 |
|
|
Info : JTAG tap: neorv32.cpu tap/device found: 0x0cafe001 (mfg: 0x000 (), part: 0xcafe, ver: 0x0)
|
78 |
|
|
Info : datacount=1 progbufsize=2
|
79 |
|
|
Info : Disabling abstract command reads from CSRs.
|
80 |
|
|
Info : Examined RISC-V core; found 1 harts
|
81 |
|
|
Info : hart 0: XLEN=32, misa=0x40801105
|
82 |
|
|
Info : starting gdb server for neorv32.cpu.0 on 3333
|
83 |
|
|
Info : Listening on port 3333 for gdb connections
|
84 |
|
|
--------------------------
|
85 |
|
|
|
86 |
|
|
OpenOCD has successfully connected to the NEORV32 on-chip debugger and has examined the CPU (showing the content of
|
87 |
|
|
the `misa` CSRs). Now you can use `gdb` to connect via port 3333.
|
88 |
|
|
|
89 |
|
|
|
90 |
|
|
:sectnums:
|
91 |
|
|
=== Debugging with GDB
|
92 |
|
|
|
93 |
|
|
This guide uses the simple "blink example" from `sw/example/blink_led` as simplified test application to
|
94 |
|
|
show the basics of in-system debugging.
|
95 |
|
|
|
96 |
|
|
At first, the application needs to be compiled. We will use the minimal machine architecture configuration
|
97 |
|
|
(`rv32i`) here to be independent of the actual processor/CPU configuration.
|
98 |
|
|
Navigate to `sw/example/blink_led` and compile the application:
|
99 |
|
|
|
100 |
|
|
.Compile the test application
|
101 |
|
|
[source, bash]
|
102 |
|
|
--------------------------
|
103 |
|
|
.../neorv32/sw/example/blink_led$ make MARCH=rv32i USER_FLAGS+=-g clean_all all
|
104 |
|
|
--------------------------
|
105 |
|
|
|
106 |
|
|
.Adding debug symbols to the executable
|
107 |
|
|
[NOTE]
|
108 |
|
|
`USER_FLAGS+=-g` passes the `-g` flag to the compiler so it adds debug information/symbols
|
109 |
|
|
to the generated ELF file. This is optional but will provide more sophisticated information for debugging
|
110 |
|
|
(like source file line numbers).
|
111 |
|
|
|
112 |
|
|
This will generate an ELF file `main.elf` that contains all the symbols required for debugging.
|
113 |
|
|
Furthermore, an assembly listing file `main.asm` is generated that we will use to define breakpoints.
|
114 |
|
|
|
115 |
|
|
Open another terminal in `sw/example/blink_led` and start `gdb`.
|
116 |
|
|
The GNU debugger is part of the toolchain (see <<_software_toolchain_setup>>).
|
117 |
|
|
|
118 |
|
|
.Starting GDB (on Linux (Ubuntu on Windows))
|
119 |
|
|
[source, bash]
|
120 |
|
|
--------------------------
|
121 |
|
|
.../neorv32/sw/example/blink_led$ riscv32-unknown-elf-gdb
|
122 |
|
|
GNU gdb (GDB) 10.1
|
123 |
|
|
Copyright (C) 2020 Free Software Foundation, Inc.
|
124 |
|
|
License GPLv3+: GNU GPL version 3 or later
|
125 |
|
|
This is free software: you are free to change and redistribute it.
|
126 |
|
|
There is NO WARRANTY, to the extent permitted by law.
|
127 |
|
|
Type "show copying" and "show warranty" for details.
|
128 |
|
|
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv32-unknown-elf".
|
129 |
|
|
Type "show configuration" for configuration details.
|
130 |
|
|
For bug reporting instructions, please see:
|
131 |
|
|
.
|
132 |
|
|
Find the GDB manual and other documentation resources online at:
|
133 |
|
|
.
|
134 |
|
|
|
135 |
|
|
For help, type "help".
|
136 |
|
|
Type "apropos word" to search for commands related to "word".
|
137 |
|
|
(gdb)
|
138 |
|
|
--------------------------
|
139 |
|
|
|
140 |
|
|
Now connect to OpenOCD using the default port 3333 on your machine.
|
141 |
|
|
We will use the previously generated ELF file `main.elf` from the `blink_led` example.
|
142 |
|
|
Finally, upload the program to the processor and start debugging.
|
143 |
|
|
|
144 |
|
|
[NOTE]
|
145 |
|
|
The executable that is uploaded to the processor is **not** the default NEORV32 executable (`neorv32_exe.bin`) that
|
146 |
|
|
is used for uploading via the bootloader. Instead, all the required sections (like `.text`) are extracted from `mail.elf`
|
147 |
|
|
by GDB and uploaded via the debugger's indirect memory access.
|
148 |
|
|
|
149 |
|
|
.Running GDB
|
150 |
|
|
[source, bash]
|
151 |
|
|
--------------------------
|
152 |
|
|
(gdb) target extended-remote localhost:3333 <1>
|
153 |
|
|
Remote debugging using localhost:3333
|
154 |
|
|
warning: No executable has been specified and target does not support
|
155 |
|
|
determining executable automatically. Try using the "file" command.
|
156 |
|
|
0xffff0c94 in ?? () <2>
|
157 |
|
|
(gdb) file main.elf <3>
|
158 |
|
|
A program is being debugged already.
|
159 |
|
|
Are you sure you want to change the file? (y or n) y
|
160 |
|
|
Reading symbols from main.elf...
|
161 |
|
|
(gdb) load <4>
|
162 |
|
|
Loading section .text, size 0xd0c lma 0x0
|
163 |
|
|
Loading section .rodata, size 0x39c lma 0xd0c
|
164 |
|
|
Start address 0x00000000, load size 4264
|
165 |
|
|
Transfer rate: 43 KB/sec, 2132 bytes/write.
|
166 |
|
|
(gdb)
|
167 |
|
|
--------------------------
|
168 |
|
|
<1> Connect to OpenOCD
|
169 |
|
|
<2> The CPU was still executing code from the bootloader ROM - but that does not matter here
|
170 |
|
|
<3> Select `mail.elf` from the `blink_led` example
|
171 |
|
|
<4> Upload the executable
|
172 |
|
|
|
173 |
|
|
After the upload, GDB will make the processor jump to the beginning of the uploaded executable
|
174 |
|
|
(by default, this is the beginning of the instruction memory at `0x00000000`) skipping the bootloader
|
175 |
|
|
and halting the CPU right before executing the `blink_led` application.
|
176 |
|
|
|
177 |
|
|
|
178 |
|
|
:sectnums:
|
179 |
|
|
==== Breakpoint Example
|
180 |
|
|
|
181 |
|
|
The following steps are just a small showcase that illustrate a simple debugging scheme.
|
182 |
|
|
|
183 |
|
|
While compiling `blink_led`, an assembly listing file `main.asm` was generated.
|
184 |
|
|
Open this file with a text editor to check out what the CPU is going to do when resumed.
|
185 |
|
|
|
186 |
|
|
The `blink_led` example implements a simple counter on the 8 lowest GPIO output ports. The program uses
|
187 |
|
|
"busy wait" to have a visible delay between increments. This waiting is done by calling the `neorv32_cpu_delay_ms`
|
188 |
|
|
function. We will add a _breakpoint_ right at the end of this wait function so we can step through the iterations
|
189 |
|
|
of the counter.
|
190 |
|
|
|
191 |
|
|
.Cut-out from `main.asm` generated from the `blink_led` example
|
192 |
|
|
[source, assembly]
|
193 |
|
|
--------------------------
|
194 |
|
|
00000688 <__neorv32_cpu_delay_ms_end>:
|
195 |
|
|
688: 01c12083 lw ra,28(sp)
|
196 |
|
|
68c: 02010113 addi sp,sp,32
|
197 |
|
|
690: 00008067 ret
|
198 |
|
|
--------------------------
|
199 |
|
|
|
200 |
|
|
The very last instruction of the `neorv32_cpu_delay_ms` function is `ret` (= return)
|
201 |
|
|
at hexadecimal `690` in this example. Add this address as _breakpoint_ to GDB.
|
202 |
|
|
|
203 |
|
|
[NOTE]
|
204 |
|
|
The address might be different if you use a different version of the software framework or
|
205 |
|
|
if different ISA options are configured.
|
206 |
|
|
|
207 |
|
|
.Adding a GDB breakpoint
|
208 |
|
|
[source, bash]
|
209 |
|
|
--------------------------
|
210 |
|
|
(gdb) b * 0x690
|
211 |
|
|
Breakpoint 1 at 0x690
|
212 |
|
|
--------------------------
|
213 |
|
|
|
214 |
|
|
.How do breakpoints work?
|
215 |
|
|
[TIP]
|
216 |
|
|
The NEORV32 on-chip debugger does not provide any hardware breakpoints (RISC-V "trigger modules") that compare an address like the PC
|
217 |
|
|
with a predefined value. Instead, gdb will modify the actual executable in IMEM: the actual instruction at the address
|
218 |
|
|
of the specified breakpoint is replaced by a `break` / `c.break` instruction. Whenever execution reaches this instruction, debug mode is
|
219 |
|
|
re-entered and the debugger restores the original instruction at this address to maintain original program behavior.
|
220 |
|
|
|
221 |
|
|
Now execute `c` (= continue). The CPU will resume operation until it hits the break-point.
|
222 |
|
|
By this we can "step" from increment to increment.
|
223 |
|
|
|
224 |
|
|
.Iterating from breakpoint to breakpoint
|
225 |
|
|
[source, bash]
|
226 |
|
|
--------------------------
|
227 |
|
|
Breakpoint 1 at 0x690
|
228 |
|
|
(gdb) c
|
229 |
|
|
Continuing.
|
230 |
|
|
|
231 |
|
|
Breakpoint 1, 0x00000690 in neorv32_cpu_delay_ms ()
|
232 |
|
|
(gdb) c
|
233 |
|
|
Continuing.
|
234 |
|
|
|
235 |
|
|
Breakpoint 1, 0x00000690 in neorv32_cpu_delay_ms ()
|
236 |
|
|
(gdb) c
|
237 |
|
|
Continuing.
|
238 |
|
|
--------------------------
|