@@ -129,35 +129,250 @@ The default Chipyard designs instantiate the DTM configured to use JTAG (i.e. ``
129129 However, they also use TSI/Serialized-TL with FESVR in case the JTAG interface isn't used.
130130 This allows users to choose how to communicate with the DUT (use TSI or JTAG).
131131
132- Debugging with JTAG
133- ~~~~~~~~~~~~~~~~~~~
132+ Debugging with JTAG + GDB
133+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
134134
135- Roughly the steps to debug with JTAG in simulation are as follows:
135+ This section provides detailed instructions for using GNU debugger (GDB) to debug RISC-V programs running on the emulator, similar to debugging with Spike.
136136
137- 1. Build a Chipyard JTAG-enabled RTL design. Remember default Chipyard designs are JTAG ready.
137+ Generating the Remote Bit-Bang (RBB) Emulator
138+ +++++++++++++++++++++++++++++++++++++++++++++++++++
139+
140+ The objective of this section is to use GNU debugger to debug RISC-V programs running on the emulator in
141+ the same fashion as in `Spike <https://github.com/riscv/riscv-isa-sim#debugging-with-gdb >`_.
142+
143+ For that we need to add a Remote Bit-Bang client to the emulator. We can do so by extending our Config
144+ with ``JtagDTMSystem ``, which will add a ``DebugTransportModuleJTAG `` to the DUT and connect a ``SimJTAG ``
145+ module in the Test Harness. This will allow OpenOCD to interface with the emulator, and GDB can interface
146+ with OpenOCD. In the following example we add this Config alteration to
147+ ``src/main/scala/system/Configs.scala ``:
148+
149+ .. code-block :: scala
150+
151+ class DefaultConfigRBB extends Config(
152+ new WithJtagDTMSystem ++ new WithNBigCores(1) ++ new WithCoherentBusTopology ++ new BaseConfig)
153+
154+ class QuadCoreConfigRBB extends Config(
155+ new WithJtagDTMSystem ++ new WithNBigCores(4) ++ new WithCoherentBusTopology ++ new BaseConfig)
156+
157+ To build the emulator with ``DefaultConfigRBB `` configuration we use the command:
138158
139159.. code-block :: bash
140160
141- cd sims/verilator
142- # or
143- cd sims/vcs
161+ rocket-chip$ cd emulator
162+ emulator$ CONFIG=freechips.rocketchip.system.DefaultConfigRBB make
163+
164+ We can also build a debug version capable of generating VCD waveforms using the command:
165+
166+ .. code-block :: bash
167+
168+ emulator$ CONFIG=freechips.rocketchip.system.DefaultConfigRBB make debug
169+
170+ By default the emulator is generated under the name
171+ ``emulator-freechips.rocketchip.system-DefaultConfigRBB `` in the first case and
172+ ``emulator-freechips.rocketchip.system-DefaultConfigRBB-debug `` in the second.
173+
174+ Compiling and executing a custom program using the emulator
175+ ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
176+
177+ We suppose that ``helloworld `` is our program. You can use ``crt.S ``, ``syscalls.c ``, and the linker script
178+ ``test.ld `` to construct your own program (see
179+ `riscv-tests <https://github.com/riscv/riscv-tests >`_). Note that ``test.ld `` loads the program at
180+ ``0x80000000 `` so you will need ``-mcmodel=medany `` (see
181+ `The RISC-V Code Models <https://www.sifive.com/blog/2017/09/11/all-aboard-part-4-risc-v-code-models/ >`_).
182+
183+ .. code-block :: c
184+
185+ char text[] = "Vafgehpgvba frgf jnag gb or serr!";
144186
145- make CONFIG=RocketConfig
187+ // Don't use the stack, because sp isn't set up.
188+ volatile int wait = 1;
146189
147- 2. Run the simulation with remote bit-bang enabled. Since we hope to load/run the binary using JTAG,
148- we can pass ``none `` as a binary (prevents FESVR from loading the program). (Adapted from: https://github.com/chipsalliance/rocket-chip#3-launch-the-emulator)
190+ int main()
191+ {
192+ while (wait)
193+ ;
194+
195+ // Doesn't actually go on the stack, because there are lots of GPRs.
196+ int i = 0;
197+ while (text[i]) {
198+ char lower = text[i] | 32;
199+ if (lower >= 'a' && lower <= 'm')
200+ text[i] += 13;
201+ else if (lower > 'm' && lower <= 'z')
202+ text[i] -= 13;
203+ i++;
204+ }
205+
206+ while (!wait)
207+ ;
208+ }
209+
210+ First, we can test if this program executes correctly in the simpler emulator (non-RBB) before debugging:
149211
150212.. code-block :: bash
151213
152- # note: this uses Chipyard make invocation to run the simulation to properly wrap the simulation args
153- make CONFIG=RocketConfig BINARY=none SIM_FLAGS=" +jtag_rbb_enable=1 --rbb-port=9823" run-binary
214+ $ ./emulator-freechips.rocketchip.system-DefaultConfig helloworld
154215
155- 3. `Follow the instructions here to connect to the simulation using OpenOCD + GDB. <https://github.com/chipsalliance/rocket-chip#4-launch-openocd >`__
216+ Additional verbose information (clock cycle, pc, instruction being executed) can be printed:
217+
218+ .. code-block :: bash
219+
220+ $ ./emulator-freechips.rocketchip.system-DefaultConfig +verbose helloworld 2>&1 | spike-dasm
221+
222+ VCD output files can be obtained using the ``-debug `` version of the emulator and are specified using ``-v `` or
223+ ``--vcd=FILE `` arguments. A detailed log file of all executed instructions can also be obtained from the emulator:
224+
225+ .. code-block :: bash
226+
227+ $ ./emulator-freechips.rocketchip.system-DefaultConfig-debug +verbose -v output.vcd helloworld 2>&1 | spike-dasm > output.log
228+
229+ .. note ::
230+ Generated VCD waveforms and execution log files can be very voluminous depending on the size of the .elf file
231+ (i.e. code size + debugging symbols).
156232
157233.. note ::
158- This section was adapted from the instruction in Rocket Chip and riscv-isa-sim. For more information refer
159- to that documentation: `Rocket Chip GDB Docs <https://github.com/chipsalliance/rocket-chip#-debugging-with-gdb >`__,
160- `riscv-isa-sim GDB Docs <https://github.com/riscv/riscv-isa-sim#debugging-with-gdb >`__
234+ The time it takes the emulator to load your program depends on executable size. Stripping the .elf executable
235+ will unsurprisingly make it run faster. For this you can use ``$RISCV/bin/riscv64-unknown-elf-strip `` tool to
236+ reduce the size. This is good for accelerating your simulation but not for debugging.
237+
238+ .. warning ::
239+ The HTIF communication interface between our system and the emulator relies on ``tohost `` and ``fromhost ``
240+ symbols to communicate. If you try to run a totally stripped executable on the emulator, you may get:
241+
242+ .. code-block :: text
243+
244+ $ ./emulator-freechips.rocketchip.system-DefaultConfig totally-stripped-helloworld
245+ This emulator compiled with JTAG Remote Bitbang client. To enable, use +jtag_rbb_enable=1.
246+ Listening on port 46529
247+ warning: tohost and fromhost symbols not in ELF; can't communicate with target
248+
249+ To resolve this, we need to strip all the .elf executable but keep ``tohost `` and ``fromhost `` symbols:
250+
251+ .. code-block :: bash
252+
253+ $ riscv64-unknown-elf-strip -s -Kfromhost -Ktohost helloworld
254+
255+ More details on the GNU strip tool can be found
256+ `here <https://www.thegeekstuff.com/2012/09/strip-command-examples/ >`_.
257+
258+ The interest of this step is to make sure your program executes well. To perform debugging you need the original
259+ unstripped version, as explained in the following steps.
260+
261+ Launch the emulator
262+ +++++++++++++++++++++++++
263+
264+ First, do not forget to compile your program with ``-g -Og `` flags to provide debugging support.
265+
266+ We can then launch the Remote Bit-Bang enabled emulator with:
267+
268+ .. code-block :: bash
269+
270+ ./emulator-freechips.rocketchip.system-DefaultConfigRBB +jtag_rbb_enable=1 --rbb-port=9823 helloworld
271+
272+ .. note ::
273+ You can also use the ``emulator-freechips.rocketchip.system-DefaultConfigRBB-debug `` version instead if you
274+ would like to generate VCD waveforms.
275+
276+ .. note ::
277+ If the argument ``--rbb-port `` is not passed, a default free TCP port on your computer will be chosen randomly.
278+
279+ .. note ::
280+ When debugging with GDB, the .elf file is not actually loaded by the FESVR. In contrast with Spike, it must
281+ be loaded from GDB as explained in step 5. So the ``helloworld `` argument may be replaced by any dummy name.
282+
283+ Launch OpenOCD
284+ ++++++++++++++++++++
285+
286+ You will need a RISC-V Enabled OpenOCD binary. This is installed with rocket-tools in ``$(RISCV)/bin/openocd ``,
287+ or can be compiled manually from riscv-openocd. OpenOCD requires a configuration file, in which we define the RBB
288+ port we will use, which is in our case ``9823 ``.
289+
290+ .. code-block :: tcl
291+
292+ interface remote_bitbang
293+ remote_bitbang_host localhost
294+ remote_bitbang_port 9823
295+
296+ set _CHIPNAME riscv
297+ jtag newtap $_CHIPNAME cpu -irlen 5
298+
299+ set _TARGETNAME $_CHIPNAME.cpu
300+ target create $_TARGETNAME riscv -chain-position $_TARGETNAME
301+
302+ gdb_report_data_abort enable
303+
304+ init
305+ halt
306+
307+ Then we launch OpenOCD in another terminal using the command:
308+
309+ .. code-block :: bash
310+
311+ $( RISCV) /bin/openocd -f ./cemulator.cfg
312+
313+ .. note ::
314+ A ``-d `` flag can be added to the command to show further debug information.
315+
316+ Launch GDB
317+ +++++++++++++++++
318+
319+ In another terminal launch GDB and point to the elf file you would like to load then run it with the debugger
320+ (in this example, ``helloworld ``):
321+
322+ .. code-block :: bash
323+
324+ $ riscv64-unknown-elf-gdb helloworld
325+
326+ Compared to Spike, the C Emulator is very slow, so several problems may be encountered due to timeouts between
327+ issuing commands and response from the emulator. To solve this problem, we increase the timeout with the GDB
328+ ``set remotetimeout `` command.
329+
330+ After that we load our program by performing a ``load `` command. This automatically sets the ``$PC `` to the
331+ ``_start `` symbol in our .elf file:
332+
333+ .. code-block :: none
334+
335+ (gdb) set remotetimeout 2000
336+ (gdb) target remote localhost:3333
337+ Remote debugging using localhost:3333
338+ 0x0000000000010050 in ?? ()
339+ (gdb) load
340+ Loading section .text.init, size 0x2cc lma 0x80000000
341+ Loading section .tohost, size 0x48 lma 0x80001000
342+ Loading section .text, size 0x98c lma 0x80001048
343+ Loading section .rodata, size 0x158 lma 0x800019d4
344+ Loading section .rodata.str1.8, size 0x20 lma 0x80001b30
345+ Loading section .data, size 0x22 lma 0x80001b50
346+ Loading section .sdata, size 0x4 lma 0x80001b74
347+ Start address 0x80000000, load size 3646
348+ Transfer rate: 40 bytes/sec, 520 bytes/write.
349+
350+ Now we can proceed as with Spike, debugging works in a similar way:
351+
352+ .. code-block :: none
353+
354+ (gdb) print wait
355+ $1 = 1
356+ (gdb) print wait=0
357+ $2 = 0
358+ (gdb) print text
359+ $3 = "Vafgehpgvba frgf jnag gb or serr!"
360+ (gdb) c
361+ Continuing.
362+
363+ ^C
364+ Program received signal SIGINT, Interrupt.
365+ main (argc=0, argv=<optimized out>) at src/main.c:33
366+ 33 while (!wait)
367+ (gdb) print wait
368+ $4 = 0
369+ (gdb) print text
370+ $5 = "Instruction sets want to be free!"
371+
372+ For more information on GDB debugging, refer to:
373+
374+ * `GDB User Manual <https://sourceware.org/gdb/onlinedocs/gdb/ >`_
375+ * `GDB Remote Debugging <https://sourceware.org/gdb/onlinedocs/gdb/Remote-Debugging.html#Remote-Debugging >`_
161376
162377Example Test Chip Bringup Communication
163378---------------------------------------
0 commit comments