mirror of
https://github.com/stnolting/neorv32.git
synced 2025-04-18 19:35:02 -04:00
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
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:
commit
fea96e0fd4
111 changed files with 3117 additions and 3006 deletions
88
.github/workflows/Processor.yml
vendored
88
.github/workflows/Processor.yml
vendored
|
@ -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
|
||||
|
|
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -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) |
|
||||
|
|
11
README.md
11
README.md
|
@ -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
|
|||
[](https://github.com/stnolting/neorv32/releases)
|
||||
[](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) | [](https://oss.linty-services.com/dashboard?id=neorv32) |
|
||||
| GitHub pages (docs) | [neorv32](https://github.com/stnolting/neorv32) | [](https://stnolting.github.io/neorv32) |
|
||||
| Build documentation | [neorv32](https://github.com/stnolting/neorv32) | [](https://github.com/stnolting/neorv32/actions?query=workflow%3ADocumentation) |
|
||||
| Processor verification | [neorv32](https://github.com/stnolting/neorv32) | [](https://github.com/stnolting/neorv32/actions?query=workflow%3AProcessor) |
|
||||
| VUnit testbench | [neorv32-vunit](https://github.com/stnolting/neorv32-vunit) | [](https://github.com/stnolting/neorv32-vunit/actions/workflows/vunit.yml) |
|
||||
| RISCOF core verification | [neorv32-riscof](https://github.com/stnolting/neorv32-riscof) | [](https://github.com/stnolting/neorv32-riscof/actions/workflows/main.yml) |
|
||||
| FPGA implementations | [neorv32-setups](https://github.com/stnolting/neorv32-setups) | [](https://github.com/stnolting/neorv32-setups/actions?query=workflow%3AImplementation) |
|
||||
| All-Verilog version | [neorv32-verilog](https://github.com/stnolting/neorv32-verilog) | [](https://github.com/stnolting/neorv32-verilog/actions/workflows/main.yml) |
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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`).
|
||||
|
||||
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
||||
<<<
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|=======================
|
||||
|
||||
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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
|
||||
|=======================
|
||||
|
|
|
@ -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).**
|
||||
|
||||
|
||||
<<<
|
||||
|
|
|
@ -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 |
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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 --
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ---------------------------------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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
|
||||
# **************************************************************
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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. --
|
||||
|
|
152
rtl/system_integration/xbus2axi4lite_bridge.vhd
Normal file
152
rtl/system_integration/xbus2axi4lite_bridge.vhd
Normal 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;
|
|
@ -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?
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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 --
|
||||
|
|
|
@ -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
4
sim/simple/ghdl.run.sh → sim/ghdl.run.sh
Executable file → Normal 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
6
sim/simple/ghdl.setup.sh → sim/ghdl.setup.sh
Executable file → Normal 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
12
sim/ghdl.sh
Normal 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 $@
|
|
@ -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 ------------------------------------------------------------------------
|
||||
|
|
56
sim/run.py
56
sim/run.py
|
@ -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()
|
|
@ -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 $@
|
|
@ -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;
|
|
@ -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;
|
|
@ -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
|
||||
|
|
|
@ -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;
|
|
@ -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
|
||||
|
|
|
@ -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)\""
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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
|
|
@ -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 "${INPUTS}"" 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 "${INPUTS}"" prefer-non-shared="true">
|
||||
<language-scope id="org.eclipse.cdt.core.gcc"/>
|
||||
<language-scope id="org.eclipse.cdt.core.g++"/>
|
||||
</provider>
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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! :)"
|
||||
|
|
|
@ -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:"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
Loading…
Add table
Reference in a new issue