OpenCores
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 67 to Rev 68
    Reverse comparison

Rev 67 → Rev 68

/docs/datasheet/cpu.adoc
611,28 → 611,31
 
The CSR access instructions as well as the exception and interrupt system (= the privileged architecture)
is implemented when the `CPU_EXTENSION_RISCV_Zicsr` configuration generic is _true_.
 
[IMPORTANT]
If the `Zicsr` extension is disabled the CPU does not provide any _privileged architecture_ features at all!
In order to provide the full set of privileged functions that are required to run more complex tasks like
operating system and to allow a secure execution environment the `Zicsr` extension should always be enabled.
 
In this case the following instructions are available:
 
* CSR access: `csrrw`, `csrrs`, `csrrc`, `csrrwi`, `csrrsi`, `csrrci`
* environment: `mret`, `wfi`
 
[WARNING]
If the `Zicsr` extension is disabled the CPU does not provide any _privileged architecture_ features at all!
In order to provide the full set of functions and to allow a secure execution
environment the `Zicsr` extension should always be enabled.
[NOTE]
If `rd=x0` for the `csrrw[i]` instructions there will be no actual read access to the according CSR.
However, access privileges are still enforced so these instruction variants _do_ cause side-effects
(the RISC-V spec. state that these combinations "_shall_ not cause any side-effects").
 
[NOTE]
The "wait for interrupt instruction" `wfi` works like a sleep command. When executed, the CPU is
The "wait for interrupt instruction" `wfi` acts like a sleep command. When executed, the CPU is
halted until a valid interrupt request occurs. To wake up again, the according interrupt source has to
be enabled via the `mie` CSR and the global interrupt enable flag in `mstatus` has to be set.
 
[NOTE]
The `wfi` instruction may also be executed in user-mode without causing an exception as <<_mstatus>> bit
`TW` (timeout wait) is hardwired to zero.
`TW` (timeout wait) is _hardwired_ to zero.
 
 
 
 
==== **`Zicntr`** CPU Base Counters
 
The `Zicntr` ISA extension adds the basic cycle `[m]cycle[h]`), instruction-retired (`[m]instret[h]`) and time (`time[h]`)
/docs/datasheet/on_chip_debugger.adoc
87,13 → 87,11
| `jtag_tms_i` | 1 | in | mode select
|=======================
 
.JTAG Clock
.Maximum JTAG Clock
[IMPORTANT]
The actual JTAG clock signal is **not** used as primary clock. Instead it is used to synchronize
JTGA accesses, while all internal operations trigger on the system clock. Hence, no additional clock domain is required
for integration of this module.
However, this constraints the maximal JTAG clock (`jtag_tck_i`) frequency to be less than or equal to
1/4 of the system clock (`clk_i`) frequency.
All JTAG signals are synchronized to the processor clock domain by oversampling them in DTM. Hence, no additional
clock domain is required for the DTM. However, this constraints the maximal JTAG clock frequency (`jtag_tck_i`) to be less
than or equal to **1/5** of the processor clock frequency (`clk_i`).
 
[NOTE]
If the on-chip debugger is disabled (_ON_CHIP_DEBUGGER_EN_ = false) the JTAG serial input `jtag_tdi_i` is directly
127,10 → 125,24
| others | `BYPASS` | 1 | default JTAG bypass register
|=======================
 
.`DTMCS` - DTM Control and Status Register
[cols="^2,^3,^1,<8"]
[options="header",grid="rows"]
|=======================
| Bit(s) | Name | r/w | Description
| 31:18 | - | r/- | _reserved_, hardwired to zero
| 17 | `dmihardreset` | r/w | setting this bit will reset the DM interface; this bit auto-clears
| 16 | `dmireset` | r/w | setting this bit will clear ste sticky error state; this bit auto-clears
| 15 | - | r/- | _reserved_, hardwired to zero
| 14:12 | `idle` | r/- | recommended idle states (= 0, no idle states required)
| 11:10 | `dmistat` | r/- | DMI statu: `00` = no error, `01` = reserved, `10` = operation failed, `11` = failed operation during pending DMI operation
| 9:4 | `abits` | r/- | number of DMI address bits (= 7)
| 3:0 | `version` | r/- | `0001` = spec version 0.13
|=======================
 
[INFO]
See the https://github.com/riscv/riscv-debug-spec[RISC-V debug specification] for more information regarding the data
registers and operations.
A local copy can be found in `docs/references`.
registers and operations. A local copy can be found in `docs/references`.
 
 
 
/docs/datasheet/overview.adoc
107,7 → 107,13
vs. size trade-off and a different focus: _embrace_ concepts like documentation, platform-independence / portability,
RISC-V compatibility, _customization_ and _ease of use_. See the <<_project_key_features>> below.
 
Furthermore, the NEORV32 pays special focus on _execution safety_ using <<_full_virtualization>>. The CPU aims to
provide fall-backs for _everything that could go wrong_. This includes malformed instruction words, privilege escalations
and even memory accesses that are checked for address space holes and deterministic response times from memory-mapped
devices. Precise exceptions allow a defined and fully-synchronized state of the CPU at every time.
 
 
 
// ####################################################################################################################
:sectnums:
=== Project Key Features
193,7 → 199,7
:sectnums:
=== VHDL File Hierarchy
 
All necessary VHDL hardware description files are located in the project's `rtl/core folder`. The top entity
All necessary VHDL hardware description files are located in the project's `rtl/core` folder. The top entity
of the entire processor including all the required configuration generics is **`neorv32_top.vhd`**.
 
[IMPORTANT]
243,14 → 249,14
├neorv32_wishbone.vhd - External (Wishbone) bus interface
├neorv32_xirq.vhd - External interrupt controller
│
├mem/neorv32_dmem.default.vhd - _Default_ data memory (architecture-only!)
â””mem/neorv32_imem.default.vhd - _Default_ instruction memory (architecture-only!)
├mem/neorv32_dmem.default.vhd - _Default_ data memory (architecture-only)
â””mem/neorv32_imem.default.vhd - _Default_ instruction memory (architecture-only)
...................................
 
[NOTE]
The processor-internal instruction and data memories (IMEM and DMEM) are split into two design files each:
a plain entity definition (`neorv32_*mem.entity.vhd`) and the actual architecture definition
(`mem/neorv32_*mem.default.vhd`). The **default** architecture definitions from `rtl/core/mem` provide a _generic_ and
(`mem/neorv32_*mem.default.vhd`). The `*.default.vhd` architecture definitions from `rtl/core/mem` provide a _generic_ and
_platform independent_ memory design that (should) infers embedded memory blocks. You can replace/modify the architecture
source file in order to use platform-specific features (like advanced memory resources) or to improve technology mapping
and/or timing.
/docs/datasheet/soc.adoc
1321,32 → 1321,35
:sectnums!:
===== Indirect Boot
 
The _indirect_ boot scenarios **1a** and **1b** use the processor-internal <<_bootloader>>. This general setup is enabled
by setting the <<_int_bootloader_en>> generic to true, which will implement the processor-internal <<_bootloader_rom_bootrom>>.
The _indirect_ boot scenarios **1a** and **1b** use the processor-internal <<_bootloader>>. This boot setup is enabled
by setting the <<_int_bootloader_en>> generic to _true_, which will implement the processor-internal <<_bootloader_rom_bootrom>>.
This read-only memory is pre-initialized during synthesis with the default bootloader firmware.
The bootloader provides several options to upload an executable (via UART or from external SPI flash) and copies it to
the beginning of the _instruction address space_ so the CPU can execute it.
 
The bootloader provides several options to upload an executable (via UART or from external SPI flash) and store it to
the _instruction address space_ so the CPU can execute it. Boot scenario **1a** uses the processor-internal IMEM
Boot scenario **1a** uses the processor-internal IMEM
(<<_mem_int_imem_en>> = _true_). This scenario implements the internal <<_instruction_memory_imem>> as non-initialized
RAM so the bootloader can write the actual executable to it.
RAM so the bootloader can copy the actual executable to it.
 
Boot scenario **1b** uses a processor-external IMEM (<<_mem_int_imem_en>> = _false_) that is connected via the processor's
bus interface. In this scenario the internal <<_instruction_memory_imem>> is not implemented at all and the bootloader will
write the executable to the processor-external memory.
copy the executable to the processor-external memory. Hence, the external memory has to be implemented as RAM.
 
:sectnums!:
===== Direct Boot
 
The _direct_ boot scenarios **2a** and **2b** do not use the processor-internal bootloader. Hence, the <<_int_bootloader_en>>
The _direct_ boot scenarios **2a** and **2b** do not use the processor-internal bootloader since the <<_int_bootloader_en>>
generic is set _false_. In this configuration the <<_bootloader_rom_bootrom>> is not implemented at all and the CPU will
directly begin executing code from the instruction address space after reset. A "pre-initialization mechanism is required
in order to provide an executable _in_ memory.
directly begin executing code from the beginning of the instruction address space after reset. An application-specific
"pre-initialization" mechanism is required in order to provide an executable _in_ memory.
 
Boot scenario **2a** uses the processor-internal IMEM (<<_mem_int_imem_en>> = _true_) that is implemented as _read-only memory_
in this scenario. It is pre-initialized (by the bitstream) with the actual application executable.
in this scenario. It is pre-initialized (by the bitstream) with the actual application executable during synthesis.
 
In contrast, boot scenario **2b** uses a processor-external IMEM (<<_mem_int_imem_en>> = _false_). In this scenario the
system designer is responsible for providing a initialized external memory that contains the actual application to be executed.
system designer is responsible for providing an initialized external memory that contains the actual application to be executed.
If the external is not already initialized after reset, a simple ROM containing a "polling loop" can be implemented that is
exited as soon as the application logic has finished initializing the memory with the acutal application code.
 
 
 
/docs/datasheet/soc_buskeeper.adoc
13,6 → 13,7
| CPU interrupts: | none |
|=======================
 
 
**Theory of Operation**
 
The Bus Keeper is a fundamental component of the processor's internal bus system that ensures correct bus operations
30,35 → 31,25
 
In case of a bus access fault exception application software can evaluate the Bus Keeper's control register
`NEORV32_BUSKEEPER.CTRL` to retrieve further details of the bus exception. The _BUSKEEPER_ERR_FLAG_ bit indicates
that an actual bus access fault has occurred. The bit is sticky once set is automatically cleared when reading the
`NEORV32_BUSKEEPER.CTRL` register. The _BUSKEEPER_ERR_TYPE_ indicated the tape or bus fault:
that an actual bus access fault has occurred. The bit is sticky once set and is automatically cleared when reading or
writing the `NEORV32_BUSKEEPER.CTRL` register. The _BUSKEEPER_ERR_TYPE_ indicated the tape of the bus fault:
 
* _BUSKEEPER_ERR_TYPE_ = `0` - "Device Error": The bus access exception was cause by the memory-mapped device that
has been accessed (the device asserted it's `err_o`).
* _BUSKEEPER_ERR_TYPE_ = `1` - "Timeout Error": The bus access exception was caused by the Bus Keeper because the
accessed memory-mapped device did not respond within the access time window.
accessed memory-mapped device did not respond within the access time window. Note that this error type can also be raised
by the optional timeout feature of the <<_processor_external_memory_interface_wishbone_axi4_lite>>).
 
[NOTE]
Bus access fault exceptions are also raised if a physical memory protection rule is violated. In this case
the _BUSKEEPER_ERR_FLAG_ bit remains zero.
 
Furthermore, application software can determine the source of the bus access fault via the _BUSKEEPER_ERR_SRC_ bit:
 
* _BUSKEEPER_ERR_SRC_ = `0`: The error was cause during access via the <<_processor_external_memory_interface_wishbone_axi4_lite>>).
* _BUSKEEPER_ERR_SRC_ = `1`: The error was cause during access to an processor-internal module.
 
[NOTE]
The Bus Keeper does not track **timeout errors** of processor-external accesses via the external memory bus interface.
However, the external memory bus interface also provides an _optional_ and independent bus timeout feature
(see section <<_processor_external_memory_interface_wishbone_axi4_lite>>).
 
 
.BUSKEEPER register map (`struct NEORV32_BUSKEEPER`)
[cols="<2,<2,<4,^1,<4"]
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.3+<| `0xffffff7C` .3+<| `NEORV32_BUSKEEPER.CTRL` <|`0` _BUSKEEPER_ERR_TYPE_ ^| r/- <| Bus error type, valid if _BUSKEEPER_ERR_FLAG_ is set: `0`=device error, `1`=access timeout
<|`1` _BUSKEEPER_ERR_SRC_ ^| r/- <| Error source: `0`=processor-internal, `1`=processor-external (via Wishbone bus interface)
<|`31` _BUSKEEPER_ERR_FLAG_ ^| r/- <| Sticky error flag, clears after read
.2+<| `0xffffff7C` .2+<| `NEORV32_BUSKEEPER.CTRL` <|`0` _BUSKEEPER_ERR_TYPE_ ^| r/- <| Bus error type, valid if _BUSKEEPER_ERR_FLAG_ is set: `0`=device error, `1`=access timeout
<|`31` _BUSKEEPER_ERR_FLAG_ ^| r/- <| Sticky error flag, clears after read or write access
|=======================
/docs/datasheet/soc_neoled.adoc
163,19 → 163,20
data word being written to the TX buffer making busy wait concepts obsolete and allowing maximum refresh rates.
 
 
**Interrupt**
**NEOLED Interrupt**
 
The NEOLED modules features a single interrupt that becomes pending based on the current TX buffer fill level.
The interrupt can only become pending if the NEOLED module is enabled. The specific interrupt condition
is configured via the _NEOLED_CTRL_IRQ_CONF_ in the control register `NEORV32_NEOLED.CTRL`.
is configured via the _NEOLED_CTRL_IRQ_CONF_ bit in the unit's control register.
 
If _NEOLED_CTRL_IRQ_CONF_ is cleared, an interrupt is generated whenever the TX FIFO is _less than half-full_.
If _NEOLED_CTRL_IRQ_CONF_ is cleared, an interrupt is generated whenever the TX FIFO _becomes_ less than half-full.
In this case software can write up to _IO_NEOLED_TX_FIFO_/2 new data words to `DATA` without checking the FIFO
status flags. The interrupt request is cleared whenever the FIFO fill level is above _half-full_ level or if
the NEOLED module is disabled.
status flags. If _NEOLED_CTRL_IRQ_CONF_ is set, an interrupt is generated whenever the TX FIFO _becomes_ empty.
 
If _NEOLED_CTRL_IRQ_CONF_ is set, an interrupt is generated whenever the TX FIFO is _empty_. The interrupt
request is cleared again when the FIFO contains at least one data word.
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
 
[NOTE]
The _NEOLED_CTRL_IRQ_CONF_ is hardwired to one if _IO_NEOLED_TX_FIFO_ = 1 (-> IRQ if FIFO is empty).
/docs/datasheet/soc_slink.adoc
79,11 → 79,14
The NEORV32 processor ensures that _any_ CPU access to memory-mapped devices (including the SLINK module)
will **time out** after a certain number of cycles (see section <<_bus_interface>>).
Hence, blocking access to a stream link that does not complete within a certain amount of cycles will
raise a _store bus access exception_ when writing a _full_ TX link or a _load bus access exception_ when reading
from an _empty_ RX link. Hence, this concept should only be used when evaluating the half-full FIFO condition
(for example via the SLINK interrupts) before actual accessing links.
raise a _store bus access exception_ when writing to a _full_ TX link's FIFO or a _load bus access exception_
when reading from an _empty_ RX 's FIFO. Hence, this concept should only be used when evaluating the half-full
FIFO condition (for example via the SLINK interrupts) before actual accessing links.
 
[NOTE]
There is no RX FIFO overflow mechanism available yet.
 
 
**Non-Blocking Link Access**
 
For a non-blocking link access concept, the FIFO status flags in `STATUS` need to be checked _before_
118,43 → 121,52
The SLINK handshake protocol is compatible with the https://developer.arm.com/documentation/ihi0051/a/Introduction/About-the-AXI4-Stream-protocol[AXI4-Stream] base protocol.
 
 
**Interrupts**
**SLINK Interrupts**
 
The stream interface provides two independent interrupts that are _globally_ driven by the RX and TX link's
FIFO fill level status. Each RX and TX link provides an individual interrupt enable flag and an individual
interrupt type flag that allows to configure interrupts only for certain (or all) links and for application-
specific interrupt conditions. The interrupt configuration is done using the `NEORV32_SLINK.IRQ` register.
specific FIFO conditions. The interrupt configuration is done using the `NEORV32_SLINK.IRQ` register.
Any interrupt can only become pending if the SLINK module is enabled at all.
 
[NOTE]
There is no RX FIFO overflow mechanism available yet.
 
The current FIFO fill-level of a specific **RX link** can only raise an interrupt request if it's interrupt enable flag
_SLINK_IRQ_RX_EN_ is set. Vice versa, the current FIFO fill-level of a specific **TX link** can only raise an interrupt
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 is _not empty_ ("RX data available").
* If a link's interrupt mode flag is `0` an IRQ is generated when the link's FIFO is _at least half-full_ ("time to get data from RX FIFO to prevent overflow").
* 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").
 
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 is _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 is _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 `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").
 
[NOTE]
If _SLINK_RX_FIFO_ is 1 the _SLINK_IRQ_RX_MODE_ bits are hardwired to one.
If _SLINK_TX_FIFO_ is 1 the _SLINK_IRQ_TX_MODE_ bits are hardwired to one.
[IMPORTANT]
The interrupt configuration register `NEORV32_SLINK.IRQ` should we written _before_ the SLINK
module is actually enabled.
 
[NOTE]
There is no RX FIFO overflow mechanism available yet.
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.
 
If _any_ configured interrupt condition is fulfilled, the according global SLINK RX / SLINK TX CPU
interrupt becomes pending.
If the interrupt enable flags of several links are set, the interrupt service handler has to evaluate the SLINK
status register is order to detect which link(s) caused the interrupt.
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
 
[NOTE]
If the programmed interrupt condition is fulfilled, the corresponding IRQ will become _pending_ until
the causing interrupt conditions is resolved (for example by reading data from the according RX FIFO).
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"]
168,9 → 180,9
<| `3:0` _SLINK_CTRL_RX_NUM3_ : _SLINK_CTRL_RX_NUM0_ ^| r/- <| Number of implemented RX links
| `0xfffffec4` | - |`31:0` | r/- | _reserved_
.4+<| `0xfffffec8` .4+<| `NEORV32_SLINK.IRQ` <|`31:24` _SLINK_IRQ_RX_EN_MSB_ : _SLINK_IRQ_RX_EN_LSB_ ^| r/w <| RX interrupt enable for link 7..0
<|`23:16` _SLINK_IRQ_RX_MODE_MSB_ : _SLINK_IRQ_RX_MODE_LSB_ ^| r/w <| RX IRQ mode for link 7..0: `0` = FIFO at least half-full; `1` = FIFO not empty
<|`23:16` _SLINK_IRQ_RX_MODE_MSB_ : _SLINK_IRQ_RX_MODE_LSB_ ^| r/w <| RX IRQ mode for link 7..0: `0` = FIFO rises above half-full; `1` = FIFO not empty
<|`15:8` _SLINK_IRQ_TX_EN_MSB_ : _SLINK_IRQ_TX_EN_LSB_ ^| r/w <| TX interrupt enable for link 7..0
<|`7:0` _SLINK_IRQ_TX_MODE_MSB_ : _SLINK_IRQ_TX_MODE_LSB_ ^| r/w <| TX IRQ mode for link 7..0: `0` = FIFO less than half-full; `1` = FIFO not full
<|`7:0` _SLINK_IRQ_TX_MODE_MSB_ : _SLINK_IRQ_TX_MODE_LSB_ ^| r/w <| TX IRQ mode for link 7..0: `0` = FIFO falls below half-full; `1` = FIFO not full
| `0xfffffeec` | - |`31:0` | r/- | _reserved_
.4+<| `0xfffffed0` .4+<| `NEORV32_SLINK.STATUS` <| `31:24` _SLINK_STATUS_TX7_HALF_ : _SLINK_STATUS_TX0_HALF_ ^| r/- <| TX link 7..0 FIFO fill level is >= half-full
<| `23:16` _SLINK_STATUS_RX7_HALF_ : _SLINK_STATUS_RX0_HALF_ ^| r/- <| RX link 7..0 FIFO fill level is >= half-full
/docs/datasheet/soc_spi.adoc
107,11 → 107,18
 
**SPI Interrupt**
 
The SPI module provides a single interrupt to signal "ready for new transmission" to the CPU. Whenever the SPI
module is currently idle (and enabled), the interrupt request is active. A pending interrupt request is cleared
by triggering a new SPI transmission or by disabling the SPI module.
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
 
[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_trng.adoc
13,65 → 13,36
| CPU interrupts: | none |
|=======================
 
 
**Theory of Operation**
 
The NEORV32 true random number generator provides _physical true random numbers_ for your application.
Instead of using a pseudo RNG like a LFSR, the TRNG of the processor uses a simple, straight-forward ring
oscillator as physical entropy source. Hence, voltage and thermal fluctuations are used to provide true
physical random data.
The NEORV32 true random number generator provides _physical_ true random numbers.
Instead of using a pseudo RNG like a LFSR, the TRNG uses a simple, straight-forward ring
oscillator concept as physical entropy source. Hence, voltage, thermal and also semiconductor manufacturing
fluctuations are used to provide a true physical entropy source.
 
The TRNG is based on the neoTRNG[https://github.com/stnolting/neoTRNG], which is a "spin-off project" of the
NEORV32 processor. The TRNG uses the default neoTRNG configuration, which showed very good results in the
`dieharder` battery of random number tests. More detailed information about the neoTRNG, it's architecture and a
detailed evaluation of the random number quality can be found it it's repository: https://github.com/stnolting/neoTRNG
 
[NOTE]
The TRNG features a platform independent architecture without FPGA-specific primitives, macros or
attributes.
attributes so it can be synthesized for _any_ FPGA.
 
**Architecture**
 
The NEORV32 TRNG is based on simple ring oscillators, which are implemented as an inverter chain with
an odd number of inverters. A **latch** is used to decouple each individual inverter. Basically, this architecture
is some king of asynchronous LFSR.
 
The output of several ring oscillators are synchronized using two registers and are XORed together. The
resulting output is de-biased using a von-Neumann randomness extractor. This de-biased output is further
processed by a simple 8-bit Fibonacci LFSR to improve whitening. After at least 8 clock cycles the state of
the LFSR is sampled and provided as final data output.
 
To prevent the synthesis tool from doing logic optimization and thus, removing all but one inverter, the
TRNG uses simple latches to decouple an inverter and its actual output. The latches are reset when the
TRNG is disabled and are enabled one by one by a "real" shift register when the TRNG is activated. This
construct can be synthesized for any FPGA platform. Thus, the NEORV32 TRNG provides a platform
independent architecture.
 
**TRNG Configuration**
 
The TRNG uses several ring-oscillators, where the next oscillator provides a slightly longer chain (more
inverters) than the one before. This increment is constant for all implemented oscillators. This setup can be
customized by modifying the "Advanced Configuration" constants in the TRNG's VHDL file:
 
* The `num_roscs_c` constant defines the total number of ring oscillators in the system. num_inv_start_c
defines the number of inverters used by the first ring oscillators (has to be an odd number). Each additional
ring oscillator provides `num_inv_inc_c` more inverters that the one before (has to be an even number).
* The LFSR-based post-processing can be deactivated using the `lfsr_en_c` constant. The polynomial tap
mask of the LFSR can be customized using `lfsr_taps_c`.
 
**Using the TRNG**
 
The TRNG features a single register for status and data access. When the _TRNG_CTRL_EN_ control register (`CTRL`)
bit is set, the TRNG is enabled and starts operation. As soon as the _TRNG_CTRL_VALID_ bit is set, the currently
sampled 8-bit random data byte can be obtained from the lowest 8 bits of the `CTRL` register
(_TRNG_CTRL_DATA_MSB_ : _TRNG_CTRL_DATA_LSB_). The _TRNG_CTRL_VALID_ bit is automatically cleared
when reading the control register.
(_TRNG_CTRL_DATA_MSB_ : _TRNG_CTRL_DATA_LSB_). These bits always keep the latest valid data obtained from the TRNG
entropy source. The _TRNG_CTRL_VALID_ bit is automatically cleared when reading the control register.
 
[IMPORTANT]
The TRNG needs at least 8 clock cycles to generate a new random byte. During this sampling time
the current output random data is kept stable in the output register until a valid sampling of the new byte has
completed.
[NOTE]
The TRNG core does not provide a dedicated reset. In order to ensure correct operations, the TRNG should be
disabled (=reset) by clearing the _TRNG_CTRL_EN_ and waiting some milliseconds before re-enabling it.
 
Randomness "Quality"
I have not verified the quality of the generated random numbers (for example using NIST test suites). The
quality is highly effected by the actual configuration of the TRNG and the resulting FPGA mapping/routing.
However, generating larger histograms of the generated random number shows an equal distribution (binary
average of the random numbers = 127). A simple evaluation test/demo program can be found in
`sw/example/demo_trng`.
 
.TRNG register map (`struct NEORV32_TRNG`)
[cols="<2,<2,<4,^1,<7"]
78,7 → 49,7
[options="header",grid="all"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.3+<| `0xffffffb8` .3+<| `NEORV32_TRNG.CTRL` <|`7:0` _TRNG_CTRL_DATA_MSB_ : _TRNG_CTRL_DATA_MSB_ ^| r/- <| 8-bit random data output
<|`30` _TRNG_CTRL_EN_ ^| r/w <| TRNG enable
<|`31` _TRNG_CTRL_VALID_ ^| r/- <| random data output is valid when set
.3+<| `0xffffffb8` .3+<| `NEORV32_TRNG.CTRL` <|`7:0` _TRNG_CTRL_DATA_MSB_ : _TRNG_CTRL_DATA_MSB_ ^| r/- <| 8-bit random data
<|`30` _TRNG_CTRL_EN_ ^| r/w <| TRNG enable
<|`31` _TRNG_CTRL_VALID_ ^| r/- <| random data is valid when set
|=======================
/docs/datasheet/soc_twi.adoc
21,8 → 21,8
clock line `twi_scl_io`) - despite of the number of connected devices - it allows easy interconnections of
several peripheral nodes.
 
The NEORV32 TWI implements a **TWI controller**. It features "clock stretching" (if enabled via the control
register), so a slow peripheral can halt the transmission by pulling the SCL line low. Currently, **no multi-controller
The NEORV32 TWI implements a **TWI controller**. It supports "clock so a slow peripheral can halt
the transmission by pulling the SCL line low. Currently, **no multi-controller
support** is available. Also, the NEORV32 TWI unit cannot operate in peripheral mode.
 
The TWI is enabled via the _TWI_CTRL_EN_ bit in the `CTRL` control register. The user program can start / stop a
70,27 → 70,34
_**f~SCL~**_ = _f~main~[Hz]_ / (4 * `clock_prescaler`)
 
 
**Interrupt**
**TWI Interrupt**
 
The TWI module provides a single interrupt to signal _idle state_ (= read for new transmission) to the CPU. Whenever TWI SPI module
is currently idle (and enabled), the interrupt request is active. A pending interrupt request is cleared
by triggering a new TWI transmission or by disabling the device.
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
 
[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"]
|=======================
| Address | Name [C] | Bit(s), Name [C] | R/W | Function
.10+<| `0xffffffb0` .10+<| `NEORV32_TWI.CTRL` <|`0` _TWI_CTRL_EN_ ^| r/w <| TWI enable
<|`1` _TWI_CTRL_START_ ^| r/w <| generate START condition
<|`2` _TWI_CTRL_STOP_ ^| r/w <| generate STOP condition
<|`3` _TWI_CTRL_PRSC0_ ^| r/w .3+<| 3-bit clock prescaler select
<|`4` _TWI_CTRL_PRSC1_ ^| r/w
<|`5` _TWI_CTRL_PRSC2_ ^| r/w
<|`6` _TWI_CTRL_MACK_ ^| r/w <| generate controller ACK for each transmission ("MACK")
<|`7` _TWI_CTRL_CKSTEN_ ^| r/w <| allow clock-stretching by peripherals when set
<|`30` _TWI_CTRL_ACK_ ^| r/- <| ACK received when set
<|`31` _TWI_CTRL_BUSY_ ^| r/- <| transfer/START/STOP in progress when set
.9+<| `0xffffffb0` .9+<| `NEORV32_TWI.CTRL` <|`0` _TWI_CTRL_EN_ ^| r/w <| TWI enable
<|`1` _TWI_CTRL_START_ ^| r/w <| generate START condition
<|`2` _TWI_CTRL_STOP_ ^| r/w <| generate STOP condition
<|`3` _TWI_CTRL_PRSC0_ ^| r/w .3+<| 3-bit clock prescaler select
<|`4` _TWI_CTRL_PRSC1_ ^| r/w
<|`5` _TWI_CTRL_PRSC2_ ^| r/w
<|`6` _TWI_CTRL_MACK_ ^| r/w <| generate controller ACK for each transmission ("MACK")
<|`30` _TWI_CTRL_ACK_ ^| r/- <| ACK received when set
<|`31` _TWI_CTRL_BUSY_ ^| r/- <| transfer/START/STOP in progress when set
| `0xffffffb4` | `NEORV32_TWI.DATA` |`7:0` _TWI_DATA_MSB_ : TWI_DATA_LSB_ | r/w | receive/transmit data
|=======================
/docs/datasheet/soc_uart.adoc
108,29 → 108,40
received character and is cleared by reading the `DATA` register.
 
 
**Interrupts**
**UART Interrupts**
 
UART0 features two independent interrupt for signaling certain RX and TX conditions. The behavior of these interrupts differ
based on the configured FIFO size. If the according FIFO size is greater than 1, the _UART_CTRL_RX_IRQ_ and _UART_CTRL_TX_IRQ_
`CTRL` flags allow a more fine-grained IRQ configuration.
UART0 features two independent interrupt for signaling certain RX and TX conditions. The behavior of these conditions differs
based on the configured FIFO sizes. If the according FIFO size is greater than 1, the _UART_CTRL_RX_IRQ_ and _UART_CTRL_TX_IRQ_
`CTRL` flags allow a more fine-grained IRQ configuration. An interrupt can only become pending if the according interrupt
condition is fulfilled and the UART is enabled at all.
 
* If _UART0_RX_FIFO_ is exactly 1, the RX interrupt becomes pending as soon as there is data available in the RX FIFO
(-> _UART_CTRL_RX_EMPTY_ clears). This flag is hardwired to `0` if _UART0_RX_FIFO_ = 1.
* If _UART0_TX_FIFO_ is exactly 1, the TX interrupt becomes pending as soon as there is a free entry left in the TX FIFO
(-> _UART_CTRL_TX_FULL_ clears). This flag is hardwired to `0` if _UART0_RX_FIFO_ = 1.
* If _UART0_RX_FIFO_ is exactly 1, the RX interrupt goes pending when data _becomes_ available in the RX FIFO
(-> _UART_CTRL_RX_EMPTY_ clears). _UART_CTRL_RX_IRQ_ is hardwired to `0` in this case.
* If _UART0_TX_FIFO_ is exactly 1, the TX interrupt goes pending when at least one entry in the TX FIFO _becomes_ free
(-> _UART_CTRL_TX_FULL_ clears). _UART_CTRL_TX_IRQ_ is hardwired to `0` in this case.
 
* If _UART0_RX_FIFO_ is greater than 1: If _UART_CTRL_RX_IRQ_ is `0` the RX interrupt becomes pending as soon as there is data
available in the RX FIFO (-> _UART_CTRL_RX_EMPTY_ clears). If _UART_CTRL_RX_IRQ_ is `1` the RX interrupt becomes pending as soon as
the RX FIFO is at least half-full (-> _UART_CTRL_RX_HALF_ sets).
* If _UART0_TX_FIFO_ is greater than 1: If _UART_CTRL_TX_IRQ_ is `0` the TX interrupt becomes pending as soon as there is a free
entry left in the TX FIFO (-> _UART_CTRL_TX_FULL_ clears). If _UART_CTRL_TX_IRQ_ is `1` the TX interrupt becomes pending as soon as
the RX FIFO is less than half-full (-> _UART_CTRL_TX_HALF_ clears).
* If _UART0_RX_FIFO_ is greater than 1: If _UART_CTRL_RX_IRQ_ is `0` the RX interrupt goes pending when data _becomes_
available in the RX FIFO (-> _UART_CTRL_RX_EMPTY_ clears). If _UART_CTRL_RX_IRQ_ is `1` the RX interrupt becomes pending
the RX FIFO _becomes_ at least half-full (-> _UART_CTRL_RX_HALF_ sets).
* If _UART0_TX_FIFO_ is greater than 1: If _UART_CTRL_TX_IRQ_ is `0` the TX interrupt goes pending when at least one entry
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).
 
An interrupt can only become pending if the according interrupt condition is fulfilled and the UART is enabled at all.
A pending interrupt is removed by resolving the interrupt-triggering conditions (for example by reading data from the
more-than-half-full RX FIFO).
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
 
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/software.adoc
588,9 → 588,18
 
[source]
----
<RTE> Illegal instruction @0x000002d6, MTVAL=0x00001537 </RTE>
<RTE> Illegal instruction @ PC=0x000002d6, MTVAL=0x00001537 </RTE>
----
 
For bus access faults the RTE also outputs the error code from the <<_internal_bus_monitor_buskeeper>>
to show the cause of the access fault. Two example are shown below.
 
[source]
----
<RTE> Load access fault [TIMEOUT_ERR] @ PC=0x00000150, MTVAL=0xFFFFFF70 </RTE>
<RTE> Store access fault [DEVICE_ERR] @ PC=0x00000162, MTVAL=0xF0000000 </RTE>
----
 
To install the **actual application's trap handlers** the NEORV32 RTE provides functions for installing and
un-installing trap handler for each implemented exception/interrupt source.
 
/docs/figures/riscv_logo_small.png Cannot display: file marked as a binary type. svn:mime-type = application/octet-stream
docs/figures/riscv_logo_small.png Property changes : Added: svn:mime-type ## -0,0 +1 ## +application/octet-stream \ No newline at end of property Index: docs/userguide/content.adoc =================================================================== --- docs/userguide/content.adoc (revision 67) +++ docs/userguide/content.adoc (revision 68) @@ -147,8 +147,8 @@ .Internal Memories [IMPORTANT] -For a _general_ first setup (technology-independent) use the _default_ memory architectures for the internal memories -(IMEM and DMEM). These are located in `rtl/core/mem`, so **make sure to add the files from `rtl/core/mem` to your project, too**. + +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` @@ -380,9 +380,11 @@ [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 fore free -from https://ttssh2.osdn.jp/index.html.en +. 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.
/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.3
:revnumber: v1.6.4
:doctype: book
:sectnums:
:stem:
/rtl/core/mem/README.md
0,0 → 1,14
# Processor Memory Source Files
 
This folder provides the architecture-only VHDL sources for the processor-internal memories
(instruction memory "IMEM", data memory "DMEM"). Different implementations are available - but
only **one** version of each (IMEM and DMEM) has to be added as actual source files.
 
For the first implementation the `*.default.vhd` files should be selected. The HDL style for describing
memories used by these files has proven **platform-independence** across several FPGA architectures and toolchains.
 
If synthesis fails to infer actual block RAM resources from these default files, try the legacy `*.cyclone2.vhd` files, which
provide a different HDL style. These files are intended for legacy support of older Intel/Altera Quartus versions (13.0 and older). However,
these files do **not** use platform-specific macros or primitives - so they might also work for other FPGAs and toolchains.
 
:warning: Make sure to add the selected files from this folder also to the `neorv32` design library.
/rtl/core/mem/neorv32_dmem.cyclone2.vhd
0,0 → 1,130
-- #################################################################################################
-- # << NEORV32 - Processor-internal data memory (DMEM) >> #
-- # ********************************************************************************************* #
-- # 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 #
-- #################################################################################################
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
library neorv32;
use neorv32.neorv32_package.all;
 
architecture neorv32_dmem_rtl of neorv32_dmem is
 
-- IO space: module base address --
constant hi_abb_c : natural := 31; -- high address boundary bit
constant lo_abb_c : natural := index_size_f(DMEM_SIZE); -- low address boundary bit
 
-- local signals --
signal acc_en : std_ulogic;
signal rdata : std_ulogic_vector(31 downto 0);
signal rden : std_ulogic;
signal addr : std_ulogic_vector(index_size_f(DMEM_SIZE/4)-1 downto 0);
signal addr_ff : std_ulogic_vector(index_size_f(DMEM_SIZE/4)-1 downto 0);
 
-- -------------------------------------------------------------------------------------------------------------- --
-- The memory (RAM) is built from 4 individual byte-wide memories b0..b3, since some synthesis tools have --
-- problems with 32-bit memories that provide dedicated byte-enable signals AND/OR with multi-dimensional arrays. --
-- -------------------------------------------------------------------------------------------------------------- --
 
-- RAM - not initialized at all --
signal mem_ram_b0 : mem8_t(0 to DMEM_SIZE/4-1);
signal mem_ram_b1 : mem8_t(0 to DMEM_SIZE/4-1);
signal mem_ram_b2 : mem8_t(0 to DMEM_SIZE/4-1);
signal mem_ram_b3 : mem8_t(0 to DMEM_SIZE/4-1);
 
-- read data --
signal mem_ram_b0_rd, mem_ram_b1_rd, mem_ram_b2_rd, mem_ram_b3_rd : std_ulogic_vector(7 downto 0);
 
begin
 
-- Sanity Checks --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Using CYCLONE-2-optimized HDL style DMEM." severity note;
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal DMEM (RAM, " & natural'image(DMEM_SIZE) & " bytes)." severity note;
 
 
-- Access Control -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = DMEM_BASE(hi_abb_c downto lo_abb_c)) else '0';
addr <= addr_i(index_size_f(DMEM_SIZE/4)+1 downto 2); -- word aligned
 
 
-- Memory Access --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
mem_access: process(clk_i)
begin
if rising_edge(clk_i) then
addr_ff <= addr;
if (acc_en = '1') then -- reduce switching activity when not accessed
if (wren_i = '1') and (ben_i(0) = '1') then -- byte 0
mem_ram_b0(to_integer(unsigned(addr))) <= data_i(07 downto 00);
end if;
if (wren_i = '1') and (ben_i(1) = '1') then -- byte 1
mem_ram_b1(to_integer(unsigned(addr))) <= data_i(15 downto 08);
end if;
if (wren_i = '1') and (ben_i(2) = '1') then -- byte 2
mem_ram_b2(to_integer(unsigned(addr))) <= data_i(23 downto 16);
end if;
if (wren_i = '1') and (ben_i(3) = '1') then -- byte 3
mem_ram_b3(to_integer(unsigned(addr))) <= data_i(31 downto 24);
end if;
end if;
end if;
end process mem_access;
 
-- sync(!) read - alternative HDL style --
mem_ram_b0_rd <= mem_ram_b0(to_integer(unsigned(addr_ff)));
mem_ram_b1_rd <= mem_ram_b1(to_integer(unsigned(addr_ff)));
mem_ram_b2_rd <= mem_ram_b2(to_integer(unsigned(addr_ff)));
mem_ram_b3_rd <= mem_ram_b3(to_integer(unsigned(addr_ff)));
 
 
-- Bus Feedback ---------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
bus_feedback: process(clk_i)
begin
if rising_edge(clk_i) then
rden <= acc_en and rden_i;
ack_o <= acc_en and (rden_i or wren_i);
end if;
end process bus_feedback;
 
-- pack --
rdata <= mem_ram_b3_rd & mem_ram_b2_rd & mem_ram_b1_rd & mem_ram_b0_rd;
 
-- output gate --
data_o <= rdata when (rden = '1') else (others => '0');
 
 
end neorv32_dmem_rtl;
/rtl/core/mem/neorv32_dmem.default.vhd
69,7 → 69,7
 
-- Sanity Checks --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Using default platform-agnostic DMEM." severity note;
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Using DEFAULT platform-agnostic DMEM." severity note;
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal DMEM (RAM, " & natural'image(DMEM_SIZE) & " bytes)." severity note;
 
 
/rtl/core/mem/neorv32_imem.cyclone2.vhd
0,0 → 1,176
-- #################################################################################################
-- # << NEORV32 - Processor-internal instruction memory (IMEM) >> #
-- # ********************************************************************************************* #
-- # This memory optionally includes the in-place executable image of the application. See the #
-- # processor's documentary to get more information. #
-- # ********************************************************************************************* #
-- # 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 #
-- #################################################################################################
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
library neorv32;
use neorv32.neorv32_package.all;
use neorv32.neorv32_application_image.all; -- this file is generated by the image generator
 
architecture neorv32_imem_rtl of neorv32_imem is
 
-- IO space: module base address --
constant hi_abb_c : natural := 31; -- high address boundary bit
constant lo_abb_c : natural := index_size_f(IMEM_SIZE); -- low address boundary bit
 
-- local signals --
signal acc_en : std_ulogic;
signal rdata : std_ulogic_vector(31 downto 0);
signal rden : std_ulogic;
signal addr : std_ulogic_vector(index_size_f(IMEM_SIZE/4)-1 downto 0);
signal addr_ff : std_ulogic_vector(index_size_f(IMEM_SIZE/4)-1 downto 0);
 
-- --------------------------- --
-- IMEM as pre-initialized ROM --
-- --------------------------- --
 
-- application (image) size in bytes --
constant imem_app_size_c : natural := (application_init_image'length)*4;
 
-- ROM - initialized with executable code --
constant mem_rom : mem32_t(0 to IMEM_SIZE/4-1) := mem32_init_f(application_init_image, IMEM_SIZE/4);
 
-- read data --
signal mem_rom_rd : std_ulogic_vector(31 downto 0);
 
-- -------------------------------------------------------------------------------------------------------------- --
-- The memory (RAM) is built from 4 individual byte-wide memories b0..b3, since some synthesis tools have --
-- problems with 32-bit memories that provide dedicated byte-enable signals AND/OR with multi-dimensional arrays. --
-- -------------------------------------------------------------------------------------------------------------- --
 
-- RAM - not initialized at all --
signal mem_ram_b0 : mem8_t(0 to IMEM_SIZE/4-1);
signal mem_ram_b1 : mem8_t(0 to IMEM_SIZE/4-1);
signal mem_ram_b2 : mem8_t(0 to IMEM_SIZE/4-1);
signal mem_ram_b3 : mem8_t(0 to IMEM_SIZE/4-1);
 
-- read data --
signal mem_b0_rd, mem_b1_rd, mem_b2_rd, mem_b3_rd : std_ulogic_vector(7 downto 0);
 
begin
 
-- Sanity Checks --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Using CYCLONE-2-optimized HDL style IMEM." severity note;
assert not (IMEM_AS_IROM = true) report "NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal IMEM as ROM (" & natural'image(IMEM_SIZE) &
" bytes), pre-initialized with application (" & natural'image(imem_app_size_c) & " bytes)." severity note;
--
assert not (IMEM_AS_IROM = false) report "NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal IMEM as blank RAM (" & natural'image(IMEM_SIZE) &
" bytes)." severity note;
--
assert not ((IMEM_AS_IROM = true) and (imem_app_size_c > IMEM_SIZE)) report "NEORV32 PROCESSOR CONFIG ERROR: Application (image = " & natural'image(imem_app_size_c) &
" bytes) does not fit into processor-internal IMEM (ROM = " & natural'image(IMEM_SIZE) & " bytes)!" severity error;
 
 
-- Access Control -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = IMEM_BASE(hi_abb_c downto lo_abb_c)) else '0';
addr <= addr_i(index_size_f(IMEM_SIZE/4)+1 downto 2); -- word aligned
 
 
-- Implement IMEM as pre-initialized ROM --------------------------------------------------
-- -------------------------------------------------------------------------------------------
imem_rom:
if (IMEM_AS_IROM = true) generate
mem_access: process(clk_i)
begin
if rising_edge(clk_i) then
if (acc_en = '1') then -- reduce switching activity when not accessed
mem_rom_rd <= mem_rom(to_integer(unsigned(addr)));
end if;
end if;
end process mem_access;
-- read data --
rdata <= mem_rom_rd;
end generate;
 
 
-- Implement IMEM as not-initialized RAM --------------------------------------------------
-- -------------------------------------------------------------------------------------------
imem_ram:
if (IMEM_AS_IROM = false) generate
mem_access: process(clk_i)
begin
if rising_edge(clk_i) then
addr_ff <= addr;
if (acc_en = '1') then -- reduce switching activity when not accessed
if (wren_i = '1') and (ben_i(0) = '1') then -- byte 0
mem_ram_b0(to_integer(unsigned(addr))) <= data_i(07 downto 00);
end if;
if (wren_i = '1') and (ben_i(1) = '1') then -- byte 1
mem_ram_b1(to_integer(unsigned(addr))) <= data_i(15 downto 08);
end if;
if (wren_i = '1') and (ben_i(2) = '1') then -- byte 2
mem_ram_b2(to_integer(unsigned(addr))) <= data_i(23 downto 16);
end if;
if (wren_i = '1') and (ben_i(3) = '1') then -- byte 3
mem_ram_b3(to_integer(unsigned(addr))) <= data_i(31 downto 24);
end if;
end if;
end if;
end process mem_access;
-- sync(!) read - alternative HDL style --
mem_b0_rd <= mem_ram_b0(to_integer(unsigned(addr_ff)));
mem_b1_rd <= mem_ram_b1(to_integer(unsigned(addr_ff)));
mem_b2_rd <= mem_ram_b2(to_integer(unsigned(addr_ff)));
mem_b3_rd <= mem_ram_b3(to_integer(unsigned(addr_ff)));
-- pack --
rdata <= mem_b3_rd & mem_b2_rd & mem_b1_rd & mem_b0_rd;
end generate;
 
 
-- Bus Feedback ---------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
bus_feedback: process(clk_i)
begin
if rising_edge(clk_i) then
rden <= acc_en and rden_i;
if (IMEM_AS_IROM = true) then
ack_o <= acc_en and rden_i;
else
ack_o <= acc_en and (rden_i or wren_i);
end if;
end if;
end process bus_feedback;
 
-- output gate --
data_o <= rdata when (rden = '1') else (others => '0');
 
 
end neorv32_imem_rtl;
/rtl/core/mem/neorv32_imem.default.vhd
86,7 → 86,7
 
-- Sanity Checks --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Using default platform-agnostic IMEM." severity note;
assert false report "NEORV32 PROCESSOR CONFIG NOTE: Using DEFAULT platform-agnostic IMEM." severity note;
assert not (IMEM_AS_IROM = true) report "NEORV32 PROCESSOR CONFIG NOTE: Implementing processor-internal IMEM as ROM (" & natural'image(IMEM_SIZE) &
" bytes), pre-initialized with application (" & natural'image(imem_app_size_c) & " bytes)." severity note;
--
/rtl/core/neorv32_bus_keeper.vhd
1,15 → 1,9
-- #################################################################################################
-- # << NEORV32 - Bus Keeper (BUSKEEPER) >> #
-- # ********************************************************************************************* #
-- # This unit monitors the processor-internal bus. If the accessed INTERNAL (IMEM if enabled, #
-- # DMEM if enabled, BOOTROM + IO region) module does not respond within the defined number of #
-- # cycles (VHDL package: max_proc_int_response_time_c) the BUS KEEPER asserts the error signal #
-- # to inform the CPU / bus driver. #
-- # #
-- # WARNING: The bus keeper timeout does not track accesses via the processor-external bus #
-- # interface! If the timeout-function of the Wishbone interface is not used, the CPU #
-- # might be permanently stalled by an an unacknowledged transfer! If the external bus #
-- # interface is disabled, ALL accesses by the CPU are internal. #
-- # This unit monitors the processor-internal bus. If the accessed module does not respond within #
-- # the defined number of cycles (VHDL package: max_proc_int_response_time_c) or issues an ERROR #
-- # conditions the BUS KEEPER asserts the error signal to inform the CPU. #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License #
-- # #
50,16 → 44,6
use neorv32.neorv32_package.all;
 
entity neorv32_bus_keeper is
generic (
-- External memory interface --
MEM_EXT_EN : boolean; -- implement external memory bus interface?
-- Internal instruction memory --
MEM_INT_IMEM_EN : boolean; -- implement processor-internal instruction memory
MEM_INT_IMEM_SIZE : natural; -- size of processor-internal instruction memory in bytes
-- Internal data memory --
MEM_INT_DMEM_EN : boolean; -- implement processor-internal data memory
MEM_INT_DMEM_SIZE : natural -- size of processor-internal data memory in bytes
);
port (
-- host access --
clk_i : in std_ulogic; -- global clock line
75,7 → 59,9
bus_rden_i : in std_ulogic; -- read enable
bus_wren_i : in std_ulogic; -- write enable
bus_ack_i : in std_ulogic; -- transfer acknowledge from bus system
bus_err_i : in std_ulogic -- transfer error from bus system
bus_err_i : in std_ulogic; -- transfer error from bus system
bus_tmo_i : in std_ulogic; -- transfer timeout (external interface)
bus_ext_i : in std_ulogic -- external bus access
);
end neorv32_bus_keeper;
 
87,11 → 73,11
 
-- Control register --
constant ctrl_err_type_c : natural := 0; -- r/-: error type: 0=device error, 1=access timeout
constant ctrl_err_src_c : natural := 1; -- r/-: error source: 0=processor-external, 1=processor-internal
constant ctrl_err_flag_c : natural := 31; -- r/c: bus error encountered, sticky; cleared by writing zero
 
-- sticky error flag --
-- sticky error flags --
signal err_flag : std_ulogic;
signal err_type : std_ulogic;
 
-- access control --
signal acc_en : std_ulogic; -- module access enable
98,21 → 84,11
signal wren : std_ulogic; -- word write enable
signal rden : std_ulogic; -- read enable
 
-- bus access check --
type access_check_t is record
int_imem : std_ulogic;
int_dmem : std_ulogic;
int_bootrom_io : std_ulogic;
valid : std_ulogic;
end record;
signal access_check : access_check_t;
 
-- 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);
err_type : std_ulogic;
int_ext : std_ulogic;
bus_err : std_ulogic;
end record;
signal control : control_t;
131,17 → 107,6
rden <= acc_en and rden_i;
 
 
-- Bus Access Check -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- access to processor-internal IMEM or DMEM? --
access_check.int_imem <= '1' when (bus_addr_i(31 downto index_size_f(MEM_INT_IMEM_SIZE)) = imem_base_c(31 downto index_size_f(MEM_INT_IMEM_SIZE))) and (MEM_INT_IMEM_EN = true) else '0';
access_check.int_dmem <= '1' when (bus_addr_i(31 downto index_size_f(MEM_INT_DMEM_SIZE)) = dmem_base_c(31 downto index_size_f(MEM_INT_DMEM_SIZE))) and (MEM_INT_DMEM_EN = true) else '0';
-- access to processor-internal BOOTROM or IO devices? --
access_check.int_bootrom_io <= '1' when (bus_addr_i(31 downto 16) = boot_rom_base_c(31 downto 16)) else '0'; -- hacky!
-- actual internal bus access? --
access_check.valid <= access_check.int_imem or access_check.int_dmem or access_check.int_bootrom_io;
 
 
-- Read/Write Access ----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
rw_access: process(clk_i)
153,15 → 118,16
-- read access --
data_o <= (others => '0');
if (rden = '1') then
data_o(ctrl_err_type_c) <= control.err_type;
data_o(ctrl_err_src_c) <= control.int_ext;
data_o(ctrl_err_type_c) <= err_type;
data_o(ctrl_err_flag_c) <= err_flag;
end if;
--
if (control.bus_err = '1') then
err_flag <= '1'; -- sticky error flag
elsif (rden = '1') then -- clear on read
if (control.bus_err = '1') then -- sticky error flag
err_flag <= '1';
err_type <= control.err_type;
elsif ((wren or rden) = '1') then -- clear on or read or write
err_flag <= '0';
err_type <= '0';
end if;
end if;
end process rw_access;
175,9 → 141,7
control.pending <= '0';
control.bus_err <= '0';
control.err_type <= def_rst_val_c;
control.int_ext <= def_rst_val_c;
control.timeout <= (others => def_rst_val_c);
err_o <= '0';
elsif rising_edge(clk_i) then
-- defaults --
control.bus_err <= '0';
186,36 → 150,31
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)));
if (bus_rden_i = '1') or (bus_wren_i = '1') then
if (access_check.valid = '1') or (MEM_EXT_EN = false) then
control.int_ext <= '1'; -- processor-internal access
else
control.int_ext <= '0'; -- processor-external access
end if;
control.pending <= '1';
end if;
 
-- access monitor: PENDING --
else
control.timeout <= std_ulogic_vector(unsigned(control.timeout) - 1); -- countdown timer
if (bus_ack_i = '1') then -- normal termination by bus system
control.err_type <= '0'; -- don't care
control.bus_err <= '0';
control.pending <= '0';
elsif (bus_err_i = '1') then -- error termination by bus system
if (bus_err_i = '1') then -- error termination by bus system
control.err_type <= '0'; -- device error
control.bus_err <= '1';
control.pending <= '0';
elsif (or_reduce_f(control.timeout) = '0') and (control.int_ext = '1') then -- timeout! terminate bus transfer (internal accesses only!)
elsif ((or_reduce_f(control.timeout) = '0') and (bus_ext_i = '0')) or -- internal access timeout
(bus_tmo_i = '1') then -- external access timeout
control.err_type <= '1'; -- timeout error
control.bus_err <= '1';
control.pending <= '0';
elsif (bus_ack_i = '1') then -- normal termination by bus system
control.err_type <= '0'; -- don't care
control.bus_err <= '0';
control.pending <= '0';
end if;
end if;
 
-- only output timeout errors here - device errors are already propagated by the bus system --
err_o <= control.bus_err and control.err_type;
end if;
end process keeper_control;
 
-- signal bus error to CPU --
err_o <= control.bus_err;
 
 
end neorv32_bus_keeper_rtl;
/rtl/core/neorv32_cfs.vhd
59,6 → 59,7
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
err_o : out std_ulogic; -- transfer error
-- clock generator --
clkgen_en_o : out std_ulogic; -- enable clock generator
clkgen_i : in std_ulogic_vector(07 downto 0); -- "clock" inputs
101,7 → 102,14
-- NOTE: Do not modify the CFS base address or the CFS' occupied address space as this might cause access
-- collisions with other modules.
 
-- This module provides an ERROR signal to signal a faulty access operation to the CPU.
-- It can be used to indicate an invalid access (for example to an unused CFS register address) or to signal
-- a faulty state (like "not operational yet"). The error signal can be checked be checked by the applications
-- "bus access fault" exception handler (provided by the system's BUSKEEPER module).
-- This signal may only be set when the module is actually accessed! Tie to zero if not explicitly used.
err_o <= '0';
 
 
-- CFS Generics ---------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- In its default version, the CFS provides the configuration generics. single generic:
/rtl/core/neorv32_cpu.vhd
156,6 → 156,7
signal be_store : std_ulogic; -- bus error on store data access
signal fetch_pc : std_ulogic_vector(data_width_c-1 downto 0); -- pc for instruction fetch
signal curr_pc : std_ulogic_vector(data_width_c-1 downto 0); -- current pc (for current executed instruction)
signal next_pc : std_ulogic_vector(data_width_c-1 downto 0); -- next pc (for next executed instruction)
signal fpu_flags : std_ulogic_vector(4 downto 0); -- FPU exception flags
 
-- pmp interface --
285,6 → 286,7
imm_o => imm, -- immediate
fetch_pc_o => fetch_pc, -- PC for instruction fetch
curr_pc_o => curr_pc, -- current PC (corresponding to current instruction)
next_pc_o => next_pc, -- next PC (corresponding to next instruction)
csr_rdata_o => csr_rdata, -- CSR read data
-- FPU interface --
fpu_flags_i => fpu_flags, -- exception flags
355,7 → 357,8
-- data input --
rs1_i => rs1, -- rf source 1
rs2_i => rs2, -- rf source 2
pc2_i => curr_pc, -- delayed PC
pc_i => curr_pc, -- current PC
pc2_i => next_pc, -- next PC
imm_i => imm, -- immediate
csr_i => csr_rdata, -- CSR read data
-- data output --
/rtl/core/neorv32_cpu_alu.vhd
60,7 → 60,8
-- data input --
rs1_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 1
rs2_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 2
pc2_i : in std_ulogic_vector(data_width_c-1 downto 0); -- delayed PC
pc_i : in std_ulogic_vector(data_width_c-1 downto 0); -- current PC
pc2_i : in std_ulogic_vector(data_width_c-1 downto 0); -- next PC
imm_i : in std_ulogic_vector(data_width_c-1 downto 0); -- immediate
csr_i : in std_ulogic_vector(data_width_c-1 downto 0); -- CSR read data
-- data output --
85,10 → 86,8
 
-- results --
signal addsub_res : std_ulogic_vector(data_width_c downto 0);
--
signal alu_res : std_ulogic_vector(data_width_c-1 downto 0);
signal cp_res : std_ulogic_vector(data_width_c-1 downto 0);
signal arith_res : std_ulogic_vector(data_width_c-1 downto 0);
signal logic_res : std_ulogic_vector(data_width_c-1 downto 0);
 
-- co-processor arbiter and interface --
type cp_ctrl_t is record
119,7 → 118,7
 
-- ALU Input Operand Mux ------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
opa <= pc2_i when (ctrl_i(ctrl_alu_opa_mux_c) = '1') else rs1_i; -- operand a (first ALU input operand), only required for arithmetic ops
opa <= pc_i when (ctrl_i(ctrl_alu_opa_mux_c) = '1') else rs1_i; -- operand a (first ALU input operand), only required for arithmetic ops
opb <= imm_i when (ctrl_i(ctrl_alu_opb_mux_c) = '1') else rs2_i; -- operand b (second ALU input operand)
 
 
136,7 → 135,7
op_a_v := (opa(opa'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & opa;
op_b_v := (opb(opb'left) and (not ctrl_i(ctrl_alu_unsigned_c))) & opb;
-- add/sub(slt) select --
if (ctrl_i(ctrl_alu_addsub_c) = '1') then -- subtraction
if (ctrl_i(ctrl_alu_op0_c) = '1') then -- subtraction
op_y_v := not op_b_v;
cin_v(0) := '1';
else -- addition
143,25 → 142,49
op_y_v := op_b_v;
cin_v(0) := '0';
end if;
-- adder core (result + carry/borrow) --
-- adder core --
addsub_res <= std_ulogic_vector(unsigned(op_a_v) + unsigned(op_y_v) + unsigned(cin_v(0 downto 0)));
end process binary_arithmetic_core;
 
-- direct output of address result --
-- direct output of adder result --
add_o <= addsub_res(data_width_c-1 downto 0);
 
-- ALU arithmetic logic core --
arithmetic_core: process(ctrl_i, addsub_res)
 
-- ALU Operation Select -------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
alu_core: process(ctrl_i, addsub_res, rs1_i, opb)
begin
if (ctrl_i(ctrl_alu_arith_c) = alu_arith_cmd_addsub_c) then -- ADD/SUB
arith_res <= addsub_res(data_width_c-1 downto 0);
else -- SLT
arith_res <= (others => '0');
arith_res(0) <= addsub_res(addsub_res'left); -- => carry/borrow
end if;
end process arithmetic_core;
case ctrl_i(ctrl_alu_op2_c downto ctrl_alu_op0_c) is
when alu_op_add_c => alu_res <= addsub_res(data_width_c-1 downto 0); -- (default)
when alu_op_sub_c => alu_res <= addsub_res(data_width_c-1 downto 0);
-- when alu_op_mova_c => alu_res <= rs1_i; -- FIXME
when alu_op_slt_c => alu_res <= (others => '0'); alu_res(0) <= addsub_res(addsub_res'left); -- => carry/borrow
when alu_op_movb_c => alu_res <= opb;
when alu_op_xor_c => alu_res <= rs1_i xor opb; -- only rs1 required for logic ops (opa would also contain pc)
when alu_op_or_c => alu_res <= rs1_i or opb;
when alu_op_and_c => alu_res <= rs1_i and opb;
when others => alu_res <= addsub_res(data_width_c-1 downto 0);
end case;
end process alu_core;
 
-- ALU Function Select --------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
alu_function_mux: process(ctrl_i, alu_res, pc2_i, csr_i, cp_res)
begin
case ctrl_i(ctrl_alu_func1_c downto ctrl_alu_func0_c) is
when alu_func_core_c => res_o <= alu_res; -- (default)
when alu_func_nxpc_c => res_o <= pc2_i;
when alu_func_csrr_c => res_o <= csr_i;
when alu_func_copro_c => res_o <= cp_res;
when others => res_o <= alu_res; -- undefined
end case;
end process alu_function_mux;
 
 
-- **************************************************************************************************************************
-- Co-Processors
-- **************************************************************************************************************************
 
-- Co-Processor Arbiter -------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- Interface:
193,7 → 216,7
end process cp_arbiter;
 
-- is co-processor operation? --
cp_ctrl.cmd <= '1' when (ctrl_i(ctrl_alu_func1_c downto ctrl_alu_func0_c) = alu_func_cmd_copro_c) else '0';
cp_ctrl.cmd <= '1' when (ctrl_i(ctrl_alu_func1_c downto ctrl_alu_func0_c) = alu_func_copro_c) else '0';
cp_ctrl.start <= '1' when (cp_ctrl.cmd = '1') and (cp_ctrl.cmd_ff = '0') else '0';
 
-- co-processor select / star trigger --
209,38 → 232,6
cp_res <= cp_result(0) or cp_result(1) or cp_result(2) or cp_result(3);
 
 
-- ALU Logic Core -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
alu_logic_core: process(ctrl_i, rs1_i, opb)
begin
case ctrl_i(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) is
when alu_logic_cmd_movb_c => logic_res <= opb; -- (default)
when alu_logic_cmd_xor_c => logic_res <= rs1_i xor opb; -- only rs1 required for logic ops (opa would also contain pc)
when alu_logic_cmd_or_c => logic_res <= rs1_i or opb;
when alu_logic_cmd_and_c => logic_res <= rs1_i and opb;
when others => logic_res <= opb; -- undefined
end case;
end process alu_logic_core;
 
 
-- ALU Function Select --------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
alu_function_mux: process(ctrl_i, arith_res, logic_res, csr_i, cp_res)
begin
case ctrl_i(ctrl_alu_func1_c downto ctrl_alu_func0_c) is
when alu_func_cmd_arith_c => res_o <= arith_res; -- (default)
when alu_func_cmd_logic_c => res_o <= logic_res;
when alu_func_cmd_csrr_c => res_o <= csr_i;
when alu_func_cmd_copro_c => res_o <= cp_res;
when others => res_o <= arith_res; -- undefined
end case;
end process alu_function_mux;
 
 
-- **************************************************************************************************************************
-- Co-Processors
-- **************************************************************************************************************************
 
-- Co-Processor 0: Shifter (CPU Core ISA) --------------------------------------------------
-- -------------------------------------------------------------------------------------------
neorv32_cpu_cp_shifter_inst: neorv32_cpu_cp_shifter
/rtl/core/neorv32_cpu_control.vhd
94,6 → 94,7
imm_o : out std_ulogic_vector(data_width_c-1 downto 0); -- immediate
fetch_pc_o : out std_ulogic_vector(data_width_c-1 downto 0); -- PC for instruction fetch
curr_pc_o : out std_ulogic_vector(data_width_c-1 downto 0); -- current PC (corresponding to current instruction)
next_pc_o : out std_ulogic_vector(data_width_c-1 downto 0); -- next PC (corresponding to next instruction)
csr_rdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- CSR read data
-- FPU interface --
fpu_flags_i : in std_ulogic_vector(04 downto 0); -- exception flags
185,7 → 186,6
 
-- instruction decoding helper logic --
type decode_aux_t is record
alu_immediate : std_ulogic;
is_atomic_lr : std_ulogic;
is_atomic_sc : std_ulogic;
is_float_op : std_ulogic;
194,6 → 194,9
is_m_div : std_ulogic;
is_bitmanip_imm : std_ulogic;
is_bitmanip_reg : std_ulogic;
rs1_zero : std_ulogic;
rs2_zero : std_ulogic;
rd_zero : std_ulogic;
end record;
signal decode_aux : decode_aux_t;
 
359,8 → 362,8
signal debug_ctrl : debug_ctrl_t;
 
-- (hpm) counter events --
signal cnt_event, cnt_event_nxt : std_ulogic_vector(hpmcnt_event_size_c-1 downto 0);
signal hpmcnt_trigger : std_ulogic_vector(HPM_NUM_CNTS-1 downto 0);
signal cnt_event : std_ulogic_vector(hpmcnt_event_size_c-1 downto 0);
signal hpmcnt_trigger : std_ulogic_vector(HPM_NUM_CNTS-1 downto 0);
 
-- illegal instruction check --
signal illegal_opcode_lsbs : std_ulogic; -- opcode != rv32
496,14 → 499,9
issue_engine.buf <= (others => '0');
elsif rising_edge(clk_i) then
if (ipb.clear = '1') then
if (CPU_EXTENSION_RISCV_C = true) then
if (execute_engine.pc(1) = '1') then -- branch to unaligned address?
issue_engine.state <= ISSUE_REALIGN;
issue_engine.align <= '1'; -- aligned on 16-bit boundary
else
issue_engine.state <= issue_engine.state_nxt;
issue_engine.align <= '0'; -- aligned on 32-bit boundary
end if;
if (CPU_EXTENSION_RISCV_C = true) and (execute_engine.pc(1) = '1') then -- branch to unaligned address?
issue_engine.state <= ISSUE_REALIGN;
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
623,42 → 621,45
if (rstn_i = '0') then
imm_o <= (others => def_rst_val_c);
elsif rising_edge(clk_i) then
if (execute_engine.state = BRANCH) then -- next_PC as immediate for jump-and-link operations (=return address) via ALU.MOV_B
imm_o <= execute_engine.next_pc;
else -- "normal" immediate from instruction word
opcode_v := execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11";
case opcode_v is -- save some bits here, the two LSBs are always "11" for rv32
when opcode_store_c => -- S-immediate
imm_o(31 downto 11) <= (others => execute_engine.i_reg(31)); -- sign extension
imm_o(10 downto 05) <= execute_engine.i_reg(30 downto 25);
imm_o(04 downto 01) <= execute_engine.i_reg(11 downto 08);
imm_o(00) <= execute_engine.i_reg(07);
when opcode_branch_c => -- B-immediate
imm_o(31 downto 12) <= (others => execute_engine.i_reg(31)); -- sign extension
imm_o(11) <= execute_engine.i_reg(07);
imm_o(10 downto 05) <= execute_engine.i_reg(30 downto 25);
imm_o(04 downto 01) <= execute_engine.i_reg(11 downto 08);
imm_o(00) <= '0';
when opcode_lui_c | opcode_auipc_c => -- U-immediate
imm_o(31 downto 20) <= execute_engine.i_reg(31 downto 20);
imm_o(19 downto 12) <= execute_engine.i_reg(19 downto 12);
imm_o(11 downto 00) <= (others => '0');
when opcode_jal_c => -- J-immediate
imm_o(31 downto 20) <= (others => execute_engine.i_reg(31)); -- sign extension
imm_o(19 downto 12) <= execute_engine.i_reg(19 downto 12);
imm_o(11) <= execute_engine.i_reg(20);
imm_o(10 downto 05) <= execute_engine.i_reg(30 downto 25);
imm_o(04 downto 01) <= execute_engine.i_reg(24 downto 21);
imm_o(00) <= '0';
when opcode_atomic_c => -- atomic memory access
imm_o <= (others => '0'); -- effective address is addr = reg + 0 = reg
when others => -- I-immediate
imm_o(31 downto 11) <= (others => execute_engine.i_reg(31)); -- sign extension
imm_o(10 downto 05) <= execute_engine.i_reg(30 downto 25);
imm_o(04 downto 01) <= execute_engine.i_reg(24 downto 21);
imm_o(00) <= execute_engine.i_reg(20);
end case;
end if;
-- default: I-immediate: ALU-immediate, loads, jump-and-link with registers
imm_o(31 downto 11) <= (others => execute_engine.i_reg(31)); -- sign extension
imm_o(10 downto 05) <= execute_engine.i_reg(30 downto 25);
imm_o(04 downto 01) <= execute_engine.i_reg(24 downto 21);
imm_o(00) <= execute_engine.i_reg(20);
 
opcode_v := execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11";
case opcode_v is -- save some bits here, the two LSBs are always "11" for rv32
when opcode_store_c => -- S-immediate: store
imm_o(31 downto 11) <= (others => execute_engine.i_reg(31)); -- sign extension
imm_o(10 downto 05) <= execute_engine.i_reg(30 downto 25);
imm_o(04 downto 01) <= execute_engine.i_reg(11 downto 08);
imm_o(00) <= execute_engine.i_reg(07);
when opcode_branch_c => -- B-immediate: conditional branches
imm_o(31 downto 12) <= (others => execute_engine.i_reg(31)); -- sign extension
imm_o(11) <= execute_engine.i_reg(07);
imm_o(10 downto 05) <= execute_engine.i_reg(30 downto 25);
imm_o(04 downto 01) <= execute_engine.i_reg(11 downto 08);
imm_o(00) <= '0';
when opcode_lui_c | opcode_auipc_c => -- U-immediate: lui, auipc
imm_o(31 downto 20) <= execute_engine.i_reg(31 downto 20);
imm_o(19 downto 12) <= execute_engine.i_reg(19 downto 12);
imm_o(11 downto 00) <= (others => '0');
when opcode_jal_c => -- J-immediate: unconditional jumps
imm_o(31 downto 20) <= (others => execute_engine.i_reg(31)); -- sign extension
imm_o(19 downto 12) <= execute_engine.i_reg(19 downto 12);
imm_o(11) <= execute_engine.i_reg(20);
imm_o(10 downto 05) <= execute_engine.i_reg(30 downto 25);
imm_o(04 downto 01) <= execute_engine.i_reg(24 downto 21);
imm_o(00) <= '0';
when opcode_atomic_c => -- atomic memory access and everything else
if (CPU_EXTENSION_RISCV_A = true) then
imm_o <= (others => '0'); -- effective address is addr = reg + 0 = reg
else
NULL; -- use default
end if;
when others => -- I-immediate
NULL; -- use default
end case;
end if;
end process imm_gen;
 
688,10 → 689,10
begin
if (rstn_i = '0') then
-- registers that DO require a specific reset state --
execute_engine.pc <= CPU_BOOT_ADDR(data_width_c-1 downto 2) & "00"; -- 32-bit aligned!
execute_engine.state <= SYS_WAIT;
execute_engine.sleep <= '0';
execute_engine.branched <= '1'; -- reset is a branch from "somewhere"
execute_engine.pc <= CPU_BOOT_ADDR(data_width_c-1 downto 2) & "00"; -- 32-bit aligned!
execute_engine.state <= SYS_WAIT;
execute_engine.sleep <= '0';
execute_engine.branched <= '1'; -- reset is a branch from "somewhere"
-- no dedicated RESET required --
execute_engine.state_prev <= SYS_WAIT; -- actual reset value is not relevant
execute_engine.i_reg <= (others => def_rst_val_c);
701,7 → 702,6
execute_engine.i_reg_last <= (others => def_rst_val_c);
execute_engine.next_pc <= (others => def_rst_val_c);
ctrl <= (others => def_rst_val_c);
--
ctrl(ctrl_bus_rd_c) <= '0';
ctrl(ctrl_bus_wr_c) <= '0';
elsif rising_edge(clk_i) then
713,12 → 713,11
execute_engine.pc <= alu_add_i(data_width_c-1 downto 1) & '0'; -- jump/taken_branch
end if;
end if;
--
execute_engine.state <= execute_engine.state_nxt;
execute_engine.sleep <= execute_engine.sleep_nxt;
execute_engine.branched <= execute_engine.branched_nxt;
--
 
execute_engine.state <= execute_engine.state_nxt;
execute_engine.state_prev <= execute_engine.state;
execute_engine.sleep <= execute_engine.sleep_nxt;
execute_engine.branched <= execute_engine.branched_nxt;
execute_engine.i_reg <= execute_engine.i_reg_nxt;
execute_engine.is_ci <= execute_engine.is_ci_nxt;
execute_engine.is_ici <= execute_engine.is_ici_nxt;
731,7 → 730,7
 
-- next PC --
case execute_engine.state is
when TRAP_ENTER =>
when TRAP_ENTER => -- ENTERING trap environment
if (CPU_EXTENSION_RISCV_DEBUG = false) then -- normal trapping
execute_engine.next_pc <= csr.mtvec(data_width_c-1 downto 1) & '0'; -- trap enter
else -- DEBUG MODE enabled
743,13 → 742,13
execute_engine.next_pc <= csr.mtvec(data_width_c-1 downto 1) & '0'; -- trap enter
end if;
end if;
when TRAP_EXIT =>
when TRAP_EXIT => -- LEAVING trap environment
if (CPU_EXTENSION_RISCV_DEBUG = false) or (debug_ctrl.running = '0') then -- normal end of trap
execute_engine.next_pc <= csr.mepc(data_width_c-1 downto 1) & '0'; -- trap exit
else -- DEBUG MODE exiting
execute_engine.next_pc <= csr.dpc(data_width_c-1 downto 1) & '0'; -- debug mode exit
end if;
when EXECUTE =>
when EXECUTE => -- NORMAL pc increment
execute_engine.next_pc <= std_ulogic_vector(unsigned(execute_engine.pc) + unsigned(execute_engine.next_pc_inc)); -- next linear PC
when others =>
NULL;
765,7 → 764,8
execute_engine.next_pc_inc <= x"00000004" when ((execute_engine.is_ci = '0') or (CPU_EXTENSION_RISCV_C = false)) else x"00000002";
 
-- PC output --
curr_pc_o <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- PC for ALU ops
curr_pc_o <= execute_engine.pc(data_width_c-1 downto 1) & '0'; -- current PC for ALU ops
next_pc_o <= execute_engine.next_pc(data_width_c-1 downto 1) & '0'; -- next PC for ALU ops
 
-- CSR access address --
csr.addr <= execute_engine.i_reg(instr_csr_id_msb_c downto instr_csr_id_lsb_c);
817,7 → 817,6
variable sys_env_cmd_mask_v : std_ulogic_vector(11 downto 0);
begin
-- defaults --
decode_aux.alu_immediate <= '0';
decode_aux.is_atomic_lr <= '0';
decode_aux.is_atomic_sc <= '0';
decode_aux.is_float_op <= '0';
825,12 → 824,12
decode_aux.is_m_div <= '0';
decode_aux.is_bitmanip_imm <= '0';
decode_aux.is_bitmanip_reg <= '0';
decode_aux.rs1_zero <= '0';
decode_aux.rs2_zero <= '0';
decode_aux.rd_zero <= '0';
 
-- is immediate ALU operation? --
decode_aux.alu_immediate <= not execute_engine.i_reg(instr_opcode_msb_c-1);
 
-- is atomic load-reservate/store-conditional? --
if (CPU_EXTENSION_RISCV_A = true) and (execute_engine.i_reg(instr_opcode_lsb_c+3 downto instr_opcode_lsb_c+2) = "11") then -- valid atomic sub-opcode
if (CPU_EXTENSION_RISCV_A = true) and (execute_engine.i_reg(instr_opcode_lsb_c+2) = '1') then -- valid atomic sub-opcode
decode_aux.is_atomic_lr <= not execute_engine.i_reg(instr_funct5_lsb_c);
decode_aux.is_atomic_sc <= execute_engine.i_reg(instr_funct5_lsb_c);
end if;
850,7 → 849,7
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0110000") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "101")) or -- RORI
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0010100") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "101") and (execute_engine.i_reg(instr_funct12_lsb_c+4 downto instr_funct12_lsb_c) = "00111")) or -- ORCB
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0110100") and (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "101") and (execute_engine.i_reg(instr_funct12_lsb_c+4 downto instr_funct12_lsb_c) = "11000")) then -- REV8
decode_aux.is_bitmanip_imm <= '1';
decode_aux.is_bitmanip_imm <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B); -- BITMANIP implemented at all?
end if;
-- register operation --
if ((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0110000") and (execute_engine.i_reg(instr_funct3_msb_c-1 downto instr_funct3_lsb_c) = "01")) or -- ROR / ROL
870,7 → 869,7
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "110") -- SH3ADD
)
) then
decode_aux.is_bitmanip_reg <= '1';
decode_aux.is_bitmanip_reg <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B); -- BITMANIP implemented at all?
end if;
 
-- floating-point operations (Zfinx) --
882,7 → 881,7
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "10100") and (execute_engine.i_reg(instr_funct3_msb_c) = '0')) or -- FEQ.S / FLT.S / FLE.S
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "11010") and (execute_engine.i_reg(instr_funct12_lsb_c+4 downto instr_funct12_lsb_c+1) = "0000")) or -- FCVT.S.W*
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c+2) = "11000") and (execute_engine.i_reg(instr_funct12_lsb_c+4 downto instr_funct12_lsb_c+1) = "0000")) then -- FCVT.W*.S
decode_aux.is_float_op <= '1';
decode_aux.is_float_op <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zfinx); -- FPU implemented at all?
end if;
 
-- system/environment instructions --
892,9 → 891,14
-- integer MUL (M/Zmmul) / DIV (M) operation --
if (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alu_c(5)) and
(execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0000001") then
decode_aux.is_m_mul <= not execute_engine.i_reg(instr_funct3_msb_c);
decode_aux.is_m_div <= execute_engine.i_reg(instr_funct3_msb_c);
decode_aux.is_m_mul <= (not execute_engine.i_reg(instr_funct3_msb_c)) and (bool_to_ulogic_f(CPU_EXTENSION_RISCV_M) or bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zmmul));
decode_aux.is_m_div <= execute_engine.i_reg(instr_funct3_msb_c) and bool_to_ulogic_f(CPU_EXTENSION_RISCV_M);
end if;
 
-- register address checks --
decode_aux.rs1_zero <= not or_reduce_f(execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c));
decode_aux.rs2_zero <= not or_reduce_f(execute_engine.i_reg(instr_rs2_msb_c downto instr_rs2_lsb_c));
decode_aux.rd_zero <= not or_reduce_f(execute_engine.i_reg(instr_rd_msb_c downto instr_rd_lsb_c));
end process decode_helper;
 
 
937,9 → 941,8
-- CONTROL DEFAULTS --
ctrl_nxt <= (others => '0'); -- default: all off
-- ALU main control --
ctrl_nxt(ctrl_alu_addsub_c) <= '0'; -- ADD(I)
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_arith_c; -- default ALU function select: arithmetic
ctrl_nxt(ctrl_alu_arith_c) <= alu_arith_cmd_addsub_c; -- default ALU arithmetic operation: ADDSUB
ctrl_nxt(ctrl_alu_op2_c downto ctrl_alu_op0_c) <= alu_op_add_c; -- default ALU operation: ADD
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_core_c; -- default ALU operation: ADD
-- ALU sign control --
if (execute_engine.i_reg(instr_opcode_lsb_c+4) = '1') then -- ALU ops
ctrl_nxt(ctrl_alu_unsigned_c) <= execute_engine.i_reg(instr_funct3_lsb_c+0); -- unsigned ALU operation? (SLTIU, SLTU)
946,12 → 949,8
else -- branches
ctrl_nxt(ctrl_alu_unsigned_c) <= execute_engine.i_reg(instr_funct3_lsb_c+1); -- unsigned branches? (BLTU, BGEU)
end if;
-- Atomic store-conditional instruction (evaluate lock status) --
if (CPU_EXTENSION_RISCV_A = true) then
ctrl_nxt(ctrl_bus_ch_lock_c) <= decode_aux.is_atomic_sc;
else
ctrl_nxt(ctrl_bus_ch_lock_c) <= '0';
end if;
-- atomic store-conditional instruction (evaluate lock status) --
ctrl_nxt(ctrl_bus_ch_lock_c) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_A) and decode_aux.is_atomic_sc;
 
 
-- state machine --
975,14 → 974,15
execute_engine.branched_nxt <= '0';
execute_engine.pc_we <= not execute_engine.branched; -- update PC with linear next_pc if there was no actual branch
-- IR update - exceptions --
trap_ctrl.instr_ma <= cmd_issue.data(33); -- misaligned instruction fetch address
trap_ctrl.instr_ma <= cmd_issue.data(33) and (not bool_to_ulogic_f(CPU_EXTENSION_RISCV_C)); -- misaligned instruction fetch address, if C disabled
trap_ctrl.instr_be <= cmd_issue.data(34); -- bus access fault during instruction fetch
execute_engine.is_ici_nxt <= cmd_issue.data(35); -- invalid decompressed instruction
-- any reason to go to trap state? --
if (execute_engine.sleep = '1') or -- WFI instruction - this will enter sleep state
if (execute_engine.sleep = '1') or -- enter sleep state
(trap_ctrl.exc_fire = '1') or -- exception during LAST instruction (illegal instruction)
(trap_ctrl.env_start = '1') or -- pending trap (IRQ or exception)
((cmd_issue.data(33) or cmd_issue.data(34)) = '1') then -- exception during instruction fetch of the NEW instruction
((cmd_issue.data(33) = '1') and (CPU_EXTENSION_RISCV_C = false)) or -- misaligned instruction fetch address, if C disabled
(cmd_issue.data(34) = '1') then -- bus access fault during instruction fetch
execute_engine.state_nxt <= TRAP_ENTER;
else
execute_engine.state_nxt <= EXECUTE;
997,12 → 997,14
execute_engine.state_nxt <= TRAP_EXECUTE;
end if;
 
 
when TRAP_EXIT => -- Return from trap environment - get xEPC
-- ------------------------------------------------------------
trap_ctrl.env_end <= '1';
execute_engine.state_nxt <= TRAP_EXECUTE;
 
when TRAP_EXECUTE => -- Start trap environment -> jump to xTVEC / return from trap environment -> jump to xEPC
 
when TRAP_EXECUTE => -- Process trap environment -> jump to xTVEC / return from trap environment -> jump to xEPC
-- ------------------------------------------------------------
execute_engine.pc_mux_sel <= '0'; -- next_PC
fetch_engine.reset <= '1';
1018,109 → 1020,76
 
when opcode_alu_c | opcode_alui_c => -- (register/immediate) ALU operation
-- ------------------------------------------------------------
ctrl_nxt(ctrl_alu_opa_mux_c) <= '0'; -- use RS1 as ALU.OPA
ctrl_nxt(ctrl_alu_opb_mux_c) <= decode_aux.alu_immediate; -- use IMM as ALU.OPB for immediate operations
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU result
ctrl_nxt(ctrl_alu_opb_mux_c) <= not execute_engine.i_reg(instr_opcode_msb_c-1); -- use IMM as ALU.OPB for immediate operations
 
-- ALU arithmetic operation type --
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_slt_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sltu_c) then
ctrl_nxt(ctrl_alu_arith_c) <= alu_arith_cmd_slt_c;
else
ctrl_nxt(ctrl_alu_arith_c) <= alu_arith_cmd_addsub_c;
end if;
 
-- ADD/SUB --
if ((decode_aux.alu_immediate = '0') and (execute_engine.i_reg(instr_funct7_msb_c-1) = '1')) or -- not an immediate op and funct7.6 set => SUB
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_slt_c) or -- SLT operation
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sltu_c) then -- SLTU operation
ctrl_nxt(ctrl_alu_addsub_c) <= '1'; -- SUB/SLT
else
ctrl_nxt(ctrl_alu_addsub_c) <= '0'; -- ADD(I)
end if;
 
-- ALU logic operation --
-- ALU core operation --
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is -- actual ALU.logic operation (re-coding)
when funct3_xor_c => ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_xor_c; -- XOR(I)
when funct3_or_c => ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_or_c; -- OR(I)
when others => ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_and_c; -- AND(I)
when funct3_subadd_c => -- ADD(I)/SUB
if ((execute_engine.i_reg(instr_opcode_msb_c-1) = '1') and (execute_engine.i_reg(instr_funct7_msb_c-1) = '1')) then -- not an immediate op and funct7.6 set => SUB
ctrl_nxt(ctrl_alu_op2_c downto ctrl_alu_op0_c) <= alu_op_sub_c;
else
ctrl_nxt(ctrl_alu_op2_c downto ctrl_alu_op0_c) <= alu_op_add_c;
end if;
when funct3_slt_c | funct3_sltu_c => -- SLT(I), SLTU(I)
ctrl_nxt(ctrl_alu_op2_c downto ctrl_alu_op0_c) <= alu_op_slt_c;
when funct3_xor_c => -- XOR(I)
ctrl_nxt(ctrl_alu_op2_c downto ctrl_alu_op0_c) <= alu_op_xor_c;
when funct3_or_c => -- OR(I)
ctrl_nxt(ctrl_alu_op2_c downto ctrl_alu_op0_c) <= alu_op_or_c;
when others => -- AND(I), multi-cycle / co-processor operations
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? --
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_cmd_copro_c;
-- co-processor bit manipulation operation? --
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? --
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
(((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
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_cmd_copro_c;
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? --
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) --
else
-- ALU operation, function select --
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)
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is
when funct3_sll_c | funct3_sr_c => -- SHIFT operation
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
when funct3_xor_c | funct3_or_c | funct3_and_c => -- LOGIC operation
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_logic_c;
when others => -- ARITHMETIC operation
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_arith_c;
end case;
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
execute_engine.state_nxt <= DISPATCH;
end if;
 
-- multi cycle ALU operation? --
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sll_c) or -- SLL shift operation?
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sr_c) or -- SR shift operation?
((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')) or -- MUL
((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 -- BITMANIP CP register operation?
((execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_alui_c(5)) and (decode_aux.is_bitmanip_imm = '1'))) -- BITMANIP CP immediate operation?
) then
execute_engine.state_nxt <= ALU_WAIT;
else -- single cycle ALU operation
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
execute_engine.state_nxt <= DISPATCH;
end if;
 
when opcode_lui_c | opcode_auipc_c => -- load upper immediate / add upper immediate to PC
-- ------------------------------------------------------------
ctrl_nxt(ctrl_alu_opa_mux_c) <= '1'; -- ALU.OPA = PC (for AUIPC only)
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB
ctrl_nxt(ctrl_alu_arith_c) <= alu_arith_cmd_addsub_c; -- ADD
ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_movb_c; -- MOVB
if (execute_engine.i_reg(instr_opcode_lsb_c+5) = opcode_lui_c(5)) then -- LUI
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_logic_c; -- actual ALU operation = MOVB
ctrl_nxt(ctrl_alu_op2_c downto ctrl_alu_op0_c) <= alu_op_movb_c; -- actual ALU operation = MOVB
else -- AUIPC
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_arith_c; -- actual ALU operation = ADD
ctrl_nxt(ctrl_alu_op2_c downto ctrl_alu_op0_c) <= alu_op_add_c; -- actual ALU operation = ADD
end if;
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU result
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
execute_engine.state_nxt <= DISPATCH;
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
execute_engine.state_nxt <= DISPATCH;
 
 
when opcode_load_c | opcode_store_c | opcode_atomic_c => -- load/store / atomic memory access
-- ------------------------------------------------------------
ctrl_nxt(ctrl_alu_opa_mux_c) <= '0'; -- use RS1 as ALU.OPA
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB
ctrl_nxt(ctrl_bus_mo_we_c) <= '1'; -- write to MAR and MDO (MDO only relevant for store)
--
if (CPU_EXTENSION_RISCV_A = false) or -- atomic extension disabled
(execute_engine.i_reg(instr_opcode_lsb_c+3 downto instr_opcode_lsb_c+2) = "00") then -- normal integer load/store
execute_engine.state_nxt <= LOADSTORE_0;
else -- atomic operation
if (execute_engine.i_reg(instr_funct5_msb_c downto instr_funct5_lsb_c) = funct5_a_sc_c) or -- store-conditional
(execute_engine.i_reg(instr_funct5_msb_c downto instr_funct5_lsb_c) = funct5_a_lr_c) then -- load-reservate
execute_engine.state_nxt <= LOADSTORE_0;
else -- unimplemented (atomic) instruction
execute_engine.state_nxt <= SYS_WAIT;
end if;
end if;
execute_engine.state_nxt <= LOADSTORE_0;
 
 
when opcode_branch_c | opcode_jal_c | opcode_jalr_c => -- branch / jump and link (with register)
-- ------------------------------------------------------------
-- target address (ALU.ADD) operands --
if (execute_engine.i_reg(instr_opcode_lsb_c+3 downto instr_opcode_lsb_c+2) = opcode_jalr_c(3 downto 2)) then -- JALR
ctrl_nxt(ctrl_alu_opa_mux_c) <= '0'; -- use RS1 as ALU.OPA (branch target address base)
else -- JAL
1129,21 → 1098,21
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB (branch target address offset)
execute_engine.state_nxt <= BRANCH;
 
 
when opcode_fence_c => -- fence operations
-- ------------------------------------------------------------
if (execute_engine.i_reg(instr_funct3_lsb_c) = funct3_fence_c(0)) then -- FENCE
ctrl_nxt(ctrl_bus_fence_c) <= '1';
execute_engine.state_nxt <= SYS_WAIT;
else -- FENCE.I
if (CPU_EXTENSION_RISCV_Zifencei = true) then
ctrl_nxt(ctrl_bus_fencei_c) <= '1';
execute_engine.branched_nxt <= '1'; -- this is an actual branch
execute_engine.state_nxt <= TRAP_EXECUTE; -- use TRAP_EXECUTE to "modify" PC (PC <= PC)
else -- fence.i not implemented
execute_engine.state_nxt <= SYS_WAIT;
end if;
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fence_c) then -- FENCE
ctrl_nxt(ctrl_bus_fence_c) <= '1';
execute_engine.state_nxt <= SYS_WAIT;
elsif (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fencei_c) and (CPU_EXTENSION_RISCV_Zifencei = true) then -- FENCE.I
ctrl_nxt(ctrl_bus_fencei_c) <= '1';
execute_engine.branched_nxt <= '1'; -- this is an actual branch
execute_engine.state_nxt <= TRAP_EXECUTE; -- use TRAP_EXECUTE to "modify" PC (PC <= PC)
else -- illegal fence instruction
execute_engine.state_nxt <= SYS_WAIT;
end if;
 
 
when opcode_syscsr_c => -- system/csr access
-- ------------------------------------------------------------
if (CPU_EXTENSION_RISCV_Zicsr = true) then
1156,17 → 1125,19
execute_engine.state_nxt <= SYS_WAIT;
end if;
 
 
when opcode_fop_c => -- floating-point operations
-- ------------------------------------------------------------
if (CPU_EXTENSION_RISCV_Zfinx = true) and (decode_aux.is_float_op = '1') then
if (CPU_EXTENSION_RISCV_Zfinx = true) then
ctrl_nxt(ctrl_cp_id_msb_c downto ctrl_cp_id_lsb_c) <= cp_sel_fpu_c; -- trigger FPU CP
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
execute_engine.state_nxt <= ALU_WAIT;
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_copro_c;
execute_engine.state_nxt <= ALU_WAIT;
else
execute_engine.state_nxt <= SYS_WAIT;
end if;
 
when others => -- undefined
 
when others => -- illegal opcode
-- ------------------------------------------------------------
execute_engine.state_nxt <= SYS_WAIT;
 
1176,57 → 1147,49
when SYS_ENV => -- system environment operation - execution
-- ------------------------------------------------------------
execute_engine.state_nxt <= SYS_WAIT; -- default
case decode_aux.sys_env_cmd is -- use a simplified input here (with permanent zeros)
when funct12_ecall_c => trap_ctrl.env_call <= '1'; -- ECALL
when funct12_ebreak_c => trap_ctrl.break_point <= '1'; -- EBREAK
when funct12_wfi_c => -- WFI
if (CPU_EXTENSION_RISCV_DEBUG = true) and
((debug_ctrl.running = '1') or (csr.dcsr_step = '1')) then -- act as NOP when in debug-mode or during single-stepping
NULL; -- executed as NOP
else
execute_engine.sleep_nxt <= '1'; -- go to sleep mode
end if;
when funct12_mret_c => -- MRET
if (csr.priv_m_mode = '1') then -- only allowed in M-mode
execute_engine.state_nxt <= TRAP_EXIT;
else
NULL; -- executed as NOP
end if;
when funct12_dret_c => -- DRET
if (CPU_EXTENSION_RISCV_DEBUG = true) and (debug_ctrl.running = '1') then -- only allowed in debug-mode
execute_engine.state_nxt <= TRAP_EXIT;
debug_ctrl.dret <= '1';
else
NULL; -- executed as NOP
end if;
when others => NULL; -- undefined / execute as NOP
end case;
if (trap_ctrl.exc_buf(exception_iillegal_c) = '0') then -- no illegal instruction
case decode_aux.sys_env_cmd is -- use a simplified input here (with hardwired zeros)
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
if (CPU_EXTENSION_RISCV_DEBUG = true) then
execute_engine.state_nxt <= TRAP_EXIT;
debug_ctrl.dret <= '1';
else
NULL; -- executed as NOP (and raise illegal instruction exception)
end if;
when funct12_wfi_c => -- WFI
if (CPU_EXTENSION_RISCV_DEBUG = true) and
((debug_ctrl.running = '1') or (csr.dcsr_step = '1')) then -- act as NOP when in debug-mode or during single-stepping
NULL; -- executed as NOP
else
execute_engine.sleep_nxt <= '1'; -- go to sleep mode
end if;
when others => NULL; -- undefined / execute as NOP
end case;
end if;
 
 
when CSR_ACCESS => -- read & write status and control register (CSR)
-- ------------------------------------------------------------
-- CSR write access --
case execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) is
when funct3_csrrw_c | funct3_csrrwi_c => -- CSRRW(I)
csr.we_nxt <= '1'; -- always write CSR
when funct3_csrrs_c | funct3_csrrsi_c | funct3_csrrc_c | funct3_csrrci_c => -- CSRRS(I) / CSRRC(I)
csr.we_nxt <= or_reduce_f(execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c)); -- write CSR if rs1/imm is not zero
when others => -- invalid
csr.we_nxt <= '0';
end case;
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]
csr.we_nxt <= not decode_aux.rs1_zero; -- write CSR if rs1/imm is not zero
end if;
-- register file write back --
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_csrr_c;
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU result
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
execute_engine.state_nxt <= DISPATCH;
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_csrr_c;
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
execute_engine.state_nxt <= DISPATCH;
 
 
when ALU_WAIT => -- wait for multi-cycle ALU operation (co-processor) to finish
-- ------------------------------------------------------------
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU result
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_copro_c;
-- wait for result --
if (alu_idone_i = '1') then -- done
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_copro_c;
if (alu_idone_i = '1') or (trap_ctrl.exc_buf(exception_iillegal_c) = '1') then -- completed or exception
ctrl_nxt(ctrl_rf_wb_en_c) <= '1'; -- valid RF write-back
execute_engine.state_nxt <= DISPATCH;
end if;
1235,13 → 1198,10
when BRANCH => -- update PC for taken branches and jumps
-- ------------------------------------------------------------
-- get and store return address (only relevant for jump-and-link operations) --
ctrl_nxt(ctrl_alu_opb_mux_c) <= '1'; -- use IMM as ALU.OPB (next_pc from immediate generator = return address)
ctrl_nxt(ctrl_alu_logic1_c downto ctrl_alu_logic0_c) <= alu_logic_cmd_movb_c; -- MOVB
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_logic_c; -- actual ALU operation = MOVB
ctrl_nxt(ctrl_rf_in_mux_c) <= '0'; -- RF input = ALU result
ctrl_nxt(ctrl_rf_wb_en_c) <= execute_engine.i_reg(instr_opcode_lsb_c+2); -- valid RF write-back? (is jump-and-link?)
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_nxpc_c; -- next PC
ctrl_nxt(ctrl_rf_wb_en_c) <= execute_engine.i_reg(instr_opcode_lsb_c+2); -- valid RF write-back? (is jump-and-link?)
-- destination address --
execute_engine.pc_mux_sel <= '1'; -- alu.add = branch/jump destination
execute_engine.pc_mux_sel <= '1'; -- PC <= alu.add = branch/jump destination
if (execute_engine.i_reg(instr_opcode_lsb_c+2) = '1') or (execute_engine.branch_taken = '1') then -- JAL/JALR or taken branch
-- no need to check for illegal instructions here; the branch condition evaluation circuit will not set "branch_taken" if funct3 is invalid
execute_engine.pc_we <= '1'; -- update PC
1259,12 → 1219,10
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') or (decode_aux.is_atomic_lr = '1') then -- normal load or atomic load-reservate
ctrl_nxt(ctrl_bus_rd_c) <= '1'; -- read request
else -- store
if (decode_aux.is_atomic_sc = '1') then -- evaluate lock state
if (excl_state_i = '1') then -- lock is still ok - perform write access
ctrl_nxt(ctrl_bus_wr_c) <= '1'; -- write request
end if;
else
ctrl_nxt(ctrl_bus_wr_c) <= '1'; -- (normal) write request
if (decode_aux.is_atomic_sc = '0') or (CPU_EXTENSION_RISCV_A = false) then -- (normal) write request
ctrl_nxt(ctrl_bus_wr_c) <= '1';
else -- evaluate lock state
ctrl_nxt(ctrl_bus_wr_c) <= excl_state_i; -- write request if lock is still ok
end if;
end if;
execute_engine.state_nxt <= LOADSTORE_1;
1280,9 → 1238,9
-- ------------------------------------------------------------
ctrl_nxt(ctrl_bus_mi_we_c) <= '1'; -- keep writing input data to MDI (only relevant for load (and SC.W) operations)
ctrl_nxt(ctrl_rf_in_mux_c) <= '1'; -- RF input = memory input (only relevant for LOADs)
-- wait for memory response / exception --
if (trap_ctrl.env_start = '1') and (trap_ctrl.cause(6 downto 5) = "00") then -- only abort if SYNC EXCEPTION (from bus) / no IRQs and NOT DEBUG-MODE-related
execute_engine.state_nxt <= SYS_WAIT;
-- wait for memory response --
if (trap_ctrl.env_start = '1') and (trap_ctrl.cause(6 downto 5) = "00") then -- abort if SYNC EXCEPTION (from bus or illegal cmd) / no IRQs and NOT DEBUG-MODE-related
execute_engine.state_nxt <= DISPATCH;
elsif (bus_d_wait_i = '0') then -- wait for bus to finish transaction
-- data write-back --
if (execute_engine.i_reg(instr_opcode_msb_c-1) = '0') or -- normal load
1312,15 → 1270,18
 
-- CSR Access Check -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
csr_access_check: process(execute_engine.i_reg, csr, debug_ctrl)
variable csr_wacc_v : std_ulogic; -- to check access to read-only CSRs
csr_access_check: process(execute_engine.i_reg, decode_aux, csr, debug_ctrl)
variable csr_wacc_v : std_ulogic; -- actual CSR write
-- variable csr_racc_v : std_ulogic; -- actual CSR read
begin
-- is this CSR instruction really going to write to a CSR? --
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
csr_wacc_v := '1'; -- always write CSR
-- csr_racc_v := or_reduce_f(execute_engine.i_reg(instr_rd_msb_c downto instr_rd_lsb_c)); -- read if rd != 0
else -- clear/set
csr_wacc_v := or_reduce_f(execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c)); -- write allowed if rs1/uimm5 != 0
csr_wacc_v := not decode_aux.rs1_zero; -- write if rs1/uimm5 != 0
-- csr_racc_v := '1'; -- always read CSR
end if;
 
-- check CSR access --
1330,7 → 1291,7
when csr_fflags_c | csr_frm_c | csr_fcsr_c =>
csr_acc_valid <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zfinx); -- full access for everyone if FPU implemented
 
-- machine trap setup & handling --
-- 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.
1341,7 → 1302,8
when csr_mvendorid_c | csr_marchid_c | csr_mimpid_c | csr_mhartid_c | csr_mconfigptr_c =>
csr_acc_valid <= (not csr_wacc_v) and csr.priv_m_mode; -- M-mode only, read-only
 
when csr_mcounteren_c | csr_menvcfg_c | csr_menvcfgh_c => -- only available if U mode is implemented
-- user-mode registers --
when csr_mcounteren_c | csr_menvcfg_c | csr_menvcfgh_c =>
csr_acc_valid <= csr.priv_m_mode and bool_to_ulogic_f(CPU_EXTENSION_RISCV_U);
 
-- physical memory protection (PMP) --
1375,7 → 1337,7
csr_mhpmevent27_c | csr_mhpmevent28_c | csr_mhpmevent29_c | csr_mhpmevent30_c | csr_mhpmevent31_c =>
csr_acc_valid <= csr.priv_m_mode and bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zihpm); -- M-mode only
 
-- user-level counters/timers --
-- user-level counters/timers (read-only) --
when csr_cycle_c | csr_cycleh_c | csr_instret_c | csr_instreth_c | csr_time_c | csr_timeh_c =>
case csr.addr(1 downto 0) is
when "00" => csr_acc_valid <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicntr) and (not csr_wacc_v) and (csr.priv_m_mode or csr.mcounteren_cy); -- cyle[h]: M-mode, U-mode if authorized, implemented at all, read-only
1429,57 → 1391,52
-- ------------------------------------------------------------
illegal_instruction <= '0';
-- illegal E-CPU register? --
if (CPU_EXTENSION_RISCV_E = true) and (execute_engine.i_reg(instr_rd_msb_c) = '1') then
illegal_register <= '1';
end if;
illegal_register <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E) and execute_engine.i_reg(instr_rd_msb_c);
 
when opcode_alu_c => -- check ALU.funct3 & ALU.funct7
-- ------------------------------------------------------------
if (decode_aux.is_m_mul = '1') then -- MUL
if (CPU_EXTENSION_RISCV_M = false) and (CPU_EXTENSION_RISCV_Zmmul = false) then -- not implemented
illegal_instruction <= '1';
end if;
elsif (decode_aux.is_m_div = '1') then -- DIV
if (CPU_EXTENSION_RISCV_M = false) then -- not implemented
illegal_instruction <= '1';
end if;
elsif (decode_aux.is_bitmanip_reg = '1') then -- bit manipulation
if (CPU_EXTENSION_RISCV_B = false) then -- not implemented
illegal_instruction <= '1';
end if;
elsif ((execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_subadd_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sr_c)) and -- ADD/SUB or SRA/SRL check
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) /= "0000000") and
(execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) /= "0100000")) then -- ADD/SUB or SRA/SRL select
if (((execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_subadd_c) or (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sr_c)) and
(execute_engine.i_reg(instr_funct7_msb_c-2 downto instr_funct7_lsb_c) = "00000") and (execute_engine.i_reg(instr_funct7_msb_c) = '0')) or
(((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_slt_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sltu_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_xor_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_or_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_and_c)) and
(execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0000000")) then -- valid base ALUI instruction?
illegal_instruction <= '0';
elsif ((CPU_EXTENSION_RISCV_M = true) or (CPU_EXTENSION_RISCV_Zmmul = false)) and (decode_aux.is_m_mul = '1') then -- valid MUL instruction?
illegal_instruction <= '0';
elsif (CPU_EXTENSION_RISCV_M = true) and (decode_aux.is_m_div = '1') then -- valid DIV instruction?
illegal_instruction <= '0';
elsif (CPU_EXTENSION_RISCV_B = true) and (decode_aux.is_bitmanip_reg = '1') then -- valid BITMANIP instruction?
illegal_instruction <= '0';
else
illegal_instruction <= '1';
else
illegal_instruction <= '0';
end if;
-- illegal E-CPU register? --
if (CPU_EXTENSION_RISCV_E = true) and
((execute_engine.i_reg(instr_rs2_msb_c) = '1') or (execute_engine.i_reg(instr_rs1_msb_c) = '1') or (execute_engine.i_reg(instr_rd_msb_c) = '1')) then
illegal_register <= '1';
end if;
illegal_register <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E) and (execute_engine.i_reg(instr_rd_msb_c) or execute_engine.i_reg(instr_rs1_msb_c) or execute_engine.i_reg(instr_rs2_msb_c));
 
when opcode_alui_c => -- check ALUI.funct7
-- ------------------------------------------------------------
if (decode_aux.is_bitmanip_imm = '1') then -- bit manipulation
if (CPU_EXTENSION_RISCV_B = false) then -- not implemented
illegal_instruction <= '1';
end if;
elsif ((execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sll_c) and
(execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) /= "0000000")) or -- shift logical left
((execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sr_c) and
((execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) /= "0000000") and
(execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) /= "0100000"))) then -- shift right
if (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_subadd_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_slt_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sltu_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_xor_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_or_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_and_c) or
((execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sll_c) and -- shift logical left
(execute_engine.i_reg(instr_funct7_msb_c downto instr_funct7_lsb_c) = "0000000")) or
((execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_sr_c) and -- shift right
((execute_engine.i_reg(instr_funct7_msb_c-2 downto instr_funct7_lsb_c) = "00000") and (execute_engine.i_reg(instr_funct7_msb_c) = '0'))) then -- valid base ALUI instruction?
illegal_instruction <= '0';
elsif (CPU_EXTENSION_RISCV_B = true) and (decode_aux.is_bitmanip_imm = '1') then -- valid BITMANIP immediate instruction?
illegal_instruction <= '0';
else
illegal_instruction <= '1';
else
illegal_instruction <= '0';
end if;
-- illegal E-CPU register? --
if (CPU_EXTENSION_RISCV_E = true) and ((execute_engine.i_reg(instr_rs1_msb_c) = '1') or (execute_engine.i_reg(instr_rd_msb_c) = '1')) then
illegal_register <= '1';
end if;
illegal_register <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E) and (execute_engine.i_reg(instr_rs1_msb_c) or execute_engine.i_reg(instr_rd_msb_c));
 
when opcode_load_c => -- check LOAD.funct3
-- ------------------------------------------------------------
1493,9 → 1450,7
illegal_instruction <= '1';
end if;
-- illegal E-CPU register? --
if (CPU_EXTENSION_RISCV_E = true) and ((execute_engine.i_reg(instr_rs1_msb_c) = '1') or (execute_engine.i_reg(instr_rd_msb_c) = '1')) then
illegal_register <= '1';
end if;
illegal_register <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E) and (execute_engine.i_reg(instr_rs1_msb_c) or execute_engine.i_reg(instr_rd_msb_c));
 
when opcode_store_c => -- check STORE.funct3
-- ------------------------------------------------------------
1507,8 → 1462,24
illegal_instruction <= '1';
end if;
-- illegal E-CPU register? --
if (CPU_EXTENSION_RISCV_E = true) and ((execute_engine.i_reg(instr_rs2_msb_c) = '1') or (execute_engine.i_reg(instr_rs1_msb_c) = '1')) then
illegal_register <= '1';
illegal_register <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E) and (execute_engine.i_reg(instr_rs2_msb_c) or execute_engine.i_reg(instr_rs1_msb_c));
 
when opcode_atomic_c => -- atomic instructions
-- ------------------------------------------------------------
if (CPU_EXTENSION_RISCV_A = true) then
if (execute_engine.i_reg(instr_funct5_msb_c downto instr_funct5_lsb_c) = "00010") then -- LR
illegal_instruction <= '0';
-- illegal E-CPU register? --
illegal_register <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E) and (execute_engine.i_reg(instr_rs1_msb_c) or execute_engine.i_reg(instr_rd_msb_c));
elsif (execute_engine.i_reg(instr_funct5_msb_c downto instr_funct5_lsb_c) = "00011") then -- SC
illegal_instruction <= '0';
-- illegal E-CPU register? --
illegal_register <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E) and (execute_engine.i_reg(instr_rs1_msb_c) or execute_engine.i_reg(instr_rs2_msb_c) or execute_engine.i_reg(instr_rd_msb_c));
else
illegal_instruction <= '1';
end if;
else
illegal_instruction <= '1';
end if;
 
when opcode_branch_c => -- check BRANCH.funct3
1524,9 → 1495,7
illegal_instruction <= '1';
end if;
-- illegal E-CPU register? --
if (CPU_EXTENSION_RISCV_E = true) and ((execute_engine.i_reg(instr_rs2_msb_c) = '1') or (execute_engine.i_reg(instr_rs1_msb_c) = '1')) then
illegal_register <= '1';
end if;
illegal_register <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E) and (execute_engine.i_reg(instr_rs2_msb_c) or execute_engine.i_reg(instr_rs1_msb_c));
 
when opcode_jalr_c => -- check JALR.funct3
-- ------------------------------------------------------------
1536,11 → 1505,9
illegal_instruction <= '1';
end if;
-- illegal E-CPU register? --
if (CPU_EXTENSION_RISCV_E = true) and ((execute_engine.i_reg(instr_rs1_msb_c) = '1') or (execute_engine.i_reg(instr_rd_msb_c) = '1')) then
illegal_register <= '1';
end if;
illegal_register <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E) and (execute_engine.i_reg(instr_rs1_msb_c) or execute_engine.i_reg(instr_rd_msb_c));
 
when opcode_fence_c => -- fence instructions
when opcode_fence_c => -- check FENCE.funct3
-- ------------------------------------------------------------
if ((execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fencei_c) and (CPU_EXTENSION_RISCV_Zifencei = true)) or -- FENCE.I
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fence_c) then -- FENCE
1548,22 → 1515,20
else
illegal_instruction <= '1';
end if;
-- illegal E-CPU register? --
illegal_register <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E) and (execute_engine.i_reg(instr_rs1_msb_c) or execute_engine.i_reg(instr_rd_msb_c));
 
when opcode_syscsr_c => -- check system instructions
-- ------------------------------------------------------------
-- CSR access --
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_csrrs_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrc_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrwi_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrsi_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrci_c) then
-- valid CSR access? --
if (csr_acc_valid = '1') then
illegal_instruction <= '0';
else
illegal_instruction <= '1';
end if;
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_csrrs_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrc_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrwi_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrsi_c) or
(execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrci_c)) and
(csr_acc_valid = '1') then -- valid CSR access?
illegal_instruction <= '0';
-- illegal E-CPU register? --
if (CPU_EXTENSION_RISCV_E = true) then
if (execute_engine.i_reg(instr_funct3_msb_c) = '0') then -- reg-reg CSR
1572,28 → 1537,14
illegal_register <= execute_engine.i_reg(instr_rd_msb_c);
end if;
end if;
 
-- ecall, ebreak, mret, wfi, dret --
elsif (execute_engine.i_reg(instr_rd_msb_c downto instr_rd_lsb_c) = "00000") and
(execute_engine.i_reg(instr_rs1_msb_c downto instr_rs1_lsb_c) = "00000") then
if (execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_ecall_c) or -- ECALL
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_ebreak_c) or -- EBREAK
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_mret_c) and (csr.priv_m_mode = '1')) or -- MRET (only allowed in M-mode)
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_dret_c) and (CPU_EXTENSION_RISCV_DEBUG = true) and (debug_ctrl.running = '1')) or -- DRET (only allowed in D-mode)
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_wfi_c) then -- WFI (always allowed to execute)
illegal_instruction <= '0';
else
illegal_instruction <= '1';
end if;
else
illegal_instruction <= '1';
end if;
 
when opcode_atomic_c => -- atomic instructions
-- ------------------------------------------------------------
if (CPU_EXTENSION_RISCV_A = true) and -- atomic memory operations (A extension) enabled
((execute_engine.i_reg(instr_funct5_msb_c downto instr_funct5_lsb_c) = funct5_a_lr_c) or -- LR
(execute_engine.i_reg(instr_funct5_msb_c downto instr_funct5_lsb_c) = funct5_a_sc_c)) then -- SC
elsif (execute_engine.i_reg(instr_funct3_msb_c downto instr_funct3_lsb_c) = "000") and
(decode_aux.rs1_zero = '1') and (decode_aux.rd_zero = '1') and
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_ecall_c) or -- ECALL
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_ebreak_c) or -- EBREAK
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_mret_c) and (csr.priv_m_mode = '1')) or -- MRET (only allowed in M-mode)
((execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_dret_c) and (CPU_EXTENSION_RISCV_DEBUG = true) and (debug_ctrl.running = '1')) or -- DRET (only allowed in D-mode)
(execute_engine.i_reg(instr_funct12_msb_c downto instr_funct12_lsb_c) = funct12_wfi_c)) then -- WFI (always allowed to execute)
illegal_instruction <= '0';
else
illegal_instruction <= '1';
1608,6 → 1559,9
else
illegal_instruction <= '1';
end if;
-- illegal E-CPU register? --
-- FIXME: rs2 is not checked!
illegal_register <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E) and (execute_engine.i_reg(instr_rs1_msb_c) or execute_engine.i_reg(instr_rd_msb_c));
 
when others => -- undefined instruction -> illegal!
-- ------------------------------------------------------------
1644,54 → 1598,46
elsif rising_edge(clk_i) then
if (CPU_EXTENSION_RISCV_Zicsr = true) then
 
-- exception queue: misaligned load/store/instruction address
-- exception queue: misaligned load/store/instruction address --
trap_ctrl.exc_buf(exception_lalign_c) <= (trap_ctrl.exc_buf(exception_lalign_c) or ma_load_i) and (not trap_ctrl.exc_ack);
trap_ctrl.exc_buf(exception_salign_c) <= (trap_ctrl.exc_buf(exception_salign_c) or ma_store_i) and (not trap_ctrl.exc_ack);
trap_ctrl.exc_buf(exception_ialign_c) <= (trap_ctrl.exc_buf(exception_ialign_c) or trap_ctrl.instr_ma) and (not trap_ctrl.exc_ack);
 
-- exception queue: load/store/instruction bus access error
-- exception queue: load/store/instruction bus access error --
trap_ctrl.exc_buf(exception_laccess_c) <= (trap_ctrl.exc_buf(exception_laccess_c) or be_load_i) and (not trap_ctrl.exc_ack);
trap_ctrl.exc_buf(exception_saccess_c) <= (trap_ctrl.exc_buf(exception_saccess_c) or be_store_i) and (not trap_ctrl.exc_ack);
trap_ctrl.exc_buf(exception_iaccess_c) <= (trap_ctrl.exc_buf(exception_iaccess_c) or trap_ctrl.instr_be) and (not trap_ctrl.exc_ack);
 
-- exception queue: illegal instruction / environment call / break point
-- exception queue: illegal instruction / environment calls --
trap_ctrl.exc_buf(exception_m_envcall_c) <= (trap_ctrl.exc_buf(exception_m_envcall_c) or (trap_ctrl.env_call and csr.priv_m_mode)) and (not trap_ctrl.exc_ack);
trap_ctrl.exc_buf(exception_u_envcall_c) <= (trap_ctrl.exc_buf(exception_u_envcall_c) or (trap_ctrl.env_call and csr.priv_u_mode)) and (not trap_ctrl.exc_ack);
trap_ctrl.exc_buf(exception_iillegal_c) <= (trap_ctrl.exc_buf(exception_iillegal_c) or trap_ctrl.instr_il) and (not trap_ctrl.exc_ack);
 
-- exception queue: break point --
if (CPU_EXTENSION_RISCV_DEBUG = true) then
trap_ctrl.exc_buf(exception_break_c) <= (trap_ctrl.exc_buf(exception_break_c) or
(
(trap_ctrl.break_point and csr.priv_m_mode and (not csr.dcsr_ebreakm) and (not debug_ctrl.running)) or -- enable break to machine-trap-handler when in machine mode on "ebreak"
(trap_ctrl.break_point and csr.priv_u_mode and (not csr.dcsr_ebreaku) and (not debug_ctrl.running)) -- enable break to machine-trap-handler when in user mode on "ebreak"
)
) and (not trap_ctrl.exc_ack);
trap_ctrl.exc_buf(exception_break_c) <= (not trap_ctrl.exc_ack) and (trap_ctrl.exc_buf(exception_break_c) or
((trap_ctrl.break_point and csr.priv_m_mode and (not csr.dcsr_ebreakm) and (not debug_ctrl.running)) or -- enable break to machine-trap-handler when in machine mode on "ebreak"
(trap_ctrl.break_point and csr.priv_u_mode and (not csr.dcsr_ebreaku) and (not debug_ctrl.running)))); -- enable break to machine-trap-handler when in user mode on "ebreak"
else
trap_ctrl.exc_buf(exception_break_c) <= (trap_ctrl.exc_buf(exception_break_c) or trap_ctrl.break_point) and (not trap_ctrl.exc_ack);
end if;
 
-- enter debug mode --
if (CPU_EXTENSION_RISCV_DEBUG = true) then
trap_ctrl.exc_buf(exception_db_break_c) <= (trap_ctrl.exc_buf(exception_db_break_c) or debug_ctrl.trig_break) and (not trap_ctrl.exc_ack);
trap_ctrl.irq_buf(interrupt_db_halt_c) <= debug_ctrl.trig_halt;
trap_ctrl.irq_buf(interrupt_db_step_c) <= debug_ctrl.trig_step;
else
trap_ctrl.exc_buf(exception_db_break_c) <= '0';
trap_ctrl.irq_buf(interrupt_db_halt_c) <= '0';
trap_ctrl.irq_buf(interrupt_db_step_c) <= '0';
end if;
-- exception buffer: enter debug mode --
trap_ctrl.exc_buf(exception_db_break_c) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_DEBUG) and (trap_ctrl.exc_buf(exception_db_break_c) or debug_ctrl.trig_break) and (not trap_ctrl.exc_ack);
trap_ctrl.irq_buf(interrupt_db_halt_c) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_DEBUG) and debug_ctrl.trig_halt;
trap_ctrl.irq_buf(interrupt_db_step_c) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_DEBUG) and debug_ctrl.trig_step;
 
-- interrupt buffer: machine software/external/timer interrupt
-- interrupt buffer: machine software/external/timer interrupt --
trap_ctrl.irq_buf(interrupt_msw_irq_c) <= csr.mie_msie and msw_irq_i;
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 queue: NEORV32-specific fast interrupts
for i in 0 to 15 loop
trap_ctrl.irq_buf(interrupt_firq_0_c+i) <= csr.mie_firqe(i) and firq_i(i);
end loop;
 
-- trap control --
-- 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);
 
-- trap environment control --
if (trap_ctrl.env_start = '0') then -- no started trap handler
if (trap_ctrl.exc_fire = '1') or ((trap_ctrl.irq_fire = '1') and -- trap triggered!
if (trap_ctrl.exc_fire = '1') or ((trap_ctrl.irq_fire = '1') and -- exception triggered!
((execute_engine.state = EXECUTE) or (execute_engine.state = TRAP_ENTER))) then -- fire IRQs in EXECUTE or TRAP state only to continue execution even on permanent IRQ
trap_ctrl.cause <= trap_ctrl.cause_nxt; -- capture source ID for program (for mcause csr)
trap_ctrl.exc_ack <= '1'; -- clear exceptions (no ack mask: these have highest priority and are always evaluated first!)
1727,7 → 1673,7
-- exceptions (from trap_ctrl.irq_buf).
 
-- ----------------------------------------------------------------------------------------
-- the following traps are caused by *synchronous* exceptions; here we do not need a
-- the following traps are caused by *synchronous* exceptions; we do not need a
-- specific acknowledge mask since only _one_ exception (the one with highest priority)
-- is allowed to kick in at once
-- ----------------------------------------------------------------------------------------
1917,45 → 1863,45
-- NOT actually have a real reset by default (def_rst_val_c = '-') and have to be explicitly initialized by software!
-- see: https://forums.xilinx.com/t5/General-Technical-Discussion/quot-Don-t-care-quot-reset-value/td-p/412845
if (rstn_i = '0') then
csr.we <= '0';
csr.we <= '0';
--
csr.mstatus_mie <= '0';
csr.mstatus_mpie <= '0';
csr.mstatus_mpp <= (others => '0');
csr.privilege <= priv_mode_m_c; -- start in MACHINE mode
csr.mie_msie <= def_rst_val_c;
csr.mie_meie <= def_rst_val_c;
csr.mie_mtie <= def_rst_val_c;
csr.mie_firqe <= (others => def_rst_val_c);
csr.mtvec <= (others => def_rst_val_c);
csr.mscratch <= x"19880704";
csr.mepc <= (others => def_rst_val_c);
csr.mcause <= (others => def_rst_val_c);
csr.mtval <= (others => def_rst_val_c);
csr.mstatus_mie <= '0';
csr.mstatus_mpie <= '0';
csr.mstatus_mpp <= (others => '0');
csr.privilege <= priv_mode_m_c; -- start in MACHINE mode
csr.mie_msie <= def_rst_val_c;
csr.mie_meie <= def_rst_val_c;
csr.mie_mtie <= def_rst_val_c;
csr.mie_firqe <= (others => def_rst_val_c);
csr.mtvec <= (others => def_rst_val_c);
csr.mscratch <= x"19880704";
csr.mepc <= (others => def_rst_val_c);
csr.mcause <= (others => def_rst_val_c);
csr.mtval <= (others => def_rst_val_c);
--
csr.pmpcfg <= (others => (others => '0'));
csr.pmpaddr <= (others => (others => def_rst_val_c));
csr.pmpcfg <= (others => (others => '0'));
csr.pmpaddr <= (others => (others => def_rst_val_c));
--
csr.mhpmevent <= (others => (others => def_rst_val_c));
csr.mhpmevent <= (others => (others => def_rst_val_c));
--
csr.mcounteren_cy <= def_rst_val_c;
csr.mcounteren_tm <= def_rst_val_c;
csr.mcounteren_ir <= def_rst_val_c;
csr.mcounteren_cy <= def_rst_val_c;
csr.mcounteren_tm <= def_rst_val_c;
csr.mcounteren_ir <= def_rst_val_c;
--
csr.mcountinhibit_cy <= def_rst_val_c;
csr.mcountinhibit_ir <= def_rst_val_c;
csr.mcountinhibit_hpm <= (others => def_rst_val_c);
--
csr.fflags <= (others => def_rst_val_c);
csr.frm <= (others => def_rst_val_c);
csr.fflags <= (others => def_rst_val_c);
csr.frm <= (others => def_rst_val_c);
--
csr.dcsr_ebreakm <= '0';
csr.dcsr_ebreaku <= '0';
csr.dcsr_step <= '0';
csr.dcsr_prv <= (others => def_rst_val_c);
csr.dcsr_cause <= (others => def_rst_val_c);
csr.dpc <= (others => def_rst_val_c);
csr.dscratch0 <= (others => def_rst_val_c);
csr.dcsr_ebreakm <= '0';
csr.dcsr_ebreaku <= '0';
csr.dcsr_step <= '0';
csr.dcsr_prv <= (others => def_rst_val_c);
csr.dcsr_cause <= (others => def_rst_val_c);
csr.dpc <= (others => def_rst_val_c);
csr.dscratch0 <= (others => def_rst_val_c);
 
elsif rising_edge(clk_i) then
-- write access? --
1965,22 → 1911,20
-- --------------------------------------------------------------------------------
-- CSR access by application software
-- --------------------------------------------------------------------------------
if (csr.we = '1') and (trap_ctrl.exc_buf(exception_iillegal_c) = '0') then -- manual update if not illegal instruction
if (csr.we = '1') and (trap_ctrl.exc_buf(exception_iillegal_c) = '0') then -- manual write access and not illegal instruction
 
-- user floating-point CSRs --
-- --------------------------------------------------------------------
if (CPU_EXTENSION_RISCV_Zfinx = true) then -- floating point CSR class
if (csr.addr(11 downto 4) = csr_class_float_c) and (csr.addr(3 downto 2) = csr_fcsr_c(3 downto 2)) then
case csr.addr(1 downto 0) is
when "01" => -- R/W: fflags - floating-point (FPU) exception flags
csr.fflags <= csr.wdata(4 downto 0);
when "10" => -- R/W: frm - floating-point (FPU) rounding mode
csr.frm <= csr.wdata(2 downto 0);
when "11" => -- R/W: fcsr - floating-point (FPU) control/status (frm + fflags)
csr.frm <= csr.wdata(7 downto 5);
csr.fflags <= csr.wdata(4 downto 0);
when others => NULL;
end case;
if (csr.addr(11 downto 2) = csr_class_float_c) then
if (csr.addr(1 downto 0) = "01") then -- R/W: fflags - floating-point (FPU) exception flags
csr.fflags <= csr.wdata(4 downto 0);
elsif (csr.addr(1 downto 0) = "10") then -- R/W: frm - floating-point (FPU) rounding mode
csr.frm <= csr.wdata(2 downto 0);
elsif (csr.addr(1 downto 0) = "11") then -- R/W: fcsr - floating-point (FPU) control/status (frm + fflags)
csr.frm <= csr.wdata(7 downto 5);
csr.fflags <= csr.wdata(4 downto 0);
end if;
end if;
end if;
 
2021,18 → 1965,18
 
-- machine trap handling --
-- --------------------------------------------------------------------
if (csr.addr(11 downto 4) = csr_class_trap_c) then -- machine trap handling CSR class
if (csr.addr(11 downto 3) = csr_class_trap_c) then -- machine trap handling CSR class
-- R/W: mscratch - machine scratch register --
if (csr.addr(3 downto 0) = csr_mscratch_c(3 downto 0)) then
if (csr.addr(2 downto 0) = csr_mscratch_c(2 downto 0)) then
csr.mscratch <= csr.wdata;
end if;
-- R/W: mepc - machine exception program counter --
if (csr.addr(3 downto 0) = csr_mepc_c(3 downto 0)) then
if (csr.addr(2 downto 0) = csr_mepc_c(2 downto 0)) then
csr.mepc <= csr.wdata;
end if;
-- R/W: mcause - machine trap cause --
if (csr.addr(3 downto 0) = csr_mcause_c(3 downto 0)) then
csr.mcause(csr.mcause'left) <= csr.wdata(31); -- 1: interrupt, 0: exception
if (csr.addr(2 downto 0) = csr_mcause_c(2 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;
end if;
2129,7 → 2073,7
 
-- floating-point (FPU) exception flags --
-- --------------------------------------------------------------------
if (CPU_EXTENSION_RISCV_Zfinx = true) then
if (CPU_EXTENSION_RISCV_Zfinx = true) and (trap_ctrl.exc_buf(exception_iillegal_c) = '0') then -- no illegal instruction
csr.fflags <= csr.fflags or fpu_flags_i; -- accumulate flags ("accrued exception flags")
end if;
 
2312,7 → 2256,7
-- -------------------------------------------------------------------------------------------
csr_counters: process(rstn_i, clk_i)
begin
-- Counter CSRs (each counter is split into two 32-bit counters - coupled via an MSB overflow detector)
-- Counter CSRs (each counter is split into two 32-bit counters - coupled via an MSB overflow FF)
if (rstn_i = '0') then
csr.mcycle <= (others => def_rst_val_c);
csr.mcycle_ovfl <= (others => def_rst_val_c);
2327,7 → 2271,7
 
-- [m]cycle --
if (cpu_cnt_lo_width_c > 0) and (CPU_EXTENSION_RISCV_Zicntr = true) then
csr.mcycle_ovfl(0) <= csr.mcycle_nxt(csr.mcycle_nxt'left);
csr.mcycle_ovfl(0) <= csr.mcycle_nxt(csr.mcycle_nxt'left) and (not csr.mcountinhibit_cy);
if (csr.we = '1') and (csr.addr = csr_mcycle_c) then -- write access
csr.mcycle(cpu_cnt_lo_width_c-1 downto 0) <= csr.wdata(cpu_cnt_lo_width_c-1 downto 0);
elsif (csr.mcountinhibit_cy = '0') and (cnt_event(hpmcnt_event_cy_c) = '1') then -- non-inhibited automatic update
2342,7 → 2286,7
if (cpu_cnt_hi_width_c > 0) and (CPU_EXTENSION_RISCV_Zicntr = true) then
if (csr.we = '1') and (csr.addr = csr_mcycleh_c) then -- write access
csr.mcycleh(cpu_cnt_hi_width_c-1 downto 0) <= csr.wdata(cpu_cnt_hi_width_c-1 downto 0);
elsif (csr.mcountinhibit_cy = '0') and (cnt_event(hpmcnt_event_cy_c) = '1') then -- non-inhibited automatic update
else -- automatic update
csr.mcycleh(cpu_cnt_hi_width_c-1 downto 0) <= std_ulogic_vector(unsigned(csr.mcycleh(cpu_cnt_hi_width_c-1 downto 0)) + unsigned(csr.mcycle_ovfl));
end if;
else
2352,7 → 2296,7
 
-- [m]instret --
if (cpu_cnt_lo_width_c > 0) and (CPU_EXTENSION_RISCV_Zicntr = true) then
csr.minstret_ovfl(0) <= csr.minstret_nxt(csr.minstret_nxt'left);
csr.minstret_ovfl(0) <= csr.minstret_nxt(csr.minstret_nxt'left) and (not csr.mcountinhibit_ir);
if (csr.we = '1') and (csr.addr = csr_minstret_c) then -- write access
csr.minstret(cpu_cnt_lo_width_c-1 downto 0) <= csr.wdata(cpu_cnt_lo_width_c-1 downto 0);
elsif (csr.mcountinhibit_ir = '0') and (cnt_event(hpmcnt_event_ir_c) = '1') then -- non-inhibited automatic update
2367,7 → 2311,7
if (cpu_cnt_hi_width_c > 0) and (CPU_EXTENSION_RISCV_Zicntr = true) then
if (csr.we = '1') and (csr.addr = csr_minstreth_c) then -- write access
csr.minstreth(cpu_cnt_hi_width_c-1 downto 0) <= csr.wdata(cpu_cnt_hi_width_c-1 downto 0);
elsif (csr.mcountinhibit_ir = '0') and (cnt_event(hpmcnt_event_ir_c) = '1') then -- non-inhibited automatic update
else -- automatic update
csr.minstreth(cpu_cnt_hi_width_c-1 downto 0) <= std_ulogic_vector(unsigned(csr.minstreth(cpu_cnt_hi_width_c-1 downto 0)) + unsigned(csr.minstret_ovfl));
end if;
else
2380,7 → 2324,7
 
-- [m]hpmcounter* --
if (hpm_cnt_lo_width_c > 0) and (CPU_EXTENSION_RISCV_Zihpm = true) then
csr.mhpmcounter_ovfl(i)(0) <= csr.mhpmcounter_nxt(i)(csr.mhpmcounter_nxt(i)'left);
csr.mhpmcounter_ovfl(i)(0) <= csr.mhpmcounter_nxt(i)(csr.mhpmcounter_nxt(i)'left) and (not csr.mcountinhibit_hpm(i));
if (csr.we = '1') and (csr.addr = std_ulogic_vector(unsigned(csr_mhpmcounter3_c) + i)) then -- write access
csr.mhpmcounter(i)(hpm_cnt_lo_width_c-1 downto 0) <= csr.wdata(hpm_cnt_lo_width_c-1 downto 0);
elsif (csr.mcountinhibit_hpm(i) = '0') and (hpmcnt_trigger(i) = '1') then -- non-inhibited automatic update
2395,7 → 2339,7
if (hpm_cnt_hi_width_c > 0) and (CPU_EXTENSION_RISCV_Zihpm = true) then
if (csr.we = '1') and (csr.addr = std_ulogic_vector(unsigned(csr_mhpmcounter3h_c) + i)) then -- write access
csr.mhpmcounterh(i)(hpm_cnt_hi_width_c-1 downto 0) <= csr.wdata(hpm_cnt_hi_width_c-1 downto 0);
elsif (csr.mcountinhibit_hpm(i) = '0') and (hpmcnt_trigger(i) = '1') then -- non-inhibited automatic update
else -- automatic update
csr.mhpmcounterh(i)(hpm_cnt_hi_width_c-1 downto 0) <= std_ulogic_vector(unsigned(csr.mhpmcounterh(i)(hpm_cnt_hi_width_c-1 downto 0)) + unsigned(csr.mhpmcounter_ovfl(i)));
end if;
else
2409,7 → 2353,7
 
 
-- mcycle & minstret increment LOW --
csr.mcycle_nxt <= std_ulogic_vector(unsigned('0' & csr.mcycle) + 1);
csr.mcycle_nxt <= std_ulogic_vector(unsigned('0' & csr.mcycle) + 1);
csr.minstret_nxt <= std_ulogic_vector(unsigned('0' & csr.minstret) + 1);
 
-- hpm counter increment LOW --
2442,11 → 2386,8
hpmcnt_ctrl: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
cnt_event <= (others => def_rst_val_c);
hpmcnt_trigger <= (others => def_rst_val_c);
elsif rising_edge(clk_i) then
-- buffer event sources --
cnt_event <= cnt_event_nxt;
-- enable selected triggers by ANDing actual events and according CSR configuration bits --
-- OR everything to see if counter should increment --
hpmcnt_trigger <= (others => '0'); -- default
2459,26 → 2400,26
end process hpmcnt_ctrl;
 
-- counter event trigger - RISC-V-specific --
cnt_event_nxt(hpmcnt_event_cy_c) <= not execute_engine.sleep; -- active cycle
cnt_event_nxt(hpmcnt_event_never_c) <= '0'; -- undefined (never)
cnt_event_nxt(hpmcnt_event_ir_c) <= '1' when (execute_engine.state = EXECUTE) else '0'; -- retired instruction
cnt_event(hpmcnt_event_cy_c) <= not execute_engine.sleep; -- active cycle
cnt_event(hpmcnt_event_never_c) <= '0'; -- undefined (never)
cnt_event(hpmcnt_event_ir_c) <= '1' when (execute_engine.state = EXECUTE) else '0'; -- retired instruction
 
-- counter event trigger - custom / NEORV32-specific --
cnt_event_nxt(hpmcnt_event_cir_c) <= '1' when (execute_engine.state = EXECUTE) and (execute_engine.is_ci = '1') else '0'; -- retired compressed instruction
cnt_event_nxt(hpmcnt_event_wait_if_c) <= '1' when (fetch_engine.state = IFETCH_ISSUE) and (fetch_engine.state_prev = IFETCH_ISSUE) else '0'; -- instruction fetch memory wait cycle
cnt_event_nxt(hpmcnt_event_wait_ii_c) <= '1' when (execute_engine.state = DISPATCH) and (execute_engine.state_prev = DISPATCH) else '0'; -- instruction issue wait cycle
cnt_event_nxt(hpmcnt_event_wait_mc_c) <= '1' when (execute_engine.state = ALU_WAIT) else '0'; -- multi-cycle alu-operation wait cycle
cnt_event(hpmcnt_event_cir_c) <= '1' when (execute_engine.state = EXECUTE) and (execute_engine.is_ci = '1') else '0'; -- retired compressed instruction
cnt_event(hpmcnt_event_wait_if_c) <= '1' when (fetch_engine.state = IFETCH_ISSUE) and (fetch_engine.state_prev = IFETCH_ISSUE) else '0'; -- instruction fetch memory wait cycle
cnt_event(hpmcnt_event_wait_ii_c) <= '1' when (execute_engine.state = DISPATCH) and (execute_engine.state_prev = DISPATCH) else '0'; -- instruction issue wait cycle
cnt_event(hpmcnt_event_wait_mc_c) <= '1' when (execute_engine.state = ALU_WAIT) else '0'; -- multi-cycle alu-operation wait cycle
 
cnt_event_nxt(hpmcnt_event_load_c) <= '1' when (execute_engine.state = LOADSTORE_1) and (ctrl(ctrl_bus_rd_c) = '1') else '0'; -- load operation
cnt_event_nxt(hpmcnt_event_store_c) <= '1' when (execute_engine.state = LOADSTORE_1) and (ctrl(ctrl_bus_wr_c) = '1') else '0'; -- store operation
cnt_event_nxt(hpmcnt_event_wait_ls_c) <= '1' when (execute_engine.state = LOADSTORE_2) and (execute_engine.state_prev = LOADSTORE_2) else '0'; -- load/store memory wait cycle
cnt_event(hpmcnt_event_load_c) <= '1' when (ctrl(ctrl_bus_rd_c) = '1') else '0'; -- load operation
cnt_event(hpmcnt_event_store_c) <= '1' when (ctrl(ctrl_bus_wr_c) = '1') else '0'; -- store operation
cnt_event(hpmcnt_event_wait_ls_c) <= '1' when (execute_engine.state = LOADSTORE_2) and (execute_engine.state_prev = LOADSTORE_2) else '0'; -- load/store memory wait cycle
 
cnt_event_nxt(hpmcnt_event_jump_c) <= '1' when (execute_engine.state = BRANCH) and (execute_engine.i_reg(instr_opcode_lsb_c+2) = '1') else '0'; -- jump (unconditional)
cnt_event_nxt(hpmcnt_event_branch_c) <= '1' when (execute_engine.state = BRANCH) and (execute_engine.i_reg(instr_opcode_lsb_c+2) = '0') else '0'; -- branch (conditional, taken or not taken)
cnt_event_nxt(hpmcnt_event_tbranch_c) <= '1' when (execute_engine.state = BRANCH) and (execute_engine.i_reg(instr_opcode_lsb_c+2) = '0') and (execute_engine.branch_taken = '1') else '0'; -- taken branch (conditional)
cnt_event(hpmcnt_event_jump_c) <= '1' when (execute_engine.state = BRANCH) and (execute_engine.i_reg(instr_opcode_lsb_c+2) = '1') else '0'; -- jump (unconditional)
cnt_event(hpmcnt_event_branch_c) <= '1' when (execute_engine.state = BRANCH) and (execute_engine.i_reg(instr_opcode_lsb_c+2) = '0') else '0'; -- branch (conditional, taken or not taken)
cnt_event(hpmcnt_event_tbranch_c) <= '1' when (execute_engine.state = BRANCH) and (execute_engine.i_reg(instr_opcode_lsb_c+2) = '0') and (execute_engine.branch_taken = '1') else '0'; -- taken branch (conditional)
 
cnt_event_nxt(hpmcnt_event_trap_c) <= '1' when (trap_ctrl.env_start_ack = '1') else '0'; -- entered trap
cnt_event_nxt(hpmcnt_event_illegal_c) <= '1' when (trap_ctrl.env_start_ack = '1') and (trap_ctrl.cause = trap_iil_c) else '0'; -- illegal operation
cnt_event(hpmcnt_event_trap_c) <= '1' when (trap_ctrl.env_start_ack = '1') else '0'; -- entered trap
cnt_event(hpmcnt_event_illegal_c) <= '1' when (trap_ctrl.env_start_ack = '1') and (trap_ctrl.cause = trap_iil_c) else '0'; -- illegal operation
 
 
-- Control and Status Registers - Read Access ---------------------------------------------
2798,12 → 2739,12
debug_control: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
debug_ctrl.state <= DEBUG_OFFLINE;
debug_ctrl.state <= DEBUG_OFFLINE;
debug_ctrl.ext_halt_req <= '0';
elsif rising_edge(clk_i) then
if (CPU_EXTENSION_RISCV_DEBUG = true) then
 
-- rising edge detector --
-- external halt request (from Debug Module) --
debug_ctrl.ext_halt_req <= db_halt_req_i;
 
-- state machine --
2836,7 → 2777,7
 
end case;
else -- debug mode NOT implemented
debug_ctrl.state <= DEBUG_OFFLINE;
debug_ctrl.state <= DEBUG_OFFLINE;
debug_ctrl.ext_halt_req <= '0';
end if;
end if;
2866,8 → 2807,8
csr.dcsr_rd(31 downto 28) <= "0100"; -- xdebugver: external debug support compatible to spec
csr.dcsr_rd(27 downto 16) <= (others => '0'); -- reserved
csr.dcsr_rd(15) <= csr.dcsr_ebreakm; -- ebreakm: what happens on ebreak in m-mode? (normal trap OR debug-enter)
csr.dcsr_rd(14) <= '0'; -- ebreakh: not available
csr.dcsr_rd(13) <= '0'; -- ebreaks: not available
csr.dcsr_rd(14) <= '0'; -- ebreakh: hypervisor mode not implemented
csr.dcsr_rd(13) <= '0'; -- ebreaks: supervisor mode not implemented
csr.dcsr_rd(12) <= csr.dcsr_ebreaku when (CPU_EXTENSION_RISCV_U = true) else '0'; -- ebreaku: what happens on ebreak in u-mode? (normal trap OR debug-enter)
csr.dcsr_rd(11) <= '0'; -- stepie: interrupts are disabled during single-stepping
csr.dcsr_rd(10) <= '0'; -- stopcount: counters increment as usual FIXME ???
/rtl/core/neorv32_debug_dtm.vhd
37,7 → 37,6
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
entity neorv32_debug_dtm is
generic (
72,10 → 71,27
architecture neorv32_debug_dtm_rtl of neorv32_debug_dtm is
 
-- DMI Configuration (fixed!) --
constant dmi_idle_c : std_ulogic_vector(02 downto 0) := "010"; -- minimum number if idle cycles
constant dmi_idle_c : std_ulogic_vector(02 downto 0) := "000"; -- no idle cycles required
constant dmi_version_c : std_ulogic_vector(03 downto 0) := "0001"; -- version (0.13)
constant dmi_abits_c : std_ulogic_vector(05 downto 0) := "000111"; -- number of DMI address bits (7)
 
-- tap JTAG signal synchronizer --
type tap_sync_t is record
-- internal --
trst_ff : std_ulogic_vector(2 downto 0);
tck_ff : std_ulogic_vector(2 downto 0);
tdi_ff : std_ulogic_vector(2 downto 0);
tms_ff : std_ulogic_vector(2 downto 0);
-- external --
trst : std_ulogic;
tck_rising : std_ulogic;
tck_falling : std_ulogic;
tdi : std_ulogic;
tdo : std_ulogic;
tms : std_ulogic;
end record;
signal tap_sync : tap_sync_t;
 
-- tap controller - fsm --
type tap_ctrl_state_t is (LOGIC_RESET, DR_SCAN, DR_CAPTURE, DR_SHIFT, DR_EXIT1, DR_PAUSE, DR_EXIT2, DR_UPDATE,
RUN_IDLE, IR_SCAN, IR_CAPTURE, IR_SHIFT, IR_EXIT1, IR_PAUSE, IR_EXIT2, IR_UPDATE);
82,11 → 98,6
type tap_ctrl_t is record
state : tap_ctrl_state_t;
state_prev : tap_ctrl_state_t;
trst_sync : std_ulogic_vector(01 downto 0);
tck_sync : std_ulogic_vector(02 downto 0);
tdi_sync : std_ulogic_vector(01 downto 0);
tdo_sync : std_ulogic;
tms_sync : std_ulogic_vector(01 downto 0);
end record;
signal tap_ctrl : tap_ctrl_t;
 
118,49 → 129,64
 
begin
 
-- JTAG Signal Synchronizer ---------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
tap_synchronizer: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
tap_sync.trst_ff <= tap_sync.trst_ff(1 downto 0) & jtag_trst_i;
tap_sync.tck_ff <= tap_sync.tck_ff( 1 downto 0) & jtag_tck_i;
tap_sync.tdi_ff <= tap_sync.tdi_ff( 1 downto 0) & jtag_tdi_i;
tap_sync.tms_ff <= tap_sync.tms_ff( 1 downto 0) & jtag_tms_i;
if (tap_sync.tck_falling = '1') then -- update output data TDO on falling edge of TCK
jtag_tdo_o <= tap_sync.tdo;
end if;
end if;
end process tap_synchronizer;
 
-- JTAG reset --
tap_sync.trst <= '0' when (tap_sync.trst_ff(2 downto 1) = "00") else '1';
 
-- JTAG clock edge --
tap_sync.tck_rising <= '1' when (tap_sync.tck_ff(2 downto 1) = "01") else '0';
tap_sync.tck_falling <= '1' when (tap_sync.tck_ff(2 downto 1) = "10") else '0';
 
-- JTAG test mode select --
tap_sync.tms <= tap_sync.tms_ff(2);
 
-- JTAG serial data input --
tap_sync.tdi <= tap_sync.tdi_ff(2);
 
 
-- Tap Control FSM ------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
tap_control: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
tap_ctrl.trst_sync <= (others => '0');
tap_ctrl.tck_sync <= (others => '0');
tap_ctrl.tdi_sync <= (others => '0');
tap_ctrl.tms_sync <= (others => '0');
jtag_tdo_o <= '0';
--
tap_ctrl.state <= LOGIC_RESET;
tap_ctrl.state_prev <= LOGIC_RESET;
elsif rising_edge(clk_i) then
-- synchronizer --
tap_ctrl.trst_sync <= tap_ctrl.trst_sync(0) & jtag_trst_i;
tap_ctrl.tck_sync <= tap_ctrl.tck_sync(1 downto 0) & jtag_tck_i;
tap_ctrl.tdi_sync <= tap_ctrl.tdi_sync(0) & jtag_tdi_i;
tap_ctrl.tms_sync <= tap_ctrl.tms_sync(0) & jtag_tms_i;
jtag_tdo_o <= tap_ctrl.tdo_sync;
 
-- state machine --
tap_ctrl.state_prev <= tap_ctrl.state;
if (tap_ctrl.trst_sync(1) = '0') then -- reset
if (tap_sync.trst = '0') then -- reset
tap_ctrl.state <= LOGIC_RESET;
elsif (tap_ctrl.tck_sync(2) = '0') and (tap_ctrl.tck_sync(1) = '1') then -- clock pulse (trigger on rising edge)
elsif (tap_sync.tck_rising = '1') then -- clock pulse (evaluate TMS on the rising edge of TCK)
case tap_ctrl.state is -- JTAG state machine
when LOGIC_RESET => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= RUN_IDLE; else tap_ctrl.state <= LOGIC_RESET; end if;
when RUN_IDLE => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= RUN_IDLE; else tap_ctrl.state <= DR_SCAN; end if;
when DR_SCAN => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= DR_CAPTURE; else tap_ctrl.state <= IR_SCAN; end if;
when DR_CAPTURE => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= DR_SHIFT; else tap_ctrl.state <= DR_EXIT1; end if;
when DR_SHIFT => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= DR_SHIFT; else tap_ctrl.state <= DR_EXIT1; end if;
when DR_EXIT1 => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= DR_PAUSE; else tap_ctrl.state <= DR_UPDATE; end if;
when DR_PAUSE => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= DR_PAUSE; else tap_ctrl.state <= DR_EXIT2; end if;
when DR_EXIT2 => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= DR_SHIFT; else tap_ctrl.state <= DR_UPDATE; end if;
when DR_UPDATE => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= RUN_IDLE; else tap_ctrl.state <= DR_SCAN; end if;
when IR_SCAN => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= IR_CAPTURE; else tap_ctrl.state <= LOGIC_RESET; end if;
when IR_CAPTURE => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= IR_SHIFT; else tap_ctrl.state <= IR_EXIT1; end if;
when IR_SHIFT => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= IR_SHIFT; else tap_ctrl.state <= IR_EXIT1; end if;
when IR_EXIT1 => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= IR_PAUSE; else tap_ctrl.state <= IR_UPDATE; end if;
when IR_PAUSE => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= IR_PAUSE; else tap_ctrl.state <= IR_EXIT2; end if;
when IR_EXIT2 => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= IR_SHIFT; else tap_ctrl.state <= IR_UPDATE; end if;
when IR_UPDATE => if (tap_ctrl.tms_sync(1) = '0') then tap_ctrl.state <= RUN_IDLE; else tap_ctrl.state <= DR_SCAN; end if;
when LOGIC_RESET => if (tap_sync.tms = '0') then tap_ctrl.state <= RUN_IDLE; else tap_ctrl.state <= LOGIC_RESET; end if;
when RUN_IDLE => if (tap_sync.tms = '0') then tap_ctrl.state <= RUN_IDLE; else tap_ctrl.state <= DR_SCAN; end if;
when DR_SCAN => if (tap_sync.tms = '0') then tap_ctrl.state <= DR_CAPTURE; else tap_ctrl.state <= IR_SCAN; end if;
when DR_CAPTURE => if (tap_sync.tms = '0') then tap_ctrl.state <= DR_SHIFT; else tap_ctrl.state <= DR_EXIT1; end if;
when DR_SHIFT => if (tap_sync.tms = '0') then tap_ctrl.state <= DR_SHIFT; else tap_ctrl.state <= DR_EXIT1; end if;
when DR_EXIT1 => if (tap_sync.tms = '0') then tap_ctrl.state <= DR_PAUSE; else tap_ctrl.state <= DR_UPDATE; end if;
when DR_PAUSE => if (tap_sync.tms = '0') then tap_ctrl.state <= DR_PAUSE; else tap_ctrl.state <= DR_EXIT2; end if;
when DR_EXIT2 => if (tap_sync.tms = '0') then tap_ctrl.state <= DR_SHIFT; else tap_ctrl.state <= DR_UPDATE; end if;
when DR_UPDATE => if (tap_sync.tms = '0') then tap_ctrl.state <= RUN_IDLE; else tap_ctrl.state <= DR_SCAN; end if;
when IR_SCAN => if (tap_sync.tms = '0') then tap_ctrl.state <= IR_CAPTURE; else tap_ctrl.state <= LOGIC_RESET; end if;
when IR_CAPTURE => if (tap_sync.tms = '0') then tap_ctrl.state <= IR_SHIFT; else tap_ctrl.state <= IR_EXIT1; end if;
when IR_SHIFT => if (tap_sync.tms = '0') then tap_ctrl.state <= IR_SHIFT; else tap_ctrl.state <= IR_EXIT1; end if;
when IR_EXIT1 => if (tap_sync.tms = '0') then tap_ctrl.state <= IR_PAUSE; else tap_ctrl.state <= IR_UPDATE; end if;
when IR_PAUSE => if (tap_sync.tms = '0') then tap_ctrl.state <= IR_PAUSE; else tap_ctrl.state <= IR_EXIT2; end if;
when IR_EXIT2 => if (tap_sync.tms = '0') then tap_ctrl.state <= IR_SHIFT; else tap_ctrl.state <= IR_UPDATE; end if;
when IR_UPDATE => if (tap_sync.tms = '0') then tap_ctrl.state <= RUN_IDLE; else tap_ctrl.state <= DR_SCAN; end if;
when others => tap_ctrl.state <= LOGIC_RESET;
end case;
end if;
173,23 → 199,20
reg_access: process(clk_i)
begin
if rising_edge(clk_i) then
if (tap_ctrl.trst_sync(1) = '0') then -- reset
tap_reg.ireg <= "00001"; -- IDCODE
elsif (tap_ctrl.tck_sync(2) = '0') and (tap_ctrl.tck_sync(1) = '1') then -- clock pulse (trigger on rising edge)
-- serial data input --
if (tap_sync.tck_rising = '1') then -- clock pulse (evaluate TDI on rising edge of TCK)
 
-- instruction register --
if (tap_ctrl.state = LOGIC_RESET) then -- reset
if (tap_ctrl.state = LOGIC_RESET) or (tap_ctrl.state = IR_CAPTURE) then -- reset or preload phase
tap_reg.ireg <= "00001"; -- IDCODE
elsif (tap_ctrl.state = IR_CAPTURE) then -- preload phase
tap_reg.ireg <= "00001"; -- IDCODE
elsif (tap_ctrl.state = IR_SHIFT) then -- access phase
tap_reg.ireg <= tap_ctrl.tdi_sync(1) & tap_reg.ireg(tap_reg.ireg'left downto 1);
tap_reg.ireg <= tap_sync.tdi & tap_reg.ireg(tap_reg.ireg'left downto 1);
end if;
 
-- data register --
if (tap_ctrl.state = DR_CAPTURE) then -- preload phase
case tap_reg.ireg is
when "00001" => tap_reg.idcode <= IDCODE_VERSION & IDCODE_PARTID & IDCODE_MANID & '1'; -- IDCODE (LBS has to be always set!)
when "00001" => tap_reg.idcode <= IDCODE_VERSION & IDCODE_PARTID & IDCODE_MANID & '1'; -- IDCODE (LSB has to be always set!)
when "10000" => tap_reg.dtmcs <= tap_reg.dtmcs_nxt;-- dtmcs
when "10001" => tap_reg.dmi <= tap_reg.dmi_nxt; -- dmi
when others => tap_reg.bypass <= '0'; -- BYPASS
196,10 → 219,10
end case;
elsif (tap_ctrl.state = DR_SHIFT) then -- access phase
case tap_reg.ireg is
when "00001" => tap_reg.idcode <= tap_ctrl.tdi_sync(1) & tap_reg.idcode(tap_reg.idcode'left downto 1); -- IDCODE
when "10000" => tap_reg.dtmcs <= tap_ctrl.tdi_sync(1) & tap_reg.dtmcs(tap_reg.dtmcs'left downto 1); -- dtmcs
when "10001" => tap_reg.dmi <= tap_ctrl.tdi_sync(1) & tap_reg.dmi(tap_reg.dmi'left downto 1); -- dmi
when others => tap_reg.bypass <= tap_ctrl.tdi_sync(1); -- BYPASS
when "00001" => tap_reg.idcode <= tap_sync.tdi & tap_reg.idcode(tap_reg.idcode'left downto 1); -- IDCODE
when "10000" => tap_reg.dtmcs <= tap_sync.tdi & tap_reg.dtmcs(tap_reg.dtmcs'left downto 1); -- dtmcs
when "10001" => tap_reg.dmi <= tap_sync.tdi & tap_reg.dmi(tap_reg.dmi'left downto 1); -- dmi
when others => tap_reg.bypass <= tap_sync.tdi; -- BYPASS
end case;
end if;
end if;
206,13 → 229,13
 
-- serial data output --
if (tap_ctrl.state = IR_SHIFT) then
tap_ctrl.tdo_sync <= tap_reg.ireg(0);
tap_sync.tdo <= tap_reg.ireg(0);
else
case tap_reg.ireg is
when "00001" => tap_ctrl.tdo_sync <= tap_reg.idcode(0); -- IDCODE
when "10000" => tap_ctrl.tdo_sync <= tap_reg.dtmcs(0); -- dtmcs
when "10001" => tap_ctrl.tdo_sync <= tap_reg.dmi(0); -- dmi
when others => tap_ctrl.tdo_sync <= tap_reg.bypass; -- BYPASS
when "00001" => tap_sync.tdo <= tap_reg.idcode(0); -- IDCODE
when "10000" => tap_sync.tdo <= tap_reg.dtmcs(0); -- dtmcs
when "10001" => tap_sync.tdo <= tap_reg.dmi(0); -- dmi
when others => tap_sync.tdo <= tap_reg.bypass; -- BYPASS
end case;
end if;
end if;
221,19 → 244,6
 
-- Debug Module Interface -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
 
-- DTM Control and Status Register (dtmcs) --
tap_reg.dtmcs_nxt(31 downto 18) <= (others => '0'); -- unused
tap_reg.dtmcs_nxt(17) <= '0'; -- dmihardreset, always reads as zero
tap_reg.dtmcs_nxt(16) <= '0'; -- dmireset, always reads as zero
tap_reg.dtmcs_nxt(15) <= '0'; -- unused
tap_reg.dtmcs_nxt(14 downto 12) <= dmi_idle_c; -- minimum number if idle cycles
tap_reg.dtmcs_nxt(11 downto 10) <= tap_reg.dmi_nxt(1 downto 0); -- dmistat
tap_reg.dtmcs_nxt(09 downto 04) <= dmi_abits_c; -- number of DMI address bits
tap_reg.dtmcs_nxt(03 downto 00) <= dmi_version_c; -- version
 
 
-- Debug Module Interface Access Register (dmi) --
dmi_controller: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
263,15 → 273,16
 
when DMI_IDLE => -- waiting for new request
if (tap_ctrl.state = DR_UPDATE) and (tap_ctrl.state_prev /= DR_UPDATE) and (tap_reg.ireg = "10001") then -- update <dmi>
case tap_reg.dmi(1 downto 0) is -- op field
when "01" => dmi_ctrl.state <= DMI_READ_WAIT; -- read
when "10" => dmi_ctrl.state <= DMI_WRITE_WAIT; -- write
when others => NULL;
end case;
dmi_ctrl.addr <= tap_reg.dmi(40 downto 34);
dmi_ctrl.wdata <= tap_reg.dmi(33 downto 02);
if (tap_reg.dmi(1 downto 0) = "01") then -- read
dmi_ctrl.state <= DMI_READ_WAIT;
elsif (tap_reg.dmi(1 downto 0) = "10") then -- write
dmi_ctrl.state <= DMI_WRITE_WAIT;
end if;
dmi_ctrl.addr <= tap_reg.dmi(40 downto 34);
dmi_ctrl.wdata <= tap_reg.dmi(33 downto 02);
end if;
 
 
when DMI_READ_WAIT => -- wait for DMI to become ready
if (dmi_req_ready_i = '1') then
dmi_ctrl.state <= DMI_READ;
287,6 → 298,7
dmi_ctrl.state <= DMI_IDLE;
end if;
 
 
when DMI_WRITE_WAIT => -- wait for DMI to become ready
if (dmi_req_ready_i = '1') then
dmi_ctrl.state <= DMI_WRITE;
301,11 → 313,12
dmi_ctrl.state <= DMI_IDLE;
end if;
 
 
when others => -- undefined
dmi_ctrl.state <= DMI_IDLE;
 
end case;
-- override sticky error flag --
-- clear sticky error flag --
if (dmi_ctrl.dmireset = '1') then
dmi_ctrl.err <= '0';
end if;
313,6 → 326,16
end if;
end process dmi_controller;
 
-- DTM Control and Status Register (dtmcs) --
tap_reg.dtmcs_nxt(31 downto 18) <= (others => '0'); -- unused
tap_reg.dtmcs_nxt(17) <= '0'; -- dmihardreset, always reads as zero
tap_reg.dtmcs_nxt(16) <= '0'; -- dmireset, always reads as zero
tap_reg.dtmcs_nxt(15) <= '0'; -- unused
tap_reg.dtmcs_nxt(14 downto 12) <= dmi_idle_c; -- minimum number of idle cycles
tap_reg.dtmcs_nxt(11 downto 10) <= tap_reg.dmi_nxt(1 downto 0); -- dmistat
tap_reg.dtmcs_nxt(09 downto 04) <= dmi_abits_c; -- number of DMI address bits
tap_reg.dtmcs_nxt(03 downto 00) <= dmi_version_c; -- version
 
-- DMI register read access --
tap_reg.dmi_nxt(40 downto 34) <= dmi_ctrl.addr; -- address
tap_reg.dmi_nxt(33 downto 02) <= dmi_ctrl.rdata; -- read data
/rtl/core/neorv32_gptmr.vhd
176,7 → 176,7
if rising_edge(clk_i) then
if (timer.cnt_we = '1') then -- write access
timer.count <= data_i;
elsif (ctrl(ctrl_en_c) = '1') then -- enabled
elsif (ctrl(ctrl_en_c) = '1') and (gptmr_clk_en = '1') then -- enabled and clock tick
if (timer.match = '1') then
if (ctrl(ctrl_mode_c) = '1') then -- reset counter if continuous mode
timer.count <= (others => '0');
/rtl/core/neorv32_neoled.vhd
89,7 → 89,7
signal rden : std_ulogic; -- read enable
 
-- Control register bits --
constant ctrl_enable_c : natural := 0; -- r/w: module enable
constant ctrl_en_c : natural := 0; -- r/w: module enable
constant ctrl_mode_c : natural := 1; -- r/w: 0 = 24-bit RGB mode, 1 = 32-bit RGBW mode
constant ctrl_strobe_c : natural := 2; -- r/w: 0 = send normal data, 1 = send LED strobe command (RESET) on data write
--
153,6 → 153,14
end record;
signal tx_buffer : tx_buffer_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;
 
-- serial transmission engine --
type serial_state_t is (S_IDLE, S_INIT, S_GETBIT, S_PULSE, S_STROBE);
type serial_t is record
159,6 → 167,7
-- state control --
state : serial_state_t;
mode : std_ulogic;
done : std_ulogic;
busy : std_ulogic;
bit_cnt : std_ulogic_vector(5 downto 0);
-- shift register --
199,7 → 208,7
 
-- write access: control register --
if (wren = '1') and (addr = neoled_ctrl_addr_c) then
ctrl.enable <= data_i(ctrl_enable_c);
ctrl.enable <= data_i(ctrl_en_c);
ctrl.mode <= data_i(ctrl_mode_c);
ctrl.strobe <= data_i(ctrl_strobe_c);
ctrl.clk_prsc <= data_i(ctrl_clksel2_c downto ctrl_clksel0_c);
212,7 → 221,7
-- read access: control register --
data_o <= (others => '0');
if (rden = '1') then -- and (addr = neoled_ctrl_addr_c) then
data_o(ctrl_enable_c) <= ctrl.enable;
data_o(ctrl_en_c) <= ctrl.enable;
data_o(ctrl_mode_c) <= ctrl.mode;
data_o(ctrl_strobe_c) <= ctrl.strobe;
data_o(ctrl_clksel2_c downto ctrl_clksel0_c) <= ctrl.clk_prsc;
241,26 → 250,42
 
-- IRQ Generator --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
irq_select: process(ctrl, tx_buffer)
begin
if (FIFO_DEPTH = 1) then
irq.set <= tx_buffer.free; -- 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;
end if;
end process irq_select;
 
-- Interrupt Arbiter --
irq_generator: process(clk_i)
begin
if rising_edge(clk_i) then
if (ctrl.enable = '0') then
irq_o <= '0'; -- no interrupt if unit is disabled
irq.pending <= '0';
else
if (FIFO_DEPTH = 1) then
irq_o <= tx_buffer.free; -- fire IRQ if FIFO is empty
else
if (ctrl.irq_conf = '0') then -- fire IRQ if FIFO is less than half-full
irq_o <= not tx_buffer.half;
else -- fire IRQ if FIFO is empty
irq_o <= tx_buffer.free;
end if;
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;
end if;
end if;
end process irq_generator;
 
-- IRQ request to CPU --
irq_o <= irq.pending;
 
-- IRQ acknowledge --
irq.clr <= '1' when (wren = '1') else '0'; -- write data or control register
 
 
-- TX Buffer (FIFO) -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
tx_data_fifo: neorv32_fifo
299,6 → 324,9
-- clock generator --
serial.pulse_clk <= clkgen_i(to_integer(unsigned(ctrl.clk_prsc)));
 
-- defaults --
serial.done <= '0';
 
-- FSM --
if (ctrl.enable = '0') then -- disabled
serial.state <= S_IDLE;
342,6 → 370,7
end if;
if (serial.bit_cnt = "000000") then -- all done?
serial.tx_out <= '0';
serial.done <= '1'; -- done sending data
serial.state <= S_IDLE;
else -- send current data MSB
serial.tx_out <= '1';
378,6 → 407,7
end if;
-- number of LOW periods reached for RESET? --
if (and_reduce_f(serial.strobe_cnt) = '1') then
serial.done <= '1'; -- done sending RESET
serial.state <= S_IDLE;
end if;
 
/rtl/core/neorv32_package.vhd
64,7 → 64,7
-- 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"01060301"; -- no touchy!
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01060400"; -- no touchy!
constant archid_c : natural := 19; -- official NEORV32 architecture ID - hands off!
 
-- External Interface Types ---------------------------------------------------------------
316,70 → 316,69
constant ctrl_rf_rd_adr4_c : natural := 15; -- destination register address bit 4
constant ctrl_rf_wb_en_c : natural := 16; -- write back enable
-- alu --
constant ctrl_alu_arith_c : natural := 17; -- ALU arithmetic command
constant ctrl_alu_logic0_c : natural := 18; -- ALU logic command bit 0
constant ctrl_alu_logic1_c : natural := 19; -- ALU logic command bit 1
constant ctrl_alu_op0_c : natural := 17; -- ALU operation select bit 0
constant ctrl_alu_op1_c : natural := 18; -- ALU operation select bit 1
constant ctrl_alu_op2_c : natural := 19; -- ALU operation select bit 2
constant ctrl_alu_func0_c : natural := 20; -- ALU function select command bit 0
constant ctrl_alu_func1_c : natural := 21; -- ALU function select command bit 1
constant ctrl_alu_addsub_c : natural := 22; -- 0=ADD, 1=SUB
constant ctrl_alu_opa_mux_c : natural := 23; -- operand A select (0=rs1, 1=PC)
constant ctrl_alu_opb_mux_c : natural := 24; -- operand B select (0=rs2, 1=IMM)
constant ctrl_alu_unsigned_c : natural := 25; -- is unsigned ALU operation
constant ctrl_alu_shift_dir_c : natural := 26; -- shift direction (0=left, 1=right)
constant ctrl_alu_shift_ar_c : natural := 27; -- is arithmetic shift
constant ctrl_alu_frm0_c : natural := 28; -- FPU rounding mode bit 0
constant ctrl_alu_frm1_c : natural := 29; -- FPU rounding mode bit 1
constant ctrl_alu_frm2_c : natural := 30; -- FPU rounding mode bit 2
constant ctrl_alu_opa_mux_c : natural := 22; -- operand A select (0=rs1, 1=PC)
constant ctrl_alu_opb_mux_c : natural := 23; -- operand B select (0=rs2, 1=IMM)
constant ctrl_alu_unsigned_c : natural := 24; -- is unsigned ALU operation
constant ctrl_alu_shift_dir_c : natural := 25; -- shift direction (0=left, 1=right)
constant ctrl_alu_shift_ar_c : natural := 26; -- is arithmetic shift
constant ctrl_alu_frm0_c : natural := 27; -- FPU rounding mode bit 0
constant ctrl_alu_frm1_c : natural := 28; -- FPU rounding mode bit 1
constant ctrl_alu_frm2_c : natural := 29; -- FPU rounding mode bit 2
-- bus interface --
constant ctrl_bus_size_lsb_c : natural := 31; -- transfer size lsb (00=byte, 01=half-word)
constant ctrl_bus_size_msb_c : natural := 32; -- transfer size msb (10=word, 11=?)
constant ctrl_bus_rd_c : natural := 33; -- read data request
constant ctrl_bus_wr_c : natural := 34; -- write data request
constant ctrl_bus_if_c : natural := 35; -- instruction fetch request
constant ctrl_bus_mo_we_c : natural := 36; -- memory address and data output register write enable
constant ctrl_bus_mi_we_c : natural := 37; -- memory data input register write enable
constant ctrl_bus_unsigned_c : natural := 38; -- is unsigned load
constant ctrl_bus_ierr_ack_c : natural := 39; -- acknowledge instruction fetch bus exceptions
constant ctrl_bus_derr_ack_c : natural := 40; -- acknowledge data access bus exceptions
constant ctrl_bus_fence_c : natural := 41; -- executed fence operation
constant ctrl_bus_fencei_c : natural := 42; -- executed fencei operation
constant ctrl_bus_lock_c : natural := 43; -- make atomic/exclusive access lock
constant ctrl_bus_de_lock_c : natural := 44; -- remove atomic/exclusive access
constant ctrl_bus_ch_lock_c : natural := 45; -- evaluate atomic/exclusive lock (SC operation)
constant ctrl_bus_size_lsb_c : natural := 30; -- transfer size lsb (00=byte, 01=half-word)
constant ctrl_bus_size_msb_c : natural := 31; -- transfer size msb (10=word, 11=?)
constant ctrl_bus_rd_c : natural := 32; -- read data request
constant ctrl_bus_wr_c : natural := 33; -- write data request
constant ctrl_bus_if_c : natural := 34; -- instruction fetch request
constant ctrl_bus_mo_we_c : natural := 35; -- memory address and data output register write enable
constant ctrl_bus_mi_we_c : natural := 36; -- memory data input register write enable
constant ctrl_bus_unsigned_c : natural := 37; -- is unsigned load
constant ctrl_bus_ierr_ack_c : natural := 38; -- acknowledge instruction fetch bus exceptions
constant ctrl_bus_derr_ack_c : natural := 39; -- acknowledge data access bus exceptions
constant ctrl_bus_fence_c : natural := 40; -- executed fence operation
constant ctrl_bus_fencei_c : natural := 41; -- executed fencei operation
constant ctrl_bus_lock_c : natural := 42; -- make atomic/exclusive access lock
constant ctrl_bus_de_lock_c : natural := 43; -- remove atomic/exclusive access
constant ctrl_bus_ch_lock_c : natural := 44; -- evaluate atomic/exclusive lock (SC operation)
-- co-processors --
constant ctrl_cp_id_lsb_c : natural := 46; -- cp select ID lsb
constant ctrl_cp_id_msb_c : natural := 47; -- cp select ID msb
constant ctrl_cp_id_lsb_c : natural := 45; -- cp select ID lsb
constant ctrl_cp_id_msb_c : natural := 46; -- cp select ID msb
-- instruction's control blocks (used by cpu co-processors) --
constant ctrl_ir_funct3_0_c : natural := 48; -- funct3 bit 0
constant ctrl_ir_funct3_1_c : natural := 49; -- funct3 bit 1
constant ctrl_ir_funct3_2_c : natural := 50; -- funct3 bit 2
constant ctrl_ir_funct12_0_c : natural := 51; -- funct12 bit 0
constant ctrl_ir_funct12_1_c : natural := 52; -- funct12 bit 1
constant ctrl_ir_funct12_2_c : natural := 53; -- funct12 bit 2
constant ctrl_ir_funct12_3_c : natural := 54; -- funct12 bit 3
constant ctrl_ir_funct12_4_c : natural := 55; -- funct12 bit 4
constant ctrl_ir_funct12_5_c : natural := 56; -- funct12 bit 5
constant ctrl_ir_funct12_6_c : natural := 57; -- funct12 bit 6
constant ctrl_ir_funct12_7_c : natural := 58; -- funct12 bit 7
constant ctrl_ir_funct12_8_c : natural := 59; -- funct12 bit 8
constant ctrl_ir_funct12_9_c : natural := 60; -- funct12 bit 9
constant ctrl_ir_funct12_10_c : natural := 61; -- funct12 bit 10
constant ctrl_ir_funct12_11_c : natural := 62; -- funct12 bit 11
constant ctrl_ir_opcode7_0_c : natural := 63; -- opcode7 bit 0
constant ctrl_ir_opcode7_1_c : natural := 64; -- opcode7 bit 1
constant ctrl_ir_opcode7_2_c : natural := 65; -- opcode7 bit 2
constant ctrl_ir_opcode7_3_c : natural := 66; -- opcode7 bit 3
constant ctrl_ir_opcode7_4_c : natural := 67; -- opcode7 bit 4
constant ctrl_ir_opcode7_5_c : natural := 68; -- opcode7 bit 5
constant ctrl_ir_opcode7_6_c : natural := 69; -- opcode7 bit 6
constant ctrl_ir_funct3_0_c : natural := 47; -- funct3 bit 0
constant ctrl_ir_funct3_1_c : natural := 48; -- funct3 bit 1
constant ctrl_ir_funct3_2_c : natural := 49; -- funct3 bit 2
constant ctrl_ir_funct12_0_c : natural := 50; -- funct12 bit 0
constant ctrl_ir_funct12_1_c : natural := 51; -- funct12 bit 1
constant ctrl_ir_funct12_2_c : natural := 52; -- funct12 bit 2
constant ctrl_ir_funct12_3_c : natural := 53; -- funct12 bit 3
constant ctrl_ir_funct12_4_c : natural := 54; -- funct12 bit 4
constant ctrl_ir_funct12_5_c : natural := 55; -- funct12 bit 5
constant ctrl_ir_funct12_6_c : natural := 56; -- funct12 bit 6
constant ctrl_ir_funct12_7_c : natural := 57; -- funct12 bit 7
constant ctrl_ir_funct12_8_c : natural := 58; -- funct12 bit 8
constant ctrl_ir_funct12_9_c : natural := 59; -- funct12 bit 9
constant ctrl_ir_funct12_10_c : natural := 60; -- funct12 bit 10
constant ctrl_ir_funct12_11_c : natural := 61; -- funct12 bit 11
constant ctrl_ir_opcode7_0_c : natural := 62; -- opcode7 bit 0
constant ctrl_ir_opcode7_1_c : natural := 63; -- opcode7 bit 1
constant ctrl_ir_opcode7_2_c : natural := 64; -- opcode7 bit 2
constant ctrl_ir_opcode7_3_c : natural := 65; -- opcode7 bit 3
constant ctrl_ir_opcode7_4_c : natural := 66; -- opcode7 bit 4
constant ctrl_ir_opcode7_5_c : natural := 67; -- opcode7 bit 5
constant ctrl_ir_opcode7_6_c : natural := 68; -- opcode7 bit 6
-- CPU status --
constant ctrl_priv_lvl_lsb_c : natural := 70; -- privilege level lsb
constant ctrl_priv_lvl_msb_c : natural := 71; -- privilege level msb
constant ctrl_sleep_c : natural := 72; -- set when CPU is in sleep mode
constant ctrl_trap_c : natural := 73; -- set when CPU is entering trap execution
constant ctrl_debug_running_c : natural := 74; -- CPU is in debug mode when set
constant ctrl_priv_lvl_lsb_c : natural := 69; -- privilege level lsb
constant ctrl_priv_lvl_msb_c : natural := 70; -- privilege level msb
constant ctrl_sleep_c : natural := 71; -- set when CPU is in sleep mode
constant ctrl_trap_c : natural := 72; -- set when CPU is entering trap execution
constant ctrl_debug_running_c : natural := 73; -- CPU is in debug mode when set
-- control bus size --
constant ctrl_width_c : natural := 75; -- control bus size
constant ctrl_width_c : natural := 74; -- control bus size
 
-- Comparator Bus -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
526,7 → 525,7
-- -------------------------------------------------------------------------------------------
-- <<< standard read/write CSRs >>> --
-- user floating-point CSRs --
constant csr_class_float_c : std_ulogic_vector(07 downto 0) := x"00"; -- floating point
constant csr_class_float_c : std_ulogic_vector(09 downto 0) := x"00" & "00"; -- floating point
constant csr_fflags_c : std_ulogic_vector(11 downto 0) := x"001";
constant csr_frm_c : std_ulogic_vector(11 downto 0) := x"002";
constant csr_fcsr_c : std_ulogic_vector(11 downto 0) := x"003";
576,7 → 575,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(07 downto 0) := x"34"; -- machine trap handling
constant csr_class_trap_c : std_ulogic_vector(08 downto 0) := x"34" & '0'; -- 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";
761,19 → 760,20
 
-- ALU Function Codes ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- arithmetic core --
constant alu_arith_cmd_addsub_c : std_ulogic := '0'; -- r.arith <= A +/- B
constant alu_arith_cmd_slt_c : std_ulogic := '1'; -- r.arith <= A < B
-- logic core --
constant alu_logic_cmd_movb_c : std_ulogic_vector(1 downto 0) := "00"; -- r.logic <= B
constant alu_logic_cmd_xor_c : std_ulogic_vector(1 downto 0) := "01"; -- r.logic <= A xor B
constant alu_logic_cmd_or_c : std_ulogic_vector(1 downto 0) := "10"; -- r.logic <= A or B
constant alu_logic_cmd_and_c : std_ulogic_vector(1 downto 0) := "11"; -- r.logic <= A and B
-- function select (actual alu result) --
constant alu_func_cmd_arith_c : std_ulogic_vector(1 downto 0) := "00"; -- r <= r.arith
constant alu_func_cmd_logic_c : std_ulogic_vector(1 downto 0) := "01"; -- r <= r.logic
constant alu_func_cmd_csrr_c : std_ulogic_vector(1 downto 0) := "10"; -- r <= CSR read
constant alu_func_cmd_copro_c : std_ulogic_vector(1 downto 0) := "11"; -- r <= CP result (multi-cycle)
-- ALU core [DO NOT CHANGE ENCODING!] --
constant alu_op_add_c : std_ulogic_vector(2 downto 0) := "000"; -- alu_result <= A + B
constant alu_op_sub_c : std_ulogic_vector(2 downto 0) := "001"; -- alu_result <= A - B
--constant alu_op_mova_c : std_ulogic_vector(2 downto 0) := "010"; -- alu_result <= A (rs1)
constant alu_op_slt_c : std_ulogic_vector(2 downto 0) := "011"; -- alu_result <= A < B
constant alu_op_movb_c : std_ulogic_vector(2 downto 0) := "100"; -- alu_result <= B
constant alu_op_xor_c : std_ulogic_vector(2 downto 0) := "101"; -- alu_result <= A xor B
constant alu_op_or_c : std_ulogic_vector(2 downto 0) := "110"; -- alu_result <= A or B
constant alu_op_and_c : std_ulogic_vector(2 downto 0) := "111"; -- alu_result <= A and B
-- function select (actual ALU result) --
constant alu_func_core_c : std_ulogic_vector(1 downto 0) := "00"; -- r <= alu_result
constant alu_func_nxpc_c : std_ulogic_vector(1 downto 0) := "01"; -- r <= next_PC
constant alu_func_csrr_c : std_ulogic_vector(1 downto 0) := "10"; -- r <= CSR read
constant alu_func_copro_c : std_ulogic_vector(1 downto 0) := "11"; -- r <= CP result (multi-cycle)
 
-- Trap ID Codes --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
1177,6 → 1177,7
imm_o : out std_ulogic_vector(data_width_c-1 downto 0); -- immediate
fetch_pc_o : out std_ulogic_vector(data_width_c-1 downto 0); -- PC for instruction fetch
curr_pc_o : out std_ulogic_vector(data_width_c-1 downto 0); -- current PC (corresponding to current instruction)
next_pc_o : out std_ulogic_vector(data_width_c-1 downto 0); -- next PC (corresponding to next instruction)
csr_rdata_o : out std_ulogic_vector(data_width_c-1 downto 0); -- CSR read data
-- FPU interface --
fpu_flags_i : in std_ulogic_vector(04 downto 0); -- exception flags
1244,7 → 1245,8
-- data input --
rs1_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 1
rs2_i : in std_ulogic_vector(data_width_c-1 downto 0); -- rf source 2
pc2_i : in std_ulogic_vector(data_width_c-1 downto 0); -- delayed PC
pc_i : in std_ulogic_vector(data_width_c-1 downto 0); -- current PC
pc2_i : in std_ulogic_vector(data_width_c-1 downto 0); -- next PC
imm_i : in std_ulogic_vector(data_width_c-1 downto 0); -- immediate
csr_i : in std_ulogic_vector(data_width_c-1 downto 0); -- CSR read data
-- data output --
1408,16 → 1410,6
-- Component: Bus Keeper ------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
component neorv32_bus_keeper is
generic (
-- External memory interface --
MEM_EXT_EN : boolean; -- implement external memory bus interface?
-- Internal instruction memory --
MEM_INT_IMEM_EN : boolean; -- implement processor-internal instruction memory
MEM_INT_IMEM_SIZE : natural; -- size of processor-internal instruction memory in bytes
-- Internal data memory --
MEM_INT_DMEM_EN : boolean; -- implement processor-internal data memory
MEM_INT_DMEM_SIZE : natural -- size of processor-internal data memory in bytes
);
port (
-- host access --
clk_i : in std_ulogic; -- global clock line
1433,7 → 1425,9
bus_rden_i : in std_ulogic; -- read enable
bus_wren_i : in std_ulogic; -- write enable
bus_ack_i : in std_ulogic; -- transfer acknowledge from bus system
bus_err_i : in std_ulogic -- transfer error from bus system
bus_err_i : in std_ulogic; -- transfer error from bus system
bus_tmo_i : in std_ulogic; -- transfer timeout (external interface)
bus_ext_i : in std_ulogic -- external bus access
);
end component;
 
1790,7 → 1784,9
lock_i : in std_ulogic; -- exclusive access request
ack_o : out std_ulogic; -- transfer acknowledge
err_o : out std_ulogic; -- transfer error
tmo_o : out std_ulogic; -- transfer timeout
priv_i : in std_ulogic_vector(01 downto 0); -- current CPU privilege level
ext_o : out std_ulogic; -- active external access
-- wishbone interface --
wb_tag_o : out std_ulogic_vector(02 downto 0); -- request tag
wb_adr_o : out std_ulogic_vector(31 downto 0); -- address
1824,6 → 1820,7
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
err_o : out std_ulogic; -- transfer error
-- clock generator --
clkgen_en_o : out std_ulogic; -- enable clock generator
clkgen_i : in std_ulogic_vector(07 downto 0); -- "clock" inputs
/rtl/core/neorv32_slink.vhd
126,6 → 126,8
signal ack_write : std_ulogic;
signal acc_en : std_ulogic;
signal addr : std_ulogic_vector(31 downto 0);
signal wren : std_ulogic; -- word write enable
signal rden : std_ulogic; -- read enable
 
-- control register --
signal enable : std_ulogic; -- global enable
148,6 → 150,17
signal rx_fifo_half : std_ulogic_vector(7 downto 0);
signal tx_fifo_half : std_ulogic_vector(7 downto 0);
 
-- 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;
 
begin
 
-- Sanity Checks --------------------------------------------------------------------------
169,6 → 182,8
-- -------------------------------------------------------------------------------------------
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = slink_base_c(hi_abb_c downto lo_abb_c)) else '0';
addr <= slink_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned
wren <= acc_en and wren_i;
rden <= acc_en and rden_i;
 
 
-- Read/Write Access ----------------------------------------------------------------------
178,7 → 193,7
if rising_edge(clk_i) then
-- write access --
ack_write <= '0';
if (acc_en = '1') and (wren_i = '1') then
if (wren = '1') then
if (addr(5) = '0') then -- control/status/irq
if (addr(4 downto 3) = "00") then -- control register
enable <= data_i(ctrl_en_c);
202,7 → 217,7
-- read access --
data_o <= (others => '0');
ack_read <= '0';
if (acc_en = '1') and (rden_i = '1') then
if (rden = '1') then
if (addr(5) = '0') then -- control/status registers
ack_read <= '1';
case addr(4 downto 3) is
246,50 → 261,110
 
-- Interrupt Generator --------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
irq_arbiter: process(clk_i)
variable rx_tmp_v : std_ulogic_vector(SLINK_NUM_RX-1 downto 0);
variable tx_tmp_v : std_ulogic_vector(SLINK_NUM_TX-1 downto 0);
irq_type: process(irq_rx_mode, rx_fifo_avail, rx_fifo_half,
irq_tx_mode, tx_fifo_free, tx_fifo_half)
begin
if rising_edge(clk_i) then
if (enable = '0') then -- no interrupts if unit is disabled
irq_rx_o <= '0';
irq_tx_o <= '0';
-- 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
else
 
-- RX interrupt --
if (SLINK_RX_FIFO = 1) then
irq_rx_o <= or_reduce_f(irq_rx_en and rx_fifo_avail); -- fire if any RX_FIFO is not empty
else
rx_tmp_v := (others => '0');
for i in 0 to SLINK_NUM_RX-1 loop
if (irq_rx_mode(i) = '0') then -- fire if any RX_FIFO is at least half-full
rx_tmp_v(i) := rx_fifo_half(i);
else -- fire if any RX_FIFO is not empty (= data available)
rx_tmp_v(i) := rx_fifo_avail(i);
end if;
end loop;
irq_rx_o <= or_reduce_f(irq_rx_en and rx_tmp_v);
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;
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
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;
end if;
end loop;
end process irq_type;
 
-- TX interrupt --
if (SLINK_TX_FIFO = 1) then
irq_tx_o <= or_reduce_f(irq_tx_en and tx_fifo_free); -- fire if any TX_FIFO is not full
else
tx_tmp_v := (others => '0');
for i in 0 to SLINK_NUM_TX-1 loop
if (irq_tx_mode(i) = '0') then -- fire if any RX_FIFO is less than half-full
tx_tmp_v(i) := not rx_fifo_half(i);
else -- fire if any RX_FIFO is not full (= free buffer space available)
tx_tmp_v(i) := tx_fifo_free(i);
end if;
end loop;
irq_tx_o <= or_reduce_f(irq_tx_en and tx_tmp_v);
-- interrupt trigger --
irq_trigger_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
rx_irq.detect(i) <= rx_irq.detect(i)(0) & rx_irq.trigger(i);
end loop;
end if;
-- TX --
tx_irq.detect <= (others => (others => '0')); -- default
if (enable = '1') then
for i in 0 to SLINK_NUM_TX-1 loop
tx_irq.detect(i) <= tx_irq.detect(i)(0) & tx_irq.trigger(i);
end loop;
end if;
end if;
end process irq_trigger_sync;
 
-- interrupt trigger --
irq_trigger_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
rx_irq.set(i) <= '1';
end if;
end loop;
-- 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
tx_irq.set(i) <= '1';
end if;
end loop;
end process irq_trigger_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;
end if;
end process irq_arbiter;
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)
309,8 → 384,8
 
fifo_access_gen:
for i in 0 to 7 generate
tx_fifo_we(i) <= link_sel(i) and acc_en and wren_i;
rx_fifo_re(i) <= link_sel(i) and acc_en and rden_i;
tx_fifo_we(i) <= link_sel(i) and wren;
rx_fifo_re(i) <= link_sel(i) and rden;
end generate;
 
 
/rtl/core/neorv32_spi.vhd
3,7 → 3,7
-- # ********************************************************************************************* #
-- # Frame format: 8/16/24/32-bit receive/transmit data, always MSB first, 2 clock modes, #
-- # 8 pre-scaled clocks (derived from system clock), 8 dedicated chip-select lines (low-active). #
-- # Interrupt: SPI_transfer_done #
-- # Interrupt: "transfer done" #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License #
-- # #
116,6 → 116,14
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 -------------------------------------------------------------------------
231,6 → 239,7
 
-- defaults --
spi_sck_o <= ctrl(ctrl_cpol_c);
irq.set <= '0';
 
-- serial engine --
rtx_engine.state(2) <= ctrl(ctrl_en_c);
264,7 → 273,8
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?
rtx_engine.state(1 downto 0) <= "00";
irq.set <= '1'; -- interrupt!
rtx_engine.state(1 downto 0) <= "00"; -- transmission done
else
rtx_engine.state(1 downto 0) <= "10";
end if;
282,9 → 292,28
rtx_engine.busy <= '0' when (rtx_engine.state(1 downto 0) = "00") else '1';
 
 
-- Interrupt ------------------------------------------------------------------------------
-- Interrupt Generator --------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
irq_o <= '1' when (rtx_engine.state = "100") else '0'; -- fire IRQ if transceiver idle and enabled
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
158,8 → 158,8
-- Memory --
sysinfo_mem(2)(00) <= bool_to_ulogic_f(INT_BOOTLOADER_EN); -- processor-internal bootloader implemented?
sysinfo_mem(2)(01) <= bool_to_ulogic_f(MEM_EXT_EN); -- external memory bus interface implemented?
sysinfo_mem(2)(02) <= bool_to_ulogic_f(MEM_INT_IMEM_EN); -- processor-internal instruction memory implemented?
sysinfo_mem(2)(03) <= bool_to_ulogic_f(MEM_INT_DMEM_EN); -- processor-internal data memory implemented?
sysinfo_mem(2)(02) <= bool_to_ulogic_f(MEM_INT_IMEM_EN) and bool_to_ulogic_f(boolean(MEM_INT_IMEM_SIZE > 0)); -- processor-internal instruction memory implemented?
sysinfo_mem(2)(03) <= bool_to_ulogic_f(MEM_INT_DMEM_EN) and bool_to_ulogic_f(boolean(MEM_INT_DMEM_SIZE > 0)); -- processor-internal data memory implemented?
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?
--
/rtl/core/neorv32_top.vhd
276,6 → 276,9
end record;
signal cpu_i, i_cache, cpu_d, p_bus : bus_interface_t;
 
-- bus access error (from BUSKEEPER) --
signal bus_error : std_ulogic;
 
-- debug core interface (DCI) --
signal dci_ndmrstn : std_ulogic;
signal dci_halt_req : std_ulogic;
334,7 → 337,9
signal gptmr_irq : std_ulogic;
 
-- misc --
signal mtime_time : std_ulogic_vector(63 downto 0); -- current system time from MTIME
signal mtime_time : std_ulogic_vector(63 downto 0); -- current system time from MTIME
signal ext_timeout : std_ulogic;
signal ext_access : std_ulogic;
 
begin
 
531,19 → 536,20
fence_o <= cpu_d.fence; -- indicates an executed FENCE operation
fencei_o <= cpu_i.fence; -- indicates an executed FENCEI operation
 
-- fast interrupts --
fast_irq(00) <= wdt_irq; -- HIGHEST PRIORITY - watchdog timeout
-- fast interrupt requests (FIRQs) --
-- these stay asserted until explicitly acknowledged --
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 interrupt
fast_irq(03) <= uart0_txd_irq; -- primary UART (UART0) TX interrupt
fast_irq(04) <= uart1_rxd_irq; -- secondary UART (UART1) RX interrupt
fast_irq(05) <= uart1_txd_irq; -- secondary UART (UART1) TX interrupt
fast_irq(06) <= spi_irq; -- SPI idle
fast_irq(07) <= twi_irq; -- TWI idle
fast_irq(02) <= uart0_rxd_irq; -- primary UART (UART0) RX
fast_irq(03) <= uart0_txd_irq; -- primary UART (UART0) TX
fast_irq(04) <= uart1_rxd_irq; -- secondary UART (UART1) RX
fast_irq(05) <= uart1_txd_irq; -- secondary UART (UART1) TX
fast_irq(06) <= spi_irq; -- SPI
fast_irq(07) <= twi_irq; -- TWI
fast_irq(08) <= xirq_irq; -- external interrupt controller
fast_irq(09) <= neoled_irq; -- NEOLED buffer free
fast_irq(10) <= slink_rx_irq; -- SLINK RX interrupt
fast_irq(11) <= slink_tx_irq; -- SLINK TX interrupt
fast_irq(10) <= slink_rx_irq; -- SLINK RX
fast_irq(11) <= slink_tx_irq; -- SLINK TX
fast_irq(12) <= gptmr_irq; -- general purpose timer
--
fast_irq(13) <= '0'; -- reserved
644,7 → 650,7
p_bus_re_o => p_bus.re, -- read enable
p_bus_lock_o => p_bus.lock, -- exclusive access request
p_bus_ack_i => p_bus.ack, -- bus transfer acknowledge
p_bus_err_i => p_bus.err -- bus transfer error
p_bus_err_i => bus_error -- bus transfer error
);
 
-- current CPU privilege level --
676,16 → 682,6
-- Bus Keeper (BUSKEEPER) -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
neorv32_bus_keeper_inst: neorv32_bus_keeper
generic map (
-- External memory interface --
MEM_EXT_EN => MEM_EXT_EN, -- implement external memory bus interface?
-- Internal instruction memory --
MEM_INT_IMEM_EN => MEM_INT_IMEM_EN, -- implement processor-internal instruction memory
MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE, -- size of processor-internal instruction memory in bytes
-- Internal data memory --
MEM_INT_DMEM_EN => MEM_INT_DMEM_EN, -- implement processor-internal data memory
MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE -- size of processor-internal data memory in bytes
)
port map (
-- host access --
clk_i => clk_i, -- global clock line
695,20 → 691,25
wren_i => io_wren, -- byte write enable
data_o => resp_bus(RESP_BUSKEEPER).rdata, -- data out
ack_o => resp_bus(RESP_BUSKEEPER).ack, -- transfer acknowledge
err_o => resp_bus(RESP_BUSKEEPER).err, -- transfer error
err_o => bus_error, -- transfer error
-- bus monitoring --
bus_addr_i => p_bus.addr, -- address
bus_rden_i => p_bus.re, -- read enable
bus_wren_i => p_bus.we, -- write enable
bus_ack_i => p_bus.ack, -- transfer acknowledge from bus system
bus_err_i => p_bus.err -- transfer error from bus system
bus_err_i => p_bus.err, -- transfer error from bus system
bus_tmo_i => ext_timeout, -- transfer timeout (external interface)
bus_ext_i => ext_access -- external bus access
);
 
-- unused, BUSKEEPER **directly** issues error to the CPU --
resp_bus(RESP_BUSKEEPER).err <= '0';
 
 
-- Processor-Internal Instruction Memory (IMEM) -------------------------------------------
-- -------------------------------------------------------------------------------------------
neorv32_int_imem_inst_true:
if (MEM_INT_IMEM_EN = true) generate
if (MEM_INT_IMEM_EN = true) and (MEM_INT_IMEM_SIZE > 0) generate
neorv32_int_imem_inst: neorv32_imem
generic map (
IMEM_BASE => imem_base_c, -- memory base address
729,7 → 730,7
end generate;
 
neorv32_int_imem_inst_false:
if (MEM_INT_IMEM_EN = false) generate
if (MEM_INT_IMEM_EN = false) or (MEM_INT_IMEM_SIZE = 0) generate
resp_bus(RESP_IMEM) <= resp_bus_entry_terminate_c;
end generate;
 
737,7 → 738,7
-- Processor-Internal Data Memory (DMEM) --------------------------------------------------
-- -------------------------------------------------------------------------------------------
neorv32_int_dmem_inst_true:
if (MEM_INT_DMEM_EN = true) generate
if (MEM_INT_DMEM_EN = true) and (MEM_INT_DMEM_SIZE > 0) generate
neorv32_int_dmem_inst: neorv32_dmem
generic map (
DMEM_BASE => dmem_base_c, -- memory base address
757,7 → 758,7
end generate;
 
neorv32_int_dmem_inst_false:
if (MEM_INT_DMEM_EN = false) generate
if (MEM_INT_DMEM_EN = false) or (MEM_INT_DMEM_SIZE = 0) generate
resp_bus(RESP_DMEM) <= resp_bus_entry_terminate_c;
end generate;
 
819,7 → 820,9
lock_i => p_bus.lock, -- exclusive access request
ack_o => resp_bus(RESP_WISHBONE).ack, -- transfer acknowledge
err_o => resp_bus(RESP_WISHBONE).err, -- transfer error
tmo_o => ext_timeout, -- transfer timeout
priv_i => p_bus.priv, -- current CPU privilege level
ext_o => ext_access, -- active external access
-- wishbone interface --
wb_tag_o => wb_tag_o, -- request tag
wb_adr_o => wb_adr_o, -- address
838,6 → 841,8
neorv32_wishbone_inst_false:
if (MEM_EXT_EN = false) generate
resp_bus(RESP_WISHBONE) <= resp_bus_entry_terminate_c;
ext_timeout <= '0';
ext_access <= '0';
--
wb_adr_o <= (others => '0');
wb_dat_o <= (others => '0');
878,6 → 883,7
data_i => p_bus.wdata, -- data in
data_o => resp_bus(RESP_CFS).rdata, -- data out
ack_o => resp_bus(RESP_CFS).ack, -- transfer acknowledge
err_o => resp_bus(RESP_CFS).err, -- access error
-- clock generator --
clkgen_en_o => cfs_cg_en, -- enable clock generator
clkgen_i => clk_gen, -- "clock" inputs
887,7 → 893,6
cfs_in_i => cfs_in_i, -- custom inputs
cfs_out_o => cfs_out_o -- custom outputs
);
resp_bus(RESP_CFS).err <= '0'; -- no access error possible
end generate;
 
neorv32_cfs_inst_false:
/rtl/core/neorv32_trng.vhd
1,10 → 1,8
-- #################################################################################################
-- # << NEORV32 - True Random Number Generator (TRNG) >> #
-- # ********************************************************************************************* #
-- # This unit implements a *true* random number generator which uses several ring oscillators as #
-- # entropy source. The outputs of all chains are XORed and de-biased using a John von Neumann #
-- # randomness extractor. The de-biased signal is further processed by a simple LFSR for improved #
-- # whitening. #
-- # This processor module instantiates the "neoTRNG" true random number generator. #
-- # See the neoTRNG's documentation for more information: https://github.com/stnolting/neoTRNG #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License #
-- # #
59,18 → 57,16
 
architecture neorv32_trng_rtl of neorv32_trng is
 
-- Advanced Configuration --------------------------------------------------------------------------------
constant num_roscs_c : natural := 4; -- total number of ring oscillators
constant num_inv_start_c : natural := 5; -- number of inverters in FIRST ring oscillator (has to be odd)
constant num_inv_inc_c : natural := 2; -- number of inverters increment for each next ring oscillator (has to be even)
constant lfsr_en_c : boolean := true; -- use LFSR-based post-processing
constant lfsr_taps_c : std_ulogic_vector(7 downto 0) := "10111000"; -- Fibonacci post-processing LFSR feedback taps
-- -------------------------------------------------------------------------------------------------------
-- neoTRNG Configuration -------------------------------------------------------------------------------------------
constant num_cells_c : natural := 3; -- total number of ring-oscillator cells
constant num_inv_start_c : natural := 3; -- number of inverters in first cell (short path), has to be odd
constant num_inv_inc_c : natural := 2; -- number of additional inverters in next cell (short path), has to be even
constant num_inv_delay_c : natural := 2; -- additional inverters to form cell's long path, has to be even
-- -----------------------------------------------------------------------------------------------------------------
 
-- control register bits --
constant ctrl_data_lsb_c : natural := 0; -- r/-: Random data byte LSB
constant ctrl_data_msb_c : natural := 7; -- r/-: Random data byte MSB
--
constant ctrl_en_c : natural := 30; -- r/w: TRNG enable
constant ctrl_valid_c : natural := 31; -- r/-: Output data valid
 
78,57 → 74,38
constant hi_abb_c : natural := index_size_f(io_size_c)-1; -- high address boundary bit
constant lo_abb_c : natural := index_size_f(trng_size_c); -- low address boundary bit
 
-- Component: Ring-Oscillator --
component neorv32_trng_ring_osc
-- access control --
signal acc_en : std_ulogic; -- module access enable
signal wren : std_ulogic; -- full word write enable
signal rden : std_ulogic; -- read enable
 
-- Component: neoTRNG true random number generator --
component neoTRNG
generic (
NUM_INV : natural := 16 -- number of inverters in chain
NUM_CELLS : natural; -- total number of ring-oscillator cells
NUM_INV_START : natural; -- number of inverters in first cell (short path), has to be odd
NUM_INV_INC : natural; -- number of additional inverters in next cell (short path), has to be even
NUM_INV_DELAY : natural -- additional inverters to form cell's long path, has to be even
);
port (
clk_i : in std_ulogic;
enable_i : in std_ulogic; -- enable chain input
enable_o : out std_ulogic; -- enable chain output
data_o : out std_ulogic -- sync random bit
clk_i : in std_ulogic; -- global clock line
enable_i : in std_ulogic; -- unit enable (high-active), reset unit when low
data_o : out std_ulogic_vector(7 downto 0); -- random data byte output
valid_o : out std_ulogic -- data_o is valid when set
);
end component;
 
-- access control --
signal acc_en : std_ulogic; -- module access enable
signal wren : std_ulogic; -- full word write enable
signal rden : std_ulogic; -- read enable
-- TRNG interface --
signal trng_data : std_ulogic_vector(7 downto 0);
signal trng_valid : std_ulogic;
 
-- ring-oscillator array --
signal osc_array_en_in : std_ulogic_vector(num_roscs_c-1 downto 0);
signal osc_array_en_out : std_ulogic_vector(num_roscs_c-1 downto 0);
signal osc_array_data : std_ulogic_vector(num_roscs_c-1 downto 0);
-- arbiter --
signal enable : std_ulogic;
signal valid : std_ulogic;
signal rnd_reg : std_ulogic_vector(7 downto 0);
 
-- von-Neumann de-biasing --
type debiasing_t is record
sreg : std_ulogic_vector(1 downto 0);
state : std_ulogic; -- process de-biasing every second cycle
valid : std_ulogic; -- de-biased data
data : std_ulogic; -- de-biased data valid
end record;
signal debiasing : debiasing_t;
 
-- (post-)processing core --
type processing_t is record
enable : std_ulogic; -- TRNG enable flag
cnt : std_ulogic_vector(3 downto 0); -- bit counter
sreg : std_ulogic_vector(7 downto 0); -- data shift register
output : std_ulogic_vector(7 downto 0); -- output register
valid : std_ulogic; -- data output valid flag
end record;
signal processing : processing_t;
 
begin
 
-- Sanity Checks --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
assert not (num_roscs_c = 0) report "NEORV32 PROCESSOR CONFIG ERROR: TRNG - Total number of ring-oscillators has to be >0." severity error;
assert not ((num_inv_start_c mod 2) = 0) report "NEORV32 PROCESSOR CONFIG ERROR: TRNG - Number of inverters in first ring has to be odd." severity error;
assert not ((num_inv_inc_c mod 2) /= 0) report "NEORV32 PROCESSOR CONFIG ERROR: TRNG - Number of inverters increment for each next ring has to be even." severity error;
 
 
-- Access Control -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = trng_base_c(hi_abb_c downto lo_abb_c)) else '0';
141,127 → 118,309
rw_access: process(clk_i)
begin
if rising_edge(clk_i) then
-- host bus acknowledge --
ack_o <= wren or rden;
 
-- write access --
if (wren = '1') then
processing.enable <= data_i(ctrl_en_c);
enable <= data_i(ctrl_en_c);
end if;
 
-- read access --
data_o <= (others => '0');
if (rden = '1') then
data_o(ctrl_data_msb_c downto ctrl_data_lsb_c) <= processing.output;
data_o(ctrl_en_c) <= processing.enable;
data_o(ctrl_valid_c) <= processing.valid;
data_o(ctrl_data_msb_c downto ctrl_data_lsb_c) <= rnd_reg;
data_o(ctrl_en_c) <= enable;
data_o(ctrl_valid_c) <= valid;
end if;
 
-- sample --
if (trng_valid = '1') then
rnd_reg <= trng_data;
end if;
 
-- data valid? --
if (enable = '0') then -- disabled
valid <= '0';
else
if (trng_valid = '1') then
valid <= '1';
elsif (rden = '1') then
valid <= '0';
end if;
end if;
end if;
end process rw_access;
 
 
-- neoTRNG --------------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
neoTRNG_inst: neoTRNG
generic map (
NUM_CELLS => num_cells_c,
NUM_INV_START => num_inv_start_c,
NUM_INV_INC => num_inv_inc_c,
NUM_INV_DELAY => num_inv_delay_c
)
port map (
clk_i => clk_i,
enable_i => enable,
data_o => trng_data,
valid_o => trng_valid
);
 
 
end neorv32_trng_rtl;
 
 
-- ############################################################################################################################
-- ############################################################################################################################
 
 
-- #################################################################################################
-- # << neoTRNG - A Tiny and Platform-Independent True Random Number Generator for any FPGA >> #
-- # ********************************************************************************************* #
-- # This generator is based on entropy cells, which implement simple ring-oscillators. Each ring- #
-- # oscillator features a short and a long delay path that is dynamically selected defining the #
-- # primary oscillation frequency. The cells are cascaded so that the random data output of a #
-- # cell controls the delay path of the next cell (which has the next-larger inverter chain). #
-- # #
-- # The random data outputs of all cells are XOR-ed and de-biased using a von Neumann randomness #
-- # extractor (converting edges into bits). The resulting bit is sampled in chunks of 8 bits to #
-- # provide the final random data output. No further internal post-processing is applied. Hence, #
-- # the TRNG produces simple de-biased *RAW* data. #
-- # #
-- # The entropy cell architecture uses individually-controlled latches and inverters to create #
-- # the inverter chain in a platform-agnostic style that can be implemented for any FPGA without #
-- # requiring primitive instantiation or technology-specific attributes. #
-- # #
-- # See the neoTRNG's documentation for more information: https://github.com/stnolting/neoTRNG #
-- # ********************************************************************************************* #
-- # 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. #
-- # ********************************************************************************************* #
-- # neoTRNG - https://github.com/stnolting/neoTRNG (c) Stephan Nolting #
-- #################################################################################################
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
entity neoTRNG is
generic (
NUM_CELLS : natural; -- total number of ring-oscillator cells
NUM_INV_START : natural; -- number of inverters in first cell (short path), has to be odd
NUM_INV_INC : natural; -- number of additional inverters in next cell (short path), has to be even
NUM_INV_DELAY : natural -- additional inverters to form cell's long path, has to be even
);
port (
clk_i : in std_ulogic; -- global clock line
enable_i : in std_ulogic; -- unit enable (high-active), reset unit when low
data_o : out std_ulogic_vector(7 downto 0); -- random data byte output
valid_o : out std_ulogic -- data_o is valid when set
);
end neoTRNG;
 
architecture neoTRNG_rtl of neoTRNG is
 
-- Component: neoTRNG entropy cell --
component neoTRNG_cell
generic (
NUM_INV_S : natural; -- number of inverters in short path
NUM_INV_L : natural -- number of inverters in long path
);
port (
clk_i : in std_ulogic; -- system clock
select_i : in std_ulogic; -- delay select
enable_i : in std_ulogic; -- enable chain input
enable_o : out std_ulogic; -- enable chain output
data_o : out std_ulogic -- sync random bit
);
end component;
 
-- ring-oscillator array interconnect --
type cell_array_t is record
en_in : std_ulogic_vector(NUM_CELLS-1 downto 0);
en_out : std_ulogic_vector(NUM_CELLS-1 downto 0);
rnd : std_ulogic_vector(NUM_CELLS-1 downto 0);
sel : std_ulogic_vector(NUM_CELLS-1 downto 0);
end record;
signal cell_array : cell_array_t;
 
-- global cell-XOR --
signal rnd_bit : std_ulogic;
 
-- von-Neumann de-biasing --
type debiasing_t is record
sreg : std_ulogic_vector(1 downto 0);
state : std_ulogic; -- process de-biasing every second cycle
valid : std_ulogic; -- de-biased data
data : std_ulogic; -- de-biased data valid
end record;
signal deb : debiasing_t;
 
-- control unit --
type ctrl_t is record
enable : std_ulogic;
run : std_ulogic;
cnt : std_ulogic_vector(2 downto 0); -- bit counter
sreg : std_ulogic_vector(7 downto 0); -- data shift register
end record;
signal ctrl : ctrl_t;
 
begin
 
-- Sanity Checks --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
assert not (NUM_CELLS < 2) report "neoTRNG config ERROR: Total number of ring-oscillator cells <NUM_CELLS> has to be >= 2." severity error;
assert not ((NUM_INV_START mod 2) = 0) report "neoTRNG config ERROR: Number of inverters in first cell <NUM_INV_START> has to be odd." severity error;
assert not ((NUM_INV_INC mod 2) /= 0) report "neoTRNG config ERROR: Inverter increment for each next cell <NUM_INV_INC> has to be even." severity error;
assert not ((NUM_INV_DELAY mod 2) /= 0) report "neoTRNG config ERROR: Inverter increment to form long path <NUM_INV_DELAY> has to be even." severity error;
 
 
-- Entropy Source -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
neorv32_trng_ring_osc_inst:
for i in 0 to num_roscs_c-1 generate
neorv32_trng_ring_osc_inst_i: neorv32_trng_ring_osc
neoTRNG_cell_inst:
for i in 0 to NUM_CELLS-1 generate
neoTRNG_cell_inst_i: neoTRNG_cell
generic map (
NUM_INV => num_inv_start_c + (i*num_inv_inc_c) -- number of inverters in chain
NUM_INV_S => NUM_INV_START + (i*NUM_INV_INC), -- number of inverters in short chain
NUM_INV_L => NUM_INV_START + (i*NUM_INV_INC) + NUM_INV_DELAY -- number of inverters in long chain
)
port map (
clk_i => clk_i,
enable_i => osc_array_en_in(i),
enable_o => osc_array_en_out(i),
data_o => osc_array_data(i)
select_i => cell_array.sel(i),
enable_i => cell_array.en_in(i),
enable_o => cell_array.en_out(i),
data_o => cell_array.rnd(i) -- SYNC data output
);
end generate;
 
-- RO enable chain --
array_intercon: process(processing.enable, osc_array_en_out)
-- path select chain --
cell_array.sel(0) <= cell_array.rnd(NUM_CELLS-1); -- use output of last cell to select path of first cell
cell_array.sel(NUM_CELLS-1 downto 1) <= cell_array.rnd(NUM_CELLS-2 downto 0); -- i+1 <= i
 
-- enable chain --
cell_array.en_in(0) <= ctrl.enable; -- start of chain
cell_array.en_in(NUM_CELLS-1 downto 1) <=cell_array.en_out(NUM_CELLS-2 downto 0); -- i+1 <= i
 
 
-- XOR All Cell's Outputs -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
cell_xor: process(cell_array.rnd)
variable tmp_v : std_ulogic;
begin
for i in 0 to num_roscs_c-1 loop
if (i = 0) then -- start of enable chain
osc_array_en_in(i) <= processing.enable;
else
osc_array_en_in(i) <= osc_array_en_out(i-1);
end if;
tmp_v := '0';
for i in 0 to NUM_CELLS-1 loop
tmp_v := tmp_v xor cell_array.rnd(i);
end loop; -- i
end process array_intercon;
rnd_bit <= tmp_v;
end process cell_xor;
 
 
-- John von Neumann De-Biasing ------------------------------------------------------------
-- John von Neumann Randomness Extractor --------------------------------------------------
-- -------------------------------------------------------------------------------------------
neumann_debiasing_sync: process(clk_i)
debiasing_sync: process(clk_i)
begin
if rising_edge(clk_i) then
debiasing.sreg <= debiasing.sreg(debiasing.sreg'left-1 downto 0) & xor_reduce_f(osc_array_data);
debiasing.state <= (not debiasing.state) and osc_array_en_out(num_roscs_c-1); -- start toggling when last RO is enabled -> process in every second cycle
deb.sreg <= deb.sreg(0) & rnd_bit;
-- start operation when last cell is enabled and process in every second cycle --
deb.state <= (not deb.state) and cell_array.en_out(NUM_CELLS-1);
end if;
end process neumann_debiasing_sync;
end process debiasing_sync;
 
-- Edge detector --
neumann_debiasing_comb: process(debiasing)
-- edge detector --
debiasing_comb: process(deb)
variable tmp_v : std_ulogic_vector(2 downto 0);
begin
-- check groups of two non-overlapping bits from the input stream
tmp_v := debiasing.state & debiasing.sreg;
tmp_v := deb.state & deb.sreg(1 downto 0); -- check groups of two non-overlapping bits from the input stream
case tmp_v is
when "101" => debiasing.valid <= '1'; debiasing.data <= '1'; -- rising edge -> '1'
when "110" => debiasing.valid <= '1'; debiasing.data <= '0'; -- falling edge -> '0'
when others => debiasing.valid <= '0'; debiasing.data <= '0'; -- no valid data
when "101" => deb.valid <= '1'; deb.data <= '0'; -- rising edge = '0'
when "110" => deb.valid <= '1'; deb.data <= '1'; -- falling edge = '1'
when others => deb.valid <= '0'; deb.data <= '-'; -- no valid data
end case;
end process neumann_debiasing_comb;
end process debiasing_comb;
 
 
-- Processing Core ------------------------------------------------------------------------
-- Control Unit ---------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
processing_core: process(clk_i)
control_unit: process(clk_i)
begin
if rising_edge(clk_i) then
-- sample random data bit and apply post-processing --
if (processing.enable = '0') then
processing.cnt <= (others => '0');
processing.sreg <= (others => '0');
elsif (debiasing.valid = '1') then -- valid random sample?
if (processing.cnt = "1000") then
processing.cnt <= (others => '0');
else
processing.cnt <= std_ulogic_vector(unsigned(processing.cnt) + 1);
end if;
if (lfsr_en_c = true) then -- LFSR post-processing
processing.sreg <= processing.sreg(processing.sreg'left-1 downto 0) & ((not xor_reduce_f(processing.sreg and lfsr_taps_c)) xnor debiasing.data);
else -- NO post-processing
processing.sreg <= processing.sreg(processing.sreg'left-1 downto 0) & debiasing.data;
end if;
-- make sure enable is sync --
ctrl.enable <= enable_i;
 
-- sample chunks of 8 bit --
if (ctrl.enable = '0') then
ctrl.cnt <= (others => '0');
ctrl.run <= '0';
elsif (deb.valid = '1') then -- valid random sample?
ctrl.cnt <= std_ulogic_vector(unsigned(ctrl.cnt) + 1);
ctrl.run <= '1';
end if;
 
-- data output register --
if (processing.cnt = "1000") then
processing.output <= processing.sreg;
-- sample shift register --
if (deb.valid = '1') then
ctrl.sreg <= ctrl.sreg(ctrl.sreg'left-1 downto 0) & deb.data;
end if;
 
-- data ready/valid flag --
if (processing.cnt = "1000") then -- new sample ready?
processing.valid <= '1';
elsif (processing.enable = '0') or (rden = '1') then -- clear when deactivated or on data read
processing.valid <= '0';
end if;
end if;
end process processing_core;
end process control_unit;
 
-- random byte output --
data_o <= ctrl.sreg;
 
end neorv32_trng_rtl;
-- data valid? --
valid_o <= '1' when (ctrl.cnt = "000") and (ctrl.run = '1') else '0';
 
 
end neoTRNG_rtl;
 
 
-- ############################################################################################################################
-- ############################################################################################################################
 
 
-- #################################################################################################
-- # << NEORV32 - True Random Number Generator (TRNG) - Ring-Oscillator-Based Entropy Source >> #
-- # << neoTRNG - A Tiny and Platform-Independent True Random Number Generator for any FPGA >> #
-- # ********************************************************************************************* #
-- # An inverter chain (ring oscillator) is used as entropy source. #
-- # The inverter chain is constructed as an "asynchronous" LFSR. The single inverters are #
-- # connected via latches that are used to enable/disable the TRNG. Also, these latches are used #
-- # as additional delay element. By using unique enable signals for each latch, the synthesis #
-- # tool cannot "optimize" (=remove) any of the inverters out of the design. #
-- # neoTRNG Entropy Cell #
-- # #
-- # The cell consists of two ring-oscillators build from inverter chains. The short chain uses #
-- # NUM_INV_S inverters and oscillates at a "high" frequency and the long chain uses NUM_INV_L #
-- # inverters and oscillates at a "low" frequency. The select_i input selects which chain is #
-- # actually used. #
-- # #
-- # Each inverter chain is constructed as an "asynchronous" shift register. The single inverters #
-- # are connected via latches that are used to enable/disable the TRNG. Also, these latches are #
-- # used as additional delay element. By using unique enable signals for each latch, the #
-- # synthesis tool cannot "optimize" (=remove) any of the inverters out of the design making the #
-- # design platform-agnostic. #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License #
-- # #
291,73 → 450,101
-- # 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 #
-- # neoTRNG - https://github.com/stnolting/neoTRNG (c) Stephan Nolting #
-- #################################################################################################
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
library neorv32;
use neorv32.neorv32_package.all;
 
entity neorv32_trng_ring_osc is
entity neoTRNG_cell is
generic (
NUM_INV : natural := 15 -- number of inverters in chain
NUM_INV_S : natural; -- number of inverters in short path
NUM_INV_L : natural -- number of inverters in long path
);
port (
clk_i : in std_ulogic;
clk_i : in std_ulogic; -- system clock
select_i : in std_ulogic; -- delay select
enable_i : in std_ulogic; -- enable chain input
enable_o : out std_ulogic; -- enable chain output
data_o : out std_ulogic -- sync random bit
);
end neorv32_trng_ring_osc;
end neoTRNG_cell;
 
architecture neorv32_trng_ring_osc_rtl of neorv32_trng_ring_osc is
architecture neoTRNG_cell_rtl of neoTRNG_cell is
 
signal inv_chain : std_ulogic_vector(NUM_INV-1 downto 0); -- oscillator chain
signal enable_sreg : std_ulogic_vector(NUM_INV-1 downto 0); -- enable shift register
signal sync_ff : std_ulogic_vector(1 downto 0); -- output signal synchronizer
signal inv_chain_s : std_ulogic_vector(NUM_INV_S-1 downto 0); -- short oscillator chain
signal inv_chain_l : std_ulogic_vector(NUM_INV_L-1 downto 0); -- long oscillator chain
signal feedback : std_ulogic; -- cell feedback/output
signal enable_sreg_s : std_ulogic_vector(NUM_INV_S-1 downto 0); -- enable shift register for short chain
signal enable_sreg_l : std_ulogic_vector(NUM_INV_L-1 downto 0); -- enable shift register for long chain
signal sync_ff : std_ulogic_vector(1 downto 0); -- output signal synchronizer
 
begin
 
-- Ring Oscillator ------------------------------------------------------------------------
-- Ring Oscillators -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
ring_osc: process(enable_i, enable_sreg, inv_chain)
-- Each cell provides a short inverter chain (high frequency) and a long oscillator chain (low frequency).
-- The select_i signals defines which chain is enabled.
-- NOTE: All signals that control a inverter-latch element have to be registered to ensure a single element
-- is mapped to a single LUT (or LUT + FF(latch-mode)).
 
-- short oscillator chain --
ring_osc_short: process(enable_i, enable_sreg_s, feedback, inv_chain_s)
begin
-- Using individual enable signals for each inverter - derived from a shift register - to prevent the synthesis tool
-- from removing all but one inverter (since they implement "logical identical functions").
-- This also allows to make the TRNG platform independent.
for i in 0 to NUM_INV-1 loop -- inverters in chain
for i in 0 to NUM_INV_S-1 loop -- inverters in short chain
if (enable_i = '0') then -- start with a defined state (latch reset)
inv_chain(i) <= '0';
elsif (enable_sreg(i) = '1') then
-- here we have the inverter chain --
if (i = NUM_INV-1) then -- left-most inverter?
inv_chain(i) <= not inv_chain(0);
inv_chain_s(i) <= '0';
elsif (enable_sreg_s(i) = '1') then
if (i = NUM_INV_S-1) then -- left-most inverter?
inv_chain_s(i) <= not feedback;
else
inv_chain(i) <= not inv_chain(i+1);
inv_chain_s(i) <= not inv_chain_s(i+1);
end if;
end if;
end loop; -- i
end process ring_osc;
end process ring_osc_short;
 
-- long oscillator chain --
ring_osc_long: process(enable_i, enable_sreg_l, feedback, inv_chain_l)
begin
for i in 0 to NUM_INV_L-1 loop -- inverters in long chain
if (enable_i = '0') then -- start with a defined state (latch reset)
inv_chain_l(i) <= '0';
elsif (enable_sreg_l(i) = '1') then
if (i = NUM_INV_L-1) then -- left-most inverter?
inv_chain_l(i) <= not feedback;
else
inv_chain_l(i) <= not inv_chain_l(i+1);
end if;
end if;
end loop; -- i
end process ring_osc_long;
 
-- length select --
feedback <= inv_chain_l(0) when (select_i = '0') else inv_chain_s(0);
 
 
-- Control --------------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- Using individual enable signals for each inverter from a shift register to prevent the synthesis tool
-- from removing all but one inverter (since they implement "logical identical functions" (='toggle')).
-- This makes the TRNG platform independent (since we do not need to use primitives to ensure a correct architecture).
ctrl_unit: process(clk_i)
begin
if rising_edge(clk_i) then
enable_sreg <= enable_sreg(enable_sreg'left-1 downto 0) & enable_i; -- activate right-most inverter first
sync_ff <= sync_ff(0) & inv_chain(0); -- synchronize to prevent metastability
-- enable sreg --
enable_sreg_s <= enable_sreg_s(enable_sreg_s'left-1 downto 0) & enable_i;
enable_sreg_l <= enable_sreg_l(enable_sreg_l'left-1 downto 0) & enable_sreg_s(enable_sreg_s'left);
-- data output sync - no metastability beyond this point --
sync_ff <= sync_ff(0) & feedback;
end if;
end process ctrl_unit;
 
-- output for "enable chain" --
enable_o <= enable_sreg(enable_sreg'left);
enable_o <= enable_sreg_l(enable_sreg_l'left);
 
-- rnd output --
-- random data output --
data_o <= sync_ff(1);
 
 
end neorv32_trng_ring_osc_rtl;
end neoTRNG_cell_rtl;
/rtl/core/neorv32_twi.vhd
3,7 → 3,7
-- # ********************************************************************************************* #
-- # Supports START and STOP conditions, 8 bit data + ACK/NACK transfers and clock stretching. #
-- # Supports ACKs by the controller. No multi-controller support and no peripheral mode support #
-- # yet. Interrupt: TWI_idle #
-- # yet. Interrupt: "operation done" #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License #
-- # #
70,45 → 70,55
constant hi_abb_c : natural := index_size_f(io_size_c)-1; -- high address boundary bit
constant lo_abb_c : natural := index_size_f(twi_size_c); -- low address boundary bit
 
-- control reg bits --
constant ctrl_twi_en_c : natural := 0; -- r/w: TWI enable
constant ctrl_twi_start_c : natural := 1; -- -/w: Generate START condition
constant ctrl_twi_stop_c : natural := 2; -- -/w: Generate STOP condition
constant ctrl_twi_prsc0_c : natural := 3; -- r/w: CLK prsc bit 0
constant ctrl_twi_prsc1_c : natural := 4; -- r/w: CLK prsc bit 1
constant ctrl_twi_prsc2_c : natural := 5; -- r/w: CLK prsc bit 2
constant ctrl_twi_mack_c : natural := 6; -- r/w: generate ACK by controller for transmission
constant ctrl_twi_cksten_c : natural := 7; -- r/w: enable clock stretching by peripheral
-- control register --
constant ctrl_en_c : natural := 0; -- r/w: TWI enable
constant ctrl_start_c : natural := 1; -- -/w: Generate START condition
constant ctrl_stop_c : natural := 2; -- -/w: Generate STOP condition
constant ctrl_prsc0_c : natural := 3; -- r/w: CLK prsc bit 0
constant ctrl_prsc1_c : natural := 4; -- r/w: CLK prsc bit 1
constant ctrl_prsc2_c : natural := 5; -- r/w: CLK prsc bit 2
constant ctrl_mack_c : natural := 6; -- r/w: generate ACK by controller for transmission
--
constant ctrl_twi_ack_c : natural := 30; -- r/-: Set if ACK received
constant ctrl_twi_busy_c : natural := 31; -- r/-: Set if TWI unit is busy
constant ctrl_ack_c : natural := 30; -- r/-: Set if ACK received
constant ctrl_busy_c : natural := 31; -- r/-: Set if TWI unit is busy
--
signal ctrl : std_ulogic_vector(6 downto 0); -- unit's control register
 
-- access control --
signal acc_en : std_ulogic; -- module access enable
signal addr : std_ulogic_vector(31 downto 0); -- access address
signal wr_en : std_ulogic; -- word write enable
signal rd_en : std_ulogic; -- read enable
signal wren : std_ulogic; -- word write enable
signal rden : std_ulogic; -- read enable
 
-- twi clocking --
signal twi_clk : std_ulogic;
signal twi_phase_gen : std_ulogic_vector(3 downto 0);
signal twi_clk_phase : std_ulogic_vector(3 downto 0);
signal twi_clk : std_ulogic;
signal twi_phase_gen : std_ulogic_vector(3 downto 0);
signal twi_clk_phase : std_ulogic_vector(3 downto 0);
 
-- twi clock stretching --
signal twi_clk_halt : std_ulogic;
 
-- twi transceiver core --
signal ctrl : std_ulogic_vector(7 downto 0); -- unit's control register
signal arbiter : std_ulogic_vector(2 downto 0);
signal bitcnt : std_ulogic_vector(3 downto 0);
signal rtx_sreg : std_ulogic_vector(8 downto 0); -- main rx/tx shift reg
 
-- tri-state I/O --
signal twi_sda_i_ff0, twi_sda_i_ff1 : std_ulogic; -- sda input sync
signal twi_scl_i_ff0, twi_scl_i_ff1 : std_ulogic; -- sda input sync
signal twi_sda_i, twi_sda_o : std_ulogic;
signal twi_scl_i, twi_scl_o : std_ulogic;
signal twi_sda_in_ff : std_ulogic_vector(1 downto 0); -- SDA input sync
signal twi_scl_in_ff : std_ulogic_vector(1 downto 0); -- SCL input sync
signal twi_sda_in : std_ulogic;
signal twi_scl_in : std_ulogic;
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 -------------------------------------------------------------------------
115,8 → 125,8
-- -------------------------------------------------------------------------------------------
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = twi_base_c(hi_abb_c downto lo_abb_c)) else '0';
addr <= twi_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned
wr_en <= acc_en and wren_i;
rd_en <= acc_en and rden_i;
wren <= acc_en and wren_i;
rden <= acc_en and rden_i;
 
 
-- Read/Write Access ----------------------------------------------------------------------
124,9 → 134,9
rw_access: process(clk_i)
begin
if rising_edge(clk_i) then
ack_o <= acc_en and (rden_i or wren_i);
ack_o <= rden or wren;
-- write access --
if (wr_en = '1') then
if (wren = '1') then
if (addr = twi_ctrl_addr_c) then
ctrl <= data_i(ctrl'left downto 0);
end if;
133,20 → 143,18
end if;
-- read access --
data_o <= (others => '0');
if (rd_en = '1') then
if (rden = '1') then
if (addr = twi_ctrl_addr_c) then
data_o(ctrl_twi_en_c) <= ctrl(ctrl_twi_en_c);
data_o(ctrl_twi_prsc0_c) <= ctrl(ctrl_twi_prsc0_c);
data_o(ctrl_twi_prsc1_c) <= ctrl(ctrl_twi_prsc1_c);
data_o(ctrl_twi_prsc2_c) <= ctrl(ctrl_twi_prsc2_c);
data_o(ctrl_twi_mack_c) <= ctrl(ctrl_twi_mack_c);
data_o(ctrl_twi_cksten_c) <= ctrl(ctrl_twi_cksten_c);
data_o(ctrl_en_c) <= ctrl(ctrl_en_c);
data_o(ctrl_prsc0_c) <= ctrl(ctrl_prsc0_c);
data_o(ctrl_prsc1_c) <= ctrl(ctrl_prsc1_c);
data_o(ctrl_prsc2_c) <= ctrl(ctrl_prsc2_c);
data_o(ctrl_mack_c) <= ctrl(ctrl_mack_c);
--
data_o(ctrl_twi_ack_c) <= not rtx_sreg(0);
data_o(ctrl_twi_busy_c) <= arbiter(1) or arbiter(0);
data_o(ctrl_ack_c) <= not rtx_sreg(0);
data_o(ctrl_busy_c) <= arbiter(1) or arbiter(0);
else -- twi_rtx_addr_c =>
data_o(7 downto 0) <= rtx_sreg(8 downto 1);
data_o(7 downto 0) <= rtx_sreg(8 downto 1);
end if;
end if;
end if;
156,16 → 164,16
-- Clock Generation -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- clock generator enable --
clkgen_en_o <= ctrl(ctrl_twi_en_c);
clkgen_en_o <= ctrl(ctrl_en_c);
 
-- twi clock select --
twi_clk <= clkgen_i(to_integer(unsigned(ctrl(ctrl_twi_prsc2_c downto ctrl_twi_prsc0_c))));
twi_clk <= clkgen_i(to_integer(unsigned(ctrl(ctrl_prsc2_c downto ctrl_prsc0_c))));
 
-- generate four non-overlapping clock ticks at twi_clk/4 --
clock_phase_gen: process(clk_i)
begin
if rising_edge(clk_i) then
if (arbiter(2) = '0') or (arbiter = "100") then -- offline or idle
if (arbiter(2) = '0') or (arbiter(1 downto 0) = "00") then -- offline or idle
twi_phase_gen <= "0001"; -- make sure to start with a new phase, bit 0,1,2,3 stepping
elsif (twi_clk = '1') and (twi_clk_halt = '0') then -- enabled and no clock stretching detected
twi_phase_gen <= twi_phase_gen(2 downto 0) & twi_phase_gen(3); -- rotate left
186,35 → 194,29
begin
if rising_edge(clk_i) then
-- input synchronizer & sampler --
twi_sda_i_ff0 <= twi_sda_i;
twi_sda_i_ff1 <= twi_sda_i_ff0;
twi_scl_i_ff0 <= twi_scl_i;
twi_scl_i_ff1 <= twi_scl_i_ff0;
twi_sda_in_ff <= twi_sda_in_ff(0) & twi_sda_in;
twi_scl_in_ff <= twi_scl_in_ff(0) & twi_scl_in;
 
-- interrupt --
if (arbiter = "100") then -- fire IRQ if enabled transceiver is idle
irq_o <= '1';
else
irq_o <= '0';
end if;
-- defaults --
irq.set <= '0';
 
-- serial engine --
arbiter(2) <= ctrl(ctrl_twi_en_c); -- still activated?
arbiter(2) <= ctrl(ctrl_en_c); -- still activated?
case arbiter is
 
when "100" => -- IDLE: waiting for requests, bus might be still claimed by this controller if no STOP condition was generated
bitcnt <= (others => '0');
if (wr_en = '1') then
if (wren = '1') then
if (addr = twi_ctrl_addr_c) then
if (data_i(ctrl_twi_start_c) = '1') then -- issue START condition
if (data_i(ctrl_start_c) = '1') then -- issue START condition
arbiter(1 downto 0) <= "01";
elsif (data_i(ctrl_twi_stop_c) = '1') then -- issue STOP condition
elsif (data_i(ctrl_stop_c) = '1') then -- issue STOP condition
arbiter(1 downto 0) <= "10";
end if;
elsif (addr = twi_rtx_addr_c) then -- start a data transmission
-- one bit extra for ack, issued by controller if ctrl_twi_mack_c is set,
-- sampled from peripheral if ctrl_twi_mack_c is cleared
rtx_sreg <= data_i(7 downto 0) & (not ctrl(ctrl_twi_mack_c));
-- one bit extra for ack, issued by controller if ctrl_mack_c is set,
-- sampled from peripheral if ctrl_mack_c is cleared
rtx_sreg <= data_i(7 downto 0) & (not ctrl(ctrl_mack_c));
arbiter(1 downto 0) <= "11";
end if;
end if;
221,51 → 223,54
 
when "101" => -- START: generate START condition
if (twi_clk_phase(0) = '1') then
twi_sda_o <= '1';
twi_sda_out <= '1';
elsif (twi_clk_phase(1) = '1') then
twi_sda_o <= '0';
twi_sda_out <= '0';
end if;
--
if (twi_clk_phase(0) = '1') then
twi_scl_o <= '1';
twi_scl_out <= '1';
elsif (twi_clk_phase(3) = '1') then
twi_scl_o <= '0';
twi_scl_out <= '0';
irq.set <= '1'; -- Interrupt!
arbiter(1 downto 0) <= "00"; -- go back to IDLE
end if;
 
when "110" => -- STOP: generate STOP condition
if (twi_clk_phase(0) = '1') then
twi_sda_o <= '0';
twi_sda_out <= '0';
elsif (twi_clk_phase(3) = '1') then
twi_sda_o <= '1';
twi_sda_out <= '1';
irq.set <= '1'; -- Interrupt!
arbiter(1 downto 0) <= "00"; -- go back to IDLE
end if;
--
if (twi_clk_phase(0) = '1') then
twi_scl_o <= '0';
twi_scl_out <= '0';
elsif (twi_clk_phase(1) = '1') then
twi_scl_o <= '1';
twi_scl_out <= '1';
end if;
 
when "111" => -- TRANSMISSION: transmission in progress
if (twi_clk_phase(0) = '1') then
bitcnt <= std_ulogic_vector(unsigned(bitcnt) + 1);
twi_scl_o <= '0';
twi_sda_o <= rtx_sreg(8); -- MSB first
twi_scl_out <= '0';
twi_sda_out <= rtx_sreg(8); -- MSB first
elsif (twi_clk_phase(1) = '1') then -- first half + second half of valid data strobe
twi_scl_o <= '1';
twi_scl_out <= '1';
elsif (twi_clk_phase(3) = '1') then
rtx_sreg <= rtx_sreg(7 downto 0) & twi_sda_i_ff1; -- sample and shift left
twi_scl_o <= '0';
rtx_sreg <= rtx_sreg(7 downto 0) & twi_sda_in_ff(twi_sda_in_ff'left); -- sample and shift left
twi_scl_out <= '0';
end if;
--
if (bitcnt = "1010") then -- 8 data bits + 1 bit for ACK + 1 tick delay
irq.set <= '1'; -- Interrupt!
arbiter(1 downto 0) <= "00"; -- go back to IDLE
end if;
 
when others => -- "0--" OFFLINE: TWI deactivated
twi_sda_o <= '1';
twi_scl_o <= '1';
twi_sda_out <= '1';
twi_scl_out <= '1';
arbiter(1 downto 0) <= "00"; -- stay here, go to idle when activated
 
end case;
275,29 → 280,43
 
-- Clock Stretching Detector --------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
clock_stretching: process(ctrl, arbiter, twi_scl_o, twi_scl_i_ff1)
begin
-- clock stretching by the peripheral can happen at "any time"
if (arbiter(2) = '1') and -- module enabled
(ctrl(ctrl_twi_cksten_c) = '1') and -- clock stretching enabled
(twi_scl_o = '1') and -- controller wants to pull scl high
(twi_scl_i_ff1 = '0') then -- but scl is pulled low by peripheral
twi_clk_halt <= '1';
else
twi_clk_halt <= '0';
end if;
end process clock_stretching;
-- controller wants to pull SCL high, but SCL is pulled low by peripheral --
twi_clk_halt <= '1' when (twi_scl_out = '1') and (twi_scl_in_ff(twi_scl_in_ff'left) = '0') else '0';
 
 
-- Tri-State Driver -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- SDA and SCL need to be of type std_logic to be correctly resolved in simulation
twi_sda_io <= '0' when (twi_sda_o = '0') else 'Z';
twi_scl_io <= '0' when (twi_scl_o = '0') else 'Z';
twi_sda_io <= '0' when (twi_sda_out = '0') else 'Z';
twi_scl_io <= '0' when (twi_scl_out = '0') else 'Z';
 
-- read-back --
twi_sda_i <= std_ulogic(twi_sda_io);
twi_scl_i <= std_ulogic(twi_scl_io);
twi_sda_in <= std_ulogic(twi_sda_io);
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
163,8 → 163,8
-- access control --
signal acc_en : std_ulogic; -- module access enable
signal addr : std_ulogic_vector(31 downto 0); -- access address
signal wr_en : std_ulogic; -- word write enable
signal rd_en : std_ulogic; -- read enable
signal wren : std_ulogic; -- word write enable
signal rden : std_ulogic; -- read enable
 
-- clock generator --
signal uart_clk : std_ulogic;
181,6 → 181,7
type tx_engine_t is record
state : tx_state_t;
busy : std_ulogic;
done : std_ulogic;
bitcnt : std_ulogic_vector(03 downto 0);
sreg : std_ulogic_vector(10 downto 0);
baud_cnt : std_ulogic_vector(11 downto 0);
192,6 → 193,7
type rx_state_t is (S_RX_IDLE, S_RX_RECEIVE);
type rx_engine_t is record
state : rx_state_t;
done : std_ulogic;
sync : std_ulogic_vector(04 downto 0);
bitcnt : std_ulogic_vector(03 downto 0);
sreg : std_ulogic_vector(09 downto 0);
227,6 → 229,14
end record;
signal rx_buffer : rx_buffer_t;
 
-- interrupt generator --
type irq_t is record
pending : std_ulogic; -- pending interrupt request
set : std_ulogic;
clr : std_ulogic;
end record;
signal rx_irq, tx_irq : irq_t;
 
begin
 
-- Sanity Checks --------------------------------------------------------------------------
241,8 → 251,8
-- -------------------------------------------------------------------------------------------
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = uart_id_base_c(hi_abb_c downto lo_abb_c)) else '0';
addr <= uart_id_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned
wr_en <= acc_en and wren_i;
rd_en <= acc_en and rden_i;
wren <= acc_en and wren_i;
rden <= acc_en and rden_i;
 
 
-- Read/Write Access ----------------------------------------------------------------------
251,10 → 261,10
begin
if rising_edge(clk_i) then
-- bus access acknowledge --
ack_o <= wr_en or rd_en;
ack_o <= wren or rden;
 
-- write access --
if (wr_en = '1') then
if (wren = '1') then
if (addr = uart_id_ctrl_addr_c) then
ctrl <= (others => '0');
ctrl(ctrl_baud11_c downto ctrl_baud00_c) <= data_i(ctrl_baud11_c downto ctrl_baud00_c);
271,7 → 281,7
 
-- read access --
data_o <= (others => '0');
if (rd_en = '1') then
if (rden = '1') then
if (addr = uart_id_ctrl_addr_c) then
data_o(ctrl_baud11_c downto ctrl_baud00_c) <= ctrl(ctrl_baud11_c downto ctrl_baud00_c);
data_o(ctrl_sim_en_c) <= ctrl(ctrl_sim_en_c);
346,7 → 356,7
tx_buffer.clear <= not ctrl(ctrl_en_c);
 
-- write access --
tx_buffer.we <= '1' when (wr_en = '1') and (addr = uart_id_rtx_addr_c) else '0';
tx_buffer.we <= '1' when (wren = '1') and (addr = uart_id_rtx_addr_c) else '0';
tx_buffer.wdata <= data_i;
 
 
356,8 → 366,9
begin
if rising_edge(clk_i) then
-- defaults --
uart_txd_o <= '1'; -- keep TX line idle (=high) if waiting for permission to start sending (->CTS)
tx_buffer.re <= '0';
uart_txd_o <= '1'; -- keep TX line idle (=high) if waiting for permission to start sending (->CTS)
tx_buffer.re <= '0';
tx_engine.done <= '0';
 
-- FSM --
if (ctrl(ctrl_en_c) = '0') then -- disabled
408,6 → 419,7
end if;
uart_txd_o <= tx_engine.sreg(0);
if (or_reduce_f(tx_engine.bitcnt) = '0') then -- all bits send?
tx_engine.done <= '1'; -- sending done
tx_engine.state <= S_TX_IDLE;
end if;
 
436,6 → 448,9
-- input synchronizer --
rx_engine.sync <= uart_rxd_i & rx_engine.sync(rx_engine.sync'left downto 1);
 
-- default --
rx_engine.done <= '0';
 
-- FSM --
if (ctrl(ctrl_en_c) = '0') then -- disabled
rx_engine.overr <= '0';
463,6 → 478,7
end if;
end if;
if (or_reduce_f(rx_engine.bitcnt) = '0') then -- all bits received?
rx_engine.done <= '1'; -- receiving done
rx_engine.state <= S_RX_IDLE;
end if;
 
473,7 → 489,7
end case;
 
-- overrun flag --
if (rd_en = '1') and (addr = uart_id_rtx_addr_c) then -- clear when reading data register
if (rden = '1') and (addr = uart_id_rtx_addr_c) then -- clear when reading data register
rx_engine.overr <= '1';
elsif (rx_buffer.we = '1') and (rx_buffer.free = '0') then -- write to full FIFO
rx_engine.overr <= '0';
520,7 → 536,7
rx_buffer.wdata(8) <= ctrl(ctrl_pmode1_c) and (xor_reduce_f(rx_engine.sreg(8 downto 0)) xor ctrl(ctrl_pmode0_c)); -- parity error flag
rx_buffer.wdata(9) <= not rx_engine.sreg(9); -- frame error flag: check stop bit (error if not set)
rx_buffer.we <= '1' when (rx_engine.bitcnt = "0000") and (rx_engine.state = S_RX_RECEIVE) else '0'; -- RX complete
rx_buffer.re <= '1' when (rd_en = '1') and (addr = uart_id_rtx_addr_c) else '0';
rx_buffer.re <= '1' when (rden = '1') and (addr = uart_id_rtx_addr_c) else '0';
 
 
-- Hardware Flow Control ------------------------------------------------------------------
538,41 → 554,66
end process flow_control_buffer;
 
 
-- Interrupts -----------------------------------------------------------------------------
-- Interrupt Generator --------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
irq_type: process(ctrl, tx_buffer, rx_buffer)
begin
-- TX interrupt --
if (UART_TX_FIFO = 1) then
tx_irq.set <= tx_buffer.free; -- 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;
end if;
 
-- RX interrupt --
if (UART_RX_FIFO = 1) 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;
end if;
end process irq_type;
 
-- interrupt arbiter --
irq_generator: process(clk_i)
begin
if rising_edge(clk_i) then
if (ctrl(ctrl_en_c) = '0') then -- no interrupts when disabled
irq_txd_o <= '0';
irq_rxd_o <= '0';
if (ctrl(ctrl_en_c) = '0') then
rx_irq.pending <= '0';
tx_irq.pending <= '0';
else
-- TX interrupt --
if (UART_TX_FIFO = 1) then
irq_txd_o <= tx_buffer.free; -- fire IRQ if FIFO is not full
else
if (ctrl(ctrl_tx_irq_c) = '1') then
irq_txd_o <= not tx_buffer.half; -- fire IRQ if FIFO is less than half-full
else
irq_txd_o <= tx_buffer.free; -- fire IRQ if FIFO is not full
end if;
-- 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 interrupt --
if (UART_RX_FIFO = 1) then
irq_rxd_o <= rx_buffer.avail; -- fire IRQ if FIFO is not empty
else
if (ctrl(ctrl_rx_irq_c) = '1') then
irq_rxd_o <= rx_buffer.half; -- fire IRQ if FIFO is at least half-full
else
irq_rxd_o <= rx_buffer.avail; -- fire IRQ is FIFO is not empty
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;
end if;
end if;
end process irq_generator;
 
-- IRQ requests to CPU --
irq_txd_o <= tx_irq.pending;
irq_rxd_o <= rx_irq.pending;
 
-- 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
140,10 → 140,8
ctrl_reg.mode <= '0'; -- trigger interrupt on WDT overflow
ctrl_reg.clk_sel <= (others => '1'); -- slowest clock source
ctrl_reg.lock <= '0';
cpu_irq.clr <= '-';
elsif rising_edge(clk_i) then
-- acknowledge interrupt when resetting WDT --
cpu_irq.clr <= ctrl_reg.reset;
if (rstn_sync = '0') then -- internal reset
ctrl_reg.reset <= '0';
ctrl_reg.enforce <= '0';
190,6 → 188,7
 
-- 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
 
 
/rtl/core/neorv32_wishbone.vhd
76,7 → 76,9
lock_i : in std_ulogic; -- exclusive access request
ack_o : out std_ulogic; -- transfer acknowledge
err_o : out std_ulogic; -- transfer error
tmo_o : out std_ulogic; -- transfer timeout
priv_i : in std_ulogic_vector(01 downto 0); -- current CPU privilege level
ext_o : out std_ulogic; -- active external access
-- wishbone interface --
wb_tag_o : out std_ulogic_vector(02 downto 0); -- request tag
wb_adr_o : out std_ulogic_vector(31 downto 0); -- address
106,18 → 108,20
-- bus arbiter
type ctrl_state_t is (IDLE, BUSY);
type ctrl_t is record
state : ctrl_state_t;
we : std_ulogic;
adr : std_ulogic_vector(31 downto 0);
wdat : std_ulogic_vector(31 downto 0);
rdat : std_ulogic_vector(31 downto 0);
sel : std_ulogic_vector(03 downto 0);
ack : std_ulogic;
err : std_ulogic;
timeout : std_ulogic_vector(index_size_f(BUS_TIMEOUT)-1 downto 0);
src : std_ulogic;
lock : std_ulogic;
priv : std_ulogic_vector(01 downto 0);
state : ctrl_state_t;
state_ff : ctrl_state_t;
we : std_ulogic;
adr : std_ulogic_vector(31 downto 0);
wdat : std_ulogic_vector(31 downto 0);
rdat : std_ulogic_vector(31 downto 0);
sel : std_ulogic_vector(03 downto 0);
ack : std_ulogic;
err : std_ulogic;
tmo : std_ulogic;
timeout : std_ulogic_vector(index_size_f(BUS_TIMEOUT)-1 downto 0);
src : std_ulogic;
lock : std_ulogic;
priv : std_ulogic_vector(01 downto 0);
end record;
signal ctrl : ctrl_t;
signal stb_int : std_ulogic;
165,24 → 169,28
bus_arbiter: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
ctrl.state <= IDLE;
ctrl.we <= def_rst_val_c;
ctrl.adr <= (others => def_rst_val_c);
ctrl.wdat <= (others => def_rst_val_c);
ctrl.rdat <= (others => def_rst_val_c);
ctrl.sel <= (others => def_rst_val_c);
ctrl.timeout <= (others => def_rst_val_c);
ctrl.ack <= def_rst_val_c;
ctrl.err <= def_rst_val_c;
ctrl.src <= def_rst_val_c;
ctrl.lock <= def_rst_val_c;
ctrl.priv <= (others => def_rst_val_c);
ctrl.state <= IDLE;
ctrl.state_ff <= IDLE;
ctrl.we <= def_rst_val_c;
ctrl.adr <= (others => def_rst_val_c);
ctrl.wdat <= (others => def_rst_val_c);
ctrl.rdat <= (others => def_rst_val_c);
ctrl.sel <= (others => def_rst_val_c);
ctrl.timeout <= (others => def_rst_val_c);
ctrl.ack <= def_rst_val_c;
ctrl.err <= def_rst_val_c;
ctrl.tmo <= def_rst_val_c;
ctrl.src <= def_rst_val_c;
ctrl.lock <= def_rst_val_c;
ctrl.priv <= (others => def_rst_val_c);
elsif rising_edge(clk_i) then
-- defaults --
ctrl.rdat <= (others => '0'); -- required for internal output gating
ctrl.ack <= '0';
ctrl.err <= '0';
ctrl.timeout <= std_ulogic_vector(to_unsigned(BUS_TIMEOUT, index_size_f(BUS_TIMEOUT)));
ctrl.state_ff <= ctrl.state;
ctrl.rdat <= (others => '0'); -- required for internal output gating
ctrl.ack <= '0';
ctrl.err <= '0';
ctrl.tmo <= '0';
ctrl.timeout <= std_ulogic_vector(to_unsigned(BUS_TIMEOUT, index_size_f(BUS_TIMEOUT)));
 
-- state machine --
case ctrl.state is
210,10 → 218,12
when BUSY => -- transfer in progress
-- ------------------------------------------------------------
ctrl.rdat <= wb_dat_i;
if (wb_err_i = '1') or -- abnormal bus termination
((timeout_en_c = true) and (or_reduce_f(ctrl.timeout) = '0')) then -- valid timeout
if (wb_err_i = '1') then -- abnormal bus termination
ctrl.err <= '1';
ctrl.state <= IDLE;
elsif (timeout_en_c = true) and (or_reduce_f(ctrl.timeout) = '0') then -- enabled timeout
ctrl.tmo <= '1';
ctrl.state <= IDLE;
elsif (wb_ack_i = '1') then -- normal bus termination
ctrl.ack <= '1';
ctrl.state <= IDLE;
236,9 → 246,12
rdata_gated <= wb_dat_i when (ctrl.state = BUSY) else (others => '0'); -- CPU read data gate for "async" RX
rdata <= ctrl.rdat when (ASYNC_RX = false) else rdata_gated;
 
ext_o <= '1' when (ctrl.state = BUSY) else '0'; -- active external access
 
data_o <= rdata when (BIG_ENDIAN = false) else bswap32_f(rdata); -- endianness conversion
ack_o <= ctrl.ack when (ASYNC_RX = false) else ack_gated;
err_o <= ctrl.err;
tmo_o <= ctrl.tmo;
 
-- wishbone interface --
wb_tag_o(0) <= '0' when (ctrl.priv = priv_mode_u_c) else '1'; -- unprivileged access when in user mode
254,7 → 267,7
wb_stb_o <= stb_int when (PIPE_MODE = true) else cyc_int;
wb_cyc_o <= cyc_int;
 
stb_int <= '1' when (ctrl.state = BUSY) else '0';
stb_int <= '1' when (ctrl.state = BUSY) and (ctrl.state_ff /= BUSY) else '0';
cyc_int <= '1' when (ctrl.state = BUSY) else '0';
 
 
/setups/osflow/board_tops/neorv32_iCEBreaker_BoardTop_MinimalBoot.vhd
0,0 → 1,163
-- #################################################################################################
-- # << NEORV32 - Example setup for the tinyVision.ai Inc. "UPduino v3" (c) Board >> #
-- # ********************************************************************************************* #
-- # 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 #
-- #################################################################################################
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
library iCE40;
use iCE40.components.all; -- for device primitives and macros
 
entity neorv32_iCEBreaker_BoardTop_MinimalBoot is
port (
-- UART (uart0) --
uart_txd_o : out std_ulogic;
uart_rxd_i : in std_ulogic;
-- GPIO --
gpio_o : out std_ulogic_vector(3 downto 0);
-- PWM (to on-board RGB power LED) --
pwm_o : out std_logic_vector(2 downto 0)
);
end entity;
 
architecture neorv32_iCEBreaker_BoardTop_MinimalBoot_rtl of neorv32_iCEBreaker_BoardTop_MinimalBoot is
 
-- configuration --
constant f_clock_c : natural := 18000000; -- PLL output clock frequency in Hz
 
-- On-chip oscillator --
signal hf_osc_clk : std_logic;
 
-- Globals
signal pll_rstn : std_logic;
signal pll_clk : std_logic;
 
-- internal IO connection --
signal con_pwm : std_logic_vector(2 downto 0);
 
begin
 
-- On-Chip HF Oscillator ------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
HSOSC_inst : SB_HFOSC
generic map (
CLKHF_DIV => "0b10" -- 12 MHz
)
port map (
CLKHFPU => '1',
CLKHFEN => '1',
CLKHF => hf_osc_clk
);
 
-- System PLL -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- Settings generated by icepll -i 12 -o 18:
-- F_PLLIN: 12.000 MHz (given)
-- F_PLLOUT: 18.000 MHz (requested)
-- F_PLLOUT: 18.000 MHz (achieved)
-- FEEDBACK: SIMPLE
-- F_PFD: 12.000 MHz
-- F_VCO: 576.000 MHz
-- DIVR: 0 (4'b0000)
-- DIVF: 47 (7'b0101111)
-- DIVQ: 5 (3'b101)
-- FILTER_RANGE: 1 (3'b001)
Pll_inst : SB_PLL40_CORE
generic map (
FEEDBACK_PATH => "SIMPLE",
DIVR => x"0",
DIVF => 7x"2F",
DIVQ => 3x"5",
FILTER_RANGE => 3x"1"
)
port map (
REFERENCECLK => hf_osc_clk,
PLLOUTCORE => open,
PLLOUTGLOBAL => pll_clk,
EXTFEEDBACK => '0',
DYNAMICDELAY => x"00",
LOCK => pll_rstn,
BYPASS => '0',
RESETB => '1',
LATCHINPUTVALUE => '0',
SDO => open,
SDI => '0',
SCLK => '0'
);
 
-- The core of the problem ----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
neorv32_inst: entity work.neorv32_ProcessorTop_MinimalBoot
generic map (
CLOCK_FREQUENCY => f_clock_c -- clock frequency of clk_i in Hz
)
port map (
-- Global control --
clk_i => std_ulogic(pll_clk),
rstn_i => std_ulogic(pll_rstn),
 
-- GPIO --
gpio_o => gpio_o,
 
-- primary UART --
uart_txd_o => uart_txd_o, -- UART0 send data
uart_rxd_i => uart_rxd_i, -- UART0 receive data
uart_rts_o => open, -- hw flow control: UART0.RX ready to receive ("RTR"), low-active, optional
uart_cts_i => '0', -- hw flow control: UART0.TX allowed to transmit, low-active, optional
 
-- PWM (to on-board RGB LED) --
pwm_o => con_pwm
);
 
-- IO Connection --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
RGB_inst: SB_RGBA_DRV
generic map (
CURRENT_MODE => "0b1",
RGB0_CURRENT => "0b000011",
RGB1_CURRENT => "0b000011",
RGB2_CURRENT => "0b000011"
)
port map (
CURREN => '1', -- I
RGBLEDEN => '1', -- I
RGB0PWM => con_pwm(1), -- I - green - pwm channel 1
RGB1PWM => con_pwm(2), -- I - blue - pwm channel 2
RGB2PWM => con_pwm(0), -- I - red - pwm channel 0
RGB2 => pwm_o(2), -- O - red
RGB1 => pwm_o(1), -- O - blue
RGB0 => pwm_o(0) -- O - green
);
 
end architecture;
/setups/osflow/board_tops/neorv32_iCEBreaker_BoardTop_UP5KDemo.vhd
0,0 → 1,205
-- #################################################################################################
-- # << NEORV32 - Example setup for the tinyVision.ai Inc. "UPduino v3" (c) Board >> #
-- # ********************************************************************************************* #
-- # 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 #
-- #################################################################################################
 
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
 
library iCE40;
use iCE40.components.all; -- for device primitives and macros
 
entity neorv32_iCEBreaker_BoardTop_UP5KDemo is
port (
user_reset_btn : in std_ulogic;
-- UART (uart0) --
uart_txd_o : out std_ulogic;
uart_rxd_i : in std_ulogic;
-- SPI to on-board flash --
flash_sck_o : out std_ulogic;
flash_sdo_o : out std_ulogic;
flash_sdi_i : in std_ulogic;
flash_csn_o : out std_ulogic; -- NEORV32.SPI_CS(0)
-- SPI to IO pins --
spi_sck_o : out std_ulogic;
spi_sdo_o : out std_ulogic;
spi_sdi_i : in std_ulogic;
spi_csn_o : out std_ulogic; -- NEORV32.SPI_CS(1)
-- TWI --
twi_sda_io : inout std_logic;
twi_scl_io : inout std_logic;
-- GPIO --
gpio_i : in std_ulogic_vector(3 downto 0);
gpio_o : out std_ulogic_vector(3 downto 0);
-- PWM (to on-board RGB power LED) --
pwm_o : out std_ulogic_vector(2 downto 0)
);
end entity;
 
architecture neorv32_iCEBreaker_BoardTop_UP5KDemo_rtl of neorv32_iCEBreaker_BoardTop_UP5KDemo is
 
-- configuration --
constant f_clock_c : natural := 18000000; -- PLL output clock frequency in Hz
 
-- On-chip oscillator --
signal hf_osc_clk : std_logic;
 
-- Globals
signal pll_rstn : std_logic;
signal pll_clk : std_logic;
 
-- internal IO connection --
signal con_pwm : std_ulogic_vector(2 downto 0);
signal con_spi_sdi : std_ulogic;
signal con_spi_csn : std_ulogic;
 
begin
 
-- On-Chip HF Oscillator ------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
HSOSC_inst : SB_HFOSC
generic map (
CLKHF_DIV => "0b10" -- 12 MHz
)
port map (
CLKHFPU => '1',
CLKHFEN => '1',
CLKHF => hf_osc_clk
);
 
 
-- System PLL -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- Settings generated by icepll -i 12 -o 18:
-- F_PLLIN: 12.000 MHz (given)
-- F_PLLOUT: 18.000 MHz (requested)
-- F_PLLOUT: 18.000 MHz (achieved)
-- FEEDBACK: SIMPLE
-- F_PFD: 12.000 MHz
-- F_VCO: 576.000 MHz
-- DIVR: 0 (4'b0000)
-- DIVF: 47 (7'b0101111)
-- DIVQ: 5 (3'b101)
-- FILTER_RANGE: 1 (3'b001)
Pll_inst : SB_PLL40_CORE
generic map (
FEEDBACK_PATH => "SIMPLE",
DIVR => x"0",
DIVF => 7x"2F",
DIVQ => 3x"5",
FILTER_RANGE => 3x"1"
)
port map (
REFERENCECLK => hf_osc_clk,
PLLOUTCORE => open,
PLLOUTGLOBAL => pll_clk,
EXTFEEDBACK => '0',
DYNAMICDELAY => x"00",
LOCK => pll_rstn,
BYPASS => '0',
RESETB => user_reset_btn,
LATCHINPUTVALUE => '0',
SDO => open,
SDI => '0',
SCLK => '0'
);
 
-- The core of the problem ----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
 
neorv32_inst: entity work.neorv32_ProcessorTop_UP5KDemo
generic map (
CLOCK_FREQUENCY => f_clock_c -- clock frequency of clk_i in Hz
)
port map (
-- Global control --
clk_i => std_ulogic(pll_clk),
rstn_i => std_ulogic(pll_rstn),
 
-- primary UART --
uart_txd_o => uart_txd_o,
uart_rxd_i => uart_rxd_i,
uart_rts_o => open,
uart_cts_i => '0',
 
-- SPI to on-board flash --
flash_sck_o => flash_sck_o,
flash_sdo_o => flash_sdo_o,
flash_sdi_i => flash_sdi_i,
flash_csn_o => flash_csn_o,
 
-- SPI to IO pins --
spi_sck_o => spi_sck_o,
spi_sdo_o => spi_sdo_o,
spi_sdi_i => con_spi_sdi,
spi_csn_o => con_spi_csn,
 
-- TWI --
twi_sda_io => twi_sda_io,
twi_scl_io => twi_scl_io,
 
-- GPIO --
gpio_i => gpio_i,
gpio_o => gpio_o,
 
-- PWM (to on-board RGB power LED) --
pwm_o => con_pwm
);
 
-- IO Connection --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
 
-- SPI sdi read-back --
spi_csn_o <= con_spi_csn;
con_spi_sdi <= flash_sdi_i when (con_spi_csn = '0') else spi_sdi_i;
 
-- RGB --
RGB_inst: SB_RGBA_DRV
generic map (
CURRENT_MODE => "0b1",
RGB0_CURRENT => "0b000001",
RGB1_CURRENT => "0b000001",
RGB2_CURRENT => "0b000001"
)
port map (
CURREN => '1', -- I
RGBLEDEN => '1', -- I
RGB0PWM => con_pwm(1), -- I - green - pwm channel 1
RGB1PWM => con_pwm(2), -- I - bluee - pwm channel 2
RGB2PWM => con_pwm(0), -- I - red - pwm channel 0
RGB2 => pwm_o(2), -- O - red
RGB1 => pwm_o(1), -- O - blue
RGB0 => pwm_o(0) -- O - green
);
 
end architecture;
/setups/osflow/boards/iCEBreaker.mk
0,0 → 1,4
.PHONY: all
 
all: bit
echo "! Built $(IMPL) for $(BOARD)"
/setups/osflow/boards/index.mk
61,7 → 61,17
 
endif
 
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
 
 
 
ifeq ($(BOARD),OrangeCrab)
$(info Setting constraints and implementation args for BOARD OrangeCrab)
 
/setups/osflow/constraints/iCEBreaker.pcf
0,0 → 1,39
## UART (uart0)
set_io uart_txd_o 9
set_io uart_rxd_i 6
 
## SPI - on-board flash
set_io flash_sdo_o 14
set_io flash_sck_o 15
set_io flash_csn_o 16
set_io flash_sdi_i 17
 
## SPI - user port
set_io spi_sdo_o 43
set_io spi_sck_o 38
set_io spi_csn_o 34
set_io spi_sdi_i 31
 
## TWI
set_io twi_sda_io 2
set_io twi_scl_io 4
 
## GPIO - input
set_io gpio_i[0] 18
set_io gpio_i[1] 19
set_io gpio_i[2] 20
set_io gpio_i[3] 28
 
## GPIO - output
set_io gpio_o[0] 25
set_io gpio_o[1] 26
set_io gpio_o[2] 27
set_io gpio_o[3] 23
 
## RGB power LED
set_io pwm_o[0] 39
set_io pwm_o[1] 40
set_io pwm_o[2] 41
 
#User Reset Btn
set_io user_reset_btn 10
/setups/osflow/Makefile
10,7 → 10,7
UPduino_REV ?= v3
 
#ifndef BOARD
#$(error BOARD needs to be set to 'Fomu', 'iCESugar', 'UPDuino' or 'OrangeCrab' !)
#$(error BOARD needs to be set to 'Fomu', 'iCESugar', 'UPDuino', 'iCEBreaker' or 'OrangeCrab' !)
#endif
 
run:
29,71 → 29,100
# Boards
 
Fomu:
$(eval BITSTREAM ?= neorv32_$(BOARD)_$(FOMU_REV)_$(DESIGN).bit)
ifeq ($(DESIGN),Minimal)
$(eval IMEM_SRC := ../../rtl/core/mem/neorv32_imem.default.vhd)
else
$(eval IMEM_SRC := devices/ice40/neorv32_imem.ice40up_spram.vhd)
endif
$(eval NEORV32_MEM_SRC ?= ${IMEM_SRC} devices/ice40/neorv32_dmem.ice40up_spram.vhd)
$(MAKE) \
BITSTREAM=neorv32_$(BOARD)_$(FOMU_REV)_$(DESIGN).bit \
NEORV32_MEM_SRC="${IMEM_SRC} devices/ice40/neorv32_dmem.ice40up_spram.vhd" \
BITSTREAM="$(BITSTREAM)" \
NEORV32_MEM_SRC="$(NEORV32_MEM_SRC)" \
run
 
iCESugar:
$(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=neorv32_$(BOARD)_$(DESIGN).bit \
NEORV32_MEM_SRC="devices/ice40/neorv32_imem.ice40up_spram.vhd devices/ice40/neorv32_dmem.ice40up_spram.vhd" \
BITSTREAM="$(BITSTREAM)" \
NEORV32_MEM_SRC="$(NEORV32_MEM_SRC)" \
run
 
UPduino:
$(eval BITSTREAM ?= neorv32_$(BOARD)_$(UPduino_REV)_$(DESIGN).bit)
$(eval NEORV32_MEM_SRC ?= devices/ice40/neorv32_imem.ice40up_spram.vhd devices/ice40/neorv32_dmem.ice40up_spram.vhd)
$(MAKE) \
BITSTREAM=neorv32_$(BOARD)_$(UPduino_REV)_$(DESIGN).bit \
NEORV32_MEM_SRC="devices/ice40/neorv32_imem.ice40up_spram.vhd devices/ice40/neorv32_dmem.ice40up_spram.vhd" \
BITSTREAM="$(BITSTREAM)" \
NEORV32_MEM_SRC="$(NEORV32_MEM_SRC)" \
run
 
OrangeCrab:
$(eval BITSTREAM ?= neorv32_$(BOARD)_$(OrangeCrab_REV)_$(DESIGN).bit)
$(eval NEORV32_MEM_SRC ?= ../../rtl/core/mem/neorv32_imem.default.vhd ../../rtl/core/mem/neorv32_dmem.default.vhd)
$(MAKE) \
BITSTREAM=neorv32_$(BOARD)_$(OrangeCrab_REV)_$(DESIGN).bit \
NEORV32_MEM_SRC="../../rtl/core/mem/neorv32_imem.default.vhd ../../rtl/core/mem/neorv32_dmem.default.vhd" \
BITSTREAM="$(BITSTREAM)" \
NEORV32_MEM_SRC="$(NEORV32_MEM_SRC)" \
run
 
AlhambraII:
$(eval BITSTREAM ?= neorv32_$(BOARD)_$(DESIGN).bit)
$(eval NEORV32_MEM_SRC ?= ../../rtl/core/mem/neorv32_imem.default.vhd ../../rtl/core/mem/neorv32_dmem.default.vhd)
$(MAKE) \
BITSTREAM=neorv32_$(BOARD)_$(DESIGN).bit \
NEORV32_MEM_SRC="../../rtl/core/mem/neorv32_imem.default.vhd ../../rtl/core/mem/neorv32_dmem.default.vhd" \
BITSTREAM="$(BITSTREAM)" \
NEORV32_MEM_SRC="$(NEORV32_MEM_SRC)" \
run
 
ULX3S:
$(eval BITSTREAM ?= neorv32_$(BOARD)_$(DESIGN).bit)
$(eval NEORV32_MEM_SRC ?= ../../rtl/core/mem/neorv32_imem.default.vhd ../../rtl/core/mem/neorv32_dmem.default.vhd)
$(MAKE) \
BITSTREAM=neorv32_$(BOARD)_$(DESIGN).bit \
NEORV32_MEM_SRC="../../rtl/core/mem/neorv32_imem.default.vhd ../../rtl/core/mem/neorv32_dmem.default.vhd" \
BITSTREAM="$(BITSTREAM)" \
NEORV32_MEM_SRC="$(NEORV32_MEM_SRC)" \
run
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
 
# Designs
 
Minimal:
$(eval DESIGN ?= $@)
$(eval DESIGN_SRC ?= $(TEMPLATES)/neorv32_ProcessorTop_Minimal*.vhd)
$(MAKE) \
DESIGN=$@ \
DESIGN_SRC=$(TEMPLATES)/neorv32_ProcessorTop_Minimal*.vhd \
DESIGN="$(DESIGN)" \
DESIGN_SRC="$(DESIGN_SRC)" \
$(BOARD)
 
MinimalBoot:
$(eval DESIGN ?= $@)
$(eval DESIGN_SRC ?= $(TEMPLATES)/neorv32_ProcessorTop_MinimalBoot.vhd)
$(MAKE) \
DESIGN=$@ \
DESIGN_SRC=$(TEMPLATES)/neorv32_ProcessorTop_MinimalBoot.vhd \
DESIGN="$(DESIGN)" \
DESIGN_SRC="$(DESIGN_SRC)" \
$(BOARD)
 
UP5KDemo:
$(eval DESIGN ?= $@)
$(eval DESIGN_SRC ?= $(TEMPLATES)/neorv32_ProcessorTop_UP5KDemo.vhd)
$(MAKE) \
DESIGN=$@ \
DESIGN_SRC=$(TEMPLATES)/neorv32_ProcessorTop_UP5KDemo.vhd \
DESIGN="$(DESIGN)" \
DESIGN_SRC="$(DESIGN_SRC)" \
$(BOARD)
 
MixedLanguage:
$(eval DESIGN ?= $@)
$(eval DESIGN_SRC ?= $(TEMPLATES)/neorv32_ProcessorTop_Minimal*.vhd)
$(eval NEORV32_VERILOG_SRC ?= devices/ice40/sb_ice40_components.v board_tops/neorv32_Fomu_MixedLanguage_ClkGen.v)
$(MAKE) \
DESIGN=$@ \
DESIGN_SRC=$(TEMPLATES)/neorv32_ProcessorTop_Minimal*.vhd \
NEORV32_VERILOG_SRC='devices/ice40/sb_ice40_components.v board_tops/neorv32_Fomu_MixedLanguage_ClkGen.v' \
DESIGN="$(DESIGN)" \
DESIGN_SRC="$(DESIGN_SRC)" \
NEORV32_VERILOG_SRC="$(NEORV32_VERILOG_SRC)" \
$(BOARD)
 
# Help
102,3 → 131,4
@echo "Open-Source Synthesis, P&R, Routing and Bitstream Generation"
@echo "Usage: make BOARD=<fpga board> <board top>"
@echo "Example: make BOARD=Fomu Minimal"
 
/setups/osflow/filesets.mk
48,7 → 48,8
# Before including this partial makefile, NEORV32_MEM_SRC needs to be set
# (containing two VHDL sources: one for IMEM and one for DMEM)
 
NEORV32_SRC := ${NEORV32_PKG} ${NEORV32_APP_SRC} ${NEORV32_MEM_ENTITIES} ${NEORV32_MEM_SRC} ${NEORV32_CORE_SRC}
NEORV32_SRC := ${NEORV32_PKG} ${NEORV32_APP_SRC} ${NEORV32_MEM_ENTITIES} ${NEORV32_MEM_SRC} ${NEORV32_MEM_SRC_EXTRA} ${NEORV32_CORE_SRC} ${NEORV32_CORE_SRC_EXTRA}
NEORV32_VERILOG_ALL := ${NEORV32_VERILOG_SRC} ${NEORV32_VERILOG_SRC_EXTRA}
 
ICE40_SRC := \
devices/ice40/sb_ice40_components.vhd
/setups/osflow/synthesis.mk
7,10 → 7,10
work-obj08.cf: neorv32-obj08.cf ${DESIGN_SRC} ${BOARD_SRC}
ghdl -a $(GHDL_FLAGS) --work=work ${DESIGN_SRC} ${BOARD_SRC}
 
${IMPL}.json: work-obj08.cf $(NEORV32_VERILOG_SRC)
${IMPL}.json: work-obj08.cf $(NEORV32_VERILOG_ALL)
$(YOSYS) $(YOSYSFLAGS) \
-p \
"$(GHDLSYNTH) $(GHDL_FLAGS) --no-formal $(TOP); \
synth_${YOSYSSYNTH} \
-top $(TOP) $(YOSYSPIPE) \
-json $@" $(NEORV32_VERILOG_SRC) 2>&1 | tee yosys-report.txt
-json $@" $(NEORV32_VERILOG_ALL) 2>&1 | tee yosys-report.txt
/setups/radiant/UPduino_v3/source/impl_1.xcf
1,6 → 1,6
<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE ispXCF SYSTEM "IspXCF.dtd" >
<ispXCF version="R2.1">
<ispXCF version="R3.0">
<Comment></Comment>
<Chain>
<Comm>SPI</Comm>
18,11 → 18,12
<BScanVal>0</BScanVal>
</Bypass>
<File>../../impl_1/neorv32_upduino_v3_impl_1.bin</File>
<FileTime>05/12/21 23:45:06</FileTime>
<FileTime>11/04/21 21:44:40</FileTime>
<MemoryType>External SPI Flash Memory (SPI FLASH)</MemoryType>
<Operation>Erase,Program,Verify</Operation>
<Option>
<SVFVendor>JTAG STANDARD</SVFVendor>
<SVFProcessor>SVF Processor</SVFProcessor>
<AccessMode>Direct Programming</AccessMode>
</Option>
<FPGALoader>
47,6 → 48,7
<SVFVendor>JTAG STANDARD</SVFVendor>
<IOState>HighZ</IOState>
<IOVectorData></IOVectorData>
<SVFProcessor>SVF Processor</SVFProcessor>
<AccessMode>Direct Programming</AccessMode>
</Option>
</Device>
81,6 → 83,7
</LocalChainList>
<Option>
<SVFVendor>JTAG STANDARD</SVFVendor>
<SVFProcessor>SVF Processor</SVFProcessor>
</Option>
</Device>
</FPGADevice>
99,7 → 102,7
</ProjectOptions>
<CableOptions>
<CableName>USB2</CableName>
<PortAdd>FTUSB-0</PortAdd>
<USBID>UPduino v3.0 Location 0001 Serial </USBID>
<PortAdd>FTUSB-1</PortAdd>
<USBID>UPduino v3.0 Location 0002 Serial </USBID>
</CableOptions>
</ispXCF>
/setups/radiant/UPduino_v3/README.md
15,7 → 15,7
 
### Processor Configuration
 
- [x] CPU: `rv32imac_Zicsr` (reduced CPU `[m]instret` & `[m]cycle` counter width!)
- [x] CPU: `rv32imacu_Zicsr_Zicntr` (reduced CPU `[m]instret` & `[m]cycle` counter width!)
- [x] Memory: 64 kB instruction memory (internal IMEM), 64 kB data memory (internal DMEM), 4 kB bootloader ROM
- [x] Peripherals: `GPIO`, `MTIME`, `UART0`, `SPI`, `TWI`, `PWM`, `WDT`, `TRNG`
- [x] Clock: 24 MHz from on-chip HF oscillator (via PLL)
70,22 → 70,21
### FPGA Utilization
 
```
Number of slice registers: 1768 out of 5280 (33%)
Number of I/O registers: 7 out of 117 (6%)
Number of LUT4s: 4850 out of 5280 (92%)
Number of IO sites used: 23 out of 39 (59%)
Number of DSPs: 0 out of 8 (0%)
Number of I2Cs: 0 out of 2 (0%)
Number of slice registers: 1754 out of 5280 (33%)
Number of I/O registers: 11 out of 117 (9%)
Number of LUT4s: 4882 out of 5280 (92%)
Number of DSPs: 0 out of 8 (0%)
Number of I2Cs: 0 out of 2 (0%)
Number of High Speed OSCs: 1 out of 1 (100%)
Number of Low Speed OSCs: 0 out of 1 (0%)
Number of RGB PWM: 0 out of 1 (0%)
Number of Low Speed OSCs: 0 out of 1 (0%)
Number of RGB PWM: 0 out of 1 (0%)
Number of RGB Drivers: 1 out of 1 (100%)
Number of SCL FILTERs: 0 out of 2 (0%)
Number of SCL FILTERs: 0 out of 2 (0%)
Number of SRAMs: 4 out of 4 (100%)
Number of WARMBOOTs: 0 out of 1 (0%)
Number of SPIs: 0 out of 2 (0%)
Number of EBRs: 15 out of 30 (50%)
Number of PLLs: 1 out of 1 (100%
Number of WARMBOOTs: 0 out of 1 (0%)
Number of SPIs: 0 out of 2 (0%)
Number of EBRs: 15 out of 30 (50%)
Number of PLLs: 1 out of 1 (100%)
```
 
### FPGA Setup
/setups/radiant/UPduino_v3/neorv32_upduino_v3_top.vhd
149,33 → 149,18
HW_THREAD_ID => 0, -- hardware thread id (32-bit)
INT_BOOTLOADER_EN => true, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
 
-- On-Chip Debugger (OCD) --
ON_CHIP_DEBUGGER_EN => false, -- implement on-chip debugger?
 
-- RISC-V CPU Extensions --
CPU_EXTENSION_RISCV_A => true, -- implement atomic extension?
CPU_EXTENSION_RISCV_C => true, -- implement compressed extension?
CPU_EXTENSION_RISCV_E => false, -- implement embedded RF extension?
CPU_EXTENSION_RISCV_M => true, -- implement mul/div extension?
CPU_EXTENSION_RISCV_U => false, -- implement user mode extension?
CPU_EXTENSION_RISCV_Zfinx => false, -- implement 32-bit floating-point extension (using INT regs!)
CPU_EXTENSION_RISCV_U => true, -- implement user mode extension?
CPU_EXTENSION_RISCV_Zicsr => true, -- implement CSR system?
CPU_EXTENSION_RISCV_Zicntr => true, -- implement base counters?
CPU_EXTENSION_RISCV_Zifencei => true, -- implement instruction stream sync.?
 
-- Extension Options --
FAST_MUL_EN => false, -- use DSPs for M extension's multiplier
FAST_SHIFT_EN => false, -- use barrel shifter for shift operations
CPU_CNT_WIDTH => 34, -- total width of CPU cycle and instret counters (0..64)
 
-- Physical Memory Protection (PMP) --
PMP_NUM_REGIONS => 0, -- number of regions (0..64)
PMP_MIN_GRANULARITY => 64*1024, -- minimal region granularity in bytes, has to be a power of 2, min 8 bytes
 
-- Hardware Performance Monitors (HPM) --
HPM_NUM_CNTS => 0, -- number of implemented HPM counters (0..29)
HPM_CNT_WIDTH => 40, -- total size of HPM counters (1..64)
 
-- Internal Instruction memory --
MEM_INT_IMEM_EN => true, -- implement processor-internal instruction memory
MEM_INT_IMEM_SIZE => 64*1024, -- size of processor-internal instruction memory in bytes
/setups/README.md
23,6 → 23,7
| :file_folder: [`nexys-a7-test-setup`](https://github.com/stnolting/neorv32/tree/master/setups/vivado/nexys-a7-test-setup) | Xilinx Vivado | [Digilent Nexys A7](https://reference.digilentinc.com/reference/programmable-logic/nexys-a7/start) | Xilinx Artix-7 `XC7A50TCSG324-1` | [AWenzel83](https://github.com/AWenzel83) |
| :file_folder: [`nexys-a7-test-setup`](https://github.com/stnolting/neorv32/tree/master/setups/vivado/nexys-a7-test-setup) | Xilinx Vivado | [Digilent Nexys 4 DDR](https://reference.digilentinc.com/reference/programmable-logic/nexys-4-ddr/start) | Xilinx Artix-7 `XC7A100TCSG324-1` | [AWenzel83](https://github.com/AWenzel83) |
| :earth_africa: [custom CRC32 processor module for the nexys-a7 boards (**tutorial**)](https://github.com/motius/neorv32/tree/add-custom-crc32-module) | Xilinx Vivado | [Digilent Nexys A7](https://reference.digilentinc.com/reference/programmable-logic/nexys-a7/start) | Xilinx Artix-7 `XC7A50TCSG324-1` | [motius](https://github.com/motius) ([ikstvn](https://github.com/ikstvn), [turbinenreiter](https://github.com/turbinenreiter)) |
| :earth_africa: [neorv32-examples](https://github.com/emb4fun/neorv32-examples) | Intel Quartus Prime | Different Terasic boards | Different Intel FPGAs | [emb4fun](https://github.com/emb4fun) |
 
 
## Setups using Open-Source Toolchains
35,6 → 36,7
| :file_folder: [`AlhambraII`](https://github.com/stnolting/neorv32/tree/master/setups/osflow) | GHDL, Yosys, nextPNR | [AlhambraII](https://alhambrabits.com/alhambra/) | Lattice iCE40HX4K | [zipotron](https://github.com/zipotron) |
| :file_folder: [`Orange Crab`](https://github.com/stnolting/neorv32/tree/master/setups/osflow) | GHDL, Yosys, nextPNR | [Orange Crab](https://github.com/gregdavill/OrangeCrab) | Lattice ECP5-25F | [umarcor](https://github.com/umarcor), [jeremyherbert](https://github.com/jeremyherbert) |
| :file_folder: [`ULX3S`](https://github.com/stnolting/neorv32/tree/master/setups/osflow) | GHDL, Yosys, nextPNR | [ULX3S](https://radiona.org/ulx3s/) | Lattice ECP5 `LFE5U-85F-6BG381C` | [zipotron](https://github.com/zipotron) |
| :earth_africa: [`ULX3S-SDRAM`](https://github.com/zipotron/neorv32-complex-setups) | GHDL, Yosys, nextPNR | [ULX3S](https://radiona.org/ulx3s/) | Lattice ECP5 `LFE5U-85F-6BG381C` | [zipotron](https://github.com/zipotron) |
 
:information_source: All setups using open-source toolchains are located in the
[`osflow`](https://github.com/stnolting/neorv32/tree/master/setups/osflow) folder.
/sim/simple/neorv32_tb.simple.vhd
351,6 → 351,7
wb_mem_a.sel <= wb_cpu.sel;
wb_mem_a.tag <= wb_cpu.tag;
wb_mem_a.cyc <= wb_cpu.cyc;
wb_mem_a.lock <= wb_cpu.lock;
 
wb_mem_b.addr <= wb_cpu.addr;
wb_mem_b.wdata <= wb_cpu.wdata;
358,6 → 359,7
wb_mem_b.sel <= wb_cpu.sel;
wb_mem_b.tag <= wb_cpu.tag;
wb_mem_b.cyc <= wb_cpu.cyc;
wb_mem_b.lock <= wb_cpu.lock;
 
wb_mem_c.addr <= wb_cpu.addr;
wb_mem_c.wdata <= wb_cpu.wdata;
365,6 → 367,7
wb_mem_c.sel <= wb_cpu.sel;
wb_mem_c.tag <= wb_cpu.tag;
wb_mem_c.cyc <= wb_cpu.cyc;
wb_mem_c.lock <= wb_cpu.lock;
 
wb_irq.addr <= wb_cpu.addr;
wb_irq.wdata <= wb_cpu.wdata;
/sim/neorv32_tb.vhd
482,6 → 482,7
wb_mem_a.sel <= wb_cpu.sel;
wb_mem_a.tag <= wb_cpu.tag;
wb_mem_a.cyc <= wb_cpu.cyc;
wb_mem_a.lock <= wb_cpu.lock;
 
wb_mem_b.addr <= wb_cpu.addr;
wb_mem_b.wdata <= wb_cpu.wdata;
489,6 → 490,7
wb_mem_b.sel <= wb_cpu.sel;
wb_mem_b.tag <= wb_cpu.tag;
wb_mem_b.cyc <= wb_cpu.cyc;
wb_mem_b.lock <= wb_cpu.lock;
 
wb_mem_c.addr <= wb_cpu.addr;
wb_mem_c.wdata <= wb_cpu.wdata;
496,6 → 498,7
wb_mem_c.sel <= wb_cpu.sel;
wb_mem_c.tag <= wb_cpu.tag;
wb_mem_c.cyc <= wb_cpu.cyc;
wb_mem_c.lock <= wb_cpu.lock;
 
wb_irq.addr <= wb_cpu.addr;
wb_irq.wdata <= wb_cpu.wdata;
/sw/bootloader/makefile
34,7 → 34,7
# The NEORV32 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting #
#################################################################################################
 
# Relative or absolute path to the NEORV32 home folder
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
NEORV32_HOME ?= ../..
 
include ../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/bitmanip_test/makefile
34,6 → 34,7
# 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 ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/blink_led/main.c
93,7 → 93,7
// use ASM version of LED blinking (file: blink_led_in_asm.S)
#ifdef USE_ASM_VERSION
 
blink_led_asm((uint32_t)(&GPIO_OUTPUT));
blink_led_asm((uint32_t)(&NEORV32_GPIO.OUTPUT_LO));
 
// use C version of LED blinking
#else
/sw/example/blink_led/makefile
34,6 → 34,7
# 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 ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/bus_explorer/main.c
0,0 → 1,436
// #################################################################################################
// # << NEORV32 - Bus Explorer - Processor Memory Space Inspector >> #
// # ********************************************************************************************* #
// # 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 bus_explorer/main.c
* @author Stephan Nolting
* @brief Interactive memory inspector.
**************************************************************************/
 
#include <neorv32.h>
#include <string.h>
 
 
/**********************************************************************//**
* @name User configuration
**************************************************************************/
/**@{*/
/** UART BAUD rate */
#define BAUD_RATE 19200
/**@}*/
 
// Global variables
char access_size;
 
// Prototypes
void read_memory(void);
void setup_access(void);
void write_memory(void);
void atomic_cas(void);
void dump_memory(void);
uint32_t hexstr_to_uint(char *buffer, uint8_t length);
void aux_print_hex_byte(uint8_t byte);
 
 
/**********************************************************************//**
* This program provides an interactive console to read/write memory.
*
* @note This program requires the UART to be synthesized.
*
* @return 0 if execution was successful
**************************************************************************/
int main() {
 
char buffer[8];
int length = 0;
 
access_size = 0;
 
// check if UART unit is implemented at all
if (neorv32_uart0_available() == 0) {
return 1;
}
 
 
// capture all exceptions and give debug info via UART
neorv32_rte_setup();
 
// disable global interrupts
neorv32_cpu_dint();
 
// init UART at default baud rate, no parity bits, ho hw flow control
neorv32_uart0_setup(BAUD_RATE, PARITY_NONE, FLOW_CONTROL_NONE);
 
// check available hardware extensions and compare with compiler flags
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
 
// intro
neorv32_uart0_printf("\n<<< NEORV32 Bus Explorer >>>\n\n");
 
// info
neorv32_uart0_printf("This program allows to read/write/dump memory space by hand.\n"
"Type 'help' to see the help menu.\n\n");
 
// Main menu
for (;;) {
neorv32_uart0_printf("BUS_EXPLORER:> ");
length = neorv32_uart0_scan(buffer, 8, 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"
" setup - configure memory access width (byte,half,word)\n"
" read - read from address (byte,half,word)\n"
" write - write to address (byte,half,word)\n"
" atomic - perform atomic LR/SC access (word-only)\n"
" dump - dump several bytes/halfs/words from base address\n");
}
 
else if (!strcmp(buffer, "setup")) {
setup_access();
}
 
else if (!strcmp(buffer, "read")) {
read_memory();
}
 
else if (!strcmp(buffer, "atomic")) {
atomic_cas();
}
 
else if (!strcmp(buffer, "write")) {
write_memory();
}
 
else if (!strcmp(buffer, "dump")) {
dump_memory();
}
 
else {
neorv32_uart0_printf("Invalid command. Type 'help' to see all commands.\n");
}
}
 
return 0;
}
 
 
/**********************************************************************//**
* Configure memory access size
**************************************************************************/
void setup_access(void) {
 
neorv32_uart0_printf("Select data size (press 'x' to abort):\n"
" 'b' - byte, 8-bit, unsigned\n"
" 'h' - half-word, 16-bit, unsigned\n"
" 'w' - word, 32-bit, unsigned\n");
 
while(1) {
neorv32_uart0_printf("selection: ");
char tmp = neorv32_uart0_getc();
neorv32_uart0_putc(tmp);
if ((tmp == 'b') || (tmp == 'h') || (tmp == 'w')) {
access_size = tmp;
neorv32_uart0_printf("\n");
return;
}
else if (tmp == 'x') {
neorv32_uart0_printf("\n");
return;
}
else {
neorv32_uart0_printf("Invalid selection!\n");
}
}
}
 
 
/**********************************************************************//**
* Read from memory address
**************************************************************************/
void read_memory(void) {
 
char terminal_buffer[16];
 
if (access_size == 0) {
neorv32_uart0_printf("Configure data size using 'setup' first.\n");
return;
}
 
// enter address
neorv32_uart0_printf("Enter address (8 hex chars): 0x");
neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0'
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_cpu_csr_write(CSR_MCAUSE, 0);
 
uint8_t mem_data_b = 0;
uint16_t mem_data_h = 0;
uint32_t mem_data_w = 0;
if (access_size == 'b') { mem_data_b = (uint32_t)neorv32_cpu_load_unsigned_byte(mem_address); }
if (access_size == 'h') { mem_data_h = (uint32_t)neorv32_cpu_load_unsigned_half(mem_address); }
if (access_size == 'w') { mem_data_w = (uint32_t)neorv32_cpu_load_unsigned_word(mem_address); }
 
// show memory content if there was no exception
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) {
neorv32_uart0_printf("0x");
if (access_size == 'b') {
aux_print_hex_byte(mem_data_b);
}
if (access_size == 'h') {
aux_print_hex_byte((uint8_t)(mem_data_h >> 8));
aux_print_hex_byte((uint8_t)(mem_data_h >> 0));
}
if (access_size == 'w') {
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));
}
}
 
neorv32_uart0_printf("\n");
}
 
 
/**********************************************************************//**
* Write to memory address
**************************************************************************/
void write_memory(void) {
 
char terminal_buffer[16];
 
if (access_size == 0) {
neorv32_uart0_printf("Configure data size using 'setup' first.\n");
return;
}
 
// enter address
neorv32_uart0_printf("Enter address (8 hex chars): 0x");
neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0'
uint32_t mem_address = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
 
// enter data
uint8_t mem_data_b = 0;
uint16_t mem_data_h = 0;
uint32_t mem_data_w = 0;
if (access_size == 'b') {
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));
}
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));
}
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));
}
 
// perform write access
if (access_size == 'b') { neorv32_cpu_store_unsigned_byte(mem_address, mem_data_b); }
if (access_size == 'h') { neorv32_cpu_store_unsigned_half(mem_address, mem_data_h); }
if (access_size == 'w') { neorv32_cpu_store_unsigned_word(mem_address, mem_data_w); }
 
neorv32_uart0_printf("\n");
}
 
 
/**********************************************************************//**
* Perform atomic compare-and-swap operation, always 32-bit
**************************************************************************/
void atomic_cas(void) {
 
char terminal_buffer[16];
uint32_t mem_address, rdata, wdata, status;
 
if ((neorv32_cpu_csr_read(CSR_MISA) & (1<<CSR_MISA_A)) != 0) {
 
// enter memory address
neorv32_uart0_printf("Enter memory address (8 hex chars): 0x");
neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0'
mem_address = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
 
// enter desired value
neorv32_uart0_printf("\nEnter new value @0x%x (8 hex chars): 0x", mem_address);
neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0'
wdata = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
 
rdata = neorv32_cpu_load_reservate_word(mem_address); // make reservation
status = neorv32_cpu_store_conditional(mem_address, wdata);
 
// status
neorv32_uart0_printf("\nOld data: 0x%x\n", rdata);
if (status == 0) {
neorv32_uart0_printf("Atomic access successful!\n");
neorv32_uart0_printf("New data: 0x%x\n", neorv32_cpu_load_unsigned_word(mem_address));
}
else {
neorv32_uart0_printf("Atomic access failed!\n");
}
}
else {
neorv32_uart0_printf("Atomic operations not implemented/enabled!\n");
}
}
 
 
/**********************************************************************//**
* Read several bytes/halfs/word from memory base address
**************************************************************************/
void dump_memory(void) {
 
char terminal_buffer[16];
 
if (access_size == 0) {
neorv32_uart0_printf("Configure data size using 'setup' first.\n");
return;
}
 
// enter base address
neorv32_uart0_printf("Enter base address (8 hex chars): 0x");
neorv32_uart0_scan(terminal_buffer, 8+1, 1); // 8 hex chars for address plus '\0'
uint32_t mem_address = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
 
neorv32_uart0_printf("\nPress key to start dumping. Press any key to abort.\n");
 
neorv32_uart0_getc(); // wait for key
 
// perform read accesses
while(neorv32_uart0_char_received() == 0) {
 
neorv32_uart0_printf("[0x%x] = ", mem_address);
 
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
 
uint8_t mem_data_b = 0;
uint16_t mem_data_h = 0;
uint32_t mem_data_w = 0;
if (access_size == 'b') { mem_data_b = (uint32_t)neorv32_cpu_load_unsigned_byte(mem_address); }
if (access_size == 'h') { mem_data_h = (uint32_t)neorv32_cpu_load_unsigned_half(mem_address); }
if (access_size == 'w') { mem_data_w = (uint32_t)neorv32_cpu_load_unsigned_word(mem_address); }
 
// show memory content if there was no exception
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) {
neorv32_uart0_printf("0x");
if (access_size == 'b') {
aux_print_hex_byte(mem_data_b);
}
if (access_size == 'h') {
aux_print_hex_byte((uint8_t)(mem_data_h >> 8));
aux_print_hex_byte((uint8_t)(mem_data_h >> 0));
}
if (access_size == 'w') {
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));
}
neorv32_uart0_printf("\n");
}
else {
break;
}
 
if (access_size == 'b') {
mem_address += 1;
}
else if (access_size == 'h') {
mem_address += 2;
}
else if (access_size == 'w') {
mem_address += 4;
}
 
}
neorv32_uart0_char_received_get(); // clear UART rx buffer
neorv32_uart0_printf("\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;
}
 
 
/**********************************************************************//**
* Print HEX byte.
*
* @param[in] byte Byte to be printed as 2-cahr hex value.
**************************************************************************/
void aux_print_hex_byte(uint8_t byte) {
 
static const char symbols[] = "0123456789abcdef";
 
neorv32_uart0_putc(symbols[(byte >> 4) & 0x0f]);
neorv32_uart0_putc(symbols[(byte >> 0) & 0x0f]);
}
/sw/example/bus_explorer/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/coremark/makefile
34,6 → 34,7
# 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 ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/demo_freeRTOS/makefile
138,7 → 138,7
 
 
 
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
NEORV32_HOME ?= ../../..
 
# Include central makefile
include ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/demo_gptmr/makefile
34,6 → 34,7
# 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 ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/demo_neopixel/makefile
34,6 → 34,7
# 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 ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/demo_pwm/makefile
34,6 → 34,7
# 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 ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/demo_spi/main.c
0,0 → 1,366
// #################################################################################################
// # << NEORV32 - SPI Bus Explorer 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_spi/main.c
* @author Stephan Nolting
* @brief SPI bus explorer (execute SPI transactions by hand).
**************************************************************************/
 
#include <neorv32.h>
#include <string.h>
 
 
/**********************************************************************//**
* @name User configuration
**************************************************************************/
/**@{*/
/** UART BAUD rate */
#define BAUD_RATE 19200
/**@}*/
 
 
// Global variables
uint32_t spi_configured;
uint32_t spi_size; // data quantity in bytes
 
// Prototypes
void spi_cs(uint32_t type);
void spi_trans(void);
void spi_setup(void);
uint32_t hexstr_to_uint(char *buffer, uint8_t length);
void aux_print_hex_byte(uint8_t byte);
 
 
/**********************************************************************//**
* This program provides an interactive console to communicate with SPI devices.
*
* @note This program requires the UART and the SPI to be synthesized.
*
* @return Irrelevant.
**************************************************************************/
int main() {
 
char buffer[8];
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<<< SPI Bus Explorer >>>\n\n");
 
// check if SPI unit is implemented at all
if (neorv32_spi_available() == 0) {
neorv32_uart0_printf("No SPI unit implemented.");
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");
 
// disable and reset SPI module
NEORV32_SPI.CTRL = 0;
spi_configured = 0; // SPI not configured yet
spi_size = 0;
 
 
// Main menu
for (;;) {
neorv32_uart0_printf("SPI_EXPLORER:> ");
length = neorv32_uart0_scan(buffer, 8, 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"
" 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"
"\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");
}
else if (!strcmp(buffer, "setup")) {
spi_setup();
}
else if (!strcmp(buffer, "cs-en")) {
spi_cs(1);
}
else if (!strcmp(buffer, "cs-dis")) {
spi_cs(0);
}
else if (!strcmp(buffer, "trans")) {
spi_trans();
}
else {
neorv32_uart0_printf("Invalid command. Type 'help' to see all commands.\n");
}
}
 
return 0;
}
 
 
/**********************************************************************//**
* Enable or disable chip-select line
*
* @param[in] type 0=disable, 1=enable
**************************************************************************/
void spi_cs(uint32_t type) {
 
char terminal_buffer[2];
uint8_t channel;
 
if (type) {
neorv32_uart0_printf("Select chip-select line to enable (set low) [0..7]: ");
}
else {
neorv32_uart0_printf("Select chip-select line to disable (set high) [0..7]: ");
}
 
while (1) {
neorv32_uart0_scan(terminal_buffer, 2, 1); // 1 hex char plus '\0'
channel = (uint8_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
if (channel > 7) {
neorv32_uart0_printf("\nInvalid channel selection!\n");
return;
}
else {
neorv32_uart0_printf("\n");
break;
}
}
 
if (type) {
neorv32_spi_cs_en(channel);
}
else {
neorv32_spi_cs_dis(channel);
}
}
 
 
/**********************************************************************//**
* SPI data transfer
**************************************************************************/
void spi_trans(void) {
 
char terminal_buffer[9];
 
if (spi_configured == 0) {
neorv32_uart0_printf("SPI module not configured yet! Use 'setup' to configure SPI module.\n");
return;
}
 
neorv32_uart0_printf("Enter TX data (%u hex chars): 0x", spi_size);
neorv32_uart0_scan(terminal_buffer, spi_size*2+1, 1);
uint32_t tx_data = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
 
uint32_t rx_data = neorv32_spi_trans(tx_data);
 
if (spi_size == 1) {
neorv32_uart0_printf("\nTX data: 0x");
aux_print_hex_byte((uint8_t)(tx_data));
neorv32_uart0_printf("\nRX data: 0x");
aux_print_hex_byte((uint8_t)(rx_data));
neorv32_uart0_printf("\n");
}
else if (spi_size == 2) {
neorv32_uart0_printf("\nTX data: 0x");
aux_print_hex_byte((uint8_t)(tx_data >> 8));
aux_print_hex_byte((uint8_t)(tx_data));
neorv32_uart0_printf("\nRX data: 0x");
aux_print_hex_byte((uint8_t)(rx_data >> 8));
aux_print_hex_byte((uint8_t)(rx_data));
neorv32_uart0_printf("\n");
}
else if (spi_size == 3) {
neorv32_uart0_printf("\nTX data: 0x");
aux_print_hex_byte((uint8_t)(tx_data >> 16));
aux_print_hex_byte((uint8_t)(tx_data >> 8));
aux_print_hex_byte((uint8_t)(tx_data));
neorv32_uart0_printf("\nRX data: 0x");
aux_print_hex_byte((uint8_t)(rx_data >> 16));
aux_print_hex_byte((uint8_t)(rx_data >> 8));
aux_print_hex_byte((uint8_t)(rx_data));
neorv32_uart0_printf("\n");
}
else {
neorv32_uart0_printf("\nTX data: 0x%x\n", tx_data);
neorv32_uart0_printf("RX data: 0x%x\n", rx_data);
}
}
 
 
/**********************************************************************//**
* Configure SPI module
**************************************************************************/
void spi_setup(void) {
 
char terminal_buffer[9];
uint8_t spi_prsc, clk_phase, clk_pol, data_size;
uint32_t tmp;
 
// ---- SPI clock ----
 
while (1) {
neorv32_uart0_printf("Select SPI clock prescaler (0..7): ");
neorv32_uart0_scan(terminal_buffer, 2, 1);
tmp = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
if (tmp > 8) {
neorv32_uart0_printf("\nInvalid selection!\n");
}
else {
spi_prsc = (uint8_t)tmp;
break;
}
}
 
uint32_t div = 0;
switch (spi_prsc) {
case 0: div = 2 * 2; break;
case 1: div = 2 * 4; break;
case 2: div = 2 * 8; break;
case 3: div = 2 * 64; break;
case 4: div = 2 * 128; break;
case 5: div = 2 * 1024; break;
case 6: div = 2 * 2048; break;
case 7: div = 2 * 4096; break;
default: div = 0; break;
}
uint32_t clock = NEORV32_SYSINFO.CLK / div;
neorv32_uart0_printf("\n+ New SPI clock speed = %u Hz\n", clock);
 
// ---- SPI clock mode ----
 
while (1) {
neorv32_uart0_printf("Select SPI clock mode (0..3): ");
neorv32_uart0_scan(terminal_buffer, 2, 1);
tmp = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
if (tmp > 4) {
neorv32_uart0_printf("\nInvalid selection!\n");
}
else {
clk_pol = (uint8_t)((tmp >> 1) & 1);
clk_phase = (uint8_t)(tmp & 1);
break;
}
}
neorv32_uart0_printf("\n+ New SPI clock mode = %u\n", tmp);
 
// ---- SPI transfer data quantity ----
 
while (1) {
neorv32_uart0_printf("Select SPI data transfer size in bytes (1,2,3,4): ");
neorv32_uart0_scan(terminal_buffer, 2, 1);
tmp = (uint32_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
if ( (tmp < 1) || (tmp > 4)) {
neorv32_uart0_printf("\nInvalid selection!\n");
}
else {
data_size = (uint8_t)(tmp - 1);
break;
}
}
neorv32_uart0_printf("\n+ New SPI data size = %u-byte(s)\n\n", tmp);
 
neorv32_spi_setup(spi_prsc, clk_phase, clk_pol, data_size);
spi_configured = 1; // SPI is configured now
spi_size = tmp;
}
 
 
/**********************************************************************//**
* 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;
}
 
 
/**********************************************************************//**
* Print HEX byte.
*
* @param[in] byte Byte to be printed as 2-cahr hex value.
**************************************************************************/
void aux_print_hex_byte(uint8_t byte) {
 
static const char symbols[] = "0123456789abcdef";
 
neorv32_uart0_putc(symbols[(byte >> 4) & 0x0f]);
neorv32_uart0_putc(symbols[(byte >> 0) & 0x0f]);
}
/sw/example/demo_spi/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_trng/main.c
82,7 → 82,7
neorv32_rte_check_isa(0); // silent = 0 -> show message if isa mismatch
 
// intro
neorv32_uart0_printf("\n--- TRNG Demo ---\n\n");
neorv32_uart0_printf("\n<<< NEORV32 TRNG Demo >>>\n");
 
// check if TRNG unit is implemented at all
if (neorv32_trng_available() == 0) {
92,13 → 92,14
 
// enable TRNG
neorv32_trng_enable();
neorv32_cpu_delay_ms(100); // TRNG "warm up"
 
while(1) {
 
// 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");
" n: Print 8-bit random numbers (abort by pressing any key)\n"
" h: Generate and print histogram\n");
 
neorv32_uart0_printf("CMD:> ");
char cmd = neorv32_uart0_getc();
/sw/example/demo_trng/makefile
34,6 → 34,7
# 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 ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/demo_twi/main.c
57,6 → 57,7
void set_speed(void);
void send_twi(void);
uint32_t hexstr_to_uint(char *buffer, uint8_t length);
void print_hex_byte(uint8_t data);
 
 
/**********************************************************************//**
104,8 → 105,8
neorv32_uart0_printf("This program allows to create TWI transfers by hand.\n"
"Type 'help' to see the help menu.\n\n");
 
// configure TWI, second slowest clock, no clock-stretching
neorv32_twi_setup(CLK_PRSC_2048, 0);
// configure TWI, second slowest clock
neorv32_twi_setup(CLK_PRSC_2048);
 
// no active bus session yet
bus_claimed = 0;
219,7 → 220,9
neorv32_twi_generate_stop();
 
if (twi_ack == 0) {
neorv32_uart0_printf("+ Found device at write-address 0x%x\n", (uint32_t)(2*i));
neorv32_uart0_printf(" + Found device at write-address 0x");
print_hex_byte(2*i);
neorv32_uart0_printf("\n");
num_devices++;
}
}
242,8 → 245,9
neorv32_uart0_scan(terminal_buffer, 3, 1); // 2 hex chars for address plus '\0'
uint8_t tmp = (uint8_t)hexstr_to_uint(terminal_buffer, strlen(terminal_buffer));
uint8_t res = neorv32_twi_trans(tmp);
neorv32_uart0_printf("\nRX data: 0x%x\n", (uint32_t)neorv32_twi_get_data());
neorv32_uart0_printf("Response: ");
neorv32_uart0_printf("\n RX data: 0x");
print_hex_byte((uint8_t)neorv32_twi_get_data());
neorv32_uart0_printf("\n Response: ");
if (res == 0)
neorv32_uart0_printf("ACK\n");
else
253,7 → 257,7
 
 
/**********************************************************************//**
* Helper function to convert N hex chars string into uint32_T
* 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.
280,4 → 284,19
}
 
return res;
}
}
 
 
/**********************************************************************//**
* Print byte as hex chars via UART0.
*
* @param data 8-bit data to be printed as two hex chars.
**************************************************************************/
void print_hex_byte(uint8_t data) {
 
static const char symbols[] = "0123456789abcdef";
 
neorv32_uart0_putc(symbols[(data >> 4) & 15]);
neorv32_uart0_putc(symbols[(data >> 0) & 15]);
}
 
/sw/example/demo_twi/makefile
34,6 → 34,7
# 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 ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/demo_wdt/makefile
34,6 → 34,7
# 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 ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/demo_xirq/makefile
34,6 → 34,7
# 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 ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/dhrystone/makefile
34,6 → 34,7
# 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 ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/floating_point_test/makefile
34,6 → 34,7
# 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 ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/game_of_life/makefile
34,6 → 34,7
# 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 ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/hello_world/makefile
34,6 → 34,7
# 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 ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/example/processor_check/main.c
483,26 → 483,26
}
 
 
// ----------------------------------------------------------
// No "real" CSR write access (because rs1 = r0)
// ----------------------------------------------------------
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
PRINT_STANDARD("[%i] Read-only CSR 'no-write' (rs1=0) access: ", cnt_test);
//// ----------------------------------------------------------
//// No "real" CSR write access (because rs1 = r0)
//// ----------------------------------------------------------
//neorv32_cpu_csr_write(CSR_MCAUSE, 0);
//PRINT_STANDARD("[%i] Read-only CSR 'no-write' (rs1=0) access: ", cnt_test);
//
//cnt_test++;
//
//// time CSR is read-only, but no actual write is performed because rs1=r0
//// -> should cause no exception
//asm volatile("csrrs zero, time, zero");
//
//if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) {
// test_ok();
//}
//else {
// test_fail();
//}
 
cnt_test++;
 
// time CSR is read-only, but no actual write is performed because rs1=r0
// -> should cause no exception
asm volatile("csrrs zero, time, zero");
 
if (neorv32_cpu_csr_read(CSR_MCAUSE) == 0) {
test_ok();
}
else {
test_fail();
}
 
 
// ----------------------------------------------------------
// Unaligned instruction address
// ----------------------------------------------------------
1124,10 → 1124,11
// configure SPI
neorv32_spi_setup(CLK_PRSC_2, 0, 0, 0);
 
// enable fast interrupt
neorv32_cpu_irq_enable(CSR_MIE_FIRQ6E);
 
// trigger SPI IRQ
neorv32_spi_trans(0);
// enable fast interrupt
neorv32_cpu_irq_enable(CSR_MIE_FIRQ6E);
while(neorv32_spi_busy()); // wait for current transfer to finish
 
// wait some time for the IRQ to arrive the CPU
1155,14 → 1156,14
 
cnt_test++;
 
// configure TWI, fastest clock, no peripheral clock stretching
neorv32_twi_setup(CLK_PRSC_2, 0);
// configure TWI, fastest clock
neorv32_twi_setup(CLK_PRSC_2);
 
// enable TWI FIRQ
neorv32_cpu_irq_enable(CSR_MIE_FIRQ7E);
 
// trigger TWI IRQ
neorv32_twi_generate_start();
neorv32_twi_trans(0);
neorv32_twi_generate_stop();
neorv32_cpu_irq_enable(CSR_MIE_FIRQ7E);
 
// wait some time for the IRQ to arrive the CPU
asm volatile("nop");
1224,9 → 1225,37
// ----------------------------------------------------------
// Fast interrupt channel 9 (NEOLED)
// ----------------------------------------------------------
PRINT_STANDARD("[%i] FIRQ9 (NEOLED): skipped\n", cnt_test);
if (neorv32_neoled_available()) {
neorv32_cpu_csr_write(CSR_MCAUSE, 0);
PRINT_STANDARD("[%i] FIRQ9 (NEOLED): ", cnt_test);
 
cnt_test++;
 
// enable fast interrupt
neorv32_cpu_irq_enable(CSR_MIE_FIRQ9E);
 
// configure NEOLED
neorv32_neoled_setup(CLK_PRSC_2, 0, 0, 0);
 
// send dummy data
neorv32_neoled_write_nonblocking(0);
 
// wait some time for the IRQ to arrive the CPU
asm volatile("nop");
neorv32_cpu_irq_disable(CSR_MIE_FIRQ9E);
 
if (neorv32_cpu_csr_read(CSR_MCAUSE) == TRAP_CODE_FIRQ_9) {
test_ok();
}
else {
test_fail();
}
 
// no more NEOLED interrupts
neorv32_neoled_disable();
}
 
 
// ----------------------------------------------------------
// Fast interrupt channel 10 & 11 (SLINK)
// ----------------------------------------------------------
1236,13 → 1265,13
 
cnt_test++;
 
// enable SLINK
neorv32_slink_enable();
 
// 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);
1306,8 → 1335,8
// enable GPTMR FIRQ
neorv32_cpu_irq_enable(CSR_MIE_FIRQ12E);
 
// configure timer IRQ for one-shot mode after 2*4 clock cycles
neorv32_gptmr_setup(CLK_PRSC_2, 0, 4);
// configure timer IRQ for one-shot mode after 2*3 clock cycles
neorv32_gptmr_setup(CLK_PRSC_2, 0, 3);
 
// wait some time for the IRQ to arrive the CPU
asm volatile("nop");
/sw/example/processor_check/makefile
34,6 → 34,7
# 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 ../../common/common.mk
include $(NEORV32_HOME)/sw/common/common.mk
/sw/lib/include/neorv32.h
740,13 → 740,13
enum NEORV32_SLINK_IRQ_enum {
SLINK_IRQ_RX_EN_LSB = 0, /**< SLINK IRQ configuration register( 0) (r/w): RX IRQ enable LSB (link 0) (#NEORV32_SLINK_IRQ_EN_enum) */
SLINK_IRQ_RX_EN_MSB = 7, /**< SLINK IRQ configuration register( 7) (r/w): RX IRQ enable MSB (link 7) (#NEORV32_SLINK_IRQ_EN_enum) */
SLINK_IRQ_RX_MODE_LSB = 8, /**< SLINK IRQ configuration register( 8) (r/w): RX IRQ mode LSB (link 0) */
SLINK_IRQ_RX_MODE_MSB = 15, /**< SLINK IRQ configuration register(15) (r/w): RX IRQ mode MSB (link 7) */
SLINK_IRQ_RX_MODE_LSB = 8, /**< SLINK IRQ configuration register( 8) (r/w): RX IRQ mode LSB (link 0) (#NEORV32_SLINK_IRQ_RX_TYPE_enum) */
SLINK_IRQ_RX_MODE_MSB = 15, /**< SLINK IRQ configuration register(15) (r/w): RX IRQ mode MSB (link 7) (#NEORV32_SLINK_IRQ_RX_TYPE_enum) */
 
SLINK_IRQ_TX_EN_LSB = 16, /**< SLINK IRQ configuration register(16) (r/w): TX IRQ enable LSB (link 0) (#NEORV32_SLINK_IRQ_EN_enum) */
SLINK_IRQ_TX_EN_MSB = 23, /**< SLINK IRQ configuration register(23) (r/w): TX IRQ enable MSB (link 7) (#NEORV32_SLINK_IRQ_EN_enum) */
SLINK_IRQ_TX_MODE_LSB = 24, /**< SLINK IRQ configuration register(24) (r/w): TX IRQ mode LSB (link 0) */
SLINK_IRQ_TX_MODE_MSB = 31 /**< SLINK IRQ configuration register(31) (r/w): TX IRQ mode MSB (link 7) */
SLINK_IRQ_TX_MODE_LSB = 24, /**< SLINK IRQ configuration register(24) (r/w): TX IRQ mode LSB (link 0) (#NEORV32_SLINK_IRQ_TX_TYPE_enum) */
SLINK_IRQ_TX_MODE_MSB = 31 /**< SLINK IRQ configuration register(31) (r/w): TX IRQ mode MSB (link 7) (#NEORV32_SLINK_IRQ_TX_TYPE_enum) */
};
 
/** SLINK interrupt configuration enable (per link) */
757,13 → 757,13
 
/** SLINK RX interrupt configuration type (per link) */
enum NEORV32_SLINK_IRQ_RX_TYPE_enum {
SLINK_IRQ_RX_FIFO_HALF = 0, /**< '0': RX FIFO is at least half-full */
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 TX interrupt configuration type (per link) */
enum NEORV32_SLINK_IRQ_TX_TYPE_enum {
SLINK_IRQ_TX_FIFO_HALF = 0, /**< '0': TX FIFO is less than half-full */
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 */
};
 
850,8 → 850,7
/** BUSKEEPER control/data register bits */
enum NEORV32_BUSKEEPER_CTRL_enum {
BUSKEEPER_ERR_TYPE = 0, /**< BUSKEEPER control register(0) (r/-): Bus error type: 0=device error, 1=access timeout */
BUSKEEPER_ERR_SRC = 1, /**< BUSKEEPER control register(1) (r/-): Bus error source: 0=processor-external, 1=processor-internal */
BUSKEEPER_ERR_FLAG = 31 /**< BUSKEEPER control register(31) (r/c): Sticky error flag, clears after read */
BUSKEEPER_ERR_FLAG = 31 /**< BUSKEEPER control register(31) (r/c): Sticky error flag, clears after read or write access */
};
/**@}*/
 
1028,17 → 1027,16
 
/** TWI control register bits */
enum NEORV32_TWI_CTRL_enum {
TWI_CTRL_EN = 0, /**< TWI control register(0) (r/w): TWI enable */
TWI_CTRL_START = 1, /**< TWI control register(1) (-/w): Generate START condition, auto-clears */
TWI_CTRL_STOP = 2, /**< TWI control register(2) (-/w): Generate STOP condition, auto-clears */
TWI_CTRL_PRSC0 = 3, /**< TWI control register(3) (r/w): Clock prescaler select bit 0 */
TWI_CTRL_PRSC1 = 4, /**< TWI control register(4) (r/w): Clock prescaler select bit 1 */
TWI_CTRL_PRSC2 = 5, /**< TWI control register(5) (r/w): Clock prescaler select bit 2 */
TWI_CTRL_MACK = 6, /**< TWI control register(6) (r/w): Generate controller ACK for each transmission */
TWI_CTRL_CKSTEN = 7, /**< TWI control register(7) (r/w): Enable clock stretching (by peripheral) */
TWI_CTRL_EN = 0, /**< TWI control register(0) (r/w): TWI enable */
TWI_CTRL_START = 1, /**< TWI control register(1) (-/w): Generate START condition, auto-clears */
TWI_CTRL_STOP = 2, /**< TWI control register(2) (-/w): Generate STOP condition, auto-clears */
TWI_CTRL_PRSC0 = 3, /**< TWI control register(3) (r/w): Clock prescaler select bit 0 */
TWI_CTRL_PRSC1 = 4, /**< TWI control register(4) (r/w): Clock prescaler select bit 1 */
TWI_CTRL_PRSC2 = 5, /**< TWI control register(5) (r/w): Clock prescaler select bit 2 */
TWI_CTRL_MACK = 6, /**< TWI control register(6) (r/w): Generate ACK by controller for each transmission */
 
TWI_CTRL_ACK = 30, /**< TWI control register(30) (r/-): ACK received when set */
TWI_CTRL_BUSY = 31 /**< TWI control register(31) (r/-): Transfer in progress, busy flag */
TWI_CTRL_ACK = 30, /**< TWI control register(30) (r/-): ACK received when set */
TWI_CTRL_BUSY = 31 /**< TWI control register(31) (r/-): Transfer in progress, busy flag */
};
 
/** WTD receive/transmit data register bits */
/sw/lib/include/neorv32_cpu.h
273,8 → 273,6
inline void __attribute__ ((always_inline)) neorv32_cpu_eint(void) {
 
asm volatile ("csrrsi zero, mstatus, %0" : : "i" (1 << CSR_MSTATUS_MIE));
asm volatile ("nop");
asm volatile ("nop");
}
 
 
284,8 → 282,6
inline void __attribute__ ((always_inline)) neorv32_cpu_dint(void) {
 
asm volatile ("csrrci zero, mstatus, %0" : : "i" (1 << CSR_MSTATUS_MIE));
asm volatile ("nop");
asm volatile ("nop");
}
 
 
/sw/lib/include/neorv32_twi.h
46,7 → 46,7
 
// prototypes
int neorv32_twi_available(void);
void neorv32_twi_setup(uint8_t prsc, uint8_t ckst_en);
void neorv32_twi_setup(uint8_t prsc);
void neorv32_twi_disable(void);
void neorv32_twi_enable(void);
void neorv32_twi_mack_enable(void);
/sw/lib/source/neorv32_rte.c
48,7 → 48,7
static uint32_t __neorv32_rte_vector_lut[NEORV32_RTE_NUM_TRAPS] __attribute__((unused)); // trap handler vector table
 
// private functions
static void __attribute__((__interrupt__)) __neorv32_rte_core(void) __attribute__((aligned(16)));
static void __attribute__((__interrupt__)) __neorv32_rte_core(void) __attribute__((aligned(4)));
static void __neorv32_rte_debug_exc_handler(void);
static void __neorv32_rte_print_true_false(int state);
static void __neorv32_rte_print_checkbox(int state);
65,8 → 65,7
void neorv32_rte_setup(void) {
 
// configure trap handler base address
uint32_t mtvec_base = (uint32_t)(&__neorv32_rte_core);
neorv32_cpu_csr_write(CSR_MTVEC, mtvec_base);
neorv32_cpu_csr_write(CSR_MTVEC, (uint32_t)(&__neorv32_rte_core));
 
// install debug handler for all sources
uint8_t id;
73,6 → 72,9
for (id = 0; id < (sizeof(__neorv32_rte_vector_lut)/sizeof(__neorv32_rte_vector_lut[0])); id++) {
neorv32_rte_exception_uninstall(id); // this will configure the debug handler
}
 
// clear BUSKEEPER error flags
NEORV32_BUSKEEPER.CTRL = 0;
}
 
 
111,7 → 113,7
 
// id valid?
if ((id >= RTE_TRAP_I_MISALIGNED) && (id <= CSR_MIE_FIRQ15E)) {
__neorv32_rte_vector_lut[id] = (uint32_t)(&__neorv32_rte_debug_exc_handler); // use dummy handler in case the exception is accidently triggered
__neorv32_rte_vector_lut[id] = (uint32_t)(&__neorv32_rte_debug_exc_handler); // use dummy handler in case the exception is accidentally triggered
return 0;
}
return 1;
126,7 → 128,7
*
* @warning When using the the RTE, this function is the ONLY function that can use the 'interrupt' attribute!
**************************************************************************/
static void __attribute__((__interrupt__)) __attribute__((aligned(16))) __neorv32_rte_core(void) {
static void __attribute__((__interrupt__)) __attribute__((aligned(4))) __neorv32_rte_core(void) {
 
register uint32_t rte_mepc = neorv32_cpu_csr_read(CSR_MEPC);
neorv32_cpu_csr_write(CSR_MSCRATCH, rte_mepc); // store for later
133,7 → 135,7
register uint32_t rte_mcause = neorv32_cpu_csr_read(CSR_MCAUSE);
 
// compute return address
if (((int32_t)rte_mcause) >= 0) { // modify pc only if exception (MSB cleared)
if (((int32_t)rte_mcause) >= 0) { // modify pc only if not interrupt (MSB cleared)
 
// get low half word of faulting instruction
register uint32_t rte_trap_inst;
151,7 → 153,7
}
 
// find according trap handler
register uint32_t rte_handler = (uint32_t)(&__neorv32_rte_debug_exc_handler);
register uint32_t rte_handler;
switch (rte_mcause) {
case TRAP_CODE_I_MISALIGNED: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_I_MISALIGNED]; break;
case TRAP_CODE_I_ACCESS: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_I_ACCESS]; break;
182,7 → 184,7
case TRAP_CODE_FIRQ_13: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_13]; break;
case TRAP_CODE_FIRQ_14: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_14]; break;
case TRAP_CODE_FIRQ_15: rte_handler = __neorv32_rte_vector_lut[RTE_TRAP_FIRQ_15]; break;
default: break;
default: rte_handler = (uint32_t)(&__neorv32_rte_debug_exc_handler); break;
}
 
// execute handler
730,7 → 732,7
/**********************************************************************//**
* NEORV32 runtime environment: Check required ISA extensions (via compiler flags) against available ISA extensions (via MISA csr).
*
* @param[in] silent Show error message (via neorv32.uart) if isa_sw > isa_hw when != 0.
* @param[in] silent Show error message (via neorv32.uart) if isa_sw > isa_hw when = 0.
* @return MISA content according to compiler configuration.
**************************************************************************/
int neorv32_rte_check_isa(int silent) {
746,7 → 748,7
return 0;
}
else {
if ((silent == 0) || (neorv32_uart0_available() == 0)) {
if ((silent == 0) && (neorv32_uart0_available() != 0)) {
neorv32_uart0_printf("\nWARNING! SW_ISA (features required) vs HW_ISA (features available) mismatch!\n"
"SW_ISA = 0x%x (compiler flags)\n"
"HW_ISA = 0x%x (misa csr)\n\n", misa_sw, misa_hw);
/sw/lib/source/neorv32_trng.c
99,20 → 99,15
**************************************************************************/
int neorv32_trng_get(uint8_t *data) {
 
const int retries = 3;
int i;
uint32_t ct_reg;
 
for (i=0; i<retries; i++) {
ct_reg = NEORV32_TRNG.CTRL;
ct_reg = NEORV32_TRNG.CTRL;
 
if ((ct_reg & (1<<TRNG_CTRL_VALID)) == 0) { // output data valid?
continue;
}
 
if (ct_reg & (1<<TRNG_CTRL_VALID)) { // output data valid?
*data = (uint8_t)(ct_reg >> TRNG_CTRL_DATA_LSB);
return 0; // valid data
}
 
return -1; // no valid data available
else {
return -1;
}
}
/sw/lib/source/neorv32_twi.c
65,9 → 65,8
* Enable and configure TWI controller. The TWI control register bits are listed in #NEORV32_TWI_CTRL_enum.
*
* @param[in] prsc Clock prescaler select (0..7). See #NEORV32_CLOCK_PRSC_enum.
* @param[in] ckst_en Enable clock-stretching by peripherals when 1.
**************************************************************************/
void neorv32_twi_setup(uint8_t prsc, uint8_t ckst_en) {
void neorv32_twi_setup(uint8_t prsc) {
 
NEORV32_TWI.CTRL = 0; // reset
 
77,10 → 76,7
uint32_t ct_prsc = (uint32_t)(prsc & 0x07);
ct_prsc = ct_prsc << TWI_CTRL_PRSC0;
 
uint32_t ct_cksten = (uint32_t)(ckst_en & 0x01);
ct_cksten = ct_cksten << TWI_CTRL_CKSTEN;
 
NEORV32_TWI.CTRL = ct_enable | ct_prsc | ct_cksten;
NEORV32_TWI.CTRL = ct_enable | ct_prsc;
}
 
 
/CHANGELOG.md
26,7 → 26,18
 
| Date (*dd.mm.yyyy*) | Version | Comment |
|:----------:|:-------:|:--------|
| 03.11.2021 | 1.6.3.1 | :sparkles: added new peripheral module - general purpose 32-bit timer `GPTMR` ([see PR #195](https://github.com/stnolting/neorv32/pull/195)) |
| 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) |
| 21.11.2021 | 1.6.3.9 | minor rtl edits: configuring an IMEM or DMEM size (`MEM_INT_IMEM_SIZE` / `MEM_INT_DMEM_SIZE` generic) of 0 will now exclude the according memory from synthesis (and also clears the according `NEORV32_SYSINFO.SOC` flags) |
| 18.11.2021 | 1.6.3.8 | TWI: removed TWI_CTRL_CKSTEN flag (enable clock stretching) from control registers, clock-stretching is now _always_ enabled |
| 14.11.2021 | 1.6.3.7 | major control unit and ALU logic optimizations, reduced hardware footprint; :lock: closed further illegal instruction encoding holes (system environment instructions, ALU and ALU-immediate instructions, FENCE instructions); [PR #204](https://github.com/stnolting/neorv32/pull/204) |
| 10.11.2021 | 1.6.3.6 | optimized BUSKEEPER: removed redundant logic - bus keeper now also shows an external interface access timeout (if implemented) as "timeout error"; removed _BUSKEEPER_ERR_SRC_ status flag; :warning: added `err_o` (fault access operation) to the custom functions subsystem (CFS) |
| 09.11.2021 | 1.6.3.5 | :warning: reworked IRQ trigger logic of SPI, TWI, UART0, UART1, NELOED and SLINK; FIRQs now only trigger **once** when the programmed interrupt condition is met instead of triggering **all the time** (see [PR #202](https://github.com/stnolting/neorv32/pull/202)) |
| 06.11.2021 | 1.6.3.4 | :bug: fixed bug in **WISHBONE** interface: _pipelined_ Wishbone mode did not clear STB after first transfer cycle |
| 05.11.2021 | 1.6.3.3 | :bug: fixed bug in general purpose timer **GPTMR** - clock prescaler had no effect, the timer was always counting at full processor clock speed; minor watchdog (WDT) code edits |
| 04.11.2021 | 1.6.3.2 | added optional _alternative_ IMEM and DMEM architecture-only design files (in `rtl/core/mem`); these are not device-specific ("cyclone 2") as they do not use any FPGA-specific primitives or macros - just a different HDL style for describing memories is used (see [PR #192](https://github.com/stnolting/neorv32/pull/198) and [Issue #197](https://github.com/stnolting/neorv32/issues/197)) |
| 03.11.2021 | 1.6.3.1 | :sparkles: added new peripheral module - **General Purpose 32-bit Timer `GPTMR`** ([see PR #195](https://github.com/stnolting/neorv32/pull/195)) |
| 02.11.2021 |[**:rocket:1.6.3**](https://github.com/stnolting/neorv32/releases/tag/v1.6.3) | **New release** |
| 01.11.2021 | 1.6.2.13 | added new top generics to explicitly control implementation of `Zicntr` (CPU base counters) and `Zihpm` (hardware performance monitors, see [PR #192](https://github.com/stnolting/neorv32/pull/192) |
| 30.10.2021 | 1.6.2.12 | :sparkles: :lock: added memory-mapped register to BUSKEEPER module - software can now retrieve the actual cause of an instruction / data-load / data-store bus access fault exception (access timeout or device error); see [PR #191](https://github.com/stnolting/neorv32/pull/191) |
/README.md
13,7 → 13,7
[![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)
46,7 → 46,7
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.
 
:information_source: Want to know more? Check out the [project's rationale](https://stnolting.github.io/neorv32/#_rationale).
: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
59,16 → 59,13
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).
 
:kite: Upstream [**Zephyr RTOS**](https://docs.zephyrproject.org/latest/boards/riscv/neorv32/doc/index.html) support.
:kite: Supported by upstream [Zephyr OS](https://docs.zephyrproject.org/latest/boards/riscv/neorv32/doc/index.html).
 
:spiral_notepad: Check out the [project boards](https://github.com/stnolting/neorv32/projects) for a list of current **ideas**,
**TODOs**, features being **planned** and **work-in-progress**.
 
: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).
 
:rocket: Check out the [quick links below](#Getting-Started) or directly jump to the
: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
setting up your NEORV32 setup!
 
75,7 → 72,7
 
### Project Key Features
 
- [x] all-in-one: [CPU](#NEORV32-CPU-Features) plus [Processor/SoC](#NEORV32-Processor-Features) plus [Software Framework & Tooling](#Software-Framework-and-Tooling)
- [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] 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:
92,8 → 89,6
The NEORV32 Processor (top entity: [`rtl/core/neorv32_top.vhd`](https://github.com/stnolting/neorv32/blob/master/rtl/core/neorv32_top.vhd))
provides a full-featured SoC build around the NEORV32 CPU. It is highly configurable via generics
to allow a flexible customization according to your needs. Note that all modules listed below are _optional_.
In-depth detailed information regarding the processor/SoC can be found in the :books:
[online documentation - _"NEORV32 Processors (SoC)"_](https://stnolting.github.io/neorv32/#_neorv32_processor_soc).
 
**Memory**
 
101,7 → 96,7
[IMEM](https://stnolting.github.io/neorv32/#_instruction_memory_imem)) &
cache ([iCACHE](https://stnolting.github.io/neorv32/#_processor_internal_instruction_cache_icache))
* bootloader ([BOOTLDROM](https://stnolting.github.io/neorv32/#_bootloader_rom_bootrom)) with serial user interface
* supports boot via UART or from external SPI flash
* allows booting application code via UART or from external SPI flash
 
**Timers**
 
136,24 → 131,19
**Advanced**
 
* _true random_ number generator ([TRNG](https://stnolting.github.io/neorv32/#_true_random_number_generator_trng))
* on-chip debugger ([OCD](https://stnolting.github.io/neorv32/#_on_chip_debugger_ocd)) via JTGA - implementing
* on-chip debugger ([OCD](https://stnolting.github.io/neorv32/#_on_chip_debugger_ocd)) accessible via JTAG interface - implementing
the [*Minimal RISC-V Debug Specification Version 0.13.2*](https://github.com/riscv/riscv-debug-spec)
and compatible with *OpenOCD* and *gdb*
* bus keeper to monitor processor-internal bus transactions ([BUSKEEPER](https://stnolting.github.io/neorv32/#_internal_bus_monitor_buskeeper))
* bus keeper to monitor the CPU's bus transactions ([BUSKEEPER](https://stnolting.github.io/neorv32/#_internal_bus_monitor_buskeeper))
 
:information_source: It is recommended to use the processor setup even if you want to **use the CPU in stand-alone mode**.
Just disable all optional processor-internal modules via the according generics and you will get a "CPU wrapper" that
provides a minimal CPU environment and an external memory interface (like AXI4). This minimal setup allows to further use
the default bootloader and software framework. From this base you can start building your own processor system.
 
[[back to top](#The-NEORV32-RISC-V-Processor)]
 
 
### FPGA Implementation Results - Processor
 
The hardware resources used by a specific processor setup is defined by the implemented CPU extensions
([see below](#FPGA-Implementation-Results---CPU)), the configuration of the peripheral modules and some "glue logic".
Section [_"FPGA Implementation Results - Processor Modules"_](https://stnolting.github.io/neorv32/#_processor_modules)
The hardware resources used by a specific processor setup is defined by the implemented CPU extensions,
the configuration of the peripheral modules and some "glue logic".
Section [_FPGA Implementation Results - Processor Modules_](https://stnolting.github.io/neorv32/#_processor_modules)
of the online datasheet shows the resource utilization of each optional processor module to allow an
estimation of the actual setup's hardware requirements.
 
167,9 → 157,6
 
## 3. NEORV32 CPU Features
 
:books: In-depth detailed information regarding the CPU can be found in the
[online documentation - _"NEORV32 Central Processing Unit"_](https://stnolting.github.io/neorv32/#_neorv32_central_processing_unit_cpu).
 
The CPU (top entity: [`rtl/core/neorv32_cpu.vhd`](https://github.com/stnolting/neorv32/blob/master/rtl/core/neorv32_cpu.vhd))
implements the RISC-V 32-bit `rv32` ISA with optional extensions (see below). It is compatible to subsets of the
*Unprivileged ISA Specification* [(Version 2.2)](https://github.com/stnolting/neorv32/blob/master/docs/references/riscv-spec.pdf)
184,7 → 171,10
It also supports **all** standard RISC-V exceptions (instruction/load/store misaligned address & bus access fault, illegal
instruction, breakpoint, environment calls).
 
:books: In-depth detailed information regarding the CPU can be found in the
[_Data Sheet: NEORV32 Central Processing Unit_](https://stnolting.github.io/neorv32/#_neorv32_central_processing_unit_cpu).
 
 
### Available ISA Extensions
 
Currently, the following _optional_ RISC-V-compatible ISA extensions are implemented (linked to the according
228,11 → 218,12
| `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
[online documentation - _"FPGA Implementation Results - CPU"_](https://stnolting.github.io/neorv32/#_cpu).
: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 provides options to further reduce the footprint (for example by constraining
the CPU-internal counters). See the [online data](https://stnolting.github.io/neorv32) sheet for more information.
:information_source: The CPU (and also the SoC) provides 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.
 
[[back to top](#The-NEORV32-RISC-V-Processor)]
 
245,20 → 236,11
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](https://www.eembc.org/coremark).
_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).
 
:information_source: A _simple_ port of the **Dhrystone** benchmark is also available:
[`sw/example/dhrystone`](https://github.com/stnolting/neorv32/blob/master/sw/example/dhrystone)
 
~~~
**CoreMark Setup**
Hardware: 32kB IMEM, 8kB DMEM, no caches, 100MHz clock
CoreMark: 2000 iterations, MEM_METHOD is MEM_STACK
Compiler: RISCV32-GCC 10.1.0 (rv32i toolchain)
Compiler flags: default, see makefile; optimization -O3
~~~
 
Results generated for hardware version [`1.5.7.10`](https://github.com/stnolting/neorv32/blob/master/CHANGELOG.md).
 
| CPU Configuration | CoreMark Score | CoreMarks/MHz | Average CPI |
268,7 → 250,7
| _performance_ (`rv32imc_Zicsr` + perf. options) | 95.23 | **0.9523** | **3.54** |
 
:information_source: More information regarding the CPU performance can be found in the
[online documentation - _"CPU Performance"_](https://stnolting.github.io/neorv32/#_cpu_performance).
[_Data Sheet: CPU Performance_](https://stnolting.github.io/neorv32/#_cpu_performance).
 
[[back to top](#The-NEORV32-RISC-V-Processor)]
 
277,7 → 259,7
## 4. Software Framework and Tooling
 
:books: In-depth detailed information regarding the software framework can be found in the
[online documentation - _"Software Framework"_](https://stnolting.github.io/neorv32/#_software_framework).
[_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
284,10 → 266,7
* gcc-based toolchain ([pre-compiled toolchains available](https://github.com/stnolting/riscv-gcc-prebuilt))
* 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](https://github.com/stnolting/neorv32/tree/master/sw/example/coremark),
[FreeRTOS](https://github.com/stnolting/neorv32/tree/master/sw/example/demo_freeRTOS) and
[Conway's Game of Life](https://github.com/stnolting/neorv32/tree/master/sw/example/game_of_life)
* 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
developed and debugged with open source tooling
332,7 → 311,7
* [Application Makefiles](https://stnolting.github.io/neorv32/#_application_makefile) - turning your application into an executable
* [Bootloader](https://stnolting.github.io/neorv32/#_bootloader) - the build-in NEORV32 bootloader
 
### :rocket: User Guides (see full [User Guide](https://stnolting.github.io/neorv32/ug/))
### :rocket: User Guide
 
* [Toolchain Setup](https://stnolting.github.io/neorv32/ug/#_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
357,12 → 336,8
 
## Acknowledgements
 
**A big shoutout to all [contributors](https://github.com/stnolting/neorv32/graphs/contributors), who helped improving this project! :heart:**
**A big shout-out to the community and all [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!
 
Continous integration provided by [:octocat: GitHub Actions](https://github.com/features/actions) and powered by [GHDL](https://github.com/ghdl/ghdl).
 
--------
 
Made with :coffee: in Hanover, Germany :eu:
Continuous integration provided by [:octocat: GitHub Actions](https://github.com/features/actions) and powered by [GHDL](https://github.com/ghdl/ghdl).

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.