mirror of
https://github.com/stnolting/neorv32.git
synced 2025-04-24 14:17:51 -04:00
Merge branch 'main' of github.com:stnolting/neorv32 into fixed-docs-makefile
This commit is contained in:
commit
37a029f24e
80 changed files with 1838 additions and 2747 deletions
89
.github/workflows/Processor.yml
vendored
89
.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,33 @@ 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 xPack RISC-V GCC'
|
||||
run: |
|
||||
wget -q https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack/releases/download/v14.2.0-2/xpack-riscv-none-elf-gcc-14.2.0-2-linux-x64.tar.gz
|
||||
mkdir $GITHUB_WORKSPACE/riscv-gcc
|
||||
tar -xzf xpack-riscv-none-elf-gcc-14.2.0-2-linux-x64.tar.gz -C $GITHUB_WORKSPACE/riscv-gcc
|
||||
echo $GITHUB_WORKSPACE/riscv-gcc/xpack-riscv-none-elf-gcc-14.2.0-2/bin >> $GITHUB_PATH
|
||||
|
||||
- name: '📦 Install GHDL'
|
||||
uses: ghdl/setup-ghdl-ci@nightly
|
||||
|
||||
VUnit:
|
||||
runs-on: ubuntu-latest
|
||||
- name: '🔍 Check tools'
|
||||
run: |
|
||||
riscv-none-elf-gcc -v
|
||||
ghdl -v
|
||||
|
||||
steps:
|
||||
- name: '⚙️ Build Software Framework Tests'
|
||||
run: |
|
||||
make RISCV_PREFIX=riscv-none-elf- -C sw/example/processor_check check
|
||||
make RISCV_PREFIX=riscv-none-elf- -C sw/example clean_all exe
|
||||
make RISCV_PREFIX=riscv-none-elf- -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 }} \
|
||||
RISCV_PREFIX=riscv-none-elf- \
|
||||
USER_FLAGS+="-DUART0_SIM_MODE -DUART1_SIM_MODE" \
|
||||
clean_all \
|
||||
info \
|
||||
all \
|
||||
sim-check
|
||||
|
|
|
@ -29,6 +29,12 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12
|
|||
|
||||
| Date | Version | Comment | Ticket |
|
||||
|:----:|:-------:|:--------|:------:|
|
||||
| 23.11.2024 | 1.10.6.6 | CPU control: large code edits and cleanups | [#1099](https://github.com/stnolting/neorv32/pull/1099) |
|
||||
| 10.11.2024 | 1.10.6.5 | :warning: switch to [xPack](https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack) as default prebuilt RISC-V GCC toolchain (now using `riscv-none-elf-` as default gcc prefix) | [#1091](https://github.com/stnolting/neorv32/pull/1091) |
|
||||
| 10.11.2024 | 1.10.6.4 | rework default processor testbench | [#1093](https://github.com/stnolting/neorv32/pull/1093) |
|
||||
| 06.11.2024 | 1.10.6.3 | minor rtl edits and cleanups | [#1090](https://github.com/stnolting/neorv32/pull/1090) |
|
||||
| 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) |
|
||||
|
@ -149,7 +155,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) |
|
||||
|
|
|
@ -39,7 +39,7 @@ informed via _precise_ and resumable hardware exceptions.
|
|||
targeting various FPGA boards and toolchains to get started.
|
||||
* :package: The entire processor is also available as [Vivado IP Block](https://stnolting.github.io/neorv32/ug/#_packaging_the_processor_as_vivado_ip_block).
|
||||
* :kite: Support for [FreeRTOS](https://github.com/stnolting/neorv32-freertos),
|
||||
[Zephyr OS](https://docs.zephyrproject.org/latest/boards/riscv/neorv32/doc/index.html) and
|
||||
[Zephyr OS](https://docs.zephyrproject.org/latest/boards/others/neorv32/doc/index.html) and
|
||||
[LiteX](https://github.com/enjoy-digital/litex/wiki/CPUs#risc-v---neorv32) SoC Builder Framework.
|
||||
* :desktop_computer: Pre-configured [Eclipse project](https://stnolting.github.io/neorv32/ug/#_eclipse_ide) for developing and debugging code using an IDE.
|
||||
* :label: The project's change log is available in [CHANGELOG.md](https://github.com/stnolting/neorv32/blob/main/CHANGELOG.md).
|
||||
|
@ -250,7 +250,8 @@ This overview provides some *quick links* to the most important sections of the
|
|||
|
||||
* [Top Entity - Signals](https://stnolting.github.io/neorv32/#_processor_top_entity_signals) - how to connect to the processor
|
||||
* [Top Entity - Generics](https://stnolting.github.io/neorv32/#_processor_top_entity_generics) - processor/CPU configuration options
|
||||
* [Address Space](https://stnolting.github.io/neorv32/#_address_space) - memory layout and boot configurations
|
||||
* [Address Space](https://stnolting.github.io/neorv32/#_address_space) - memory layout and address mapping
|
||||
* [Boot Configuration](https://stnolting.github.io/neorv32/#_boot_configuration) - how to make the processor start executing
|
||||
* [SoC Modules](https://stnolting.github.io/neorv32/#_processor_internal_modules) - IO/peripheral modules and memories
|
||||
* [On-Chip Debugger](https://stnolting.github.io/neorv32/#_on_chip_debugger_ocd) - in-system debugging of the processor via JTAG
|
||||
|
||||
|
|
|
@ -1051,6 +1051,7 @@ The NEORV32 PMP is fully compatible to the RISC-V Privileged Architecture Specif
|
|||
by default has full permissions. The PMP is configured via the <<_machine_physical_memory_protection_csrs>>.
|
||||
|
||||
Several <<_processor_top_entity_generics>> are provided to fine-tune the CPU's PMP capabilities:
|
||||
|
||||
* `PMP_NUM_REGIONS` defines the number of implemented PMP region
|
||||
* `PMP_MIN_GRANULARITY` defines the minimal granularity of each region
|
||||
* `PMP_TOR_MODE_EN` controls the implementation of the top-of-region (TOR) mode
|
||||
|
|
|
@ -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.
|
||||
|
@ -435,10 +435,10 @@ However, any write-access will be ignored and will not cause an exception to mai
|
|||
[options="header",grid="rows"]
|
||||
|=======================
|
||||
| Bit | Name [C] | R/W | Function
|
||||
| 3 | `CSR_MIP_MSIP` | r/- | **MSIP**: Machine _software_ interrupt pending; _cleared by platform-defined mechanism_
|
||||
| 7 | `CSR_MIP_MTIP` | r/- | **MTIP**: Machine _timer_ interrupt pending; _cleared by platform-defined mechanism_
|
||||
| 11 | `CSR_MIP_MEIP` | r/- | **MEIP**: Machine _external_ interrupt pending; _cleared by platform-defined mechanism_
|
||||
| 31:16 | `CSR_MIP_FIRQ15P` : `CSR_MIP_FIRQ0P` | r/- | **FIRQxP**: Fast interrupt channel 15..0 pending; _cleared by platform-defined mechanism_
|
||||
| 3 | `CSR_MIP_MSIP` | r/- | **MSIP**: Machine _software_ interrupt pending, triggered by `msi_i` top port (see <<_cpu_top_entity_signals>>); _cleared by source-specific mechanism_
|
||||
| 7 | `CSR_MIP_MTIP` | r/- | **MTIP**: Machine _timer_ interrupt pending, triggered by `mei_i` top port (see <<_cpu_top_entity_signals>>); _cleared by source-specific mechanism_
|
||||
| 11 | `CSR_MIP_MEIP` | r/- | **MEIP**: Machine _external_ interrupt pending, triggered by `mti_i` top port (see <<_cpu_top_entity_signals>>) or by the processor-internal <<_machine_system_timer_mtime>>; _cleared by source-specific mechanism_
|
||||
| 31:16 | `CSR_MIP_FIRQ15P` : `CSR_MIP_FIRQ0P` | r/- | **FIRQxP**: Fast interrupt channel 15..0 pending, see <<_neorv32_specific_fast_interrupt_requests>>; _cleared by source-specific mechanism_
|
||||
|=======================
|
||||
|
||||
.FIRQ Channel Mapping
|
||||
|
@ -528,7 +528,7 @@ See section <<_smpmp_isa_extension>> for more information.
|
|||
[cols="<1,<8"]
|
||||
[frame="topbot",grid="none"]
|
||||
|=======================
|
||||
| Name | PMP region configuration registers
|
||||
| Name | Physical memory protection region configuration registers
|
||||
| Address | `0x3a0` (`pmpcfg0`)
|
||||
| | `0x3a1` (`pmpcfg1`)
|
||||
| | `0x3a2` (`pmpcfg2`)
|
||||
|
@ -538,7 +538,7 @@ See section <<_smpmp_isa_extension>> for more information.
|
|||
| Description | Configuration of physical memory protection regions. Each region provides an individual 8-bit array in these CSRs.
|
||||
|=======================
|
||||
|
||||
.`pmpcfg0` CSR Bits
|
||||
.`pmpcfg*` CSR Bits
|
||||
[cols="^1,^2,^1,<11"]
|
||||
[options="header",grid="rows"]
|
||||
|=======================
|
||||
|
@ -560,12 +560,10 @@ implementation of the according modes.
|
|||
[discrete]
|
||||
===== **`pmpaddr`**
|
||||
|
||||
The `pmpaddr*` CSRs are used to configure the region's address boundaries.
|
||||
|
||||
[cols="<1,<8"]
|
||||
[frame="topbot",grid="none"]
|
||||
|=======================
|
||||
| Name | Physical memory protection address registers
|
||||
| Name | Physical memory protection region address registers
|
||||
| Address | `0x3b0` (`pmpaddr1`)
|
||||
| | `0x3b1` (`pmpaddr2`)
|
||||
| | `0x3b2` (`pmpaddr3`)
|
||||
|
@ -584,7 +582,16 @@ The `pmpaddr*` CSRs are used to configure the region's address boundaries.
|
|||
| | `0x3bf` (`pmpaddr15`)
|
||||
| Reset value | `0x00000000`
|
||||
| ISA | `Zicsr` & `Smpmp`
|
||||
| Description | Region address configuration. The two MSBs of each CSR are hardwired to zero (= bits 33:32 of the physical address).
|
||||
| Description | Region address/boundaries configuration.
|
||||
|=======================
|
||||
|
||||
.`pmpaddr*` CSR Bits
|
||||
[cols="^1,^2,^1,<11"]
|
||||
[options="header",grid="rows"]
|
||||
|=======================
|
||||
| Bit | R/W | Description
|
||||
| 31:30 | r-w | address bits `33 downto 32`´, hardwired to zero
|
||||
| 29:0 | r/w | address bits `31 downto 2`
|
||||
|=======================
|
||||
|
||||
|
||||
|
|
|
@ -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,48 +44,58 @@ ____
|
|||
|
||||
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 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
|
||||
|
@ -94,29 +105,15 @@ in real-world applications (i.e. FPGA block RAM is entirely synchronous). Furthe
|
|||
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 architectureral state changes have to be made _undone_
|
||||
requiring additional (exception-handling) logic. In a multi-cycle architecture this situation cannot occur since only a
|
||||
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]
|
||||
==== Objective
|
||||
|
||||
[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).
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -55,7 +55,7 @@ The basic timing configuration is programmed via the clock prescaler bits `ONEWI
|
|||
clock divider bits `ONEWIRE_CTRL_CLKDIVx` (see next section).
|
||||
|
||||
The controller can execute three basic bus operations, which are triggered by setting one out of three specific
|
||||
control register bits (the bits auto-clear):
|
||||
control register bits (all those bits auto-clear):
|
||||
|
||||
[start=1]
|
||||
. generate reset pulse and check for device presence; triggered when setting `ONEWIRE_CTRL_TRIG_RST`
|
||||
|
@ -158,8 +158,8 @@ constant t_presence_end_c : unsigned(6 downto 0) := to_unsigned(96, 7); -- t6
|
|||
|
||||
.Overdrive
|
||||
[IMPORTANT]
|
||||
The ONEWIRE controller does not support the _overdrive_ mode. However, it can be implemented by reducing the base
|
||||
time **T~base~** (and by eventually changing the hardwired timing configuration in the VHDL source file).
|
||||
The ONEWIRE controller does not support the overdrive mode natively. However, it can be implemented by reducing
|
||||
the base time **T~base~** (and by eventually changing the hardwired timing configuration in the VHDL source file).
|
||||
|
||||
|
||||
**Interrupt**
|
||||
|
|
|
@ -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)
|
||||
|=======================
|
||||
|
||||
|
||||
|
|
|
@ -116,7 +116,7 @@ unconnected. If the CTS handshake is not required it has to be tied to zero.
|
|||
The UART provides a _simulation-only_ mode to dump console data as well as raw data directly to a file. When the simulation
|
||||
mode is enabled (by setting the `UART_CTRL_SIM_MODE` bit) there will be **no** physical transaction on the `uart0_txd_o` signal.
|
||||
Instead, all data written to the `DATA` register is immediately dumped to a file. Data written to `DATA[7:0]` will be dumped as
|
||||
ASCII chars to a file named `neorv32.uart0.sim_mode.text.out`. Additionally, the ASCII data is printed to the simulator console.
|
||||
ASCII chars to a file named `neorv32.uart0_sim_mode.out`. Additionally, the ASCII data is printed to the simulator console.
|
||||
|
||||
Both file are created in the simulation's home folder.
|
||||
|
||||
|
@ -151,7 +151,7 @@ Both file are created in the simulation's home folder.
|
|||
<|`31` `UART_CTRL_TX_BUSY` ^| r/- <| TX busy or TX FIFO not empty
|
||||
.4+<| `0xfffff504` .4+<| `DATA` <|`7:0` `UART_DATA_RTX_MSB : UART_DATA_RTX_LSB` ^| r/w <| receive/transmit data
|
||||
<|`11:8` `UART_DATA_RX_FIFO_SIZE_MSB : UART_DATA_RX_FIFO_SIZE_LSB` ^| r/- <| log2(RX FIFO size)
|
||||
<|`15:12` `UART_DATA_TX_FIFO_SIZE_MSB : UART_DATA_TX_FIFO_SIZE_LSB` ^| r/- <| log2(RX FIFO size)
|
||||
<|`15:12` `UART_DATA_TX_FIFO_SIZE_MSB : UART_DATA_TX_FIFO_SIZE_LSB` ^| r/- <| log2(TX FIFO size)
|
||||
<|`31:16` ^| r/- <| _reserved_, read as zero
|
||||
|=======================
|
||||
|
||||
|
@ -192,7 +192,7 @@ as for the primary UART. The RX and TX interrupts of UART1 are mapped to differe
|
|||
**Simulation Mode**
|
||||
|
||||
The secondary UART (UART1) provides the same simulation options as the primary UART (UART0). However, output data is
|
||||
written to UART1-specific file `neorv32.uart1.sim_mode.text.out`. This data is also printed to the simulator console.
|
||||
written to UART1-specific file `neorv32.uart1_sim_mode.out`. This data is also printed to the simulator console.
|
||||
|
||||
|
||||
**Register Map**
|
||||
|
|
|
@ -220,7 +220,7 @@ Variables:
|
|||
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-"
|
||||
RISCV_PREFIX - Toolchain prefix: "riscv-none-elf-"
|
||||
NEORV32_HOME - NEORV32 home folder: "../../.."
|
||||
GDB_ARGS - GDB (connection) arguments: "-ex target extended-remote localhost:3333"
|
||||
GHDL_RUN_FLAGS - GHDL simulation run arguments: ""
|
||||
|
@ -407,7 +407,7 @@ The `crt0.S` start-up performs the following operations:
|
|||
|
||||
|
||||
:sectnums:
|
||||
===== Early Trap Handler
|
||||
==== 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.
|
||||
|
@ -429,8 +429,8 @@ by a flag when calling the generator.
|
|||
[grid="none"]
|
||||
|=======================
|
||||
| `-app_bin` | Generates an executable binary file (including a bootloader header) for upload via the bootloader.
|
||||
| `-app_img` | Generates an executable VHDL memory initialization image for the processor-internal IMEM.
|
||||
| `-bld_img` | Generates an executable VHDL memory initialization image for the processor-internal BOOT ROM.
|
||||
| `-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.
|
||||
|
|
|
@ -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 |
|
@ -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.
|
||||
|
|
|
@ -2,85 +2,71 @@
|
|||
:sectnums:
|
||||
== Software Toolchain Setup
|
||||
|
||||
To compile (and debug) executables for the NEORV32 a RISC-V toolchain is required.
|
||||
There are two possibilities to get this:
|
||||
To compile (and debug) executables for the NEORV32 a RISC-V-compatible toolchain is required.
|
||||
By default, the project's software framework uses the GNU C Compiler RISC-V port "RISC-V GCC".
|
||||
Basically, there are two options to obtain such a toolchain:
|
||||
|
||||
1. Download and _build_ the official RISC-V GNU toolchain yourself.
|
||||
2. Download and install a prebuilt version of the toolchain; this might also done via the package manager / app store of your OS
|
||||
1. Download and _build_ the RISC-V GNU toolchain by yourself.
|
||||
2. Download and _install_ a **prebuilt** version of the toolchain.
|
||||
|
||||
.Default GCC Prefix
|
||||
[NOTE]
|
||||
The default toolchain prefix (`RISCV_PREFIX` variable) for this project is **`riscv32-unknown-elf-`**. Of course you can use any other RISC-V
|
||||
toolchain (like `riscv64-unknown-elf-`) that is capable to emit code for a `rv32` architecture. Just change `RISCV_PREFIX`
|
||||
according to your needs.
|
||||
The default toolchain prefix for this project is **`riscv-none-elf-`** (`RISCV_PREFIX` variable).
|
||||
|
||||
|
||||
:sectnums:
|
||||
=== Building the Toolchain from Scratch
|
||||
**Toolchain Requirements**
|
||||
|
||||
To build the toolchain by yourself you can follow the guide from the official https://github.com/riscv-collab/riscv-gnu-toolchain GitHub page.
|
||||
You need to make sure the generated toolchain fits the architecture of the NEORV32 core. To get a toolchain that even supports minimal
|
||||
ISA extension configurations, it is recommend to compile for `rv32i` only. Please note that this minimal ISA also provides further ISA
|
||||
extensions like `m` or `c`. Of course you can use a _multilib_ approach to generate toolchains for several target ISAs at once.
|
||||
[start=1]
|
||||
.The toolchain must be able to emit code for a 32-bit architecture (i.e. `mabi=rv32`).
|
||||
.A "bare metal" / stand-alone C standard library should be used (i.e. the no-Linux version; for example "Newlib").
|
||||
|
||||
.Preparing GCC build for `rv32i` (minimal ISA)
|
||||
.Library/ISA Considerations
|
||||
[IMPORTANT]
|
||||
Note that a toolchain build with `--with-arch=rv32imc` provides library code (like the C standard library)
|
||||
compiled entirely using compressed (`C`) and `mul`/`div` instructions (`M`). Hence, this pre-compiled library
|
||||
code CANNOT be executed (without emulation) on an architecture that does not support these ISA extensions.
|
||||
|
||||
|
||||
**Building the Toolchain from Scratch**
|
||||
|
||||
The official RISC-V GCC GitHub repository (https://github.com/riscv-collab/riscv-gnu-toolchain) provides instructions
|
||||
for building the toolchain from scratch:
|
||||
|
||||
.Preparing GCC build for `rv32i` (minimal ISA only in this example)
|
||||
[source,bash]
|
||||
----
|
||||
$ git clone https://github.com/riscv/riscv-gnu-toolchain
|
||||
$ cd riscv-gnu-toolchain
|
||||
|
||||
$ riscv-gnu-toolchain$ ./configure --prefix=/opt/riscv --with-arch=rv32i --with-abi=ilp32
|
||||
$ riscv-gnu-toolchain$ make
|
||||
----
|
||||
|
||||
[IMPORTANT]
|
||||
Keep in mind that - for instance - a toolchain build with `--with-arch=rv32imc` provides library code (like the C
|
||||
standard library) compiled entirely utilizing compressed (`C`) and `mul`/`div` instructions (`M`). Hence, this
|
||||
code CANNOT be executed (without emulation) on an architecture that does not support these ISA extensions.
|
||||
|
||||
**Downloading and Installing a Prebuilt Toolchain**
|
||||
|
||||
Alternatively, a prebuilt toolchain can be used. Some OS package managers provide embedded RISC-V GCC toolchain.
|
||||
However, I can highly recommend the toolchain provided by the X-Pack project (MIT license):
|
||||
https://github.com/xpack-dev-tools/riscv-none-elf-gcc-xpack
|
||||
|
||||
|
||||
:sectnums:
|
||||
=== Downloading and Installing a Prebuilt Toolchain
|
||||
**Toolchain Installation**
|
||||
|
||||
Alternatively, you can download a prebuilt toolchain.
|
||||
|
||||
:sectnums:
|
||||
==== Use The Pre-Built Toolchains
|
||||
|
||||
We have compiled several GCC toolchains on a 64-bit x86 Ubuntu (Ubuntu on Windows, actually) and uploaded it to
|
||||
GitHub. You can directly download the according toolchain archive as single _zip-file_ within a packed
|
||||
release from https://github.com/stnolting/riscv-gcc-prebuilt. More information about downloading and installing
|
||||
these prebuilt toolchains can be found in the repository's README.
|
||||
|
||||
|
||||
:sectnums:
|
||||
==== Use a Third Party Toolchain
|
||||
|
||||
Of course you can also use any other prebuilt version of the toolchain. There are a lot RISC-V GCC packages out there -
|
||||
even for Windows. On Linux system you might even be able to fetch a toolchain via your distribution's package manager.
|
||||
|
||||
[IMPORTANT]
|
||||
Make sure the toolchain can (also) emit code for a `rv32i` architecture, uses the `ilp32` or `ilp32e` ABI and **was not build** using
|
||||
CPU extensions that are not supported by the NEORV32 (like `D`).
|
||||
|
||||
|
||||
:sectnums:
|
||||
=== Installation
|
||||
|
||||
Now you have the toolchain binaries. The last step is to add them to your `PATH` environment variable (if you have not
|
||||
already done so): make sure to add the _binaries_ folder (`bin`) of your toolchain.
|
||||
To integrate the toolchain of choice into the NEORV32 software framework, the toolchain's binaries need
|
||||
to be added to the system path (e.g. `PATH` environment variable) so they can be used by a shell. Therefore,
|
||||
the absolute path to the toolchain's `bin` folder has to be appended to the `PATH` variable:
|
||||
|
||||
[source,bash]
|
||||
----
|
||||
$ export PATH=$PATH:/opt/riscv/bin
|
||||
----
|
||||
|
||||
You should add this command to your `.bashrc` (if you are using bash) to automatically add the RISC-V
|
||||
.bashrc
|
||||
[TIP]
|
||||
This command can be added to `.bashrc` (or similar) to automatically add the RISC-V
|
||||
toolchain at every console start.
|
||||
|
||||
:sectnums:
|
||||
=== Testing the Installation
|
||||
|
||||
To make sure everything works fine, navigate to an example project in the NEORV32 example folder and
|
||||
To make sure everything works fine, navigate to an example project in the NEORV32 `sw/example` folder and
|
||||
execute the following command:
|
||||
|
||||
[source,bash]
|
||||
|
@ -89,4 +75,4 @@ neorv32/sw/example/demo_blink_led$ make check
|
|||
----
|
||||
|
||||
This will test all the tools required for generating NEORV32 executables.
|
||||
Everything is working fine if `Toolchain check OK` appears at the end.
|
||||
Everything is working fine if "Toolchain check OK" appears at the end of the log output.
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
:sectnums:
|
||||
== Zephyr RTOS Support
|
||||
|
||||
The NEORV32 processor is supported by upstream Zephyr RTOS: https://docs.zephyrproject.org/latest/boards/riscv/neorv32/doc/index.html
|
||||
The NEORV32 processor is supported by upstream Zephyr RTOS: https://docs.zephyrproject.org/latest/boards/others/neorv32/doc/index.html
|
||||
|
||||
[IMPORTANT]
|
||||
The absolute path to the NEORV32 executable image generator binary (`.../neorv32/sw/image_gen`) has to be added to the `PATH` variable
|
||||
|
|
|
@ -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');
|
||||
|
@ -417,38 +417,38 @@ entity neorv32_bus_io_switch is
|
|||
main_req_i : in bus_req_t; -- host request
|
||||
main_rsp_o : out bus_rsp_t; -- host response
|
||||
-- device ports --
|
||||
dev_00_req_o : out bus_req_t; dev_00_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_01_req_o : out bus_req_t; dev_01_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_02_req_o : out bus_req_t; dev_02_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_03_req_o : out bus_req_t; dev_03_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_04_req_o : out bus_req_t; dev_04_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_05_req_o : out bus_req_t; dev_05_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_06_req_o : out bus_req_t; dev_06_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_07_req_o : out bus_req_t; dev_07_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_08_req_o : out bus_req_t; dev_08_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_09_req_o : out bus_req_t; dev_09_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_10_req_o : out bus_req_t; dev_10_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_11_req_o : out bus_req_t; dev_11_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_12_req_o : out bus_req_t; dev_12_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_13_req_o : out bus_req_t; dev_13_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_14_req_o : out bus_req_t; dev_14_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_15_req_o : out bus_req_t; dev_15_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_16_req_o : out bus_req_t; dev_16_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_17_req_o : out bus_req_t; dev_17_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_18_req_o : out bus_req_t; dev_18_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_19_req_o : out bus_req_t; dev_19_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_20_req_o : out bus_req_t; dev_20_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_21_req_o : out bus_req_t; dev_21_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_22_req_o : out bus_req_t; dev_22_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_23_req_o : out bus_req_t; dev_23_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_24_req_o : out bus_req_t; dev_24_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_25_req_o : out bus_req_t; dev_25_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_26_req_o : out bus_req_t; dev_26_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_27_req_o : out bus_req_t; dev_27_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_28_req_o : out bus_req_t; dev_28_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_29_req_o : out bus_req_t; dev_29_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_30_req_o : out bus_req_t; dev_30_rsp_i : in bus_rsp_t := rsp_terminate_c;
|
||||
dev_31_req_o : out bus_req_t; dev_31_rsp_i : in bus_rsp_t := rsp_terminate_c
|
||||
dev_00_req_o : out bus_req_t; dev_00_rsp_i : in bus_rsp_t;
|
||||
dev_01_req_o : out bus_req_t; dev_01_rsp_i : in bus_rsp_t;
|
||||
dev_02_req_o : out bus_req_t; dev_02_rsp_i : in bus_rsp_t;
|
||||
dev_03_req_o : out bus_req_t; dev_03_rsp_i : in bus_rsp_t;
|
||||
dev_04_req_o : out bus_req_t; dev_04_rsp_i : in bus_rsp_t;
|
||||
dev_05_req_o : out bus_req_t; dev_05_rsp_i : in bus_rsp_t;
|
||||
dev_06_req_o : out bus_req_t; dev_06_rsp_i : in bus_rsp_t;
|
||||
dev_07_req_o : out bus_req_t; dev_07_rsp_i : in bus_rsp_t;
|
||||
dev_08_req_o : out bus_req_t; dev_08_rsp_i : in bus_rsp_t;
|
||||
dev_09_req_o : out bus_req_t; dev_09_rsp_i : in bus_rsp_t;
|
||||
dev_10_req_o : out bus_req_t; dev_10_rsp_i : in bus_rsp_t;
|
||||
dev_11_req_o : out bus_req_t; dev_11_rsp_i : in bus_rsp_t;
|
||||
dev_12_req_o : out bus_req_t; dev_12_rsp_i : in bus_rsp_t;
|
||||
dev_13_req_o : out bus_req_t; dev_13_rsp_i : in bus_rsp_t;
|
||||
dev_14_req_o : out bus_req_t; dev_14_rsp_i : in bus_rsp_t;
|
||||
dev_15_req_o : out bus_req_t; dev_15_rsp_i : in bus_rsp_t;
|
||||
dev_16_req_o : out bus_req_t; dev_16_rsp_i : in bus_rsp_t;
|
||||
dev_17_req_o : out bus_req_t; dev_17_rsp_i : in bus_rsp_t;
|
||||
dev_18_req_o : out bus_req_t; dev_18_rsp_i : in bus_rsp_t;
|
||||
dev_19_req_o : out bus_req_t; dev_19_rsp_i : in bus_rsp_t;
|
||||
dev_20_req_o : out bus_req_t; dev_20_rsp_i : in bus_rsp_t;
|
||||
dev_21_req_o : out bus_req_t; dev_21_rsp_i : in bus_rsp_t;
|
||||
dev_22_req_o : out bus_req_t; dev_22_rsp_i : in bus_rsp_t;
|
||||
dev_23_req_o : out bus_req_t; dev_23_rsp_i : in bus_rsp_t;
|
||||
dev_24_req_o : out bus_req_t; dev_24_rsp_i : in bus_rsp_t;
|
||||
dev_25_req_o : out bus_req_t; dev_25_rsp_i : in bus_rsp_t;
|
||||
dev_26_req_o : out bus_req_t; dev_26_rsp_i : in bus_rsp_t;
|
||||
dev_27_req_o : out bus_req_t; dev_27_rsp_i : in bus_rsp_t;
|
||||
dev_28_req_o : out bus_req_t; dev_28_rsp_i : in bus_rsp_t;
|
||||
dev_29_req_o : out bus_req_t; dev_29_rsp_i : in bus_rsp_t;
|
||||
dev_30_req_o : out bus_req_t; dev_30_rsp_i : in bus_rsp_t;
|
||||
dev_31_req_o : out bus_req_t; dev_31_rsp_i : in bus_rsp_t
|
||||
);
|
||||
end neorv32_bus_io_switch;
|
||||
|
||||
|
|
|
@ -30,12 +30,12 @@ entity neorv32_cfs is
|
|||
clk_i : in std_ulogic; -- global clock line
|
||||
rstn_i : in std_ulogic; -- global reset line, low-active, use as async
|
||||
bus_req_i : in bus_req_t; -- bus request
|
||||
bus_rsp_o : out bus_rsp_t := rsp_terminate_c; -- bus response
|
||||
clkgen_en_o : out std_ulogic := '0'; -- enable clock generator
|
||||
bus_rsp_o : out bus_rsp_t; -- bus response
|
||||
clkgen_en_o : out std_ulogic; -- enable clock generator
|
||||
clkgen_i : in std_ulogic_vector(7 downto 0); -- "clock" inputs
|
||||
irq_o : out std_ulogic := '0'; -- interrupt request
|
||||
irq_o : out std_ulogic; -- interrupt request
|
||||
cfs_in_i : in std_ulogic_vector(CFS_IN_SIZE-1 downto 0); -- custom inputs
|
||||
cfs_out_o : out std_ulogic_vector(CFS_OUT_SIZE-1 downto 0) := (others => '0') -- custom outputs
|
||||
cfs_out_o : out std_ulogic_vector(CFS_OUT_SIZE-1 downto 0) -- custom outputs
|
||||
);
|
||||
end neorv32_cfs;
|
||||
|
||||
|
|
|
@ -123,7 +123,7 @@ architecture neorv32_cpu_rtl of neorv32_cpu is
|
|||
signal lsu_err : std_ulogic_vector(3 downto 0); -- lsu alignment/access errors
|
||||
signal pc_fetch : std_ulogic_vector(XLEN-1 downto 0); -- pc for instruction fetch
|
||||
signal pc_curr : std_ulogic_vector(XLEN-1 downto 0); -- current pc (for currently executed instruction)
|
||||
signal pc_next : std_ulogic_vector(XLEN-1 downto 0); -- next pc (return address)
|
||||
signal pc_ret : std_ulogic_vector(XLEN-1 downto 0); -- return address
|
||||
signal pmp_ex_fault : std_ulogic; -- pmp instruction fetch fault
|
||||
signal pmp_rw_fault : std_ulogic; -- pmp read/write access fault
|
||||
signal irq_machine : std_ulogic_vector(2 downto 0); -- risc-v standard machine-level interrupts
|
||||
|
@ -245,7 +245,7 @@ begin
|
|||
rf_rs1_i => rs1, -- rf source 1
|
||||
pc_fetch_o => pc_fetch, -- instruction fetch address
|
||||
pc_curr_o => pc_curr, -- current PC (corresponding to current instruction)
|
||||
pc_next_o => pc_next, -- next PC (return address)
|
||||
pc_ret_o => pc_ret, -- return address
|
||||
csr_rdata_o => csr_rdata, -- CSR read data
|
||||
-- external CSR interface --
|
||||
xcsr_we_o => xcsr_we, -- global write enable
|
||||
|
@ -294,7 +294,7 @@ begin
|
|||
);
|
||||
|
||||
-- all buses are zero unless there is an according operation --
|
||||
rf_wdata <= alu_res or lsu_rdata or csr_rdata or pc_next;
|
||||
rf_wdata <= alu_res or lsu_rdata or csr_rdata or pc_ret;
|
||||
|
||||
|
||||
-- ALU (Arithmetic/Logic Unit) and ALU Co-Processors --------------------------------------
|
||||
|
|
|
@ -90,7 +90,7 @@ entity neorv32_cpu_control is
|
|||
rf_rs1_i : in std_ulogic_vector(XLEN-1 downto 0); -- rf source 1
|
||||
pc_fetch_o : out std_ulogic_vector(XLEN-1 downto 0); -- instruction fetch address
|
||||
pc_curr_o : out std_ulogic_vector(XLEN-1 downto 0); -- current PC (corresponding to current instruction)
|
||||
pc_next_o : out std_ulogic_vector(XLEN-1 downto 0); -- next PC (return address)
|
||||
pc_ret_o : out std_ulogic_vector(XLEN-1 downto 0); -- return address
|
||||
csr_rdata_o : out std_ulogic_vector(XLEN-1 downto 0); -- CSR read data
|
||||
-- external CSR interface --
|
||||
xcsr_we_o : out std_ulogic; -- global write enable
|
||||
|
@ -150,31 +150,26 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is
|
|||
signal issue_engine : issue_engine_t;
|
||||
|
||||
-- instruction execution engine --
|
||||
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_state_t is (DISPATCH, TRAP_ENTER, TRAP_EXIT, RESTART, SLEEP, EXECUTE, ALU_WAIT, BRANCH, BRANCHED, SYSTEM, MEM_REQ, MEM_RSP);
|
||||
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
|
||||
is_ci_nxt : std_ulogic;
|
||||
branch_taken : std_ulogic; -- branch condition fulfilled
|
||||
pc : std_ulogic_vector(XLEN-1 downto 0); -- actual PC, corresponding to current executed instruction
|
||||
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
|
||||
state : exe_engine_state_t;
|
||||
ir : std_ulogic_vector(31 downto 0); -- instruction word being executed right now
|
||||
ci : std_ulogic; -- current instruction is de-compressed instruction
|
||||
pc : std_ulogic_vector(XLEN-1 downto 0); -- current PC (current instruction)
|
||||
pc2 : std_ulogic_vector(XLEN-1 downto 0); -- next PC (next linear instruction)
|
||||
ra : std_ulogic_vector(XLEN-1 downto 0); -- return address
|
||||
end record;
|
||||
signal exe_engine : exe_engine_t;
|
||||
signal exe_engine, exe_engine_nxt : exe_engine_t;
|
||||
|
||||
-- taken branch --
|
||||
signal branch_taken : std_ulogic;
|
||||
|
||||
-- simplified opcode (2 LSBs hardwired to "11" to indicate rv32) --
|
||||
signal opcode : std_ulogic_vector(6 downto 0);
|
||||
|
||||
-- execution monitor --
|
||||
type monitor_t is record
|
||||
cnt, cnt_add : std_ulogic_vector(monitor_mc_tmo_c downto 0);
|
||||
exc : std_ulogic;
|
||||
end record;
|
||||
signal monitor : monitor_t;
|
||||
signal monitor_cnt, monitor_add : std_ulogic_vector(monitor_mc_tmo_c downto 0);
|
||||
signal monitor_exc : std_ulogic;
|
||||
|
||||
-- CPU sleep-mode --
|
||||
signal sleep_mode : std_ulogic;
|
||||
|
@ -211,8 +206,8 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is
|
|||
type csr_t is record
|
||||
addr : std_ulogic_vector(11 downto 0); -- physical access address
|
||||
we, we_nxt : std_ulogic; -- write enable
|
||||
re, re_nxt : std_ulogic; -- read enable
|
||||
wdata, rdata : std_ulogic_vector(XLEN-1 downto 0); -- read/write data
|
||||
wdata : std_ulogic_vector(XLEN-1 downto 0); -- write data
|
||||
rdata : std_ulogic_vector(XLEN-1 downto 0); -- read data
|
||||
--
|
||||
mstatus_mie : std_ulogic; -- machine-mode IRQ enable
|
||||
mstatus_mpie : std_ulogic; -- previous machine-mode IRQ enable
|
||||
|
@ -292,7 +287,7 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is
|
|||
signal illegal_cmd : std_ulogic;
|
||||
|
||||
-- CSR access existence/read-write/privilege check --
|
||||
signal csr_valid : std_ulogic_vector(2 downto 0); -- 2: implemented, 1: r/w access, 0: privilege
|
||||
signal csr_valid : std_ulogic_vector(2 downto 0); -- [2]: implemented, [1]: r/w access, [0]: privilege
|
||||
|
||||
-- hardware trigger module --
|
||||
signal hw_trigger_match, hw_trigger_fired : std_ulogic;
|
||||
|
@ -345,7 +340,7 @@ begin
|
|||
|
||||
when others => -- IF_RESTART: set new start address
|
||||
-- ------------------------------------------------------------
|
||||
fetch_engine.pc <= exe_engine.next_pc(XLEN-1 downto 1) & '0'; -- initialize from PC incl. 16-bit-alignment bit
|
||||
fetch_engine.pc <= exe_engine.pc2(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;
|
||||
|
||||
|
@ -413,7 +408,7 @@ begin
|
|||
|
||||
|
||||
-- ****************************************************************************************************************************
|
||||
-- Instruction Issue (decompress 16-bit instructions and assemble a 32-bit instruction word)
|
||||
-- Instruction Issue (decompress 16-bit instruction and/or assemble a 32-bit instruction word)
|
||||
-- ****************************************************************************************************************************
|
||||
|
||||
issue_engine_enabled:
|
||||
|
@ -427,7 +422,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 <= exe_engine.next_pc(1); -- branch to unaligned address?
|
||||
issue_engine.align <= exe_engine.pc2(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 +501,7 @@ begin
|
|||
if (rstn_i = '0') then
|
||||
alu_imm_o <= (others => '0');
|
||||
elsif rising_edge(clk_i) then
|
||||
if (exe_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,7 +509,6 @@ begin
|
|||
alu_imm_o(3 downto 0) <= x"4";
|
||||
end if;
|
||||
else
|
||||
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(exe_engine.ir(31), 21) & exe_engine.ir(30 downto 25) & exe_engine.ir(11 downto 7);
|
||||
|
@ -525,9 +519,9 @@ begin
|
|||
when opcode_jal_c => -- J-immediate
|
||||
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 =>
|
||||
NULL; -- use default
|
||||
alu_imm_o <= (others => '0');
|
||||
when others => -- I-immediate
|
||||
alu_imm_o <= replicate_f(exe_engine.ir(31), 21) & exe_engine.ir(30 downto 21) & exe_engine.ir(20);
|
||||
end case;
|
||||
end if;
|
||||
end if;
|
||||
|
@ -540,12 +534,12 @@ begin
|
|||
begin
|
||||
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);
|
||||
branch_taken <= alu_cmp_i(cmp_equal_c) xor exe_engine.ir(instr_funct3_lsb_c);
|
||||
else -- blt(u) / bge(u)
|
||||
exe_engine.branch_taken <= alu_cmp_i(cmp_less_c) xor exe_engine.ir(instr_funct3_lsb_c);
|
||||
branch_taken <= alu_cmp_i(cmp_less_c) xor exe_engine.ir(instr_funct3_lsb_c);
|
||||
end if;
|
||||
else -- unconditional branch
|
||||
exe_engine.branch_taken <= '1';
|
||||
branch_taken <= '1';
|
||||
end if;
|
||||
end process branch_check;
|
||||
|
||||
|
@ -555,79 +549,22 @@ begin
|
|||
execute_engine_fsm_sync: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
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');
|
||||
ctrl <= ctrl_bus_zero_c;
|
||||
exe_engine.state <= RESTART;
|
||||
exe_engine.ir <= (others => '0');
|
||||
exe_engine.ci <= '0';
|
||||
exe_engine.pc <= BOOT_ADDR(XLEN-1 downto 2) & "00"; -- 32-bit-aligned boot address
|
||||
exe_engine.pc2 <= BOOT_ADDR(XLEN-1 downto 2) & "00"; -- 32-bit-aligned boot address
|
||||
exe_engine.ra <= (others => '0');
|
||||
elsif rising_edge(clk_i) then
|
||||
-- control bus --
|
||||
ctrl <= ctrl_nxt;
|
||||
|
||||
-- execute engine arbiter --
|
||||
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 (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 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
|
||||
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
|
||||
exe_engine.next_pc <= csr.mtvec(XLEN-1 downto 7) & trap_ctrl.cause(4 downto 0) & "00"; -- pc = mtvec + 4 * mcause
|
||||
else
|
||||
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.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
|
||||
exe_engine.next_pc <= csr.mepc(XLEN-1 downto 1) & '0';
|
||||
end if;
|
||||
|
||||
when BRANCH => -- branch instruction
|
||||
-- ------------------------------------------------------------
|
||||
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))
|
||||
-- ------------------------------------------------------------
|
||||
exe_engine.next_pc <= alu_add_i(XLEN-1 downto 1) & '0';
|
||||
|
||||
when others => -- no update
|
||||
-- ------------------------------------------------------------
|
||||
NULL;
|
||||
|
||||
end case;
|
||||
ctrl <= ctrl_nxt;
|
||||
exe_engine <= exe_engine_nxt;
|
||||
end if;
|
||||
end process execute_engine_fsm_sync;
|
||||
|
||||
-- check if branch destination is misaligned --
|
||||
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 <= exe_engine.pc(XLEN-1 downto 1) & '0';
|
||||
-- PC output --
|
||||
pc_curr_o <= exe_engine.pc(XLEN-1 downto 1) & '0'; -- address of current instruction
|
||||
pc_ret_o <= exe_engine.ra(XLEN-1 downto 1) & '0'; -- return address
|
||||
|
||||
-- simplified rv32 opcode --
|
||||
opcode <= exe_engine.ir(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11";
|
||||
|
@ -635,7 +572,7 @@ begin
|
|||
|
||||
-- Execute Engine FSM Comb ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
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)
|
||||
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, alu_add_i, branch_taken)
|
||||
variable funct3_v : std_ulogic_vector(2 downto 0);
|
||||
variable funct7_v : std_ulogic_vector(6 downto 0);
|
||||
begin
|
||||
|
@ -644,20 +581,22 @@ begin
|
|||
funct7_v := exe_engine.ir(instr_funct7_msb_c downto instr_funct7_lsb_c);
|
||||
|
||||
-- arbiter defaults --
|
||||
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';
|
||||
exe_engine_nxt.state <= exe_engine.state;
|
||||
exe_engine_nxt.ir <= exe_engine.ir;
|
||||
exe_engine_nxt.ci <= exe_engine.ci;
|
||||
exe_engine_nxt.pc <= exe_engine.pc;
|
||||
exe_engine_nxt.pc2 <= exe_engine.pc2;
|
||||
exe_engine_nxt.ra <= (others => '0'); -- output zero if not a branch instruction
|
||||
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.instr_ma <= '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 --
|
||||
|
@ -695,45 +634,65 @@ begin
|
|||
|
||||
when DISPATCH => -- wait for ISSUE ENGINE to emit a valid instruction word
|
||||
-- ------------------------------------------------------------
|
||||
ctrl_nxt.alu_opa_mux <= '1'; -- prepare update of next_pc in EXECUTE (opa = current_pc)
|
||||
ctrl_nxt.alu_opb_mux <= '1'; -- prepare update of next_pc in EXECUTE (opb = imm = +2/4)
|
||||
ctrl_nxt.alu_opa_mux <= '1'; -- prepare update of next PC in EXECUTE (opa = current PC)
|
||||
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)
|
||||
exe_engine.state_nxt <= TRAP_ENTER;
|
||||
exe_engine_nxt.state <= TRAP_ENTER;
|
||||
elsif RISCV_ISA_Sdtrig and (hw_trigger_match = '1') then -- hardware breakpoint
|
||||
exe_engine.pc_we <= '1'; -- pc <= next_pc; intercept BEFORE executing the instruction
|
||||
exe_engine_nxt.pc <= exe_engine.pc2(XLEN-1 downto 1) & '0'; -- 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
|
||||
exe_engine_nxt.state <= 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
|
||||
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;
|
||||
exe_engine_nxt.ci <= issue_engine.data(33); -- this is a de-compressed instruction
|
||||
exe_engine_nxt.ir <= issue_engine.data(31 downto 0); -- instruction word
|
||||
exe_engine_nxt.pc <= exe_engine.pc2(XLEN-1 downto 1) & '0'; -- PC <= next PC
|
||||
exe_engine_nxt.state <= EXECUTE; -- start executing new instruction
|
||||
end if;
|
||||
|
||||
when TRAP_ENTER => -- enter trap environment and jump to trap vector
|
||||
-- ------------------------------------------------------------
|
||||
if (trap_ctrl.cause(5) = '1') and RISCV_ISA_Sdext then -- debug mode (re-)entry
|
||||
exe_engine_nxt.pc2 <= 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_nxt.pc2 <= 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
|
||||
exe_engine_nxt.pc2 <= csr.mtvec(XLEN-1 downto 7) & trap_ctrl.cause(4 downto 0) & "00"; -- PC = mtvec + 4 * mcause
|
||||
else
|
||||
exe_engine_nxt.pc2 <= csr.mtvec(XLEN-1 downto 2) & "00"; -- PC = mtvec
|
||||
end if;
|
||||
end if;
|
||||
--
|
||||
if (trap_ctrl.env_pending = '1') then -- wait for sync. exceptions to become pending
|
||||
trap_ctrl.env_enter <= '1';
|
||||
exe_engine.state_nxt <= RESTART;
|
||||
exe_engine_nxt.state <= RESTART; -- restart instruction fetch
|
||||
end if;
|
||||
|
||||
when TRAP_EXIT => -- return from trap environment and jump to trap PC
|
||||
-- ------------------------------------------------------------
|
||||
if (debug_ctrl.run = '1') and RISCV_ISA_Sdext then -- debug mode exit
|
||||
exe_engine_nxt.pc2 <= csr.dpc(XLEN-1 downto 1) & '0';
|
||||
else -- normal end of trap
|
||||
exe_engine_nxt.pc2 <= csr.mepc(XLEN-1 downto 1) & '0';
|
||||
end if;
|
||||
trap_ctrl.env_exit <= '1';
|
||||
exe_engine.state_nxt <= RESTART;
|
||||
exe_engine_nxt.state <= RESTART; -- restart instruction fetch
|
||||
|
||||
when RESTART => -- reset and restart instruction fetch at <next_pc>
|
||||
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';
|
||||
exe_engine.state_nxt <= BRANCHED;
|
||||
exe_engine_nxt.state <= BRANCHED; -- delay cycle to restart front-end
|
||||
|
||||
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
|
||||
-- ------------------------------------------------------------
|
||||
exe_engine_nxt.pc2 <= alu_add_i(XLEN-1 downto 1) & '0'; -- next PC (= PC + immediate)
|
||||
|
||||
-- decode instruction class/type --
|
||||
case opcode is
|
||||
|
||||
-- register/immediate ALU operation --
|
||||
|
@ -763,51 +722,50 @@ begin
|
|||
((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;
|
||||
exe_engine_nxt.state <= 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
|
||||
exe_engine.state_nxt <= ALU_WAIT;
|
||||
exe_engine_nxt.state <= 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)
|
||||
exe_engine.state_nxt <= DISPATCH;
|
||||
exe_engine_nxt.state <= 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)
|
||||
exe_engine.state_nxt <= DISPATCH;
|
||||
exe_engine_nxt.state <= DISPATCH;
|
||||
|
||||
-- memory access --
|
||||
when opcode_load_c | opcode_store_c | opcode_amo_c =>
|
||||
exe_engine.state_nxt <= MEM_REQ;
|
||||
exe_engine_nxt.state <= MEM_REQ;
|
||||
|
||||
-- branch / jump-and-link (with register) --
|
||||
when opcode_branch_c | opcode_jal_c | opcode_jalr_c =>
|
||||
exe_engine.state_nxt <= BRANCH;
|
||||
exe_engine_nxt.state <= 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
|
||||
exe_engine.state_nxt <= RESTART; -- reset instruction fetch + IPB (actually only required for fence.i)
|
||||
exe_engine_nxt.state <= 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
|
||||
exe_engine.state_nxt <= ALU_WAIT; -- will be aborted via monitor timeout if FPU is not implemented
|
||||
exe_engine_nxt.state <= 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
|
||||
exe_engine.state_nxt <= ALU_WAIT; -- will be aborted via monitor timeout if CFU is not implemented
|
||||
exe_engine_nxt.state <= 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';
|
||||
exe_engine.state_nxt <= SYSTEM;
|
||||
exe_engine_nxt.state <= SYSTEM;
|
||||
|
||||
end case; -- /EXECUTE
|
||||
|
||||
|
@ -816,31 +774,34 @@ 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)
|
||||
exe_engine.state_nxt <= DISPATCH;
|
||||
exe_engine_nxt.state <= DISPATCH;
|
||||
end if;
|
||||
|
||||
when BRANCH => -- update next_pc on taken branches and jumps
|
||||
when BRANCH => -- update next PC on taken branches and jumps
|
||||
-- ------------------------------------------------------------
|
||||
exe_engine_nxt.ra <= exe_engine.pc2(XLEN-1 downto 1) & '0'; -- output return address
|
||||
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 (exe_engine.branch_taken = '1') then -- valid taken branch
|
||||
if (trap_ctrl.exc_buf(exc_illegal_c) = '0') and (branch_taken = '1') then -- valid taken branch
|
||||
trap_ctrl.instr_ma <= alu_add_i(1) and bool_to_ulogic_f(not RISCV_ISA_C); -- branch destination is misaligned?
|
||||
fetch_engine.reset <= '1'; -- reset instruction fetch to restart at modified PC
|
||||
exe_engine.state_nxt <= BRANCHED; -- shortcut (faster than going to RESTART)
|
||||
exe_engine_nxt.pc2 <= alu_add_i(XLEN-1 downto 1) & '0';
|
||||
exe_engine_nxt.state <= BRANCHED; -- shortcut (faster than going to RESTART)
|
||||
else
|
||||
exe_engine.state_nxt <= DISPATCH;
|
||||
exe_engine_nxt.state <= DISPATCH;
|
||||
end if;
|
||||
|
||||
when BRANCHED => -- delay cycle to wait for reset of pipeline front-end (instruction fetch)
|
||||
-- ------------------------------------------------------------
|
||||
exe_engine.state_nxt <= DISPATCH;
|
||||
exe_engine_nxt.state <= 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;
|
||||
exe_engine.state_nxt <= MEM_WAIT;
|
||||
exe_engine_nxt.state <= MEM_RSP;
|
||||
|
||||
when MEM_WAIT => -- wait for bus transaction to finish
|
||||
when MEM_RSP => -- wait for memory response
|
||||
-- ------------------------------------------------------------
|
||||
if (lsu_wait_i = '0') or -- bus system has completed the transaction (if there was any)
|
||||
(trap_ctrl.exc_buf(exc_saccess_c) = '1') or (trap_ctrl.exc_buf(exc_laccess_c) = '1') or -- access exception
|
||||
|
@ -849,25 +810,25 @@ 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;
|
||||
exe_engine.state_nxt <= DISPATCH;
|
||||
exe_engine_nxt.state <= DISPATCH;
|
||||
end if;
|
||||
|
||||
when SLEEP => -- sleep mode
|
||||
-- ------------------------------------------------------------
|
||||
if (trap_ctrl.wakeup = '1') then
|
||||
exe_engine.state_nxt <= DISPATCH;
|
||||
exe_engine_nxt.state <= DISPATCH;
|
||||
end if;
|
||||
|
||||
when others => -- SYSTEM - CSR/ENVIRONMENT operation; no effect if illegal instruction
|
||||
-- ------------------------------------------------------------
|
||||
exe_engine.state_nxt <= DISPATCH; -- default
|
||||
exe_engine_nxt.state <= DISPATCH; -- default
|
||||
if (funct3_v = funct3_env_c) and (trap_ctrl.exc_buf(exc_illegal_c) = '0') then -- non-illegal ENVIRONMENT
|
||||
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
|
||||
when "010" => exe_engine_nxt.state <= TRAP_EXIT; -- xret
|
||||
when "101" => exe_engine_nxt.state <= SLEEP; -- wfi
|
||||
when others => exe_engine_nxt.state <= 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 --
|
||||
|
@ -925,17 +886,17 @@ begin
|
|||
multi_cycle_monitor: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
monitor.cnt <= (others => '0');
|
||||
monitor_cnt <= (others => '0');
|
||||
elsif rising_edge(clk_i) then
|
||||
monitor.cnt <= std_ulogic_vector(unsigned(monitor.cnt_add) + 1);
|
||||
monitor_cnt <= std_ulogic_vector(unsigned(monitor_add) + 1);
|
||||
end if;
|
||||
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 (exe_engine.state = ALU_WAIT) else (others => '0');
|
||||
monitor_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);
|
||||
monitor_exc <= monitor_cnt(monitor_cnt'left);
|
||||
|
||||
|
||||
-- CSR Access Check -----------------------------------------------------------------------
|
||||
|
@ -1119,7 +1080,7 @@ begin
|
|||
-- Illegal Operation Check ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
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
|
||||
((monitor_exc = '1') or (illegal_cmd = '1')) else '0'; -- instruction timeout or illegal instruction
|
||||
|
||||
|
||||
-- ****************************************************************************************************************************
|
||||
|
@ -1233,7 +1194,7 @@ begin
|
|||
if (trap_ctrl.exc_buf(exc_iaccess_c) = '1') then trap_ctrl.cause <= trap_iaf_c; -- instruction access fault
|
||||
elsif (trap_ctrl.exc_buf(exc_illegal_c) = '1') then trap_ctrl.cause <= trap_iil_c; -- illegal instruction
|
||||
elsif (trap_ctrl.exc_buf(exc_ialign_c) = '1') then trap_ctrl.cause <= trap_ima_c; -- instruction address misaligned
|
||||
elsif (trap_ctrl.exc_buf(exc_ecall_c) = '1') then trap_ctrl.cause <= trap_env_c(6 downto 2) & csr.privilege & csr.privilege; -- environment call (U/M)
|
||||
elsif (trap_ctrl.exc_buf(exc_ecall_c) = '1') then trap_ctrl.cause <= trap_env_c(6 downto 2) & replicate_f(csr.privilege, 2); -- environment call (U/M)
|
||||
elsif (trap_ctrl.exc_buf(exc_ebreak_c) = '1') then trap_ctrl.cause <= trap_brk_c; -- environment breakpoint
|
||||
elsif (trap_ctrl.exc_buf(exc_salign_c) = '1') then trap_ctrl.cause <= trap_sma_c; -- store address misaligned
|
||||
elsif (trap_ctrl.exc_buf(exc_lalign_c) = '1') then trap_ctrl.cause <= trap_lma_c; -- load address misaligned
|
||||
|
@ -1270,7 +1231,7 @@ begin
|
|||
end process trap_priority;
|
||||
|
||||
-- exception program counter: async. interrupt or sync. exception? --
|
||||
trap_ctrl.epc <= exe_engine.next_pc when (trap_ctrl.cause(trap_ctrl.cause'left) = '1') else exe_engine.pc;
|
||||
trap_ctrl.epc <= exe_engine.pc2 when (trap_ctrl.cause(trap_ctrl.cause'left) = '1') else exe_engine.pc;
|
||||
|
||||
|
||||
-- Trap Controller ------------------------------------------------------------------------
|
||||
|
@ -1410,7 +1371,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');
|
||||
|
@ -1437,115 +1398,126 @@ begin
|
|||
-- Software CSR access
|
||||
-- ********************************************************************************
|
||||
if (csr.we = '1') then
|
||||
case csr.addr is
|
||||
|
||||
-- --------------------------------------------------------------------
|
||||
-- machine trap setup
|
||||
-- --------------------------------------------------------------------
|
||||
when csr_mstatus_c => -- machine status register
|
||||
csr.mstatus_mie <= csr.wdata(3);
|
||||
csr.mstatus_mpie <= csr.wdata(7);
|
||||
if RISCV_ISA_U then
|
||||
csr.mstatus_mpp <= csr.wdata(11) or csr.wdata(12); -- everything /= U will fall back to M
|
||||
csr.mstatus_mprv <= csr.wdata(17);
|
||||
csr.mstatus_tw <= csr.wdata(21);
|
||||
end if;
|
||||
-- --------------------------------------------------------------------
|
||||
-- machine trap setup
|
||||
-- --------------------------------------------------------------------
|
||||
|
||||
when csr_mie_c => -- machine interrupt enable register
|
||||
csr.mie_msi <= csr.wdata(3);
|
||||
csr.mie_mti <= csr.wdata(7);
|
||||
csr.mie_mei <= csr.wdata(11);
|
||||
csr.mie_firq <= csr.wdata(31 downto 16);
|
||||
-- machine status register --
|
||||
if (csr.addr = csr_mstatus_c) then
|
||||
csr.mstatus_mie <= csr.wdata(3);
|
||||
csr.mstatus_mpie <= csr.wdata(7);
|
||||
if RISCV_ISA_U then
|
||||
csr.mstatus_mpp <= csr.wdata(11) or csr.wdata(12); -- everything /= U will fall back to M
|
||||
csr.mstatus_mprv <= csr.wdata(17);
|
||||
csr.mstatus_tw <= csr.wdata(21);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
when csr_mtvec_c => -- machine trap-handler base address
|
||||
csr.mtvec <= csr.wdata(XLEN-1 downto 2) & '0' & csr.wdata(0); -- base + mode (vectored/direct)
|
||||
-- machine interrupt enable register --
|
||||
if (csr.addr = csr_mie_c) then
|
||||
csr.mie_msi <= csr.wdata(3);
|
||||
csr.mie_mti <= csr.wdata(7);
|
||||
csr.mie_mei <= csr.wdata(11);
|
||||
csr.mie_firq <= csr.wdata(31 downto 16);
|
||||
end if;
|
||||
|
||||
when csr_mcounteren_c => -- machine counter access enable
|
||||
if RISCV_ISA_U and RISCV_ISA_Zicntr then
|
||||
csr.mcounteren_cy <= csr.wdata(0);
|
||||
csr.mcounteren_ir <= csr.wdata(2);
|
||||
end if;
|
||||
-- machine trap-handler base address --
|
||||
if (csr.addr = csr_mtvec_c) then
|
||||
csr.mtvec <= csr.wdata(XLEN-1 downto 2) & '0' & csr.wdata(0); -- base + mode (vectored/direct)
|
||||
end if;
|
||||
|
||||
-- --------------------------------------------------------------------
|
||||
-- machine trap handling
|
||||
-- --------------------------------------------------------------------
|
||||
when csr_mscratch_c => -- machine scratch register
|
||||
csr.mscratch <= csr.wdata;
|
||||
-- machine counter access enable --
|
||||
if (csr.addr = csr_mcounteren_c) and RISCV_ISA_U and RISCV_ISA_Zicntr then
|
||||
csr.mcounteren_cy <= csr.wdata(0);
|
||||
csr.mcounteren_ir <= csr.wdata(2);
|
||||
end if;
|
||||
|
||||
when csr_mepc_c => -- machine exception program counter
|
||||
csr.mepc <= csr.wdata(XLEN-1 downto 1) & '0';
|
||||
if not RISCV_ISA_C then -- RISC-V priv. spec.: MEPC[1] is masked when IALIGN = 32
|
||||
csr.mepc(1) <= '0';
|
||||
end if;
|
||||
-- --------------------------------------------------------------------
|
||||
-- machine trap handling
|
||||
-- --------------------------------------------------------------------
|
||||
|
||||
when csr_mcause_c => -- machine trap cause
|
||||
csr.mcause <= csr.wdata(31) & csr.wdata(4 downto 0); -- type (exception/interrupt) & identifier
|
||||
-- machine scratch register --
|
||||
if (csr.addr = csr_mscratch_c) then
|
||||
csr.mscratch <= csr.wdata;
|
||||
end if;
|
||||
|
||||
-- --------------------------------------------------------------------
|
||||
-- machine counter setup
|
||||
-- --------------------------------------------------------------------
|
||||
when csr_mcountinhibit_c => -- machine counter-inhibit register
|
||||
if RISCV_ISA_Zicntr then
|
||||
csr.mcountinhibit(0) <= csr.wdata(0);
|
||||
csr.mcountinhibit(2) <= csr.wdata(2);
|
||||
end if;
|
||||
if RISCV_ISA_Zihpm then
|
||||
csr.mcountinhibit(15 downto 3) <= csr.wdata(15 downto 3);
|
||||
end if;
|
||||
-- machine exception program counter --
|
||||
if (csr.addr = csr_mepc_c) then
|
||||
csr.mepc <= csr.wdata(XLEN-1 downto 1) & '0';
|
||||
if not RISCV_ISA_C then -- RISC-V priv. spec.: MEPC[1] is masked when IALIGN = 32
|
||||
csr.mepc(1) <= '0';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- --------------------------------------------------------------------
|
||||
-- debug mode CSRs
|
||||
-- --------------------------------------------------------------------
|
||||
when csr_dcsr_c => -- debug mode control and status register
|
||||
if RISCV_ISA_Sdext then
|
||||
csr.dcsr_ebreakm <= csr.wdata(15);
|
||||
csr.dcsr_step <= csr.wdata(2);
|
||||
if RISCV_ISA_U then
|
||||
csr.dcsr_ebreaku <= csr.wdata(12);
|
||||
csr.dcsr_prv <= csr.wdata(1) or csr.wdata(0); -- everything /= U will fall back to M
|
||||
end if;
|
||||
end if;
|
||||
-- machine trap cause --
|
||||
if (csr.addr = csr_mcause_c) then
|
||||
csr.mcause <= csr.wdata(31) & csr.wdata(4 downto 0); -- type (exception/interrupt) & identifier
|
||||
end if;
|
||||
|
||||
when csr_dpc_c => -- debug mode program counter
|
||||
if RISCV_ISA_Sdext then
|
||||
csr.dpc <= csr.wdata(XLEN-1 downto 1) & '0';
|
||||
if not RISCV_ISA_C then -- RISC-V priv. spec.: DPC[1] is masked when IALIGN = 32
|
||||
csr.dpc(1) <= '0';
|
||||
end if;
|
||||
end if;
|
||||
-- --------------------------------------------------------------------
|
||||
-- machine counter setup
|
||||
-- --------------------------------------------------------------------
|
||||
|
||||
when csr_dscratch0_c => -- debug mode scratch register 0
|
||||
if RISCV_ISA_Sdext then
|
||||
csr.dscratch0 <= csr.wdata;
|
||||
end if;
|
||||
-- machine counter-inhibit register --
|
||||
if (csr.addr = csr_mcountinhibit_c) then
|
||||
if RISCV_ISA_Zicntr then
|
||||
csr.mcountinhibit(0) <= csr.wdata(0);
|
||||
csr.mcountinhibit(2) <= csr.wdata(2);
|
||||
end if;
|
||||
if RISCV_ISA_Zihpm then
|
||||
csr.mcountinhibit(15 downto 3) <= csr.wdata(15 downto 3);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- --------------------------------------------------------------------
|
||||
-- trigger module CSRs
|
||||
-- --------------------------------------------------------------------
|
||||
when csr_tdata1_c => -- match control
|
||||
if RISCV_ISA_Sdtrig then
|
||||
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.run = '1') then -- writable from debug-mode only
|
||||
csr.tdata1_dmode <= csr.wdata(27);
|
||||
end if;
|
||||
end if;
|
||||
-- --------------------------------------------------------------------
|
||||
-- debug mode CSRs
|
||||
-- --------------------------------------------------------------------
|
||||
|
||||
when csr_tdata2_c => -- address compare
|
||||
if RISCV_ISA_Sdtrig then
|
||||
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;
|
||||
-- debug mode control and status register --
|
||||
if (csr.addr = csr_dcsr_c) and RISCV_ISA_Sdext then
|
||||
csr.dcsr_ebreakm <= csr.wdata(15);
|
||||
csr.dcsr_step <= csr.wdata(2);
|
||||
if RISCV_ISA_U then
|
||||
csr.dcsr_ebreaku <= csr.wdata(12);
|
||||
csr.dcsr_prv <= csr.wdata(1) or csr.wdata(0); -- everything /= U will fall back to M
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- --------------------------------------------------------------------
|
||||
-- not implemented (or implemented externally)
|
||||
-- --------------------------------------------------------------------
|
||||
when others => NULL;
|
||||
-- debug mode program counter --
|
||||
if (csr.addr = csr_dpc_c) and RISCV_ISA_Sdext then
|
||||
csr.dpc <= csr.wdata(XLEN-1 downto 1) & '0';
|
||||
if not RISCV_ISA_C then -- RISC-V priv. spec.: DPC[1] is masked when IALIGN = 32
|
||||
csr.dpc(1) <= '0';
|
||||
end if;
|
||||
end if;
|
||||
|
||||
end case;
|
||||
-- debug mode scratch register 0 --
|
||||
if (csr.addr = csr_dscratch0_c) and RISCV_ISA_Sdext then
|
||||
csr.dscratch0 <= csr.wdata;
|
||||
end if;
|
||||
|
||||
-- --------------------------------------------------------------------
|
||||
-- trigger module CSRs
|
||||
-- --------------------------------------------------------------------
|
||||
|
||||
-- match control --
|
||||
if (csr.addr = csr_tdata1_c) and RISCV_ISA_Sdtrig then
|
||||
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.run = '1') then -- writable from debug-mode only
|
||||
csr.tdata1_dmode <= csr.wdata(27);
|
||||
end if;
|
||||
end if;
|
||||
|
||||
-- address compare --
|
||||
if (csr.addr = csr_tdata2_c) and RISCV_ISA_Sdtrig then
|
||||
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;
|
||||
|
||||
-- ********************************************************************************
|
||||
-- Hardware CSR access: TRAP ENTER
|
||||
|
@ -1565,7 +1537,7 @@ begin
|
|||
-- trap instruction --
|
||||
if (trap_ctrl.cause(6) = '0') then -- exception
|
||||
csr.mtinst <= exe_engine.ir;
|
||||
if (exe_engine.is_ci = '1') and RISCV_ISA_C then
|
||||
if (exe_engine.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
|
||||
|
@ -1679,12 +1651,10 @@ begin
|
|||
csr_read_access: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
csr.re <= '0';
|
||||
csr.rdata <= (others => '0');
|
||||
elsif rising_edge(clk_i) then
|
||||
csr.re <= csr.re_nxt;
|
||||
csr.rdata <= (others => '0'); -- default; output all-zero if there is no explicit CSR read operation
|
||||
if (csr.re = '1') then
|
||||
if (exe_engine.state = SYSTEM) then -- always read from CSR file in SYSTEM state
|
||||
case csr.addr is -- address is zero if there is no CSR operation
|
||||
|
||||
-- --------------------------------------------------------------------
|
||||
|
@ -2084,14 +2054,14 @@ begin
|
|||
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 (exe_engine.state = EXECUTE) and (exe_engine.is_ci = '1') else '0'; -- executed compressed instruction
|
||||
cnt_event(hpmcnt_event_compr_c) <= '1' when (exe_engine.state = EXECUTE) and (exe_engine.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_wait_alu_c) <= '1' when (exe_engine.state = ALU_WAIT) else '0'; -- multi-cycle ALU 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_wait_lsu_c) <= '1' when (ctrl.lsu_req = '0') and (exe_engine.state = MEM_RSP) else '0'; -- load/store memory wait cycle
|
||||
cnt_event(hpmcnt_event_trap_c) <= '1' when (trap_ctrl.env_enter = '1') else '0'; -- entered trap
|
||||
|
||||
|
||||
|
@ -2170,7 +2140,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) = exe_engine.next_pc(XLEN-1 downto 1)) -- address match
|
||||
(csr.tdata2(XLEN-1 downto 1) = exe_engine.pc2(XLEN-1 downto 1)) -- address match
|
||||
else '0';
|
||||
|
||||
-- status flag - set when trigger has fired --
|
||||
|
|
|
@ -65,6 +65,7 @@ begin
|
|||
end if;
|
||||
end process mem_addr_reg;
|
||||
|
||||
-- address output --
|
||||
dbus_req_o.addr <= mar; -- bus address
|
||||
mar_o <= mar; -- for MTVAL CSR
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ architecture neorv32_cpu_pmp_rtl of neorv32_cpu_pmp is
|
|||
-- auto-configuration --
|
||||
constant granularity_c : natural := cond_sel_natural_f(boolean(GRANULARITY < 4), 4, 2**index_size_f(GRANULARITY));
|
||||
|
||||
-- PMP configuration register bits --
|
||||
-- configuration register bits --
|
||||
constant cfg_r_c : natural := 0; -- read permit
|
||||
constant cfg_w_c : natural := 1; -- write permit
|
||||
constant cfg_x_c : natural := 2; -- execute permit
|
||||
|
@ -59,16 +59,16 @@ architecture neorv32_cpu_pmp_rtl of neorv32_cpu_pmp is
|
|||
constant cfg_rh_c : natural := 6; -- reserved
|
||||
constant cfg_l_c : natural := 7; -- locked entry
|
||||
|
||||
-- PMP modes --
|
||||
-- operation modes --
|
||||
constant mode_off_c : std_ulogic_vector(1 downto 0) := "00"; -- null region (disabled)
|
||||
constant mode_tor_c : std_ulogic_vector(1 downto 0) := "01"; -- top of range
|
||||
constant mode_na4_c : std_ulogic_vector(1 downto 0) := "10"; -- naturally aligned four-byte region
|
||||
constant mode_napot_c : std_ulogic_vector(1 downto 0) := "11"; -- naturally aligned power-of-two region (>= 8 bytes)
|
||||
|
||||
-- PMP helpers --
|
||||
-- address LSB according to granularity --
|
||||
constant pmp_lsb_c : natural := index_size_f(granularity_c); -- min = 2
|
||||
|
||||
-- PMP CSRs --
|
||||
-- CSRs --
|
||||
type csr_cfg_t is array (0 to NUM_REGIONS-1) of std_ulogic_vector(7 downto 0);
|
||||
type csr_addr_t is array (0 to NUM_REGIONS-1) of std_ulogic_vector(XLEN-1 downto 0);
|
||||
type csr_cfg_rd_t is array (0 to 15) of std_ulogic_vector(7 downto 0);
|
||||
|
@ -85,7 +85,7 @@ architecture neorv32_cpu_pmp_rtl of neorv32_cpu_pmp is
|
|||
signal cfg_rd32 : csr_cfg_rd32_t;
|
||||
signal addr_rd : csr_addr_rd_t;
|
||||
|
||||
-- PMP address extension to 34 bit --
|
||||
-- extended address (34-bit) --
|
||||
type xaddr_t is array (0 to NUM_REGIONS-1) of std_ulogic_vector(XLEN+1 downto 0);
|
||||
signal xaddr : xaddr_t;
|
||||
|
||||
|
@ -240,7 +240,7 @@ begin
|
|||
-- extend region addresses to 34-bit --
|
||||
xaddr(r) <= csr.addr(r) & "00"; -- mask byte offset
|
||||
|
||||
|
||||
-- naturally-aligned address mask --
|
||||
nap_mode_enable:
|
||||
if NAP_EN generate
|
||||
|
||||
|
@ -366,7 +366,6 @@ begin
|
|||
fail_rw(r) <= not region.perm_rw(r) when (region.d_match(r) = '1') else fail_rw(r+1);
|
||||
end generate;
|
||||
|
||||
|
||||
-- final access check --
|
||||
access_check: process(rstn_i, clk_i)
|
||||
begin
|
||||
|
|
|
@ -128,11 +128,11 @@ architecture neorv32_debug_dm_rtl of neorv32_debug_dm is
|
|||
|
||||
-- authentication --
|
||||
type auth_t is record
|
||||
busy : std_ulogic; -- authenticator is busy when set
|
||||
valid : std_ulogic; -- authentication successful
|
||||
reset : std_ulogic; -- reset authentication (sync, high-active)
|
||||
re, we : std_ulogic; -- data interface read/write enable
|
||||
rdata : std_ulogic_vector(31 downto 0); -- read data
|
||||
busy : std_ulogic; -- authenticator is busy when set
|
||||
valid : std_ulogic; -- authentication successful
|
||||
re : std_ulogic; -- data interface read enable
|
||||
we : std_ulogic; -- data interface write enable
|
||||
rdata : std_ulogic_vector(31 downto 0); -- read data
|
||||
end record;
|
||||
signal auth : auth_t;
|
||||
|
||||
|
|
|
@ -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"01100600"; -- hardware version
|
||||
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100606"; -- hardware version
|
||||
constant archid_c : natural := 19; -- official RISC-V architecture ID
|
||||
constant XLEN : natural := 32; -- native data path width
|
||||
|
||||
|
@ -181,6 +181,43 @@ package neorv32_package is
|
|||
ack : std_ulogic;
|
||||
end record;
|
||||
|
||||
-- External Bus Interface (XBUS / Wishbone) -----------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- xbus request --
|
||||
type xbus_req_t is record
|
||||
addr : std_ulogic_vector(31 downto 0); -- access address
|
||||
data : std_ulogic_vector(31 downto 0); -- write data
|
||||
tag : std_ulogic_vector(2 downto 0); -- access tag
|
||||
we : std_ulogic; -- read/write
|
||||
sel : std_ulogic_vector(3 downto 0); -- byte enable
|
||||
stb : std_ulogic; -- strobe
|
||||
cyc : std_ulogic; -- valid cycle
|
||||
end record;
|
||||
|
||||
-- xbus response --
|
||||
type xbus_rsp_t is record
|
||||
data : std_ulogic_vector(31 downto 0); -- read data, valid if ack=1
|
||||
ack : std_ulogic; -- access acknowledge
|
||||
err : std_ulogic; -- access error
|
||||
end record;
|
||||
|
||||
-- endpoint (response) termination --
|
||||
constant xbus_rsp_terminate_c : xbus_rsp_t := (
|
||||
data => (others => '0'),
|
||||
ack => '0',
|
||||
err => '0'
|
||||
);
|
||||
|
||||
-- External Stream-Link Interface (SLINK / AXI4-Stream) -----------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
type slink_t is record
|
||||
data : std_ulogic_vector(31 downto 0); -- data
|
||||
addr : std_ulogic_vector(3 downto 0); -- source/destination ID
|
||||
valid : std_ulogic; -- source valid
|
||||
last : std_ulogic; -- last element of packet
|
||||
ready : std_ulogic; -- sink ready
|
||||
end record;
|
||||
|
||||
-- **********************************************************************************************************
|
||||
-- RISC-V ISA Definitions
|
||||
-- **********************************************************************************************************
|
||||
|
@ -667,12 +704,15 @@ package neorv32_package is
|
|||
|
||||
component neorv32_top
|
||||
generic (
|
||||
-- General --
|
||||
-- Processor 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 +1156,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,
|
||||
|
@ -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;
|
||||
|
||||
|
@ -1191,7 +1217,8 @@ begin
|
|||
if IO_UART0_EN generate
|
||||
neorv32_uart0_inst: entity neorv32.neorv32_uart
|
||||
generic map (
|
||||
SIM_LOG_FILE => "neorv32.uart0.sim_mode.text.out",
|
||||
SIM_MODE_EN => true,
|
||||
SIM_LOG_FILE => "neorv32.uart0_sim_mode.out",
|
||||
UART_RX_FIFO => IO_UART0_RX_FIFO,
|
||||
UART_TX_FIFO => IO_UART0_TX_FIFO
|
||||
)
|
||||
|
@ -1228,7 +1255,8 @@ begin
|
|||
if IO_UART1_EN generate
|
||||
neorv32_uart1_inst: entity neorv32.neorv32_uart
|
||||
generic map (
|
||||
SIM_LOG_FILE => "neorv32.uart1.sim_mode.text.out",
|
||||
SIM_MODE_EN => true,
|
||||
SIM_LOG_FILE => "neorv32.uart1_sim_mode.out",
|
||||
UART_RX_FIFO => IO_UART1_RX_FIFO,
|
||||
UART_TX_FIFO => IO_UART1_TX_FIFO
|
||||
)
|
||||
|
@ -1551,8 +1579,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 +1679,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 +1689,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;
|
||||
|
||||
|
||||
|
|
|
@ -448,16 +448,21 @@ begin
|
|||
-- latch with global reset and individual enable --
|
||||
latch(i) <= '0' when (en_i = '0') else latch(i) when (sreg(i) = '0') else inv_out(i);
|
||||
|
||||
-- inverter with "propagation delay" --
|
||||
inverter_sim:
|
||||
if SIM_MODE generate
|
||||
inv_out(i) <= not inv_in(i) when rising_edge(clk_i); -- for SIMULATION ONLY
|
||||
end generate;
|
||||
|
||||
-- inverter for actual synthesis --
|
||||
inverter_phy:
|
||||
if not SIM_MODE generate
|
||||
inv_out(i) <= not inv_in(i);
|
||||
inv_out(i) <= not inv_in(i); -- this is one part of the ring oscillator's physical propagation delay
|
||||
end generate;
|
||||
|
||||
-- inverter with "propagation delay (as a simple FF)" --
|
||||
inverter_sim:
|
||||
if SIM_MODE generate -- for SIMULATION ONLY
|
||||
inverter_sim_ff: process(clk_i) -- this will NOT generate true random numbers
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
inv_out(i) <= not inv_in(i);
|
||||
end if;
|
||||
end process inverter_sim_ff;
|
||||
end generate;
|
||||
|
||||
end generate;
|
||||
|
|
|
@ -23,7 +23,8 @@ use neorv32.neorv32_package.all;
|
|||
|
||||
entity neorv32_uart is
|
||||
generic (
|
||||
SIM_LOG_FILE : string; -- name of SIM mode log file
|
||||
SIM_MODE_EN : boolean; -- enable simulation-mode option
|
||||
SIM_LOG_FILE : string; -- name of SIM mode log file
|
||||
UART_RX_FIFO : natural range 1 to 2**15; -- RX fifo depth, has to be a power of two, min 1
|
||||
UART_TX_FIFO : natural range 1 to 2**15 -- TX fifo depth, has to be a power of two, min 1
|
||||
);
|
||||
|
@ -45,6 +46,9 @@ end neorv32_uart;
|
|||
|
||||
architecture neorv32_uart_rtl of neorv32_uart is
|
||||
|
||||
-- simulation mode available? --
|
||||
constant sim_mode_en_c : boolean := SIM_MODE_EN and is_simulation_c;
|
||||
|
||||
-- control register bits --
|
||||
constant ctrl_en_c : natural := 0; -- r/w: UART enable
|
||||
constant ctrl_sim_en_c : natural := 1; -- r/w: simulation-mode enable
|
||||
|
@ -169,7 +173,7 @@ begin
|
|||
if (bus_req_i.rw = '1') then -- write access
|
||||
if (bus_req_i.addr(2) = '0') then -- control register
|
||||
ctrl.enable <= bus_req_i.data(ctrl_en_c);
|
||||
ctrl.sim_mode <= bus_req_i.data(ctrl_sim_en_c);
|
||||
ctrl.sim_mode <= bus_req_i.data(ctrl_sim_en_c) and bool_to_ulogic_f(sim_mode_en_c);
|
||||
ctrl.hwfc_en <= bus_req_i.data(ctrl_hwfc_en_c);
|
||||
ctrl.prsc <= bus_req_i.data(ctrl_prsc2_c downto ctrl_prsc0_c);
|
||||
ctrl.baud <= bus_req_i.data(ctrl_baud9_c downto ctrl_baud0_c);
|
||||
|
@ -185,7 +189,7 @@ begin
|
|||
else -- read access
|
||||
if (bus_req_i.addr(2) = '0') then -- control register
|
||||
bus_rsp_o.data(ctrl_en_c) <= ctrl.enable;
|
||||
bus_rsp_o.data(ctrl_sim_en_c) <= ctrl.sim_mode;
|
||||
bus_rsp_o.data(ctrl_sim_en_c) <= ctrl.sim_mode and bool_to_ulogic_f(sim_mode_en_c);
|
||||
bus_rsp_o.data(ctrl_hwfc_en_c) <= ctrl.hwfc_en;
|
||||
bus_rsp_o.data(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl.prsc;
|
||||
bus_rsp_o.data(ctrl_baud9_c downto ctrl_baud0_c) <= ctrl.baud;
|
||||
|
@ -473,7 +477,7 @@ begin
|
|||
-- pragma translate_off
|
||||
-- RTL_SYNTHESIS OFF
|
||||
simulation_transmitter:
|
||||
if is_simulation_c generate -- for simulation only!
|
||||
if sim_mode_en_c generate -- for simulation only!
|
||||
sim_tx: process(clk_i)
|
||||
file file_out : text open write_mode is SIM_LOG_FILE;
|
||||
variable char_v : integer;
|
||||
|
|
|
@ -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';
|
||||
|
||||
|
|
|
@ -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
|
||||
|
@ -55,6 +59,7 @@ set_property top $ip_top [current_fileset]
|
|||
|
||||
update_compile_order -fileset sources_1
|
||||
|
||||
|
||||
# **************************************************************
|
||||
# Package as IP block
|
||||
# **************************************************************
|
||||
|
@ -64,6 +69,10 @@ 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]
|
||||
|
||||
|
||||
# **************************************************************
|
||||
# Setup configuration GUI
|
||||
# **************************************************************
|
||||
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]]
|
||||
|
@ -105,28 +114,33 @@ proc setup_ip_gui {} {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
# **************************************************************
|
||||
# Interfaces: Configuration Dependencies
|
||||
# **************************************************************
|
||||
set_property enablement_dependency {$AXI4_STREAM_EN} [ipx::get_bus_interfaces s0_axis -of_objects [ipx::current_core]]
|
||||
set_property enablement_dependency {$AXI4_STREAM_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]]
|
||||
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 pages
|
||||
# **************************************************************
|
||||
# Remove default page
|
||||
set page [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]]
|
||||
if {$page ne ""} {
|
||||
|
@ -139,8 +153,23 @@ proc setup_ip_gui {} {
|
|||
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 signal in Hz} }
|
||||
{ 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} }
|
||||
}
|
||||
|
@ -159,6 +188,7 @@ proc setup_ip_gui {} {
|
|||
|
||||
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} }
|
||||
|
@ -166,9 +196,9 @@ proc setup_ip_gui {} {
|
|||
|
||||
set group [add_group $page {Stream Link Interface (SLINK / AXI4-Stream Source & Sink)}]
|
||||
add_params $group {
|
||||
{ AXI4_STREAM_EN {Enable SLINK} {} }
|
||||
{ IO_SLINK_RX_FIFO {RX FIFO Depth} {Number of entries (use a power of two)} {$AXI4_STREAM_EN} }
|
||||
{ IO_SLINK_TX_FIFO {TX FIFO Depth} {Number of entries (use a power of two)} {$AXI4_STREAM_EN} }
|
||||
{ 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} }
|
||||
}
|
||||
|
||||
|
||||
|
@ -214,7 +244,7 @@ proc setup_ip_gui {} {
|
|||
}
|
||||
set_property value_validation_range_minimum 4 [ipx::get_user_parameters PMP_MIN_GRANULARITY -of_objects [ipx::current_core]]
|
||||
|
||||
set group [add_group $page {Architecture Tuning Options}]
|
||||
set group [add_group $page {Tuning Options}]
|
||||
add_params $group {
|
||||
{ FAST_MUL_EN {DSP-Based Multiplier} }
|
||||
{ FAST_SHIFT_EN {Barrel Shifter} }
|
||||
|
@ -261,11 +291,6 @@ proc setup_ip_gui {} {
|
|||
{ XIP_CACHE_BLOCK_SIZE {Cache Block Size} {In bytes (use a power of two)} {$XIP_CACHE_EN} }
|
||||
}
|
||||
|
||||
set group [add_group $page {Internal Bootloader}]
|
||||
add_params $group {
|
||||
{ INT_BOOTLOADER_EN {Enable Bootloader} {Start interactive bootloader console after reset} }
|
||||
}
|
||||
|
||||
|
||||
# **************************************************************
|
||||
# GUI Page: Peripherals
|
||||
|
@ -376,6 +401,7 @@ proc setup_ip_gui {} {
|
|||
|
||||
setup_ip_gui
|
||||
|
||||
|
||||
# **************************************************************
|
||||
# Configuration GUI: IP logo
|
||||
# **************************************************************
|
||||
|
@ -392,6 +418,7 @@ set_property type LOGO [ipx::get_files ../../$neorv32_home/$ip_logo -of_objects
|
|||
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;
|
||||
|
@ -87,6 +88,7 @@ entity neorv32_vivado_ip is
|
|||
-- 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;
|
||||
|
@ -129,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
|
||||
|
@ -170,7 +173,7 @@ entity neorv32_vivado_ip is
|
|||
m_axi_bvalid : in std_logic := '0';
|
||||
m_axi_bready : out std_logic;
|
||||
-- ------------------------------------------------------------
|
||||
-- AXI4-Stream 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
|
||||
|
@ -260,54 +263,44 @@ architecture neorv32_vivado_ip_rtl of neorv32_vivado_ip is
|
|||
-- 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
|
||||
-- Global control
|
||||
clk : in std_logic;
|
||||
resetn : in std_logic;
|
||||
-- XBUS device interface --
|
||||
xbus_adr_i : in std_ulogic_vector(31 downto 0);
|
||||
xbus_dat_i : in std_ulogic_vector(31 downto 0);
|
||||
xbus_tag_i : in std_ulogic_vector(2 downto 0);
|
||||
xbus_we_i : in std_ulogic;
|
||||
xbus_sel_i : in std_ulogic_vector(3 downto 0);
|
||||
xbus_stb_i : in std_ulogic;
|
||||
xbus_cyc_i : in std_ulogic;
|
||||
xbus_ack_o : out std_ulogic;
|
||||
xbus_err_o : out std_ulogic;
|
||||
xbus_dat_o : out std_ulogic_vector(31 downto 0);
|
||||
-- AXI4-Lite host 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;
|
||||
-- AXI4-Lite host 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;
|
||||
-- AXI4-Lite host 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;
|
||||
-- AXI4-Lite host 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;
|
||||
-- AXI4-Lite host 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;
|
||||
|
||||
|
@ -334,16 +327,16 @@ architecture neorv32_vivado_ip_rtl of neorv32_vivado_ip is
|
|||
signal xirq_i_aux : std_ulogic_vector(31 downto 0);
|
||||
|
||||
-- internal wishbone bus --
|
||||
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
|
||||
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
|
||||
|
||||
|
@ -351,12 +344,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,
|
||||
|
@ -412,7 +408,7 @@ begin
|
|||
-- External bus interface --
|
||||
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,
|
||||
|
@ -424,6 +420,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,
|
||||
|
@ -451,7 +448,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
|
||||
|
@ -618,14 +615,10 @@ begin
|
|||
if XBUS_EN generate
|
||||
axi4_bridge_inst: xbus2axi4lite_bridge
|
||||
port map (
|
||||
-- ------------------------------------------------------------
|
||||
-- Global Control
|
||||
-- ------------------------------------------------------------
|
||||
-- Global control --
|
||||
clk => clk,
|
||||
resetn => resetn,
|
||||
-- ------------------------------------------------------------
|
||||
-- XBUS Device Interface
|
||||
-- ------------------------------------------------------------
|
||||
-- XBUS device interface --
|
||||
xbus_adr_i => xbus_adr,
|
||||
xbus_dat_i => xbus_do,
|
||||
xbus_tag_i => xbus_tag,
|
||||
|
@ -636,30 +629,27 @@ begin
|
|||
xbus_ack_o => xbus_ack,
|
||||
xbus_err_o => xbus_err,
|
||||
xbus_dat_o => xbus_di,
|
||||
-- ------------------------------------------------------------
|
||||
-- AXI4-Lite Host Interface
|
||||
-- ------------------------------------------------------------
|
||||
-- Write Address Channel --
|
||||
-- AXI4-Lite host 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 --
|
||||
-- AXI4-Lite host 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 --
|
||||
-- AXI4-Lite host 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 --
|
||||
-- AXI4-Lite host 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 --
|
||||
-- AXI4-Lite host write response channel --
|
||||
m_axi_bresp => m_axi_bresp,
|
||||
m_axi_bvalid => m_axi_bvalid,
|
||||
m_axi_bready => m_axi_bready
|
||||
|
|
|
@ -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. --
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
-- ================================================================================ --
|
||||
-- NEORV32 SoC - XBUS to AXI4-Lite Bridge (non-overlapping single transfers only) --
|
||||
-- NEORV32 SoC - XBUS to AXI4-Lite Bridge (single non-overlapping transfers only) --
|
||||
-- -------------------------------------------------------------------------------- --
|
||||
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
|
||||
-- Copyright (c) NEORV32 contributors. --
|
||||
|
@ -14,139 +14,94 @@ 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
|
||||
-- Global control --
|
||||
clk : in std_logic;
|
||||
resetn : in std_logic;
|
||||
-- XBUS device interface --
|
||||
xbus_adr_i : in std_ulogic_vector(31 downto 0);
|
||||
xbus_dat_i : in std_ulogic_vector(31 downto 0);
|
||||
xbus_tag_i : in std_ulogic_vector(2 downto 0);
|
||||
xbus_we_i : in std_ulogic;
|
||||
xbus_sel_i : in std_ulogic_vector(3 downto 0);
|
||||
xbus_stb_i : in std_ulogic;
|
||||
xbus_cyc_i : in std_ulogic;
|
||||
xbus_ack_o : out std_ulogic;
|
||||
xbus_err_o : out std_ulogic;
|
||||
xbus_dat_o : out std_ulogic_vector(31 downto 0);
|
||||
-- AXI4-Lite host 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;
|
||||
-- AXI4-Lite host 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;
|
||||
-- AXI4-Lite host 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;
|
||||
-- AXI4-Lite host 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;
|
||||
-- AXI4-Lite host 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;
|
||||
signal ready : std_ulogic_vector(2 downto 0);
|
||||
signal xbus_rd_ack, xbus_rd_err, xbus_wr_ack, xbus_wr_err : std_ulogic;
|
||||
|
||||
begin
|
||||
|
||||
-- channel arbiter --
|
||||
axi_arbiter: process(resetn, clk)
|
||||
-- channel handshake arbiter --
|
||||
axi_handshake: process(resetn, clk)
|
||||
begin
|
||||
if (resetn = '0') then
|
||||
axi_radr_received <= '0';
|
||||
axi_wadr_received <= '0';
|
||||
axi_wdat_received <= '0';
|
||||
ready <= (others => '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;
|
||||
ready(0) <= xbus_cyc_i and (ready(0) or std_ulogic(m_axi_arready));
|
||||
ready(1) <= xbus_cyc_i and (ready(1) or std_ulogic(m_axi_awready));
|
||||
ready(2) <= xbus_cyc_i and (ready(2) or std_ulogic(m_axi_wready));
|
||||
end if;
|
||||
end process axi_arbiter;
|
||||
end process axi_handshake;
|
||||
|
||||
|
||||
-- read address channel --
|
||||
-- AXI 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));
|
||||
m_axi_arvalid <= std_logic(xbus_cyc_i and (not xbus_we_i) and (not ready(0)));
|
||||
|
||||
-- read data channel --
|
||||
-- AXI 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);
|
||||
xbus_rd_ack <= '1' when (m_axi_rvalid = '1') and (m_axi_rresp = "00") else '0';
|
||||
xbus_rd_err <= '1' when (m_axi_rvalid = '1') and (m_axi_rresp /= "00") else '0';
|
||||
|
||||
-- write address channel --
|
||||
-- AXI 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));
|
||||
m_axi_awvalid <= std_logic(xbus_cyc_i and xbus_we_i and (not ready(1)));
|
||||
|
||||
-- write data channel --
|
||||
-- AXI 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));
|
||||
m_axi_wvalid <= std_logic(xbus_cyc_i and xbus_we_i and (not ready(2)));
|
||||
|
||||
-- write response channel --
|
||||
-- AXI write response channel --
|
||||
m_axi_bready <= std_logic(xbus_cyc_i and xbus_we_i);
|
||||
xbus_wr_ack <= '1' when (m_axi_bvalid = '1') and (m_axi_bresp = "00") else '0';
|
||||
xbus_wr_err <= '1' when (m_axi_bvalid = '1') and (m_axi_bresp /= "00") else '0';
|
||||
|
||||
|
||||
-- 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;
|
||||
-- XBUS response --
|
||||
xbus_ack_o <= xbus_rd_ack when (xbus_we_i = '0') else xbus_wr_ack;
|
||||
xbus_err_o <= xbus_rd_err when (xbus_we_i = '0') else xbus_wr_err;
|
||||
|
||||
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)
|
57
sim/ghdl.run.sh
Normal file
57
sim/ghdl.run.sh
Normal file
|
@ -0,0 +1,57 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
cd $(dirname "$0")
|
||||
|
||||
NEORV32_RTL=${NEORV32_RTL:-../rtl}
|
||||
FILE_LIST=`cat $NEORV32_RTL/file_list_soc.f`
|
||||
CORE_SRCS="${FILE_LIST//NEORV32_RTL_PATH_PLACEHOLDER/"$NEORV32_RTL"}"
|
||||
GHDL="${GHDL:-ghdl}"
|
||||
|
||||
# Prepare UART SIM_MODE output files
|
||||
touch neorv32.uart0_sim_mode.out neorv32.uart1_sim_mode.out
|
||||
chmod 777 neorv32.uart0_sim_mode.out neorv32.uart1_sim_mode.out
|
||||
|
||||
# Prepare testbench UART log files
|
||||
touch neorv32_tb.uart0_rx.out neorv32_tb.uart1_rx.out
|
||||
chmod 777 neorv32_tb.uart0_rx.out neorv32_tb.uart1_rx.out
|
||||
|
||||
# GHDL build directory
|
||||
mkdir -p build
|
||||
|
||||
# GHDL import
|
||||
$GHDL -i --work=neorv32 --workdir=build \
|
||||
$CORE_SRCS \
|
||||
"$NEORV32_RTL"/processor_templates/*.vhd \
|
||||
"$NEORV32_RTL"/system_integration/*.vhd \
|
||||
"$NEORV32_RTL"/test_setups/*.vhd \
|
||||
neorv32_tb.vhd \
|
||||
sim_uart_rx.vhd \
|
||||
xbus_gateway.vhd \
|
||||
xbus_memory.vhd
|
||||
|
||||
# GHDL analyze
|
||||
$GHDL -m --work=neorv32 --workdir=build neorv32_tb
|
||||
|
||||
# GHDL run parameters
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
GHDL_RUN_ARGS="${@:---stop-time=10ms}"
|
||||
else
|
||||
# Let's pass down all the parameters to GHDL
|
||||
GHDL_RUN_ARGS=$@
|
||||
fi
|
||||
echo "GHDL simulation run parameters: $GHDL_RUN_ARGS";
|
||||
|
||||
# GHDL run
|
||||
runcmd="$GHDL -r --work=neorv32 --workdir=build neorv32_tb \
|
||||
--max-stack-alloc=0 \
|
||||
--ieee-asserts=disable \
|
||||
--assert-level=error $GHDL_RUN_ARGS"
|
||||
|
||||
if [ -n "$GHDL_DEVNULL" ]; then
|
||||
$runcmd >> /dev/null
|
||||
else
|
||||
$runcmd
|
||||
fi
|
11
sim/ghdl.sh
Normal file
11
sim/ghdl.sh
Normal file
|
@ -0,0 +1,11 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Abort if any command returns != 0
|
||||
set -e
|
||||
|
||||
cd $(dirname "$0")
|
||||
|
||||
echo "[TIP] Compile application with USER_FLAGS+=-DUART[0/1]_SIM_MODE to enable UART[0/1]'s simulation mode (redirect UART output to simulator console)."
|
||||
|
||||
# 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;
|
||||
|
@ -20,599 +15,452 @@ 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;
|
||||
|
||||
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 (
|
||||
CLOCK_FREQUENCY : natural := 100_000_000; -- clock frequency of clk_i in Hz
|
||||
BOOT_MODE_SELECT : natural range 0 to 2 := 2; -- boot from pre-initialized IMEM
|
||||
RISCV_ISA_C : boolean := false; -- implement compressed extension
|
||||
RISCV_ISA_E : boolean := false; -- implement embedded RF extension
|
||||
RISCV_ISA_M : boolean := true; -- implement mul/div extension
|
||||
RISCV_ISA_U : boolean := true; -- implement user mode extension
|
||||
RISCV_ISA_Zalrsc : boolean := true; -- implement atomic reservation-set extension
|
||||
RISCV_ISA_Zba : boolean := true; -- implement shifted-add bit-manipulation extension
|
||||
RISCV_ISA_Zbb : boolean := true; -- implement basic bit-manipulation extension
|
||||
RISCV_ISA_Zbkb : boolean := true; -- implement bit-manipulation instructions for cryptography
|
||||
RISCV_ISA_Zbkc : boolean := true; -- implement carry-less multiplication instructions
|
||||
RISCV_ISA_Zbkx : boolean := true; -- implement cryptography crossbar permutation extension
|
||||
RISCV_ISA_Zbs : boolean := true; -- implement single-bit bit-manipulation extension
|
||||
RISCV_ISA_Zfinx : boolean := true; -- implement 32-bit floating-point extension
|
||||
RISCV_ISA_Zicntr : boolean := true; -- implement base counters
|
||||
RISCV_ISA_Zicond : boolean := true; -- implement integer conditional operations
|
||||
RISCV_ISA_Zihpm : boolean := true; -- implement hardware performance monitors
|
||||
RISCV_ISA_Zknd : boolean := true; -- implement cryptography NIST AES decryption extension
|
||||
RISCV_ISA_Zkne : boolean := true; -- implement cryptography NIST AES encryption extension
|
||||
RISCV_ISA_Zknh : boolean := true; -- implement cryptography NIST hash extension
|
||||
RISCV_ISA_Zksed : boolean := true; -- implement ShangMi block cypher extension
|
||||
RISCV_ISA_Zksh : boolean := true; -- implement ShangMi hash extension
|
||||
RISCV_ISA_Zmmul : boolean := true; -- implement multiply-only M sub-extension
|
||||
RISCV_ISA_Zxcfu : boolean := true; -- implement custom (instr.) functions unit
|
||||
FAST_MUL_EN : boolean := true; -- use DSPs for M extension's multiplier
|
||||
FAST_SHIFT_EN : boolean := true; -- use barrel shifter for shift operations
|
||||
REGFILE_HW_RST : boolean := true; -- implement full hardware reset for register file
|
||||
MEM_INT_IMEM_EN : boolean := true; -- implement processor-internal instruction memory
|
||||
MEM_INT_IMEM_SIZE : natural := 32*1024; -- size of processor-internal instruction memory in bytes (use a power of 2)
|
||||
MEM_INT_DMEM_EN : boolean := true; -- implement processor-internal data memory
|
||||
MEM_INT_DMEM_SIZE : natural := 8*1024; -- size of processor-internal data memory in bytes (use a power of 2)
|
||||
ICACHE_EN : boolean := true; -- implement instruction cache
|
||||
ICACHE_NUM_BLOCKS : natural range 1 to 256 := 64; -- i-cache: number of blocks (min 1), has to be a power of 2
|
||||
ICACHE_BLOCK_SIZE : natural range 4 to 2**16 := 32; -- i-cache: block size in bytes (min 4), has to be a power of 2
|
||||
DCACHE_EN : boolean := true; -- implement data cache
|
||||
DCACHE_NUM_BLOCKS : natural range 1 to 256 := 32; -- d-cache: number of blocks (min 1), has to be a power of 2
|
||||
DCACHE_BLOCK_SIZE : natural range 4 to 2**16 := 32 -- d-cache: block size in bytes (min 4), has to be a power of 2
|
||||
);
|
||||
end neorv32_tb;
|
||||
|
||||
architecture neorv32_tb_rtl of neorv32_tb is
|
||||
|
||||
-- User Configuration ---------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- 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 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_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 := icache_block_size_c/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';
|
||||
|
||||
-- uart --
|
||||
signal uart0_txd, uart1_txd : std_ulogic;
|
||||
signal uart0_cts, uart1_cts : std_ulogic;
|
||||
|
||||
-- gpio --
|
||||
-- IO connection --
|
||||
signal uart0_txd, uart0_cts, uart1_txd, uart1_cts : std_ulogic;
|
||||
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_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;
|
||||
signal msi, mei, mti : std_ulogic;
|
||||
|
||||
-- irq --
|
||||
signal msi_ring, mei_ring : std_ulogic;
|
||||
-- slink --
|
||||
signal slink_tx, slink_rx : slink_t;
|
||||
|
||||
-- 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;
|
||||
|
||||
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);
|
||||
-- XBUS (Wishbone b4) bus --
|
||||
signal xbus_core_req, xbus_imem_req, xbus_dmem_req, xbus_mmio_req, xbus_trig_req : xbus_req_t;
|
||||
signal xbus_core_rsp, xbus_imem_rsp, xbus_dmem_rsp, xbus_mmio_rsp, xbus_trig_rsp : xbus_rsp_t;
|
||||
|
||||
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/55" & 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 ------------------------------------------------------------------
|
||||
-- Clock & Reset Generators ---------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
clk_gen <= not clk_gen after (t_clock_c/2);
|
||||
rst_gen <= '0', '1' after 60*(t_clock_c/2);
|
||||
clk_gen <= not clk_gen after (((1 sec) / CLOCK_FREQUENCY) / 2);
|
||||
rst_gen <= '0', '1' after 60*(((1 sec) / CLOCK_FREQUENCY) / 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
|
||||
-- Clocking --
|
||||
CLOCK_FREQUENCY => CLOCK_FREQUENCY,
|
||||
CLOCK_GATING_EN => true,
|
||||
-- Identification --
|
||||
HART_ID => x"00000000",
|
||||
JEDEC_ID => "00000000000",
|
||||
-- Boot Configuration --
|
||||
BOOT_MODE_SELECT => BOOT_MODE_SELECT,
|
||||
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 => RISCV_ISA_C,
|
||||
RISCV_ISA_E => RISCV_ISA_E,
|
||||
RISCV_ISA_M => RISCV_ISA_M,
|
||||
RISCV_ISA_U => RISCV_ISA_U,
|
||||
RISCV_ISA_Zalrsc => RISCV_ISA_Zalrsc,
|
||||
RISCV_ISA_Zba => RISCV_ISA_Zba,
|
||||
RISCV_ISA_Zbb => RISCV_ISA_Zbb,
|
||||
RISCV_ISA_Zbkb => RISCV_ISA_Zbkb,
|
||||
RISCV_ISA_Zbkc => RISCV_ISA_Zbkc,
|
||||
RISCV_ISA_Zbkx => RISCV_ISA_Zbkx,
|
||||
RISCV_ISA_Zbs => RISCV_ISA_Zbs,
|
||||
RISCV_ISA_Zfinx => RISCV_ISA_Zfinx,
|
||||
RISCV_ISA_Zicntr => RISCV_ISA_Zicntr,
|
||||
RISCV_ISA_Zicond => RISCV_ISA_Zicond,
|
||||
RISCV_ISA_Zihpm => RISCV_ISA_Zihpm,
|
||||
RISCV_ISA_Zknd => RISCV_ISA_Zknd,
|
||||
RISCV_ISA_Zkne => RISCV_ISA_Zkne,
|
||||
RISCV_ISA_Zknh => RISCV_ISA_Zknh,
|
||||
RISCV_ISA_Zksed => RISCV_ISA_Zksed,
|
||||
RISCV_ISA_Zksh => RISCV_ISA_Zksh,
|
||||
RISCV_ISA_Zmmul => RISCV_ISA_Zmmul,
|
||||
RISCV_ISA_Zxcfu => RISCV_ISA_Zxcfu,
|
||||
-- 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 => FAST_MUL_EN,
|
||||
FAST_SHIFT_EN => FAST_SHIFT_EN,
|
||||
REGFILE_HW_RST => REGFILE_HW_RST,
|
||||
-- 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 => MEM_INT_IMEM_EN ,
|
||||
MEM_INT_IMEM_SIZE => MEM_INT_IMEM_SIZE,
|
||||
-- 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 => MEM_INT_DMEM_EN,
|
||||
MEM_INT_DMEM_SIZE => MEM_INT_DMEM_SIZE,
|
||||
-- Internal Cache memory --
|
||||
ICACHE_EN => false, -- implement instruction cache
|
||||
ICACHE_EN => ICACHE_EN,
|
||||
ICACHE_NUM_BLOCKS => ICACHE_NUM_BLOCKS,
|
||||
ICACHE_BLOCK_SIZE => ICACHE_BLOCK_SIZE,
|
||||
-- Internal Data Cache (dCACHE) --
|
||||
DCACHE_EN => false, -- implement data cache
|
||||
DCACHE_EN => DCACHE_EN,
|
||||
DCACHE_NUM_BLOCKS => DCACHE_NUM_BLOCKS,
|
||||
DCACHE_BLOCK_SIZE => DCACHE_BLOCK_SIZE,
|
||||
-- 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
|
||||
-- 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 => '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
|
||||
-- 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
|
||||
clk_i => clk_gen,
|
||||
rstn_i => rst_gen,
|
||||
-- JTAG on-chip debugger interface --
|
||||
jtag_tck_i => '0',
|
||||
jtag_tdi_i => '0',
|
||||
jtag_tdo_o => open,
|
||||
jtag_tms_i => '0',
|
||||
-- External bus interface --
|
||||
xbus_adr_o => xbus_core_req.addr,
|
||||
xbus_dat_o => xbus_core_req.data,
|
||||
xbus_tag_o => xbus_core_req.tag,
|
||||
xbus_we_o => xbus_core_req.we,
|
||||
xbus_sel_o => xbus_core_req.sel,
|
||||
xbus_stb_o => xbus_core_req.stb,
|
||||
xbus_cyc_o => xbus_core_req.cyc,
|
||||
xbus_dat_i => xbus_core_rsp.data,
|
||||
xbus_ack_i => xbus_core_rsp.ack,
|
||||
xbus_err_i => xbus_core_rsp.err,
|
||||
-- Stream Link Interface --
|
||||
slink_rx_dat_i => slink_rx.data,
|
||||
slink_rx_src_i => slink_rx.addr,
|
||||
slink_rx_val_i => slink_rx.valid,
|
||||
slink_rx_lst_i => slink_rx.last,
|
||||
slink_rx_rdy_o => slink_rx.ready,
|
||||
slink_tx_dat_o => slink_tx.data,
|
||||
slink_tx_dst_o => slink_tx.addr,
|
||||
slink_tx_val_o => slink_tx.valid,
|
||||
slink_tx_lst_o => slink_tx.last,
|
||||
slink_tx_rdy_i => slink_tx.ready,
|
||||
-- XIP --
|
||||
xip_csn_o => open,
|
||||
xip_clk_o => open,
|
||||
xip_dat_i => '0',
|
||||
xip_dat_o => open,
|
||||
-- GPIO --
|
||||
gpio_o => gpio,
|
||||
gpio_i => gpio,
|
||||
-- primary UART0 --
|
||||
uart0_txd_o => uart0_txd,
|
||||
uart0_rxd_i => uart0_txd,
|
||||
uart0_rts_o => uart0_cts,
|
||||
uart0_cts_i => uart0_cts,
|
||||
-- secondary UART1 --
|
||||
uart1_txd_o => uart1_txd,
|
||||
uart1_rxd_i => uart1_txd,
|
||||
uart1_rts_o => uart1_cts,
|
||||
uart1_cts_i => uart1_cts,
|
||||
-- SPI --
|
||||
spi_clk_o => spi_clk,
|
||||
spi_dat_o => spi_do,
|
||||
spi_dat_i => spi_di,
|
||||
spi_csn_o => spi_csn,
|
||||
-- SDI --
|
||||
sdi_clk_i => sdi_clk,
|
||||
sdi_dat_o => sdi_do,
|
||||
sdi_dat_i => sdi_di,
|
||||
sdi_csn_i => sdi_csn,
|
||||
-- TWI --
|
||||
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 --
|
||||
onewire_i => onewire_i,
|
||||
onewire_o => onewire_o,
|
||||
-- PWM --
|
||||
pwm_o => open,
|
||||
-- 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) --
|
||||
cfs_in_i => (others => '0'),
|
||||
cfs_out_o => open,
|
||||
-- NeoPixel-compatible smart LED interface --
|
||||
neoled_o => open,
|
||||
-- Machine timer system time --
|
||||
mtime_time_o => open,
|
||||
-- External platform interrupts (available if XIRQ_NUM_CH > 0) --
|
||||
xirq_i => gpio(31 downto 0), -- IRQ channels
|
||||
-- External platform interrupts --
|
||||
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 => mti,
|
||||
msw_irq_i => msi,
|
||||
mext_irq_i => mei
|
||||
);
|
||||
|
||||
-- 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);
|
||||
-- Two-Wire Bus ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
twi_sda <= '0' when (twi_sda_o = '0') else 'Z'; -- tristate driver: module can only pull the line low actively
|
||||
twi_scl <= '0' when (twi_scl_o = '0') else 'Z'; -- tristate driver: module can only pull the line low actively
|
||||
twi_sda_i <= std_ulogic(twi_sda); -- sense input
|
||||
twi_scl_i <= std_ulogic(twi_scl); -- sense input
|
||||
|
||||
-- TWI termination (pull-ups) --
|
||||
twi_scl <= 'H';
|
||||
twi_sda <= 'H';
|
||||
-- TWI bus termination --
|
||||
twi_scl <= 'H'; -- weak pull-up "resistor"
|
||||
twi_sda <= 'H'; -- weak pull-up "resistor"
|
||||
|
||||
-- 1-Wire termination (pull-up) --
|
||||
onewire <= 'H';
|
||||
|
||||
-- SPI/SDI echo with propagation delay --
|
||||
sdi_clk <= spi_clk after 40 ns;
|
||||
-- One-Wire Bus ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
onewire <= '0' when (onewire_o = '0') else 'Z'; -- tristate driver: module can only pull the line low actively
|
||||
onewire_i <= std_ulogic(onewire); -- sense input
|
||||
|
||||
-- 1-Wire bus termination --
|
||||
onewire <= 'H'; -- weak pull-up "resistor"
|
||||
|
||||
|
||||
-- SP/SDI ---------------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
sdi_clk <= spi_clk after 40 ns; -- echo with propagation delay
|
||||
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;
|
||||
|
||||
uart0_checker: entity work.uart_rx
|
||||
generic map (uart0_rx_handle)
|
||||
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);
|
||||
|
||||
|
||||
-- Wishbone Fabric ------------------------------------------------------------------------
|
||||
-- Stream-Link FIFO Buffer ----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
-- 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';
|
||||
slink_buffer: entity neorv32.neorv32_fifo
|
||||
generic map (
|
||||
FIFO_DEPTH => 4,
|
||||
FIFO_WIDTH => 32+4+1,
|
||||
FIFO_RSYNC => false,
|
||||
FIFO_SAFE => true,
|
||||
FULL_RESET => true
|
||||
)
|
||||
port map (
|
||||
-- control --
|
||||
clk_i => clk_gen,
|
||||
rstn_i => rst_gen,
|
||||
clear_i => '0',
|
||||
half_o => open,
|
||||
-- write port --
|
||||
wdata_i(31 downto 0) => slink_tx.data,
|
||||
wdata_i(35 downto 32) => slink_tx.addr,
|
||||
wdata_i(36) => slink_tx.last,
|
||||
we_i => slink_tx.valid,
|
||||
free_o => slink_tx.ready,
|
||||
-- read port --
|
||||
re_i => slink_rx.ready,
|
||||
rdata_o(31 downto 0) => slink_rx.data,
|
||||
rdata_o(35 downto 32) => slink_rx.addr,
|
||||
rdata_o(36) => slink_rx.last,
|
||||
avail_o => slink_rx.valid
|
||||
);
|
||||
|
||||
|
||||
-- Wishbone Memory A (simulated external IMEM) --------------------------------------------
|
||||
-- UART Simulation Receivers --------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
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
|
||||
sim_rx_uart0: entity work.sim_uart_rx
|
||||
generic map (
|
||||
name => "uart0",
|
||||
fclk => real(CLOCK_FREQUENCY),
|
||||
baud => real(19200)
|
||||
)
|
||||
port map (
|
||||
clk => clk_gen,
|
||||
rxd => uart0_txd
|
||||
);
|
||||
|
||||
-- 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;
|
||||
sim_rx_uart1: entity work.sim_uart_rx
|
||||
generic map (
|
||||
name => "uart1",
|
||||
fclk => real(CLOCK_FREQUENCY),
|
||||
baud => real(19200)
|
||||
)
|
||||
port map (
|
||||
clk => clk_gen,
|
||||
rxd => uart1_txd
|
||||
);
|
||||
|
||||
|
||||
-- Wishbone Memory B (simulated external DMEM) --------------------------------------------
|
||||
-- XBUS / Wishbone Interconnect -----------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
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;
|
||||
xbus_interconnect: entity work.xbus_gateway
|
||||
generic map (
|
||||
-- device address size in bytes and base address --
|
||||
DEV_0_SIZE => MEM_INT_IMEM_SIZE, DEV_0_BASE => mem_imem_base_c,
|
||||
DEV_1_SIZE => MEM_INT_DMEM_SIZE, DEV_1_BASE => mem_dmem_base_c,
|
||||
DEV_2_SIZE => 64, DEV_2_BASE => x"F0000000",
|
||||
DEV_3_SIZE => 4, DEV_3_BASE => x"FF000000"
|
||||
)
|
||||
port map (
|
||||
-- host port --
|
||||
host_req_i => xbus_core_req,
|
||||
host_rsp_o => xbus_core_rsp,
|
||||
-- device ports --
|
||||
dev_0_req_o => xbus_imem_req, dev_0_rsp_i => xbus_imem_rsp,
|
||||
dev_1_req_o => xbus_dmem_req, dev_1_rsp_i => xbus_dmem_rsp,
|
||||
dev_2_req_o => xbus_mmio_req, dev_2_rsp_i => xbus_mmio_rsp,
|
||||
dev_3_req_o => xbus_trig_req, dev_3_rsp_i => xbus_trig_rsp
|
||||
);
|
||||
|
||||
|
||||
-- Wishbone Memory C (simulated external IO) ----------------------------------------------
|
||||
-- XBUS: Instruction Memory ---------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
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;
|
||||
xbus_imem: entity work.xbus_memory
|
||||
generic map (
|
||||
MEM_SIZE => MEM_INT_IMEM_SIZE,
|
||||
MEM_LATE => 1
|
||||
)
|
||||
port map (
|
||||
clk_i => clk_gen,
|
||||
rstn_i => rst_gen,
|
||||
xbus_req_i => xbus_imem_req,
|
||||
xbus_rsp_o => xbus_imem_rsp
|
||||
);
|
||||
|
||||
|
||||
-- Wishbone IRQ Triggers ------------------------------------------------------------------
|
||||
-- XBUS: Data Memory ----------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
irq_trigger: process(rst_gen, clk_gen)
|
||||
xbus_dmem: entity work.xbus_memory
|
||||
generic map (
|
||||
MEM_SIZE => MEM_INT_DMEM_SIZE,
|
||||
MEM_LATE => 1
|
||||
)
|
||||
port map (
|
||||
clk_i => clk_gen,
|
||||
rstn_i => rst_gen,
|
||||
xbus_req_i => xbus_dmem_req,
|
||||
xbus_rsp_o => xbus_dmem_rsp
|
||||
);
|
||||
|
||||
|
||||
-- XBUS: Memory-Mapped IO -----------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
xbus_mmio: entity work.xbus_memory
|
||||
generic map (
|
||||
MEM_SIZE => 64,
|
||||
MEM_LATE => 32
|
||||
)
|
||||
port map (
|
||||
clk_i => clk_gen,
|
||||
rstn_i => rst_gen,
|
||||
xbus_req_i => xbus_mmio_req,
|
||||
xbus_rsp_o => xbus_mmio_rsp
|
||||
);
|
||||
|
||||
|
||||
-- XBUS: IRQ Triggers ---------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
xbus_irq_trigger: process(rst_gen, clk_gen)
|
||||
begin
|
||||
if (rst_gen = '0') then
|
||||
msi_ring <= '0';
|
||||
mei_ring <= '0';
|
||||
msi <= '0';
|
||||
mti <= '0';
|
||||
mei <= '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';
|
||||
-- bus response defaults --
|
||||
xbus_trig_rsp.data <= (others => '0');
|
||||
xbus_trig_rsp.ack <= '0';
|
||||
xbus_trig_rsp.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
|
||||
if ((xbus_trig_req.cyc and xbus_trig_req.stb and xbus_trig_req.we and and_reduce_f(xbus_trig_req.sel)) = '1') then
|
||||
xbus_trig_rsp.ack <= '1';
|
||||
msi <= xbus_trig_req.data(03); -- machine software interrupt
|
||||
mti <= xbus_trig_req.data(07); -- machine timer interrupt
|
||||
mei <= xbus_trig_req.data(11); -- machine external interrupt
|
||||
end if;
|
||||
end if;
|
||||
end process irq_trigger;
|
||||
end process xbus_irq_trigger;
|
||||
|
||||
|
||||
end neorv32_tb_rtl;
|
||||
|
|
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()
|
93
sim/sim_uart_rx.vhd
Normal file
93
sim/sim_uart_rx.vhd
Normal file
|
@ -0,0 +1,93 @@
|
|||
-- ================================================================================ --
|
||||
-- NEORV32 - Simulation UART Receiver (print to simulator console) --
|
||||
-- -------------------------------------------------------------------------------- --
|
||||
-- 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;
|
||||
use std.textio.all;
|
||||
|
||||
entity sim_uart_rx is
|
||||
generic (
|
||||
name : string; -- receiver name (for log file)
|
||||
fclk : real; -- clock speed of clk_i in Hz
|
||||
baud : real -- baud rate
|
||||
);
|
||||
port (
|
||||
clk : in std_ulogic; -- global clock
|
||||
rxd : in std_ulogic -- serial UART RX data
|
||||
);
|
||||
end entity sim_uart_rx;
|
||||
|
||||
architecture sim_uart_rx_rtl of sim_uart_rx is
|
||||
|
||||
signal sync : std_ulogic_vector(4 downto 0) := (others => '1');
|
||||
signal busy : std_ulogic := '0';
|
||||
signal sreg : std_ulogic_vector(8 downto 0) := (others => '0');
|
||||
signal baudcnt : real;
|
||||
signal bitcnt : natural;
|
||||
constant baud_val_c : real := fclk / baud;
|
||||
file file_out : text open write_mode is "neorv32_tb." & name & "_rx.out";
|
||||
|
||||
begin
|
||||
|
||||
sim_receiver: process(clk)
|
||||
variable c : integer;
|
||||
variable l : line;
|
||||
begin
|
||||
if rising_edge(clk) then
|
||||
-- synchronizer --
|
||||
sync <= sync(3 downto 0) & rxd;
|
||||
-- arbiter --
|
||||
if (busy = '0') then -- idle
|
||||
busy <= '0';
|
||||
baudcnt <= round(0.5 * baud_val_c);
|
||||
bitcnt <= 9;
|
||||
if (sync(4 downto 1) = "1100") then -- start bit (falling edge)
|
||||
busy <= '1';
|
||||
end if;
|
||||
else -- receiving
|
||||
|
||||
if (baudcnt <= 0.0) then
|
||||
if (bitcnt = 1) then
|
||||
baudcnt <= round(0.5 * baud_val_c);
|
||||
else
|
||||
baudcnt <= round(baud_val_c);
|
||||
end if;
|
||||
|
||||
if (bitcnt = 0) then
|
||||
busy <= '0'; -- done
|
||||
c := to_integer(unsigned(sreg(8 downto 1)));
|
||||
|
||||
if (c < 32) or (c > 32+95) then -- non-printable character?
|
||||
report name & ".rx: (" & integer'image(c) & ")";
|
||||
else
|
||||
report name & ".rx: " & character'val(c);
|
||||
end if;
|
||||
|
||||
if (c = 10) then -- LF line break
|
||||
writeline(file_out, l);
|
||||
elsif (c /= 13) then -- no additional CR
|
||||
write(l, character'val(c));
|
||||
end if;
|
||||
|
||||
else
|
||||
sreg <= sync(4) & sreg(8 downto 1);
|
||||
bitcnt <= bitcnt - 1;
|
||||
end if;
|
||||
|
||||
else
|
||||
baudcnt <= baudcnt - 1.0;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process sim_receiver;
|
||||
|
||||
end architecture sim_uart_rx_rtl;
|
|
@ -1,44 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
cd $(dirname "$0")
|
||||
|
||||
echo "[TIP] Compile application with USER_FLAGS+=-DUART[0/1]_SIM_MODE to enable UART[0/1]'s simulation mode (redirect UART output to simulator console)."
|
||||
|
||||
# Prepare simulation output files for UART0 and UART 1
|
||||
# - Testbench receiver log file (neorv32.testbench_uart?.out)
|
||||
# - Direct simulation output (neorv32.uart?.sim_mode.text.out)
|
||||
for uart in 0 1; do
|
||||
for item in \
|
||||
testbench_uart"$uart" \
|
||||
uart"$uart".sim_mode.text; do
|
||||
touch neorv32."$item".out
|
||||
chmod 777 neorv32."$item".out
|
||||
done
|
||||
done
|
||||
|
||||
GHDL="${GHDL:-ghdl}"
|
||||
|
||||
$GHDL -m --work=neorv32 --workdir=build neorv32_tb_simple
|
||||
|
||||
if [ -z "$1" ]
|
||||
then
|
||||
GHDL_RUN_ARGS="${@:---stop-time=10ms}"
|
||||
else
|
||||
# Lets pass down all the parameters to GHDL instead of just 1
|
||||
GHDL_RUN_ARGS=$@
|
||||
fi
|
||||
|
||||
echo "Using simulation run arguments: $GHDL_RUN_ARGS";
|
||||
|
||||
runcmd="$GHDL -r --work=neorv32 --workdir=build neorv32_tb_simple \
|
||||
--max-stack-alloc=0 \
|
||||
--ieee-asserts=disable \
|
||||
--assert-level=error $GHDL_RUN_ARGS"
|
||||
|
||||
if [ -n "$GHDL_DEVNULL" ]; then
|
||||
$runcmd >> /dev/null
|
||||
else
|
||||
$runcmd
|
||||
fi
|
|
@ -1,20 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
cd $(dirname "$0")
|
||||
|
||||
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"}"
|
||||
|
||||
mkdir -p build
|
||||
|
||||
ghdl -i --work=neorv32 --workdir=build \
|
||||
$CORE_SRCS \
|
||||
"$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
|
|
@ -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;
|
119
sim/uart_rx.vhd
119
sim/uart_rx.vhd
|
@ -1,119 +0,0 @@
|
|||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
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);
|
||||
port (
|
||||
clk : in std_ulogic;
|
||||
uart_txd : in std_ulogic
|
||||
);
|
||||
end entity;
|
||||
|
||||
architecture a of uart_rx 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_" & get_name(handle.p_logger) & ".out";
|
||||
constant checker : checker_t := new_checker(handle.p_logger);
|
||||
constant character_queue : queue_t := new_queue;
|
||||
|
||||
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
|
||||
-- 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 * handle.p_baud_val);
|
||||
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 * handle.p_baud_val);
|
||||
else
|
||||
uart_rx_baud_cnt <= round(handle.p_baud_val);
|
||||
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");
|
||||
else
|
||||
expected_character := pop(character_queue);
|
||||
check_equal(checker, character'val(i), expected_character);
|
||||
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;
|
|
@ -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;
|
102
sim/xbus_gateway.vhd
Normal file
102
sim/xbus_gateway.vhd
Normal file
|
@ -0,0 +1,102 @@
|
|||
-- ================================================================================ --
|
||||
-- NEORV32 - Simple Combinatorial XBUS / Wishbone Gateway --
|
||||
-- -------------------------------------------------------------------------------- --
|
||||
-- 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;
|
||||
|
||||
library neorv32;
|
||||
use neorv32.neorv32_package.all;
|
||||
|
||||
entity xbus_gateway is
|
||||
generic (
|
||||
-- device address size in bytes and base address --
|
||||
DEV_0_SIZE : natural := 0; DEV_0_BASE : std_ulogic_vector(31 downto 0) := (others => '0');
|
||||
DEV_1_SIZE : natural := 0; DEV_1_BASE : std_ulogic_vector(31 downto 0) := (others => '0');
|
||||
DEV_2_SIZE : natural := 0; DEV_2_BASE : std_ulogic_vector(31 downto 0) := (others => '0');
|
||||
DEV_3_SIZE : natural := 0; DEV_3_BASE : std_ulogic_vector(31 downto 0) := (others => '0')
|
||||
);
|
||||
port (
|
||||
-- host port --
|
||||
host_req_i : in xbus_req_t;
|
||||
host_rsp_o : out xbus_rsp_t;
|
||||
-- device ports --
|
||||
dev_0_req_o : out xbus_req_t; dev_0_rsp_i : in xbus_rsp_t;
|
||||
dev_1_req_o : out xbus_req_t; dev_1_rsp_i : in xbus_rsp_t;
|
||||
dev_2_req_o : out xbus_req_t; dev_2_rsp_i : in xbus_rsp_t;
|
||||
dev_3_req_o : out xbus_req_t; dev_3_rsp_i : in xbus_rsp_t
|
||||
);
|
||||
end xbus_gateway;
|
||||
|
||||
architecture xbus_gateway_rtl of xbus_gateway is
|
||||
|
||||
-- module configuration --
|
||||
constant num_devs_c : natural := 4; -- number of device ports
|
||||
|
||||
-- list of device base address and address size --
|
||||
type dev_base_list_t is array (0 to num_devs_c-1) of std_ulogic_vector(31 downto 0);
|
||||
type dev_size_list_t is array (0 to num_devs_c-1) of natural;
|
||||
constant dev_base_list_c : dev_base_list_t := (DEV_0_BASE, DEV_1_BASE, DEV_2_BASE, DEV_3_BASE);
|
||||
constant dev_size_list_c : dev_size_list_t := (DEV_0_SIZE, DEV_1_SIZE, DEV_2_SIZE, DEV_3_SIZE);
|
||||
|
||||
-- device ports combined as arrays --
|
||||
type dev_req_t is array (0 to num_devs_c-1) of xbus_req_t;
|
||||
type dev_rsp_t is array (0 to num_devs_c-1) of xbus_rsp_t;
|
||||
signal dev_req : dev_req_t;
|
||||
signal dev_rsp : dev_rsp_t;
|
||||
|
||||
-- access enable --
|
||||
signal acc_en : std_ulogic_vector(num_devs_c-1 downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- combine device ports --
|
||||
dev_0_req_o <= dev_req(0); dev_rsp(0) <= dev_0_rsp_i;
|
||||
dev_1_req_o <= dev_req(1); dev_rsp(1) <= dev_1_rsp_i;
|
||||
dev_2_req_o <= dev_req(2); dev_rsp(2) <= dev_2_rsp_i;
|
||||
dev_3_req_o <= dev_req(3); dev_rsp(3) <= dev_3_rsp_i;
|
||||
|
||||
-- device select --
|
||||
acc_en_gen:
|
||||
for i in 0 to num_devs_c-1 generate
|
||||
acc_en(i) <= '1' when (dev_size_list_c(i) > 0) and
|
||||
(unsigned(host_req_i.addr) >= unsigned(dev_base_list_c(i))) and
|
||||
(unsigned(host_req_i.addr) < (unsigned(dev_base_list_c(i)) + dev_size_list_c(i))) else '0';
|
||||
end generate;
|
||||
|
||||
-- request --
|
||||
bus_request_gen:
|
||||
for i in 0 to num_devs_c-1 generate
|
||||
bus_request: process(host_req_i, acc_en)
|
||||
begin
|
||||
dev_req(i) <= host_req_i;
|
||||
dev_req(i).cyc <= host_req_i.cyc and acc_en(i);
|
||||
dev_req(i).stb <= host_req_i.stb and acc_en(i);
|
||||
end process bus_request;
|
||||
end generate;
|
||||
|
||||
-- response --
|
||||
bus_response: process(dev_rsp, acc_en)
|
||||
variable tmp_v : xbus_rsp_t;
|
||||
begin
|
||||
tmp_v.data := (others => '0');
|
||||
tmp_v.ack := '0';
|
||||
tmp_v.err := '0';
|
||||
for i in 0 to num_devs_c-1 loop -- OR all enabled response buses
|
||||
if (acc_en(i) = '1') then
|
||||
tmp_v.data := tmp_v.data or dev_rsp(i).data;
|
||||
tmp_v.ack := tmp_v.ack or dev_rsp(i).ack;
|
||||
tmp_v.err := tmp_v.err or dev_rsp(i).err;
|
||||
end if;
|
||||
end loop;
|
||||
host_rsp_o <= tmp_v;
|
||||
end process bus_response;
|
||||
|
||||
end xbus_gateway_rtl;
|
100
sim/xbus_memory.vhd
Normal file
100
sim/xbus_memory.vhd
Normal file
|
@ -0,0 +1,100 @@
|
|||
-- ================================================================================ --
|
||||
-- NEORV32 - Simple XBUS / Wishbone Memory (meant for simulation 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;
|
||||
|
||||
library neorv32;
|
||||
use neorv32.neorv32_package.all;
|
||||
|
||||
entity xbus_memory is
|
||||
generic (
|
||||
MEM_SIZE : natural := 1024; -- memory size in bytes; should be a power of two
|
||||
MEM_LATE : natural := 1 -- number of latency cycles (min 1)
|
||||
);
|
||||
port (
|
||||
clk_i : in std_ulogic;
|
||||
rstn_i : in std_ulogic;
|
||||
xbus_req_i : in xbus_req_t;
|
||||
xbus_rsp_o : out xbus_rsp_t
|
||||
);
|
||||
end xbus_memory;
|
||||
|
||||
architecture xbus_memory_rtl of xbus_memory is
|
||||
|
||||
-- memory type --
|
||||
type mem8_bv_t is array (natural range <>) of bit_vector(7 downto 0); -- bit_vector type for optimized system storage
|
||||
|
||||
-- memory access --
|
||||
signal addr : integer range 0 to (MEM_SIZE/4)-1;
|
||||
signal rdata : std_ulogic_vector(31 downto 0);
|
||||
signal ack : std_ulogic;
|
||||
|
||||
-- latency generator --
|
||||
type late_data_t is array (MEM_LATE downto 0) of std_ulogic_vector(31 downto 0);
|
||||
signal late_data : late_data_t;
|
||||
signal late_ack : std_ulogic_vector(MEM_LATE downto 0);
|
||||
|
||||
begin
|
||||
|
||||
-- word-aligned read/write address --
|
||||
addr <= to_integer(unsigned(xbus_req_i.addr(index_size_f(MEM_SIZE/4)+1 downto 2)));
|
||||
|
||||
|
||||
-- Non-Initialized Memory Core ------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
memory_core: process(clk_i)
|
||||
variable mem8_bv_b0_v, mem8_bv_b1_v, mem8_bv_b2_v, mem8_bv_b3_v : mem8_bv_t(0 to (MEM_SIZE/4)-1);
|
||||
begin
|
||||
if rising_edge(clk_i) then
|
||||
ack <= '0';
|
||||
if (xbus_req_i.cyc = '1') and (xbus_req_i.stb = '1') then
|
||||
ack <= '1';
|
||||
if (xbus_req_i.we = '1') then
|
||||
if (xbus_req_i.sel(0) = '1') then mem8_bv_b0_v(addr) := to_bitvector(xbus_req_i.data(07 downto 00)); end if;
|
||||
if (xbus_req_i.sel(1) = '1') then mem8_bv_b1_v(addr) := to_bitvector(xbus_req_i.data(15 downto 08)); end if;
|
||||
if (xbus_req_i.sel(2) = '1') then mem8_bv_b2_v(addr) := to_bitvector(xbus_req_i.data(23 downto 16)); end if;
|
||||
if (xbus_req_i.sel(3) = '1') then mem8_bv_b3_v(addr) := to_bitvector(xbus_req_i.data(31 downto 24)); end if;
|
||||
else
|
||||
rdata(07 downto 00) <= to_stdulogicvector(mem8_bv_b0_v(addr));
|
||||
rdata(15 downto 08) <= to_stdulogicvector(mem8_bv_b1_v(addr));
|
||||
rdata(23 downto 16) <= to_stdulogicvector(mem8_bv_b2_v(addr));
|
||||
rdata(31 downto 24) <= to_stdulogicvector(mem8_bv_b3_v(addr));
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process memory_core;
|
||||
|
||||
|
||||
-- Latency Generator ----------------------------------------------------------------------
|
||||
-- -------------------------------------------------------------------------------------------
|
||||
latency_gen: process(rstn_i, clk_i)
|
||||
begin
|
||||
if (rstn_i = '0') then
|
||||
late_data <= (others => (others => '0'));
|
||||
late_ack <= (others => '0');
|
||||
elsif rising_edge(clk_i) then
|
||||
late_data(0) <= rdata;
|
||||
late_ack(0) <= ack;
|
||||
for i in 0 to MEM_LATE-1 loop
|
||||
late_data(i+1) <= late_data(i);
|
||||
late_ack(i+1) <= late_ack(i);
|
||||
end loop;
|
||||
end if;
|
||||
end process latency_gen;
|
||||
|
||||
-- bus response --
|
||||
xbus_rsp_o.data <= rdata when (MEM_LATE = 1) else late_data(MEM_LATE-1);
|
||||
xbus_rsp_o.ack <= ack when (MEM_LATE = 1) else late_ack(MEM_LATE-1);
|
||||
xbus_rsp_o.err <= '0';
|
||||
|
||||
|
||||
end xbus_memory_rtl;
|
|
@ -2,11 +2,13 @@
|
|||
|
||||
# Minimal RISC-V ISA only
|
||||
MARCH = rv32i_zicsr_zifencei
|
||||
MABI = ilp32
|
||||
|
||||
# Optimize for minimal size
|
||||
EFFORT = -Os
|
||||
|
||||
# Adjust memory size and base for BOOTROM
|
||||
# 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 += \
|
||||
|
|
|
@ -25,8 +25,8 @@ ASM_INC ?= -I .
|
|||
# Optimization
|
||||
EFFORT ?= -Os
|
||||
|
||||
# Compiler toolchain
|
||||
RISCV_PREFIX ?= riscv32-unknown-elf-
|
||||
# Compiler toolchain prefix
|
||||
RISCV_PREFIX ?= riscv-none-elf-
|
||||
|
||||
# CPU architecture and ABI
|
||||
MARCH ?= rv32i_zicsr_zifencei
|
||||
|
@ -59,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
|
||||
|
||||
|
@ -195,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)
|
||||
|
@ -213,26 +215,31 @@ 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))
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
@ -241,7 +248,8 @@ $(APP_MEM): 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 BOOTROM image to VHDL source directory
|
||||
bootloader: bl_image
|
||||
|
@ -279,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)
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
|
@ -375,7 +383,7 @@ help:
|
|||
@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/simple testbench and GHDL"
|
||||
@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"
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
## Dhrystone Benchmark
|
||||
|
||||
**:warning: The Dhrystone port is outdated. Have a look at the CoreMark port for benchmarking.**
|
||||
|
||||
:copyright: Original sources from [https://github.com/sifive/benchmark-dhrystone](https://github.com/sifive/benchmark-dhrystone);
|
||||
see `LICENSE` file. The origianl source code has been modified for the NEORV32 RISC-V Processor.
|
||||
see `LICENSE` file. The original source code has been modified for the NEORV32 RISC-V Processor.
|
||||
|
||||
To compile the `main.exe` executable:
|
||||
|
||||
|
|
|
@ -54,12 +54,10 @@
|
|||
|
||||
#define __USE_GNU
|
||||
|
||||
#include <fenv.h>
|
||||
//#pragma STDC FENV_ACCESS ON
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <float.h>
|
||||
#include <fenv.h>
|
||||
#include <math.h>
|
||||
|
||||
|
||||
|
@ -130,37 +128,6 @@ uint32_t get_hw_exceptions(void) {
|
|||
}
|
||||
|
||||
|
||||
/**********************************************************************//**
|
||||
* Get exception flags from C runtime (floating-point emulation).
|
||||
*
|
||||
* @warning WORK-IN-PROGRESS!
|
||||
*
|
||||
* @return Floating point exception status word.
|
||||
**************************************************************************/
|
||||
uint32_t get_sw_exceptions(void) {
|
||||
|
||||
const uint32_t FP_EXC_NV_C = 1 << 0; // invalid operation
|
||||
const uint32_t FP_EXC_DZ_C = 1 << 1; // divide by zero
|
||||
const uint32_t FP_EXC_OF_C = 1 << 2; // overflow
|
||||
const uint32_t FP_EXC_UF_C = 1 << 3; // underflow
|
||||
const uint32_t FP_EXC_NX_C = 1 << 4; // inexact
|
||||
|
||||
int fpeRaised = fetestexcept(FE_ALL_EXCEPT);
|
||||
|
||||
uint32_t res = 0;
|
||||
|
||||
if (fpeRaised & FE_INVALID) { res |= FP_EXC_NV_C; }
|
||||
if (fpeRaised & FE_DIVBYZERO) { res |= FP_EXC_DZ_C; }
|
||||
if (fpeRaised & FE_OVERFLOW) { res |= FP_EXC_OF_C; }
|
||||
if (fpeRaised & FE_UNDERFLOW) { res |= FP_EXC_UF_C; }
|
||||
if (fpeRaised & FE_INEXACT) { res |= FP_EXC_NX_C; }
|
||||
|
||||
feclearexcept(FE_ALL_EXCEPT);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// ################################################################################################
|
||||
// "Intrinsics"
|
||||
// ################################################################################################
|
||||
|
|
|
@ -33,4 +33,4 @@ NEORV32_HOME ?= ../../..
|
|||
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.out | grep "Hello world! :)"
|
||||
|
|
|
@ -6,8 +6,8 @@ TOPTARGETS := exe clean_all check info all
|
|||
SUBDIRS := $(wildcard */.)
|
||||
# ignore dummy folders (starting with '~')
|
||||
EXCLDIR := $(wildcard ~*/.)
|
||||
# ignore the Eclipse project
|
||||
EXCLDIR += eclipse/.
|
||||
# ignore some of the default projects/examples
|
||||
EXCLDIR += eclipse/. dhrystone/. performance_tests/. float_corner_test/.
|
||||
SUBDIRS := $(filter-out $(EXCLDIR), $(SUBDIRS))
|
||||
|
||||
$(TOPTARGETS): $(SUBDIRS)
|
||||
|
|
|
@ -31,6 +31,8 @@
|
|||
#define ADDR_UNREACHABLE (NEORV32_DM_BASE)
|
||||
//** External memory base address */
|
||||
#define EXT_MEM_BASE (0xF0000000UL)
|
||||
//** External IRQ trigger base address */
|
||||
#define SIM_TRIG_BASE (0xFF000000UL)
|
||||
/**@}*/
|
||||
|
||||
|
||||
|
@ -239,9 +241,9 @@ int main() {
|
|||
|
||||
cnt_test++;
|
||||
|
||||
// set execute permission for u-mode
|
||||
// set execute permission for u-mode for the entire address range
|
||||
// use entry 2 so we can use entries 0 & 1 later on for higher-prioritized configurations
|
||||
tmp_a = neorv32_cpu_pmp_configure_region(2, -1, (PMP_NAPOT << PMPCFG_A_LSB) | (1 << PMPCFG_X));
|
||||
tmp_a = neorv32_cpu_pmp_configure_region(2, 0xffffffff, (PMP_NAPOT << PMPCFG_A_LSB) | (1 << PMPCFG_X));
|
||||
|
||||
if ((neorv32_cpu_csr_read(CSR_MCAUSE) == mcause_never_c) && (tmp_a == 0)) {
|
||||
test_ok();
|
||||
|
@ -2237,7 +2239,7 @@ int main() {
|
|||
**************************************************************************/
|
||||
void sim_irq_trigger(uint32_t sel) {
|
||||
|
||||
*((volatile uint32_t*) (0xFF000000)) = sel;
|
||||
*((volatile uint32_t*)SIM_TRIG_BASE) = sel;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ override USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=32k
|
|||
override USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k
|
||||
|
||||
# Adjust maximum heap size
|
||||
#SER_FLAGS += -Wl,--defsym,__neorv32_heap_size=3096
|
||||
override USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=3096
|
||||
|
||||
# Simulation arguments
|
||||
override GHDL_RUN_FLAGS ?= --stop-time=15ms
|
||||
|
@ -40,4 +40,4 @@ include $(NEORV32_HOME)/sw/common/common.mk
|
|||
|
||||
# Add test-specific makefile target
|
||||
sim-check: sim
|
||||
cat $(NEORV32_HOME)/sim/simple/neorv32.uart0.sim_mode.text.out | grep "PROCESSOR TEST COMPLETED SUCCESSFULLY!"
|
||||
cat $(NEORV32_HOME)/sim/neorv32.uart0_sim_mode.out | grep "PROCESSOR TEST COMPLETED SUCCESSFULLY!"
|
||||
|
|
|
@ -20,8 +20,8 @@ const uint32_t signature = 0x4788CAFE;
|
|||
// output file types (operation select)
|
||||
enum operation_enum {
|
||||
OP_APP_BIN,
|
||||
OP_APP_IMG,
|
||||
OP_BLD_IMG,
|
||||
OP_APP_VHD,
|
||||
OP_BLD_VHD,
|
||||
OP_RAW_HEX,
|
||||
OP_RAW_BIN,
|
||||
OP_RAW_COE,
|
||||
|
@ -36,8 +36,8 @@ int main(int argc, char *argv[]) {
|
|||
"Three arguments are required.\n"
|
||||
"1st: Operation\n"
|
||||
" -app_bin : Generate application executable binary (binary file, little-endian, with header) \n"
|
||||
" -app_img : Generate application raw executable memory image (vhdl package body file, no header)\n"
|
||||
" -bld_img : Generate bootloader raw executable memory image (vhdl package body file, no header)\n"
|
||||
" -app_vhd : Generate application raw executable memory image (vhdl package body file, no header)\n"
|
||||
" -bld_vhd : Generate bootloader raw executable memory image (vhdl package body file, no header)\n"
|
||||
" -raw_hex : Generate application raw executable (ASCII hex file, no header)\n"
|
||||
" -raw_bin : Generate application raw executable (binary file, no header)\n"
|
||||
" -raw_coe : Generate application raw executable (COE file, no header)\n"
|
||||
|
@ -58,22 +58,22 @@ int main(int argc, char *argv[]) {
|
|||
unsigned long raw_exe_size = 0;
|
||||
|
||||
if (strcmp(argv[1], "-app_bin") == 0) { operation = OP_APP_BIN; }
|
||||
else if (strcmp(argv[1], "-app_img") == 0) { operation = OP_APP_IMG; }
|
||||
else if (strcmp(argv[1], "-bld_img") == 0) { operation = OP_BLD_IMG; }
|
||||
else if (strcmp(argv[1], "-app_vhd") == 0) { operation = OP_APP_VHD; }
|
||||
else if (strcmp(argv[1], "-bld_vhd") == 0) { operation = OP_BLD_VHD; }
|
||||
else if (strcmp(argv[1], "-raw_hex") == 0) { operation = OP_RAW_HEX; }
|
||||
else if (strcmp(argv[1], "-raw_bin") == 0) { operation = OP_RAW_BIN; }
|
||||
else if (strcmp(argv[1], "-raw_coe") == 0) { operation = OP_RAW_COE; }
|
||||
else if (strcmp(argv[1], "-raw_mem") == 0) { operation = OP_RAW_MEM; }
|
||||
else if (strcmp(argv[1], "-raw_mif") == 0) { operation = OP_RAW_MIF; }
|
||||
else {
|
||||
printf("Invalid operation!");
|
||||
printf("Invalid operation '%s'!\n", argv[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// open input file
|
||||
input = fopen(argv[2], "rb");
|
||||
if(input == NULL) {
|
||||
printf("Input file error!");
|
||||
printf("Input file error (%s)!\n", argv[2]);
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
@ -84,12 +84,12 @@ int main(int argc, char *argv[]) {
|
|||
rewind(input);
|
||||
|
||||
if ((input_size % 4) != 0) {
|
||||
printf("WARNING - image size is not a multiple of 4 bytes.\n");
|
||||
printf("WARNING - image size is not a multiple of 4 bytes!\n");
|
||||
}
|
||||
|
||||
// input file empty?
|
||||
if(input_size == 0) {
|
||||
printf("Input file is empty!");
|
||||
printf("Input file is empty (%s)!\n", argv[2]);
|
||||
fclose(input);
|
||||
return -3;
|
||||
}
|
||||
|
@ -97,32 +97,21 @@ int main(int argc, char *argv[]) {
|
|||
// open output file
|
||||
output = fopen(argv[3], "wb");
|
||||
if(output == NULL) {
|
||||
printf("Output file error!");
|
||||
printf("Output file error (%s)!\n", argv[3]);
|
||||
fclose(input);
|
||||
return -4;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Try to find out targeted CPU configuration via MARCH environment variable
|
||||
// --------------------------------------------------------------------------
|
||||
char string_march[64] = "default";
|
||||
char *envvar_march = "MARCH";
|
||||
if (getenv(envvar_march)) {
|
||||
if (snprintf(string_march, 64, "%s", getenv(envvar_march)) >= 64){
|
||||
strcpy(string_march, "default");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Get image's compilation date and time
|
||||
// Image's compilation date and time
|
||||
// --------------------------------------------------------------------------
|
||||
time_t time_current;
|
||||
time(&time_current);
|
||||
struct tm *time_local = localtime(&time_current);
|
||||
char compile_time[64];
|
||||
|
||||
snprintf(compile_time, 64, "%02d.%02d.%d %02d:%02d:%02d (dd.mm.yyyy hh:mm:ss)",
|
||||
snprintf(compile_time, 64, "%02d.%02d.%d %02d:%02d:%02d",
|
||||
time_local->tm_mday,
|
||||
time_local->tm_mon + 1,
|
||||
time_local->tm_year + 1900,
|
||||
|
@ -133,7 +122,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Get size of application (in bytes)
|
||||
// Size of application (in bytes)
|
||||
// --------------------------------------------------------------------------
|
||||
fseek(input, 0L, SEEK_END);
|
||||
|
||||
|
@ -204,22 +193,26 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Generate RAW APPLICATION's executable memory initialization file
|
||||
// -> VHDL package body
|
||||
// Generate APPLICATION executable memory initialization image package (IMEM)
|
||||
// --------------------------------------------------------------------------
|
||||
else if (operation == OP_APP_IMG) {
|
||||
else if (operation == OP_APP_VHD) {
|
||||
|
||||
// header
|
||||
sprintf(tmp_string, "-- The NEORV32 RISC-V Processor: https://github.com/stnolting/neorv32\n"
|
||||
"-- Auto-generated memory initialization file (for APPLICATION) from source file <%s/%s>\n"
|
||||
sprintf(tmp_string, "-- The NEORV32 RISC-V Processor - github.com/stnolting/neorv32\n"
|
||||
"-- Auto-generated memory initialization package (for internal IMEM)\n"
|
||||
"-- Source: %s/%s\n"
|
||||
"-- Size: %lu bytes\n"
|
||||
"-- MARCH: %s\n"
|
||||
"-- Built: %s\n"
|
||||
"\n"
|
||||
"-- prototype defined in 'neorv32_package.vhd'\n"
|
||||
"package body neorv32_application_image is\n"
|
||||
"library ieee;\n"
|
||||
"use ieee.std_logic_1164.all;\n"
|
||||
"\n"
|
||||
"constant application_init_image : mem32_t := (\n", argv[4], argv[2], raw_exe_size, string_march, compile_time);
|
||||
"library neorv32;\n"
|
||||
"use neorv32.neorv32_package.all;\n"
|
||||
"\n"
|
||||
"package neorv32_application_image is\n"
|
||||
"\n"
|
||||
"constant application_init_image : mem32_t := (\n", argv[4], argv[2], raw_exe_size, compile_time);
|
||||
fputs(tmp_string, output);
|
||||
|
||||
i = 0;
|
||||
|
@ -261,22 +254,26 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Generate RAW BOOTLOADER's executable memory initialization file
|
||||
// -> VHDL package body
|
||||
// Generate BOOTLOADER executable memory initialization image package (BOOTROM)
|
||||
// --------------------------------------------------------------------------
|
||||
else if (operation == OP_BLD_IMG) {
|
||||
else if (operation == OP_BLD_VHD) {
|
||||
|
||||
// header
|
||||
sprintf(tmp_string, "-- The NEORV32 RISC-V Processor: https://github.com/stnolting/neorv32\n"
|
||||
"-- Auto-generated memory initialization file (for BOOTLOADER) from source file <%s/%s>\n"
|
||||
sprintf(tmp_string, "-- The NEORV32 RISC-V Processor - github.com/stnolting/neorv32\n"
|
||||
"-- Auto-generated memory initialization package (for internal BOOTROM)\n"
|
||||
"-- Source: %s/%s\n"
|
||||
"-- Size: %lu bytes\n"
|
||||
"-- MARCH: %s\n"
|
||||
"-- Built: %s\n"
|
||||
"\n"
|
||||
"-- prototype defined in 'neorv32_package.vhd'\n"
|
||||
"package body neorv32_bootloader_image is\n"
|
||||
"library ieee;\n"
|
||||
"use ieee.std_logic_1164.all;\n"
|
||||
"\n"
|
||||
"constant bootloader_init_image : mem32_t := (\n", argv[4], argv[2], raw_exe_size, string_march, compile_time);
|
||||
"library neorv32;\n"
|
||||
"use neorv32.neorv32_package.all;\n"
|
||||
"\n"
|
||||
"package neorv32_bootloader_image is\n"
|
||||
"\n"
|
||||
"constant bootloader_init_image : mem32_t := (\n", argv[4], argv[2], raw_exe_size, compile_time);
|
||||
fputs(tmp_string, output);
|
||||
|
||||
i = 0;
|
||||
|
@ -352,7 +349,7 @@ int main(int argc, char *argv[]) {
|
|||
// header
|
||||
sprintf(tmp_string, "memory_initialization_radix=16;\n");
|
||||
fputs(tmp_string, output);
|
||||
sprintf(tmp_string, "memory_initialization_vector=");
|
||||
sprintf(tmp_string, "memory_initialization_vector=\n");
|
||||
fputs(tmp_string, output);
|
||||
|
||||
i = 0;
|
||||
|
@ -362,18 +359,14 @@ int main(int argc, char *argv[]) {
|
|||
tmp |= (uint32_t)(buffer[2] << 16);
|
||||
tmp |= (uint32_t)(buffer[3] << 24);
|
||||
if (i == (input_words-1)) {
|
||||
sprintf(tmp_string, "\n%08x", (unsigned int)tmp);
|
||||
sprintf(tmp_string, "%08x;\n", (unsigned int)tmp);
|
||||
}
|
||||
else {
|
||||
sprintf(tmp_string, "\n%08x,", (unsigned int)tmp);
|
||||
sprintf(tmp_string, "%08x,\n", (unsigned int)tmp);
|
||||
}
|
||||
fputs(tmp_string, output);
|
||||
i++;
|
||||
}
|
||||
|
||||
// footer
|
||||
sprintf(tmp_string, ";\n");
|
||||
fputs(tmp_string, output);
|
||||
}
|
||||
|
||||
|
||||
|
@ -435,7 +428,7 @@ int main(int argc, char *argv[]) {
|
|||
// Invalid operation
|
||||
// --------------------------------------------------------------------------
|
||||
else {
|
||||
printf("Invalid operation!");
|
||||
printf("Invalid operation!\n");
|
||||
fclose(input);
|
||||
fclose(output);
|
||||
return -1;
|
||||
|
@ -443,7 +436,7 @@ int main(int argc, char *argv[]) {
|
|||
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Done, clean up
|
||||
// Clean up
|
||||
// --------------------------------------------------------------------------
|
||||
fclose(input);
|
||||
fclose(output);
|
||||
|
|
|
@ -66,6 +66,7 @@ enum NEORV32_RTE_TRAP_enum {
|
|||
**************************************************************************/
|
||||
/**@{*/
|
||||
void neorv32_rte_setup(void);
|
||||
void neorv32_rte_core(void);
|
||||
int neorv32_rte_handler_install(int id, void (*handler)(void));
|
||||
int neorv32_rte_handler_uninstall(int id);
|
||||
void neorv32_rte_debug_handler(void);
|
||||
|
|
|
@ -37,12 +37,14 @@ typedef volatile struct __attribute__((packed,aligned(4))) {
|
|||
/** NEORV32_SYSINFO.MEM (r/-): Memory configuration (sizes) */
|
||||
enum NEORV32_SYSINFO_MEM_enum {
|
||||
SYSINFO_MEM_IMEM = 0, /**< SYSINFO_MEM byte 0 (r/-): log2(internal IMEM size in bytes) (via MEM_INT_IMEM_SIZE generic) */
|
||||
SYSINFO_MEM_DMEM = 1 /**< SYSINFO_MEM byte 1 (r/-): log2(internal DMEM size in bytes) (via MEM_INT_DMEM_SIZE generic) */
|
||||
SYSINFO_MEM_DMEM = 1, /**< SYSINFO_MEM byte 1 (r/-): log2(internal DMEM size in bytes) (via MEM_INT_DMEM_SIZE generic) */
|
||||
SYSINFO_MEM_res = 2, /**< SYSINFO_MEM byte 2 (r/-): reserved, read as zero */
|
||||
SYSINFO_MEM_BOOT = 3 /**< SYSINFO_MEM byte 3 (r/-): boot mode configuration (via BOOT_MODE_SELECT generic) */
|
||||
};
|
||||
|
||||
/** NEORV32_SYSINFO.SOC (r/-): Implemented processor devices/features */
|
||||
enum NEORV32_SYSINFO_SOC_enum {
|
||||
SYSINFO_SOC_BOOTLOADER = 0, /**< SYSINFO_SOC (0) (r/-): Bootloader implemented when 1 (via INT_BOOTLOADER_EN generic) */
|
||||
SYSINFO_SOC_BOOTLOADER = 0, /**< SYSINFO_SOC (0) (r/-): Bootloader implemented when 1 (via BOOT_MODE_SELECT generic) */
|
||||
SYSINFO_SOC_XBUS = 1, /**< SYSINFO_SOC (1) (r/-): External bus interface implemented when 1 (via XBUS_EN generic) */
|
||||
SYSINFO_SOC_MEM_INT_IMEM = 2, /**< SYSINFO_SOC (2) (r/-): Processor-internal instruction memory implemented when 1 (via MEM_INT_IMEM_EN generic) */
|
||||
SYSINFO_SOC_MEM_INT_DMEM = 3, /**< SYSINFO_SOC (3) (r/-): Processor-internal data memory implemented when 1 (via MEM_INT_DMEM_EN generic) */
|
||||
|
@ -54,6 +56,7 @@ enum NEORV32_SYSINFO_SOC_enum {
|
|||
SYSINFO_SOC_XIP = 9, /**< SYSINFO_SOC (9) (r/-): Execute in-place module implemented when 1 (via XIP_EN generic) */
|
||||
SYSINFO_SOC_XIP_CACHE = 10, /**< SYSINFO_SOC (10) (r/-): Execute in-place cache implemented when 1 (via XIP_CACHE_EN generic) */
|
||||
SYSINFO_SOC_OCD_AUTH = 11, /**< SYSINFO_SOC (11) (r/-): On-chip debugger authentication implemented when 1 (via OCD_AUTHENTICATION generic) */
|
||||
SYSINFO_SOC_IMEM_ROM = 12, /**< SYSINFO_SOC (12) (r/-): Processor-internal instruction memory implemented as pre-initialized ROM when 1 (via BOOT_MODE_SELECT generic) */
|
||||
|
||||
SYSINFO_SOC_IO_DMA = 14, /**< SYSINFO_SOC (14) (r/-): Direct memory access controller implemented when 1 (via IO_DMA_EN generic) */
|
||||
SYSINFO_SOC_IO_GPIO = 15, /**< SYSINFO_SOC (15) (r/-): General purpose input/output port unit implemented when 1 (via IO_GPIO_EN generic) */
|
||||
|
|
|
@ -301,7 +301,7 @@ uint32_t neorv32_cpu_pmp_get_granularity(void) {
|
|||
* @warning This function expects a WORD address!
|
||||
*
|
||||
* @param[in] index Region number (index, 0..PMP_NUM_REGIONS-1).
|
||||
* @param[in] addr Region address (word address!).
|
||||
* @param[in] addr Region address (bits [33:2]).
|
||||
* @param[in] config Region configuration byte (see #NEORV32_PMPCFG_ATTRIBUTES_enum).
|
||||
* @return Returns 0 on success, !=0 on failure.
|
||||
**************************************************************************/
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
static uint32_t __neorv32_rte_vector_lut[NEORV32_RTE_NUM_TRAPS] __attribute__((unused)); // trap handler vector table
|
||||
|
||||
// private functions
|
||||
static void __attribute__((__naked__,aligned(4))) __neorv32_rte_core(void);
|
||||
static void __neorv32_rte_print_hex_word(uint32_t num);
|
||||
|
||||
|
||||
|
@ -41,7 +40,7 @@ void neorv32_rte_setup(void) {
|
|||
neorv32_cpu_csr_write(CSR_MSTATUS, (1<<CSR_MSTATUS_MPP_H) | (1<<CSR_MSTATUS_MPP_L));
|
||||
|
||||
// configure trap handler base address
|
||||
neorv32_cpu_csr_write(CSR_MTVEC, (uint32_t)(&__neorv32_rte_core));
|
||||
neorv32_cpu_csr_write(CSR_MTVEC, (uint32_t)(&neorv32_rte_core));
|
||||
|
||||
// disable all IRQ channels
|
||||
neorv32_cpu_csr_write(CSR_MIE, 0);
|
||||
|
@ -98,7 +97,7 @@ int neorv32_rte_handler_uninstall(int id) {
|
|||
* NEORV32 runtime environment (RTE):
|
||||
* This is the core of the NEORV32 RTE (first-level trap handler, executed in machine mode).
|
||||
**************************************************************************/
|
||||
static void __attribute__((__naked__,aligned(4))) __neorv32_rte_core(void) {
|
||||
void __attribute__((__naked__,aligned(4))) neorv32_rte_core(void) {
|
||||
|
||||
// save context
|
||||
asm volatile (
|
||||
|
@ -493,21 +492,24 @@ void neorv32_rte_print_hw_config(void) {
|
|||
neorv32_uart0_printf("\nPhys. Memory Prot.: ");
|
||||
uint32_t pmp_num_regions = neorv32_cpu_pmp_get_num_regions();
|
||||
if (pmp_num_regions != 0) {
|
||||
neorv32_uart0_printf("%u region(s), %u bytes granularity, modes={OFF", pmp_num_regions, neorv32_cpu_pmp_get_granularity());
|
||||
neorv32_uart0_printf("%u region(s), %u bytes granularity, modes =", pmp_num_regions, neorv32_cpu_pmp_get_granularity());
|
||||
// check implemented modes
|
||||
neorv32_cpu_csr_write(CSR_PMPCFG0, (PMP_OFF << PMPCFG_A_LSB)); // try to set mode "OFF"
|
||||
if ((neorv32_cpu_csr_read(CSR_PMPCFG0) & 0xff) == (PMP_OFF << PMPCFG_A_LSB)) {
|
||||
neorv32_uart0_printf(" OFF");
|
||||
}
|
||||
neorv32_cpu_csr_write(CSR_PMPCFG0, (PMP_TOR << PMPCFG_A_LSB)); // try to set mode "TOR"
|
||||
if ((neorv32_cpu_csr_read(CSR_PMPCFG0) & 0xff) == (PMP_TOR << PMPCFG_A_LSB)) {
|
||||
neorv32_uart0_printf(",TOR");
|
||||
neorv32_uart0_printf(" TOR");
|
||||
}
|
||||
neorv32_cpu_csr_write(CSR_PMPCFG0, (PMP_NA4 << PMPCFG_A_LSB)); // try to set mode "NA4"
|
||||
if ((neorv32_cpu_csr_read(CSR_PMPCFG0) & 0xff) == (PMP_NA4 << PMPCFG_A_LSB)) {
|
||||
neorv32_uart0_printf(",NA4");
|
||||
neorv32_uart0_printf(" NA4");
|
||||
}
|
||||
neorv32_cpu_csr_write(CSR_PMPCFG0, (PMP_NAPOT << PMPCFG_A_LSB)); // try to set mode "NAPOT"
|
||||
if ((neorv32_cpu_csr_read(CSR_PMPCFG0) & 0xff) == (PMP_NAPOT << PMPCFG_A_LSB)) {
|
||||
neorv32_uart0_printf(",NAPOT");
|
||||
neorv32_uart0_printf(" NAPOT");
|
||||
}
|
||||
neorv32_uart0_putc('}');
|
||||
neorv32_cpu_csr_write(CSR_PMPCFG0, 0); // disable PMP entry again
|
||||
}
|
||||
else {
|
||||
|
@ -524,12 +526,13 @@ void neorv32_rte_print_hw_config(void) {
|
|||
neorv32_uart0_printf("none");
|
||||
}
|
||||
|
||||
neorv32_uart0_printf("\nBoot configuration: Boot ");
|
||||
if (NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_BOOTLOADER)) {
|
||||
neorv32_uart0_printf("via Bootloader\n");
|
||||
}
|
||||
else {
|
||||
neorv32_uart0_printf("from memory\n");
|
||||
neorv32_uart0_printf("\nBoot configuration: ");
|
||||
int boot_config = (int)(NEORV32_SYSINFO->MEM[SYSINFO_MEM_BOOT]);
|
||||
switch (boot_config) {
|
||||
case 0: neorv32_uart0_printf("boot via bootloader (0)\n"); break;
|
||||
case 1: neorv32_uart0_printf("boot from custom address (1)\n"); break;
|
||||
case 2: neorv32_uart0_printf("boot from pre-initialized IMEM (2)\n"); break;
|
||||
default: neorv32_uart0_printf("unknown (%u)\n", boot_config); break;
|
||||
}
|
||||
|
||||
// internal IMEM
|
||||
|
@ -618,9 +621,9 @@ void neorv32_rte_print_hw_config(void) {
|
|||
neorv32_uart0_printf("Ext. bus interface: ");
|
||||
tmp = NEORV32_SYSINFO->SOC;
|
||||
if (tmp & (1 << SYSINFO_SOC_XBUS)) {
|
||||
neorv32_uart0_printf("Wishbone-b4 ");
|
||||
neorv32_uart0_printf("enabled ");
|
||||
if (tmp & (1 << SYSINFO_SOC_XBUS_CACHE)) {
|
||||
neorv32_uart0_printf("x-cache\n");
|
||||
neorv32_uart0_printf("+ xbus-cache\n");
|
||||
}
|
||||
else {
|
||||
neorv32_uart0_printf("\n");
|
||||
|
|
|
@ -83,14 +83,14 @@ void neorv32_uart_setup(neorv32_uart_t *UARTx, uint32_t baudrate, uint32_t irq_m
|
|||
tmp |= (uint32_t)(irq_mask & (0x1fU << UART_CTRL_IRQ_RX_NEMPTY));
|
||||
|
||||
#ifdef UART0_SIM_MODE
|
||||
#warning UART0_SIM_MODE (primary UART) enabled! Sending all UART0.TX data to text.io simulation output instead of real UART0 transmitter. Use this for simulations only!
|
||||
#warning UART0_SIM_MODE (primary UART) enabled! Sending all UART0.TX data to text.io simulation output instead of real UART0 transmitter. Use this for simulation only!
|
||||
if (((uint32_t)UARTx) == NEORV32_UART0_BASE) {
|
||||
tmp |= 1U << UART_CTRL_SIM_MODE;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef UART1_SIM_MODE
|
||||
#warning UART1_SIM_MODE (secondary UART) enabled! Sending all UART1.TX data to text.io simulation output instead of real UART1 transmitter. Use this for simulations only!
|
||||
#warning UART1_SIM_MODE (secondary UART) enabled! Sending all UART1.TX data to text.io simulation output instead of real UART1 transmitter. Use this for simulation only!
|
||||
if (((uint32_t)UARTx) == NEORV32_UART1_BASE) {
|
||||
tmp |= 1U << UART_CTRL_SIM_MODE;
|
||||
}
|
||||
|
|
|
@ -1591,10 +1591,10 @@
|
|||
<addressOffset>0x04</addressOffset>
|
||||
<access>read-only</access>
|
||||
<fields>
|
||||
<field><name>SYSINFO_MEM_0</name><bitRange>[7:0]</bitRange><description>log2(IMEM size in bytes)</description></field>
|
||||
<field><name>SYSINFO_MEM_1</name><bitRange>[15:8]</bitRange><description>log2(DMEM size in bytes)</description></field>
|
||||
<field><name>SYSINFO_MEM_2</name><bitRange>[23:16]</bitRange><description>yet unused</description></field>
|
||||
<field><name>SYSINFO_MEM_3</name><bitRange>[31:24]</bitRange><description>yet unused</description></field>
|
||||
<field><name>SYSINFO_MEM_IMEM</name><bitRange>[7:0]</bitRange><description>log2(IMEM size in bytes)</description></field>
|
||||
<field><name>SYSINFO_MEM_DMEM</name><bitRange>[15:8]</bitRange><description>log2(DMEM size in bytes)</description></field>
|
||||
<field><name>SYSINFO_MEM_res</name><bitRange>[23:16]</bitRange><description>yet unused</description></field>
|
||||
<field><name>SYSINFO_MEM_BOOT</name><bitRange>[31:24]</bitRange><description>Boot mode configuration select</description></field>
|
||||
</fields>
|
||||
</register>
|
||||
<register>
|
||||
|
@ -1615,6 +1615,7 @@
|
|||
<field><name>SYSINFO_SOC_XIP</name><bitRange>[9:9]</bitRange><description>Execute in place module implemented</description></field>
|
||||
<field><name>SYSINFO_SOC_XIP_CACHE</name><bitRange>[10:10]</bitRange><description>Execute in place cache implemented</description></field>
|
||||
<field><name>SYSINFO_SOC_OCD_AUTH</name><bitRange>[11:11]</bitRange><description>On-chip debugger authentication implemented</description></field>
|
||||
<field><name>SYSINFO_SOC_IMEM_ROM</name><bitRange>[12:12]</bitRange><description>Processor-internal instruction memory implemented as pre-initialized ROM</description></field>
|
||||
<field><name>SYSINFO_SOC_IO_DMA</name><bitRange>[14:14]</bitRange><description>Direct memory access controller implemented</description></field>
|
||||
<field><name>SYSINFO_SOC_IO_GPIO</name><bitRange>[15:15]</bitRange><description>General purpose input/output port unit implemented</description></field>
|
||||
<field><name>SYSINFO_SOC_IO_MTIME</name><bitRange>[16:16]</bitRange><description>Machine system timer implemented</description></field>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue