-
Notifications
You must be signed in to change notification settings - Fork 7
/
ORPSoC_RTL_simulation_debugging.mw
172 lines (90 loc) · 10.5 KB
/
ORPSoC_RTL_simulation_debugging.mw
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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
= Introduction =
This page contains tips on how to debug the operation of an ORPSoC system under RTL simulation.
= Development environment setup =
The following assumes the user already [[ORPSoC#Download_ORPSoC|has a copy of the ORPSoC source]] and be attempting to run either the ORPSoC reference build (in the root of the project) from <code>PROJECT_ROOT/sim/run</code> or be attempting to simulate a particular board, in which case they will be in <code>$PROJECT_ROOT/boards/FPGA_VENDOR/BOARD_NAME/sim/run</code>.
The [[OpenRISC_GNU_tool_chain | OpenRISC GNU toolchain]] must be installed and ready to go, too.
The following details will rely on the user having the [[EDA#GTKWave | GTKWave]] waveform viewer installed, or have a suitable alternative setup.
== Check setup ==
A good test of the setup is to attempt to run tests in the reference design in <code>$PROJECT_ROOT/sim/run</code> with something like:
/path/to/orpsocv2/sim/run$ make rtl-test
Confirm the test compiles and runs and exits OK. A successful run of the simulation will finish with the following lines:
report (0x8000000d);
exit(00000000)
== If in doubt, clean it out ==
If things are not behaving correctly, it's advised to try a clean out of everything, which will remove all intermediate and resulting files from previous simulation builds.
From any <code>sim/run</code> directory run
/path/to/any/sim/run$ make distclean
= Starting simulation =
The very first simulation to run would be the <code>or1200-simple</code> test.
This test just goes through the processor initialisation, into the main loop of the C code and exits, reporting success. This test checks that part of the fundamentals of the system are in place - that is the processor can start, fetch code, access data and exit the simulation gracefully.
This simulation is typically the default one when no other test is specified for the <code>make rtl-test</code> command.
= Running a simulation and dumping a waveform (VCD) =
A convenient way of debugging the system is by looking a waveform of what is occurring on the bus.
This can be done by adding the <code>VCD=1</code> option to the command line when running the simulation.
/path/to/sim/run$ make rtl-test VCD=1
The VCD will be created in <code>/path/to/sim/out/test-name.vcd</code>.
When the VCD option is enabled, it will be indicated to the user, like the following:
* VCD in ../out/or1200-simple.vcd
VCD info: dumpfile ../out/or1200-simple.vcd opened for output.
Running a simulation and generating a VCD will generally slow its execution time down as it must write out the system state at each step to the VCD file.
Once a simulation has run and finished, the VCD file can be opened with [[EDA#GTKWave | GTKWave]] like so:
/path/to/sim/run$ gtkwave ../out/test-name/vcd
= Debugging system startup =
Outlined here are some basic steps to help double check the system starts OK under RTL simulation.
== Run a simulation, dump a VCD ==
The first step to looking at the internal function of the system is to run a simulation and dump out a waveform. Do this by running the simulation with the <code>VCD=1</code> option on the end of the make command as [[#Running a simulation and dumping a waveform (VCD) | mentioned above]].
Open the VCD in the waveform viewer like [[EDA#GTKWave | GTKWave]].
== Preload memories ==
A common method used to speed up notoriously slow RTL simulations is to preload the system's main memory with the software image to execute.
This feature is provided when simulating all board ports in ORPSoC as a way to allow quick testing of system functions without repeating the lengthy boot-from-non-volatile memory sequences.
The usual way of enabling this is to add <code>PRELOAD_RAM=1</code> to the command line when launching a simulation.
/path/to/sim/run$ make rtl-test PRELOAD_RAM=1
Note that this will usually also change the [[#bootrom | bootrom]] code to simply start execution from the reset vector in main memory.
== Check clocks and resets ==
If you are implementing a new ORPSoC board port, or have significantly altered an existing one, double check the system's clock and resets. If none of the clocking or reset configuration has been altered, then skip this step.
An ORPSoC build should have all of its clock and reset-generation infrastructure inside a build-specific module named <code>clkgen</code>. This is typically instantiated inside the ORPSoC top-level as <code>clkgen0</code>.
Double check all is well with this module - that is the clock supplied by the testbench is there, and is the right frequency. A mistake when working on new board ports is to have an incorrect timescale set in the top-level testbench (<code>/path/to/bench/verilog/orpsoc_testbench.v</code> which results in the clock being supplied to a PLL model being much too fast (or too slow) and odd behaviour, like a PLL not locking, can be seen.
Resets that are incorrect polarity, or even X'd, will also cause problems.
Double check everything going in and coming out to the internal system is OK.
Note that this is just an RTL simulation and although things might look OK here, it's not neccessarily the case that what is done in clkgen is synthesizable or correct for use on FPGA or in silicon. If problems with clocks or resets are suspected on the board, then check this module at gatelevel. This is not covered here.
== Check processor boot ==
Double checking the processor is starting up OK requires ensuring most of the basics of the system are OK.
In ORPSoC, a commonly used boot mechanism is implemented in the <code>bootrom</code> module. This provides some instructions that perform some basic bootstrapping of the processor. The routine used can be configured by a <code>#define</code> in the <code>/path/to/sw/board/include/board.h</code> software header file.
The bootrom usually causes the processor to access main memory and/or a non-volatile memory to load or start executing a program.
For this to function correctly, the processor must be configured appropriately, the system bus must be implemented correctly, and the various memory controllers and simulation models need to be instantiated and configured correctly.
The following steps help to check this is the case.
=== bootrom ===
The system typically starts by executing some code out of the <code>bootrom</code> module. This module is typically on the processor's instruction bus at address <code>0xf0000100</code> and will contain 40-50 instructions - enough to do some basic bootstrapping.
The details of the bootrom are not covered here, but probably should be at some point [[ORPSoC_bootrom | here]].
=== Processor instruction bus ===
When the processor is taken out of reset, it begins to fetch instructions from its reset address.
For the OR1200, this can be either <code>0xf000100</code> or <code>0x100</code>. If the [[#bootrom | bootrom]] is being used then it is usually <code>0xf0000100</code>.
In the waveform, descend into the <code>orpsoc_top</code> module - usually represented as <code>dut</code> in waveform viewers as this is its instantiated name.
Add the following signals to the waveform to view the processor's instruction Wishbone bus port.
wbm_i_or1200_ack_i
wbm_i_or1200_dat_i
wbm_i_or1200_err_i
wbm_i_or1200_adr_o
wbm_i_or1200_stb_o
It may also help to see the processor's clock and reset signals:
or1200_clk
or1200_rst
[[File:Orpsoc_or1200_boot_1.png]]
Once the reset is deasserted the processor can be seen to fetch instructions by asserting the <code>wbm_i_or1200_stb_o</code> line and presenting the address it wants on the <code>wbm_i_or1200_adr_o</code> line.
The instruction bus only reads, so every access is a read request from a memory. Each time the <code>wbm_i_or1200_ack_i</code> signal is high for a cycle indicates that the data on <code>wbm_i_or1200_dat_i</code> is valid.
If the <code>wbm_i_or1200_err_i</code> line is ever high, it usually means an invalid read request was put out by the processor, usually to anon-existing address on the bus. This will cause the bus to go to its bus exception vector code at <code>0x200</code>.
=== Bus arbiters and memory controllers ===
Depending on the configuration of the system, the processor's instruction bus requests will end up going through an arbiter and then onto a memory controller.
==== Bus arbiter problems ====
If it looks like the processor's instruction requests are sane, and problems are encountered, then the next place to check is the system's bus arbiter or the memory controller.
The bus arbiter can be ruled out simply by looking at the input bus to the memory controller is the same as what is being generated on the processor's instruction bus. If the input to the appropriate memory controller is not the same as what's coming from the processor (ie. the address is not the same) then check the configuration of the bus wires, the bus arbiter, or its internal function.
==== Memory controller, model, preload problems ====
If the bus' function looks OK then problems can be isolated to the memory controller, memory model or preloading mechanism.
Of course, it's possible the bootrom is not correctly configured for the system and it is attempting to access a non-existant non-volatile memory controller, or for some reason the [[#Preload memories | PRELOAD_RAM=1]] option is not getting into the bootrom and it is attempting an unexpected boot sequence.
=== Debugging strategies ===
Although it can be tedious, it helps to present all of the relevant signals in the instruction fetch path and ensure each is being completed correctly.
This means dumping the bus signals from the processor, the bus signals into the memory controller, the memory bus signals to the memory model and potentially internals of the memory controller.
An understanding of the mapping of the instructions to the memory's external bus helps to quickly identify problems with the content of the image has been preloaded into the memory model.
If the problem occurs well into boot, most memory models provide a verbose debug output option which will report exactly what is being fetched from what address to help follow the program's execution.
The OR1200 will also generate an execution log in <code>/path/to/sim/out/test-name-executed.log</code>. This file will contain the state of the processor for each instruction executed.
The OR1200 will also generate an instruction execution time log in <code>/path/to/sim/out/test-name-lookup.log</code>. This file will contain the time of each of the instructions executed which can be used in conjunction with the execution log to lookup what time, and thus where in the waveform, a particular instruction was fetched (either from cache or on the bus) and executed.