1 |
60 |
zero_gravi |
Let's Get It Started!
|
2 |
|
|
|
3 |
|
|
To make your NEORV32 project run, follow the guides from the upcoming sections. Follow these guides
|
4 |
|
|
step by step and in the presented order.
|
5 |
|
|
|
6 |
|
|
:sectnums:
|
7 |
|
|
== Toolchain Setup
|
8 |
|
|
|
9 |
|
|
There are two possibilities to get the actual RISC-V GCC toolchain:
|
10 |
|
|
|
11 |
|
|
1. Download and _build_ the official RISC-V GNU toolchain yourself
|
12 |
|
|
2. Download and install a prebuilt version of the toolchain
|
13 |
|
|
|
14 |
|
|
[NOTE]
|
15 |
|
|
The default toolchain prefix for this project is **`riscv32-unknown-elf`**. Of course you can use any other RISC-V
|
16 |
|
|
toolchain (like `riscv64-unknown-elf`) that is capable to emit code for a `rv32` architecture. Just change the _RISCV_TOOLCHAIN_ variable in the application
|
17 |
|
|
makefile(s) according to your needs or define this variable when invoking the makefile.
|
18 |
|
|
|
19 |
|
|
[IMPORTANT]
|
20 |
|
|
Keep in mind that – for instance – a rv32imc toolchain only provides library code compiled with
|
21 |
|
|
compressed (_C_) and `mul`/`div` instructions (_M_)! Hence, this code cannot be executed (without
|
22 |
|
|
emulation) on an architecture without these extensions!
|
23 |
|
|
|
24 |
|
|
|
25 |
|
|
:sectnums:
|
26 |
|
|
=== Building the Toolchain from Scratch
|
27 |
|
|
|
28 |
|
|
To build the toolchain by yourself you can follow the guide from the official https://github.com/riscv/riscvgnu-toolchain GitHub page.
|
29 |
|
|
|
30 |
|
|
The official RISC-V repository uses submodules. You need the `--recursive` option to fetch the submodules
|
31 |
|
|
automatically:
|
32 |
|
|
|
33 |
|
|
[source,bash]
|
34 |
|
|
----
|
35 |
|
|
$ git clone --recursive https://github.com/riscv/riscv-gnu-toolchain
|
36 |
|
|
----
|
37 |
|
|
|
38 |
|
|
Download and install the prerequisite standard packages:
|
39 |
|
|
|
40 |
|
|
[source,bash]
|
41 |
|
|
----
|
42 |
|
|
$ sudo apt-get install autoconf automake autotools-dev curl python3 libmpc-dev libmpfrdev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev
|
43 |
|
|
----
|
44 |
|
|
|
45 |
|
|
To build the Linux cross-compiler, pick an install path. If you choose, say, `/opt/riscv`, then add
|
46 |
|
|
`/opt/riscv/bin` to your `PATH` variable.
|
47 |
|
|
|
48 |
|
|
[source,bash]
|
49 |
|
|
----
|
50 |
|
|
$ export PATH=$PATH:/opt/riscv/bin
|
51 |
|
|
----
|
52 |
|
|
|
53 |
|
|
Then, simply run the following commands and configuration in the RISC-V GNU toolchain source folder to compile a
|
54 |
|
|
`rv32i` toolchain:
|
55 |
|
|
|
56 |
|
|
[source,bash]
|
57 |
|
|
----
|
58 |
|
|
riscv-gnu-toolchain$ ./configure --prefix=/opt/riscv --with-arch=rv32i –-with-abi=ilp32
|
59 |
|
|
riscv-gnu-toolchain$ make
|
60 |
|
|
----
|
61 |
|
|
|
62 |
|
|
After a while you will get `riscv32-unknown-elf-gcc` and all of its friends in your `/opt/riscv/bin` folder.
|
63 |
|
|
|
64 |
|
|
|
65 |
|
|
:sectnums:
|
66 |
|
|
=== Downloading and Installing a Prebuilt Toolchain
|
67 |
|
|
|
68 |
|
|
Alternatively, you can download a prebuilt toolchain.
|
69 |
|
|
|
70 |
|
|
**Use The Toolchain I have Build**
|
71 |
|
|
|
72 |
|
|
I have compiled the toolchain on a 64-bit x86 Ubuntu (Ubuntu on Windows, actually) and uploaded it to
|
73 |
|
|
GitHub. You can directly download the according toolchain archive as single _zip-file_ within a packed
|
74 |
|
|
release from github.com/stnolting/riscv-gcc-prebuilt.
|
75 |
|
|
|
76 |
|
|
Unpack the downloaded toolchain archive and copy the content to a location in your file system (e.g.
|
77 |
|
|
`/opt/riscv`). More information about downloading and installing my prebuilt toolchains can be found in
|
78 |
|
|
the repository's README.
|
79 |
|
|
|
80 |
|
|
**Use a Third Party Toolchain**
|
81 |
|
|
|
82 |
|
|
Of course you can also use any other prebuilt version of the toolchain. There are a lot RISC-V GCC packages out there -
|
83 |
|
|
even for Windows.
|
84 |
|
|
|
85 |
|
|
[IMPORTANT]
|
86 |
|
|
Make sure the toolchain can (also) emit code for a `rv32i` architecture, uses the `ilp32` or `ilp32e` ABI and **was not build** using
|
87 |
|
|
CPU extensions that are not supported by the NEORV32 (like `D`).
|
88 |
|
|
|
89 |
|
|
|
90 |
|
|
:sectnums:
|
91 |
|
|
=== Installation
|
92 |
|
|
|
93 |
|
|
Now you have the binaries. The last step is to add them to your `PATH` environment variable (if you have not
|
94 |
|
|
already done so). Make sure to add the binaries folder (`bin`) of your toolchain.
|
95 |
|
|
|
96 |
|
|
[source,bash]
|
97 |
|
|
----
|
98 |
|
|
$ export PATH:$PATH:/opt/riscv/bin
|
99 |
|
|
----
|
100 |
|
|
|
101 |
|
|
You should add this command to your `.bashrc` (if you are using bash) to automatically add the RISC-V
|
102 |
|
|
toolchain at every console start.
|
103 |
|
|
|
104 |
|
|
:sectnums:
|
105 |
|
|
=== Testing the Installation
|
106 |
|
|
|
107 |
|
|
To make sure everything works fine, navigate to an example project in the NEORV32 example folder and
|
108 |
|
|
execute the following command:
|
109 |
|
|
|
110 |
|
|
[source,bash]
|
111 |
|
|
----
|
112 |
|
|
neorv32/sw/example/blink_led$ make check
|
113 |
|
|
----
|
114 |
|
|
|
115 |
|
|
This will test all the tools required for the NEORV32. Everything is working fine if "Toolchain check OK" appears at the end.
|
116 |
|
|
|
117 |
|
|
|
118 |
|
|
|
119 |
|
|
<<<
|
120 |
|
|
// ####################################################################################################################
|
121 |
|
|
:sectnums:
|
122 |
|
|
== General Hardware Setup
|
123 |
|
|
|
124 |
|
|
The following steps are required to generate a bitstream for your FPGA board. If you want to run the
|
125 |
|
|
NEORV32 processor in simulation only, the following steps might also apply.
|
126 |
|
|
|
127 |
|
|
[TIP]
|
128 |
|
|
Check out the example setups in the `boards` folder (@GitHub: https://github.com/stnolting/neorv32/tree/master/boards), which provides script-based
|
129 |
|
|
demo projects for various FPGA boars.
|
130 |
|
|
|
131 |
|
|
In this tutorial we will use a test implementation of the processor – using many of the processor's optional
|
132 |
|
|
modules but just propagating the minimal signals to the outer world. Hence, this guide is intended as
|
133 |
|
|
evaluation or "hello world" project to check out the NEORV32. A little note: The order of the following
|
134 |
|
|
steps might be a little different for your specific EDA tool.
|
135 |
|
|
|
136 |
|
|
[start=0]
|
137 |
|
|
. Create a new project with your FPGA EDA tool of choice.
|
138 |
|
|
. Add all VHDL files from the project's `rtl/core` folder to your project. Make sure to _reference_ the
|
139 |
|
|
files only – do not copy them.
|
140 |
|
|
. Make sure to add all the rtl files to a new library called **`neorv32`**. If your FPGA tools does not
|
141 |
|
|
provide a field to enter the library name, check out the "properties" menu of the rtl files.
|
142 |
|
|
. The `rtl/core/neorv32_top.vhd` VHDL file is the top entity of the NEORV32 processor. If you
|
143 |
|
|
already have a design, instantiate this unit into your design and proceed.
|
144 |
|
|
. If you do not have a design yet and just want to check out the NEORV32 – no problem! In this guide
|
145 |
|
|
we will use a simplified top entity, that encapsulated the actual processor top entity: add the
|
146 |
|
|
`rtl/core/top_templates/neorv32_test_setup.vhd` VHDL file to your project too, and
|
147 |
|
|
select it as top entity.
|
148 |
|
|
. This test setup provides a minimal test hardware setup:
|
149 |
|
|
|
150 |
|
|
.NEORV32 "hello world" test setup
|
151 |
|
|
image::neorv32_test_setup.png[align=center]
|
152 |
|
|
|
153 |
|
|
[start=7]
|
154 |
|
|
. This test setup only implements some very basic processor and CPU features. Also, only the
|
155 |
|
|
minimum number of signals is propagated to the outer world. Please note that the reset input signal
|
156 |
|
|
`rstn_i` is **low-active**.
|
157 |
|
|
. The configuration of the NEORV32 processor is done using the generics of the instantiated processor
|
158 |
|
|
top entity. Let's keep things simple at first and use the default configuration:
|
159 |
|
|
|
160 |
|
|
.Cut-out of `neorv32_test_setup.vhd` showing the processor instance and its configuration
|
161 |
|
|
[source,vhdl]
|
162 |
|
|
----
|
163 |
|
|
neorv32_top_inst: neorv32_top
|
164 |
|
|
generic map (
|
165 |
|
|
-- General --
|
166 |
|
|
CLOCK_FREQUENCY => 100000000, -- in Hz # <1>
|
167 |
|
|
BOOTLOADER_EN => true,
|
168 |
|
|
USER_CODE => x"00000000",
|
169 |
|
|
...
|
170 |
|
|
-- Internal instruction memory --
|
171 |
|
|
MEM_INT_IMEM_EN => true,
|
172 |
|
|
MEM_INT_IMEM_SIZE => 16*1024, # <2>
|
173 |
|
|
MEM_INT_IMEM_ROM => false,
|
174 |
|
|
-- Internal data memory --
|
175 |
|
|
MEM_INT_DMEM_EN => true,
|
176 |
|
|
MEM_INT_DMEM_SIZE => 8*1024, # <3>
|
177 |
|
|
...
|
178 |
|
|
----
|
179 |
|
|
<1> Clock frequency of `clk_i` in Hertz
|
180 |
|
|
<2> Default size of internal instruction memory: 16kB (no need to change that _now_)
|
181 |
|
|
<3> Default size of internal data memory: 8kB (no need to change that _now_)
|
182 |
|
|
|
183 |
|
|
[start=9]
|
184 |
|
|
. There is one generic that has to be set according to your FPGA / board: The clock frequency of the
|
185 |
|
|
top's clock input signal (`clk_i`). Use the _CLOCK_FREQUENC_Y generic to specify your clock source's
|
186 |
|
|
frequency in Hertz (Hz) (note "1").
|
187 |
|
|
. If you feel like it – or if your FPGA does not provide so many resources – you can modify the
|
188 |
|
|
**memory sizes** (_MEM_INT_IMEM_SIZE_ and _MEM_INT_DMEM_SIZE_ – marked with notes "2" and "3") or even
|
189 |
|
|
exclude certain ISa extensions and peripheral modules from implementation - but as mentioned above, let's keep things
|
190 |
|
|
simple at first and use the standard configuration for now.
|
191 |
|
|
|
192 |
|
|
[NOTE]
|
193 |
|
|
Keep the internal instruction and data memory sizes in mind – these values are required for setting
|
194 |
|
|
up the software framework in the next section <<_general_software_framework_setup>>.
|
195 |
|
|
|
196 |
|
|
[start=11]
|
197 |
|
|
. Depending on your FPGA tool of choice, it is time to assign the signals of the test setup top entity to
|
198 |
|
|
the according pins of your FPGA board. All the signals can be found in the entity declaration:
|
199 |
|
|
|
200 |
|
|
.Entity signals of `neorv32_test_setup.vhd`
|
201 |
|
|
[source,vhdl]
|
202 |
|
|
----
|
203 |
|
|
entity neorv32_test_setup is
|
204 |
|
|
port (
|
205 |
|
|
-- Global control --
|
206 |
|
|
clk_i : in std_ulogic := '0'; -- global clock, rising edge
|
207 |
|
|
rstn_i : in std_ulogic := '0'; -- global reset, low-active, async
|
208 |
|
|
-- GPIO --
|
209 |
|
|
gpio_o : out std_ulogic_vector(7 downto 0); -- parallel output
|
210 |
|
|
-- UART0 --
|
211 |
|
|
uart0_txd_o : out std_ulogic; -- UART0 send data
|
212 |
|
|
uart0_rxd_i : in std_ulogic := '0' -- UART0 receive data
|
213 |
|
|
);
|
214 |
|
|
end neorv32_test_setup;
|
215 |
|
|
----
|
216 |
|
|
|
217 |
|
|
[start=12]
|
218 |
|
|
. Attach the clock input `clk_i` to your clock source and connect the reset line `rstn_i` to a button of
|
219 |
|
|
your FPGA board. Check whether it is low-active or high-active – the reset signal of the processor is
|
220 |
|
|
**low-active**, so maybe you need to invert the input signal.
|
221 |
|
|
. If possible, connected at least bit `0` of the GPIO output port `gpio_o` to a high-active LED (invert
|
222 |
|
|
the signal when your LEDs are low-active) - this LED will be used as status LED by the bootloader.
|
223 |
|
|
. Finally, connect the primary UART's (UART0) communication signals `uart0_txd_o` and
|
224 |
|
|
`uart0_rxd_i` to your serial host interface (USB-to-serial converter).
|
225 |
|
|
. Perform the project HDL compilation (synthesis, mapping, bitstream generation).
|
226 |
|
|
. Download the generated bitstream into your FPGA ("program" it) and press the reset button (just to
|
227 |
|
|
make sure everything is sync).
|
228 |
|
|
. Done! If you have assigned the bootloader status LED , it should be
|
229 |
|
|
flashing now and you should receive the bootloader start prompt in your UART console (check the baudrate!).
|
230 |
|
|
|
231 |
|
|
|
232 |
|
|
|
233 |
|
|
<<<
|
234 |
|
|
// ####################################################################################################################
|
235 |
|
|
:sectnums:
|
236 |
|
|
== General Software Framework Setup
|
237 |
|
|
|
238 |
|
|
While your synthesis tool is crunching the NEORV32 HDL files, it is time to configure the project's software
|
239 |
|
|
framework for your processor hardware setup.
|
240 |
|
|
|
241 |
|
|
[start=1]
|
242 |
|
|
. You need to tell the linker the actual size of the processor's instruction and data memories. This has to be always sync
|
243 |
|
|
to the *hardware memory configuration* (done in section <<_general_hardware_setup>>).
|
244 |
|
|
. Open the NEORV32 linker script `sw/common/neorv32.ld` with a text editor. Right at the
|
245 |
|
|
beginning of the linker script you will find the **MEMORY** configuration showing two regions: `rom` and `ram`
|
246 |
|
|
|
247 |
|
|
.Cut-out of the linker script `neorv32.ld`: Memory configuration
|
248 |
|
|
[source,c]
|
249 |
|
|
----
|
250 |
|
|
MEMORY
|
251 |
|
|
{
|
252 |
|
|
rom (rx) : ORIGIN = DEFINED(make_bootloader) ? 0xFFFF0000 : 0x00000000, LENGTH = DEFINED(make_bootloader) ? 4*1024 : 16*1024 # <1>
|
253 |
|
|
ram (rwx) : ORIGIN = 0x80000000, LENGTH = 8*1024 # <2>
|
254 |
|
|
}
|
255 |
|
|
----
|
256 |
|
|
<1> Size of internal instruction memory (IMEM): 16kB
|
257 |
|
|
<2> Size of internal data memory (DMEM): 8kB
|
258 |
|
|
|
259 |
|
|
[WARNING]
|
260 |
|
|
The `rom` region provides conditional assignments (via the _make_bootloader_ symbol) for the _origin_
|
261 |
|
|
and the _length_ configuration depending on whether the executable is built as normal application (for the IMEM) or
|
262 |
|
|
as bootloader code (for the BOOTROM). To modify the IMEM configuration of the `rom` region,
|
263 |
|
|
make sure to **only edit the most right values** for `ORIGIN` and `LENGTH` (marked with notes "1" and "2").
|
264 |
|
|
|
265 |
|
|
[start=3]
|
266 |
|
|
. There are four parameters that are relevant here (only the right-most value for the `rom` section): The _origin_
|
267 |
|
|
and the _length_ of the instruction memory (region name `rom`) and the _origin_ and the _length_ of the data
|
268 |
|
|
memory (region name `ram`). These four parameters have to be always sync to your hardware memory
|
269 |
|
|
configuration as described in section <<_general_hardware_setup>>.
|
270 |
|
|
|
271 |
|
|
[IMPORTANT]
|
272 |
|
|
The `rom` _ORIGIN_ parameter has to be equal to the configuration of the NEORV32 ispace_base_c
|
273 |
|
|
(default: 0x00000000) VHDL package (`rtl/core/neorv32_package.vhd`) configuration constant. The `ram` _ORIGIN_ parameter has to
|
274 |
|
|
be equal to the configuration of the NEORV32 `dspace_base_c` (default: 0x80000000) VHDL
|
275 |
|
|
package (`rtl/core/neorv32_package.vhd`) configuration constant.
|
276 |
|
|
|
277 |
|
|
[IMPORTANT]
|
278 |
|
|
The `rom` _LENGTH_ and the `ram` _LENGTH_ parameters have to match the configured memory sizes. For
|
279 |
|
|
instance, if the system does not have any external memories connected, the `rom` _LENGTH_ parameter
|
280 |
|
|
has to be equal to the processor-internal IMEM size (defined via top's _MEM_INT_IMEM_SIZE_ generic)
|
281 |
|
|
and the `ram` _LENGTH_ parameter has to be equal to the processor-internal DMEM size (defined via top's
|
282 |
|
|
_MEM_INT_DMEM_SIZE_ generic).
|
283 |
|
|
|
284 |
|
|
|
285 |
|
|
|
286 |
|
|
<<<
|
287 |
|
|
// ####################################################################################################################
|
288 |
|
|
:sectnums:
|
289 |
|
|
== Application Program Compilation
|
290 |
|
|
|
291 |
|
|
[start=1]
|
292 |
|
|
. Open a terminal console and navigate to one of the project's example programs. For instance navigate to the
|
293 |
|
|
simple `sw/example_blink_led` example program. This program uses the NEORV32 GPIO unit to display
|
294 |
|
|
an 8-bit counter on the lowest eight bit of the `gpio_o` output port.
|
295 |
|
|
. To compile the project and generate an executable simply execute:
|
296 |
|
|
|
297 |
|
|
[source,bash]
|
298 |
|
|
----
|
299 |
|
|
neorv32/sw/example/blink_led$ make exe
|
300 |
|
|
----
|
301 |
|
|
|
302 |
|
|
[start=3]
|
303 |
|
|
. This will compile and link the application sources together with all the included libraries. At the end,
|
304 |
|
|
your application is transformed into an ELF file (`main.elf`). The *NEORV32 image generator* (in `sw/image_gen`) takes this file and creates a
|
305 |
|
|
final executable. The makefile will show the resulting memory utilization and the executable size:
|
306 |
|
|
|
307 |
|
|
[source,bash]
|
308 |
|
|
----
|
309 |
|
|
neorv32/sw/example/blink_led$ make exe
|
310 |
|
|
Memory utilization:
|
311 |
|
|
text data bss dec hex filename
|
312 |
|
|
852 0 0 852 354 main.elf
|
313 |
|
|
Executable (neorv32_exe.bin) size in bytes:
|
314 |
|
|
864
|
315 |
|
|
----
|
316 |
|
|
|
317 |
|
|
[start=4]
|
318 |
|
|
. That's it. The `exe` target has created the actual executable `neorv32_exe.bin` in the current
|
319 |
|
|
folder, which is ready to be uploaded to the processor via the bootloader's UART interface.
|
320 |
|
|
|
321 |
|
|
[TIP]
|
322 |
|
|
The compilation process will also create a `main.asm` assembly listing file in the project directory, which
|
323 |
|
|
shows the actual assembly code of the complete application.
|
324 |
|
|
|
325 |
|
|
|
326 |
|
|
|
327 |
|
|
<<<
|
328 |
|
|
// ####################################################################################################################
|
329 |
|
|
:sectnums:
|
330 |
|
|
== Uploading and Starting of a Binary Executable Image via UART
|
331 |
|
|
|
332 |
|
|
You have just created the executable. Now it is time to upload it to the processor. There are basically two
|
333 |
|
|
options to do so.
|
334 |
|
|
|
335 |
|
|
[TIP]
|
336 |
|
|
Executables can also be uploaded via the **on-chip debugger**.
|
337 |
|
|
See section <<_debugging_with_gdb>> for more information.
|
338 |
|
|
|
339 |
|
|
**Option 1**
|
340 |
|
|
|
341 |
|
|
The NEORV32 makefiles provide an upload target that allows to directly upload an executable from the
|
342 |
|
|
command line. Reset the processor and execute:
|
343 |
|
|
|
344 |
|
|
[source,bash]
|
345 |
|
|
----
|
346 |
|
|
sw/example/blink_led$ make COM_PORT=/dev/ttyUSB1 upload
|
347 |
|
|
----
|
348 |
|
|
|
349 |
|
|
Replace `/dev/ttyUSB1` with the actual serial port you are using to communicate with the processor. You
|
350 |
|
|
might have to use `sudo make ...` if the targeted device requires elevated access rights.
|
351 |
|
|
|
352 |
|
|
|
353 |
|
|
**Option 2**
|
354 |
|
|
|
355 |
|
|
The "better" option is to use a standard terminal program to upload an executable. This provides a more
|
356 |
|
|
comfortable way as you can directly interact with the bootloader console. Additionally, using a terminal program
|
357 |
|
|
also allows to directly communicate with the uploaded application.
|
358 |
|
|
|
359 |
|
|
[start=1]
|
360 |
|
|
. Connect the primary UART (UART0) interface of your FPGA board to a serial port of your
|
361 |
|
|
computer or use an USB-to-serial adapter.
|
362 |
|
|
. Start a terminal program. In this tutorial, I am using TeraTerm for Windows. You can download it from https://ttssh2.osdn.jp/index.html.en
|
363 |
|
|
|
364 |
|
|
[WARNING]
|
365 |
|
|
Make sure your terminal program can transfer the executable in raw byte mode without any protocol stuff around it.
|
366 |
|
|
|
367 |
|
|
[start=3]
|
368 |
|
|
. Open a connection to the corresponding srial port. Configure the terminal according to the
|
369 |
|
|
following parameters:
|
370 |
|
|
|
371 |
|
|
* 19200 Baud
|
372 |
|
|
* 8 data bits
|
373 |
|
|
* 1 stop bit
|
374 |
|
|
* no parity bits
|
375 |
|
|
* no transmission/flow control protocol! (just raw byte mode)
|
376 |
|
|
* newline on `\r\n` (carriage return & newline)
|
377 |
|
|
|
378 |
|
|
[start=4]
|
379 |
|
|
. Also make sure, that single chars are transmitted without any consecutive "new line" or "carriage
|
380 |
|
|
return" commands (this is highly dependent on your terminal application of choice, TeraTerm only
|
381 |
|
|
sends the raw chars by default).
|
382 |
|
|
. Press the NEORV32 reset button to restart the bootloader. The status LED starts blinking and the
|
383 |
|
|
bootloader intro screen appears in your console. Hurry up and press any key (hit space!) to abort the
|
384 |
|
|
automatic boot sequence and to start the actual bootloader user interface console.
|
385 |
|
|
|
386 |
|
|
.Bootloader console; aborted auto-boot sequence
|
387 |
|
|
[source,bash]
|
388 |
|
|
----
|
389 |
|
|
<< NEORV32 Bootloader >>
|
390 |
|
|
|
391 |
|
|
BLDV: Mar 23 2021
|
392 |
|
|
HWV: 0x01050208
|
393 |
|
|
CLK: 0x05F5E100
|
394 |
|
|
USER: 0x10000DE0
|
395 |
|
|
MISA: 0x40901105
|
396 |
|
|
ZEXT: 0x00000023
|
397 |
|
|
PROC: 0x0EFF0037
|
398 |
|
|
IMEM: 0x00004000 bytes @ 0x00000000
|
399 |
|
|
DMEM: 0x00002000 bytes @ 0x80000000
|
400 |
|
|
|
401 |
|
|
Autoboot in 8s. Press key to abort.
|
402 |
|
|
Aborted.
|
403 |
|
|
|
404 |
|
|
Available commands:
|
405 |
|
|
h: Help
|
406 |
|
|
r: Restart
|
407 |
|
|
u: Upload
|
408 |
|
|
s: Store to flash
|
409 |
|
|
l: Load from flash
|
410 |
|
|
e: Execute
|
411 |
|
|
CMD:>
|
412 |
|
|
----
|
413 |
|
|
|
414 |
|
|
[start=6]
|
415 |
|
|
. Execute the "Upload" command by typing `u`. Now the bootloader is waiting for a binary executable
|
416 |
|
|
to be send.
|
417 |
|
|
|
418 |
|
|
[source,bash]
|
419 |
|
|
----
|
420 |
|
|
CMD:> u
|
421 |
|
|
Awaiting neorv32_exe.bin...
|
422 |
|
|
----
|
423 |
|
|
|
424 |
|
|
[start=7]
|
425 |
|
|
. Use the "send file" option of your terminal program to transmit the previously generated binary executable `neorv32_exe.bin`.
|
426 |
|
|
. Again, make sure to transmit the executable in raw binary mode (no transfer protocol, no additional
|
427 |
|
|
header stuff). When using TeraTerm, select the "binary" option in the send file dialog.
|
428 |
|
|
. If everything went fine, OK will appear in your terminal:
|
429 |
|
|
|
430 |
|
|
[source,bash]
|
431 |
|
|
----
|
432 |
|
|
CMD:> u
|
433 |
|
|
Awaiting neorv32_exe.bin... OK
|
434 |
|
|
----
|
435 |
|
|
|
436 |
|
|
[start=10]
|
437 |
|
|
. The executable now resides in the instruction memory of the processor. To execute the program right
|
438 |
|
|
now run the "Execute" command by typing `e`:
|
439 |
|
|
|
440 |
|
|
[source,bash]
|
441 |
|
|
----
|
442 |
|
|
CMD:> u
|
443 |
|
|
Awaiting neorv32_exe.bin... OK
|
444 |
|
|
CMD:> e
|
445 |
|
|
Booting...
|
446 |
|
|
Blinking LED demo program
|
447 |
|
|
----
|
448 |
|
|
|
449 |
|
|
[start=11]
|
450 |
|
|
. Now you should see the LEDs counting.
|
451 |
|
|
|
452 |
|
|
|
453 |
|
|
|
454 |
|
|
<<<
|
455 |
|
|
// ####################################################################################################################
|
456 |
|
|
:sectnums:
|
457 |
|
|
== Setup of a New Application Program Project
|
458 |
|
|
|
459 |
|
|
Done with all the introduction tutorials and those example programs? Then it is time to start your own
|
460 |
|
|
application project!
|
461 |
|
|
|
462 |
|
|
[start=1]
|
463 |
|
|
. The easiest way of creating a *new* project is to make a copy of an *existing* project (like the
|
464 |
|
|
`blink_led` project) inside the `sw/example` folder. By this, all file dependencies are kept and you can
|
465 |
|
|
start coding and compiling.
|
466 |
|
|
. If you want to place the project folder somewhere else you need to adapt the project's makefile. In
|
467 |
|
|
the makefile you will find a variable that keeps the relative or absolute path to the NEORV32 home
|
468 |
|
|
folder. Just modify this variable according to your new project's home location:
|
469 |
|
|
|
470 |
|
|
[source,makefile]
|
471 |
|
|
----
|
472 |
|
|
# Relative or absolute path to the NEORV32 home folder (use default if not set by user)
|
473 |
|
|
NEORV32_HOME ?= ../../..
|
474 |
|
|
----
|
475 |
|
|
|
476 |
|
|
[start=3]
|
477 |
|
|
. If your project contains additional source files outside of the project folder, you can add them to the _APP_SRC_ variable:
|
478 |
|
|
|
479 |
|
|
[source,makefile]
|
480 |
|
|
----
|
481 |
|
|
# User's application sources (add additional files here)
|
482 |
|
|
APP_SRC = $(wildcard *.c) ../somewhere/some_file.c
|
483 |
|
|
----
|
484 |
|
|
|
485 |
|
|
[start=4]
|
486 |
|
|
. You also need to add the folder containing the include files of your new project to the _APP_INC variable_ (do not forget the `-I` prefix):
|
487 |
|
|
|
488 |
|
|
[source,makefile]
|
489 |
|
|
----
|
490 |
|
|
# User's application include folders (don't forget the '-I' before each entry)
|
491 |
|
|
APP_INC = -I . -I ../somewhere/include_stuff_folder
|
492 |
|
|
----
|
493 |
|
|
|
494 |
|
|
[start=5]
|
495 |
|
|
. If you feel like it, you can change the default optimization level:
|
496 |
|
|
|
497 |
|
|
[source,makefile]
|
498 |
|
|
----
|
499 |
|
|
# Compiler effort
|
500 |
|
|
EFFORT = -Os
|
501 |
|
|
----
|
502 |
|
|
|
503 |
|
|
[TIP]
|
504 |
|
|
All the assignments made to the makefile variable can also be done "inline" when invoking the makefile. For example: `$make EFFORT=-Os clean_all exe`
|
505 |
|
|
|
506 |
|
|
|
507 |
|
|
|
508 |
|
|
|
509 |
|
|
<<<
|
510 |
|
|
// ####################################################################################################################
|
511 |
|
|
:sectnums:
|
512 |
|
|
== Enabling RISC-V CPU Extensions
|
513 |
|
|
|
514 |
|
|
Whenever you enable/disable a RISC-V CPU extensions via the according _CPU_EXTENSION_RISCV_x_ generic, you need to
|
515 |
|
|
adapt the toolchain configuration so the compiler can actually generate according code for it.
|
516 |
|
|
|
517 |
|
|
To do so, open the makefile of your project (for example `sw/example/blink_led/makefile`) and scroll to the
|
518 |
|
|
"USER CONFIGURATION" section right at the beginning of the file. You need to modify the _MARCH_ variable and eventually
|
519 |
|
|
the _MABI_ variable according to your CPU hardware configuration.
|
520 |
|
|
|
521 |
|
|
[source,makefile]
|
522 |
|
|
----
|
523 |
|
|
# CPU architecture and ABI
|
524 |
|
|
MARCH = -march=rv32i # <1>
|
525 |
|
|
MABI = -mabi=ilp32 # <2>
|
526 |
|
|
----
|
527 |
|
|
<1> MARCH = Machine architecture ("ISA string")
|
528 |
|
|
<2> MABI = Machine binary interface
|
529 |
|
|
|
530 |
|
|
For example when you enable the RISC-V `C` extension (16-bit compressed instructions) via the _CPU_EXTENSION_RISCV_C_ generic (set _true_) you need
|
531 |
|
|
to add the 'c' extension also to the _MARCH_ ISA string.
|
532 |
|
|
|
533 |
|
|
You can also override the default _MARCH_ and _MABI_ configurations from the makefile when invoking the makefile:
|
534 |
|
|
|
535 |
|
|
[source,bash]
|
536 |
|
|
----
|
537 |
|
|
$ make MARCH=-march=rv32ic clean_all all
|
538 |
|
|
----
|
539 |
|
|
|
540 |
|
|
[NOTE]
|
541 |
|
|
The RISC-V ISA string (for _MARCH_) follows a certain canonical structure:
|
542 |
|
|
`rev32[i/e][m][a][f][d][g][q][c][b][v][n]...` For example `rv32imac` is valid while `rv32icma` is not valid.
|
543 |
|
|
|
544 |
|
|
|
545 |
|
|
|
546 |
|
|
|
547 |
|
|
<<<
|
548 |
|
|
// ####################################################################################################################
|
549 |
|
|
:sectnums:
|
550 |
|
|
== Building a Non-Volatile Application without External Boot Memory
|
551 |
|
|
|
552 |
|
|
The primary purpose of the bootloader is to allow an easy and fast update of the current application. In particular, this is very handy
|
553 |
|
|
during the development stage of a project as you can upload modified programs at any time via the UART.
|
554 |
|
|
Maybe at some time your project has become mature and you want to actually _embed_ your processor
|
555 |
|
|
including the application.
|
556 |
|
|
|
557 |
|
|
There are two options to provide _non-volatile_ storage of your application. The simplest (but also most constrained) one is to implement the IMEM
|
558 |
|
|
as true ROM to contain your program. The second option is to use an external boot memory - this concept is shown in a different section:
|
559 |
|
|
<<_programming_an_external_spi_flash_via_the_bootloader>>.
|
560 |
|
|
|
561 |
|
|
Using the IMEM as ROM:
|
562 |
|
|
|
563 |
|
|
* for this boot concept the bootloader is no longer required
|
564 |
|
|
* this concept only works for the internal IMEM (but can be extended to work with external memories coupled via the processor's bus interface)
|
565 |
|
|
* make sure that the memory components (like block RAM) the IMEM is mapped to support an initialization via the bitstream
|
566 |
|
|
|
567 |
|
|
[start=1]
|
568 |
|
|
. At first, compile your application code by running the `make install` command:
|
569 |
|
|
|
570 |
|
|
[source,bash]
|
571 |
|
|
----
|
572 |
|
|
neorv32/sw/example/blink_led$ make compile
|
573 |
|
|
Memory utilization:
|
574 |
|
|
text data bss dec hex filename
|
575 |
|
|
852 0 0 852 354 main.elf
|
576 |
|
|
Executable (neorv32_exe.bin) size in bytes:
|
577 |
|
|
864
|
578 |
|
|
Installing application image to ../../../rtl/core/neorv32_application_image.vhd
|
579 |
|
|
----
|
580 |
|
|
|
581 |
|
|
[start=2]
|
582 |
|
|
. The `install` target has created an executable, too, but this time also in the form of a VHDL memory
|
583 |
|
|
initialization file. during synthesis, this initialization will become part of the final FPGA bitstream, which
|
584 |
|
|
in terms initializes the IMEM's memory primitives.
|
585 |
|
|
. To allow a direct boot of this image without interference of the bootloader you _can_ deactivate the implementation of
|
586 |
|
|
the bootloader via the according top entity's generic:
|
587 |
|
|
|
588 |
|
|
[source,vhdl]
|
589 |
|
|
----
|
590 |
|
|
BOOTLOADER_EN => false, -- implement processor-internal bootloader? # <1>
|
591 |
|
|
----
|
592 |
|
|
<1> Set to _false_ to make the CPU directly boot from the IMEM. In this case the BOOTROM is discarded from the design.
|
593 |
|
|
|
594 |
|
|
[start=4]
|
595 |
|
|
. When the bootloader is deactivated, the according module (BOOTROM) is removed from the design and the CPU will start booting
|
596 |
|
|
at the base address of the instruction memory space (IMEM base address) making the CPU directly executing your
|
597 |
|
|
application after reset.
|
598 |
|
|
. The IMEM could be still modified, since it is implemented as RAM by default, which might corrupt your
|
599 |
|
|
executable. To prevent this and to implement the IMEM as true ROM (and eventually saving some
|
600 |
|
|
more hardware resources), active the "IMEM as ROM" feature using the processor's according top entity
|
601 |
|
|
generic:
|
602 |
|
|
|
603 |
|
|
[source,vhdl]
|
604 |
|
|
----
|
605 |
|
|
MEM_INT_IMEM_ROM => true, -- implement processor-internal instruction memory as ROM
|
606 |
|
|
----
|
607 |
|
|
|
608 |
|
|
[start=6]
|
609 |
|
|
. Perform a new synthesis and upload your bitstream. Your application code now resides unchangeable
|
610 |
|
|
in the processor's IMEM and is directly executed after reset.
|
611 |
|
|
|
612 |
|
|
|
613 |
|
|
|
614 |
|
|
|
615 |
|
|
<<<
|
616 |
|
|
// ####################################################################################################################
|
617 |
|
|
:sectnums:
|
618 |
|
|
== Customizing the Internal Bootloader
|
619 |
|
|
|
620 |
|
|
The bootloader provides several configuration options to customize it for your specific applications. The
|
621 |
|
|
most important user-defined configuration options are available as C `#defines` right at the beginning of the
|
622 |
|
|
bootloader source code `sw/bootloader/bootloader.c`):
|
623 |
|
|
|
624 |
|
|
.Cut-out from the bootloader source code `bootloader.c`: configuration parameters
|
625 |
|
|
[source,c]
|
626 |
|
|
----
|
627 |
|
|
/** UART BAUD rate */
|
628 |
|
|
#define BAUD_RATE (19200)
|
629 |
|
|
/** Enable auto-boot sequence if != 0 */
|
630 |
|
|
#define AUTOBOOT_EN (1)
|
631 |
|
|
/** Time until the auto-boot sequence starts (in seconds) */
|
632 |
|
|
#define AUTOBOOT_TIMEOUT 8
|
633 |
|
|
/** Set to 0 to disable bootloader status LED */
|
634 |
|
|
#define STATUS_LED_EN (1)
|
635 |
|
|
/** SPI_DIRECT_BOOT_EN: Define/uncomment to enable SPI direct boot */
|
636 |
|
|
//#define SPI_DIRECT_BOOT_EN
|
637 |
|
|
/** Bootloader status LED at GPIO output port */
|
638 |
|
|
#define STATUS_LED (0)
|
639 |
|
|
/** SPI flash boot image base address (warning! address might wrap-around!) */
|
640 |
|
|
#define SPI_FLASH_BOOT_ADR (0x00800000)
|
641 |
|
|
/** SPI flash chip select line at spi_csn_o */
|
642 |
|
|
#define SPI_FLASH_CS (0)
|
643 |
|
|
/** Default SPI flash clock prescaler */
|
644 |
|
|
#define SPI_FLASH_CLK_PRSC (CLK_PRSC_8)
|
645 |
|
|
/** SPI flash sector size in bytes (default = 64kb) */
|
646 |
|
|
#define SPI_FLASH_SECTOR_SIZE (64*1024)
|
647 |
|
|
/** ASCII char to start fast executable upload process */
|
648 |
|
|
#define FAST_UPLOAD_CMD '#'
|
649 |
|
|
----
|
650 |
|
|
|
651 |
|
|
**Changing the Default Size of the Bootloader ROM**
|
652 |
|
|
|
653 |
|
|
The NEORV32 default bootloader uses 4kB of storage. This is also the default size of the BOOTROM memory component.
|
654 |
|
|
If your new/modified bootloader exceeds this size, you need to modify the boot ROM configurations.
|
655 |
|
|
|
656 |
|
|
[start=1]
|
657 |
|
|
. Open the processor's main package file `rtl/core/neorv32_package.vhd` and edit the
|
658 |
|
|
`boot_size_c` constant according to your requirements. The boot ROM size must not exceed 32kB
|
659 |
|
|
and should be a power of two (for optimal hardware mapping).
|
660 |
|
|
|
661 |
|
|
[source,vhdl]
|
662 |
|
|
----
|
663 |
|
|
-- Bootloader ROM --
|
664 |
|
|
constant boot_size_c : natural := 4*1024; -- bytes
|
665 |
|
|
----
|
666 |
|
|
|
667 |
|
|
[start=2]
|
668 |
|
|
. Now open the NEORV32 linker script `sw/common/neorv32.ld` and adapt the _LENGTH_ parameter
|
669 |
|
|
of the `rom` according to your new memory size. `boot_size_c` and the `rom` _LENGTH_ attribute have to be always
|
670 |
|
|
identical. Do **not modify** the _ORIGIN_ of the `rom` section.
|
671 |
|
|
|
672 |
|
|
[source,c]
|
673 |
|
|
----
|
674 |
|
|
MEMORY
|
675 |
|
|
{
|
676 |
|
|
rom (rx) : ORIGIN = DEFINED(make_bootloader) ? 0xFFFF0000 : 0x00000000, LENGTH = DEFINED(make_bootloader) ? 4*1024 : 16*1024 # <1>
|
677 |
|
|
ram (rwx) : ORIGIN = 0x80000000, LENGTH = 8*1024
|
678 |
|
|
}
|
679 |
|
|
----
|
680 |
|
|
<1> Bootloader ROM default size = 4*1024 bytes (**left** value)
|
681 |
|
|
|
682 |
|
|
[IMPORTANT]
|
683 |
|
|
The `rom` region provides conditional assignments (via symbol `make_bootloader`) for the origin
|
684 |
|
|
and the length depending on whether the executable is built as normal application (for the IMEM) or
|
685 |
|
|
as bootloader code (for the BOOTROM). To modify the BOOTLOADER memory size, make
|
686 |
|
|
sure to edit the first value for the origin (note "1").
|
687 |
|
|
|
688 |
|
|
**Re-Compiling and Re-Installing the Bootloader**
|
689 |
|
|
|
690 |
|
|
Whenever you have modified the bootloader you need to recompile and re-install it and re-synthesize your design.
|
691 |
|
|
|
692 |
|
|
[start=1]
|
693 |
|
|
. Compile and install the bootloader using the explicit `bootloader` makefile target.
|
694 |
|
|
|
695 |
|
|
[source,bash]
|
696 |
|
|
----
|
697 |
|
|
neorv32/sw/bootloader$ make bootloader
|
698 |
|
|
----
|
699 |
|
|
|
700 |
|
|
[start=1]
|
701 |
|
|
. Now perform a new synthesis / HDL compilation to update the bitstream with the new bootloader
|
702 |
|
|
image (some synthesis tools also allow to only update the BRAM initialization without re-running
|
703 |
|
|
the entire synthesis process).
|
704 |
|
|
|
705 |
|
|
[NOTE]
|
706 |
|
|
The bootloader is intended to work regardless of the actual NEORV32 hardware configuration –
|
707 |
|
|
especially when it comes to CPU extensions. Hence, the bootloader should be build using the
|
708 |
|
|
minimal `rv32i` ISA only (`rv32e` would be even better).
|
709 |
|
|
|
710 |
|
|
|
711 |
|
|
|
712 |
|
|
|
713 |
|
|
<<<
|
714 |
|
|
// ####################################################################################################################
|
715 |
|
|
:sectnums:
|
716 |
|
|
== Programming an External SPI Flash via the Bootloader
|
717 |
|
|
|
718 |
|
|
As described in section https://stnolting.github.io/neorv32/#_external_spi_flash_for_booting[Documentation: External SPI Flash for Booting]
|
719 |
|
|
the bootloader provides an option to store an application image to an external SPI flash
|
720 |
|
|
and to read this image back for booting. These steps show how to store a
|
721 |
|
|
|
722 |
|
|
[start=1]
|
723 |
|
|
. At first, reset the NEORV32 processor and wait until the bootloader start screen appears in your terminal program.
|
724 |
|
|
. Abort the auto boot sequence and start the user console by pressing any key.
|
725 |
|
|
. Press u to upload the program image, that you want to store to the external flash:
|
726 |
|
|
|
727 |
|
|
[source]
|
728 |
|
|
----
|
729 |
|
|
CMD:> u
|
730 |
|
|
Awaiting neorv32_exe.bin...
|
731 |
|
|
----
|
732 |
|
|
|
733 |
|
|
[start=4]
|
734 |
|
|
. Send the binary in raw binary via your terminal program. When the uploaded is completed and "OK"
|
735 |
|
|
appears, press `p` to trigger the programming of the flash (do not execute the image via the `e`
|
736 |
|
|
command as this might corrupt the image):
|
737 |
|
|
|
738 |
|
|
[source]
|
739 |
|
|
----
|
740 |
|
|
CMD:> u
|
741 |
|
|
Awaiting neorv32_exe.bin... OK
|
742 |
|
|
CMD:> p
|
743 |
|
|
Write 0x000013FC bytes to SPI flash @ 0x00800000? (y/n)
|
744 |
|
|
----
|
745 |
|
|
|
746 |
|
|
[start=5]
|
747 |
|
|
. The bootloader shows the size of the executable and the base address inside the SPI flash where the
|
748 |
|
|
executable is going to be stored. A prompt appears: Type `y` to start the programming or type `n` to
|
749 |
|
|
abort. See section <<_external_spi_flash_for_booting> for more information on how to configure the base address.
|
750 |
|
|
|
751 |
|
|
[source]
|
752 |
|
|
----
|
753 |
|
|
CMD:> u
|
754 |
|
|
Awaiting neorv32_exe.bin... OK
|
755 |
|
|
CMD:> p
|
756 |
|
|
Write 0x000013FC bytes to SPI flash @ 0x00800000? (y/n) y
|
757 |
|
|
Flashing... OK
|
758 |
|
|
CMD:>
|
759 |
|
|
----
|
760 |
|
|
|
761 |
|
|
[start=6]
|
762 |
|
|
. If "OK" appears in the terminal line, the programming process was successful. Now you can use the
|
763 |
|
|
auto boot sequence to automatically boot your application from the flash at system start-up without
|
764 |
|
|
any user interaction.
|
765 |
|
|
|
766 |
|
|
|
767 |
|
|
|
768 |
|
|
<<<
|
769 |
|
|
// ####################################################################################################################
|
770 |
|
|
:sectnums:
|
771 |
|
|
== Simulating the Processor
|
772 |
|
|
|
773 |
|
|
**Testbench**
|
774 |
|
|
|
775 |
|
|
The NEORV32 project features a simple default testbench (`sim/neorv32_tb.vhd`) that can be used to simulate
|
776 |
|
|
and test the processor setup. This testbench features a 100MHz clock and enables all optional peripheral and
|
777 |
|
|
CPU extensions except for the `E` extension and the TRNG IO module (that CANNOT be simulated due to its
|
778 |
|
|
combinatorial (looped) oscillator architecture).
|
779 |
|
|
|
780 |
|
|
The simulation setup is configured via the "User Configuration" section located right at the beginning of
|
781 |
|
|
the testbench's architecture. Each configuration constant provides comments to explain the functionality.
|
782 |
|
|
|
783 |
|
|
Besides the actual NEORV32 Processor, the testbench also simulates "external" components that are connected
|
784 |
|
|
to the processor's external bus/memory interface. These components are:
|
785 |
|
|
|
786 |
|
|
* an external instruction memory (that also allows booting from it)
|
787 |
|
|
* an external data memory
|
788 |
|
|
* an external memory to simulate "external IO devices"
|
789 |
|
|
* a memory-mapped registers to trigger the processor's interrupt signals
|
790 |
|
|
|
791 |
|
|
The following table shows the base addresses of these four components and their default configuration and
|
792 |
|
|
properties (attributes: `r` = read, `w` = write, `e` = execute, `a` = atomic accesses possible, `8` = byte-accessible, `16` =
|
793 |
|
|
half-word-accessible, `32` = word-accessible).
|
794 |
|
|
|
795 |
|
|
.Testbench: processor-external memories
|
796 |
|
|
[cols="^4,>3,^5,<11"]
|
797 |
|
|
[options="header",grid="rows"]
|
798 |
|
|
|=======================
|
799 |
|
|
| Base address | Size | Attributes | Description
|
800 |
|
|
| `0x00000000` | `imem_size_c` | `r/w/e, a, 8/16/32` | external IMEM (initialized with application image)
|
801 |
|
|
| `0x80000000` | `dmem_size_c` | `r/w/e, a, 8/16/32` | external DMEM
|
802 |
|
|
| `0xf0000000` | 64 bytes | `r/w/e, !a, 8/16/32` | external "IO" memory, atomic accesses will fail
|
803 |
|
|
| `0xff000000` | 4 bytes | `-/w/-, a, -/-/32` | memory-mapped register to trigger "machine external", "machine software" and "SoC Fast Interrupt" interrupts
|
804 |
|
|
|=======================
|
805 |
|
|
|
806 |
|
|
The simulated NEORV32 does not use the bootloader and directly boots the current application image (from
|
807 |
|
|
the `rtl/core/neorv32_application_image.vhd` image file). Make sure to use the `all` target of the
|
808 |
|
|
makefile to install your application as VHDL image after compilation:
|
809 |
|
|
|
810 |
|
|
[source, bash]
|
811 |
|
|
----
|
812 |
|
|
sw/example/blink_led$ make clean_all all
|
813 |
|
|
----
|
814 |
|
|
|
815 |
|
|
.Simulation-Optimized CPU/Processors Modules
|
816 |
|
|
[NOTE]
|
817 |
|
|
The `sim/rtl_modules` folder provides simulation-optimized versions of certain CPU/processor modules.
|
818 |
|
|
These alternatives can be used to replace the default CPU/processor HDL files to allow faster/easier/more
|
819 |
|
|
efficient simulation. **These files are not intended for synthesis!**
|
820 |
|
|
|
821 |
|
|
**Simulation Console Output**
|
822 |
|
|
|
823 |
|
|
Data written to the NEORV32 UART0 / UART1 transmitter is send to a virtual UART receiver implemented
|
824 |
|
|
as part of the testbench. Received chars are send to the simulator console and are also stored to a log file
|
825 |
|
|
(`neorv32.testbench_uart0.out` for UART0, `neorv32.testbench_uart1.out` for UART1) inside the simulator home folder.
|
826 |
|
|
|
827 |
|
|
**Faster Simulation Console Output**
|
828 |
|
|
|
829 |
|
|
When printing data via the UART the communication speed will always be based on the configured BAUD
|
830 |
|
|
rate. For a simulation this might take some time. To have faster output you can enable the **simulation mode**
|
831 |
|
|
or UART0/UART1 (see section https://stnolting.github.io/neorv32/#_primary_universal_asynchronous_receiver_and_transmitter_uart0[Documentation: Primary Universal Asynchronous Receiver and Transmitter (UART0)]).
|
832 |
|
|
|
833 |
|
|
ASCII data send to UART0 will be immediately printed to the simulator console. Additionally, the
|
834 |
|
|
ASCII data is logged in a file (`neorv32.uart0.sim_mode.text.out`) in the simulator home folder. All
|
835 |
|
|
written 32-bit data is also dumped as 8-char hexadecimal value into a file
|
836 |
|
|
(`neorv32.uart0.sim_mode.data.out`) also in the simulator home folder.
|
837 |
|
|
|
838 |
|
|
ASCII data send to UART1 will be immediately printed to the simulator console. Additionally, the
|
839 |
|
|
ASCII data is logged in a file (`neorv32.uart1.sim_mode.text.out`) in the simulator home folder. All
|
840 |
|
|
written 32-bit data is also dumped as 8-char hexadecimal value into a file
|
841 |
|
|
(`neorv32.uart1.sim_mode.data.out`) also in the simulator home folder.
|
842 |
|
|
|
843 |
|
|
You can "automatically" enable the simulation mode of UART0/UART1 when compiling an application. In this case the
|
844 |
|
|
"real" UART0/UART1 transmitter unit is permanently disabled. To enable the simulation mode just compile
|
845 |
|
|
and install your application and add _UART0_SIM_MODE_ for UART0 and/or _UART1_SIM_MODE_ for UART1 to
|
846 |
|
|
the compiler's _USER_FLAGS_ variable (do not forget the `-D` suffix flag):
|
847 |
|
|
|
848 |
|
|
[source, bash]
|
849 |
|
|
----
|
850 |
|
|
sw/example/blink_led$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all all
|
851 |
|
|
----
|
852 |
|
|
|
853 |
|
|
The provided define will change the default UART0/UART1 setup function in order to set the simulation mode flag in the according UART's control register.
|
854 |
|
|
|
855 |
|
|
[NOTE]
|
856 |
|
|
The UART simulation output (to file and to screen) outputs "complete lines" at once. A line is
|
857 |
|
|
completed with a line feed (newline, ASCII `\n` = 10).
|
858 |
|
|
|
859 |
|
|
**Simulation with Xilinx Vivado**
|
860 |
|
|
|
861 |
|
|
The project features default a Vivado simulation waveform configuration in `sim/vivado`.
|
862 |
|
|
|
863 |
|
|
**Simulation with GHDL**
|
864 |
|
|
|
865 |
|
|
To simulate the processor using _GHDL_ navigate to the `sim` folder and run the provided shell script. All arguments are passed to GHDL.
|
866 |
|
|
For example the simulation time can be configured using `--stop-time=4ms` as argument.
|
867 |
|
|
|
868 |
|
|
[source, bash]
|
869 |
|
|
----
|
870 |
|
|
neorv32/sim$ sh ghdl_sim.sh --stop-time=4ms
|
871 |
|
|
----
|
872 |
|
|
|
873 |
|
|
|
874 |
|
|
|
875 |
|
|
<<<
|
876 |
|
|
// ####################################################################################################################
|
877 |
|
|
:sectnums:
|
878 |
|
|
== Building the Documentation
|
879 |
|
|
|
880 |
|
|
The documentation is written using `asciidoc`. The according source files can be found in `docs/...`.
|
881 |
|
|
The documentation of the software framework is written _in-code_ using `doxygen`.
|
882 |
|
|
|
883 |
|
|
A makefiles in the project's root directory is provided to either build all of the documentation as HTML pages
|
884 |
|
|
or as PDF documents.
|
885 |
|
|
|
886 |
|
|
[TIP]
|
887 |
|
|
Pre-rendered PDFs are available online as nightly pre-releases: https://github.com/stnolting/neorv32/releases.
|
888 |
|
|
The HTML-based documentation is also available online at the project's https://stnolting.github.io/neorv32/[GitHub Pages].
|
889 |
|
|
|
890 |
|
|
The makefile provides a help target to show all available build options and their according outputs.
|
891 |
|
|
|
892 |
|
|
[source,bash]
|
893 |
|
|
----
|
894 |
|
|
neorv32$ make help
|
895 |
|
|
----
|
896 |
|
|
|
897 |
|
|
.Example: Generate HTML documentation (data sheet) using `asciidoctor`
|
898 |
|
|
[source,bash]
|
899 |
|
|
----
|
900 |
|
|
neorv32$ make html
|
901 |
|
|
----
|
902 |
|
|
|
903 |
|
|
[TIP]
|
904 |
|
|
If you don't have `asciidoctor` / `asciidoctor-pdf` installed, you can still generate all the documentation using
|
905 |
|
|
a _docker container_ via `make container`.
|
906 |
|
|
|
907 |
|
|
|
908 |
|
|
|
909 |
|
|
// ####################################################################################################################
|
910 |
|
|
:sectnums:
|
911 |
|
|
== Building the Project Documentation
|
912 |
|
|
|
913 |
|
|
|
914 |
|
|
|
915 |
|
|
<<<
|
916 |
|
|
// ####################################################################################################################
|
917 |
|
|
:sectnums:
|
918 |
|
|
== FreeRTOS Support
|
919 |
|
|
|
920 |
|
|
A NEORV32-specific port and a simple demo for FreeRTOS (https://github.com/FreeRTOS/FreeRTOS) are
|
921 |
|
|
available in the `sw/example/demo_freeRTOS` folder.
|
922 |
|
|
|
923 |
|
|
See the according documentation (`sw/example/demo_freeRTOS/README.md`) for more information.
|
924 |
|
|
|
925 |
|
|
|
926 |
|
|
|
927 |
|
|
// ####################################################################################################################
|
928 |
|
|
:sectnums:
|
929 |
|
|
== RISC-V Architecture Test Framework
|
930 |
|
|
|
931 |
|
|
The NEORV32 Processor passes the according tests provided by the official RISC-V Architecture Test Suite
|
932 |
|
|
(V2.0+), which is available online at GitHub: https://github.com/riscv/riscv-arch-test
|
933 |
|
|
|
934 |
|
|
All files required for executing the test framework on a simulated instance of the processor (including port
|
935 |
|
|
files) are located in the `riscv-arch-test` folder in the root directory of the NEORV32 repository. Take a
|
936 |
|
|
look at the provided `riscv-arch-test/README.md` (https://github.com/stnolting/neorv32/blob/master/riscv-arch-test/README.md[online at GitHunb])
|
937 |
|
|
file for more information on how to run the tests and how testing is conducted in detail.
|
938 |
|
|
|
939 |
|
|
|
940 |
|
|
|
941 |
|
|
<<<
|
942 |
|
|
// ####################################################################################################################
|
943 |
|
|
:sectnums:
|
944 |
|
|
== Debugging using the On-Chip Debugger
|
945 |
|
|
|
946 |
|
|
The NEORV32 https://stnolting.github.io/neorv32/#_on_chip_debugger_ocd[Documentation: On-Chip Debugger]
|
947 |
|
|
allows _online_ in-system debugging via an external JTAG access port from a
|
948 |
|
|
host machine. The general flow is independent of the host machine's operating system. However, this tutorial uses
|
949 |
|
|
Windows and Linux (Ubuntu on Windows) in parallel.
|
950 |
|
|
|
951 |
|
|
[NOTE]
|
952 |
|
|
This tutorial uses `gdb` to **directly upload an executable** to the processor. If you are using the default
|
953 |
|
|
processor setup _with_ internal instruction memory (IMEM) make sure it is implemented as RAM
|
954 |
|
|
(_MEM_INT_IMEM_ROM_ generic = false).
|
955 |
|
|
|
956 |
|
|
|
957 |
|
|
:sectnums:
|
958 |
|
|
=== Hardware Requirements
|
959 |
|
|
|
960 |
|
|
Make sure the on-chip debugger of your NEORV32 setups is implemented (_ON_CHIP_DEBUGGER_EN_ generic = true).
|
961 |
|
|
Connect a JTAG adapter to the NEORV32 `jtag_*` interface signals. If you do not have a full-scale JTAG adapter, you can
|
962 |
|
|
also use a FTDI-based adapter like the "FT2232H-56Q Mini Module", which is a simple and inexpensive FTDI breakout board.
|
963 |
|
|
|
964 |
|
|
.JTAG pin mapping
|
965 |
|
|
[cols="^3,^2,^2"]
|
966 |
|
|
[options="header",grid="rows"]
|
967 |
|
|
|=======================
|
968 |
|
|
| NEORV32 top signal | JTAG signal | FTDI port
|
969 |
|
|
| `jtag_tck_i` | TCK | D0
|
970 |
|
|
| `jtag_tdi_i` | TDI | D1
|
971 |
|
|
| `jtag_tdo_o` | TDO | D2
|
972 |
|
|
| `jtag_tms_i` | TMS | D3
|
973 |
|
|
| `jtag_trst_i` | TRST | D4
|
974 |
|
|
|=======================
|
975 |
|
|
|
976 |
|
|
[TIP]
|
977 |
|
|
The low-active JTAG _test reset_ (TRST) signals is _optional_ as a reset can also be triggered via the TAP controller.
|
978 |
|
|
If TRST is not used make sure to pull the signal _high_.
|
979 |
|
|
|
980 |
|
|
|
981 |
|
|
:sectnums:
|
982 |
|
|
=== OpenOCD
|
983 |
|
|
|
984 |
|
|
The NEORV32 on-chip debugger can be accessed using the https://github.com/riscv/riscv-openocd[RISC-V port of OpenOCD].
|
985 |
|
|
Prebuilt binaries can be obtained - for example - from https://www.sifive.com/software[SiFive]. A pre-configured
|
986 |
|
|
OpenOCD configuration file (`sw/openocd/openocd_neorv32.cfg`) is available that allows easy access to the NEORV32 CPU.
|
987 |
|
|
|
988 |
|
|
[NOTE]
|
989 |
|
|
You might need to adapt `ftdi_vid_pid`, `ftdi_channel` and `ftdi_layout_init` in `sw/openocd/openocd_neorv32.cfg`
|
990 |
|
|
according to your interface chip and your operating system.
|
991 |
|
|
|
992 |
|
|
[TIP]
|
993 |
|
|
If you want to modify the JTAG clock speed (via `adapter speed` in `sw/openocd/openocd_neorv32.cfg`) make sure to meet
|
994 |
|
|
the clock requirements noted in https://stnolting.github.io/neorv32/#_debug_module_dm[Documentation: Debug Transport Module (DTM)].
|
995 |
|
|
|
996 |
|
|
To access the processor using OpenOCD, open a terminal and start OpenOCD with the pre-configured configuration file.
|
997 |
|
|
|
998 |
|
|
.Connecting via OpenOCD (on Windows)
|
999 |
|
|
[source, bash]
|
1000 |
|
|
--------------------------
|
1001 |
|
|
N:\Projects\neorv32\sw\openocd>openocd -f openocd_neorv32.cfg
|
1002 |
|
|
Open On-Chip Debugger 0.11.0-rc1+dev (SiFive OpenOCD 0.10.0-2020.12.1)
|
1003 |
|
|
Licensed under GNU GPL v2
|
1004 |
|
|
For bug reports:
|
1005 |
|
|
https://github.com/sifive/freedom-tools/issues
|
1006 |
|
|
1
|
1007 |
|
|
Info : Listening on port 6666 for tcl connections
|
1008 |
|
|
Info : Listening on port 4444 for telnet connections
|
1009 |
|
|
Info : clock speed 1000 kHz
|
1010 |
|
|
Info : JTAG tap: neorv32.cpu tap/device found: 0x0cafe001 (mfg: 0x000 (), part: 0xcafe, ver: 0x0)
|
1011 |
|
|
Info : datacount=1 progbufsize=2
|
1012 |
|
|
Info : Disabling abstract command reads from CSRs.
|
1013 |
|
|
Info : Examined RISC-V core; found 1 harts
|
1014 |
|
|
Info : hart 0: XLEN=32, misa=0x40801105
|
1015 |
|
|
Info : starting gdb server for neorv32.cpu.0 on 3333
|
1016 |
|
|
Info : Listening on port 3333 for gdb connections
|
1017 |
|
|
--------------------------
|
1018 |
|
|
|
1019 |
|
|
OpenOCD has successfully connected to the NEORV32 on-chip debugger and has examined the CPU (showing the content of
|
1020 |
|
|
the `misa` CSRs). Now you can use `gdb` to connect via port 3333.
|
1021 |
|
|
|
1022 |
|
|
|
1023 |
|
|
:sectnums:
|
1024 |
|
|
=== Debugging with GDB
|
1025 |
|
|
|
1026 |
|
|
This guide uses the simple "blink example" from `sw/example/blink_led` as simplified test application to
|
1027 |
|
|
show the basics of in-system debugging.
|
1028 |
|
|
|
1029 |
|
|
At first, the application needs to be compiled. We will use the minimal machine architecture configuration
|
1030 |
|
|
(`rv32i`) here to be independent of the actual processor/CPU configuration.
|
1031 |
|
|
Navigate to `sw/example/blink_led` and compile the application:
|
1032 |
|
|
|
1033 |
|
|
.Compile the test application
|
1034 |
|
|
[source, bash]
|
1035 |
|
|
--------------------------
|
1036 |
|
|
.../neorv32/sw/example/blink_led$ make MARCH=-march=rv32i clean_all all
|
1037 |
|
|
--------------------------
|
1038 |
|
|
|
1039 |
|
|
This will generate an ELF file `main.elf` that contains all the symbols required for debugging.
|
1040 |
|
|
Furthermore, an assembly listing file `main.asm` is generated that we will use to define breakpoints.
|
1041 |
|
|
|
1042 |
|
|
Open another terminal in `sw/example/blink_led` and start `gdb`.
|
1043 |
|
|
The GNU debugger is part of the toolchain (see <<_toolchain_setup>>).
|
1044 |
|
|
|
1045 |
|
|
.Starting GDB (on Linux (Ubuntu on Windows))
|
1046 |
|
|
[source, bash]
|
1047 |
|
|
--------------------------
|
1048 |
|
|
.../neorv32/sw/example/blink_led$ riscv32-unknown-elf-gdb
|
1049 |
|
|
GNU gdb (GDB) 10.1
|
1050 |
|
|
Copyright (C) 2020 Free Software Foundation, Inc.
|
1051 |
|
|
License GPLv3+: GNU GPL version 3 or later
|
1052 |
|
|
This is free software: you are free to change and redistribute it.
|
1053 |
|
|
There is NO WARRANTY, to the extent permitted by law.
|
1054 |
|
|
Type "show copying" and "show warranty" for details.
|
1055 |
|
|
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv32-unknown-elf".
|
1056 |
|
|
Type "show configuration" for configuration details.
|
1057 |
|
|
For bug reporting instructions, please see:
|
1058 |
|
|
.
|
1059 |
|
|
Find the GDB manual and other documentation resources online at:
|
1060 |
|
|
.
|
1061 |
|
|
|
1062 |
|
|
For help, type "help".
|
1063 |
|
|
Type "apropos word" to search for commands related to "word".
|
1064 |
|
|
(gdb)
|
1065 |
|
|
--------------------------
|
1066 |
|
|
|
1067 |
|
|
Now connect to OpenOCD using the default port 3333 on your local machine.
|
1068 |
|
|
Set the ELF file we want to debug to the recently generated `main.elf` from the `blink_led` example.
|
1069 |
|
|
Finally, upload the program to the processor.
|
1070 |
|
|
|
1071 |
|
|
[NOTE]
|
1072 |
|
|
The executable that is uploaded to the processor is **not** the default NEORV32 executable (`neorv32_exe.bin`) that
|
1073 |
|
|
is used for uploading via the bootloader. Instead, all the required sections (like `.text`) are extracted from `mail.elf`
|
1074 |
|
|
by GDB and uploaded via the debugger's indirect memory access.
|
1075 |
|
|
|
1076 |
|
|
.Running GDB
|
1077 |
|
|
[source, bash]
|
1078 |
|
|
--------------------------
|
1079 |
|
|
(gdb) target remote localhost:3333 <1>
|
1080 |
|
|
Remote debugging using localhost:3333
|
1081 |
|
|
warning: No executable has been specified and target does not support
|
1082 |
|
|
determining executable automatically. Try using the "file" command.
|
1083 |
|
|
0xffff0c94 in ?? () <2>
|
1084 |
|
|
(gdb) file main.elf <3>
|
1085 |
|
|
A program is being debugged already.
|
1086 |
|
|
Are you sure you want to change the file? (y or n) y
|
1087 |
|
|
Reading symbols from main.elf...
|
1088 |
|
|
(gdb) load <4>
|
1089 |
|
|
Loading section .text, size 0xd0c lma 0x0
|
1090 |
|
|
Loading section .rodata, size 0x39c lma 0xd0c
|
1091 |
|
|
Start address 0x00000000, load size 4264
|
1092 |
|
|
Transfer rate: 43 KB/sec, 2132 bytes/write.
|
1093 |
|
|
(gdb)
|
1094 |
|
|
--------------------------
|
1095 |
|
|
<1> Connect to OpenOCD
|
1096 |
|
|
<2> The CPU was still executing code from the bootloader ROM - but that does not matter here
|
1097 |
|
|
<3> Select `mail.elf` from the `blink_led` example
|
1098 |
|
|
<4> Upload the executable
|
1099 |
|
|
|
1100 |
|
|
After the upload, GDB will make the processor jump to the beginning of the uploaded executable
|
1101 |
|
|
(by default, this is the beginning of the instruction memory at `0x00000000`) skipping the bootloader
|
1102 |
|
|
and halting the CPU right before executing the `blink_led` application.
|
1103 |
|
|
|
1104 |
|
|
|
1105 |
|
|
:sectnums:
|
1106 |
|
|
==== Breakpoint Example
|
1107 |
|
|
|
1108 |
|
|
The following steps are just a small showcase that illustrate a simple debugging scheme.
|
1109 |
|
|
|
1110 |
|
|
While compiling `blink_led`, an assembly listing file `main.asm` was generated.
|
1111 |
|
|
Open this file with a text editor to check out what the CPU is going to do when resumed.
|
1112 |
|
|
|
1113 |
|
|
The `blink_led` example implements a simple counter on the 8 lowest GPIO output ports. The program uses
|
1114 |
|
|
"busy wait" to have a visible delay between increments. This waiting is done by calling the `neorv32_cpu_delay_ms`
|
1115 |
|
|
function. We will add a _breakpoint_ right at the end of this wait function so we can step through the iterations
|
1116 |
|
|
of the counter.
|
1117 |
|
|
|
1118 |
|
|
.Cut-out from `main.asm` generated from the `blink_led` example
|
1119 |
|
|
[source, assembly]
|
1120 |
|
|
--------------------------
|
1121 |
|
|
00000688 <__neorv32_cpu_delay_ms_end>:
|
1122 |
|
|
688: 01c12083 lw ra,28(sp)
|
1123 |
|
|
68c: 02010113 addi sp,sp,32
|
1124 |
|
|
690: 00008067 ret
|
1125 |
|
|
--------------------------
|
1126 |
|
|
|
1127 |
|
|
The very last instruction of the `neorv32_cpu_delay_ms` function is `ret` (= return)
|
1128 |
|
|
at hexadecimal `690` in this example. Add this address as _breakpoint_ to GDB.
|
1129 |
|
|
|
1130 |
|
|
[NOTE]
|
1131 |
|
|
The address might be different if you use a different version of the software framework or
|
1132 |
|
|
if different ISA options are configured.
|
1133 |
|
|
|
1134 |
|
|
.Adding a GDB breakpoint
|
1135 |
|
|
[source, bash]
|
1136 |
|
|
--------------------------
|
1137 |
|
|
(gdb) b * 0x690
|
1138 |
|
|
Breakpoint 1 at 0x690
|
1139 |
|
|
--------------------------
|
1140 |
|
|
|
1141 |
|
|
Now execute `c` (= continue). The CPU will resume operation until it hits the break-point.
|
1142 |
|
|
By this we can "step" from increment to increment.
|
1143 |
|
|
|
1144 |
|
|
.Iterating from breakpoint to breakpoint
|
1145 |
|
|
[source, bash]
|
1146 |
|
|
--------------------------
|
1147 |
|
|
Breakpoint 1 at 0x690
|
1148 |
|
|
(gdb) c
|
1149 |
|
|
Continuing.
|
1150 |
|
|
|
1151 |
|
|
Breakpoint 1, 0x00000690 in neorv32_cpu_delay_ms ()
|
1152 |
|
|
(gdb) c
|
1153 |
|
|
Continuing.
|
1154 |
|
|
|
1155 |
|
|
Breakpoint 1, 0x00000690 in neorv32_cpu_delay_ms ()
|
1156 |
|
|
(gdb) c
|
1157 |
|
|
Continuing.
|
1158 |
|
|
--------------------------
|
1159 |
|
|
|
1160 |
|
|
include::../legal.adoc[]
|