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
|
# ThreadX example for Erbium
This directory runs the standard ThreadX demo on one hart of Erbium, the
16-hart RISC-V platform of the OpenHW Foundation CORE-ET project, using the
RISC-V64 GNU port in machine mode. The public `et-platform` functional
simulator, `erbium_emu`, is the reference target.
## Hardware used
| Item | Address | Notes |
|------|---------|-------|
| Hart 0 | - | RV64IMC, machine mode; other harts are parked |
| MRAM | `0x4000_0200` | 16 MiB window; the first 512 bytes belong to the boot flow |
| System registers | `0x0200_0000` | `SystemConfig` bit 6 enables the UART |
| UART0 | `0x0200_4000` | Original Shakti integration, polling, 115200 8N1 |
| Machine timer | `0x80F4_0200` | `mtime`, with `mtimecmp` at `+0x08` |
| PLIC | `0xA000_0000` | Machine-mode context of hart 0; sources 1 to 6 |
## Port notes
* **Soft float.** Erbium implements only part of the F extension: divide,
square root and conversions between single precision and 64-bit integers
raise an emulation exception. The example and the ThreadX library are
built for `rv64imc_zicsr_zifencei` with the `lp64` ABI, so the port saves
no FP state. `csr.h` rejects a build with F enabled.
* **No C library.** The `riscv64-unknown-elf` toolchain installed by
`scripts/install_riscv.sh` ships `lp64d` libraries only, so the example
links with `-nostdlib` and `board.c` provides `memset`. A missing runtime
helper shows up as a link error, not as a mix of ABIs.
* **No WFI.** The example never executes `wfi`, like the Zephyr Erbium
port. `TX_USE_WFI_IDLE` stays undefined, so the scheduler spins while
idle, and parked harts and fatal-trap halts spin as well.
* **Trap vector.** Erbium ignores `mtvec` base bits 11:1, so the trap
vector must be 4 KiB aligned. `trap_entry` is placed in its own 4 KiB
aligned section and used in direct mode.
* **PLIC.** The silicon hardwires source priorities to 1 and thresholds to
0. The simulator models them as writable registers that reset to 0, so
`plic_init()` writes the hardwired values. Drivers register a callback and
enable their source with `plic_irq_enable()`.
* **Clocks.** The UART divisor assumes a 400 MHz input clock and the tick
assumes a 2 MHz `mtime` rate, the values used by the Zephyr and NuttX
Erbium ports. If the boot firmware programs other rates, define
`ERBIUM_UART_CLOCK_HZ` and `ERBIUM_MTIME_FREQ_HZ` when you build.
* **UART.** The console only polls. `uart_init()` sets the UART enable bit
in `SystemConfig` with a read-modify-write, which leaves the watchdog
setting as the boot flow left it.
## Building
Install the toolchain with `scripts/install_riscv.sh`, or put another
`riscv64-unknown-elf` GCC on `PATH`, then run:
```bash
./build.sh
```
This configures `CMakeLists.txt` with `erbium_gnu.cmake`, builds
`libthreadx.a` for the soft-float ABI and links `build/demo_threadx.elf`.
Set `BUILD_DIR` to build elsewhere.
## Running on the simulator
Build `erbium_emu` from
[et-platform](https://github.com/aifoundry-org/et-platform). The example was
tested at revision `836a4ab600e93c3059bb58c898edbc37744cd8d0`:
```bash
git clone https://github.com/aifoundry-org/et-platform.git
cd et-platform
git checkout 836a4ab600e93c3059bb58c898edbc37744cd8d0
cmake -S erbium-hal -B build-hal -DCMAKE_INSTALL_PREFIX="$PWD/install"
cmake --build build-hal --target install
cmake -S sw-sysemu -B build-emu -GNinja -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS=-Wno-error=unused-result \
-DCMAKE_PREFIX_PATH="$PWD/install"
cmake --build build-emu --target erbium_emu
```
At that revision a release build with a distribution GCC that enables
`_FORTIFY_SOURCE` stops on an unused `write()` result in the UART model;
the `CMAKE_CXX_FLAGS` setting above keeps that warning from being an error.
Load the ELF and start hart 0 at the MRAM load address, bypassing the boot
ROM:
```bash
erbium_emu -elf_load build/demo_threadx.elf -reset_pc 0x40000200 \
-minions 1 -single_thread -max_cycles 100000000 \
-uart_rx_file /dev/null -uart_tx_file uart.log
cat uart.log
```
The log starts with `[UART0] : Erbium UART initialized`, followed by lines
from all eight demo threads. The simulator ends with a `max cycles reached`
error once the cycle budget is spent; judge the run by the UART log, not by
the exit status. With the default clocks one ThreadX tick is 2,000,000
simulated cycles, so the 100,000,000-cycle run shows `thread_0` five times.
The simulator verifies register accesses, the trap flow and the console.
It does not verify baud timing or the timer rate of real silicon.
## Simulator regression tests
With `erbium_emu` on `PATH`, run:
```bash
ERBIUM_EMU=erbium_emu ./test/run_simulator_tests.sh
```
The UART test checks that a long polling write does not lose ThreadX ticks.
The PLIC test changes one source in timer context while a thread changes
another, and checks that neither update is lost. The runner builds both
images with CMake and Ninja and reports a failure if either check fails.
These tests use the simulator's UART drain rate, not physical baud timing.
## Files
| File | Purpose |
|------|---------|
| `entry.S` | Reset entry: parks other harts, sets `gp`, stack and `.bss` |
| `tx_initialize_low_level.S` | Trap vector and `_tx_initialize_low_level` |
| `trap.c` | Dispatches the timer, the PLIC and fatal exceptions |
| `board.c` | `board_init()` and `memset` |
| `plic.c`, `plic.h` | PLIC driver for the hart's machine-mode context |
| `hwtimer.c`, `hwtimer.h` | Periodic tick from `mtime` and `mtimecmp` |
| `uart.c`, `uart.h` | Polling console |
| `demo_threadx.c` | The standard ThreadX demo |
| `link.lds` | MRAM layout |
| `erbium_gnu.cmake` | Toolchain file: `rv64imc_zicsr_zifencei`, `lp64` |
| `CMakeLists.txt`, `build.sh` | Build of the library and the demo |
| `test/` | Simulator tests for UART timekeeping and PLIC updates |
## References
* [Erbium processor](https://github.com/openhwfoundation/core-et-erbium)
* [UART registers](https://github.com/openhwfoundation/core-et-erbium/blob/325b32b7efaa2c2ab9c91001c89d3f49a4740826/doc/uart.md)
* [CPU memory map](https://github.com/openhwfoundation/core-et-erbium/blob/325b32b7efaa2c2ab9c91001c89d3f49a4740826/doc/cpu_mm.md)
* [Platform interrupts](https://github.com/openhwfoundation/core-et-erbium/blob/325b32b7efaa2c2ab9c91001c89d3f49a4740826/doc/interrupts.md)
* [CPU subsystem](https://github.com/openhwfoundation/core-et-erbium/blob/325b32b7efaa2c2ab9c91001c89d3f49a4740826/doc/cpu_subsystem.md)
* [et-platform simulator](https://github.com/aifoundry-org/et-platform)
|