URL
https://opencores.org/ocsvn/neorv32/neorv32/trunk
Subversion Repositories neorv32
Compare Revisions
- This comparison shows the changes necessary to convert path
/neorv32/trunk
- from Rev 68 to Rev 69
- ↔ Reverse comparison
Rev 68 → Rev 69
/docs/datasheet/cpu.adoc
252,36 → 252,29
This list shows the currently identified issues regarding full RISC-V-compatibility. More specific information |
can be found in section <<_instruction_sets_and_extensions>>. |
|
.Hardwired R/W CSRs |
.Read-Only "Read-Write" CSRs |
[IMPORTANT] |
The `misa`, `mip` and `mtval` CSRs in the NEORV32 are _read-only_. |
Any write access to it (in machine mode) to them are ignored and will _not_ cause any exceptions or side-effects. |
Pending interrupt can only be cleared by acknowledging the interrupt-causing device. However, pending interrupts |
can still be ignored by clearing the according `mie` register bits. |
The `misa` and `mtval` CSRs in the NEORV32 are _read-only_. |
Any machine-mode write access to them is ignored and will _not_ cause any exceptions or side-effects to maintain |
RISC-V compatibility. |
|
.Physical memory protection |
.Physical Memory Protection |
[IMPORTANT] |
The physical memory protection (see section <<_machine_physical_memory_protection>>) |
only supports the modes _OFF_ and _NAPOT_ yet and a minimal granularity of 8 bytes per region. |
|
.Atomic memory operations |
.Atomic Memory Operations |
[IMPORTANT] |
The `A` CPU extension only implements the `lr.w` and `sc.w` instructions yet. |
However, these instructions are sufficient to emulate all further atomic memory operations. |
|
.Bit-manipulation operations |
.Bit-Manipulation ISA Extension |
[IMPORTANT] |
The NEORV32 `B` extension only implements the _basic bit-manipulation instructions_ (`Zbb`) subset |
and the _address generation instructions_ (`Zba`) subset yet. |
|
.Instruction Misalignment |
[NOTE] |
This is not a real RISC-V incompatibility, but something that might not be clear when studying the RISC-V privileged |
architecture specifications: for 32-bit only instructions (no `C` extension) the misaligned instruction exception |
is raised if bit 1 of the access address is set (i.e. not on 32-bit boundary). If the `C` extension is implemented |
there will be no misaligned instruction exceptions _at all_. |
In both cases bit 0 of the program counter and all related registers is hardwired to zero. |
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
300,6 → 293,7
| `clk_i` | 1 | in | global clock line, all registers triggering on rising edge |
| `rstn_i` | 1 | in | global reset, low-active |
| `sleep_o` | 1 | out | CPU is in sleep mode when set |
| `debug_o` | 1 | out | CPU is in debug mode when set |
4+^| **Instruction Bus Interface (<<_bus_interface>>)** |
| `i_bus_addr_o` | 32 | out | destination address |
| `i_bus_rdata_i` | 32 | in | read data |
561,7 → 555,7
|
The most important points of the NEORV32-specific extensions are: |
* The CPU provides 16 _fast interrupt_ interrupts (`FIRQ)`, which are controlled via custom bits in the `mie` |
and `mip` CSR. This extension is mapped to _reserved_ CSR bits, that are available for custom use (according to the |
and `mip` CSR. This extension is mapped to CSR bits, that are available for custom use (according to the |
RISC-V specs). Also, custom trap codes for `mcause` are implemented. |
* All undefined/unimplemented/malformed/illegal instructions do raise an illegal instruction exception (see <<_full_virtualization>>). |
|
780,8 → 774,8
| Memory access | `I/E` | `lb` `lh` `lw` `lbu` `lhu` `sb` `sh` `sw` | 4 + ML |
| Memory access | `C` | `c.lw` `c.sw` `c.lwsp` `c.swsp` | 4 + ML |
| Memory access | `A` | `lr.w` `sc.w` | 4 + ML |
| Multiplication | `M` | `mul` `mulh` `mulhsu` `mulhu` | 2+31+3; FAST_MULfootnote:[DSP-based multiplication; enabled via `FAST_MUL_EN`.]: 5 |
| Division | `M` | `div` `divu` `rem` `remu` | 22+32+4 |
| Multiplication | `M` | `mul` `mulh` `mulhsu` `mulhu` | 2+32+2; FAST_MULfootnote:[DSP-based multiplication; enabled via `FAST_MUL_EN`.]: 4 |
| Division | `M` | `div` `divu` `rem` `remu` | 2+32+2 |
| CSR access | `Zicsr` | `csrrw` `csrrs` `csrrc` `csrrwi` `csrrsi` `csrrci` | 4 |
| System | `I/E`+`Zicsr` | `ecall` `ebreak` | 4 |
| System | `I/E` | `fence` | 3 |
836,11 → 830,17
is serviced first while the remaining ones stay _pending_. After completing the interrupt handler the interrupt with |
the second highest priority will get serviced and so on until no further interrupt are pending. |
|
.Interrupt Signal Requirements |
.Interrupt Signal Requirements - Standard RISC-V Interrupts |
[IMPORTANT] |
All interrupts request signals (including FIRQs) are **high-active**. A request has to stay at high-level (=asserted) |
All standard RISC-V interrupts request signals are **high-active**. A request has to stay at high-level (=asserted) |
until it is explicitly acknowledged by the CPU software (for example by writing to a specific memory-mapped register). |
|
.Interrupt Signal Requirements - Fast Interrupt Requests |
[IMPORTANT] |
The NEORV32-specific FIRQ request lines are triggered by a rising edge. Each request is buffered in the CPU control |
unit until the channel is either disabled (by clearing the according `mie` CSR bit) or the request is explicitly cleared (by setting |
the according `mip` CSR bit). |
|
.Instruction Atomicity |
[NOTE] |
All instructions execute as atomic operations - interrupts can only trigger between two instructions. |
868,10 → 868,31
|
<<< |
// #################################################################################################################### |
:sectnums!: |
===== NEORV32 Trap Listing |
:sectnums: |
==== NEORV32 Trap Listing |
|
.NEORV32 trap listing |
The following table shows all traps that are currently supported by the NEORV32 CPU. It also shows the prioritization |
and the CSR side-effects. A more detailed description of the actual trap triggering events is provided in a further table. |
|
[NOTE] |
_Asynchronous exceptions_ (= interrupts) set the MSB of `mcause` while _synchronous exception_ (= "software exception") |
clear the MSB. |
|
**Table Annotations** |
|
The "Prio." column shows the priority of each trap. The highest priority is 1. The "`mcause`" column shows the |
cause ID of the according trap that is written to `mcause` CSR. The "[RISC-V]" columns show the interrupt/exception code value from the |
official RISC-V privileged architecture manual. The "[C]" names are defined by the NEORV32 core library (`sw/lib/include/neorv32.h`) and can |
be used in plain C code. The "`mepc`" and "`mtval`" columns show the value written to |
`mepc` and `mtval` CSRs when a trap is triggered: |
|
* _I-PC_ - address of interrupted instruction (instruction has not been execute/completed yet) |
* _B-ADR_- bad memory access address that cause the trap |
* _PC_ - address of instruction that caused the trap |
* _0_ - zero |
* _Inst_ - the faulting instruction itself |
|
.NEORV32 Trap Listing |
[cols="3,6,5,14,11,4,4"] |
[options="header",grid="rows"] |
|======================= |
881,7 → 902,7
| 3 | `0x00000002` | 0.2 | _TRAP_CODE_I_ILLEGAL_ | illegal instruction | _PC_ | _Inst_ |
| 4 | `0x0000000B` | 0.11 | _TRAP_CODE_MENV_CALL_ | environment call from M-mode (`ecall` in machine-mode) | _PC_ | _PC_ |
| 5 | `0x00000008` | 0.8 | _TRAP_CODE_UENV_CALL_ | environment call from U-mode (`ecall` in user-mode) | _PC_ | _PC_ |
| 6 | `0x00000003` | 0.3 | _TRAP_CODE_BREAKPOINT_ | breakpoint (EBREAK) | _PC_ | _PC_ |
| 6 | `0x00000003` | 0.3 | _TRAP_CODE_BREAKPOINT_ | breakpoint (`ebreak`) | _PC_ | _PC_ |
| 7 | `0x00000006` | 0.6 | _TRAP_CODE_S_MISALIGNED_ | store address misaligned | _B-ADR_ | _B-ADR_ |
| 8 | `0x00000004` | 0.4 | _TRAP_CODE_L_MISALIGNED_ | load address misaligned | _B-ADR_ | _B-ADR_ |
| 9 | `0x00000007` | 0.7 | _TRAP_CODE_S_ACCESS_ | store access fault | _B-ADR_ | _B-ADR_ |
907,20 → 928,36
| 29 | `0x80000007` | 1.7 | _TRAP_CODE_MTI_ | machine timer interrupt | _I-PC_ | _0_ |
|======================= |
|
**Notes** |
|
The "Prio." column shows the priority of each trap. The highest priority is 1. The "`mcause`" column shows the |
cause ID of the according trap that is written to `mcause` CSR. The "[RISC-V]" columns show the interrupt/exception code value from the |
official RISC-V privileged architecture manual. The "[C]" names are defined by the NEORV32 core library (`sw/lib/include/neorv32.h`) and can |
be used in plain C code. The "`mepc`" and "`mtval`" columns show the value written to |
`mepc` and `mtval` CSRs when a trap is triggered: |
The following table provides a summarized description of the actual events for triggering a specific trap. |
|
* _I-PC_ - address of interrupted instruction (instruction has not been execute/completed yet) |
* _B-ADR_- bad memory access address that cause the trap |
* _PC_ - address of instruction that caused the trap |
* _0_ - zero |
* _Inst_ - the faulting instruction itself |
.NEORV32 Trap Description |
[cols="<3,<7"] |
[options="header",grid="rows"] |
|======================= |
| Trap ID | Triggered when ... |
| _TRAP_CODE_I_MISALIGNED_ | fetching an 32-bit instruction word that is not 32-bit-aligned (_see note below!_) |
| _TRAP_CODE_I_ACCESS_ | bus timeout or bus error during instruction word fetch |
| _TRAP_CODE_I_ILLEGAL_ | trying to execute an invalid instruction word (malformed or not supported) or on a privilege violation |
| _TRAP_CODE_MENV_CALL_ | executing `ecall` instruction in machine-mode |
| _TRAP_CODE_UENV_CALL_ | executing `ecall` instruction in user-mode |
| _TRAP_CODE_BREAKPOINT_ | executing `ebreak` instruction (or triggered by on-chip debugger) |
| _TRAP_CODE_S_MISALIGNED_ | storing data to an address that is not naturally aligned to the data size (byte, half, word) being stored |
| _TRAP_CODE_L_MISALIGNED_ | loading data from an address that is not naturally aligned to the data size (byte, half, word) being loaded |
| _TRAP_CODE_S_ACCESS_ | bus timeout or bus error during load data operation |
| _TRAP_CODE_L_ACCESS_ | bus timeout or bus error during store data operation |
| _TRAP_CODE_FIRQ_0_ ... _TRAP_CODE_FIRQ_15_| caused by interrupt-condition of processor-internal modules, see <<_neorv32_specific_fast_interrupt_requests>> |
| _TRAP_CODE_MEI_ | user-defined processor-external source (via dedicated top-entity signal) |
| _TRAP_CODE_MSI_ | user-defined processor-external source (via dedicated top-entity signal) |
| _TRAP_CODE_MTI_ | processor-internal machine timer overflow OR user-defined processor-external source (via dedicated top-entity signal) |
|======================= |
|
.Instruction Address Misaligned Exception |
[NOTE] |
For 32-bit-only instructions (= no `C` extension) the misaligned instruction exception |
is raised if bit 1 of the fetch address is set (i.e. not on a 32-bit boundary). If the `C` extension is implemented |
there will never be a misaligned instruction exception _at all_. |
In both cases bit 0 of the program counter (and all related registers) is hardwired to zero. |
|
|
<<< |
/docs/datasheet/cpu_csr.adoc
60,7 → 60,7
* `C`: _constrained_ - have a constrained compatibility, not all specified bits are implemented |
|
.NEORV32 Control and Status Registers (CSRs) |
[cols="<4,<7,<10,^3,<11,^3"] |
[cols="<6,<11,<16,^3,<25,^3"] |
[options="header"] |
|======================= |
| Address | Name [ASM] | Name [C] | R/W | Function | Note |
82,8 → 82,8
| 0x340 | <<_mscratch>> | _CSR_MSCRATCH_ | r/w | Machine scratch register | |
| 0x341 | <<_mepc>> | _CSR_MEPC_ | r/w | Machine exception program counter | |
| 0x342 | <<_mcause>> | _CSR_MCAUSE_ | r/w | Machine trap cause | `X` |
| 0x343 | <<_mtval>> | _CSR_MTVAL_ | r/- | Machine bad address or instruction | `XR` |
| 0x344 | <<_mip>> | _CSR_MIP_ | r/- | Machine interrupt pending register | `XR` |
| 0x343 | <<_mtval>> | _CSR_MTVAL_ | r/- | Machine bad address or instruction | `R` |
| 0x344 | <<_mip>> | _CSR_MIP_ | r/w | Machine interrupt pending register | `X` |
6+^| **<<_machine_physical_memory_protection_csrs>>** |
| 0x3a0 .. 0x3af | <<_pmpcfg, `pmpcfg0`>> .. <<_pmpcfg, `pmpcfg15`>> | _CSR_PMPCFG0_ .. _CSR_PMPCFG15_ | r/w | Physical memory protection config. for region 0..63 | `C` |
| 0x3b0 .. 0x3ef | <<_pmpaddr, `pmpaddr0`>> .. <<_pmpaddr, `pmpaddr63`>> | _CSR_PMPADDR0_ .. _CSR_PMPADDR63_ | r/w | Physical memory protection addr. register region 0..63 | |
446,9 → 446,10
| 0x344 | **Machine interrupt Pending** | `mip` |
3+| Reset value: _0x00000000_ |
3+| The `mip` CSR is compatible to the RISC-V specifications and also provides custom extensions. It shows currently _pending_ interrupts. |
Since this register is read-only, pending interrupts of processor-internal modules can only be cleared by acknowledging the interrupt-causing |
device. However, pending interrupts can be ignored by clearing the according <<_mie>> register bits. |
The following CSR bits are implemented (all remaining bits are always zero and are read-only). |
The bits for the standard RISC-V interrupts are read-only. Hence, these interrupts cannot be cleared using the `mip` register and must |
be cleared/acknowledged within the according interrupt-generating device. |
The upper 16 bits represent the status of the CPU's fast interrupt request lines (FIRQ). Once triggered, these _have to be cleared_ again by setting |
the according `mip` bit in the interrupt handler routine to clear the current interrupt request. |
|====== |
|
.Machine interrupt pending register |
456,16 → 457,13
[options="header",grid="rows"] |
|======================= |
| Bit | Name [C] | R/W | Function |
| 31:16 | _CSR_MIP_FIRQ15P_ : _CSR_MIP_FIRQ0P_ | r/- | fast interrupt channel 15..0 pending |
| 11 | _CSR_MIP_MEIP_ | r/- | machine _external_ interrupt pending |
| 7 | _CSR_MIP_MTIP_ | r/- | machine _timer_ interrupt pending |
| 3 | _CSR_MIP_MSIP_ | r/- | machine _software_ interrupt pending |
| 31:16 | _CSR_MIP_FIRQ15P_ : _CSR_MIP_FIRQ0P_ | r/w | fast interrupt channel 15..0 pending; cleared request by writing 1 |
| 11 | _CSR_MIP_MEIP_ | r/- | machine _external_ interrupt pending; _cleared by user-defined mechanism_ |
| 7 | _CSR_MIP_MTIP_ | r/- | machine _timer_ interrupt pending; cleared by incrementing MTIME's time compare register |
| 3 | _CSR_MIP_MSIP_ | r/- | machine _software_ interrupt pending; _cleared by user-defined mechanism_ |
|======================= |
|
[IMPORTAN] |
The NEORV32 `mip` CSR is read-only. However, a write access will _NOT_ raise an illegal instruction exception. |
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
/docs/datasheet/overview.adoc
181,15 → 181,16
├common - Linker script, crt0.S start-up code and central makefile |
├example - Various example programs |
│└... |
├lib - Processor core library |
│├include - Header files (*.h) |
│└source - Source files (*.c) |
├image_gen - Helper program to generate NEORV32 executables |
├isa-test |
│├riscv-arch-test - RISC-V spec. compatibility test framework (submodule) |
│└port-neorv32 - Port files for the official RISC-V architecture tests |
├ocd_firmware - Source code for on-chip debugger's "park loop" |
├openocd - OpenOCD on-chip debugger configuration files |
├image_gen - Helper program to generate NEORV32 executables |
└lib - Processor core library |
├include - Header files (*.h) |
└source - Source files (*.c) |
└svd - Processor system view description file (CMSIS-SVD) |
................................... |
|
|
277,6 → 278,8
|======================= |
| Hardware version: | `1.5.7.10` |
| Top entity: | `rtl/core/neorv32_cpu.vhd` |
| FPGA: | Intel Cyclone IV E `EP4CE22F17C6` |
| Toolchain: | Quartus Prime 20.1.0 |
|======================= |
|
[cols="<5,>1,>1,>1,>1,>1"] |
294,9 → 297,6
| `rv32imacu_Zicsr_Zicntr_Zifencei_Zfinx_DebugMode` | 3974 | 1815 | 1024 | 7 | 116 MHz |
|======================= |
|
[NOTE] |
No HPM counters and no PMP regions were implemented for generating these results. |
|
[TIP] |
The CPU provides further options to reduce the area footprint (for example by constraining the CPU-internal |
counter sizes) or to increase performance (for example by using a barrel-shifter; at cost of extra hardware). |
312,6 → 312,8
|======================= |
| Hardware version: | `1.5.7.15` |
| Top entity: | `rtl/core/neorv32_top.vhd` |
| FPGA: | Intel Cyclone IV E `EP4CE22F17C6` |
| Toolchain: | Quartus Prime 20.1.0 |
|======================= |
|
.Hardware utilization by the processor modules (mandatory core modules in **bold**) |
/docs/datasheet/soc.adoc
1057,9 → 1057,8
|
.Trigger type |
[IMPORTANT] |
The fast interrupt request channel trigger on **high-level** and have to stay asserted until explicitly acknowledged |
by the software (for example by writing to a specific memory-mapped register). Hence, pending interrupts remain pending |
as long as the interrupt-causing device's state fulfills it's interrupt condition(s). |
The fast interrupt request channels become pending after being triggering by **a rising edge**. A pending FIRQ has to |
be explicitly cleared by setting the according `mip` CSR bit. |
|
|
:sectnums: |
1117,9 → 1116,8
|
.Trigger type |
[IMPORTANT] |
The fast interrupt request channel trigger on **high-level** and have to stay asserted until explicitly acknowledged |
by the software (for example by writing to a specific memory-mapped register). Hence, pending interrupts remain pending |
as long as the interrupt-causing device's state fulfills it's interrupt condition(s). |
The fast interrupt request channels become pending after being triggering by **a rising edge**. A pending FIRQ has to |
be explicitly cleared by setting the according `mip` CSR bit. |
|
|
|
1424,6 → 1422,9
register and register bit accesses. |
|
[TIP] |
A CMSIS-SVD-compatible **System View Description (SVD)** file including all peripherals is available in `sw/svd`. |
|
[TIP] |
Most of the IO devices do not have a hardware reset. Instead, the devices are reset via software by |
writing zero to the unit's control register. A general software-based reset of all devices is done by the |
application start-up code `crt0.S`. |
/docs/datasheet/soc_cfs.adoc
55,9 → 55,9
|
**CFS Interrupt** |
|
The CFS provides a single high-level-triggered interrupt request signal mapped to the CPU's fast interrupt channel 1. |
Once set, the interrupt has to stay asserted until explicitly acknowledged by the software (for example by |
writing to a specific CFS register). See section <<_processor_interrupts>> for more information. |
The CFS provides a single rising-edge-triggered interrupt request signal mapped to the CPU's fast interrupt channel 1. |
Once triggered, the interrupt becomes pending (if enabled in the `mis` CSR) and has to be explicitly cleared again by setting |
the according `mip` CSR bit. See section <<_processor_interrupts>> for more information. |
|
|
**CFS Configuration Generic** |
/docs/datasheet/soc_gptmr.adoc
46,10 → 46,8
|
**Timer Interrupt** |
|
The timer interrupt gets pending when the timer is enabled and `COUNT` matches `THRES`. The interrupt |
request is indicated via the _GPTMR_CTRL_ALARM_ control register bit. This bit as well as the actual |
interrupt keeps pending until the bit is explicitly cleared by application software or if the |
timer is disabled. |
The timer interrupt is triggered when the timer is enabled and `COUNT` matches `THRES`. The interrupt |
remains pending until explicitly cleared by writing the according `mip` CSR bit. |
|
|
.GPTMR register map (`struct NEORV32_GPTMR`) |
57,12 → 55,11
[options="header",grid="all"] |
|======================= |
| Address | Name [C] | Bit(s), Name [C] | R/W | Function |
.6+<| `0xffffff60` .6+<| `NEORV32_GPTMR.CTRL` <|`0` _GPTMR_CTRL_EN_ ^| r/w <| Timer enable flag |
.5+<| `0xffffff60` .5+<| `NEORV32_GPTMR.CTRL` <|`0` _GPTMR_CTRL_EN_ ^| r/w <| Timer enable flag |
<|`1` _GPTMR_CTRL_PRSC0_ ^| r/w .3+| 3-bit clock prescaler select |
<|`2` _GPTMR_CTRL_PRSC1_ ^| r/w |
<|`3` _GPTMR_CTRL_PRSC2_ ^| r/w |
<|`4` _GPTMR_CTRL_MODE_ ^| r/w <| Counter mode: `0`=single-shot, `1`=continuous |
<|`5` _GPTMR_CTRL_ALARM_ ^| r/c <| Pending interrupt/alarm, cleared by setting bit to zero |
| `0xffffff64` | `NEORV32_GPTMR.THRES` |`31:0` | r/w | Threshold value register |
| `0xffffff68` | `NEORV32_GPTMR.COUNT` |`31:0` | r/w | Counter register |
|======================= |
/docs/datasheet/soc_neoled.adoc
173,14 → 173,11
In this case software can write up to _IO_NEOLED_TX_FIFO_/2 new data words to `DATA` without checking the FIFO |
status flags. If _NEOLED_CTRL_IRQ_CONF_ is set, an interrupt is generated whenever the TX FIFO _becomes_ empty. |
|
A pending interrupt request is cleared is cleared by any of the following operations: |
* write access to `NEORV32_NEOLED.DATA` (for example to send more LED data) |
* write access to `NEORV32_NEOLED.CTRL` |
* disabling the NEOLED module |
One the NEOLED interrupt has been triggered and became pending, it has to explicitly cleared again by setting the |
according `mip` CSR bit. |
|
[NOTE] |
The _NEOLED_CTRL_IRQ_CONF_ is hardwired to one if _IO_NEOLED_TX_FIFO_ = 1 (-> IRQ if FIFO is empty). |
|
If the FIFO is configured to contain only a single entry (_IO_NEOLED_TX_FIFO_ = 1) the interrupt |
will become pending if the FIFO (which is just a single register providing simple _double-buffering_) is empty. |
|
/docs/datasheet/soc_slink.adoc
137,13 → 137,16
request if it's interrupt enable flag _SLINK_IRQ_TX_EN_ is set. |
|
The **RX link's** _SLINK_IRQ_RX_MODE_ flags define the FIFO fill-level condition for raising an RX interrupt request: |
* If a link's interrupt mode flag is `1` an IRQ is generated when the link's FIFO _becomes_ not empty ("RX data available"). |
* If a link's interrupt mode flag is `0` an IRQ is generated when the link's FIFO _becomes_ at least half-full ("time to get data from RX FIFO to prevent overflow"). |
* If a link's interrupt mode flag is `0` an IRQ is generated when the link's FIFO _becomes_ not empty ("RX data available"). |
* If a link's interrupt mode flag is `1` an IRQ is generated when the link's FIFO _becomes_ at least half-full ("time to get data from RX FIFO to prevent overflow"). |
|
The **TX link's** _SLINK_IRQ_TX_MODE_ flags define the FIFO fill-level condition for raising an TX interrupt request: |
* If a link's interrupt mode flag is `1` an IRQ is generated when the link's FIFO _becomes_ not full ("space left in FIFO for new TX data"). |
* If a link's interrupt mode flag is `0` an IRQ is generated when the link's FIFO _becomes_ less than half-full ("SW can send _SLINK_TX_FIFO_/2 data words without checking any flags"). |
* If a link's interrupt mode flag is `0` an IRQ is generated when the link's FIFO _becomes_ not full ("space left in FIFO for new TX data"). |
* If a link's interrupt mode flag is `1` an IRQ is generated when the link's FIFO _becomes_ less than half-full ("SW can send _SLINK_TX_FIFO_/2 data words without checking any flags"). |
|
Once the SLINK's RX or TX interrupt has become pending, it has to be explicitly cleared again by setting the according |
`mip` CSR bit. |
|
[IMPORTANT] |
The interrupt configuration register `NEORV32_SLINK.IRQ` should we written _before_ the SLINK |
module is actually enabled. |
152,21 → 155,7
If _SLINK_RX_FIFO_ is 1 all _SLINK_IRQ_RX_MODE_ bits are hardwired to one. |
If _SLINK_TX_FIFO_ is 1 all _SLINK_IRQ_TX_MODE_ bits are hardwired to one. |
|
A **pending RX interrupt** request is cleared by any of the following operations: |
* read access to any `NEORV32_SLINK.DATA` (for example to read incoming data) |
* write access to `NEORV32_SLINK.CTRL` |
* disabling the SLINK module |
|
A **pending TX interrupt** request is cleared by any of the following operations: |
* write access any `NEORV32_SLINK.DATA` (for example to send more data) |
* write access to `NEORV32_SLINK.CTRL` |
* disabling the SLINK module |
|
[TIP] |
A dummy write to to the control register (i.e. `NEORV32_SLINK.DATA = NEORV32_SLINK.DATA`) |
can be executed to acknowledge any interrupt. |
|
|
.SLINK register map (`struct NEORV32_SLINK`) |
[cols="^4,<5,^2,^2,<14"] |
[options="header",grid="all"] |
/docs/datasheet/soc_spi.adoc
108,17 → 108,10
**SPI Interrupt** |
|
The SPI module provides a single interrupt to signal "transmission done" to the CPU. Whenever the SPI |
module completes the current transfer operation, the interrupt request is set. A pending interrupt request |
is cleared by any of the following operations: |
* read or write access to `NEORV32_SPI.DATA` (for example to trigger a new transmission) |
* write access to `NEORV32_SPI.CTRL` |
* disabling the SPI module |
module completes the current transfer operation, the interrupt is triggered and has to be explicitly cleared again |
by setting the according `mip` CSR bit. |
|
[TIP] |
A dummy read from `NEORV32_SPI.DATA` can be executed to acknowledge the interrupt without affecting data |
or the state of the SPI module. |
|
|
.SPI register map (`struct NEORV32_SPI`) |
[cols="<2,<2,<4,^1,<7"] |
[options="header",grid="all"] |
/docs/datasheet/soc_sysinfo.adoc
71,6 → 71,7
| `3` | _SYSINFO_SOC_MEM_INT_DMEM_ | set if the processor-internal IMEM is implemented (via top's <<_mem_int_imem_en>> generic) |
| `4` | _SYSINFO_SOC_MEM_EXT_ENDIAN_ | set if external bus interface uses BIG-endian byte-order (via top's <<_mem_ext_big_endian>> generic) |
| `5` | _SYSINFO_SOC_ICACHE_ | set if processor-internal instruction cache is implemented (via top's <<_icache_en>> generic) |
| `13` | _SYSINFO_SOC_IS_SIM_ | set if processor is being **simulated** (⚠️ not guaranteed) |
| `14` | _SYSINFO_SOC_OCD_ | set if on-chip debugger implemented (via top's <<_on_chip_debugger_en>> generic) |
| `15` | _SYSINFO_SOC_HW_RESET_ | set if a dedicated hardware reset of all core registers is implemented (via package's `dedicated_reset_c` constant) |
| `16` | _SYSINFO_SOC_IO_GPIO_ | set if the GPIO is implemented (via top's <<_io_gpio_en>> generic) |
/docs/datasheet/soc_twi.adoc
74,17 → 74,10
|
The SPI module provides a single interrupt to signal "operation done" to the CPU. Whenever the TWI |
module completes the current operation (generate stop condition, generate start conditions or transfer byte), |
the interrupt request is set. A pending interrupt request is cleared is cleared by any of |
the following operations: |
* read or write access to `NEORV32_TWI.DATA` (for example to trigger a new transmission) |
* write access to `NEORV32_TWI.CTRL` |
* disabling the TWI module |
the interrupt is triggered. Once triggered, the interrupt has to be explicitly cleared again by setting the according |
`mip` CSR bit. |
|
[TIP] |
A dummy read from `NEORV32_TWI.DATA` can be executed to acknowledge the interrupt without affecting data |
or the state of the TWI module. |
|
|
.TWI register map (`struct NEORV32_TWI`) |
[cols="<2,<2,<4,^1,<7"] |
[options="header",grid="all"] |
/docs/datasheet/soc_uart.adoc
127,21 → 127,10
in the TX FIFO _becomes_ free (-> _UART_CTRL_TX_FULL_ clears). If _UART_CTRL_TX_IRQ_ is `1` the TX interrupt goes pending |
when the RX FIFO _becomes_ less than half-full (-> _UART_CTRL_TX_HALF_ clears). |
|
A **pending RX interrupt** request is cleared by any of the following operations: |
* read access to `NEORV32_UART0.DATA` (for example to read incoming data) |
* write access to `NEORV32_UART0.CTRL` |
* disabling the UART module |
Once the RX or TX interrupt has become pending, it has to be explicitly cleared again by setting the |
according `mip` CSR bit. |
|
A **pending TX interrupt** request is cleared by any of the following operations: |
* write access to `NEORV32_UART0.DATA` (for example to send more data) |
* write access to `NEORV32_UART0.CTRL` |
* disabling the UART module |
|
[TIP] |
A dummy write to to the control register (i.e. `NEORV32_UART0.DATA = NEORV32_UART0.DATA`) |
can be executed to acknowledge any interrupt. |
|
|
**Simulation Mode** |
|
The default UART0 operation will transmit any data written to the `DATA` register via the serial TX line at |
/docs/datasheet/soc_wdt.adoc
13,15 → 13,17
| CPU interrupts: | fast IRQ channel 0 | watchdog timer overflow (see <<_processor_interrupts>>) |
|======================= |
|
|
**Theory of Operation** |
|
The watchdog (WDT) provides a last resort for safety-critical applications. The WDT has an internal 20-bit |
wide counter that needs to be reset every now and then by the user program. If the counter overflows, either |
a system reset or an interrupt is generated (depending on the configured operation mode). |
The _WDT_CTRL_HALF_ flag of the control register `CTRL` indicates that at least half of the maximum timeout |
value has been reached. |
|
Configuration of the watchdog is done by a single control register `CTRL`. The watchdog is enabled by |
setting the _WDT_CTRL_EN_ bit. The clock used to increment the internal counter is selected via the 3-bit |
_WDT_CTRL_CLK_SELx_ prescaler: |
The watchdog is enabled by setting the _WDT_CTRL_EN_ bit. The clock used to increment the internal counter |
is selected via the 3-bit _WDT_CTRL_CLK_SELx_ prescaler: |
|
[cols="^3,^3,>4"] |
[options="header",grid="rows"] |
44,7 → 46,7
any time by setting the _WDT_CTRL_FORCE_ bit. The watchdog is reset by setting the _WDT_CTRL_RESET_ bit. |
|
A watchdog interrupt can only occur if the watchdog is enabled and interrupt mode is enabled. |
A pending interrupt is cleared by either disabling the watchdog or by resetting the watchdog. |
A triggered interrupt has to be cleared again by setting the according `mip` CSR bit. |
|
The cause of the last action of the watchdog can be determined via the _WDT_CTRL_RCAUSE_ flag. If this flag is |
zero, the processor has been reset via the external reset signal. If this flag is set the last system reset was |
52,21 → 54,32
|
The Watchdog control register can be locked in order to protect the current configuration. The lock is |
activated by setting bit _WDT_CTRL_LOCK_. In the locked state any write access to the configuration flags is |
ignored (see table below, "accessible if locked"). Read accesses to the control register are not effected. The |
ignored (see table below, "writable if locked"). Read accesses to the control register are not effected. The |
lock can only be removed by a system reset (via external reset signal or via a watchdog reset action). |
|
.Watchdog Operation during Debugging |
[IMPORTANT] |
By default the watchdog pauses operation when the CPU enters debug mode and will resume normal operation after |
the CPU has left debug mode. This will prevent an unintended watchdog timeout (and a hardware reset if configured) |
during a debug session. However, the watchdog can be configured to keep operating even when the CPU is in debug |
mode by setting the control register's _WDT_CTRL_DBEN_ bit. If the CPU's debug mode is not implemented this flag |
is hardwired to zero. |
|
|
.WDT register map (`struct NEORV32_WDT`) |
[cols="<2,<2,<4,^1,^2,<4"] |
[cols="<2,<2,<4,^1,^1,^2,<4"] |
[options="header",grid="all"] |
|======================= |
| Address | Name [C] | Bit(s), Name [C] | R/W | Writable if locked | Function |
.9+<| `0xffffffbc` .9+<| `NEORV32_WDT.CTRL` <|`0` _WDT_CTRL_EN_ ^| r/w ^| no <| watchdog enable |
<|`1` _WDT_CTRL_CLK_SEL0_ ^| r/w ^| no .3+<| 3-bit clock prescaler select |
<|`2` _WDT_CTRL_CLK_SEL1_ ^| r/w ^| no |
<|`3` _WDT_CTRL_CLK_SEL2_ ^| r/w ^| no |
<|`4` _WDT_CTRL_MODE_ ^| r/w ^| no <| overflow action: `1`=reset, `0`=IRQ |
<|`5` _WDT_CTRL_RCAUSE_ ^| r/- ^| - <| cause of last system reset: `0`=caused by external reset signal, `1`=caused by watchdog |
<|`6` _WDT_CTRL_RESET_ ^| -/w ^| yes <| watchdog reset when set, auto-clears |
<|`7` _WDT_CTRL_FORCE_ ^| -/w ^| yes <| force configured watchdog action when set, auto-clears |
<|`8` _WDT_CTRL_LOCK_ ^| r/w ^| no <| lock access to configuration when set, clears only on system reset (via external reset signal OR watchdog reset action = reset) |
| Address | Name [C] | Bit(s), Name [C] | R/W | Reset value | Writable if locked | Function |
.11+<| `0xffffffbc` .11+<| `NEORV32_WDT.CTRL` <|`0` _WDT_CTRL_EN_ ^| r/w ^| `0` ^| no <| watchdog enable |
<|`1` _WDT_CTRL_CLK_SEL0_ ^| r/w ^| `0` ^| no .3+<| 3-bit clock prescaler select |
<|`2` _WDT_CTRL_CLK_SEL1_ ^| r/w ^| `0` ^| no |
<|`3` _WDT_CTRL_CLK_SEL2_ ^| r/w ^| `0` ^| no |
<|`4` _WDT_CTRL_MODE_ ^| r/w ^| `0` ^| no <| overflow action: `1`=reset, `0`=IRQ |
<|`5` _WDT_CTRL_RCAUSE_ ^| r/- ^| `0` ^| - <| cause of last system reset: `0`=caused by external reset signal, `1`=caused by watchdog |
<|`6` _WDT_CTRL_RESET_ ^| -/w ^| - ^| yes <| watchdog reset when set, auto-clears |
<|`7` _WDT_CTRL_FORCE_ ^| -/w ^| - ^| yes <| force configured watchdog action when set, auto-clears |
<|`8` _WDT_CTRL_LOCK_ ^| r/w ^| `0` ^| no <| lock access to configuration when set, clears only on system reset (via external reset signal OR watchdog reset action = reset) |
<|`9` _WDT_CTRL_DBEN_ ^| r/w ^| `0` ^| no <| allow WDT to continue operation even when in debug mode |
<|`10` _WDT_CTRL_HALF_ ^| r/- ^| `0` ^| - <| set if at least half of the max. timeout counter value has been reached |
|======================= |
/docs/datasheet/soc_wishbone.adoc
28,28 → 28,32
| CPU interrupts: | none | |
|======================= |
|
The external memory interface uses the Wishbone interface protocol. The external interface port is available |
when the _MEM_EXT_EN_ generic is _true_. This interface can be used to attach external memories, custom |
hardware accelerators additional IO devices or all other kinds of IP blocks. All memory accesses from the |
CPU, that do not target the internal bootloader ROM, the internal IO region or the internal data/instruction |
memories (if implemented at all) are forwarded to the Wishbone gateway and thus to the external memory |
interface. |
|
The external memory interface provides a Wishbone b4-compatible on-chip bus interface. The bus interface is |
implemented when the _MEM_EXT_EN_ generic is _true_. This interface can be used to attach external memories, |
custom hardware accelerators, additional IO devices or all other kinds of IP blocks. |
|
The external interface is _not_ mapped to a _specific_ address space region. Instead, all CPU memory accesses that |
do not target a processor-internal module are delegated to the external memory interface. In summary, a CPU load/store |
access is delegated to the external bus interface if... |
|
. it does not target the internal instruction memory IMEM (if implemented at all) |
. **and** it does not target the internal data memory DMEM (if implemented at all) |
. **and** it does not target the internal bootloader ROM or any of the IO devices - regardless if one or more of these components are |
actually implemented or not. |
|
[TIP] |
When using the default processor setup, all access addresses between 0x00000000 and |
0xffff0000 (= beginning of processor-internal BOOT ROM) are delegated to the external memory |
/ bus interface if they are not targeting the (actually enabled/implemented) processor-internal |
instruction memory (IMEM) or the (actually enabled/implemented) processor-internal data memory |
(DMEM). See section <<_address_space>> for more information. |
See section <<_address_space>> for more information. |
|
|
**Wishbone Bus Protocol** |
|
The external memory interface either uses **standard** ("classic") Wishbone transactions (default) or |
**pipelined** Wishbone transactions. The transaction protocol is configured via the _MEM_EXT_PIPE_MODE_ generic: |
The external memory interface either uses the **standard** ("classic") Wishbone transaction protocol (default) or |
**pipelined** Wishbone transaction protocol. The transaction protocol is configured via the _MEM_EXT_PIPE_MODE_ generic: |
|
When _MEM_EXT_PIPE_MODE_ is _false_, all bus control signals including _STB_ are active (and stable) until the |
When _MEM_EXT_PIPE_MODE_ is _false_, all bus control signals including _STB_ are active and remain stable until the |
transfer is acknowledged/terminated. If _MEM_EXT_PIPE_MODE_ is _true_, all bus control except _STB_ are active |
(and stable) until the transfer is acknowledged/terminated. In this case, _STB_ is active only during the very |
and remain until the transfer is acknowledged/terminated. In this case, _STB_ is asserted only during the very |
first bus clock cycle. |
|
.Exemplary Wishbone bus accesses using "classic" and "pipelined" protocol |
62,39 → 66,37
|======================= |
|
|
[TOP] |
[TIP] |
A detailed description of the implemented Wishbone bus protocol and the according interface signals |
can be found in the data sheet "Wishbone B4 - WISHBONE System-on-Chip (SoC) Interconnection |
Architecture for Portable IP Cores". A copy of this document can be found in the docs folder of this |
project. |
|
**Interface Latency** |
|
By default, the Wishbone gateway introduces two additional latency cycles: processor-outgoing ("TX") and |
processor-incoming ("RX") signals are fully registered. Thus, any access from the CPU to a processor-external devices |
via Wishbone requires 2 additional clock cycles (at least; depending on device's latency). |
**Bus Access** |
|
If the attached Wishbone network / peripheral already provides output registers or if the Wishbone network is not relevant |
for timing closure, the default buffering of incoming ("RX") data within the gateway can be disabled by implementing an |
"asynchronous" RX path. The configuration is done via the _MEM_EXT_ASYNC_RX_ generic. |
The NEORV32 Wishbone gateway does not support burst transfer yet, so there is always just one transfer in progress. |
Hence, the Wishbone `STALL` signal is not implemented. An accessed Wishbone device does not have to respond immediately to a bus |
request by sending an ACK. instead, there is a _time window_ where the device has to acknowledge the transfer. This time window |
id configured by the _MEM_EXT_TIMEOUT_ top generic that defines the maximum time (in clock cycles) a bus access can be pending |
before it is automatically terminated. If _MEM_EXT_TIMEOUT_ is set to zero, the timeout disabled an a bus access can take an |
arbitrary number of cycles to complete. |
|
**Bus Access Timeout** |
|
The Wishbone bus interface provides an option to configure a bus access timeout counter. The _MEM_EXT_TIMEOUT_ |
top generic is used to specify the _maximum_ time (in clock cycles) a bus access can be pending before it is automatically |
terminated. If _MEM_EXT_TIMEOUT_ is set to zero, the timeout disabled an a bus access can take an arbitrary number of cycles to complete. |
|
When _MEM_EXT_TIMEOUT_ is greater than zero, the WIshbone adapter starts an internal countdown whenever the CPU |
When _MEM_EXT_TIMEOUT_ is greater than zero, the Wishbone gateway starts an internal countdown whenever the CPU |
accesses a memory address via the external memory interface. If the accessed memory / device does not acknowledge (via `wb_ack_i`) |
or terminate (via `wb_err_i`) the transfer within _MEM_EXT_TIMEOUT_ clock cycles, the bus access is automatically canceled |
(setting `wb_cyc_o` low again) and a load/store/instruction fetch bus access fault exception is raised. |
setting `wb_cyc_o` low again and a CPU load/store/instruction fetch bus access fault exception is raised. |
|
[TIP] |
This feature can be used as **safety guard** if the external memory system does not check for "address space holes". That means that addresses, which |
do not belong to a certain memory or device, do not permanently stall the processor due to an unacknowledged/unterminated bus access. If the external |
memory system can guarantee to access **any** bus access (even it targets an unimplemented address) the timeout feature should be disabled |
(_MEM_EXT_TIMEOUT_ = 0). |
[IMPORTANT] |
Setting _MEM_EXT_TIMEOUT_ to zero will permanently stall the CPU if the targeted Wishbone device never responds. Hence, |
_MEM_EXT_TIMEOUT_ should be always set to a value greater than zero. + |
+ |
This feature can be used as **safety guard** if the external memory system does not check for "address space holes". That means |
that accessing addresses, which do not belong to a certain memory or device, do not permanently stall the processor due to an |
unacknowledged/unterminated bus access. If the external memory system can guarantee to access **any** bus access |
(even it targets an unimplemented address) the timeout feature should be disabled (_MEM_EXT_TIMEOUT_ = 0). |
|
|
**Wishbone Tag** |
|
The 3-bit wishbone `wb_tag_o` signal provides additional information regarding the access type. This signal |
104,6 → 106,7
* `wb_tag_o(1)` always zero (indicating "secure access") |
* `wb_tag_o(2)` 1: instruction fetch access, 0: data access |
|
|
**Exclusive / Atomic Bus Access** |
|
If the atomic memory access CPU extension (via _CPU_EXTENSION_RISCV_A_) is enabled, the CPU can |
120,6 → 123,7
[TIP] |
See section <<_bus_interface>> for the CPU bus interface protocol. |
|
|
**Endianness** |
|
The NEORV32 CPU and the Processor setup are *little-endian* architectures. To allow direct connection |
130,6 → 134,18
Application software can check the Endianness configuration of the external bus interface via the |
SYSINFO module (see section <<_system_configuration_information_memory_sysinfo>> for more information). |
|
|
**Gateway Latency** |
|
By default, the Wishbone gateway introduces two additional latency cycles: processor-outgoing ("TX") and |
processor-incoming ("RX") signals are fully registered. Thus, any access from the CPU to a processor-external devices |
via Wishbone requires 2 additional clock cycles (at least; depending on device's latency). |
|
If the attached Wishbone network / peripheral already provides output registers or if the Wishbone network is not relevant |
for timing closure, the default buffering of incoming ("RX") data within the gateway can be disabled by implementing an |
"asynchronous" RX path. The configuration is done via the _MEM_EXT_ASYNC_RX_ generic. |
|
|
**AXI4-Lite Connectivity** |
|
The AXI4-Lite wrapper (`rtl/system_integration/neorv32_SystemTop_axi4lite.vhd`) provides a Wishbone-to- |
143,5 → 159,6
image::neorv32_axi_soc.png[] |
|
[WARNING] |
Using the auto-termination timeout feature (_MEM_EXT_TIMEOUT_ greater than zero) is **not AXI4 compliant** as the AXI protocol does not support canceling of |
bus transactions. Therefore, the NEORV32 top wrapper with AXI4-Lite interface (`rtl/system_integration/neorv32_SystemTop_axi4lite`) configures _MEM_EXT_TIMEOUT_ = 0 by default. |
Using the auto-termination timeout feature (_MEM_EXT_TIMEOUT_ greater than zero) is **not AXI4 compliant** as |
the AXI protocol does not support canceling of bus transactions. Therefore, the NEORV32 top wrapper with AXI4-Lite interface |
(`rtl/system_integration/neorv32_SystemTop_axi4lite`) configures _MEM_EXT_TIMEOUT_ = 0 by default. |
/docs/datasheet/soc_xirq.adoc
42,7 → 42,8
The CPU can use the ID from `SCR` to service IRQ according to their priority. To acknowledge the according |
interrupt the CPU can write `1 << SCR` to `IPR`. |
|
In order to clear a pending FIRQ interrupt from the external interrupt controller, the CPU has to write _any_ |
In order to clear a pending FIRQ interrupt from the external interrupt controller again, the according `mip` CSR bit has |
to be set. Additionally, the XIRQ interrupt has to be acknowledged by writing _any_ |
value to the interrupt source register `SRC`. |
|
[NOTE] |
/docs/datasheet/software.adoc
51,6 → 51,9
#include <neorv32.h> |
---- |
|
[TIP] |
A CMSIS-SVD-compatible **System View Description (SVD)** file including all peripherals is available in `sw/svd`. |
|
Together with the makefile, this will automatically include all the processor's header files located in |
`sw/lib/include` into your application. The actual source files of the core libraries are located in |
`sw/lib/source` and are automatically included into the source list of your software project. The following |
65,8 → 68,7
| `neorv32_cpu.c` | `neorv32_cpu.h` | HW driver functions for the NEORV32 **CPU** |
| `neorv32_gpio.c` | `neorv32_gpio.h` | HW driver functions for the **GPIO** |
| `neorv32_gptmr.c` | `neorv32_gptmr.h` | HW driver functions for the **GPTRM** |
| - | `neorv32_intrinsics.h` | macros for custom intrinsics/instructions |
| - | `neorv32_legacy.h` | legacy back-compatibility layer |
| - | `neorv32_intrinsics.h` | macros for (custom) intrinsics/instructions |
| `neorv32_mtime.c` | `neorv32_mtime.h` | HW driver functions for the **MTIME** |
| `neorv32_neoled.c` | `neorv32_neoled.h` | HW driver functions for the **NEOLED** |
| `neorv32_pwm.c` | `neorv32_pwm.h` | HW driver functions for the **PWM** |
119,23 → 121,34
[source,makefile] |
---- |
$ make |
<<< NEORV32 Application Makefile >>> |
<<< NEORV32 SW Application Makefile >>> |
Make sure to add the bin folder of RISC-V GCC to your PATH variable. |
Targets: |
help - show this text |
check - check toolchain |
info - show makefile/toolchain configuration |
exe - compile and generate <neorv32_exe.bin> executable for upload via bootloader |
hex - compile and generate <neorv32_exe.hex> executable raw file |
image - compile and generate VHDL IMEM boot image (for application) in local folder |
install - compile, generate and install VHDL IMEM boot image (for application) |
sim - in-console simulation using default/simple testbench and GHDL |
all - exe + hex + install |
elf_info - show ELF layout info |
clean - clean up project |
clean_all - clean up project, core libraries and image generator |
bl_image - compile and generate VHDL BOOTROM boot image (for bootloader only!) in local folder |
bootloader - compile, generate and install VHDL BOOTROM boot image (for bootloader only!) |
|
== Targets == |
help - show this text |
check - check toolchain |
info - show makefile/toolchain configuration |
exe - compile and generate <neorv32_exe.bin> executable for upload via bootloader |
hex - compile and generate <neorv32_exe.hex> executable raw file |
image - compile and generate VHDL IMEM boot image (for application) in local folder |
install - compile, generate and install VHDL IMEM boot image (for application) |
sim - in-console simulation using default/simple testbench and GHDL |
all - exe + hex + install |
elf_info - show ELF layout info |
clean - clean up project |
clean_all - clean up project, core libraries and image generator |
bl_image - compile and generate VHDL BOOTROM boot image (for bootloader only!) in local folder |
bootloader - compile, generate and install VHDL BOOTROM boot image (for bootloader only!) |
|
== Variables == |
USER_FLAGS - Custom toolchain flags [append only], default "" |
EFFORT - Optimization level, default "-Os" |
MARCH - Machine architecture, default "rv32i" |
MABI - Machine binary interface, default "ilp32" |
APP_INC - C include folder(s) [append only], default "-I ." |
ASM_INC - ASM include folder(s) [append only], default "-I ." |
RISCV_PREFIX - Toolchain prefix, default "riscv32-unknown-elf-" |
NEORV32_HOME - NEORV32 home folder, default "../../.." |
---- |
|
|
506,8 → 519,8
* `h`: Show the help text (again) |
* `r`: Restart the bootloader and the auto-boot sequence |
* `u`: Upload new program executable (`neorv32_exe.bin`) via UART into the instruction memory |
* `s`: Store executable to SPI flash at `spi_csn_o(0)` |
* `l`: Load executable from SPI flash at `spi_csn_o(0)` |
* `s`: Store executable to SPI flash at `spi_csn_o(0)` (little-endian byte order) |
* `l`: Load executable from SPI flash at `spi_csn_o(0)` (little-endian byte order) |
* `e`: Start the application, which is currently stored in the instruction memory (IMEM) |
|
A new executable can be uploaded via UART by executing the `u` command. After that, the executable can be directly |
/docs/figures/license.md
2,6 → 2,16
|
Figures are own work if not otherwise stated. License: https://github.com/stnolting/neorv32/blob/master/LICENSE |
|
No copyright infringement intended. |
|
|
## `neopixel.png` |
|
source: Adafruit NeoPixel Überguide |
|
License: |
* ? |
|
## `SPI_timing_diagram2.wikimedia.png` |
|
source: https://en.wikipedia.org/wiki/File:SPI_timing_diagram2.svg |
8,4 → 18,25
|
License: |
* Creative Commons: https://en.wikipedia.org/wiki/Creative_Commons |
* Attribution-Share Alike 3.0 Unported: https://creativecommons.org/licenses/by-sa/3.0/deed.en |
* Attribution-Share Alike 3.0 Unported: https://creativecommons.org/licenses/by-sa/3.0/deed.en |
|
## `riscv_logo.png` and `riscv_logo_small.png` |
|
source: https://riscv.org/risc-v-logo/ |
|
License: |
* https://riscv.org/about/risc-v-branding-guidelines/ |
|
## `oshw_logo.png` |
|
source: https://www.oshwa.org/open-source-hardware-logo/ |
|
License: |
* Creative Commons Attribution-ShareAlike 4.0 International License |
|
## `neorv32_logo_smcard.jpg` |
|
source: background image by https://pixabay.com |
|
License: |
* Pixabay license |
/docs/userguide/adding_custom_hw_modules.adoc
0,0 → 1,61
<<< |
:sectnums: |
== Adding Custom Hardware Modules |
|
In resemblance to the RISC-V ISA, the NEORV32 processor was designed to ease customization and _extensibility_. |
The processor provides several predefined options to add application-specific custom hardware modules and accelerators. |
|
|
=== Standard (_External_) Interfaces |
|
The processor already provides a set of standard interfaces that are intended to connect _chip-external_ devices. |
However, these interfaces can also be used chip-internally. The most suitable interfaces are |
https://stnolting.github.io/neorv32/#_general_purpose_input_and_output_port_gpio[GPIO], |
https://stnolting.github.io/neorv32/#_primary_universal_asynchronous_receiver_and_transmitter_uart0[UART], |
https://stnolting.github.io/neorv32/#_serial_peripheral_interface_controller_spi[SPI] and |
https://stnolting.github.io/neorv32/#_two_wire_serial_interface_controller_twi[TWI]. |
|
The SPI and (especially) the GPIO interfaces might be the most straightforward approaches since they |
have a minimal protocol overhead. Device-specific interrupt capabilities can be added using the |
https://stnolting.github.io/neorv32/#_external_interrupt_controller_xirq[External Interrupt Controller (XIRQ)]. |
Beyond simplicity, these interface only provide a very limited bandwidth and require more sophisticated |
software handling ("bit-banging" for the GPIO). |
|
|
=== External Bus Interface |
|
The https://stnolting.github.io/neorv32/#_processor_external_memory_interface_wishbone_axi4_lite[External Bus Interface] |
provides the classic approach to connect to custom IP. By default, the bus interface implements the widely adopted |
Wishbone interface standard. However, this project also includes wrappers to bridge to other protocol standards like ARM's |
AXI4-Lite or Intel's Avalon. By using a full-featured bus protocol, complex SoC structures can be implemented (including |
several modules and even multi-core architectures). Many FPGA EDA tools provide graphical editors to build and customize |
whole SoC architectures and even include pre-defined IP libraries. |
|
.Example AXI SoC using Xilinx Vivado |
image::neorv32_axi_soc.png[] |
|
The bus interface uses a memory-mapped approach. All data transfers are handled by simple load/store operations since the |
external bus interface is mapped into the processor's https://stnolting.github.io/neorv32/#_address_space[address space]. |
This allows a very simple still high-bandwidth communications. |
|
|
=== Stream Link Interface |
|
The NEORV32 https://stnolting.github.io/neorv32/#_stream_link_interface_slink[Stream Link Interface] provides |
point-to-point, unidirectional and parallel data channels that can be used to transfer streaming data. In |
contrast to the external bus interface, the streaming data does not provide any kind of "direction" control, |
so it can be seen as "constant address bursts". The stream link interface provides less protocol overhead |
and less latency than the bus interface. Furthermore, FIFOs can be be configured to each direction (RX/TX) to |
allow more CPU-independent operation. |
|
|
=== Custom Functions Subsystem |
|
The NEORV32 https://stnolting.github.io/neorv32/#_custom_functions_subsystem_cfs[Custom Functions Subsystem] is |
an "empty" template for a processor-internal module. It provides 32 32-bit memory-mapped interface |
registers that can be used to communicate with any arbitrary custom design logic. The intentions of this |
subsystem is to provide a simple base, where the user can concentrate on implementing the actual design logic |
rather than taking care of the communication between the CPU/software and the design logic. The interface |
registers are already allocated within the processor's address space and are supported by the software framework |
via low-level hardware access mechanisms. Additionally, the CFS provides a direct pre-defined interrupt channel to |
the CPU, which is also supported by the NEORV32 runtime environment. |
/docs/userguide/application_program_compilation.adoc
0,0 → 1,48
<<< |
:sectnums: |
== Application Program Compilation |
|
This guide shows how to compile an example C-code application into a NEORV32 executable that |
can be uploaded via the bootloader or the on-chip debugger. |
|
[IMPORTANT] |
If your FPGA board does not provide such an interface - don't worry! |
Section <<_installing_an_executable_directly_into_memory>> shows how to |
run custom programs on your FPGA setup without having a UART. |
|
[start=1] |
. Open a terminal console and navigate to one of the project's example programs. For instance, navigate to the |
simple `sw/example_blink_led` example program. This program uses the NEORV32 GPIO module to display |
an 8-bit counter on the lowest eight bit of the `gpio_o` output port. |
. To compile the project and generate an executable simply execute: |
|
[source,bash] |
---- |
neorv32/sw/example/blink_led$ make clean_all exe |
---- |
|
[start=3] |
. We are using the `clean_all` target to make sure everything is re-build. |
. This will compile and link the application sources together with all the included libraries. At the end, |
your application is transformed into an ELF file (`main.elf`). The _NEORV32 image generator_ (in `sw/image_gen`) |
takes this file and creates a final executable. The makefile will show the resulting memory utilization and |
the executable size: |
|
[source,bash] |
---- |
neorv32/sw/example/blink_led$ make clean_all exe |
Memory utilization: |
text data bss dec hex filename |
3176 0 120 3296 ce0 main.elf |
Compiling ../../../sw/image_gen/image_gen |
Executable (neorv32_exe.bin) size in bytes: |
3188 |
---- |
|
[start=5] |
. That's it. The `exe` target has created the actual executable `neorv32_exe.bin` in the current folder |
that is ready to be uploaded to the processor. |
|
[TIP] |
The compilation process will also create a `main.asm` assembly listing file in the current folder, which |
shows the actual assembly code of the application. |
/docs/userguide/application_specific_configuration.adoc
0,0 → 1,105
<<< |
:sectnums: |
== Application-Specific Processor Configuration |
|
Due to the processor's configuration options, which are mainly defined via the top entity VHDL generics, the SoC |
can be tailored to the application-specific requirements. Note that this chapter does not focus on optional |
_SoC features_ like IO/peripheral modules. It rather gives ideas on how to optimize for _overall goals_ |
like performance and area. |
|
[NOTE] |
Please keep in mind that optimizing the design in one direction (like performance) will also effect other potential |
optimization goals (like area and energy). |
|
=== Optimize for Performance |
|
The following points show some concepts to optimize the processor for performance regardless of the costs |
(i.e. increasing area and energy requirements): |
|
* Enable all performance-related RISC-V CPU extensions that implement dedicated hardware accelerators instead |
of emulating operations entirely in software: `M`, `C`, `Zfinx` |
* Enable mapping of compleX CPU operations to dedicated hardware: `FAST_MUL_EN => true` to use DSP slices for |
multiplications, `FAST_SHIFT_EN => true` use a fast barrel shifter for shift operations. |
* Implement the instruction cache: `ICACHE_EN => true` |
* Use as many _internal_ memory as possible to reduce memory access latency: `MEM_INT_IMEM_EN => true` and |
`MEM_INT_DMEM_EN => true`, maximize `MEM_INT_IMEM_SIZE` and `MEM_INT_DMEM_SIZE` |
* Increase the CPU's instruction prefetch buffer size: `CPU_IPB_ENTRIES` |
* _To be continued..._ |
|
|
=== Optimize for Size |
|
The NEORV32 is a size-optimized processor system that is intended to fit into tiny niches within large SoC |
designs or to be used a customized microcontroller in really tiny / low-power FPGAs (like Lattice iCE40). |
Here are some ideas how to make the processor even smaller while maintaining it's _general purpose system_ |
concept and maximum RISC-V compatibility. |
|
**SoC** |
|
* This is obvious, but exclude all unused optional IO/peripheral modules from synthesis via the processor |
configuration generics. |
* If an IO module provides an option to configure the number of "channels", constrain this number to the |
actually required value (e.g. the PWM module `IO_PWM_NUM_CH` or the external interrupt controller `XIRQ_NUM_CH`). |
* Reduce the FIFO sizes of implemented modules (e.g. `SLINK_TX_FIFO`). |
* Disable the instruction cache (`ICACHE_EN => false`) if the design only uses processor-internal IMEM |
and DMEM memories. |
* _To be continued..._ |
|
**CPU** |
|
* Use the _embedded_ RISC-V CPU architecture extension (`CPU_EXTENSION_RISCV_E`) to reduce block RAM utilization. |
* The compressed instructions extension (`CPU_EXTENSION_RISCV_C`) requires additional logic for the decoder but |
also reduces program code size by approximately 30%. |
* If not explicitly used/required, constrain the CPU's counter sizes: `CPU_CNT_WIDTH` for `[m]instret[h]` |
(number of instruction) and `[m]cycle[h]` (number of cycles) counters. You can even remove these counters |
by setting `CPU_CNT_WIDTH => 0` if they are not used at all (note, this is not RISC-V compliant). |
* Reduce the CPU's prefetch buffer size (`CPU_IPB_ENTRIES`). |
* Map CPU shift operations to a small and iterative shifter unit (`FAST_SHIFT_EN => false`). |
* If you have unused DSP block available, you can map multiplication operations to those slices instead of |
using LUTs to implement the multiplier (`FAST_MUL_EN => true`). |
* If there is no need to execute division in hardware, use the `Zmmul` extension instead of the full-scale |
`M` extension. |
* Disable CPU extension that are not explicitly used (`A`, `U`, `Zfinx`). |
* _To be continued..._ |
|
=== Optimize for Clock Speed |
|
The NEORV32 Processor and CPU are designed to provide minimal logic between register stages to keep the |
critical path as short as possible. When enabling additional extension or modules the impact on the existing |
logic is also kept at a minimum to prevent timing degrading. If there is a major impact on existing |
logic (example: many physical memory protection address configuration registers) the VHDL code automatically |
adds additional register stages to maintain critical path length. Obviously, this increases operation latency. |
|
In order to optimize for a minimal critical path (= maximum clock speed) the following points should be considered: |
|
* Complex CPU extensions (in terms of hardware requirements) should be avoided (examples: floating-point unit, physical memory protection). |
* Large carry chains (>32-bit) should be avoided (constrain CPU counter sizes: e.g. `CPU_CNT_WIDTH => 32` and `HPM_NUM_CNTS => 32`). |
* If the target FPGA provides sufficient DSP resources, CPU multiplication operations can be mapped to DSP slices (`FAST_MUL_EN => true`) |
reducing LUT usage and critical path impact while also increasing overall performance. |
* Use the synchronous (registered) RX path configuration of the external memory interface (`MEM_EXT_ASYNC_RX => false`). |
* _To be continued..._ |
|
[NOTE] |
The short and fixed-length critical path allows to integrate the core into existing clock domains. |
So no clock domain-crossing and no sub-clock generation is required. However, for very high clock |
frequencies (this is technology / platform dependent) clock domain crossing becomes crucial for chip-internal |
connections. |
|
|
=== Optimize for Energy |
|
There are no _dedicated_ configuration options to optimize the processor for energy (minimal consumption; |
energy/instruction ratio) yet. However, a reduced processor area (<<_optimize_for_size>>) will also reduce |
static energy consumption. |
|
To optimize your setup for low-power applications, you can make use of the CPU sleep mode (`wfi` instruction). |
Put the CPU to sleep mode whenever possible. Disable all processor modules that are not actually used (exclude them |
from synthesis if the will be _never_ used; disable the module via it's control register if the module is not |
_currently_ used). When is sleep mode, you can keep a timer module running (MTIME or the watch dog) to wake up |
the CPU again. Since the wake up is triggered by _any_ interrupt, the external interrupt controller can also |
be used to wake up the CPU again. By this, all timers (and all other modules) can be deactivated as well. |
|
.Processor-internal clock generator shutdown |
[TIP] |
If _no_ IO/peripheral module is currently enabled, the processor's internal clock generator circuit will be |
shut down reducing switching activity and thus, dynamic energy consumption. |
/docs/userguide/building_the_documentation.adoc
0,0 → 1,30
<<< |
:sectnums: |
== Building the Documentation |
|
The documentation (datasheet + user guide) is written using `asciidoc`. The according source files |
can be found in `docs/...`. The documentation of the software framework is written _in-code_ using `doxygen`. |
|
A makefiles in the project's `docs` directory is provided to build all of the documentation as HTML pages |
or as PDF documents. |
|
[TIP] |
Pre-rendered PDFs are available online as _nightly pre-releases_: https://github.com/stnolting/neorv32/releases. |
The HTML-based documentation is also available online at the project's https://stnolting.github.io/neorv32/[GitHub Pages]. |
|
The makefile provides a help target to show all available build options and their according outputs. |
|
[source,bash] |
---- |
neorv32/docs$ make help |
---- |
|
.Example: Generate HTML documentation (data sheet) using `asciidoctor` |
[source,bash] |
---- |
neorv32/docs$ make html |
---- |
|
[TIP] |
If you don't have `asciidoctor` / `asciidoctor-pdf` installed, you can still generate all the documentation using |
a _docker container_ via `make container`. |
/docs/userguide/content.adoc
11,1588 → 11,44
which provides more sophisticated example setups for various FPGAs/FPGA boards and toolchains. |
|
|
:sectnums: |
== Software Toolchain Setup |
include::sw_toolchain_setup.adoc[] |
|
To compile (and debug) executables for the NEORV32 a RISC-V toolchain is required. |
There are two possibilities to get this: |
include::general_hw_setup.adoc[] |
|
1. Download and _build_ the official RISC-V GNU toolchain yourself. |
2. Download and install a prebuilt version of the toolchain; this might also done via the package manager / app store of your OS |
include::general_sw_framework_setup.adoc[] |
|
[NOTE] |
The default toolchain prefix (`RISCV_PREFIX` variable) for this project is **`riscv32-unknown-elf-`**. Of course you can use any other RISC-V |
toolchain (like `riscv64-unknown-elf-`) that is capable to emit code for a `rv32` architecture. Just change `RISCV_PREFIX` |
according to your needs. |
include::application_program_compilation.adoc[] |
|
include::executable_upload.adoc[] |
|
:sectnums: |
=== Building the Toolchain from Scratch |
include::installing_an_executable.adoc[] |
|
To build the toolchain by yourself you can follow the guide from the official https://github.com/riscv-collab/riscv-gnu-toolchain GitHub page. |
You need to make sure the generated toolchain fits the architecture of the NEORV32 core. To get a toolchain that even supports minimal |
ISA extension configurations, it is recommend to compile for `rv32i` only. Please note that this minimal ISA also provides further ISA |
extensions like `m` or `c`. Of course you can use a _multilib_ approach to generate toolchains for several target ISAs at once. |
include::new_application_project.adoc[] |
|
.Configuring GCC build for `rv32i` (minimal ISA) |
[source,bash] |
---- |
riscv-gnu-toolchain$ ./configure --prefix=/opt/riscv --with-arch=rv32i --with-abi=ilp32 |
riscv-gnu-toolchain$ make |
---- |
include::enabling_riscv_extensions.adoc[] |
|
[IMPORTANT] |
Keep in mind that - for instance - a toolchain build with `--with-arch=rv32imc` only provides library code compiled with |
compressed (`C`) and `mul`/`div` instructions (`M`)! Hence, this code cannot be executed (without |
emulation) on an architecture without these extensions! |
include::application_specific_configuration.adoc[] |
|
include::adding_custom_hw_modules.adoc[] |
|
:sectnums: |
=== Downloading and Installing a Prebuilt Toolchain |
include::customizing_the_bootloader.adoc[] |
|
Alternatively, you can download a prebuilt toolchain. |
include::programming_an_external_spi_flash_via_bootloader.adoc[] |
|
:sectnums: |
==== Use The Toolchain I have Build |
include::packaging_vivado.adoc[] |
|
I have compiled a GCC toolchain on a 64-bit x86 Ubuntu (Ubuntu on Windows, actually) and uploaded it to |
GitHub. You can directly download the according toolchain archive as single _zip-file_ within a packed |
release from https://github.com/stnolting/riscv-gcc-prebuilt. |
include::simulating_the_processor.adoc[] |
|
Unpack the downloaded toolchain archive and copy the content to a location in your file system (e.g. |
`/opt/riscv`). More information about downloading and installing my prebuilt toolchains can be found in |
the repository's README. |
include::building_the_documentation.adoc[] |
|
include::zephyr_support.adoc[] |
|
:sectnums: |
==== Use a Third Party Toolchain |
include::free_rtos_support.adoc[] |
|
Of course you can also use any other prebuilt version of the toolchain. There are a lot RISC-V GCC packages out there - |
even for Windows. On Linux system you might even be able to fetch a toolchain via your distribution's package manager. |
include::riscv_architecture_tests.adoc[] |
|
[IMPORTANT] |
Make sure the toolchain can (also) emit code for a `rv32i` architecture, uses the `ilp32` or `ilp32e` ABI and **was not build** using |
CPU extensions that are not supported by the NEORV32 (like `D`). |
include::debugging_with_ocd.adoc[] |
|
|
:sectnums: |
=== Installation |
|
Now you have the toolchain binaries. The last step is to add them to your `PATH` environment variable (if you have not |
already done so): make sure to add the _binaries_ folder (`bin`) of your toolchain. |
|
[source,bash] |
---- |
$ export PATH:$PATH:/opt/riscv/bin |
---- |
|
You should add this command to your `.bashrc` (if you are using bash) to automatically add the RISC-V |
toolchain at every console start. |
|
:sectnums: |
=== Testing the Installation |
|
To make sure everything works fine, navigate to an example project in the NEORV32 example folder and |
execute the following command: |
|
[source,bash] |
---- |
neorv32/sw/example/blink_led$ make check |
---- |
|
This will test all the tools required for generating NEORV32 executables. |
Everything is working fine if `Toolchain check OK` appears at the end. |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== General Hardware Setup |
|
This guide shows the basics of setting up a NEORV32 project for FPGA implementation (or simulation only) |
_from scratch_. It uses a _simplified_ test "SoC" setup of the processor to keeps things simple at the beginning. |
This simple setup is intended for evaluation or as "hello world" project to check out the NEORV32 |
on _your_ FPGA board. |
|
[TIP] |
If you want to use a more sophisticated pre-defined setup to start with, check out the |
`setups` folder, which provides example setups for various FPGA, boards and toolchains. |
|
The NEORV32 project features two minimalistic pre-configured test setups in |
https://github.com/stnolting/neorv32/blob/master/rtl/test_setups[`rtl/test_setups`]. |
Both test setups only implement very basic processor and CPU features. |
The main difference between the two setups is the processor boot concept - so how to get a software executable |
_into_ the processor: |
|
* **`rtl/test_setups/neorv32_testsetup_approm.vhd`**: this setup does not require a connection via UART. The |
software executable is "installed" into the bitstream to initialize a read-only memory. Use this setup |
if your FPGA board does _not_ provide a UART interface. |
* **`rtl/test_setups/neorv32_testsetup_bootloader.vhd`**: this setups uses the UART and the default NEORV32 |
bootloader to upload new software executables. Use this setup if your board _does_ provide a UART interface. |
|
.NEORV32 "hello world" test setup (`rtl/test_setups/neorv32_testsetup_bootloader.vhd`) |
image::neorv32_test_setup.png[align=center] |
|
.External Clock Source |
[NOTE] |
These test setups are intended to be directly used as **design top entity**. Of course you can also instantiate them |
into another design unit. If your FPGA board only provides _very fast_ external clock sources (like on the FOMU board) |
you might need to add clock management components (PLLs, DCMs, MMCMs, ...) to the test setup or to the according top entity |
if you instantiate one of the test setups. |
|
[start=1] |
. Create a new project with your FPGA EDA tool of choice. |
. Add all VHDL files from the project's `rtl/core` folder to your project. |
|
.Internal Memories |
[IMPORTANT] |
For a _general_ first setup (technology-independent) use the `*.default.vhd` memory architectures for the internal memories |
(IMEM and DMEM). These are located in `rtl/core/mem` so make sure to add the files to your project, too. + |
+ |
If synthesis cannot efficiently map those default memory descriptions to the available memory resources, you can later replace the |
default memory architectures by optimized platform-specific memory architectures. **Example:** The `setups/radiant/UPduino_v3` |
example setup uses optimized memory primitives. Hence, it does not include the default memory architectures from |
`rtl/core/mem` as these are replaced by device-specific implementations. However, it still has to include the entity |
definitions from `rtl/core`. |
|
[start=3] |
. Make sure to add all the rtl files to a new library called `neorv32`. If your FPGA tools does not |
provide a field to enter the library name, check out the "properties" menu of the added rtl files. |
|
.Compile order |
[NOTE] |
Some tools (like Lattice Radiant) might require a _manual compile order_ of the VHDL source files to identify the dependencies. |
The package file `neorv32_package.vhd` should be analyzed first followed by the memory image files (`neorv32_application_imagevhd` |
and `neorv32_bootloader_image.vhd`) and the entity-only files (`neorv32_*mem.entity.vhd`). |
|
[start=4] |
. The `rtl/core/neorv32_top.vhd` VHDL file is the top entity of the NEORV32 processor, which can be |
instantiated into the "real" project. However, in this tutorial we will use one of the pre-defined |
test setups from `rtl/test_setups` (see above). |
|
[IMPORTANT] |
Make sure to include the `neorv32` package into your design when instantiating the processor: add |
`library neorv32;` and `use neorv32.neorv32_package.all;` to your design unit. |
|
[start=5] |
. Add the pre-defined test setup of choice to the project, too, and select it as _top entity_. |
. The entity of both test setups |
provide a minimal set of configuration generics, that might have to be adapted to match your FPGA and board: |
|
.Test setup entity - configuration generics |
[source,vhdl] |
---- |
generic ( |
-- adapt these for your setup -- |
CLOCK_FREQUENCY : natural := 100000000; <1> |
MEM_INT_IMEM_SIZE : natural := 16*1024; <2> |
MEM_INT_DMEM_SIZE : natural := 8*1024 <3> |
); |
---- |
<1> Clock frequency of `clk_i` signal in Hertz |
<2> Default size of internal instruction memory: 16kB |
<3> Default size of internal data memory: 8kB |
|
[start=7] |
. If you feel like it - or if your FPGA does not provide sufficient resources - you can modify the |
_memory sizes_ (`MEM_INT_IMEM_SIZE` and `MEM_INT_DMEM_SIZE` - marked with notes "2" and "3"). But as mentioned |
above, let's keep things simple at first and use the standard configuration for now. |
. There is one generic that _has to be set according to your FPGA board_ setup: the actual clock frequency |
of the top's clock input signal (`clk_i`). Use the `CLOCK_FREQUENCY` generic to specify your clock source's |
frequency in Hertz (Hz). |
|
[NOTE] |
If you have changed the default memory configuration (`MEM_INT_IMEM_SIZE` and `MEM_INT_DMEM_SIZE` generics) |
keep those new sizes in mind - these values are required for setting |
up the software framework in the next section <<_general_software_framework_setup>>. |
|
[start=9] |
. Depending on your FPGA tool of choice, it is time to assign the signals of the test setup top entity to |
the according pins of your FPGA board. All the signals can be found in the entity declaration of the |
corresponding test setup: |
|
.Entity signals of `neorv32_testsetup_approm.vhd` |
[source,vhdl] |
---- |
port ( |
-- Global control -- |
clk_i : in std_ulogic; -- global clock, rising edge |
rstn_i : in std_ulogic; -- global reset, low-active, async |
-- GPIO -- |
gpio_o : out std_ulogic_vector(7 downto 0) -- parallel output |
); |
---- |
|
.Entity signals of `neorv32_testsetup_bootloader.vhd` |
[source,vhdl] |
---- |
port ( |
-- Global control -- |
clk_i : in std_ulogic; -- global clock, rising edge |
rstn_i : in std_ulogic; -- global reset, low-active, async |
-- GPIO -- |
gpio_o : out std_ulogic_vector(7 downto 0); -- parallel output |
-- UART0 -- |
uart0_txd_o : out std_ulogic; -- UART0 send data |
uart0_rxd_i : in std_ulogic -- UART0 receive data |
); |
---- |
|
.Signal Polarity |
[NOTE] |
If your FPGA board has inverse polarity for certain input/output you can add `not` gates. Example: The reset signal |
`rstn_i` is low-active by default; the LEDs connected to `gpio_o` high-active by default. |
You can do this in your board top if you instantiate the test setup, |
or _inside_ the test setup if this is your top entity (low-active LEDs example: `gpio_o <= NOT con_gpio_o(7 downto 0);`). |
|
[start=10] |
. Attach the clock input `clk_i` to your clock source and connect the reset line `rstn_i` to a button of |
your FPGA board. Check whether it is low-active or high-active - the reset signal of the processor is |
**low-active**, so maybe you need to invert the input signal. |
. If possible, connected _at least_ bit `0` of the GPIO output port `gpio_o` to a LED (see "Signal Polarity" note above). |
. Finally, if your are using the UART-based test setup (`neorv32_testsetup_bootloader.vhd`) |
connect the UART communication signals `uart0_txd_o` and `uart0_rxd_i` to the host interface (e.g. USB-UART converter). |
. Perform the project HDL compilation (synthesis, mapping, bitstream generation). |
. Program the generated bitstream into your FPGA and press the button connected to the reset signal. |
. Done! The LED at `gpio_o(0)` should be flashing now. |
|
[TIP] |
After the GCC toolchain for compiling RISC-V source code is ready (chapter <<_general_software_framework_setup>>), |
you can advance to one of these chapters to learn how to get a software executable into your processor setup: |
* If you are using the `neorv32_testsetup_approm.vhd` setup: See section <<_installing_an_executable_directly_into_memory>>. |
* If you are using the `neorv32_testsetup_bootloader.vhd` setup: See section <<_uploading_and_starting_of_a_binary_executable_image_via_uart>>. |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== General Software Framework Setup |
|
To allow executables to be _actually executed_ on the NEORV32 Processor the configuration of the software framework |
has to be aware to the hardware configuration. This guide focuses on the memory configuration. To enabled |
certain CPU ISA features refer to the <<_enabling_risc_v_cpu_extensions>> section. |
|
[TIP] |
If you have **not** changed the _default_ memory configuration in section <<_general_hardware_setup>> |
you are already done and you can skip the rest of this guide. |
|
[start=1] |
. Open the NEORV32 linker script `sw/common/neorv32.ld` with a text editor. Right at the |
beginning of this script you will find the `MEMORY` configuration listing the different memory section: |
|
.Cut-out of the linker script `neorv32.ld`: `ram` memory section configuration |
[source,c] |
---- |
MEMORY |
{ |
ram (rwx) : ORIGIN = 0x80000000, LENGTH = DEFINED(make_bootloader) ? 512 : 8*1024 <1> |
... |
---- |
<1> Size of the data memory address space (right-most value) (internal/external DMEM); here 8kB |
|
[start=2] |
. We only need to change the `ram` section, which presents the available data address space. |
If you have changed the DMEM (_MEM_INT_DMEM_SIZE_ generic) size adapt the `LENGTH` parameter of the `ram` |
section (here: `8*1024`) so it is equal to your DMEM hardware configuration. |
|
[IMPORTANT] |
Make sure you only modify the _right-most_ value (here: 8*1024)! + |
The "`512`" are not relevant for the application. |
|
[start=3] |
. Done! Save your changes and close the linker script. |
|
.Advanced: Section base address and size |
[IMPORTANT] |
More information can be found in the datasheet section https://stnolting.github.io/neorv32/#_address_space[Address Space]. |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== Application Program Compilation |
|
This guide shows how to compile an example C-code application into a NEORV32 executable that |
can be uploaded via the bootloader or the on-chip debugger. |
|
[IMPORTANT] |
If your FPGA board does not provide such an interface - don't worry! |
Section <<_installing_an_executable_directly_into_memory>> shows how to |
run custom programs on your FPGA setup without having a UART. |
|
[start=1] |
. Open a terminal console and navigate to one of the project's example programs. For instance, navigate to the |
simple `sw/example_blink_led` example program. This program uses the NEORV32 GPIO module to display |
an 8-bit counter on the lowest eight bit of the `gpio_o` output port. |
. To compile the project and generate an executable simply execute: |
|
[source,bash] |
---- |
neorv32/sw/example/blink_led$ make clean_all exe |
---- |
|
[start=3] |
. We are using the `clean_all` target to make sure everything is re-build. |
. This will compile and link the application sources together with all the included libraries. At the end, |
your application is transformed into an ELF file (`main.elf`). The _NEORV32 image generator_ (in `sw/image_gen`) |
takes this file and creates a final executable. The makefile will show the resulting memory utilization and |
the executable size: |
|
[source,bash] |
---- |
neorv32/sw/example/blink_led$ make clean_all exe |
Memory utilization: |
text data bss dec hex filename |
3176 0 120 3296 ce0 main.elf |
Compiling ../../../sw/image_gen/image_gen |
Executable (neorv32_exe.bin) size in bytes: |
3188 |
---- |
|
[start=5] |
. That's it. The `exe` target has created the actual executable `neorv32_exe.bin` in the current folder |
that is ready to be uploaded to the processor. |
|
[TIP] |
The compilation process will also create a `main.asm` assembly listing file in the current folder, which |
shows the actual assembly code of the application. |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== Uploading and Starting of a Binary Executable Image via UART |
|
Follow this guide to use the bootloader to upload an executable via UART. |
|
[NOTE] |
This concept uses the default "Indirect Boot" scenario that uses the bootloader to upload new executables. |
See datasheet section https://stnolting.github.io/neorv32/#_indirect_boot[Indirect Boot] for more information. |
|
[IMPORTANT] |
If your FPGA board does not provide such an interface - don't worry! |
Section <<_installing_an_executable_directly_into_memory>> shows how to |
run custom programs on your FPGA setup without having a UART. |
|
[start=1] |
. Connect the primary UART (UART0) interface of your FPGA board to a serial port of your host computer. |
. Start a terminal program. In this tutorial, I am using TeraTerm for Windows. You can download it for free |
from https://ttssh2.osdn.jp/index.html.en . On Linux you could use GTKTerm, which you can get here |
https://github.com/Jeija/gtkterm.git (or install via your package manager). |
|
|
[NOTE] |
_Any_ terminal program that can connect to a serial port should work. However, make sure the program |
can transfer data in _raw_ byte mode without any protocol overhead around it. |
|
[start=3] |
. Open a connection to the the serial port your UART is connected to. Configure the terminal setting according to the |
following parameters: |
|
* 19200 Baud |
* 8 data bits |
* 1 stop bit |
* no parity bits |
* _no_ transmission/flow control protocol |
* receiver (host computer) newline on `\r\n` (carriage return & newline) |
|
[start=4] |
. Also make sure that single chars are send from your computer _without_ any consecutive "new line" or "carriage |
return" commands (this is highly dependent on your terminal application of choice, TeraTerm only |
sends the raw chars by default). |
. Press the NEORV32 reset button to restart the bootloader. The status LED starts blinking and the |
bootloader intro screen appears in your console. Hurry up and press any key (hit space!) to abort the |
automatic boot sequence and to start the actual bootloader user interface console. |
|
.Bootloader console; aborted auto-boot sequence |
[source,bash] |
---- |
<< NEORV32 Bootloader >> |
|
BLDV: Mar 23 2021 |
HWV: 0x01050208 |
CLK: 0x05F5E100 |
MISA: 0x40901105 |
ZEXT: 0x00000023 |
PROC: 0x0EFF0037 |
IMEM: 0x00004000 bytes @ 0x00000000 |
DMEM: 0x00002000 bytes @ 0x80000000 |
|
Autoboot in 8s. Press key to abort. |
Aborted. |
|
Available commands: |
h: Help |
r: Restart |
u: Upload |
s: Store to flash |
l: Load from flash |
e: Execute |
CMD:> |
---- |
|
[start=6] |
. Execute the "Upload" command by typing `u`. Now the bootloader is waiting for a binary executable to be send. |
|
[source,bash] |
---- |
CMD:> u |
Awaiting neorv32_exe.bin... |
---- |
|
[start=7] |
. Use the "send file" option of your terminal program to send a NEORV32 executable (`neorv32_exe.bin`). |
. Again, make sure to transmit the executable in raw binary mode (no transfer protocol). |
When using TeraTerm, select the "binary" option in the send file dialog. |
. If everything went fine, OK will appear in your terminal: |
|
[source,bash] |
---- |
CMD:> u |
Awaiting neorv32_exe.bin... OK |
---- |
|
[start=10] |
. The executable is now in the instruction memory of the processor. To execute the program right |
now run the "Execute" command by typing `e`: |
|
[source,bash] |
---- |
CMD:> u |
Awaiting neorv32_exe.bin... OK |
CMD:> e |
Booting... |
Blinking LED demo program |
---- |
|
[start=11] |
. If everything went fine, you should see the LEDs blinking. |
|
[NOTE] |
The bootloader will print error codes if something went wrong. |
See section https://stnolting.github.io/neorv32/#_bootloader[Bootloader] of the NEORV32 datasheet for more information. |
|
[TIP] |
See section <<_programming_an_external_spi_flash_via_the_bootloader>> to learn how to use an external SPI |
flash for nonvolatile program storage. |
|
[TIP] |
Executables can also be uploaded via the **on-chip debugger**. |
See section <<_debugging_with_gdb>> for more information. |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== Installing an Executable Directly Into Memory |
|
If you do not want to use the bootloader (or the on-chip debugger) for executable upload or if your setup does not provide |
a serial interface for that, you can also directly install an application into embedded memory. |
|
This concept uses the "Direct Boot" scenario that implements the processor-internal IMEM as ROM, which is |
pre-initialized with the application's executable during synthesis. Hence, it provides _non-volatile_ storage of the |
executable inside the processor. This storage cannot be altered during runtime and any source code modification of |
the application requires to re-program the FPGA via the bitstream. |
|
[TIP] |
See datasheet section https://stnolting.github.io/neorv32/#_direct_boot[Direct Boot] for more information. |
|
|
|
Using the IMEM as ROM: |
|
* for this boot concept the bootloader is no longer required |
* this concept only works for the internal IMEM (but can be extended to work with external memories coupled via the processor's bus interface) |
* make sure that the memory components (like block RAM) the IMEM is mapped to support an initialization via the bitstream |
|
[start=1] |
. At first, make sure your processor setup actually implements the internal IMEM: the `MEM_INT_IMEM_EN` generics has to be set to `true`: |
|
.Processor top entity configuration - enable internal IMEM |
[source,vhdl] |
---- |
-- Internal Instruction memory -- |
MEM_INT_IMEM_EN => true, -- implement processor-internal instruction memory |
---- |
|
[start=2] |
. For this setup we do not want the bootloader to be implemented at all. Disable implementation of the bootloader by setting the |
`INT_BOOTLOADER_EN` generic to `false`. This will also modify the processor-internal IMEM so it is initialized with the executable during synthesis. |
|
.Processor top entity configuration - disable internal bootloader |
[source,vhdl] |
---- |
-- General -- |
INT_BOOTLOADER_EN => false, -- boot configuration: false = boot from int/ext (I)MEM |
---- |
|
[start=3] |
. To generate an "initialization image" for the IMEM that contains the actual application, run the `install` target when compiling your application: |
|
[source,bash] |
---- |
neorv32/sw/example/blink_led$ make clean_all install |
Memory utilization: |
text data bss dec hex filename |
3176 0 120 3296 ce0 main.elf |
Compiling ../../../sw/image_gen/image_gen |
Installing application image to ../../../rtl/core/neorv32_application_image.vhd |
---- |
|
[start=4] |
. The `install` target has compiled all the application sources but instead of creating an executable (`neorv32_exe.bit`) that can be uploaded via the |
bootloader, it has created a VHDL memory initialization image `core/neorv32_application_image.vhd`. |
. This VHDL file is automatically copied to the core's rtl folder (`rtl/core`) so it will be included for the next synthesis. |
. Perform a new synthesis. The IMEM will be build as pre-initialized ROM (inferring embedded memories if possible). |
. Upload your bitstream. Your application code now resides unchangeable in the processor's IMEM and is directly executed after reset. |
|
|
The synthesis tool / simulator will print asserts to inform about the (IMEM) memory / boot configuration: |
|
[source] |
---- |
NEORV32 PROCESSOR CONFIG NOTE: Boot configuration: Direct boot from memory (processor-internal IMEM). |
NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal IMEM as ROM (3176 bytes), pre-initialized with application. |
---- |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== Setup of a New Application Program Project |
|
[start=1] |
. The easiest way of creating a _new_ software application project is to copy an _existing_ one. This will keep all |
file dependencies. For example you can copy `sw/example/blink_led` to `sw/example/flux_capacitor`. |
. If you want to place you application somewhere outside `sw/example` you need to adapt the application's makefile. |
In the makefile you will find a variable that keeps the relative or absolute path to the NEORV32 repository home |
folder. Just modify this variable according to your new project's home location: |
|
[source,makefile] |
---- |
# Relative or absolute path to the NEORV32 home folder (use default if not set by user) |
NEORV32_HOME ?= ../../.. |
---- |
|
[start=3] |
. If your project contains additional source files outside of the project folder, you can add them to |
the `APP_SRC` variable: |
|
[source,makefile] |
---- |
# User's application sources (add additional files here) |
APP_SRC = $(wildcard *.c) ../somewhere/some_file.c |
---- |
|
[start=4] |
. You also can add a folder containing your application's include files to the |
`APP_INC` variable (do not forget the `-I` prefix): |
|
[source,makefile] |
---- |
# User's application include folders (don't forget the '-I' before each entry) |
APP_INC = -I . -I ../somewhere/include_stuff_folder |
---- |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== Enabling RISC-V CPU Extensions |
|
Whenever you enable/disable a RISC-V CPU extensions via the according `CPU_EXTENSION_RISCV_x` generic, you need to |
adapt the toolchain configuration so the compiler can actually generate according code for it. |
|
To do so, open the makefile of your project (for example `sw/example/blink_led/makefile`) and scroll to the |
"USER CONFIGURATION" section right at the beginning of the file. You need to modify the `MARCH` variable and eventually |
the `MABI` variable according to your CPU hardware configuration. |
|
[source,makefile] |
---- |
# CPU architecture and ABI |
MARCH ?= rv32i <1> |
MABI ?= ilp32 <2> |
---- |
<1> MARCH = Machine architecture ("ISA string") |
<2> MABI = Machine binary interface |
|
For example, if you enable the RISC-V `C` extension (16-bit compressed instructions) via the `CPU_EXTENSION_RISCV_C` |
generic (set `true`) you need to add the `c` extension also to the `MARCH` ISA string in order to make the compiler |
emit compressed instructions. |
|
.Privileged Architecture Extensions |
[IMPORTANT] |
Privileged architecture extensions like `Zicsr` or `Zifencei` are "used" _implicitly_ by the compiler. Hence, according |
instruction will only be generated when "encoded" via inline assembly or when linking according libraries. In this case, |
these instruction will _always_ be emitted (even if the according extension is not specified in `MARCH`). + |
**I recommend to _not_ specify any privileged architecture extensions in `MARCH`.** |
|
[WARNING] |
ISA extension enabled in hardware can be a superset of the extensions enabled in software, but not the other way |
around. For example generating compressed instructions for a CPU configuration that has the `c` extension disabled |
will cause _illegal instruction exceptions_ at runtime. |
|
You can also override the default `MARCH` and `MABI` configurations from the makefile when invoking the makefile: |
|
[source,bash] |
---- |
$ make MARCH=rv32ic clean_all all |
---- |
|
[NOTE] |
The RISC-V ISA string for `MARCH` follows a certain _canonical_ structure: |
`rev32[i/e][m][a][f][d][g][q][c][b][v][n]...` For example `rv32imac` is valid while `rv32icma` is not. |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== Application-Specific Processor Configuration |
|
Due to the processor's configuration options, which are mainly defined via the top entity VHDL generics, the SoC |
can be tailored to the application-specific requirements. Note that this chapter does not focus on optional |
_SoC features_ like IO/peripheral modules. It rather gives ideas on how to optimize for _overall goals_ |
like performance and area. |
|
[NOTE] |
Please keep in mind that optimizing the design in one direction (like performance) will also effect other potential |
optimization goals (like area and energy). |
|
=== Optimize for Performance |
|
The following points show some concepts to optimize the processor for performance regardless of the costs |
(i.e. increasing area and energy requirements): |
|
* Enable all performance-related RISC-V CPU extensions that implement dedicated hardware accelerators instead |
of emulating operations entirely in software: `M`, `C`, `Zfinx` |
* Enable mapping of compleX CPU operations to dedicated hardware: `FAST_MUL_EN => true` to use DSP slices for |
multiplications, `FAST_SHIFT_EN => true` use a fast barrel shifter for shift operations. |
* Implement the instruction cache: `ICACHE_EN => true` |
* Use as many _internal_ memory as possible to reduce memory access latency: `MEM_INT_IMEM_EN => true` and |
`MEM_INT_DMEM_EN => true`, maximize `MEM_INT_IMEM_SIZE` and `MEM_INT_DMEM_SIZE` |
* Increase the CPU's instruction prefetch buffer size: `CPU_IPB_ENTRIES` |
* _To be continued..._ |
|
|
=== Optimize for Size |
|
The NEORV32 is a size-optimized processor system that is intended to fit into tiny niches within large SoC |
designs or to be used a customized microcontroller in really tiny / low-power FPGAs (like Lattice iCE40). |
Here are some ideas how to make the processor even smaller while maintaining it's _general purpose system_ |
concept and maximum RISC-V compatibility. |
|
**SoC** |
|
* This is obvious, but exclude all unused optional IO/peripheral modules from synthesis via the processor |
configuration generics. |
* If an IO module provides an option to configure the number of "channels", constrain this number to the |
actually required value (e.g. the PWM module `IO_PWM_NUM_CH` or the external interrupt controller `XIRQ_NUM_CH`). |
* Reduce the FIFO sizes of implemented modules (e.g. `SLINK_TX_FIFO`). |
* Disable the instruction cache (`ICACHE_EN => false`) if the design only uses processor-internal IMEM |
and DMEM memories. |
* _To be continued..._ |
|
**CPU** |
|
* Use the _embedded_ RISC-V CPU architecture extension (`CPU_EXTENSION_RISCV_E`) to reduce block RAM utilization. |
* The compressed instructions extension (`CPU_EXTENSION_RISCV_C`) requires additional logic for the decoder but |
also reduces program code size by approximately 30%. |
* If not explicitly used/required, constrain the CPU's counter sizes: `CPU_CNT_WIDTH` for `[m]instret[h]` |
(number of instruction) and `[m]cycle[h]` (number of cycles) counters. You can even remove these counters |
by setting `CPU_CNT_WIDTH => 0` if they are not used at all (note, this is not RISC-V compliant). |
* Reduce the CPU's prefetch buffer size (`CPU_IPB_ENTRIES`). |
* Map CPU shift operations to a small and iterative shifter unit (`FAST_SHIFT_EN => false`). |
* If you have unused DSP block available, you can map multiplication operations to those slices instead of |
using LUTs to implement the multiplier (`FAST_MUL_EN => true`). |
* If there is no need to execute division in hardware, use the `Zmmul` extension instead of the full-scale |
`M` extension. |
* Disable CPU extension that are not explicitly used (`A`, `U`, `Zfinx`). |
* _To be continued..._ |
|
=== Optimize for Clock Speed |
|
The NEORV32 Processor and CPU are designed to provide minimal logic between register stages to keep the |
critical path as short as possible. When enabling additional extension or modules the impact on the existing |
logic is also kept at a minimum to prevent timing degrading. If there is a major impact on existing |
logic (example: many physical memory protection address configuration registers) the VHDL code automatically |
adds additional register stages to maintain critical path length. Obviously, this increases operation latency. |
|
In order to optimize for a minimal critical path (= maximum clock speed) the following points should be considered: |
|
* Complex CPU extensions (in terms of hardware requirements) should be avoided (examples: floating-point unit, physical memory protection). |
* Large carry chains (>32-bit) should be avoided (constrain CPU counter sizes: e.g. `CPU_CNT_WIDTH => 32` and `HPM_NUM_CNTS => 32`). |
* If the target FPGA provides sufficient DSP resources, CPU multiplication operations can be mapped to DSP slices (`FAST_MUL_EN => true`) |
reducing LUT usage and critical path impact while also increasing overall performance. |
* Use the synchronous (registered) RX path configuration of the external memory interface (`MEM_EXT_ASYNC_RX => false`). |
* _To be continued..._ |
|
[NOTE] |
The short and fixed-length critical path allows to integrate the core into existing clock domains. |
So no clock domain-crossing and no sub-clock generation is required. However, for very high clock |
frequencies (this is technology / platform dependent) clock domain crossing becomes crucial for chip-internal |
connections. |
|
|
=== Optimize for Energy |
|
There are no _dedicated_ configuration options to optimize the processor for energy (minimal consumption; |
energy/instruction ratio) yet. However, a reduced processor area (<<_optimize_for_size>>) will also reduce |
static energy consumption. |
|
To optimize your setup for low-power applications, you can make use of the CPU sleep mode (`wfi` instruction). |
Put the CPU to sleep mode whenever possible. Disable all processor modules that are not actually used (exclude them |
from synthesis if the will be _never_ used; disable the module via it's control register if the module is not |
_currently_ used). When is sleep mode, you can keep a timer module running (MTIME or the watch dog) to wake up |
the CPU again. Since the wake up is triggered by _any_ interrupt, the external interrupt controller can also |
be used to wake up the CPU again. By this, all timers (and all other modules) can be deactivated as well. |
|
.Processor-internal clock generator shutdown |
[TIP] |
If _no_ IO/peripheral module is currently enabled, the processor's internal clock generator circuit will be |
shut down reducing switching activity and thus, dynamic energy consumption. |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== Adding Custom Hardware Modules |
|
In resemblance to the RISC-V ISA, the NEORV32 processor was designed to ease customization and _extensibility_. |
The processor provides several predefined options to add application-specific custom hardware modules and accelerators. |
|
|
=== Standard (_External_) Interfaces |
|
The processor already provides a set of standard interfaces that are intended to connect _chip-external_ devices. |
However, these interfaces can also be used chip-internally. The most suitable interfaces are |
https://stnolting.github.io/neorv32/#_general_purpose_input_and_output_port_gpio[GPIO], |
https://stnolting.github.io/neorv32/#_primary_universal_asynchronous_receiver_and_transmitter_uart0[UART], |
https://stnolting.github.io/neorv32/#_serial_peripheral_interface_controller_spi[SPI] and |
https://stnolting.github.io/neorv32/#_two_wire_serial_interface_controller_twi[TWI]. |
|
The SPI and (especially) the GPIO interfaces might be the most straightforward approaches since they |
have a minimal protocol overhead. Device-specific interrupt capabilities can be added using the |
https://stnolting.github.io/neorv32/#_external_interrupt_controller_xirq[External Interrupt Controller (XIRQ)]. |
Beyond simplicity, these interface only provide a very limited bandwidth and require more sophisticated |
software handling ("bit-banging" for the GPIO). |
|
|
=== External Bus Interface |
|
The https://stnolting.github.io/neorv32/#_processor_external_memory_interface_wishbone_axi4_lite[External Bus Interface] |
provides the classic approach to connect to custom IP. By default, the bus interface implements the widely adopted |
Wishbone interface standard. However, this project also includes wrappers to bridge to other protocol standards like ARM's |
AXI4-Lite or Intel's Avalon. By using a full-featured bus protocol, complex SoC structures can be implemented (including |
several modules and even multi-core architectures). Many FPGA EDA tools provide graphical editors to build and customize |
whole SoC architectures and even include pre-defined IP libraries. |
|
.Example AXI SoC using Xilinx Vivado |
image::neorv32_axi_soc.png[] |
|
The bus interface uses a memory-mapped approach. All data transfers are handled by simple load/store operations since the |
external bus interface is mapped into the processor's https://stnolting.github.io/neorv32/#_address_space[address space]. |
This allows a very simple still high-bandwidth communications. |
|
|
=== Stream Link Interface |
|
The NEORV32 https://stnolting.github.io/neorv32/#_stream_link_interface_slink[Stream Link Interface] provides |
point-to-point, unidirectional and parallel data channels that can be used to transfer streaming data. In |
contrast to the external bus interface, the streaming data does not provide any kind of "direction" control, |
so it can be seen as "constant address bursts". The stream link interface provides less protocol overhead |
and less latency than the bus interface. Furthermore, FIFOs can be be configured to each direction (RX/TX) to |
allow more CPU-independent operation. |
|
|
=== Custom Functions Subsystem |
|
The NEORV32 https://stnolting.github.io/neorv32/#_custom_functions_subsystem_cfs[Custom Functions Subsystem] is |
an "empty" template for a processor-internal module. It provides 32 32-bit memory-mapped interface |
registers that can be used to communicate with any arbitrary custom design logic. The intentions of this |
subsystem is to provide a simple base, where the user can concentrate on implementing the actual design logic |
rather than taking care of the communication between the CPU/software and the design logic. The interface |
registers are already allocated within the processor's address space and are supported by the software framework |
via low-level hardware access mechanisms. Additionally, the CFS provides a direct pre-defined interrupt channel to |
the CPU, which is also supported by the NEORV32 runtime environment. |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== Customizing the Internal Bootloader |
|
The NEORV32 bootloader provides several options to configure and customize it for a certain application setup. |
This configuration is done by passing _defines_ when compiling the bootloader. Of course you can also |
modify to bootloader source code to provide a setup that perfectly fits your needs. |
|
[IMPORTANT] |
Each time the bootloader sources are modified, the bootloader has to be re-compiled (and re-installed to the |
bootloader ROM) and the processor has to be re-synthesized. |
|
[NOTE] |
Keep in mind that the maximum size for the bootloader is limited to 32kB and should be compiled using the |
base ISA `rv32i` only to ensure it can work independently of the actual CPU configuration. |
|
.Bootloader configuration parameters |
[cols="<2,^1,^2,<6"] |
[options="header", grid="rows"] |
|======================= |
| Parameter | Default | Legal values | Description |
4+^| Serial console interface |
| `UART_EN` | `1` | `0`, `1` | Set to `0` to disable UART0 (no serial console at all) |
| `UART_BAUD` | `19200` | _any_ | Baud rate of UART0 |
4+^| Status LED |
| `STATUS_LED_EN` | `1` | `0`, `1` | Enable bootloader status led ("heart beat") at `GPIO` output port pin #`STATUS_LED_PIN` when `1` |
| `STATUS_LED_PIN` | `0` | `0` ... `31` | `GPIO` output pin used for the high-active status LED |
4+^| Boot configuration |
| `AUTO_BOOT_SPI_EN` | `0` | `0`, `1` | Set `1` to enable immediate boot from external SPI flash |
| `AUTO_BOOT_OCD_EN` | `0` | `0`, `1` | Set `1` to enable boot via on-chip debugger (OCD) |
| `AUTO_BOOT_TIMEOUT` | `8` | _any_ | Time in seconds after the auto-boot sequence starts (if there is no UART input by user); set to 0 to disabled auto-boot sequence |
4+^| SPI configuration |
| `SPI_EN` | `1` | `0`, `1` | Set `1` to enable the usage of the SPI module (including load/store executables from/to SPI flash options) |
| `SPI_FLASH_CS` | `0` | `0` ... `7` | SPI chip select output (`spi_csn_o`) for selecting flash |
| `SPI_FLASH_SECTOR_SIZE` | `65536` | _any_ | SPI flash sector size in bytes |
| `SPI_FLASH_CLK_PRSC` | `CLK_PRSC_8` | `CLK_PRSC_2` `CLK_PRSC_4` `CLK_PRSC_8` `CLK_PRSC_64` `CLK_PRSC_128` `CLK_PRSC_1024` `CLK_PRSC_2024` `CLK_PRSC_4096` | SPI clock pre-scaler (dividing main processor clock) |
| `SPI_BOOT_BASE_ADDR` | `0x08000000` | _any_ 32-bit value | Defines the _base_ address of the executable in external flash |
|======================= |
|
Each configuration parameter is implemented as C-language `define` that can be manually overridden (_redefined_) when |
invoking the bootloader's makefile. The according parameter and its new value has to be _appended_ |
(using `+=`) to the makefile `USER_FLAGS` variable. Make sure to use the `-D` prefix here. |
|
For example, to configure a UART Baud rate of 57600 and redirecting the status LED to output pin 20 |
use the following command (_in_ the bootloader's source folder `sw/bootloader`): |
|
.Example: customizing, re-compiling and re-installing the bootloader |
[source,console] |
---- |
$ make USER_FLAGS+=-DUART_BAUD=57600 USER_FLAGS+=-DSTATUS_LED_PIN=20 clean_all bootloader |
---- |
|
[NOTE] |
The `clean_all` target ensure that all libraries are re-compiled. The `bootloader` target will automatically |
compile and install the bootloader to the HDL boot ROM (updating `rtl/core/neorv32_bootloader_image.vhd`). |
|
:sectnums: |
=== Bootloader Boot Configuration |
|
The bootloader provides several _boot configurations_ that define where the actual application's executable |
shall be fetched from. Note that the non-default boot configurations provide a smaller memory footprint |
reducing boot ROM implementation costs. |
|
:sectnums!: |
==== Default Boot Configuration |
|
The _default_ bootloader configuration provides a UART-based user interface that allows to upload new executables |
at any time. Optionally, the executable can also be programmed to an external SPI flash by the bootloader (see |
section <<_programming_an_external_spi_flash_via_the_bootloader>>). |
|
This configuration also provides an _automatic boot sequence_ (auto-boot) which will start fetching an executable |
from external SPI flash using the default SPI configuration. By this, the default bootloader configuration |
provides a "non volatile program storage" mechanism that automatically boot from external SPI flash |
(after `AUTO_BOOT_TIMEOUT`) while still providing the option to re-program SPI flash at any time |
via the UART interface. |
|
:sectnums!: |
==== `AUTO_BOOT_SPI_EN` |
|
The automatic boot from SPI flash (enabled when `AUTO_BOOT_SPI_EN` is `1`) will fetch an executable from an external |
SPI flash (using the according _SPI configuration_) right after reset. The bootloader will start fetching |
the image at SPI flash base address `SPI_BOOT_BASE_ADDR`. |
|
Note that there is _no_ UART console to interact with the bootloader. However, this boot configuration will |
output minimal status messages via UART (if `UART_EN` is `1`). |
|
:sectnums!: |
==== `AUTO_BOOT_OCD_EN` |
|
If `AUTO_BOOT_OCD_EN` is `1` the bootloader is implemented as minimal "halt loop" to be used with the on-chip debugger. |
After initializing the hardware, the CPU waits in this endless loop until the on-chip debugger takes control over |
the core (to upload and run the actual executable). See section <<_debugging_using_the_on_chip_debugger>> |
for more information on how to use the on-chip debugger to upload and run executables. |
|
[NOTE] |
All bootloader boot configuration support uploading new executables via the on-chip debugger. |
|
[WARNING] |
Note that this boot configuration does not load any executable at all! Hence, |
this boot configuration is intended to be used with the on-chip debugger only. |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== Programming an External SPI Flash via the Bootloader |
|
The default processor-internal NEORV32 bootloader supports automatic booting from an external SPI flash. |
This guide shows how to write an executable to the SPI flash via the bootloader so it can be automatically |
fetched and executed after processor reset. For example, you can use a section of the FPGA bitstream configuration |
memory to store an application executable. |
|
[NOTE] |
This section assumes the _default_ configuration of the NEORV32 bootloader. |
See section <<_customizing_the_internal_bootloader>> on how to customize the bootloader and its setting |
(for example the SPI chip-select port, the SPI clock speed or the flash base address for storing the executable). |
|
|
:sectnums: |
=== SPI Flash |
|
The bootloader can access an SPI compatible flash via the processor top entity's SPI port. By default, the flash |
chip-select line is to `spi_csn_o(0)` and uses 1/8 of the processor's main clock as clock frequency. |
The SPI flash has to support single-byte read and write, 24-bit addresses and at least the following standard commands: |
|
* READ `0x03` |
* READ STATUS `0x05` |
* WRITE ENABLE `0x06` |
* PAGE PROGRAM `0x02` |
* SECTOR ERASE `0xD8` |
* READ ID `0x9E` |
|
Compatible (FGPA configuration) SPI flash memories are for example the "Winbond W25Q64FV2 or the "Micron N25Q032A". |
|
|
:sectnums: |
=== Programming an Executable |
|
[start=1] |
. At first, reset the NEORV32 processor and wait until the bootloader start screen appears in your terminal program. |
. Abort the auto boot sequence and start the user console by pressing any key. |
. Press u to upload the executable that you want to store to the external flash: |
|
[source] |
---- |
CMD:> u |
Awaiting neorv32_exe.bin... |
---- |
|
[start=4] |
. Send the binary in raw binary via your terminal program. When the upload is completed and "OK" |
appears, press `p` to trigger the programming of the flash (do not execute the image via the `e` |
command as this might corrupt the image): |
|
[source] |
---- |
CMD:> u |
Awaiting neorv32_exe.bin... OK |
CMD:> p |
Write 0x000013FC bytes to SPI flash @ 0x00800000? (y/n) |
---- |
|
[start=5] |
. The bootloader shows the size of the executable and the base address inside the SPI flash where the |
executable is going to be stored. A prompt appears: Type `y` to start the programming or type `n` to |
abort. |
|
[TIP] |
Section <<_customizing_the_internal_bootloader>> show the according C-language `define` that can be modified |
to specify the base address of the executable inside the SPI flash. |
|
[source] |
---- |
CMD:> u |
Awaiting neorv32_exe.bin... OK |
CMD:> p |
Write 0x000013FC bytes to SPI flash @ 0x08000000? (y/n) y |
Flashing... OK |
CMD:> |
---- |
|
[start=6] |
. If "OK" appears in the terminal line, the programming process was successful. Now you can use the |
auto boot sequence to automatically boot your application from the flash at system start-up without |
any user interaction. |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== Packaging the Processor as IP block for Xilinx Vivado Block Designer |
|
[start=1] |
. Import all the core files from `rtl/core` (including default internal memory architectures from `rtl/core/mem`) |
and assign them to a _new_ design library `neorv32`. |
. Instantiate the `rtl/wrappers/neorv32_top_axi4lite.vhd` module. |
. Then either directly use that module in a new block-design ("Create Block Design", right-click -> "Add Module", |
thats easier for a first try) or package it ("Tools", "Create and Package new IP") for the use in other projects. |
. Connect your AXI-peripheral directly to the core's AXI4-Interface if you only have one, or to an AXI-Interconnect |
(from the IP-catalog) if you have multiple peripherals. |
. Connect ALL the `ACLK` and `ARESETN` pins of all peripherals and interconnects to the processor's clock and reset |
signals to have a _unified_ clock and reset domain (easier for a first setup). |
. Open the "Address Editor" tab and let Vivado assign the base-addresses for the AXI-peripherals (you can modify them |
according to your needs). |
. For all FPGA-external signals (like UART signals) make all the connections you need "external" |
(right-click on the signal/pin -> "Make External"). |
. Save everything, let VIVADO create a HDL-Wrapper for the block-design and choose this as your _Top Level Design_. |
. Define your constraints and generate your bitstream. |
|
.TWI Tri-State Drivers |
[IMPORTANT] |
Set the synthesis option "global" when generating the block design to maintain the internal TWI tri-state drivers. |
|
[NOTE] |
Guide provided by GitHub user https://github.com/AWenzel83[`AWenzel83`] (see |
https://github.com/stnolting/neorv32/discussions/52#discussioncomment-819013). ❤️ |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== Simulating the Processor |
|
The NEORV32 project includes a core CPU, built-in peripherals in the Processor Subsystem, and additional peripherals in |
the templates and examples. |
Therefore, there is a wide range of possible testing and verification strategies. |
|
On the one hand, a simple smoke testbench allows ensuring that functionality is correct from a software point of view. |
That is used for running the RISC-V architecture tests, in order to guarantee compliance with the ISA specification(s). |
|
On the other hand, http://vunit.github.io/[VUnit] and http://vunit.github.io/verification_components/user_guide.html[Verification Components] are used for verifying the functionality of the various peripherals from a hardware point of view. |
|
:sectnums: |
=== Testbench |
|
A plain-VHDL (no third-party libraries) testbench (`sim/simple/neorv32_tb.simple.vhd`) can be used for simulating and |
testing the processor. |
This testbench features a 100MHz clock and enables all optional peripheral and CPU extensions except for the `E` |
extension and the TRNG IO module (that CANNOT be simulated due to its combinatorial (looped) architecture). |
|
The simulation setup is configured via the "User Configuration" section located right at the beginning of |
the testbench's architecture. Each configuration constant provides comments to explain the functionality. |
|
Besides the actual NEORV32 Processor, the testbench also simulates "external" components that are connected |
to the processor's external bus/memory interface. These components are: |
|
* an external instruction memory (that also allows booting from it) |
* an external data memory |
* an external memory to simulate "external IO devices" |
* a memory-mapped registers to trigger the processor's interrupt signals |
|
The following table shows the base addresses of these four components and their default configuration and |
properties: |
|
[NOTE] |
==== |
Attributes: |
|
* `r` = read |
* `w` = write |
* `e` = execute |
* `a` = atomic accesses possible |
* `8` = byte-accessible |
* `16` = half-word-accessible |
* `32` = word-accessible |
==== |
|
.Testbench: processor-external memories |
[cols="^4,>3,^5,<11"] |
[options="header",grid="rows"] |
|======================= |
| Base address | Size | Attributes | Description |
| `0x00000000` | `imem_size_c` | `r/w/e, a, 8/16/32` | external IMEM (initialized with application image) |
| `0x80000000` | `dmem_size_c` | `r/w/e, a, 8/16/32` | external DMEM |
| `0xf0000000` | 64 bytes | `r/w/e, !a, 8/16/32` | external "IO" memory, atomic accesses will fail |
| `0xff000000` | 4 bytes | `-/w/-, a, -/-/32` | memory-mapped register to trigger "machine external", "machine software" and "SoC Fast Interrupt" interrupts |
|======================= |
|
[IMPORTANT] |
The simulated NEORV32 does not use the bootloader and _directly boots_ the current application image (from |
the `rtl/core/neorv32_application_image.vhd` image file). |
|
.UART output during simulation |
[IMPORTANT] |
Data written to the NEORV32 UART0 / UART1 transmitter is send to a virtual UART receiver implemented |
as part of the testbench. Received chars are send to the simulator console and are also stored to a log file |
(`neorv32.testbench_uart0.out` for UART0, `neorv32.testbench_uart1.out` for UART1) inside the simulation's home folder. |
**Please note that printing via the native UART receiver takes a lot of time.** For faster simulation console output |
see section <<_faster_simulation_console_output>>. |
|
|
:sectnums: |
=== Faster Simulation Console Output |
|
When printing data via the UART the communication speed will always be based on the configured BAUD |
rate. For a simulation this might take some time. To have faster output you can enable the **simulation mode** |
for UART0/UART1 (see section https://stnolting.github.io/neorv32/#_primary_universal_asynchronous_receiver_and_transmitter_uart0[Documentation: Primary Universal Asynchronous Receiver and Transmitter (UART0)]). |
|
ASCII data sent to UART0|UART1 will be immediately printed to the simulator console and logged to files in the simulator |
execution directory: |
|
* `neorv32.uart?.sim_mode.text.out`: ASCII data. |
* `neorv32.uart?.sim_mode.data.out`: all written 32-bit dumped as 8-char hexadecimal values. |
|
You can "automatically" enable the simulation mode of UART0/UART1 when compiling an application. |
In this case, the "real" UART0/UART1 transmitter unit is permanently disabled. |
To enable the simulation mode just compile and install your application and add _UART?_SIM_MODE_ to the compiler's |
_USER_FLAGS_ variable (do not forget the `-D` suffix flag): |
|
[source, bash] |
---- |
sw/example/blink_led$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all all |
---- |
|
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. |
|
[NOTE] |
The UART simulation output (to file and to screen) outputs "complete lines" at once. A line is |
completed with a line feed (newline, ASCII `\n` = 10). |
|
|
:sectnums: |
=== Simulation using a shell script (with GHDL) |
|
To simulate the processor using _GHDL_ navigate to the `sim/simple/` folder and run the provided shell script. |
Any arguments that are provided while executing this script are passed to GHDL. |
For example the simulation time can be set to 20ms using `--stop-time=20ms` as argument. |
|
[source, bash] |
---- |
neorv32/sim/simple$ sh ghdl_sim.sh --stop-time=20ms |
---- |
|
|
:sectnums: |
=== Simulation using Application Makefiles (In-Console with GHDL) |
|
To directly compile and run a program in the console (using the default testbench and GHDL |
as simulator) you can use the `sim` makefile target. Make sure to use the UART simulation mode |
(`USER_FLAGS+=-DUART0_SIM_MODE` and/or `USER_FLAGS+=-DUART1_SIM_MODE`) to get |
faster / direct-to-console UART output. |
|
[source, bash] |
---- |
sw/example/blink_led$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all sim |
[...] |
Blinking LED demo program |
---- |
|
|
:sectnums: |
==== Hello World! |
|
To do a quick test of the NEORV32 make sure to have https://github.com/ghdl/ghdl[GHDL] and a |
[RISC-V gcc toolchain](https://github.com/stnolting/riscv-gcc-prebuilt) installed. |
Navigate to the project's `sw/example/hello_world` folder and run `make USER_FLAGS+=-DUART0_SIM_MODE MARCH=rv32imac clean_all sim`: |
|
[TIP] |
The simulator will output some _sanity check_ notes (and warnings or even errors if something is ill-configured) |
right at the beginning of the simulation to give a brief overview of the actual NEORV32 SoC and CPU configurations. |
|
[source, bash] |
---- |
stnolting@Einstein:/mnt/n/Projects/neorv32/sw/example/hello_world$ make USER_FLAGS+=-DUART0_SIM_MODE MARCH=rv32imac clean_all sim |
../../../sw/lib/source/neorv32_uart.c: In function 'neorv32_uart0_setup': |
../../../sw/lib/source/neorv32_uart.c:301:4: warning: #warning UART0_SIM_MODE (primary UART) enabled! Sending all UART0.TX data to text.io simulation output instead of real UART0 transmitter. Use this for simulations only! [-Wcpp] |
301 | #warning UART0_SIM_MODE (primary UART) enabled! Sending all UART0.TX data to text.io simulation output instead of real UART0 transmitter. Use this for simulations only! <1> |
| ^~~~~~~ |
Memory utilization: |
text data bss dec hex filename |
4612 0 120 4732 127c main.elf <2> |
Compiling ../../../sw/image_gen/image_gen |
Installing application image to ../../../rtl/core/neorv32_application_image.vhd <3> |
Simulating neorv32_application_image.vhd... |
Tip: Compile application with USER_FLAGS+=-DUART[0/1]_SIM_MODE to auto-enable UART[0/1]'s simulation mode (redirect UART output to simulator console). <4> |
Using simulation runtime args: --stop-time=10ms <5> |
../rtl/core/neorv32_top.vhd:347:3:@0ms:(assertion note): NEORV32 PROCESSOR IO Configuration: GPIO MTIME UART0 UART1 SPI TWI PWM WDT CFS SLINK NEOLED XIRQ <6> |
../rtl/core/neorv32_top.vhd:370:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Boot configuration: Direct boot from memory (processor-internal IMEM). |
../rtl/core/neorv32_top.vhd:394:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing on-chip debugger (OCD). |
../rtl/core/neorv32_cpu.vhd:169:3:@0ms:(assertion note): NEORV32 CPU ISA Configuration (MARCH): RV32IMACU_Zbb_Zicsr_Zifencei_Zfinx_Debug |
../rtl/core/neorv32_cpu.vhd:189:3:@0ms:(assertion note): NEORV32 CPU CONFIG NOTE: Implementing NO dedicated hardware reset for uncritical registers (default, might reduce area). Set package constant <dedicated_reset_c> = TRUE to configure a DEFINED reset value for all CPU registers. |
../rtl/core/neorv32_imem.vhd:107:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal IMEM as ROM (16384 bytes), pre-initialized with application (4612 bytes). |
../rtl/core/neorv32_dmem.vhd:89:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal DMEM (RAM, 8192 bytes). |
../rtl/core/neorv32_wishbone.vhd:136:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing STANDARD Wishbone protocol. |
../rtl/core/neorv32_wishbone.vhd:140:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing auto-timeout (255 cycles). |
../rtl/core/neorv32_wishbone.vhd:144:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing LITTLE-endian byte order. |
../rtl/core/neorv32_wishbone.vhd:148:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing registered RX path. |
../rtl/core/neorv32_slink.vhd:161:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing 8 RX and 8 TX stream links. |
<7> |
## |
## ## ## ## |
## ## ######### ######## ######## ## ## ######## ######## ## ################ |
#### ## ## ## ## ## ## ## ## ## ## ## ## ## #### #### |
## ## ## ## ## ## ## ## ## ## ## ## ## ## ###### ## |
## ## ## ######### ## ## ######### ## ## ##### ## ## #### ###### #### |
## ## ## ## ## ## ## ## ## ## ## ## ## ## ###### ## |
## #### ## ## ## ## ## ## ## ## ## ## ## #### #### |
## ## ######### ######## ## ## ## ######## ########## ## ################ |
## ## ## ## |
## |
Hello world! :) |
---- |
<1> Notifier that "simulation mode" of UART0 is enabled (by the `USER_FLAGS+=-DUART0_SIM_MODE` makefile flag). All UART0 output is send to the simulator console. |
<2> Final executable size (`text`) and _static_ data memory requirements (`data`, `bss`). |
<3> The application code is _installed_ as pre-initialized IMEM. This is the default approach for simulation. |
<4> A note regarding UART "simulation mode", but we have already enabled that. |
<5> List of (default) arguments that were send to the simulator. Here: maximum simulation time (10ms). |
<6> "Sanity checks" from the core's VHDL files. These reports give some brief information about the SoC/CPU configuration (-> generics). If there are problems with the current configuration, an ERROR will appear. |
<7> Execution of the actual program starts. |
|
|
:sectnums: |
=== Advanced Simulation using VUnit |
|
https://vunit.github.io/[VUnit] is an open source unit testing framework for VHDL/SystemVerilog. |
It allows continuous and automated testing of HDL code by complementing traditional testing methodologies. |
The motto of VUnit is _"testing early and often"_ through automation. |
|
VUnit is composed by a http://vunit.github.io/py/ui.html[Python interface] and multiple optional |
http://vunit.github.io/vhdl_libraries.html[VHDL libraries]. |
The Python interface allows declaring sources and simulation options, and it handles the compilation, execution and |
gathering of the results regardless of the simulator used. |
That allows having a single `run.py` script to be used with GHDL, ModelSim/QuestaSim, Riviera PRO, etc. |
On the other hand, the VUnit's VHDL libraries provide utilities for assertions, logging, having virtual queues, handling CSV files, etc. |
The http://vunit.github.io/verification_components/user_guide.html[Verification Component Library] uses those features |
for abstracting away bit-toggling when verifying standard interfaces such as Wishbone, AXI, Avalon, UARTs, etc. |
|
Testbench sources in `sim` (such as `sim/neorv32_tb.vhd` and `sim/uart_rx*.vhd`) use VUnit's VHDL libraries for testing |
NEORV32 and peripherals. |
The entry-point for executing the tests is `sim/run.py`. |
|
[source, bash] |
---- |
# ./sim/run.py -l |
neorv32.neorv32_tb.all |
Listed 1 tests |
|
# ./sim/run.py -v |
Compiling into neorv32: rtl/core/neorv32_uart.vhd passed |
Compiling into neorv32: rtl/core/neorv32_twi.vhd passed |
Compiling into neorv32: rtl/core/neorv32_trng.vhd passed |
... |
---- |
|
See http://vunit.github.io/user_guide.html[VUnit: User Guide] and http://vunit.github.io/cli.html[VUnit: Command Line Interface] for further info about VUnit's features. |
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== Building the Documentation |
|
The documentation (datasheet + user guide) is written using `asciidoc`. The according source files |
can be found in `docs/...`. The documentation of the software framework is written _in-code_ using `doxygen`. |
|
A makefiles in the project's `docs` directory is provided to build all of the documentation as HTML pages |
or as PDF documents. |
|
[TIP] |
Pre-rendered PDFs are available online as _nightly pre-releases_: https://github.com/stnolting/neorv32/releases. |
The HTML-based documentation is also available online at the project's https://stnolting.github.io/neorv32/[GitHub Pages]. |
|
The makefile provides a help target to show all available build options and their according outputs. |
|
[source,bash] |
---- |
neorv32/docs$ make help |
---- |
|
.Example: Generate HTML documentation (data sheet) using `asciidoctor` |
[source,bash] |
---- |
neorv32/docs$ make html |
---- |
|
[TIP] |
If you don't have `asciidoctor` / `asciidoctor-pdf` installed, you can still generate all the documentation using |
a _docker container_ via `make container`. |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== Zephyr RTOS Support 🪁 |
|
The NEORV32 processor is supported by upstream Zephyr RTOS: https://docs.zephyrproject.org/latest/boards/riscv/neorv32/doc/index.html |
|
[IMPORTANT] |
The absolute path to the NEORV32 executable image generator binary (`.../neorv32/sw/image_gen`) has to be added to the `PATH` variable |
so the Zephyr build system can generate executables and memory-initialization images. |
|
[NOTE] |
Zephyr OS port provided by GitHub user https://github.com/henrikbrixandersen[henrikbrixandersen] |
(see https://github.com/stnolting/neorv32/discussions/172). ❤️ |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== FreeRTOS Support |
|
A NEORV32-specific port and a simple demo for FreeRTOS (https://github.com/FreeRTOS/FreeRTOS) are |
available in the `sw/example/demo_freeRTOS` folder. See the according documentation (`sw/example/demo_freeRTOS/README.md`) |
for more information. |
|
|
|
// #################################################################################################################### |
:sectnums: |
== RISC-V Architecture Test Framework |
|
The NEORV32 Processor passes the according tests provided by the official RISC-V Architecture Test Suite |
(V2.0+), which is available online at GitHub: https://github.com/riscv/riscv-arch-test |
|
All files required for executing the test framework on a simulated instance of the processor (including port |
files) are located in the `sw/isa-test` folder of the NEORV32 repository. The test framework is executed via the |
`sim/run_riscv_arch_test.sh` script. Take a look at the provided `sim/README.md` |
(https://github.com/stnolting/neorv32/tree/master/sim[online at GitHub]) |
file for more information on how to run the tests and how testing is conducted in detail. |
|
|
|
<<< |
// #################################################################################################################### |
:sectnums: |
== Debugging using the On-Chip Debugger |
|
The NEORV32 on-chip debugger allows _online_ in-system debugging via an external JTAG access port from a |
host machine. The general flow is independent of the host machine's operating system. However, this tutorial uses |
Windows and Linux (Ubuntu on Windows) in parallel. |
|
[TIP] |
See datasheet section https://stnolting.github.io/neorv32/#_on_chip_debugger_ocd[On Chip Debugger (OCD)] |
for more information. |
|
[NOTE] |
This tutorial uses `gdb` to **directly upload an executable** to the processor. If you are using the default |
processor setup _with_ internal instruction memory (IMEM) make sure it is implemented as RAM |
(_INT_BOOTLOADER_EN_ generic = true). |
|
[IMPORTANT] |
The on-chip debugger is only implemented if the _ON_CHIP_DEBUGGER_EN_ generic is set _true_. Furthermore, it requires |
the `Zicsr` and `Zifencei` CPU extension to be implemented (top generics _CPU_EXTENSION_RISCV_Zicsr_ |
and _CPU_EXTENSION_RISCV_Zifencei_ = true). |
|
|
:sectnums: |
=== Hardware Requirements |
|
Make sure the on-chip debugger of your NEORV32 setups is implemented (_ON_CHIP_DEBUGGER_EN_ generic = true). |
Connect a JTAG adapter to the NEORV32 `jtag_*` interface signals. If you do not have a full-scale JTAG adapter, you can |
also use a FTDI-based adapter like the "FT2232H-56Q Mini Module", which is a simple and inexpensive FTDI breakout board. |
|
.JTAG pin mapping |
[cols="^3,^2,^2"] |
[options="header",grid="rows"] |
|======================= |
| NEORV32 top signal | JTAG signal | FTDI port |
| `jtag_tck_i` | TCK | D0 |
| `jtag_tdi_i` | TDI | D1 |
| `jtag_tdo_o` | TDO | D2 |
| `jtag_tms_i` | TMS | D3 |
| `jtag_trst_i` | TRST | D4 |
|======================= |
|
[TIP] |
The low-active JTAG _test reset_ (TRST) signals is _optional_ as a reset can also be triggered via the TAP controller. |
If TRST is not used make sure to pull the signal _high_. |
|
|
:sectnums: |
=== OpenOCD |
|
The NEORV32 on-chip debugger can be accessed using the https://github.com/riscv/riscv-openocd[RISC-V port of OpenOCD]. |
Prebuilt binaries can be obtained - for example - from https://www.sifive.com/software[SiFive]. A pre-configured |
OpenOCD configuration file (`sw/openocd/openocd_neorv32.cfg`) is available that allows easy access to the NEORV32 CPU. |
|
[NOTE] |
You might need to adapt `ftdi_vid_pid`, `ftdi_channel` and `ftdi_layout_init` in `sw/openocd/openocd_neorv32.cfg` |
according to your interface chip and your operating system. |
|
[TIP] |
If you want to modify the JTAG clock speed (via `adapter speed` in `sw/openocd/openocd_neorv32.cfg`) make sure to meet |
the clock requirements noted in https://stnolting.github.io/neorv32/#_debug_module_dm[Documentation: Debug Transport Module (DTM)]. |
|
To access the processor using OpenOCD, open a terminal and start OpenOCD with the pre-configured configuration file. |
|
.Connecting via OpenOCD (on Windows) |
[source, bash] |
-------------------------- |
N:\Projects\neorv32\sw\openocd>openocd -f openocd_neorv32.cfg |
Open On-Chip Debugger 0.11.0-rc1+dev (SiFive OpenOCD 0.10.0-2020.12.1) |
Licensed under GNU GPL v2 |
For bug reports: |
https://github.com/sifive/freedom-tools/issues |
1 |
Info : Listening on port 6666 for tcl connections |
Info : Listening on port 4444 for telnet connections |
Info : clock speed 1000 kHz |
Info : JTAG tap: neorv32.cpu tap/device found: 0x0cafe001 (mfg: 0x000 (<invalid>), part: 0xcafe, ver: 0x0) |
Info : datacount=1 progbufsize=2 |
Info : Disabling abstract command reads from CSRs. |
Info : Examined RISC-V core; found 1 harts |
Info : hart 0: XLEN=32, misa=0x40801105 |
Info : starting gdb server for neorv32.cpu.0 on 3333 |
Info : Listening on port 3333 for gdb connections |
-------------------------- |
|
OpenOCD has successfully connected to the NEORV32 on-chip debugger and has examined the CPU (showing the content of |
the `misa` CSRs). Now you can use `gdb` to connect via port 3333. |
|
|
:sectnums: |
=== Debugging with GDB |
|
This guide uses the simple "blink example" from `sw/example/blink_led` as simplified test application to |
show the basics of in-system debugging. |
|
At first, the application needs to be compiled. We will use the minimal machine architecture configuration |
(`rv32i`) here to be independent of the actual processor/CPU configuration. |
Navigate to `sw/example/blink_led` and compile the application: |
|
.Compile the test application |
[source, bash] |
-------------------------- |
.../neorv32/sw/example/blink_led$ make MARCH=rv32i USER_FLAGS+=-g clean_all all |
-------------------------- |
|
.Adding debug symbols to the executable |
[NOTE] |
`USER_FLAGS+=-g` passes the `-g` flag to the compiler so it adds debug information/symbols |
to the generated ELF file. This is optional but will provide more sophisticated information for debugging |
(like source file line numbers). |
|
This will generate an ELF file `main.elf` that contains all the symbols required for debugging. |
Furthermore, an assembly listing file `main.asm` is generated that we will use to define breakpoints. |
|
Open another terminal in `sw/example/blink_led` and start `gdb`. |
The GNU debugger is part of the toolchain (see <<_software_toolchain_setup>>). |
|
.Starting GDB (on Linux (Ubuntu on Windows)) |
[source, bash] |
-------------------------- |
.../neorv32/sw/example/blink_led$ riscv32-unknown-elf-gdb |
GNU gdb (GDB) 10.1 |
Copyright (C) 2020 Free Software Foundation, Inc. |
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> |
This is free software: you are free to change and redistribute it. |
There is NO WARRANTY, to the extent permitted by law. |
Type "show copying" and "show warranty" for details. |
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv32-unknown-elf". |
Type "show configuration" for configuration details. |
For bug reporting instructions, please see: |
<https://www.gnu.org/software/gdb/bugs/>. |
Find the GDB manual and other documentation resources online at: |
<http://www.gnu.org/software/gdb/documentation/>. |
|
For help, type "help". |
Type "apropos word" to search for commands related to "word". |
(gdb) |
-------------------------- |
|
Now connect to OpenOCD using the default port 3333 on your machine. |
We will use the previously generated ELF file `main.elf` from the `blink_led` example. |
Finally, upload the program to the processor and start debugging. |
|
[NOTE] |
The executable that is uploaded to the processor is **not** the default NEORV32 executable (`neorv32_exe.bin`) that |
is used for uploading via the bootloader. Instead, all the required sections (like `.text`) are extracted from `mail.elf` |
by GDB and uploaded via the debugger's indirect memory access. |
|
.Running GDB |
[source, bash] |
-------------------------- |
(gdb) target extended-remote localhost:3333 <1> |
Remote debugging using localhost:3333 |
warning: No executable has been specified and target does not support |
determining executable automatically. Try using the "file" command. |
0xffff0c94 in ?? () <2> |
(gdb) file main.elf <3> |
A program is being debugged already. |
Are you sure you want to change the file? (y or n) y |
Reading symbols from main.elf... |
(gdb) load <4> |
Loading section .text, size 0xd0c lma 0x0 |
Loading section .rodata, size 0x39c lma 0xd0c |
Start address 0x00000000, load size 4264 |
Transfer rate: 43 KB/sec, 2132 bytes/write. |
(gdb) |
-------------------------- |
<1> Connect to OpenOCD |
<2> The CPU was still executing code from the bootloader ROM - but that does not matter here |
<3> Select `mail.elf` from the `blink_led` example |
<4> Upload the executable |
|
After the upload, GDB will make the processor jump to the beginning of the uploaded executable |
(by default, this is the beginning of the instruction memory at `0x00000000`) skipping the bootloader |
and halting the CPU right before executing the `blink_led` application. |
|
|
:sectnums: |
==== Breakpoint Example |
|
The following steps are just a small showcase that illustrate a simple debugging scheme. |
|
While compiling `blink_led`, an assembly listing file `main.asm` was generated. |
Open this file with a text editor to check out what the CPU is going to do when resumed. |
|
The `blink_led` example implements a simple counter on the 8 lowest GPIO output ports. The program uses |
"busy wait" to have a visible delay between increments. This waiting is done by calling the `neorv32_cpu_delay_ms` |
function. We will add a _breakpoint_ right at the end of this wait function so we can step through the iterations |
of the counter. |
|
.Cut-out from `main.asm` generated from the `blink_led` example |
[source, assembly] |
-------------------------- |
00000688 <__neorv32_cpu_delay_ms_end>: |
688: 01c12083 lw ra,28(sp) |
68c: 02010113 addi sp,sp,32 |
690: 00008067 ret |
-------------------------- |
|
The very last instruction of the `neorv32_cpu_delay_ms` function is `ret` (= return) |
at hexadecimal `690` in this example. Add this address as _breakpoint_ to GDB. |
|
[NOTE] |
The address might be different if you use a different version of the software framework or |
if different ISA options are configured. |
|
.Adding a GDB breakpoint |
[source, bash] |
-------------------------- |
(gdb) b * 0x690 |
Breakpoint 1 at 0x690 |
-------------------------- |
|
.How do breakpoints work? |
[TIP] |
The NEORV32 on-chip debugger does not provide any hardware breakpoints (RISC-V "trigger modules") that compare an address like the PC |
with a predefined value. Instead, gdb will modify the actual executable in IMEM: the actual instruction at the address |
of the specified breakpoint is replaced by a `break` / `c.break` instruction. Whenever execution reaches this instruction, debug mode is |
re-entered and the debugger restores the original instruction at this address to maintain original program behavior. |
|
Now execute `c` (= continue). The CPU will resume operation until it hits the break-point. |
By this we can "step" from increment to increment. |
|
.Iterating from breakpoint to breakpoint |
[source, bash] |
-------------------------- |
Breakpoint 1 at 0x690 |
(gdb) c |
Continuing. |
|
Breakpoint 1, 0x00000690 in neorv32_cpu_delay_ms () |
(gdb) c |
Continuing. |
|
Breakpoint 1, 0x00000690 in neorv32_cpu_delay_ms () |
(gdb) c |
Continuing. |
-------------------------- |
|
include::../legal.adoc[] |
/docs/userguide/customizing_the_bootloader.adoc
0,0 → 1,100
<<< |
:sectnums: |
== Customizing the Internal Bootloader |
|
The NEORV32 bootloader provides several options to configure and customize it for a certain application setup. |
This configuration is done by passing _defines_ when compiling the bootloader. Of course you can also |
modify to bootloader source code to provide a setup that perfectly fits your needs. |
|
[IMPORTANT] |
Each time the bootloader sources are modified, the bootloader has to be re-compiled (and re-installed to the |
bootloader ROM) and the processor has to be re-synthesized. |
|
[NOTE] |
Keep in mind that the maximum size for the bootloader is limited to 32kB and should be compiled using the |
base ISA `rv32i` only to ensure it can work independently of the actual CPU configuration. |
|
.Bootloader configuration parameters |
[cols="<2,^1,^2,<6"] |
[options="header", grid="rows"] |
|======================= |
| Parameter | Default | Legal values | Description |
4+^| Serial console interface |
| `UART_EN` | `1` | `0`, `1` | Set to `0` to disable UART0 (no serial console at all) |
| `UART_BAUD` | `19200` | _any_ | Baud rate of UART0 |
4+^| Status LED |
| `STATUS_LED_EN` | `1` | `0`, `1` | Enable bootloader status led ("heart beat") at `GPIO` output port pin #`STATUS_LED_PIN` when `1` |
| `STATUS_LED_PIN` | `0` | `0` ... `31` | `GPIO` output pin used for the high-active status LED |
4+^| Boot configuration |
| `AUTO_BOOT_SPI_EN` | `0` | `0`, `1` | Set `1` to enable immediate boot from external SPI flash |
| `AUTO_BOOT_OCD_EN` | `0` | `0`, `1` | Set `1` to enable boot via on-chip debugger (OCD) |
| `AUTO_BOOT_TIMEOUT` | `8` | _any_ | Time in seconds after the auto-boot sequence starts (if there is no UART input by user); set to 0 to disabled auto-boot sequence |
4+^| SPI configuration |
| `SPI_EN` | `1` | `0`, `1` | Set `1` to enable the usage of the SPI module (including load/store executables from/to SPI flash options) |
| `SPI_FLASH_CS` | `0` | `0` ... `7` | SPI chip select output (`spi_csn_o`) for selecting flash |
| `SPI_FLASH_SECTOR_SIZE` | `65536` | _any_ | SPI flash sector size in bytes |
| `SPI_FLASH_CLK_PRSC` | `CLK_PRSC_8` | `CLK_PRSC_2` `CLK_PRSC_4` `CLK_PRSC_8` `CLK_PRSC_64` `CLK_PRSC_128` `CLK_PRSC_1024` `CLK_PRSC_2024` `CLK_PRSC_4096` | SPI clock pre-scaler (dividing main processor clock) |
| `SPI_BOOT_BASE_ADDR` | `0x08000000` | _any_ 32-bit value | Defines the _base_ address of the executable in external flash |
|======================= |
|
Each configuration parameter is implemented as C-language `define` that can be manually overridden (_redefined_) when |
invoking the bootloader's makefile. The according parameter and its new value has to be _appended_ |
(using `+=`) to the makefile `USER_FLAGS` variable. Make sure to use the `-D` prefix here. |
|
For example, to configure a UART Baud rate of 57600 and redirecting the status LED to output pin 20 |
use the following command (_in_ the bootloader's source folder `sw/bootloader`): |
|
.Example: customizing, re-compiling and re-installing the bootloader |
[source,console] |
---- |
$ make USER_FLAGS+=-DUART_BAUD=57600 USER_FLAGS+=-DSTATUS_LED_PIN=20 clean_all bootloader |
---- |
|
[NOTE] |
The `clean_all` target ensure that all libraries are re-compiled. The `bootloader` target will automatically |
compile and install the bootloader to the HDL boot ROM (updating `rtl/core/neorv32_bootloader_image.vhd`). |
|
:sectnums: |
=== Bootloader Boot Configuration |
|
The bootloader provides several _boot configurations_ that define where the actual application's executable |
shall be fetched from. Note that the non-default boot configurations provide a smaller memory footprint |
reducing boot ROM implementation costs. |
|
:sectnums!: |
==== Default Boot Configuration |
|
The _default_ bootloader configuration provides a UART-based user interface that allows to upload new executables |
at any time. Optionally, the executable can also be programmed to an external SPI flash by the bootloader (see |
section <<_programming_an_external_spi_flash_via_the_bootloader>>). |
|
This configuration also provides an _automatic boot sequence_ (auto-boot) which will start fetching an executable |
from external SPI flash using the default SPI configuration. By this, the default bootloader configuration |
provides a "non volatile program storage" mechanism that automatically boot from external SPI flash |
(after `AUTO_BOOT_TIMEOUT`) while still providing the option to re-program SPI flash at any time |
via the UART interface. |
|
:sectnums!: |
==== `AUTO_BOOT_SPI_EN` |
|
The automatic boot from SPI flash (enabled when `AUTO_BOOT_SPI_EN` is `1`) will fetch an executable from an external |
SPI flash (using the according _SPI configuration_) right after reset. The bootloader will start fetching |
the image at SPI flash base address `SPI_BOOT_BASE_ADDR`. |
|
Note that there is _no_ UART console to interact with the bootloader. However, this boot configuration will |
output minimal status messages via UART (if `UART_EN` is `1`). |
|
:sectnums!: |
==== `AUTO_BOOT_OCD_EN` |
|
If `AUTO_BOOT_OCD_EN` is `1` the bootloader is implemented as minimal "halt loop" to be used with the on-chip debugger. |
After initializing the hardware, the CPU waits in this endless loop until the on-chip debugger takes control over |
the core (to upload and run the actual executable). See section <<_debugging_using_the_on_chip_debugger>> |
for more information on how to use the on-chip debugger to upload and run executables. |
|
[NOTE] |
All bootloader boot configuration support uploading new executables via the on-chip debugger. |
|
[WARNING] |
Note that this boot configuration does not load any executable at all! Hence, |
this boot configuration is intended to be used with the on-chip debugger only. |
/docs/userguide/debugging_with_ocd.adoc
0,0 → 1,238
<<< |
:sectnums: |
== Debugging using the On-Chip Debugger |
|
The NEORV32 on-chip debugger allows _online_ in-system debugging via an external JTAG access port from a |
host machine. The general flow is independent of the host machine's operating system. However, this tutorial uses |
Windows and Linux (Ubuntu on Windows) in parallel. |
|
[TIP] |
See datasheet section https://stnolting.github.io/neorv32/#_on_chip_debugger_ocd[On Chip Debugger (OCD)] |
for more information. |
|
[NOTE] |
This tutorial uses `gdb` to **directly upload an executable** to the processor. If you are using the default |
processor setup _with_ internal instruction memory (IMEM) make sure it is implemented as RAM |
(_INT_BOOTLOADER_EN_ generic = true). |
|
[IMPORTANT] |
The on-chip debugger is only implemented if the _ON_CHIP_DEBUGGER_EN_ generic is set _true_. Furthermore, it requires |
the `Zicsr` and `Zifencei` CPU extension to be implemented (top generics _CPU_EXTENSION_RISCV_Zicsr_ |
and _CPU_EXTENSION_RISCV_Zifencei_ = true). |
|
|
:sectnums: |
=== Hardware Requirements |
|
Make sure the on-chip debugger of your NEORV32 setups is implemented (_ON_CHIP_DEBUGGER_EN_ generic = true). |
Connect a JTAG adapter to the NEORV32 `jtag_*` interface signals. If you do not have a full-scale JTAG adapter, you can |
also use a FTDI-based adapter like the "FT2232H-56Q Mini Module", which is a simple and inexpensive FTDI breakout board. |
|
.JTAG pin mapping |
[cols="^3,^2,^2"] |
[options="header",grid="rows"] |
|======================= |
| NEORV32 top signal | JTAG signal | FTDI port |
| `jtag_tck_i` | TCK | D0 |
| `jtag_tdi_i` | TDI | D1 |
| `jtag_tdo_o` | TDO | D2 |
| `jtag_tms_i` | TMS | D3 |
| `jtag_trst_i` | TRST | D4 |
|======================= |
|
[TIP] |
The low-active JTAG _test reset_ (TRST) signals is _optional_ as a reset can also be triggered via the TAP controller. |
If TRST is not used make sure to pull the signal _high_. |
|
|
:sectnums: |
=== OpenOCD |
|
The NEORV32 on-chip debugger can be accessed using the https://github.com/riscv/riscv-openocd[RISC-V port of OpenOCD]. |
Prebuilt binaries can be obtained - for example - from https://www.sifive.com/software[SiFive]. A pre-configured |
OpenOCD configuration file (`sw/openocd/openocd_neorv32.cfg`) is available that allows easy access to the NEORV32 CPU. |
|
[NOTE] |
You might need to adapt `ftdi_vid_pid`, `ftdi_channel` and `ftdi_layout_init` in `sw/openocd/openocd_neorv32.cfg` |
according to your interface chip and your operating system. |
|
[TIP] |
If you want to modify the JTAG clock speed (via `adapter speed` in `sw/openocd/openocd_neorv32.cfg`) make sure to meet |
the clock requirements noted in https://stnolting.github.io/neorv32/#_debug_module_dm[Documentation: Debug Transport Module (DTM)]. |
|
To access the processor using OpenOCD, open a terminal and start OpenOCD with the pre-configured configuration file. |
|
.Connecting via OpenOCD (on Windows) |
[source, bash] |
-------------------------- |
N:\Projects\neorv32\sw\openocd>openocd -f openocd_neorv32.cfg |
Open On-Chip Debugger 0.11.0-rc1+dev (SiFive OpenOCD 0.10.0-2020.12.1) |
Licensed under GNU GPL v2 |
For bug reports: |
https://github.com/sifive/freedom-tools/issues |
1 |
Info : Listening on port 6666 for tcl connections |
Info : Listening on port 4444 for telnet connections |
Info : clock speed 1000 kHz |
Info : JTAG tap: neorv32.cpu tap/device found: 0x0cafe001 (mfg: 0x000 (<invalid>), part: 0xcafe, ver: 0x0) |
Info : datacount=1 progbufsize=2 |
Info : Disabling abstract command reads from CSRs. |
Info : Examined RISC-V core; found 1 harts |
Info : hart 0: XLEN=32, misa=0x40801105 |
Info : starting gdb server for neorv32.cpu.0 on 3333 |
Info : Listening on port 3333 for gdb connections |
-------------------------- |
|
OpenOCD has successfully connected to the NEORV32 on-chip debugger and has examined the CPU (showing the content of |
the `misa` CSRs). Now you can use `gdb` to connect via port 3333. |
|
|
:sectnums: |
=== Debugging with GDB |
|
This guide uses the simple "blink example" from `sw/example/blink_led` as simplified test application to |
show the basics of in-system debugging. |
|
At first, the application needs to be compiled. We will use the minimal machine architecture configuration |
(`rv32i`) here to be independent of the actual processor/CPU configuration. |
Navigate to `sw/example/blink_led` and compile the application: |
|
.Compile the test application |
[source, bash] |
-------------------------- |
.../neorv32/sw/example/blink_led$ make MARCH=rv32i USER_FLAGS+=-g clean_all all |
-------------------------- |
|
.Adding debug symbols to the executable |
[NOTE] |
`USER_FLAGS+=-g` passes the `-g` flag to the compiler so it adds debug information/symbols |
to the generated ELF file. This is optional but will provide more sophisticated information for debugging |
(like source file line numbers). |
|
This will generate an ELF file `main.elf` that contains all the symbols required for debugging. |
Furthermore, an assembly listing file `main.asm` is generated that we will use to define breakpoints. |
|
Open another terminal in `sw/example/blink_led` and start `gdb`. |
The GNU debugger is part of the toolchain (see <<_software_toolchain_setup>>). |
|
.Starting GDB (on Linux (Ubuntu on Windows)) |
[source, bash] |
-------------------------- |
.../neorv32/sw/example/blink_led$ riscv32-unknown-elf-gdb |
GNU gdb (GDB) 10.1 |
Copyright (C) 2020 Free Software Foundation, Inc. |
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> |
This is free software: you are free to change and redistribute it. |
There is NO WARRANTY, to the extent permitted by law. |
Type "show copying" and "show warranty" for details. |
This GDB was configured as "--host=x86_64-pc-linux-gnu --target=riscv32-unknown-elf". |
Type "show configuration" for configuration details. |
For bug reporting instructions, please see: |
<https://www.gnu.org/software/gdb/bugs/>. |
Find the GDB manual and other documentation resources online at: |
<http://www.gnu.org/software/gdb/documentation/>. |
|
For help, type "help". |
Type "apropos word" to search for commands related to "word". |
(gdb) |
-------------------------- |
|
Now connect to OpenOCD using the default port 3333 on your machine. |
We will use the previously generated ELF file `main.elf` from the `blink_led` example. |
Finally, upload the program to the processor and start debugging. |
|
[NOTE] |
The executable that is uploaded to the processor is **not** the default NEORV32 executable (`neorv32_exe.bin`) that |
is used for uploading via the bootloader. Instead, all the required sections (like `.text`) are extracted from `mail.elf` |
by GDB and uploaded via the debugger's indirect memory access. |
|
.Running GDB |
[source, bash] |
-------------------------- |
(gdb) target extended-remote localhost:3333 <1> |
Remote debugging using localhost:3333 |
warning: No executable has been specified and target does not support |
determining executable automatically. Try using the "file" command. |
0xffff0c94 in ?? () <2> |
(gdb) file main.elf <3> |
A program is being debugged already. |
Are you sure you want to change the file? (y or n) y |
Reading symbols from main.elf... |
(gdb) load <4> |
Loading section .text, size 0xd0c lma 0x0 |
Loading section .rodata, size 0x39c lma 0xd0c |
Start address 0x00000000, load size 4264 |
Transfer rate: 43 KB/sec, 2132 bytes/write. |
(gdb) |
-------------------------- |
<1> Connect to OpenOCD |
<2> The CPU was still executing code from the bootloader ROM - but that does not matter here |
<3> Select `mail.elf` from the `blink_led` example |
<4> Upload the executable |
|
After the upload, GDB will make the processor jump to the beginning of the uploaded executable |
(by default, this is the beginning of the instruction memory at `0x00000000`) skipping the bootloader |
and halting the CPU right before executing the `blink_led` application. |
|
|
:sectnums: |
==== Breakpoint Example |
|
The following steps are just a small showcase that illustrate a simple debugging scheme. |
|
While compiling `blink_led`, an assembly listing file `main.asm` was generated. |
Open this file with a text editor to check out what the CPU is going to do when resumed. |
|
The `blink_led` example implements a simple counter on the 8 lowest GPIO output ports. The program uses |
"busy wait" to have a visible delay between increments. This waiting is done by calling the `neorv32_cpu_delay_ms` |
function. We will add a _breakpoint_ right at the end of this wait function so we can step through the iterations |
of the counter. |
|
.Cut-out from `main.asm` generated from the `blink_led` example |
[source, assembly] |
-------------------------- |
00000688 <__neorv32_cpu_delay_ms_end>: |
688: 01c12083 lw ra,28(sp) |
68c: 02010113 addi sp,sp,32 |
690: 00008067 ret |
-------------------------- |
|
The very last instruction of the `neorv32_cpu_delay_ms` function is `ret` (= return) |
at hexadecimal `690` in this example. Add this address as _breakpoint_ to GDB. |
|
[NOTE] |
The address might be different if you use a different version of the software framework or |
if different ISA options are configured. |
|
.Adding a GDB breakpoint |
[source, bash] |
-------------------------- |
(gdb) b * 0x690 |
Breakpoint 1 at 0x690 |
-------------------------- |
|
.How do breakpoints work? |
[TIP] |
The NEORV32 on-chip debugger does not provide any hardware breakpoints (RISC-V "trigger modules") that compare an address like the PC |
with a predefined value. Instead, gdb will modify the actual executable in IMEM: the actual instruction at the address |
of the specified breakpoint is replaced by a `break` / `c.break` instruction. Whenever execution reaches this instruction, debug mode is |
re-entered and the debugger restores the original instruction at this address to maintain original program behavior. |
|
Now execute `c` (= continue). The CPU will resume operation until it hits the break-point. |
By this we can "step" from increment to increment. |
|
.Iterating from breakpoint to breakpoint |
[source, bash] |
-------------------------- |
Breakpoint 1 at 0x690 |
(gdb) c |
Continuing. |
|
Breakpoint 1, 0x00000690 in neorv32_cpu_delay_ms () |
(gdb) c |
Continuing. |
|
Breakpoint 1, 0x00000690 in neorv32_cpu_delay_ms () |
(gdb) c |
Continuing. |
-------------------------- |
/docs/userguide/enabling_riscv_extensions.adoc
0,0 → 1,46
<<< |
:sectnums: |
== Enabling RISC-V CPU Extensions |
|
Whenever you enable/disable a RISC-V CPU extensions via the according `CPU_EXTENSION_RISCV_x` generic, you need to |
adapt the toolchain configuration so the compiler can actually generate according code for it. |
|
To do so, open the makefile of your project (for example `sw/example/blink_led/makefile`) and scroll to the |
"USER CONFIGURATION" section right at the beginning of the file. You need to modify the `MARCH` variable and eventually |
the `MABI` variable according to your CPU hardware configuration. |
|
[source,makefile] |
---- |
# CPU architecture and ABI |
MARCH ?= rv32i <1> |
MABI ?= ilp32 <2> |
---- |
<1> MARCH = Machine architecture ("ISA string") |
<2> MABI = Machine binary interface |
|
For example, if you enable the RISC-V `C` extension (16-bit compressed instructions) via the `CPU_EXTENSION_RISCV_C` |
generic (set `true`) you need to add the `c` extension also to the `MARCH` ISA string in order to make the compiler |
emit compressed instructions. |
|
.Privileged Architecture Extensions |
[IMPORTANT] |
Privileged architecture extensions like `Zicsr` or `Zifencei` are "used" _implicitly_ by the compiler. Hence, according |
instruction will only be generated when "encoded" via inline assembly or when linking according libraries. In this case, |
these instruction will _always_ be emitted (even if the according extension is not specified in `MARCH`). + |
**I recommend to _not_ specify any privileged architecture extensions in `MARCH`.** |
|
[WARNING] |
ISA extension enabled in hardware can be a superset of the extensions enabled in software, but not the other way |
around. For example generating compressed instructions for a CPU configuration that has the `c` extension disabled |
will cause _illegal instruction exceptions_ at runtime. |
|
You can also override the default `MARCH` and `MABI` configurations from the makefile when invoking the makefile: |
|
[source,bash] |
---- |
$ make MARCH=rv32ic clean_all all |
---- |
|
[NOTE] |
The RISC-V ISA string for `MARCH` follows a certain _canonical_ structure: |
`rev32[i/e][m][a][f][d][g][q][c][b][v][n]...` For example `rv32imac` is valid while `rv32icma` is not. |
/docs/userguide/executable_upload.adoc
0,0 → 1,120
<<< |
:sectnums: |
== Uploading and Starting of a Binary Executable Image via UART |
|
Follow this guide to use the bootloader to upload an executable via UART. |
|
[NOTE] |
This concept uses the default "Indirect Boot" scenario that uses the bootloader to upload new executables. |
See datasheet section https://stnolting.github.io/neorv32/#_indirect_boot[Indirect Boot] for more information. |
|
[IMPORTANT] |
If your FPGA board does not provide such an interface - don't worry! |
Section <<_installing_an_executable_directly_into_memory>> shows how to |
run custom programs on your FPGA setup without having a UART. |
|
[start=1] |
. Connect the primary UART (UART0) interface of your FPGA board to a serial port of your host computer. |
. Start a terminal program. In this tutorial, I am using TeraTerm for Windows. You can download it for free |
from https://ttssh2.osdn.jp/index.html.en . On Linux you could use GTKTerm, which you can get here |
https://github.com/Jeija/gtkterm.git (or install via your package manager). |
|
|
[NOTE] |
_Any_ terminal program that can connect to a serial port should work. However, make sure the program |
can transfer data in _raw_ byte mode without any protocol overhead around it. |
|
[start=3] |
. Open a connection to the the serial port your UART is connected to. Configure the terminal setting according to the |
following parameters: |
|
* 19200 Baud |
* 8 data bits |
* 1 stop bit |
* no parity bits |
* _no_ transmission/flow control protocol |
* receiver (host computer) newline on `\r\n` (carriage return & newline) |
|
[start=4] |
. Also make sure that single chars are send from your computer _without_ any consecutive "new line" or "carriage |
return" commands (this is highly dependent on your terminal application of choice, TeraTerm only |
sends the raw chars by default). |
. Press the NEORV32 reset button to restart the bootloader. The status LED starts blinking and the |
bootloader intro screen appears in your console. Hurry up and press any key (hit space!) to abort the |
automatic boot sequence and to start the actual bootloader user interface console. |
|
.Bootloader console; aborted auto-boot sequence |
[source,bash] |
---- |
<< NEORV32 Bootloader >> |
|
BLDV: Mar 23 2021 |
HWV: 0x01050208 |
CLK: 0x05F5E100 |
MISA: 0x40901105 |
ZEXT: 0x00000023 |
PROC: 0x0EFF0037 |
IMEM: 0x00004000 bytes @ 0x00000000 |
DMEM: 0x00002000 bytes @ 0x80000000 |
|
Autoboot in 8s. Press key to abort. |
Aborted. |
|
Available commands: |
h: Help |
r: Restart |
u: Upload |
s: Store to flash |
l: Load from flash |
e: Execute |
CMD:> |
---- |
|
[start=6] |
. Execute the "Upload" command by typing `u`. Now the bootloader is waiting for a binary executable to be send. |
|
[source,bash] |
---- |
CMD:> u |
Awaiting neorv32_exe.bin... |
---- |
|
[start=7] |
. Use the "send file" option of your terminal program to send a NEORV32 executable (`neorv32_exe.bin`). |
. Again, make sure to transmit the executable in raw binary mode (no transfer protocol). |
When using TeraTerm, select the "binary" option in the send file dialog. |
. If everything went fine, OK will appear in your terminal: |
|
[source,bash] |
---- |
CMD:> u |
Awaiting neorv32_exe.bin... OK |
---- |
|
[start=10] |
. The executable is now in the instruction memory of the processor. To execute the program right |
now run the "Execute" command by typing `e`: |
|
[source,bash] |
---- |
CMD:> u |
Awaiting neorv32_exe.bin... OK |
CMD:> e |
Booting... |
Blinking LED demo program |
---- |
|
[start=11] |
. If everything went fine, you should see the LEDs blinking. |
|
[NOTE] |
The bootloader will print error codes if something went wrong. |
See section https://stnolting.github.io/neorv32/#_bootloader[Bootloader] of the NEORV32 datasheet for more information. |
|
[TIP] |
See section <<_programming_an_external_spi_flash_via_the_bootloader>> to learn how to use an external SPI |
flash for nonvolatile program storage. |
|
[TIP] |
Executables can also be uploaded via the **on-chip debugger**. |
See section <<_debugging_with_gdb>> for more information. |
/docs/userguide/free_rtos_support.adoc
0,0 → 1,7
<<< |
:sectnums: |
== FreeRTOS Support |
|
A NEORV32-specific port and a simple demo for FreeRTOS (https://github.com/FreeRTOS/FreeRTOS) are |
available in the `sw/example/demo_freeRTOS` folder. See the according documentation (`sw/example/demo_freeRTOS/README.md`) |
for more information. |
/docs/userguide/general_hw_setup.adoc
0,0 → 1,156
<<< |
:sectnums: |
== General Hardware Setup |
|
This guide shows the basics of setting up a NEORV32 project for FPGA implementation (or simulation only) |
_from scratch_. It uses a _simplified_ test "SoC" setup of the processor to keeps things simple at the beginning. |
This simple setup is intended for evaluation or as "hello world" project to check out the NEORV32 |
on _your_ FPGA board. |
|
[TIP] |
If you want to use a more sophisticated pre-defined setup to start with, check out the |
`setups` folder, which provides example setups for various FPGA, boards and toolchains. |
|
The NEORV32 project features two minimalistic pre-configured test setups in |
https://github.com/stnolting/neorv32/blob/master/rtl/test_setups[`rtl/test_setups`]. |
Both test setups only implement very basic processor and CPU features. |
The main difference between the two setups is the processor boot concept - so how to get a software executable |
_into_ the processor: |
|
* **`rtl/test_setups/neorv32_testsetup_approm.vhd`**: this setup does not require a connection via UART. The |
software executable is "installed" into the bitstream to initialize a read-only memory. Use this setup |
if your FPGA board does _not_ provide a UART interface. |
* **`rtl/test_setups/neorv32_testsetup_bootloader.vhd`**: this setups uses the UART and the default NEORV32 |
bootloader to upload new software executables. Use this setup if your board _does_ provide a UART interface. |
|
.NEORV32 "hello world" test setup (`rtl/test_setups/neorv32_testsetup_bootloader.vhd`) |
image::neorv32_test_setup.png[align=center] |
|
.External Clock Source |
[NOTE] |
These test setups are intended to be directly used as **design top entity**. Of course you can also instantiate them |
into another design unit. If your FPGA board only provides _very fast_ external clock sources (like on the FOMU board) |
you might need to add clock management components (PLLs, DCMs, MMCMs, ...) to the test setup or to the according top entity |
if you instantiate one of the test setups. |
|
[start=1] |
. Create a new project with your FPGA EDA tool of choice. |
. Add all VHDL files from the project's `rtl/core` folder to your project. |
|
.Internal Memories |
[IMPORTANT] |
For a _general_ first setup (technology-independent) use the `*.default.vhd` memory architectures for the internal memories |
(IMEM and DMEM). These are located in `rtl/core/mem` so make sure to add the files to your project, too. + |
+ |
If synthesis cannot efficiently map those default memory descriptions to the available memory resources, you can later replace the |
default memory architectures by optimized platform-specific memory architectures. **Example:** The `setups/radiant/UPduino_v3` |
example setup uses optimized memory primitives. Hence, it does not include the default memory architectures from |
`rtl/core/mem` as these are replaced by device-specific implementations. However, it still has to include the entity |
definitions from `rtl/core`. |
|
[start=3] |
. Make sure to add all the rtl files to a new library called `neorv32`. If your FPGA tools does not |
provide a field to enter the library name, check out the "properties" menu of the added rtl files. |
|
.Compile order |
[NOTE] |
Some tools (like Lattice Radiant) might require a _manual compile order_ of the VHDL source files to identify the dependencies. |
The package file `neorv32_package.vhd` should be analyzed first followed by the memory image files (`neorv32_application_imagevhd` |
and `neorv32_bootloader_image.vhd`) and the entity-only files (`neorv32_*mem.entity.vhd`). |
|
[start=4] |
. The `rtl/core/neorv32_top.vhd` VHDL file is the top entity of the NEORV32 processor, which can be |
instantiated into the "real" project. However, in this tutorial we will use one of the pre-defined |
test setups from `rtl/test_setups` (see above). |
|
[IMPORTANT] |
Make sure to include the `neorv32` package into your design when instantiating the processor: add |
`library neorv32;` and `use neorv32.neorv32_package.all;` to your design unit. |
|
[start=5] |
. Add the pre-defined test setup of choice to the project, too, and select it as _top entity_. |
. The entity of both test setups |
provide a minimal set of configuration generics, that might have to be adapted to match your FPGA and board: |
|
.Test setup entity - configuration generics |
[source,vhdl] |
---- |
generic ( |
-- adapt these for your setup -- |
CLOCK_FREQUENCY : natural := 100000000; <1> |
MEM_INT_IMEM_SIZE : natural := 16*1024; <2> |
MEM_INT_DMEM_SIZE : natural := 8*1024 <3> |
); |
---- |
<1> Clock frequency of `clk_i` signal in Hertz |
<2> Default size of internal instruction memory: 16kB |
<3> Default size of internal data memory: 8kB |
|
[start=7] |
. If you feel like it - or if your FPGA does not provide sufficient resources - you can modify the |
_memory sizes_ (`MEM_INT_IMEM_SIZE` and `MEM_INT_DMEM_SIZE` - marked with notes "2" and "3"). But as mentioned |
above, let's keep things simple at first and use the standard configuration for now. |
. There is one generic that _has to be set according to your FPGA board_ setup: the actual clock frequency |
of the top's clock input signal (`clk_i`). Use the `CLOCK_FREQUENCY` generic to specify your clock source's |
frequency in Hertz (Hz). |
|
[NOTE] |
If you have changed the default memory configuration (`MEM_INT_IMEM_SIZE` and `MEM_INT_DMEM_SIZE` generics) |
keep those new sizes in mind - these values are required for setting |
up the software framework in the next section <<_general_software_framework_setup>>. |
|
[start=9] |
. Depending on your FPGA tool of choice, it is time to assign the signals of the test setup top entity to |
the according pins of your FPGA board. All the signals can be found in the entity declaration of the |
corresponding test setup: |
|
.Entity signals of `neorv32_testsetup_approm.vhd` |
[source,vhdl] |
---- |
port ( |
-- Global control -- |
clk_i : in std_ulogic; -- global clock, rising edge |
rstn_i : in std_ulogic; -- global reset, low-active, async |
-- GPIO -- |
gpio_o : out std_ulogic_vector(7 downto 0) -- parallel output |
); |
---- |
|
.Entity signals of `neorv32_testsetup_bootloader.vhd` |
[source,vhdl] |
---- |
port ( |
-- Global control -- |
clk_i : in std_ulogic; -- global clock, rising edge |
rstn_i : in std_ulogic; -- global reset, low-active, async |
-- GPIO -- |
gpio_o : out std_ulogic_vector(7 downto 0); -- parallel output |
-- UART0 -- |
uart0_txd_o : out std_ulogic; -- UART0 send data |
uart0_rxd_i : in std_ulogic -- UART0 receive data |
); |
---- |
|
.Signal Polarity |
[NOTE] |
If your FPGA board has inverse polarity for certain input/output you can add `not` gates. Example: The reset signal |
`rstn_i` is low-active by default; the LEDs connected to `gpio_o` high-active by default. |
You can do this in your board top if you instantiate the test setup, |
or _inside_ the test setup if this is your top entity (low-active LEDs example: `gpio_o <= NOT con_gpio_o(7 downto 0);`). |
|
[start=10] |
. Attach the clock input `clk_i` to your clock source and connect the reset line `rstn_i` to a button of |
your FPGA board. Check whether it is low-active or high-active - the reset signal of the processor is |
**low-active**, so maybe you need to invert the input signal. |
. If possible, connected _at least_ bit `0` of the GPIO output port `gpio_o` to a LED (see "Signal Polarity" note above). |
. Finally, if your are using the UART-based test setup (`neorv32_testsetup_bootloader.vhd`) |
connect the UART communication signals `uart0_txd_o` and `uart0_rxd_i` to the host interface (e.g. USB-UART converter). |
. Perform the project HDL compilation (synthesis, mapping, bitstream generation). |
. Program the generated bitstream into your FPGA and press the button connected to the reset signal. |
. Done! The LED at `gpio_o(0)` should be flashing now. |
|
[TIP] |
After the GCC toolchain for compiling RISC-V source code is ready (chapter <<_general_software_framework_setup>>), |
you can advance to one of these chapters to learn how to get a software executable into your processor setup: |
* If you are using the `neorv32_testsetup_approm.vhd` setup: See section <<_installing_an_executable_directly_into_memory>>. |
* If you are using the `neorv32_testsetup_bootloader.vhd` setup: See section <<_uploading_and_starting_of_a_binary_executable_image_via_uart>>. |
/docs/userguide/general_sw_framework_setup.adoc
0,0 → 1,41
<<< |
:sectnums: |
== General Software Framework Setup |
|
To allow executables to be _actually executed_ on the NEORV32 Processor the configuration of the software framework |
has to be aware to the hardware configuration. This guide focuses on the memory configuration. To enabled |
certain CPU ISA features refer to the <<_enabling_risc_v_cpu_extensions>> section. |
|
[TIP] |
If you have **not** changed the _default_ memory configuration in section <<_general_hardware_setup>> |
you are already done and you can skip the rest of this guide. |
|
[start=1] |
. Open the NEORV32 linker script `sw/common/neorv32.ld` with a text editor. Right at the |
beginning of this script you will find the `MEMORY` configuration listing the different memory section: |
|
.Cut-out of the linker script `neorv32.ld`: `ram` memory section configuration |
[source,c] |
---- |
MEMORY |
{ |
ram (rwx) : ORIGIN = 0x80000000, LENGTH = DEFINED(make_bootloader) ? 512 : 8*1024 <1> |
... |
---- |
<1> Size of the data memory address space (right-most value) (internal/external DMEM); here 8kB |
|
[start=2] |
. We only need to change the `ram` section, which presents the available data address space. |
If you have changed the DMEM (_MEM_INT_DMEM_SIZE_ generic) size adapt the `LENGTH` parameter of the `ram` |
section (here: `8*1024`) so it is equal to your DMEM hardware configuration. |
|
[IMPORTANT] |
Make sure you only modify the _right-most_ value (here: 8*1024)! + |
The "`512`" are not relevant for the application. |
|
[start=3] |
. Done! Save your changes and close the linker script. |
|
.Advanced: Section base address and size |
[IMPORTANT] |
More information can be found in the datasheet section https://stnolting.github.io/neorv32/#_address_space[Address Space]. |
/docs/userguide/installing_an_executable.adoc
0,0 → 1,71
<<< |
:sectnums: |
== Installing an Executable Directly Into Memory |
|
If you do not want to use the bootloader (or the on-chip debugger) for executable upload or if your setup does not provide |
a serial interface for that, you can also directly install an application into embedded memory. |
|
This concept uses the "Direct Boot" scenario that implements the processor-internal IMEM as ROM, which is |
pre-initialized with the application's executable during synthesis. Hence, it provides _non-volatile_ storage of the |
executable inside the processor. This storage cannot be altered during runtime and any source code modification of |
the application requires to re-program the FPGA via the bitstream. |
|
[TIP] |
See datasheet section https://stnolting.github.io/neorv32/#_direct_boot[Direct Boot] for more information. |
|
|
Using the IMEM as ROM: |
|
* for this boot concept the bootloader is no longer required |
* this concept only works for the internal IMEM (but can be extended to work with external memories coupled via the processor's bus interface) |
* make sure that the memory components (like block RAM) the IMEM is mapped to support an initialization via the bitstream |
|
[start=1] |
. At first, make sure your processor setup actually implements the internal IMEM: the `MEM_INT_IMEM_EN` generics has to be set to `true`: |
|
.Processor top entity configuration - enable internal IMEM |
[source,vhdl] |
---- |
-- Internal Instruction memory -- |
MEM_INT_IMEM_EN => true, -- implement processor-internal instruction memory |
---- |
|
[start=2] |
. For this setup we do not want the bootloader to be implemented at all. Disable implementation of the bootloader by setting the |
`INT_BOOTLOADER_EN` generic to `false`. This will also modify the processor-internal IMEM so it is initialized with the executable during synthesis. |
|
.Processor top entity configuration - disable internal bootloader |
[source,vhdl] |
---- |
-- General -- |
INT_BOOTLOADER_EN => false, -- boot configuration: false = boot from int/ext (I)MEM |
---- |
|
[start=3] |
. To generate an "initialization image" for the IMEM that contains the actual application, run the `install` target when compiling your application: |
|
[source,bash] |
---- |
neorv32/sw/example/blink_led$ make clean_all install |
Memory utilization: |
text data bss dec hex filename |
3176 0 120 3296 ce0 main.elf |
Compiling ../../../sw/image_gen/image_gen |
Installing application image to ../../../rtl/core/neorv32_application_image.vhd |
---- |
|
[start=4] |
. The `install` target has compiled all the application sources but instead of creating an executable (`neorv32_exe.bit`) that can be uploaded via the |
bootloader, it has created a VHDL memory initialization image `core/neorv32_application_image.vhd`. |
. This VHDL file is automatically copied to the core's rtl folder (`rtl/core`) so it will be included for the next synthesis. |
. Perform a new synthesis. The IMEM will be build as pre-initialized ROM (inferring embedded memories if possible). |
. Upload your bitstream. Your application code now resides unchangeable in the processor's IMEM and is directly executed after reset. |
|
|
The synthesis tool / simulator will print asserts to inform about the (IMEM) memory / boot configuration: |
|
[source] |
---- |
NEORV32 PROCESSOR CONFIG NOTE: Boot configuration: Direct boot from memory (processor-internal IMEM). |
NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal IMEM as ROM (3176 bytes), pre-initialized with application. |
---- |
/docs/userguide/new_application_project.adoc
0,0 → 1,36
<<< |
:sectnums: |
== Setup of a New Application Program Project |
|
[start=1] |
. The easiest way of creating a _new_ software application project is to copy an _existing_ one. This will keep all |
file dependencies. For example you can copy `sw/example/blink_led` to `sw/example/flux_capacitor`. |
. If you want to place you application somewhere outside `sw/example` you need to adapt the application's makefile. |
In the makefile you will find a variable that keeps the relative or absolute path to the NEORV32 repository home |
folder. Just modify this variable according to your new project's home location: |
|
[source,makefile] |
---- |
# Relative or absolute path to the NEORV32 home folder (use default if not set by user) |
NEORV32_HOME ?= ../../.. |
---- |
|
[start=3] |
. If your project contains additional source files outside of the project folder, you can add them to |
the `APP_SRC` variable: |
|
[source,makefile] |
---- |
# User's application sources (add additional files here) |
APP_SRC = $(wildcard *.c) ../somewhere/some_file.c |
---- |
|
[start=4] |
. You also can add a folder containing your application's include files to the |
`APP_INC` variable (do not forget the `-I` prefix): |
|
[source,makefile] |
---- |
# User's application include folders (don't forget the '-I' before each entry) |
APP_INC = -I . -I ../somewhere/include_stuff_folder |
---- |
/docs/userguide/packaging_vivado.adoc
0,0 → 1,36
<<< |
:sectnums: |
== Packaging the Processor as IP block for Xilinx Vivado Block Designer |
|
[start=1] |
. Import all the core files from `rtl/core` (including default internal memory architectures from `rtl/core/mem`) |
and assign them to a _new_ design library `neorv32`. |
. Instantiate the `rtl/system_integration/neorv32_top_axi4lite.vhd` module. |
. Then either directly use that module in a new block-design ("Create Block Design", right-click -> "Add Module", |
thats easier for a first try) or package it ("Tools", "Create and Package new IP") for the use in other projects. |
. Connect your AXI-peripheral directly to the core's AXI4-Interface if you only have one, or to an AXI-Interconnect |
(from the IP-catalog) if you have multiple peripherals. |
. Connect ALL the `ACLK` and `ARESETN` pins of all peripherals and interconnects to the processor's clock and reset |
signals to have a _unified_ clock and reset domain (easier for a first setup). |
. Open the "Address Editor" tab and let Vivado assign the base-addresses for the AXI-peripherals (you can modify them |
according to your needs). |
. For all FPGA-external signals (like UART signals) make all the connections you need "external" |
(right-click on the signal/pin -> "Make External"). |
. Save everything, let VIVADO create a HDL-Wrapper for the block-design and choose this as your _Top Level Design_. |
. Define your constraints and generate your bitstream. |
|
.True Random Number Generator |
[IMPORTANT] |
The NEORV32 TRNG peripheral is enabled by default in the `neorv32_top_axi4lite` AXI wrapper. Otherwise, Vivado |
cannot insert the wrapper into a block design (see https://github.com/stnolting/neorv32/issues/227.). |
footnote:[Seems like Vivado has problem evaluating design source files that have more than two in-file sub-entities.] |
If the TRNG is not needed, you can disable it by double-clicking on the module's block and de-selecting |
"Io Trng En" after inserting the module. |
|
.TWI Tri-State Drivers |
[IMPORTANT] |
Set the synthesis option "global" when generating the block design to maintain the internal TWI tri-state drivers. |
|
[NOTE] |
Guide provided by GitHub user https://github.com/AWenzel83[`AWenzel83`] (see |
https://github.com/stnolting/neorv32/discussions/52#discussioncomment-819013). ❤️ |
/docs/userguide/programming_an_external_spi_flash_via_bootloader.adoc
0,0 → 1,85
<<< |
:sectnums: |
== Programming an External SPI Flash via the Bootloader |
|
The default processor-internal NEORV32 bootloader supports automatic booting from an external SPI flash. |
This guide shows how to write an executable to the SPI flash via the bootloader so it can be automatically |
fetched and executed after processor reset. For example, you can use a section of the FPGA bitstream configuration |
memory to store an application executable. |
|
[NOTE] |
This section assumes the _default_ configuration of the NEORV32 bootloader. |
See section <<_customizing_the_internal_bootloader>> on how to customize the bootloader and its setting |
(for example the SPI chip-select port, the SPI clock speed or the flash base address for storing the executable). |
|
|
:sectnums: |
=== SPI Flash |
|
The bootloader can access an SPI compatible flash via the processor top entity's SPI port. By default, the flash |
chip-select line is to `spi_csn_o(0)` and uses 1/8 of the processor's main clock as clock frequency. |
The SPI flash has to support single-byte read and write, 24-bit addresses and at least the following standard commands: |
|
* READ `0x03` |
* READ STATUS `0x05` |
* WRITE ENABLE `0x06` |
* PAGE PROGRAM `0x02` |
* SECTOR ERASE `0xD8` |
* READ ID `0x9E` |
|
Compatible (FGPA configuration) SPI flash memories are for example the "Winbond W25Q64FV2 or the "Micron N25Q032A". |
|
|
:sectnums: |
=== Programming an Executable |
|
[start=1] |
. At first, reset the NEORV32 processor and wait until the bootloader start screen appears in your terminal program. |
. Abort the auto boot sequence and start the user console by pressing any key. |
. Press u to upload the executable that you want to store to the external flash: |
|
[source] |
---- |
CMD:> u |
Awaiting neorv32_exe.bin... |
---- |
|
[start=4] |
. Send the binary in raw binary via your terminal program. When the upload is completed and "OK" |
appears, press `p` to trigger the programming of the flash (do not execute the image via the `e` |
command as this might corrupt the image): |
|
[source] |
---- |
CMD:> u |
Awaiting neorv32_exe.bin... OK |
CMD:> p |
Write 0x000013FC bytes to SPI flash @ 0x00800000? (y/n) |
---- |
|
[start=5] |
. The bootloader shows the size of the executable and the base address inside the SPI flash where the |
executable is going to be stored. A prompt appears: Type `y` to start the programming or type `n` to |
abort. |
|
[TIP] |
Section <<_customizing_the_internal_bootloader>> show the according C-language `define` that can be modified |
to specify the base address of the executable inside the SPI flash. |
|
[source] |
---- |
CMD:> u |
Awaiting neorv32_exe.bin... OK |
CMD:> p |
Write 0x000013FC bytes to SPI flash @ 0x08000000? (y/n) y |
Flashing... OK |
CMD:> |
---- |
|
[NOTE] |
The bootloader stores the executable in **little-endian** byte-order to the flash. |
|
[start=6] |
. If "OK" appears in the terminal line, the programming process was successful. Now you can use the |
auto boot sequence to automatically boot your application from the flash at system start-up without |
any user interaction. |
/docs/userguide/riscv_architecture_tests.adoc
0,0 → 1,12
<<< |
:sectnums: |
== RISC-V Architecture Test Framework |
|
The NEORV32 Processor passes the according tests provided by the official RISC-V Architecture Test Suite |
(V2.0+), which is available online at GitHub: https://github.com/riscv/riscv-arch-test |
|
All files required for executing the test framework on a simulated instance of the processor (including port |
files) are located in the `sw/isa-test` folder of the NEORV32 repository. The test framework is executed via the |
`sim/run_riscv_arch_test.sh` script. Take a look at the provided `sim/README.md` |
(https://github.com/stnolting/neorv32/tree/master/sim[online at GitHub]) |
file for more information on how to run the tests and how testing is conducted in detail. |
/docs/userguide/simulating_the_processor.adoc
0,0 → 1,233
<<< |
:sectnums: |
== Simulating the Processor |
|
The NEORV32 project includes a core CPU, built-in peripherals in the Processor Subsystem, and additional peripherals in |
the templates and examples. |
Therefore, there is a wide range of possible testing and verification strategies. |
|
On the one hand, a simple smoke testbench allows ensuring that functionality is correct from a software point of view. |
That is used for running the RISC-V architecture tests, in order to guarantee compliance with the ISA specification(s). |
|
On the other hand, http://vunit.github.io/[VUnit] and http://vunit.github.io/verification_components/user_guide.html[Verification Components] |
are used for verifying the functionality of the various peripherals from a hardware point of view. |
|
[TIP] |
The processor can check if it is being simulated by checking the SYSINFO _SYSINFO_SOC_IS_SIM_ flag |
(see https://stnolting.github.io/neorv32/#_system_configuration_information_memory_sysinfo). |
Note that this flag is not guaranteed to be set correctly (depending on the HDL toolchain's pragma support). |
|
:sectnums: |
=== Testbench |
|
A plain-VHDL (no third-party libraries) testbench (`sim/simple/neorv32_tb.simple.vhd`) can be used for simulating and |
testing the processor. |
This testbench features a 100MHz clock and enables all optional peripheral and CPU extensions except for the `E` |
extension and the TRNG IO module (that CANNOT be simulated due to its combinatorial (looped) architecture). |
|
The simulation setup is configured via the "User Configuration" section located right at the beginning of |
the testbench's architecture. Each configuration constant provides comments to explain the functionality. |
|
Besides the actual NEORV32 Processor, the testbench also simulates "external" components that are connected |
to the processor's external bus/memory interface. These components are: |
|
* an external instruction memory (that also allows booting from it) |
* an external data memory |
* an external memory to simulate "external IO devices" |
* a memory-mapped registers to trigger the processor's interrupt signals |
|
The following table shows the base addresses of these four components and their default configuration and |
properties: |
|
[NOTE] |
==== |
Attributes: |
|
* `r` = read |
* `w` = write |
* `e` = execute |
* `a` = atomic accesses possible |
* `8` = byte-accessible |
* `16` = half-word-accessible |
* `32` = word-accessible |
==== |
|
.Testbench: processor-external memories |
[cols="^4,>3,^5,<11"] |
[options="header",grid="rows"] |
|======================= |
| Base address | Size | Attributes | Description |
| `0x00000000` | `imem_size_c` | `r/w/e, a, 8/16/32` | external IMEM (initialized with application image) |
| `0x80000000` | `dmem_size_c` | `r/w/e, a, 8/16/32` | external DMEM |
| `0xf0000000` | 64 bytes | `r/w/e, !a, 8/16/32` | external "IO" memory, atomic accesses will fail |
| `0xff000000` | 4 bytes | `-/w/-, a, -/-/32` | memory-mapped register to trigger "machine external", "machine software" and "SoC Fast Interrupt" interrupts |
|======================= |
|
[IMPORTANT] |
The simulated NEORV32 does not use the bootloader and _directly boots_ the current application image (from |
the `rtl/core/neorv32_application_image.vhd` image file). |
|
.UART output during simulation |
[IMPORTANT] |
Data written to the NEORV32 UART0 / UART1 transmitter is send to a virtual UART receiver implemented |
as part of the testbench. Received chars are send to the simulator console and are also stored to a log file |
(`neorv32.testbench_uart0.out` for UART0, `neorv32.testbench_uart1.out` for UART1) inside the simulation's home folder. |
**Please note that printing via the native UART receiver takes a lot of time.** For faster simulation console output |
see section <<_faster_simulation_console_output>>. |
|
|
:sectnums: |
=== Faster Simulation Console Output |
|
When printing data via the UART the communication speed will always be based on the configured BAUD |
rate. For a simulation this might take some time. To have faster output you can enable the **simulation mode** |
for UART0/UART1 (see section https://stnolting.github.io/neorv32/#_primary_universal_asynchronous_receiver_and_transmitter_uart0[Documentation: Primary Universal Asynchronous Receiver and Transmitter (UART0)]). |
|
ASCII data sent to UART0|UART1 will be immediately printed to the simulator console and logged to files in the simulator |
execution directory: |
|
* `neorv32.uart?.sim_mode.text.out`: ASCII data. |
* `neorv32.uart?.sim_mode.data.out`: all written 32-bit dumped as 8-char hexadecimal values. |
|
You can "automatically" enable the simulation mode of UART0/UART1 when compiling an application. |
In this case, the "real" UART0/UART1 transmitter unit is permanently disabled. |
To enable the simulation mode just compile and install your application and add _UART?_SIM_MODE_ to the compiler's |
_USER_FLAGS_ variable (do not forget the `-D` suffix flag): |
|
[source, bash] |
---- |
sw/example/blink_led$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all all |
---- |
|
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. |
|
[NOTE] |
The UART simulation output (to file and to screen) outputs "complete lines" at once. A line is |
completed with a line feed (newline, ASCII `\n` = 10). |
|
|
:sectnums: |
=== Simulation using a shell script (with GHDL) |
|
To simulate the processor using _GHDL_ navigate to the `sim/simple/` folder and run the provided shell script. |
Any arguments that are provided while executing this script are passed to GHDL. |
For example the simulation time can be set to 20ms using `--stop-time=20ms` as argument. |
|
[source, bash] |
---- |
neorv32/sim/simple$ sh ghdl_sim.sh --stop-time=20ms |
---- |
|
|
:sectnums: |
=== Simulation using Application Makefiles (In-Console with GHDL) |
|
To directly compile and run a program in the console (using the default testbench and GHDL |
as simulator) you can use the `sim` makefile target. Make sure to use the UART simulation mode |
(`USER_FLAGS+=-DUART0_SIM_MODE` and/or `USER_FLAGS+=-DUART1_SIM_MODE`) to get |
faster / direct-to-console UART output. |
|
[source, bash] |
---- |
sw/example/blink_led$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all sim |
[...] |
Blinking LED demo program |
---- |
|
|
:sectnums: |
==== Hello World! |
|
To do a quick test of the NEORV32 make sure to have https://github.com/ghdl/ghdl[GHDL] and a |
https://github.com/stnolting/riscv-gcc-prebuilt[RISC-V gcc toolchain] installed. |
Navigate to the project's `sw/example/hello_world` folder and run `make USER_FLAGS+=-DUART0_SIM_MODE MARCH=rv32imac clean_all sim`: |
|
[TIP] |
The simulator will output some _sanity check_ notes (and warnings or even errors if something is ill-configured) |
right at the beginning of the simulation to give a brief overview of the actual NEORV32 SoC and CPU configurations. |
|
[source, bash] |
---- |
stnolting@Einstein:/mnt/n/Projects/neorv32/sw/example/hello_world$ make USER_FLAGS+=-DUART0_SIM_MODE MARCH=rv32imac clean_all sim |
../../../sw/lib/source/neorv32_uart.c: In function 'neorv32_uart0_setup': |
../../../sw/lib/source/neorv32_uart.c:301:4: warning: #warning UART0_SIM_MODE (primary UART) enabled! Sending all UART0.TX data to text.io simulation output instead of real UART0 transmitter. Use this for simulations only! [-Wcpp] |
301 | #warning UART0_SIM_MODE (primary UART) enabled! Sending all UART0.TX data to text.io simulation output instead of real UART0 transmitter. Use this for simulations only! <1> |
| ^~~~~~~ |
Memory utilization: |
text data bss dec hex filename |
4612 0 120 4732 127c main.elf <2> |
Compiling ../../../sw/image_gen/image_gen |
Installing application image to ../../../rtl/core/neorv32_application_image.vhd <3> |
Simulating neorv32_application_image.vhd... |
Tip: Compile application with USER_FLAGS+=-DUART[0/1]_SIM_MODE to auto-enable UART[0/1]'s simulation mode (redirect UART output to simulator console). <4> |
Using simulation runtime args: --stop-time=10ms <5> |
../rtl/core/neorv32_top.vhd:347:3:@0ms:(assertion note): NEORV32 PROCESSOR IO Configuration: GPIO MTIME UART0 UART1 SPI TWI PWM WDT CFS SLINK NEOLED XIRQ <6> |
../rtl/core/neorv32_top.vhd:370:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Boot configuration: Direct boot from memory (processor-internal IMEM). |
../rtl/core/neorv32_top.vhd:394:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing on-chip debugger (OCD). |
../rtl/core/neorv32_cpu.vhd:169:3:@0ms:(assertion note): NEORV32 CPU ISA Configuration (MARCH): RV32IMACU_Zbb_Zicsr_Zifencei_Zfinx_Debug |
../rtl/core/neorv32_cpu.vhd:189:3:@0ms:(assertion note): NEORV32 CPU CONFIG NOTE: Implementing NO dedicated hardware reset for uncritical registers (default, might reduce area). Set package constant <dedicated_reset_c> = TRUE to configure a DEFINED reset value for all CPU registers. |
../rtl/core/neorv32_imem.vhd:107:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal IMEM as ROM (16384 bytes), pre-initialized with application (4612 bytes). |
../rtl/core/neorv32_dmem.vhd:89:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal DMEM (RAM, 8192 bytes). |
../rtl/core/neorv32_wishbone.vhd:136:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing STANDARD Wishbone protocol. |
../rtl/core/neorv32_wishbone.vhd:140:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing auto-timeout (255 cycles). |
../rtl/core/neorv32_wishbone.vhd:144:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing LITTLE-endian byte order. |
../rtl/core/neorv32_wishbone.vhd:148:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing registered RX path. |
../rtl/core/neorv32_slink.vhd:161:3:@0ms:(assertion note): NEORV32 PROCESSOR CONFIG NOTE: Implementing 8 RX and 8 TX stream links. |
<7> |
## |
## ## ## ## |
## ## ######### ######## ######## ## ## ######## ######## ## ################ |
#### ## ## ## ## ## ## ## ## ## ## ## ## ## #### #### |
## ## ## ## ## ## ## ## ## ## ## ## ## ## ###### ## |
## ## ## ######### ## ## ######### ## ## ##### ## ## #### ###### #### |
## ## ## ## ## ## ## ## ## ## ## ## ## ## ###### ## |
## #### ## ## ## ## ## ## ## ## ## ## ## #### #### |
## ## ######### ######## ## ## ## ######## ########## ## ################ |
## ## ## ## |
## |
Hello world! :) |
---- |
<1> Notifier that "simulation mode" of UART0 is enabled (by the `USER_FLAGS+=-DUART0_SIM_MODE` makefile flag). All UART0 output is send to the simulator console. |
<2> Final executable size (`text`) and _static_ data memory requirements (`data`, `bss`). |
<3> The application code is _installed_ as pre-initialized IMEM. This is the default approach for simulation. |
<4> A note regarding UART "simulation mode", but we have already enabled that. |
<5> List of (default) arguments that were send to the simulator. Here: maximum simulation time (10ms). |
<6> "Sanity checks" from the core's VHDL files. These reports give some brief information about the SoC/CPU configuration (-> generics). If there are problems with the current configuration, an ERROR will appear. |
<7> Execution of the actual program starts. |
|
|
:sectnums: |
=== Advanced Simulation using VUnit |
|
https://vunit.github.io/[VUnit] is an open source unit testing framework for VHDL/SystemVerilog. |
It allows continuous and automated testing of HDL code by complementing traditional testing methodologies. |
The motto of VUnit is _"testing early and often"_ through automation. |
|
VUnit is composed by a http://vunit.github.io/py/ui.html[Python interface] and multiple optional |
http://vunit.github.io/vhdl_libraries.html[VHDL libraries]. |
The Python interface allows declaring sources and simulation options, and it handles the compilation, execution and |
gathering of the results regardless of the simulator used. |
That allows having a single `run.py` script to be used with GHDL, ModelSim/QuestaSim, Riviera PRO, etc. |
On the other hand, the VUnit's VHDL libraries provide utilities for assertions, logging, having virtual queues, handling CSV files, etc. |
The http://vunit.github.io/verification_components/user_guide.html[Verification Component Library] uses those features |
for abstracting away bit-toggling when verifying standard interfaces such as Wishbone, AXI, Avalon, UARTs, etc. |
|
Testbench sources in `sim` (such as `sim/neorv32_tb.vhd` and `sim/uart_rx*.vhd`) use VUnit's VHDL libraries for testing |
NEORV32 and peripherals. |
The entry-point for executing the tests is `sim/run.py`. |
|
[source, bash] |
---- |
# ./sim/run.py -l |
neorv32.neorv32_tb.all |
Listed 1 tests |
|
# ./sim/run.py -v |
Compiling into neorv32: rtl/core/neorv32_uart.vhd passed |
Compiling into neorv32: rtl/core/neorv32_twi.vhd passed |
Compiling into neorv32: rtl/core/neorv32_trng.vhd passed |
... |
---- |
|
See http://vunit.github.io/user_guide.html[VUnit: User Guide] and http://vunit.github.io/cli.html[VUnit: Command Line Interface] for further info about VUnit's features. |
/docs/userguide/sw_toolchain_setup.adoc
0,0 → 1,92
<<< |
:sectnums: |
== Software Toolchain Setup |
|
To compile (and debug) executables for the NEORV32 a RISC-V toolchain is required. |
There are two possibilities to get this: |
|
1. Download and _build_ the official RISC-V GNU toolchain yourself. |
2. Download and install a prebuilt version of the toolchain; this might also done via the package manager / app store of your OS |
|
[NOTE] |
The default toolchain prefix (`RISCV_PREFIX` variable) for this project is **`riscv32-unknown-elf-`**. Of course you can use any other RISC-V |
toolchain (like `riscv64-unknown-elf-`) that is capable to emit code for a `rv32` architecture. Just change `RISCV_PREFIX` |
according to your needs. |
|
|
:sectnums: |
=== Building the Toolchain from Scratch |
|
To build the toolchain by yourself you can follow the guide from the official https://github.com/riscv-collab/riscv-gnu-toolchain GitHub page. |
You need to make sure the generated toolchain fits the architecture of the NEORV32 core. To get a toolchain that even supports minimal |
ISA extension configurations, it is recommend to compile for `rv32i` only. Please note that this minimal ISA also provides further ISA |
extensions like `m` or `c`. Of course you can use a _multilib_ approach to generate toolchains for several target ISAs at once. |
|
.Configuring GCC build for `rv32i` (minimal ISA) |
[source,bash] |
---- |
riscv-gnu-toolchain$ ./configure --prefix=/opt/riscv --with-arch=rv32i --with-abi=ilp32 |
riscv-gnu-toolchain$ make |
---- |
|
[IMPORTANT] |
Keep in mind that - for instance - a toolchain build with `--with-arch=rv32imc` only provides library code compiled with |
compressed (`C`) and `mul`/`div` instructions (`M`)! Hence, this code cannot be executed (without |
emulation) on an architecture without these extensions! |
|
|
:sectnums: |
=== Downloading and Installing a Prebuilt Toolchain |
|
Alternatively, you can download a prebuilt toolchain. |
|
:sectnums: |
==== Use The Toolchain I have Build |
|
I have compiled a GCC toolchain on a 64-bit x86 Ubuntu (Ubuntu on Windows, actually) and uploaded it to |
GitHub. You can directly download the according toolchain archive as single _zip-file_ within a packed |
release from https://github.com/stnolting/riscv-gcc-prebuilt. |
|
Unpack the downloaded toolchain archive and copy the content to a location in your file system (e.g. |
`/opt/riscv`). More information about downloading and installing my prebuilt toolchains can be found in |
the repository's README. |
|
|
:sectnums: |
==== Use a Third Party Toolchain |
|
Of course you can also use any other prebuilt version of the toolchain. There are a lot RISC-V GCC packages out there - |
even for Windows. On Linux system you might even be able to fetch a toolchain via your distribution's package manager. |
|
[IMPORTANT] |
Make sure the toolchain can (also) emit code for a `rv32i` architecture, uses the `ilp32` or `ilp32e` ABI and **was not build** using |
CPU extensions that are not supported by the NEORV32 (like `D`). |
|
|
:sectnums: |
=== Installation |
|
Now you have the toolchain binaries. The last step is to add them to your `PATH` environment variable (if you have not |
already done so): make sure to add the _binaries_ folder (`bin`) of your toolchain. |
|
[source,bash] |
---- |
$ export PATH:$PATH:/opt/riscv/bin |
---- |
|
You should add this command to your `.bashrc` (if you are using bash) to automatically add the RISC-V |
toolchain at every console start. |
|
:sectnums: |
=== Testing the Installation |
|
To make sure everything works fine, navigate to an example project in the NEORV32 example folder and |
execute the following command: |
|
[source,bash] |
---- |
neorv32/sw/example/blink_led$ make check |
---- |
|
This will test all the tools required for generating NEORV32 executables. |
Everything is working fine if `Toolchain check OK` appears at the end. |
/docs/userguide/zephyr_support.adoc
0,0 → 1,13
<<< |
:sectnums: |
== Zephyr RTOS Support 🪁 |
|
The NEORV32 processor is supported by upstream Zephyr RTOS: https://docs.zephyrproject.org/latest/boards/riscv/neorv32/doc/index.html |
|
[IMPORTANT] |
The absolute path to the NEORV32 executable image generator binary (`.../neorv32/sw/image_gen`) has to be added to the `PATH` variable |
so the Zephyr build system can generate executables and memory-initialization images. |
|
[NOTE] |
Zephyr OS port provided by GitHub user https://github.com/henrikbrixandersen[henrikbrixandersen] |
(see https://github.com/stnolting/neorv32/discussions/172). ❤️ |
/docs/attrs.adoc
2,7 → 2,7
:email: stnolting@gmail.com |
:keywords: neorv32, risc-v, riscv, fpga, soft-core, vhdl, microcontroller, cpu, soc, processor, gcc, openocd, gdb |
:description: A size-optimized, customizable and open-source full-scale 32-bit RISC-V soft-core CPU and SoC written in platform-independent VHDL. |
:revnumber: v1.6.4 |
:revnumber: v1.6.5 |
:doctype: book |
:sectnums: |
:stem: |
/docs/legal.adoc
87,15 → 87,14
|
.Contributors ❤️ |
[NOTE] |
Please add as many https://github.com/stnolting/neorv32/graphs/contributors[contributors] as possible to the `authors` field 😉. + |
This project would not be where it is without them. + |
Full names can be found in the repository's https://github.com/stnolting/neorv32/blob/master/.mailmap[`.mailmap`]. |
Please add as many https://github.com/stnolting/neorv32/graphs/contributors[contributors] as possible to the `authors` field. + |
This project would not be where it is without them. |
|
.BibTeX |
[source] |
---- |
@misc{nolting20, |
author = {Nolting, S.}, |
author = {Nolting, S. and ...}, |
title = {The NEORV32 RISC-V Processor}, |
year = {2020}, |
publisher = {GitHub}, |
113,7 → 112,7
:sectnums!: |
=== Acknowledgments |
|
**A big shoutout to all https://github.com/stnolting/neorv32/graphs/contributors[contributors], |
**A big shout-out to the community and all https://github.com/stnolting/neorv32/graphs/contributors[contributors], |
who helped improving this project! ❤️** |
|
https://riscv.org[RISC-V] - instruction sets want to be free! |
/rtl/core/neorv32_bootloader_image.vhd
1,6 → 1,6
-- The NEORV32 RISC-V Processor, https://github.com/stnolting/neorv32 |
-- Auto-generated memory init file (for BOOTLOADER) from source file <bootloader/main.bin> |
-- Size: 4068 bytes |
-- Size: 4040 bytes |
|
library ieee; |
use ieee.std_logic_1164.all; |
51,7 → 51,7
00000037 => x"00158593", |
00000038 => x"ff5ff06f", |
00000039 => x"00001597", |
00000040 => x"f4858593", |
00000040 => x"f2c58593", |
00000041 => x"80010617", |
00000042 => x"f5c60613", |
00000043 => x"80010697", |
105,929 → 105,922
00000091 => x"0007a023", |
00000092 => x"8001a223", |
00000093 => x"ffff07b7", |
00000094 => x"4c478793", |
00000094 => x"4ac78793", |
00000095 => x"30579073", |
00000096 => x"00000693", |
00000097 => x"00000613", |
00000098 => x"00000593", |
00000099 => x"00200513", |
00000100 => x"385000ef", |
00000101 => x"419000ef", |
00000100 => x"369000ef", |
00000101 => x"3fd000ef", |
00000102 => x"00048493", |
00000103 => x"00050863", |
00000104 => x"00100513", |
00000105 => x"00000593", |
00000106 => x"445000ef", |
00000106 => x"429000ef", |
00000107 => x"00005537", |
00000108 => x"00000613", |
00000109 => x"00000593", |
00000110 => x"b0050513", |
00000111 => x"1f5000ef", |
00000112 => x"1b9000ef", |
00000113 => x"02050a63", |
00000114 => x"321000ef", |
00000111 => x"1d9000ef", |
00000112 => x"19d000ef", |
00000113 => x"02050663", |
00000114 => x"305000ef", |
00000115 => x"fe002783", |
00000116 => x"0027d793", |
00000117 => x"00a78533", |
00000118 => x"00f537b3", |
00000119 => x"00b785b3", |
00000120 => x"1a9000ef", |
00000120 => x"18d000ef", |
00000121 => x"08000793", |
00000122 => x"30479073", |
00000123 => x"30046073", |
00000124 => x"00000013", |
00000125 => x"00000013", |
00000126 => x"ffff1537", |
00000127 => x"f1450513", |
00000128 => x"291000ef", |
00000129 => x"f1302573", |
00000130 => x"24c000ef", |
00000131 => x"ffff1537", |
00000132 => x"f4c50513", |
00000133 => x"27d000ef", |
00000134 => x"fe002503", |
00000135 => x"238000ef", |
00000136 => x"ffff1537", |
00000137 => x"f5450513", |
00000138 => x"269000ef", |
00000139 => x"30102573", |
00000140 => x"224000ef", |
00000141 => x"ffff1537", |
00000142 => x"f5c50513", |
00000143 => x"255000ef", |
00000144 => x"fe402503", |
00000145 => x"ffff1437", |
00000146 => x"20c000ef", |
00000147 => x"ffff1537", |
00000148 => x"f6450513", |
00000149 => x"23d000ef", |
00000150 => x"fe802503", |
00000151 => x"1f8000ef", |
00000152 => x"ffff1537", |
00000153 => x"f6c50513", |
00000154 => x"229000ef", |
00000155 => x"ff802503", |
00000156 => x"1e4000ef", |
00000157 => x"f7440513", |
00000158 => x"219000ef", |
00000159 => x"ff002503", |
00000160 => x"1d4000ef", |
00000161 => x"ffff1537", |
00000162 => x"f8050513", |
00000163 => x"205000ef", |
00000164 => x"ffc02503", |
00000165 => x"1c0000ef", |
00000166 => x"f7440513", |
00000167 => x"1f5000ef", |
00000168 => x"ff402503", |
00000169 => x"1b0000ef", |
00000170 => x"0d1000ef", |
00000171 => x"06050663", |
00000172 => x"ffff1537", |
00000173 => x"f8850513", |
00000174 => x"1d9000ef", |
00000175 => x"22d000ef", |
00000176 => x"fe002403", |
00000177 => x"00341413", |
00000178 => x"00a40933", |
00000179 => x"00893433", |
00000180 => x"00b40433", |
00000181 => x"0cd000ef", |
00000182 => x"02051663", |
00000183 => x"20d000ef", |
00000184 => x"fe85eae3", |
00000185 => x"00b41463", |
00000186 => x"ff2566e3", |
00000187 => x"00100513", |
00000188 => x"4dc000ef", |
00000189 => x"ffff1537", |
00000190 => x"fb050513", |
00000191 => x"195000ef", |
00000192 => x"0d4000ef", |
00000193 => x"181000ef", |
00000194 => x"fc050ae3", |
00000195 => x"ffff1537", |
00000196 => x"fb450513", |
00000197 => x"17d000ef", |
00000198 => x"0b0000ef", |
00000199 => x"ffff19b7", |
00000200 => x"ffff1a37", |
00000201 => x"07200a93", |
00000202 => x"06800b13", |
00000203 => x"07500b93", |
00000204 => x"07300c13", |
00000205 => x"ffff1937", |
00000206 => x"ffff1cb7", |
00000207 => x"fc098513", |
00000208 => x"151000ef", |
00000209 => x"131000ef", |
00000210 => x"00050413", |
00000211 => x"0f5000ef", |
00000212 => x"fb0a0513", |
00000213 => x"13d000ef", |
00000214 => x"101000ef", |
00000215 => x"fe051ee3", |
00000216 => x"01541863", |
00000217 => x"ffff02b7", |
00000218 => x"00028067", |
00000219 => x"fd1ff06f", |
00000220 => x"01641663", |
00000221 => x"054000ef", |
00000222 => x"fc5ff06f", |
00000223 => x"01741663", |
00000224 => x"44c000ef", |
00000225 => x"fb9ff06f", |
00000226 => x"01841663", |
00000227 => x"670000ef", |
00000228 => x"fadff06f", |
00000229 => x"06c00793", |
00000230 => x"00f41663", |
00000231 => x"00100513", |
00000232 => x"fe1ff06f", |
00000233 => x"06500793", |
00000234 => x"00f41c63", |
00000235 => x"0004a783", |
00000236 => x"f40798e3", |
00000237 => x"ebcc8513", |
00000238 => x"0d9000ef", |
00000239 => x"f81ff06f", |
00000240 => x"fc890513", |
00000241 => x"ff5ff06f", |
00000242 => x"ffff1537", |
00000243 => x"dfc50513", |
00000244 => x"0c10006f", |
00000245 => x"ff010113", |
00000246 => x"00112623", |
00000247 => x"30047073", |
00000248 => x"00000013", |
00000249 => x"00000013", |
00000250 => x"ffff1537", |
00000251 => x"e6050513", |
00000252 => x"0a1000ef", |
00000253 => x"065000ef", |
00000254 => x"fe051ee3", |
00000255 => x"ff002783", |
00000256 => x"00078067", |
00000257 => x"0000006f", |
00000258 => x"ff010113", |
00000259 => x"00812423", |
00000260 => x"00050413", |
00000261 => x"ffff1537", |
00000262 => x"e7050513", |
00000263 => x"00112623", |
00000264 => x"071000ef", |
00000265 => x"03040513", |
00000266 => x"0ff57513", |
00000267 => x"015000ef", |
00000268 => x"30047073", |
00000269 => x"00000013", |
00000270 => x"00000013", |
00000271 => x"171000ef", |
00000272 => x"00050863", |
00000273 => x"00100513", |
00000274 => x"00000593", |
00000275 => x"1a1000ef", |
00000276 => x"0000006f", |
00000277 => x"fe010113", |
00000278 => x"01212823", |
00000279 => x"00050913", |
00000280 => x"ffff1537", |
00000281 => x"00912a23", |
00000282 => x"e7c50513", |
00000283 => x"ffff14b7", |
00000284 => x"00812c23", |
00000285 => x"01312623", |
00000286 => x"00112e23", |
00000287 => x"01c00413", |
00000288 => x"011000ef", |
00000289 => x"fd448493", |
00000290 => x"ffc00993", |
00000291 => x"008957b3", |
00000292 => x"00f7f793", |
00000293 => x"00f487b3", |
00000294 => x"0007c503", |
00000295 => x"ffc40413", |
00000296 => x"7a0000ef", |
00000297 => x"ff3414e3", |
00000298 => x"01c12083", |
00000299 => x"01812403", |
00000300 => x"01412483", |
00000301 => x"01012903", |
00000302 => x"00c12983", |
00000303 => x"02010113", |
00000304 => x"00008067", |
00000305 => x"fb010113", |
00000306 => x"04112623", |
00000307 => x"04512423", |
00000308 => x"04612223", |
00000309 => x"04712023", |
00000310 => x"02812e23", |
00000311 => x"02912c23", |
00000312 => x"02a12a23", |
00000313 => x"02b12823", |
00000314 => x"02c12623", |
00000315 => x"02d12423", |
00000316 => x"02e12223", |
00000317 => x"02f12023", |
00000318 => x"01012e23", |
00000319 => x"01112c23", |
00000320 => x"01c12a23", |
00000321 => x"01d12823", |
00000322 => x"01e12623", |
00000323 => x"01f12423", |
00000324 => x"342024f3", |
00000325 => x"800007b7", |
00000326 => x"00778793", |
00000327 => x"08f49463", |
00000328 => x"08d000ef", |
00000329 => x"00050663", |
00000330 => x"00000513", |
00000331 => x"091000ef", |
00000332 => x"648000ef", |
00000333 => x"02050063", |
00000334 => x"7b0000ef", |
00000335 => x"fe002783", |
00000336 => x"0027d793", |
00000337 => x"00a78533", |
00000338 => x"00f537b3", |
00000339 => x"00b785b3", |
00000340 => x"638000ef", |
00000341 => x"03c12403", |
00000342 => x"04c12083", |
00000343 => x"04812283", |
00000344 => x"04412303", |
00000345 => x"04012383", |
00000346 => x"03812483", |
00000347 => x"03412503", |
00000348 => x"03012583", |
00000349 => x"02c12603", |
00000350 => x"02812683", |
00000351 => x"02412703", |
00000352 => x"02012783", |
00000353 => x"01c12803", |
00000354 => x"01812883", |
00000355 => x"01412e03", |
00000356 => x"01012e83", |
00000357 => x"00c12f03", |
00000358 => x"00812f83", |
00000359 => x"05010113", |
00000360 => x"30200073", |
00000361 => x"00700793", |
00000362 => x"00f49a63", |
00000363 => x"8041a783", |
00000364 => x"00078663", |
00000365 => x"00100513", |
00000366 => x"e51ff0ef", |
00000367 => x"34102473", |
00000368 => x"5e0000ef", |
00000369 => x"04050263", |
00000370 => x"ffff1537", |
00000371 => x"e8050513", |
00000372 => x"6c0000ef", |
00000373 => x"00048513", |
00000374 => x"e7dff0ef", |
00000375 => x"02000513", |
00000376 => x"660000ef", |
00000377 => x"00040513", |
00000378 => x"e6dff0ef", |
00000379 => x"02000513", |
00000380 => x"650000ef", |
00000381 => x"34302573", |
00000382 => x"e5dff0ef", |
00000383 => x"ffff1537", |
00000384 => x"e8850513", |
00000385 => x"68c000ef", |
00000386 => x"00440413", |
00000387 => x"34141073", |
00000388 => x"f45ff06f", |
00000389 => x"ff010113", |
00000124 => x"ffff1537", |
00000125 => x"ef850513", |
00000126 => x"27d000ef", |
00000127 => x"f1302573", |
00000128 => x"23c000ef", |
00000129 => x"ffff1537", |
00000130 => x"f3050513", |
00000131 => x"269000ef", |
00000132 => x"fe002503", |
00000133 => x"228000ef", |
00000134 => x"ffff1537", |
00000135 => x"f3850513", |
00000136 => x"255000ef", |
00000137 => x"30102573", |
00000138 => x"214000ef", |
00000139 => x"ffff1537", |
00000140 => x"f4050513", |
00000141 => x"241000ef", |
00000142 => x"fe402503", |
00000143 => x"ffff1437", |
00000144 => x"1fc000ef", |
00000145 => x"ffff1537", |
00000146 => x"f4850513", |
00000147 => x"229000ef", |
00000148 => x"fe802503", |
00000149 => x"1e8000ef", |
00000150 => x"ffff1537", |
00000151 => x"f5050513", |
00000152 => x"215000ef", |
00000153 => x"ff802503", |
00000154 => x"1d4000ef", |
00000155 => x"f5840513", |
00000156 => x"205000ef", |
00000157 => x"ff002503", |
00000158 => x"1c4000ef", |
00000159 => x"ffff1537", |
00000160 => x"f6450513", |
00000161 => x"1f1000ef", |
00000162 => x"ffc02503", |
00000163 => x"1b0000ef", |
00000164 => x"f5840513", |
00000165 => x"1e1000ef", |
00000166 => x"ff402503", |
00000167 => x"1a0000ef", |
00000168 => x"0bd000ef", |
00000169 => x"06050663", |
00000170 => x"ffff1537", |
00000171 => x"f6c50513", |
00000172 => x"1c5000ef", |
00000173 => x"219000ef", |
00000174 => x"fe002403", |
00000175 => x"00341413", |
00000176 => x"00a40933", |
00000177 => x"00893433", |
00000178 => x"00b40433", |
00000179 => x"0b9000ef", |
00000180 => x"02051663", |
00000181 => x"1f9000ef", |
00000182 => x"fe85eae3", |
00000183 => x"00b41463", |
00000184 => x"ff2566e3", |
00000185 => x"00100513", |
00000186 => x"4c8000ef", |
00000187 => x"ffff1537", |
00000188 => x"f9450513", |
00000189 => x"181000ef", |
00000190 => x"0d4000ef", |
00000191 => x"16d000ef", |
00000192 => x"fc050ae3", |
00000193 => x"ffff1537", |
00000194 => x"f9850513", |
00000195 => x"169000ef", |
00000196 => x"0b0000ef", |
00000197 => x"ffff19b7", |
00000198 => x"ffff1a37", |
00000199 => x"07200a93", |
00000200 => x"06800b13", |
00000201 => x"07500b93", |
00000202 => x"07300c13", |
00000203 => x"ffff1937", |
00000204 => x"ffff1cb7", |
00000205 => x"fa498513", |
00000206 => x"13d000ef", |
00000207 => x"11d000ef", |
00000208 => x"00050413", |
00000209 => x"0e1000ef", |
00000210 => x"f94a0513", |
00000211 => x"129000ef", |
00000212 => x"0ed000ef", |
00000213 => x"fe051ee3", |
00000214 => x"01541863", |
00000215 => x"ffff02b7", |
00000216 => x"00028067", |
00000217 => x"fd1ff06f", |
00000218 => x"01641663", |
00000219 => x"054000ef", |
00000220 => x"fc5ff06f", |
00000221 => x"01741663", |
00000222 => x"438000ef", |
00000223 => x"fb9ff06f", |
00000224 => x"01841663", |
00000225 => x"65c000ef", |
00000226 => x"fadff06f", |
00000227 => x"06c00793", |
00000228 => x"00f41663", |
00000229 => x"00100513", |
00000230 => x"fe1ff06f", |
00000231 => x"06500793", |
00000232 => x"00f41c63", |
00000233 => x"0004a783", |
00000234 => x"f40798e3", |
00000235 => x"ea0c8513", |
00000236 => x"0c5000ef", |
00000237 => x"f81ff06f", |
00000238 => x"fac90513", |
00000239 => x"ff5ff06f", |
00000240 => x"ffff1537", |
00000241 => x"de050513", |
00000242 => x"0ad0006f", |
00000243 => x"ff010113", |
00000244 => x"00112623", |
00000245 => x"30047073", |
00000246 => x"ffff1537", |
00000247 => x"e4450513", |
00000248 => x"095000ef", |
00000249 => x"059000ef", |
00000250 => x"fe051ee3", |
00000251 => x"ff002783", |
00000252 => x"00078067", |
00000253 => x"0000006f", |
00000254 => x"ff010113", |
00000255 => x"00812423", |
00000256 => x"00050413", |
00000257 => x"ffff1537", |
00000258 => x"e5450513", |
00000259 => x"00112623", |
00000260 => x"065000ef", |
00000261 => x"03040513", |
00000262 => x"0ff57513", |
00000263 => x"009000ef", |
00000264 => x"30047073", |
00000265 => x"16d000ef", |
00000266 => x"00050863", |
00000267 => x"00100513", |
00000268 => x"00000593", |
00000269 => x"19d000ef", |
00000270 => x"0000006f", |
00000271 => x"fe010113", |
00000272 => x"01212823", |
00000273 => x"00050913", |
00000274 => x"ffff1537", |
00000275 => x"00912a23", |
00000276 => x"e6050513", |
00000277 => x"ffff14b7", |
00000278 => x"00812c23", |
00000279 => x"01312623", |
00000280 => x"00112e23", |
00000281 => x"01c00413", |
00000282 => x"00d000ef", |
00000283 => x"fb848493", |
00000284 => x"ffc00993", |
00000285 => x"008957b3", |
00000286 => x"00f7f793", |
00000287 => x"00f487b3", |
00000288 => x"0007c503", |
00000289 => x"ffc40413", |
00000290 => x"79c000ef", |
00000291 => x"ff3414e3", |
00000292 => x"01c12083", |
00000293 => x"01812403", |
00000294 => x"01412483", |
00000295 => x"01012903", |
00000296 => x"00c12983", |
00000297 => x"02010113", |
00000298 => x"00008067", |
00000299 => x"fb010113", |
00000300 => x"04112623", |
00000301 => x"04512423", |
00000302 => x"04612223", |
00000303 => x"04712023", |
00000304 => x"02812e23", |
00000305 => x"02912c23", |
00000306 => x"02a12a23", |
00000307 => x"02b12823", |
00000308 => x"02c12623", |
00000309 => x"02d12423", |
00000310 => x"02e12223", |
00000311 => x"02f12023", |
00000312 => x"01012e23", |
00000313 => x"01112c23", |
00000314 => x"01c12a23", |
00000315 => x"01d12823", |
00000316 => x"01e12623", |
00000317 => x"01f12423", |
00000318 => x"342024f3", |
00000319 => x"800007b7", |
00000320 => x"00778793", |
00000321 => x"08f49463", |
00000322 => x"089000ef", |
00000323 => x"00050663", |
00000324 => x"00000513", |
00000325 => x"08d000ef", |
00000326 => x"644000ef", |
00000327 => x"02050063", |
00000328 => x"7ac000ef", |
00000329 => x"fe002783", |
00000330 => x"0027d793", |
00000331 => x"00a78533", |
00000332 => x"00f537b3", |
00000333 => x"00b785b3", |
00000334 => x"634000ef", |
00000335 => x"03c12403", |
00000336 => x"04c12083", |
00000337 => x"04812283", |
00000338 => x"04412303", |
00000339 => x"04012383", |
00000340 => x"03812483", |
00000341 => x"03412503", |
00000342 => x"03012583", |
00000343 => x"02c12603", |
00000344 => x"02812683", |
00000345 => x"02412703", |
00000346 => x"02012783", |
00000347 => x"01c12803", |
00000348 => x"01812883", |
00000349 => x"01412e03", |
00000350 => x"01012e83", |
00000351 => x"00c12f03", |
00000352 => x"00812f83", |
00000353 => x"05010113", |
00000354 => x"30200073", |
00000355 => x"00700793", |
00000356 => x"00f49a63", |
00000357 => x"8041a783", |
00000358 => x"00078663", |
00000359 => x"00100513", |
00000360 => x"e59ff0ef", |
00000361 => x"34102473", |
00000362 => x"5dc000ef", |
00000363 => x"04050263", |
00000364 => x"ffff1537", |
00000365 => x"e6450513", |
00000366 => x"6bc000ef", |
00000367 => x"00048513", |
00000368 => x"e7dff0ef", |
00000369 => x"02000513", |
00000370 => x"65c000ef", |
00000371 => x"00040513", |
00000372 => x"e6dff0ef", |
00000373 => x"02000513", |
00000374 => x"64c000ef", |
00000375 => x"34302573", |
00000376 => x"e5dff0ef", |
00000377 => x"ffff1537", |
00000378 => x"e6c50513", |
00000379 => x"688000ef", |
00000380 => x"00440413", |
00000381 => x"34141073", |
00000382 => x"f45ff06f", |
00000383 => x"ff010113", |
00000384 => x"00000513", |
00000385 => x"00112623", |
00000386 => x"00812423", |
00000387 => x"72c000ef", |
00000388 => x"09e00513", |
00000389 => x"768000ef", |
00000390 => x"00000513", |
00000391 => x"00112623", |
00000392 => x"00812423", |
00000393 => x"730000ef", |
00000394 => x"09e00513", |
00000395 => x"76c000ef", |
00000396 => x"00000513", |
00000397 => x"764000ef", |
00000398 => x"00050413", |
00000399 => x"00000513", |
00000400 => x"734000ef", |
00000401 => x"00c12083", |
00000402 => x"0ff47513", |
00000403 => x"00812403", |
00000404 => x"01010113", |
00000405 => x"00008067", |
00000406 => x"ff010113", |
00000407 => x"00112623", |
00000408 => x"00812423", |
00000409 => x"00000513", |
00000410 => x"6ec000ef", |
00000411 => x"00500513", |
00000412 => x"728000ef", |
00000413 => x"00000513", |
00000414 => x"720000ef", |
00000415 => x"00050413", |
00000416 => x"00147413", |
00000417 => x"00000513", |
00000418 => x"6ec000ef", |
00000419 => x"fc041ce3", |
00000420 => x"00c12083", |
00000421 => x"00812403", |
00000422 => x"01010113", |
00000423 => x"00008067", |
00000424 => x"ff010113", |
00000391 => x"760000ef", |
00000392 => x"00050413", |
00000393 => x"00000513", |
00000394 => x"730000ef", |
00000395 => x"00c12083", |
00000396 => x"0ff47513", |
00000397 => x"00812403", |
00000398 => x"01010113", |
00000399 => x"00008067", |
00000400 => x"ff010113", |
00000401 => x"00112623", |
00000402 => x"00812423", |
00000403 => x"00000513", |
00000404 => x"6e8000ef", |
00000405 => x"00500513", |
00000406 => x"724000ef", |
00000407 => x"00000513", |
00000408 => x"71c000ef", |
00000409 => x"00050413", |
00000410 => x"00147413", |
00000411 => x"00000513", |
00000412 => x"6e8000ef", |
00000413 => x"fc041ce3", |
00000414 => x"00c12083", |
00000415 => x"00812403", |
00000416 => x"01010113", |
00000417 => x"00008067", |
00000418 => x"ff010113", |
00000419 => x"00000513", |
00000420 => x"00112623", |
00000421 => x"6a4000ef", |
00000422 => x"00600513", |
00000423 => x"6e0000ef", |
00000424 => x"00c12083", |
00000425 => x"00000513", |
00000426 => x"00112623", |
00000427 => x"6a8000ef", |
00000428 => x"00600513", |
00000429 => x"6e4000ef", |
00000430 => x"00c12083", |
00000431 => x"00000513", |
00000432 => x"01010113", |
00000433 => x"6b00006f", |
00000434 => x"ff010113", |
00000435 => x"00812423", |
00000436 => x"00050413", |
00000437 => x"01055513", |
00000438 => x"0ff57513", |
00000439 => x"00112623", |
00000440 => x"6b8000ef", |
00000441 => x"00845513", |
00000442 => x"0ff57513", |
00000443 => x"6ac000ef", |
00000444 => x"0ff47513", |
00000445 => x"00812403", |
00000446 => x"00c12083", |
00000447 => x"01010113", |
00000448 => x"6980006f", |
00000449 => x"ff010113", |
00000450 => x"00812423", |
00000451 => x"00050413", |
00000452 => x"00000513", |
00000453 => x"00112623", |
00000454 => x"63c000ef", |
00000455 => x"00300513", |
00000456 => x"678000ef", |
00000457 => x"00040513", |
00000458 => x"fa1ff0ef", |
00000459 => x"00000513", |
00000460 => x"668000ef", |
00000461 => x"00050413", |
00000462 => x"00000513", |
00000463 => x"638000ef", |
00000464 => x"00c12083", |
00000465 => x"0ff47513", |
00000466 => x"00812403", |
00000467 => x"01010113", |
00000468 => x"00008067", |
00000469 => x"fd010113", |
00000470 => x"02812423", |
00000471 => x"02912223", |
00000472 => x"03212023", |
00000473 => x"01312e23", |
00000474 => x"01412c23", |
00000475 => x"02112623", |
00000476 => x"00050913", |
00000477 => x"00058993", |
00000478 => x"00c10493", |
00000479 => x"00000413", |
00000480 => x"00400a13", |
00000481 => x"02091e63", |
00000482 => x"4ec000ef", |
00000483 => x"00a48023", |
00000484 => x"00140413", |
00000485 => x"00148493", |
00000486 => x"ff4416e3", |
00000487 => x"02c12083", |
00000488 => x"02812403", |
00000489 => x"00c12503", |
00000490 => x"02412483", |
00000491 => x"02012903", |
00000492 => x"01c12983", |
00000493 => x"01812a03", |
00000494 => x"03010113", |
00000495 => x"00008067", |
00000496 => x"00898533", |
00000497 => x"f41ff0ef", |
00000498 => x"fc5ff06f", |
00000499 => x"fd010113", |
00000500 => x"01412c23", |
00000501 => x"02812423", |
00000502 => x"80418793", |
00000503 => x"02112623", |
00000504 => x"02912223", |
00000505 => x"03212023", |
00000506 => x"01312e23", |
00000507 => x"01512a23", |
00000508 => x"01612823", |
00000509 => x"01712623", |
00000510 => x"01812423", |
00000511 => x"00100713", |
00000512 => x"00e7a023", |
00000513 => x"00050413", |
00000514 => x"80418a13", |
00000515 => x"02051863", |
00000516 => x"ffff1537", |
00000517 => x"e8c50513", |
00000518 => x"478000ef", |
00000519 => x"080005b7", |
00000520 => x"00040513", |
00000521 => x"f31ff0ef", |
00000522 => x"4788d7b7", |
00000523 => x"afe78793", |
00000524 => x"02f50463", |
00000525 => x"00000513", |
00000526 => x"01c0006f", |
00000527 => x"ffff1537", |
00000528 => x"eac50513", |
00000529 => x"44c000ef", |
00000530 => x"dcdff0ef", |
00000531 => x"fc0518e3", |
00000532 => x"00300513", |
00000533 => x"bb5ff0ef", |
00000534 => x"080009b7", |
00000535 => x"00498593", |
00000536 => x"00040513", |
00000537 => x"ef1ff0ef", |
00000538 => x"00050a93", |
00000539 => x"00898593", |
00000540 => x"00040513", |
00000541 => x"ee1ff0ef", |
00000542 => x"ff002c03", |
00000543 => x"00050b13", |
00000544 => x"ffcafb93", |
00000545 => x"00000913", |
00000546 => x"00000493", |
00000547 => x"00c98993", |
00000548 => x"013905b3", |
00000549 => x"052b9c63", |
00000550 => x"016484b3", |
00000551 => x"00200513", |
00000552 => x"fa049ae3", |
00000553 => x"ffff1537", |
00000554 => x"eb850513", |
00000555 => x"3e4000ef", |
00000556 => x"02c12083", |
00000557 => x"02812403", |
00000558 => x"800007b7", |
00000559 => x"0157a023", |
00000560 => x"000a2023", |
00000561 => x"02412483", |
00000562 => x"02012903", |
00000563 => x"01c12983", |
00000564 => x"01812a03", |
00000565 => x"01412a83", |
00000566 => x"01012b03", |
00000567 => x"00c12b83", |
00000568 => x"00812c03", |
00000569 => x"03010113", |
00000570 => x"00008067", |
00000571 => x"00040513", |
00000572 => x"e65ff0ef", |
00000573 => x"012c07b3", |
00000574 => x"00a484b3", |
00000575 => x"00a7a023", |
00000576 => x"00490913", |
00000577 => x"f8dff06f", |
00000578 => x"ff010113", |
00000579 => x"00112623", |
00000580 => x"00812423", |
00000581 => x"00912223", |
00000582 => x"00058413", |
00000583 => x"00050493", |
00000584 => x"d81ff0ef", |
00000585 => x"00000513", |
00000586 => x"42c000ef", |
00000587 => x"00200513", |
00000588 => x"468000ef", |
00000589 => x"00048513", |
00000590 => x"d91ff0ef", |
00000591 => x"00040513", |
00000592 => x"458000ef", |
00000593 => x"00000513", |
00000594 => x"42c000ef", |
00000595 => x"00812403", |
00000596 => x"00c12083", |
00000597 => x"00412483", |
00000598 => x"01010113", |
00000599 => x"cfdff06f", |
00000600 => x"fe010113", |
00000601 => x"00812c23", |
00000602 => x"00912a23", |
00000603 => x"01212823", |
00000604 => x"00112e23", |
00000605 => x"00050493", |
00000606 => x"00b12623", |
00000607 => x"00000413", |
00000608 => x"00400913", |
00000609 => x"00c10793", |
00000610 => x"008787b3", |
00000611 => x"0007c583", |
00000612 => x"00848533", |
00000613 => x"00140413", |
00000614 => x"f71ff0ef", |
00000615 => x"ff2414e3", |
00000616 => x"01c12083", |
00000617 => x"01812403", |
00000618 => x"01412483", |
00000619 => x"01012903", |
00000620 => x"02010113", |
00000621 => x"00008067", |
00000622 => x"ff010113", |
00000623 => x"00112623", |
00000624 => x"00812423", |
00000625 => x"00050413", |
00000626 => x"cd9ff0ef", |
00000627 => x"00000513", |
00000628 => x"384000ef", |
00000629 => x"0d800513", |
00000630 => x"3c0000ef", |
00000631 => x"00040513", |
00000632 => x"ce9ff0ef", |
00000633 => x"00000513", |
00000634 => x"38c000ef", |
00000635 => x"00812403", |
00000636 => x"00c12083", |
00000637 => x"01010113", |
00000638 => x"c61ff06f", |
00000639 => x"fe010113", |
00000640 => x"800007b7", |
00000641 => x"00812c23", |
00000642 => x"0007a403", |
00000643 => x"00112e23", |
00000644 => x"00912a23", |
00000645 => x"01212823", |
00000646 => x"01312623", |
00000647 => x"01412423", |
00000648 => x"01512223", |
00000649 => x"02041863", |
00000650 => x"ffff1537", |
00000651 => x"ebc50513", |
00000652 => x"01812403", |
00000653 => x"01c12083", |
00000654 => x"01412483", |
00000655 => x"01012903", |
00000656 => x"00c12983", |
00000657 => x"00812a03", |
00000658 => x"00412a83", |
00000659 => x"02010113", |
00000660 => x"2400006f", |
00000661 => x"ffff1537", |
00000662 => x"ed850513", |
00000663 => x"234000ef", |
00000664 => x"00040513", |
00000665 => x"9f1ff0ef", |
00000666 => x"ffff1537", |
00000667 => x"ee050513", |
00000668 => x"220000ef", |
00000669 => x"08000537", |
00000670 => x"9ddff0ef", |
00000671 => x"ffff1537", |
00000672 => x"ef850513", |
00000673 => x"20c000ef", |
00000674 => x"1ec000ef", |
00000675 => x"00050493", |
00000676 => x"1b0000ef", |
00000677 => x"07900793", |
00000678 => x"0af49e63", |
00000679 => x"b79ff0ef", |
00000680 => x"00051663", |
00000681 => x"00300513", |
00000682 => x"961ff0ef", |
00000683 => x"ffff1537", |
00000684 => x"f0450513", |
00000685 => x"01045493", |
00000686 => x"1d8000ef", |
00000687 => x"00148493", |
00000688 => x"08000937", |
00000689 => x"fff00993", |
00000690 => x"00010a37", |
00000691 => x"fff48493", |
00000692 => x"07349063", |
00000693 => x"4788d5b7", |
00000694 => x"afe58593", |
00000695 => x"08000537", |
00000696 => x"e81ff0ef", |
00000697 => x"08000537", |
00000698 => x"00040593", |
00000699 => x"00450513", |
00000700 => x"e71ff0ef", |
00000701 => x"ff002a03", |
00000702 => x"080009b7", |
00000703 => x"ffc47413", |
00000704 => x"00000493", |
00000705 => x"00000913", |
00000706 => x"00c98a93", |
00000707 => x"01548533", |
00000708 => x"009a07b3", |
00000709 => x"02849663", |
00000710 => x"00898513", |
00000711 => x"412005b3", |
00000712 => x"e41ff0ef", |
00000713 => x"ffff1537", |
00000714 => x"eb850513", |
00000715 => x"f05ff06f", |
00000716 => x"00090513", |
00000717 => x"e85ff0ef", |
00000718 => x"01490933", |
00000719 => x"f91ff06f", |
00000720 => x"0007a583", |
00000721 => x"00448493", |
00000722 => x"00b90933", |
00000723 => x"e15ff0ef", |
00000724 => x"fbdff06f", |
00000725 => x"01c12083", |
00000726 => x"01812403", |
00000727 => x"01412483", |
00000728 => x"01012903", |
00000729 => x"00c12983", |
00000730 => x"00812a03", |
00000731 => x"00412a83", |
00000732 => x"02010113", |
00000733 => x"00008067", |
00000734 => x"fe802503", |
00000735 => x"01155513", |
00000736 => x"00157513", |
00000737 => x"00008067", |
00000738 => x"f9000793", |
00000739 => x"fff00713", |
00000740 => x"00e7a423", |
00000741 => x"00b7a623", |
00000742 => x"00a7a423", |
00000743 => x"00008067", |
00000744 => x"fe802503", |
00000745 => x"01255513", |
00000746 => x"00157513", |
00000747 => x"00008067", |
00000748 => x"fa002023", |
00000749 => x"fe002703", |
00000750 => x"00151513", |
00000751 => x"00000793", |
00000752 => x"04a77463", |
00000753 => x"000016b7", |
00000754 => x"00000713", |
00000755 => x"ffe68693", |
00000756 => x"04f6e663", |
00000757 => x"00367613", |
00000758 => x"0035f593", |
00000759 => x"fff78793", |
00000760 => x"01461613", |
00000761 => x"00c7e7b3", |
00000762 => x"01659593", |
00000763 => x"01871713", |
00000764 => x"00b7e7b3", |
00000765 => x"00e7e7b3", |
00000766 => x"10000737", |
00000767 => x"00e7e7b3", |
00000768 => x"faf02023", |
00000769 => x"00008067", |
00000770 => x"00178793", |
00000771 => x"01079793", |
00000772 => x"40a70733", |
00000773 => x"0107d793", |
00000774 => x"fa9ff06f", |
00000775 => x"ffe70513", |
00000776 => x"0fd57513", |
00000777 => x"00051a63", |
00000778 => x"0037d793", |
00000779 => x"00170713", |
00000780 => x"0ff77713", |
00000781 => x"f9dff06f", |
00000782 => x"0017d793", |
00000783 => x"ff1ff06f", |
00000784 => x"00040737", |
00000785 => x"fa002783", |
00000786 => x"00e7f7b3", |
00000787 => x"fe079ce3", |
00000788 => x"faa02223", |
00000426 => x"01010113", |
00000427 => x"6ac0006f", |
00000428 => x"ff010113", |
00000429 => x"00812423", |
00000430 => x"00050413", |
00000431 => x"01055513", |
00000432 => x"0ff57513", |
00000433 => x"00112623", |
00000434 => x"6b4000ef", |
00000435 => x"00845513", |
00000436 => x"0ff57513", |
00000437 => x"6a8000ef", |
00000438 => x"0ff47513", |
00000439 => x"00812403", |
00000440 => x"00c12083", |
00000441 => x"01010113", |
00000442 => x"6940006f", |
00000443 => x"ff010113", |
00000444 => x"00812423", |
00000445 => x"00050413", |
00000446 => x"00000513", |
00000447 => x"00112623", |
00000448 => x"638000ef", |
00000449 => x"00300513", |
00000450 => x"674000ef", |
00000451 => x"00040513", |
00000452 => x"fa1ff0ef", |
00000453 => x"00000513", |
00000454 => x"664000ef", |
00000455 => x"00050413", |
00000456 => x"00000513", |
00000457 => x"634000ef", |
00000458 => x"00c12083", |
00000459 => x"0ff47513", |
00000460 => x"00812403", |
00000461 => x"01010113", |
00000462 => x"00008067", |
00000463 => x"fd010113", |
00000464 => x"02812423", |
00000465 => x"02912223", |
00000466 => x"03212023", |
00000467 => x"01312e23", |
00000468 => x"02112623", |
00000469 => x"00050993", |
00000470 => x"00058493", |
00000471 => x"00c10913", |
00000472 => x"00358413", |
00000473 => x"04099063", |
00000474 => x"4f0000ef", |
00000475 => x"00a90023", |
00000476 => x"fff40793", |
00000477 => x"00190913", |
00000478 => x"02849263", |
00000479 => x"02c12083", |
00000480 => x"02812403", |
00000481 => x"00c12503", |
00000482 => x"02412483", |
00000483 => x"02012903", |
00000484 => x"01c12983", |
00000485 => x"03010113", |
00000486 => x"00008067", |
00000487 => x"00078413", |
00000488 => x"fc5ff06f", |
00000489 => x"00040513", |
00000490 => x"f45ff0ef", |
00000491 => x"fc1ff06f", |
00000492 => x"fd010113", |
00000493 => x"01412c23", |
00000494 => x"02812423", |
00000495 => x"80418793", |
00000496 => x"02112623", |
00000497 => x"02912223", |
00000498 => x"03212023", |
00000499 => x"01312e23", |
00000500 => x"01512a23", |
00000501 => x"01612823", |
00000502 => x"01712623", |
00000503 => x"01812423", |
00000504 => x"00100713", |
00000505 => x"00e7a023", |
00000506 => x"00050413", |
00000507 => x"80418a13", |
00000508 => x"02051863", |
00000509 => x"ffff1537", |
00000510 => x"e7050513", |
00000511 => x"478000ef", |
00000512 => x"080005b7", |
00000513 => x"00040513", |
00000514 => x"f35ff0ef", |
00000515 => x"4788d7b7", |
00000516 => x"afe78793", |
00000517 => x"02f50463", |
00000518 => x"00000513", |
00000519 => x"01c0006f", |
00000520 => x"ffff1537", |
00000521 => x"e9050513", |
00000522 => x"44c000ef", |
00000523 => x"dd1ff0ef", |
00000524 => x"fc0518e3", |
00000525 => x"00300513", |
00000526 => x"bc1ff0ef", |
00000527 => x"080009b7", |
00000528 => x"00498593", |
00000529 => x"00040513", |
00000530 => x"ef5ff0ef", |
00000531 => x"00050a93", |
00000532 => x"00898593", |
00000533 => x"00040513", |
00000534 => x"ee5ff0ef", |
00000535 => x"ff002c03", |
00000536 => x"00050b13", |
00000537 => x"ffcafb93", |
00000538 => x"00000913", |
00000539 => x"00000493", |
00000540 => x"00c98993", |
00000541 => x"013905b3", |
00000542 => x"052b9c63", |
00000543 => x"016484b3", |
00000544 => x"00200513", |
00000545 => x"fa049ae3", |
00000546 => x"ffff1537", |
00000547 => x"e9c50513", |
00000548 => x"3e4000ef", |
00000549 => x"02c12083", |
00000550 => x"02812403", |
00000551 => x"800007b7", |
00000552 => x"0157a023", |
00000553 => x"000a2023", |
00000554 => x"02412483", |
00000555 => x"02012903", |
00000556 => x"01c12983", |
00000557 => x"01812a03", |
00000558 => x"01412a83", |
00000559 => x"01012b03", |
00000560 => x"00c12b83", |
00000561 => x"00812c03", |
00000562 => x"03010113", |
00000563 => x"00008067", |
00000564 => x"00040513", |
00000565 => x"e69ff0ef", |
00000566 => x"012c07b3", |
00000567 => x"00a484b3", |
00000568 => x"00a7a023", |
00000569 => x"00490913", |
00000570 => x"f8dff06f", |
00000571 => x"ff010113", |
00000572 => x"00112623", |
00000573 => x"00812423", |
00000574 => x"00912223", |
00000575 => x"00058413", |
00000576 => x"00050493", |
00000577 => x"d85ff0ef", |
00000578 => x"00000513", |
00000579 => x"42c000ef", |
00000580 => x"00200513", |
00000581 => x"468000ef", |
00000582 => x"00048513", |
00000583 => x"d95ff0ef", |
00000584 => x"00040513", |
00000585 => x"458000ef", |
00000586 => x"00000513", |
00000587 => x"42c000ef", |
00000588 => x"00812403", |
00000589 => x"00c12083", |
00000590 => x"00412483", |
00000591 => x"01010113", |
00000592 => x"d01ff06f", |
00000593 => x"fe010113", |
00000594 => x"00812c23", |
00000595 => x"00912a23", |
00000596 => x"01212823", |
00000597 => x"00112e23", |
00000598 => x"00050413", |
00000599 => x"00b12623", |
00000600 => x"00c10913", |
00000601 => x"00350493", |
00000602 => x"00094583", |
00000603 => x"00048513", |
00000604 => x"00190913", |
00000605 => x"f79ff0ef", |
00000606 => x"00048793", |
00000607 => x"fff48493", |
00000608 => x"fef414e3", |
00000609 => x"01c12083", |
00000610 => x"01812403", |
00000611 => x"01412483", |
00000612 => x"01012903", |
00000613 => x"02010113", |
00000614 => x"00008067", |
00000615 => x"ff010113", |
00000616 => x"00112623", |
00000617 => x"00812423", |
00000618 => x"00050413", |
00000619 => x"cddff0ef", |
00000620 => x"00000513", |
00000621 => x"384000ef", |
00000622 => x"0d800513", |
00000623 => x"3c0000ef", |
00000624 => x"00040513", |
00000625 => x"cedff0ef", |
00000626 => x"00000513", |
00000627 => x"38c000ef", |
00000628 => x"00812403", |
00000629 => x"00c12083", |
00000630 => x"01010113", |
00000631 => x"c65ff06f", |
00000632 => x"fe010113", |
00000633 => x"800007b7", |
00000634 => x"00812c23", |
00000635 => x"0007a403", |
00000636 => x"00112e23", |
00000637 => x"00912a23", |
00000638 => x"01212823", |
00000639 => x"01312623", |
00000640 => x"01412423", |
00000641 => x"01512223", |
00000642 => x"02041863", |
00000643 => x"ffff1537", |
00000644 => x"ea050513", |
00000645 => x"01812403", |
00000646 => x"01c12083", |
00000647 => x"01412483", |
00000648 => x"01012903", |
00000649 => x"00c12983", |
00000650 => x"00812a03", |
00000651 => x"00412a83", |
00000652 => x"02010113", |
00000653 => x"2400006f", |
00000654 => x"ffff1537", |
00000655 => x"ebc50513", |
00000656 => x"234000ef", |
00000657 => x"00040513", |
00000658 => x"9f5ff0ef", |
00000659 => x"ffff1537", |
00000660 => x"ec450513", |
00000661 => x"220000ef", |
00000662 => x"08000537", |
00000663 => x"9e1ff0ef", |
00000664 => x"ffff1537", |
00000665 => x"edc50513", |
00000666 => x"20c000ef", |
00000667 => x"1ec000ef", |
00000668 => x"00050493", |
00000669 => x"1b0000ef", |
00000670 => x"07900793", |
00000671 => x"0af49e63", |
00000672 => x"b7dff0ef", |
00000673 => x"00051663", |
00000674 => x"00300513", |
00000675 => x"96dff0ef", |
00000676 => x"ffff1537", |
00000677 => x"ee850513", |
00000678 => x"01045493", |
00000679 => x"1d8000ef", |
00000680 => x"00148493", |
00000681 => x"08000937", |
00000682 => x"fff00993", |
00000683 => x"00010a37", |
00000684 => x"fff48493", |
00000685 => x"07349063", |
00000686 => x"4788d5b7", |
00000687 => x"afe58593", |
00000688 => x"08000537", |
00000689 => x"e81ff0ef", |
00000690 => x"08000537", |
00000691 => x"00040593", |
00000692 => x"00450513", |
00000693 => x"e71ff0ef", |
00000694 => x"ff002a03", |
00000695 => x"080009b7", |
00000696 => x"ffc47413", |
00000697 => x"00000493", |
00000698 => x"00000913", |
00000699 => x"00c98a93", |
00000700 => x"01548533", |
00000701 => x"009a07b3", |
00000702 => x"02849663", |
00000703 => x"00898513", |
00000704 => x"412005b3", |
00000705 => x"e41ff0ef", |
00000706 => x"ffff1537", |
00000707 => x"e9c50513", |
00000708 => x"f05ff06f", |
00000709 => x"00090513", |
00000710 => x"e85ff0ef", |
00000711 => x"01490933", |
00000712 => x"f91ff06f", |
00000713 => x"0007a583", |
00000714 => x"00448493", |
00000715 => x"00b90933", |
00000716 => x"e15ff0ef", |
00000717 => x"fbdff06f", |
00000718 => x"01c12083", |
00000719 => x"01812403", |
00000720 => x"01412483", |
00000721 => x"01012903", |
00000722 => x"00c12983", |
00000723 => x"00812a03", |
00000724 => x"00412a83", |
00000725 => x"02010113", |
00000726 => x"00008067", |
00000727 => x"fe802503", |
00000728 => x"01155513", |
00000729 => x"00157513", |
00000730 => x"00008067", |
00000731 => x"f9000793", |
00000732 => x"fff00713", |
00000733 => x"00e7a423", |
00000734 => x"00b7a623", |
00000735 => x"00a7a423", |
00000736 => x"00008067", |
00000737 => x"fe802503", |
00000738 => x"01255513", |
00000739 => x"00157513", |
00000740 => x"00008067", |
00000741 => x"fa002023", |
00000742 => x"fe002703", |
00000743 => x"00151513", |
00000744 => x"00000793", |
00000745 => x"04a77463", |
00000746 => x"000016b7", |
00000747 => x"00000713", |
00000748 => x"ffe68693", |
00000749 => x"04f6e663", |
00000750 => x"00367613", |
00000751 => x"0035f593", |
00000752 => x"fff78793", |
00000753 => x"01461613", |
00000754 => x"00c7e7b3", |
00000755 => x"01659593", |
00000756 => x"01871713", |
00000757 => x"00b7e7b3", |
00000758 => x"00e7e7b3", |
00000759 => x"10000737", |
00000760 => x"00e7e7b3", |
00000761 => x"faf02023", |
00000762 => x"00008067", |
00000763 => x"00178793", |
00000764 => x"01079793", |
00000765 => x"40a70733", |
00000766 => x"0107d793", |
00000767 => x"fa9ff06f", |
00000768 => x"ffe70513", |
00000769 => x"0fd57513", |
00000770 => x"00051a63", |
00000771 => x"0037d793", |
00000772 => x"00170713", |
00000773 => x"0ff77713", |
00000774 => x"f9dff06f", |
00000775 => x"0017d793", |
00000776 => x"ff1ff06f", |
00000777 => x"00040737", |
00000778 => x"fa002783", |
00000779 => x"00e7f7b3", |
00000780 => x"fe079ce3", |
00000781 => x"faa02223", |
00000782 => x"00008067", |
00000783 => x"fa002783", |
00000784 => x"00100513", |
00000785 => x"0007c863", |
00000786 => x"0107d513", |
00000787 => x"00154513", |
00000788 => x"00157513", |
00000789 => x"00008067", |
00000790 => x"fa002783", |
00000791 => x"00100513", |
00000792 => x"0007c863", |
00000793 => x"0107d513", |
00000794 => x"00154513", |
00000795 => x"00157513", |
00000790 => x"fa402503", |
00000791 => x"fe055ee3", |
00000792 => x"0ff57513", |
00000793 => x"00008067", |
00000794 => x"fa402503", |
00000795 => x"01f55513", |
00000796 => x"00008067", |
00000797 => x"fa402503", |
00000798 => x"fe055ee3", |
00000799 => x"0ff57513", |
00000800 => x"00008067", |
00000801 => x"fa402503", |
00000802 => x"01f55513", |
00000803 => x"00008067", |
00000804 => x"ff010113", |
00000805 => x"00812423", |
00000806 => x"01212023", |
00000807 => x"00112623", |
00000808 => x"00912223", |
00000809 => x"00050413", |
00000810 => x"00a00913", |
00000811 => x"00044483", |
00000812 => x"00140413", |
00000813 => x"00049e63", |
00000814 => x"00c12083", |
00000815 => x"00812403", |
00000816 => x"00412483", |
00000817 => x"00012903", |
00000818 => x"01010113", |
00000819 => x"00008067", |
00000820 => x"01249663", |
00000821 => x"00d00513", |
00000822 => x"f69ff0ef", |
00000823 => x"00048513", |
00000824 => x"f61ff0ef", |
00000825 => x"fc9ff06f", |
00000826 => x"ff010113", |
00000827 => x"c81026f3", |
00000828 => x"c0102773", |
00000829 => x"c81027f3", |
00000830 => x"fed79ae3", |
00000831 => x"00e12023", |
00000832 => x"00f12223", |
00000833 => x"00012503", |
00000834 => x"00412583", |
00000835 => x"01010113", |
00000836 => x"00008067", |
00000837 => x"00757513", |
00000838 => x"0036f793", |
00000839 => x"00167613", |
00000840 => x"00a51513", |
00000841 => x"00d79793", |
00000842 => x"0015f593", |
00000843 => x"00f567b3", |
00000844 => x"00f61613", |
00000845 => x"00c7e7b3", |
00000846 => x"00959593", |
00000847 => x"fa800713", |
00000848 => x"00b7e7b3", |
00000849 => x"00072023", |
00000850 => x"1007e793", |
00000851 => x"00f72023", |
00000852 => x"00008067", |
00000853 => x"fa800713", |
00000854 => x"00072683", |
00000855 => x"00757793", |
00000856 => x"00100513", |
00000857 => x"00f51533", |
00000858 => x"00d56533", |
00000859 => x"00a72023", |
00000860 => x"00008067", |
00000861 => x"fa800713", |
00000862 => x"00072683", |
00000863 => x"00757513", |
00000864 => x"00100793", |
00000865 => x"00a797b3", |
00000866 => x"fff7c793", |
00000867 => x"00d7f7b3", |
00000868 => x"00f72023", |
00000869 => x"00008067", |
00000870 => x"faa02623", |
00000871 => x"fa802783", |
00000872 => x"fe07cee3", |
00000873 => x"fac02503", |
00000874 => x"00008067", |
00000875 => x"fe802503", |
00000876 => x"01055513", |
00000877 => x"00157513", |
00000878 => x"00008067", |
00000879 => x"00100793", |
00000880 => x"01f00713", |
00000881 => x"00a797b3", |
00000882 => x"00a74a63", |
00000883 => x"fc802703", |
00000884 => x"00f747b3", |
00000885 => x"fcf02423", |
00000886 => x"00008067", |
00000887 => x"fcc02703", |
00000888 => x"00f747b3", |
00000889 => x"fcf02623", |
00000890 => x"00008067", |
00000891 => x"fc000793", |
00000892 => x"00a7a423", |
00000893 => x"00b7a623", |
00000894 => x"00008067", |
00000895 => x"69617641", |
00000896 => x"6c62616c", |
00000897 => x"4d432065", |
00000898 => x"0a3a7344", |
00000899 => x"203a6820", |
00000900 => x"706c6548", |
00000901 => x"3a72200a", |
00000902 => x"73655220", |
00000903 => x"74726174", |
00000904 => x"3a75200a", |
00000905 => x"6c705520", |
00000906 => x"0a64616f", |
00000907 => x"203a7320", |
00000908 => x"726f7453", |
00000909 => x"6f742065", |
00000910 => x"616c6620", |
00000911 => x"200a6873", |
00000912 => x"4c203a6c", |
00000913 => x"2064616f", |
00000914 => x"6d6f7266", |
00000915 => x"616c6620", |
00000916 => x"200a6873", |
00000917 => x"45203a65", |
00000918 => x"75636578", |
00000919 => x"00006574", |
00000920 => x"746f6f42", |
00000921 => x"2e676e69", |
00000922 => x"0a0a2e2e", |
00000923 => x"00000000", |
00000924 => x"52450a07", |
00000925 => x"5f524f52", |
00000926 => x"00000000", |
00000927 => x"00007830", |
00000928 => x"52455b0a", |
00000929 => x"00002052", |
00000930 => x"00000a5d", |
00000931 => x"69617741", |
00000932 => x"676e6974", |
00000933 => x"6f656e20", |
00000934 => x"32337672", |
00000935 => x"6578655f", |
00000936 => x"6e69622e", |
00000937 => x"202e2e2e", |
00000938 => x"00000000", |
00000939 => x"64616f4c", |
00000940 => x"2e676e69", |
00000941 => x"00202e2e", |
00000942 => x"00004b4f", |
00000943 => x"65206f4e", |
00000944 => x"75636578", |
00000945 => x"6c626174", |
00000946 => x"76612065", |
00000947 => x"616c6961", |
00000948 => x"2e656c62", |
00000949 => x"00000000", |
00000950 => x"74697257", |
00000951 => x"00002065", |
00000952 => x"74796220", |
00000953 => x"74207365", |
00000954 => x"5053206f", |
00000955 => x"6c662049", |
00000956 => x"20687361", |
00000957 => x"00783040", |
00000958 => x"7928203f", |
00000959 => x"20296e2f", |
00000960 => x"00000000", |
00000961 => x"616c460a", |
00000962 => x"6e696873", |
00000963 => x"2e2e2e67", |
00000964 => x"00000020", |
00000965 => x"3c0a0a0a", |
00000966 => x"454e203c", |
00000967 => x"3356524f", |
00000968 => x"6f422032", |
00000969 => x"6f6c746f", |
00000970 => x"72656461", |
00000971 => x"0a3e3e20", |
00000972 => x"444c420a", |
00000973 => x"4f203a56", |
00000974 => x"32207463", |
00000975 => x"30322037", |
00000976 => x"480a3132", |
00000977 => x"203a5657", |
00000978 => x"00000020", |
00000979 => x"4b4c430a", |
00000980 => x"0020203a", |
00000981 => x"53494d0a", |
00000982 => x"00203a41", |
00000983 => x"5550430a", |
00000984 => x"0020203a", |
00000985 => x"434f530a", |
00000986 => x"0020203a", |
00000987 => x"454d490a", |
00000988 => x"00203a4d", |
00000989 => x"74796220", |
00000990 => x"40207365", |
00000991 => x"00000000", |
00000992 => x"454d440a", |
00000993 => x"00203a4d", |
00000994 => x"75410a0a", |
00000995 => x"6f626f74", |
00000996 => x"6920746f", |
00000997 => x"7338206e", |
00000998 => x"7250202e", |
00000999 => x"20737365", |
00001000 => x"2079656b", |
00001001 => x"61206f74", |
00001002 => x"74726f62", |
00001003 => x"00000a2e", |
00001004 => x"0000000a", |
00001005 => x"726f6241", |
00001006 => x"2e646574", |
00001007 => x"00000a0a", |
00001008 => x"444d430a", |
00001009 => x"00203e3a", |
00001010 => x"61766e49", |
00001011 => x"2064696c", |
00001012 => x"00444d43", |
00001013 => x"33323130", |
00001014 => x"37363534", |
00001015 => x"62613938", |
00001016 => x"66656463" |
00000797 => x"ff010113", |
00000798 => x"00812423", |
00000799 => x"01212023", |
00000800 => x"00112623", |
00000801 => x"00912223", |
00000802 => x"00050413", |
00000803 => x"00a00913", |
00000804 => x"00044483", |
00000805 => x"00140413", |
00000806 => x"00049e63", |
00000807 => x"00c12083", |
00000808 => x"00812403", |
00000809 => x"00412483", |
00000810 => x"00012903", |
00000811 => x"01010113", |
00000812 => x"00008067", |
00000813 => x"01249663", |
00000814 => x"00d00513", |
00000815 => x"f69ff0ef", |
00000816 => x"00048513", |
00000817 => x"f61ff0ef", |
00000818 => x"fc9ff06f", |
00000819 => x"ff010113", |
00000820 => x"c81026f3", |
00000821 => x"c0102773", |
00000822 => x"c81027f3", |
00000823 => x"fed79ae3", |
00000824 => x"00e12023", |
00000825 => x"00f12223", |
00000826 => x"00012503", |
00000827 => x"00412583", |
00000828 => x"01010113", |
00000829 => x"00008067", |
00000830 => x"00757513", |
00000831 => x"0036f793", |
00000832 => x"00167613", |
00000833 => x"00a51513", |
00000834 => x"00d79793", |
00000835 => x"0015f593", |
00000836 => x"00f567b3", |
00000837 => x"00f61613", |
00000838 => x"00c7e7b3", |
00000839 => x"00959593", |
00000840 => x"fa800713", |
00000841 => x"00b7e7b3", |
00000842 => x"00072023", |
00000843 => x"1007e793", |
00000844 => x"00f72023", |
00000845 => x"00008067", |
00000846 => x"fa800713", |
00000847 => x"00072683", |
00000848 => x"00757793", |
00000849 => x"00100513", |
00000850 => x"00f51533", |
00000851 => x"00d56533", |
00000852 => x"00a72023", |
00000853 => x"00008067", |
00000854 => x"fa800713", |
00000855 => x"00072683", |
00000856 => x"00757513", |
00000857 => x"00100793", |
00000858 => x"00a797b3", |
00000859 => x"fff7c793", |
00000860 => x"00d7f7b3", |
00000861 => x"00f72023", |
00000862 => x"00008067", |
00000863 => x"faa02623", |
00000864 => x"fa802783", |
00000865 => x"fe07cee3", |
00000866 => x"fac02503", |
00000867 => x"00008067", |
00000868 => x"fe802503", |
00000869 => x"01055513", |
00000870 => x"00157513", |
00000871 => x"00008067", |
00000872 => x"00100793", |
00000873 => x"01f00713", |
00000874 => x"00a797b3", |
00000875 => x"00a74a63", |
00000876 => x"fc802703", |
00000877 => x"00f747b3", |
00000878 => x"fcf02423", |
00000879 => x"00008067", |
00000880 => x"fcc02703", |
00000881 => x"00f747b3", |
00000882 => x"fcf02623", |
00000883 => x"00008067", |
00000884 => x"fc000793", |
00000885 => x"00a7a423", |
00000886 => x"00b7a623", |
00000887 => x"00008067", |
00000888 => x"69617641", |
00000889 => x"6c62616c", |
00000890 => x"4d432065", |
00000891 => x"0a3a7344", |
00000892 => x"203a6820", |
00000893 => x"706c6548", |
00000894 => x"3a72200a", |
00000895 => x"73655220", |
00000896 => x"74726174", |
00000897 => x"3a75200a", |
00000898 => x"6c705520", |
00000899 => x"0a64616f", |
00000900 => x"203a7320", |
00000901 => x"726f7453", |
00000902 => x"6f742065", |
00000903 => x"616c6620", |
00000904 => x"200a6873", |
00000905 => x"4c203a6c", |
00000906 => x"2064616f", |
00000907 => x"6d6f7266", |
00000908 => x"616c6620", |
00000909 => x"200a6873", |
00000910 => x"45203a65", |
00000911 => x"75636578", |
00000912 => x"00006574", |
00000913 => x"746f6f42", |
00000914 => x"2e676e69", |
00000915 => x"0a0a2e2e", |
00000916 => x"00000000", |
00000917 => x"52450a07", |
00000918 => x"5f524f52", |
00000919 => x"00000000", |
00000920 => x"00007830", |
00000921 => x"52455b0a", |
00000922 => x"00002052", |
00000923 => x"00000a5d", |
00000924 => x"69617741", |
00000925 => x"676e6974", |
00000926 => x"6f656e20", |
00000927 => x"32337672", |
00000928 => x"6578655f", |
00000929 => x"6e69622e", |
00000930 => x"202e2e2e", |
00000931 => x"00000000", |
00000932 => x"64616f4c", |
00000933 => x"2e676e69", |
00000934 => x"00202e2e", |
00000935 => x"00004b4f", |
00000936 => x"65206f4e", |
00000937 => x"75636578", |
00000938 => x"6c626174", |
00000939 => x"76612065", |
00000940 => x"616c6961", |
00000941 => x"2e656c62", |
00000942 => x"00000000", |
00000943 => x"74697257", |
00000944 => x"00002065", |
00000945 => x"74796220", |
00000946 => x"74207365", |
00000947 => x"5053206f", |
00000948 => x"6c662049", |
00000949 => x"20687361", |
00000950 => x"00783040", |
00000951 => x"7928203f", |
00000952 => x"20296e2f", |
00000953 => x"00000000", |
00000954 => x"616c460a", |
00000955 => x"6e696873", |
00000956 => x"2e2e2e67", |
00000957 => x"00000020", |
00000958 => x"3c0a0a0a", |
00000959 => x"454e203c", |
00000960 => x"3356524f", |
00000961 => x"6f422032", |
00000962 => x"6f6c746f", |
00000963 => x"72656461", |
00000964 => x"0a3e3e20", |
00000965 => x"444c420a", |
00000966 => x"4e203a56", |
00000967 => x"3220766f", |
00000968 => x"30322038", |
00000969 => x"480a3132", |
00000970 => x"203a5657", |
00000971 => x"00000020", |
00000972 => x"4b4c430a", |
00000973 => x"0020203a", |
00000974 => x"53494d0a", |
00000975 => x"00203a41", |
00000976 => x"5550430a", |
00000977 => x"0020203a", |
00000978 => x"434f530a", |
00000979 => x"0020203a", |
00000980 => x"454d490a", |
00000981 => x"00203a4d", |
00000982 => x"74796220", |
00000983 => x"40207365", |
00000984 => x"00000000", |
00000985 => x"454d440a", |
00000986 => x"00203a4d", |
00000987 => x"75410a0a", |
00000988 => x"6f626f74", |
00000989 => x"6920746f", |
00000990 => x"7338206e", |
00000991 => x"7250202e", |
00000992 => x"20737365", |
00000993 => x"2079656b", |
00000994 => x"61206f74", |
00000995 => x"74726f62", |
00000996 => x"00000a2e", |
00000997 => x"0000000a", |
00000998 => x"726f6241", |
00000999 => x"2e646574", |
00001000 => x"00000a0a", |
00001001 => x"444d430a", |
00001002 => x"00203e3a", |
00001003 => x"61766e49", |
00001004 => x"2064696c", |
00001005 => x"00444d43", |
00001006 => x"33323130", |
00001007 => x"37363534", |
00001008 => x"62613938", |
00001009 => x"66656463" |
); |
|
end neorv32_bootloader_image; |
/rtl/core/neorv32_bus_keeper.vhd
87,7 → 87,7
-- controller -- |
type control_t is record |
pending : std_ulogic; |
timeout : std_ulogic_vector(index_size_f(max_proc_int_response_time_c)-1 downto 0); |
timeout : std_ulogic_vector(index_size_f(max_proc_int_response_time_c) downto 0); |
err_type : std_ulogic; |
bus_err : std_ulogic; |
end record; |
148,7 → 148,7
|
-- access monitor: IDLE -- |
if (control.pending = '0') then |
control.timeout <= std_ulogic_vector(to_unsigned(max_proc_int_response_time_c, index_size_f(max_proc_int_response_time_c))); |
control.timeout <= std_ulogic_vector(to_unsigned(max_proc_int_response_time_c, index_size_f(max_proc_int_response_time_c)+1)); |
if (bus_rden_i = '1') or (bus_wren_i = '1') then |
control.pending <= '1'; |
end if; |
/rtl/core/neorv32_cfs.vhd
174,10 → 174,10
-- Interrupt ------------------------------------------------------------------------------ |
-- ------------------------------------------------------------------------------------------- |
-- The CFS features a single interrupt signal, which is connected to the CPU's "fast interrupt" channel 1. |
-- The interrupt is high-level-active. When set, the interrupt appears as "pending" in the CPU's mie register |
-- ready to trigger execution of the according interrupt handler. |
-- Once set, the irq_o signal **has to stay set** until explicitly acknowledged by the CPU |
-- (for example by reading/writing from/to a specific CFS interface register address). |
-- The interrupt is triggered by a one-shot rising edge. After triggering, the interrupt appears as "pending" in the CPU's mie register |
-- ready to trigger execution of the according interrupt handler. The interrupt request signal should be triggered |
-- whenever an interrupt condition is fulfilled. It is the task of the application to programmer to enable/clear the CFS interrupt |
-- using the CPU's mie and mip registers when reuqired. |
|
irq_o <= '0'; -- not used for this minimal example |
|
/rtl/core/neorv32_cpu.vhd
94,6 → 94,7
clk_i : in std_ulogic; -- global clock, rising edge |
rstn_i : in std_ulogic; -- global reset, low-active, async |
sleep_o : out std_ulogic; -- cpu is in sleep mode when set |
debug_o : out std_ulogic; -- cpu is in debug mode when set |
-- instruction bus interface -- |
i_bus_addr_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus access address |
i_bus_rdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus read data |
316,7 → 317,10
-- CPU is sleeping? -- |
sleep_o <= ctrl(ctrl_sleep_c); -- set when CPU is sleeping (after WFI) |
|
-- CPU is in debug mode? -- |
debug_o <= ctrl(ctrl_debug_running_c); |
|
|
-- Register File -------------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
neorv32_cpu_regfile_inst: neorv32_cpu_regfile |
/rtl/core/neorv32_cpu_control.vhd
287,6 → 287,8
mie_mtie : std_ulogic; -- mie.MEIE: machine timer interrupt enable (R/W) |
mie_firqe : std_ulogic_vector(15 downto 0); -- mie.firq*e: fast interrupt enabled (R/W) |
-- |
mip_clr : std_ulogic_vector(15 downto 0); -- clear pending FIRQ |
-- |
mcounteren_cy : std_ulogic; -- mcounteren.cy: allow cycle[h] access from user-mode |
mcounteren_tm : std_ulogic; -- mcounteren.tm: allow time[h] access from user-mode |
mcounteren_ir : std_ulogic; -- mcounteren.ir: allow instret[h] access from user-mode |
392,7 → 394,7
elsif rising_edge(clk_i) then |
fetch_engine.state <= fetch_engine.state_nxt; |
fetch_engine.state_prev <= fetch_engine.state; |
fetch_engine.restart <= fetch_engine.restart_nxt; |
fetch_engine.restart <= fetch_engine.restart_nxt or fetch_engine.reset; |
if (fetch_engine.restart = '1') then |
fetch_engine.pc <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- initialize with "real" application PC |
else |
414,9 → 416,9
fetch_engine.state_nxt <= fetch_engine.state; |
fetch_engine.pc_nxt <= fetch_engine.pc; |
fetch_engine.bus_err_ack <= '0'; |
fetch_engine.restart_nxt <= fetch_engine.restart or fetch_engine.reset; |
fetch_engine.restart_nxt <= fetch_engine.restart; |
|
-- instruction prefetch buffer interface -- |
-- instruction prefetch buffer defaults -- |
ipb.we <= '0'; |
ipb.wdata <= be_instr_i & ma_instr_i & instr_i(31 downto 0); -- store exception info and instruction word |
ipb.clear <= fetch_engine.restart; |
430,20 → 432,16
bus_fast_ir <= '1'; -- fast instruction fetch request |
fetch_engine.state_nxt <= IFETCH_ISSUE; |
end if; |
if (fetch_engine.restart = '1') then -- reset request? |
fetch_engine.restart_nxt <= '0'; |
end if; |
fetch_engine.restart_nxt <= '0'; |
|
when IFETCH_ISSUE => -- store instruction data to prefetch buffer |
-- ------------------------------------------------------------ |
fetch_engine.bus_err_ack <= be_instr_i or ma_instr_i; -- ACK bus/alignment errors |
if (bus_i_wait_i = '0') or (be_instr_i = '1') or (ma_instr_i = '1') then -- wait for bus response |
fetch_engine.pc_nxt <= std_ulogic_vector(unsigned(fetch_engine.pc) + 4); |
ipb.we <= not fetch_engine.restart; -- write to IPB if not being reset |
if (fetch_engine.restart = '1') then -- reset request? |
fetch_engine.restart_nxt <= '0'; |
end if; |
fetch_engine.state_nxt <= IFETCH_REQUEST; |
fetch_engine.pc_nxt <= std_ulogic_vector(unsigned(fetch_engine.pc) + 4); |
ipb.we <= not fetch_engine.restart; -- write to IPB if not being reset |
fetch_engine.restart_nxt <= '0'; |
fetch_engine.state_nxt <= IFETCH_REQUEST; |
end if; |
|
when others => -- undefined |
504,7 → 502,7
issue_engine.align <= '1'; -- aligned on 16-bit boundary |
else |
issue_engine.state <= issue_engine.state_nxt; |
issue_engine.align <= '0'; -- always aligned on 32-bit boundaries |
issue_engine.align <= '0'; -- aligned on 32-bit boundary |
end if; |
else |
issue_engine.state <= issue_engine.state_nxt; |
541,14 → 539,13
|
if (issue_engine.align = '0') or (CPU_EXTENSION_RISCV_C = false) then -- begin check in LOW instruction half-word |
if (execute_engine.state = DISPATCH) then -- ready to issue new command? |
ipb.re <= '1'; |
cmd_issue.valid <= '1'; |
issue_engine.buf_nxt <= ipb.rdata(33 downto 32) & ipb.rdata(31 downto 16); -- store high half-word - we might need it for an unaligned uncompressed instruction |
if (ipb.rdata(1 downto 0) = "11") or (CPU_EXTENSION_RISCV_C = false) then -- uncompressed and "aligned" |
ipb.re <= '1'; |
cmd_issue.data <= '0' & ipb.rdata(33 downto 32) & '0' & ipb.rdata(31 downto 0); |
else -- compressed |
ipb.re <= '1'; |
cmd_issue.data <= ci_illegal & ipb.rdata(33 downto 32) & '1' & ci_instr32; |
cmd_issue.data <= ci_illegal & ipb.rdata(33 downto 32) & '1' & ci_instr32; |
issue_engine.align_nxt <= '1'; |
end if; |
end if; |
558,11 → 555,11
cmd_issue.valid <= '1'; |
issue_engine.buf_nxt <= ipb.rdata(33 downto 32) & ipb.rdata(31 downto 16); -- store high half-word - we might need it for an unaligned uncompressed instruction |
if (issue_engine.buf(1 downto 0) = "11") then -- uncompressed and "unaligned" |
ipb.re <= '1'; |
ipb.re <= '1'; |
cmd_issue.data <= '0' & (ipb.rdata(33 downto 32) or issue_engine.buf(17 downto 16)) & '0' & (ipb.rdata(15 downto 0) & issue_engine.buf(15 downto 0)); |
else -- compressed |
-- do not read from ipb here! |
cmd_issue.data <= ci_illegal & ipb.rdata(33 downto 32) & '1' & ci_instr32; |
cmd_issue.data <= ci_illegal & ipb.rdata(33 downto 32) & '1' & ci_instr32; |
issue_engine.align_nxt <= '0'; |
end if; |
end if; |
573,7 → 570,7
-- ------------------------------------------------------------ |
issue_engine.buf_nxt <= ipb.rdata(33 downto 32) & ipb.rdata(31 downto 16); |
if (ipb.avail = '1') then -- instructions available? |
ipb.re <= '1'; |
ipb.re <= '1'; |
issue_engine.state_nxt <= ISSUE_ACTIVE; |
end if; |
|
787,7 → 784,7
ctrl_o(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c) <= execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c); |
ctrl_o(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c) <= execute_engine.i_reg(instr_rs2_msb_c downto instr_rs2_lsb_c); |
ctrl_o(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) <= execute_engine.i_reg(instr_rd_msb_c downto instr_rd_lsb_c); |
-- fast bus access requests -- |
-- instruction fetch request -- |
ctrl_o(ctrl_bus_if_c) <= bus_fast_ir; |
-- bus error control -- |
ctrl_o(ctrl_bus_ierr_ack_c) <= fetch_engine.bus_err_ack; -- instruction fetch bus access error ACK |
1040,14 → 1037,13
ctrl_nxt(ctrl_alu_op2_c downto ctrl_alu_op0_c) <= alu_op_and_c; |
end case; |
|
-- Check if single-cycle or multi-cycle (co-processor) operation -- |
-- co-processor MULDIV operation? -- |
-- co-processor MULDIV operation (multi-cycle)? -- |
if ((CPU_EXTENSION_RISCV_M = true) and ((decode_aux.is_m_mul = '1') or (decode_aux.is_m_div = '1'))) or -- MUL/DIV |
((CPU_EXTENSION_RISCV_Zmmul = true) and (decode_aux.is_m_mul = '1')) then -- MUL |
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_muldiv_c; -- use MULDIV CP |
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_copro_c; |
execute_engine.state_nxt <= ALU_WAIT; |
-- co-processor BIT-MANIPULATION operation? -- |
-- co-processor BIT-MANIPULATION operation (multi-cycle)? -- |
elsif (CPU_EXTENSION_RISCV_B = true) and |
(((execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and (decode_aux.is_bitmanip_reg = '1')) or -- register operation |
((execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alui_c(5)) and (decode_aux.is_bitmanip_imm = '1'))) then -- immediate operation |
1054,13 → 1050,13
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_bitmanip_c; -- use BITMANIP CP |
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_copro_c; |
execute_engine.state_nxt <= ALU_WAIT; |
-- co-processor SHIFT operation? -- |
-- co-processor SHIFT operation (multi-cycle)? -- |
elsif (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sll_c) or |
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sr_c) then |
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_shifter_c; -- use SHIFTER CP (only relevant for shift operations) |
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_copro_c; |
execute_engine.state_nxt <= ALU_WAIT; |
-- ALU core operations (single-cycle) -- |
-- ALU CORE operation (single-cycle) -- |
else |
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_core_c; |
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back |
1152,7 → 1148,7
when funct12_ecall_c => trap_ctrl.env_call <= '1'; -- ECALL |
when funct12_ebreak_c => trap_ctrl.break_point <= '1'; -- EBREAK |
when funct12_mret_c => execute_engine.state_nxt <= TRAP_EXIT; -- MRET |
when funct12_dret_c => -- DRET |
when funct12_dret_c => -- DRET |
if (CPU_EXTENSION_RISCV_DEBUG = true) then |
execute_engine.state_nxt <= TRAP_EXIT; |
debug_ctrl.dret <= '1'; |
1177,7 → 1173,7
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrw_c) or |
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrwi_c) then -- CSRRW(I) |
csr.we_nxt <= '1'; -- always write CSR |
else -- CSRRS(I) / CSRRC(I) [invalid CSR instruction are already checked by the illegal instruction logic] |
else -- CSRRS(I) / CSRRC(I) [invalid CSR instructions are already checked by the illegal instruction logic] |
csr.we_nxt <= not decode_aux.rs1_zero; -- write CSR if rs1/imm is not zero |
end if; |
-- register file write back -- |
1294,7 → 1290,7
-- machine trap setup/handling & counters -- |
when csr_mstatus_c | csr_mstatush_c | csr_misa_c | csr_mie_c | csr_mtvec_c | csr_mscratch_c | csr_mepc_c | csr_mcause_c | csr_mip_c | csr_mtval_c | |
csr_mcycle_c | csr_mcycleh_c | csr_minstret_c | csr_minstreth_c | csr_mcountinhibit_c => |
-- NOTE: MISA, MIP and MTVAL are read-only in the NEORV32 but we do not cause an exception here for compatibility. |
-- NOTE: MISA and MTVAL are read-only in the NEORV32 but we do not cause an exception here for compatibility. |
-- Machine-level code should read-back those CSRs after writing them to realize they are read-only. |
csr_acc_valid <= csr.priv_m_mode; -- M-mode only |
|
1632,8 → 1628,8
trap_ctrl.irq_buf(interrupt_mext_irq_c) <= csr.mie_meie and mext_irq_i; |
trap_ctrl.irq_buf(interrupt_mtime_irq_c) <= csr.mie_mtie and mtime_irq_i; |
|
-- interrupt buffer: NEORV32-specific fast interrupts (FIRQ) -- |
trap_ctrl.irq_buf(interrupt_firq_15_c downto interrupt_firq_0_c) <= csr.mie_firqe(15 downto 0) and firq_i(15 downto 0); |
-- interrupt queue: NEORV32-specific fast interrupts (FIRQ) -- |
trap_ctrl.irq_buf(interrupt_firq_15_c downto interrupt_firq_0_c) <= (trap_ctrl.irq_buf(interrupt_firq_15_c downto interrupt_firq_0_c) or (csr.mie_firqe and firq_i)) and (not csr.mip_clr); |
|
-- trap environment control -- |
if (trap_ctrl.env_start = '0') then -- no started trap handler |
1722,7 → 1718,7
|
|
-- ---------------------------------------------------------------------------------------- |
-- (re-)enter debug mode requests; basically, these are standard traps that have some |
-- (re-)enter debug mode requests: basically, these are standard traps that have some |
-- special handling - they have the highest INTERRUPT priority in order to go to debug when requested |
-- even if other IRQs are pending right now |
-- ---------------------------------------------------------------------------------------- |
1878,6 → 1874,7
csr.mepc <= (others => def_rst_val_c); |
csr.mcause <= (others => def_rst_val_c); |
csr.mtval <= (others => def_rst_val_c); |
csr.mip_clr <= (others => def_rst_val_c); |
-- |
csr.pmpcfg <= (others => (others => '0')); |
csr.pmpaddr <= (others => (others => def_rst_val_c)); |
1907,6 → 1904,9
-- write access? -- |
csr.we <= csr.we_nxt; |
|
-- defaults -- |
csr.mip_clr <= (others => '0'); |
|
if (CPU_EXTENSION_RISCV_Zicsr = true) then |
-- -------------------------------------------------------------------------------- |
-- CSR access by application software |
1965,20 → 1965,24
|
-- machine trap handling -- |
-- -------------------------------------------------------------------- |
if (csr.addr(11 downto 3) = csr_class_trap_c) then -- machine trap handling CSR class |
if (csr.addr(11 downto 4) = csr_class_trap_c) then -- machine trap handling CSR class |
-- R/W: mscratch - machine scratch register -- |
if (csr.addr(2 downto 0) = csr_mscratch_c(2 downto 0)) then |
if (csr.addr(3 downto 0) = csr_mscratch_c(3 downto 0)) then |
csr.mscratch <= csr.wdata; |
end if; |
-- R/W: mepc - machine exception program counter -- |
if (csr.addr(2 downto 0) = csr_mepc_c(2 downto 0)) then |
if (csr.addr(3 downto 0) = csr_mepc_c(3 downto 0)) then |
csr.mepc <= csr.wdata; |
end if; |
-- R/W: mcause - machine trap cause -- |
if (csr.addr(2 downto 0) = csr_mcause_c(2 downto 0)) then |
if (csr.addr(3 downto 0) = csr_mcause_c(3 downto 0)) then |
csr.mcause(csr.mcause'left) <= csr.wdata(31); -- 1: async/interrupt, 0: sync/exception |
csr.mcause(4 downto 0) <= csr.wdata(4 downto 0); -- identifier |
end if; |
-- R/W: mip - machine interrupt pending -- |
if (csr.addr(3 downto 0) = csr_mip_c(3 downto 0)) then |
csr.mip_clr <= csr.wdata(31 downto 16); |
end if; |
end if; |
|
-- physical memory protection: R/W: pmpcfg* - PMP configuration registers -- |
2491,7 → 2495,7
csr.rdata(csr.mcause'left-1 downto 0) <= csr.mcause(csr.mcause'left-1 downto 0); |
when csr_mtval_c => -- mtval (r/-): machine bad address or instruction |
csr.rdata <= csr.mtval; |
when csr_mip_c => -- mip (r/-): machine interrupt pending |
when csr_mip_c => -- mip (r/w): machine interrupt pending |
csr.rdata(03) <= trap_ctrl.irq_buf(interrupt_msw_irq_c); |
csr.rdata(07) <= trap_ctrl.irq_buf(interrupt_mtime_irq_c); |
csr.rdata(11) <= trap_ctrl.irq_buf(interrupt_mext_irq_c); |
/rtl/core/neorv32_cpu_cp_muldiv.vhd
79,7 → 79,7
constant cp_op_remu_c : std_ulogic_vector(2 downto 0) := "111"; -- remu |
|
-- controller -- |
type state_t is (IDLE, DIV_PREPROCESS, PROCESSING, FINALIZE, COMPLETED); |
type state_t is (IDLE, DIV_PREPROCESS, PROCESSING, FINALIZE); |
signal state : state_t; |
signal cnt : std_ulogic_vector(4 downto 0); |
signal cp_op : std_ulogic_vector(2 downto 0); -- operation to execute |
87,13 → 87,12
signal start_div : std_ulogic; |
signal start_mul : std_ulogic; |
signal operation : std_ulogic; |
signal div_opx : std_ulogic_vector(data_width_c-1 downto 0); |
signal div_opy : std_ulogic_vector(data_width_c-1 downto 0); |
signal rs1_is_signed : std_ulogic; |
signal rs2_is_signed : std_ulogic; |
signal opy_is_zero : std_ulogic; |
signal div_res_corr : std_ulogic; |
signal valid : std_ulogic; |
signal out_en : std_ulogic; |
|
-- divider core -- |
signal remainder : std_ulogic_vector(data_width_c-1 downto 0); |
110,7 → 109,6
signal mul_p_sext : std_ulogic; |
signal mul_op_x : signed(32 downto 0); -- for using DSPs |
signal mul_op_y : signed(32 downto 0); -- for using DSPs |
signal mul_buf_ff : signed(65 downto 0); -- for using DSPs |
|
begin |
|
120,31 → 118,34
begin |
if (rstn_i = '0') then |
state <= IDLE; |
div_opx <= (others => def_rst_val_c); |
div_opy <= (others => def_rst_val_c); |
cnt <= (others => def_rst_val_c); |
cp_op_ff <= (others => def_rst_val_c); |
start_div <= '0'; |
valid <= '0'; |
out_en <= '0'; |
valid_o <= '0'; |
div_res_corr <= def_rst_val_c; |
opy_is_zero <= def_rst_val_c; |
elsif rising_edge(clk_i) then |
-- defaults -- |
start_div <= '0'; |
valid <= '0'; |
out_en <= '0'; |
valid_o <= '0'; |
|
-- FSM -- |
case state is |
|
when IDLE => |
cp_op_ff <= cp_op; |
cnt <= "11110"; |
if (start_i = '1') then |
if (operation = '1') and (DIVISION_EN = true) then -- division |
cnt <= "11111"; |
state <= DIV_PREPROCESS; |
else |
cnt <= "11110"; |
start_div <= '1'; |
state <= DIV_PREPROCESS; |
else -- multiplication |
if (FAST_MUL_EN = true) then |
state <= FINALIZE; |
valid_o <= '1'; |
state <= FINALIZE; |
else |
state <= PROCESSING; |
end if; |
152,47 → 153,37
end if; |
|
when DIV_PREPROCESS => |
if (DIVISION_EN = true) then |
-- check rlevatn input signs -- |
if (cp_op = cp_op_div_c) then -- result sign compensation for div? |
div_res_corr <= rs1_i(rs1_i'left) xor rs2_i(rs2_i'left); |
elsif (cp_op = cp_op_rem_c) then -- result sign compensation for rem? |
div_res_corr <= rs1_i(rs1_i'left); |
else |
div_res_corr <= '0'; |
end if; |
-- divide by zero? -- |
opy_is_zero <= not or_reduce_f(rs2_i); -- set if rs2 = 0 |
-- abs(rs1) -- |
if ((rs1_i(rs1_i'left) and rs1_is_signed) = '1') then -- signed division? |
div_opx <= std_ulogic_vector(0 - unsigned(rs1_i)); -- make positive |
else |
div_opx <= rs1_i; |
end if; |
-- abs(rs2) -- |
if ((rs2_i(rs2_i'left) and rs2_is_signed) = '1') then -- signed division? |
div_opy <= std_ulogic_vector(0 - unsigned(rs2_i)); -- make positive |
else |
div_opy <= rs2_i; |
end if; |
-- |
start_div <= '1'; |
state <= PROCESSING; |
-- check relevant input signs -- |
if (cp_op = cp_op_div_c) then -- result sign compensation for div? |
div_res_corr <= rs1_i(rs1_i'left) xor rs2_i(rs2_i'left); |
elsif (cp_op = cp_op_rem_c) then -- result sign compensation for rem? |
div_res_corr <= rs1_i(rs1_i'left); |
else |
state <= IDLE; |
div_res_corr <= '0'; |
end if; |
-- divide by zero? -- |
opy_is_zero <= not or_reduce_f(rs2_i); -- set if rs2 = 0 |
-- abs(rs2) -- |
if ((rs2_i(rs2_i'left) and rs2_is_signed) = '1') then -- signed division? |
div_opy <= std_ulogic_vector(0 - unsigned(rs2_i)); -- make positive |
else |
div_opy <= rs2_i; |
end if; |
-- |
state <= PROCESSING; |
|
when PROCESSING => |
cnt <= std_ulogic_vector(unsigned(cnt) - 1); |
if (cnt = "00000") then |
state <= FINALIZE; |
valid_o <= '1'; |
state <= FINALIZE; |
end if; |
|
when FINALIZE => |
state <= COMPLETED; |
out_en <= '1'; |
state <= IDLE; |
|
when COMPLETED => |
valid <= '1'; |
when others => |
state <= IDLE; |
end case; |
end if; |
235,10 → 226,11
end process multiplier_core; |
end generate; |
|
-- parallel multiplication -- |
-- parallel multiplication (using DSP blocks) -- |
multiplier_core_dsp: |
if (FAST_MUL_EN = true) generate |
multiplier_core: process(clk_i) |
variable tmp_v : signed(65 downto 0); |
begin |
if rising_edge(clk_i) then |
if (start_mul = '1') then |
245,8 → 237,10
mul_op_x <= signed((rs1_i(rs1_i'left) and rs1_is_signed) & rs1_i); |
mul_op_y <= signed((rs2_i(rs2_i'left) and rs2_is_signed) & rs2_i); |
end if; |
mul_buf_ff <= mul_op_x * mul_op_y; |
mul_product <= std_ulogic_vector(mul_buf_ff(63 downto 0)); -- let the register balancing do the magic here |
tmp_v := mul_op_x * mul_op_y; |
mul_product <= std_ulogic_vector(tmp_v(63 downto 0)); |
--mul_buf_ff <= mul_op_x * mul_op_y; |
--mul_product <= std_ulogic_vector(mul_buf_ff(63 downto 0)); -- let the register balancing do the magic here |
end if; |
end process multiplier_core; |
end generate; |
282,7 → 276,11
remainder <= (others => def_rst_val_c); |
elsif rising_edge(clk_i) then |
if (start_div = '1') then -- start new division |
quotient <= div_opx; |
if ((rs1_i(rs1_i'left) and rs1_is_signed) = '1') then -- signed division? |
quotient <= std_ulogic_vector(0 - unsigned(rs1_i)); -- make positive |
else |
quotient <= rs1_i; |
end if; |
remainder <= (others => '0'); |
elsif (state = PROCESSING) or (state = FINALIZE) then -- running? |
quotient <= quotient(30 downto 0) & (not div_sub(32)); |
307,49 → 305,39
-- no divider -- |
divider_core_serial_none: |
if (DIVISION_EN = false) generate |
remainder <= (others => '-'); |
quotient <= (others => '-'); |
div_res <= (others => '-'); |
remainder <= (others => '0'); |
quotient <= (others => '0'); |
div_res <= (others => '0'); |
end generate; |
|
|
-- Data Output ---------------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
operation_result: process(rstn_i, clk_i) |
operation_result: process(out_en, cp_op_ff, mul_product, div_res, quotient, opy_is_zero, rs1_i, remainder) |
begin |
if (rstn_i = '0') then |
res_o <= (others => def_rst_val_c); |
elsif rising_edge(clk_i) then |
if (out_en = '1') then |
case cp_op_ff is |
when cp_op_mul_c => |
res_o <= mul_product(31 downto 00); |
when cp_op_mulh_c | cp_op_mulhsu_c | cp_op_mulhu_c => |
res_o <= mul_product(63 downto 32); |
when cp_op_div_c => |
res_o <= div_res; |
when cp_op_divu_c => |
res_o <= quotient; |
when cp_op_rem_c => |
if (opy_is_zero = '0') then |
res_o <= div_res; |
else |
res_o <= rs1_i; |
end if; |
when others => -- cp_op_remu_c |
res_o <= remainder; |
end case; |
else |
res_o <= (others => '0'); |
if (valid = '1') then |
case cp_op_ff is |
when cp_op_mul_c => |
res_o <= mul_product(31 downto 00); |
when cp_op_mulh_c | cp_op_mulhsu_c | cp_op_mulhu_c => |
res_o <= mul_product(63 downto 32); |
when cp_op_div_c => |
if (DIVISION_EN = true) then res_o <= div_res; else NULL; end if; |
when cp_op_divu_c => |
if (DIVISION_EN = true) then res_o <= quotient; else NULL; end if; |
when cp_op_rem_c => |
if (DIVISION_EN = true) then |
if (opy_is_zero = '0') then |
res_o <= div_res; |
else |
res_o <= rs1_i; |
end if; |
else |
NULL; |
end if; |
when others => -- cp_op_remu_c |
if (DIVISION_EN = true) then res_o <= remainder; else NULL; end if; |
end case; |
end if; |
end if; |
end process operation_result; |
|
-- status output -- |
valid_o <= valid; |
|
|
end neorv32_cpu_cp_muldiv_rtl; |
/rtl/core/neorv32_gptmr.vhd
74,7 → 74,6
constant ctrl_prsc1_c : natural := 2; -- r/w: clock prescaler select bit 1 |
constant ctrl_prsc2_c : natural := 3; -- r/w: clock prescaler select bit 2 |
constant ctrl_mode_c : natural := 4; -- r/w: mode (0=single-shot, 1=continuous) |
constant ctrl_alarm_c : natural := 5; -- r/c: alarm flag (interrupt), cleared by writing zero |
-- |
signal ctrl : std_ulogic_vector(4 downto 0); |
|
96,13 → 95,8
end record; |
signal timer : timer_t; |
|
-- interrupt generator -- |
type irq_t is record |
pending : std_ulogic; -- pending interrupt request |
detect : std_ulogic_vector(1 downto 0); -- rising-edge detector |
clearn : std_ulogic; -- clear/ack IRQ request, active-low |
end record; |
signal irq : irq_t; |
-- interrupt detector -- |
signal irq_detect : std_ulogic_vector(1 downto 0); |
|
begin |
|
123,7 → 117,6
ack_o <= rden or wren; |
|
-- write access -- |
irq.clearn <= '1'; |
timer.cnt_we <= '0'; |
if (wren = '1') then |
if (addr = gptmr_ctrl_addr_c) then -- control register |
132,7 → 125,6
ctrl(ctrl_prsc1_c) <= data_i(ctrl_prsc1_c); |
ctrl(ctrl_prsc2_c) <= data_i(ctrl_prsc2_c); |
ctrl(ctrl_mode_c) <= data_i(ctrl_mode_c); |
irq.clearn <= data_i(ctrl_alarm_c); |
end if; |
if (addr = gptmr_thres_addr_c) then -- threshold register |
timer.thres <= data_i; |
152,7 → 144,6
data_o(ctrl_prsc1_c) <= ctrl(ctrl_prsc1_c); |
data_o(ctrl_prsc2_c) <= ctrl(ctrl_prsc2_c); |
data_o(ctrl_mode_c) <= ctrl(ctrl_mode_c); |
data_o(ctrl_alarm_c) <= irq.pending; |
when "01" => -- threshold register |
data_o <= timer.thres; |
when others => -- counter register |
198,21 → 189,15
begin |
if rising_edge(clk_i) then |
if (ctrl(ctrl_en_c) = '0') then |
irq.detect <= "00"; |
irq.pending <= '0'; |
irq_detect <= "00"; |
else |
irq.detect <= irq.detect(0) & timer.match; |
if (irq.detect = "01") then -- rising edge |
irq.pending <= '1'; |
elsif (irq.clearn = '0') then |
irq.pending <= '0'; |
end if; |
irq_detect <= irq_detect(0) & timer.match; |
end if; |
end if; |
end process irq_generator; |
|
-- IRQ request to CPU -- |
irq_o <= irq.pending; |
irq_o <= '1' when (irq_detect = "01") else '0'; |
|
|
end neorv32_gptmr_rtl; |
/rtl/core/neorv32_neoled.vhd
155,9 → 155,8
|
-- interrupt generator -- |
type irq_t is record |
pending : std_ulogic; -- pending interrupt request |
set : std_ulogic; |
clr : std_ulogic; |
set : std_ulogic; |
buf : std_ulogic_vector(1 downto 0); |
end record; |
signal irq : irq_t; |
|
250,42 → 249,31
|
-- IRQ Generator -------------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
irq_select: process(ctrl, tx_buffer) |
irq_select: process(ctrl, tx_buffer, serial.done) |
begin |
if (FIFO_DEPTH = 1) then |
irq.set <= tx_buffer.free; -- fire IRQ if FIFO is empty |
if (FIFO_DEPTH = 1) or (ctrl.irq_conf = '1') then |
irq.set <= tx_buffer.free and serial.done; -- fire IRQ if FIFO is empty |
else |
if (ctrl.irq_conf = '0') then -- fire IRQ if FIFO is less than half-full |
irq.set <= not tx_buffer.half; |
else -- fire IRQ if FIFO is empty |
irq.set <= tx_buffer.free; |
end if; |
irq.set <= not tx_buffer.half; -- fire IRQ if FIFO is less than half-full |
end if; |
end process irq_select; |
|
-- Interrupt Arbiter -- |
irq_generator: process(clk_i) |
-- Interrupt Edge Detector -- |
irq_detect: process(clk_i) |
begin |
if rising_edge(clk_i) then |
if (ctrl.enable = '0') then |
irq.pending <= '0'; |
irq.buf <= "00"; |
else |
if (irq.set = '1') and (serial.done = '1') then -- evaluate IRQ condition when transmitter is done again |
irq.pending <= '1'; |
elsif (irq.clr = '1') then |
irq.pending <= '0'; |
end if; |
irq.buf <= irq.buf(0) & irq.set; |
end if; |
end if; |
end process irq_generator; |
end process irq_detect; |
|
-- IRQ request to CPU -- |
irq_o <= irq.pending; |
irq_o <= '1' when (irq.buf = "01") else '0'; |
|
-- IRQ acknowledge -- |
irq.clr <= '1' when (wren = '1') else '0'; -- write data or control register |
|
|
-- TX Buffer (FIFO) ----------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
tx_data_fifo: neorv32_fifo |
/rtl/core/neorv32_package.vhd
53,7 → 53,7
-- increasing instruction fetch & data access latency by +1 cycle but also reducing critical path length |
constant pmp_num_regions_critical_c : natural := 8; -- default=8 |
|
-- "response time window" for processor-internal memories and IO devices |
-- "response time window" for processor-internal modules -- |
constant max_proc_int_response_time_c : natural := 15; -- cycles after which an *unacknowledged* internal bus access will timeout and trigger a bus fault exception (min 2) |
|
-- jtag tap - identifier -- |
64,9 → 64,23
-- Architecture Constants (do not modify!) ------------------------------------------------ |
-- ------------------------------------------------------------------------------------------- |
constant data_width_c : natural := 32; -- native data path width - do not change! |
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01060400"; -- no touchy! |
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01060500"; -- no touchy! |
constant archid_c : natural := 19; -- official NEORV32 architecture ID - hands off! |
|
-- Check if we're inside the Matrix ------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
constant is_simulation_c : boolean := false -- seems like we're on real hardware |
-- pragma translate_off |
-- synthesis translate_off |
-- synthesis synthesis_off |
-- RTL_SYNTHESIS OFF |
or true -- this MIGHT be a simulation |
-- RTL_SYNTHESIS ON |
-- synthesis synthesis_on |
-- synthesis translate_on |
-- pragma translate_on |
; |
|
-- External Interface Types --------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
type sdata_8x32_t is array (0 to 7) of std_ulogic_vector(31 downto 0); |
575,7 → 589,7
constant csr_mhpmevent30_c : std_ulogic_vector(11 downto 0) := x"33e"; |
constant csr_mhpmevent31_c : std_ulogic_vector(11 downto 0) := x"33f"; |
-- machine trap handling -- |
constant csr_class_trap_c : std_ulogic_vector(08 downto 0) := x"34" & '0'; -- machine trap handling |
constant csr_class_trap_c : std_ulogic_vector(07 downto 0) := x"34"; -- machine trap handling |
constant csr_mscratch_c : std_ulogic_vector(11 downto 0) := x"340"; |
constant csr_mepc_c : std_ulogic_vector(11 downto 0) := x"341"; |
constant csr_mcause_c : std_ulogic_vector(11 downto 0) := x"342"; |
1089,6 → 1103,7
clk_i : in std_ulogic; -- global clock, rising edge |
rstn_i : in std_ulogic; -- global reset, low-active, async |
sleep_o : out std_ulogic; -- cpu is in sleep mode when set |
debug_o : out std_ulogic; -- cpu is in debug mode when set |
-- instruction bus interface -- |
i_bus_addr_o : out std_ulogic_vector(data_width_c-1 downto 0); -- bus access address |
i_bus_rdata_i : in std_ulogic_vector(data_width_c-1 downto 0); -- bus read data |
1616,6 → 1631,9
-- Component: Watchdog Timer (WDT) -------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
component neorv32_wdt |
generic ( |
DEBUG_EN : boolean -- CPU debug mode implemented? |
); |
port ( |
-- host access -- |
clk_i : in std_ulogic; -- global clock line |
1626,6 → 1644,8
data_i : in std_ulogic_vector(31 downto 0); -- data in |
data_o : out std_ulogic_vector(31 downto 0); -- data out |
ack_o : out std_ulogic; -- transfer acknowledge |
-- CPU in debug mode? -- |
cpu_debug_i : in std_ulogic; |
-- clock generator -- |
clkgen_en_o : out std_ulogic; -- enable clock generator |
clkgen_i : in std_ulogic_vector(07 downto 0); |
2090,7 → 2110,7
|
package body neorv32_package is |
|
-- Function: Minimal required number of bits to represent input number -------------------- |
-- Function: Minimal required number of bits to represent <input> numbers ----------------- |
-- ------------------------------------------------------------------------------------------- |
function index_size_f(input : natural) return natural is |
begin |
/rtl/core/neorv32_slink.vhd
153,11 → 153,9
-- interrupt generator -- |
type detect_t is array (0 to 7) of std_ulogic_vector(1 downto 0); |
type irq_t is record |
pending : std_ulogic; -- pending interrupt request |
detect : detect_t; -- rising-edge detector |
trigger : std_ulogic_vector(7 downto 0); |
set : std_ulogic_vector(7 downto 0); |
clr : std_ulogic; |
end record; |
signal rx_irq, tx_irq : irq_t; |
|
261,65 → 259,59
|
-- Interrupt Generator -------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
irq_type: process(irq_rx_mode, rx_fifo_avail, rx_fifo_half, |
irq_tx_mode, tx_fifo_free, tx_fifo_half) |
-- interrupt trigger type / condition -- |
irq_type: process(irq_rx_mode, rx_fifo_avail, rx_fifo_half, irq_tx_mode, tx_fifo_free, tx_fifo_half, tx_fifo_we) |
begin |
-- RX interrupt -- |
rx_irq.trigger <= (others => '0'); |
for i in 0 to SLINK_NUM_RX-1 loop |
if (SLINK_RX_FIFO = 1) then |
rx_irq.trigger(i) <= rx_fifo_avail(i); -- fire if any RX_FIFO is not empty |
if (SLINK_RX_FIFO = 1) or (irq_rx_mode(i) = '0') then |
rx_irq.trigger(i) <= rx_fifo_avail(i); -- fire if any RX_FIFO is not empty (= data available) |
else |
if (irq_rx_mode(i) = '0') then -- fire if any RX_FIFO is at least half-full |
rx_irq.trigger(i) <= rx_fifo_half(i); |
else -- fire if any RX_FIFO is not empty (= data available) |
rx_irq.trigger(i) <= rx_fifo_avail(i); |
end if; |
rx_irq.trigger(i) <= rx_fifo_half(i); |
end if; |
end loop; |
-- TX interrupt -- |
tx_irq.trigger <= (others => '0'); |
for i in 0 to SLINK_NUM_TX-1 loop |
if (SLINK_TX_FIFO = 1) then |
tx_irq.trigger(i) <= tx_fifo_free(i); -- fire if any TX_FIFO is not full |
if (SLINK_TX_FIFO = 1) or (irq_tx_mode(i) = '0') then |
tx_irq.trigger(i) <= tx_fifo_free(i) and tx_fifo_we(i); -- fire if any TX_FIFO is not full (= free buffer space available) |
else |
if (irq_tx_mode(i) = '0') then -- fire if any TX_FIFO is less than half-full |
tx_irq.trigger(i) <= not tx_fifo_half(i); |
else -- fire if any TX_FIFO is not full (= free buffer space available) |
tx_irq.trigger(i) <= tx_fifo_free(i); |
end if; |
tx_irq.trigger(i) <= not tx_fifo_half(i); |
end if; |
end loop; |
end process irq_type; |
|
-- interrupt trigger -- |
irq_trigger_sync: process(clk_i) |
-- edge detector - sync -- |
irq_edge_detect_sync: process(clk_i) |
begin |
if rising_edge(clk_i) then |
-- RX -- |
rx_irq.detect <= (others => (others => '0')); -- default |
if (enable = '1') then |
for i in 0 to SLINK_NUM_RX-1 loop |
for i in 0 to SLINK_NUM_RX-1 loop |
if (enable = '1') and (irq_rx_en(i) = '1') then |
rx_irq.detect(i) <= rx_irq.detect(i)(0) & rx_irq.trigger(i); |
end loop; |
end if; |
else |
rx_irq.detect(i) <= "00"; |
end if; |
end loop; |
-- TX -- |
tx_irq.detect <= (others => (others => '0')); -- default |
if (enable = '1') then |
for i in 0 to SLINK_NUM_TX-1 loop |
for i in 0 to SLINK_NUM_TX-1 loop |
if (enable = '1') and (irq_tx_en(i) = '1') then |
tx_irq.detect(i) <= tx_irq.detect(i)(0) & tx_irq.trigger(i); |
end loop; |
end if; |
else |
tx_irq.detect(i) <= "00"; |
end if; |
end loop; |
end if; |
end process irq_trigger_sync; |
end process irq_edge_detect_sync; |
|
-- interrupt trigger -- |
irq_trigger_comb: process(rx_irq, irq_rx_en, tx_irq, irq_tx_en) |
-- edge detector - sync -- |
irq_edge_detect_comb: process(rx_irq, irq_rx_en, tx_irq, irq_tx_en) |
begin |
-- RX -- |
rx_irq.set <= (others => '0'); |
for i in 0 to SLINK_NUM_RX-1 loop |
if (rx_irq.detect(i) = "01") and (irq_rx_en(i) = '1') then -- rising-edge |
if (rx_irq.detect(i) = "01") then -- rising-edge |
rx_irq.set(i) <= '1'; |
end if; |
end loop; |
326,45 → 318,22
-- TX -- |
tx_irq.set <= (others => '0'); |
for i in 0 to SLINK_NUM_TX-1 loop |
if (tx_irq.detect(i) = "01") and (irq_tx_en(i) = '1') then -- rising-edge |
if (tx_irq.detect(i) = "01") then -- rising-edge |
tx_irq.set(i) <= '1'; |
end if; |
end loop; |
end process irq_trigger_comb; |
end process irq_edge_detect_comb; |
|
-- interrupt arbiter -- |
irq_generator: process(clk_i) |
begin |
if rising_edge(clk_i) then |
if (enable = '0') then |
rx_irq.pending <= '0'; |
tx_irq.pending <= '0'; |
else |
-- RX -- |
if (or_reduce_f(rx_irq.set) = '1') then |
rx_irq.pending <= '1'; |
elsif (rx_irq.clr = '1') then |
rx_irq.pending <= '0'; |
end if; |
-- TX -- |
if (or_reduce_f(tx_irq.set) = '1') then |
tx_irq.pending <= '1'; |
elsif (tx_irq.clr = '1') then |
tx_irq.pending <= '0'; |
end if; |
end if; |
irq_rx_o <= or_reduce_f(rx_irq.set); |
irq_tx_o <= or_reduce_f(tx_irq.set); |
end if; |
end process irq_generator; |
|
-- IRQ requests to CPU -- |
irq_rx_o <= rx_irq.pending; |
irq_tx_o <= tx_irq.pending; |
|
-- IRQ acknowledge -- |
rx_irq.clr <= '1' when ((rden = '1') and (addr(5) = '1')) or ((wren = '1') and (addr(5 downto 3) = "000")) else '0'; -- read from data FIFO OR write to control register |
tx_irq.clr <= '1' when ((wren = '1') and (addr(5) = '1')) or ((wren = '1') and (addr(5 downto 3) = "000")) else '0'; -- write to data FIFO OR write to control register |
|
|
-- Link Select ---------------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
link_select: process(addr) |
/rtl/core/neorv32_spi.vhd
116,14 → 116,6
end record; |
signal rtx_engine : rtx_engine_t; |
|
-- interrupt generator -- |
type irq_t is record |
pending : std_ulogic; -- pending interrupt request |
set : std_ulogic; |
clr : std_ulogic; |
end record; |
signal irq : irq_t; |
|
begin |
|
-- Access Control ------------------------------------------------------------------------- |
239,7 → 231,7
|
-- defaults -- |
spi_sck_o <= ctrl(ctrl_cpol_c); |
irq.set <= '0'; |
irq_o <= '0'; |
|
-- serial engine -- |
rtx_engine.state(2) <= ctrl(ctrl_en_c); |
273,7 → 265,7
if (spi_clk_en = '1') then |
rtx_engine.sreg <= rtx_engine.sreg(30 downto 0) & rtx_engine.sdi_sync(rtx_engine.sdi_sync'left); |
if (rtx_engine.bitcnt(5 downto 3) = rtx_engine.bytecnt) then -- all bits transferred? |
irq.set <= '1'; -- interrupt! |
irq_o <= '1'; -- interrupt! |
rtx_engine.state(1 downto 0) <= "00"; -- transmission done |
else |
rtx_engine.state(1 downto 0) <= "10"; |
292,28 → 284,4
rtx_engine.busy <= '0' when (rtx_engine.state(1 downto 0) = "00") else '1'; |
|
|
-- Interrupt Generator -------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
irq_generator: process(clk_i) |
begin |
if rising_edge(clk_i) then |
if (ctrl(ctrl_en_c) = '0') then |
irq.pending <= '0'; |
else |
if (irq.set = '1') then |
irq.pending <= '1'; |
elsif (irq.clr = '1') then |
irq.pending <= '0'; |
end if; |
end if; |
end if; |
end process irq_generator; |
|
-- IRQ request to CPU -- |
irq_o <= irq.pending; |
|
-- IRQ acknowledge -- |
irq.clr <= '1' when ((rden = '1') and (addr = spi_rtx_addr_c)) or (wren = '1') else '0'; -- read data register OR write data/control register |
|
|
end neorv32_spi_rtl; |
/rtl/core/neorv32_sysinfo.vhd
163,8 → 163,9
sysinfo_mem(2)(04) <= bool_to_ulogic_f(MEM_EXT_BIG_ENDIAN); -- is external memory bus interface using BIG-endian byte-order? |
sysinfo_mem(2)(05) <= bool_to_ulogic_f(ICACHE_EN); -- processor-internal instruction cache implemented? |
-- |
sysinfo_mem(2)(13 downto 06) <= (others => '0'); -- reserved |
sysinfo_mem(2)(12 downto 06) <= (others => '0'); -- reserved |
-- Misc -- |
sysinfo_mem(2)(13) <= bool_to_ulogic_f(is_simulation_c); -- is this a simulation? |
sysinfo_mem(2)(14) <= bool_to_ulogic_f(ON_CHIP_DEBUGGER_EN); -- on-chip debugger implemented? |
sysinfo_mem(2)(15) <= bool_to_ulogic_f(dedicated_reset_c); -- dedicated hardware reset of all core registers? |
-- IO -- |
/rtl/core/neorv32_top.vhd
340,6 → 340,7
signal mtime_time : std_ulogic_vector(63 downto 0); -- current system time from MTIME |
signal ext_timeout : std_ulogic; |
signal ext_access : std_ulogic; |
signal debug_mode : std_ulogic; |
|
begin |
|
492,6 → 493,7
clk_i => clk_i, -- global clock, rising edge |
rstn_i => sys_rstn, -- global reset, low-active, async |
sleep_o => open, -- cpu is in sleep mode when set |
debug_o => debug_mode, -- cpu is in debug mode when set |
-- instruction bus interface -- |
i_bus_addr_o => cpu_i.addr, -- bus access address |
i_bus_rdata_i => cpu_i.rdata, -- bus read data |
537,7 → 539,7
fencei_o <= cpu_i.fence; -- indicates an executed FENCEI operation |
|
-- fast interrupt requests (FIRQs) -- |
-- these stay asserted until explicitly acknowledged -- |
-- these signals are single-shot -- |
fast_irq(00) <= wdt_irq; -- HIGHEST PRIORITY - watchdog |
fast_irq(01) <= cfs_irq; -- custom functions subsystem |
fast_irq(02) <= uart0_rxd_irq; -- primary UART (UART0) RX |
937,6 → 939,9
neorv32_wdt_inst_true: |
if (IO_WDT_EN = true) generate |
neorv32_wdt_inst: neorv32_wdt |
generic map( |
DEBUG_EN => ON_CHIP_DEBUGGER_EN -- CPU debug mode implemented? |
) |
port map ( |
-- host access -- |
clk_i => clk_i, -- global clock line |
947,6 → 952,8
data_i => p_bus.wdata, -- data in |
data_o => resp_bus(RESP_WDT).rdata, -- data out |
ack_o => resp_bus(RESP_WDT).ack, -- transfer acknowledge |
-- CPU in debug mode? -- |
cpu_debug_i => debug_mode, |
-- clock generator -- |
clkgen_en_o => wdt_cg_en, -- enable clock generator |
clkgen_i => clk_gen, |
/rtl/core/neorv32_twi.vhd
111,14 → 111,6
signal twi_sda_out : std_ulogic; |
signal twi_scl_out : std_ulogic; |
|
-- interrupt generator -- |
type irq_t is record |
pending : std_ulogic; -- pending interrupt request |
set : std_ulogic; |
clr : std_ulogic; |
end record; |
signal irq : irq_t; |
|
begin |
|
-- Access Control ------------------------------------------------------------------------- |
198,7 → 190,7
twi_scl_in_ff <= twi_scl_in_ff(0) & twi_scl_in; |
|
-- defaults -- |
irq.set <= '0'; |
irq_o <= '0'; |
|
-- serial engine -- |
arbiter(2) <= ctrl(ctrl_en_c); -- still activated? |
232,7 → 224,7
twi_scl_out <= '1'; |
elsif (twi_clk_phase(3) = '1') then |
twi_scl_out <= '0'; |
irq.set <= '1'; -- Interrupt! |
irq_o <= '1'; -- Interrupt! |
arbiter(1 downto 0) <= "00"; -- go back to IDLE |
end if; |
|
241,7 → 233,7
twi_sda_out <= '0'; |
elsif (twi_clk_phase(3) = '1') then |
twi_sda_out <= '1'; |
irq.set <= '1'; -- Interrupt! |
irq_o <= '1'; -- Interrupt! |
arbiter(1 downto 0) <= "00"; -- go back to IDLE |
end if; |
-- |
264,7 → 256,7
end if; |
-- |
if (bitcnt = "1010") then -- 8 data bits + 1 bit for ACK + 1 tick delay |
irq.set <= '1'; -- Interrupt! |
irq_o <= '1'; -- Interrupt! |
arbiter(1 downto 0) <= "00"; -- go back to IDLE |
end if; |
|
295,28 → 287,4
twi_scl_in <= std_ulogic(twi_scl_io); |
|
|
-- Interrupt Generator -------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
irq_generator: process(clk_i) |
begin |
if rising_edge(clk_i) then |
if (ctrl(ctrl_en_c) = '0') then |
irq.pending <= '0'; |
else |
if (irq.set = '1') then |
irq.pending <= '1'; |
elsif (irq.clr = '1') then |
irq.pending <= '0'; |
end if; |
end if; |
end if; |
end process irq_generator; |
|
-- IRQ request to CPU -- |
irq_o <= irq.pending; |
|
-- IRQ acknowledge -- |
irq.clr <= '1' when ((rden = '1') and (addr = twi_rtx_addr_c)) or (wren = '1') else '0'; -- read data register OR write data/control register |
|
|
end neorv32_twi_rtl; |
/rtl/core/neorv32_uart.vhd
231,9 → 231,8
|
-- interrupt generator -- |
type irq_t is record |
pending : std_ulogic; -- pending interrupt request |
set : std_ulogic; |
clr : std_ulogic; |
set : std_ulogic; |
buf : std_ulogic_vector(1 downto 0); |
end record; |
signal rx_irq, tx_irq : irq_t; |
|
490,9 → 489,9
|
-- overrun flag -- |
if (rden = '1') and (addr = uart_id_rtx_addr_c) then -- clear when reading data register |
rx_engine.overr <= '0'; |
elsif (rx_buffer.we = '1') and (rx_buffer.free = '0') then -- write to full FIFO |
rx_engine.overr <= '1'; |
elsif (rx_buffer.we = '1') and (rx_buffer.free = '0') then -- write to full FIFO |
rx_engine.overr <= '0'; |
end if; |
end if; |
end if; |
556,64 → 555,41
|
-- Interrupt Generator -------------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
irq_type: process(ctrl, tx_buffer, rx_buffer) |
irq_type: process(ctrl, tx_buffer, rx_buffer, tx_engine.done) |
begin |
-- TX interrupt -- |
if (UART_TX_FIFO = 1) then |
tx_irq.set <= tx_buffer.free; -- fire IRQ if FIFO is not full |
if (UART_TX_FIFO = 1) or (ctrl(ctrl_tx_irq_c) = '0') then |
tx_irq.set <= tx_buffer.free and tx_engine.done; -- fire IRQ if FIFO is not full |
else |
if (ctrl(ctrl_tx_irq_c) = '1') then |
tx_irq.set <= not tx_buffer.half; -- fire IRQ if FIFO is less than half-full |
else |
tx_irq.set <= tx_buffer.free; -- fire IRQ if FIFO is not full |
end if; |
tx_irq.set <= (not tx_buffer.half) and tx_engine.done; -- fire IRQ if FIFO is less than half-full |
end if; |
|
-- RX interrupt -- |
if (UART_RX_FIFO = 1) then |
if (UART_RX_FIFO = 1) or (ctrl(ctrl_rx_irq_c) = '0') then |
rx_irq.set <= rx_buffer.avail; -- fire IRQ if FIFO is not empty |
else |
if (ctrl(ctrl_rx_irq_c) = '1') then |
rx_irq.set <= rx_buffer.half; -- fire IRQ if FIFO is at least half-full |
else |
rx_irq.set <= rx_buffer.avail; -- fire IRQ is FIFO is not empty |
end if; |
rx_irq.set <= rx_buffer.half; -- fire IRQ if FIFO is at least half-full |
end if; |
end process irq_type; |
|
-- interrupt arbiter -- |
irq_generator: process(clk_i) |
-- interrupt edge detector -- |
irq_detect: process(clk_i) |
begin |
if rising_edge(clk_i) then |
if (ctrl(ctrl_en_c) = '0') then |
rx_irq.pending <= '0'; |
tx_irq.pending <= '0'; |
tx_irq.buf <= "00"; |
rx_irq.buf <= "00"; |
else |
-- TX -- |
if (tx_irq.set = '1') and (tx_engine.done = '1') then -- evaluate IRQ condition when TX is done with current sending |
tx_irq.pending <= '1'; |
elsif (tx_irq.clr = '1') then |
tx_irq.pending <= '0'; |
end if; |
-- RX -- |
if (rx_irq.set = '1') and (rx_engine.done = '1') then -- evaluate IRQ condition when RX is done with current receiving |
rx_irq.pending <= '1'; |
elsif (rx_irq.clr = '1') then |
rx_irq.pending <= '0'; |
end if; |
tx_irq.buf <= tx_irq.buf(0) & tx_irq.set; |
rx_irq.buf <= rx_irq.buf(0) & rx_irq.set; |
end if; |
end if; |
end process irq_generator; |
end process irq_detect; |
|
-- IRQ requests to CPU -- |
irq_txd_o <= tx_irq.pending; |
irq_rxd_o <= rx_irq.pending; |
irq_txd_o <= '1' when (tx_irq.buf = "01") else '0'; |
irq_rxd_o <= '1' when (rx_irq.buf = "01") else '0'; |
|
-- IRQ acknowledge -- |
tx_irq.clr <= '1' when (tx_buffer.we = '1') or ((wren = '1') and (addr = uart_id_ctrl_addr_c)) else '0'; -- write to data reg OR write to control reg |
rx_irq.clr <= '1' when (rx_buffer.re = '1') or ((wren = '1') and (addr = uart_id_ctrl_addr_c)) else '0'; -- read from data reg OR write to control reg |
|
|
-- SIMULATION Transmitter ----------------------------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
-- pragma translate_off |
/rtl/core/neorv32_wdt.vhd
48,6 → 48,9
use neorv32.neorv32_package.all; |
|
entity neorv32_wdt is |
generic ( |
DEBUG_EN : boolean -- CPU debug mode implemented? |
); |
port ( |
-- host access -- |
clk_i : in std_ulogic; -- global clock line |
58,6 → 61,8
data_i : in std_ulogic_vector(31 downto 0); -- data in |
data_o : out std_ulogic_vector(31 downto 0); -- data out |
ack_o : out std_ulogic; -- transfer acknowledge |
-- CPU in debug mode? -- |
cpu_debug_i : in std_ulogic; |
-- clock generator -- |
clkgen_en_o : out std_ulogic; -- enable clock generator |
clkgen_i : in std_ulogic_vector(07 downto 0); |
74,15 → 79,17
constant lo_abb_c : natural := index_size_f(wdt_size_c); -- low address boundary bit |
|
-- Control register bits -- |
constant ctrl_enable_c : natural := 0; -- r/w: WDT enable |
constant ctrl_clksel0_c : natural := 1; -- r/w: prescaler select bit 0 |
constant ctrl_clksel1_c : natural := 2; -- r/w: prescaler select bit 1 |
constant ctrl_clksel2_c : natural := 3; -- r/w: prescaler select bit 2 |
constant ctrl_mode_c : natural := 4; -- r/w: 0: WDT timeout triggers interrupt, 1: WDT timeout triggers hard reset |
constant ctrl_rcause_c : natural := 5; -- r/-: cause of last action (reset/IRQ): 0=external reset, 1=watchdog overflow |
constant ctrl_reset_c : natural := 6; -- -/w: reset WDT if set |
constant ctrl_force_c : natural := 7; -- -/w: force WDT action |
constant ctrl_lock_c : natural := 8; -- r/w: lock access to control register when set |
constant ctrl_enable_c : natural := 0; -- r/w: WDT enable |
constant ctrl_clksel0_c : natural := 1; -- r/w: prescaler select bit 0 |
constant ctrl_clksel1_c : natural := 2; -- r/w: prescaler select bit 1 |
constant ctrl_clksel2_c : natural := 3; -- r/w: prescaler select bit 2 |
constant ctrl_mode_c : natural := 4; -- r/w: 0: WDT timeout triggers interrupt, 1: WDT timeout triggers hard reset |
constant ctrl_rcause_c : natural := 5; -- r/-: cause of last action (reset/IRQ): 0=external reset, 1=watchdog overflow |
constant ctrl_reset_c : natural := 6; -- -/w: reset WDT if set |
constant ctrl_force_c : natural := 7; -- -/w: force WDT action |
constant ctrl_lock_c : natural := 8; -- r/w: lock access to control register when set |
constant ctrl_dben_c : natural := 9; -- r/w: allow WDT to continue operation even when in debug mode |
constant ctrl_half_c : natural := 10; -- r/-: set if at least half of the max. timeout counter value has been reached |
|
-- access control -- |
signal acc_en : std_ulogic; -- module access enable |
90,7 → 97,7
signal rden : std_ulogic; |
|
-- control register -- |
type ctrl_reg_t is record |
type ctrl_t is record |
enable : std_ulogic; -- 1=WDT enabled |
clk_sel : std_ulogic_vector(2 downto 0); |
mode : std_ulogic; -- 0=trigger IRQ on overflow; 1=trigger hard reset on overflow |
98,8 → 105,9
reset : std_ulogic; -- reset WDT |
enforce : std_ulogic; -- force action |
lock : std_ulogic; -- lock control register |
dben : std_ulogic; -- allow operation also in debug mode |
end record; |
signal ctrl_reg : ctrl_reg_t; |
signal ctrl : ctrl_t; |
|
-- prescaler clock generator -- |
signal prsc_tick : std_ulogic; |
108,18 → 116,11
signal wdt_cnt : std_ulogic_vector(20 downto 0); |
signal hw_rst : std_ulogic; |
signal rst_gen : std_ulogic_vector(03 downto 0); |
signal cnt_en : std_ulogic; |
|
-- internal reset (sync, low-active) -- |
signal rstn_sync : std_ulogic; |
|
-- cpu interrupt -- |
type cpu_irq_t is record |
pending : std_ulogic; |
set : std_ulogic; |
clr : std_ulogic; |
end record; |
signal cpu_irq : cpu_irq_t; |
|
begin |
|
-- Access Control ------------------------------------------------------------------------- |
134,34 → 135,36
write_access: process(rstn_i, clk_i) |
begin |
if (rstn_i = '0') then |
ctrl_reg.reset <= '0'; |
ctrl_reg.enforce <= '0'; |
ctrl_reg.enable <= '0'; -- disable WDT |
ctrl_reg.mode <= '0'; -- trigger interrupt on WDT overflow |
ctrl_reg.clk_sel <= (others => '1'); -- slowest clock source |
ctrl_reg.lock <= '0'; |
ctrl.reset <= '1'; -- reset counter on start-up |
ctrl.enforce <= '0'; |
ctrl.enable <= '0'; -- disable WDT |
ctrl.mode <= '0'; |
ctrl.clk_sel <= (others => '0'); |
ctrl.lock <= '0'; |
ctrl.dben <= '0'; |
elsif rising_edge(clk_i) then |
-- acknowledge interrupt when resetting WDT -- |
if (rstn_sync = '0') then -- internal reset |
ctrl_reg.reset <= '0'; |
ctrl_reg.enforce <= '0'; |
ctrl_reg.enable <= '0'; -- disable WDT |
ctrl_reg.mode <= '0'; -- trigger interrupt on WDT overflow |
ctrl_reg.clk_sel <= (others => '1'); -- slowest clock source |
ctrl_reg.lock <= '0'; |
ctrl.reset <= '1'; -- reset counter on start-up |
ctrl.enforce <= '0'; |
ctrl.enable <= '0'; -- disable WDT |
ctrl.mode <= '0'; |
ctrl.clk_sel <= (others => '0'); |
ctrl.lock <= '0'; |
ctrl.dben <= '0'; |
else |
-- auto-clear WDT reset and WDT force flags -- |
ctrl_reg.reset <= '0'; |
ctrl_reg.enforce <= '0'; |
ctrl.reset <= '0'; |
ctrl.enforce <= '0'; |
-- actual write access -- |
if (wren = '1') then |
ctrl_reg.reset <= data_i(ctrl_reset_c); |
ctrl_reg.enforce <= data_i(ctrl_force_c); |
if (ctrl_reg.lock = '0') then -- update configuration only if unlocked |
ctrl_reg.enable <= data_i(ctrl_enable_c); |
ctrl_reg.mode <= data_i(ctrl_mode_c); |
ctrl_reg.clk_sel <= data_i(ctrl_clksel2_c downto ctrl_clksel0_c); |
ctrl_reg.lock <= data_i(ctrl_lock_c); |
ctrl.reset <= data_i(ctrl_reset_c); |
ctrl.enforce <= data_i(ctrl_force_c); |
if (ctrl.lock = '0') then -- update configuration only if not locked |
ctrl.enable <= data_i(ctrl_enable_c); |
ctrl.mode <= data_i(ctrl_mode_c); |
ctrl.clk_sel <= data_i(ctrl_clksel2_c downto ctrl_clksel0_c); |
ctrl.lock <= data_i(ctrl_lock_c); |
ctrl.dben <= data_i(ctrl_dben_c) and bool_to_ulogic_f(DEBUG_EN); |
end if; |
end if; |
end if; |
169,8 → 172,8
end process write_access; |
|
-- clock generator -- |
clkgen_en_o <= ctrl_reg.enable; -- enable clock generator |
prsc_tick <= clkgen_i(to_integer(unsigned(ctrl_reg.clk_sel))); -- clock enable tick |
clkgen_en_o <= ctrl.enable; -- enable clock generator |
prsc_tick <= clkgen_i(to_integer(unsigned(ctrl.clk_sel))); -- clock enable tick |
|
|
-- Watchdog Counter ----------------------------------------------------------------------- |
178,53 → 181,32
wdt_counter: process(clk_i) |
begin |
if rising_edge(clk_i) then |
if (ctrl_reg.reset = '1') then -- watchdog reset |
if (ctrl.reset = '1') then -- watchdog reset |
wdt_cnt <= (others => '0'); |
elsif (ctrl_reg.enable = '1') and (prsc_tick = '1') then |
wdt_cnt <= std_ulogic_vector(unsigned(wdt_cnt) + 1); |
elsif (cnt_en = '1') then |
wdt_cnt <= std_ulogic_vector(unsigned('0' & wdt_cnt(wdt_cnt'left-1 downto 0)) + 1); |
end if; |
end if; |
end process wdt_counter; |
|
-- WDT counter enable -- |
cnt_en <= ctrl.enable and prsc_tick and ((not cpu_debug_i) or ctrl.dben); |
|
-- action trigger -- |
cpu_irq.set <= ctrl_reg.enable and (wdt_cnt(wdt_cnt'left) or ctrl_reg.enforce) and (not ctrl_reg.mode); -- mode 0: IRQ |
cpu_irq.clr <= ctrl_reg.reset; -- ack IRQ on WDT reset |
hw_rst <= ctrl_reg.enable and (wdt_cnt(wdt_cnt'left) or ctrl_reg.enforce) and ( ctrl_reg.mode); -- mode 1: RESET |
irq_o <= ctrl.enable and (wdt_cnt(wdt_cnt'left) or ctrl.enforce) and (not ctrl.mode); -- mode 0: IRQ |
hw_rst <= ctrl.enable and (wdt_cnt(wdt_cnt'left) or ctrl.enforce) and ( ctrl.mode); -- mode 1: RESET |
|
|
-- Interrupt ------------------------------------------------------------------------------ |
-- ------------------------------------------------------------------------------------------- |
irq_gen: process(clk_i) |
begin |
if rising_edge(clk_i) then |
if (ctrl_reg.enable = '0') then |
cpu_irq.pending <= '0'; |
else |
if (cpu_irq.set = '1') then |
cpu_irq.pending <= '1'; |
elsif(cpu_irq.clr = '1') then |
cpu_irq.pending <= '0'; |
else |
cpu_irq.pending <= cpu_irq.pending; |
end if; |
end if; |
end if; |
end process irq_gen; |
|
-- CPU IRQ -- |
irq_o <= cpu_irq.pending; |
|
|
-- Reset Generator & Action Cause Indicator ----------------------------------------------- |
-- ------------------------------------------------------------------------------------------- |
reset_generator: process(rstn_i, clk_i) |
begin |
if (rstn_i = '0') then |
ctrl_reg.rcause <= '0'; |
rst_gen <= (others => '1'); -- do NOT fire on reset! |
rstn_sync <= '1'; |
ctrl.rcause <= '0'; |
rst_gen <= (others => '1'); -- do NOT fire on reset! |
rstn_sync <= '1'; |
elsif rising_edge(clk_i) then |
ctrl_reg.rcause <= ctrl_reg.rcause or hw_rst; -- sticky-set on WDT timeout/force |
ctrl.rcause <= ctrl.rcause or hw_rst; -- sticky-set on WDT timeout/force |
if (hw_rst = '1') then |
rst_gen <= (others => '0'); |
else |
243,13 → 225,15
read_access: process(clk_i) |
begin |
if rising_edge(clk_i) then |
ack_o <= rden or wren; |
ack_o <= rden or wren; |
if (rden = '1') then |
data_o(ctrl_enable_c) <= ctrl_reg.enable; |
data_o(ctrl_mode_c) <= ctrl_reg.mode; |
data_o(ctrl_rcause_c) <= ctrl_reg.rcause; |
data_o(ctrl_clksel2_c downto ctrl_clksel0_c) <= ctrl_reg.clk_sel; |
data_o(ctrl_lock_c) <= ctrl_reg.lock; |
data_o(ctrl_enable_c) <= ctrl.enable; |
data_o(ctrl_mode_c) <= ctrl.mode; |
data_o(ctrl_rcause_c) <= ctrl.rcause; |
data_o(ctrl_clksel2_c downto ctrl_clksel0_c) <= ctrl.clk_sel; |
data_o(ctrl_lock_c) <= ctrl.lock; |
data_o(ctrl_dben_c) <= ctrl.dben; |
data_o(ctrl_half_c) <= wdt_cnt(wdt_cnt'left-1); |
else |
data_o <= (others => '0'); |
end if; |
/rtl/core/neorv32_wishbone.vhd
118,7 → 118,7
ack : std_ulogic; |
err : std_ulogic; |
tmo : std_ulogic; |
timeout : std_ulogic_vector(index_size_f(BUS_TIMEOUT)-1 downto 0); |
timeout : std_ulogic_vector(index_size_f(BUS_TIMEOUT) downto 0); |
src : std_ulogic; |
lock : std_ulogic; |
priv : std_ulogic_vector(01 downto 0); |
142,7 → 142,7
|
-- bus timeout -- |
assert not (BUS_TIMEOUT /= 0) report "NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing auto-timeout (" & integer'image(BUS_TIMEOUT) & " cycles)." severity note; |
assert not (BUS_TIMEOUT = 0) report "NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing no auto-timeout (can cause permanent CPU stall!)." severity note; |
assert not (BUS_TIMEOUT = 0) report "NEORV32 PROCESSOR CONFIG WARNING: External Bus Interface - Implementing NO auto-timeout (can cause permanent CPU stall!)." severity warning; |
|
-- endianness -- |
assert not (BIG_ENDIAN = false) report "NEORV32 PROCESSOR CONFIG NOTE: External Bus Interface - Implementing LITTLE-endian byte order." severity note; |
190,7 → 190,7
ctrl.ack <= '0'; |
ctrl.err <= '0'; |
ctrl.tmo <= '0'; |
ctrl.timeout <= std_ulogic_vector(to_unsigned(BUS_TIMEOUT, index_size_f(BUS_TIMEOUT))); |
ctrl.timeout <= std_ulogic_vector(to_unsigned(BUS_TIMEOUT, index_size_f(BUS_TIMEOUT)+1)); |
|
-- state machine -- |
case ctrl.state is |
/rtl/core/neorv32_xirq.vhd
210,10 → 210,12
irq_arbiter: process(clk_i) |
begin |
if rising_edge(clk_i) then |
cpu_irq_o <= '0'; |
if (irq_run = '0') then -- no active IRQ |
if (irq_fire = '1') then |
irq_run <= '1'; |
irq_src <= irq_src_nxt; |
cpu_irq_o <= '1'; |
irq_run <= '1'; |
irq_src <= irq_src_nxt; |
end if; |
else -- active IRQ, wait for CPU to acknowledge |
if (wren = '1') and (addr = xirq_source_addr_c) then -- write _any_ value to acknowledge |
223,8 → 225,5
end if; |
end process irq_arbiter; |
|
-- interrupt request -- |
cpu_irq_o <= irq_run; |
|
|
end neorv32_xirq_rtl; |
/rtl/processor_templates/README.md
1,3 → 1,35
# SoC Templates |
# SoC/Processor Templates |
|
:construction: Work in Progress :construction: |
This folder provides exemplary templates that wrap the processor top entity and provide a simplified |
set of configuration generics and IOs. These setups are intended to allow beginner an easy start by |
hiding much of the processor's configuration complexity. Furthermore, these setups are used by many |
of the provided [example setups](https://github.com/stnolting/neorv32/tree/master/setups). |
|
Alternatively, you can directly instantiate the processor's top entity |
[`rtl/core/neorv32_top.vhd`](https://github.com/stnolting/neorv32/blob/master/rtl/core/neorv32_top.vhd) |
to have full access to _all_ features. |
|
### [`neorv32_ProcessorTop_Minimal.vhd`](https://github.com/stnolting/neorv32/blob/master/rtl/processor_templates/neorv32_ProcessorTop_Minimal.vhd) |
|
This setup used the ["Direct Boot Configuration"](https://stnolting.github.io/neorv32/#_boot_configuration). |
Application software is installed directly into the processor-internal instruction memory (IMEM) during |
synthesis. This memory is implemented as ROM and these is no bootloader available. Hence, the executable |
remains unchangeable is executed right after reset. |
|
The setup only provides 3 PWM channels as IO. |
|
### [`neorv32_ProcessorTop_MinimalBoot.vhd`](https://github.com/stnolting/neorv32/blob/master/rtl/processor_templates/neorv32_ProcessorTop_MinimalBoot.vhd) |
|
This setup used the ["Indirect Boot Configuration"](https://stnolting.github.io/neorv32/#_boot_configuration). |
The NEORV32 bootloader is enabled in this setup allowing to upload new application software at any time |
via a UART connection. |
|
The setup provides 8 GPIO outputs and the UART communication lines as IO. |
|
### [`neorv32_ProcessorTop_UP5KDemo.vhd`](https://github.com/stnolting/neorv32/blob/master/rtl/processor_templates/neorv32_ProcessorTop_UP5KDemo.vhd) |
|
This is a more complex template that implements a small microcontroller-like NEORV32. |
It was originally designed for _UPDuino V3_ board, which features a Lattice iCE40up5k FPGA, but has |
also been ported to other boards that provide the same FPGA. |
|
This setup provides a rich set of IOs including GPIO, SPI, TWI and PWM. |
/rtl/system_integration/neorv32_SystemTop_axi4lite.vhd
103,7 → 103,7
IO_TWI_EN : boolean := true; -- implement two-wire interface (TWI)? |
IO_PWM_NUM_CH : natural := 4; -- number of PWM channels to implement (0..60); 0 = disabled |
IO_WDT_EN : boolean := true; -- implement watch dog timer (WDT)? |
IO_TRNG_EN : boolean := false; -- implement true random number generator (TRNG)? |
IO_TRNG_EN : boolean := true; -- implement true random number generator (TRNG)? |
IO_CFS_EN : boolean := false; -- implement custom functions subsystem (CFS)? |
IO_CFS_CONFIG : std_logic_vector(31 downto 0) := x"00000000"; -- custom CFS configuration generic |
IO_CFS_IN_SIZE : positive := 32; -- size of CFS input conduit in bits |
/rtl/test_setups/README.md
3,8 → 3,7
This folder contains very simple test setups that are intended for project beginners |
to setup a minimal NEORV32 SoC. These setups are used in the :books: |
[NEORV32 User Guide](https://stnolting.github.io/neorv32/ug/). |
|
:information_source: Note that these setups provides a minimalistic configuration to keep |
Note that these setups provides a minimalistic configuration to keep |
things at a simple level at first. Additional CPU ISA extensions, performance options and |
optional peripheral modules can be enabled by specifying the according :book: |
[configuration generics](https://stnolting.github.io/neorv32/#_processor_top_entity_generics). |
33,7 → 32,7
This setup configures a `rv32imc_Zicsr` CPU with 16kB IMEM (as pre-initialized ROM), |
8kB DMEM and includes the GPIO module to drive 8 external signals (`gpio_o`) |
and the MTIME module for generating timer interrupts. |
The setup uses the [indidrect boot](https://stnolting.github.io/neorv32/#_indirect_boot) |
The setup uses the ["indirect boot"](https://stnolting.github.io/neorv32/#_indirect_boot) |
configuration, so software applications are "installed" directly into the |
processor-internal IMEM during synthesis. |
|
46,7 → 45,7
and includes the GPIO module to drive 8 external signals (`gpio_o`), the MTIME |
module for generating timer interrupts and UART0 to interface with the bootloader |
(via `uart0_txd_o` and `uart0_rxd_i`) via a serial terminal. |
The setup uses the [direct boot](https://stnolting.github.io/neorv32/#_direct_boot) |
The setup uses the ["direct boot"](https://stnolting.github.io/neorv32/#_direct_boot) |
configuration, so software applications can be uploaded and run at any timer via a serial terminal. |
|
:books: See User Guide section |
/setups/osflow/README.md
1,12 → 1,21
# Exemplary FPAG Board Setups - Using Open Source Toolchains |
|
* [Folder Structure](#Folder-Structure) |
* [Prerequisites](#Prerequisites) |
* [How To Run](#How-To-Run) |
* [Porting to a new FPGA or Board](#Porting-to-a-new-FPGA-or-Board) |
|
This folder provides the infrastructure for generating bitstream for various FPGAs using |
open source toolchains. Synthesis based on [ghdl-yosys](https://github.com/ghdl/ghdl-yosys-plugin). |
open-source toolchains. Synthesis is based on [ghdl-yosys](https://github.com/ghdl/ghdl-yosys-plugin). |
|
:information_source: Note that the provided setups just implement very basic SoC configurations. |
These setups are intended as minimal example (how to synthesize the processor) for a given FPGA + board |
that can be used as starting point to build more complex user-defined SoCs. |
|
## Folder Structure |
|
* `.`: Main makefile (main entry point) and partial-makefiles for synthesis, place & route and bitstream generation |
* `boards`: board-specific _partial makefiles_ (used in by main makefile `Makefile`) for generating bitstreams |
* `boards`: board-specific _partial makefiles_ (used by main makefile "`Makefile`") for generating bitstreams |
* `board_top`: board-specific top entities (board wrappers; may include FPGA-specific modules) |
* `constraints`: physical constraints (mainly pin mappings) |
* `devices`: FPGA-specific primitives and optimized processor modules (like memories) |
14,7 → 23,7
|
## Prerequisites |
|
:construction: **TODO - Under Construction** :construction: |
:construction: TODO :construction: |
|
* local installation of the tools |
* using containers |
22,6 → 31,8
|
## How To Run |
|
:construction: TODO :construction: |
|
The `Makefile` in this folder is the main entry point. To run the whole process of synthesis, place & route and bitstream |
generation run: |
|
42,4 → 53,93
[`rtl/processor_templates`](https://github.com/stnolting/neorv32/tree/master/rtl/processor_templates). |
|
|
See https://github.com/stnolting/neorv32/blob/master/.github/workflows/Implementation.yml |
## Porting to a new FPGA or Board |
|
This sections illustrates how to add a new basic setup for a specific FPGA and board. This tutorial used the iCEBreaker |
"MinimalBoot" setup as reference. |
|
#### 1. Setup a board- and FPGA-specific top entity |
|
1. Write a new top design unit that instantiates one of the provided processor templates from |
[`rtl/processor_templates`](https://github.com/stnolting/neorv32/tree/master/rtl/processor_templates). |
This new top unit can be a Verilog or VHDL file. |
2. _Optional:_ You can also include FPGA-specific primitives like PLLs or block RAMs (but keep it simple). These components |
need to be added to a FPGA-specific library in [`setups/osflow/devices`](https://github.com/stnolting/neorv32/tree/master/setups/osflow/devices). |
3. Try to keep the external IO at a minimum even if the targeted FPGA boards provides cool features. Besides of clock and reset |
you need to add at least one kind of IO interface like a UART, GPIO or PWM. |
4. Give your new top entity file a specific name that includes the board's name and the instantiated processor template. |
The name scheme is `neorv32_[board-name]_BoardTop_[template-name].[v/vhd]`. |
5. Put this file in `setups/osflow/board_tops`. |
6. Take a look at the iCEBreaker MinimalBoot top entity as a reference: |
[`setups/osflow/board_tops/neorv32_iCEBreaker_BoardTop_MinimalBoot.vhd`](https://github.com/stnolting/neorv32/blob/master/setups/osflow/board_tops/neorv32_iCEBreaker_BoardTop_MinimalBoot.vhd) |
|
#### 2. Pin mapping |
|
1. Add a new constraints file to define the mapping between the your top unit's IO and the FPGA's physical pins. |
You can add _all_ of the FPGA's physical pins even though just a subset is used by the new setup. |
2. Name the new constraints file according to the board `[board-name].pcf`. |
3. Put this file in `setups/osflow/constraints`. |
4. Take a look at the iCEBreaker pin mapping as a reference: |
[`setups/osflow/constraints/iCEBreaker.pcf`](https://github.com/stnolting/neorv32/blob/master/setups/osflow/constraints/iCEBreaker.pcf) |
|
#### 3. Adding a board-specific makefile |
|
1. Add a board-specific makefile to the `setups/osflow/boards` folder. Name the new constraints file according to the board `[board-name].mk`. |
2. The makefile contains (at least) one target to build the final bitstream: |
```makefile |
.PHONY: all |
|
all: bit |
echo "! Built $(IMPL) for $(BOARD)" |
``` |
3. Take a look at the iCEBreaker pin mapping as a reference: |
[` setups/osflow/boards/iCEBreaker.mk`](https://github.com/stnolting/neorv32/blob/master/setups/osflow/boards/iCEBreaker.mk) |
|
#### 4. Adding a new target to `index.mk` |
|
1. Add a new conditional section to the boards management makefile `setups/osflow/boards/index.mk`. |
2. This board-specific section sets variables that are required to run synthesis, mapping, place & route and bitstream generation: |
* `CONSTRAINTS` defines the physical pin mapping file |
* `PNRFLAGS` defines the FPGA-specific flags for mapping and place & route |
* `IMPL` defines the setup's implementation name |
```makefile |
ifeq ($(BOARD),iCEBreaker) |
$(info Setting constraints and implementation args for BOARD iCEBreaker) |
|
CONSTRAINTS ?= $(PCF_PATH)/$(BOARD).pcf |
PNRFLAGS ?= --up5k --package sg48 --ignore-loops --timing-allow-fail |
IMPL ?= neorv32_$(BOARD)_$(ID) |
|
endif |
``` |
|
#### 5. Adding a new target to the main makefile |
|
1. As final step add the new setup to the main osflow makefile `setups/osflow/Makefile`. |
2. Use the board's name to create a new makefile target. |
* The new target should set the final bitstream's name using the `BITSTREAM` variable. |
* Alternative _memory_ HDL sources like FPGA-optimized module can be set using the `NEORV32_MEM_SRC` variable. |
```makefile |
iCEBreaker: |
$(eval BITSTREAM ?= neorv32_$(BOARD)_$(DESIGN).bit) |
$(eval NEORV32_MEM_SRC ?= devices/ice40/neorv32_imem.ice40up_spram.vhd devices/ice40/neorv32_dmem.ice40up_spram.vhd) |
$(MAKE) \ |
BITSTREAM="$(BITSTREAM)" \ |
NEORV32_MEM_SRC="$(NEORV32_MEM_SRC)" \ |
run |
``` |
|
#### 6. _Optional:_ Add the new setup to the automatic "Implementation" github workflow |
|
If you like you can add the new setup to the automatic build environment of the project. The project's "Implementation" |
workflow will generate bitstreams for all configured osflow setups on every repository push. This is used to check for |
regressions and also to provide up-to-date bitstreams that can be used right away. |
|
1. Add the new setup to the job matrix file `.github/generate-job-matrix.py`. |
```python |
{ |
'board': 'iCEBreaker', |
'design': 'MinimalBoot', |
'bitstream': 'neorv32_iCEBreaker_MinimalBoot.bit' |
}, |
``` |
/sim/simple/neorv32_tb.simple.vhd
210,7 → 210,7
ICACHE_ASSOCIATIVITY => 2, -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2 |
-- External memory interface -- |
MEM_EXT_EN => true, -- implement external memory bus interface? |
MEM_EXT_TIMEOUT => 255, -- cycles after a pending bus access auto-terminates (0 = disabled) |
MEM_EXT_TIMEOUT => 256, -- cycles after a pending bus access auto-terminates (0 = disabled) |
-- Stream link interface -- |
SLINK_NUM_TX => 8, -- number of TX links (0..8) |
SLINK_NUM_RX => 8, -- number of TX links (0..8) |
/sim/neorv32_tb.vhd
317,7 → 317,7
ICACHE_ASSOCIATIVITY => 2, -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2 |
-- External memory interface -- |
MEM_EXT_EN => true, -- implement external memory bus interface? |
MEM_EXT_TIMEOUT => 255, -- cycles after a pending bus access auto-terminates (0 = disabled) |
MEM_EXT_TIMEOUT => 256, -- cycles after a pending bus access auto-terminates (0 = disabled) |
-- Stream link interface -- |
SLINK_NUM_TX => 8, -- number of TX links (0..8) |
SLINK_NUM_RX => 8, -- number of TX links (0..8) |
/sw/bootloader/bootloader.c
202,13 → 202,13
* This global variable keeps the size of the available executable in bytes. |
* If =0 no executable is available (yet). |
**************************************************************************/ |
volatile uint32_t exe_available = 0; |
volatile uint32_t exe_available; |
|
|
/**********************************************************************//** |
* Only set during executable fetch (required for capturing STORE BUS-TIMOUT exception). |
**************************************************************************/ |
volatile uint32_t getting_exe = 0; |
volatile uint32_t getting_exe; |
|
|
// Function prototypes |
687,7 → 687,7
} |
#if (SPI_EN != 0) |
else { |
data.uint8[i] = spi_flash_read_byte(addr + i); |
data.uint8[i] = spi_flash_read_byte(addr + (3-i)); |
} |
#endif |
} |
809,7 → 809,7
|
int i; |
for (i=0; i<4; i++) { |
spi_flash_write_byte(addr + i, data.uint8[i]); |
spi_flash_write_byte(addr + (3-i), data.uint8[i]); |
} |
#endif |
} |
/sw/common/common.mk
327,23 → 327,35
# Help |
# ----------------------------------------------------------------------------- |
help: |
@echo "<<< NEORV32 Application Makefile >>>" |
@echo "<<< NEORV32 SW Application Makefile >>>" |
@echo "Make sure to add the bin folder of RISC-V GCC to your PATH variable." |
@echo "Targets:" |
@echo " help - show this text" |
@echo " check - check toolchain" |
@echo " info - show makefile/toolchain configuration" |
@echo " exe - compile and generate <neorv32_exe.bin> executable for upload via bootloader" |
@echo " hex - compile and generate <neorv32_exe.hex> executable raw file" |
@echo " image - compile and generate VHDL IMEM boot image (for application) in local folder" |
@echo " install - compile, generate and install VHDL IMEM boot image (for application)" |
@echo " sim - in-console simulation using default/simple testbench and GHDL" |
@echo " all - exe + hex + install" |
@echo " elf_info - show ELF layout info" |
@echo " clean - clean up project" |
@echo " clean_all - clean up project, core libraries and image generator" |
@echo " bl_image - compile and generate VHDL BOOTROM boot image (for bootloader only!) in local folder" |
@echo " bootloader - compile, generate and install VHDL BOOTROM boot image (for bootloader only!)" |
@echo "" |
@echo "== Targets ==" |
@echo " help - show this text" |
@echo " check - check toolchain" |
@echo " info - show makefile/toolchain configuration" |
@echo " exe - compile and generate <neorv32_exe.bin> executable for upload via bootloader" |
@echo " hex - compile and generate <neorv32_exe.hex> executable raw file" |
@echo " image - compile and generate VHDL IMEM boot image (for application) in local folder" |
@echo " install - compile, generate and install VHDL IMEM boot image (for application)" |
@echo " sim - in-console simulation using default/simple testbench and GHDL" |
@echo " all - exe + hex + install" |
@echo " elf_info - show ELF layout info" |
@echo " clean - clean up project" |
@echo " clean_all - clean up project, core libraries and image generator" |
@echo " bl_image - compile and generate VHDL BOOTROM boot image (for bootloader only!) in local folder" |
@echo " bootloader - compile, generate and install VHDL BOOTROM boot image (for bootloader only!)" |
@echo "" |
@echo "== Variables ==" |
@echo " USER_FLAGS - Custom toolchain flags [append only], default \"$(USER_FLAGS)\"" |
@echo " EFFORT - Optimization level, default \"$(EFFORT)\"" |
@echo " MARCH - Machine architecture, default \"$(MARCH)\"" |
@echo " MABI - Machine binary interface, default \"$(MABI)\"" |
@echo " APP_INC - C include folder(s) [append only], default \"$(APP_INC)\"" |
@echo " ASM_INC - ASM include folder(s) [append only], default \"$(ASM_INC)\"" |
@echo " RISCV_PREFIX - Toolchain prefix, default \"$(RISCV_PREFIX)\"" |
@echo " NEORV32_HOME - NEORV32 home folder, default \"$(NEORV32_HOME)\"" |
@echo "" |
|
|
# ----------------------------------------------------------------------------- |
/sw/example/bus_explorer/main.c
176,7 → 176,7
return; |
} |
else { |
neorv32_uart0_printf("Invalid selection!\n"); |
neorv32_uart0_printf("\nInvalid selection!\n"); |
} |
} |
} |
200,7 → 200,7
register uint32_t mem_address = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
|
// perform read access |
neorv32_uart0_printf("\n[0x%x] = ", mem_address); |
neorv32_uart0_printf("\n[0x%x] => ", mem_address); |
|
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
|
258,16 → 258,26
neorv32_uart0_printf("\nEnter data (2 hex chars): 0x"); |
neorv32_uart0_scan(terminal_buffer, 2+1, 1); // 2 hex chars for address plus '\0' |
mem_data_b = (uint8_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
neorv32_uart0_printf("\n[0x%x] <= 0x", mem_address); |
aux_print_hex_byte(mem_data_b); |
} |
if (access_size == 'h') { |
neorv32_uart0_printf("\nEnter data (4 hex chars): 0x"); |
neorv32_uart0_scan(terminal_buffer, 4+1, 1); // 4 hex chars for address plus '\0' |
mem_data_h = (uint16_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
neorv32_uart0_printf("\n[0x%x] <= 0x", mem_address); |
aux_print_hex_byte((uint8_t)(mem_data_h >> 8)); |
aux_print_hex_byte((uint8_t)(mem_data_h >> 0)); |
} |
if (access_size == 'w') { |
neorv32_uart0_printf("\nEnter data (8 hex chars): 0x"); |
neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0' |
mem_data_w = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
neorv32_uart0_printf("\n[0x%x] <= 0x", mem_address); |
aux_print_hex_byte((uint8_t)(mem_data_w >> 24)); |
aux_print_hex_byte((uint8_t)(mem_data_w >> 16)); |
aux_print_hex_byte((uint8_t)(mem_data_w >> 8)); |
aux_print_hex_byte((uint8_t)(mem_data_w >> 0)); |
} |
|
// perform write access |
/sw/example/demo_gptmr/main.c
113,7 → 113,7
**************************************************************************/ |
void gptmr_firq_handler(void) { |
|
neorv32_gptmr_ack_irq(); // IRQ acknowledge / clear pending alarm interrupt |
neorv32_cpu_csr_write(CSR_MIP, 1<<GPTMR_FIRQ_PENDING); // clear/ack pending FIRQ |
|
neorv32_uart0_putc('.'); // send tick symbol via UART |
neorv32_gpio_pin_toggle(0); // toggle output port bit 0 |
/sw/example/demo_slink/main.c
0,0 → 1,522
// ################################################################################################# |
// # << NEORV32 - SLINK Demo Program >> # |
// # ********************************************************************************************* # |
// # BSD 3-Clause License # |
// # # |
// # Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
// # # |
// # Redistribution and use in source and binary forms, with or without modification, are # |
// # permitted provided that the following conditions are met: # |
// # # |
// # 1. Redistributions of source code must retain the above copyright notice, this list of # |
// # conditions and the following disclaimer. # |
// # # |
// # 2. Redistributions in binary form must reproduce the above copyright notice, this list of # |
// # conditions and the following disclaimer in the documentation and/or other materials # |
// # provided with the distribution. # |
// # # |
// # 3. Neither the name of the copyright holder nor the names of its contributors may be used to # |
// # endorse or promote products derived from this software without specific prior written # |
// # permission. # |
// # # |
// # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # |
// # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # |
// # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # |
// # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # |
// # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # |
// # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # |
// # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # |
// # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # |
// # OF THE POSSIBILITY OF SUCH DAMAGE. # |
// # ********************************************************************************************* # |
// # The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # |
// ################################################################################################# |
|
|
/**********************************************************************//** |
* @file demo_slink/main.c |
* @author Stephan Nolting |
* @brief SLINK demo program. |
**************************************************************************/ |
|
#include <neorv32.h> |
#include <string.h> |
|
|
/**********************************************************************//** |
* @name User configuration |
**************************************************************************/ |
/**@{*/ |
/** UART BAUD rate */ |
#define BAUD_RATE 19200 |
/**@}*/ |
|
|
// Global variables |
uint32_t slink_configured; // 0 = not configured, 1 = blocking mode, 2 = non-blocking mode |
uint32_t slink_irq_en; |
uint32_t slink_irq_mode; |
|
// Prototypes |
void slink_read(void); |
void slink_write(void); |
void slink_status(void); |
void slink_setup(void); |
void slink_irq_enable(void); |
void slink_irq_setup(void); |
void slink_reset(void); |
uint32_t hexstr_to_uint(char *buffer, uint8_t length); |
void slink_rx_firq_handler(void); |
void slink_tx_firq_handler(void); |
|
|
|
/**********************************************************************//** |
* This program provides an interactive console to initiate SLINK transfers. |
* |
* @note This program requires the UART and the SLINK to be synthesized. |
* |
* @return Irrelevant. |
**************************************************************************/ |
int main() { |
|
char buffer[16]; |
int length = 0; |
|
|
// capture all exceptions and give debug info via UART |
// this is not required, but keeps us safe |
neorv32_rte_setup(); |
|
// init UART0 at default baud rate, no parity bits, ho hw flow control |
neorv32_uart0_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE); |
|
|
// check if UART0 unit is implemented at all |
if (neorv32_uart0_available() == 0) { |
return 1; |
} |
|
// intro |
neorv32_uart0_printf("\n<<< SLINK Access Test Program >>>\n\n"); |
|
// check if SLINK is implemented at all |
if (neorv32_slink_available() == 0) { |
neorv32_uart0_printf("No SLINK implemented."); |
return 1; |
} |
|
// info |
neorv32_uart0_printf("This program allows to create SLINK transfers by hand.\n" |
"Type 'help' to see the help menu.\n\n"); |
|
// enable SLINK module |
neorv32_slink_enable(); |
slink_configured = 0; // SLINK not configured yet |
slink_irq_en = 0; // interrupts disabled |
slink_irq_mode = 0; |
|
|
// configure SLINK interrupts |
int i; |
for (i=0; i<neorv32_slink_get_rx_num(); i++) { |
neorv32_slink_rx_irq_config(i, SLINK_IRQ_ENABLE, SLINK_IRQ_RX_NOT_EMPTY); |
} |
for (i=0; i<neorv32_slink_get_tx_num(); i++) { |
neorv32_slink_tx_irq_config(i, SLINK_IRQ_ENABLE, SLINK_IRQ_TX_NOT_FULL); |
} |
|
neorv32_rte_exception_install(SLINK_RX_RTE_ID, slink_rx_firq_handler); |
neorv32_rte_exception_install(SLINK_TX_RTE_ID, slink_tx_firq_handler); |
neorv32_cpu_eint(); // enable global interrupt flag |
|
|
// Main menu |
for (;;) { |
neorv32_uart0_printf("SLINK_ACCESS:> "); |
length = neorv32_uart0_scan(buffer, 15, 1); |
neorv32_uart0_printf("\n"); |
|
if (!length) // nothing to be done |
continue; |
|
// decode input and execute command |
if (!strcmp(buffer, "help")) { |
neorv32_uart0_printf("Available commands:\n" |
" help - show this text\n" |
" status - show SLINK HW status\n" |
" setup - configure SLINK module\n" |
" read - read from SLINK channel\n" |
" write - write to SLINK channel\n" |
" irq_mode - toggle SLINK IRQ mode\n" |
" irq_en - toggle SLINK IRQ enable\n" |
" reset - reset SLINK module\n" |
"\n" |
"Configure the SLINK module using 'setup'. Then transfer data using 'read' and 'write'.\n\n"); |
} |
else if (!strcmp(buffer, "setup")) { |
slink_setup(); |
} |
else if (!strcmp(buffer, "status")) { |
slink_status(); |
} |
else if (!strcmp(buffer, "read")) { |
slink_read(); |
} |
else if (!strcmp(buffer, "write")) { |
slink_write(); |
} |
else if (!strcmp(buffer, "irq_en")) { |
slink_irq_enable(); |
} |
else if (!strcmp(buffer, "irq_mode")) { |
slink_irq_setup(); |
} |
else if (!strcmp(buffer, "reset")) { |
slink_reset(); |
} |
else { |
neorv32_uart0_printf("Invalid command. Type 'help' to see all commands.\n"); |
} |
} |
|
return 0; |
} |
|
|
/**********************************************************************//** |
* Show SLINK status |
**************************************************************************/ |
void slink_status(void) { |
|
neorv32_uart0_printf("Hardware configuration\n"); |
neorv32_uart0_printf(" TX links: %u\n", neorv32_slink_get_rx_num()); |
neorv32_uart0_printf(" RX links: %u\n", neorv32_slink_get_tx_num()); |
neorv32_uart0_printf(" TX FIFO: %u entries \n", neorv32_slink_get_rx_depth()); |
neorv32_uart0_printf(" RX FIFO: %u entries \n\n", neorv32_slink_get_tx_depth()); |
|
neorv32_uart0_printf("SLINK status:\n"); |
neorv32_uart0_printf(" Link status: 0x%x \n", NEORV32_SLINK.STATUS); |
neorv32_uart0_printf(" IRQ config.: 0x%x \n\n", NEORV32_SLINK.IRQ); |
} |
|
|
/**********************************************************************//** |
* Configure SLINK |
**************************************************************************/ |
void slink_setup(void) { |
|
char tmp_c; |
|
while (1) { |
neorv32_uart0_printf("Select SLINK access mode:\n" |
" n: non-blocking access -> check SLINK status flags before access\n" |
" b: blocking access -> raise an exception on invalid access request\n" |
"Select: "); |
tmp_c = neorv32_uart0_getc(); |
neorv32_uart0_putc(tmp_c); |
if (tmp_c == 'n') { |
slink_configured = 2; |
break; |
} |
else if (tmp_c == 'b') { |
slink_configured = 1; |
break; |
} |
else { |
neorv32_uart0_printf("\nInvalid selection!\n"); |
} |
} |
|
neorv32_uart0_printf("\n\n"); |
} |
|
|
/**********************************************************************//** |
* Reset SLINK |
**************************************************************************/ |
void slink_reset(void) { |
|
int i; |
|
for (i=0; i<neorv32_slink_get_rx_num(); i++) { |
neorv32_slink_rx_irq_config(i, SLINK_IRQ_DISABLE, SLINK_IRQ_RX_NOT_EMPTY); |
} |
for (i=0; i<neorv32_slink_get_tx_num(); i++) { |
neorv32_slink_tx_irq_config(i, SLINK_IRQ_DISABLE, SLINK_IRQ_TX_NOT_FULL); |
} |
|
neorv32_slink_disable(); |
neorv32_slink_enable(); |
|
slink_configured = 0; |
slink_irq_en = 0; |
slink_irq_mode = 0; |
|
neorv32_uart0_printf("SLINK has been reset.\n\n"); |
} |
|
|
/**********************************************************************//** |
* Toggle SLINK interrupt mode |
**************************************************************************/ |
void slink_irq_setup(void) { |
|
int i; |
|
if (slink_irq_mode == 0) { |
for (i=0; i<neorv32_slink_get_rx_num(); i++) { |
neorv32_slink_rx_irq_config(i, SLINK_IRQ_DISABLE, SLINK_IRQ_RX_NOT_EMPTY); // disable first to reset trigger logic |
neorv32_slink_rx_irq_config(i, SLINK_IRQ_ENABLE, SLINK_IRQ_RX_NOT_EMPTY); |
} |
for (i=0; i<neorv32_slink_get_tx_num(); i++) { |
neorv32_slink_tx_irq_config(i, SLINK_IRQ_DISABLE, SLINK_IRQ_TX_NOT_FULL); |
neorv32_slink_tx_irq_config(i, SLINK_IRQ_ENABLE, SLINK_IRQ_TX_NOT_FULL); |
} |
neorv32_uart0_printf("New SLINK IRQ mode: SLINK_IRQ_RX_NOT_EMPTY + SLINK_IRQ_TX_NOT_FULL\n\n"); |
} |
else { |
for (i=0; i<neorv32_slink_get_rx_num(); i++) { |
neorv32_slink_rx_irq_config(i, SLINK_IRQ_DISABLE, SLINK_IRQ_RX_FIFO_HALF); |
neorv32_slink_rx_irq_config(i, SLINK_IRQ_ENABLE, SLINK_IRQ_RX_FIFO_HALF); |
} |
for (i=0; i<neorv32_slink_get_tx_num(); i++) { |
neorv32_slink_tx_irq_config(i, SLINK_IRQ_DISABLE, SLINK_IRQ_TX_FIFO_HALF); |
neorv32_slink_tx_irq_config(i, SLINK_IRQ_ENABLE, SLINK_IRQ_TX_FIFO_HALF); |
} |
neorv32_uart0_printf("New SLINK IRQ mode: SLINK_IRQ_RX_FIFO_HALF + SLINK_IRQ_TX_FIFO_HALF\n\n"); |
} |
slink_irq_mode = ~slink_irq_mode; |
} |
|
|
/**********************************************************************//** |
* Toggle SLINK interrupt enable |
**************************************************************************/ |
void slink_irq_enable(void) { |
|
if (slink_irq_en == 0) { |
neorv32_cpu_irq_enable(SLINK_RX_FIRQ_ENABLE); |
neorv32_cpu_irq_enable(SLINK_TX_FIRQ_ENABLE); |
neorv32_uart0_printf("SLINK interrupts are now ENABLED.\n\n"); |
} |
else { |
neorv32_cpu_irq_disable(SLINK_RX_FIRQ_ENABLE); |
neorv32_cpu_irq_disable(SLINK_TX_FIRQ_ENABLE); |
neorv32_uart0_printf("SLINK interrupts are now DISABLED.\n\n"); |
} |
slink_irq_en = ~slink_irq_en; |
} |
|
|
/**********************************************************************//** |
* Read from SLINK channel |
**************************************************************************/ |
void slink_read(void) { |
|
char terminal_buffer[9]; |
uint32_t num_ch; |
uint32_t channel; |
uint32_t rxdata; |
int status = 1; |
|
if (slink_configured == 0) { |
neorv32_uart0_printf("SLINK module not configured yet! Use 'setup' to configure SLINK module.\n"); |
return; |
} |
|
num_ch = (uint32_t)neorv32_slink_get_rx_num(); |
if (num_ch == 0) { |
neorv32_uart0_printf("No SLINK RX channels implemented.\n"); |
return; |
} |
|
// select channel |
while (1) { |
neorv32_uart0_printf("Enter RX channel ID (0..%u): ", num_ch-1); |
neorv32_uart0_scan(terminal_buffer, 2, 1); // 1 hex char plus '\0' |
channel = hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
if ((channel < 0) || (channel > num_ch)) { |
neorv32_uart0_printf("\nInvalid channel selection!\n"); |
continue; |
} |
else { |
break; |
} |
} |
channel &= 0x7; |
|
// actual read access |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart0_printf("\nReading from RX channel %u...\n", channel); |
|
if (slink_configured == 2) { // non-blocking access |
switch (channel) { |
case 0: status = neorv32_slink_rx0_nonblocking(&rxdata); break; |
case 1: status = neorv32_slink_rx1_nonblocking(&rxdata); break; |
case 2: status = neorv32_slink_rx2_nonblocking(&rxdata); break; |
case 3: status = neorv32_slink_rx3_nonblocking(&rxdata); break; |
case 4: status = neorv32_slink_rx4_nonblocking(&rxdata); break; |
case 5: status = neorv32_slink_rx5_nonblocking(&rxdata); break; |
case 6: status = neorv32_slink_rx6_nonblocking(&rxdata); break; |
case 7: status = neorv32_slink_rx7_nonblocking(&rxdata); break; |
default: status = 1; break; |
} |
} |
else { // blocking access |
status = 0; |
switch (channel) { |
case 0: neorv32_slink_rx0_blocking(&rxdata); break; |
case 1: neorv32_slink_rx1_blocking(&rxdata); break; |
case 2: neorv32_slink_rx2_blocking(&rxdata); break; |
case 3: neorv32_slink_rx3_blocking(&rxdata); break; |
case 4: neorv32_slink_rx4_blocking(&rxdata); break; |
case 5: neorv32_slink_rx5_blocking(&rxdata); break; |
case 6: neorv32_slink_rx6_blocking(&rxdata); break; |
case 7: neorv32_slink_rx7_blocking(&rxdata); break; |
default: status = 1; break; |
} |
} |
|
if ((status == 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_L_ACCESS)) { |
neorv32_uart0_printf("RX data: 0x%x\n\n", rxdata); |
} |
else { |
neorv32_uart0_printf("No data available.\n\n"); |
} |
} |
|
|
/**********************************************************************//** |
* Write to SLINK channel |
**************************************************************************/ |
void slink_write(void) { |
|
char terminal_buffer[9]; |
uint32_t num_ch; |
uint32_t channel; |
uint32_t txdata; |
int status = 1; |
|
if (slink_configured == 0) { |
neorv32_uart0_printf("SLINK module not configured yet! Use 'setup' to configure SLINK module.\n"); |
return; |
} |
|
num_ch = (uint32_t)neorv32_slink_get_tx_num(); |
if (num_ch == 0) { |
neorv32_uart0_printf("No SLINK TX channels implemented.\n"); |
return; |
} |
|
// select channel |
while (1) { |
neorv32_uart0_printf("Enter TX channel ID (0..%u): ", num_ch-1); |
neorv32_uart0_scan(terminal_buffer, 2, 1); // 1 hex char plus '\0' |
channel = hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
if ((channel < 0) || (channel > num_ch)) { |
neorv32_uart0_printf("\nInvalid channel selection!\n"); |
continue; |
} |
else { |
break; |
} |
} |
channel &= 0x7; |
|
// get TX data |
neorv32_uart0_printf("\nEnter TX data (8 hex chars): 0x"); |
neorv32_uart0_scan(terminal_buffer, 9, 1); // 8 hex char plus '\0' |
txdata = hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
|
// actual write access |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
neorv32_uart0_printf("\nWriting '0x%x' to TX channel %u...\n", txdata, channel); |
|
if (slink_configured == 2) { // non-blocking access |
switch (channel) { |
case 0: status = neorv32_slink_tx0_nonblocking(txdata); break; |
case 1: status = neorv32_slink_tx1_nonblocking(txdata); break; |
case 2: status = neorv32_slink_tx2_nonblocking(txdata); break; |
case 3: status = neorv32_slink_tx3_nonblocking(txdata); break; |
case 4: status = neorv32_slink_tx4_nonblocking(txdata); break; |
case 5: status = neorv32_slink_tx5_nonblocking(txdata); break; |
case 6: status = neorv32_slink_tx6_nonblocking(txdata); break; |
case 7: status = neorv32_slink_tx7_nonblocking(txdata); break; |
default: status = 1; break; |
} |
} |
else { // blocking access |
status = 0; |
switch (channel) { |
case 0: neorv32_slink_tx0_blocking(txdata); break; |
case 1: neorv32_slink_tx1_blocking(txdata); break; |
case 2: neorv32_slink_tx2_blocking(txdata); break; |
case 3: neorv32_slink_tx3_blocking(txdata); break; |
case 4: neorv32_slink_tx4_blocking(txdata); break; |
case 5: neorv32_slink_tx5_blocking(txdata); break; |
case 6: neorv32_slink_tx6_blocking(txdata); break; |
case 7: neorv32_slink_tx7_blocking(txdata); break; |
default: status = 1; break; |
} |
} |
|
if ((status == 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_S_ACCESS)) { |
neorv32_uart0_printf("Write successful.\n\n"); |
} |
else { |
neorv32_uart0_printf("Write failed.\n\n", status); |
} |
} |
|
|
/**********************************************************************//** |
* SLINK RX FIRQ handler |
**************************************************************************/ |
void slink_rx_firq_handler(void) { |
|
neorv32_cpu_csr_write(CSR_MIP, 1 << SLINK_RX_FIRQ_PENDING); // ACK interrupt |
neorv32_uart0_printf("\n<SLINK_RX_IRQ>\n"); |
} |
|
|
/**********************************************************************//** |
* SLINK TX FIRQ handler |
**************************************************************************/ |
void slink_tx_firq_handler(void) { |
|
neorv32_cpu_csr_write(CSR_MIP, 1 << SLINK_TX_FIRQ_PENDING); // ACK interrupt |
neorv32_uart0_printf("\n<SLINK_TX_IRQ>\n"); |
} |
|
|
/**********************************************************************//** |
* Helper function to convert N hex chars string into uint32_T |
* |
* @param[in,out] buffer Pointer to array of chars to convert into number. |
* @param[in,out] length Length of the conversion string. |
* @return Converted number. |
**************************************************************************/ |
uint32_t hexstr_to_uint(char *buffer, uint8_t length) { |
|
uint32_t res = 0, d = 0; |
char c = 0; |
|
while (length--) { |
c = *buffer++; |
|
if ((c >= '0') && (c <= '9')) |
d = (uint32_t)(c - '0'); |
else if ((c >= 'a') && (c <= 'f')) |
d = (uint32_t)((c - 'a') + 10); |
else if ((c >= 'A') && (c <= 'F')) |
d = (uint32_t)((c - 'A') + 10); |
else |
d = 0; |
|
res = res + (d << (length*4)); |
} |
|
return res; |
} |
|
/sw/example/demo_slink/makefile
0,0 → 1,40
################################################################################################# |
# << NEORV32 - Application Makefile >> # |
# ********************************************************************************************* # |
# Make sure to add the RISC-V GCC compiler's bin folder to your PATH environment variable. # |
# ********************************************************************************************* # |
# BSD 3-Clause License # |
# # |
# Copyright (c) 2021, Stephan Nolting. All rights reserved. # |
# # |
# Redistribution and use in source and binary forms, with or without modification, are # |
# permitted provided that the following conditions are met: # |
# # |
# 1. Redistributions of source code must retain the above copyright notice, this list of # |
# conditions and the following disclaimer. # |
# # |
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of # |
# conditions and the following disclaimer in the documentation and/or other materials # |
# provided with the distribution. # |
# # |
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to # |
# endorse or promote products derived from this software without specific prior written # |
# permission. # |
# # |
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # |
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # |
# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # |
# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # |
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # |
# GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # |
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # |
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # |
# OF THE POSSIBILITY OF SUCH DAMAGE. # |
# ********************************************************************************************* # |
# The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # |
################################################################################################# |
|
# Modify this variable to fit your NEORV32 setup (neorv32 home folder) |
NEORV32_HOME ?= ../../.. |
|
include $(NEORV32_HOME)/sw/common/common.mk |
/sw/example/demo_spi/main.c
60,11 → 60,24
void spi_cs(uint32_t type); |
void spi_trans(void); |
void spi_setup(void); |
void flash_write(void); |
void flash_read(void); |
uint32_t hexstr_to_uint(char *buffer, uint8_t length); |
void aux_print_hex_byte(uint8_t byte); |
|
|
/**********************************************************************//** |
* SPI flash commands |
**************************************************************************/ |
enum SPI_FLASH_CMD { |
SPI_FLASH_CMD_WRITE = 0x02, /**< Write data */ |
SPI_FLASH_CMD_READ = 0x03, /**< Read data */ |
SPI_FLASH_CMD_READ_SR = 0x05, /**< Get status register */ |
SPI_FLASH_CMD_WREN = 0x06 /**< Enable write access */ |
}; |
|
|
/**********************************************************************//** |
* This program provides an interactive console to communicate with SPI devices. |
* |
* @note This program requires the UART and the SPI to be synthesized. |
73,7 → 86,7
**************************************************************************/ |
int main() { |
|
char buffer[8]; |
char buffer[16]; |
int length = 0; |
|
|
99,7 → 112,6
return 1; |
} |
|
|
// info |
neorv32_uart0_printf("This program allows to create SPI transfers by hand.\n" |
"Type 'help' to see the help menu.\n\n"); |
113,7 → 125,7
// Main menu |
for (;;) { |
neorv32_uart0_printf("SPI_EXPLORER:> "); |
length = neorv32_uart0_scan(buffer, 8, 1); |
length = neorv32_uart0_scan(buffer, 15, 1); |
neorv32_uart0_printf("\n"); |
|
if (!length) // nothing to be done |
122,14 → 134,20
// decode input and execute command |
if (!strcmp(buffer, "help")) { |
neorv32_uart0_printf("Available commands:\n" |
" help - show this text\n" |
" setup - configure SPI module\n" |
" cs-en - enable CS line (set low)\n" |
" cs-dis - disable CS line (set high)\n" |
" trans - execute a transmission (write & read to/from SPI)\n" |
" help - show this text\n" |
" setup - configure SPI module (clock speed and mode, data size)\n" |
" cs-en - enable CS line (set low)\n" |
" cs-dis - disable CS line (set high)\n" |
" trans - execute a transmission (write & read to/from SPI)\n" |
"\n" |
" flash-wr - write binary file to SPI flash\n" |
" flash-rd - dump SPI flash\n" |
"\n" |
"Configure the SPI module using 'setup'. Enable a certain module using 'cs-en',\n" |
"then transfer data using 'trans' and disable the module again using 'cs-dis'.\n\n"); |
"then transfer data using 'trans' and disable the module again using 'cs-dis'.\n" |
"\n" |
"Standard SPI flash and EEPROM memories can be programmed/read\n" |
"via 'flash-wr' and 'flash-rd'.\n\n"); |
} |
else if (!strcmp(buffer, "setup")) { |
spi_setup(); |
143,6 → 161,12
else if (!strcmp(buffer, "trans")) { |
spi_trans(); |
} |
else if (!strcmp(buffer, "flash-wr")) { |
flash_write(); |
} |
else if (!strcmp(buffer, "flash-rd")) { |
flash_read(); |
} |
else { |
neorv32_uart0_printf("Invalid command. Type 'help' to see all commands.\n"); |
} |
203,7 → 227,7
return; |
} |
|
neorv32_uart0_printf("Enter TX data (%u hex chars): 0x", spi_size); |
neorv32_uart0_printf("Enter TX data (%u hex chars): 0x", spi_size*2); |
neorv32_uart0_scan(terminal_buffer, spi_size*2+1, 1); |
uint32_t tx_data = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
|
322,6 → 346,214
|
|
/**********************************************************************//** |
* Read (dump) flash |
**************************************************************************/ |
void flash_read(void) { |
|
char terminal_buffer[9]; |
uint32_t tmp, addr, channel, num_addr_bytes; |
|
if (spi_configured == 0) { |
neorv32_uart0_printf("SPI module not configured yet! Use 'setup' to configure SPI module.\n"); |
return; |
} |
|
// configure 8-bit SPI mode |
tmp = NEORV32_SPI.CTRL; |
tmp &= ~(0x03 << SPI_CTRL_SIZE0); |
NEORV32_SPI.CTRL = tmp; |
neorv32_uart0_printf("Warning! SPI size configuration has been overridden!\n"); |
|
// how many address bytes? |
while (1) { |
neorv32_uart0_printf("Enter number of address bytes (2,3): "); |
neorv32_uart0_scan(terminal_buffer, 2, 1); // 1 hex char plus '\0' |
num_addr_bytes = hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
if ((num_addr_bytes < 2) || (num_addr_bytes > 3)) { |
neorv32_uart0_printf("\nInvalid channel selection!\n"); |
continue; |
} |
else { |
break; |
} |
} |
|
// chip-select |
while (1) { |
neorv32_uart0_printf("\nSelect flash chip-select line [0..7]: "); |
neorv32_uart0_scan(terminal_buffer, 2, 1); // 1 hex char plus '\0' |
channel = hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
if (channel > 7) { |
neorv32_uart0_printf("\nInvalid channel selection!\n"); |
continue; |
} |
else { |
break; |
} |
} |
|
// base address |
neorv32_uart0_printf("\nEnter base address (8 hex chars): 0x"); |
neorv32_uart0_scan(terminal_buffer, 9, 1); |
addr = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
|
neorv32_uart0_printf("\nPress any key to start. Press any key to stop reading.\n"); |
while(neorv32_uart0_char_received() == 0); |
|
while(1) { |
if (neorv32_uart0_char_received()) { // abort when key pressed |
break; |
} |
|
if ((addr & 0x1f) == 0) { |
neorv32_uart0_printf("\n%x: ", addr); |
} |
|
// read byte |
neorv32_spi_cs_en((uint8_t)channel); |
neorv32_spi_trans(SPI_FLASH_CMD_READ); |
if (num_addr_bytes == 3) { |
neorv32_spi_trans(addr >> 16); |
} |
neorv32_spi_trans(addr >> 8); |
neorv32_spi_trans(addr >> 0); |
tmp = neorv32_spi_trans(0); |
neorv32_spi_cs_dis((uint8_t)channel); |
|
aux_print_hex_byte((uint8_t)tmp); |
neorv32_uart0_putc(' '); |
|
addr++; |
} |
|
neorv32_uart0_printf("\n"); |
spi_configured = 0; |
} |
|
|
/**********************************************************************//** |
* Write flash |
**************************************************************************/ |
void flash_write(void) { |
|
neorv32_uart0_printf("work-in-progress\n"); |
return; |
|
char terminal_buffer[9], rx_data; |
uint32_t tmp, addr, channel, num_data_bytes, num_addr_bytes; |
int res; |
|
if (spi_configured == 0) { |
neorv32_uart0_printf("SPI module not configured yet! Use 'setup' to configure SPI module.\n"); |
return; |
} |
|
// configure 8-bit SPI mode |
tmp = NEORV32_SPI.CTRL; |
tmp &= ~(0x03 << SPI_CTRL_SIZE0); |
NEORV32_SPI.CTRL = tmp; |
neorv32_uart0_printf("Warning! SPI size configuration has been overridden!\n"); |
|
// how many address bytes? |
while (1) { |
neorv32_uart0_printf("Enter number of address bytes (2,3): "); |
neorv32_uart0_scan(terminal_buffer, 2, 1); // 1 hex char plus '\0' |
num_addr_bytes = hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
if ((num_addr_bytes < 2) || (num_addr_bytes > 3)) { |
neorv32_uart0_printf("\nInvalid channel selection!\n"); |
continue; |
} |
else { |
break; |
} |
} |
|
// how many bytes? |
neorv32_uart0_printf("\nEnter total number of bytes to write (%u hex chars): ", num_addr_bytes*2); |
neorv32_uart0_scan(terminal_buffer, num_addr_bytes*2+1, 1); // 1 hex char plus '\0' |
num_data_bytes = hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
|
// chip-select |
while (1) { |
neorv32_uart0_printf("\nSelect flash chip-select line [0..7]: "); |
neorv32_uart0_scan(terminal_buffer, 2, 1); // 1 hex char plus '\0' |
channel = hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
if (channel > 7) { |
neorv32_uart0_printf("\nInvalid channel selection!\n"); |
continue; |
} |
else { |
break; |
} |
} |
|
// base address |
neorv32_uart0_printf("\nEnter base address (8 hex chars): 0x"); |
neorv32_uart0_scan(terminal_buffer, 9, 1); |
addr = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer)); |
|
// start! |
neorv32_uart0_printf("\nSend raw data via UART (%u bytes)...\n", num_data_bytes); |
while (neorv32_uart0_tx_busy()); |
|
// clear UART0 FIFOs |
neorv32_uart0_disable(); |
neorv32_uart0_enable(); |
|
while (num_data_bytes) { |
|
// write enable |
neorv32_spi_cs_en((uint8_t)channel); |
neorv32_spi_trans(SPI_FLASH_CMD_WREN); |
neorv32_spi_cs_dis((uint8_t)channel); |
|
// get new UART data |
while(1) { |
res = neorv32_uart0_getc_safe(&rx_data); |
if (res == -1) { |
continue; |
} |
if (res == 0) { |
break; |
} |
else { |
neorv32_uart0_printf("UART transmission error (%i)!\n", res); |
return; |
} |
} |
|
// write byte |
neorv32_spi_cs_en((uint8_t)channel); |
neorv32_spi_trans(SPI_FLASH_CMD_WRITE); |
if (num_addr_bytes == 3) { |
neorv32_spi_trans(addr >> 16); |
} |
neorv32_spi_trans(addr >> 8); |
neorv32_spi_trans(addr >> 0); |
neorv32_spi_trans((uint32_t)rx_data); |
neorv32_spi_cs_dis((uint8_t)channel); |
|
// check status register |
while (1) { |
neorv32_spi_cs_en((uint8_t)channel); |
neorv32_spi_trans(SPI_FLASH_CMD_READ_SR); |
tmp = neorv32_spi_trans(0); |
neorv32_spi_cs_dis((uint8_t)channel); |
if ((tmp & 0x01) == 0) { // write-in-progress flag cleared? |
break; |
} |
} |
|
addr++; |
num_data_bytes--; |
} |
|
neorv32_uart0_printf("\n"); |
spi_configured = 0; |
} |
|
|
/**********************************************************************//** |
* Helper function to convert N hex chars string into uint32_T |
* |
* @param[in,out] buffer Pointer to array of chars to convert into number. |
/sw/example/demo_trng/main.c
99,7 → 99,7
// main menu |
neorv32_uart0_printf("\nCommands:\n" |
" n: Print 8-bit random numbers (abort by pressing any key)\n" |
" h: Generate and print histogram\n"); |
" h: Generate histogram and analyze data\n"); |
|
neorv32_uart0_printf("CMD:> "); |
char cmd = neorv32_uart0_getc(); |
154,8 → 154,8
uint32_t hist[256]; |
uint32_t i; |
uint32_t cnt = 0; |
int err = 0; |
uint8_t trng_data; |
uint64_t average = 0; |
|
neorv32_uart0_printf("Press any key to start.\n"); |
|
167,48 → 167,72
hist[i] = 0; |
} |
|
|
// sample random data |
while(1) { |
|
err = neorv32_trng_get(&trng_data); |
// get raw TRNG data |
if (neorv32_trng_get(&trng_data)) { |
continue; |
} |
|
// add to histogram |
hist[trng_data & 0xff]++; |
cnt++; |
|
if (err) { |
neorv32_uart0_printf("\nTRNG error!\n"); |
break; |
} |
// average |
average += (uint64_t)trng_data; |
|
if (neorv32_uart0_char_received()) { // abort when key pressed |
// abort conditions |
if ((neorv32_uart0_char_received()) || // abort when key pressed |
(cnt & 0x80000000UL)) { // to prevent overflow |
break; |
} |
} |
|
if (cnt & 0x80000000UL) { // to prevent overflow |
break; |
average = average / cnt; |
|
|
// deviation (histogram samples) |
uint32_t avg_occurence = cnt / 256; |
int32_t tmp_int; |
int32_t dev_int; |
int32_t dev_int_max = 0x80000000UL; uint32_t bin_max = 0; |
int32_t dev_int_min = 0x7fffffffUL; uint32_t bin_min = 0; |
int32_t dev_int_avg = 0; |
for (i=0; i<256; i++) { |
tmp_int = (int32_t)hist[i]; |
dev_int = tmp_int - avg_occurence; |
|
dev_int_avg += (uint64_t)dev_int; |
|
if (dev_int < dev_int_min) { |
dev_int_min = dev_int; |
bin_min = i; |
} |
if (dev_int > dev_int_max) { |
dev_int_max = dev_int; |
bin_max = i; |
} |
} |
|
dev_int_avg = dev_int_avg / 256; |
|
// print histogram |
neorv32_uart0_printf("Histogram [random data value] : [# occurences]\n"); |
neorv32_uart0_printf("Histogram [random data value] : [# occurrences]\n"); |
for (i=0; i<256; i++) { |
neorv32_uart0_printf("%u: %u\n", (uint32_t)i, hist[i]); |
} |
neorv32_uart0_printf("\n"); |
|
neorv32_uart0_printf("\nSamples: %u\n", cnt); |
|
// average |
uint64_t average = 0; |
for (i=0; i<256; i++) { |
average += (uint64_t)hist[i] * i; |
} |
average = average / ((uint64_t)cnt); |
neorv32_uart0_printf("Average value: %u ", (uint32_t)average); |
|
if (((uint8_t)average) == ((uint8_t)(255/2))) { |
neorv32_uart0_printf("%c[1m[TEST OK]%c[0m\n", 27, 27); |
} |
else { |
neorv32_uart0_printf("%c[1m[TEST FAILED]%c[0m\n", 27, 27); |
} |
|
// print results |
neorv32_uart0_printf("Analysis results (integer only)\n\n"); |
neorv32_uart0_printf("Number of samples: %u\n", cnt); |
neorv32_uart0_printf("Arithmetic mean: %u\n", (uint32_t)average); |
neorv32_uart0_printf("\nArithmetic deviation\n"); |
neorv32_uart0_printf("Avg. occurrence: %u\n", avg_occurence); |
neorv32_uart0_printf("Avg. deviation: %i\n", dev_int_avg); |
neorv32_uart0_printf("Minimum: %i (histogram bin %u)\n", dev_int_min, bin_min); |
neorv32_uart0_printf("Maximum: %i (histogram bin %u)\n", dev_int_max, bin_max); |
} |
/sw/example/processor_check/main.c
151,6 → 151,13
// intro |
PRINT_STANDARD("\n<< PROCESSOR CHECK >>\n"); |
PRINT_STANDARD("build: "__DATE__" "__TIME__"\n"); |
PRINT_STANDARD("is simulation: "); |
if (NEORV32_SYSINFO.SOC & (1 << SYSINFO_SOC_IS_SIM)) { |
PRINT_STANDARD("yes\n"); |
} |
else { |
PRINT_STANDARD("no\n"); |
} |
|
|
// reset performance counter |
252,32 → 259,32
} |
|
|
// ---------------------------------------------------------- |
// Test standard RISC-V performance counter [m]cycle[h] |
// ---------------------------------------------------------- |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] cycle counter: ", cnt_test); |
//// ---------------------------------------------------------- |
//// Test standard RISC-V performance counter [m]cycle[h] |
//// ---------------------------------------------------------- |
//neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
//PRINT_STANDARD("[%i] cycle counter: ", cnt_test); |
// |
//cnt_test++; |
// |
//// make sure counter is enabled |
//asm volatile ("csrci %[addr], %[imm]" : : [addr] "i" (CSR_MCOUNTINHIBIT), [imm] "i" (1<<CSR_MCOUNTINHIBIT_CY)); |
// |
//// prepare overflow |
//neorv32_cpu_set_mcycle(0x00000000FFFFFFFFULL); |
// |
//// get current cycle counter HIGH |
//tmp_a = neorv32_cpu_csr_read(CSR_MCYCLEH); |
// |
//// make sure cycle counter high has incremented and there was no exception during access |
//if ((tmp_a == 1) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
// test_ok(); |
//} |
//else { |
// test_fail(); |
//} |
|
cnt_test++; |
|
// make sure counter is enabled |
asm volatile ("csrci %[addr], %[imm]" : : [addr] "i" (CSR_MCOUNTINHIBIT), [imm] "i" (1<<CSR_MCOUNTINHIBIT_CY)); |
|
// prepare overflow |
neorv32_cpu_set_mcycle(0x00000000FFFFFFFFULL); |
|
// get current cycle counter HIGH |
tmp_a = neorv32_cpu_csr_read(CSR_MCYCLEH); |
|
// make sure cycle counter high has incremented and there was no exception during access |
if ((tmp_a == 1) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
test_ok(); |
} |
else { |
test_fail(); |
} |
|
|
// ---------------------------------------------------------- |
// Test standard RISC-V performance counter [m]instret[h] |
// ---------------------------------------------------------- |
429,13 → 436,9
tmp_a = (uint32_t)EXT_MEM_BASE; // call the dummy sub program |
asm volatile ("jalr ra, %[input_i]" : : [input_i] "r" (tmp_a)); |
|
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) { // make sure there was no exception |
if (neorv32_cpu_csr_read(CSR_MSCRATCH) == 15) { // make sure the program was executed in the right way |
test_ok(); |
} |
else { |
test_fail(); |
} |
if ((neorv32_cpu_csr_read(CSR_MCAUSE) == 0) && // make sure there was no exception |
(neorv32_cpu_csr_read(CSR_MSCRATCH) == 15)) { // make sure the program was executed in the right way |
test_ok(); |
} |
else { |
test_fail(); |
919,7 → 922,7
|
// configure WDT |
neorv32_wdt_setup(CLK_PRSC_4096, 0, 1); // highest clock prescaler, trigger IRQ on timeout, lock access |
NEORV32_WDT.CTRL = 0; // try to deactivate WDT (should fail as access is loced) |
NEORV32_WDT.CTRL = 0; // try to deactivate WDT (should fail as access is locked) |
neorv32_wdt_force(); // force watchdog into action |
|
// wait some time for the IRQ to arrive the CPU |
965,14 → 968,14
// make sure sim mode is disabled |
NEORV32_UART0.CTRL &= ~(1 << UART_CTRL_SIM_MODE); |
|
// enable fast interrupt |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ2E); |
|
// trigger UART0 RX IRQ |
neorv32_uart0_putc(0); |
// wait for UART0 to finish transmitting |
while(neorv32_uart0_tx_busy()); |
|
// enable fast interrupt |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ2E); |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
neorv32_cpu_irq_disable(CSR_MIE_FIRQ2E); |
1009,10 → 1012,11
// make sure sim mode is disabled |
NEORV32_UART0.CTRL &= ~(1 << UART_CTRL_SIM_MODE); |
|
// UART0 TX interrupt enable |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ3E); |
|
// trigger UART0 TX IRQ |
neorv32_uart0_putc(0); |
// UART0 TX interrupt enable |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ3E); |
// wait for UART to finish transmitting |
while(neorv32_uart0_tx_busy()); |
|
1049,12 → 1053,13
// make sure sim mode is disabled |
NEORV32_UART1.CTRL &= ~(1 << UART_CTRL_SIM_MODE); |
|
// UART1 RX interrupt enable |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ4E); |
|
// trigger UART1 RX IRQ |
neorv32_uart1_putc(0); |
// wait for UART1 to finish transmitting |
while(neorv32_uart1_tx_busy()); |
// UART1 RX interrupt enable |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ4E); |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
1089,10 → 1094,11
// make sure sim mode is disabled |
NEORV32_UART1.CTRL &= ~(1 << UART_CTRL_SIM_MODE); |
|
// UART1 RX interrupt enable |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ5E); |
|
// trigger UART1 TX IRQ |
neorv32_uart1_putc(0); |
// UART1 RX interrupt enable |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ5E); |
// wait for UART1 to finish transmitting |
while(neorv32_uart1_tx_busy()); |
|
1257,59 → 1263,43
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 10 & 11 (SLINK) |
// Fast interrupt channel 10 (SLINK RX) |
// ---------------------------------------------------------- |
if (neorv32_slink_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ10 & 11 (SLINK): ", cnt_test); |
PRINT_STANDARD("[%i] FIRQ10 (SLINK RX): ", cnt_test); |
|
cnt_test++; |
|
// configure SLINK IRQs |
neorv32_slink_tx_irq_config(0, SLINK_IRQ_ENABLE, SLINK_IRQ_TX_NOT_FULL); |
neorv32_slink_rx_irq_config(0, SLINK_IRQ_ENABLE, SLINK_IRQ_RX_NOT_EMPTY); |
|
// enable SLINK |
neorv32_slink_enable(); |
|
// enable SLINK FIRQs |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ10E); |
neorv32_cpu_irq_enable(CSR_MIE_FIRQ11E); |
neorv32_slink_rx_irq_config(0, SLINK_IRQ_ENABLE, SLINK_IRQ_RX_NOT_EMPTY); |
neorv32_cpu_irq_enable(SLINK_RX_FIRQ_ENABLE); |
|
tmp_a = 0; // error counter |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
|
// check if TX FIFO fires IRQ |
if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_FIRQ_11) { |
tmp_a += 1; |
} |
neorv32_slink_tx_irq_config(0, SLINK_IRQ_DISABLE, SLINK_IRQ_TX_NOT_FULL); |
|
// send single data word via link 0 |
if (neorv32_slink_tx0_nonblocking(0xA1B2C3D4)) { |
tmp_a += 2; // sending failed |
tmp_a += 1; // sending failed |
} |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
|
// check if RX FIFO fires IRQ |
if (neorv32_cpu_csr_read(CSR_MCAUSE) != TRAP_CODE_FIRQ_10) { |
tmp_a += 4; |
// check if RX link fires IRQ |
if (neorv32_cpu_csr_read(CSR_MCAUSE) != SLINK_RX_TRAP_CODE) { |
tmp_a += 2; |
} |
neorv32_slink_rx_irq_config(0, SLINK_IRQ_DISABLE, SLINK_IRQ_RX_NOT_EMPTY); |
neorv32_cpu_irq_disable(SLINK_RX_FIRQ_ENABLE); |
|
// get single data word from link 0 |
uint32_t slink_rx_data; |
if (neorv32_slink_rx0_nonblocking(&slink_rx_data)) { |
tmp_a += 8; // receiving failed |
tmp_a += 4; // receiving failed |
} |
|
neorv32_cpu_irq_disable(CSR_MIE_FIRQ10E); |
neorv32_cpu_irq_disable(CSR_MIE_FIRQ11E); |
|
if ((tmp_a == 0) && // local error counter = 0 |
(slink_rx_data == 0xA1B2C3D4)) { // correct data read-back |
test_ok(); |
1324,6 → 1314,50
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 11 (SLINK TX) |
// ---------------------------------------------------------- |
if (neorv32_slink_available()) { |
neorv32_cpu_csr_write(CSR_MCAUSE, 0); |
PRINT_STANDARD("[%i] FIRQ11 (SLINK TX): ", cnt_test); |
|
cnt_test++; |
|
// enable SLINK |
neorv32_slink_enable(); |
|
// enable SLINK FIRQs |
neorv32_slink_tx_irq_config(0, SLINK_IRQ_ENABLE, SLINK_IRQ_TX_NOT_FULL); |
neorv32_cpu_irq_enable(SLINK_TX_FIRQ_ENABLE); |
|
tmp_a = 0; // error counter |
|
// send single data word via link 0 |
if (neorv32_slink_tx0_nonblocking(0x11223344)) { |
tmp_a += 1; // sending failed |
} |
|
// wait some time for the IRQ to arrive the CPU |
asm volatile("nop"); |
|
// check if TX link fires IRQ |
if (neorv32_cpu_csr_read(CSR_MCAUSE) != SLINK_TX_TRAP_CODE) { |
tmp_a += 2; |
} |
neorv32_cpu_irq_disable(SLINK_RX_FIRQ_ENABLE); |
|
if (tmp_a == 0) { // local error counter = 0 |
test_ok(); |
} |
else { |
test_fail(); |
} |
|
// shutdown SLINK |
neorv32_slink_disable(); |
} |
|
|
// ---------------------------------------------------------- |
// Fast interrupt channel 12 (GPTMR) |
// ---------------------------------------------------------- |
if (neorv32_slink_available()) { |
1464,7 → 1498,7
PRINT_STANDARD("Creating protected page (NAPOT, [!X,!W,!R], %u bytes) @ 0x%x: ", tmp_b, tmp_a); |
|
// configure |
int pmp_return = neorv32_cpu_pmp_configure_region(0, tmp_a, tmp_b, 0b00011000); // NAPOT, NO read permission, NO write permission, and NO execute permissions |
int pmp_return = neorv32_cpu_pmp_configure_region(0, tmp_a, tmp_b, PMPCFG_MODE_NAPOT << PMPCFG_A_LSB); // NAPOT, NO read/write/execute permissions |
|
if ((pmp_return == 0) && (neorv32_cpu_csr_read(CSR_MCAUSE) == 0)) { |
test_ok(); |
1751,6 → 1785,9
**************************************************************************/ |
void global_trap_handler(void) { |
|
// clear all pending FIRQs |
neorv32_cpu_csr_write(CSR_MIP, -1); |
|
// hack: always come back in MACHINE MODE |
register uint32_t mask = (1<<CSR_MSTATUS_MPP_H) | (1<<CSR_MSTATUS_MPP_L); |
asm volatile ("csrrs zero, mstatus, %[input_j]" : : [input_j] "r" (mask)); |
/sw/lib/include/neorv32_legacy.h
File deleted
/sw/lib/include/neorv32.h
434,6 → 434,24
|
|
/**********************************************************************//** |
* CPU <b>pmpcfg</b> PMP configuration attributed |
**************************************************************************/ |
enum NEORV32_PMPCFG_ATTRIBUTES_enum { |
PMPCFG_R = 0, /**< CPU pmpcfg attribute (0): Read */ |
PMPCFG_W = 1, /**< CPU pmpcfg attribute (1): Write */ |
PMPCFG_X = 2, /**< CPU pmpcfg attribute (2): Execute */ |
PMPCFG_A_LSB = 3, /**< CPU pmpcfg attribute (3): Mode LSB */ |
PMPCFG_A_MSB = 4, /**< CPU pmpcfg attribute (4): Mode MSB */ |
PMPCFG_L = 7 /**< CPU pmpcfg attribute (7): Locked */ |
}; |
|
/**********************************************************************//** |
* PMP modes |
**************************************************************************/ |
#define PMPCFG_MODE_NAPOT 3 |
|
|
/**********************************************************************//** |
* Trap codes from mcause CSR. |
**************************************************************************/ |
enum NEORV32_EXCEPTION_CODES_enum { |
733,7 → 751,7
SLINK_CTRL_TX_FIFO_S2 = 14, /**< SLINK control register(14) (r/-): log2(TX FIFO size) bit 2 */ |
SLINK_CTRL_TX_FIFO_S3 = 15, /**< SLINK control register(15) (r/-): log2(TX FIFO size) bit 3 */ |
|
SLINK_CTRL_EN = 31, /**< SLINK control register(0) (r/w): SLINK controller enable */ |
SLINK_CTRL_EN = 31 /**< SLINK control register(0) (r/w): SLINK controller enable */ |
}; |
|
/** SLINK interrupt control register bits */ |
757,14 → 775,14
|
/** SLINK RX interrupt configuration type (per link) */ |
enum NEORV32_SLINK_IRQ_RX_TYPE_enum { |
SLINK_IRQ_RX_FIFO_HALF = 0, /**< '0': RX FIFO fill-level rises above half-full */ |
SLINK_IRQ_RX_NOT_EMPTY = 1 /**< '1': RX FIFO is not empty */ |
SLINK_IRQ_RX_NOT_EMPTY = 0, /**< '1': RX FIFO is not empty */ |
SLINK_IRQ_RX_FIFO_HALF = 1 /**< '0': RX FIFO fill-level rises above half-full */ |
}; |
|
/** SLINK TX interrupt configuration type (per link) */ |
enum NEORV32_SLINK_IRQ_TX_TYPE_enum { |
SLINK_IRQ_TX_FIFO_HALF = 0, /**< '0': TX FIFO fill-level falls below half-full */ |
SLINK_IRQ_TX_NOT_FULL = 1 /**< '1': TX FIFO is not FULL */ |
SLINK_IRQ_TX_NOT_FULL = 0, /**< '1': TX FIFO is not FULL */ |
SLINK_IRQ_TX_FIFO_HALF = 1 /**< '0': TX FIFO fill-level falls below half-full */ |
}; |
|
/** SLINK status register bits */ |
825,12 → 843,11
|
/** GPTMR control/data register bits */ |
enum NEORV32_GPTMR_CTRL_enum { |
GPTMR_CTRL_EN = 0, /**< GPTIMR control register(0) (r/w): Timer unit enable */ |
GPTMR_CTRL_PRSC0 = 1, /**< GPTIMR control register(1) (r/w): Clock prescaler select bit 0 */ |
GPTMR_CTRL_PRSC1 = 2, /**< GPTIMR control register(2) (r/w): Clock prescaler select bit 1 */ |
GPTMR_CTRL_PRSC2 = 3, /**< GPTIMR control register(3) (r/w): Clock prescaler select bit 2 */ |
GPTMR_CTRL_MODE = 4, /**< GPTIMR control register(4) (r/w): Timer mode: 0=single-shot mode, 1=continuous mode */ |
GPTMR_CTRL_ALARM = 5 /**< GPTIMR control register(5) (r/c): Interrupt/alarm pending, cleared by setting bit to zero */ |
GPTMR_CTRL_EN = 0, /**< GPTIMR control register(0) (r/w): Timer unit enable */ |
GPTMR_CTRL_PRSC0 = 1, /**< GPTIMR control register(1) (r/w): Clock prescaler select bit 0 */ |
GPTMR_CTRL_PRSC1 = 2, /**< GPTIMR control register(2) (r/w): Clock prescaler select bit 1 */ |
GPTMR_CTRL_PRSC2 = 3, /**< GPTIMR control register(3) (r/w): Clock prescaler select bit 2 */ |
GPTMR_CTRL_MODE = 4 /**< GPTIMR control register(4) (r/w): Timer mode: 0=single-shot mode, 1=continuous mode */ |
}; |
/**@}*/ |
|
970,7 → 987,7
UART_DATA_PERR = 28, /**< UART receive/transmit data register(18) (r/-): RX parity error detected when set */ |
UART_DATA_FERR = 29, /**< UART receive/transmit data register(29) (r/-): RX frame error (no valid stop bit) detected when set */ |
UART_DATA_OVERR = 30, /**< UART receive/transmit data register(30) (r/-): RX data overrun when set */ |
UART_DATA_AVAIL = 31 /**< UART receive/transmit data register(31) (r/-): RX data available when set */ |
UART_DATA_AVAIL = 31 /**< UART receive/transmit data register(31) (r/-): RX data available when set */ |
}; |
/**@}*/ |
|
1084,15 → 1101,17
|
/** WTD control register bits */ |
enum NEORV32_WDT_CTRL_enum { |
WDT_CTRL_EN = 0, /**< WDT control register(0) (r/w): Watchdog enable */ |
WDT_CTRL_CLK_SEL0 = 1, /**< WDT control register(1) (r/w): Clock prescaler select bit 0 */ |
WDT_CTRL_CLK_SEL1 = 2, /**< WDT control register(2) (r/w): Clock prescaler select bit 1 */ |
WDT_CTRL_CLK_SEL2 = 3, /**< WDT control register(3) (r/w): Clock prescaler select bit 2 */ |
WDT_CTRL_MODE = 4, /**< WDT control register(4) (r/w): Watchdog mode: 0=timeout causes interrupt, 1=timeout causes processor reset */ |
WDT_CTRL_RCAUSE = 5, /**< WDT control register(5) (r/-): Cause of last system reset: 0=external reset, 1=watchdog */ |
WDT_CTRL_RESET = 6, /**< WDT control register(6) (-/w): Reset WDT counter when set, auto-clears */ |
WDT_CTRL_FORCE = 7, /**< WDT control register(7) (-/w): Force WDT action, auto-clears */ |
WDT_CTRL_LOCK = 8 /**< WDT control register(8) (r/w): Lock write access to control register, clears on reset (HW or WDT) only */ |
WDT_CTRL_EN = 0, /**< WDT control register(0) (r/w): Watchdog enable */ |
WDT_CTRL_CLK_SEL0 = 1, /**< WDT control register(1) (r/w): Clock prescaler select bit 0 */ |
WDT_CTRL_CLK_SEL1 = 2, /**< WDT control register(2) (r/w): Clock prescaler select bit 1 */ |
WDT_CTRL_CLK_SEL2 = 3, /**< WDT control register(3) (r/w): Clock prescaler select bit 2 */ |
WDT_CTRL_MODE = 4, /**< WDT control register(4) (r/w): Watchdog mode: 0=timeout causes interrupt, 1=timeout causes processor reset */ |
WDT_CTRL_RCAUSE = 5, /**< WDT control register(5) (r/-): Cause of last system reset: 0=external reset, 1=watchdog */ |
WDT_CTRL_RESET = 6, /**< WDT control register(6) (-/w): Reset WDT counter when set, auto-clears */ |
WDT_CTRL_FORCE = 7, /**< WDT control register(7) (-/w): Force WDT action, auto-clears */ |
WDT_CTRL_LOCK = 8, /**< WDT control register(8) (r/w): Lock write access to control register, clears on reset (HW or WDT) only */ |
WDT_CTRL_DBEN = 9, /**< WDT control register(9) (r/w): Allow WDT to continue operation even when in debug mode */ |
WDT_CTRL_HALF = 10 /**< WDT control register(10) (r/-): Set if at least half of the max. timeout counter value has been reached */ |
}; |
/**@}*/ |
|
1180,7 → 1199,7
const uint32_t CACHE; /**< offset 12: cache configuration (#NEORV32_SYSINFO_CACHE_enum) */ |
const uint32_t ISPACE_BASE; /**< offset 16: instruction memory address space base */ |
const uint32_t DSPACE_BASE; /**< offset 20: data memory address space base */ |
const uint32_t IMEM_SIZE; /**< offset 24: internal instruction memory (IMEM) size in bytes */ |
const uint32_t IMEM_SIZE; /**< offset 24: internal instruction memory (IMEM) size in bytes */ |
const uint32_t DMEM_SIZE; /**< offset 28: internal data memory (DMEM) size in bytes */ |
} neorv32_sysinfo_t; |
|
1195,7 → 1214,7
|
SYSINFO_CPU_ZFINX = 5, /**< SYSINFO_CPU (5): Zfinx extension (F sub-/alternative-extension) available when set (r/-) */ |
SYSINFO_CPU_ZXSCNT = 6, /**< SYSINFO_CPU (6): Custom extension - Small CPU counters: "cycle" & "instret" CSRs have less than 64-bit when set (r/-) */ |
SYSINFO_CPU_ZICNTR = 7, /**< SYSINFO_CPU (7): Basie CPU counters available when set (r/-) */ |
SYSINFO_CPU_ZICNTR = 7, /**< SYSINFO_CPU (7): Basic CPU counters available when set (r/-) */ |
SYSINFO_CPU_PMP = 8, /**< SYSINFO_CPU (8): PMP (physical memory protection) extension available when set (r/-) */ |
SYSINFO_CPU_ZIHPM = 9, /**< SYSINFO_CPU (9): HPM (hardware performance monitors) extension available when set (r/-) */ |
SYSINFO_CPU_DEBUGMODE = 10, /**< SYSINFO_CPU (10): RISC-V CPU debug mode available when set (r/-) */ |
1213,6 → 1232,7
SYSINFO_SOC_MEM_EXT_ENDIAN = 4, /**< SYSINFO_FEATURES (4) (r/-): External bus interface uses BIG-endian byte-order when 1 (via MEM_EXT_BIG_ENDIAN generic) */ |
SYSINFO_SOC_ICACHE = 5, /**< SYSINFO_FEATURES (5) (r/-): Processor-internal instruction cache implemented when 1 (via ICACHE_EN generic) */ |
|
SYSINFO_SOC_IS_SIM = 13, /**< SYSINFO_FEATURES (13) (r/-): Set during simulation (not guaranteed) */ |
SYSINFO_SOC_OCD = 14, /**< SYSINFO_FEATURES (14) (r/-): On-chip debugger implemented when 1 (via ON_CHIP_DEBUGGER_EN generic) */ |
SYSINFO_SOC_HW_RESET = 15, /**< SYSINFO_FEATURES (15) (r/-): Dedicated hardware reset of core registers implemented when 1 (via package's dedicated_reset_c constant) */ |
|
1260,9 → 1280,6
// ---------------------------------------------------------------------------- |
// Include all IO driver headers |
// ---------------------------------------------------------------------------- |
// legacy compatibility layer |
#include "neorv32_legacy.h" |
|
// cpu core |
#include "neorv32_cpu.h" |
|
/sw/lib/include/neorv32_gptmr.h
50,6 → 50,5
void neorv32_gptmr_disable(void); |
void neorv32_gptmr_enable(void); |
void neorv32_gptmr_restart(void); |
void neorv32_gptmr_ack_irq(void); |
|
#endif // neorv32_gptmr_h |
/sw/lib/include/neorv32_uart.h
49,21 → 49,6
// Libs required by functions |
#include <stdarg.h> |
|
// compatibility wrappers (mapping to primary UART -> UART0) (OBSOLETE, do not use for new designs!) |
int neorv32_uart_available(void); |
void neorv32_uart_setup(uint32_t baudrate, uint8_t parity, uint8_t flow_con); |
void neorv32_uart_disable(void); |
void neorv32_uart_enable(void); |
void neorv32_uart_putc(char c); |
int neorv32_uart_tx_busy(void); |
char neorv32_uart_getc(void); |
int neorv32_uart_char_received(void); |
int neorv32_uart_getc_safe(char *data); |
char neorv32_uart_char_received_get(void); |
void neorv32_uart_print(const char *s); |
void neorv32_uart_printf(const char *format, ...); |
int neorv32_uart_scan(char *buffer, int max_size, int echo); |
|
// prototypes for UART0 (primary UART) |
int neorv32_uart0_available(void); |
void neorv32_uart0_setup(uint32_t baudrate, uint8_t parity, uint8_t flow_con); |
/sw/lib/source/neorv32_gpio.c
164,8 → 164,8
uint32_t uint32[sizeof(uint64_t)/2]; |
} data; |
|
data.uint32[0] = NEORV32_GPIO.OUTPUT_LO; |
data.uint32[1] = NEORV32_GPIO.OUTPUT_HI; |
data.uint32[0] = NEORV32_GPIO.INPUT_LO; |
data.uint32[1] = NEORV32_GPIO.INPUT_HI; |
|
return data.uint64; |
} |
/sw/lib/source/neorv32_gptmr.c
114,12 → 114,3
|
NEORV32_GPTMR.COUNT = 0; |
} |
|
|
/**********************************************************************//** |
* Acknowledge interrupt / clear pending alarm. |
**************************************************************************/ |
void neorv32_gptmr_ack_irq(void) { |
|
NEORV32_GPTMR.CTRL &= ~((uint32_t)(1 << GPTMR_CTRL_ALARM)); |
} |
/sw/lib/source/neorv32_uart.c
55,167 → 55,7
/// \endcond |
|
|
|
// ################################################################################################# |
// Compatibility wrappers mapping to UART0 (primary UART) |
// ################################################################################################# |
|
/**********************************************************************//** |
* Check if UART0 unit was synthesized. |
* |
* @warning This functions maps to UART0 (primary UART). |
* |
* @return 0 if UART0 was not synthesized, 1 if UART0 is available. |
**************************************************************************/ |
int neorv32_uart_available(void) { return neorv32_uart0_available(); } |
|
|
/**********************************************************************//** |
* Enable and configure primary UART (UART0). |
* |
* @warning This functions maps to UART0 (primary UART). |
* |
* @note The 'UART0_SIM_MODE' compiler flag will configure UART0 for simulation mode: all UART0 TX data will be redirected to simulation output. Use this for simulations only! |
* @note To enable simulation mode add <USER_FLAGS+=-DUART0_SIM_MODE> when compiling. |
* |
* @warning The baud rate is computed using INTEGER operations (truncation errors might occur). |
* |
* @param[in] baudrate Targeted BAUD rate (e.g. 9600). |
* @param[in] parity Parity configuration (00=off, 10=even, 11=odd), see #NEORV32_UART_PARITY_enum. |
* @param[in] flow_con Hardware flow control configuration (00=off, 01=RTS, 10=CTS, 11=RTS/CTS), see #NEORV32_UART_FLOW_CONTROL_enum. |
**************************************************************************/ |
void neorv32_uart_setup(uint32_t baudrate, uint8_t parity, uint8_t flow_con) { neorv32_uart0_setup(baudrate, parity, flow_con); } |
|
|
/**********************************************************************//** |
* Disable UART0. |
* @warning This functions maps to UART0 (primary UART). |
**************************************************************************/ |
void neorv32_uart_disable(void) { neorv32_uart0_disable(); } |
|
|
/**********************************************************************//** |
* Enable UART0. |
* @warning This functions maps to UART0 (primary UART). |
**************************************************************************/ |
void neorv32_uart_enable(void) { neorv32_uart0_enable(); } |
|
|
/**********************************************************************//** |
* Send single char via UART0. |
* |
* @warning This functions maps to UART0 (primary UART). |
* @note This function is blocking. |
* |
* @param[in] c Char to be send. |
**************************************************************************/ |
void neorv32_uart_putc(char c) { neorv32_uart0_putc(c); } |
|
|
/**********************************************************************//** |
* Check if UART0 TX is busy. |
* |
* @warning This functions maps to UART0 (primary UART). |
* @note This function is blocking. |
* |
* @return 0 if idle, 1 if busy |
**************************************************************************/ |
int neorv32_uart_tx_busy(void) { return neorv32_uart0_tx_busy(); } |
|
|
/**********************************************************************//** |
* Get char from UART0. |
* |
* @warning This functions maps to UART0 (primary UART). |
* @note This function is blocking and does not check for UART frame/parity errors. |
* |
* @return Received char. |
**************************************************************************/ |
char neorv32_uart_getc(void) { return neorv32_uart0_getc(); } |
|
|
/**********************************************************************//** |
* Check if UART0 has received a char. |
* |
* @warning This functions maps to UART0 (primary UART). |
* @note This function is non-blocking. |
* @note Use neorv32_uart0_char_received_get(void) to get the char. |
* |
* @return =!0 when a char has been received. |
**************************************************************************/ |
int neorv32_uart_char_received(void) { return neorv32_uart0_char_received(); } |
|
|
/**********************************************************************//** |
* Get char from UART0 (and check errors). |
* |
* @warning This functions maps to UART0 (primary UART). |
* @note This function is non-blocking and checks for frame and parity errors. |
* |
* @param[in,out] data Received char. |
* @return Status code (0=nothing received, 1: char received without errors; -1: char received with frame error; -2: char received with parity error; -3 char received with frame & parity error). |
**************************************************************************/ |
int neorv32_uart_getc_safe(char *data) { return neorv32_uart0_getc_safe(data); } |
|
|
/**********************************************************************//** |
* Get a received char from UART0. |
* |
* @warning This functions maps to UART0 (primary UART). |
* @note This function is non-blocking. |
* @note Should only be used in combination with neorv32_uart_char_received(void). |
* |
* @return Received char. |
**************************************************************************/ |
char neorv32_uart_char_received_get(void) { return neorv32_uart0_char_received_get(); } |
|
|
/**********************************************************************//** |
* Print string (zero-terminated) via UART0. Print full line break "\r\n" for every '\n'. |
* |
* @warning This functions maps to UART0 (primary UART). |
* @note This function is blocking. |
* |
* @param[in] s Pointer to string. |
**************************************************************************/ |
void neorv32_uart_print(const char *s) { neorv32_uart0_print(s); } |
|
|
/**********************************************************************//** |
* Custom version of 'printf' function using UART0. |
* |
* @warning This functions maps to UART0 (primary UART). |
* @note This function is blocking. |
* |
* @param[in] format Pointer to format string. |
* |
* <TABLE> |
* <TR><TD>%s</TD><TD>String (array of chars, zero-terminated)</TD></TR> |
* <TR><TD>%c</TD><TD>Single char</TD></TR> |
* <TR><TD>%i</TD><TD>32-bit signed number, printed as decimal</TD></TR> |
* <TR><TD>%u</TD><TD>32-bit unsigned number, printed as decimal</TD></TR> |
* <TR><TD>%x</TD><TD>32-bit number, printed as 8-char hexadecimal</TD></TR> |
* </TABLE> |
**************************************************************************/ |
void neorv32_uart_printf(const char *format, ...) { neorv32_uart0_printf(format); } |
|
|
/**********************************************************************//** |
* Simplified custom version of 'scanf' function for UART0. |
* |
* @warning This functions maps to UART0 (primary UART). |
* @note This function is blocking. |
* |
* @param[in,out] buffer Pointer to array of chars to store string. |
* @param[in] max_size Maximum number of chars to sample. |
* @param[in] echo Echo UART input when 1. |
* @return Number of chars read. |
**************************************************************************/ |
int neorv32_uart_scan(char *buffer, int max_size, int echo) { return neorv32_uart0_scan(buffer, max_size, echo); } |
|
|
|
// ################################################################################################# |
// Primary UART (UART0) |
// ################################################################################################# |
|
321,7 → 161,7
**************************************************************************/ |
void neorv32_uart0_enable(void) { |
|
NEORV32_UART0.CTRL = ((uint32_t)(1 << UART_CTRL_EN)); |
NEORV32_UART0.CTRL |= ((uint32_t)(1 << UART_CTRL_EN)); |
} |
|
|
/sw/lib/source/neorv32_xirq.c
237,8 → 237,11
|
uint32_t mask = 1 << src; |
NEORV32_XIRQ.IPR = ~mask; // clear current pending interrupt |
NEORV32_XIRQ.SCR = 0; // acknowledge current interrupt (CPU FIRQ) |
|
neorv32_cpu_csr_write(CSR_MIP, 1 << XIRQ_FIRQ_PENDING); // acknowledge XIRQ FIRQ |
|
NEORV32_XIRQ.SCR = 0; // acknowledge current XIRQ interrupt source |
|
// execute handler |
register uint32_t xirq_handler = __neorv32_xirq_vector_lut[src]; |
void (*handler_pnt)(void); |
/sw/openocd/openocd_neorv32.cfg
1,6 → 1,10
# config file for generic FT2232H based USB-jtag interface |
# openOCD configuration file for generic FT2232H-based USB-jtag interface |
# references: https://mcuoneclipse.com/2019/10/20/jtag-debugging-the-esp32-with-ft2232-and-openocd/ |
|
# ---------------------------------------------- |
# Interface configuration |
# ---------------------------------------------- |
|
# FT2232H pinout: |
# TCK: D0 |
# TDI: D1 |
17,12 → 21,21
ftdi_layout_signal nTRST -ndata 0x0010 -noe 0x0040 |
transport select jtag |
|
# ---------------------------------------------- |
# Target configuration |
# ---------------------------------------------- |
|
set _CHIPNAME neorv32 |
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x0cafe001 |
set _JTAGID 0x0cafe001 |
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id $_JTAGID |
|
set _TARGETNAME $_CHIPNAME.cpu |
|
target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME |
|
# work area ("scratch pad RAM"): beginning of internal DMEM, 256 bytes, REQUIRES backup |
# ---------------------------------------------- |
# Scratch pad RAM |
# ---------------------------------------------- |
|
# work area ("scratch pad RAM"): beginning of (internal) DMEM, 256 bytes, requires(!) backup |
$_TARGETNAME.0 configure -work-area-phys 0x80000000 -work-area-size 256 -work-area-backup 1 |
/sw/svd/README.md
0,0 → 1,10
# NEORV32 System View Description (SVD) File |
|
Manually created from `sw/lib/include/neorv32.h`. |
|
* Format: CMSIS-SVD |
* Copyright by ARM Ltd, Apache-2.0 License |
* Documentation: |
* https://www.keil.com/pack/doc/CMSIS/SVD/html/index.html |
* https://github.com/ARM-software/CMSIS |
* https://github.com/ARM-software/CMSIS_5 |
/sw/svd/neorv32.svd
0,0 → 1,1189
<?xml version="1.0" encoding="utf-8"?> |
|
<device schemaVersion="1.1" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xs:noNamespaceSchemaLocation="CMSIS-SVD.xsd" > |
<vendor>stnolting</vendor> |
<name>neorv32</name> |
<series>RISC-V</series> |
<version>1.6.4</version> |
<description>The NEORV32 RISC-V Processor</description> |
|
<!-- CPU core --> |
<cpu> |
<name>NEORV32</name> |
<revision>r2p0</revision> |
<endian>little</endian> |
<mpuPresent>true</mpuPresent> |
<fpuPresent>true</fpuPresent> |
<fpuDP>false</fpuDP> |
<dspPresent>false</dspPresent> |
<icachePresent>true</icachePresent> |
<dcachePresent>true</dcachePresent> |
<nvicPrioBits>0</nvicPrioBits> |
<vendorSystickConfig>false</vendorSystickConfig> |
</cpu> |
|
<!-- defaults for all peripherals --> |
<addressUnitBits>8</addressUnitBits> |
<width>32</width> |
<size>32</size> |
<access>read-write</access> |
<resetValue>0x00000000</resetValue> |
<resetMask>0x00000000</resetMask> <!-- default IO devices do not have a dedicated reset --> |
|
<!-- Peripherals --> |
<peripherals> |
|
<!-- CFS --> |
<peripheral> |
<name>CFS</name> |
<description>Custom functions subsystem</description> |
<groupName>CFS</groupName> |
<baseAddress>0xFFFFFE00</baseAddress> |
|
<interrupt><name>CFS_FIRQ</name><value>1</value></interrupt> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x80</size> |
<usage>registers</usage> |
</addressBlock> |
|
<registers> |
<register><name>REG0</name><description>Application-defined</description><addressOffset>0x00</addressOffset></register> |
<register><name>REG1</name><description>Application-defined</description><addressOffset>0x04</addressOffset></register> |
<register><name>REG2</name><description>Application-defined</description><addressOffset>0x08</addressOffset></register> |
<register><name>REG3</name><description>Application-defined</description><addressOffset>0x0C</addressOffset></register> |
<register><name>REG4</name><description>Application-defined</description><addressOffset>0x10</addressOffset></register> |
<register><name>REG5</name><description>Application-defined</description><addressOffset>0x14</addressOffset></register> |
<register><name>REG6</name><description>Application-defined</description><addressOffset>0x18</addressOffset></register> |
<register><name>REG7</name><description>Application-defined</description><addressOffset>0x1C</addressOffset></register> |
<register><name>REG8</name><description>Application-defined</description><addressOffset>0x20</addressOffset></register> |
<register><name>REG9</name><description>Application-defined</description><addressOffset>0x24</addressOffset></register> |
<register><name>REG10</name><description>Application-defined</description><addressOffset>0x28</addressOffset></register> |
<register><name>REG11</name><description>Application-defined</description><addressOffset>0x2C</addressOffset></register> |
<register><name>REG12</name><description>Application-defined</description><addressOffset>0x30</addressOffset></register> |
<register><name>REG13</name><description>Application-defined</description><addressOffset>0x34</addressOffset></register> |
<register><name>REG14</name><description>Application-defined</description><addressOffset>0x38</addressOffset></register> |
<register><name>REG15</name><description>Application-defined</description><addressOffset>0x3C</addressOffset></register> |
<register><name>REG16</name><description>Application-defined</description><addressOffset>0x40</addressOffset></register> |
<register><name>REG17</name><description>Application-defined</description><addressOffset>0x44</addressOffset></register> |
<register><name>REG18</name><description>Application-defined</description><addressOffset>0x48</addressOffset></register> |
<register><name>REG19</name><description>Application-defined</description><addressOffset>0x4C</addressOffset></register> |
<register><name>REG20</name><description>Application-defined</description><addressOffset>0x50</addressOffset></register> |
<register><name>REG21</name><description>Application-defined</description><addressOffset>0x54</addressOffset></register> |
<register><name>REG22</name><description>Application-defined</description><addressOffset>0x58</addressOffset></register> |
<register><name>REG23</name><description>Application-defined</description><addressOffset>0x5C</addressOffset></register> |
<register><name>REG24</name><description>Application-defined</description><addressOffset>0x60</addressOffset></register> |
<register><name>REG25</name><description>Application-defined</description><addressOffset>0x64</addressOffset></register> |
<register><name>REG26</name><description>Application-defined</description><addressOffset>0x68</addressOffset></register> |
<register><name>REG27</name><description>Application-defined</description><addressOffset>0x6C</addressOffset></register> |
<register><name>REG28</name><description>Application-defined</description><addressOffset>0x70</addressOffset></register> |
<register><name>REG29</name><description>Application-defined</description><addressOffset>0x74</addressOffset></register> |
<register><name>REG30</name><description>Application-defined</description><addressOffset>0x78</addressOffset></register> |
<register><name>REG31</name><description>Application-defined</description><addressOffset>0x7C</addressOffset></register> |
</registers> |
</peripheral> |
|
<!-- PWM --> |
<peripheral> |
<name>PWM</name> |
<description>Pulse-width modulation controller</description> |
<groupName>PWM</groupName> |
<baseAddress>0xFFFFFE80</baseAddress> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x40</size> |
<usage>registers</usage> |
</addressBlock> |
|
<registers> |
<register> |
<name>CTRL</name> |
<description>Control register</description> |
<addressOffset>0x00</addressOffset> |
<fields> |
<field> |
<name>PWM_CTRL_EN</name> |
<bitRange>[0:0]</bitRange> |
<description>PWM controller enable flag</description> |
</field> |
<field> |
<name>PWM_CTRL_PRSCx</name> |
<bitRange>[3:1]</bitRange> |
<description>Clock prescaler select</description> |
</field> |
</fields> |
</register> |
<register> |
<name>DUTY0</name> |
<description>Duty cycle register 0</description> |
<addressOffset>0x04</addressOffset> |
</register> |
<register> |
<name>DUTY1</name> |
<description>Duty cycle register 1</description> |
<addressOffset>0x08</addressOffset> |
</register> |
<register> |
<name>DUTY2</name> |
<description>Duty cycle register 2</description> |
<addressOffset>0x0C</addressOffset> |
</register> |
<register> |
<name>DUTY3</name> |
<description>Duty cycle register 3</description> |
<addressOffset>0x10</addressOffset> |
</register> |
<register> |
<name>DUTY4</name> |
<description>Duty cycle register 4</description> |
<addressOffset>0x14</addressOffset> |
</register> |
<register> |
<name>DUTY5</name> |
<description>Duty cycle register 5</description> |
<addressOffset>0x18</addressOffset> |
</register> |
<register> |
<name>DUTY6</name> |
<description>Duty cycle register 6</description> |
<addressOffset>0x1C</addressOffset> |
</register> |
<register> |
<name>DUTY7</name> |
<description>Duty cycle register 7</description> |
<addressOffset>0x20</addressOffset> |
</register> |
<register> |
<name>DUTY8</name> |
<description>Duty cycle register 8</description> |
<addressOffset>0x24</addressOffset> |
</register> |
<register> |
<name>DUTY9</name> |
<description>Duty cycle register 9</description> |
<addressOffset>0x28</addressOffset> |
</register> |
<register> |
<name>DUTY10</name> |
<description>Duty cycle register 10</description> |
<addressOffset>0x2C</addressOffset> |
</register> |
<register> |
<name>DUTY11</name> |
<description>Duty cycle register 11</description> |
<addressOffset>0x30</addressOffset> |
</register> |
<register> |
<name>DUTY12</name> |
<description>Duty cycle register 12</description> |
<addressOffset>0x34</addressOffset> |
</register> |
<register> |
<name>DUTY13</name> |
<description>Duty cycle register 13</description> |
<addressOffset>0x38</addressOffset> |
</register> |
<register> |
<name>DUTY14</name> |
<description>Duty cycle register 14</description> |
<addressOffset>0x3C</addressOffset> |
</register> |
</registers> |
</peripheral> |
|
<!-- SLINK --> |
<peripheral> |
<name>SLINK</name> |
<description>Stream link interface</description> |
<groupName>SLINK</groupName> |
<baseAddress>0xFFFFFEC0</baseAddress> |
|
<interrupt><name>SLINK_RX_FIRQ</name><value>10</value></interrupt> |
<interrupt><name>SLINK_TX_FIRQ</name><value>11</value></interrupt> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x40</size> |
<usage>registers</usage> |
</addressBlock> |
|
<registers> |
<register> |
<name>CTRL</name> |
<description>Control register</description> |
<addressOffset>0x00</addressOffset> |
<fields> |
<field> |
<name>SLINK_CTRL_RX_NUMx</name> |
<access>read-only</access> |
<bitRange>[3:0]</bitRange> |
<description>Number of implemented RX links</description> |
</field> |
<field> |
<name>SLINK_CTRL_TX_NUMx</name> |
<access>read-only</access> |
<bitRange>[7:4]</bitRange> |
<description>Number of implemented TX links</description> |
</field> |
<field> |
<name>SLINK_CTRL_RX_FIFO_Sx</name> |
<access>read-only</access> |
<bitRange>[11:8]</bitRange> |
<description>log2(RX FIFO size)</description> |
</field> |
<field> |
<name>SLINK_CTRL_TX_FIFO_Sx</name> |
<access>read-only</access> |
<bitRange>[15:12]</bitRange> |
<description>log2(TX FIFO size)</description> |
</field> |
<field> |
<name>SLINK_CTRL_EN</name> |
<access>read-write</access> |
<bitRange>[31:31]</bitRange> |
<description>SLINK enable flag</description> |
</field> |
</fields> |
</register> |
<register> |
<name>IRQ</name> |
<description>Link interrupt configuration register</description> |
<addressOffset>0x08</addressOffset> |
<fields> |
<field> |
<name>SLINK_IRQ_RX_EN</name> |
<bitRange>[7:0]</bitRange> |
<description>RX link interrupt enable</description> |
</field> |
<field> |
<name>SLINK_IRQ_RX_MODE</name> |
<bitRange>[15:8]</bitRange> |
<description>RX link interrupt mode</description> |
</field> |
<field> |
<name>SLINK_IRQ_TX_EN</name> |
<bitRange>[23:16]</bitRange> |
<description>TX link interrupt enable</description> |
</field> |
<field> |
<name>SLINK_IRQ_TX_MODE</name> |
<bitRange>[31:24]</bitRange> |
<description>TX link interrupt mode</description> |
</field> |
</fields> |
</register> |
<register> |
<name>STATUS</name> |
<description>Link status register</description> |
<addressOffset>0x10</addressOffset> |
<fields> |
<field> |
<name>SLINK_STATUS_RX_AVAIL</name> |
<bitRange>[7:0]</bitRange> |
<description>RX link n FIFO is NOT empty (data available)</description> |
</field> |
<field> |
<name>SLINK_STATUS_TX_FREE</name> |
<bitRange>[15:8]</bitRange> |
<description>TX link n FIFO is NOT full (ready to send)</description> |
</field> |
<field> |
<name>SLINK_STATUS_RX_HALF</name> |
<bitRange>[23:16]</bitRange> |
<description>RX link n FIFO fill level is >= half-full</description> |
</field> |
<field> |
<name>SLINK_STATUS_TX_HALF</name> |
<bitRange>[31:24]</bitRange> |
<description>TX link 0 FIFO fill level is > half-full</description> |
</field> |
</fields> |
</register> |
<register> |
<name>DATA0</name> |
<description>Link 0 RTX data register</description> |
<addressOffset>0x20</addressOffset> |
</register> |
<register> |
<name>DATA1</name> |
<description>Link 1 RTX data register</description> |
<addressOffset>0x24</addressOffset> |
</register> |
<register> |
<name>DATA2</name> |
<description>Link 2 RTX data register</description> |
<addressOffset>0x28</addressOffset> |
</register> |
<register> |
<name>DATA3</name> |
<description>Link 3 RTX data register</description> |
<addressOffset>0x2C</addressOffset> |
</register> |
<register> |
<name>DATA4</name> |
<description>Link 4 RTX data register</description> |
<addressOffset>0x30</addressOffset> |
</register> |
<register> |
<name>DATA5</name> |
<description>Link 5 RTX data register</description> |
<addressOffset>0x34</addressOffset> |
</register> |
<register> |
<name>DATA6</name> |
<description>Link 6 RTX data register</description> |
<addressOffset>0x38</addressOffset> |
</register> |
<register> |
<name>DATA7</name> |
<description>Link 7 RTX data register</description> |
<addressOffset>0x3C</addressOffset> |
</register> |
</registers> |
</peripheral> |
|
<!-- GPTMR --> |
<peripheral> |
<name>GPTMR</name> |
<description>General purpose timer</description> |
<groupName>GPTMR</groupName> |
<baseAddress>0xFFFFFF60</baseAddress> |
|
<interrupt><name>GPTMR_FIRQ</name><value>12</value></interrupt> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x10</size> |
<usage>registers</usage> |
</addressBlock> |
|
<registers> |
<register> |
<name>CTRL</name> |
<description>Control register</description> |
<addressOffset>0x00</addressOffset> |
<fields> |
<field> |
<name>GPTMR_CTRL_EN</name> |
<bitRange>[0:0]</bitRange> |
<description>Timer enable flag</description> |
</field> |
<field> |
<name>GPTMR_CTRL_PRSC</name> |
<bitRange>[3:1]</bitRange> |
<description>Clock prescaler select</description> |
</field> |
<field> |
<name>GPTMR_CTRL_MODE</name> |
<bitRange>[4:4]</bitRange> |
<description>Timer mode: 0=single-shot mode, 1=continuous mode</description> |
</field> |
</fields> |
</register> |
<register> |
<name>THRES</name> |
<description>Threshold register</description> |
<addressOffset>0x04</addressOffset> |
</register> |
<register> |
<name>COUNT</name> |
<description>Counter register</description> |
<addressOffset>0x08</addressOffset> |
</register> |
</registers> |
</peripheral> |
|
<!-- BUSKEEPER --> |
<peripheral> |
<name>BUSKEEPER</name> |
<description>Bus keeper</description> |
<groupName>BUSKEEPER</groupName> |
<baseAddress>0xFFFFFF7C</baseAddress> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x04</size> |
<usage>registers</usage> |
</addressBlock> |
|
<registers> |
<register> |
<name>CTRL</name> |
<description>Control register</description> |
<addressOffset>0x00</addressOffset> |
<fields> |
<field> |
<name>BUSKEEPER_ERR_TYPE</name> |
<bitRange>[0:0]</bitRange> |
<access>read-only</access> |
<description>Bus error type: 0=device error, 1=access timeout</description> |
</field> |
<field> |
<name>BUSKEEPER_ERR_FLAG</name> |
<bitRange>[31:31]</bitRange> |
<description>Sticky error flag, clears after read or write access</description> |
</field> |
</fields> |
</register> |
</registers> |
</peripheral> |
|
<!-- XIRQ --> |
<peripheral> |
<name>XIRQ</name> |
<description>External interrupts controller</description> |
<groupName>XIRQ</groupName> |
<baseAddress>0xFFFFFF80</baseAddress> |
|
<interrupt><name>XIRQ_FIRQ</name><value>8</value></interrupt> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x10</size> |
<usage>registers</usage> |
</addressBlock> |
|
<registers> |
<register> |
<name>IER</name> |
<description>IRQ input enable register</description> |
<addressOffset>0x00</addressOffset> |
</register> |
<register> |
<name>IPR</name> |
<description>IRQ pending/ack/clear register</description> |
<addressOffset>0x04</addressOffset> |
</register> |
<register> |
<name>SCR</name> |
<description>IRQ source register</description> |
<addressOffset>0x08</addressOffset> |
</register> |
</registers> |
</peripheral> |
|
<!-- MTIME --> |
<peripheral> |
<name>MTIME</name> |
<description>Machine timer</description> |
<groupName>MTIME</groupName> |
<baseAddress>0xFFFFFF90</baseAddress> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x10</size> |
<usage>registers</usage> |
</addressBlock> |
|
<registers> |
<register> |
<name>TIME_LO</name> |
<description>System time register - low</description> |
<addressOffset>0x00</addressOffset> |
</register> |
<register> |
<name>TIME_HI</name> |
<description>System time register - high</description> |
<addressOffset>0x04</addressOffset> |
</register> |
<register> |
<name>TIMECMP_LO</name> |
<description>Time compare register - low</description> |
<addressOffset>0x08</addressOffset> |
</register> |
<register> |
<name>TIMECMP_HI</name> |
<description>Time compare register - high</description> |
<addressOffset>0x0C</addressOffset> |
</register> |
</registers> |
</peripheral> |
|
<!-- UART0 --> |
<peripheral> |
<name>UART0</name> |
<description>Primary universal asynchronous receiver and transmitter</description> |
<groupName>UART0</groupName> |
<baseAddress>0xFFFFFFA0</baseAddress> |
|
<interrupt><name>UART0_RX_FIRQ</name><value>2</value></interrupt> |
<interrupt><name>UART0_TX_FIRQ</name><value>3</value></interrupt> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x08</size> |
<usage>registers</usage> |
</addressBlock> |
|
<registers> |
<register> |
<name>CTRL</name> |
<description>Control register</description> |
<addressOffset>0x00</addressOffset> |
<fields> |
<field> |
<name>UART_CTRL_BAUD</name> |
<bitRange>[11:0]</bitRange> |
<description>Baud rate divisor</description> |
</field> |
<field> |
<name>UART_CTRL_SIM_MODE</name> |
<bitRange>[12:12]</bitRange> |
<description>Simulation output override enable, for use in simulation only</description> |
</field> |
<field> |
<name>UART_CTRL_RX_EMPTY</name> |
<bitRange>[13:13]</bitRange> |
<access>read-only</access> |
<description>RX FIFO is empty</description> |
</field> |
<field> |
<name>UART_CTRL_RX_HALF</name> |
<bitRange>[14:14]</bitRange> |
<access>read-only</access> |
<description>RX FIFO is at least half-full</description> |
</field> |
<field> |
<name>UART_CTRL_RX_FULL</name> |
<bitRange>[15:15]</bitRange> |
<access>read-only</access> |
<description>RX FIFO is full</description> |
</field> |
<field> |
<name>UART_CTRL_TX_EMPTY</name> |
<bitRange>[16:16]</bitRange> |
<access>read-only</access> |
<description>TX FIFO is empty</description> |
</field> |
<field> |
<name>UART_CTRL_TX_HALF</name> |
<bitRange>[17:17]</bitRange> |
<access>read-only</access> |
<description>TX FIFO is at least half-full</description> |
</field> |
<field> |
<name>UART_CTRL_TX_FULL</name> |
<bitRange>[18:18]</bitRange> |
<access>read-only</access> |
<description>TX FIFO is full</description> |
</field> |
<field> |
<name>UART_CTRL_RTS_EN</name> |
<bitRange>[20:20]</bitRange> |
<description>Enable hardware flow control: Assert RTS output if UART.RX is ready to receive</description> |
</field> |
<field> |
<name>UART_CTRL_CTS_EN</name> |
<bitRange>[21:21]</bitRange> |
<description>Enable hardware flow control: UART.TX starts sending only if CTS input is asserted</description> |
</field> |
<field> |
<name>UART_CTRL_PMODE0</name> |
<bitRange>[22:22]</bitRange> |
<description>Parity configuration (0=even; 1=odd)</description> |
</field> |
<field> |
<name>UART_CTRL_PMODE1</name> |
<bitRange>[23:23]</bitRange> |
<description>Parity bit enabled when set</description> |
</field> |
<field> |
<name>UART_CTRL_PRSC</name> |
<bitRange>[26:24]</bitRange> |
<description>Clock prescaler select</description> |
</field> |
<field> |
<name>UART_CTRL_CTS</name> |
<bitRange>[27:27]</bitRange> |
<access>read-only</access> |
<description>current state of CTS input</description> |
</field> |
<field> |
<name>UART_CTRL_EN</name> |
<bitRange>[28:28]</bitRange> |
<description>UART enable flag</description> |
</field> |
<field> |
<name>UART_CTRL_RX_IRQ</name> |
<bitRange>[29:29]</bitRange> |
<description>RX IRQ mode: 1=FIFO at least half-full; 0=FIFO not empty</description> |
</field> |
<field> |
<name>UART_CTRL_TX_IRQ</name> |
<bitRange>[30:30]</bitRange> |
<description>TX IRQ mode: 1=FIFO less than half-full; 0=FIFO not full</description> |
</field> |
<field> |
<name>UART_CTRL_TX_BUSY</name> |
<bitRange>[31:31]</bitRange> |
<access>read-only</access> |
<description>Transmitter is busy when set</description> |
</field> |
</fields> |
</register> |
<register> |
<name>DATA</name> |
<description>RX/TX data register</description> |
<addressOffset>0x04</addressOffset> |
<fields> |
<field> |
<name>UART_DATA</name> |
<bitRange>[7:0]</bitRange> |
<description>Receive/transmit data</description> |
</field> |
<field> |
<name>UART_DATA_PERR</name> |
<bitRange>[28:28]</bitRange> |
<access>read-only</access> |
<description>RX parity error detected when set</description> |
</field> |
<field> |
<name>UART_DATA_FERR</name> |
<bitRange>[29:29]</bitRange> |
<access>read-only</access> |
<description>RX frame error (no valid stop bit) detected when set</description> |
</field> |
<field> |
<name>UART_DATA_OVERR</name> |
<bitRange>[30:30]</bitRange> |
<access>read-only</access> |
<description>RX parity error detected when set</description> |
</field> |
<field> |
<name>UART_DATA_AVAIL</name> |
<bitRange>[31:31]</bitRange> |
<access>read-only</access> |
<description>RX data available when set</description> |
</field> |
</fields> |
</register> |
</registers> |
</peripheral> |
|
<!-- UART1 --> |
<peripheral derivedFrom="UART0"> |
<name>UART1</name> |
<description>Secondary universal asynchronous receiver and transmitter</description> |
<groupName>UART1</groupName> |
<baseAddress>0xFFFFFFD0</baseAddress> |
|
<interrupt><name>UART1_RX_FIRQ</name><value>4</value></interrupt> |
<interrupt><name>UART1_TX_FIRQ</name><value>5</value></interrupt> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x08</size> |
<usage>registers</usage> |
</addressBlock> |
|
</peripheral> |
|
<!-- SPI --> |
<peripheral> |
<name>SPI</name> |
<description>Serial peripheral interface controller</description> |
<groupName>SPI</groupName> |
<baseAddress>0xFFFFFFA8</baseAddress> |
|
<interrupt><name>SPI_FIRQ</name><value>6</value></interrupt> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x08</size> |
<usage>registers</usage> |
</addressBlock> |
|
<registers> |
<register> |
<name>CTRL</name> |
<description>Control register</description> |
<addressOffset>0x00</addressOffset> |
<fields> |
<field> |
<name>SPI_CTRL_CS</name> |
<bitRange>[7:0]</bitRange> |
<description>Direct chip select line</description> |
</field> |
<field> |
<name>SPI_CTRL_EN</name> |
<bitRange>[8:8]</bitRange> |
<description>SPI enable flag</description> |
</field> |
<field> |
<name>SPI_CTRL_CPHA</name> |
<bitRange>[9:9]</bitRange> |
<description>Clock phase</description> |
</field> |
<field> |
<name>SPI_CTRL_PRSC</name> |
<bitRange>[12:10]</bitRange> |
<description>Clock prescaler select</description> |
</field> |
<field> |
<name>SPI_CTRL_SIZE</name> |
<bitRange>[14:13]</bitRange> |
<description>Data transfer size</description> |
</field> |
<field> |
<name>SPI_CTRL_CPOL</name> |
<bitRange>[15:15]</bitRange> |
<description>Clock polarity</description> |
</field> |
<field> |
<name>SPI_CTRL_BUSY</name> |
<bitRange>[31:31]</bitRange> |
<access>read-only</access> |
<description>SPI busy flag</description> |
</field> |
</fields> |
</register> |
<register> |
<name>DATA</name> |
<description>RX/TX data register</description> |
<addressOffset>0x04</addressOffset> |
</register> |
</registers> |
</peripheral> |
|
<!-- TWI --> |
<peripheral> |
<name>TWI</name> |
<description>Two-wire interface controller</description> |
<groupName>SPI</groupName> |
<baseAddress>0xFFFFFFB0</baseAddress> |
|
<interrupt><name>TWI_FIRQ</name><value>7</value></interrupt> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x08</size> |
<usage>registers</usage> |
</addressBlock> |
|
<registers> |
<register> |
<name>CTRL</name> |
<description>Control register</description> |
<addressOffset>0x00</addressOffset> |
<fields> |
<field> |
<name>TWI_CTRL_EN</name> |
<bitRange>[0:0]</bitRange> |
<description>TWI enable flag</description> |
</field> |
<field> |
<name>TWI_CTRL_START</name> |
<bitRange>[1:1]</bitRange> |
<description>Generate START condition, auto-clears</description> |
</field> |
<field> |
<name>TWI_CTRL_STOP</name> |
<bitRange>[2:2]</bitRange> |
<description>Generate STOP condition, auto-clears</description> |
</field> |
<field> |
<name>TWI_CTRL_PRSC</name> |
<bitRange>[5:3]</bitRange> |
<description>Clock prescaler select</description> |
</field> |
<field> |
<name>TWI_CTRL_MACK</name> |
<bitRange>[6:6]</bitRange> |
<description>Generate ACK by controller for each transmission</description> |
</field> |
<field> |
<name>TWI_CTRL_ACK</name> |
<bitRange>[30:30]</bitRange> |
<access>read-only</access> |
<description>ACK received when set</description> |
</field> |
<field> |
<name>TWI_CTRL_BUSY</name> |
<bitRange>[31:31]</bitRange> |
<access>read-only</access> |
<description>Transfer in progress, busy flag</description> |
</field> |
</fields> |
</register> |
<register> |
<name>DATA</name> |
<description>RX/TX data register</description> |
<addressOffset>0x04</addressOffset> |
<fields> |
<field> |
<name>TWI_DATA</name> |
<bitRange>[7:0]</bitRange> |
<description>RX/TX data</description> |
</field> |
</fields> |
</register> |
</registers> |
</peripheral> |
|
<!-- TRNG --> |
<peripheral> |
<name>TRNG</name> |
<description>True random number generator</description> |
<groupName>TRNG</groupName> |
<baseAddress>0xFFFFFFB8</baseAddress> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x04</size> |
<usage>registers</usage> |
</addressBlock> |
|
<registers> |
<register> |
<name>CTRL</name> |
<description>Control and data register</description> |
<addressOffset>0x00</addressOffset> |
<fields> |
<field> |
<name>TRNG_CTRL_DATA</name> |
<bitRange>[7:0]</bitRange> |
<access>read-only</access> |
<description>Random data</description> |
</field> |
<field> |
<name>TRNG_CTRL_EN</name> |
<bitRange>[30:30]</bitRange> |
<description>TRNG enable flag</description> |
</field> |
<field> |
<name>TRNG_CTRL_VALID</name> |
<bitRange>[31:31]</bitRange> |
<access>read-only</access> |
<description>Random data output valid</description> |
</field> |
</fields> |
</register> |
</registers> |
</peripheral> |
|
<!-- WDT --> |
<peripheral> |
<name>WDT</name> |
<description>Watchdog timer</description> |
<groupName>WDT</groupName> |
<baseAddress>0xFFFFFFBC</baseAddress> |
|
<interrupt><name>WDT_FIRQ</name><value>0</value></interrupt> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x04</size> |
<usage>registers</usage> |
</addressBlock> |
|
<registers> |
<register> |
<name>CTRL</name> |
<description>Control register</description> |
<addressOffset>0x00</addressOffset> |
<fields> |
<field> |
<name>WDT_CTRL_EN</name> |
<bitRange>[0:0]</bitRange> |
<description>WDT enable flag</description> |
</field> |
<field> |
<name>WDT_CTRL_CLK_SEL</name> |
<bitRange>[3:1]</bitRange> |
<description>Clock prescaler select</description> |
</field> |
<field> |
<name>WDT_CTRL_MODE</name> |
<bitRange>[4:4]</bitRange> |
<description>Watchdog mode: 0=timeout causes interrupt, 1=timeout causes processor reset</description> |
</field> |
<field> |
<name>WDT_CTRL_RCAUSE</name> |
<bitRange>[5:5]</bitRange> |
<access>read-only</access> |
<description>Cause of last system reset: 0=external reset, 1=watchdog</description> |
</field> |
<field> |
<name>WDT_CTRL_RESET</name> |
<bitRange>[6:6]</bitRange> |
<description>Reset WDT counter when set, auto-clears</description> |
</field> |
<field> |
<name>WDT_CTRL_FORCE</name> |
<bitRange>[7:7]</bitRange> |
<description>Force WDT action, auto-clears</description> |
</field> |
<field> |
<name>WDT_CTRL_LOCK</name> |
<bitRange>[8:8]</bitRange> |
<description>Lock write access to control register, clears on reset (HW or WDT) only</description> |
</field> |
<field> |
<name>WDT_CTRL_DBEN</name> |
<bitRange>[9:9]</bitRange> |
<description>Allow WDT to continue operation even when in debug mode</description> |
</field> |
<field> |
<name>WDT_CTRL_HALF</name> |
<bitRange>[10:10]</bitRange> |
<access>read-only</access> |
<description>Set if at least half of the max. timeout counter value has been reached</description> |
</field> |
</fields> |
</register> |
</registers> |
</peripheral> |
|
<!-- GPIO --> |
<peripheral> |
<name>GPIO</name> |
<description>General purpose input/output port</description> |
<groupName>GPIO</groupName> |
<baseAddress>0xFFFFFFc0</baseAddress> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x10</size> |
<usage>registers</usage> |
</addressBlock> |
|
<registers> |
<register> |
<name>INPUT_LO</name> |
<description>Parallel input register - low</description> |
<addressOffset>0x00</addressOffset> |
<access>read-only</access> |
</register> |
<register> |
<name>INPUT_HI</name> |
<description>Parallel input register - high</description> |
<addressOffset>0x04</addressOffset> |
<access>read-only</access> |
</register> |
<register> |
<name>OUTPUT_LO</name> |
<description>Parallel output register - low</description> |
<addressOffset>0x08</addressOffset> |
</register> |
<register> |
<name>OUTPUT_HI</name> |
<description>Parallel output register - high</description> |
<addressOffset>0x0C</addressOffset> |
</register> |
</registers> |
</peripheral> |
|
<!-- NEOLED --> |
<peripheral> |
<name>NEOLED</name> |
<description>Smart LED hardware interface</description> |
<groupName>NEOLED</groupName> |
<baseAddress>0xFFFFFFD8</baseAddress> |
|
<interrupt><name>NEOLED_FIRQ</name><value>9</value></interrupt> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x08</size> |
<usage>registers</usage> |
</addressBlock> |
|
<registers> |
<register> |
<name>CTRL</name> |
<description>Control register</description> |
<addressOffset>0x00</addressOffset> |
<fields> |
<field> |
<name>NEOLED_CTRL_EN</name> |
<bitRange>[0:0]</bitRange> |
<description>NEOLED enable flag</description> |
</field> |
<field> |
<name>NEOLED_CTRL_MODE</name> |
<bitRange>[1:1]</bitRange> |
<description>TX mode (0=24-bit, 1=32-bit)</description> |
</field> |
<field> |
<name>NEOLED_CTRL_STROBE</name> |
<bitRange>[2:2]</bitRange> |
<description>Strobe (0=send normal data, 1=send RESET command on data write)</description> |
</field> |
<field> |
<name>NEOLED_CTRL_PRSC</name> |
<bitRange>[5:3]</bitRange> |
<description>Clock prescaler select</description> |
</field> |
<field> |
<name>NEOLED_CTRL_BUFS</name> |
<bitRange>[9:6]</bitRange> |
<access>read-only</access> |
<description>log2(tx buffer size)</description> |
</field> |
<field> |
<name>NEOLED_CTRL_T_TOT</name> |
<bitRange>[14:10]</bitRange> |
<description>pulse-clock ticks per total period bit</description> |
</field> |
<field> |
<name>NEOLED_CTRL_T_ZERO_H</name> |
<bitRange>[19:15]</bitRange> |
<description>pulse-clock ticks per ZERO high-time</description> |
</field> |
<field> |
<name>NEOLED_CTRL_T_ONE_H</name> |
<bitRange>[24:20]</bitRange> |
<description>pulse-clock ticks per ONE high-time</description> |
</field> |
<field> |
<name>NEOLED_CTRL_IRQ_CONF</name> |
<bitRange>[27:27]</bitRange> |
<description>TX FIFO interrupt: 0=IRQ if FIFO is less than half-full, 1=IRQ if FIFO is empty</description> |
</field> |
<field> |
<name>NEOLED_CTRL_TX_EMPTY</name> |
<bitRange>[28:28]</bitRange> |
<access>read-only</access> |
<description>TX FIFO is empty</description> |
</field> |
<field> |
<name>NEOLED_CTRL_TX_HALF</name> |
<bitRange>[29:29]</bitRange> |
<access>read-only</access> |
<description>TX FIFO is at least half-full</description> |
</field> |
<field> |
<name>NEOLED_CTRL_TX_FULL</name> |
<bitRange>[30:30]</bitRange> |
<access>read-only</access> |
<description>TX FIFO is full</description> |
</field> |
<field> |
<name>NEOLED_CTRL_TX_BUSY</name> |
<bitRange>[31:31]</bitRange> |
<access>read-only</access> |
<description>busy flag</description> |
</field> |
</fields> |
</register> |
<register> |
<name>DATA</name> |
<description>Data register</description> |
<addressOffset>0x04</addressOffset> |
</register> |
</registers> |
</peripheral> |
|
<!-- SYSINFO --> |
<peripheral> |
<name>SYSINFO</name> |
<description>System configuration information memory</description> |
<groupName>SYSINFO</groupName> |
<baseAddress>0xFFFFFFE0</baseAddress> |
|
<addressBlock> |
<offset>0</offset> |
<size>0x20</size> |
<usage>registers</usage> |
</addressBlock> |
|
<registers> |
<register> |
<name>CLK</name> |
<description>Clock speed in Hz</description> |
<addressOffset>0x00</addressOffset> |
<access>read-only</access> |
</register> |
<register> |
<name>CPU</name> |
<description>CPU core features</description> |
<addressOffset>0x04</addressOffset> |
<access>read-only</access> |
<fields> |
<field><name>SYSINFO_CPU_ZICSR</name><bitRange>[0:0]</bitRange><description>Zicsr extension (I sub-extension) available when set</description></field> |
<field><name>SYSINFO_CPU_ZIFENCEI</name><bitRange>[1:1]</bitRange><description>Zifencei extension (I sub-extension) available when set</description></field> |
<field><name>SYSINFO_CPU_ZMMUL</name><bitRange>[2:2]</bitRange><description>Zmmul extension (M sub-extension) available when set</description></field> |
<field><name>SYSINFO_CPU_ZFINX</name><bitRange>[5:5]</bitRange><description>Zfinx extension (F sub-/alternative-extension) available when set</description></field> |
<field><name>SYSINFO_CPU_ZXSCNT</name><bitRange>[6:6]</bitRange><description>Custom extension - Small CPU counters</description></field> |
<field><name>SYSINFO_CPU_ZICNTR</name><bitRange>[7:7]</bitRange><description>Basic CPU counters available when set</description></field> |
<field><name>SYSINFO_CPU_PMP</name><bitRange>[8:8]</bitRange><description>PMP (physical memory protection) extension available when set</description></field> |
<field><name>SYSINFO_CPU_ZIHPM</name><bitRange>[9:9]</bitRange><description>HPM (hardware performance monitors) extension available when set</description></field> |
<field><name>SYSINFO_CPU_DEBUGMODE</name><bitRange>[10:10]</bitRange><description>RISC-V CPU debug mode available when set</description></field> |
<field><name>SYSINFO_CPU_FASTMUL</name><bitRange>[30:30]</bitRange><description>fast multiplications (via FAST_MUL_EN generic) available when set</description></field> |
<field><name>SYSINFO_CPU_FASTSHIFT</name><bitRange>[31:31]</bitRange><description>fast shifts (via FAST_SHIFT_EN generic) available when set</description></field> |
</fields> |
</register> |
<register> |
<name>SOC</name> |
<description>SoC features</description> |
<addressOffset>0x08</addressOffset> |
<access>read-only</access> |
<fields> |
<field><name>SYSINFO_SOC_BOOTLOADER</name><bitRange>[0:0]</bitRange><description>Bootloader implemented</description></field> |
<field><name>SYSINFO_SOC_MEM_EXT</name><bitRange>[1:1]</bitRange><description>External bus interface implemented</description></field> |
<field><name>SYSINFO_SOC_MEM_INT_IMEM</name><bitRange>[2:2]</bitRange><description>Processor-internal instruction memory implemented</description></field> |
<field><name>SYSINFO_SOC_MEM_INT_DMEM</name><bitRange>[3:3]</bitRange><description>Processor-internal data memory implemented</description></field> |
<field><name>SYSINFO_SOC_MEM_EXT_ENDIAN</name><bitRange>[4:4]</bitRange><description>External bus interface uses BIG-endian byte-order</description></field> |
<field><name>SYSINFO_SOC_ICACHE</name><bitRange>[5:5]</bitRange><description>Processor-internal instruction cache implemented</description></field> |
<field><name>SYSINFO_SOC_IS_SIM</name><bitRange>[13:13]</bitRange><description>Set if processor is being simulated</description></field> |
<field><name>SYSINFO_SOC_OCD</name><bitRange>[14:14]</bitRange><description>On-chip debugger implemented</description></field> |
<field><name>SYSINFO_SOC_HW_RESET</name><bitRange>[15:15]</bitRange><description>Dedicated hardware reset of core registers implemented</description></field> |
<field><name>SYSINFO_SOC_IO_GPIO</name><bitRange>[16:16]</bitRange><description>General purpose input/output port unit implemented</description></field> |
<field><name>SYSINFO_SOC_IO_MTIME</name><bitRange>[17:17]</bitRange><description>Machine system timer implemented</description></field> |
<field><name>SYSINFO_SOC_IO_UART0</name><bitRange>[18:18]</bitRange><description>Primary universal asynchronous receiver/transmitter 0 implemented</description></field> |
<field><name>SYSINFO_SOC_IO_SPI</name><bitRange>[19:19]</bitRange><description>Serial peripheral interface implemented</description></field> |
<field><name>SYSINFO_SOC_IO_TWI</name><bitRange>[20:20]</bitRange><description>Two-wire interface implemented</description></field> |
<field><name>SYSINFO_SOC_IO_PWM</name><bitRange>[21:21]</bitRange><description>Pulse-width modulation unit implemented</description></field> |
<field><name>SYSINFO_SOC_IO_WDT</name><bitRange>[22:22]</bitRange><description>Watchdog timer implemented</description></field> |
<field><name>SYSINFO_SOC_IO_CFS</name><bitRange>[23:23]</bitRange><description>Custom functions subsystem implemented</description></field> |
<field><name>SYSINFO_SOC_IO_TRNG</name><bitRange>[24:24]</bitRange><description>True random number generator implemented</description></field> |
<field><name>SYSINFO_SOC_IO_SLINK</name><bitRange>[25:25]</bitRange><description>Stream link interface implemented</description></field> |
<field><name>SYSINFO_SOC_IO_UART1</name><bitRange>[26:26]</bitRange><description>Secondary universal asynchronous receiver/transmitter 1 implemented</description></field> |
<field><name>SYSINFO_SOC_IO_NEOLED</name><bitRange>[27:27]</bitRange><description>NeoPixel-compatible smart LED interface implemented</description></field> |
<field><name>SYSINFO_SOC_IO_XIRQ</name><bitRange>[28:28]</bitRange><description>External interrupt controller implemented</description></field> |
<field><name>SYSINFO_SOC_IO_GPTMR</name><bitRange>[29:29]</bitRange><description>General purpose timer implemented</description></field> |
</fields> |
</register> |
<register> |
<name>CACHE</name> |
<description>Cache configuration</description> |
<addressOffset>0x0C</addressOffset> |
<access>read-only</access> |
<fields> |
<field><name>SYSINFO_CACHE_IC_BLOCK_SIZE</name><bitRange>[3:0]</bitRange><description>i-cache: log2(Block size in bytes)</description></field> |
<field><name>SYSINFO_CACHE_IC_NUM_BLOCKS</name><bitRange>[7:4]</bitRange><description>i-cache: log2(Number of cache blocks/pages/lines)</description></field> |
<field><name>SYSINFO_CACHE_IC_ASSOCIATIVITY</name><bitRange>[11:8]</bitRange><description>i-cache: log2(associativity)</description></field> |
<field><name>SYSINFO_CACHE_IC_REPLACEMENT</name><bitRange>[15:12]</bitRange><description>i-cache: replacement policy (0001 = LRU if associativity > 0)</description></field> |
</fields> |
</register> |
<register> |
<name>ISPACE_BASE</name> |
<description>Instruction memory address space base address</description> |
<addressOffset>0x10</addressOffset> |
<access>read-only</access> |
</register> |
<register> |
<name>DSPACE_BASE</name> |
<description>Data memory address space base address</description> |
<addressOffset>0x14</addressOffset> |
<access>read-only</access> |
</register> |
<register> |
<name>IMEM_SIZE</name> |
<description>Internal instruction memory (IMEM) size in bytes</description> |
<addressOffset>0x18</addressOffset> |
<access>read-only</access> |
</register> |
<register> |
<name>DMEM_SIZE</name> |
<description>Internal data memory (DMEM) size in bytes</description> |
<addressOffset>0x1C</addressOffset> |
<access>read-only</access> |
</register> |
</registers> |
</peripheral> |
|
</peripherals> |
</device> |
/sw/README.md
48,3 → 48,8
## [openocd](openocd) |
|
Configuration file for openOCD to connect to the NEORV32 on-chip debugger via JTAG. |
|
|
## [svd](svd) |
|
Contains a CMSIS-SVD compatible system view description file including _all_ peripherals. |
/CHANGELOG.md
26,6 → 26,17
|
| Date (*dd.mm.yyyy*) | Version | Comment | |
|:----------:|:-------:|:--------| |
| 16.12.2021 |[**:rocket:1.6.5**](https://github.com/stnolting/neorv32/releases/tag/v1.6.5) | **New release** | |
| 15.12.2021 | 1.6.4.10 | minor logic optimization of CPU's pipeline front-end (instruction fetch and instruction issue) | |
| 14.12.2021 | 1.6.4.9 | optimized CPU's multiplication/division co-processor: divisions are 1 cycle faster, fast-multiplications (when using DSPs) are 1 cycle faster, slightly less resource utilization, see [PR #240](https://github.com/stnolting/neorv32/pull/240) | |
| 11.12.2021 | 1.6.4.8 | watchdog: added new _DBEN_ and _HALF_ flags to control register (enable WDT during debugging, check timeout counter level), see [PR #239](https://github.com/stnolting/neorv32/pull/239) | |
| 10.12.2021 | 1.6.4.7 | optimized CPU's multiplication/division co-processor: all mul/div operations are 1 cycle faster + slightly less resource utilization, see [PR #238](https://github.com/stnolting/neorv32/pull/238) | |
| 08.12.2021 | 1.6.4.6 | :warning: reworked **Fast Interrupt Requests (FIRQ)** system, see [PR #236](https://github.com/stnolting/neorv32/pull/236) | |
| 03.12.2021 | 1.6.4.5 | added _SYSINFO_SOC_IS_SIM_ flag to SYSINFO to check if processor is being simulated (not guaranteed, depends on the toolchain's 'pragma' support), see [PR #231](https://github.com/stnolting/neorv32/pull/231) | |
| 03.12.2021 | 1.6.4.4 | :bug: fixed bug in **Wishbone** bus interface: timeout configurations (via `MEM_EXT_TIMEOUT` generic) that are a power of two (e.g. 256) caused _immediate_ timeouts; timeout counter was one bit short; same problem for processor-internal bus monitor (BUSKEEPER); see [PR #230](https://github.com/stnolting/neorv32/pull/230) | |
| 02.12.2021 | 1.6.4.3 | :warning: removed legacy software compatibility wrappers (`sw/lib/include/neorv32_legacy.h` and `neorv32_uart_*` functions) | |
| 28.11.2021 | 1.6.4.2 | :bug: fixed bug in **UART[0/1]** overrun flag (was not set/cleared correctly); fixed bug in UART0 enable function `neorv32_uart0_enable()` | |
| 28.11.2021 | 1.6.4.1 | (:warning:) bootloader now stores executable in _little-endian_ byte-order to SPI flash | |
| 26.11.2021 |[**:rocket:1.6.4**](https://github.com/stnolting/neorv32/releases/tag/v1.6.4) | **New release** | |
| 22.11.2021 | 1.6.3.11 | on-chip debugger: reworked JTAG signal input/output synchronization logic (see [PR #216](https://github.com/stnolting/neorv32/pull/216)) | |
| 22.11.2021 | 1.6.3.10 | reworked **TRNG** (less hardware requirements, improved quality), see [PR #212](https://github.com/stnolting/neorv32/pull/212) and [stnolting/neoTRNG](https://github.com/stnolting/neoTRNG) | |
/CONTRIBUTING.md
1,8 → 1,9
# Contributing |
|
I'm always thankful for help! So if you have any questions, bug reports, ideas or if you want to give any kind of feedback, feel free |
to [open a new issue](https://github.com/stnolting/neorv32/issues), start a new |
[discussion on GitHub](https://github.com/stnolting/neorv32/discussions) or directly [drop me a line](mailto:stnolting@gmail.com). |
We're always thankful for help! So if you have any questions, bug reports, ideas or if you want to give any kind of feedback, feel free |
to [open a new issue](https://github.com/stnolting/neorv32/issues) or start a new [discussion](https://github.com/stnolting/neorv32/discussions). |
Also look out for issues and pull requests labeled with |
[![help-wanted](https://img.shields.io/badge/-help%20wanted-brightgreen)](https://github.com/stnolting/neorv32/labels/help%20wanted). |
|
:information_source: Please note we have a [Code of Conduct](https://github.com/stnolting/neorv32/tree/master/CODE_OF_CONDUCT.md), |
please follow it in all your interactions with the project. |
9,7 → 10,7
|
## Contributing Process |
|
Here is a simple guide line if you'd like to contribute to this project: |
Here is a simple guide line if you'd like to contribute code modifications to this project: |
|
0. :star: this repository :wink: |
1. Check out the project's [code of conduct](https://github.com/stnolting/neorv32/tree/master/CODE_OF_CONDUCT.md) |
/README.md
1,19 → 1,7
[![GitHub Pages](https://img.shields.io/website.svg?label=stnolting.github.io%2Fneorv32&longCache=true&style=flat-square&url=http%3A%2F%2Fstnolting.github.io%2Fneorv32%2Findex.html&logo=GitHub)](https://stnolting.github.io/neorv32) |
[![Documentation](https://img.shields.io/github/workflow/status/stnolting/neorv32/Documentation/master?longCache=true&style=flat-square&label=Documentation&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3ADocumentation) |
\ |
[![riscv-arch-test](https://img.shields.io/github/workflow/status/stnolting/neorv32/riscv-arch-test/master?longCache=true&style=flat-square&label=riscv-arch-test&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3Ariscv-arch-test) |
[![Processor](https://img.shields.io/github/workflow/status/stnolting/neorv32/Processor/master?longCache=true&style=flat-square&label=Processor&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3AProcessor) |
[![Implementation](https://img.shields.io/github/workflow/status/stnolting/neorv32/Implementation/master?longCache=true&style=flat-square&label=Implementation&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3AImplementation) |
[![Windows](https://img.shields.io/github/workflow/status/stnolting/neorv32/Windows/master?longCache=true&style=flat-square&label=Windows&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3AWindows) |
|
[![NEORV32](https://raw.githubusercontent.com/stnolting/neorv32/master/docs/figures/neorv32_logo_dark.png)](https://github.com/stnolting/neorv32) |
|
# The NEORV32 RISC-V Processor |
|
[![license](https://img.shields.io/github/license/stnolting/neorv32?longCache=true&style=flat-square)](https://github.com/stnolting/neorv32/blob/master/LICENSE) |
[![release](https://img.shields.io/github/v/release/stnolting/neorv32?longCache=true&style=flat-square&logo=GitHub)](https://github.com/stnolting/neorv32/releases) |
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5018888.svg)](https://doi.org/10.5281/zenodo.5018888) |
\ |
[![datasheet (pdf)](https://img.shields.io/badge/data%20sheet-PDF-ffbd00?longCache=true&style=flat-square&logo=asciidoctor)](https://github.com/stnolting/neorv32/releases/tag/nightly) |
[![datasheet (html)](https://img.shields.io/badge/-HTML-ffbd00?longCache=true&style=flat-square)](https://stnolting.github.io/neorv32) |
[![userguide (pdf)](https://img.shields.io/badge/user%20guide-PDF-ffbd00?longCache=true&style=flat-square&logo=asciidoctor)](https://github.com/stnolting/neorv32/releases/tag/nightly) |
22,13 → 10,14
[![Gitter](https://img.shields.io/badge/Chat-on%20gitter-4db797.svg?longCache=true&style=flat-square&logo=gitter&logoColor=e8ecef)](https://gitter.im/neorv32/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) |
|
1. [Overview](#1-Overview) |
1. [Key Features](#Project-Key-Features) |
* [Key Features](#Project-Key-Features) |
* [Status](#status) |
2. [Processor/SoC Features](#2-NEORV32-Processor-Features) |
1. [FPGA Implementation Results](#FPGA-Implementation-Results---Processor) |
* [FPGA Implementation Results](#FPGA-Implementation-Results---Processor) |
3. [CPU Features](#3-NEORV32-CPU-Features) |
1. [Available ISA Extensions](#Available-ISA-Extensions) |
2. [FPGA Implementation Results](#FPGA-Implementation-Results---CPU) |
3. [Performance](#Performance) |
* [Available ISA Extensions](#Available-ISA-Extensions) |
* [FPGA Implementation Results](#FPGA-Implementation-Results---CPU) |
* [Performance](#Performance) |
4. [Software Framework & Tooling](#4-Software-Framework-and-Tooling) |
5. [**Getting Started**](#5-Getting-Started) :rocket: |
|
38,32 → 27,30
|
![neorv32 Overview](https://raw.githubusercontent.com/stnolting/neorv32/master/docs/figures/neorv32_processor.png) |
|
The NEORV32 Processor is a customizable microcontroller-like system on chip (SoC) that is based on the RISC-V NEORV32 CPU. |
The NEORV32 Processor is a **customizable microcontroller-like system on chip (SoC)** that is based on the RISC-V NEORV32 CPU. |
The project is intended as auxiliary processor in larger SoC designs or as *ready-to-go* stand-alone |
custom / customizable microcontroller. |
custom microcontroller that even fits into a Lattice iCE40 UltraPlus 5k low-power FPGA running at 24 MHz. |
|
Special focus is paid on **execution safety** to provide defined and predictable behavior at any time. |
Therefore, the CPU ensures that all memory access are acknowledged and no invalid/malformed instructions |
are executed. Whenever an unexpected situation occurs, the application code is informed via hardware exceptions. |
are executed. Whenever an unexpected situation occurs the application code is informed via precise and resumable hardware exceptions. |
|
:thinking: Want to know more? Check out the [project's rationale](https://stnolting.github.io/neorv32/#_rationale). |
|
:books: For detailed information take a look at the [NEORV32 documentation (online at GitHub-pages)](https://stnolting.github.io/neorv32/). |
The *doxygen*-based documentation of the *software framework* is also available online |
at [GitHub-pages](https://stnolting.github.io/neorv32/sw/files.html). |
:books: For detailed information take a look at the [NEORV32 documentation](https://stnolting.github.io/neorv32/) (online at GitHub-pages). |
|
:label: The project's change log is available in [`CHANGELOG.md`](https://github.com/stnolting/neorv32/blob/master/CHANGELOG.md). |
To see the changes between *official* releases visit the project's [release page](https://github.com/stnolting/neorv32/releases). |
To see the changes between _official releases_ visit the project's [release page](https://github.com/stnolting/neorv32/releases). |
|
:package: The [`setups`](https://github.com/stnolting/neorv32/tree/master/setups) folder provides exemplary setups targeting |
various FPGA boards and toolchains to get you started. Several example programs (including a FreeRTOS port) to be run on your setup |
can be found in [`sw/example`](https://github.com/stnolting/neorv32/tree/master/sw/example). |
:package: [Exemplary setups](https://github.com/stnolting/neorv32/tree/master/setups) targeting |
various FPGA boards and toolchains to get you started. |
|
:kite: Supported by upstream [Zephyr OS](https://docs.zephyrproject.org/latest/boards/riscv/neorv32/doc/index.html). |
:kite: Supported by upstream [Zephyr OS](https://docs.zephyrproject.org/latest/boards/riscv/neorv32/doc/index.html) and FreeRTOS. |
|
:bulb: Feel free to open a [new issue](https://github.com/stnolting/neorv32/issues) or start a |
[new discussion](https://github.com/stnolting/neorv32/discussions) if you have questions, comments, ideas or if something is |
not working as expected. Or have a chat on our [gitter channel](https://gitter.im/neorv32/community). |
See how to [contribute](https://github.com/stnolting/neorv32/blob/master/CONTRIBUTING.md). |
|
:rocket: Check out the [quick links below](#5-Getting-Started) or directly jump to the |
[*User Guide*](https://stnolting.github.io/neorv32/ug/) to get started |
72,18 → 59,27
|
### Project Key Features |
|
- [x] all-in-one: [CPU](#3-NEORV32-CPU-Features) plus [SoC](#2-NEORV32-Processor-Features) plus [Software Framework & Tooling](#4-Software-Framework-and-Tooling) |
- [x] all-in-one package: [CPU](#3-NEORV32-CPU-Features) plus [SoC](#2-NEORV32-Processor-Features) plus [Software Framework & Tooling](#4-Software-Framework-and-Tooling) |
- [x] completely described in behavioral, platform-independent VHDL - no primitives, macros, etc. |
- [x] fully synchronous design, no latches, no gated clocks |
- [x] be as small as possible while being as RISC-V-compliant as possible – but with a reasonable size-performance trade-off: |
the processor (CPU _including_ privileged architecture) fits into a Lattice iCE40 UltraPlus 5k low-power FPGA running at 24 MHz |
- [x] from zero to `printf("hello world!");` - completely open source and documented |
- [x] be as small as possible while being as RISC-V-compliant as possible |
- [x] from zero to *printf("hello world!");* - completely open source and documented |
- [x] easy to use even for FPGA/RISC-V starters – intended to work *out of the box* |
|
|
### Status |
|
[![release](https://img.shields.io/github/v/release/stnolting/neorv32?longCache=true&style=flat-square&logo=GitHub)](https://github.com/stnolting/neorv32/releases) |
[![GitHub Pages](https://img.shields.io/website.svg?label=stnolting.github.io%2Fneorv32&longCache=true&style=flat-square&url=http%3A%2F%2Fstnolting.github.io%2Fneorv32%2Findex.html&logo=GitHub)](https://stnolting.github.io/neorv32) |
[![Documentation](https://img.shields.io/github/workflow/status/stnolting/neorv32/Documentation/master?longCache=true&style=flat-square&label=Documentation&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3ADocumentation) |
\ |
[![riscv-arch-test](https://img.shields.io/github/workflow/status/stnolting/neorv32/riscv-arch-test/master?longCache=true&style=flat-square&label=riscv-arch-test&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3Ariscv-arch-test) |
[![Processor](https://img.shields.io/github/workflow/status/stnolting/neorv32/Processor/master?longCache=true&style=flat-square&label=Processor&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3AProcessor) |
[![Implementation](https://img.shields.io/github/workflow/status/stnolting/neorv32/Implementation/master?longCache=true&style=flat-square&label=Implementation&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3AImplementation) |
[![Windows](https://img.shields.io/github/workflow/status/stnolting/neorv32/Windows/master?longCache=true&style=flat-square&label=Windows&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3AWindows) |
|
[[back to top](#The-NEORV32-RISC-V-Processor)] |
|
|
|
## 2. NEORV32 Processor Features |
|
The NEORV32 Processor (top entity: [`rtl/core/neorv32_top.vhd`](https://github.com/stnolting/neorv32/blob/master/rtl/core/neorv32_top.vhd)) |
104,7 → 100,7
* general purpose 32-bit timer ([GPTMR](https://stnolting.github.io/neorv32/#_general_purpose_timer_gptmr)) |
* watchdog timer ([WDT](https://stnolting.github.io/neorv32/#_watchdog_timer_wdt)) |
|
**IO** |
**Input/Output** |
|
* standard serial interfaces |
([UART](https://stnolting.github.io/neorv32/#_primary_universal_asynchronous_receiver_and_transmitter_uart0), |
114,7 → 110,7
[PWM](https://stnolting.github.io/neorv32/#_pulse_width_modulation_controller_pwm) |
* smart LED interface ([NEOLED](https://stnolting.github.io/neorv32/#_smart_led_interface_neoled)) to directly drive _NeoPixel(TM)_ LEDs |
|
**SoC Connectivity and Integration** |
**SoC Connectivity** |
|
* 32-bit external bus interface, Wishbone b4 compatible |
([WISHBONE](https://stnolting.github.io/neorv32/#_processor_external_memory_interface_wishbone_axi4_lite)) |
147,9 → 143,10
of the online datasheet shows the resource utilization of each optional processor module to allow an |
estimation of the actual setup's hardware requirements. |
|
:information_source: The [`setups`](https://github.com/stnolting/neorv32/tree/master/setups) folder provides exemplary FPGA |
The [`setups`](https://github.com/stnolting/neorv32/tree/master/setups) folder provides exemplary FPGA |
setups targeting various FPGA boards and toolchains. These setups also provide resource utilization reports for different |
SoC configurations |
SoC configurations. The latest utilization reports for those setups can be found in the report of the |
[Implementation Workflow](https://github.com/stnolting/neorv32/actions/workflows/Implementation.yml). |
|
[[back to top](#The-NEORV32-RISC-V-Processor)] |
|
199,7 → 196,7
[[`DEBUG`](https://stnolting.github.io/neorv32/#_cpu_debug_mode)]** |
|
:warning: The `B`, `Zfinx` and `Zmmul` RISC-V extensions are frozen but not officially ratified yet. Hence, there is no |
upstream gcc support. To circumvent this, the NEORV32 software framework provides _intrinsic_ libraries for these extensions. |
upstream gcc support. To circumvent this, the NEORV32 software framework provides _intrinsic libraries_ for these extensions. |
|
[[back to top](#The-NEORV32-RISC-V-Processor)] |
|
207,21 → 204,18
### FPGA Implementation Results - CPU |
|
Implementation results for _exemplary_ CPU configuration generated for an **Intel Cyclone IV EP4CE22F17C6N FPGA** |
using **Intel Quartus Prime Lite 20.1** ("balanced implementation"). The timing information is derived |
from the Timing Analyzer / Slow 1200mV 0C Model. No constraints were used at all. |
using **Intel Quartus Prime Lite 20.1** ("balanced implementation, Slow 1200mV 0C Model"). |
|
Results generated for hardware version [`1.5.7.10`](https://github.com/stnolting/neorv32/blob/master/CHANGELOG.md). |
| CPU Configuration (version [1.5.7.10](https://github.com/stnolting/neorv32/blob/master/CHANGELOG.md)) | LEs | FFs | Memory bits | DSPs (9-bit) | f_max | |
|:------------------------|:----:|:----:|:----:|:-:|:-------:| |
| `rv32i` | 806 | 359 | 1024 | 0 | 125 MHz | |
| `rv32i_Zicsr_Zicntr` | 1729 | 813 | 1024 | 0 | 124 MHz | |
| `rv32imac_Zicsr_Zicntr` | 2511 | 1074 | 1024 | 0 | 124 MHz | |
|
| CPU Configuration | LEs | FFs | Memory bits | DSPs (9-bit) | f_max | |
|:--------------------------------------------------|:----:|:----:|:-----------:|:------------:|:-------:| |
| `rv32i` | 806 | 359 | 1024 | 0 | 125 MHz | |
| `rv32i_Zicsr_Zicntr` | 1729 | 813 | 1024 | 0 | 124 MHz | |
| `rv32imac_Zicsr_Zicntr` | 2511 | 1074 | 1024 | 0 | 124 MHz | |
|
:information_source: An incremental list of CPU extension's hardware utilization can found in the |
[_Data Sheet: FPGA Implementation Results - CPU_](https://stnolting.github.io/neorv32/#_cpu). |
|
:information_source: The CPU (and also the SoC) provides advanced options to optimize for performance, area or energy. |
:information_source: The CPU and SoC provide advanced options to optimize for performance, area or energy. |
See [_User Guide: Application-Specific Processor Configuration_](https://stnolting.github.io/neorv32/ug/#_application_specific_processor_configuration) |
for more information. |
|
230,25 → 224,19
|
### Performance |
|
The NEORV32 CPU is based on a two-stages pipelined architecture. Since both stage use a multi-cycle processing scheme, |
each instruction requires several clock cycles to execute (2 cycles for ALU operations, up to 40 cycles for divisions). |
The NEORV32 CPU is based on a two-stages pipeline architecture (fetch and execute). |
The average CPI (cycles per instruction) depends on the instruction mix of a specific applications and also on the |
available CPU extensions. |
|
The following table shows the performance results (relative CoreMark score and average cycles per instruction) for |
_exemplary_ CPU configuration running 2000 iterations of the CoreMark CPU benchmark. |
The source files are available in [`sw/example/coremark`](https://github.com/stnolting/neorv32/blob/master/sw/example/coremark). |
A simple(!) port of the **Dhrystone** benchmark is also available in |
[`sw/example/dhrystone`](https://github.com/stnolting/neorv32/blob/master/sw/example/dhrystone). |
The following table shows the performance results (scores and average CPI) for _exemplary_ CPU configurations executing |
2000 iterations of the [CoreMark](https://github.com/stnolting/neorv32/blob/master/sw/example/coremark) CPU benchmark. |
|
Results generated for hardware version [`1.5.7.10`](https://github.com/stnolting/neorv32/blob/master/CHANGELOG.md). |
| CPU Configuration (version [1.5.7.10](https://github.com/stnolting/neorv32/blob/master/CHANGELOG.md)) | CoreMark Score | CoreMarks/MHz | Average CPI | |
|:------------------------------------------------|:-----:|:----------:|:--------:| |
| _small_ (`rv32i_Zicsr`) | 33.89 | **0.3389** | **4.04** | |
| _medium_ (`rv32imc_Zicsr`) | 62.50 | **0.6250** | **5.34** | |
| _performance_ (`rv32imc_Zicsr` + perf. options) | 95.23 | **0.9523** | **3.54** | |
|
| CPU Configuration | CoreMark Score | CoreMarks/MHz | Average CPI | |
|:------------------------------------------------|:--------------:|:-------------:|:-----------:| |
| _small_ (`rv32i_Zicsr`) | 33.89 | **0.3389** | **4.04** | |
| _medium_ (`rv32imc_Zicsr`) | 62.50 | **0.6250** | **5.34** | |
| _performance_ (`rv32imc_Zicsr` + perf. options) | 95.23 | **0.9523** | **3.54** | |
|
:information_source: More information regarding the CPU performance can be found in the |
[_Data Sheet: CPU Performance_](https://stnolting.github.io/neorv32/#_cpu_performance). |
|
258,24 → 246,24
|
## 4. Software Framework and Tooling |
|
:books: In-depth detailed information regarding the software framework can be found in the |
[_Data Sheet: Software Framework_](https://stnolting.github.io/neorv32/#_software_framework). |
|
* [core libraries](https://github.com/stnolting/neorv32/tree/master/sw/lib) for high-level usage of the provided functions and peripherals |
* application compilation based on GNU makefiles |
* gcc-based toolchain ([pre-compiled toolchains available](https://github.com/stnolting/riscv-gcc-prebuilt)) |
* [SVD file](https://github.com/stnolting/neorv32/tree/master/sw/svd) for advanced debugging and IDE integration |
* bootloader with UART interface console |
* runtime environment for handling traps |
* several [example programs](https://github.com/stnolting/neorv32/tree/master/sw/example) to get started including CoreMark, FreeRTOS and Conway's Game of Life |
* `doxygen`-based documentation, available on :books: [GitHub pages](https://stnolting.github.io/neorv32/sw/files.html) |
* supports implementation using open source tooling (GHDL, Yosys and nextpnr; in the future Verilog-to-Routing); both, software and hardware can be |
* doxygen-based documentation, available on [GitHub pages](https://stnolting.github.io/neorv32/sw/files.html) |
* supports implementation using open source tooling (GHDL, Yosys and nextpnr; in the future: "Verilog-to-Routing") - both, software and hardware can be |
developed and debugged with open source tooling |
* [continuous integration](https://github.com/stnolting/neorv32/actions) :octocat: is available for: |
* [continuous integration](https://github.com/stnolting/neorv32/actions) is available for: |
* allowing users to see the expected execution/output of the tools |
* ensuring specification compliance |
* catching regressions |
* providing ready-to-use and up-to-date bitstreams and documentation |
|
:books: Want to know more? Check out [_Data Sheet: Software Framework_](https://stnolting.github.io/neorv32/#_software_framework). |
|
[[back to top](#The-NEORV32-RISC-V-Processor)] |
|
|
294,7 → 282,7
* [Top Entity - Signals](https://stnolting.github.io/neorv32/#_processor_top_entity_signals) - how to connect to the processor |
* [Top Entity - Generics](https://stnolting.github.io/neorv32/#_processor_top_entity_generics) - configuration options |
* [Address Space](https://stnolting.github.io/neorv32/#_address_space) - memory layout and boot configuration |
* [SoC Modules](https://stnolting.github.io/neorv32/#_processor_internal_modules) - available IO/peripheral modules and memories |
* [SoC Modules](https://stnolting.github.io/neorv32/#_processor_internal_modules) - available peripheral modules and memories |
* [On-Chip Debugger](https://stnolting.github.io/neorv32/#_on_chip_debugger_ocd) - online & in-system debugging of the processor via JTAG |
|
* [NEORV32 CPU](https://stnolting.github.io/neorv32/#_neorv32_central_processing_unit_cpu) - the CPU |
306,6 → 294,7
|
### :floppy_disk: Software Overview |
|
* [Example Programs](https://github.com/stnolting/neorv32/tree/master/sw/example) - test program execution on your setup |
* [Core Libraries](https://stnolting.github.io/neorv32/#_core_libraries) - high-level functions for accessing the processor's peripherals |
* [Software Framework Documentation](https://stnolting.github.io/neorv32/sw/files.html) - `doxygen`-based documentation |
* [Application Makefiles](https://stnolting.github.io/neorv32/#_application_makefile) - turning your application into an executable |
313,7 → 302,7
|
### :rocket: User Guide |
|
* [Toolchain Setup](https://stnolting.github.io/neorv32/ug/#_toolchain_setup) - install and setup RISC-V gcc |
* [Toolchain Setup](https://stnolting.github.io/neorv32/ug/#_software_toolchain_setup) - install and setup RISC-V gcc |
* [General Hardware Setup](https://stnolting.github.io/neorv32/ug/#_general_hardware_setup) - setup a new NEORV32 EDA project |
* [General Software Setup](https://stnolting.github.io/neorv32/ug/#_general_software_framework_setup) - configure the software framework |
* [Application Compilation](https://stnolting.github.io/neorv32/ug/#_application_program_compilation) - compile an application using `make` |
326,10 → 315,13
|
### :copyright: Legal |
|
* [Overview](https://stnolting.github.io/neorv32/#_legal) - license, disclaimer, proprietary notice, ... |
* [Citing](https://stnolting.github.io/neorv32/#_citing) - citing information (DOI) |
* [Impressum](https://github.com/stnolting/neorv32/blob/master/docs/impressum.md) - imprint (:de:) |
[![license](https://img.shields.io/github/license/stnolting/neorv32?longCache=true&style=flat-square)](https://github.com/stnolting/neorv32/blob/master/LICENSE) |
[![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.5018888.svg)](https://doi.org/10.5281/zenodo.5018888) |
|
* [Overview](https://stnolting.github.io/neorv32/#_legal) - license, disclaimer, limitation of liability for external links, proprietary notice, ... |
* [Citing](https://stnolting.github.io/neorv32/#_citing) - citing information |
* [Impressum](https://github.com/stnolting/neorv32/blob/master/docs/impressum.md) - imprint |
|
[[back to top](#The-NEORV32-RISC-V-Processor)] |
|
|
336,7 → 328,7
|
## Acknowledgements |
|
**A big shout-out to the community and all [contributors](https://github.com/stnolting/neorv32/graphs/contributors), who helped improving this project! :heart:** |
**A big shout-out goes to the community and all the [contributors](https://github.com/stnolting/neorv32/graphs/contributors), who helped improving this project! :heart:** |
|
[RISC-V](https://riscv.org/) - Instruction Sets Want To Be Free! |
|