Merge branch 'main' into linty_test
Some checks failed
Documentation / SW Framework (push) Has been cancelled
Documentation / Datasheet (push) Has been cancelled
Linty / Linty (push) Has been cancelled
Processor / processor simulation (push) Has been cancelled
Documentation / Deploy to Releases and Pages (push) Has been cancelled

Signed-off-by: stnolting <stnolting@gmail.com>
This commit is contained in:
stnolting 2024-11-02 22:20:15 +01:00 committed by GitHub
commit fea96e0fd4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
111 changed files with 3117 additions and 3006 deletions

View file

@ -17,25 +17,9 @@ on:
jobs:
Software:
sim_default_tb:
runs-on: ubuntu-latest
container: ghcr.io/stnolting/neorv32/sim
steps:
- name: '🧰 Repository Checkout'
uses: actions/checkout@v4
- name: '⚙️ Build Software Framework Tests'
run: |
make -C sw/example/processor_check check
make -C sw/example clean_all exe
make -C sw/bootloader clean_all info bootloader
Simple:
runs-on: ubuntu-latest
name: 'Simple testbench'
name: 'processor simulation'
strategy:
fail-fast: false
matrix:
@ -48,50 +32,32 @@ jobs:
- name: '🧰 Repository Checkout'
uses: actions/checkout@v4
- name: '🚧 Build and install software; then simulate with shell script'
uses: docker://ghcr.io/stnolting/neorv32/sim
# Redirect UART0 TX to text.io simulation output via <UARTx_SIM_MODE> user flags
with:
args: >-
make -C sw/example/${{ matrix.example }}
clean_all
USER_FLAGS+="-DUART0_SIM_MODE -DUART1_SIM_MODE -flto"
EFFORT=-Os
MARCH=rv32ima_zicsr_zifencei
info
all
sim-check
- name: '📦 Install RISC-V GCC'
run: |
wget -q https://github.com/stnolting/riscv-gcc-prebuilt/releases/download/rv32i-131023/riscv32-unknown-elf.gcc-13.2.0.tar.gz
mkdir $GITHUB_WORKSPACE/riscv-gcc
tar -xzf riscv32-unknown-elf.gcc-13.2.0.tar.gz -C $GITHUB_WORKSPACE/riscv-gcc
echo $GITHUB_WORKSPACE/riscv-gcc/bin >> $GITHUB_PATH
- name: '📦 Install GHDL'
uses: ghdl/setup-ghdl-ci@nightly
VUnit:
runs-on: ubuntu-latest
- name: '🔍 Check tools'
run: |
riscv32-unknown-elf-gcc -v
ghdl -v
steps:
- name: '⚙️ Build Software Framework Tests'
run: |
make -C sw/example/processor_check check
make -C sw/example clean_all exe
make -C sw/bootloader clean_all info bootloader
- name: '🧰 Repository Checkout'
uses: actions/checkout@v4
- name: '⚙️ Build and install Processor Check software'
uses: docker://ghcr.io/stnolting/neorv32/sim
with:
args: >-
make -C sw/example/processor_check
clean_all
USER_FLAGS+=-DUART0_SIM_MODE
USER_FLAGS+=-DSUPPRESS_OPTIONAL_UART_PRINT
USER_FLAGS+=-flto
MARCH=rv32imac_zicsr_zifencei
info
all
- name: '📤 Archive Processor Check application image'
uses: actions/upload-artifact@v4
with:
name: application
path: rtl/core/neorv32_application_image.vhd
- name: '🚧 Run Processor Hardware Tests with VUnit'
uses: VUnit/vunit_action@master
with:
image: ghcr.io/stnolting/neorv32/sim
cmd: ./sim/run.py --ci-mode -v
- name: '🚧 Compile executable and run simulation'
run: |
make -C sw/example/${{ matrix.example }} \
USER_FLAGS+="-DUART0_SIM_MODE -DUART1_SIM_MODE" \
clean_all \
info \
all \
sim-check

View file

@ -29,6 +29,14 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12
| Date | Version | Comment | Ticket |
|:----:|:-------:|:--------|:------:|
| 02.11.2024 | 1.10.6.2 | :warning: rework processor boot configuration; add new boot-configuration generics | [#1086](https://github.com/stnolting/neorv32/pull/1086) |
| 01.11.2024 | 1.10.6.1 | :test_tube: convert VHDL memory images into full-scale VHDL packages | [#1084](https://github.com/stnolting/neorv32/pull/1084) |
| 26.10.2024 | [**:rocket:1.10.6**](https://github.com/stnolting/neorv32/releases/tag/v1.10.6) | **New release** | |
| 26.10.2024 | 1.10.5.11 | cleanup central makefile and linker script | [#1077](https://github.com/stnolting/neorv32/pull/1077) |
| 21.10.2024 | 1.10.5.10 | :test_tube: rework linker script's ROM/IMEM default size (=16kB); add customization variable to all makefiles in `sw/example` | [#1072](https://github.com/stnolting/neorv32/pull/1072) |
| 20.10.2024 | 1.10.5.9 | :warning: rework XIRQ controller; remove "interrupt pending" register `EIP` | [#1071](https://github.com/stnolting/neorv32/pull/1071) |
| 18.10.2024 | 1.10.5.8 | minor RTL code cleanups | [#1068](https://github.com/stnolting/neorv32/pull/1068) |
| 18.10.2024 | 1.10.5.7 | use individual/new module for XBUS-to-AXI4-Lite bridge | [#1063](https://github.com/stnolting/neorv32/pull/1063) |
| 12.10.2024 | 1.10.5.6 | :warning: remove legacy support for on-chip debugger DM version v0.13; now only supporting DM v1.0 (removing `OCD_DM_LEGACY_MODE` generic) | [#1056](https://github.com/stnolting/neorv32/pull/1056) |
| 11.10.2024 | 1.10.5.5 | :sparkles: :lock: add support for optional on-chip debugger authentication; :warning: rename OCD-related top generics | [#1053](https://github.com/stnolting/neorv32/pull/1053) |
| 06.10.2024 | 1.10.5.4 | :warning: rework PWM module | [#1049](https://github.com/stnolting/neorv32/pull/1049) |
@ -143,7 +151,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12
| 16.02.2024 | 1.9.5.2 | :warning: **revert** support for page faults (keep that in mmu branch for now) | [#809](https://github.com/stnolting/neorv32/pull/809) |
| 16.02.2024 | 1.9.5.1 | :sparkles: add two new generics to exclude certain PMP modes from synthesis | [#808](https://github.com/stnolting/neorv32/pull/808) |
| 16.02.2024 | [**:rocket:1.9.5**](https://github.com/stnolting/neorv32/releases/tag/v1.9.5) | **New release** | |
| 15.02.2023 | 1.9.4.13 | allow the DMA to issue a FENCE operation | [#807](https://github.com/stnolting/neorv32/pull/807) |
| 15.02.2024 | 1.9.4.13 | allow the DMA to issue a FENCE operation | [#807](https://github.com/stnolting/neorv32/pull/807) |
| 14.02.2024 | 1.9.4.12 | :lock: close another illegal compressed instruction encoding loophole | [#806](https://github.com/stnolting/neorv32/pull/806) |
| 11.02.2024 | 1.9.4.11 | :bug: fix several FPU bugs and design flaws | [#794](https://github.com/stnolting/neorv32/pull/794) |
| 11.02.2024 | 1.9.4.10 | minor additions to previous version (1.9.4.9): fix HPM configuration read-back | [#804](https://github.com/stnolting/neorv32/pull/804) |

View file

@ -56,13 +56,11 @@ not working as expected. See how to [contribute](https://github.com/stnolting/ne
- [x] all-in-one package: **CPU** + **SoC** + **Software Framework & Tooling**
- [x] completely described in behavioral, platform-independent VHDL - **no** platform-specific primitives, macros, attributes, etc.; an all-Verilog "version" is also [available](https://github.com/stnolting/neorv32-verilog)
- [x] extensive configuration options for adapting the processor to the requirements of the application
- [x] highly [extensible hardware](https://stnolting.github.io/neorv32/ug/#_comparative_summary) - on CPU, processor and system level
- [x] extensive configuration options for adapting the processor to the requirements of the application (on CPU, processor and system level)
- [x] aims to be as small as possible while being as RISC-V-compliant as possible - with a reasonable area-vs-performance trade-off
- [x] FPGA friendly (e.g. _all_ internal memories can be mapped to block RAM - including the CPU's register file)
- [x] optimized for high clock frequencies to ease integration / timing closure
- [x] from zero to _"hello world!"_ - completely open source and documented
- [x] highly documented - on software and hardware side
- [x] from zero to _"hello world!"_ - completely open source and documented (on software and hardware side)
- [x] easy to use even for FPGA / RISC-V starters intended to work _out of the box_
### Project Status
@ -70,12 +68,13 @@ not working as expected. See how to [contribute](https://github.com/stnolting/ne
[![release](https://img.shields.io/github/v/release/stnolting/neorv32?longCache=true&style=flat-square&logo=GitHub)](https://github.com/stnolting/neorv32/releases)
[![commits-since-latest-release](https://img.shields.io/github/commits-since/stnolting/neorv32/latest?longCache=true&style=flat-square&logo=GitHub)](https://github.com/stnolting/neorv32/activity)
| Task / Subproject | Repository | CI Status |
|:---------------------------------------------------|:-----------|:----------|
| Task / Subproject | Repository | CI Status |
|:------------------|:-----------|:----------|
| Code quality ([Linty](https://linty-services.com)) | [neorv32](https://github.com/stnolting/neorv32) | [![Quality Gate Status](https://oss.linty-services.com/api/project_badges/measure?project=neorv32&metric=alert_status&token=sqb_97b392f36051f7887215e61c53d6f0f858ca2697)](https://oss.linty-services.com/dashboard?id=neorv32) |
| GitHub pages (docs) | [neorv32](https://github.com/stnolting/neorv32) | [![GitHub Pages](https://img.shields.io/website.svg?label=stnolting.github.io%2Fneorv32&longCache=true&style=flat-square&url=http%3A%2F%2Fstnolting.github.io%2Fneorv32%2Findex.html&logo=GitHub)](https://stnolting.github.io/neorv32) |
| Build documentation | [neorv32](https://github.com/stnolting/neorv32) | [![Documentation](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32/Documentation.yml?branch=main&longCache=true&style=flat-square&label=Documentation&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3ADocumentation) |
| Processor verification | [neorv32](https://github.com/stnolting/neorv32) | [![Processor](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32/Processor.yml?branch=main&longCache=true&style=flat-square&label=Processor%20Check&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3AProcessor) |
| VUnit testbench | [neorv32-vunit](https://github.com/stnolting/neorv32-vunit) | [![neorv32-vunit](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32-vunit/vunit.yml?branch=main&longCache=true&style=flat-square&label=neorv32-vunit&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32-vunit/actions/workflows/vunit.yml) |
| RISCOF core verification | [neorv32-riscof](https://github.com/stnolting/neorv32-riscof) | [![neorv32-riscof](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32-riscof/main.yml?branch=main&longCache=true&style=flat-square&label=neorv32-riscof&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32-riscof/actions/workflows/main.yml) |
| FPGA implementations | [neorv32-setups](https://github.com/stnolting/neorv32-setups) | [![Implementation](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32-setups/Implementation.yml?branch=main&longCache=true&style=flat-square&label=Implementation&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32-setups/actions?query=workflow%3AImplementation) |
| All-Verilog version | [neorv32-verilog](https://github.com/stnolting/neorv32-verilog) | [![neorv32-verilog](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32-verilog/main.yml?branch=main&longCache=true&style=flat-square&label=neorv32-verilog&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32-verilog/actions/workflows/main.yml) |

View file

@ -2,7 +2,7 @@
:email: stnolting@gmail.com
:keywords: neorv32, risc-v, riscv, rv32, fpga, soft-core, vhdl, microcontroller, cpu, soc, processor, gcc, openocd, gdb, verilog, rtl, asip, asic, safety
:description: A size-optimized, customizable and highly extensible MCU-class 32-bit RISC-V soft-core CPU and microcontroller-like SoC written in platform-independent VHDL.
:revnumber: v1.10.5
:revnumber: v1.10.6
:doctype: book
:sectnums:
:stem:

View file

@ -531,6 +531,7 @@ The `I` ISA extensions is the base RISC-V integer ISA that is always enabled.
|=======================
| Class | Instructions | Execution cycles
| ALU | `add[i]` `slt[i]` `slt[i]u` `xor[i]` `or[i]` `and[i]` `sub` `lui` `auipc` | 2
| No-operation | "`nop`" | 2
| ALU shifts | `sll[i]` `srl[i]` `sra[i]` | 3 + 1..32; FAST_SHIFT: 4
| Branches | `beq` `bne` `blt` `bge` `bltu` `bgeu` | taken: 6; not taken: 3
| Jump/call | `jal[r]` | 6

View file

@ -360,7 +360,7 @@ As software does not need to determine the interrupt cause the reduction in late
|=======================
| Name | Machine exception program counter
| Address | `0x341`
| Reset value | `0x00000000`
| Reset value | `BOOT_ADDR` (CPU boot address, see <<_cpu_top_entity_generics>>)
| ISA | `Zicsr`
| Description | The `mepc` CSR provides the instruction address where execution has stopped/failed when
an interrupt is triggered / an exception is raised. See section <<_traps_exceptions_and_interrupts>> for a list of all legal values.

View file

@ -179,7 +179,7 @@ All core VHDL files from the list below have to be assigned to a **new library**
[NOTE]
See section <<_file_list_files>> for more information.
.RTL File List and Hierarchy
.RTL File List and Hierarchy (in alphabetical order)
...................................
neorv32_top.vhd - NEORV32 PROCESSOR/SOC TOP ENTITY
@ -199,7 +199,7 @@ neorv32_top.vhd - NEORV32 PROCESSOR/SOC TOP ENTITY
│└neorv32_cpu_regfile.vhd - Data register file
├neorv32_boot_rom.vhd - Bootloader ROM
│└neorv32_bootloader_image.vhd - Bootloader ROM memory image
│└neorv32_bootloader_image.vhd - Bootloader ROM memory image (package)
├neorv32_bus.vhd - SoC bus infrastructure modules
├neorv32_cache.vhd - Generic cache module
├neorv32_cfs.vhd - Custom functions subsystem
@ -214,7 +214,7 @@ neorv32_top.vhd - NEORV32 PROCESSOR/SOC TOP ENTITY
├neorv32_gpio.vhd - General purpose input/output port unit
├neorv32_gptmr.vhd - General purpose 32-bit timer
├neorv32_imem.vhd - Generic processor-internal instruction memory
│└neorv32_application_image.vhd - IMEM application initialization image
│└neorv32_application_image.vhd - IMEM application initialization image (package)
├neorv32_mtime.vhd - Machine system timer
├neorv32_neoled.vhd - NeoPixel (TM) compatible smart LED interface
├neorv32_onewire.vhd - One-Wire serial interface controller
@ -284,7 +284,7 @@ puts $file_list
.File-List Usage Examples
[TIP]
The provided file-list files are used by the GHDL-based simple simulation setup (`sim/tb_simple/ghdl.setup.sh`) as
The provided file-list files are used by the GHDL-based simple simulation setup (`sim/ghdl.setup.sh`) as
well as by the Vivado IP packager script (`rtl/system_integration/neorv32_vivado_ip.tcl`).

View file

@ -4,14 +4,14 @@
[discrete]
==== Why did you make this?
Processor and CPU architecture designs are fascinating things: they are the magic frontier where software meets hardware.
This project started as something like a _journey_ into this magic realm to understand how things actually work
down on this very low level and evolved over time to a capable system on chip.
For me, processor and CPU architecture designs are fascinating things: they are the magic frontier where software meets hardware.
This project started as something like a _journey_ into this realm to understand how things actually work
down on the very low level and evolved over time to a quite capable system-on-chip.
But there is more: when I started to dive into the emerging RISC-V ecosystem I felt overwhelmed by the complexity.
When I started to dive into the emerging RISC-V ecosystem I felt overwhelmed by the complexity.
As a beginner it is hard to get an overview - especially when you want to setup a minimal platform to tinker with...
Which core to use? How to get the right toolchain? What features do I need? How does booting work? How do I
create an actual executable? How to get that into the hardware? How to customize things? **_Where to start???_**
create an actual executable? How to get that into the hardware? How to customize things? _Where to start???_
This project aims to provide a _simple to understand_ and _easy to use_ yet _powerful_ and _flexible_ platform
that targets FPGA and RISC-V beginners as well as advanced users.
@ -20,15 +20,16 @@ that targets FPGA and RISC-V beginners as well as advanced users.
[discrete]
==== Why a _soft-core_ processor?
As a matter of fact soft-core processors _cannot_ compete with discrete (like FPGA hard-macro) processors in terms
of performance, energy efficiency and size. But they do fill a niche in FPGA design space: for example, soft-core
processors allow to implement the _control flow part_ of certain applications (e.g. communication protocol handling)
As a matter of fact soft-core processors _cannot_ compete with discrete (ASIC) processors in terms
of performance, energy efficiency and size. But they do fill a niche in the design space: for example, soft-core
processors allow to implement the _control flow part_ of certain applications (like communication protocol handling)
using software like plain C. This provides high flexibility as software can be easily changed, re-compiled and
re-uploaded again.
Furthermore, the concept of flexibility applies to all aspects of a soft-core processor. The user can add
_exactly_ the features that are required by the application: additional memories, custom interfaces, specialized
co-processors and even user-defined instructions.
co-processors and even user-defined instructions. These application-specific optimization capabilities compensate
for many of the limitations of soft-core processors.
[discrete]
@ -43,80 +44,76 @@ ____
Open-source is a great thing!
While open-source has already become quite popular in _software_, hardware-focused projects still need to catch up.
Admittedly, there has been quite a development, but mainly in terms of _platforms_ and _applications_ (so
schematics, PCBs, etc.). Although processors and CPUs are the heart of almost every digital system, having a true
open-source silicon is still a rarity. RISC-V aims to change that - and even it is _just one approach_, it helps paving
the road for future development.
Although processors and CPUs are the heart of almost every digital system, having a true open-source platform is still
a rarity. RISC-V aims to change that - and even it is _just one approach_, it helps paving the road for future development.
Furthermore, I highly appreciate the community aspect of RISC-V. The ISA and everything beyond is developed in direct
contact with the community: this includes businesses and professionals but also hobbyist, amateurs and people
that are just curious. Everyone can join discussions and contribute to RISC-V in their very own way.
contact with the community: this includes businesses and professionals but also hobbyist, amateurs and enthusiasts.
Everyone can join discussions and contribute to RISC-V in their very own way.
Finally, I really like the RISC-V ISA itself. It aims to be a clean, orthogonal and "intuitive" ISA that
resembles with the basic concepts of _RISC_: simple yet effective.
resembles with the basic concepts of RISC: _simple yet effective_.
[discrete]
==== Yet another RISC-V core? What makes it special?
The NEORV32 is not based on another RISC-V core. It was build entirely from ground up (just following the official
ISA specs). The project does not intend to replace certain RISC-V cores or
just beat existing ones like https://github.com/SpinalHDL/VexRiscv[VexRISC] in terms of performance or
https://github.com/olofk/serv[SERV] in terms of size. It was build having a different design goal in mind.
The NEORV32 is not based on another (RISC-V) core. It was build entirely from ground up just following the official
ISA specs. The project does not intend to replace certain RISC-V cores or beat existing ones in terms of _performance_
or _size_. It was build having a different design goal in mind.
The project aims to provide _another option_ in the RISC-V / soft-core design space with a different performance
vs. size trade-off and a different focus: _embrace_ concepts like documentation, platform-independence / portability,
RISC-V compatibility, _extensibility & customization_ and _ease of use_ (see the <<_project_key_features>> below).
vs. size trade-off and a different focus: embrace concepts like documentation, platform-independence / portability,
RISC-V compatibility, extensibility & customization and - last but not least - ease of use.
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 of memory-mapped
devices. Precise exceptions allow a defined and fully-synchronized state of the CPU at every time an in every situation.
To summarize, this project pursues the following objectives (in rough order of importance):
[start=1]
. RISC-V-compliance and -compatibility
. Functionality and features
. Extensibility
. Safety and security
. Minimal area
. Short critical paths, high operating clock
. Simplicity / easy to understand
. Low-power design
. High overall performance
[discrete]
==== A multi-cycle architecture?!
Most mainstream CPUs out there are pipelined architectures to increase throughput. In contrast, most CPUs used for
teaching are single-cycle designs since they are probably the most easiest to understand. But what about the
multi-cycle architectures?
The primary goal of many mainstream CPUs is pure performance. Deep pipelines and out-of-order execution are some concepts
to boost performance, while also increasing complexity. In contrast, most CPUs used for teaching are single-cycle designs
since they are probably the most easiest to understand. But what about something in-between?
In terms of energy, throughput, area and maximal clock frequency multi-cycle architectures are somewhere in between
In terms of energy, throughput, area and maximal clock frequency, multi-cycle architectures are somewhere in between
single-cycle and fully-pipelined designs: they provide higher throughput and clock speed when compared to their
single-cycle counterparts while having less hardware complexity (= area) then a fully-pipelined designs. I decided to
use the multi-cycle approach because of the following reasons:
single-cycle counterparts while having less hardware complexity (= area) and thus, less performance, then a fully-pipelined
designs. So I decided to use the multi-cycle-approach because of the following reasons:
* Multi-cycle architecture are quite small! There is no need for pipeline hazard detection and resolution logic
(e.g. forwarding). Furthermore, you can "re-use" parts of the core to do several tasks (e.g. the ALU is used for the
actual data processing, but also for address generation, branch condition check and branch target computation).
* Multi-cycle architectures are quite small! There is no need for pipeline hazard detection/resolution logic
(e.g. forwarding). Furthermore, you can "re-use" parts of the core to do several tasks (e.g. the ALU is used for
actual data processing and also for address generation, branch condition check and branch target computation).
* Single-cycle architectures require memories that can be read asynchronously - a thing that is not feasible to implement
in real world applications (i.e. FPGA block RAM is entirely synchronous). Furthermore, such design usually have a very
in real-world applications (i.e. FPGA block RAM is entirely synchronous). Furthermore, such designs usually have a very
long critical path tremendously reducing maximal operating frequency.
* Pipelined designs increase performance by having several instruction "in fly" at the same time. But this also means
there is some kind of "out-of-order" behavior: if an instruction at the end of the pipeline causes an exception
all the instructions in earlier stages have to be invalidated. Potential architecture state changes have to be made _undone_
requiring additional (exception-handling) logic. In a multi-cycle architecture this situation cannot occur because only a
single instruction is "in fly" at a time.
all the instructions in earlier stages have to be invalidated. Potential architectural state changes have to be made _undone_
requiring additional logic (Spectre and Meltdown...). In a multi-cycle architecture this situation cannot occur since only a
single instruction is being processed ("in-fly") at a time.
* Having only a single instruction in fly does not only reduce hardware costs, it also simplifies
simulation/verification/debugging, state preservation/restoring during exceptions and extensibility (no need to care
about pipeline hazards) - but of course at the cost of reduced throughput.
To counteract the loss of performance implied by a _pure_ multi-cycle architecture, the NEORV32 CPU uses a _mixed_
approach: instruction fetch (front-end) and instruction execution (back-end) are de-coupled to operate independently
approach: instruction-fetch (front-end) and instruction-execution (back-end) are de-coupled to operate independently
of each other. Data is interchanged via a queue building a simple 2-stage pipeline. Each "pipeline" stage in terms is
implemented as multi-cycle architecture to simplify the hardware and to provide _precise_ state control (e.g. during
exceptions).
[discrete]
==== Design Goals
[start=1]
. RISC-V-compliance and -compatibility
. Functionality and features
. Safety and security
. Minimal area
. Short critical paths, high operating clock
. Low-power design
. High overall performance
. Simplicity / easy to understand
implemented as multi-cycle architecture to simplify the hardware and to provide _precise_ state control (for example
during exceptions).

View file

@ -79,7 +79,7 @@ clock domain also using registers. However, for ASIC implementations it is recom
to all inputs and output so the synthesis tool can insert an explicit IO (boundary) scan chain.
.NEORV32 Processor Signal List
[cols="<3,^1,^1,^1,<8"]
[cols="<4,^2,^2,^2,<7"]
[options="header",grid="rows"]
|=======================
| Name | Width | Direction | Default | Description
@ -202,12 +202,15 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt
[options="header",grid="rows"]
|=======================
| Name | Type | Default | Description
4+^| **General**
4+^| **<<_processor_clocking>>**
| `CLOCK_FREQUENCY` | natural | 0 | The clock frequency of the processor's `clk_i` input port in Hertz (Hz).
| `CLOCK_GATING_EN` | boolean | false | Enable clock gating when CPU is in sleep mode (see sections <<_sleep_mode>> and <<_processor_clocking>>).
| `INT_BOOTLOADER_EN` | boolean | false | Implement the processor-internal <<_bootloader_rom_bootrom>>, pre-initialized with the default <<_bootloader>> image.
| `HART_ID` | suv(31:0) | 0x00000000 | The hart thread ID of the CPU (passed to <<_mhartid>> CSR).
| `JEDEC_ID` | suv(10:0) | 0b00000000000 | JEDEC ID; continuation codes plus vendor ID (passed to <<_mvendorid>> CSR and to the <<_debug_transport_module_dtm>>).
4+^| **Core Identification**
| `HART_ID` | suv(31:0) | x"00000000" | The hart thread ID of the CPU (passed to <<_mhartid>> CSR).
| `JEDEC_ID` | suv(10:0) | "00000000000" | JEDEC ID; continuation codes plus vendor ID (passed to <<_mvendorid>> CSR and to the <<_debug_transport_module_dtm>>).
4+^| **<<_boot_configuration>>**
| `BOOT_MODE_SELECT` | natural | 0 | Boot mode select; see <<_boot_configuration>>.
| `BOOT_ADDR_CUSTOM` | suv(31:0) | x"00000000" | Custom CPU boot address (available if `BOOT_MODE_SELECT` = 1).
4+^| **<<_on_chip_debugger_ocd>>**
| `OCD_EN` | boolean | false | Implement the on-chip debugger and the CPU debug mode.
| `OCD_AUTHENTICATION` | boolean | false | Implement <<_debug_authentication>> module.
@ -295,7 +298,7 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt
| `IO_TRNG_EN` | boolean | false | Implement the <<_true_random_number_generator_trng>>.
| `IO_TRNG_FIFO` | natural | 1 | Depth of the TRNG data FIFO. Has to be a power of two, min 1, max 32768.
| `IO_CFS_EN` | boolean | false | Implement the <<_custom_functions_subsystem_cfs>>.
| `IO_CFS_CONFIG` | suv(31:0) | 0x00000000 | "Conduit" generic to pass user-defined flags to the <<_custom_functions_subsystem_cfs>>.
| `IO_CFS_CONFIG` | suv(31:0) | x"00000000" | "Conduit" generic to pass user-defined flags to the <<_custom_functions_subsystem_cfs>>.
| `IO_CFS_IN_SIZE` | natural | 32 | Size of the <<_custom_functions_subsystem_cfs>> input signal conduit (`cfs_in_i`).
| `IO_CFS_OUT_SIZE` | natural | 32 | Size of the <<_custom_functions_subsystem_cfs>> output signal conduit (`cfs_out_o`).
| `IO_NEOLED_EN` | boolean | false | Implement the <<_smart_led_interface_neoled>>.
@ -564,7 +567,7 @@ monitor starts an internal timer. The accessed module has to respond ("ACK") to
.Internal Bus Timeout Configuration
[source,vhdl]
----
constant bus_timeout_c : natural := 15;
constant bus_timeout_c : natural := 15;
----
This constant defines the _maximum_ number of cycles after which a non-responding bus request (i.e. no `ack`
@ -657,11 +660,11 @@ package file (`rtl/core/neorv323_package.vhd`).
.Exemplary Cut-Out from the IO Address Map
[source,vhdl]
----
-- IO Address Map --
constant iodev_size_c : natural := 256; -- size of a single IO device (bytes)
constant base_io_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffeb00";
constant base_io_slink_c : std_ulogic_vector(31 downto 0) := x"ffffec00";
constant base_io_dma_c : std_ulogic_vector(31 downto 0) := x"ffffed00";
-- IO Address Map --
constant iodev_size_c : natural := 256; -- size of a single IO device (bytes)
constant base_io_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffeb00";
constant base_io_slink_c : std_ulogic_vector(31 downto 0) := x"ffffec00";
constant base_io_dma_c : std_ulogic_vector(31 downto 0) := x"ffffed00";
----
.IO Access Latency
@ -671,47 +674,67 @@ buffers the address bus. Hence, accesses to the processor-internal IO region req
to complete.
<<<
// ####################################################################################################################
:sectnums:
==== Boot Configuration
=== Boot Configuration
Due to the flexible memory configuration, the NEORV32 Processor provides several different boot scenarios.
The following section illustrates the two most common boot scenarios.
The NEORV32 processor provides some pre-defined boot configurations to adjust system start-up to
the requirements of the application. The actual boot configuration is defined by the `BOOT_MODE_SELECT`
generic (see <<_processor_top_entity_generics>>).
.NEORV32 Boot Configurations
image::neorv32_boot_configurations.png[800]
[cols="^2,^2,^2,<6"]
[options="header",grid="rows"]
|=======================
| `BOOT_MODE_SELECT` | Name | Boot address | Description
| 0 (default) | Bootloader | Base of internal BOOTROM | Implement the processor-internal <<_bootloader_rom_bootrom>> as pre-initialized ROM and boot from there.
| 1 | Custom Address | `BOOT_ADDR_CUSTOM` generic | Start booting at user-defined address (`BOOT_ADDR_CUSTOM` top generic).
| 2 | IMEM Image | Base of internal IMEM | Implement the processor-internal <<_instruction_memory_imem>> as pre-initialized ROM and boot from there.
|=======================
There are two general boot scenarios: _Indirect Boot_ (1a and 1b) and _Direct Boot_ (2a and 2b) configured via the
`INT_BOOTLOADER_EN` generic. If this generic is `true` the _indirect boot scenario_ is used. This is also the
default boot configuration of the processor. If `INT_BOOTLOADER_EN` is `*false` the _direct boot scenario_ is used.
:sectnums!:
===== Indirect Boot
:sectnums:
==== Booting via Bootloader
The indirect_boot scenarios **1a** and **1b** are based on 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 copying it to the beginning of the _instruction address space_ so the CPU can execute it.
This is the most common and thus, the default boot configuration. When selected, the processor-internal
<<_bootloader_rom_bootrom>> is enabled. This ROM contains the executable image (`rtl/core/neorv32_bootloader_image.vhd`)
of the default NEORV32 <<_bootloader>> that will be executed right after reset. The bootloader provides an interactive
user console for executable upload as well as an automatic boot-configuration targeting external (SPI) memories.
Boot scenario **1a** uses the processor-internal IMEM. This scenario implements the internal <<_instruction_memory_imem>>
as non-initialized RAM so the bootloader can copy the actual executable to it.
If the processor-internal <<_instruction_memory_imem>> is enabled it will be implemented as _blank_ RAM.
Boot scenario **1b** uses a processor-external IMEM 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 copy the executable to the
processor-external memory. Hence, the external memory has to be implemented as RAM.
:sectnums!:
===== Direct Boot
:sectnums:
==== Boot from Custom Address
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 beginning of the instruction address space after reset. An application-specific
"pre-initialization" mechanism is required in order to provide an executable inside the memory.
This is the most flexible boot configuration as it allows the user to specify a custom boot address via the
`BOOT_ADDR_CUSTOM` generic. Note that this address has to be aligned to 4-byte boundary. The processor will
start executing from the defined address right after reset. For example, this boot configuration ca be used to
execute a _custom bootloader_ from a memory that is attached via the <<_processor_external_bus_interface_xbus>>.
Boot scenario **2a** uses the processor-internal IMEM implemented as _read-only memory_ in this scenario.
It is pre-initialized (by the bitstream) with the actual application executable during synthesis.
The <<_bootloader_rom_bootrom>> is not enabled / implement at all.
If the processor-internal <<_instruction_memory_imem>> is enabled it will be implemented as _blank_ RAM.
In contrast, boot scenario **2b** uses a processor-external IMEM. In this scenario the system designer is responsible for
providing an initialized external memory that contains the actual application to be executed.
:sectnums:
==== Boot IMEM Image
This configuration will implement the <<_instruction_memory_imem>> as _pre-initialized read-only memory_ (ROM).
The ROM is initialized during synthesis with the according application image file (`rtl/core/neorv32_application_image.vhd`).
After reset, the CPU will directly start executing this image. Since the IMEM is implemented as ROM, the executable cannot
be altered at runtime at all.
The <<_bootloader_rom_bootrom>> is not enabled / implement at all.
.Internal IMEM is Required
[IMPORTANT]
This boot configuration requires the IMEM to be enabled (`MEM_INT_IMEM_EN` = true).
.Simulation Setup
[TIP]
This boot configuration is handy for simulations as the application software is executed right away without the
need for an explicit initialization / executable upload.
<<<

View file

@ -5,28 +5,24 @@
[cols="<3,<3,<4"]
[frame="topbot",grid="none"]
|=======================
| Hardware source files: | neorv32_boot_rom.vhd |
| Software driver files: | none |
| Top entity ports: | none |
| Configuration generics: | `INT_BOOTLOADER_EN` | implement processor-internal bootloader when `true`
| CPU interrupts: | none |
| Hardware source files: | neorv32_boot_rom.vhd | default platform-agnostic bootloader ROM
| | neorv32_bootloader_image.vhd | initialization image (a VHDL package)
| Software driver files: | none | _implicitly used_
| Top entity ports: | none |
| Configuration generics: | `BOOT_MODE_SELECT` | implement BOOTROM when `BOOT_MODE_SELECT` = 0; see <<_boot_configuration>>
| CPU interrupts: | none |
| Access restrictions: 2+| privileged access only, read-only
|=======================
**Overview**
This boot ROM module provides a read-only memory that contain the executable image of the default NEORV32
<<_bootloader>>. If the internal bootloader is enabled via the `INT_BOOTLOADER_EN` generic the CPU's boot address
is automatically set to the beginning of the bootloader ROM. See sections <<_address_space>> and
<<_boot_configuration>> for more information regarding the processor's different boot scenarios.
.Memory Size
[IMPORTANT]
If the configured boot ROM size is **not** a power of two the actual memory size will be auto-adjusted to
the next power of two (e.g. configuring a memory size of 6kB will result in a physical memory size of 8kB).
The boot ROM contains the executable image of the default NEORV32 <<_bootloader>>. When the
<<_boot_configuration>> is set to _bootloader_ mode (0) via the `BOOT_MODE_SELECT` generic, the
boot ROM is automatically enabled and the CPU boot address is automatically adjusted to the
base address of the boot ROM.
.Bootloader Image
[IMPORTANT]
The boot ROM is initialized during synthesis with the default bootloader image
(`rtl/core/neorv32_bootloader_image.vhd`).
(`rtl/core/neorv32_bootloader_image.vhd`). Note that the BOOTROM size is constrained to 4kB.

View file

@ -36,7 +36,7 @@ physical memory size of 64kB).
.Legacy HDL Style
[TIP]
If synthesis fails to infer block RAM for the DMEM, turn on the `alternaitve_style_en_c` option inside
If synthesis fails to infer block RAM for the DMEM, turn on the `alt_style_c` option inside
the memory's VHDL source file. When enabled, a different HDL style is used to describe the memory core.
.Execute from RAM

View file

@ -5,13 +5,14 @@
[cols="<3,<3,<4"]
[frame="topbot",grid="none"]
|=======================
| Hardware source files: | neorv32_imem.vhd | default platform-agnostic instruction memory
| Software driver files: | none | _implicitly used_
| Top entity ports: | none |
| Configuration generics: | `MEM_INT_IMEM_EN` | implement processor-internal IMEM when `true`
| | `MEM_INT_IMEM_SIZE` | IMEM size in bytes (use a power of 2)
| | `INT_BOOTLOADER_EN` | use internal bootloader when `true` (implements IMEM as _uninitialized_ RAM, otherwise the IMEM is implemented an _pre-intialized_ ROM)
| CPU interrupts: | none |
| Hardware source files: | neorv32_imem.vhd | default platform-agnostic instruction memory (RAM or ROM)
| | neorv32_application_image.vhd | initialization image (a VHDL package)
| Software driver files: | none | _implicitly used_
| Top entity ports: | none |
| Configuration generics: | `MEM_INT_IMEM_EN` | implement processor-internal IMEM when `true`
| | `MEM_INT_IMEM_SIZE` | IMEM size in bytes (use a power of 2)
| | `BOOT_MODE_SELECT` | implement IMEM as ROM when `BOOT_MODE_SELECT` = 2; see <<_boot_configuration>>
| CPU interrupts: | none |
| Access restrictions: 2+| none / read-only if `INT_BOOTLOADER_EN = true`
|=======================
@ -20,19 +21,19 @@
Implementation of the processor-internal instruction memory is enabled by the processor's
`MEM_INT_IMEM_EN` generic. The total memory size in bytes is defined via the `MEM_INT_IMEM_SIZE` generic.
Note that this size should be a power of two to optimize physical implementation. If the IMEM is implemented,
it is mapped to base address `0x00000000` by default (see section <<_address_space>>).
Note that this size should be a power of two to optimize physical implementation. If enabled,
the IMEM is mapped to base address `0x00000000` (see section <<_address_space>>).
By default the IMEM is implemented as true RAM so the content can be modified during run time. This is
required when using the bootloader (or the on-chip debugger) so it can update the content of the IMEM at
any time. If this feature is not required the IMEM can be implemented as _pre-intialized_ ROM so that the
application code permanently resides in memory. This is automatically implemented when the
processor-internal bootloader is disabled (`INT_BOOTLOADER_EN` = `false`).
required when using the <<_bootloader>> (or the <<_on_chip_debugger>>) so it can update the content of the IMEM at
any time.
When the IMEM is implemented as ROM, it will be initialized during synthesis with the actual application program
image. The compiler toolchain provides an option to generate and override the default VHDL initialization file
`rtl/core/neorv32_application_image.vhd`, which is automatically inserted into the IMEM. If the IMEM is implemented
as RAM (default), the memory block will **not be initialized at all**.
Alternatively, the IMEM can be implemented as **pre-initialized read-only memory (ROM)**, so the processor can
directly boot from it after reset. This option is configured via the `BOOT_MODE_SELECT` generic. See section
<<_boot_configuration>> for more information. The initialization image is embedded into the bitstream during synthesis.
The software framework provides an option to generate and override the default VHDL initialization file
`rtl/core/neorv32_application_image.vhd`, which is automatically inserted into the IMEM (see <<_makefile_targets>>.
If the IMEM is implemented as RAM (default), the memory block will not be initialized at all.
.Platform-Specific Memory Primitives
[NOTE]
@ -47,9 +48,9 @@ physical memory size of 64kB).
.Legacy HDL Style
[TIP]
If synthesis fails to infer block RAM for the IMEM, turn on the `alternaitve_style_en_c` option inside
If synthesis fails to infer block RAM for the IMEM, turn on the `alt_style_c` option inside
the memory's VHDL source file. When enabled, a different HDL style is used to describe the memory core.
.Read-Only Access
[NOTE]
If the IMEM is implemented as true ROM any write attempt to it will raise a _store access fault_ exception.
If the IMEM is implemented as ROM any write attempt to it will raise a _store access fault_ exception.

View file

@ -62,7 +62,7 @@ Bit fields in this register are set to all-zero if the according memory system i
| `0` | `SYSINFO_MEM_IMEM` | _log2_(internal IMEM size in bytes), via top's `MEM_INT_IMEM_SIZE` generic
| `1` | `SYSINFO_MEM_DMEM` | _log2_(internal DMEM size in bytes), via top's `MEM_INT_DMEM_SIZE` generic
| `2` | - | _reserved_, read as zero
| `3` | - | _reserved_, read as zero
| `3` | `SYSINFO_MEM_BOOT` | boot mode configuration, via top's `BOOT_MODE_SELECT` generic (see <<_boot_configuration>>))
|=======================
@ -73,37 +73,38 @@ Bit fields in this register are set to all-zero if the according memory system i
[options="header",grid="all"]
|=======================
| Bit | Name [C] | Description
| `0` | `SYSINFO_SOC_BOOTLOADER` | set if processor-internal bootloader is implemented (via top's `INT_BOOTLOADER_EN` generic)
| `1` | `SYSINFO_SOC_XBUS` | set if external Wishbone bus interface is implemented (via top's `XBUS_EN` generic)
| `2` | `SYSINFO_SOC_MEM_INT_IMEM` | set if processor-internal DMEM implemented (via top's `MEM_INT_DMEM_EN` generic)
| `3` | `SYSINFO_SOC_MEM_INT_DMEM` | set if processor-internal IMEM is implemented (via top's `MEM_INT_IMEM_EN` generic)
| `4` | `SYSINFO_SOC_OCD` | set if on-chip debugger is implemented (via top's `OCD_EN` generic)
| `5` | `SYSINFO_SOC_ICACHE` | set if processor-internal instruction cache is implemented (via top's `ICACHE_EN` generic)
| `6` | `SYSINFO_SOC_DCACHE` | set if processor-internal data cache is implemented (via top's `DCACHE_EN` generic)
| `7` | `SYSINFO_SOC_CLOCK_GATING` | set if CPU clock gating is implemented (via top's `CLOCK_GATING_EN` generic)
| `8` | `SYSINFO_SOC_XBUS_CACHE` | set if external bus interface cache is implemented (via top's `XBUS_CACHE_EN` generic)
| `9` | `SYSINFO_SOC_XIP` | set if XIP module is implemented (via top's `XIP_EN` generic)
| `10` | `SYSINFO_SOC_XIP_CACHE` | set if XIP cache is implemented (via top's `XIP_CACHE_EN` generic)
| `11` | `SYSINFO_SOC_OCD_AUTH` | set if on-chip debugger authentication is implemented (via top's `OCD_AUTHENTICATION` generic)
| `13:12` | - | _reserved_, read as zero
| `14` | `SYSINFO_SOC_IO_DMA` | set if direct memory access controller is implemented (via top's `IO_DMA_EN` generic)
| `15` | `SYSINFO_SOC_IO_GPIO` | set if GPIO is implemented (via top's `IO_GPIO_EN` generic)
| `16` | `SYSINFO_SOC_IO_MTIME` | set if MTIME is implemented (via top's `IO_MTIME_EN` generic)
| `17` | `SYSINFO_SOC_IO_UART0` | set if primary UART0 is implemented (via top's `IO_UART0_EN` generic)
| `18` | `SYSINFO_SOC_IO_SPI` | set if SPI is implemented (via top's `IO_SPI_EN` generic)
| `19` | `SYSINFO_SOC_IO_TWI` | set if TWI is implemented (via top's `IO_TWI_EN` generic)
| `20` | `SYSINFO_SOC_IO_PWM` | set if PWM is implemented (via top's `IO_PWM_NUM_CH` generic)
| `21` | `SYSINFO_SOC_IO_WDT` | set if WDT is implemented (via top's `IO_WDT_EN` generic)
| `22` | `SYSINFO_SOC_IO_CFS` | set if custom functions subsystem is implemented (via top's `IO_CFS_EN` generic)
| `23` | `SYSINFO_SOC_IO_TRNG` | set if TRNG is implemented (via top's `IO_TRNG_EN` generic)
| `24` | `SYSINFO_SOC_IO_SDI` | set if SDI is implemented (via top's `IO_SDI_EN` generic)
| `25` | `SYSINFO_SOC_IO_UART1` | set if secondary UART1 is implemented (via top's `IO_UART1_EN` generic)
| `26` | `SYSINFO_SOC_IO_NEOLED` | set if NEOLED is implemented (via top's `IO_NEOLED_EN` generic)
| `27` | `SYSINFO_SOC_IO_XIRQ` | set if XIRQ is implemented (via top's `XIRQ_NUM_CH` generic)
| `28` | `SYSINFO_SOC_IO_GPTMR` | set if GPTMR is implemented (via top's `IO_GPTMR_EN` generic)
| `29` | `SYSINFO_SOC_IO_SLINK` | set if stream link interface is implemented (via top's `IO_SLINK_EN` generic)
| `30` | `SYSINFO_SOC_IO_ONEWIRE` | set if ONEWIRE interface is implemented (via top's `IO_ONEWIRE_EN` generic)
| `31` | `SYSINFO_SOC_IO_CRC` | set if cyclic redundancy check unit is implemented (via top's `IO_CRC_EN` generic)
| `0` | `SYSINFO_SOC_BOOTLOADER` | set if processor-internal bootloader is implemented (via top's `BOOT_MODE_SELECT` generic; see <<_boot_configuration>>)
| `1` | `SYSINFO_SOC_XBUS` | set if external Wishbone bus interface is implemented (via top's `XBUS_EN` generic)
| `2` | `SYSINFO_SOC_MEM_INT_IMEM` | set if processor-internal DMEM is implemented (via top's `MEM_INT_IMEM_EN` generic)
| `3` | `SYSINFO_SOC_MEM_INT_DMEM` | set if processor-internal IMEM is implemented (via top's `MEM_INT_DMEM_EN` generic)
| `4` | `SYSINFO_SOC_OCD` | set if on-chip debugger is implemented (via top's `OCD_EN` generic)
| `5` | `SYSINFO_SOC_ICACHE` | set if processor-internal instruction cache is implemented (via top's `ICACHE_EN` generic)
| `6` | `SYSINFO_SOC_DCACHE` | set if processor-internal data cache is implemented (via top's `DCACHE_EN` generic)
| `7` | `SYSINFO_SOC_CLOCK_GATING` | set if CPU clock gating is implemented (via top's `CLOCK_GATING_EN` generic)
| `8` | `SYSINFO_SOC_XBUS_CACHE` | set if external bus interface cache is implemented (via top's `XBUS_CACHE_EN` generic)
| `9` | `SYSINFO_SOC_XIP` | set if XIP module is implemented (via top's `XIP_EN` generic)
| `10` | `SYSINFO_SOC_XIP_CACHE` | set if XIP cache is implemented (via top's `XIP_CACHE_EN` generic)
| `11` | `SYSINFO_SOC_OCD_AUTH` | set if on-chip debugger authentication is implemented (via top's `OCD_AUTHENTICATION` generic)
| `12` | `SYSINFO_SOC_IMEM_ROM` | set if processor-internal IMEM is implemented as pre-initialized ROM (via top's `BOOT_MODE_SELECT` generic; see <<_boot_configuration>>)
| `13` | - | _reserved_, read as zero
| `14` | `SYSINFO_SOC_IO_DMA` | set if direct memory access controller is implemented (via top's `IO_DMA_EN` generic)
| `15` | `SYSINFO_SOC_IO_GPIO` | set if GPIO is implemented (via top's `IO_GPIO_EN` generic)
| `16` | `SYSINFO_SOC_IO_MTIME` | set if MTIME is implemented (via top's `IO_MTIME_EN` generic)
| `17` | `SYSINFO_SOC_IO_UART0` | set if primary UART0 is implemented (via top's `IO_UART0_EN` generic)
| `18` | `SYSINFO_SOC_IO_SPI` | set if SPI is implemented (via top's `IO_SPI_EN` generic)
| `19` | `SYSINFO_SOC_IO_TWI` | set if TWI is implemented (via top's `IO_TWI_EN` generic)
| `20` | `SYSINFO_SOC_IO_PWM` | set if PWM is implemented (via top's `IO_PWM_NUM_CH` generic)
| `21` | `SYSINFO_SOC_IO_WDT` | set if WDT is implemented (via top's `IO_WDT_EN` generic)
| `22` | `SYSINFO_SOC_IO_CFS` | set if custom functions subsystem is implemented (via top's `IO_CFS_EN` generic)
| `23` | `SYSINFO_SOC_IO_TRNG` | set if TRNG is implemented (via top's `IO_TRNG_EN` generic)
| `24` | `SYSINFO_SOC_IO_SDI` | set if SDI is implemented (via top's `IO_SDI_EN` generic)
| `25` | `SYSINFO_SOC_IO_UART1` | set if secondary UART1 is implemented (via top's `IO_UART1_EN` generic)
| `26` | `SYSINFO_SOC_IO_NEOLED` | set if NEOLED is implemented (via top's `IO_NEOLED_EN` generic)
| `27` | `SYSINFO_SOC_IO_XIRQ` | set if XIRQ is implemented (via top's `XIRQ_NUM_CH` generic)
| `28` | `SYSINFO_SOC_IO_GPTMR` | set if GPTMR is implemented (via top's `IO_GPTMR_EN` generic)
| `29` | `SYSINFO_SOC_IO_SLINK` | set if stream link interface is implemented (via top's `IO_SLINK_EN` generic)
| `30` | `SYSINFO_SOC_IO_ONEWIRE` | set if ONEWIRE interface is implemented (via top's `IO_ONEWIRE_EN` generic)
| `31` | `SYSINFO_SOC_IO_CRC` | set if cyclic redundancy check unit is implemented (via top's `IO_CRC_EN` generic)
|=======================

View file

@ -44,9 +44,8 @@ see section <<_address_space>>) are **redirected** to the external bus interface
.AXI4-Lite Interface Bridge
[TIP]
A processor top entity with an AXI4-Lite-compatible bus interface can be found in `rtl/system_inegration`.
More information regarding this alternate top entity can be found in in the user guide:
https://stnolting.github.io/neorv32/ug/#_packaging_the_processor_as_vivado_ip_block
A simple bridge that converts the processor's XBUS into an AXI4-lite-compatible host interface can
be found in in `rtl/system_inegration` (`xbus2axi4lite_bridge.vhd`).
.AHB3-Lite Interface Bridge
[TIP]

View file

@ -28,22 +28,17 @@ The XIRQ provides up to 32 external interrupt channels configured via the `XIRQ_
`xirq_i` input signal vector represents one interrupt channel. If less than 32 channels are configured, only the
LSB-aligned channels are used while the remaining ones are left unconnected internally.
The external interrupt controller features five interface registers:
The external interrupt controller features four interface registers:
[start=1]
. external interrupt channel enable (`EIE`)
. external interrupt channel pending (`EIP`)
. external interrupt source (`ESC`)
. trigger type configuration (`TTYP`)
. trigger polarity configuration (`TPOL`)
[TIP]
From a functional point of view, the `EIE`, `EIP` and `ESC` registers follow the behavior
of the RISC-V <<_mie>>, <<_mip>> and <<_mcause>> CSRs.
The actual interrupt trigger type can be configured individually for each channel using the `TTYP` and `TPOL`
registers. `TTYP` defines the actual trigger type (level-triggered or edge-triggered), while `TPOL` defines
the trigger's polarity (low-level/falling-edge or high-level_/rising-edge). The position of each bit in these
the trigger's polarity (low-level/falling-edge or high-level/rising-edge). The position of each bit in these
registers corresponds the according XIRQ channel.
.XIRQ Trigger Configuration
@ -57,24 +52,19 @@ registers corresponds the according XIRQ channel.
| `1` | `1` | rising-edge
|=======================
When the configured trigger of an interrupt channel fires the according interrupt channel becomes _pending_
which is indicated by the according channel bit being set in the `EIP` register. This pending interrupt can
be manually cleared at any time by writing zero to the according `EIP` bit.
Each interrupt channel can be enabled or disabled individually using the `EIE` register. If the trigger of a
disabled channel fires the interrupt request is entirely ignored.
A pending interrupt can only generate a CPU interrupt if the according channel is enabled by the `EIE`
register. Once triggered, disabled channels that **were already triggered** remain pending until explicitly
(= manually) cleared. The channels are prioritized in a static order, i.e. channel 0 (`xirq_i(0)`) has the
highest priority and channel 31 (`xirq_i(31)`) has the lowest priority. If **any** pending interrupt channel is
also enabled, an interrupt request is sent to the CPU.
If the configured trigger of an _enabled_ channels fires, the according interrupt request is buffered internally
and an interrupt request is sent to the CPU. If more than one trigger fires at one a prioritization is used:
the channels are prioritized in a static order, i.e. channel 0 (`xirq_i(0)`) has the highest priority and channel
31 (`xirq_i(31)`) has the lowest priority.
The CPU can determine the most prioritized external interrupt request either by checking the bits in the `EIP`
register or by reading the interrupt source register `ESC`. This register provides a 5-bit wide ID (0..31)
identifying the currently firing external interrupt source channel. Writing _any_ value to this register will
acknowledge and clear the _current_ CPU interrupt (so the XIRQ controller can issue a new CPU interrupt).
In order to acknowledge an XIRQ interrupt, the interrupt handler has to...
* clear the pending XIRQ channel by clearing the according `EIP` bit
* writing _any_ value to `ESC` to acknowledge the XIRQ CPU interrupt
The CPU can determine the most prioritized external interrupt request by reading the interrupt source register `ESC`.
This register provides a 5-bit wide ID (0..31) identifying the currently firing external interrupt source channel as
well as a single bit (the MSB) that
Writing _any_ value to this register will acknowledge and clear the _current_ CPU interrupt (so the XIRQ controller
can issue a new CPU interrupt).
**Register Map**
@ -85,11 +75,9 @@ In order to acknowledge an XIRQ interrupt, the interrupt handler has to...
|=======================
| Address | Name [C] | Bit(s) | R/W | Description
| `0xfffff300` | `EIE` | `31:0` | r/w | External interrupt enable register (one bit per channel, LSB-aligned)
| `0xfffff304` | `EIP` | `31:0` | r/w | External interrupt pending register (one bit per channel, LSB-aligned); writing 0 to a bit clears the according pending interrupt
| `0xfffff308` | `ESC` | `4:0` | r/w | Interrupt source ID (0..31) of firing IRQ (prioritized!); writing _any_ value will acknowledge the current XIRQ CPU interrupt
| `0xfffff30c` | `TTYP` | `31:0` | r/w | Trigger type select (`0` = level trigger, `1` = edge trigger); each bit corresponds to the according channel number
| `0xfffff310` | `TPOL` | `31:0` | r/w | Trigger polarity select (`0` = low-level/falling-edge, `1` = high-level/rising-edge); each bit corresponds to the according channel number
| `0xfffff314` | - | `31:0` | r/- | _reserved_, read as zero
| `0xfffff318` | - | `31:0` | r/- | _reserved_, read as zero
| `0xfffff31c` | - | `31:0` | r/- | _reserved_, read as zero
.3+^| `0xfffff304` .3+<| `ESC` ^| `31` ^| r/c <| XIRQ interrupt when set; write any value to this register to acknowledge the current XIRQ interrupt
^| `30:5` ^| r/- <| _reserved_, read as zero
^| `4:0` ^| r/c <| Interrupt source ID (0..31) of firing IRQ (prioritized!)
| `0xfffff308` | `TTYP` | `31:0` | r/w | Trigger type select (`0` = level trigger, `1` = edge trigger); each bit corresponds to the according channel number
| `0xfffff30c` | `TPOL` | `31:0` | r/w | Trigger polarity select (`0` = low-level/falling-edge, `1` = high-level/rising-edge); each bit corresponds to the according channel number
|=======================

View file

@ -1,34 +1,20 @@
:sectnums:
== Software Framework
The NEORV32 project comes with a complete software ecosystem called the "software framework", which
The NEORV32 project comes with a complete software ecosystem called the "software framework" which
is based on the C-language RISC-V GCC port and consists of the following parts:
* <<_compiler_toolchain>>
* <<_core_libraries>>
* <<_system_view_description_file_svd>>
* <<_application_makefile>>
* <<_executable_image_format>>
** <<_linker_script>>
** <<_ram_layout>>
** <<_c_standard_library>>
** <<_start_up_code_crt0>>
* <<_bootloader>>
* <<_default_compiler_flags>>
* <<_linker_script>>
* <<_c_standard_library>>
* <<_start_up_code_crt0>>
* <<_executable_image_formats>>
* <<_neorv32_runtime_environment>>
A summarizing list of the most important elements of the software framework and their according
files and folders is shown below:
[cols="<5,<5"]
[grid="none"]
|=======================
| Application start-up code | `sw/common/crt0.S`
| Application linker script | `sw/common/neorv32.ld`
| Core hardware driver libraries ("HAL") | `sw/lib/include/` & `sw/lib/source/`
| Central application makefile | `sw/common/common.mk`
| Tool for generating NEORV32 executables | `sw/image_gen/`
| Default bootloader | `sw/bootloader`
| Example programs | `sw/example`
|=======================
* <<_bootloader>>
.Software Documentation
[TIP]
@ -38,26 +24,18 @@ at https://stnolting.github.io/neorv32/sw/files.html.
.Example Programs
[TIP]
A collection of annotated example programs, which show how to use certain CPU functions
and peripheral/IO modules, can be found in `sw/example`.
A collection of annotated example programs illustrating how to use certain CPU functions
and peripheral/IO modules can be found in `sw/example`.
// ####################################################################################################################
:sectnums:
=== Compiler Toolchain
The toolchain for this project is based on the free and open RISC-V GCC-port. You can find the compiler sources and
build instructions on the official RISC-V GNU toolchain GitHub page: https://github.com/riscv/riscv-gnutoolchain.
The NEORV32 implements a 32-bit RISC-V architecture and uses a 32-bit integer and soft-float ABI by default.
Make sure the toolchain / toolchain build is configured accordingly.
* `MARCH=rv32i`
* `MABI=ilp32`
* `RISCV_PREFIX=riscv32-unknown-elf-`
These default configurations can be overridden at any times using <<_application_makefile>> variables.
The toolchain for this project is based on the free and open RISC-V GCC-port. You can find the compiler sources and
build instructions in the official RISC-V GNU toolchain GitHub repository: https://github.com/riscv/riscv-gnutoolchain.
.Toolchain Installation
[TIP]
More information regarding the toolchain (building from scratch or downloading prebuilt ones) can be found in the
user guide section https://stnolting.github.io/neorv32/ug/#_software_toolchain_setup[Software Toolchain Setup].
@ -77,6 +55,8 @@ The NEORV32 project provides a set of pre-defined C libraries that allow an easy
#include <neorv32.h> // NEORV32 HAL, core and runtime libraries
----
The NEORV32 HAL consists of the following files.
.NEORV32 Hardware Abstraction Layer File List
[cols="<3,<3,<6"]
[options="header",grid="rows"]
@ -115,14 +95,16 @@ The NEORV32 project provides a set of pre-defined C libraries that allow an easy
.Core Library Documentation
[TIP]
The _doxygen_-based documentation of the software framework including all core libraries is available online at
The Doxygen-based documentation of the software framework including all core libraries is available online at
https://stnolting.github.io/neorv32/sw/files.html.
.CMSIS System View Description File (SVD)
[TIP]
<<<
// ####################################################################################################################
:sectnums:
=== System View Description File (SVD)
A CMSIS-SVD-compatible **System View Description (SVD)** file including all peripherals is available in `sw/svd`.
Together with a third-party plugin the processor's SVD file can be imported right into GDB to allow comfortable
debugging of peripheral/IO devices (see https://github.com/stnolting/neorv32/discussions/656).
<<<
@ -130,29 +112,76 @@ debugging of peripheral/IO devices (see https://github.com/stnolting/neorv32/dis
:sectnums:
=== Application Makefile
Application compilation is based on a single, centralized GNU makefile (`sw/common/common.mk`). Each project in the
`sw/example` folder provides a makefile that just _includes_ this central makefile.
Application compilation is based on a centralized GNU makefile (`sw/common/common.mk`). Each software project
(for example the ones in `sw/example` folder) should provide a local makefile that just includes the central makefile:
```makefile
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk
```
Thus, the functionality of the central makefile (including all targets) becomes available for the project.
The project-local makefile should be used to define all setup-relevant configuration options instead of changing the
central makefile to keep the code base clean. Setting variables in the project-local makefile will override the default
configuration. Most example projects already provide a makefile that list all relevant configuration options.
The following example shows all relevant configuration variables:
```makefile
# Override the default CPU ISA
MARCH = rv32imc_zicsr_zifencei
# Override the default RISC-V GCC prefix
RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Additional sources
APP_SRC += $(wildcard ./*.c)
APP_INC += -I .
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional compiler flags (append to this variable)
#USER_FLAGS += ...
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk
```
.New Project
[TIP]
When creating a new project, copy an existing project folder or at least the makefile to the new project folder.
It is recommended to create new projects also in `sw/example` to keep the file dependencies. However, these
dependencies can be manually configured via makefile variables if the new project is located somewhere else.
[NOTE]
Before the makefile can be used to compile applications, the RISC-V GCC toolchain needs to be installed and
the compiler's `bin` folder has to be added to the system's `PATH` environment variable. More information can be
found in https://stnolting.github.io/neorv32/ug/#_software_toolchain_setup[User Guide: Software Toolchain Setup].
:sectnums:
==== Makefile Targets
Just executing `make` (or executing `make help`) will show the help menu listing all available targets.
Invoking a project-local makefile (executing `make` or `make help`) will show the help menu that lists all
available targets as well as all variable including their _current_ setting.
[source,makefile]
----
$ make
NEORV32 Software Application Makefile
neorv32/sw/example/hello_world$ make
NEORV32 Software Makefile
Find more information at https://github.com/stnolting/neorv32
Targets:
@ -160,35 +189,36 @@ Targets:
help - show this text
check - check toolchain
info - show makefile/toolchain configuration
gdb - run GNU debugging session
gdb - start GNU debugging session
asm - compile and generate <main.asm> assembly listing file for manual debugging
elf - compile and generate <main.elf> ELF file
exe - compile and generate <neorv32_exe.bin> executable image file for upload via default bootloader (binary file)
bin - compile and generate <neorv32_raw_exe.bin> RAW executable memory image (binary file)
hex - compile and generate <neorv32_raw_exe.hex> RAW executable memory image (hex char file)
coe - compile and generate <neorv32_raw_exe.coe> RAW executable memory image (COE file)
mem - compile and generate <neorv32_raw_exe.mem> RAW executable memory image (MEM file)
mif - compile and generate <neorv32_raw_exe.mif> RAW executable memory image (MIF file)
image - compile and generate VHDL IMEM boot image (for application, no header) in local folder
install - compile, generate and install VHDL IMEM boot image (for application, no header)
exe - compile and generate <neorv32_exe.bin> executable image file for bootloader upload (includes a HEADER!)
bin - compile and generate <neorv32_raw_exe.bin> executable memory image
hex - compile and generate <neorv32_raw_exe.hex> executable memory image
coe - compile and generate <neorv32_raw_exe.coe> executable memory image
mem - compile and generate <neorv32_raw_exe.mem> executable memory image
mif - compile and generate <neorv32_raw_exe.mif> executable memory image
image - compile and generate VHDL IMEM application boot image <neorv32_application_image.vhd> in local folder
install - compile, generate and install VHDL IMEM application boot image <neorv32_application_image.vhd>
sim - in-console simulation using default/simple testbench and GHDL
hdl_lists - regenerate HDL file-lists in NEORV32_HOME/rtl
hdl_lists - regenerate HDL file-lists (*.f) in NEORV32_HOME/rtl
all - exe + install + hex + bin + asm
elf_info - show ELF layout info
elf_sections - show ELF sections
clean - clean up project home folder
clean_all - clean up whole project, core libraries and image generator
bl_image - compile and generate VHDL BOOTROM boot image (for bootloader only, no header) in local folder
bootloader - compile, generate and install VHDL BOOTROM boot image (for bootloader only, no header)
bl_image - compile and generate VHDL BOOTROM bootloader boot image <neorv32_bootloader_image.vhd> in local folder
bootloader - compile, generate and install VHDL BOOTROM bootloader boot image <neorv32_bootloader_image.vhd>
Variables:
USER_FLAGS - Custom toolchain flags [append only]: ""
USER_FLAGS - Custom toolchain flags [append only]: "-ggdb -gdwarf-3 -Wl,--defsym,__neorv32_rom_size=16k -Wl,--defsym,__neorv32_ram_size=8k"
USER_LIBS - Custom libraries [append only]: ""
EFFORT - Optimization level: "-Os"
MARCH - Machine architecture: "rv32i_zicsr_zifencei"
MABI - Machine binary interface: "ilp32"
APP_INC - C include folder(s) [append only]: "-I ."
APP_SRC - C source folder(s) [append only]: "./main.c "
ASM_INC - ASM include folder(s) [append only]: "-I ."
RISCV_PREFIX - Toolchain prefix: "riscv32-unknown-elf-"
NEORV32_HOME - NEORV32 home folder: "../../.."
@ -197,289 +227,137 @@ Variables:
----
:sectnums:
==== Makefile Configuration
The compilation flow is configured via variables right at the beginning of the central
makefile (`sw/common/common.mk`):
.Customizing Makefile Variables
[TIP]
The makefile configuration variables can be overridden or extended directly when invoking the makefile. For
example `$ make MARCH=rv32ic_zicsr_zifencei clean_all exe` overrides the default `MARCH` variable definitions.
.Default Makefile Configuration
[source,makefile]
----
# *****************************************************************************
# USER CONFIGURATION
# *****************************************************************************
# User's application sources (*.c, *.cpp, *.s, *.S); add additional files here
APP_SRC ?= $(wildcard ./*.c) $(wildcard ./*.s) $(wildcard ./*.cpp) $(wildcard ./*.S)
# User's application include folders (don't forget the '-I' before each entry)
APP_INC ?= -I .
# User's application include folders - for assembly files only (don't forget the '-I' before each
entry)
ASM_INC ?= -I .
# Optimization
EFFORT ?= -Os
# Compiler toolchain
RISCV_PREFIX ?= riscv32-unknown-elf-
# CPU architecture and ABI
MARCH ?= rv32i_zicsr_zifencei
MABI ?= ilp32
# User flags for additional configuration (will be added to compiler flags)
USER_FLAGS ?=
# User libraries (will be included by linker)
USER_LIBS ?=
# Language specific compiler flags: C
CFLAGS ?=
# C++
CXXFLAGS ?=
# Assembly
ASFLAGS ?=
# Flags passed only to the linker
LDFLAGS ?=
# Relative or absolute path to the NEORV32 home folder
NEORV32_HOME ?= ../../..
# GDB arguments
GDB_ARGS ?= -ex "target extended-remote localhost:3333"
# *****************************************************************************
----
.Variables Description
[cols="<2,<8"]
[grid="none"]
|=======================
| `APP_SRC` | The source files of the application (`*.c`, `*.cpp`, `*.S` and `*.s` files are allowed; files of these types in the project folder are automatically added via wild cards). Additional files can be added separated by white spaces
| `APP_INC` | Include file folders; separated by white spaces; must be defined with `-I` prefix
| `ASM_INC` | Include file folders that are used only for the assembly source files (`*.S`/`*.s`).
| `EFFORT` | Optimization level, optimize for size (`-Os`) is default; legal values: `-O0`, `-O1`, `-O2`, `-O3`, `-Os`, `-Ofast`, ...
| `RISCV_PREFIX` | The toolchain prefix to be used; follows the triplet naming convention `[architecture]-[host_system]-[output]-...`
| `MARCH` | The targeted RISC-V architecture/ISA
| `MABI` | Application binary interface (default: 32-bit integer ABI `ilp32`)
| `USER_FLAGS` | Additional flags that will be forwarded to the compiler tools
| `USER_LIBS` | Additional libraries to include during linking (`*.a`)
| `CFLAGS` | Additional flags that will be forwarded to the C compiler
| `CXXFLAGS` | Additional flags that will be forwarded to the C++ compiler
| `ASFLAGS` | Additional flags that will be forwarded to the assembler
| `LDFLAGS` | Additional flags that will be forwarded to the linker
| `NEORV32_HOME` | Relative or absolute path to the NEORV32 project home folder; adapt this if the makefile/project is not in the project's default `sw/example` folder
| `GDB_ARGS` | Default GDB arguments when running the `gdb` target
| `GHDL_RUN_FLAGS` | GHDL run arguments (e.g. `--stop-time=1ms`)
|=======================
:sectnums:
==== Default Compiler Flags
The following default compiler flags are used for compiling an application. These flags are defined via the
`CC_OPTS` variable.
[TIP]
The makefile's `CC_OPTS` is exported as **define** to be available within a C program; for example
`neorv32_uart0_printf("%s\n", CC_OPTS);`.
The central makefile uses specific compiler flags to tune the code to the NEORV32 hardware. Hence, these flags should not
be altered. However, experienced users can modify them to further tune compilation.
.Compiler Options (`CC_OPTS`)
[cols="<3,<9"]
[grid="none"]
|=======================
| `-Wall` | Enable all compiler warnings.
| `-ffunction-sections` | Put functions and data segment in independent sections. This allows a code optimization as dead code and unused data can be easily removed.
| `-ffunction-sections` | Put functions in independent sections. This allows a code optimization as dead code can be easily removed.
| `-fdata-sections` | Put data segment in independent sections. This allows a code optimization as unused data can be easily removed.
| `-nostartfiles` | Do not use the default start code. Instead, the NEORV32-specific start-up code (`sw/common/crt0.S`) is used (pulled-in by the linker script).
| `-Wl,--gc-sections` | Make the linker perform dead code elimination.
| `-lm` | Include/link with `math.h`.
| `-lc` | Search for the standard C library when linking.
| `-lgcc` | Make sure we have no unresolved references to internal GCC library subroutines.
| `-mno-fdiv` | Use built-in software functions for floating-point divisions and square roots (since the according instructions are not supported yet).
| `-mstrict-align` | Unaligned memory accesses cannot be resolved by the hardware and require emulation.
| `-mbranch-cost=10` | Branching costs a lot of cycles.
| `-ffp-contract=off` | Do not allow contraction of floating-point operations (no fused operations as they are not supported).
| `-Wl,--gc-sections` | Make the linker perform dead code elimination.
| `-ffp-contract=off` | Disable floating-point expression contraction.
| `-g` | Add (simple) debug information.
|=======================
.Debug Symbols
.Checking Compiler Flags from a Compiled Program
[TIP]
The makefile's `CC_OPTS` is exported as **define** to be available within a C program; for example
`neorv32_uart0_printf("%s\n", CC_OPTS);`.
.Linker Libraries (`LD_LIBS`)
[cols="<2,<9"]
[grid="none"]
|=======================
| `-lm` | Include/link with `math.h`.
| `-lc` | Search for the standard C library when linking.
| `-lgcc` | Make sure we have no unresolved references to internal GCC library subroutines.
|=======================
.Advanced Debug Symbols
[IMPORTANT]
By default, no debug symbols are added to the ELF.
You can add them manually (to your local project's makefile) via `USER_FLAGS+=-g`.
Note that other debug flags may be required depending of the GCC/GDB version
(e.g. `USER_FLAGS += -ggdb -gdwarf-3`).
:sectnums:
==== Custom (Compiler) Flags
Custom flags can be _appended_ to the `USER_FLAGS` variable. This allows to customize the entire software framework while
calling `make` without the need to change the makefile(s) or the linker script. The following example will add debug symbols
to the executable (`-g`) and will also re-define the linker script's `__neorv32_heap_size` variable setting the maximal heap
size to 4096 bytes (see sections <<_linker_script>> and <<_ram_layout>>):
.Using the `USER_FLAGS` Variable for Customization
[source,bash]
----
$ make USER_FLAGS+="-g -Wl,--__neorv32_heap_size,__heap_size=4096" clean_all exe
----
The configuration can also be made "permanent" by adapting the application's makefile (make sure to use the
`override` command here):
.Using the `USER_FLAGS` Variable for Permanent Customization
[source,makefile]
----
override USER_FLAGS += "-g -Wl,--__neorv32_heap_size,__heap_size=4096"
----
By default, only "simple" symbols are added to the ELF (`-g`). Extended debug flags (e.g. for Eclipse) can be added
using the `USER_FLAGS` variable (e.g. `USER_FLAGS += -ggdb -gdwarf-3`). Note that other debug flags may be required
depending of the GCC/GDB version
<<<
// ####################################################################################################################
:sectnums:
=== Executable Image Format
=== Linker Script
In order to generate an executable for the processors all source files have to be compiled, linked
and packed into a final executable. This executable can be further converted into several image formats.
The NEORV32-specific linker script (`sw/common/neorv32.ld`) is used to link the compiled sources according to the
processor's <<_address_space>>). For the final executable, only two memory segments are required:
.Memory Image Formats
[TIP]
The NEORV32 software framework includes an <<_executable_image_generator>> than can convert an application
into several different file formats. These include raw hex files, a proprietary format for uploading via the
default <<_bootloader>> as well as several standard FPGA memory initialization file types (e.g. `*.coe`,
`*.mem` and `*.mif`). These image file formats are generated by the according <<_makefile_targets>>.
:sectnums:
==== Linker Script
After all the application sources have been compiled, they need to be _linked_.
For this purpose the makefile uses the NEORV32-specific linker script. This linker script defines several sections
for the final executable (compare with <<_address_space>>). However, only the `ram` and `rom` sections are
relevant for the executable itself; the remaining sections are just listed for completeness.
.Linker script - memory sections
.Linker script - Memory Segments
[cols="<2,<8"]
[options="header",grid="rows"]
|=======================
| Memory section | Description
| `ram` | Data memory address space (processor-internal <<_data_memory_dmem>> and/or external memory)
| `rom` | Instruction memory address space (processor-internal <<_instruction_memory_imem>> and/or external memory)
| `xip` | Address space for the <<_execute_in_place_module_xip>> (accessing an external SPI memory)
| `boot` | Address space for the processor-internal <<_bootloader_rom_bootrom>>
| `io` | Address space for the processor-internal IO/peripheral devices
| `ram` | Data memory address space (processor-internal <<_data_memory_dmem>> and/or external memory)
|=======================
[NOTE]
The `rom` section is automatically re-mapped to the processor-internal <<_bootloader_rom_bootrom>> when compiling the
bootloader sources.
These two sections are configured by several variables defined in the linker script and exposed to the build
framework (aka the makefile). Those variable allow to customized the RAM/ROM sizes and base addresses. Additionally,
a certain amount of the RAM can be reserved for the software-managed heap (see <<_ram_layout>>).
Each section has two main attributes: `ORIGIN` and `LENGTH`. `ORIGIN` defines the base address of the according section
while `LENGTH` defines its size in bytes. For the `ram` and `rom` sections these attributes are configured indirectly
via variables that provide default values.
.Linker script - section configuration
[source]
----
/* Default rom/ram (IMEM/DMEM) sizes */
__neorv32_rom_size = DEFINED(__neorv32_rom_size) ? __neorv32_rom_size : 2048M;
__neorv32_ram_size = DEFINED(__neorv32_ram_size) ? __neorv32_ram_size : 8K;
/* Default section base addresses */
__neorv32_rom_base = DEFINED(__neorv32_rom_base) ? __neorv32_rom_base : 0x00000000;
__neorv32_ram_base = DEFINED(__neorv32_ram_base) ? __neorv32_ram_base : 0x80000000;
----
The region size and base address configuration can be edited by the user - either by explicitly
changing the default values in the linker script or by overriding them when invoking `make`:
.Overriding default `rom` size configuration (configuring 4096 bytes)
[source, bash]
----
$ make USER_FLAGS+="-Wl,--defsym,__neorv32_rom_size=4096" clean_all exe
----
[IMPORTANT]
`__neorv32_rom_base` (= `ORIGIN` of the `rom` section) and `__neorv32_ram_base` (= `ORIGIN` of the `ram` section) have to
be sync to the actual memory layout configuration of the processor (see section <<_address_space>>).
[NOTE]
The default configuration for the `rom` section assumes a maximum of 2GB _logical_ memory address space. This size does not
have to reflect the _actual_ physical size of the entire instruction memory. It just provides a maximum limit. When uploading
a new executable via the bootloader, the bootloader itself checks if sufficient _physical_ instruction memory is available.
If a new executable is embedded right into the internal-IMEM the synthesis tool will check, if the configured instruction memory
size is sufficient.
The linker maps all the regions from the compiled object files into five final sections: `.text`,
`.rodata`, `.data`, `.bss` and `.heap`:
.Linker script - memory regions
[cols="<1,<9"]
.Linker script - Configuration
[cols="<2,<7,^1"]
[options="header",grid="rows"]
|=======================
| Region | Description
| `.text` | Executable instructions generated from the start-up code and all application sources.
| `.rodata` | Constants (like strings) from the application; also the initial data for initialized variables.
| `.data` | This section is required for the address generation of fixed (= global) variables only.
| `.bss` | This section is required for the address generation of dynamic memory constructs only.
| `.heap` | This section is required for the address generation of dynamic memory constructs only.
| Memory section | Description | Default
| `__neorv32_rom_size` | "ROM" size (instruction memory / IMEM) | 16kB
| `__neorv32_ram_size` | "RAM" size (data memory / DMEM) | 8kB
| `__neorv32_rom_base` | "ROM" base address (instruction memory / IMEM) | `0x00000000`
| `__neorv32_ram_base` | "RAM" base address (data memory / DMEM) | `0x80000000`
| `__neorv32_heap_size` | Maximum heap size; part of the "RAM" | 0kB
|=======================
The `.text` and `.rodata` sections are mapped to processor's instruction memory space and the `.data`,
`.bss` and `heap` sections are mapped to the processor's data memory space. Finally, the `.text`, `.rodata` and `.data`
sections are extracted and concatenated into a single file `main.bin`.
Each variable provides a default value (e.g. "16K" for the instruction memory /ROM /IMEM size). These defaults can
be overridden by setup-specific values to take the user-defined processor configuration into account (e.g. a different IMEM
size). The `USER_FLAGS` variable provided by the <<_application_makefile>> can also be used to customize the memory
configuration. For example, the following line can be added to a project-specific local makefile to adjust the memory
sizes:
.Section Alignment
[NOTE]
The default NEORV32 linker script aligns _all_ regions so they start and end on a 32-bit (word) boundaries. The default
NEORV32 start-up code (crt0) makes use of this alignment by using word-level memory instructions to initialize the `.data`
section and to clear the `.bss` section (faster!).
.Overriding Default Memory Sizes (configuring 64kB IMEM and 32kB DMEM)
[source, makefile]
----
USER_FLAGS += "-Wl,--defsym,__neorv32_rom_size=64k -Wl,--defsym,__neorv32_ram_size=32k"
----
.Memory Configuration Constraints
[IMPORTANT]
Memory sizes have to be a multiple of 4 bytes. Memory base addresses have to be 32-bit-aligned.
:sectnums:
==== RAM Layout
The default NEORV32 linker script uses all of the defined RAM (linker script memory section `ram`) to several sections.
The default NEORV32 linker script uses the defined RAM size to map several sections.
Note that depending on the application some sections might have zero size.
.Default RAM Layout
image::ram_layout.png[400]
[start=1]
. **Constant data (`.data`)**: The constant data section is placed right at the beginning of the RAM. For example, this section
contains _explicitly initialized_ global variables. This section is initialized by the executable.
. **Dynamic data (`.bss`)**: The constant data section is followed by the dynamic data section, which contains _uninitialized_ data
like global variables without explicit initialization. This section is cleared by the start-up code `crt0.S`.
. **Heap (`.heap`)**: The heap is used for dynamic memory that is managed by functions like `malloc()` and `free()`. The heap
grows upwards. This section is not initialized at all.
. **Stack**: The stack starts at the very end of the RAM at address `ORIGIN(ram) + LENGTH(ram) - 1`. According to the RISC-V ABI / calling
. **Constant data (`.data`)**: The constant data section is placed right at the beginning of the RAM. For example, this
section contains _explicitly initialized_ global variables. This section is initialized by the <<_start_up_code_crt0>>.
. **Dynamic data (`.bss`)**: The constant data section is followed by the dynamic data section that contains _uninitialized_
data like global variables without explicit initialization. This section is cleared by the <<_start_up_code_crt0>>.
. **Heap (`.heap`)**: The heap is used for dynamic memory that is managed by functions like `malloc()` and `free()`.
The heap grows upwards. This section is not initialized at all.
. **Stack**: The stack starts at the end of the RAM at the last 16-byte aligned address. According to the RISC-V ABI / calling
convention the stack is 128-bit-aligned before procedure entry. The stack grows downwards.
There is _no explicit limit_ for the maximum stack size as this is hard to check. However, a physical memory protection rule could
be used to configure a maximum size by adding a "protection area" between stack and heap (a PMP region without any access rights).
.Heap Size
[IMPORTANT]
The maximum size of the heap is defined by the linker script's `__neorv32_heap_size` variable. This variable has to be
**explicitly defined** in order to define a heap size (and to use dynamic memory allocation at all) other than zero. The user
can define the heap size while invoking the application makefile: `$ USER_FLAGS+="-Wl,--defsym,__neorv32_heap_size=4k" make clean_all exe`
(defines a heap size of 4*1024 bytes).
The maximum size of the heap is defined by the `__neorv32_heap_size` variable. This variable has to be
**explicitly defined** in order to define a heap size (and to use dynamic memory allocation at all) other than zero.
.Heap-Stack Collisions
.Heap-Stack Collision
[WARNING]
Take care when using dynamic memory to avoid collision of the heap and stack memory areas. There is no compile-time protection
mechanism available as the actual heap and stack size are defined by _runtime_ data. Also beware of fragmentation when
using dynamic memory allocation.
Take care when using dynamic memory to avoid collision of the heap and stack memory areas. There is no compile-time
protection mechanism available as the actual heap and stack size are defined by _runtime_ data.
<<<
// ####################################################################################################################
:sectnums:
==== C Standard Library
=== C Standard Library
The default software framework relies on **newlib** as default C standard library.
.RTOS Support
[NOTE]
The NEORV32 CPU and processor **do support** embedded RTOS like FreeRTOS and Zephyr. See the User guide section
https://stnolting.github.io/neorv32/ug/#_zephyr_rtos_support[Zephyr RTOS Support] and
https://stnolting.github.io/neorv32/ug/#_freertos_support[FreeRTOS Support]
for more information. +
+
The FreeRTOS port and demo is available in a separate repository: https://github.com/stnolting/neorv32-freertos
Newlib provides stubs for common "system calls" (like file handling and standard input/output) that are used by other
C libraries like `stdio`. These stubs are available in `sw/source/source/syscalls.c` and were adapted for the NEORV32 processor.
The default software framework relies on **newlib** as default C standard library. Newlib provides hooks for common
"system calls" (like file handling and standard input/output) that are used by other C libraries like `stdio`.
These hooks are available in `sw/lib/source/newlib.c` and were adapted for the NEORV32 processor.
.Standard Consoles
[NOTE]
@ -494,86 +372,86 @@ See `sw/example/hello_cpp` for a minimal example.
.Newlib Test/Demo Program
[TIP]
A simple test and demo program, which uses some of newlib's core functions (like `malloc`/`free` and `read`/`write`)
is available in `sw/example/demo_newlib`
A simple test and demo program that uses some of newlib's system functions (like `malloc`/`free` and `read`/`write`)
is available in `sw/example/demo_newlib`.
<<<
// ####################################################################################################################
:sectnums:
==== Executable Image Generator
=== Start-Up Code (crt0)
The `main.bin` file is packed by the NEORV32 image generator (`sw/image_gen`) to generate the final executable file.
The image generator can generate several types of executable file formats selected by a flag when calling the generator:
[cols="<2,<8"]
[grid="none"]
|=======================
| `-app_bin` | Generates an executable binary file `neorv32_exe.bin` (including bootloader header) for uploading via the bootloader.
| `-app_img` | Generates an executable VHDL memory initialization image for the processor-internal IMEM. This option regenerates the `rtl/core/neorv32_application_image.vhd` file.
| `-bld_img` | Generates an executable VHDL memory initialization image for the processor-internal BOOT ROM. This option regenerates the `rtl/core/neorv32_bootloader_image.vhd` file.
| `-raw_hex` | Generates a raw 8x ASCII hex-char file `neorv32_raw_exe.hex` for custom purpose.
| `-raw_bin` | Generates a raw binary file `neorv32_raw_exe.bin` for custom purpose.
| `-raw_coe` | Generates a raw COE file `neorv32_raw_exe.coe` for FPGA memory initialization.
| `-raw_mem` | Generates a raw MEM file `neorv32_raw_exe.mem` for FPGA memory initialization.
| `-raw_mif` | Generates a raw MIF file `neorv32_raw_exe.mif` for FPGA memory initialization.
|=======================
**All these options are managed by the makefile (see <<_makefile_targets>>).**
.Image Generator Compilation
[NOTE]
The sources of the image generator are automatically compiled when invoking the makefile (requiring a _native_ GCC installation).
.Executable Header
[NOTE]
The image generator add a small header to the `neorv32_exe.bin` executable, which consists of three 32-bit words located right
at the beginning of the file. The first word of the executable is the signature word and is always `0x4788cafe`. Based on this
word the bootloader can identify a valid image file. The next word represents the size in bytes of the actual program image in
bytes. A simple "complement" checksum of the actual program image is given by the third word. This provides a simple protection
against data transmission or storage errors. **Note that this executable format cannot be used for _direct_ execution (e.g. via
XIP or direct memory access).**
:sectnums:
==== Start-Up Code (crt0)
The CPU and also the processor require a minimal start-up and initialization code to bring the CPU (and the SoC)
into a stable and initialized state and to initialize the C runtime environment before the actual application can be executed.
This start-up code is located in `sw/common/crt0.S` and is automatically linked _every_ application program
and placed right before the actual application code so it gets executed right after reset.
The CPU and also the processor require a minimal start-up and initialization code to bring the hardware into an
operational state. Furthermore, the C runtime requires an initialization before compiled code can be executed.
This setup is done by the start-up code (`sw/common/crt0.S`) which is automatically linked with _every_ application
program and gets mapped before the actual application code so it gets executed right after boot.
The `crt0.S` start-up performs the following operations:
[start=1]
. Clear <<_mstatus>>.
. Clear <<_mie>> disabling all interrupt sources.
. Install an <<_early_trap_handler>> to <<_mtvec>>.
. Initialize the global pointer `gp` and the stack pointer `sp` according to the <<_ram_layout>> provided by the linker script. According to the RISC-V ABI the stack pointer gets 128-bit-aligned.
. Clear <<_mstatus>> CSR.
. Clear <<_mie>> CSR disabling all interrupt sources.
. Install an <<_early_trap_handler>> to <<_mtvec>> CSR.
. Initialize the global pointer `gp` and the stack pointer `sp` according to the <<_ram_layout>> provided by the linker script.
. Initialize all integer register `x1` - `x31` (only `x1` - `x15` if the `E` CPU extension is enabled).
. Setup `.data` section to configure initialized variables.
. Clear the `.bss` section.
. Call all _constructors_ (if there are any).
. Call the application's `main` function (with no arguments: `argc` = `argv` = 0).
. If `main` returns:
** All interrupt sources are disabled by clearing <<_mie>>.
** The return value of `main` is copied to the <<_mscratch>> CSR to allow inspection by the debugger.
** Call all _destructors_ (if there are any). If any destructor causes an exception the crt0's trap handler is used for handling (= skipping) this.
. Call the application's `main()` function (with no arguments; `argc` = `argv` = 0).
. If `main()` returns:
** All interrupt sources are disabled by clearing <<_mie>> CSR.
** The return value of `main()` is copied to the <<_mscratch>> CSR to allow inspection by the debugger.
** Call all _destructors_ (if there are any).
** Re-install an <<_early_trap_handler>> to <<_mtvec>> CSR. If any destructor causes an exception the <<_early_trap_handler>> is used for handling.
** The CPU enters sleep mode executing the `wfi` instruction in an endless loop.
:sectnums:
===== Early Trap Handler
The start-up code provides a very basic trap handler for the early boot stage. This handler does nothing but trying to move
on to the next linear instruction whenever an interrupt or synchronous exception is encountered.
==== Early Trap Handler
The start-up code provides a very basic trap handler for the early boot phase. This handler does nothing but
trying to move on to the next linear instruction whenever an interrupt or synchronous exception is encountered.
This simple trap handler does not interact with the stack at all as it just uses a single register that is backup-ed
using the <<_mscratch>> CSR. Furthermore, the information if the trap-causing instruction is compressed or uncompressed
is **not** determined by loading the instruction from memory. Instead, the transformed instruction word is read from the
<<_mtinst>> CSRs. These two features allow the trap handler to execute with minimal latency and high robustness.
using the <<_mscratch>> CSR.
<<<
// ####################################################################################################################
:sectnums:
=== Executable Image Formats
The compiled and linked executable (ELF file) is further processed by the NEORV32 image generator (`sw/image_gen`) to
generate the final executable file. The image generator can generate several types of executable file formats selected
by a flag when calling the generator.
**Note that all these options are managed by the makefile (see <<_makefile_targets>>).**
[cols="<2,<8"]
[grid="none"]
|=======================
| `-app_bin` | Generates an executable binary file (including a bootloader header) for upload via the bootloader.
| `-app_vhd` | Generates an executable VHDL memory initialization image for the processor-internal IMEM.
| `-bld_vhd` | Generates an executable VHDL memory initialization image for the processor-internal BOOT ROM.
| `-raw_hex` | Generates a raw 8x ASCII hex-char file for custom purpose.
| `-raw_bin` | Generates a raw binary file `for custom purpose.
| `-raw_coe` | Generates a raw COE file for FPGA memory initialization.
| `-raw_mem` | Generates a raw MEM file for FPGA memory initialization.
| `-raw_mif` | Generates a raw MIF file for FPGA memory initialization.
|=======================
.Image Generator Compilation
[NOTE]
The early-trap handler should be replaced by a more capable / informative one as soon as the application software is started
(for example by using the <<_neorv32_runtime_environment>>).
The sources of the image generator are automatically compiled when invoking the makefile
(requiring a _native_ GCC installation).
.Executable Header
[NOTE]
for the `app_bin` option the image generator adds a small header to the executable. This header is required by the
<<_bootloader>> to identify and manage the executable. The header consists of three 32-bit words located right
at the beginning of the file. The first word of the executable is the signature word and is always `0x4788cafe`.
Based on this word the bootloader can identify a valid image file. The next word represents the size in bytes of the
actual program image in bytes. A simple complement checksum of the actual program image is given by the third word.
This provides a simple protection against data transmission or storage errors.
**Note that this executable format cannot be used for _direct_ execution (e.g. via XIP or direct memory access).**
<<<

View file

@ -26,7 +26,7 @@ The bootloader requires certain CPU and SoC extensions and modules to be enabled
[cols="^2,<8"]
[grid="none"]
|=======================
| **REQUIRED** | The bootloader is implemented only if the `INT_BOOTLOADER_EN` top generic is `true`. This will automatically select the CPU's <<_indirect_boot>> boot configuration.
| **REQUIRED** | The <<_boot_configuration>> (`BOOT_MODE_SELECT` generic) has to be set to "bootloader" mode.
| **REQUIRED** | The bootloader requires the privileged architecture CPU extension (<<_zicsr_isa_extension>>) to be enabled.
| **REQUIRED** | At least 512 bytes of data memory (processor-internal DMEM or processor-external DMEM) are required for the bootloader's stack and global variables.
| _RECOMMENDED_ | For user interaction via the <<_bootloader_console>> (like uploading executables) the primary UART (<<_primary_universal_asynchronous_receiver_and_transmitter_uart0>>) is required.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 86 KiB

View file

@ -58,6 +58,11 @@ to a different location (makefile, NEORV32 sources, etc.).
Make sure to adjust the binaries / installation folders of the RISC-V GCC toolchain
and OpenOCD according to your installation. See the following chapter for more information.
.Makefile Adjustment
[IMPORTANT]
Make sure to adjust the variables inside the project's makefile to match your processor
configuration (memory sizes, CPU ISA configuration, etc.).
:sectnums:
=== Setup a new Eclipse Project from Scratch

View file

@ -46,8 +46,9 @@ Vivado project.
.Combinatorial Loops DRC Errors
[WARNING]
If the TRNG is enabled it is recommended to add the following commands to the project's constraints file in order
to prevent DRC errors during bitstream generation:
to prevent DRC errors during bitstream generation.
.Allow Combinatorial Loops
[source,xdc]
----
set_property SEVERITY {warning} [get_drc_checks LUTLP-1]
@ -65,3 +66,9 @@ shall be updated. It is **not** not possible to replace the IMEM image (`neorv32
in the packaged_ip folder. For the Vivado design suite, the new program to be executed must be compiled and installed using the
`install` makefile target. Next, the `neorv32_vivado_ip.tcl` script has to be executed again. Finally, Vivado will prompt to upgrade
the NEORV32 IP.
.AMD Vivado / ISIM - Incremental Compilation of Simulation Sources
[IMPORTANT]
When using AMD Vivado (ISIM for simulation) make sure to **TURN OFF** "incremental compilation" (_Project Setting_
-> _Simulation_ -> _Advanced_ -> _Enable incremental compilation). This will slow down simulation relaunch but will
ensure that all application images (`*_image.vhd`) are reanalyzed when recompiling the NEORV32 application or bootloader.

View file

@ -2,9 +2,9 @@
:sectnums:
== Simulating the Processor
The NEORV32 project includes a core CPU, built-in peripherals in the Processor Subsystem, and additional peripherals in
the templates and examples.
Therefore, there is a wide range of possible testing and verification strategies.
The NEORV32 project includes a core CPU, built-in peripherals in the Processor Subsystem, and additional
peripherals in the templates and examples. Therefore, there is a wide range of possible testing and
verification strategies.
On the one hand, a simple smoke testbench allows ensuring that functionality is correct from a software point of view.
That is used for running the RISC-V architecture tests, in order to guarantee compliance with the ISA specification(s).
@ -12,28 +12,23 @@ That is used for running the RISC-V architecture tests, in order to guarantee co
On the other hand, http://vunit.github.io/[VUnit] and http://vunit.github.io/verification_components/user_guide.html[Verification Components]
are used for verifying the functionality of the various peripherals from a hardware point of view.
.AMD Vivado / ISIM
.AMD Vivado / ISIM - Incremental Compilation
[IMPORTANT]
When using AMD Vivado (ISIM for simulation) make sure to **turn of** "incremental compilation" (_Project Setting_
When using AMD Vivado (ISIM for simulation) make sure to **TURN OFF** "incremental compilation" (_Project Setting_
-> _Simulation_ -> _Advanced_ -> _Enable incremental compilation). This will slow down simulation relaunch but will
ensure that all application images (`*_image.vhd`) are reanalyzed when recompiling the NEORV32 application or bootloader
[TIP]
The processor can check if it is being _simulated_ by checking the SYSINFO _SYSINFO_SOC_IS_SIM_ flag
(see https://stnolting.github.io/neorv32/#_system_configuration_information_memory_sysinfo).
Note that this flag is not guaranteed to be set correctly (depending on the HDL toolchain's pragma support).
ensure that all application images (`*_image.vhd`) are reanalyzed when recompiling the NEORV32 application or bootloader.
:sectnums:
=== Testbench
A plain-VHDL (no third-party libraries) testbench (`sim/simple/neorv32_tb.simple.vhd`) can be used for simulating and
testing the processor.
This testbench features a 100MHz clock and enables all optional peripheral and CPU extensions except for the `E`.
.VUnit Testbench
[TIP]
A more sophisticated testbench using **VUnit** is available in a separate repository:
https://github.com/stnolting/neorv32-vunit
[IMPORTANT]
In the simple testbench several optional extensions are disabled, such as C or E.
If software is compiled using instructions corresponding to disabled extensions, the whole processor will hang in an eternal exception loop and, therefore, the simulation will timeout.
The `MARCH` must be a subset of the extensions enabled in the testbench.
A plain-VHDL (no third-party libraries) testbench (`sim/neorv32_tb.vhd`) can be used for simulating and
testing the processor. This testbench features a 100MHz clock and enables all optional peripheral and CPU
extensions.
.True Random Number Generator
[NOTE]
@ -41,41 +36,7 @@ The NEORV32 TRNG will be set to "simulation mode" when enabled for simulation (r
by pseudo-random LFSRs). See the neoTRNG documentation for more information.
The simulation setup is configured via the "User Configuration" section located right at the beginning of
the testbench's architecture. Each configuration constant provides comments to explain the functionality.
Besides the actual NEORV32 Processor, the testbench also simulates "external" components that are connected
to the processor's external bus/memory interface. These components are:
* an external instruction memory (that also allows booting from it)
* an external data memory
* an external memory to simulate "external IO devices"
* a memory-mapped registers to trigger the processor's interrupt signals
The following table shows the base addresses of these four components and their default configuration and
properties:
[NOTE]
====
Attributes:
* `r` = read
* `w` = write
* `e` = execute
* `8` = byte-accessible
* `16` = half-word-accessible
* `32` = word-accessible
====
.Testbench: processor-external memories
[cols="^4,>3,^5,<11"]
[options="header",grid="rows"]
|=======================
| Base address | Size | Attributes | Description
| `0x00000000` | `imem_size_c` | `r/w/e 8/16/32` | external IMEM (initialized with application image)
| `0x80000000` | `dmem_size_c` | `r/w/e 8/16/32` | external DMEM
| `0xf0000000` | 64 bytes | `r/w/e 8/16/32` | external "IO" memory
| `0xff000000` | 4 bytes | `-/w/- -/-/32` | memory-mapped register to trigger "machine external", "machine software" and "SoC Fast Interrupt" interrupts
|=======================
the testbench architecture. Each configuration constant provides comments to explain the functionality.
[IMPORTANT]
The simulated NEORV32 does not use the bootloader and _directly boots_ the current application image (from
@ -100,7 +61,7 @@ for UART0/UART1 (see section https://stnolting.github.io/neorv32/#_primary_unive
ASCII data sent to UART0|UART1 will be immediately printed to the simulator console and logged to files in the simulator
execution directory:
* `neorv32.uart?.sim_mode.text.out`: ASCII data.
* `neorv32.uart*.sim_mode.text.out`: ASCII data.
You can "automatically" enable the simulation mode of UART0/UART1 when compiling an application.
In this case, the "real" UART0/UART1 transmitter unit is permanently disabled.
@ -123,13 +84,13 @@ completed with a line feed (newline, ASCII `\n` = 10).
:sectnums:
=== Simulation using a shell script (with GHDL)
To simulate the processor using _GHDL_ navigate to the `sim/simple/` folder and run the provided shell script.
To simulate the processor using _GHDL_ navigate to the `sim` folder and run the provided shell script.
Any arguments that are provided while executing this script are passed to GHDL.
For example the simulation time can be set to 20ms using `--stop-time=20ms` as argument.
[source, bash]
----
neorv32/sim/simple$ sh ghdl.sh --stop-time=20ms
neorv32/sim$ sh ghdl.sh --stop-time=20ms
----
@ -156,10 +117,6 @@ To do a quick test of the NEORV32 make sure to have https://github.com/ghdl/ghdl
https://github.com/stnolting/riscv-gcc-prebuilt[RISC-V gcc toolchain] installed.
Navigate to the project's `sw/example/hello_world` folder and run `make USER_FLAGS+=-DUART0_SIM_MODE clean_all sim`:
[TIP]
The simulator will output some _sanity check_ notes (and warnings or even errors if something is ill-configured)
right at the beginning of the simulation to give a brief overview of the actual NEORV32 SoC and CPU configurations.
[source, bash]
----
neorv32/sw/example/hello_world$ make USER_FLAGS+=-DUART0_SIM_MODE clean_all sim
@ -208,39 +165,3 @@ Hello world! :)
<5> List of (default) arguments that were send to the simulator. Here: maximum simulation time (10ms).
<6> "Sanity checks" from the core's VHDL files. These reports give some brief information about the SoC/CPU configuration (-> generics). If there are problems with the current configuration, an ERROR will appear.
<7> Execution of the actual program starts.
:sectnums:
=== Advanced Simulation using VUnit
https://vunit.github.io/[VUnit] is an open source unit testing framework for VHDL/SystemVerilog.
It allows continuous and automated testing of HDL code by complementing traditional testing methodologies.
The motto of VUnit is _"testing early and often"_ through automation.
VUnit is composed by a http://vunit.github.io/py/ui.html[Python interface] and multiple optional
http://vunit.github.io/vhdl_libraries.html[VHDL libraries].
The Python interface allows declaring sources and simulation options, and it handles the compilation, execution and
gathering of the results regardless of the simulator used.
That allows having a single `run.py` script to be used with GHDL, ModelSim/QuestaSim, Riviera PRO, etc.
On the other hand, the VUnit's VHDL libraries provide utilities for assertions, logging, having virtual queues, handling CSV files, etc.
The http://vunit.github.io/verification_components/user_guide.html[Verification Component Library] uses those features
for abstracting away bit-toggling when verifying standard interfaces such as Wishbone, AXI, Avalon, UARTs, etc.
Testbench sources in `sim` (such as `sim/neorv32_tb.vhd` and `sim/uart_rx*.vhd`) use VUnit's VHDL libraries for testing
NEORV32 and peripherals.
The entry-point for executing the tests is `sim/run.py`.
[source, bash]
----
# ./sim/run.py -l
neorv32.neorv32_tb.all
Listed 1 tests
# ./sim/run.py -v
Compiling into neorv32: rtl/core/neorv32_uart.vhd passed
Compiling into neorv32: rtl/core/neorv32_twi.vhd passed
Compiling into neorv32: rtl/core/neorv32_trng.vhd passed
...
----
See http://vunit.github.io/user_guide.html[VUnit: User Guide] and http://vunit.github.io/cli.html[VUnit: Command Line Interface] for further info about VUnit's features.

View file

@ -1,11 +1,16 @@
-- The NEORV32 RISC-V Processor: https://github.com/stnolting/neorv32
-- Auto-generated memory initialization file (for APPLICATION) from source file <demo_blink_led/main.bin>
-- The NEORV32 RISC-V Processor - github.com/stnolting/neorv32
-- Auto-generated memory initialization package (for internal IMEM)
-- Source: demo_blink_led/main.bin
-- Size: 1100 bytes
-- MARCH: default
-- Built: 15.09.2024 21:48:24 (dd.mm.yyyy hh:mm:ss)
-- Built: 31.10.2024 22:32:21
-- prototype defined in 'neorv32_package.vhd'
package body neorv32_application_image is
library ieee;
use ieee.std_logic_1164.all;
library neorv32;
use neorv32.neorv32_package.all;
package neorv32_application_image is
constant application_init_image : mem32_t := (
x"000020b7",

View file

@ -1,11 +1,16 @@
-- The NEORV32 RISC-V Processor: https://github.com/stnolting/neorv32
-- Auto-generated memory initialization file (for BOOTLOADER) from source file <bootloader/main.bin>
-- The NEORV32 RISC-V Processor - github.com/stnolting/neorv32
-- Auto-generated memory initialization package (for internal BOOTROM)
-- Source: bootloader/main.bin
-- Size: 4072 bytes
-- MARCH: default
-- Built: 27.09.2024 05:54:10 (dd.mm.yyyy hh:mm:ss)
-- Built: 31.10.2024 22:31:51
-- prototype defined in 'neorv32_package.vhd'
package body neorv32_bootloader_image is
library ieee;
use ieee.std_logic_1164.all;
library neorv32;
use neorv32.neorv32_package.all;
package neorv32_bootloader_image is
constant bootloader_init_image : mem32_t := (
x"000020b7",
@ -894,9 +899,9 @@ x"6f6c746f",
x"72656461",
x"0a3e3e20",
x"444c420a",
x"53203a56",
x"32207065",
x"30322037",
x"4f203a56",
x"33207463",
x"30322031",
x"480a3432",
x"203a5657",
x"00000020",

View file

@ -374,7 +374,7 @@ use neorv32.neorv32_package.all;
entity neorv32_bus_io_switch is
generic (
DEV_SIZE : natural; -- size of a single IO device, has to be a power of two
DEV_SIZE : natural; -- size of each single IO device, has to be a power of two
-- device port enable and base address; enabled ports do not have to be contiguous --
DEV_00_EN : boolean := false; DEV_00_BASE : std_ulogic_vector(31 downto 0) := (others => '0');
DEV_01_EN : boolean := false; DEV_01_BASE : std_ulogic_vector(31 downto 0) := (others => '0');

View file

@ -150,11 +150,11 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is
signal issue_engine : issue_engine_t;
-- instruction execution engine --
type execute_engine_state_t is (DISPATCH, TRAP_ENTER, TRAP_EXIT, RESTART, SLEEP, EXECUTE,
ALU_WAIT, BRANCH, BRANCHED, SYSTEM, MEM_REQ, MEM_WAIT);
type execute_engine_t is record
state : execute_engine_state_t;
state_nxt : execute_engine_state_t;
type exe_engine_state_t is (DISPATCH, TRAP_ENTER, TRAP_EXIT, RESTART, SLEEP, EXECUTE,
ALU_WAIT, BRANCH, BRANCHED, SYSTEM, MEM_REQ, MEM_WAIT);
type exe_engine_t is record
state : exe_engine_state_t;
state_nxt : exe_engine_state_t;
ir : std_ulogic_vector(31 downto 0); -- instruction word being executed right now
ir_nxt : std_ulogic_vector(31 downto 0);
is_ci : std_ulogic; -- current instruction is de-compressed instruction
@ -164,9 +164,9 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is
pc_we : std_ulogic; -- PC update enable
next_pc : std_ulogic_vector(XLEN-1 downto 0); -- next PC, corresponding to next instruction to be executed
end record;
signal execute_engine : execute_engine_t;
signal exe_engine : exe_engine_t;
-- simplified opcode --
-- simplified opcode (2 LSBs hardwired to "11" to indicate rv32) --
signal opcode : std_ulogic_vector(6 downto 0);
-- execution monitor --
@ -284,7 +284,7 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is
-- debug-mode controller --
type debug_ctrl_t is record
running, trig_hw, trig_break, trig_halt, trig_step : std_ulogic; -- single-stepping mode trigger
run, trig_hw, trig_break, trig_halt, trig_step : std_ulogic;
end record;
signal debug_ctrl : debug_ctrl_t;
@ -345,7 +345,7 @@ begin
when others => -- IF_RESTART: set new start address
-- ------------------------------------------------------------
fetch_engine.pc <= execute_engine.next_pc(XLEN-1 downto 1) & '0'; -- initialize from PC incl. 16-bit-alignment bit
fetch_engine.pc <= exe_engine.next_pc(XLEN-1 downto 1) & '0'; -- initialize from PC incl. 16-bit-alignment bit
fetch_engine.priv <= csr.privilege_eff; -- set new privilege level
fetch_engine.state <= IF_REQUEST;
@ -427,7 +427,7 @@ begin
issue_engine.align <= '0'; -- start aligned after reset
elsif rising_edge(clk_i) then
if (fetch_engine.restart = '1') then
issue_engine.align <= execute_engine.next_pc(1); -- branch to unaligned address?
issue_engine.align <= exe_engine.next_pc(1); -- branch to unaligned address?
elsif (issue_engine.ack = '1') then
issue_engine.align <= (issue_engine.align and (not issue_engine.align_clr)) or issue_engine.align_set; -- "rs flip-flop"
end if;
@ -506,7 +506,7 @@ begin
if (rstn_i = '0') then
alu_imm_o <= (others => '0');
elsif rising_edge(clk_i) then
if (execute_engine.state = DISPATCH) then -- prepare update of next_pc (using ALU's PC + IMM in EXECUTE state)
if (exe_engine.state = DISPATCH) then -- prepare update of next_pc (using ALU's PC + IMM in EXECUTE state)
alu_imm_o <= (others => '0');
if RISCV_ISA_C and (issue_engine.data(33) = '1') then -- is de-compressed C instruction?
alu_imm_o(3 downto 0) <= x"2";
@ -514,16 +514,16 @@ begin
alu_imm_o(3 downto 0) <= x"4";
end if;
else
alu_imm_o <= replicate_f(execute_engine.ir(31), 21) & execute_engine.ir(30 downto 21) & execute_engine.ir(20); -- default: I-immediate
alu_imm_o <= replicate_f(exe_engine.ir(31), 21) & exe_engine.ir(30 downto 21) & exe_engine.ir(20); -- default: I-immediate
case opcode is
when opcode_store_c => -- S-immediate
alu_imm_o <= replicate_f(execute_engine.ir(31), 21) & execute_engine.ir(30 downto 25) & execute_engine.ir(11 downto 7);
alu_imm_o <= replicate_f(exe_engine.ir(31), 21) & exe_engine.ir(30 downto 25) & exe_engine.ir(11 downto 7);
when opcode_branch_c => -- B-immediate
alu_imm_o <= replicate_f(execute_engine.ir(31), 20) & execute_engine.ir(7) & execute_engine.ir(30 downto 25) & execute_engine.ir(11 downto 8) & '0';
alu_imm_o <= replicate_f(exe_engine.ir(31), 20) & exe_engine.ir(7) & exe_engine.ir(30 downto 25) & exe_engine.ir(11 downto 8) & '0';
when opcode_lui_c | opcode_auipc_c => -- U-immediate
alu_imm_o <= execute_engine.ir(31 downto 12) & x"000";
alu_imm_o <= exe_engine.ir(31 downto 12) & x"000";
when opcode_jal_c => -- J-immediate
alu_imm_o <= replicate_f(execute_engine.ir(31), 12) & execute_engine.ir(19 downto 12) & execute_engine.ir(20) & execute_engine.ir(30 downto 21) & '0';
alu_imm_o <= replicate_f(exe_engine.ir(31), 12) & exe_engine.ir(19 downto 12) & exe_engine.ir(20) & exe_engine.ir(30 downto 21) & '0';
when opcode_amo_c => -- atomic memory access
if RISCV_ISA_Zalrsc then alu_imm_o <= (others => '0'); end if;
when others =>
@ -536,16 +536,16 @@ begin
-- Branch Condition Check -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
branch_check: process(execute_engine.ir, alu_cmp_i)
branch_check: process(exe_engine.ir, alu_cmp_i)
begin
if (execute_engine.ir(instr_opcode_lsb_c+2) = '0') then -- conditional branch
if (execute_engine.ir(instr_funct3_msb_c) = '0') then -- beq / bne
execute_engine.branch_taken <= alu_cmp_i(cmp_equal_c) xor execute_engine.ir(instr_funct3_lsb_c);
if (exe_engine.ir(instr_opcode_lsb_c+2) = '0') then -- conditional branch
if (exe_engine.ir(instr_funct3_msb_c) = '0') then -- beq / bne
exe_engine.branch_taken <= alu_cmp_i(cmp_equal_c) xor exe_engine.ir(instr_funct3_lsb_c);
else -- blt(u) / bge(u)
execute_engine.branch_taken <= alu_cmp_i(cmp_less_c) xor execute_engine.ir(instr_funct3_lsb_c);
exe_engine.branch_taken <= alu_cmp_i(cmp_less_c) xor exe_engine.ir(instr_funct3_lsb_c);
end if;
else -- unconditional branch
execute_engine.branch_taken <= '1';
exe_engine.branch_taken <= '1';
end if;
end process branch_check;
@ -555,63 +555,63 @@ begin
execute_engine_fsm_sync: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
ctrl <= ctrl_bus_zero_c;
execute_engine.state <= RESTART;
execute_engine.ir <= (others => '0');
execute_engine.is_ci <= '0';
execute_engine.pc <= BOOT_ADDR(XLEN-1 downto 2) & "00"; -- 32-bit-aligned boot address
execute_engine.next_pc <= BOOT_ADDR(XLEN-1 downto 2) & "00"; -- 32-bit-aligned boot address
pc_next_o <= (others => '0');
ctrl <= ctrl_bus_zero_c;
exe_engine.state <= RESTART;
exe_engine.ir <= (others => '0');
exe_engine.is_ci <= '0';
exe_engine.pc <= BOOT_ADDR(XLEN-1 downto 2) & "00"; -- 32-bit-aligned boot address
exe_engine.next_pc <= BOOT_ADDR(XLEN-1 downto 2) & "00"; -- 32-bit-aligned boot address
pc_next_o <= (others => '0');
elsif rising_edge(clk_i) then
-- control bus --
ctrl <= ctrl_nxt;
-- execute engine arbiter --
execute_engine.state <= execute_engine.state_nxt;
execute_engine.ir <= execute_engine.ir_nxt;
execute_engine.is_ci <= execute_engine.is_ci_nxt;
exe_engine.state <= exe_engine.state_nxt;
exe_engine.ir <= exe_engine.ir_nxt;
exe_engine.is_ci <= exe_engine.is_ci_nxt;
-- current PC: address of instruction being executed --
if (execute_engine.pc_we = '1') then
execute_engine.pc <= execute_engine.next_pc(XLEN-1 downto 1) & '0';
if (exe_engine.pc_we = '1') then
exe_engine.pc <= exe_engine.next_pc(XLEN-1 downto 1) & '0';
end if;
-- next PC: address of next instruction --
pc_next_o <= (others => '0'); -- output zero if not a branch instruction
case execute_engine.state is
case exe_engine.state is
when TRAP_ENTER => -- starting trap environment
-- ------------------------------------------------------------
if (trap_ctrl.cause(5) = '1') and RISCV_ISA_Sdext then -- debug mode (re-)entry
execute_engine.next_pc <= DEBUG_PARK_ADDR(XLEN-1 downto 2) & "00"; -- debug mode enter; start at "parking loop" <normal_entry>
elsif (debug_ctrl.running = '1') and RISCV_ISA_Sdext then -- any other trap INSIDE debug mode
execute_engine.next_pc <= DEBUG_EXC_ADDR(XLEN-1 downto 2) & "00"; -- debug mode enter: start at "parking loop" <exception_entry>
exe_engine.next_pc <= DEBUG_PARK_ADDR(XLEN-1 downto 2) & "00"; -- debug mode enter; start at "parking loop" <normal_entry>
elsif (debug_ctrl.run = '1') and RISCV_ISA_Sdext then -- any other trap INSIDE debug mode
exe_engine.next_pc <= DEBUG_EXC_ADDR(XLEN-1 downto 2) & "00"; -- debug mode enter: start at "parking loop" <exception_entry>
else -- normal start of trap
if (csr.mtvec(0) = '1') and (trap_ctrl.cause(6) = '1') then -- vectored mode + interrupt
execute_engine.next_pc <= csr.mtvec(XLEN-1 downto 7) & trap_ctrl.cause(4 downto 0) & "00"; -- pc = mtvec + 4 * mcause
exe_engine.next_pc <= csr.mtvec(XLEN-1 downto 7) & trap_ctrl.cause(4 downto 0) & "00"; -- pc = mtvec + 4 * mcause
else
execute_engine.next_pc <= csr.mtvec(XLEN-1 downto 2) & "00"; -- pc = mtvec
exe_engine.next_pc <= csr.mtvec(XLEN-1 downto 2) & "00"; -- pc = mtvec
end if;
end if;
when TRAP_EXIT => -- leaving trap environment
-- ------------------------------------------------------------
if (debug_ctrl.running = '1') and RISCV_ISA_Sdext then -- debug mode exit
execute_engine.next_pc <= csr.dpc(XLEN-1 downto 1) & '0';
if (debug_ctrl.run = '1') and RISCV_ISA_Sdext then -- debug mode exit
exe_engine.next_pc <= csr.dpc(XLEN-1 downto 1) & '0';
else -- normal end of trap
execute_engine.next_pc <= csr.mepc(XLEN-1 downto 1) & '0';
exe_engine.next_pc <= csr.mepc(XLEN-1 downto 1) & '0';
end if;
when BRANCH => -- branch instruction
-- ------------------------------------------------------------
pc_next_o <= execute_engine.next_pc(XLEN-1 downto 1) & '0'; -- output as link/return address
if (trap_ctrl.exc_buf(exc_illegal_c) = '0') and (execute_engine.branch_taken = '1') then -- valid taken branch
execute_engine.next_pc <= alu_add_i(XLEN-1 downto 1) & '0';
pc_next_o <= exe_engine.next_pc(XLEN-1 downto 1) & '0'; -- output as link/return address
if (trap_ctrl.exc_buf(exc_illegal_c) = '0') and (exe_engine.branch_taken = '1') then -- valid taken branch
exe_engine.next_pc <= alu_add_i(XLEN-1 downto 1) & '0';
end if;
when EXECUTE => -- linear increment (use ALU's adder to compute next_pc = current_pc + imm (2/4))
-- ------------------------------------------------------------
execute_engine.next_pc <= alu_add_i(XLEN-1 downto 1) & '0';
exe_engine.next_pc <= alu_add_i(XLEN-1 downto 1) & '0';
when others => -- no update
-- ------------------------------------------------------------
@ -622,43 +622,43 @@ begin
end process execute_engine_fsm_sync;
-- check if branch destination is misaligned --
trap_ctrl.instr_ma <= '1' when (execute_engine.state = BRANCH) and -- branch instruction (can also be INVALID as exc_illegal_c has higher priority)
(execute_engine.branch_taken = '1') and -- branch is taken
trap_ctrl.instr_ma <= '1' when (exe_engine.state = BRANCH) and -- branch instruction (can also be INVALID as exc_illegal_c has higher priority)
(exe_engine.branch_taken = '1') and -- branch is taken
(alu_add_i(1) = '1') and (not RISCV_ISA_C) else '0'; -- misaligned destination
-- current PC output --
pc_curr_o <= execute_engine.pc(XLEN-1 downto 1) & '0';
pc_curr_o <= exe_engine.pc(XLEN-1 downto 1) & '0';
-- simplified rv32 opcode --
opcode <= execute_engine.ir(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11";
opcode <= exe_engine.ir(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11";
-- Execute Engine FSM Comb ----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
execute_engine_fsm_comb: process(execute_engine, debug_ctrl, trap_ctrl, hw_trigger_match, opcode, issue_engine, csr, alu_cp_done_i, lsu_wait_i)
execute_engine_fsm_comb: process(exe_engine, debug_ctrl, trap_ctrl, hw_trigger_match, opcode, issue_engine, csr, alu_cp_done_i, lsu_wait_i)
variable funct3_v : std_ulogic_vector(2 downto 0);
variable funct7_v : std_ulogic_vector(6 downto 0);
begin
-- shortcuts --
funct3_v := execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c);
funct7_v := execute_engine.ir(instr_funct7_msb_c downto instr_funct7_lsb_c);
funct3_v := exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c);
funct7_v := exe_engine.ir(instr_funct7_msb_c downto instr_funct7_lsb_c);
-- arbiter defaults --
execute_engine.state_nxt <= execute_engine.state;
execute_engine.ir_nxt <= execute_engine.ir;
execute_engine.is_ci_nxt <= execute_engine.is_ci;
execute_engine.pc_we <= '0';
issue_engine.ack <= '0';
fetch_engine.reset <= '0';
trap_ctrl.env_enter <= '0';
trap_ctrl.env_exit <= '0';
trap_ctrl.instr_be <= '0';
trap_ctrl.ecall <= '0';
trap_ctrl.ebreak <= '0';
trap_ctrl.hwtrig <= '0';
csr.we_nxt <= '0';
csr.re_nxt <= '0';
ctrl_nxt <= ctrl_bus_zero_c; -- all zero/off by default (default ALU operation = ZERO, ALU.adder_out = ADD)
exe_engine.state_nxt <= exe_engine.state;
exe_engine.ir_nxt <= exe_engine.ir;
exe_engine.is_ci_nxt <= exe_engine.is_ci;
exe_engine.pc_we <= '0';
issue_engine.ack <= '0';
fetch_engine.reset <= '0';
trap_ctrl.env_enter <= '0';
trap_ctrl.env_exit <= '0';
trap_ctrl.instr_be <= '0';
trap_ctrl.ecall <= '0';
trap_ctrl.ebreak <= '0';
trap_ctrl.hwtrig <= '0';
csr.we_nxt <= '0';
csr.re_nxt <= '0';
ctrl_nxt <= ctrl_bus_zero_c; -- all zero/off by default (ALU operation = ZERO, ALU.adder_out = ADD)
-- ALU sign control --
if (opcode(4) = '1') then -- ALU ops
@ -685,13 +685,13 @@ begin
-- memory read/write access --
if RISCV_ISA_Zalrsc and (opcode(2) = opcode_amo_c(2)) then -- atomic lr/sc
ctrl_nxt.lsu_rw <= execute_engine.ir(instr_funct7_lsb_c+2);
ctrl_nxt.lsu_rw <= exe_engine.ir(instr_funct7_lsb_c+2);
else -- normal load/store
ctrl_nxt.lsu_rw <= execute_engine.ir(5);
ctrl_nxt.lsu_rw <= exe_engine.ir(5);
end if;
-- state machine --
case execute_engine.state is
case exe_engine.state is
when DISPATCH => -- wait for ISSUE ENGINE to emit a valid instruction word
-- ------------------------------------------------------------
@ -699,37 +699,37 @@ begin
ctrl_nxt.alu_opb_mux <= '1'; -- prepare update of next_pc in EXECUTE (opb = imm = +2/4)
--
if (trap_ctrl.env_pending = '1') or (trap_ctrl.exc_fire = '1') then -- pending trap or pending exception (fast)
execute_engine.state_nxt <= TRAP_ENTER;
exe_engine.state_nxt <= TRAP_ENTER;
elsif RISCV_ISA_Sdtrig and (hw_trigger_match = '1') then -- hardware breakpoint
execute_engine.pc_we <= '1'; -- pc <= next_pc; intercept BEFORE executing the instruction
trap_ctrl.hwtrig <= '1';
execute_engine.state_nxt <= DISPATCH; -- stay here another round until trap_ctrl.hwtrig arrives in trap_ctrl.env_pending
exe_engine.pc_we <= '1'; -- pc <= next_pc; intercept BEFORE executing the instruction
trap_ctrl.hwtrig <= '1';
exe_engine.state_nxt <= DISPATCH; -- stay here another round until trap_ctrl.hwtrig arrives in trap_ctrl.env_pending
elsif (issue_engine.valid(0) = '1') or (issue_engine.valid(1) = '1') then -- new instruction word available
issue_engine.ack <= '1';
trap_ctrl.instr_be <= issue_engine.data(32); -- access fault during instruction fetch
execute_engine.is_ci_nxt <= issue_engine.data(33); -- this is a de-compressed instruction
execute_engine.ir_nxt <= issue_engine.data(31 downto 0); -- instruction word
execute_engine.pc_we <= '1'; -- pc <= next_pc
execute_engine.state_nxt <= EXECUTE;
issue_engine.ack <= '1';
trap_ctrl.instr_be <= issue_engine.data(32); -- access fault during instruction fetch
exe_engine.is_ci_nxt <= issue_engine.data(33); -- this is a de-compressed instruction
exe_engine.ir_nxt <= issue_engine.data(31 downto 0); -- instruction word
exe_engine.pc_we <= '1'; -- pc <= next_pc
exe_engine.state_nxt <= EXECUTE;
end if;
when TRAP_ENTER => -- enter trap environment and jump to trap vector
-- ------------------------------------------------------------
if (trap_ctrl.env_pending = '1') then -- wait for sync. exceptions to become pending
trap_ctrl.env_enter <= '1';
execute_engine.state_nxt <= RESTART;
trap_ctrl.env_enter <= '1';
exe_engine.state_nxt <= RESTART;
end if;
when TRAP_EXIT => -- return from trap environment and jump to trap PC
-- ------------------------------------------------------------
trap_ctrl.env_exit <= '1';
execute_engine.state_nxt <= RESTART;
trap_ctrl.env_exit <= '1';
exe_engine.state_nxt <= RESTART;
when RESTART => -- reset and restart instruction fetch at <next_pc>
-- ------------------------------------------------------------
ctrl_nxt.rf_zero_we <= not bool_to_ulogic_f(REGFILE_HW_RST); -- house keeping: force writing zero to x0 if it's a phys. register
fetch_engine.reset <= '1';
execute_engine.state_nxt <= BRANCHED;
ctrl_nxt.rf_zero_we <= not bool_to_ulogic_f(REGFILE_HW_RST); -- house keeping: force writing zero to x0 if it's a phys. register
fetch_engine.reset <= '1';
exe_engine.state_nxt <= BRANCHED;
when EXECUTE => -- decode and execute instruction (control will be here for exactly 1 cycle in any case)
-- [NOTE] register file is read in this stage; due to the sync read, data will be available in the _next_ state
@ -741,77 +741,73 @@ begin
-- ALU core operation --
case funct3_v is
when funct3_subadd_c => ctrl_nxt.alu_op <= alu_op_add_c; -- ADD(I), SUB
when funct3_slt_c => ctrl_nxt.alu_op <= alu_op_slt_c; -- SLT(I)
when funct3_sltu_c => ctrl_nxt.alu_op <= alu_op_slt_c; -- SLTU(I)
when funct3_xor_c => ctrl_nxt.alu_op <= alu_op_xor_c; -- XOR(I)
when funct3_or_c => ctrl_nxt.alu_op <= alu_op_or_c; -- OR(I)
when funct3_and_c => ctrl_nxt.alu_op <= alu_op_and_c; -- AND(I)
when others => ctrl_nxt.alu_op <= alu_op_zero_c;
when funct3_sadd_c => ctrl_nxt.alu_op <= alu_op_add_c; -- ADD(I), SUB
when funct3_slt_c => ctrl_nxt.alu_op <= alu_op_slt_c; -- SLT(I)
when funct3_sltu_c => ctrl_nxt.alu_op <= alu_op_slt_c; -- SLTU(I)
when funct3_xor_c => ctrl_nxt.alu_op <= alu_op_xor_c; -- XOR(I)
when funct3_or_c => ctrl_nxt.alu_op <= alu_op_or_c; -- OR(I)
when funct3_and_c => ctrl_nxt.alu_op <= alu_op_and_c; -- AND(I)
when others => ctrl_nxt.alu_op <= alu_op_zero_c;
end case;
-- addition/subtraction control --
if (funct3_v(2 downto 1) = funct3_slt_c(2 downto 1)) or -- SLT(I), SLTU(I)
((funct3_v = funct3_subadd_c) and (opcode(5) = '1') and (execute_engine.ir(instr_funct7_msb_c-1) = '1')) then -- SUB
((funct3_v = funct3_sadd_c) and (opcode(5) = '1') and (exe_engine.ir(instr_funct7_msb_c-1) = '1')) then -- SUB
ctrl_nxt.alu_sub <= '1';
end if;
-- is base rv32i/e ALU[I] instruction (excluding shifts)? --
if ((opcode(5) = '0') and (funct3_v /= funct3_sll_c) and (funct3_v /= funct3_sr_c)) or -- base ALUI instruction (excluding SLLI, SRLI, SRAI)
((opcode(5) = '1') and (((funct3_v = funct3_subadd_c) and (funct7_v = "0000000")) or
((funct3_v = funct3_subadd_c) and (funct7_v = "0100000")) or
((funct3_v = funct3_slt_c) and (funct7_v = "0000000")) or
((funct3_v = funct3_sltu_c) and (funct7_v = "0000000")) or
((funct3_v = funct3_xor_c) and (funct7_v = "0000000")) or
((funct3_v = funct3_or_c) and (funct7_v = "0000000")) or
((funct3_v = funct3_and_c) and (funct7_v = "0000000")) -- base ALU instruction (excluding SLL, SRL, SRA)?
)) then
ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception)
execute_engine.state_nxt <= DISPATCH;
((opcode(5) = '1') and (((funct3_v = funct3_sadd_c) and (funct7_v = "0000000")) or ((funct3_v = funct3_sadd_c) and (funct7_v = "0100000")) or
((funct3_v = funct3_slt_c) and (funct7_v = "0000000")) or ((funct3_v = funct3_sltu_c) and (funct7_v = "0000000")) or
((funct3_v = funct3_xor_c) and (funct7_v = "0000000")) or ((funct3_v = funct3_or_c) and (funct7_v = "0000000")) or
((funct3_v = funct3_and_c) and (funct7_v = "0000000")))) then -- base ALU instruction (excluding SLL, SRL, SRA)?
ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception)
exe_engine.state_nxt <= DISPATCH;
else -- [NOTE] potential illegal ALU[I] instruction are handled as multi-cycle operations that will time-out if no co-processor responds
ctrl_nxt.alu_cp_alu <= '1'; -- trigger ALU[I] opcode-space co-processor
execute_engine.state_nxt <= ALU_WAIT;
ctrl_nxt.alu_cp_alu <= '1'; -- trigger ALU[I] opcode-space co-processor
exe_engine.state_nxt <= ALU_WAIT;
end if;
-- load upper immediate --
when opcode_lui_c =>
ctrl_nxt.alu_op <= alu_op_movb_c; -- pass immediate
ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception)
execute_engine.state_nxt <= DISPATCH;
ctrl_nxt.alu_op <= alu_op_movb_c; -- pass immediate
ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception)
exe_engine.state_nxt <= DISPATCH;
-- add upper immediate to PC --
when opcode_auipc_c =>
ctrl_nxt.alu_op <= alu_op_add_c; -- add PC and immediate
ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception)
execute_engine.state_nxt <= DISPATCH;
ctrl_nxt.alu_op <= alu_op_add_c; -- add PC and immediate
ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception)
exe_engine.state_nxt <= DISPATCH;
-- memory access --
when opcode_load_c | opcode_store_c | opcode_amo_c =>
execute_engine.state_nxt <= MEM_REQ;
exe_engine.state_nxt <= MEM_REQ;
-- branch / jump-and-link (with register) --
when opcode_branch_c | opcode_jal_c | opcode_jalr_c =>
execute_engine.state_nxt <= BRANCH;
exe_engine.state_nxt <= BRANCH;
-- memory fence operations (execute even if illegal funct3) --
when opcode_fence_c =>
ctrl_nxt.lsu_fence <= '1'; -- [NOTE] fence == fence.i; ignore all ordering bits
execute_engine.state_nxt <= RESTART; -- reset instruction fetch + IPB (actually only required for fence.i)
ctrl_nxt.lsu_fence <= '1'; -- [NOTE] fence == fence.i; ignore all ordering bits
exe_engine.state_nxt <= RESTART; -- reset instruction fetch + IPB (actually only required for fence.i)
-- FPU: floating-point operations --
when opcode_fop_c =>
ctrl_nxt.alu_cp_fpu <= '1'; -- trigger FPU co-processor
execute_engine.state_nxt <= ALU_WAIT; -- will be aborted via monitor timeout if FPU is not implemented
ctrl_nxt.alu_cp_fpu <= '1'; -- trigger FPU co-processor
exe_engine.state_nxt <= ALU_WAIT; -- will be aborted via monitor timeout if FPU is not implemented
-- CFU: custom RISC-V instructions --
when opcode_cust0_c | opcode_cust1_c =>
ctrl_nxt.alu_cp_cfu <= '1'; -- trigger CFU co-processor
execute_engine.state_nxt <= ALU_WAIT; -- will be aborted via monitor timeout if CFU is not implemented
ctrl_nxt.alu_cp_cfu <= '1'; -- trigger CFU co-processor
exe_engine.state_nxt <= ALU_WAIT; -- will be aborted via monitor timeout if CFU is not implemented
-- environment/CSR operation or ILLEGAL opcode --
when others =>
csr.re_nxt <= '1';
execute_engine.state_nxt <= SYSTEM;
csr.re_nxt <= '1';
exe_engine.state_nxt <= SYSTEM;
end case; -- /EXECUTE
@ -819,30 +815,30 @@ begin
-- ------------------------------------------------------------
ctrl_nxt.alu_op <= alu_op_cp_c;
if (alu_cp_done_i = '1') or (trap_ctrl.exc_buf(exc_illegal_c) = '1') then
ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception)
execute_engine.state_nxt <= DISPATCH;
ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception)
exe_engine.state_nxt <= DISPATCH;
end if;
when BRANCH => -- update next_pc on taken branches and jumps
-- ------------------------------------------------------------
ctrl_nxt.rf_wb_en <= opcode(2); -- save return address if link operation (won't happen if exception)
if (trap_ctrl.exc_buf(exc_illegal_c) = '0') and (execute_engine.branch_taken = '1') then -- valid taken branch
fetch_engine.reset <= '1'; -- reset instruction fetch to restart at modified PC
execute_engine.state_nxt <= BRANCHED; -- shortcut (faster than going to RESTART)
if (trap_ctrl.exc_buf(exc_illegal_c) = '0') and (exe_engine.branch_taken = '1') then -- valid taken branch
fetch_engine.reset <= '1'; -- reset instruction fetch to restart at modified PC
exe_engine.state_nxt <= BRANCHED; -- shortcut (faster than going to RESTART)
else
execute_engine.state_nxt <= DISPATCH;
exe_engine.state_nxt <= DISPATCH;
end if;
when BRANCHED => -- delay cycle to wait for reset of pipeline front-end (instruction fetch)
-- ------------------------------------------------------------
execute_engine.state_nxt <= DISPATCH;
exe_engine.state_nxt <= DISPATCH;
when MEM_REQ => -- trigger memory request
-- ------------------------------------------------------------
if (trap_ctrl.exc_buf(exc_illegal_c) = '0') then -- memory request only if not an illegal instruction
ctrl_nxt.lsu_req <= '1'; -- memory access request
end if;
execute_engine.state_nxt <= MEM_WAIT;
exe_engine.state_nxt <= MEM_WAIT;
when MEM_WAIT => -- wait for bus transaction to finish
-- ------------------------------------------------------------
@ -853,29 +849,29 @@ begin
if (RISCV_ISA_Zalrsc and (opcode(2) = opcode_amo_c(2))) or (opcode(5) = '0') then -- atomic operation / normal load
ctrl_nxt.rf_wb_en <= '1'; -- allow write-back to register file (won't happen in case of exception)
end if;
execute_engine.state_nxt <= DISPATCH;
exe_engine.state_nxt <= DISPATCH;
end if;
when SLEEP => -- sleep mode
-- ------------------------------------------------------------
if (trap_ctrl.wakeup = '1') then
execute_engine.state_nxt <= DISPATCH;
exe_engine.state_nxt <= DISPATCH;
end if;
when others => -- SYSTEM - CSR/ENVIRONMENT operation; no effect if illegal instruction
-- ------------------------------------------------------------
execute_engine.state_nxt <= DISPATCH; -- default
exe_engine.state_nxt <= DISPATCH; -- default
if (funct3_v = funct3_env_c) and (trap_ctrl.exc_buf(exc_illegal_c) = '0') then -- non-illegal ENVIRONMENT
case execute_engine.ir(instr_funct12_lsb_c+2 downto instr_funct12_lsb_c) is -- three LSBs are sufficient here
when "000" => trap_ctrl.ecall <= '1'; -- ecall
when "001" => trap_ctrl.ebreak <= '1'; -- ebreak
when "010" => execute_engine.state_nxt <= TRAP_EXIT; -- xret
when "101" => execute_engine.state_nxt <= SLEEP; -- wfi
when others => execute_engine.state_nxt <= DISPATCH; -- illegal or CSR operation
case exe_engine.ir(instr_funct12_lsb_c+2 downto instr_funct12_lsb_c) is -- three LSBs are sufficient here
when "000" => trap_ctrl.ecall <= '1'; -- ecall
when "001" => trap_ctrl.ebreak <= '1'; -- ebreak
when "010" => exe_engine.state_nxt <= TRAP_EXIT; -- xret
when "101" => exe_engine.state_nxt <= SLEEP; -- wfi
when others => exe_engine.state_nxt <= DISPATCH; -- illegal or CSR operation
end case;
end if;
-- always write to CSR (if CSR instruction); ENVIRONMENT operations have rs1/imm5 = zero so this won't happen then --
if (funct3_v = funct3_csrrw_c) or (funct3_v = funct3_csrrwi_c) or (execute_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c) /= "00000") then
if (funct3_v = funct3_csrrw_c) or (funct3_v = funct3_csrrwi_c) or (exe_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c) /= "00000") then
csr.we_nxt <= '1'; -- CSRRW[I]: always write CSR; CSRR[S/C][I]: write CSR if rs1/imm5 is NOT zero
end if;
-- always write to RF; ENVIRONMENT operations have rd = zero so this does not hurt --
@ -890,9 +886,9 @@ begin
-- register file --
ctrl_o.rf_wb_en <= ctrl.rf_wb_en and (not trap_ctrl.exc_fire); -- inhibit write-back if exception
ctrl_o.rf_rs1 <= execute_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c);
ctrl_o.rf_rs2 <= execute_engine.ir(instr_rs2_msb_c downto instr_rs2_lsb_c);
ctrl_o.rf_rd <= execute_engine.ir(instr_rd_msb_c downto instr_rd_lsb_c);
ctrl_o.rf_rs1 <= exe_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c);
ctrl_o.rf_rs2 <= exe_engine.ir(instr_rs2_msb_c downto instr_rs2_lsb_c);
ctrl_o.rf_rd <= exe_engine.ir(instr_rd_msb_c downto instr_rd_lsb_c);
ctrl_o.rf_zero_we <= ctrl.rf_zero_we;
-- alu --
ctrl_o.alu_op <= ctrl.alu_op;
@ -906,18 +902,18 @@ begin
-- load/store unit --
ctrl_o.lsu_req <= ctrl.lsu_req;
ctrl_o.lsu_rw <= ctrl.lsu_rw;
ctrl_o.lsu_mo_we <= '1' when (execute_engine.state = MEM_REQ) else '0'; -- write memory output registers (data & address)
ctrl_o.lsu_mo_we <= '1' when (exe_engine.state = MEM_REQ) else '0'; -- write memory output registers (data & address)
ctrl_o.lsu_fence <= ctrl.lsu_fence;
ctrl_o.lsu_priv <= csr.mstatus_mpp when (csr.mstatus_mprv = '1') else csr.privilege_eff; -- effective privilege level for loads/stores in M-mode
-- instruction word bit fields --
ctrl_o.ir_funct3 <= execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c);
ctrl_o.ir_funct12 <= execute_engine.ir(instr_funct12_msb_c downto instr_funct12_lsb_c);
ctrl_o.ir_funct3 <= exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c);
ctrl_o.ir_funct12 <= exe_engine.ir(instr_funct12_msb_c downto instr_funct12_lsb_c);
ctrl_o.ir_opcode <= opcode;
-- cpu status --
ctrl_o.cpu_priv <= csr.privilege_eff;
ctrl_o.cpu_sleep <= sleep_mode;
ctrl_o.cpu_trap <= trap_ctrl.env_enter;
ctrl_o.cpu_debug <= debug_ctrl.running;
ctrl_o.cpu_debug <= debug_ctrl.run;
-- ****************************************************************************************************************************
@ -936,7 +932,7 @@ begin
end process multi_cycle_monitor;
-- timeout counter (allow mapping of entire logic into the LUTs in front of the carry-chain) --
monitor.cnt_add <= monitor.cnt when (execute_engine.state = ALU_WAIT) else (others => '0');
monitor.cnt_add <= monitor.cnt when (exe_engine.state = ALU_WAIT) else (others => '0');
-- raise illegal instruction exception if a multi-cycle instruction takes longer than a bound amount of time --
monitor.exc <= monitor.cnt(monitor.cnt'left);
@ -944,11 +940,11 @@ begin
-- CSR Access Check -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
csr_check: process(execute_engine.ir, debug_ctrl.running, csr)
csr_check: process(exe_engine.ir, debug_ctrl.run, csr)
variable csr_addr_v : std_ulogic_vector(11 downto 0);
begin
-- CSR address right from the instruction word --
csr_addr_v := execute_engine.ir(instr_imm12_msb_c downto instr_imm12_lsb_c);
-- shortcut: CSR address right from the instruction word --
csr_addr_v := exe_engine.ir(instr_imm12_msb_c downto instr_imm12_lsb_c);
-- ------------------------------------------------------------
-- Available at all
@ -1015,9 +1011,9 @@ begin
-- R/W capabilities
-- ------------------------------------------------------------
if (csr_addr_v(11 downto 10) = "11") and -- CSR is read-only
((execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrw_c) or -- will always write to CSR
(execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrwi_c) or -- will always write to CSR
(execute_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c) /= "00000")) then -- clear/set instructions: write to CSR only if rs1/imm5 is NOT zero
((exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrw_c) or -- will always write to CSR
(exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrwi_c) or -- will always write to CSR
(exe_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c) /= "00000")) then -- clear/set instructions: write to CSR only if rs1/imm5 is NOT zero
csr_valid(1) <= '0'; -- invalid access
else
csr_valid(1) <= '1'; -- access granted
@ -1027,7 +1023,7 @@ begin
-- Privilege level
-- ------------------------------------------------------------
if (csr_addr_v(11 downto 2) = csr_dcsr_c(11 downto 2)) and -- debug-mode-only CSR (dcsr, dpc, dscratch)?
RISCV_ISA_Sdext and (debug_ctrl.running = '0') then -- debug-mode implemented and not running?
RISCV_ISA_Sdext and (debug_ctrl.run = '0') then -- debug-mode implemented and not running?
csr_valid(0) <= '0'; -- invalid access
elsif RISCV_ISA_Zicntr and RISCV_ISA_U and (csr.privilege_eff = '0') and -- any user-mode counters available and in user-mode?
(csr_addr_v(11 downto 8) = csr_cycle_c(11 downto 8)) and -- user-mode counter access
@ -1045,40 +1041,40 @@ begin
-- Illegal Instruction Check --------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
illegal_check: process(execute_engine, csr, csr_valid, debug_ctrl)
illegal_check: process(exe_engine, csr, csr_valid, debug_ctrl)
begin
case execute_engine.ir(instr_opcode_msb_c downto instr_opcode_lsb_c) is -- check entire opcode
case exe_engine.ir(instr_opcode_msb_c downto instr_opcode_lsb_c) is -- check entire opcode
when opcode_lui_c | opcode_auipc_c | opcode_jal_c => -- U-instruction type
illegal_cmd <= '0'; -- all encodings are valid
when opcode_jalr_c => -- unconditional jump-and-link
case execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is
case exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is
when "000" => illegal_cmd <= '0';
when others => illegal_cmd <= '1';
end case;
when opcode_branch_c => -- conditional branch
case execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is
case exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is
when funct3_beq_c | funct3_bne_c | funct3_blt_c | funct3_bge_c | funct3_bltu_c | funct3_bgeu_c => illegal_cmd <= '0';
when others => illegal_cmd <= '1';
end case;
when opcode_load_c => -- memory load
case execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is
case exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is
when funct3_lb_c | funct3_lh_c | funct3_lw_c | funct3_lbu_c | funct3_lhu_c => illegal_cmd <= '0';
when others => illegal_cmd <= '1';
end case;
when opcode_store_c => -- memory store
case execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is
case exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is
when funct3_sb_c | funct3_sh_c | funct3_sw_c => illegal_cmd <= '0';
when others => illegal_cmd <= '1';
end case;
when opcode_amo_c => -- atomic memory operation (LR/SC)
if RISCV_ISA_Zalrsc and (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = "010") and
(execute_engine.ir(instr_funct7_lsb_c+6 downto instr_funct7_lsb_c+3) = "0001") then -- LR.W/SC.W
if RISCV_ISA_Zalrsc and (exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = "010") and
(exe_engine.ir(instr_funct7_lsb_c+6 downto instr_funct7_lsb_c+3) = "0001") then -- LR.W/SC.W
illegal_cmd <= '0';
else
illegal_cmd <= '1';
@ -1088,25 +1084,26 @@ begin
illegal_cmd <= '0'; -- [NOTE] valid if not terminated by the "instruction execution monitor"
when opcode_fence_c => -- memory ordering
case execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is
case exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is
when funct3_fence_c | funct3_fencei_c => illegal_cmd <= '0';
when others => illegal_cmd <= '1';
end case;
when opcode_system_c => -- CSR / system instruction
if (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_env_c) then -- system environment
if (execute_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c) = "00000") and (execute_engine.ir(instr_rd_msb_c downto instr_rd_lsb_c) = "00000") then
case execute_engine.ir(instr_funct12_msb_c downto instr_funct12_lsb_c) is
when funct12_ecall_c | funct12_ebreak_c => illegal_cmd <= '0'; -- ecall and ebreak are always allowed
when funct12_mret_c => illegal_cmd <= (not csr.privilege) or debug_ctrl.running; -- mret allowed in (real/non-debug) M-mode only
when funct12_dret_c => illegal_cmd <= not debug_ctrl.running; -- dret allowed in debug mode only
when funct12_wfi_c => illegal_cmd <= (not csr.privilege) and csr.mstatus_tw; -- wfi allowed in M-mode or if TW is zero
when others => illegal_cmd <= '1'; -- undefined
if (exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_env_c) then -- system environment
if (exe_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c) = "00000") and (exe_engine.ir(instr_rd_msb_c downto instr_rd_lsb_c) = "00000") then
case exe_engine.ir(instr_funct12_msb_c downto instr_funct12_lsb_c) is
when funct12_ecall_c => illegal_cmd <= '0'; -- ecall is always allowed
when funct12_ebreak_c => illegal_cmd <= '0'; -- ebreak is always allowed
when funct12_mret_c => illegal_cmd <= (not csr.privilege) or debug_ctrl.run; -- mret allowed in (real/non-debug) M-mode only
when funct12_dret_c => illegal_cmd <= not debug_ctrl.run; -- dret allowed in debug mode only
when funct12_wfi_c => illegal_cmd <= (not csr.privilege) and csr.mstatus_tw; -- wfi allowed in M-mode or if TW is zero
when others => illegal_cmd <= '1'; -- undefined
end case;
else
illegal_cmd <= '1';
end if;
elsif (csr_valid /= "111") or (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csril_c) then -- invalid CSR operation
elsif (csr_valid /= "111") or (exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csril_c) then -- invalid CSR operation
illegal_cmd <= '1';
else
illegal_cmd <= '0';
@ -1121,7 +1118,7 @@ begin
-- Illegal Operation Check ----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
trap_ctrl.instr_il <= '1' when ((execute_engine.state = EXECUTE) or (execute_engine.state = ALU_WAIT)) and -- check in execution states only
trap_ctrl.instr_il <= '1' when ((exe_engine.state = EXECUTE) or (exe_engine.state = ALU_WAIT)) and -- check in execution states only
((monitor.exc = '1') or (illegal_cmd = '1')) else '0'; -- instruction timeout or illegal instruction
@ -1162,8 +1159,8 @@ begin
if RISCV_ISA_Sdext then
trap_ctrl.exc_buf(exc_ebreak_c) <= (not trap_ctrl.env_enter) and (trap_ctrl.exc_buf(exc_ebreak_c) or
(trap_ctrl.hwtrig and (not csr.tdata1_action)) or -- trigger module fires and enter-debug-action is disabled
(trap_ctrl.ebreak and ( csr.privilege) and (not csr.dcsr_ebreakm) and (not debug_ctrl.running)) or -- enter M-mode handler on ebreak in M-mode
(trap_ctrl.ebreak and (not csr.privilege) and (not csr.dcsr_ebreaku) and (not debug_ctrl.running))); -- enter M-mode handler on ebreak in U-mode
(trap_ctrl.ebreak and ( csr.privilege) and (not csr.dcsr_ebreakm) and (not debug_ctrl.run)) or -- enter M-mode handler on ebreak in M-mode
(trap_ctrl.ebreak and (not csr.privilege) and (not csr.dcsr_ebreaku) and (not debug_ctrl.run))); -- enter M-mode handler on ebreak in U-mode
else
trap_ctrl.exc_buf(exc_ebreak_c) <= (trap_ctrl.exc_buf(exc_ebreak_c) or trap_ctrl.ebreak or (trap_ctrl.hwtrig and (not csr.tdata1_action))) and (not trap_ctrl.env_enter);
end if;
@ -1273,7 +1270,7 @@ begin
end process trap_priority;
-- exception program counter: async. interrupt or sync. exception? --
trap_ctrl.epc <= execute_engine.next_pc when (trap_ctrl.cause(trap_ctrl.cause'left) = '1') else execute_engine.pc;
trap_ctrl.epc <= exe_engine.next_pc when (trap_ctrl.cause(trap_ctrl.cause'left) = '1') else exe_engine.pc;
-- Trap Controller ------------------------------------------------------------------------
@ -1295,7 +1292,7 @@ begin
end if;
end if;
-- trap environment has just been entered --
if (execute_engine.state = EXECUTE) then -- first instruction of trap environment is executing
if (exe_engine.state = EXECUTE) then -- first instruction of trap environment is executing
trap_ctrl.env_entered <= '0';
elsif (trap_ctrl.env_enter = '1') then
trap_ctrl.env_entered <= '1';
@ -1306,26 +1303,23 @@ begin
-- any exception? --
trap_ctrl.exc_fire <= '1' when (or_reduce_f(trap_ctrl.exc_buf) = '1') else '0'; -- sync. exceptions CANNOT be masked
-- any "normal" system interrupt? --
-- system interrupt? --
trap_ctrl.irq_fire(0) <= '1' when
(execute_engine.state = EXECUTE) and -- trigger system IRQ only in EXECUTE state
(exe_engine.state = EXECUTE) and -- trigger system IRQ only in EXECUTE state
(or_reduce_f(trap_ctrl.irq_buf(irq_firq_15_c downto irq_msi_irq_c)) = '1') and -- pending system IRQ
((csr.mstatus_mie = '1') or (csr.privilege = priv_mode_u_c)) and -- IRQ only when in M-mode and MIE=1 OR when in U-mode
(debug_ctrl.running = '0') and (csr.dcsr_step = '0') -- no system IRQs when in debug-mode / during single-stepping
else '0';
(debug_ctrl.run = '0') and (csr.dcsr_step = '0') else '0'; -- no system IRQs when in debug-mode / during single-stepping
-- debug-entry halt interrupt? --
trap_ctrl.irq_fire(1) <= '1' when
((execute_engine.state = EXECUTE) or (execute_engine.state = BRANCHED)) and -- allow halt also after "reset" (#879)
(trap_ctrl.irq_buf(irq_db_halt_c) = '1') -- pending external halt
else '0';
((exe_engine.state = EXECUTE) or (exe_engine.state = BRANCHED)) and -- allow halt also after "reset" (#879)
(trap_ctrl.irq_buf(irq_db_halt_c) = '1') else '0'; -- pending external halt
-- debug-entry single-step interrupt? --
trap_ctrl.irq_fire(2) <= '1' when
((execute_engine.state = EXECUTE) or -- trigger single-step in EXECUTE state
((trap_ctrl.env_entered = '1') and (execute_engine.state = BRANCHED))) and -- also allow triggering when entering a system trap (#887)
(trap_ctrl.irq_buf(irq_db_step_c) = '1') -- pending single-step halt
else '0';
((exe_engine.state = EXECUTE) or -- trigger single-step in EXECUTE state
((trap_ctrl.env_entered = '1') and (exe_engine.state = BRANCHED))) and -- also allow triggering when entering a system trap (#887)
(trap_ctrl.irq_buf(irq_db_step_c) = '1') else '0'; -- pending single-step halt
-- CPU Sleep Mode Control -----------------------------------------------------------------
@ -1335,7 +1329,7 @@ begin
if (rstn_i = '0') then
sleep_mode <= '0';
elsif rising_edge(clk_aux_i) then
if (execute_engine.state = SLEEP) and -- instruction execution has halted
if (exe_engine.state = SLEEP) and -- instruction execution has halted
(ipb.free /= "11") and -- instruction fetch has halted
(trap_ctrl.wakeup = '0') then -- no wake-up request
sleep_mode <= '1';
@ -1346,7 +1340,7 @@ begin
end process sleep_control;
-- wake-up from / do not enter sleep mode: during debugging or on pending IRQ --
trap_ctrl.wakeup <= or_reduce_f(trap_ctrl.irq_buf) or debug_ctrl.running or csr.dcsr_step;
trap_ctrl.wakeup <= or_reduce_f(trap_ctrl.irq_buf) or debug_ctrl.run or csr.dcsr_step;
-- ****************************************************************************************************************************
@ -1362,9 +1356,9 @@ begin
elsif rising_edge(clk_i) then
-- update only for actual CSR operations to reduce switching activity on the CSR address net --
if (opcode = opcode_system_c) then
csr.addr(11 downto 10) <= execute_engine.ir(instr_imm12_lsb_c+11 downto instr_imm12_lsb_c+10);
csr.addr(9 downto 8) <= replicate_f(execute_engine.ir(instr_imm12_lsb_c+8), 2); -- M-mode (11) and U-mode (00) CSRs only
csr.addr(7 downto 0) <= execute_engine.ir(instr_imm12_lsb_c+7 downto instr_imm12_lsb_c);
csr.addr(11 downto 10) <= exe_engine.ir(instr_imm12_lsb_c+11 downto instr_imm12_lsb_c+10);
csr.addr(9 downto 8) <= replicate_f(exe_engine.ir(instr_imm12_lsb_c+8), 2); -- M-mode (11) and U-mode (00) CSRs only
csr.addr(7 downto 0) <= exe_engine.ir(instr_imm12_lsb_c+7 downto instr_imm12_lsb_c);
end if;
end if;
end process csr_addr_reg;
@ -1372,18 +1366,18 @@ begin
-- CSR Write-Data ALU ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
csr_write_data: process(execute_engine.ir, csr.rdata, rf_rs1_i)
csr_write_data: process(exe_engine.ir, csr.rdata, rf_rs1_i)
variable tmp_v : std_ulogic_vector(XLEN-1 downto 0);
begin
-- immediate/register operand --
if (execute_engine.ir(instr_funct3_msb_c) = '1') then
if (exe_engine.ir(instr_funct3_msb_c) = '1') then
tmp_v := (others => '0');
tmp_v(4 downto 0) := execute_engine.ir(19 downto 15); -- uimm5
tmp_v(4 downto 0) := exe_engine.ir(19 downto 15); -- uimm5
else
tmp_v := rf_rs1_i;
end if;
-- tiny ALU to compute CSR write data --
case execute_engine.ir(instr_funct3_msb_c-1 downto instr_funct3_lsb_c) is
case exe_engine.ir(instr_funct3_msb_c-1 downto instr_funct3_lsb_c) is
when "10" => csr.wdata <= csr.rdata or tmp_v; -- set
when "11" => csr.wdata <= csr.rdata and (not tmp_v); -- clear
when others => csr.wdata <= tmp_v; -- write
@ -1416,7 +1410,7 @@ begin
csr.mie_firq <= (others => '0');
csr.mtvec <= (others => '0');
csr.mscratch <= x"19880704";
csr.mepc <= (others => '0');
csr.mepc <= BOOT_ADDR(XLEN-1 downto 2) & "00"; -- 32-bit-aligned boot address
csr.mcause <= (others => '0');
csr.mtval <= (others => '0');
csr.mtinst <= (others => '0');
@ -1530,18 +1524,18 @@ begin
-- --------------------------------------------------------------------
when csr_tdata1_c => -- match control
if RISCV_ISA_Sdtrig then
if (csr.tdata1_dmode = '0') or (debug_ctrl.running = '1') then -- write access from debug-mode only?
if (csr.tdata1_dmode = '0') or (debug_ctrl.run = '1') then -- write access from debug-mode only?
csr.tdata1_execute <= csr.wdata(2);
csr.tdata1_action <= csr.wdata(12);
end if;
if (debug_ctrl.running = '1') then -- writable from debug-mode only
if (debug_ctrl.run = '1') then -- writable from debug-mode only
csr.tdata1_dmode <= csr.wdata(27);
end if;
end if;
when csr_tdata2_c => -- address compare
if RISCV_ISA_Sdtrig then
if (csr.tdata1_dmode = '0') or (debug_ctrl.running = '1') then -- write access from debug-mode only?
if (csr.tdata1_dmode = '0') or (debug_ctrl.run = '1') then -- write access from debug-mode only?
csr.tdata2 <= csr.wdata(XLEN-1 downto 1) & '0';
end if;
end if;
@ -1559,10 +1553,10 @@ begin
elsif (trap_ctrl.env_enter = '1') then
-- NORMAL trap entry - no CSR update when in debug-mode! --
if (not RISCV_ISA_Sdext) or ((trap_ctrl.cause(5) = '0') and (debug_ctrl.running = '0')) then
if (not RISCV_ISA_Sdext) or ((trap_ctrl.cause(5) = '0') and (debug_ctrl.run = '0')) then
csr.mcause <= trap_ctrl.cause(trap_ctrl.cause'left) & trap_ctrl.cause(4 downto 0); -- trap type & identifier
csr.mepc <= trap_ctrl.epc(XLEN-1 downto 1) & '0'; -- trap PC
-- trap value --
-- trap value (load/store trap address only, permitted by RISC-V priv. spec.) --
if (trap_ctrl.cause(6) = '0') and (trap_ctrl.cause(2) = '1') then -- load/store misaligned/access faults [hacky!]
csr.mtval <= lsu_mar_i; -- faulting data access address
else -- everything else including all interrupts
@ -1570,8 +1564,8 @@ begin
end if;
-- trap instruction --
if (trap_ctrl.cause(6) = '0') then -- exception
csr.mtinst <= execute_engine.ir;
if (execute_engine.is_ci = '1') and RISCV_ISA_C then
csr.mtinst <= exe_engine.ir;
if (exe_engine.is_ci = '1') and RISCV_ISA_C then
csr.mtinst(1) <= '0'; -- RISC-V priv. spec: clear bit 1 if compressed instruction
end if;
else -- interrupt
@ -1584,8 +1578,8 @@ begin
csr.mstatus_mpp <= csr.privilege; -- backup previous privilege mode
end if;
-- DEBUG MODE entry - no CSR update when already in debug-mode! --
if RISCV_ISA_Sdext and (trap_ctrl.cause(5) = '1') and (debug_ctrl.running = '0') then
-- DEBUG trap entry - no CSR update when already in debug-mode! --
if RISCV_ISA_Sdext and (trap_ctrl.cause(5) = '1') and (debug_ctrl.run = '0') then
csr.dcsr_cause <= trap_ctrl.cause(2 downto 0); -- trap cause
csr.dcsr_prv <= csr.privilege; -- current privilege mode when debug mode was entered
csr.dpc <= trap_ctrl.epc(XLEN-1 downto 1) & '0'; -- trap PC
@ -1597,7 +1591,7 @@ begin
elsif (trap_ctrl.env_exit = '1') then
-- return from debug mode --
if RISCV_ISA_Sdext and (debug_ctrl.running = '1') then
if RISCV_ISA_Sdext and (debug_ctrl.run = '1') then
if RISCV_ISA_U then
csr.privilege <= csr.dcsr_prv;
if (csr.dcsr_prv /= priv_mode_m_c) then
@ -1624,7 +1618,7 @@ begin
-- ********************************************************************************
-- hardwired bits --
csr.mcountinhibit(1) <= '0'; -- "time" not implemented
csr.mcountinhibit(1) <= '0'; -- "time" not defined
-- no base counters --
if not RISCV_ISA_Zicntr then
@ -1677,7 +1671,7 @@ begin
end process csr_write_access;
-- effective privilege mode is MACHINE when in debug mode --
csr.privilege_eff <= priv_mode_m_c when (debug_ctrl.running = '1') else csr.privilege;
csr.privilege_eff <= priv_mode_m_c when (debug_ctrl.run = '1') else csr.privilege;
-- CSR Read Access ------------------------------------------------------------------------
@ -1911,9 +1905,8 @@ begin
csr.rdata(23) <= bool_to_ulogic_f(RISCV_ISA_Zbb); -- Zbb: basic bit-manipulation extension
csr.rdata(24) <= bool_to_ulogic_f(RISCV_ISA_Zbs); -- Zbs: single-bit bit-manipulation extension
csr.rdata(25) <= bool_to_ulogic_f(RISCV_ISA_Zalrsc); -- Zalrsc: reservation set extension
-- reserved --
csr.rdata(26) <= '0';
csr.rdata(27) <= '0';
csr.rdata(26) <= '0'; -- reserved
csr.rdata(27) <= '0'; -- reserved
-- tuning options --
csr.rdata(28) <= bool_to_ulogic_f(REGFILE_HW_RST); -- full hardware reset of register file
csr.rdata(29) <= bool_to_ulogic_f(FAST_MUL_EN); -- DSP-based multiplication (M extensions only)
@ -2075,31 +2068,31 @@ begin
cnt.inc <= (others => (others => '0'));
elsif rising_edge(clk_i) then
-- base counters --
cnt.inc(0) <= (others => (cnt_event(hpmcnt_event_cy_c) and (not csr.mcountinhibit(0)) and (not debug_ctrl.running)));
cnt.inc(0) <= (others => (cnt_event(hpmcnt_event_cy_c) and (not csr.mcountinhibit(0)) and (not debug_ctrl.run)));
cnt.inc(1) <= (others => '0'); -- time: not available
cnt.inc(2) <= (others => (cnt_event(hpmcnt_event_ir_c) and (not csr.mcountinhibit(2)) and (not debug_ctrl.running)));
cnt.inc(2) <= (others => (cnt_event(hpmcnt_event_ir_c) and (not csr.mcountinhibit(2)) and (not debug_ctrl.run)));
-- hpm counters --
for i in 3 to 15 loop
cnt.inc(i) <= (others => (or_reduce_f(cnt_event and hpmevent_cfg(i)) and (not csr.mcountinhibit(i)) and (not debug_ctrl.running)));
cnt.inc(i) <= (others => (or_reduce_f(cnt_event and hpmevent_cfg(i)) and (not csr.mcountinhibit(i)) and (not debug_ctrl.run)));
end loop;
end if;
end process counter_event;
-- RISC-V-compliant counter events --
cnt_event(hpmcnt_event_cy_c) <= '1' when (sleep_mode = '0') else '0'; -- cycle: active cycle
cnt_event(hpmcnt_event_tm_c) <= '0'; -- time: not available
cnt_event(hpmcnt_event_ir_c) <= '1' when (execute_engine.state = EXECUTE) else '0'; -- instret: retired (==executed) instruction
cnt_event(hpmcnt_event_cy_c) <= '1' when (sleep_mode = '0') else '0'; -- cycle: active cycle
cnt_event(hpmcnt_event_tm_c) <= '0'; -- time: not available
cnt_event(hpmcnt_event_ir_c) <= '1' when (exe_engine.state = EXECUTE) else '0'; -- instret: retired (==executed!) instruction
-- NEORV32-specific counter events --
cnt_event(hpmcnt_event_compr_c) <= '1' when (execute_engine.state = EXECUTE) and (execute_engine.is_ci = '1') else '0'; -- executed compressed instruction
cnt_event(hpmcnt_event_wait_dis_c) <= '1' when (execute_engine.state = DISPATCH) and (issue_engine.valid = "00") else '0'; -- instruction dispatch wait cycle
cnt_event(hpmcnt_event_wait_alu_c) <= '1' when (execute_engine.state = ALU_WAIT) else '0'; -- multi-cycle ALU co-processor wait cycle
cnt_event(hpmcnt_event_branch_c) <= '1' when (execute_engine.state = BRANCH) else '0'; -- executed branch instruction
cnt_event(hpmcnt_event_branched_c) <= '1' when (execute_engine.state = BRANCHED) else '0'; -- control flow transfer
cnt_event(hpmcnt_event_load_c) <= '1' when (ctrl.lsu_req = '1') and (ctrl.lsu_rw = '0') else '0'; -- executed load operation
cnt_event(hpmcnt_event_store_c) <= '1' when (ctrl.lsu_req = '1') and (ctrl.lsu_rw = '1') else '0'; -- executed store operation
cnt_event(hpmcnt_event_wait_lsu_c) <= '1' when (ctrl.lsu_req = '0') and (execute_engine.state = MEM_WAIT) else '0'; -- load/store unit memory wait cycle
cnt_event(hpmcnt_event_trap_c) <= '1' when (trap_ctrl.env_enter = '1') else '0'; -- entered trap
cnt_event(hpmcnt_event_compr_c) <= '1' when (exe_engine.state = EXECUTE) and (exe_engine.is_ci = '1') else '0'; -- executed compressed instruction
cnt_event(hpmcnt_event_wait_dis_c) <= '1' when (exe_engine.state = DISPATCH) and (issue_engine.valid = "00") else '0'; -- instruction dispatch wait cycle
cnt_event(hpmcnt_event_wait_alu_c) <= '1' when (exe_engine.state = ALU_WAIT) else '0'; -- multi-cycle ALU co-processor wait cycle
cnt_event(hpmcnt_event_branch_c) <= '1' when (exe_engine.state = BRANCH) else '0'; -- executed branch instruction
cnt_event(hpmcnt_event_branched_c) <= '1' when (exe_engine.state = BRANCHED) else '0'; -- control flow transfer
cnt_event(hpmcnt_event_load_c) <= '1' when (ctrl.lsu_req = '1') and (ctrl.lsu_rw = '0') else '0'; -- executed load operation
cnt_event(hpmcnt_event_store_c) <= '1' when (ctrl.lsu_req = '1') and (ctrl.lsu_rw = '1') else '0'; -- executed store operation
cnt_event(hpmcnt_event_wait_lsu_c) <= '1' when (ctrl.lsu_req = '0') and (exe_engine.state = MEM_WAIT) else '0'; -- load/store unit memory wait cycle
cnt_event(hpmcnt_event_trap_c) <= '1' when (trap_ctrl.env_enter = '1') else '0'; -- entered trap
-- ****************************************************************************************************************************
@ -2114,34 +2107,34 @@ begin
debug_control: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
debug_ctrl.running <= '0';
debug_ctrl.run <= '0';
elsif rising_edge(clk_i) then
if (debug_ctrl.running = '0') then -- debug mode OFFLINE
if (debug_ctrl.run = '0') then -- debug mode OFFLINE
if (trap_ctrl.env_enter = '1') and (trap_ctrl.cause(5) = '1') then -- waiting for entry event
debug_ctrl.running <= '1';
debug_ctrl.run <= '1';
end if;
else -- debug mode ONLINE
if (trap_ctrl.env_exit = '1') then -- waiting for exit event
debug_ctrl.running <= '0';
debug_ctrl.run <= '0';
end if;
end if;
end if;
end process debug_control;
-- debug mode entry triggers --
debug_ctrl.trig_hw <= trap_ctrl.hwtrig and (not debug_ctrl.running) and csr.tdata1_action and csr.tdata1_dmode; -- enter debug mode by HW trigger module
debug_ctrl.trig_break <= trap_ctrl.ebreak and (debug_ctrl.running or -- re-enter debug mode
debug_ctrl.trig_hw <= trap_ctrl.hwtrig and (not debug_ctrl.run) and csr.tdata1_action and csr.tdata1_dmode; -- enter debug mode by HW trigger module
debug_ctrl.trig_break <= trap_ctrl.ebreak and (debug_ctrl.run or -- re-enter debug mode
(( csr.privilege) and csr.dcsr_ebreakm) or -- enabled goto-debug-mode in machine mode on "ebreak"
((not csr.privilege) and csr.dcsr_ebreaku)); -- enabled goto-debug-mode in user mode on "ebreak"
debug_ctrl.trig_halt <= irq_dbg_i and (not debug_ctrl.running); -- external halt request (if not halted already)
debug_ctrl.trig_step <= csr.dcsr_step and (not debug_ctrl.running); -- single-step mode (trigger when NOT CURRENTLY in debug mode)
debug_ctrl.trig_halt <= irq_dbg_i and (not debug_ctrl.run); -- external halt request (if not halted already)
debug_ctrl.trig_step <= csr.dcsr_step and (not debug_ctrl.run); -- single-step mode (trigger when NOT CURRENTLY in debug mode)
end generate;
-- Sdext ISA extension not enabled --
debug_mode_disable:
if not RISCV_ISA_Sdext generate
debug_ctrl.running <= '0';
debug_ctrl.run <= '0';
debug_ctrl.trig_hw <= '0';
debug_ctrl.trig_break <= '0';
debug_ctrl.trig_halt <= '0';
@ -2177,7 +2170,7 @@ begin
-- trigger on instruction address match (trigger right BEFORE execution) --
hw_trigger_match <= '1' when (csr.tdata1_execute = '1') and -- trigger enabled to match on instruction address
(hw_trigger_fired = '0') and -- trigger has not fired yet
(csr.tdata2(XLEN-1 downto 1) = execute_engine.next_pc(XLEN-1 downto 1)) -- address match
(csr.tdata2(XLEN-1 downto 1) = exe_engine.next_pc(XLEN-1 downto 1)) -- address match
else '0';
-- status flag - set when trigger has fired --

View file

@ -72,7 +72,7 @@ begin
decoded(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alui_c;
decoded(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "00010"; -- stack pointer
decoded(instr_rd_msb_c downto instr_rd_lsb_c) <= "01" & instr_i(ci_rd_3_msb_c downto ci_rd_3_lsb_c);
decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_subadd_c;
decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_sadd_c;
decoded(instr_imm12_msb_c downto instr_imm12_lsb_c) <= "00" & instr_i(10 downto 7) & instr_i(12 downto 11) & instr_i(5) & instr_i(6) & "00";
if (instr_i(12 downto 5) = "00000000") then -- canonical illegal C instruction or C.ADDI4SPN with nzuimm = 0
illegal <= '1';
@ -131,7 +131,7 @@ begin
when "010" => -- C.LI
-- --------------------------------------------------------------------------------------
decoded(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alui_c;
decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_subadd_c;
decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_sadd_c;
decoded(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "00000"; -- x0
decoded(instr_rd_msb_c downto instr_rd_lsb_c) <= instr_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c);
decoded(instr_imm12_msb_c downto instr_imm12_lsb_c) <= replicate_f(instr_i(12),6) & instr_i(12) & instr_i(6 downto 2);
@ -140,7 +140,7 @@ begin
-- --------------------------------------------------------------------------------------
if (instr_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c) = "00010") then -- C.ADDI16SP
decoded(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alui_c;
decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_subadd_c;
decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_sadd_c;
decoded(instr_rd_msb_c downto instr_rd_lsb_c) <= instr_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c);
decoded(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "00010"; -- stack pointer
decoded(instr_rd_msb_c downto instr_rd_lsb_c) <= "00010"; -- stack pointer
@ -157,7 +157,7 @@ begin
when "000" => -- C.NOP (rd=0) / C.ADDI
-- --------------------------------------------------------------------------------------
decoded(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alui_c;
decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_subadd_c;
decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_sadd_c;
decoded(instr_rs1_msb_c downto instr_rs1_lsb_c) <= instr_i(ci_rs1_5_msb_c downto ci_rs1_5_lsb_c);
decoded(instr_rd_msb_c downto instr_rd_lsb_c) <= instr_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c);
decoded(instr_imm12_msb_c downto instr_imm12_lsb_c) <= replicate_f(instr_i(12),7) & instr_i(6 downto 2);
@ -188,7 +188,7 @@ begin
decoded(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alu_c;
case instr_i(6 downto 5) is
when "00" => -- C.SUB
decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_subadd_c;
decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_sadd_c;
decoded(instr_funct7_msb_c downto instr_funct7_lsb_c) <= "0100000";
when "01" => -- C.XOR
decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_xor_c;

View file

@ -1,6 +1,8 @@
-- ================================================================================ --
-- NEORV32 SoC - RISC-V-Compatible Debug Transport Module (DTM) --
-- -------------------------------------------------------------------------------- --
-- Compatible to RISC-V debug spec. versions 0.13 and 1.0. --
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
-- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. --
@ -24,11 +26,11 @@ entity neorv32_debug_dtm is
-- global control --
clk_i : in std_ulogic; -- global clock line
rstn_i : in std_ulogic; -- global reset line, low-active
-- jtag connection --
jtag_tck_i : in std_ulogic;
jtag_tdi_i : in std_ulogic;
jtag_tdo_o : out std_ulogic;
jtag_tms_i : in std_ulogic;
-- jtag connection (TAP access) --
jtag_tck_i : in std_ulogic; -- serial clock
jtag_tdi_i : in std_ulogic; -- serial data input
jtag_tdo_o : out std_ulogic; -- serial data output
jtag_tms_i : in std_ulogic; -- mode select
-- debug module interface (DMI) --
dmi_req_o : out dmi_req_t; -- request
dmi_rsp_i : in dmi_rsp_t -- response
@ -37,11 +39,6 @@ end neorv32_debug_dtm;
architecture neorv32_debug_dtm_rtl of neorv32_debug_dtm is
-- DMI Configuration (fixed!) --
constant dmi_idle_c : std_ulogic_vector(2 downto 0) := "000"; -- no idle cycles required
constant dmi_version_c : std_ulogic_vector(3 downto 0) := "0001"; -- debug spec. version (0.13 & 1.0)
constant dmi_abits_c : std_ulogic_vector(5 downto 0) := "000111"; -- number of DMI address bits (7)
-- TAP data register addresses --
constant addr_idcode_c : std_ulogic_vector(4 downto 0) := "00001"; -- identifier
constant addr_dtmcs_c : std_ulogic_vector(4 downto 0) := "10000"; -- DTM status and control
@ -49,10 +46,8 @@ architecture neorv32_debug_dtm_rtl of neorv32_debug_dtm is
-- tap JTAG signal synchronizer --
type tap_sync_t is record
-- internal --
tck_ff, tdi_ff, tms_ff : std_ulogic_vector(2 downto 0);
-- external --
tck_rising, tck_falling, tdi, tms: std_ulogic;
tck_rising, tck_falling, tdi, tms : std_ulogic;
end record;
signal tap_sync : tap_sync_t;
@ -85,8 +80,7 @@ architecture neorv32_debug_dtm_rtl of neorv32_debug_dtm is
dmihardreset : std_ulogic;
dmireset : std_ulogic;
err : std_ulogic;
rdata : std_ulogic_vector(31 downto 0);
wdata : std_ulogic_vector(31 downto 0);
rdata, wdata : std_ulogic_vector(31 downto 0);
addr : std_ulogic_vector(6 downto 0);
end record;
signal dmi_ctrl : dmi_ctrl_t;
@ -108,14 +102,12 @@ begin
end if;
end process tap_synchronizer;
-- JTAG clock edge --
-- JTAG clock edges --
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 --
-- JTAG inputs --
tap_sync.tms <= tap_sync.tms_ff(2);
-- JTAG serial data input --
tap_sync.tdi <= tap_sync.tdi_ff(2);
@ -165,6 +157,7 @@ begin
end if;
end process update_trigger;
-- edge detector --
dr_trigger.valid <= '1' when (dr_trigger.sreg = "01") else '0';
@ -184,10 +177,8 @@ begin
-- serial data input: instruction register --
if (tap_ctrl_state = LOGIC_RESET) or (tap_ctrl_state = IR_CAPTURE) then -- preload phase
tap_reg.ireg <= addr_idcode_c;
elsif (tap_ctrl_state = IR_SHIFT) then -- access phase
if (tap_sync.tck_rising = '1') then -- [JTAG-SYNC] evaluate TDI on rising edge of TCK
tap_reg.ireg <= tap_sync.tdi & tap_reg.ireg(tap_reg.ireg'left downto 1);
end if;
elsif (tap_ctrl_state = IR_SHIFT) and (tap_sync.tck_rising = '1') then -- access phase; [JTAG-SYNC] evaluate TDI on rising edge of TCK
tap_reg.ireg <= tap_sync.tdi & tap_reg.ireg(tap_reg.ireg'left downto 1);
end if;
-- serial data input: data register --
@ -198,15 +189,13 @@ begin
when addr_dmi_c => tap_reg.dmi <= tap_reg.dmi_nxt; -- register interface
when others => tap_reg.bypass <= '0'; -- pass through
end case;
elsif (tap_ctrl_state = DR_SHIFT) then -- access phase
if (tap_sync.tck_rising = '1') then -- [JTAG-SYNC] evaluate TDI on rising edge of TCK
case tap_reg.ireg is
when addr_idcode_c => tap_reg.idcode <= tap_sync.tdi & tap_reg.idcode(tap_reg.idcode'left downto 1);
when addr_dtmcs_c => tap_reg.dtmcs <= tap_sync.tdi & tap_reg.dtmcs(tap_reg.dtmcs'left downto 1);
when addr_dmi_c => tap_reg.dmi <= tap_sync.tdi & tap_reg.dmi(tap_reg.dmi'left downto 1);
when others => tap_reg.bypass <= tap_sync.tdi;
end case;
end if;
elsif (tap_ctrl_state = DR_SHIFT) and (tap_sync.tck_rising = '1') then -- access phase; [JTAG-SYNC] evaluate TDI on rising edge of TCK
case tap_reg.ireg is
when addr_idcode_c => tap_reg.idcode <= tap_sync.tdi & tap_reg.idcode(tap_reg.idcode'left downto 1);
when addr_dtmcs_c => tap_reg.dtmcs <= tap_sync.tdi & tap_reg.dtmcs(tap_reg.dtmcs'left downto 1);
when addr_dmi_c => tap_reg.dmi <= tap_sync.tdi & tap_reg.dmi(tap_reg.dmi'left downto 1);
when others => tap_reg.bypass <= tap_sync.tdi;
end case;
end if;
-- serial data output --
@ -226,20 +215,18 @@ begin
end if;
end process reg_access;
-- DTM Control and Status Register (dtmcs) --
-- DTM control and status register (dtmcs) read-back --
tap_reg.dtmcs_nxt(31 downto 18) <= (others => '0'); -- reserved
tap_reg.dtmcs_nxt(17) <= dmi_ctrl.dmihardreset; -- dmihardreset
tap_reg.dtmcs_nxt(16) <= dmi_ctrl.dmireset; -- dmireset
tap_reg.dtmcs_nxt(15) <= '0'; -- reserved
tap_reg.dtmcs_nxt(14 downto 12) <= dmi_idle_c; -- minimum number of idle cycles
tap_reg.dtmcs_nxt(14 downto 12) <= "000"; -- minimum number of idle cycles (= 0)
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
tap_reg.dtmcs_nxt(09 downto 04) <= "000111"; -- number of DMI address bits (7)
tap_reg.dtmcs_nxt(03 downto 00) <= "0001"; -- compatible to debug spec. version (0.13 & 1.0)
-- 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
tap_reg.dmi_nxt(01 downto 00) <= (others => dmi_ctrl.err); -- status
-- DMI register (dmi) read-back --
tap_reg.dmi_nxt <= dmi_ctrl.addr & dmi_ctrl.rdata & replicate_f(dmi_ctrl.err, 2); -- address & read data & status
-- Debug Module Interface -----------------------------------------------------------------
@ -275,14 +262,12 @@ begin
-- DMI interface arbiter --
dmi_ctrl.op <= dmi_req_nop_c; -- default
if (dmi_ctrl.busy = '0') then -- idle: waiting for new request
if (dmi_ctrl.dmihardreset = '0') then -- no DMI hard reset
if (dr_trigger.valid = '1') and (tap_reg.ireg = addr_dmi_c) then
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) = dmi_req_rd_c) or (tap_reg.dmi(1 downto 0) = dmi_req_wr_c) then
dmi_ctrl.op <= tap_reg.dmi(1 downto 0);
dmi_ctrl.busy <= '1';
end if;
if (dmi_ctrl.dmihardreset = '0') and (dr_trigger.valid = '1') and (tap_reg.ireg = addr_dmi_c) then -- valid non-reset access
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) = dmi_req_rd_c) or (tap_reg.dmi(1 downto 0) = dmi_req_wr_c) then
dmi_ctrl.op <= tap_reg.dmi(1 downto 0);
dmi_ctrl.busy <= '1';
end if;
end if;
else -- busy: read/write access in progress

View file

@ -20,7 +20,7 @@ use neorv32.neorv32_package.all;
entity neorv32_dmem is
generic (
DMEM_SIZE : natural -- processor-internal instruction memory size in bytes, has to be a power of 2
DMEM_SIZE : natural -- memory size in bytes, has to be a power of 2, min 4
);
port (
clk_i : in std_ulogic; -- global clock line
@ -38,7 +38,7 @@ architecture neorv32_dmem_rtl of neorv32_dmem is
-- local signals --
signal rdata : std_ulogic_vector(31 downto 0);
signal rden : std_ulogic;
signal addr, addr_ff : std_ulogic_vector(index_size_f(DMEM_SIZE/4)-1 downto 0);
signal addr, addr_ff : unsigned(index_size_f(DMEM_SIZE/4)-1 downto 0);
-- [NOTE] The memory (RAM) is built from 4 individual byte-wide memories as some synthesis tools
-- have issues inferring 32-bit memories with individual byte-enable signals.
@ -57,22 +57,22 @@ begin
if rising_edge(clk_i) then
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
if (bus_req_i.ben(0) = '1') then -- byte 0
mem_ram_b0(to_integer(unsigned(addr))) <= bus_req_i.data(7 downto 0);
mem_ram_b0(to_integer(addr)) <= bus_req_i.data(7 downto 0);
end if;
if (bus_req_i.ben(1) = '1') then -- byte 1
mem_ram_b1(to_integer(unsigned(addr))) <= bus_req_i.data(15 downto 8);
mem_ram_b1(to_integer(addr)) <= bus_req_i.data(15 downto 8);
end if;
if (bus_req_i.ben(2) = '1') then -- byte 2
mem_ram_b2(to_integer(unsigned(addr))) <= bus_req_i.data(23 downto 16);
mem_ram_b2(to_integer(addr)) <= bus_req_i.data(23 downto 16);
end if;
if (bus_req_i.ben(3) = '1') then -- byte 3
mem_ram_b3(to_integer(unsigned(addr))) <= bus_req_i.data(31 downto 24);
mem_ram_b3(to_integer(addr)) <= bus_req_i.data(31 downto 24);
end if;
end if;
rdata(7 downto 0) <= mem_ram_b0(to_integer(unsigned(addr)));
rdata(15 downto 8) <= mem_ram_b1(to_integer(unsigned(addr)));
rdata(23 downto 16) <= mem_ram_b2(to_integer(unsigned(addr)));
rdata(31 downto 24) <= mem_ram_b3(to_integer(unsigned(addr)));
rdata(7 downto 0) <= mem_ram_b0(to_integer(addr));
rdata(15 downto 8) <= mem_ram_b1(to_integer(addr));
rdata(23 downto 16) <= mem_ram_b2(to_integer(addr));
rdata(31 downto 24) <= mem_ram_b3(to_integer(addr));
end if;
end process mem_access;
addr_ff <= (others => '0'); -- unused
@ -86,28 +86,28 @@ begin
addr_ff <= addr;
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
if (bus_req_i.ben(0) = '1') then -- byte 0
mem_ram_b0(to_integer(unsigned(addr))) <= bus_req_i.data(7 downto 0);
mem_ram_b0(to_integer(addr)) <= bus_req_i.data(7 downto 0);
end if;
if (bus_req_i.ben(1) = '1') then -- byte 1
mem_ram_b1(to_integer(unsigned(addr))) <= bus_req_i.data(15 downto 8);
mem_ram_b1(to_integer(addr)) <= bus_req_i.data(15 downto 8);
end if;
if (bus_req_i.ben(2) = '1') then -- byte 2
mem_ram_b2(to_integer(unsigned(addr))) <= bus_req_i.data(23 downto 16);
mem_ram_b2(to_integer(addr)) <= bus_req_i.data(23 downto 16);
end if;
if (bus_req_i.ben(3) = '1') then -- byte 3
mem_ram_b3(to_integer(unsigned(addr))) <= bus_req_i.data(31 downto 24);
mem_ram_b3(to_integer(addr)) <= bus_req_i.data(31 downto 24);
end if;
end if;
end if;
end process mem_access;
rdata(7 downto 0) <= mem_ram_b0(to_integer(unsigned(addr_ff)));
rdata(15 downto 8) <= mem_ram_b1(to_integer(unsigned(addr_ff)));
rdata(23 downto 16) <= mem_ram_b2(to_integer(unsigned(addr_ff)));
rdata(31 downto 24) <= mem_ram_b3(to_integer(unsigned(addr_ff)));
rdata(7 downto 0) <= mem_ram_b0(to_integer(addr_ff));
rdata(15 downto 8) <= mem_ram_b1(to_integer(addr_ff));
rdata(23 downto 16) <= mem_ram_b2(to_integer(addr_ff));
rdata(31 downto 24) <= mem_ram_b3(to_integer(addr_ff));
end generate;
-- word aligned access address --
addr <= bus_req_i.addr(index_size_f(DMEM_SIZE/4)+1 downto 2);
addr <= unsigned(bus_req_i.addr(index_size_f(DMEM_SIZE/4)+1 downto 2));
-- Bus Response ---------------------------------------------------------------------------

View file

@ -21,8 +21,8 @@ use neorv32.neorv32_application_image.all; -- generated by the image generator
entity neorv32_imem is
generic (
IMEM_SIZE : natural; -- processor-internal instruction memory size in bytes, has to be a power of 2
IMEM_AS_IROM : boolean -- implement IMEM as pre-initialized read-only memory?
IMEM_SIZE : natural; -- memory size in bytes, has to be a power of 2, min 4
IMEM_INIT : boolean -- implement IMEM as pre-initialized read-only memory?
);
port (
clk_i : in std_ulogic; -- global clock line
@ -37,16 +37,14 @@ architecture neorv32_imem_rtl of neorv32_imem is
-- alternative memory description style --
constant alt_style_c : boolean := false; -- [TIP] enable this if synthesis fails to infer block RAM
-- ROM - initialized with executable code --
constant imem_app_size_c : natural := (application_init_image'length)*4; -- application (image) size in bytes
constant mem_rom_c : mem32_t(0 to IMEM_SIZE/4-1) := mem32_init_f(application_init_image, IMEM_SIZE/4);
-- local signals --
signal rdata : std_ulogic_vector(31 downto 0);
signal rden : std_ulogic;
signal addr, addr_ff : std_ulogic_vector(index_size_f(IMEM_SIZE/4)-1 downto 0);
-- application (image) size in bytes --
constant imem_app_size_c : natural := (application_init_image'length)*4;
-- ROM - initialized with executable code --
constant mem_rom_c : mem32_t(0 to IMEM_SIZE/4-1) := mem32_init_f(application_init_image, IMEM_SIZE/4);
signal addr, addr_ff : unsigned(index_size_f(IMEM_SIZE/4)-1 downto 0);
-- [NOTE] The memory (RAM) is built from 4 individual byte-wide memories as some synthesis tools
-- have issues inferring 32-bit memories with individual byte-enable signals.
@ -60,9 +58,9 @@ begin
-- -------------------------------------------------------------------------------------------
assert false report
"[NEORV32] Implementing processor-internal IMEM as " &
cond_sel_string_f(IMEM_AS_IROM, "pre-initialized ROM.", "blank RAM.") severity note;
cond_sel_string_f(IMEM_INIT, "pre-initialized ROM.", "blank RAM.") severity note;
assert not ((IMEM_AS_IROM = true) and (imem_app_size_c > IMEM_SIZE)) report
assert not ((IMEM_INIT = true) and (imem_app_size_c > IMEM_SIZE)) report
"[NEORV32] Application image (" & natural'image(imem_app_size_c) &
" bytes) does not fit into processor-internal IMEM (" &
natural'image(IMEM_SIZE) & " bytes)!" severity error;
@ -71,14 +69,14 @@ begin
-- Implement IMEM as pre-initialized ROM --------------------------------------------------
-- -------------------------------------------------------------------------------------------
imem_rom:
if IMEM_AS_IROM generate
if IMEM_INIT generate
imem_rom_default: -- default memory HDL style
if not alt_style_c generate
mem_access: process(clk_i)
begin
if rising_edge(clk_i) then
rdata <= mem_rom_c(to_integer(unsigned(addr)));
rdata <= mem_rom_c(to_integer(addr));
end if;
end process mem_access;
addr_ff <= (others => '0'); -- unused
@ -92,19 +90,19 @@ begin
addr_ff <= addr;
end if;
end process mem_access;
rdata <= mem_rom_c(to_integer(unsigned(addr_ff)));
rdata <= mem_rom_c(to_integer(addr_ff));
end generate;
end generate;
-- word aligned access address --
addr <= bus_req_i.addr(index_size_f(IMEM_SIZE/4)+1 downto 2);
addr <= unsigned(bus_req_i.addr(index_size_f(IMEM_SIZE/4)+1 downto 2));
-- Implement IMEM as non-initialized RAM --------------------------------------------------
-- -------------------------------------------------------------------------------------------
imem_ram:
if not IMEM_AS_IROM generate
if not IMEM_INIT generate
imem_ram_default: -- default memory HDL style
if not alt_style_c generate
@ -113,22 +111,22 @@ begin
if rising_edge(clk_i) then
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
if (bus_req_i.ben(0) = '1') then -- byte 0
mem_ram_b0(to_integer(unsigned(addr))) <= bus_req_i.data(7 downto 0);
mem_ram_b0(to_integer(addr)) <= bus_req_i.data(7 downto 0);
end if;
if (bus_req_i.ben(1) = '1') then -- byte 1
mem_ram_b1(to_integer(unsigned(addr))) <= bus_req_i.data(15 downto 8);
mem_ram_b1(to_integer(addr)) <= bus_req_i.data(15 downto 8);
end if;
if (bus_req_i.ben(2) = '1') then -- byte 2
mem_ram_b2(to_integer(unsigned(addr))) <= bus_req_i.data(23 downto 16);
mem_ram_b2(to_integer(addr)) <= bus_req_i.data(23 downto 16);
end if;
if (bus_req_i.ben(3) = '1') then -- byte 3
mem_ram_b3(to_integer(unsigned(addr))) <= bus_req_i.data(31 downto 24);
mem_ram_b3(to_integer(addr)) <= bus_req_i.data(31 downto 24);
end if;
end if;
rdata(7 downto 0) <= mem_ram_b0(to_integer(unsigned(addr)));
rdata(15 downto 8) <= mem_ram_b1(to_integer(unsigned(addr)));
rdata(23 downto 16) <= mem_ram_b2(to_integer(unsigned(addr)));
rdata(31 downto 24) <= mem_ram_b3(to_integer(unsigned(addr)));
rdata(7 downto 0) <= mem_ram_b0(to_integer(addr));
rdata(15 downto 8) <= mem_ram_b1(to_integer(addr));
rdata(23 downto 16) <= mem_ram_b2(to_integer(addr));
rdata(31 downto 24) <= mem_ram_b3(to_integer(addr));
end if;
end process mem_access;
addr_ff <= (others => '0'); -- unused
@ -142,24 +140,24 @@ begin
addr_ff <= addr;
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
if (bus_req_i.ben(0) = '1') then -- byte 0
mem_ram_b0(to_integer(unsigned(addr))) <= bus_req_i.data(7 downto 0);
mem_ram_b0(to_integer(addr)) <= bus_req_i.data(7 downto 0);
end if;
if (bus_req_i.ben(1) = '1') then -- byte 1
mem_ram_b1(to_integer(unsigned(addr))) <= bus_req_i.data(15 downto 8);
mem_ram_b1(to_integer(addr)) <= bus_req_i.data(15 downto 8);
end if;
if (bus_req_i.ben(2) = '1') then -- byte 2
mem_ram_b2(to_integer(unsigned(addr))) <= bus_req_i.data(23 downto 16);
mem_ram_b2(to_integer(addr)) <= bus_req_i.data(23 downto 16);
end if;
if (bus_req_i.ben(3) = '1') then -- byte 3
mem_ram_b3(to_integer(unsigned(addr))) <= bus_req_i.data(31 downto 24);
mem_ram_b3(to_integer(addr)) <= bus_req_i.data(31 downto 24);
end if;
end if;
end if;
end process mem_access;
rdata(7 downto 0) <= mem_ram_b0(to_integer(unsigned(addr_ff)));
rdata(15 downto 8) <= mem_ram_b1(to_integer(unsigned(addr_ff)));
rdata(23 downto 16) <= mem_ram_b2(to_integer(unsigned(addr_ff)));
rdata(31 downto 24) <= mem_ram_b3(to_integer(unsigned(addr_ff)));
rdata(7 downto 0) <= mem_ram_b0(to_integer(addr_ff));
rdata(15 downto 8) <= mem_ram_b1(to_integer(addr_ff));
rdata(23 downto 16) <= mem_ram_b2(to_integer(addr_ff));
rdata(31 downto 24) <= mem_ram_b3(to_integer(addr_ff));
end generate;
end generate;
@ -174,7 +172,7 @@ begin
bus_rsp_o.ack <= '0';
elsif rising_edge(clk_i) then
rden <= bus_req_i.stb and (not bus_req_i.rw);
if (IMEM_AS_IROM = true) then
if (IMEM_INIT = true) then
bus_rsp_o.ack <= bus_req_i.stb and (not bus_req_i.rw); -- read-only!
else
bus_rsp_o.ack <= bus_req_i.stb;

View file

@ -29,7 +29,7 @@ package neorv32_package is
-- Architecture Constants -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100506"; -- hardware version
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100602"; -- hardware version
constant archid_c : natural := 19; -- official RISC-V architecture ID
constant XLEN : natural := 32; -- native data path width
@ -58,7 +58,7 @@ package neorv32_package is
constant mem_io_size_c : natural := 8*1024; -- = 32 * iodev_size_c
-- Start of uncached memory access (256MB page / 4MSBs only) --
constant uncached_begin_c : std_ulogic_vector(31 downto 0) := x"f0000000";
constant mem_uncached_begin_c : std_ulogic_vector(31 downto 0) := x"f0000000";
-- IO Address Map (base address must be aligned to the region's size) --
constant iodev_size_c : natural := 256; -- size of a single IO device (bytes)
@ -254,7 +254,7 @@ package neorv32_package is
constant funct3_sh_c : std_ulogic_vector(2 downto 0) := "001"; -- store half word
constant funct3_sw_c : std_ulogic_vector(2 downto 0) := "010"; -- store word
-- alu --
constant funct3_subadd_c : std_ulogic_vector(2 downto 0) := "000"; -- sub/add
constant funct3_sadd_c : std_ulogic_vector(2 downto 0) := "000"; -- sub/add
constant funct3_sll_c : std_ulogic_vector(2 downto 0) := "001"; -- shift logical left
constant funct3_slt_c : std_ulogic_vector(2 downto 0) := "010"; -- set on less
constant funct3_sltu_c : std_ulogic_vector(2 downto 0) := "011"; -- set on less unsigned
@ -667,12 +667,15 @@ package neorv32_package is
component neorv32_top
generic (
-- General --
-- Clocking --
CLOCK_FREQUENCY : natural := 0;
CLOCK_GATING_EN : boolean := false;
-- Identification --
HART_ID : std_ulogic_vector(31 downto 0) := x"00000000";
JEDEC_ID : std_ulogic_vector(10 downto 0) := "00000000000";
INT_BOOTLOADER_EN : boolean := false;
-- Boot Configuration --
BOOT_MODE_SELECT : natural range 0 to 2 := 0;
BOOT_ADDR_CUSTOM : std_ulogic_vector(31 downto 0) := x"00000000";
-- On-Chip Debugger (OCD) --
OCD_EN : boolean := false;
OCD_AUTHENTICATION : boolean := false;
@ -1116,40 +1119,3 @@ package body neorv32_package is
end function print_version_f;
end neorv32_package;
-- **********************************************************************************************************
-- Additional Packages
-- **********************************************************************************************************
-- Prototype Definition: bootloader_init_image --------------------------------------------
-- -------------------------------------------------------------------------------------------
-- > memory content in 'neorv32_bootloader_image.vhd', auto-generated by 'image_gen'
-- > used by 'neorv32_boot_rom.vhd'
-- > enables body-only recompile in case of firmware change (NEORV32 PR #338)
library ieee;
use ieee.std_logic_1164.all;
library neorv32;
use neorv32.neorv32_package.all;
package neorv32_bootloader_image is
constant bootloader_init_image : mem32_t;
end neorv32_bootloader_image;
-- Prototype Definition: neorv32_application_image ----------------------------------------
-- -------------------------------------------------------------------------------------------
-- > memory content in 'neorv32_application_image.vhd', auto-generated by 'image_gen'
-- > used by 'mem/neorv32_imem.*.vhd'
-- > enables body-only recompile in case of firmware change (NEORV32 PR #338)
library ieee;
use ieee.std_logic_1164.all;
library neorv32;
use neorv32.neorv32_package.all;
package neorv32_application_image is
constant application_init_image : mem32_t;
end neorv32_application_image;

View file

@ -19,8 +19,10 @@ entity neorv32_sysinfo is
generic (
CLOCK_FREQUENCY : natural; -- clock frequency of clk_i in Hz
CLOCK_GATING_EN : boolean; -- enable clock gating when in sleep mode
BOOT_MODE_SELECT : natural; -- boot configuration select (default = 0 = bootloader)
INT_BOOTLOADER_EN : boolean; -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
MEM_INT_IMEM_EN : boolean; -- implement processor-internal instruction memory
MEM_INT_IMEM_ROM : boolean; -- implement processor-internal instruction memory as pre-initialized ROM
MEM_INT_IMEM_SIZE : natural; -- size of processor-internal instruction memory in bytes
MEM_INT_DMEM_EN : boolean; -- implement processor-internal data memory
MEM_INT_DMEM_SIZE : natural; -- size of processor-internal data memory in bytes
@ -75,6 +77,7 @@ architecture neorv32_sysinfo_rtl of neorv32_sysinfo is
constant xcache_en_c : boolean := XBUS_EN and XBUS_CACHE_EN;
constant xip_cache_en_c : boolean := XIP_EN and XIP_CACHE_EN;
constant ocd_auth_en_c : boolean := OCD_EN and OCD_AUTHENTICATION;
constant int_imem_rom_c : boolean := int_imem_en_c and MEM_INT_IMEM_ROM;
-- system information memory --
type sysinfo_t is array (0 to 3) of std_ulogic_vector(31 downto 0);
@ -104,7 +107,7 @@ begin
sysinfo(1)(7 downto 0) <= std_ulogic_vector(to_unsigned(index_size_f(MEM_INT_IMEM_SIZE), 8)); -- log2(IMEM size)
sysinfo(1)(15 downto 8) <= std_ulogic_vector(to_unsigned(index_size_f(MEM_INT_DMEM_SIZE), 8)); -- log2(DMEM size)
sysinfo(1)(23 downto 16) <= (others => '0'); -- reserved
sysinfo(1)(31 downto 24) <= (others => '0'); -- reserved
sysinfo(1)(31 downto 24) <= std_ulogic_vector(to_unsigned(BOOT_MODE_SELECT, 8)); -- boot configuration
-- SYSINFO(2): SoC Configuration --
sysinfo(2)(0) <= '1' when INT_BOOTLOADER_EN else '0'; -- processor-internal bootloader implemented?
@ -119,7 +122,7 @@ begin
sysinfo(2)(9) <= '1' when XIP_EN else '0'; -- execute in-place module implemented?
sysinfo(2)(10) <= '1' when xip_cache_en_c else '0'; -- execute in-place cache implemented?
sysinfo(2)(11) <= '1' when ocd_auth_en_c else '0'; -- on-chip debugger authentication implemented?
sysinfo(2)(12) <= '0'; -- reserved
sysinfo(2)(12) <= '1' when int_imem_rom_c else '0'; -- processor-internal instruction memory implemented as pre-initialized ROM?
sysinfo(2)(13) <= '0'; -- reserved
sysinfo(2)(14) <= '1' when IO_DMA_EN else '0'; -- direct memory access controller (DMA) implemented?
sysinfo(2)(15) <= '1' when IO_GPIO_EN else '0'; -- general purpose input/output port unit (GPIO) implemented?

View file

@ -21,12 +21,17 @@ use neorv32.neorv32_package.all;
entity neorv32_top is
generic (
-- General --
-- Processor Clocking --
CLOCK_FREQUENCY : natural := 0; -- clock frequency of clk_i in Hz
CLOCK_GATING_EN : boolean := false; -- enable clock gating when in sleep mode
-- Core Identification --
HART_ID : std_ulogic_vector(31 downto 0) := x"00000000"; -- hardware thread ID
JEDEC_ID : std_ulogic_vector(10 downto 0) := "00000000000"; -- JEDEC ID: continuation codes + vendor ID
INT_BOOTLOADER_EN : boolean := false; -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
-- Boot Configuration --
BOOT_MODE_SELECT : natural range 0 to 2 := 0; -- boot configuration select (default = 0 = bootloader)
BOOT_ADDR_CUSTOM : std_ulogic_vector(31 downto 0) := x"00000000"; -- custom CPU boot address (if boot_config = 1)
-- On-Chip Debugger (OCD) --
OCD_EN : boolean := false; -- implement on-chip debugger
@ -244,16 +249,28 @@ end neorv32_top;
architecture neorv32_top_rtl of neorv32_top is
-- ----------------------------------------------------------
-- Boot Configuration (BOOT_MODE_SELECT)
-- ----------------------------------------------------------
-- 0: Internal bootloader ROM
-- 1: Custom (use BOOT_ADDR_CUSTOM)
-- 2: Internal IMEM initialized with application image
-- ----------------------------------------------------------
constant bootrom_en_c : boolean := boolean(BOOT_MODE_SELECT = 0);
constant imem_as_rom_c : boolean := boolean(BOOT_MODE_SELECT = 2);
constant cpu_boot_addr_c : std_ulogic_vector(31 downto 0) :=
cond_sel_suv_f(boolean(BOOT_MODE_SELECT = 0), mem_boot_base_c,
cond_sel_suv_f(boolean(BOOT_MODE_SELECT = 1), BOOT_ADDR_CUSTOM,
cond_sel_suv_f(boolean(BOOT_MODE_SELECT = 2), mem_imem_base_c, x"00000000")));
-- auto-configuration --
constant cpu_boot_addr_c : std_ulogic_vector(31 downto 0) := cond_sel_suv_f(INT_BOOTLOADER_EN, mem_boot_base_c, mem_imem_base_c);
constant imem_as_rom_c : boolean := not INT_BOOTLOADER_EN;
constant io_gpio_en_c : boolean := boolean(IO_GPIO_NUM > 0);
constant io_xirq_en_c : boolean := boolean(XIRQ_NUM_CH > 0);
constant io_pwm_en_c : boolean := boolean(IO_PWM_NUM_CH > 0);
constant cpu_smpmp_c : boolean := boolean(PMP_NUM_REGIONS > 0);
constant io_sysinfo_en_c : boolean := not IO_DISABLE_SYSINFO;
-- convert JEDEC ID to mvendorid CSR --
-- convert JEDEC ID to MVENDORID CSR --
constant vendorid_c : std_ulogic_vector(31 downto 0) := x"00000" & "0" & JEDEC_ID;
-- make sure physical memory sizes are a power of two --
@ -282,7 +299,7 @@ architecture neorv32_top_rtl of neorv32_top is
signal dmi_rsp : dmi_rsp_t;
-- debug core interface (DCI) --
signal dci_ndmrstn, dci_halt_req : std_ulogic;
signal dci_ndmrstn, dci_haltreq : std_ulogic;
-- bus: core complex (CPU + caches) and DMA --
signal cpu_i_req, cpu_d_req, icache_req, dcache_req, core_req, main_req, main2_req, dma_req : bus_req_t;
@ -330,9 +347,9 @@ begin
-- show SoC configuration --
assert false report
"[NEORV32] Processor Configuration: CPU " & -- cpu core is always enabled
cond_sel_string_f(MEM_INT_IMEM_EN, "IMEM ", "") &
cond_sel_string_f(MEM_INT_IMEM_EN, cond_sel_string_f(imem_as_rom_c, "IMEM_ROM ", "IMEM "), "") &
cond_sel_string_f(MEM_INT_DMEM_EN, "DMEM ", "") &
cond_sel_string_f(INT_BOOTLOADER_EN, "BOOTROM ", "") &
cond_sel_string_f(bootrom_en_c, "BOOTROM ", "") &
cond_sel_string_f(ICACHE_EN, "I-CACHE ", "") &
cond_sel_string_f(DCACHE_EN, "D-CACHE ", "") &
cond_sel_string_f(XBUS_EN, "XBUS ", "") &
@ -358,7 +375,7 @@ begin
cond_sel_string_f(IO_SLINK_EN, "SLINK ", "") &
cond_sel_string_f(IO_CRC_EN, "CRC ", "") &
cond_sel_string_f(io_sysinfo_en_c, "SYSINFO ", "") &
cond_sel_string_f(OCD_EN, cond_sel_string_f(OCD_AUTHENTICATION, "OCD-AUTH ", "OCD "), "") &
cond_sel_string_f(OCD_EN, cond_sel_string_f(OCD_AUTHENTICATION, "OCD-AUTH ", "OCD "), "") &
""
severity note;
@ -378,6 +395,15 @@ begin
assert not (CLOCK_FREQUENCY = 0) report
"[NEORV32] CLOCK_FREQUENCY must be configured according to the frequency of clk_i port!" severity warning;
-- Boot configuration notifier --
assert not (BOOT_MODE_SELECT = 0) report "[NEORV32] BOOT_MODE_SELECT = 0: booting via bootloader" severity note;
assert not (BOOT_MODE_SELECT = 1) report "[NEORV32] BOOT_MODE_SELECT = 1: booting from custom address" severity note;
assert not (BOOT_MODE_SELECT = 2) report "[NEORV32] BOOT_MODE_SELECT = 2: booting IMEM image" severity note;
-- Boot configuration: boot from initialized IMEM requires the IMEM to be enabled --
assert not ((BOOT_MODE_SELECT = 2) and (MEM_INT_IMEM_EN = false)) report
"[NEORV32] BOOT_MODE_SELECT = 2 (boot IMEM image) requires the internal instruction memory (IMEM) to be enabled!" severity error;
end generate; -- /sanity_checks
@ -507,7 +533,7 @@ begin
mei_i => mext_irq_i,
mti_i => mtime_irq,
firq_i => cpu_firq,
dbi_i => dci_halt_req,
dbi_i => dci_haltreq,
-- instruction bus interface --
ibus_req_o => cpu_i_req,
ibus_rsp_i => cpu_i_rsp,
@ -543,7 +569,7 @@ begin
generic map (
NUM_BLOCKS => ICACHE_NUM_BLOCKS,
BLOCK_SIZE => ICACHE_BLOCK_SIZE,
UC_BEGIN => uncached_begin_c(31 downto 28),
UC_BEGIN => mem_uncached_begin_c(31 downto 28),
UC_ENABLE => true,
READ_ONLY => true
)
@ -572,7 +598,7 @@ begin
generic map (
NUM_BLOCKS => DCACHE_NUM_BLOCKS,
BLOCK_SIZE => DCACHE_BLOCK_SIZE,
UC_BEGIN => uncached_begin_c(31 downto 28),
UC_BEGIN => mem_uncached_begin_c(31 downto 28),
UC_ENABLE => true,
READ_ONLY => false
)
@ -717,7 +743,7 @@ begin
C_TMO_EN => false, -- no timeout for XIP accesses
C_PRIV => false,
-- port D: BOOT ROM --
D_ENABLE => INT_BOOTLOADER_EN,
D_ENABLE => bootrom_en_c,
D_BASE => mem_boot_base_c,
D_SIZE => mem_boot_size_c,
D_TMO_EN => true,
@ -768,8 +794,8 @@ begin
if MEM_INT_IMEM_EN generate
neorv32_int_imem_inst: entity neorv32.neorv32_imem
generic map (
IMEM_SIZE => imem_size_c,
IMEM_AS_IROM => imem_as_rom_c
IMEM_SIZE => imem_size_c,
IMEM_INIT => imem_as_rom_c
)
port map (
clk_i => clk_i,
@ -810,7 +836,7 @@ begin
-- Processor-Internal Bootloader ROM (BOOTROM) --------------------------------------------
-- -------------------------------------------------------------------------------------------
neorv32_boot_rom_inst_true:
if INT_BOOTLOADER_EN generate
if bootrom_en_c generate
neorv32_boot_rom_inst: entity neorv32.neorv32_boot_rom
port map (
clk_i => clk_i,
@ -821,7 +847,7 @@ begin
end generate;
neorv32_boot_rom_inst_false:
if not INT_BOOTLOADER_EN generate
if not bootrom_en_c generate
boot_rsp <= rsp_terminate_c;
end generate;
@ -927,7 +953,7 @@ begin
generic map (
NUM_BLOCKS => XBUS_CACHE_NUM_BLOCKS,
BLOCK_SIZE => XBUS_CACHE_BLOCK_SIZE,
UC_BEGIN => uncached_begin_c(31 downto 28),
UC_BEGIN => mem_uncached_begin_c(31 downto 28),
UC_ENABLE => true,
READ_ONLY => false
)
@ -1551,8 +1577,10 @@ begin
generic map (
CLOCK_FREQUENCY => CLOCK_FREQUENCY,
CLOCK_GATING_EN => CLOCK_GATING_EN,
INT_BOOTLOADER_EN => INT_BOOTLOADER_EN,
BOOT_MODE_SELECT => BOOT_MODE_SELECT,
INT_BOOTLOADER_EN => bootrom_en_c,
MEM_INT_IMEM_EN => MEM_INT_IMEM_EN,
MEM_INT_IMEM_ROM => imem_as_rom_c,
MEM_INT_IMEM_SIZE => imem_size_c,
MEM_INT_DMEM_EN => MEM_INT_DMEM_EN,
MEM_INT_DMEM_SIZE => dmem_size_c,
@ -1649,7 +1677,7 @@ begin
bus_req_i => iodev_req(IODEV_OCD),
bus_rsp_o => iodev_rsp(IODEV_OCD),
cpu_ndmrstn_o => dci_ndmrstn,
cpu_halt_req_o => dci_halt_req
cpu_halt_req_o => dci_haltreq
);
end generate;
@ -1659,7 +1687,7 @@ begin
iodev_rsp(IODEV_OCD) <= rsp_terminate_c;
jtag_tdo_o <= jtag_tdi_i; -- JTAG pass-through
dci_ndmrstn <= '1';
dci_halt_req <= '0';
dci_haltreq <= '0';
end generate;

View file

@ -126,7 +126,7 @@ begin
xbus_tag_o <= bus_req.src & '0' & bus_req.priv; -- instr/data, secure, privileged/unprivileged
-- response gating --
bus_rsp.data <= xbus_dat_i when (pending = '1') and (bus_rw = '0') else (others => '0'); -- no read-back if READ operation
bus_rsp.data <= xbus_dat_i when (pending = '1') and (bus_rw = '0') else (others => '0'); -- no read-back if WRITE operation
bus_rsp.ack <= xbus_ack_i when (pending = '1') else '0';
bus_rsp.err <= (xbus_err_i or timeout) when (pending = '1') else '0';

View file

@ -2,8 +2,8 @@
-- NEORV32 SoC - External Interrupt Controller (XIRQ) --
-- -------------------------------------------------------------------------------- --
-- Simple interrupt controller for platform (processor-external) interrupts. Up to --
-- 32 channels are supported that get (optionally) prioritized into a single CPU --
-- interrupt. Trigger type is programmable per channel by configuration registers. --
-- 32 channels are supported that get prioritized into a single CPU interrupt. --
-- Trigger type is programmable per-channel by configuration registers. --
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
@ -36,27 +36,29 @@ end neorv32_xirq;
architecture neorv32_xirq_rtl of neorv32_xirq is
-- register addresses --
constant addr_enable_c : std_ulogic_vector(2 downto 0) := "000"; -- r/w: channel enable
constant addr_pending_c : std_ulogic_vector(2 downto 0) := "001"; -- r/w: pending IRQs
constant addr_source_c : std_ulogic_vector(2 downto 0) := "010"; -- r/w: source IRQ, ACK on write
constant addr_ttype_c : std_ulogic_vector(2 downto 0) := "011"; -- r/w: trigger type (level/edge)
constant addr_tpolarity_c : std_ulogic_vector(2 downto 0) := "100"; -- r/w: trigger polarity (high/low or rising/falling)
constant addr_eie_c : std_ulogic_vector(1 downto 0) := "00"; -- r/w: channel enable
constant addr_esc_c : std_ulogic_vector(1 downto 0) := "01"; -- r/w: source IRQ, ACK on write
constant addr_ttyp_c : std_ulogic_vector(1 downto 0) := "10"; -- r/w: trigger type (level/edge)
constant addr_tpol_c : std_ulogic_vector(1 downto 0) := "11"; -- r/w: trigger polarity (high/low or rising/falling)
-- interface registers --
signal irq_enable, nclr_pending, irq_type, irq_polarity : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0);
signal irq_source : std_ulogic_vector(4 downto 0);
-- configuration registers --
signal irq_enable, irq_type, irq_polarity : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0);
-- interrupt trigger --
signal irq_sync, irq_sync2, irq_trig : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0);
signal irq_sync1, irq_sync2, irq_trig : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0);
-- interrupt buffer --
signal irq_pending, irq_raw : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0);
signal irq_fire, irq_active : std_ulogic;
-- pending interrupt(s) --
signal irq_pending : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0);
-- priority encoder --
type prio_enc_t is array (0 to XIRQ_NUM_CH-1) of std_ulogic_vector(4 downto 0);
signal prio_enc : prio_enc_t;
-- interrupt arbiter --
signal irq_state : std_ulogic_vector(1 downto 0);
signal irq_source : std_ulogic_vector(4 downto 0);
signal irq_clear : std_ulogic_vector(31 downto 0);
begin
-- Bus Access -----------------------------------------------------------------------------
@ -65,7 +67,6 @@ begin
begin
if (rstn_i = '0') then
bus_rsp_o <= rsp_terminate_c;
nclr_pending <= (others => '0');
irq_type <= (others => '0');
irq_polarity <= (others => '0');
irq_enable <= (others => '0');
@ -74,29 +75,29 @@ begin
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
nclr_pending <= (others => '1');
-- bus access --
if (bus_req_i.stb = '1') then
if (bus_req_i.rw = '1') then -- write access
if (bus_req_i.addr(4 downto 2) = addr_enable_c) then -- channel-enable
if (bus_req_i.addr(3 downto 2) = addr_eie_c) then -- channel-enable
irq_enable <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0);
end if;
if (bus_req_i.addr(4 downto 2) = addr_pending_c) then -- clear pending IRQs
nclr_pending <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0); -- set zero to clear pending IRQ
end if;
if (bus_req_i.addr(4 downto 2) = addr_ttype_c) then -- trigger type
if (bus_req_i.addr(3 downto 2) = addr_ttyp_c) then -- trigger type
irq_type <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0);
end if;
if (bus_req_i.addr(4 downto 2) = addr_tpolarity_c) then -- trigger polarity
if (bus_req_i.addr(3 downto 2) = addr_tpol_c) then -- trigger polarity
irq_polarity <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0);
end if;
else -- read access
case bus_req_i.addr(4 downto 2) is
when addr_enable_c => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_enable; -- channel-enable
when addr_pending_c => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_pending; -- pending IRQs
when addr_source_c => bus_rsp_o.data(4 downto 0) <= irq_source; -- IRQ source
when addr_ttype_c => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_type; -- trigger type
when others => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_polarity; -- trigger polarity
case bus_req_i.addr(3 downto 2) is
when addr_eie_c => -- channel-enable
bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_enable;
when addr_esc_c =>
bus_rsp_o.data(31) <= irq_state(1); -- active interrupt waiting for ACK
bus_rsp_o.data(4 downto 0) <= irq_source; -- interrupt source (channel number)
when addr_ttyp_c => -- trigger type
bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_type;
when others => -- trigger polarity
bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_polarity;
end case;
end if;
end if;
@ -109,55 +110,51 @@ begin
synchronizer: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
irq_sync <= (others => '0');
irq_sync1 <= (others => '0');
irq_sync2 <= (others => '0');
elsif rising_edge(clk_i) then
irq_sync <= xirq_i(XIRQ_NUM_CH-1 downto 0);
irq_sync2 <= irq_sync;
irq_sync1 <= xirq_i(XIRQ_NUM_CH-1 downto 0);
irq_sync2 <= irq_sync1;
end if;
end process synchronizer;
-- trigger type select --
irq_trigger_gen:
for i in 0 to XIRQ_NUM_CH-1 generate
irq_trigger: process(irq_sync, irq_sync2, irq_type, irq_polarity)
irq_trigger: process(irq_sync1, irq_sync2, irq_type, irq_polarity)
variable sel_v : std_ulogic_vector(1 downto 0);
begin
sel_v := irq_type(i) & irq_polarity(i);
case sel_v is
when "00" => irq_trig(i) <= not irq_sync(i); -- low-level
when "01" => irq_trig(i) <= irq_sync(i); -- high-level
when "10" => irq_trig(i) <= (not irq_sync(i)) and irq_sync2(i); -- falling-edge
when "11" => irq_trig(i) <= irq_sync(i) and (not irq_sync2(i)); -- rising-edge
when "00" => irq_trig(i) <= not irq_sync1(i); -- low-level
when "01" => irq_trig(i) <= irq_sync1(i); -- high-level
when "10" => irq_trig(i) <= (not irq_sync1(i)) and irq_sync2(i); -- falling-edge
when "11" => irq_trig(i) <= irq_sync1(i) and (not irq_sync2(i)); -- rising-edge
when others => irq_trig(i) <= '0';
end case;
end process irq_trigger;
end generate;
-- IRQ Buffer ---------------------------------------------------------------
-- Interrupt-Pending Buffer -------------------------------------------------
-- -----------------------------------------------------------------------------
irq_buffer: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
irq_pending <= (others => '0');
elsif rising_edge(clk_i) then
irq_pending <= (irq_pending and nclr_pending) or irq_trig;
irq_pending <= irq_enable and ((irq_pending and (not irq_clear(XIRQ_NUM_CH-1 downto 0))) or irq_trig);
end if;
end process irq_buffer;
-- filter enabled channels --
irq_raw <= irq_pending and irq_enable;
-- anyone firing? --
irq_fire <= or_reduce_f(irq_raw);
-- encode highest-priority source (structural code: mux-chain) --
-- Priority Encoder (structural code: mux-chain) ----------------------------
-- -----------------------------------------------------------------------------
priority_encoder_gen:
for i in 0 to XIRQ_NUM_CH-1 generate -- start with highest priority
for i in 0 to XIRQ_NUM_CH-1 generate -- start with highest priority (=0)
priority_encoder_gen_chain: -- inside chain
if i < XIRQ_NUM_CH-1 generate
prio_enc(i) <= std_ulogic_vector(to_unsigned(i, 5)) when (irq_raw(i) = '1') else prio_enc(i+1);
prio_enc(i) <= std_ulogic_vector(to_unsigned(i, 5)) when (irq_pending(i) = '1') else prio_enc(i+1);
end generate;
priority_encoder_gen_last: -- end of chain
if i = XIRQ_NUM_CH-1 generate
@ -171,23 +168,34 @@ begin
irq_arbiter: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
irq_active <= '0';
irq_clear <= (others => '0');
irq_source <= (others => '0');
irq_state <= (others => '0');
elsif rising_edge(clk_i) then
if (irq_active = '0') then -- no active IRQ
irq_source <= prio_enc(0); -- get IRQ source
if (irq_fire = '1') then
irq_active <= '1';
end if;
elsif (bus_req_i.stb = '1') and (bus_req_i.rw = '1') and
(bus_req_i.addr(4 downto 2) = addr_source_c) then -- acknowledge on write access
irq_active <= '0';
end if;
irq_clear <= (others => '0'); -- default
case irq_state is
when "00" => -- wait for pending interrupt
irq_source <= prio_enc(0); -- highest-priority channel
if (or_reduce_f(irq_pending) = '1') then
irq_state <= "01";
end if;
when "01" => -- clear triggering channel
irq_clear(to_integer(unsigned(irq_source))) <= '1'; -- ACK/clear according pending bit
irq_state <= "11";
when others => -- wait for CPU acknowledge
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') and (bus_req_i.addr(3 downto 2) = addr_esc_c) then -- acknowledge on write access
irq_state <= "00";
end if;
end case;
end if;
end process irq_arbiter;
-- CPU interrupt --
cpu_irq_o <= irq_active;
cpu_irq_o <= irq_state(0);
end neorv32_xirq_rtl;

View file

@ -14,5 +14,3 @@ NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cpu_alu.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cpu_lsu.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cpu_pmp.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cpu.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_bootloader_image.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_application_image.vhd

View file

@ -19,8 +19,10 @@ NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cpu.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_bus.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_cache.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_dma.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_application_image.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_imem.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_dmem.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_bootloader_image.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_boot_rom.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_xip.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_xbus.vhd
@ -45,5 +47,3 @@ NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_debug_dtm.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_debug_auth.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_debug_dm.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_top.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_application_image.vhd
NEORV32_RTL_PATH_PLACEHOLDER/core/neorv32_bootloader_image.vhd

View file

@ -16,7 +16,7 @@ library neorv32;
entity neorv32_ProcessorTop_Minimal is
generic (
-- General --
-- Clocking --
CLOCK_FREQUENCY : natural := 0; -- clock frequency of clk_i in Hz
-- Internal Instruction memory --
MEM_INT_IMEM_EN : boolean := true; -- implement processor-internal instruction memory
@ -47,9 +47,10 @@ begin
-- -------------------------------------------------------------------------------------------
neorv32_inst: entity neorv32.neorv32_top
generic map (
-- General --
-- Clocking --
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
INT_BOOTLOADER_EN => false, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
-- Boot Configuration --
BOOT_MODE_SELECT => 2, -- boot from pre-initialized interal IMEM
-- 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

View file

@ -16,7 +16,7 @@ library neorv32;
entity neorv32_ProcessorTop_MinimalBoot is
generic (
-- General --
-- Clocking --
CLOCK_FREQUENCY : natural := 0; -- clock frequency of clk_i in Hz
-- Internal Instruction memory --
MEM_INT_IMEM_EN : boolean := true; -- implement processor-internal instruction memory
@ -54,9 +54,10 @@ begin
-- -------------------------------------------------------------------------------------------
neorv32_inst: entity neorv32.neorv32_top
generic map (
-- General --
-- Clocking --
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
INT_BOOTLOADER_EN => true, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
-- Boot Configuration --
BOOT_MODE_SELECT => 0, -- boot via internal bootloader
-- 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

View file

@ -16,7 +16,7 @@ library neorv32;
entity neorv32_ProcessorTop_UP5KDemo is
generic (
-- General --
-- Clocking --
CLOCK_FREQUENCY : natural := 0; -- clock frequency of clk_i in Hz
-- Internal Instruction memory --
MEM_INT_IMEM_EN : boolean := true; -- implement processor-internal instruction memory
@ -77,9 +77,10 @@ begin
-- -------------------------------------------------------------------------------------------
neorv32_inst: entity neorv32.neorv32_top
generic map (
-- General --
-- Clocking --
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
INT_BOOTLOADER_EN => true, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
-- Boot Configuration --
BOOT_MODE_SELECT => 0, -- boot via internal bootloader
-- RISC-V CPU Extensions --
RISCV_ISA_M => true, -- implement mul/div extension?
RISCV_ISA_U => true, -- implement user mode extension?

View file

@ -11,6 +11,7 @@
# -- SPDX-License-Identifier: BSD-3-Clause --
# -- ================================================================================ --
# **************************************************************
# Global configuration
# **************************************************************
@ -20,6 +21,7 @@ set ip_logo docs/figures/neorv32_logo_riscv_small.png
set outputdir neorv32_vivado_ip_work
set cur_dir [file normalize .]
# **************************************************************
# Create empty (!) output/working directory
# **************************************************************
@ -30,11 +32,13 @@ if {[llength $files] != 0} {
file delete -force {*}[glob -directory $outputdir *];
}
# **************************************************************
# Create Vivado project
# **************************************************************
create_project "neorv32-ip" $outputdir
#set_property target_language VHDL [current_project]
set_property INCREMENTAL false [get_filesets sim_1]
# **************************************************************
# Import HDL source files
@ -48,12 +52,14 @@ puts $file_list
add_files $file_list
set_property library neorv32 [get_files $file_list]
# IP top module
# IP top module and AXI4-Lite bridge
add_file $neorv32_home/rtl/system_integration/xbus2axi4lite_bridge.vhd
add_file $neorv32_home/rtl/system_integration/$ip_top.vhd
set_property top $ip_top [current_fileset]
update_compile_order -fileset sources_1
# **************************************************************
# Package as IP block
# **************************************************************
@ -63,286 +69,338 @@ set_property vendor_display_name "Stephan Nolting" [ipx::current_core]
set_property company_url https://github.com/stnolting/neorv32 [ipx::current_core]
set_property description "The NEORV32 RISC-V Processor" [ipx::current_core]
# **************************************************************
# Interfaces: Configuration Dependencies
# **************************************************************
set_property enablement_dependency {$axi4_stream_en = true} [ipx::get_bus_interfaces s0_axis -of_objects [ipx::current_core]]
set_property enablement_dependency {$axi4_stream_en = true} [ipx::get_bus_interfaces s1_axis -of_objects [ipx::current_core]]
set_property enablement_dependency {$ocd_en = true} [ipx::get_ports jtag_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$xip_en = true} [ipx::get_ports xip_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$io_gpio_en = true} [ipx::get_ports gpio_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$io_uart0_en = true} [ipx::get_ports uart0_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$io_uart1_en = true} [ipx::get_ports uart1_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$io_spi_en = true} [ipx::get_ports spi_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$io_sdi_en = true} [ipx::get_ports sdi_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$io_twi_en = true} [ipx::get_ports twi_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$io_onewire_en = true} [ipx::get_ports onewire_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$io_pwm_en = true} [ipx::get_ports pwm_o -of_objects [ipx::current_core]]
set_property enablement_dependency {$io_cfs_en = true} [ipx::get_ports cfs_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$io_neoled_en = true} [ipx::get_ports neoled_o -of_objects [ipx::current_core]]
set_property enablement_dependency {$xirq_en = true} [ipx::get_ports xirq_i -of_objects [ipx::current_core]]
set_property enablement_dependency {$io_mtime_en = true} [ipx::get_ports mtime_time_o -of_objects [ipx::current_core]]
set_property enablement_dependency {$io_mtime_en = false} [ipx::get_ports mtime_irq_i -of_objects [ipx::current_core]]
# **************************************************************
# Configuration GUI: General
# Setup configuration GUI
# **************************************************************
set_property display_name {Clock frequency (Hz)} [ipgui::get_guiparamspec -name "CLOCK_FREQUENCY" -component [ipx::current_core]]
set_property tooltip {Frequency of the clk signal in Hz} [ipgui::get_guiparamspec -name "CLOCK_FREQUENCY" -component [ipx::current_core]]
set_property display_name {HART ID} [ipgui::get_guiparamspec -name "HART_ID" -component [ipx::current_core]]
set_property tooltip {For mhartid CSR} [ipgui::get_guiparamspec -name "HART_ID" -component [ipx::current_core]]
set_property display_name {JEDEC ID} [ipgui::get_guiparamspec -name "JEDEC_ID" -component [ipx::current_core]]
set_property tooltip {For JTAG tap identification and mvendorid CSR} [ipgui::get_guiparamspec -name "JEDEC_ID" -component [ipx::current_core]]
set_property display_name {RISC-V on-chip debugger} [ipgui::get_guiparamspec -name "OCD_EN" -component [ipx::current_core]]
set_property display_name {RISC-V on-chip debugger authentication} [ipgui::get_guiparamspec -name "OCD_AUTHENTICATION" -component [ipx::current_core]]
set_property display_name {AXI4-Lite (XBUS) timeout} [ipgui::get_guiparamspec -name "XBUS_TIMEOUT" -component [ipx::current_core]]
set_property tooltip {Max number of clock cycles before AXI access times out} [ipgui::get_guiparamspec -name "XBUS_TIMEOUT" -component [ipx::current_core]]
set_property display_name {AXI4-Lite (XBUS) cache} [ipgui::get_guiparamspec -name "XBUS_CACHE_EN" -component [ipx::current_core]]
set_property display_name {AXI4-Lite (XBUS) cache number of blocks} [ipgui::get_guiparamspec -name "XBUS_CACHE_NUM_BLOCKS" -component [ipx::current_core]]
set_property display_name {AXI4-Lite (XBUS) cache block size} [ipgui::get_guiparamspec -name "XBUS_CACHE_BLOCK_SIZE" -component [ipx::current_core]]
set_property tooltip {In bytes (use a power of two)} [ipgui::get_guiparamspec -name "XBUS_CACHE_BLOCK_SIZE" -component [ipx::current_core]]
set_property display_name {AXI4-Stream (SLINK) source and sink} [ipgui::get_guiparamspec -name "AXI4_STREAM_EN" -component [ipx::current_core]]
set_property display_name {AXI4-Stream (SLINK) input FIFO depth} [ipgui::get_guiparamspec -name "IO_SLINK_RX_FIFO" -component [ipx::current_core]]
set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_SLINK_RX_FIFO" -component [ipx::current_core]]
set_property display_name {AXI4-Stream (SLINK) output FIFO depth} [ipgui::get_guiparamspec -name "IO_SLINK_TX_FIFO" -component [ipx::current_core]]
set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_SLINK_TX_FIFO" -component [ipx::current_core]]
proc setup_ip_gui {} {
proc set_param_properties {name {display_name ""} {tooltip ""} {enablement_expr ""} {value_expr ""}} {
set param_spec [ipgui::get_guiparamspec -name $name -component [ipx::current_core]]
set user_param [ipx::get_user_parameters $name -of_objects [ipx::current_core]]
if {$display_name ne ""} {
set_property display_name $display_name $param_spec
}
if {$tooltip ne ""} {
set_property tooltip $tooltip $param_spec
}
if {$enablement_expr ne ""} {
set_property enablement_tcl_expr $enablement_expr $user_param
}
if {$value_expr ne ""} {
set_property value_tcl_expr $value_expr $user_param
}
}
ipgui::add_group -name {General} -component [ipx::current_core] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]] -display_name {General}
ipgui::move_group -component [ipx::current_core] -order 0 [ipgui::get_groupspec -name "General" -component [ipx::current_core]] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 0 [ipgui::get_guiparamspec -name "CLOCK_FREQUENCY" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 1 [ipgui::get_guiparamspec -name "HART_ID" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 2 [ipgui::get_guiparamspec -name "JEDEC_ID" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 3 [ipgui::get_guiparamspec -name "OCD_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 4 [ipgui::get_guiparamspec -name "OCD_AUTHENTICATION" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 5 [ipgui::get_guiparamspec -name "XBUS_TIMEOUT" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 6 [ipgui::get_guiparamspec -name "XBUS_CACHE_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 7 [ipgui::get_guiparamspec -name "XBUS_CACHE_NUM_BLOCKS" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 8 [ipgui::get_guiparamspec -name "XBUS_CACHE_BLOCK_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 9 [ipgui::get_guiparamspec -name "AXI4_STREAM_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 10 [ipgui::get_guiparamspec -name "IO_SLINK_RX_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 11 [ipgui::get_guiparamspec -name "IO_SLINK_TX_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]]
proc add_page { name {tooltip ""} } {
set page [ipgui::add_page -name $name -component [ipx::current_core] -display_name $name]
if {$tooltip eq ""} {
set_property tooltip $tooltip $page
}
return $page
}
# **************************************************************
# Configuration GUI: CPU
# **************************************************************
set_property display_name {RISC-V C ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_C" -component [ipx::current_core]]
set_property tooltip {Compressed instructions} [ipgui::get_guiparamspec -name "RISCV_ISA_C" -component [ipx::current_core]]
set_property display_name {RISC-V E ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_E" -component [ipx::current_core]]
set_property tooltip {Reduced register file size (16 registers only)} [ipgui::get_guiparamspec -name "RISCV_ISA_E" -component [ipx::current_core]]
set_property display_name {RISC-V M ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_M" -component [ipx::current_core]]
set_property tooltip {Integer multiplication and division hardware} [ipgui::get_guiparamspec -name "RISCV_ISA_M" -component [ipx::current_core]]
set_property display_name {RISC-V U ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_U" -component [ipx::current_core]]
set_property tooltip {Less-privileged user-mode} [ipgui::get_guiparamspec -name "RISCV_ISA_U" -component [ipx::current_core]]
set_property display_name {RISC-V Zalrsc ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zalrsc" -component [ipx::current_core]]
set_property tooltip {Atomic reservation-set instructions} [ipgui::get_guiparamspec -name "RISCV_ISA_Zalrsc" -component [ipx::current_core]]
set_property display_name {RISC-V Zba ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zba" -component [ipx::current_core]]
set_property tooltip {Shifted-add bit-manipulation instructions} [ipgui::get_guiparamspec -name "RISCV_ISA_Zba" -component [ipx::current_core]]
set_property display_name {RISC-V Zbb ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbb" -component [ipx::current_core]]
set_property tooltip {Basic bit-manipulation instructions} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbb" -component [ipx::current_core]]
set_property display_name {RISC-V Zfinx ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zfinx" -component [ipx::current_core]]
set_property tooltip {Embedded FPU} [ipgui::get_guiparamspec -name "RISCV_ISA_Zfinx" -component [ipx::current_core]]
set_property display_name {RISC-V Zihpm ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zihpm" -component [ipx::current_core]]
set_property tooltip {Hardware performance monitors (HPMs)} [ipgui::get_guiparamspec -name "RISCV_ISA_Zihpm" -component [ipx::current_core]]
set_property display_name {HPM counters} [ipgui::get_guiparamspec -name "HPM_NUM_CNTS" -component [ipx::current_core]]
set_property tooltip {Numer of hardware performance monitor counters} [ipgui::get_guiparamspec -name "HPM_NUM_CNTS" -component [ipx::current_core]]
set_property display_name {HPM width} [ipgui::get_guiparamspec -name "HPM_CNT_WIDTH" -component [ipx::current_core]]
set_property tooltip {Counter width in bits} [ipgui::get_guiparamspec -name "HPM_CNT_WIDTH" -component [ipx::current_core]]
set_property display_name {RISC-V Zicntr ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zicntr" -component [ipx::current_core]]
set_property tooltip {Base counters (cycles and instructions)} [ipgui::get_guiparamspec -name "RISCV_ISA_Zicntr" -component [ipx::current_core]]
set_property display_name {RISC-V Zicond ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zicond" -component [ipx::current_core]]
set_property tooltip {Conditional-move instructions} [ipgui::get_guiparamspec -name "RISCV_ISA_Zicond" -component [ipx::current_core]]
set_property display_name {RISC-V Zmmul ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zmmul" -component [ipx::current_core]]
set_property tooltip {Integer multiplication-only hardware} [ipgui::get_guiparamspec -name "RISCV_ISA_Zmmul" -component [ipx::current_core]]
set_property display_name {NEORV32 Zxcfu ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zxcfu" -component [ipx::current_core]]
set_property tooltip {Custom-instructions unit} [ipgui::get_guiparamspec -name "RISCV_ISA_Zxcfu" -component [ipx::current_core]]
set_property display_name {RISC-V Zbkb ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkb" -component [ipx::current_core]]
set_property tooltip {Bit manipulation instructions for cryptography} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkb" -component [ipx::current_core]]
set_property display_name {RISC-V Zbkc ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkc" -component [ipx::current_core]]
set_property tooltip {Carry-less multiply instr. for cryptography} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkc" -component [ipx::current_core]]
set_property display_name {RISC-V Zbkx ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkx" -component [ipx::current_core]]
set_property tooltip {Scalar cryptographic - crossbar permutations} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkx" -component [ipx::current_core]]
set_property display_name {RISC-V Zbs ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbs" -component [ipx::current_core]]
set_property tooltip {Single-bit bit-manipulation instructions} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbs" -component [ipx::current_core]]
set_property display_name {RISC-V Zknd ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zknd" -component [ipx::current_core]]
set_property tooltip {Scalar cryptographic - NIST AES decryption} [ipgui::get_guiparamspec -name "RISCV_ISA_Zknd" -component [ipx::current_core]]
set_property display_name {RISC-V Zkne ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zkne" -component [ipx::current_core]]
set_property tooltip {Scalar cryptographic - NIST AES encryption} [ipgui::get_guiparamspec -name "RISCV_ISA_Zkne" -component [ipx::current_core]]
set_property display_name {RISC-V Zknh ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zknh" -component [ipx::current_core]]
set_property tooltip {Scalar cryptographic - NIST hash functions} [ipgui::get_guiparamspec -name "RISCV_ISA_Zknh" -component [ipx::current_core]]
set_property display_name {RISC-V Zksed ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zksed" -component [ipx::current_core]]
set_property tooltip {Scalar cryptographic - ShangMi block cyphers} [ipgui::get_guiparamspec -name "RISCV_ISA_Zksed" -component [ipx::current_core]]
set_property display_name {RISC-V Zksh ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zksh" -component [ipx::current_core]]
set_property tooltip {Scalar cryptographic - ShangMi hash functions} [ipgui::get_guiparamspec -name "RISCV_ISA_Zksh" -component [ipx::current_core]]
set_property display_name {DSP-based multiplier} [ipgui::get_guiparamspec -name "FAST_MUL_EN" -component [ipx::current_core]]
set_property display_name {Barrel shifter} [ipgui::get_guiparamspec -name "FAST_SHIFT_EN" -component [ipx::current_core]]
set_property display_name {FF-based register file with full HW reset} [ipgui::get_guiparamspec -name "REGFILE_HW_RST" -component [ipx::current_core]]
set_property display_name {PMP regions} [ipgui::get_guiparamspec -name "PMP_NUM_REGIONS" -component [ipx::current_core]]
set_property tooltip {Number of physical memory protection regions} [ipgui::get_guiparamspec -name "PMP_NUM_REGIONS" -component [ipx::current_core]]
set_property display_name {PMP minimal granularity} [ipgui::get_guiparamspec -name "PMP_MIN_GRANULARITY" -component [ipx::current_core]]
set_property tooltip {In bytes (min 4 bytes)} [ipgui::get_guiparamspec -name "PMP_MIN_GRANULARITY" -component [ipx::current_core]]
set_property display_name {Enable PMP TOR mode} [ipgui::get_guiparamspec -name "PMP_TOR_MODE_EN" -component [ipx::current_core]]
set_property tooltip {Top-of-region} [ipgui::get_guiparamspec -name "PMP_TOR_MODE_EN" -component [ipx::current_core]]
set_property display_name {Enable PMP NA2 and NAPOT modes} [ipgui::get_guiparamspec -name "PMP_NAP_MODE_EN" -component [ipx::current_core]]
set_property tooltip {Naturally-aligned-power-of-two} [ipgui::get_guiparamspec -name "PMP_NAP_MODE_EN" -component [ipx::current_core]]
proc add_group { parent name {display_name ""} } {
if {$display_name eq ""} {
set display_name $name
}
ipgui::add_group -name $name -component [ipx::current_core] -parent $parent -display_name $display_name
}
ipgui::add_group -name {CPU Configuration} -component [ipx::current_core] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]] -display_name {CPU Configuration}
ipgui::move_group -component [ipx::current_core] -order 1 [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 0 [ipgui::get_guiparamspec -name "RISCV_ISA_C" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 1 [ipgui::get_guiparamspec -name "RISCV_ISA_E" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 2 [ipgui::get_guiparamspec -name "RISCV_ISA_M" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 3 [ipgui::get_guiparamspec -name "RISCV_ISA_U" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 4 [ipgui::get_guiparamspec -name "RISCV_ISA_Zalrsc" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 5 [ipgui::get_guiparamspec -name "RISCV_ISA_Zba" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 6 [ipgui::get_guiparamspec -name "RISCV_ISA_Zbb" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 7 [ipgui::get_guiparamspec -name "RISCV_ISA_Zfinx" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 8 [ipgui::get_guiparamspec -name "RISCV_ISA_Zihpm" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 9 [ipgui::get_guiparamspec -name "HPM_NUM_CNTS" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 10 [ipgui::get_guiparamspec -name "HPM_CNT_WIDTH" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 11 [ipgui::get_guiparamspec -name "RISCV_ISA_Zicntr" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 12 [ipgui::get_guiparamspec -name "RISCV_ISA_Zicond" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 13 [ipgui::get_guiparamspec -name "RISCV_ISA_Zmmul" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 14 [ipgui::get_guiparamspec -name "RISCV_ISA_Zxcfu" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 15 [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkb" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 16 [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkc" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 17 [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkx" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 18 [ipgui::get_guiparamspec -name "RISCV_ISA_Zbs" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 19 [ipgui::get_guiparamspec -name "RISCV_ISA_Zknd" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 20 [ipgui::get_guiparamspec -name "RISCV_ISA_Zkne" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 21 [ipgui::get_guiparamspec -name "RISCV_ISA_Zknh" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 22 [ipgui::get_guiparamspec -name "RISCV_ISA_Zksed" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 23 [ipgui::get_guiparamspec -name "RISCV_ISA_Zksh" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 24 [ipgui::get_guiparamspec -name "FAST_MUL_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 25 [ipgui::get_guiparamspec -name "FAST_SHIFT_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 26 [ipgui::get_guiparamspec -name "REGFILE_HW_RST" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 27 [ipgui::get_guiparamspec -name "PMP_NUM_REGIONS" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 28 [ipgui::get_guiparamspec -name "PMP_MIN_GRANULARITY" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 29 [ipgui::get_guiparamspec -name "PMP_TOR_MODE_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 30 [ipgui::get_guiparamspec -name "PMP_NAP_MODE_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]]
proc add_params { parent params } {
foreach param $params {
set name [lindex $param 0]
ipgui::add_param -name $name -component [ipx::current_core] -parent $parent
set_param_properties {*}$param
}
}
# **************************************************************
# Configuration GUI: Memory System
# **************************************************************
set_property display_name {Internal instruction memory (IMEM)} [ipgui::get_guiparamspec -name "MEM_INT_IMEM_EN" -component [ipx::current_core]]
set_property display_name {Internal instruction memory size} [ipgui::get_guiparamspec -name "MEM_INT_IMEM_SIZE" -component [ipx::current_core]]
set_property tooltip {In bytes (use a power of two)} [ipgui::get_guiparamspec -name "MEM_INT_IMEM_SIZE" -component [ipx::current_core]]
set_property display_name {Internal data memory (DMEM)} [ipgui::get_guiparamspec -name "MEM_INT_DMEM_EN" -component [ipx::current_core]]
set_property display_name {Internal data memory size} [ipgui::get_guiparamspec -name "MEM_INT_DMEM_SIZE" -component [ipx::current_core]]
set_property tooltip {In bytes (use a power of two)} [ipgui::get_guiparamspec -name "MEM_INT_DMEM_SIZE" -component [ipx::current_core]]
set_property display_name {CPU instruction cache (ICACHE)} [ipgui::get_guiparamspec -name "ICACHE_EN" -component [ipx::current_core]]
set_property display_name {CPU instruction cache (ICACHE) number of blocks} [ipgui::get_guiparamspec -name "ICACHE_NUM_BLOCKS" -component [ipx::current_core]]
set_property display_name {CPU instruction cache (ICACHE) block size} [ipgui::get_guiparamspec -name "ICACHE_BLOCK_SIZE" -component [ipx::current_core]]
set_property tooltip {In bytes (use a power of two)} [ipgui::get_guiparamspec -name "ICACHE_BLOCK_SIZE" -component [ipx::current_core]]
set_property display_name {CPU data cache (DCACHE)} [ipgui::get_guiparamspec -name "DCACHE_EN" -component [ipx::current_core]]
set_property display_name {CPU data cache (DCACHE) number of blocks} [ipgui::get_guiparamspec -name "DCACHE_NUM_BLOCKS" -component [ipx::current_core]]
set_property display_name {CPU data cache (DCACHE) block size} [ipgui::get_guiparamspec -name "DCACHE_BLOCK_SIZE" -component [ipx::current_core]]
set_property tooltip {In bytes (use a power of two)} [ipgui::get_guiparamspec -name "DCACHE_BLOCK_SIZE" -component [ipx::current_core]]
set_property display_name {Execute in-place module (XIP)} [ipgui::get_guiparamspec -name "XIP_EN" -component [ipx::current_core]]
set_property display_name {Execute in-place module (XIP) cache} [ipgui::get_guiparamspec -name "XIP_CACHE_EN" -component [ipx::current_core]]
set_property display_name {Execute in-place module (XIP) cache number of blocks} [ipgui::get_guiparamspec -name "XIP_CACHE_NUM_BLOCKS" -component [ipx::current_core]]
set_property display_name {Execute in-place module (XIP) cache block size} [ipgui::get_guiparamspec -name "XIP_CACHE_BLOCK_SIZE" -component [ipx::current_core]]
set_property tooltip {In bytes (use a power of two)} [ipgui::get_guiparamspec -name "XIP_CACHE_BLOCK_SIZE" -component [ipx::current_core]]
set_property display_name {Internal bootloader} [ipgui::get_guiparamspec -name "INT_BOOTLOADER_EN" -component [ipx::current_core]]
set_property tooltip {Start interactive bootloader console after reset} [ipgui::get_guiparamspec -name "INT_BOOTLOADER_EN" -component [ipx::current_core]]
ipgui::add_group -name {Memory System} -component [ipx::current_core] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]] -display_name {Memory System}
ipgui::move_group -component [ipx::current_core] -order 2 [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 0 [ipgui::get_guiparamspec -name "MEM_INT_IMEM_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 1 [ipgui::get_guiparamspec -name "MEM_INT_IMEM_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 2 [ipgui::get_guiparamspec -name "MEM_INT_DMEM_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 3 [ipgui::get_guiparamspec -name "MEM_INT_DMEM_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 4 [ipgui::get_guiparamspec -name "ICACHE_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 5 [ipgui::get_guiparamspec -name "ICACHE_NUM_BLOCKS" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 6 [ipgui::get_guiparamspec -name "ICACHE_BLOCK_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 7 [ipgui::get_guiparamspec -name "DCACHE_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 8 [ipgui::get_guiparamspec -name "DCACHE_NUM_BLOCKS" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 9 [ipgui::get_guiparamspec -name "DCACHE_BLOCK_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 10 [ipgui::get_guiparamspec -name "XIP_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 11 [ipgui::get_guiparamspec -name "XIP_CACHE_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 12 [ipgui::get_guiparamspec -name "XIP_CACHE_NUM_BLOCKS" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 13 [ipgui::get_guiparamspec -name "XIP_CACHE_BLOCK_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 14 [ipgui::get_guiparamspec -name "INT_BOOTLOADER_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]]
# **************************************************************
# Interfaces: Configuration Dependencies
# **************************************************************
set_property enablement_dependency {$IO_SLINK_EN} [ipx::get_bus_interfaces s0_axis -of_objects [ipx::current_core]]
set_property enablement_dependency {$IO_SLINK_EN} [ipx::get_bus_interfaces s1_axis -of_objects [ipx::current_core]]
set_property enablement_dependency {$XBUS_EN} [ipx::get_bus_interfaces m_axi -of_objects [ipx::current_core]]
set_property enablement_dependency {$OCD_EN} [ipx::get_ports jtag_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$XIP_EN} [ipx::get_ports xip_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$IO_GPIO_EN} [ipx::get_ports gpio_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$IO_UART0_EN} [ipx::get_ports uart0_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$IO_UART1_EN} [ipx::get_ports uart1_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$IO_SPI_EN} [ipx::get_ports spi_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$IO_SDI_EN} [ipx::get_ports sdi_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$IO_TWI_EN} [ipx::get_ports twi_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$IO_ONEWIRE_EN} [ipx::get_ports onewire_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$IO_PWM_EN} [ipx::get_ports pwm_o -of_objects [ipx::current_core]]
set_property enablement_dependency {$IO_CFS_EN} [ipx::get_ports cfs_* -of_objects [ipx::current_core]]
set_property enablement_dependency {$IO_NEOLED_EN} [ipx::get_ports neoled_o -of_objects [ipx::current_core]]
set_property enablement_dependency {$XIRQ_EN} [ipx::get_ports xirq_i -of_objects [ipx::current_core]]
set_property enablement_dependency {$IO_MTIME_EN} [ipx::get_ports mtime_time_o -of_objects [ipx::current_core]]
set_property enablement_dependency {!$IO_MTIME_EN} [ipx::get_ports mtime_irq_i -of_objects [ipx::current_core]]
# **************************************************************
# Configuration GUI: Peripherals
# **************************************************************
set_property display_name {External interrupt controller (XIRQ)} [ipgui::get_guiparamspec -name "XIRQ_EN" -component [ipx::current_core]]
set_property display_name {External interrupt controller (XIRQ) channels} [ipgui::get_guiparamspec -name "XIRQ_NUM_CH" -component [ipx::current_core]]
set_property display_name {General-Purpose Input/Output (GPIO) controller} [ipgui::get_guiparamspec -name "IO_GPIO_EN" -component [ipx::current_core]]
set_property display_name {General-purpose (GPIO) inputs} [ipgui::get_guiparamspec -name "IO_GPIO_IN_NUM" -component [ipx::current_core]]
set_property display_name {General-purpose (GPIO) outputs} [ipgui::get_guiparamspec -name "IO_GPIO_OUT_NUM" -component [ipx::current_core]]
set_property display_name {Machine timer (MTIME)} [ipgui::get_guiparamspec -name "IO_MTIME_EN" -component [ipx::current_core]]
set_property display_name {Primary UART (UART0)} [ipgui::get_guiparamspec -name "IO_UART0_EN" -component [ipx::current_core]]
set_property display_name {Primary UART (UART0) RX FIFO depth} [ipgui::get_guiparamspec -name "IO_UART0_RX_FIFO" -component [ipx::current_core]]
set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_UART0_RX_FIFO" -component [ipx::current_core]]
set_property display_name {Primary UART (UART0) TX FIFO depth} [ipgui::get_guiparamspec -name "IO_UART0_TX_FIFO" -component [ipx::current_core]]
set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_UART0_TX_FIFO" -component [ipx::current_core]]
set_property display_name {Secondary UART (UART1)} [ipgui::get_guiparamspec -name "IO_UART1_EN" -component [ipx::current_core]]
set_property display_name {Secondary UART (UART1) RX FIFO depth} [ipgui::get_guiparamspec -name "IO_UART1_RX_FIFO" -component [ipx::current_core]]
set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_UART1_RX_FIFO" -component [ipx::current_core]]
set_property display_name {Secondary UART (UART1) TX FIFO depth} [ipgui::get_guiparamspec -name "IO_UART1_TX_FIFO" -component [ipx::current_core]]
set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_UART1_TX_FIFO" -component [ipx::current_core]]
set_property display_name {SPI host controller (SPI)} [ipgui::get_guiparamspec -name "IO_SPI_EN" -component [ipx::current_core]]
set_property display_name {SPI host controller (SPI) FIFO depth} [ipgui::get_guiparamspec -name "IO_SPI_FIFO" -component [ipx::current_core]]
set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_SPI_FIFO" -component [ipx::current_core]]
set_property display_name {SPI device controller (SDI)} [ipgui::get_guiparamspec -name "IO_SDI_EN" -component [ipx::current_core]]
set_property display_name {SPI device controller (SDI) FIFO depth} [ipgui::get_guiparamspec -name "IO_SDI_FIFO" -component [ipx::current_core]]
set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_SDI_FIFO" -component [ipx::current_core]]
set_property display_name {Two-Wire/I2C Interface (TWI)} [ipgui::get_guiparamspec -name "IO_TWI_EN" -component [ipx::current_core]]
set_property display_name {Two-Wire/I2C Interface (TWI) FIFO depth} [ipgui::get_guiparamspec -name "IO_TWI_FIFO" -component [ipx::current_core]]
set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_TWI_FIFO" -component [ipx::current_core]]
set_property display_name {Pulse-Width Moduleation (PWM) controller} [ipgui::get_guiparamspec -name "IO_PWM_EN" -component [ipx::current_core]]
set_property display_name {Pulse-Width Moduleation (PWM) channels} [ipgui::get_guiparamspec -name "IO_PWM_NUM_CH" -component [ipx::current_core]]
set_property display_name {Watchdog timer (WDT)} [ipgui::get_guiparamspec -name "IO_WDT_EN" -component [ipx::current_core]]
set_property display_name {True-Random-Number Generator (TRNG)} [ipgui::get_guiparamspec -name "IO_TRNG_EN" -component [ipx::current_core]]
set_property display_name {True-Random-Number Generator (TRNG) FIFO depth} [ipgui::get_guiparamspec -name "IO_TRNG_FIFO" -component [ipx::current_core]]
set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_TRNG_FIFO" -component [ipx::current_core]]
set_property display_name {Custom Functions Subsystem (CFS)} [ipgui::get_guiparamspec -name "IO_CFS_EN" -component [ipx::current_core]]
set_property display_name {Custom Functions Subsystem (CFS) configuration word} [ipgui::get_guiparamspec -name "IO_CFS_CONFIG" -component [ipx::current_core]]
set_property display_name {Custom Functions Subsystem (CFS) input port width} [ipgui::get_guiparamspec -name "IO_CFS_IN_SIZE" -component [ipx::current_core]]
set_property display_name {Custom Functions Subsystem (CFS) output port width} [ipgui::get_guiparamspec -name "IO_CFS_OUT_SIZE" -component [ipx::current_core]]
set_property display_name {Smart LED Interface (NEOLED)} [ipgui::get_guiparamspec -name "IO_NEOLED_EN" -component [ipx::current_core]]
set_property display_name {Smart LED Interface (NEOLED) FIFO depth} [ipgui::get_guiparamspec -name "IO_NEOLED_TX_FIFO" -component [ipx::current_core]]
set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_NEOLED_TX_FIFO" -component [ipx::current_core]]
set_property display_name {General Purpose Timer (GPTMR)} [ipgui::get_guiparamspec -name "IO_GPTMR_EN" -component [ipx::current_core]]
set_property display_name {1-Wire (ONEWIRE) controller} [ipgui::get_guiparamspec -name "IO_ONEWIRE_EN" -component [ipx::current_core]]
set_property display_name {Direct Memory Access (DMA) controller} [ipgui::get_guiparamspec -name "IO_DMA_EN" -component [ipx::current_core]]
set_property display_name {Cyclic Redundancy Check (CRC) Unit} [ipgui::get_guiparamspec -name "IO_CRC_EN" -component [ipx::current_core]]
ipgui::add_group -name {Peripherals} -component [ipx::current_core] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]] -display_name {Peripherals}
ipgui::move_group -component [ipx::current_core] -order 3 [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 0 [ipgui::get_guiparamspec -name "IO_GPIO_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 1 [ipgui::get_guiparamspec -name "IO_GPIO_IN_NUM" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 2 [ipgui::get_guiparamspec -name "IO_GPIO_OUT_NUM" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 3 [ipgui::get_guiparamspec -name "IO_MTIME_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 4 [ipgui::get_guiparamspec -name "IO_UART0_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 5 [ipgui::get_guiparamspec -name "IO_UART0_RX_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 6 [ipgui::get_guiparamspec -name "IO_UART0_TX_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 7 [ipgui::get_guiparamspec -name "IO_UART1_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 8 [ipgui::get_guiparamspec -name "IO_UART1_RX_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 9 [ipgui::get_guiparamspec -name "IO_UART1_TX_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 10 [ipgui::get_guiparamspec -name "IO_SPI_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 11 [ipgui::get_guiparamspec -name "IO_SPI_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 12 [ipgui::get_guiparamspec -name "IO_SDI_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 13 [ipgui::get_guiparamspec -name "IO_SDI_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 14 [ipgui::get_guiparamspec -name "IO_TWI_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 15 [ipgui::get_guiparamspec -name "IO_TWI_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 16 [ipgui::get_guiparamspec -name "IO_PWM_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 17 [ipgui::get_guiparamspec -name "IO_PWM_NUM_CH" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 18 [ipgui::get_guiparamspec -name "IO_WDT_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 19 [ipgui::get_guiparamspec -name "IO_TRNG_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 20 [ipgui::get_guiparamspec -name "IO_TRNG_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 21 [ipgui::get_guiparamspec -name "IO_CFS_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 22 [ipgui::get_guiparamspec -name "IO_CFS_CONFIG" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 23 [ipgui::get_guiparamspec -name "IO_CFS_IN_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 24 [ipgui::get_guiparamspec -name "IO_CFS_OUT_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 25 [ipgui::get_guiparamspec -name "IO_NEOLED_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 26 [ipgui::get_guiparamspec -name "IO_NEOLED_TX_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 27 [ipgui::get_guiparamspec -name "IO_GPTMR_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 28 [ipgui::get_guiparamspec -name "IO_ONEWIRE_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 29 [ipgui::get_guiparamspec -name "IO_DMA_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 30 [ipgui::get_guiparamspec -name "XIRQ_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 31 [ipgui::get_guiparamspec -name "XIRQ_NUM_CH" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
ipgui::move_param -component [ipx::current_core] -order 32 [ipgui::get_guiparamspec -name "IO_CRC_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]]
# **************************************************************
# Configuration pages
# **************************************************************
# Remove default page
set page [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]]
if {$page ne ""} {
ipgui::remove_page -component [ipx::current_core] $page
}
# **************************************************************
# GUI Page: General
# **************************************************************
set page [add_page {General}]
# { param_name {display_name} {tooltip} {enablement_expr} {value_expr} }
set group [add_group $page {Clocking}]
add_params $page {
{ CLOCK_FREQUENCY {Clock Frequency (Hz)} {Frequency of the clk input signal in Hz} }
}
set group [add_group $page {Boot Configuration}]
add_params $group {
{ BOOT_MODE_SELECT {Boot mode select} {Processor boot configuration} }
{ BOOT_ADDR_CUSTOM {Custom boot address} {Available if BOOT_MODE_SELECT = 1; has to be 4-byte aligned} {$BOOT_MODE_SELECT == 1}}
}
set_property widget {comboBox} [ipgui::get_guiparamspec -name "BOOT_MODE_SELECT" -component [ipx::current_core] ]
set_property value_validation_type pairs [ipx::get_user_parameters BOOT_MODE_SELECT -of_objects [ipx::current_core]]
set_property value_validation_pairs {{Internal bootloader} 0 {Custom address} 1 {Internal IMEM image} 2} [ipx::get_user_parameters BOOT_MODE_SELECT -of_objects [ipx::current_core]]
set group [add_group $page {Core Identification}]
add_params $group {
{ HART_ID {HART ID} {The hart thread ID of the CPU (passed to mhartid CSR)} }
{ JEDEC_ID {JEDEC ID} {For JTAG tap identification and mvendorid CSR} }
}
set group [add_group $page {On-Chip Debugger (OCD)}]
add_params $group {
{ OCD_EN {Enable OCD} {Implement the on-chip debugger and the CPU debug mode} }
{ OCD_AUTHENTICATION {OCD Authentication} {Implement Debug Authentication module} {$OCD_EN} {$OCD_EN ? $OCD_AUTHENTICATION : false}}
}
set group [add_group $page {External Bus Interface (XBUS / AXI4-Lite-MM Host)}]
add_params $group {
{ XBUS_EN {Enable XBUS} {} }
{ XBUS_TIMEOUT {Timeout} {Max number of clock cycles before AXI access times out} {$XBUS_EN} }
}
set sub_group [add_group $group {XBUS Cache}]
add_params $sub_group {
{ XBUS_REGSTAGE_EN {Add register stages} {Relaxes timing, but will increase latency} {$XBUS_EN} }
{ XBUS_CACHE_EN {Enable XBUS Cache} {} {$XBUS_EN} {$XBUS_EN ? $XBUS_CACHE_EN : false}}
{ XBUS_CACHE_NUM_BLOCKS {Number of Blocks} {} {$XBUS_CACHE_EN} }
{ XBUS_CACHE_BLOCK_SIZE {Block Size} {In bytes (use a power of two)} {$XBUS_CACHE_EN} }
}
set group [add_group $page {Stream Link Interface (SLINK / AXI4-Stream Source & Sink)}]
add_params $group {
{ IO_SLINK_EN {Enable SLINK} {} }
{ IO_SLINK_RX_FIFO {RX FIFO Depth} {Number of entries (use a power of two)} {$IO_SLINK_EN} }
{ IO_SLINK_TX_FIFO {TX FIFO Depth} {Number of entries (use a power of two)} {$IO_SLINK_EN} }
}
# **************************************************************
# GUI Page: CPU
# **************************************************************
set page [add_page {CPU Configuration}]
set group [add_group $page {RISC-V ISA Extensions}]
add_params $group {
{ RISCV_ISA_C {C Extension} {Compressed instructions} }
{ RISCV_ISA_E {E Extension} {Reduced register file size (16 registers only)} }
{ RISCV_ISA_M {M Extension} {Integer multiplication and division hardware} }
{ RISCV_ISA_U {U Extension} {Less-privileged user-mode} }
{ RISCV_ISA_Zalrsc {Zalrsc Extension} {Atomic reservation-set instructions} }
{ RISCV_ISA_Zba {Zba Extension} {Shifted-add bit-manipulation instructions} }
{ RISCV_ISA_Zbb {Zbb Extension} {Basic bit-manipulation instructions} }
{ RISCV_ISA_Zbkb {Zbkb Extension} {Bit manipulation instructions for cryptography} }
{ RISCV_ISA_Zbkc {Zbkc Extension} {Carry-less multiply instr. for cryptography} }
{ RISCV_ISA_Zbkx {Zbkx Extension} {Scalar cryptographic - crossbar permutations} }
{ RISCV_ISA_Zbs {Zbs Extension} {Single-bit bit-manipulation instructions} }
{ RISCV_ISA_Zfinx {Zfinx Extension} {Embedded FPU} }
{ RISCV_ISA_Zicntr {Zicntr Extension} {Base counters (cycles and instructions)} }
{ RISCV_ISA_Zicond {Zicond Extension} {Conditional-move instructions} }
{ RISCV_ISA_Zihpm {Zihpm Extension} {Hardware performance monitors (HPMs)} }
{ HPM_CNT_WIDTH {HPM Width} {Counter width in bits} {$RISCV_ISA_Zihpm}}
{ HPM_NUM_CNTS {HPM Counters} {Numer of hardware performance monitor counters} {$RISCV_ISA_Zihpm}}
{ RISCV_ISA_Zknd {Zknd Extension} {Scalar cryptographic - NIST AES decryption} }
{ RISCV_ISA_Zkne {Zkne Extension} {Scalar cryptographic - NIST AES encryption} }
{ RISCV_ISA_Zknh {Zknh Extension} {Scalar cryptographic - NIST hash functions} }
{ RISCV_ISA_Zksed {Zksed Extension} {Scalar cryptographic - ShangMi block cyphers} }
{ RISCV_ISA_Zksh {Zksh Extension} {Scalar cryptographic - ShangMi hash functions} }
{ RISCV_ISA_Zmmul {Zmmul Extension} {Integer multiplication-only hardware} }
{ RISCV_ISA_Zxcfu {NEORV32 Zxcfu ISA Extension} {Custom-instructions unit} }
}
set group [add_group $page {Physical Memory Protection (PMP)}]
add_params $group {
{ PMP_NUM_REGIONS {PMP Regions} {Number of physical memory protection regions} }
{ PMP_MIN_GRANULARITY {PMP Minimal Granularity} {Minimal region granularity in bytes. Has to be a power of two.} {$PMP_NUM_REGIONS > 0} }
{ PMP_TOR_MODE_EN {Enable PMP TOR Mode} {Implement support for top-of-region (TOR) mode} {$PMP_NUM_REGIONS > 0} }
{ PMP_NAP_MODE_EN {Enable PMP NAPOT and NA4 Modes} {Implement support for naturally-aligned power-of-two (NAPOT & NA4) modes} {$PMP_NUM_REGIONS > 0} }
}
set_property value_validation_range_minimum 4 [ipx::get_user_parameters PMP_MIN_GRANULARITY -of_objects [ipx::current_core]]
set group [add_group $page {Tuning Options}]
add_params $group {
{ FAST_MUL_EN {DSP-Based Multiplier} }
{ FAST_SHIFT_EN {Barrel Shifter} }
{ REGFILE_HW_RST {Allow Full HW Reset for Register File} {Implement register file with FFs instead of BRAM to allow full hardware reset} }
}
# **************************************************************
# GUI Page: Memory System
# **************************************************************
set page [add_page {Memory System}]
set group [add_group $page {Internal Instruction Memory (IMEM)}]
add_params $group {
{ MEM_INT_IMEM_EN {Enable IMEM} }
{ MEM_INT_IMEM_SIZE {IMEM Size} {In bytes (use a power of two)} {$MEM_INT_IMEM_EN} }
}
set group [add_group $page {Internal Data Memory (DMEM)}]
add_params $group {
{ MEM_INT_DMEM_EN {Enbale DMEM} }
{ MEM_INT_DMEM_SIZE {DMEM Size} {In bytes (use a power of two)} {$MEM_INT_DMEM_EN} }
}
set group [add_group $page {CPU Instruction Cache (ICACHE)}]
add_params $group {
{ ICACHE_EN {Enable ICACHE} }
{ ICACHE_NUM_BLOCKS {Number of Blocks} {} {$ICACHE_EN} }
{ ICACHE_BLOCK_SIZE {Block Size} {In bytes (use a power of two)} {$ICACHE_EN} }
}
set group [add_group $page {CPU Data Cache (DCACHE)}]
add_params $group {
{ DCACHE_EN {Enable DCACHE} }
{ DCACHE_NUM_BLOCKS {Number of Blocks} {} {$DCACHE_EN} }
{ DCACHE_BLOCK_SIZE {Block Size} {In bytes (use a power of two)} {$DCACHE_EN} }
}
set group [add_group $page {Execute In-Place Module (XIP)}]
add_params $group {
{ XIP_EN {Enable XIP} }
{ XIP_CACHE_EN {Enable XIP Cache} {} {$XIP_EN} {$XIP_EN ? $XIP_CACHE_EN : false} }
{ XIP_CACHE_NUM_BLOCKS {Cache Blocks} {} {$XIP_CACHE_EN} }
{ XIP_CACHE_BLOCK_SIZE {Cache Block Size} {In bytes (use a power of two)} {$XIP_CACHE_EN} }
}
# **************************************************************
# GUI Page: Peripherals
# **************************************************************
set page [add_page {Peripherals}]
set group [add_group $page {External Interrupt Controller (XIRQ)}]
add_params $group {
{ XIRQ_EN {Enable XIRQ} }
{ XIRQ_NUM_CH {Number of Channels} {} {$XIRQ_EN} }
}
set group [add_group $page {General-Purpose Input/Output Controller (GPIO)}]
add_params $group {
{ IO_GPIO_EN {Enable GPIO} }
{ IO_GPIO_IN_NUM {Number of Inputs} {} {$IO_GPIO_EN} }
{ IO_GPIO_OUT_NUM {Number of Outputs} {} {$IO_GPIO_EN} }
}
set group [add_group $page {Machine Timer (MTIME)}]
add_params $group {
{ IO_MTIME_EN {Enable Machine Timer} }
}
set group [add_group $page {Primary UART (UART0)}]
add_params $group {
{ IO_UART0_EN {Enable UART0} }
{ IO_UART0_RX_FIFO {RX FIFO Depth} {Number of entries (use a power of two)} {$IO_UART0_EN} }
{ IO_UART0_TX_FIFO {TX FIFO Depth} {Number of entries (use a power of two)} {$IO_UART0_EN} }
}
set group [add_group $page {Secondary UART (UART1)}]
add_params $group {
{ IO_UART1_EN {Enable UART1} }
{ IO_UART1_RX_FIFO {RX FIFO Depth} {Number of entries (use a power of two)} {$IO_UART1_EN} }
{ IO_UART1_TX_FIFO {TX FIFO Depth} {Number of entries (use a power of two)} {$IO_UART1_EN} }
}
set group [add_group $page {SPI Host Controller (SPI)}]
add_params $group {
{ IO_SPI_EN {Enable SPI} }
{ IO_SPI_FIFO {FIFO Depth} {Number of entries (use a power of two)} {$IO_SPI_EN} }
}
set group [add_group $page {SPI Device Controller (SDI)}]
add_params $group {
{ IO_SDI_EN {Enable SDI} }
{ IO_SDI_FIFO {FIFO Depth} {Number of entries (use a power of two)} {$IO_SDI_EN} }
}
set group [add_group $page {Two-Wire/I2C Interface (TWI)}]
add_params $group {
{ IO_TWI_EN {Enable TWI} }
{ IO_TWI_FIFO {FIFO Depth} {Number of entries (use a power of two)} {$IO_TWI_EN} }
}
set group [add_group $page {Pulse-Width Modulation Controller (PWM)}]
add_params $group {
{ IO_PWM_EN {Enable PWM} }
{ IO_PWM_NUM_CH {Number of Channels} {} {$IO_PWM_EN} }
}
set group [add_group $page {Watchdog Timer (WDT)}]
add_params $group {
{ IO_WDT_EN {Enable WDT} }
}
set group [add_group $page {True Random-Number Generator (TRNG)}]
add_params $group {
{ IO_TRNG_EN {Enable TRNG} }
{ IO_TRNG_FIFO {FIFO Depth} {Number of entries (use a power of two)} {$IO_TRNG_EN} }
}
set group [add_group $page {Custom Functions Subsystem (CFS)}]
add_params $group {
{ IO_CFS_EN {Enable CFS} }
{ IO_CFS_CONFIG {Configuration Word} {} {$IO_CFS_EN} }
{ IO_CFS_IN_SIZE {Input Port Width} {} {$IO_CFS_EN} }
{ IO_CFS_OUT_SIZE {Output Port Width} {} {$IO_CFS_EN} }
}
set group [add_group $page {Smart LED Interface (NEOLED)}]
add_params $group {
{ IO_NEOLED_EN {Enable NEOLED} }
{ IO_NEOLED_TX_FIFO {FIFO Depth} {Number of entries (use a power of two)} {$IO_NEOLED_EN} }
}
set group [add_group $page {General Purpose Timer (GPTMR)}]
add_params $group {
{ IO_GPTMR_EN {Enable GPTMR} }
}
set group [add_group $page {One-Wire Interface Controller (ONEWIRE)}]
add_params $group {
{ IO_ONEWIRE_EN {Enable ONEWIRE} }
}
set group [add_group $page {Direct Memory Access Controller (DMA)}]
add_params $group {
{ IO_DMA_EN {Enable DMA} }
}
set group [add_group $page {Cyclic Redundancy Check (CRC)}]
add_params $group {
{ IO_CRC_EN {Enable CRC} }
}
}
setup_ip_gui
# **************************************************************
# Configuration GUI: IP logo
@ -357,6 +415,10 @@ ipx::add_file ../../$neorv32_home/$ip_logo [ipx::get_file_groups xilinx_coreguii
set_property type image [ipx::get_files ../../$neorv32_home/$ip_logo -of_objects [ipx::get_file_groups xilinx_coreguiicon -of_objects [ipx::current_core]]]
set_property type LOGO [ipx::get_files ../../$neorv32_home/$ip_logo -of_objects [ipx::get_file_groups xilinx_coreguiicon -of_objects [ipx::current_core]]]
ipx::add_file_group -type product_guide {} [ipx::current_core]
ipx::add_file {https://stnolting.github.io/neorv32/} [ipx::get_file_groups xilinx_productguide -of_objects [ipx::current_core]]
# **************************************************************
# Finalize and add to IP repository
# **************************************************************

View file

@ -25,13 +25,14 @@ entity neorv32_vivado_ip is
-- ------------------------------------------------------------
-- Configuration Generics
-- ------------------------------------------------------------
-- AXI-Stream Interfaces --
AXI4_STREAM_EN : boolean := false;
-- General --
-- Clocking --
CLOCK_FREQUENCY : natural := 100_000_000;
-- Identification --
HART_ID : std_logic_vector(31 downto 0) := x"00000000";
JEDEC_ID : std_logic_vector(10 downto 0) := "00000000000";
INT_BOOTLOADER_EN : boolean := false;
-- Boot Configuration --
BOOT_MODE_SELECT : natural range 0 to 2 := 0;
BOOT_ADDR_CUSTOM : std_ulogic_vector(31 downto 0) := x"00000000";
-- On-Chip Debugger (OCD) --
OCD_EN : boolean := false;
OCD_AUTHENTICATION : boolean := false;
@ -85,7 +86,9 @@ entity neorv32_vivado_ip is
DCACHE_NUM_BLOCKS : natural range 1 to 256 := 4;
DCACHE_BLOCK_SIZE : natural range 4 to 2**16 := 64;
-- External Bus Interface --
XBUS_EN : boolean := true;
XBUS_TIMEOUT : natural range 8 to 65536 := 64;
XBUS_REGSTAGE_EN : boolean := false;
XBUS_CACHE_EN : boolean := false;
XBUS_CACHE_NUM_BLOCKS : natural range 1 to 256 := 8;
XBUS_CACHE_BLOCK_SIZE : natural range 1 to 2**16 := 256;
@ -128,6 +131,7 @@ entity neorv32_vivado_ip is
IO_GPTMR_EN : boolean := false;
IO_ONEWIRE_EN : boolean := false;
IO_DMA_EN : boolean := false;
IO_SLINK_EN : boolean := false;
IO_SLINK_RX_FIFO : natural range 1 to 2**15 := 1;
IO_SLINK_TX_FIFO : natural range 1 to 2**15 := 1;
IO_CRC_EN : boolean := false
@ -139,7 +143,7 @@ entity neorv32_vivado_ip is
clk : in std_logic;
resetn : in std_logic; -- low-active
-- ------------------------------------------------------------
-- AXI4-Lite-Compatible Host Interface (always available)
-- AXI4-Lite Host Interface (available if XBUS_EN = true)
-- ------------------------------------------------------------
-- Clock and Reset --
-- m_axi_aclk : in std_logic := '0'; -- just to satisfy Vivado, but not actually used
@ -161,15 +165,15 @@ entity neorv32_vivado_ip is
m_axi_arready : in std_logic := '0';
-- Read Data Channel --
m_axi_rdata : in std_logic_vector(31 downto 0) := x"00000000";
m_axi_rresp : in std_logic_vector(1 downto 0) := "11"; -- error by default
m_axi_rresp : in std_logic_vector(1 downto 0); -- no default here (#1067)
m_axi_rvalid : in std_logic := '0';
m_axi_rready : out std_logic;
-- Write Response Channel --
m_axi_bresp : in std_logic_vector(1 downto 0) := "11"; -- error by default
m_axi_bresp : in std_logic_vector(1 downto 0); -- no default here (#1067)
m_axi_bvalid : in std_logic := '0';
m_axi_bready : out std_logic;
-- ------------------------------------------------------------
-- AXI4-Stream-Compatible Interfaces (available if AXI4_STREAM_EN = true)
-- AXI4-Stream Interfaces (available if IO_SLINK_EN = true)
-- ------------------------------------------------------------
-- Source --
-- s0_axis_aclk : in std_logic := '0'; -- just to satisfy Vivado, but not actually used
@ -256,6 +260,60 @@ architecture neorv32_vivado_ip_rtl of neorv32_vivado_ip is
constant num_xirq_c : natural := cond_sel_natural_f(XIRQ_EN, XIRQ_NUM_CH, 0);
constant num_pwm_c : natural := cond_sel_natural_f(IO_PWM_EN, IO_PWM_NUM_CH, 0);
-- AXI4-Lite bridge --
component xbus2axi4lite_bridge
port (
-- ------------------------------------------------------------
-- Global Control
-- ------------------------------------------------------------
clk : in std_logic;
resetn : in std_logic; -- low-active
-- ------------------------------------------------------------
-- XBUS Device Interface
-- ------------------------------------------------------------
xbus_adr_i : in std_ulogic_vector(31 downto 0); -- address
xbus_dat_i : in std_ulogic_vector(31 downto 0); -- write data
xbus_tag_i : in std_ulogic_vector(2 downto 0); -- access tag
xbus_we_i : in std_ulogic; -- read/write
xbus_sel_i : in std_ulogic_vector(3 downto 0); -- byte enable
xbus_stb_i : in std_ulogic; -- strobe
xbus_cyc_i : in std_ulogic; -- valid cycle
xbus_ack_o : out std_ulogic; -- transfer acknowledge
xbus_err_o : out std_ulogic; -- transfer error
xbus_dat_o : out std_ulogic_vector(31 downto 0); -- read data
-- ------------------------------------------------------------
-- AXI4-Lite Host Interface
-- ------------------------------------------------------------
-- Clock and Reset --
-- m_axi_aclk : in std_logic; -- just to satisfy Vivado, but not actually used
-- m_axi_aresetn : in std_logic; -- just to satisfy Vivado, but not actually used
-- Write Address Channel --
m_axi_awaddr : out std_logic_vector(31 downto 0);
m_axi_awprot : out std_logic_vector(2 downto 0);
m_axi_awvalid : out std_logic;
m_axi_awready : in std_logic;
-- Write Data Channel --
m_axi_wdata : out std_logic_vector(31 downto 0);
m_axi_wstrb : out std_logic_vector(3 downto 0);
m_axi_wvalid : out std_logic;
m_axi_wready : in std_logic;
-- Read Address Channel --
m_axi_araddr : out std_logic_vector(31 downto 0);
m_axi_arprot : out std_logic_vector(2 downto 0);
m_axi_arvalid : out std_logic;
m_axi_arready : in std_logic;
-- Read Data Channel --
m_axi_rdata : in std_logic_vector(31 downto 0);
m_axi_rresp : in std_logic_vector(1 downto 0);
m_axi_rvalid : in std_logic;
m_axi_rready : out std_logic;
-- Write Response Channel --
m_axi_bresp : in std_logic_vector(1 downto 0);
m_axi_bvalid : in std_logic;
m_axi_bready : out std_logic
);
end component;
-- type conversion --
signal jtag_tdo_aux : std_ulogic;
signal s0_axis_tdata_aux : std_ulogic_vector(31 downto 0);
@ -279,21 +337,16 @@ architecture neorv32_vivado_ip_rtl of neorv32_vivado_ip is
signal xirq_i_aux : std_ulogic_vector(31 downto 0);
-- internal wishbone bus --
type wb_bus_t is record
adr : std_ulogic_vector(31 downto 0);
di : std_ulogic_vector(31 downto 0);
do : std_ulogic_vector(31 downto 0);
tag : std_ulogic_vector(2 downto 0);
we : std_ulogic;
sel : std_ulogic_vector(3 downto 0);
cyc : std_ulogic;
ack : std_ulogic;
err : std_ulogic;
end record;
signal wb_core : wb_bus_t;
-- AXI bridge control --
signal axi_radr_received, axi_wadr_received, axi_wdat_received : std_ulogic;
signal xbus_adr : std_ulogic_vector(31 downto 0); -- address
signal xbus_do : std_ulogic_vector(31 downto 0); -- write data
signal xbus_tag : std_ulogic_vector(2 downto 0); -- access tag
signal xbus_we : std_ulogic; -- read/write
signal xbus_sel : std_ulogic_vector(3 downto 0); -- byte enable
signal xbus_stb : std_ulogic; -- strobe
signal xbus_cyc : std_ulogic; -- valid cycle
signal xbus_di : std_ulogic_vector(31 downto 0); -- read data
signal xbus_ack : std_ulogic; -- transfer acknowledge
signal xbus_err : std_ulogic; -- transfer error
begin
@ -301,12 +354,15 @@ begin
-- -------------------------------------------------------------------------------------------
neorv32_top_inst: neorv32_top
generic map (
-- General --
-- Clocking --
CLOCK_FREQUENCY => CLOCK_FREQUENCY,
CLOCK_GATING_EN => false, -- clock gating is not supported here
-- Identification --
HART_ID => std_ulogic_vector(HART_ID),
JEDEC_ID => std_ulogic_vector(JEDEC_ID),
INT_BOOTLOADER_EN => INT_BOOTLOADER_EN,
-- Boot Configuration --
BOOT_MODE_SELECT => BOOT_MODE_SELECT,
BOOT_ADDR_CUSTOM => BOOT_ADDR_CUSTOM,
-- On-Chip Debugger --
OCD_EN => OCD_EN,
OCD_AUTHENTICATION => OCD_AUTHENTICATION,
@ -360,9 +416,9 @@ begin
DCACHE_NUM_BLOCKS => DCACHE_NUM_BLOCKS,
DCACHE_BLOCK_SIZE => DCACHE_BLOCK_SIZE,
-- External bus interface --
XBUS_EN => true,
XBUS_EN => XBUS_EN,
XBUS_TIMEOUT => XBUS_TIMEOUT,
XBUS_REGSTAGE_EN => false,
XBUS_REGSTAGE_EN => XBUS_REGSTAGE_EN,
XBUS_CACHE_EN => XBUS_CACHE_EN,
XBUS_CACHE_NUM_BLOCKS => XBUS_CACHE_NUM_BLOCKS,
XBUS_CACHE_BLOCK_SIZE => XBUS_CACHE_BLOCK_SIZE,
@ -374,6 +430,7 @@ begin
-- External Interrupts Controller --
XIRQ_NUM_CH => num_xirq_c,
-- Processor peripherals --
IO_DISABLE_SYSINFO => false,
IO_GPIO_NUM => num_gpio_c,
IO_MTIME_EN => IO_MTIME_EN,
IO_UART0_EN => IO_UART0_EN,
@ -401,7 +458,7 @@ begin
IO_GPTMR_EN => IO_GPTMR_EN,
IO_ONEWIRE_EN => IO_ONEWIRE_EN,
IO_DMA_EN => IO_DMA_EN,
IO_SLINK_EN => AXI4_STREAM_EN,
IO_SLINK_EN => IO_SLINK_EN,
IO_SLINK_RX_FIFO => IO_SLINK_RX_FIFO,
IO_SLINK_TX_FIFO => IO_SLINK_TX_FIFO,
IO_CRC_EN => IO_CRC_EN
@ -416,16 +473,16 @@ begin
jtag_tdo_o => jtag_tdo_aux,
jtag_tms_i => std_ulogic(jtag_tms_i),
-- External bus interface (available if XBUS_EN = true) --
xbus_adr_o => wb_core.adr,
xbus_dat_o => wb_core.do,
xbus_tag_o => wb_core.tag,
xbus_we_o => wb_core.we,
xbus_sel_o => wb_core.sel,
xbus_stb_o => open,
xbus_cyc_o => wb_core.cyc,
xbus_dat_i => wb_core.di,
xbus_ack_i => wb_core.ack,
xbus_err_i => wb_core.err,
xbus_adr_o => xbus_adr,
xbus_dat_o => xbus_do,
xbus_tag_o => xbus_tag,
xbus_we_o => xbus_we,
xbus_sel_o => xbus_sel,
xbus_stb_o => xbus_stb,
xbus_cyc_o => xbus_cyc,
xbus_dat_i => xbus_di,
xbus_ack_i => xbus_ack,
xbus_err_i => xbus_err,
-- Stream Link Interface (available if IO_SLINK_EN = true) --
slink_rx_dat_i => std_ulogic_vector(s1_axis_tdata),
slink_rx_src_i => std_ulogic_vector(s1_axis_tid),
@ -564,81 +621,56 @@ begin
-- Wishbone-to-AXI4-Lite Bridge -----------------------------------------------------------
-- -------------------------------------------------------------------------------------------
axi_arbiter: process(resetn, clk)
begin
if (resetn = '0') then
axi_radr_received <= '0';
axi_wadr_received <= '0';
axi_wdat_received <= '0';
elsif rising_edge(clk) then
if (wb_core.cyc = '0') then
axi_radr_received <= '0';
axi_wadr_received <= '0';
axi_wdat_received <= '0';
else -- pending access
if (wb_core.we = '0') then -- read
if (m_axi_arready = '1') then -- read address received by interconnect?
axi_radr_received <= '1';
end if;
else -- write
if (m_axi_awready = '1') then -- write address received by interconnect?
axi_wadr_received <= '1';
end if;
if (m_axi_wready = '1') then -- write data received by interconnect?
axi_wdat_received <= '1';
end if;
end if;
end if;
end if;
end process axi_arbiter;
-- read address channel --
m_axi_araddr <= std_logic_vector(wb_core.adr);
m_axi_arprot <= std_logic_vector(wb_core.tag);
m_axi_arvalid <= std_logic(wb_core.cyc and (not wb_core.we) and (not axi_radr_received));
-- read data channel --
m_axi_rready <= std_logic(wb_core.cyc and (not wb_core.we));
wb_core.di <= std_ulogic_vector(m_axi_rdata);
-- write address channel --
m_axi_awaddr <= std_logic_vector(wb_core.adr);
m_axi_awprot <= std_logic_vector(wb_core.tag);
m_axi_awvalid <= std_logic(wb_core.cyc and wb_core.we and (not axi_wadr_received));
-- write data channel --
m_axi_wdata <= std_logic_vector(wb_core.do);
m_axi_wstrb <= std_logic_vector(wb_core.sel);
m_axi_wvalid <= std_logic(wb_core.cyc and wb_core.we and (not axi_wdat_received));
-- write response channel --
m_axi_bready <= std_logic(wb_core.cyc and wb_core.we);
-- read/write response --
axi_response: process(wb_core, m_axi_bvalid, m_axi_bresp, m_axi_rvalid, m_axi_rresp)
begin
wb_core.ack <= '0'; -- default
wb_core.err <= '0'; -- default
if (wb_core.we = '1') then -- write operation
if (m_axi_bvalid = '1') then -- valid write response
if (m_axi_bresp = "00") then -- status check
wb_core.ack <= '1'; -- OK
else
wb_core.err <= '1'; -- ERROR
end if;
end if;
else -- read operation
if (m_axi_rvalid = '1') then -- valid read response
if (m_axi_rresp = "00") then -- status check
wb_core.ack <= '1'; -- OK
else
wb_core.err <= '1'; -- ERROR
end if;
end if;
end if;
end process axi_response;
axi4_bridge:
if XBUS_EN generate
axi4_bridge_inst: xbus2axi4lite_bridge
port map (
-- ------------------------------------------------------------
-- Global Control
-- ------------------------------------------------------------
clk => clk,
resetn => resetn,
-- ------------------------------------------------------------
-- XBUS Device Interface
-- ------------------------------------------------------------
xbus_adr_i => xbus_adr,
xbus_dat_i => xbus_do,
xbus_tag_i => xbus_tag,
xbus_we_i => xbus_we,
xbus_sel_i => xbus_sel,
xbus_stb_i => xbus_stb,
xbus_cyc_i => xbus_cyc,
xbus_ack_o => xbus_ack,
xbus_err_o => xbus_err,
xbus_dat_o => xbus_di,
-- ------------------------------------------------------------
-- AXI4-Lite Host Interface
-- ------------------------------------------------------------
-- Write Address Channel --
m_axi_awaddr => m_axi_awaddr,
m_axi_awprot => m_axi_awprot,
m_axi_awvalid => m_axi_awvalid,
m_axi_awready => m_axi_awready,
-- Write Data Channel --
m_axi_wdata => m_axi_wdata,
m_axi_wstrb => m_axi_wstrb,
m_axi_wvalid => m_axi_wvalid,
m_axi_wready => m_axi_wready,
-- Read Address Channel --
m_axi_araddr => m_axi_araddr,
m_axi_arprot => m_axi_arprot,
m_axi_arvalid => m_axi_arvalid,
m_axi_arready => m_axi_arready,
-- Read Data Channel --
m_axi_rdata => m_axi_rdata,
m_axi_rresp => m_axi_rresp,
m_axi_rvalid => m_axi_rvalid,
m_axi_rready => m_axi_rready,
-- Write Response Channel --
m_axi_bresp => m_axi_bresp,
m_axi_bvalid => m_axi_bvalid,
m_axi_bready => m_axi_bready
);
end generate;
end architecture neorv32_vivado_ip_rtl;

View file

@ -1,5 +1,5 @@
-- ================================================================================ --
-- NEORV32 SoC - XBUS to AHB3-Lite Bridge (non-overlapping single transfers only) --
-- NEORV32 SoC - XBUS to AHB3-Lite Bridge (single non-overlapping transfers only) --
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --

View file

@ -0,0 +1,152 @@
-- ================================================================================ --
-- NEORV32 SoC - XBUS to AXI4-Lite Bridge (non-overlapping single transfers only) --
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
-- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. --
-- Licensed under the BSD-3-Clause license, see LICENSE for details. --
-- SPDX-License-Identifier: BSD-3-Clause --
-- ================================================================================ --
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity xbus2axi4lite_bridge is
port (
-- ------------------------------------------------------------
-- Global Control
-- ------------------------------------------------------------
clk : in std_logic;
resetn : in std_logic; -- low-active
-- ------------------------------------------------------------
-- XBUS Device Interface
-- ------------------------------------------------------------
xbus_adr_i : in std_ulogic_vector(31 downto 0); -- address
xbus_dat_i : in std_ulogic_vector(31 downto 0); -- write data
xbus_tag_i : in std_ulogic_vector(2 downto 0); -- access tag
xbus_we_i : in std_ulogic; -- read/write
xbus_sel_i : in std_ulogic_vector(3 downto 0); -- byte enable
xbus_stb_i : in std_ulogic; -- strobe
xbus_cyc_i : in std_ulogic; -- valid cycle
xbus_ack_o : out std_ulogic; -- transfer acknowledge
xbus_err_o : out std_ulogic; -- transfer error
xbus_dat_o : out std_ulogic_vector(31 downto 0); -- read data
-- ------------------------------------------------------------
-- AXI4-Lite Host Interface
-- ------------------------------------------------------------
-- Clock and Reset --
-- m_axi_aclk : in std_logic; -- just to satisfy Vivado, but not actually used
-- m_axi_aresetn : in std_logic; -- just to satisfy Vivado, but not actually used
-- Write Address Channel --
m_axi_awaddr : out std_logic_vector(31 downto 0);
m_axi_awprot : out std_logic_vector(2 downto 0);
m_axi_awvalid : out std_logic;
m_axi_awready : in std_logic;
-- Write Data Channel --
m_axi_wdata : out std_logic_vector(31 downto 0);
m_axi_wstrb : out std_logic_vector(3 downto 0);
m_axi_wvalid : out std_logic;
m_axi_wready : in std_logic;
-- Read Address Channel --
m_axi_araddr : out std_logic_vector(31 downto 0);
m_axi_arprot : out std_logic_vector(2 downto 0);
m_axi_arvalid : out std_logic;
m_axi_arready : in std_logic;
-- Read Data Channel --
m_axi_rdata : in std_logic_vector(31 downto 0);
m_axi_rresp : in std_logic_vector(1 downto 0);
m_axi_rvalid : in std_logic;
m_axi_rready : out std_logic;
-- Write Response Channel --
m_axi_bresp : in std_logic_vector(1 downto 0);
m_axi_bvalid : in std_logic;
m_axi_bready : out std_logic
);
end entity;
architecture xbus2axi4lite_bridge_rtl of xbus2axi4lite_bridge is
-- AXI bridge control --
signal axi_radr_received, axi_wadr_received, axi_wdat_received : std_ulogic;
begin
-- channel arbiter --
axi_arbiter: process(resetn, clk)
begin
if (resetn = '0') then
axi_radr_received <= '0';
axi_wadr_received <= '0';
axi_wdat_received <= '0';
elsif rising_edge(clk) then
if (xbus_cyc_i = '0') then
axi_radr_received <= '0';
axi_wadr_received <= '0';
axi_wdat_received <= '0';
else -- pending access
if (xbus_we_i = '0') then -- read
if (m_axi_arready = '1') then -- read address received by interconnect?
axi_radr_received <= '1';
end if;
else -- write
if (m_axi_awready = '1') then -- write address received by interconnect?
axi_wadr_received <= '1';
end if;
if (m_axi_wready = '1') then -- write data received by interconnect?
axi_wdat_received <= '1';
end if;
end if;
end if;
end if;
end process axi_arbiter;
-- read address channel --
m_axi_araddr <= std_logic_vector(xbus_adr_i);
m_axi_arprot <= std_logic_vector(xbus_tag_i);
m_axi_arvalid <= std_logic(xbus_cyc_i and (not xbus_we_i) and (not axi_radr_received));
-- read data channel --
m_axi_rready <= std_logic(xbus_cyc_i and (not xbus_we_i));
xbus_dat_o <= std_ulogic_vector(m_axi_rdata);
-- write address channel --
m_axi_awaddr <= std_logic_vector(xbus_adr_i);
m_axi_awprot <= std_logic_vector(xbus_tag_i);
m_axi_awvalid <= std_logic(xbus_cyc_i and xbus_we_i and (not axi_wadr_received));
-- write data channel --
m_axi_wdata <= std_logic_vector(xbus_dat_i);
m_axi_wstrb <= std_logic_vector(xbus_sel_i);
m_axi_wvalid <= std_logic(xbus_cyc_i and xbus_we_i and (not axi_wdat_received));
-- write response channel --
m_axi_bready <= std_logic(xbus_cyc_i and xbus_we_i);
-- read/write response --
axi_response: process(xbus_we_i, m_axi_bvalid, m_axi_bresp, m_axi_rvalid, m_axi_rresp)
begin
xbus_ack_o <= '0'; -- default
xbus_err_o <= '0'; -- default
if (xbus_we_i = '1') then -- write operation
if (m_axi_bvalid = '1') then -- valid write response
if (m_axi_bresp = "00") then -- status check
xbus_ack_o <= '1'; -- OK
else
xbus_err_o <= '1'; -- ERROR
end if;
end if;
else -- read operation
if (m_axi_rvalid = '1') then -- valid read response
if (m_axi_rresp = "00") then -- status check
xbus_ack_o <= '1'; -- OK
else
xbus_err_o <= '1'; -- ERROR
end if;
end if;
end if;
end process axi_response;
end architecture xbus2axi4lite_bridge_rtl;

View file

@ -41,9 +41,10 @@ begin
-- -------------------------------------------------------------------------------------------
neorv32_top_inst: neorv32_top
generic map (
-- General --
-- Clocking --
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
INT_BOOTLOADER_EN => false, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
-- Boot Configuration --
BOOT_MODE_SELECT => 2, -- boot from pre-initialized IMEM
-- RISC-V CPU Extensions --
RISCV_ISA_C => true, -- implement compressed extension?
RISCV_ISA_M => true, -- implement mul/div extension?

View file

@ -44,9 +44,10 @@ begin
-- -------------------------------------------------------------------------------------------
neorv32_top_inst: neorv32_top
generic map (
-- General --
-- Clocking --
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
INT_BOOTLOADER_EN => true, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
-- Boot Configuration --
BOOT_MODE_SELECT => 0, -- boot via internal bootloader
-- RISC-V CPU Extensions --
RISCV_ISA_C => true, -- implement compressed extension?
RISCV_ISA_M => true, -- implement mul/div extension?

View file

@ -49,9 +49,10 @@ begin
-- -------------------------------------------------------------------------------------------
neorv32_top_inst: neorv32_top
generic map (
-- General --
-- Clocking --
CLOCK_FREQUENCY => CLOCK_FREQUENCY, -- clock frequency of clk_i in Hz
INT_BOOTLOADER_EN => true, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
-- Boot Configuration --
BOOT_MODE_SELECT => 0, -- boot via internal bootloader
-- On-Chip Debugger (OCD) --
OCD_EN => true, -- implement on-chip debugger
-- RISC-V CPU Extensions --

View file

@ -1,24 +0,0 @@
## Simulation Sources
### > [`simple`](simple) testbench
"Simple" testbench for the NEORV32 Processor and script for simulation using GHDL.
- [`ghdl.setup.sh`](simple/ghdl.setup.sh)
- [`ghdl.run.sh`](simple/ghdl.run.sh)
- [`ghdl.sh`](simple/ghdl.sh)
- [`neorv32_tb.simple.vhd`](simple/neorv32_tb.simple.vhd)
- [`uart_rx.simple.vhd`](simple/uart_rx.simple.vhd)
### > VUnit testbench (this folder)
VUnit testbench for the NEORV32 Processor.
> [!WARNING]
> This testbench requires VHDL-2008 (or newer) as standard!
- [`run.py`](run.py)
- [`neorv32_tb.vhd`](neorv32_tb.vhd)
- [`uart_rx_pkg.vhd`](uart_rx_pkg.vhd)
- [`uart_rx.vhd`](uart_rx.vhd)

4
sim/simple/ghdl.run.sh → sim/ghdl.run.sh Executable file → Normal file
View file

@ -20,7 +20,7 @@ done
GHDL="${GHDL:-ghdl}"
$GHDL -m --work=neorv32 --workdir=build neorv32_tb_simple
$GHDL -m --work=neorv32 --workdir=build neorv32_tb
if [ -z "$1" ]
then
@ -32,7 +32,7 @@ fi
echo "Using simulation run arguments: $GHDL_RUN_ARGS";
runcmd="$GHDL -r --work=neorv32 --workdir=build neorv32_tb_simple \
runcmd="$GHDL -r --work=neorv32 --workdir=build neorv32_tb \
--max-stack-alloc=0 \
--ieee-asserts=disable \
--assert-level=error $GHDL_RUN_ARGS"

6
sim/simple/ghdl.setup.sh → sim/ghdl.setup.sh Executable file → Normal file
View file

@ -4,7 +4,7 @@ set -e
cd $(dirname "$0")
NEORV32_LOCAL_RTL=${NEORV32_LOCAL_RTL:-../../rtl}
NEORV32_LOCAL_RTL=${NEORV32_LOCAL_RTL:-../rtl}
FILE_LIST=`cat $NEORV32_LOCAL_RTL/file_list_soc.f`
CORE_SRCS="${FILE_LIST//NEORV32_RTL_PATH_PLACEHOLDER/"$NEORV32_LOCAL_RTL"}"
@ -16,5 +16,5 @@ ghdl -i --work=neorv32 --workdir=build \
"$NEORV32_LOCAL_RTL"/processor_templates/*.vhd \
"$NEORV32_LOCAL_RTL"/system_integration/*.vhd \
"$NEORV32_LOCAL_RTL"/test_setups/*.vhd \
neorv32_tb.simple.vhd \
uart_rx.simple.vhd
neorv32_tb.vhd \
uart_rx.vhd

12
sim/ghdl.sh Normal file
View file

@ -0,0 +1,12 @@
#!/usr/bin/env bash
# Abort if any command returns != 0
set -e
cd $(dirname "$0")
# Setup simulation
/bin/bash ghdl.setup.sh
# Run simulation (pass down more than 1 parameter to GHDL)
/bin/bash ghdl.run.sh $@

View file

@ -1,5 +1,5 @@
-- ================================================================================ --
-- NEORV32 - VUnit Processor Testbench --
-- NEORV32 - Default Processor Testbench --
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
@ -8,11 +8,6 @@
-- SPDX-License-Identifier: BSD-3-Clause --
-- ================================================================================ --
library vunit_lib;
context vunit_lib.vunit_context;
context vunit_lib.com_context;
context vunit_lib.vc_context;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
@ -24,33 +19,55 @@ use neorv32.neorv32_application_image.all; -- this file is generated by the imag
use std.textio.all;
library osvvm;
use osvvm.RandomPkg.all;
use work.uart_rx_pkg.all;
entity neorv32_tb is
generic (runner_cfg : string := runner_cfg_default;
ci_mode : boolean := false);
generic (
PERFORMANCE_OPTION : natural := 0 -- Set core options for performance measurements
);
end neorv32_tb;
architecture neorv32_tb_rtl of neorv32_tb is
-- advanced configuration --
constant num_configs_c : natural := 3; -- number of pre-defined configurations
-- helpers --
type bool_t is array (0 to num_configs_c-1) of boolean;
type natural_t is array (0 to num_configs_c-1) of natural;
type performance_options_type_t is record
fast_mul_en_c : bool_t;
fast_shift_en_c : bool_t;
imem_size_c : natural_t;
icache_en_c : bool_t;
icache_block_size_c : natural_t;
dcache_en_c : bool_t;
dcache_block_size_c : natural_t;
end record;
-- User Configuration ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- core performance options --
constant performance_options_c : performance_options_type_t := (
-- default fast core area core
fast_mul_en_c => ( true, true, false), -- Fast multiplication, more area
fast_shift_en_c => ( true, true, false), -- Fast shifting, more area
imem_size_c => ( 32*1024, 128*1024, 128*1024), -- Instruction memory size min. 128kB for performance tests
icache_en_c => ( true, false, false), -- I$ disabled for performance tests
icache_block_size_c => ( 32, 32, 32), -- I$ block size
dcache_en_c => ( true, false, false), -- D$ disabled for performance tests
dcache_block_size_c => ( 32, 32, 32) -- D$ block size
);
-- general --
constant int_imem_c : boolean := false; -- true: use proc-internal IMEM, false: use external simulated IMEM (ext. mem A)
constant int_dmem_c : boolean := false; -- true: use proc-internal DMEM, false: use external simulated DMEM (ext. mem B)
constant imem_size_c : natural := 32*1024; -- size in bytes of processor-internal IMEM / external mem A
constant int_imem_c : boolean := true; -- true: use proc-internal IMEM, false: use external simulated IMEM (ext. mem A)
constant int_dmem_c : boolean := true; -- true: use proc-internal DMEM, false: use external simulated DMEM (ext. mem B)
constant dmem_size_c : natural := 8*1024; -- size in bytes of processor-internal DMEM / external mem B
constant f_clock_c : natural := 100000000; -- main clock in Hz
constant baud0_rate_c : natural := 19200; -- simulation UART0 (primary UART) baud rate
constant baud1_rate_c : natural := 19200; -- simulation UART1 (secondary UART) baud rate
constant icache_en_c : boolean := false; -- implement i-cache
constant icache_block_size_c : natural := 64; -- i-cache block size in bytes
-- simulated external Wishbone memory A (can be used as external IMEM) --
constant ext_mem_a_base_addr_c : std_ulogic_vector(31 downto 0) := x"00000000"; -- wishbone memory base address (external IMEM base)
constant ext_mem_a_size_c : natural := imem_size_c; -- wishbone memory size in bytes
constant ext_mem_a_size_c : natural := performance_options_c.imem_size_c(PERFORMANCE_OPTION); -- wishbone memory size in bytes
constant ext_mem_a_latency_c : natural := 8; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay
-- simulated external Wishbone memory B (can be used as external DMEM) --
constant ext_mem_b_base_addr_c : std_ulogic_vector(31 downto 0) := x"80000000"; -- wishbone memory base address (external DMEM base)
@ -58,7 +75,7 @@ architecture neorv32_tb_rtl of neorv32_tb is
constant ext_mem_b_latency_c : natural := 8; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay
-- simulated external Wishbone memory C (can be used to simulate external IO access) --
constant ext_mem_c_base_addr_c : std_ulogic_vector(31 downto 0) := x"F0000000"; -- wishbone memory base address (default begin of EXTERNAL IO area)
constant ext_mem_c_size_c : natural := icache_block_size_c/2; -- wishbone memory size in bytes, should be smaller than an iCACHE block
constant ext_mem_c_size_c : natural := performance_options_c.icache_block_size_c(PERFORMANCE_OPTION)/2; -- wishbone memory size in bytes, should be smaller than an iCACHE block
constant ext_mem_c_latency_c : natural := 128; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay
-- simulation interrupt trigger --
constant irq_trigger_base_addr_c : std_ulogic_vector(31 downto 0) := x"FF000000";
@ -72,6 +89,9 @@ architecture neorv32_tb_rtl of neorv32_tb is
-- generators --
signal clk_gen, rst_gen : std_ulogic := '0';
-- text.io --
file file_uart0_tx_out : text open write_mode is "neorv32.testbench_uart0.out";
-- uart --
signal uart0_txd, uart1_txd : std_ulogic;
signal uart0_cts, uart1_cts : std_ulogic;
@ -131,55 +151,7 @@ architecture neorv32_tb_rtl of neorv32_tb is
end record;
signal ext_mem_a, ext_mem_b, ext_mem_c : ext_mem_t;
constant uart0_rx_logger : logger_t := get_logger("UART0.RX");
constant uart1_rx_logger : logger_t := get_logger("UART1.RX");
constant uart0_rx_handle : uart_rx_t := new_uart_rx(uart0_baud_val_c, uart0_rx_logger);
constant uart1_rx_handle : uart_rx_t := new_uart_rx(uart1_baud_val_c, uart1_rx_logger);
begin
test_runner : process
variable msg : msg_t;
variable rnd : RandomPType;
begin
test_runner_setup(runner, runner_cfg);
rnd.InitSeed(test_runner'path_name);
-- Show passing checks for UART0 on the display (stdout)
show(uart0_rx_logger, display_handler, pass);
show(uart1_rx_logger, display_handler, pass);
if ci_mode then
check_uart(net, uart0_rx_handle, nul & nul);
else
check_uart(net, uart0_rx_handle, "Blinking LED demo program" & cr & lf);
end if;
if ci_mode then
-- No need to send the full expectation in one big chunk
check_uart(net, uart1_rx_handle, nul & nul);
check_uart(net, uart1_rx_handle, "0/56" & cr & lf);
end if;
-- Wait until all expected data has been received
--
-- wait_until_idle can take the VC actor as argument but
-- the more abstract view is that wait_until_idle is part
-- of the sync VCI and to use it a VC must be cast
-- to a sync VC
wait_until_idle(net, as_sync(uart0_rx_handle));
wait_until_idle(net, as_sync(uart1_rx_handle));
-- Wait a bit more if some extra unexpected data is produced. If so,
-- uart_rx will fail
wait for (20 * (1e9 / baud0_rate_c)) * ns;
test_runner_cleanup(runner);
end process;
-- In case we get stuck waiting there is a watchdog timeout to terminate and fail the
-- testbench
test_runner_watchdog(runner, 50 ms);
-- Clock/Reset Generator ------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
@ -191,189 +163,196 @@ begin
-- -------------------------------------------------------------------------------------------
neorv32_top_inst: neorv32_top
generic map (
-- General --
CLOCK_FREQUENCY => f_clock_c, -- clock frequency of clk_i in Hz
CLOCK_GATING_EN => true, -- enable clock gating when in sleep mode
HART_ID => x"00000000", -- hardware thread ID
JEDEC_ID => "00000000000", -- vendor's JEDEC ID
INT_BOOTLOADER_EN => false, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
-- Clocking --
CLOCK_FREQUENCY => f_clock_c,
CLOCK_GATING_EN => true,
-- Identification --
HART_ID => x"00000000",
JEDEC_ID => "00000000000",
-- Boot Configuration --
BOOT_MODE_SELECT => 2, -- boot from pre-initialized internal IMEM
BOOT_ADDR_CUSTOM => x"00000000",
-- On-Chip Debugger (OCD) --
OCD_EN => true, -- implement on-chip debugger
OCD_AUTHENTICATION => true, -- implement on-chip debugger authentication
OCD_EN => true,
OCD_AUTHENTICATION => true,
-- RISC-V CPU Extensions --
RISCV_ISA_C => true, -- implement compressed extension?
RISCV_ISA_E => false, -- implement embedded RF extension?
RISCV_ISA_M => true, -- implement mul/div extension?
RISCV_ISA_U => true, -- implement user mode extension?
RISCV_ISA_Zalrsc => true, -- implement atomic reservation-set extension
RISCV_ISA_Zba => true, -- implement shifted-add bit-manipulation extension
RISCV_ISA_Zbb => true, -- implement basic bit-manipulation extension
RISCV_ISA_Zbkb => true, -- implement bit-manipulation instructions for cryptography
RISCV_ISA_Zbkc => true, -- implement carry-less multiplication instructions?
RISCV_ISA_Zbkx => true, -- implement cryptography crossbar permutation extension?
RISCV_ISA_Zbs => true, -- implement single-bit bit-manipulation extension
RISCV_ISA_Zfinx => true, -- implement 32-bit floating-point extension (using INT reg!)
RISCV_ISA_Zicntr => true, -- implement base counters?
RISCV_ISA_Zicond => true, -- implement integer conditional operations?
RISCV_ISA_Zihpm => true, -- implement hardware performance monitors?
RISCV_ISA_Zknd => true, -- implement cryptography NIST AES decryption extension?
RISCV_ISA_Zkne => true, -- implement cryptography NIST AES encryption extension?
RISCV_ISA_Zknh => true, -- implement cryptography NIST hash extension?
RISCV_ISA_Zksed => true, -- implement ShangMi block cypher extension?
RISCV_ISA_Zksh => true, -- implement ShangMi hash extension?
RISCV_ISA_Zmmul => false, -- implement multiply-only M sub-extension?
RISCV_ISA_Zxcfu => true, -- implement custom (instr.) functions unit?
RISCV_ISA_C => false,
RISCV_ISA_E => false,
RISCV_ISA_M => true,
RISCV_ISA_U => true,
RISCV_ISA_Zalrsc => true,
RISCV_ISA_Zba => true,
RISCV_ISA_Zbb => true,
RISCV_ISA_Zbkb => true,
RISCV_ISA_Zbkc => true,
RISCV_ISA_Zbkx => true,
RISCV_ISA_Zbs => true,
RISCV_ISA_Zfinx => true,
RISCV_ISA_Zicntr => true,
RISCV_ISA_Zicond => true,
RISCV_ISA_Zihpm => true,
RISCV_ISA_Zknd => true,
RISCV_ISA_Zkne => true,
RISCV_ISA_Zknh => true,
RISCV_ISA_Zksed => true,
RISCV_ISA_Zksh => true,
RISCV_ISA_Zmmul => false,
RISCV_ISA_Zxcfu => true,
-- Extension Options --
FAST_MUL_EN => false, -- use DSPs for M extension's multiplier
FAST_SHIFT_EN => false, -- use barrel shifter for shift operations
REGFILE_HW_RST => true, -- full hardware reset
FAST_MUL_EN => performance_options_c.fast_mul_en_c(PERFORMANCE_OPTION),
FAST_SHIFT_EN => performance_options_c.fast_shift_en_c(PERFORMANCE_OPTION),
REGFILE_HW_RST => false,
-- Physical Memory Protection (PMP) --
PMP_NUM_REGIONS => 5, -- number of regions (0..16)
PMP_MIN_GRANULARITY => 4, -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes
PMP_TOR_MODE_EN => true, -- implement TOR mode
PMP_NAP_MODE_EN => true, -- implement NAPOT/NA4 mode
PMP_NUM_REGIONS => 5,
PMP_MIN_GRANULARITY => 4,
PMP_TOR_MODE_EN => true,
PMP_NAP_MODE_EN => true,
-- Hardware Performance Monitors (HPM) --
HPM_NUM_CNTS => 12, -- number of implemented HPM counters (0..29)
HPM_CNT_WIDTH => 40, -- total size of HPM counters (0..64)
HPM_NUM_CNTS => 12,
HPM_CNT_WIDTH => 40,
-- Internal Instruction memory --
MEM_INT_IMEM_EN => int_imem_c , -- implement processor-internal instruction memory
MEM_INT_IMEM_SIZE => imem_size_c, -- size of processor-internal instruction memory in bytes
MEM_INT_IMEM_EN => int_imem_c ,
MEM_INT_IMEM_SIZE => performance_options_c.imem_size_c(PERFORMANCE_OPTION),
-- Internal Data memory --
MEM_INT_DMEM_EN => int_dmem_c, -- implement processor-internal data memory
MEM_INT_DMEM_SIZE => dmem_size_c, -- size of processor-internal data memory in bytes
MEM_INT_DMEM_EN => int_dmem_c,
MEM_INT_DMEM_SIZE => dmem_size_c,
-- Internal Cache memory --
ICACHE_EN => false, -- implement instruction cache
ICACHE_EN => performance_options_c.icache_en_c(PERFORMANCE_OPTION),
ICACHE_NUM_BLOCKS => 64,
ICACHE_BLOCK_SIZE => performance_options_c.icache_block_size_c(PERFORMANCE_OPTION),
-- Internal Data Cache (dCACHE) --
DCACHE_EN => false, -- implement data cache
DCACHE_EN => performance_options_c.dcache_en_c(PERFORMANCE_OPTION),
DCACHE_NUM_BLOCKS => 32,
DCACHE_BLOCK_SIZE => performance_options_c.dcache_block_size_c(PERFORMANCE_OPTION),
-- External bus interface --
XBUS_EN => true, -- implement external memory bus interface?
XBUS_TIMEOUT => 256, -- cycles after a pending bus access auto-terminates (0 = disabled)
XBUS_REGSTAGE_EN => false, -- add register stage
XBUS_CACHE_EN => true, -- enable external bus cache (x-cache)
XBUS_CACHE_NUM_BLOCKS => 64, -- x-cache: number of blocks (min 1), has to be a power of 2
XBUS_CACHE_BLOCK_SIZE => 32, -- x-cache: block size in bytes (min 4), has to be a power of 2
XBUS_EN => true,
XBUS_TIMEOUT => 256,
XBUS_REGSTAGE_EN => true,
XBUS_CACHE_EN => true,
XBUS_CACHE_NUM_BLOCKS => 4,
XBUS_CACHE_BLOCK_SIZE => 32,
-- Execute in-place module (XIP) --
XIP_EN => true, -- implement execute in place module (XIP)?
XIP_CACHE_EN => true, -- implement XIP cache?
XIP_CACHE_NUM_BLOCKS => 4, -- number of blocks (min 1), has to be a power of 2
XIP_CACHE_BLOCK_SIZE => 256, -- block size in bytes (min 4), has to be a power of 2
XIP_EN => true,
XIP_CACHE_EN => true,
XIP_CACHE_NUM_BLOCKS => 4,
XIP_CACHE_BLOCK_SIZE => 256,
-- External Interrupts Controller (XIRQ) --
XIRQ_NUM_CH => 32, -- number of external IRQ channels (0..32)
XIRQ_NUM_CH => 32,
-- Processor peripherals --
IO_GPIO_NUM => 64, -- number of GPIO input/output pairs (0..64)
IO_MTIME_EN => true, -- implement machine system timer (MTIME)?
IO_UART0_EN => true, -- implement primary universal asynchronous receiver/transmitter (UART0)?
IO_UART0_RX_FIFO => 32, -- RX fifo depth, has to be a power of two, min 1
IO_UART0_TX_FIFO => 32, -- TX fifo depth, has to be a power of two, min 1
IO_UART1_EN => true, -- implement secondary universal asynchronous receiver/transmitter (UART1)?
IO_UART1_RX_FIFO => 1, -- RX fifo depth, has to be a power of two, min 1
IO_UART1_TX_FIFO => 1, -- TX fifo depth, has to be a power of two, min 1
IO_SPI_EN => true, -- implement serial peripheral interface (SPI)?
IO_SPI_FIFO => 4, -- SPI RTX fifo depth, has to be zero or a power of two
IO_SDI_EN => true, -- implement serial data interface (SDI)?
IO_SDI_FIFO => 4, -- SDI RTX fifo depth, has to be zero or a power of two
IO_TWI_EN => true, -- implement two-wire interface (TWI)?
IO_TWI_FIFO => 4, -- RTX fifo depth, has to be zero or a power of two, min 1
IO_PWM_NUM_CH => 8, -- number of PWM channels to implement (0..16)
IO_WDT_EN => true, -- implement watch dog timer (WDT)?
IO_TRNG_EN => true, -- implement true random number generator (TRNG)?
IO_TRNG_FIFO => 4, -- TRNG fifo depth, has to be a power of two, min 1
IO_CFS_EN => true, -- implement custom functions subsystem (CFS)?
IO_CFS_CONFIG => (others => '0'), -- custom CFS configuration generic
IO_CFS_IN_SIZE => 32, -- size of CFS input conduit in bits
IO_CFS_OUT_SIZE => 32, -- size of CFS output conduit in bits
IO_NEOLED_EN => true, -- implement NeoPixel-compatible smart LED interface (NEOLED)?
IO_NEOLED_TX_FIFO => 8, -- NEOLED TX FIFO depth, 1..32k, has to be a power of two
IO_GPTMR_EN => true, -- implement general purpose timer (GPTMR)?
IO_ONEWIRE_EN => true, -- implement 1-wire interface (ONEWIRE)?
IO_DMA_EN => true, -- implement direct memory access controller (DMA)?
IO_SLINK_EN => true, -- implement stream link interface (SLINK)?
IO_SLINK_RX_FIFO => 4, -- RX fifo depth, has to be a power of two, min 1
IO_SLINK_TX_FIFO => 4, -- TX fifo depth, has to be a power of two, min 1
IO_CRC_EN => true -- implement cyclic redundancy check unit (CRC)?
IO_GPIO_NUM => 64,
IO_MTIME_EN => true,
IO_UART0_EN => true,
IO_UART0_RX_FIFO => 32,
IO_UART0_TX_FIFO => 32,
IO_UART1_EN => true,
IO_UART1_RX_FIFO => 1,
IO_UART1_TX_FIFO => 1,
IO_SPI_EN => true,
IO_SPI_FIFO => 4,
IO_SDI_EN => true,
IO_SDI_FIFO => 4,
IO_TWI_EN => true,
IO_TWI_FIFO => 4,
IO_PWM_NUM_CH => 8,
IO_WDT_EN => true,
IO_TRNG_EN => true,
IO_TRNG_FIFO => 4,
IO_CFS_EN => true,
IO_CFS_CONFIG => (others => '0'),
IO_CFS_IN_SIZE => 32,
IO_CFS_OUT_SIZE => 32,
IO_NEOLED_EN => true,
IO_NEOLED_TX_FIFO => 8,
IO_GPTMR_EN => true,
IO_ONEWIRE_EN => true,
IO_DMA_EN => true,
IO_SLINK_EN => true,
IO_SLINK_RX_FIFO => 4,
IO_SLINK_TX_FIFO => 4,
IO_CRC_EN => true
)
port map (
-- Global control --
clk_i => clk_gen, -- global clock, rising edge
rstn_i => rst_gen, -- global reset, low-active, async
clk_i => clk_gen,
rstn_i => rst_gen,
-- JTAG on-chip debugger interface (available if OCD_EN = true) --
jtag_tck_i => '0', -- serial clock
jtag_tdi_i => '0', -- serial data input
jtag_tdo_o => open, -- serial data output
jtag_tms_i => '0', -- mode select
jtag_tck_i => '0',
jtag_tdi_i => '0',
jtag_tdo_o => open,
jtag_tms_i => '0',
-- External bus interface (available if XBUS_EN = true) --
xbus_adr_o => wb_cpu.addr, -- address
xbus_dat_o => wb_cpu.wdata, -- write data
xbus_tag_o => wb_cpu.tag, -- access tag
xbus_we_o => wb_cpu.we, -- read/write
xbus_sel_o => wb_cpu.sel, -- byte enable
xbus_stb_o => wb_cpu.stb, -- strobe
xbus_cyc_o => wb_cpu.cyc, -- valid cycle
xbus_dat_i => wb_cpu.rdata, -- read data
xbus_ack_i => wb_cpu.ack, -- transfer acknowledge
xbus_err_i => wb_cpu.err, -- transfer error
xbus_adr_o => wb_cpu.addr,
xbus_dat_o => wb_cpu.wdata,
xbus_tag_o => wb_cpu.tag,
xbus_we_o => wb_cpu.we,
xbus_sel_o => wb_cpu.sel,
xbus_stb_o => wb_cpu.stb,
xbus_cyc_o => wb_cpu.cyc,
xbus_dat_i => wb_cpu.rdata,
xbus_ack_i => wb_cpu.ack,
xbus_err_i => wb_cpu.err,
-- Stream Link Interface (available if IO_SLINK_EN = true) --
slink_rx_dat_i => slink_dat, -- RX input data
slink_rx_src_i => slink_id, -- RX source routing information
slink_rx_val_i => slink_val, -- RX valid input
slink_rx_lst_i => slink_lst, -- RX last element of stream
slink_rx_rdy_o => slink_rdy, -- RX ready to receive
slink_tx_dat_o => slink_dat, -- TX output data
slink_tx_dst_o => slink_id, -- TX destination routing information
slink_tx_val_o => slink_val, -- TX valid output
slink_tx_lst_o => slink_lst, -- TX last element of stream
slink_tx_rdy_i => slink_rdy, -- TX ready to send
slink_rx_dat_i => slink_dat,
slink_rx_src_i => slink_id,
slink_rx_val_i => slink_val,
slink_rx_lst_i => slink_lst,
slink_rx_rdy_o => slink_rdy,
slink_tx_dat_o => slink_dat,
slink_tx_dst_o => slink_id,
slink_tx_val_o => slink_val,
slink_tx_lst_o => slink_lst,
slink_tx_rdy_i => slink_rdy,
-- XIP (execute in place via SPI) signals (available if XIP_EN = true) --
xip_csn_o => open, -- chip-select, low-active
xip_clk_o => open, -- serial clock
xip_dat_i => '1', -- device data input
xip_dat_o => open, -- controller data output
-- GPIO (available if IO_GPIO_NUM > 0) --
gpio_o => gpio, -- parallel output
gpio_i => gpio, -- parallel input
xip_csn_o => open,
xip_clk_o => open,
xip_dat_i => '0',
xip_dat_o => open,
-- GPIO (available if IO_GPIO_NUM > true) --
gpio_o => gpio,
gpio_i => gpio,
-- primary UART0 (available if IO_UART0_EN = true) --
uart0_txd_o => uart0_txd, -- UART0 send data
uart0_rxd_i => uart0_txd, -- UART0 receive data
uart0_rts_o => uart1_cts, -- HW flow control: UART0.RX ready to receive ("RTR"), low-active, optional
uart0_cts_i => uart0_cts, -- HW flow control: UART0.TX allowed to transmit, low-active, optional
uart0_txd_o => uart0_txd,
uart0_rxd_i => uart0_txd,
uart0_rts_o => uart1_cts,
uart0_cts_i => uart0_cts,
-- secondary UART1 (available if IO_UART1_EN = true) --
uart1_txd_o => uart1_txd, -- UART1 send data
uart1_rxd_i => uart1_txd, -- UART1 receive data
uart1_rts_o => uart0_cts, -- HW flow control: UART0.RX ready to receive ("RTR"), low-active, optional
uart1_cts_i => uart1_cts, -- HW flow control: UART0.TX allowed to transmit, low-active, optional
uart1_txd_o => uart1_txd,
uart1_rxd_i => uart1_txd,
uart1_rts_o => uart0_cts,
uart1_cts_i => uart1_cts,
-- SPI (available if IO_SPI_EN = true) --
spi_clk_o => spi_clk, -- SPI serial clock
spi_dat_o => spi_do, -- controller data out, peripheral data in
spi_dat_i => spi_di, -- controller data in, peripheral data out
spi_csn_o => spi_csn, -- SPI CS
spi_clk_o => spi_clk,
spi_dat_o => spi_do,
spi_dat_i => spi_di,
spi_csn_o => spi_csn,
-- SDI (available if IO_SDI_EN = true) --
sdi_clk_i => sdi_clk, -- SDI serial clock
sdi_dat_o => sdi_do, -- controller data out, peripheral data in
sdi_dat_i => sdi_di, -- controller data in, peripheral data out
sdi_csn_i => sdi_csn, -- chip-select
sdi_clk_i => sdi_clk,
sdi_dat_o => sdi_do,
sdi_dat_i => sdi_di,
sdi_csn_i => sdi_csn,
-- TWI (available if IO_TWI_EN = true) --
twi_sda_i => twi_sda_i, -- serial data line sense input
twi_sda_o => twi_sda_o, -- serial data line output (pull low only)
twi_scl_i => twi_scl_i, -- serial clock line sense input
twi_scl_o => twi_scl_o, -- serial clock line output (pull low only)
twi_sda_i => twi_sda_i,
twi_sda_o => twi_sda_o,
twi_scl_i => twi_scl_i,
twi_scl_o => twi_scl_o,
-- 1-Wire Interface (available if IO_ONEWIRE_EN = true) --
onewire_i => onewire_i, -- 1-wire bus sense input
onewire_o => onewire_o, -- 1-wire bus output (pull low only)
onewire_i => onewire_i,
onewire_o => onewire_o,
-- PWM (available if IO_PWM_NUM_CH > 0) --
pwm_o => open, -- pwm channels
pwm_o => open,
-- Custom Functions Subsystem IO --
cfs_in_i => (others => '0'), -- custom CFS inputs
cfs_out_o => open, -- custom CFS outputs
cfs_in_i => (others => '0'),
cfs_out_o => open,
-- NeoPixel-compatible smart LED interface (available if IO_NEOLED_EN = true) --
neoled_o => open, -- async serial data line
neoled_o => open,
-- Machine timer system time (available if IO_MTIME_EN = true) --
mtime_time_o => open,
-- External platform interrupts (available if XIRQ_NUM_CH > 0) --
xirq_i => gpio(31 downto 0), -- IRQ channels
xirq_i => gpio(31 downto 0),
-- CPU Interrupts --
mtime_irq_i => '0', -- machine software interrupt, available if IO_MTIME_EN = false
msw_irq_i => msi_ring, -- machine software interrupt
mext_irq_i => mei_ring -- machine external interrupt
mtime_irq_i => '0',
msw_irq_i => msi_ring,
mext_irq_i => mei_ring
);
-- TWI tri-state driver --
@ -399,17 +378,28 @@ begin
sdi_di <= spi_do after 40 ns;
spi_di <= sdi_do when (spi_csn(7) = '0') else spi_do after 40 ns;
-- UART Simulation Receiver ---------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
uart0_checker: entity work.uart_rx
generic map (uart0_rx_handle)
port map (
clk => clk_gen,
uart_txd => uart0_txd);
generic map (
name => "uart0",
uart_baud_val_c => uart0_baud_val_c
)
port map (
clk => clk_gen,
uart_txd => uart0_txd
);
uart1_checker: entity work.uart_rx
generic map (uart1_rx_handle)
port map (
clk => clk_gen,
uart_txd => uart1_txd);
generic map (
name => "uart1",
uart_baud_val_c => uart1_baud_val_c
)
port map (
clk => clk_gen,
uart_txd => uart1_txd
);
-- Wishbone Fabric ------------------------------------------------------------------------

View file

@ -1,56 +0,0 @@
#!/usr/bin/env python3
import json
from pathlib import Path
from vunit import VUnit, VUnitCLI
cli = VUnitCLI()
cli.parser.add_argument(
"--ci-mode",
action="store_true",
default=False,
help="Enable special settings used by the CI",
)
args = cli.parse_args()
PRJ = VUnit.from_args(args=args)
PRJ.add_vhdl_builtins()
PRJ.add_com()
PRJ.add_verification_components()
PRJ.add_osvvm()
ROOT = Path(__file__).parent
NEORV32 = PRJ.add_library("neorv32")
NEORV32.add_source_files([
ROOT / "*.vhd",
ROOT / ".." / "rtl" / "**" / "*.vhd",
])
NEORV32.test_bench("neorv32_tb").set_generic("ci_mode", args.ci_mode)
PRJ.set_sim_option("disable_ieee_warnings", True)
PRJ.set_sim_option("ghdl.sim_flags", ["--max-stack-alloc=256"])
def _gen_vhdl_ls(vu):
"""
Generate the vhdl_ls.toml file required by VHDL-LS language server.
"""
# Repo root
parent = Path(__file__).parent.parent
proj = vu._project
libs = proj.get_libraries()
with open(parent / 'vhdl_ls.toml', "w") as f:
for lib in libs:
f.write(f"[libraries.{lib.name}]\n")
files = [str(file).replace('\\', '/') for file in lib._source_files
# Conflicts with *.default.vhd
if not any(exclude in file for exclude in ('neorv32_imem.simple.vhd', 'neorv32_imem.legacy.vhd', 'neorv32_dmem.legacy.vhd'))
]
f.write(f"files = {json.dumps(files, indent=4)}\n")
_gen_vhdl_ls(PRJ)
PRJ.main()

View file

@ -1,10 +0,0 @@
#!/usr/bin/env bash
# Abort if any command returns != 0
set -e
cd $(dirname "$0")
./ghdl.setup.sh
# We want to be able to pass down more than 1 parameter to GHDL
./ghdl.run.sh $@

View file

@ -1,605 +0,0 @@
-- ================================================================================ --
-- NEORV32 - Default Processor Testbench --
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
-- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. --
-- Licensed under the BSD-3-Clause license, see LICENSE for details. --
-- SPDX-License-Identifier: BSD-3-Clause --
-- ================================================================================ --
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
library neorv32;
use neorv32.neorv32_package.all;
use neorv32.neorv32_application_image.all; -- this file is generated by the image generator
use std.textio.all;
entity neorv32_tb_simple is
generic (
PERFORMANCE_OPTION : natural := 0 -- Set core options for performance measurements
);
end neorv32_tb_simple;
architecture neorv32_tb_simple_rtl of neorv32_tb_simple is
-- advanced configuration --
constant num_configs_c : natural := 3; -- number of pre-defined configurations
-- helpers --
type bool_t is array (0 to num_configs_c-1) of boolean;
type natural_t is array (0 to num_configs_c-1) of natural;
type performance_options_type_t is record
fast_mul_en_c : bool_t;
fast_shift_en_c : bool_t;
imem_size_c : natural_t;
icache_en_c : bool_t;
icache_block_size_c : natural_t;
dcache_en_c : bool_t;
dcache_block_size_c : natural_t;
end record;
-- User Configuration ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- core performance options --
constant performance_options_c : performance_options_type_t := (
-- default fast core area core
fast_mul_en_c => ( true, true, false), -- Fast multiplication, more area
fast_shift_en_c => ( true, true, false), -- Fast shifting, more area
imem_size_c => ( 32*1024, 128*1024, 128*1024), -- Instruction memory size min. 128kB for performance tests
icache_en_c => ( true, false, false), -- I$ disabled for performance tests
icache_block_size_c => ( 32, 32, 32), -- I$ block size
dcache_en_c => ( true, false, false), -- D$ disabled for performance tests
dcache_block_size_c => ( 32, 32, 32) -- D$ block size
);
-- general --
constant int_imem_c : boolean := true; -- true: use proc-internal IMEM, false: use external simulated IMEM (ext. mem A)
constant int_dmem_c : boolean := true; -- true: use proc-internal DMEM, false: use external simulated DMEM (ext. mem B)
constant dmem_size_c : natural := 8*1024; -- size in bytes of processor-internal DMEM / external mem B
constant f_clock_c : natural := 100000000; -- main clock in Hz
constant baud0_rate_c : natural := 19200; -- simulation UART0 (primary UART) baud rate
constant baud1_rate_c : natural := 19200; -- simulation UART1 (secondary UART) baud rate
-- simulated external Wishbone memory A (can be used as external IMEM) --
constant ext_mem_a_base_addr_c : std_ulogic_vector(31 downto 0) := x"00000000"; -- wishbone memory base address (external IMEM base)
constant ext_mem_a_size_c : natural := performance_options_c.imem_size_c(PERFORMANCE_OPTION); -- wishbone memory size in bytes
constant ext_mem_a_latency_c : natural := 8; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay
-- simulated external Wishbone memory B (can be used as external DMEM) --
constant ext_mem_b_base_addr_c : std_ulogic_vector(31 downto 0) := x"80000000"; -- wishbone memory base address (external DMEM base)
constant ext_mem_b_size_c : natural := dmem_size_c; -- wishbone memory size in bytes
constant ext_mem_b_latency_c : natural := 8; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay
-- simulated external Wishbone memory C (can be used to simulate external IO access) --
constant ext_mem_c_base_addr_c : std_ulogic_vector(31 downto 0) := x"F0000000"; -- wishbone memory base address (default begin of EXTERNAL IO area)
constant ext_mem_c_size_c : natural := performance_options_c.icache_block_size_c(PERFORMANCE_OPTION)/2; -- wishbone memory size in bytes, should be smaller than an iCACHE block
constant ext_mem_c_latency_c : natural := 128; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay
-- simulation interrupt trigger --
constant irq_trigger_base_addr_c : std_ulogic_vector(31 downto 0) := x"FF000000";
-- -------------------------------------------------------------------------------------------
-- internals - hands off! --
constant uart0_baud_val_c : real := real(f_clock_c) / real(baud0_rate_c);
constant uart1_baud_val_c : real := real(f_clock_c) / real(baud1_rate_c);
constant t_clock_c : time := (1 sec) / f_clock_c;
-- generators --
signal clk_gen, rst_gen : std_ulogic := '0';
-- text.io --
file file_uart0_tx_out : text open write_mode is "neorv32.testbench_uart0.out";
-- uart --
signal uart0_txd, uart1_txd : std_ulogic;
signal uart0_cts, uart1_cts : std_ulogic;
-- gpio --
signal gpio : std_ulogic_vector(63 downto 0);
-- twi --
signal twi_scl, twi_sda : std_logic;
signal twi_scl_i, twi_scl_o, twi_sda_i, twi_sda_o : std_ulogic;
-- 1-wire --
signal onewire : std_logic;
signal onewire_i, onewire_o : std_ulogic;
-- spi & sdi --
signal spi_csn: std_ulogic_vector(7 downto 0);
signal spi_di, spi_do, spi_clk : std_ulogic;
signal sdi_di, sdi_do, sdi_clk, sdi_csn : std_ulogic;
-- irq --
signal msi_ring, mei_ring : std_ulogic;
-- SLINK echo --
signal slink_dat : std_ulogic_vector(31 downto 0);
signal slink_val : std_ulogic;
signal slink_lst : std_ulogic;
signal slink_rdy : std_ulogic;
signal slink_id : std_ulogic_vector(3 downto 0);
-- Wishbone bus --
type wishbone_t is record
addr : std_ulogic_vector(31 downto 0); -- address
wdata : std_ulogic_vector(31 downto 0); -- master write data
rdata : std_ulogic_vector(31 downto 0); -- master read data
tag : std_ulogic_vector(2 downto 0); -- access tag
we : std_ulogic; -- write enable
sel : std_ulogic_vector(3 downto 0); -- byte enable
stb : std_ulogic; -- strobe
cyc : std_ulogic; -- valid cycle
ack : std_ulogic; -- transfer acknowledge
err : std_ulogic; -- transfer error
end record;
signal wb_cpu, wb_mem_a, wb_mem_b, wb_mem_c, wb_irq : wishbone_t;
-- Wishbone access latency type --
type ext_mem_read_latency_t is array (0 to 255) of std_ulogic_vector(31 downto 0);
-- simulated external memory c (IO) --
signal ext_ram_c : mem32_t(0 to ext_mem_c_size_c/4-1); -- uninitialized, used to simulate external IO
-- simulated external memory bus feedback type --
type ext_mem_t is record
rdata : ext_mem_read_latency_t;
acc_en : std_ulogic;
ack : std_ulogic_vector(255 downto 0);
end record;
signal ext_mem_a, ext_mem_b, ext_mem_c : ext_mem_t;
begin
-- Clock/Reset Generator ------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
clk_gen <= not clk_gen after (t_clock_c/2);
rst_gen <= '0', '1' after 60*(t_clock_c/2);
-- The Core of the Problem ----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
neorv32_top_inst: neorv32_top
generic map (
-- General --
CLOCK_FREQUENCY => f_clock_c, -- clock frequency of clk_i in Hz
CLOCK_GATING_EN => true, -- enable clock gating when in sleep mode
HART_ID => x"00000000", -- hardware thread ID
JEDEC_ID => "00000000000", -- vendor's JEDEC ID
INT_BOOTLOADER_EN => false, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM
-- On-Chip Debugger (OCD) --
OCD_EN => true, -- implement on-chip debugger
OCD_AUTHENTICATION => true, -- implement on-chip debugger authentication
-- RISC-V CPU Extensions --
RISCV_ISA_C => false, -- implement compressed extension?
RISCV_ISA_E => false, -- implement embedded RF extension?
RISCV_ISA_M => true, -- implement mul/div extension?
RISCV_ISA_U => true, -- implement user mode extension?
RISCV_ISA_Zalrsc => true, -- implement atomic reservation-set extension
RISCV_ISA_Zba => true, -- implement shifted-add bit-manipulation extension
RISCV_ISA_Zbb => true, -- implement basic bit-manipulation extension
RISCV_ISA_Zbkb => true, -- implement bit-manipulation instructions for cryptography
RISCV_ISA_Zbkc => true, -- implement carry-less multiplication instructions?
RISCV_ISA_Zbkx => true, -- implement cryptography crossbar permutation extension?
RISCV_ISA_Zbs => true, -- implement single-bit bit-manipulation extension
RISCV_ISA_Zfinx => true, -- implement 32-bit floating-point extension (using INT reg!)
RISCV_ISA_Zicntr => true, -- implement base counters?
RISCV_ISA_Zicond => true, -- implement integer conditional operations?
RISCV_ISA_Zihpm => true, -- implement hardware performance monitors?
RISCV_ISA_Zknd => true, -- implement cryptography NIST AES decryption extension?
RISCV_ISA_Zkne => true, -- implement cryptography NIST AES encryption extension?
RISCV_ISA_Zknh => true, -- implement cryptography NIST hash extension?
RISCV_ISA_Zksed => true, -- implement ShangMi block cypher extension?
RISCV_ISA_Zksh => true, -- implement ShangMi hash extension?
RISCV_ISA_Zmmul => false, -- implement multiply-only M sub-extension?
RISCV_ISA_Zxcfu => true, -- implement custom (instr.) functions unit?
-- Extension Options --
FAST_MUL_EN => performance_options_c.fast_mul_en_c(PERFORMANCE_OPTION), -- use DSPs for M extension's multiplier
FAST_SHIFT_EN => performance_options_c.fast_shift_en_c(PERFORMANCE_OPTION), -- use barrel shifter for shift operations
REGFILE_HW_RST => false, -- no hardware reset
-- Physical Memory Protection (PMP) --
PMP_NUM_REGIONS => 5, -- number of regions (0..16)
PMP_MIN_GRANULARITY => 4, -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes
PMP_TOR_MODE_EN => true, -- implement TOR mode
PMP_NAP_MODE_EN => true, -- implement NAPOT/NA4 mode
-- Hardware Performance Monitors (HPM) --
HPM_NUM_CNTS => 12, -- number of implemented HPM counters (0..29)
HPM_CNT_WIDTH => 40, -- total size of HPM counters (0..64)
-- Internal Instruction memory --
MEM_INT_IMEM_EN => int_imem_c , -- implement processor-internal instruction memory
MEM_INT_IMEM_SIZE => performance_options_c.imem_size_c(PERFORMANCE_OPTION), -- size of processor-internal instruction memory in bytes
-- Internal Data memory --
MEM_INT_DMEM_EN => int_dmem_c, -- implement processor-internal data memory
MEM_INT_DMEM_SIZE => dmem_size_c, -- size of processor-internal data memory in bytes
-- Internal Cache memory --
ICACHE_EN => performance_options_c.icache_en_c(PERFORMANCE_OPTION), -- implement instruction cache
ICACHE_NUM_BLOCKS => 64, -- i-cache: number of blocks (min 2), has to be a power of 2
ICACHE_BLOCK_SIZE => performance_options_c.icache_block_size_c(PERFORMANCE_OPTION), -- i-cache: block size in bytes (min 4), has to be a power of 2
-- Internal Data Cache (dCACHE) --
DCACHE_EN => performance_options_c.dcache_en_c(PERFORMANCE_OPTION), -- implement data cache
DCACHE_NUM_BLOCKS => 32, -- d-cache: number of blocks (min 1), has to be a power of 2
DCACHE_BLOCK_SIZE => performance_options_c.dcache_block_size_c(PERFORMANCE_OPTION), -- d-cache: block size in bytes (min 4), has to be a power of 2
-- External bus interface --
XBUS_EN => true, -- implement external memory bus interface?
XBUS_TIMEOUT => 256, -- cycles after a pending bus access auto-terminates (0 = disabled)
XBUS_REGSTAGE_EN => true, -- add register stage
XBUS_CACHE_EN => true, -- enable external bus cache (x-cache)
XBUS_CACHE_NUM_BLOCKS => 4, -- x-cache: number of blocks (min 1), has to be a power of 2
XBUS_CACHE_BLOCK_SIZE => 32, -- x-cache: block size in bytes (min 4), has to be a power of 2
-- Execute in-place module (XIP) --
XIP_EN => true, -- implement execute in place module (XIP)?
XIP_CACHE_EN => true, -- implement XIP cache?
XIP_CACHE_NUM_BLOCKS => 4, -- number of blocks (min 1), has to be a power of 2
XIP_CACHE_BLOCK_SIZE => 256, -- block size in bytes (min 4), has to be a power of 2
-- External Interrupts Controller (XIRQ) --
XIRQ_NUM_CH => 32, -- number of external IRQ channels (0..32)
-- Processor peripherals --
IO_GPIO_NUM => 64, -- number of GPIO input/output pairs (0..64)
IO_MTIME_EN => true, -- implement machine system timer (MTIME)?
IO_UART0_EN => true, -- implement primary universal asynchronous receiver/transmitter (UART0)?
IO_UART0_RX_FIFO => 32, -- RX fifo depth, has to be a power of two, min 1
IO_UART0_TX_FIFO => 32, -- TX fifo depth, has to be a power of two, min 1
IO_UART1_EN => true, -- implement secondary universal asynchronous receiver/transmitter (UART1)?
IO_UART1_RX_FIFO => 1, -- RX fifo depth, has to be a power of two, min 1
IO_UART1_TX_FIFO => 1, -- TX fifo depth, has to be a power of two, min 1
IO_SPI_EN => true, -- implement serial peripheral interface (SPI)?
IO_SPI_FIFO => 4, -- SPI RTX fifo depth, has to be zero or a power of two
IO_SDI_EN => true, -- implement serial data interface (SDI)?
IO_SDI_FIFO => 4, -- SDI RTX fifo depth, has to be zero or a power of two
IO_TWI_EN => true, -- implement two-wire interface (TWI)?
IO_TWI_FIFO => 4, -- RTX fifo depth, has to be zero or a power of two, min 1
IO_PWM_NUM_CH => 8, -- number of PWM channels to implement (0..16)
IO_WDT_EN => true, -- implement watch dog timer (WDT)?
IO_TRNG_EN => true, -- implement true random number generator (TRNG)?
IO_TRNG_FIFO => 4, -- TRNG fifo depth, has to be a power of two, min 1
IO_CFS_EN => true, -- implement custom functions subsystem (CFS)?
IO_CFS_CONFIG => (others => '0'), -- custom CFS configuration generic
IO_CFS_IN_SIZE => 32, -- size of CFS input conduit in bits
IO_CFS_OUT_SIZE => 32, -- size of CFS output conduit in bits
IO_NEOLED_EN => true, -- implement NeoPixel-compatible smart LED interface (NEOLED)?
IO_NEOLED_TX_FIFO => 8, -- NEOLED TX FIFO depth, 1..32k, has to be a power of two
IO_GPTMR_EN => true, -- implement general purpose timer (GPTMR)?
IO_ONEWIRE_EN => true, -- implement 1-wire interface (ONEWIRE)?
IO_DMA_EN => true, -- implement direct memory access controller (DMA)?
IO_SLINK_EN => true, -- implement stream link interface (SLINK)?
IO_SLINK_RX_FIFO => 4, -- RX fifo depth, has to be a power of two, min 1
IO_SLINK_TX_FIFO => 4, -- TX fifo depth, has to be a power of two, min 1
IO_CRC_EN => true -- implement cyclic redundancy check unit (CRC)?
)
port map (
-- Global control --
clk_i => clk_gen, -- global clock, rising edge
rstn_i => rst_gen, -- global reset, low-active, async
-- JTAG on-chip debugger interface (available if OCD_EN = true) --
jtag_tck_i => '0', -- serial clock
jtag_tdi_i => '0', -- serial data input
jtag_tdo_o => open, -- serial data output
jtag_tms_i => '0', -- mode select
-- External bus interface (available if XBUS_EN = true) --
xbus_adr_o => wb_cpu.addr, -- address
xbus_dat_o => wb_cpu.wdata, -- write data
xbus_tag_o => wb_cpu.tag, -- access tag
xbus_we_o => wb_cpu.we, -- read/write
xbus_sel_o => wb_cpu.sel, -- byte enable
xbus_stb_o => wb_cpu.stb, -- strobe
xbus_cyc_o => wb_cpu.cyc, -- valid cycle
xbus_dat_i => wb_cpu.rdata, -- read data
xbus_ack_i => wb_cpu.ack, -- transfer acknowledge
xbus_err_i => wb_cpu.err, -- transfer error
-- Stream Link Interface (available if IO_SLINK_EN = true) --
slink_rx_dat_i => slink_dat, -- RX input data
slink_rx_src_i => slink_id, -- RX source routing information
slink_rx_val_i => slink_val, -- RX valid input
slink_rx_lst_i => slink_lst, -- RX last element of stream
slink_rx_rdy_o => slink_rdy, -- RX ready to receive
slink_tx_dat_o => slink_dat, -- TX output data
slink_tx_dst_o => slink_id, -- TX destination routing information
slink_tx_val_o => slink_val, -- TX valid output
slink_tx_lst_o => slink_lst, -- TX last element of stream
slink_tx_rdy_i => slink_rdy, -- TX ready to send
-- XIP (execute in place via SPI) signals (available if XIP_EN = true) --
xip_csn_o => open, -- chip-select, low-active
xip_clk_o => open, -- serial clock
xip_dat_i => '0', -- device data input
xip_dat_o => open, -- controller data output
-- GPIO (available if IO_GPIO_NUM > true) --
gpio_o => gpio, -- parallel output
gpio_i => gpio, -- parallel input
-- primary UART0 (available if IO_UART0_EN = true) --
uart0_txd_o => uart0_txd, -- UART0 send data
uart0_rxd_i => uart0_txd, -- UART0 receive data
uart0_rts_o => uart1_cts, -- HW flow control: UART0.RX ready to receive ("RTR"), low-active, optional
uart0_cts_i => uart0_cts, -- HW flow control: UART0.TX allowed to transmit, low-active, optional
-- secondary UART1 (available if IO_UART1_EN = true) --
uart1_txd_o => uart1_txd, -- UART1 send data
uart1_rxd_i => uart1_txd, -- UART1 receive data
uart1_rts_o => uart0_cts, -- HW flow control: UART0.RX ready to receive ("RTR"), low-active, optional
uart1_cts_i => uart1_cts, -- HW flow control: UART0.TX allowed to transmit, low-active, optional
-- SPI (available if IO_SPI_EN = true) --
spi_clk_o => spi_clk, -- SPI serial clock
spi_dat_o => spi_do, -- controller data out, peripheral data in
spi_dat_i => spi_di, -- controller data in, peripheral data out
spi_csn_o => spi_csn, -- SPI CS
-- SDI (available if IO_SDI_EN = true) --
sdi_clk_i => sdi_clk, -- SDI serial clock
sdi_dat_o => sdi_do, -- controller data out, peripheral data in
sdi_dat_i => sdi_di, -- controller data in, peripheral data out
sdi_csn_i => sdi_csn, -- chip-select
-- TWI (available if IO_TWI_EN = true) --
twi_sda_i => twi_sda_i, -- serial data line sense input
twi_sda_o => twi_sda_o, -- serial data line output (pull low only)
twi_scl_i => twi_scl_i, -- serial clock line sense input
twi_scl_o => twi_scl_o, -- serial clock line output (pull low only)
-- 1-Wire Interface (available if IO_ONEWIRE_EN = true) --
onewire_i => onewire_i, -- 1-wire bus sense input
onewire_o => onewire_o, -- 1-wire bus output (pull low only)
-- PWM (available if IO_PWM_NUM_CH > 0) --
pwm_o => open, -- pwm channels
-- Custom Functions Subsystem IO --
cfs_in_i => (others => '0'), -- custom CFS inputs
cfs_out_o => open, -- custom CFS outputs
-- NeoPixel-compatible smart LED interface (available if IO_NEOLED_EN = true) --
neoled_o => open, -- async serial data line
-- Machine timer system time (available if IO_MTIME_EN = true) --
mtime_time_o => open,
-- External platform interrupts (available if XIRQ_NUM_CH > 0) --
xirq_i => gpio(31 downto 0), -- IRQ channels
-- CPU Interrupts --
mtime_irq_i => '0', -- machine software interrupt, available if IO_MTIME_EN = false
msw_irq_i => msi_ring, -- machine software interrupt
mext_irq_i => mei_ring -- machine external interrupt
);
-- TWI tri-state driver --
twi_sda <= '0' when (twi_sda_o = '0') else 'Z'; -- module can only pull the line low actively
twi_scl <= '0' when (twi_scl_o = '0') else 'Z';
twi_sda_i <= std_ulogic(twi_sda);
twi_scl_i <= std_ulogic(twi_scl);
-- 1-Wire tri-state driver --
onewire <= '0' when (onewire_o = '0') else 'Z'; -- module can only pull the line low actively
onewire_i <= std_ulogic(onewire);
-- TWI termination (pull-ups) --
twi_scl <= 'H';
twi_sda <= 'H';
-- 1-Wire termination (pull-up) --
onewire <= 'H';
-- SPI/SDI echo with propagation delay --
sdi_clk <= spi_clk after 40 ns;
sdi_csn <= spi_csn(7) after 40 ns;
sdi_di <= spi_do after 40 ns;
spi_di <= sdi_do when (spi_csn(7) = '0') else spi_do after 40 ns;
-- UART Simulation Receiver ---------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
uart0_checker: entity work.uart_rx_simple
generic map (
name => "uart0",
uart_baud_val_c => uart0_baud_val_c
)
port map (
clk => clk_gen,
uart_txd => uart0_txd
);
uart1_checker: entity work.uart_rx_simple
generic map (
name => "uart1",
uart_baud_val_c => uart1_baud_val_c
)
port map (
clk => clk_gen,
uart_txd => uart1_txd
);
-- Wishbone Fabric ------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- CPU broadcast signals --
wb_mem_a.addr <= wb_cpu.addr;
wb_mem_a.wdata <= wb_cpu.wdata;
wb_mem_a.we <= wb_cpu.we;
wb_mem_a.sel <= wb_cpu.sel;
wb_mem_a.cyc <= wb_cpu.cyc;
wb_mem_b.addr <= wb_cpu.addr;
wb_mem_b.wdata <= wb_cpu.wdata;
wb_mem_b.we <= wb_cpu.we;
wb_mem_b.sel <= wb_cpu.sel;
wb_mem_b.cyc <= wb_cpu.cyc;
wb_mem_c.addr <= wb_cpu.addr;
wb_mem_c.wdata <= wb_cpu.wdata;
wb_mem_c.we <= wb_cpu.we;
wb_mem_c.sel <= wb_cpu.sel;
wb_mem_c.cyc <= wb_cpu.cyc;
wb_irq.addr <= wb_cpu.addr;
wb_irq.wdata <= wb_cpu.wdata;
wb_irq.we <= wb_cpu.we;
wb_irq.sel <= wb_cpu.sel;
wb_irq.cyc <= wb_cpu.cyc;
-- CPU read-back signals (no mux here since peripherals have "output gates") --
wb_cpu.rdata <= wb_mem_a.rdata or wb_mem_b.rdata or wb_mem_c.rdata or wb_irq.rdata;
wb_cpu.ack <= wb_mem_a.ack or wb_mem_b.ack or wb_mem_c.ack or wb_irq.ack;
wb_cpu.err <= wb_mem_a.err or wb_mem_b.err or wb_mem_c.err or wb_irq.err;
-- peripheral select via STROBE signal --
wb_mem_a.stb <= wb_cpu.stb when (wb_cpu.addr >= ext_mem_a_base_addr_c) and (wb_cpu.addr < std_ulogic_vector(unsigned(ext_mem_a_base_addr_c) + ext_mem_a_size_c)) else '0';
wb_mem_b.stb <= wb_cpu.stb when (wb_cpu.addr >= ext_mem_b_base_addr_c) and (wb_cpu.addr < std_ulogic_vector(unsigned(ext_mem_b_base_addr_c) + ext_mem_b_size_c)) else '0';
wb_mem_c.stb <= wb_cpu.stb when (wb_cpu.addr >= ext_mem_c_base_addr_c) and (wb_cpu.addr < std_ulogic_vector(unsigned(ext_mem_c_base_addr_c) + ext_mem_c_size_c)) else '0';
wb_irq.stb <= wb_cpu.stb when (wb_cpu.addr = irq_trigger_base_addr_c) else '0';
-- Wishbone Memory A (simulated external IMEM) --------------------------------------------
-- -------------------------------------------------------------------------------------------
generate_ext_imem:
if (int_imem_c = false) generate
ext_mem_a_access: process(clk_gen)
variable ext_ram_a : mem32_t(0 to ext_mem_a_size_c/4-1) := mem32_init_f(application_init_image, ext_mem_a_size_c/4); -- initialized, used to simulate external IMEM
begin
if rising_edge(clk_gen) then
-- control --
ext_mem_a.ack(0) <= wb_mem_a.cyc and wb_mem_a.stb; -- wishbone acknowledge
-- write access --
if ((wb_mem_a.cyc and wb_mem_a.stb and wb_mem_a.we) = '1') then -- valid write access
for i in 0 to 3 loop
if (wb_mem_a.sel(i) = '1') then
ext_ram_a(to_integer(unsigned(wb_mem_a.addr(index_size_f(ext_mem_a_size_c/4)+1 downto 2))))(7+i*8 downto 0+i*8) := wb_mem_a.wdata(7+i*8 downto 0+i*8);
end if;
end loop; -- i
end if;
-- read access --
ext_mem_a.rdata(0) <= ext_ram_a(to_integer(unsigned(wb_mem_a.addr(index_size_f(ext_mem_a_size_c/4)+1 downto 2)))); -- word aligned
-- virtual read and ack latency --
if (ext_mem_a_latency_c > 1) then
for i in 1 to ext_mem_a_latency_c-1 loop
ext_mem_a.rdata(i) <= ext_mem_a.rdata(i-1);
ext_mem_a.ack(i) <= ext_mem_a.ack(i-1) and wb_mem_a.cyc;
end loop;
end if;
-- bus output register --
wb_mem_a.err <= '0';
if (ext_mem_a.ack(ext_mem_a_latency_c-1) = '1') and (wb_mem_a.cyc = '1') then
wb_mem_a.rdata <= ext_mem_a.rdata(ext_mem_a_latency_c-1);
wb_mem_a.ack <= '1';
else
wb_mem_a.rdata <= (others => '0');
wb_mem_a.ack <= '0';
end if;
end if;
end process ext_mem_a_access;
end generate;
generate_ext_imem_false:
if (int_imem_c = true) generate
wb_mem_a.rdata <= (others => '0');
wb_mem_a.ack <= '0';
wb_mem_a.err <= '0';
end generate;
-- Wishbone Memory B (simulated external DMEM) --------------------------------------------
-- -------------------------------------------------------------------------------------------
generate_ext_dmem:
if (int_dmem_c = false) generate
ext_mem_b_access: process(clk_gen)
variable ext_ram_b : mem32_t(0 to ext_mem_b_size_c/4-1) := (others => (others => '0')); -- zero, used to simulate external DMEM
begin
if rising_edge(clk_gen) then
-- control --
ext_mem_b.ack(0) <= wb_mem_b.cyc and wb_mem_b.stb; -- wishbone acknowledge
-- write access --
if ((wb_mem_b.cyc and wb_mem_b.stb and wb_mem_b.we) = '1') then -- valid write access
for i in 0 to 3 loop
if (wb_mem_b.sel(i) = '1') then
ext_ram_b(to_integer(unsigned(wb_mem_b.addr(index_size_f(ext_mem_b_size_c/4)+1 downto 2))))(7+i*8 downto 0+i*8) := wb_mem_b.wdata(7+i*8 downto 0+i*8);
end if;
end loop; -- i
end if;
-- read access --
ext_mem_b.rdata(0) <= ext_ram_b(to_integer(unsigned(wb_mem_b.addr(index_size_f(ext_mem_b_size_c/4)+1 downto 2)))); -- word aligned
-- virtual read and ack latency --
if (ext_mem_b_latency_c > 1) then
for i in 1 to ext_mem_b_latency_c-1 loop
ext_mem_b.rdata(i) <= ext_mem_b.rdata(i-1);
ext_mem_b.ack(i) <= ext_mem_b.ack(i-1) and wb_mem_b.cyc;
end loop;
end if;
-- bus output register --
wb_mem_b.err <= '0';
if (ext_mem_b.ack(ext_mem_b_latency_c-1) = '1') and (wb_mem_b.cyc = '1') then
wb_mem_b.rdata <= ext_mem_b.rdata(ext_mem_b_latency_c-1);
wb_mem_b.ack <= '1';
else
wb_mem_b.rdata <= (others => '0');
wb_mem_b.ack <= '0';
end if;
end if;
end process ext_mem_b_access;
end generate;
generate_ext_dmem_false:
if (int_dmem_c = true) generate
wb_mem_b.rdata <= (others => '0');
wb_mem_b.ack <= '0';
wb_mem_b.err <= '0';
end generate;
-- Wishbone Memory C (simulated external IO) ----------------------------------------------
-- -------------------------------------------------------------------------------------------
ext_mem_c_access: process(clk_gen)
begin
if rising_edge(clk_gen) then
-- control --
ext_mem_c.ack(0) <= wb_mem_c.cyc and wb_mem_c.stb; -- wishbone acknowledge
-- write access --
if ((wb_mem_c.cyc and wb_mem_c.stb and wb_mem_c.we) = '1') then -- valid write access
for i in 0 to 3 loop
if (wb_mem_c.sel(i) = '1') then
ext_ram_c(to_integer(unsigned(wb_mem_c.addr(index_size_f(ext_mem_c_size_c/4)+1 downto 2))))(7+i*8 downto 0+i*8) <= wb_mem_c.wdata(7+i*8 downto 0+i*8);
end if;
end loop; -- i
end if;
-- read access --
ext_mem_c.rdata(0) <= ext_ram_c(to_integer(unsigned(wb_mem_c.addr(index_size_f(ext_mem_c_size_c/4)+1 downto 2)))); -- word aligned
-- virtual read and ack latency --
if (ext_mem_c_latency_c > 1) then
for i in 1 to ext_mem_c_latency_c-1 loop
ext_mem_c.rdata(i) <= ext_mem_c.rdata(i-1);
ext_mem_c.ack(i) <= ext_mem_c.ack(i-1) and wb_mem_c.cyc;
end loop;
end if;
-- bus output register --
if (ext_mem_c.ack(ext_mem_c_latency_c-1) = '1') and (wb_mem_c.cyc = '1') then
wb_mem_c.rdata <= ext_mem_c.rdata(ext_mem_c_latency_c-1);
wb_mem_c.ack <= '1';
wb_mem_c.err <= '0';
else
wb_mem_c.rdata <= (others => '0');
wb_mem_c.ack <= '0';
wb_mem_c.err <= '0';
end if;
end if;
end process ext_mem_c_access;
-- Wishbone IRQ Triggers ------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
irq_trigger: process(rst_gen, clk_gen)
begin
if (rst_gen = '0') then
msi_ring <= '0';
mei_ring <= '0';
elsif rising_edge(clk_gen) then
-- bus interface --
wb_irq.rdata <= (others => '0');
wb_irq.ack <= wb_irq.cyc and wb_irq.stb and wb_irq.we and and_reduce_f(wb_irq.sel);
wb_irq.err <= '0';
-- trigger RISC-V platform IRQs --
if ((wb_irq.cyc and wb_irq.stb and wb_irq.we and and_reduce_f(wb_irq.sel)) = '1') then
msi_ring <= wb_irq.wdata(03); -- machine software interrupt
mei_ring <= wb_irq.wdata(11); -- machine software interrupt
end if;
end if;
end process irq_trigger;
end neorv32_tb_simple_rtl;

View file

@ -1,77 +0,0 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use std.textio.all;
entity uart_rx_simple is
generic (
name : string;
uart_baud_val_c : real);
port (
clk : in std_ulogic;
uart_txd : in std_ulogic
);
end entity;
architecture a of uart_rx_simple is
signal uart_rx_sync : std_ulogic_vector(04 downto 0) := (others => '1');
signal uart_rx_busy : std_ulogic := '0';
signal uart_rx_sreg : std_ulogic_vector(08 downto 0) := (others => '0');
signal uart_rx_baud_cnt : real;
signal uart_rx_bitcnt : natural;
file file_uart_tx_out : text open write_mode is "neorv32.testbench_" & name & ".out";
begin
uart_rx_console : process(clk)
variable i : integer;
variable l : line;
begin
-- "UART" --
if rising_edge(clk) then
-- synchronizer --
uart_rx_sync <= uart_rx_sync(3 downto 0) & uart_txd;
-- arbiter --
if (uart_rx_busy = '0') then -- idle
uart_rx_busy <= '0';
uart_rx_baud_cnt <= round(0.5 * uart_baud_val_c);
uart_rx_bitcnt <= 9;
if (uart_rx_sync(4 downto 1) = "1100") then -- start bit? (falling edge)
uart_rx_busy <= '1';
end if;
else
if (uart_rx_baud_cnt <= 0.0) then
if (uart_rx_bitcnt = 1) then
uart_rx_baud_cnt <= round(0.5 * uart_baud_val_c);
else
uart_rx_baud_cnt <= round(uart_baud_val_c);
end if;
if (uart_rx_bitcnt = 0) then
uart_rx_busy <= '0'; -- done
i := to_integer(unsigned(uart_rx_sreg(8 downto 1)));
if (i < 32) or (i > 32+95) then -- printable char?
report name & ".tx: (" & integer'image(i) & ")"; -- print code
else
report name & ".tx: " & character'val(i); -- print ASCII
end if;
if (i = 10) then -- Linux line break
writeline(file_uart_tx_out, l);
elsif (i /= 13) then -- Remove additional carriage return
write(l, character'val(i));
end if;
else
uart_rx_sreg <= uart_rx_sync(4) & uart_rx_sreg(8 downto 1);
uart_rx_bitcnt <= uart_rx_bitcnt - 1;
end if;
else
uart_rx_baud_cnt <= uart_rx_baud_cnt - 1.0;
end if;
end if;
end if;
end process uart_rx_console;
end architecture;

View file

@ -5,15 +5,11 @@ use ieee.math_real.all;
use std.textio.all;
library vunit_lib;
context vunit_lib.vunit_context;
context vunit_lib.com_context;
context vunit_lib.vc_context;
use work.uart_rx_pkg.all;
entity uart_rx is
generic (handle : uart_rx_t);
generic (
name : string;
uart_baud_val_c : real);
port (
clk : in std_ulogic;
uart_txd : in std_ulogic
@ -27,49 +23,12 @@ architecture a of uart_rx is
signal uart_rx_baud_cnt : real;
signal uart_rx_bitcnt : natural;
file file_uart_tx_out : text open write_mode is "neorv32.testbench_" & get_name(handle.p_logger) & ".out";
constant checker : checker_t := new_checker(handle.p_logger);
constant character_queue : queue_t := new_queue;
file file_uart_tx_out : text open write_mode is "neorv32.testbench_" & name & ".out";
begin
control : process
variable request_msg, reply_msg : msg_t;
variable msg_type : msg_type_t;
procedure put_characters_in_queue(s : string) is
begin
for idx in s'range loop
push(character_queue, s(idx));
end loop;
end procedure put_characters_in_queue;
begin
receive(net, handle.p_actor, request_msg);
msg_type := message_type(request_msg);
-- Standard handling of standard wait_for_time messages = wait for the given time
-- before proceeeding
handle_wait_for_time(net, msg_type, request_msg);
if msg_type = check_uart_msg then
put_characters_in_queue(pop(request_msg));
-- Custom handling of standard wait_until_idle message
elsif msg_type = wait_until_idle_msg then
while not is_empty(character_queue) loop
wait until rising_edge(clk);
end loop;
reply_msg := new_msg(wait_until_idle_reply_msg);
reply(net, request_msg, reply_msg);
else
unexpected_msg_type(msg_type);
end if;
end process;
uart_rx_console : process(clk)
variable i : integer;
variable l : line;
variable expected_character : character;
begin
-- "UART" --
if rising_edge(clk) then
@ -78,7 +37,7 @@ begin
-- arbiter --
if (uart_rx_busy = '0') then -- idle
uart_rx_busy <= '0';
uart_rx_baud_cnt <= round(0.5 * handle.p_baud_val);
uart_rx_baud_cnt <= round(0.5 * uart_baud_val_c);
uart_rx_bitcnt <= 9;
if (uart_rx_sync(4 downto 1) = "1100") then -- start bit? (falling edge)
uart_rx_busy <= '1';
@ -86,19 +45,18 @@ begin
else
if (uart_rx_baud_cnt <= 0.0) then
if (uart_rx_bitcnt = 1) then
uart_rx_baud_cnt <= round(0.5 * handle.p_baud_val);
uart_rx_baud_cnt <= round(0.5 * uart_baud_val_c);
else
uart_rx_baud_cnt <= round(handle.p_baud_val);
uart_rx_baud_cnt <= round(uart_baud_val_c);
end if;
if (uart_rx_bitcnt = 0) then
uart_rx_busy <= '0'; -- done
i := to_integer(unsigned(uart_rx_sreg(8 downto 1)));
if is_empty(character_queue) then
check_failed(checker, "Extra characters received");
if (i < 32) or (i > 32+95) then -- printable char?
report name & ".tx: (" & integer'image(i) & ")"; -- print code
else
expected_character := pop(character_queue);
check_equal(checker, character'val(i), expected_character);
report name & ".tx: " & character'val(i); -- print ASCII
end if;
if (i = 10) then -- Linux line break

View file

@ -1,60 +0,0 @@
library vunit_lib;
context vunit_lib.vunit_context;
context vunit_lib.com_context;
use vunit_lib.sync_pkg.all;
package uart_rx_pkg is
constant check_uart_msg : msg_type_t := new_msg_type("check_uart");
type uart_rx_t is record
p_baud_val : real;
p_logger : logger_t;
p_actor : actor_t;
end record;
impure function new_uart_rx(
baud_val : real;
logger : logger_t := null_logger;
actor : actor_t := null_actor) return uart_rx_t;
function as_sync(handle : uart_rx_t) return sync_handle_t;
procedure check_uart(
signal net : inout network_t;
constant handle : in uart_rx_t;
constant data : in string);
end package uart_rx_pkg;
package body uart_rx_pkg is
constant uart_rx_logger : logger_t := get_logger("neorv32_lib:uart_rx_pkg");
impure function new_uart_rx(
baud_val : real;
logger : logger_t := null_logger;
actor : actor_t := null_actor) return uart_rx_t is
variable result : uart_rx_t;
begin
result.p_baud_val := baud_val;
result.p_logger := logger when logger /= null_logger else uart_rx_logger;
result.p_actor := actor when actor /= null_actor else new_actor;
return result;
end;
function as_sync(handle : uart_rx_t) return sync_handle_t is
begin
return handle.p_actor;
end;
procedure check_uart(
signal net : inout network_t;
constant handle : in uart_rx_t;
constant data : in string) is
variable msg : msg_t;
begin
msg := new_msg(check_uart_msg);
push(msg, data);
send(net, handle.p_actor, msg);
end;
end package body uart_rx_pkg;

View file

@ -1,4 +1,25 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Bootloader (for BOOTROM) makefile.
# Minimal RISC-V ISA only
MARCH = rv32i_zicsr_zifencei
MABI = ilp32
# Optimize for minimal size
EFFORT = -Os
# Adjust "rom" memory size and base for BOOTROM
# Just use a minimal "ram" size that should be available on any platform configuration.
# Define MAKE_BOOTLOADER for SW library (reduces footprint)
# Enable link-time-optimization
USER_FLAGS += \
-Wl,--defsym,__neorv32_rom_size=4k \
-Wl,--defsym,__neorv32_rom_base=0xFFFFC000 \
-Wl,--defsym,__neorv32_ram_size=512 \
-DMAKE_BOOTLOADER \
-flto
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,6 +1,8 @@
# ================================================================================ #
# NEORV32 Application Software Makefile #
# -------------------------------------------------------------------------------- #
# Do not edit this file! Use the re-defines in the project-local makefile instead. #
# -------------------------------------------------------------------------------- #
# The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 #
# Copyright (c) NEORV32 contributors. #
# Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. #
@ -9,8 +11,8 @@
# ================================================================================ #
# -----------------------------------------------------------------------------
# Default configuration (do not edit this file; override the configuration
# when including this Makefile in the project-specific Makefile)
# Default configuration (DO NOT EDIT THIS FILE! REDEFINE / OVERRIDE THE DEFAULT
# CONFIGURATION WHEN INCLUDING THIS MAKEFILE IN THE PROJECT-SPECIFIC MAKEFILE)
# -----------------------------------------------------------------------------
# User's application sources (*.c, *.cpp, *.s, *.S); add additional files here
APP_SRC ?= $(wildcard ./*.c) $(wildcard ./*.s) $(wildcard ./*.cpp) $(wildcard ./*.S)
@ -57,7 +59,7 @@ NEORV32_EXG_PATH = $(NEORV32_HOME)/sw/image_gen
# Path to NEORV32 rtl folder
NEORV32_RTL_PATH = $(NEORV32_LOCAL_RTL)
# Path to NEORV32 sim folder
NEORV32_SIM_PATH = $(NEORV32_HOME)/sim/simple
NEORV32_SIM_PATH = $(NEORV32_HOME)/sim
# Marker file to check for NEORV32 home folder
NEORV32_HOME_MARKER = $(NEORV32_INC_PATH)/neorv32.h
@ -106,7 +108,7 @@ IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen
# Compiler & linker flags
CC_OPTS = -march=$(MARCH) -mabi=$(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv
CC_OPTS += -mstrict-align -mbranch-cost=10 -Wl,--gc-sections -ffp-contract=off
CC_OPTS += -mstrict-align -mbranch-cost=10 -Wl,--gc-sections -ffp-contract=off -g
CC_OPTS += $(USER_FLAGS)
LD_LIBS = -lm -lc -lgcc
LD_LIBS += $(USER_LIBS)
@ -127,7 +129,7 @@ NEO_ASFLAGS = $(CC_FLAGS) $(ASFLAGS)
# -----------------------------------------------------------------------------
# Application output definitions
# -----------------------------------------------------------------------------
.PHONY: check info help elf_info clean clean_all bootloader
.PHONY: check info help elf_info clean clean_all
.DEFAULT_GOAL := help
asm: $(APP_ASM)
@ -142,12 +144,6 @@ image: $(APP_VHD)
install: image install-$(APP_VHD)
all: $(APP_ASM) $(APP_EXE) $(APP_HEX) $(APP_BIN) $(APP_COE) $(APP_MEM) $(APP_MIF) $(APP_VHD) install hex bin
# Check if making bootloader
# Use different base address and length for instruction memory/"rom" (BOOTROM instead of IMEM)
# Also define "MAKE_BOOTLOADER" symbol for simplified code when building the bootloader
# Use link-time optimization to further shrink bootloader code size
target bootloader | bl_image: CC_OPTS += -Wl,--defsym=MAKE_BOOTLOADER=1 -DMAKE_BOOTLOADER -flto
# -----------------------------------------------------------------------------
# Image generator targets
# -----------------------------------------------------------------------------
@ -199,14 +195,16 @@ main.bin: $(APP_ELF)
# Generate NEORV32 executable image for upload via bootloader
$(APP_EXE): main.bin $(IMAGE_GEN)
@set -e
@echo "Generating $(APP_EXE)"
@$(IMAGE_GEN) -app_bin $< $@ $(shell basename $(CURDIR))
@echo "Executable ($(APP_EXE)) size in bytes:"
@echo "Executable size in bytes:"
@wc -c < $(APP_EXE)
# Generate NEORV32 executable VHDL boot image
$(APP_VHD): main.bin $(IMAGE_GEN)
@set -e
@$(IMAGE_GEN) -app_img $< $@ $(shell basename $(CURDIR))
@echo "Generating $(APP_VHD)"
@$(IMAGE_GEN) -app_vhd $< $@ $(shell basename $(CURDIR))
# Install VHDL memory initialization file
install-$(APP_VHD): $(APP_VHD)
@ -217,48 +215,48 @@ install-$(APP_VHD): $(APP_VHD)
# Generate NEORV32 RAW executable image in plain hex format
$(APP_HEX): main.bin $(IMAGE_GEN)
@set -e
@echo "Generating $(APP_HEX)"
@$(IMAGE_GEN) -raw_hex $< $@ $(shell basename $(CURDIR))
# Generate NEORV32 RAW executable image in binary format
$(APP_BIN): main.bin $(IMAGE_GEN)
@set -e
@echo "Generating $(APP_BIN)"
@$(IMAGE_GEN) -raw_bin $< $@ $(shell basename $(CURDIR))
# Generate NEORV32 RAW executable image in COE format
$(APP_COE): main.bin $(IMAGE_GEN)
@set -e
@echo "Generating $(APP_COE)"
@$(IMAGE_GEN) -raw_coe $< $@ $(shell basename $(CURDIR))
# Generate NEORV32 RAW executable image in MIF format
$(APP_MIF): main.bin $(IMAGE_GEN)
@set -e
@echo "Generating $(APP_MIF)"
@$(IMAGE_GEN) -raw_mif $< $@ $(shell basename $(CURDIR))
# Generate NEORV32 RAW executable image in MEM format
$(APP_MEM): main.bin $(IMAGE_GEN)
@set -e
@echo "Generating $(APP_MEM)"
@$(IMAGE_GEN) -raw_mem $< $@ $(shell basename $(CURDIR))
# -----------------------------------------------------------------------------
# Boot image targets
# BOOTROM / booloader image targets
# -----------------------------------------------------------------------------
# Create VHDL boot image
$(BOOT_VHD): main.bin $(IMAGE_GEN)
# Create local VHDL BOOTROM image
bl_image: main.bin $(IMAGE_GEN)
@set -e
@$(IMAGE_GEN) -bld_img $< $(BOOT_VHD) $(shell basename $(CURDIR))
@echo "Generating $(BOOT_VHD)"
@$(IMAGE_GEN) -bld_vhd $< $(BOOT_VHD) $(shell basename $(CURDIR))
# Install image to VHDL source directory
install-$(BOOT_VHD): $(BOOT_VHD)
# Install BOOTROM image to VHDL source directory
bootloader: bl_image
@set -e
@echo "Installing bootloader image to $(NEORV32_RTL_PATH)/core/$(BOOT_VHD)"
@cp $(BOOT_VHD) $(NEORV32_RTL_PATH)/core/.
# Just an alias
bl_image: $(BOOT_VHD)
# Compile and install as VHDL bootloader image
bootloader: bl_image install-$(BOOT_VHD)
# -----------------------------------------------------------------------------
# Check toolchain
# -----------------------------------------------------------------------------
@ -289,10 +287,10 @@ endif
@echo "Toolchain check OK"
# -----------------------------------------------------------------------------
# In-console simulation using default/simple testbench and GHDL
# In-console simulation using default testbench and GHDL
# -----------------------------------------------------------------------------
sim: $(APP_VHD) install
@echo "Simulating processor using simple testbench..."
@echo "Simulating processor using default testbench..."
@sh $(NEORV32_SIM_PATH)/ghdl.sh $(GHDL_RUN_FLAGS)
# -----------------------------------------------------------------------------
@ -374,26 +372,26 @@ help:
@echo " help - show this text"
@echo " check - check toolchain"
@echo " info - show makefile/toolchain configuration"
@echo " gdb - run GNU debugging session"
@echo " gdb - start GNU debugging session"
@echo " asm - compile and generate <$(APP_ASM)> assembly listing file for manual debugging"
@echo " elf - compile and generate <$(APP_ELF)> ELF file"
@echo " exe - compile and generate <$(APP_EXE)> executable image file for upload via default bootloader (binary file)"
@echo " bin - compile and generate <$(APP_BIN)> RAW executable memory image (binary file)"
@echo " hex - compile and generate <$(APP_HEX)> RAW executable memory image (hex char file)"
@echo " coe - compile and generate <$(APP_COE)> RAW executable memory image (COE file)"
@echo " mem - compile and generate <$(APP_MEM)> RAW executable memory image (MEM file)"
@echo " mif - compile and generate <$(APP_MIF)> RAW executable memory image (MIF file)"
@echo " image - compile and generate VHDL IMEM boot image (for application, no header) in local folder"
@echo " install - compile, generate and install VHDL IMEM boot image (for application, no header)"
@echo " sim - in-console simulation using default/simple testbench and GHDL"
@echo " exe - compile and generate <$(APP_EXE)> executable image file for bootloader upload (includes a HEADER!)"
@echo " bin - compile and generate <$(APP_BIN)> executable memory image"
@echo " hex - compile and generate <$(APP_HEX)> executable memory image"
@echo " coe - compile and generate <$(APP_COE)> executable memory image"
@echo " mem - compile and generate <$(APP_MEM)> executable memory image"
@echo " mif - compile and generate <$(APP_MIF)> executable memory image"
@echo " image - compile and generate VHDL IMEM application boot image <$(APP_VHD)> in local folder"
@echo " install - compile, generate and install VHDL IMEM application boot image <$(APP_VHD)>"
@echo " sim - in-console simulation using default testbench (sim folder) and GHDL"
@echo " hdl_lists - regenerate HDL file-lists (*.f) in NEORV32_HOME/rtl"
@echo " all - exe + install + hex + bin + asm"
@echo " elf_info - show ELF layout info"
@echo " elf_sections - show ELF sections"
@echo " clean - clean up project home folder"
@echo " clean_all - clean up whole project, core libraries and image generator"
@echo " bl_image - compile and generate VHDL BOOTROM boot image (for bootloader only, no header) in local folder"
@echo " bootloader - compile, generate and install VHDL BOOTROM boot image (for bootloader only, no header)"
@echo " bl_image - compile and generate VHDL BOOTROM bootloader boot image <$(BOOT_VHD)> in local folder"
@echo " bootloader - compile, generate and install VHDL BOOTROM bootloader boot image <$(BOOT_VHD)>"
@echo ""
@echo "Variables:"
@echo ""
@ -403,6 +401,7 @@ help:
@echo " MARCH - Machine architecture: \"$(MARCH)\""
@echo " MABI - Machine binary interface: \"$(MABI)\""
@echo " APP_INC - C include folder(s) [append only]: \"$(APP_INC)\""
@echo " APP_SRC - C source folder(s) [append only]: \"$(APP_SRC)\""
@echo " ASM_INC - ASM include folder(s) [append only]: \"$(ASM_INC)\""
@echo " RISCV_PREFIX - Toolchain prefix: \"$(RISCV_PREFIX)\""
@echo " NEORV32_HOME - NEORV32 home folder: \"$(NEORV32_HOME)\""

View file

@ -1,5 +1,5 @@
/* ================================================================================ */
/* NEORV32 CPU - RISC-V GCC Linker Script */
/* NEORV32 - RISC-V GCC Linker Script */
/* -------------------------------------------------------------------------------- */
/* The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 */
/* Copyright (c) NEORV32 contributors. */
@ -8,12 +8,6 @@
/* SPDX-License-Identifier: BSD-3-Clause */
/* ================================================================================ */
/* Copyright (C) 2014-2020 Free Software Foundation, Inc.
* Copying and distribution of this script, with or without modification,
* are permitted in any medium without royalty provided the copyright
* notice and this notice are preserved. */
OUTPUT_FORMAT("elf32-littleriscv")
OUTPUT_ARCH(riscv)
ENTRY(_start)
@ -25,34 +19,29 @@ SEARCH_DIR("=/usr/lib")
/* ************************************************************************************************* */
/* +++ NEORV32 memory layout configuration +++ */
/* If the symbols are not explicitly defined the default configurations are used. If required, only */
/* edit the very last entry in each row. */
/* If the "__neorv32_*" symbols are not explicitly defined the default configurations are used. */
/* NOTE: section sizes have to be a multiple of 4 bytes; base addresses have to be 32-bit-aligned. */
/* ************************************************************************************************* */
/* Default rom/ram (IMEM/DMEM) sizes */
__neorv32_rom_size = DEFINED(__neorv32_rom_size) ? __neorv32_rom_size : 2048M;
__neorv32_ram_size = DEFINED(__neorv32_ram_size) ? __neorv32_ram_size : 8K;
/* Default HEAP size (= 0; no heap at all) */
__neorv32_heap_size = DEFINED(__neorv32_heap_size) ? __neorv32_heap_size : 0;
/* Default section base addresses */
/* Default rom/ram (IMEM/DMEM) sizes */
__neorv32_rom_size = DEFINED(__neorv32_rom_size) ? __neorv32_rom_size : 16k;
__neorv32_ram_size = DEFINED(__neorv32_ram_size) ? __neorv32_ram_size : 8K;
/* Default rom/ram (IMEM/DMEM) base addresses */
__neorv32_rom_base = DEFINED(__neorv32_rom_base) ? __neorv32_rom_base : 0x00000000;
__neorv32_ram_base = DEFINED(__neorv32_ram_base) ? __neorv32_ram_base : 0x80000000;
/* ************************************************************************************************* */
/* when compiling the bootloader the ROM section is automatically re-mapped to the */
/* processor-internal bootloader ROM address space. */
/* Main memory segments that are relevant for the executable. */
/* ************************************************************************************************* */
MEMORY
{
rom (rx) : ORIGIN = DEFINED(MAKE_BOOTLOADER) ? 0xFFFFC000 : __neorv32_rom_base, LENGTH = DEFINED(MAKE_BOOTLOADER) ? 8K : __neorv32_rom_size
ram (rwx) : ORIGIN = __neorv32_ram_base, LENGTH = DEFINED(MAKE_BOOTLOADER) ? 512 : __neorv32_ram_size
xip (rx) : ORIGIN = 0xE0000000, LENGTH = 256M
boot (rx) : ORIGIN = 0xFFFFC000, LENGTH = 8K
io (rwx) : ORIGIN = 0xFFFFE000, LENGTH = 8K
rom (rx) : ORIGIN = __neorv32_rom_base, LENGTH = __neorv32_rom_size
ram (rwx) : ORIGIN = __neorv32_ram_base, LENGTH = __neorv32_ram_size
}

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32ia_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32imc_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -O3
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=32k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,5 +1,33 @@
# Configure max HEAP size
override USER_FLAGS += "-Wl,--defsym,__neorv32_heap_size=3072"
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=3072
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
include $(NEORV32_HOME)/sw/common/common.mk
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
include $(NEORV32_HOME)/sw/common/common.mk
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
include $(NEORV32_HOME)/sw/common/common.mk
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
include $(NEORV32_HOME)/sw/common/common.mk
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,7 +1,32 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
APP_SRC += $(wildcard ./*.c) $(wildcard ./*.s) $(wildcard ./*.cpp) $(wildcard ./*.S) $(wildcard ./drv/*.c)
APP_INC += -I . -I ./drv
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
APP_SRC ?= $(wildcard ./*.c) $(wildcard ./*.s) $(wildcard ./*.cpp) $(wildcard ./*.S) $(wildcard ./drv/*.c)
APP_INC ?= -I . -I ./drv
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
include $(NEORV32_HOME)/sw/common/common.mk
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
include $(NEORV32_HOME)/sw/common/common.mk
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
include $(NEORV32_HOME)/sw/common/common.mk
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
include $(NEORV32_HOME)/sw/common/common.mk
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -155,8 +155,6 @@ int main() {
// All incoming XIRQ interrupt requests are "prioritized" in this example. The XIRQ FIRQ handler
// reads the ID of the interrupt with the highest priority from the XIRQ controller ("source" register) and calls the according
// handler function (installed via neorv32_xirq_install();).
// Non-prioritized handling of interrupts (or custom prioritization) can be implemented by manually reading the
// XIRQ controller's "pending" register. Then it is up to the software to define which pending IRQ should be serviced first.
asm volatile ("nop");
asm volatile ("nop");
@ -165,15 +163,12 @@ int main() {
// just as an example: to disable certain XIRQ interrupt channels, we can
// un-install the according handler. this will also clear a pending interrupt for that channel
// un-install the according handler. this will also disable the according channel.
neorv32_xirq_uninstall(0); // disable XIRQ channel 0 and remove associated handler
neorv32_xirq_uninstall(1); // disable XIRQ channel 1 and remove associated handler
neorv32_xirq_uninstall(2); // disable XIRQ channel 2 and remove associated handler
neorv32_xirq_uninstall(3); // disable XIRQ channel 3 and remove associated handler
// you can also manually clear pending interrupts
neorv32_xirq_clear_pending(0); // clear pending interrupt of channel 0
// manually enable and disable XIRQ channels
neorv32_xirq_channel_enable(0); // enable channel 0
neorv32_xirq_channel_disable(0); // disable channel 0

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
include $(NEORV32_HOME)/sw/common/common.mk
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -26,6 +26,8 @@
#include <string.h>
#include "dhry.h"
/** UART BAUD rate */
#define BAUD_RATE 19200
#ifndef DHRY_ITERS
#define DHRY_ITERS 10000
@ -104,7 +106,7 @@ int main (void)
{ /* ***** NEORV32-SPECIFIC ***** */
neorv32_rte_setup();
neorv32_cpu_csr_write(CSR_MIE, 0); // no interrupts
neorv32_uart0_setup(19200, 0);
neorv32_uart0_setup(BAUD_RATE, 0);
neorv32_uart0_printf("NEORV32: Processor running at %u Hz\n", (uint32_t)neorv32_sysinfo_get_clk());
neorv32_uart0_printf("NEORV32: Executing Dhrystone (%u iterations). This may take some time...\n\n", (uint32_t)DHRY_ITERS);

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
include $(NEORV32_HOME)/sw/common/common.mk
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -5,7 +5,7 @@
<provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/>
<provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/>
<provider copy-of="extension" id="org.eclipse.cdt.managedbuilder.core.GCCBuildCommandParser"/>
<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector" console="false" env-hash="122111132715565018" id="org.eclipse.embedcdt.managedbuild.cross.riscv.core.GCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT RISC-V Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} ${cross_toolchain_flags} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<provider class="org.eclipse.cdt.managedbuilder.language.settings.providers.GCCBuiltinSpecsDetector" console="false" env-hash="492677979462914387" id="org.eclipse.embedcdt.managedbuild.cross.riscv.core.GCCBuiltinSpecsDetector" keep-relative-paths="false" name="CDT RISC-V Cross GCC Built-in Compiler Settings" parameter="${COMMAND} ${FLAGS} ${cross_toolchain_flags} -E -P -v -dD &quot;${INPUTS}&quot;" prefer-non-shared="true">
<language-scope id="org.eclipse.cdt.core.gcc"/>
<language-scope id="org.eclipse.cdt.core.g++"/>
</provider>

View file

@ -1,5 +1,5 @@
#include <neorv32.h>
#include <stdio.h> // better use an embedded version of printf
#include <stdio.h>
// UART baud rate
#define BAUD_RATE 19200
@ -21,7 +21,8 @@ int main() {
int cnt = 0;
while (1) {
neorv32_gpio_port_set(cnt++ & 0xff); // increment counter and mask for lowest 8 bit
cnt = (cnt + 1) & 0xff; // increment counter and mask for lowest 8 bit
neorv32_gpio_port_set(cnt); // output via GPIO.out
neorv32_cpu_delay_ms(250); // wait 250ms using busy wait
}

View file

@ -1,16 +1,32 @@
# Use this makefile to specify all relevant CPU / compiler options
# as these cannot be issued by Eclipse (since this is a makefile-based project).
# Use this makefile to configure all relevant CPU / compiler options
# as these cannot be set by Eclipse (since this is a makefile-based project).
# Override the default CPU ISA
#override MARCH = rv32imc_zicsr_zifencei
MARCH = rv32imc_zicsr_zifencei
# Override the default RISC-V GCC prefix
RISCV_PREFIX = riscv-none-elf-
RISCV_PREFIX ?= riscv-none-elf-
# Add debug symbols
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols for Eclipse
USER_FLAGS += -ggdb -gdwarf-3
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Additional sources
APP_SRC += $(wildcard ./*.c)
APP_INC += -I .
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
include $(NEORV32_HOME)/sw/common/common.mk
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,4 +1,33 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
APP_SRC += $(wildcard ./*.c)
APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -1,7 +1,37 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk
# Use c++ compiler and define c++ standard
override CC = $(RISCV_PREFIX)g++
override USER_FLAGS += -std=c++11
USER_FLAGS += -std=c++11

View file

@ -1,7 +1,36 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
# Application makefile.
# Use this makefile to configure all relevant CPU / compiler options.
# Override the default CPU ISA
MARCH = rv32i_zicsr_zifencei
# Override the default RISC-V GCC prefix
#RISCV_PREFIX ?= riscv-none-elf-
# Override default optimization goal
EFFORT = -Os
# Add extended debug symbols
USER_FLAGS += -ggdb -gdwarf-3
# Adjust processor IMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k
# Adjust processor DMEM size
USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
# Adjust maximum heap size
#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k
# Additional sources
#APP_SRC += $(wildcard ./*.c)
#APP_INC += -I .
# Set path to NEORV32 root directory
NEORV32_HOME ?= ../../..
# Include the main NEORV32 makefile
include $(NEORV32_HOME)/sw/common/common.mk
sim-check: sim
cat $(NEORV32_HOME)/sim/simple/neorv32.uart0.sim_mode.text.out | grep "Hello world! :)"
cat $(NEORV32_HOME)/sim/neorv32.uart0.sim_mode.text.out | grep "Hello world! :)"

View file

@ -1,6 +1,3 @@
#-------------------------------------------------------------------------------
# Make defaults and targets
#-------------------------------------------------------------------------------
.SUFFIXES:
.DEFAULT_GOAL := help
@ -20,10 +17,6 @@ $(SUBDIRS):
.PHONY: $(TOPTARGETS) $(SUBDIRS)
#-------------------------------------------------------------------------------
# Help
#-------------------------------------------------------------------------------
help:
@echo "Build / clean up all projects"
@echo "Targets:"

View file

@ -1,5 +1,8 @@
# Modify this variable to fit your NEORV32 setup (neorv32 home folder)
NEORV32_HOME ?= ../../../..
MARCH ?= rv32i_zicsr_zifencei
GHDL_RUN_FLAGS ?= -gPERFORMANCE_OPTION=1 --stop-time=4500us
override USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=128k
override USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=16k
include $(NEORV32_HOME)/sw/common/common.mk

View file

@ -2,5 +2,7 @@
NEORV32_HOME ?= ../../../..
MARCH ?= rv32im_zicsr_zifencei
GHDL_RUN_FLAGS ?= -gPERFORMANCE_OPTION=1 --stop-time=1500us
override USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=128k
override USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=16k
include $(NEORV32_HOME)/sw/common/common.mk

Some files were not shown because too many files have changed in this diff Show more