Skip to content

Commit ca9c246

Browse files
committed
linux-on-de0nano: Add multicore tutorial too
1 parent f6b7082 commit ca9c246

File tree

2 files changed

+371
-2
lines changed

2 files changed

+371
-2
lines changed

docs/linux-on-de0nano-multicore.md

Lines changed: 368 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,368 @@
1+
---
2+
title: SMP Linux on De0 Nano Multicore
3+
layout: page
4+
parent: Linux
5+
nav_order: 6
6+
---
7+
8+
# Prerequisites
9+
10+
#### Tutorials
11+
12+
Run our [Linux on De0 Nano tutorial](linux-on-de0nano.html) to ensure you have:
13+
14+
- A working version of OpenOCD
15+
- A UART connected to the De0 Nano development board
16+
- `fusesoc` - The [FuseSoC build system](../fusesoc.html).
17+
- OpenOCD 0.10.0 (As of 2025, versions 0.11.0 and 0.12.0 have jtag timing issues)
18+
- `or1k-elf-` Toolchain as installed in our [newlib tutorial](../newlib.html).
19+
- `or1k-none-linux-musl-` - OpenRISC musl linux userspace toolchain
20+
21+
#### System
22+
23+
Additionally for the Linux tutorial we will need:
24+
25+
- An x86 Linux workstation
26+
- The `curl` and `git` command line utilities
27+
- A serial terminal emulator, here we use `picocom`
28+
- 2.5 GB of disk space
29+
30+
#### Files
31+
32+
We will download these below.
33+
34+
- linux - Linux kernel source code
35+
- [busybox-small-rootfs-20250708.tar.xz](https://github.com/stffrdhrn/or1k-rootfs-build/releases/download/or1k-20250708/busybox-small-rootfs-20250708.tar.xz) - Linux rootfs for userspace programs
36+
37+
# SMP Linux on De0 Nano Multicore Tutorial
38+
39+
In this tutorial we will cover building a Symetrical Multi-Processing (SMP) Linux kernel and booting it on [De0 Nano](../de0_nano/index.html)
40+
with a [busybox](https://busybox.net) root filesystem. This builds on the De0 Nano
41+
hello world FGPA board bring up and the Linux on De0 Nano tutorials.
42+
43+
In this tutorial we will be able to expirment with an OpenRISC design with 2 cpu's.
44+
45+
We break this tutorial down into parts:
46+
47+
- Downloading the pieces
48+
- Compiling the kernel
49+
- Building the FPGA bitstream
50+
- Running the kernel
51+
52+
## Downloading the Pieces
53+
54+
To get started we will create a temporary directory and setup our environment, if
55+
you plan to do a lot of OpenRISC development consider adding these tools to your
56+
`PATH` permanently.
57+
58+
To get everything you need run:
59+
60+
```bash
61+
mkdir /tmp/linux-on-de0nano-multicore/
62+
cd /tmp/linux-on-de0nano-multicore/
63+
64+
# Get our config for openocd
65+
curl -L -O https://openrisc.io/tutorials/de0_nano/de0_nano.cfg
66+
67+
# Clone kernel source, ~2GiB
68+
git clone --depth 1 --branch v7.0.0-rc1 https://kernel.googlesource.com/pub/scm/linux/kernel/git/torvalds/linux.git
69+
70+
# Download a busybox rootfs and our toolchain
71+
curl -L -O https://github.com/stffrdhrn/or1k-rootfs-build/releases/download/or1k-20250708/busybox-small-rootfs-20250708.tar.xz
72+
73+
# Add IP cores to the environment
74+
fusesoc library add fusesoc-cores https://github.com/fusesoc/fusesoc-cores
75+
fusesoc library add elf-loader https://github.com/fusesoc/elf-loader.git
76+
fusesoc library add openrisc-cores https://github.com/openrisc/openrisc-cores
77+
fusesoc library add de0_nano-multicore https://github.com/stffrdhrn/de0_nano-multicore.git
78+
79+
# Check the SoC design is available
80+
fusesoc core show de0_nano-multicore
81+
82+
# Extract software needed for the kernel
83+
tar -xf busybox-small-rootfs-20250708.tar.xz
84+
85+
# Check the OpenRISC linux toolchain is on the path, if not see the Linux on De0 Nano tutorial
86+
or1k-none-linux-musl-gcc --version
87+
```
88+
89+
## Compiling the Kernel
90+
91+
To build a Linux kernel we use the toolchain, kernel source code and rootfs just downloaded
92+
in the following make commands:
93+
94+
```bash
95+
make -C linux \
96+
ARCH=openrisc \
97+
CROSS_COMPILE=or1k-none-linux-musl- \
98+
de0_nano_multicore_defconfig
99+
100+
make -C linux \
101+
-j$(nproc) \
102+
ARCH=openrisc \
103+
CROSS_COMPILE=or1k-none-linux-musl- \
104+
CONFIG_INITRAMFS_SOURCE="$PWD/busybox-small-rootfs-20250708/initramfs/ $PWD/busybox-small-rootfs-20250708/initramfs.devnodes"
105+
```
106+
107+
The first command configures the kernel with the default configuration `de0_nano_multicore_defconfig` which is for the De0 Nano
108+
board using our Mutlicore design. The `make` arguments are as follows:
109+
110+
* `-C linux` - This saves us from having to change directory, `make` will run from within the Linux source code directory.
111+
* `ARCH=openrisc` - This passes the `ARCH` variable to the build system selecting the OpenRISC architecture.
112+
* `CROSS_COMPILE=or1k-none-linux-musl-` - This passes the `CROSS_COMPILE` variable to the build system selecting our toolchain.
113+
* `de0_nano_multicore_defconfig` - The make target, configures the linux kernel for the build.
114+
115+
The second command builds the kernel. The new argument is:
116+
117+
* `CONFIG_INITRAMFS_SOURCE=...` - This configures the built in root filesystem.
118+
119+
When running on machines with no disk capabilities such as De0 Nano we can use an [initfamfs](https://www.kernel.org/doc/Documentation/filesystems/ramfs-rootfs-initramfs.txt)
120+
that is built directly into our kernel ELF binary. This is one of the most
121+
simple ways to boot Linux but it means that our data is only in RAM and will be
122+
lost after reset. Also, it means that updating the rootfs userspace utilties
123+
requires rebuilding the kernel.
124+
125+
## Building the FPGA bitstream
126+
127+
As with the De0 Nano hello world tutorial we can build the bitstream with:
128+
129+
```bash
130+
fusesoc run de0_nano-multicore
131+
```
132+
133+
*Note*: The De0 Nano multicore design uses 16K or 73% of the Cyclone IV LEs
134+
compared to 10K or 49% for the single core design. Also, you may notice that
135+
the total number of memory bits in the multicore design is slightly less
136+
compared to the single core design as we shrank the cache sizes on each core to
137+
allow for the design to fit.
138+
139+
See fitting details below:
140+
141+
```
142+
$ tail build/de0_nano-multicore_1.1/default-quartus/de0_nano-multicore_1_1.fit.summary
143+
Timing Models : Final
144+
Total logic elements : 16,245 / 22,320 ( 73 % )
145+
Total combinational functions : 14,659 / 22,320 ( 66 % )
146+
Dedicated logic registers : 7,440 / 22,320 ( 33 % )
147+
Total registers : 7440
148+
Total pins : 53 / 154 ( 34 % )
149+
Total virtual pins : 0
150+
Total memory bits : 312,576 / 608,256 ( 51 % )
151+
Embedded Multiplier 9-bit elements : 12 / 132 ( 9 % )
152+
Total PLLs : 1 / 4 ( 25 % )
153+
154+
$ tail ../or1k-de0nano/build/de0_nano_1.1/default-quartus/de0_nano_1_1.fit.summary
155+
Timing Models : Final
156+
Total logic elements : 10,980 / 22,320 ( 49 % )
157+
Total combinational functions : 9,706 / 22,320 ( 43 % )
158+
Dedicated logic registers : 5,472 / 22,320 ( 25 % )
159+
Total registers : 5472
160+
Total pins : 73 / 154 ( 47 % )
161+
Total virtual pins : 0
162+
Total memory bits : 327,936 / 608,256 ( 54 % )
163+
Embedded Multiplier 9-bit elements : 6 / 132 ( 5 % )
164+
Total PLLs : 1 / 4 ( 25 % )
165+
```
166+
167+
## Running the Kernel
168+
169+
*(Note: this step is the same as Linux on De0 Nano)*
170+
171+
To start Linux on the De0 Nano development board we need to load the bitstream then
172+
upload the kernel image into RAM over the debug interface. The steps being:
173+
174+
1. Program the FPGA bitstream onto the FPGA board
175+
2. Using GDB load the kernel image - including the embedded rootfs - into RAM
176+
3. Reset the FPGA design, kicking off the kernel boot process
177+
178+
#### Terminal 1
179+
180+
We can program the OpenRISC FPGA bitstream and Linux kernel to the board with
181+
the following commands.
182+
183+
```bash
184+
fusesoc run de0_nano-multicore --pgm quartus
185+
186+
# Run openocd in the background so we can use one terminal.
187+
openocd -f interface/altera-usb-blaster.cfg -f de0_nano.cfg > openocd.log 2>&1 &
188+
189+
or1k-elf-gdb ./linux/vmlinux \
190+
-ex 'target remote :3333' \
191+
-ex 'monitor reset' \
192+
-ex 'monitor halt' \
193+
-ex load \
194+
-ex 'monitor reset' \
195+
-ex detach \
196+
-ex quit
197+
198+
pkill openocd
199+
```
200+
201+
The GDB command will connect to OpenOCD, then reset and halt the board making
202+
it ready to program. The `load` command will load the `vmlinux` ELF binary into
203+
the De0 Nano RAM. The next `monitor reset` command will reset the FPGA design
204+
kicking off the Linux boot process.
205+
206+
In a second terminal while the FPGA board is running connect
207+
to the serial console using `picocom`.
208+
209+
#### Terminal 2
210+
211+
*(Note: this step is the same as Linux on De0 Nano)*
212+
213+
We will use terminal 2 for connecting to the development board.
214+
215+
Open `picocom` with the following:
216+
217+
```bash
218+
cd /tmp/linux-on-de0nano-multicore/
219+
220+
picocom -b 115200 /dev/ttyUSB0 --receive-cmd 'rx -vv' --send-cmd 'sx -vv'
221+
```
222+
223+
To disconnect press `Ctrl-a` `Ctrl-q`
224+
225+
To upload files to the board press `Ctrl-a` `Ctrl-s`
226+
227+
## Example Boot Sequence
228+
229+
For reference in the `picocom` terminal the boot sequence will look as follows:
230+
231+
#### Terminal 2
232+
233+
```
234+
[ 0.000000] Compiled-in FDT at (ptrval)
235+
[ 0.000000] Linux version 7.0.0-rc1-de0nano-smp (shorne@antec) (or1k-none-linux-musl-gcc (GCC) 15.1.0, GNU ld (GNU Binutils) 2.44) #2 SMP Thu Feb 26 21:37:09 GMT 2026
236+
[ 0.000000] OF: reserved mem: Reserved memory: No reserved-memory node in the DT
237+
[ 0.000000] CPU: OpenRISC-10 (revision 0) @50 MHz
238+
[ 0.000000] -- dmmu: 64 entries, 1 way(s)
239+
[ 0.000000] -- immu: 64 entries, 1 way(s)
240+
[ 0.000000] -- additional features:
241+
[ 0.000000] -- debug unit
242+
[ 0.000000] -- PIC
243+
[ 0.000000] -- timer
244+
[ 0.000000] Initial ramdisk not found
245+
[ 0.000000] Setting up paging and PTEs.
246+
[ 0.000000] map_ram: Memory: 0x0-0x2000000
247+
[ 0.000000] itlb_miss_handler (ptrval)
248+
[ 0.000000] dtlb_miss_handler (ptrval)
249+
[ 0.000000] OpenRISC Linux -- http://openrisc.io
250+
[ 0.000000] Zone ranges:
251+
[ 0.000000] Normal [mem 0x0000000000000000-0x0000000001ffffff]
252+
[ 0.000000] Movable zone start for each node
253+
[ 0.000000] Early memory node ranges
254+
[ 0.000000] node 0: [mem 0x0000000000000000-0x0000000001ffffff]
255+
[ 0.000000] Initmem setup node 0 [mem 0x0000000000000000-0x0000000001ffffff]
256+
[ 0.000000] percpu: Embedded 5 pages/cpu s16032 r0 d24928 u40960
257+
[ 0.000000] Kernel command line: earlycon
258+
[ 0.000000] earlycon: ns16550a0 at MMIO 0x90000000 (options '115200')
259+
[ 0.000000] printk: legacy bootconsole [ns16550a0] enabled
260+
[ 0.000000] printk: log buffer data + meta data: 16384 + 51200 = 67584 bytes
261+
[ 0.000000] Dentry cache hash table entries: 4096 (order: 1, 16384 bytes, linear)
262+
[ 0.000000] Inode-cache hash table entries: 2048 (order: 0, 8192 bytes, linear)
263+
[ 0.000000] Sorting __ex_table...
264+
[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 4096
265+
[ 0.000000] mem auto-init: stack:all(zero), heap alloc:off, heap free:off
266+
[ 0.000000] mem_init_done ...........................................
267+
[ 0.000000] SLUB: HWalign=16, Order=0-1, MinObjects=0, CPUs=2, Nodes=1
268+
[ 0.000000] rcu: Hierarchical RCU implementation.
269+
[ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 10 jiffies.
270+
[ 0.000000] NR_IRQS: 32, nr_irqs: 32, preallocated irqs: 0
271+
[ 0.000000] rcu: srcu_init: Setting srcu_struct sizes based on contention.
272+
[ 0.000000] clocksource: openrisc_timer: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 38225208935 ns
273+
[ 0.000000] 100.00 BogoMIPS (lpj=500000)
274+
[ 0.000000] pid_max: default: 32768 minimum: 301
275+
[ 0.010000] Mount-cache hash table entries: 2048 (order: 0, 8192 bytes, linear)
276+
[ 0.020000] Mountpoint-cache hash table entries: 2048 (order: 0, 8192 bytes, linear)
277+
[ 0.040000] VFS: Finished mounting rootfs on nullfs
278+
[ 0.120000] rcu: Hierarchical SRCU implementation.
279+
[ 0.120000] rcu: Max phase no-delay instances is 1000.
280+
[ 0.140000] Timer migration: 1 hierarchy levels; 8 children per group; 1 crossnode level
281+
[ 0.160000] smp: Bringing up secondary CPUs ...
282+
[ 0.190000] CPU1: Booted secondary processor
283+
[ 0.190000] CPU: OpenRISC-10 (revision 0) @50 MHz
284+
[ 0.190000] -- dmmu: 64 entries, 1 way(s)
285+
[ 0.190000] -- immu: 64 entries, 1 way(s)
286+
[ 0.190000] -- additional features:
287+
[ 0.190000] -- debug unit
288+
[ 0.190000] -- PIC
289+
[ 0.190000] -- timer
290+
[ 0.190000] Synchronize counters for CPU 1: done.
291+
[ 0.230000] smp: Brought up 1 node, 2 CPUs
292+
[ 0.260000] Memory: 19960K/32768K available (5412K kernel code, 167K rwdata, 776K rodata, 5383K init, 79K bss, 12096K reserved, 0K cma-reserved)
293+
[ 0.280000] devtmpfs: initialized
294+
[ 0.360000] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
295+
[ 0.370000] posixtimers hash table entries: 1024 (order: 0, 8192 bytes, linear)
296+
[ 0.370000] futex hash table entries: 512 (16384 bytes on 1 NUMA nodes, total 16 KiB, linear).
297+
[ 0.440000] NET: Registered PF_NETLINK/PF_ROUTE protocol family
298+
[ 0.540000] pps_core: LinuxPPS API ver. 1 registered
299+
[ 0.540000] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
300+
[ 0.550000] PTP clock support registered
301+
[ 0.620000] clocksource: Switched to clocksource openrisc_timer
302+
[ 0.740000] NET: Registered PF_INET protocol family
303+
[ 0.760000] IP idents hash table entries: 2048 (order: 1, 16384 bytes, linear)
304+
[ 0.800000] tcp_listen_portaddr_hash hash table entries: 1024 (order: 0, 8192 bytes, linear)
305+
[ 0.810000] Table-perturb hash table entries: 65536 (order: 5, 262144 bytes, linear)
306+
[ 0.820000] TCP established hash table entries: 2048 (order: 0, 8192 bytes, linear)
307+
[ 0.830000] TCP bind hash table entries: 2048 (order: 2, 32768 bytes, linear)
308+
[ 0.840000] TCP: Hash tables configured (established 2048 bind 2048)
309+
[ 0.850000] UDP hash table entries: 256 (order: 1, 14336 bytes, linear)
310+
[ 0.860000] UDP-Lite hash table entries: 256 (order: 1, 14336 bytes, linear)
311+
[ 0.880000] NET: Registered PF_UNIX/PF_LOCAL protocol family
312+
[ 0.910000] RPC: Registered named UNIX socket transport module.
313+
[ 0.920000] RPC: Registered udp transport module.
314+
[ 0.920000] RPC: Registered tcp transport module.
315+
[ 0.930000] RPC: Registered tcp-with-tls transport module.
316+
[ 0.940000] RPC: Registered tcp NFSv4.1 backchannel transport module.
317+
[ 0.990000] workingset: timestamp_bits=30 max_order=12 bucket_order=0
318+
[ 1.140000] ledtrig-cpu: registered to indicate activity on CPUs
319+
[ 1.170000] Serial: 8250/16550 driver, 4 ports, IRQ sharing disabled
320+
[ 1.260000] printk: legacy console [ttyS0] disabled
321+
[ 1.280000] 90000000.serial: ttyS0 at MMIO 0x90000000 (irq = 2, base_baud = 3125000) is a 16550A
322+
[ 1.290000] printk: legacy console [ttyS0] enabled
323+
[ 1.290000] printk: legacy console [ttyS0] enabled
324+
[ 1.310000] printk: legacy bootconsole [ns16550a0] disabled
325+
[ 1.310000] printk: legacy bootconsole [ns16550a0] disabled
326+
[ 1.340000] -- dcache: 4096 bytes total, 32 bytes/line, 128 set(s), 1 way(s)
327+
[ 1.350000] -- icache: 4096 bytes total, 32 bytes/line, 128 set(s), 1 way(s)
328+
[ 1.370000] -- dcache: 4096 bytes total, 32 bytes/line, 128 set(s), 1 way(s)
329+
[ 1.380000] -- icache: 4096 bytes total, 32 bytes/line, 128 set(s), 1 way(s)
330+
[ 1.500000] NET: Registered PF_PACKET protocol family
331+
[ 1.830000] clk: Disabling unused clocks
332+
[ 4.840000] Freeing unused kernel image (initmem) memory: 5376K
333+
[ 4.840000] This architecture does not have kernel memory protection.
334+
[ 4.850000] Run /init as init process
335+
ifconfig: SIOCSIFADDR: No such device
336+
route: SIOCADDRT: Network unreachable
337+
338+
Please press Enter to activate this console. run-parts: /etc/network/if-pre-up.d: No such file or directory
339+
~ # uname -a
340+
Linux openrisc 7.0.0-rc1-de0nano-smp #2 SMP Thu Feb 26 21:37:09 GMT 2026 openrisc GNU/Linux
341+
~ # cat /proc/cpuinfo
342+
processor : 0
343+
cpu architecture : OpenRISC 1000 (1.1-rev0)
344+
cpu implementation id : 0x1
345+
cpu version : 0x50001
346+
frequency : 50000000
347+
immu : 64 entries, 1 ways
348+
dmmu : 64 entries, 1 ways
349+
bogomips : 100.00
350+
features : orbis32
351+
352+
processor : 1
353+
cpu architecture : OpenRISC 1000 (1.1-rev0)
354+
cpu implementation id : 0x1
355+
cpu version : 0x50001
356+
frequency : 50000000
357+
immu : 64 entries, 1 ways
358+
dmmu : 64 entries, 1 ways
359+
bogomips : 100.00
360+
features : orbis32
361+
```
362+
363+
## Further Reading
364+
365+
- [de0_nano-multicore](https://github.com/stffrdhrn/de0_nano-multicore) - A De0 Nano Multicore OpenRISC SoC design
366+
- [Linux Releases](https://kernel.org) - Linux release tarballs
367+
- [OpenRISC toolchain Releases](https://github.com/stffrdhrn/or1k-toolchain-build/releases) - Toolchain point releases
368+
- [OpenRISC rootfs Releases](https://github.com/stffrdhrn/or1k-rootfs-build/releases) - Rootfs point release

docs/linux-on-de0nano.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Linux on De0 Nano
33
layout: page
44
parent: Linux
5-
nav_order: 2
5+
nav_order: 5
66
---
77

88
# Prerequisites
@@ -387,7 +387,8 @@ Linux openrisc 7.0.0-rc1 #1 Tue Feb 24 18:26:47 GMT 2026 openrisc GNU/Linux
387387

388388
## Further Reading
389389

390-
- [openrisc/or1ksim](https://github.com/openrisc/or1ksim) - The or1ksim home page and git repo
390+
- [de0_nano](https://github.com/olofk/de0_nano) - The De0 Nano OpenRISC design
391+
- [OpenRISC on De0 Nano](https://www.rs-online.com/designspark/booting-linux-on-a-de0-nano-with-orpsoc) - One of the first tutorials for Linux on the De0 Nano
391392
- [or1ksim Releases](https://github.com/openrisc/or1ksim/releases) - Nightly build and point release
392393
- [Linux Releases](https://kernel.org) - Linux release tarballs
393394
- [OpenRISC toolchain Releases](https://github.com/stffrdhrn/or1k-toolchain-build/releases) - Toolchain point releases

0 commit comments

Comments
 (0)