diff --git a/.github/workflows/Processor.yml b/.github/workflows/Processor.yml index ec47a46f6..dc4ffda7e 100644 --- a/.github/workflows/Processor.yml +++ b/.github/workflows/Processor.yml @@ -17,25 +17,9 @@ on: jobs: - Software: + sim_default_tb: runs-on: ubuntu-latest - container: ghcr.io/stnolting/neorv32/sim - - steps: - - - name: '🧰 Repository Checkout' - uses: actions/checkout@v4 - - - name: '⚙️ Build Software Framework Tests' - run: | - make -C sw/example/processor_check check - make -C sw/example clean_all exe - make -C sw/bootloader clean_all info bootloader - - - Simple: - runs-on: ubuntu-latest - name: 'Simple testbench' + name: 'processor simulation' strategy: fail-fast: false matrix: @@ -48,50 +32,32 @@ jobs: - name: '🧰 Repository Checkout' uses: actions/checkout@v4 - - name: '🚧 Build and install software; then simulate with shell script' - uses: docker://ghcr.io/stnolting/neorv32/sim - # Redirect UART0 TX to text.io simulation output via 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 - - - VUnit: - runs-on: ubuntu-latest - - steps: + - name: '📦 Install RISC-V GCC' + run: | + wget -q https://github.com/stnolting/riscv-gcc-prebuilt/releases/download/rv32i-131023/riscv32-unknown-elf.gcc-13.2.0.tar.gz + mkdir $GITHUB_WORKSPACE/riscv-gcc + tar -xzf riscv32-unknown-elf.gcc-13.2.0.tar.gz -C $GITHUB_WORKSPACE/riscv-gcc + echo $GITHUB_WORKSPACE/riscv-gcc/bin >> $GITHUB_PATH - - name: '🧰 Repository Checkout' - uses: actions/checkout@v4 + - name: '📦 Install GHDL' + uses: ghdl/setup-ghdl-ci@nightly - - 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: '🔍 Check tools' + run: | + riscv32-unknown-elf-gcc -v + ghdl -v - - name: '📤 Archive Processor Check application image' - uses: actions/upload-artifact@v4 - with: - name: application - path: rtl/core/neorv32_application_image.vhd + - name: '⚙️ Build Software Framework Tests' + run: | + make -C sw/example/processor_check check + make -C sw/example clean_all exe + make -C sw/bootloader clean_all info bootloader - - name: '🚧 Run Processor Hardware Tests with VUnit' - uses: VUnit/vunit_action@master - with: - image: ghcr.io/stnolting/neorv32/sim - cmd: ./sim/run.py --ci-mode -v + - name: '🚧 Compile executable and run simulation' + run: | + make -C sw/example/${{ matrix.example }} \ + USER_FLAGS+="-DUART0_SIM_MODE -DUART1_SIM_MODE" \ + clean_all \ + info \ + all \ + sim-check diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d89a8878..d883fe7e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,14 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12 | Date | Version | Comment | Ticket | |:----:|:-------:|:--------|:------:| +| 02.11.2024 | 1.10.6.2 | :warning: rework processor boot configuration; add new boot-configuration generics | [#1086](https://github.com/stnolting/neorv32/pull/1086) | +| 01.11.2024 | 1.10.6.1 | :test_tube: convert VHDL memory images into full-scale VHDL packages | [#1084](https://github.com/stnolting/neorv32/pull/1084) | +| 26.10.2024 | [**:rocket:1.10.6**](https://github.com/stnolting/neorv32/releases/tag/v1.10.6) | **New release** | | +| 26.10.2024 | 1.10.5.11 | cleanup central makefile and linker script | [#1077](https://github.com/stnolting/neorv32/pull/1077) | +| 21.10.2024 | 1.10.5.10 | :test_tube: rework linker script's ROM/IMEM default size (=16kB); add customization variable to all makefiles in `sw/example` | [#1072](https://github.com/stnolting/neorv32/pull/1072) | +| 20.10.2024 | 1.10.5.9 | :warning: rework XIRQ controller; remove "interrupt pending" register `EIP` | [#1071](https://github.com/stnolting/neorv32/pull/1071) | +| 18.10.2024 | 1.10.5.8 | minor RTL code cleanups | [#1068](https://github.com/stnolting/neorv32/pull/1068) | +| 18.10.2024 | 1.10.5.7 | use individual/new module for XBUS-to-AXI4-Lite bridge | [#1063](https://github.com/stnolting/neorv32/pull/1063) | | 12.10.2024 | 1.10.5.6 | :warning: remove legacy support for on-chip debugger DM version v0.13; now only supporting DM v1.0 (removing `OCD_DM_LEGACY_MODE` generic) | [#1056](https://github.com/stnolting/neorv32/pull/1056) | | 11.10.2024 | 1.10.5.5 | :sparkles: :lock: add support for optional on-chip debugger authentication; :warning: rename OCD-related top generics | [#1053](https://github.com/stnolting/neorv32/pull/1053) | | 06.10.2024 | 1.10.5.4 | :warning: rework PWM module | [#1049](https://github.com/stnolting/neorv32/pull/1049) | @@ -143,7 +151,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12 | 16.02.2024 | 1.9.5.2 | :warning: **revert** support for page faults (keep that in mmu branch for now) | [#809](https://github.com/stnolting/neorv32/pull/809) | | 16.02.2024 | 1.9.5.1 | :sparkles: add two new generics to exclude certain PMP modes from synthesis | [#808](https://github.com/stnolting/neorv32/pull/808) | | 16.02.2024 | [**:rocket:1.9.5**](https://github.com/stnolting/neorv32/releases/tag/v1.9.5) | **New release** | | -| 15.02.2023 | 1.9.4.13 | allow the DMA to issue a FENCE operation | [#807](https://github.com/stnolting/neorv32/pull/807) | +| 15.02.2024 | 1.9.4.13 | allow the DMA to issue a FENCE operation | [#807](https://github.com/stnolting/neorv32/pull/807) | | 14.02.2024 | 1.9.4.12 | :lock: close another illegal compressed instruction encoding loophole | [#806](https://github.com/stnolting/neorv32/pull/806) | | 11.02.2024 | 1.9.4.11 | :bug: fix several FPU bugs and design flaws | [#794](https://github.com/stnolting/neorv32/pull/794) | | 11.02.2024 | 1.9.4.10 | minor additions to previous version (1.9.4.9): fix HPM configuration read-back | [#804](https://github.com/stnolting/neorv32/pull/804) | diff --git a/README.md b/README.md index 01b7c59b6..6aee10c3b 100644 --- a/README.md +++ b/README.md @@ -56,13 +56,11 @@ not working as expected. See how to [contribute](https://github.com/stnolting/ne - [x] all-in-one package: **CPU** + **SoC** + **Software Framework & Tooling** - [x] completely described in behavioral, platform-independent VHDL - **no** platform-specific primitives, macros, attributes, etc.; an all-Verilog "version" is also [available](https://github.com/stnolting/neorv32-verilog) -- [x] extensive configuration options for adapting the processor to the requirements of the application -- [x] highly [extensible hardware](https://stnolting.github.io/neorv32/ug/#_comparative_summary) - on CPU, processor and system level +- [x] extensive configuration options for adapting the processor to the requirements of the application (on CPU, processor and system level) - [x] aims to be as small as possible while being as RISC-V-compliant as possible - with a reasonable area-vs-performance trade-off - [x] FPGA friendly (e.g. _all_ internal memories can be mapped to block RAM - including the CPU's register file) - [x] optimized for high clock frequencies to ease integration / timing closure -- [x] from zero to _"hello world!"_ - completely open source and documented -- [x] highly documented - on software and hardware side +- [x] from zero to _"hello world!"_ - completely open source and documented (on software and hardware side) - [x] easy to use even for FPGA / RISC-V starters – intended to work _out of the box_ ### Project Status @@ -70,12 +68,13 @@ not working as expected. See how to [contribute](https://github.com/stnolting/ne [![release](https://img.shields.io/github/v/release/stnolting/neorv32?longCache=true&style=flat-square&logo=GitHub)](https://github.com/stnolting/neorv32/releases) [![commits-since-latest-release](https://img.shields.io/github/commits-since/stnolting/neorv32/latest?longCache=true&style=flat-square&logo=GitHub)](https://github.com/stnolting/neorv32/activity) -| Task / Subproject | Repository | CI Status | -|:---------------------------------------------------|:-----------|:----------| +| Task / Subproject | Repository | CI Status | +|:------------------|:-----------|:----------| | Code quality ([Linty](https://linty-services.com)) | [neorv32](https://github.com/stnolting/neorv32) | [![Quality Gate Status](https://oss.linty-services.com/api/project_badges/measure?project=neorv32&metric=alert_status&token=sqb_97b392f36051f7887215e61c53d6f0f858ca2697)](https://oss.linty-services.com/dashboard?id=neorv32) | | GitHub pages (docs) | [neorv32](https://github.com/stnolting/neorv32) | [![GitHub Pages](https://img.shields.io/website.svg?label=stnolting.github.io%2Fneorv32&longCache=true&style=flat-square&url=http%3A%2F%2Fstnolting.github.io%2Fneorv32%2Findex.html&logo=GitHub)](https://stnolting.github.io/neorv32) | | Build documentation | [neorv32](https://github.com/stnolting/neorv32) | [![Documentation](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32/Documentation.yml?branch=main&longCache=true&style=flat-square&label=Documentation&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3ADocumentation) | | Processor verification | [neorv32](https://github.com/stnolting/neorv32) | [![Processor](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32/Processor.yml?branch=main&longCache=true&style=flat-square&label=Processor%20Check&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32/actions?query=workflow%3AProcessor) | +| VUnit testbench | [neorv32-vunit](https://github.com/stnolting/neorv32-vunit) | [![neorv32-vunit](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32-vunit/vunit.yml?branch=main&longCache=true&style=flat-square&label=neorv32-vunit&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32-vunit/actions/workflows/vunit.yml) | | RISCOF core verification | [neorv32-riscof](https://github.com/stnolting/neorv32-riscof) | [![neorv32-riscof](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32-riscof/main.yml?branch=main&longCache=true&style=flat-square&label=neorv32-riscof&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32-riscof/actions/workflows/main.yml) | | FPGA implementations | [neorv32-setups](https://github.com/stnolting/neorv32-setups) | [![Implementation](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32-setups/Implementation.yml?branch=main&longCache=true&style=flat-square&label=Implementation&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32-setups/actions?query=workflow%3AImplementation) | | All-Verilog version | [neorv32-verilog](https://github.com/stnolting/neorv32-verilog) | [![neorv32-verilog](https://img.shields.io/github/actions/workflow/status/stnolting/neorv32-verilog/main.yml?branch=main&longCache=true&style=flat-square&label=neorv32-verilog&logo=Github%20Actions&logoColor=fff)](https://github.com/stnolting/neorv32-verilog/actions/workflows/main.yml) | diff --git a/docs/attrs.adoc b/docs/attrs.adoc index b096ceb19..501bb6509 100644 --- a/docs/attrs.adoc +++ b/docs/attrs.adoc @@ -2,7 +2,7 @@ :email: stnolting@gmail.com :keywords: neorv32, risc-v, riscv, rv32, fpga, soft-core, vhdl, microcontroller, cpu, soc, processor, gcc, openocd, gdb, verilog, rtl, asip, asic, safety :description: A size-optimized, customizable and highly extensible MCU-class 32-bit RISC-V soft-core CPU and microcontroller-like SoC written in platform-independent VHDL. -:revnumber: v1.10.5 +:revnumber: v1.10.6 :doctype: book :sectnums: :stem: diff --git a/docs/datasheet/cpu.adoc b/docs/datasheet/cpu.adoc index 7ddcfd43e..be48035d6 100644 --- a/docs/datasheet/cpu.adoc +++ b/docs/datasheet/cpu.adoc @@ -531,6 +531,7 @@ The `I` ISA extensions is the base RISC-V integer ISA that is always enabled. |======================= | Class | Instructions | Execution cycles | ALU | `add[i]` `slt[i]` `slt[i]u` `xor[i]` `or[i]` `and[i]` `sub` `lui` `auipc` | 2 +| No-operation | "`nop`" | 2 | ALU shifts | `sll[i]` `srl[i]` `sra[i]` | 3 + 1..32; FAST_SHIFT: 4 | Branches | `beq` `bne` `blt` `bge` `bltu` `bgeu` | taken: 6; not taken: 3 | Jump/call | `jal[r]` | 6 diff --git a/docs/datasheet/cpu_csr.adoc b/docs/datasheet/cpu_csr.adoc index 7af2b6447..6f1b3eeca 100644 --- a/docs/datasheet/cpu_csr.adoc +++ b/docs/datasheet/cpu_csr.adoc @@ -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. diff --git a/docs/datasheet/overview.adoc b/docs/datasheet/overview.adoc index 374b24348..3fc05877e 100644 --- a/docs/datasheet/overview.adoc +++ b/docs/datasheet/overview.adoc @@ -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`). diff --git a/docs/datasheet/rationale.adoc b/docs/datasheet/rationale.adoc index 3bfe1386c..d98dc790b 100644 --- a/docs/datasheet/rationale.adoc +++ b/docs/datasheet/rationale.adoc @@ -4,14 +4,14 @@ [discrete] ==== Why did you make this? -Processor and CPU architecture designs are fascinating things: they are the magic frontier where software meets hardware. -This project started as something like a _journey_ into this magic realm to understand how things actually work -down on this very low level and evolved over time to a capable system on chip. +For me, processor and CPU architecture designs are fascinating things: they are the magic frontier where software meets hardware. +This project started as something like a _journey_ into this realm to understand how things actually work +down on the very low level and evolved over time to a quite capable system-on-chip. -But there is more: when I started to dive into the emerging RISC-V ecosystem I felt overwhelmed by the complexity. +When I started to dive into the emerging RISC-V ecosystem I felt overwhelmed by the complexity. As a beginner it is hard to get an overview - especially when you want to setup a minimal platform to tinker with... Which core to use? How to get the right toolchain? What features do I need? How does booting work? How do I -create an actual executable? How to get that into the hardware? How to customize things? **_Where to start???_** +create an actual executable? How to get that into the hardware? How to customize things? _Where to start???_ This project aims to provide a _simple to understand_ and _easy to use_ yet _powerful_ and _flexible_ platform that targets FPGA and RISC-V beginners as well as advanced users. @@ -20,15 +20,16 @@ that targets FPGA and RISC-V beginners as well as advanced users. [discrete] ==== Why a _soft-core_ processor? -As a matter of fact soft-core processors _cannot_ compete with discrete (like FPGA hard-macro) processors in terms -of performance, energy efficiency and size. But they do fill a niche in FPGA design space: for example, soft-core -processors allow to implement the _control flow part_ of certain applications (e.g. communication protocol handling) +As a matter of fact soft-core processors _cannot_ compete with discrete (ASIC) processors in terms +of performance, energy efficiency and size. But they do fill a niche in the design space: for example, soft-core +processors allow to implement the _control flow part_ of certain applications (like communication protocol handling) using software like plain C. This provides high flexibility as software can be easily changed, re-compiled and re-uploaded again. Furthermore, the concept of flexibility applies to all aspects of a soft-core processor. The user can add _exactly_ the features that are required by the application: additional memories, custom interfaces, specialized -co-processors and even user-defined instructions. +co-processors and even user-defined instructions. These application-specific optimization capabilities compensate +for many of the limitations of soft-core processors. [discrete] @@ -43,80 +44,76 @@ ____ Open-source is a great thing! While open-source has already become quite popular in _software_, hardware-focused projects still need to catch up. -Admittedly, there has been quite a development, but mainly in terms of _platforms_ and _applications_ (so -schematics, PCBs, etc.). Although processors and CPUs are the heart of almost every digital system, having a true -open-source silicon is still a rarity. RISC-V aims to change that - and even it is _just one approach_, it helps paving -the road for future development. +Although processors and CPUs are the heart of almost every digital system, having a true open-source platform is still +a rarity. RISC-V aims to change that - and even it is _just one approach_, it helps paving the road for future development. Furthermore, I highly appreciate the community aspect of RISC-V. The ISA and everything beyond is developed in direct -contact with the community: this includes businesses and professionals but also hobbyist, amateurs and people -that are just curious. Everyone can join discussions and contribute to RISC-V in their very own way. +contact with the community: this includes businesses and professionals but also hobbyist, amateurs and enthusiasts. +Everyone can join discussions and contribute to RISC-V in their very own way. Finally, I really like the RISC-V ISA itself. It aims to be a clean, orthogonal and "intuitive" ISA that -resembles with the basic concepts of _RISC_: simple yet effective. +resembles with the basic concepts of RISC: _simple yet effective_. [discrete] ==== Yet another RISC-V core? What makes it special? -The NEORV32 is not based on another RISC-V core. It was build entirely from ground up (just following the official -ISA specs). The project does not intend to replace certain RISC-V cores or -just beat existing ones like https://github.com/SpinalHDL/VexRiscv[VexRISC] in terms of performance or -https://github.com/olofk/serv[SERV] in terms of size. It was build having a different design goal in mind. +The NEORV32 is not based on another (RISC-V) core. It was build entirely from ground up just following the official +ISA specs. The project does not intend to replace certain RISC-V cores or beat existing ones in terms of _performance_ +or _size_. It was build having a different design goal in mind. The project aims to provide _another option_ in the RISC-V / soft-core design space with a different performance -vs. size trade-off and a different focus: _embrace_ concepts like documentation, platform-independence / portability, -RISC-V compatibility, _extensibility & customization_ and _ease of use_ (see the <<_project_key_features>> below). +vs. size trade-off and a different focus: embrace concepts like documentation, platform-independence / portability, +RISC-V compatibility, extensibility & customization and - last but not least - ease of use. Furthermore, the NEORV32 pays special focus on _execution safety_ using <<_full_virtualization>>. The CPU aims to provide fall-backs for _everything that could go wrong_. This includes malformed instruction words, privilege escalations and even memory accesses that are checked for address space holes and deterministic response times of memory-mapped devices. Precise exceptions allow a defined and fully-synchronized state of the CPU at every time an in every situation. +To summarize, this project pursues the following objectives (in rough order of importance): + +[start=1] +. RISC-V-compliance and -compatibility +. Functionality and features +. Extensibility +. Safety and security +. Minimal area +. Short critical paths, high operating clock +. Simplicity / easy to understand +. Low-power design +. High overall performance + [discrete] ==== A multi-cycle architecture?! -Most mainstream CPUs out there are pipelined architectures to increase throughput. In contrast, most CPUs used for -teaching are single-cycle designs since they are probably the most easiest to understand. But what about the -multi-cycle architectures? +The primary goal of many mainstream CPUs is pure performance. Deep pipelines and out-of-order execution are some concepts +to boost performance, while also increasing complexity. In contrast, most CPUs used for teaching are single-cycle designs +since they are probably the most easiest to understand. But what about something in-between? -In terms of energy, throughput, area and maximal clock frequency multi-cycle architectures are somewhere in between +In terms of energy, throughput, area and maximal clock frequency, multi-cycle architectures are somewhere in between single-cycle and fully-pipelined designs: they provide higher throughput and clock speed when compared to their -single-cycle counterparts while having less hardware complexity (= area) then a fully-pipelined designs. I decided to -use the multi-cycle approach because of the following reasons: +single-cycle counterparts while having less hardware complexity (= area) and thus, less performance, then a fully-pipelined +designs. So I decided to use the multi-cycle-approach because of the following reasons: -* Multi-cycle architecture are quite small! There is no need for pipeline hazard detection and resolution logic -(e.g. forwarding). Furthermore, you can "re-use" parts of the core to do several tasks (e.g. the ALU is used for the -actual data processing, but also for address generation, branch condition check and branch target computation). +* Multi-cycle architectures are quite small! There is no need for pipeline hazard detection/resolution logic +(e.g. forwarding). Furthermore, you can "re-use" parts of the core to do several tasks (e.g. the ALU is used for +actual data processing and also for address generation, branch condition check and branch target computation). * Single-cycle architectures require memories that can be read asynchronously - a thing that is not feasible to implement -in real world applications (i.e. FPGA block RAM is entirely synchronous). Furthermore, such design usually have a very +in real-world applications (i.e. FPGA block RAM is entirely synchronous). Furthermore, such designs usually have a very long critical path tremendously reducing maximal operating frequency. * Pipelined designs increase performance by having several instruction "in fly" at the same time. But this also means there is some kind of "out-of-order" behavior: if an instruction at the end of the pipeline causes an exception -all the instructions in earlier stages have to be invalidated. Potential architecture state changes have to be made _undone_ -requiring additional (exception-handling) logic. In a multi-cycle architecture this situation cannot occur because only a -single instruction is "in fly" at a time. +all the instructions in earlier stages have to be invalidated. Potential architectural state changes have to be made _undone_ +requiring additional logic (Spectre and Meltdown...). In a multi-cycle architecture this situation cannot occur since only a +single instruction is being processed ("in-fly") at a time. * Having only a single instruction in fly does not only reduce hardware costs, it also simplifies simulation/verification/debugging, state preservation/restoring during exceptions and extensibility (no need to care about pipeline hazards) - but of course at the cost of reduced throughput. To counteract the loss of performance implied by a _pure_ multi-cycle architecture, the NEORV32 CPU uses a _mixed_ -approach: instruction fetch (front-end) and instruction execution (back-end) are de-coupled to operate independently +approach: instruction-fetch (front-end) and instruction-execution (back-end) are de-coupled to operate independently of each other. Data is interchanged via a queue building a simple 2-stage pipeline. Each "pipeline" stage in terms is -implemented as multi-cycle architecture to simplify the hardware and to provide _precise_ state control (e.g. during -exceptions). - - -[discrete] -==== Design Goals - -[start=1] -. RISC-V-compliance and -compatibility -. Functionality and features -. Safety and security -. Minimal area -. Short critical paths, high operating clock -. Low-power design -. High overall performance -. Simplicity / easy to understand +implemented as multi-cycle architecture to simplify the hardware and to provide _precise_ state control (for example +during exceptions). diff --git a/docs/datasheet/soc.adoc b/docs/datasheet/soc.adoc index 9f3b9dc47..2cddb5268 100644 --- a/docs/datasheet/soc.adoc +++ b/docs/datasheet/soc.adoc @@ -79,7 +79,7 @@ clock domain also using registers. However, for ASIC implementations it is recom to all inputs and output so the synthesis tool can insert an explicit IO (boundary) scan chain. .NEORV32 Processor Signal List -[cols="<3,^1,^1,^1,<8"] +[cols="<4,^2,^2,^2,<7"] [options="header",grid="rows"] |======================= | Name | Width | Direction | Default | Description @@ -202,12 +202,15 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt [options="header",grid="rows"] |======================= | Name | Type | Default | Description -4+^| **General** +4+^| **<<_processor_clocking>>** | `CLOCK_FREQUENCY` | natural | 0 | The clock frequency of the processor's `clk_i` input port in Hertz (Hz). | `CLOCK_GATING_EN` | boolean | false | Enable clock gating when CPU is in sleep mode (see sections <<_sleep_mode>> and <<_processor_clocking>>). -| `INT_BOOTLOADER_EN` | boolean | false | Implement the processor-internal <<_bootloader_rom_bootrom>>, pre-initialized with the default <<_bootloader>> image. -| `HART_ID` | suv(31:0) | 0x00000000 | The hart thread ID of the CPU (passed to <<_mhartid>> CSR). -| `JEDEC_ID` | suv(10:0) | 0b00000000000 | JEDEC ID; continuation codes plus vendor ID (passed to <<_mvendorid>> CSR and to the <<_debug_transport_module_dtm>>). +4+^| **Core Identification** +| `HART_ID` | suv(31:0) | x"00000000" | The hart thread ID of the CPU (passed to <<_mhartid>> CSR). +| `JEDEC_ID` | suv(10:0) | "00000000000" | JEDEC ID; continuation codes plus vendor ID (passed to <<_mvendorid>> CSR and to the <<_debug_transport_module_dtm>>). +4+^| **<<_boot_configuration>>** +| `BOOT_MODE_SELECT` | natural | 0 | Boot mode select; see <<_boot_configuration>>. +| `BOOT_ADDR_CUSTOM` | suv(31:0) | x"00000000" | Custom CPU boot address (available if `BOOT_MODE_SELECT` = 1). 4+^| **<<_on_chip_debugger_ocd>>** | `OCD_EN` | boolean | false | Implement the on-chip debugger and the CPU debug mode. | `OCD_AUTHENTICATION` | boolean | false | Implement <<_debug_authentication>> module. @@ -295,7 +298,7 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt | `IO_TRNG_EN` | boolean | false | Implement the <<_true_random_number_generator_trng>>. | `IO_TRNG_FIFO` | natural | 1 | Depth of the TRNG data FIFO. Has to be a power of two, min 1, max 32768. | `IO_CFS_EN` | boolean | false | Implement the <<_custom_functions_subsystem_cfs>>. -| `IO_CFS_CONFIG` | suv(31:0) | 0x00000000 | "Conduit" generic to pass user-defined flags to the <<_custom_functions_subsystem_cfs>>. +| `IO_CFS_CONFIG` | suv(31:0) | x"00000000" | "Conduit" generic to pass user-defined flags to the <<_custom_functions_subsystem_cfs>>. | `IO_CFS_IN_SIZE` | natural | 32 | Size of the <<_custom_functions_subsystem_cfs>> input signal conduit (`cfs_in_i`). | `IO_CFS_OUT_SIZE` | natural | 32 | Size of the <<_custom_functions_subsystem_cfs>> output signal conduit (`cfs_out_o`). | `IO_NEOLED_EN` | boolean | false | Implement the <<_smart_led_interface_neoled>>. @@ -564,7 +567,7 @@ monitor starts an internal timer. The accessed module has to respond ("ACK") to .Internal Bus Timeout Configuration [source,vhdl] ---- - constant bus_timeout_c : natural := 15; +constant bus_timeout_c : natural := 15; ---- This constant defines the _maximum_ number of cycles after which a non-responding bus request (i.e. no `ack` @@ -657,11 +660,11 @@ package file (`rtl/core/neorv323_package.vhd`). .Exemplary Cut-Out from the IO Address Map [source,vhdl] ---- - -- IO Address Map -- - constant iodev_size_c : natural := 256; -- size of a single IO device (bytes) - constant base_io_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffeb00"; - constant base_io_slink_c : std_ulogic_vector(31 downto 0) := x"ffffec00"; - constant base_io_dma_c : std_ulogic_vector(31 downto 0) := x"ffffed00"; +-- IO Address Map -- +constant iodev_size_c : natural := 256; -- size of a single IO device (bytes) +constant base_io_cfs_c : std_ulogic_vector(31 downto 0) := x"ffffeb00"; +constant base_io_slink_c : std_ulogic_vector(31 downto 0) := x"ffffec00"; +constant base_io_dma_c : std_ulogic_vector(31 downto 0) := x"ffffed00"; ---- .IO Access Latency @@ -671,47 +674,67 @@ buffers the address bus. Hence, accesses to the processor-internal IO region req to complete. +<<< +// #################################################################################################################### :sectnums: -==== Boot Configuration +=== Boot Configuration -Due to the flexible memory configuration, the NEORV32 Processor provides several different boot scenarios. -The following section illustrates the two most common boot scenarios. +The NEORV32 processor provides some pre-defined boot configurations to adjust system start-up to +the requirements of the application. The actual boot configuration is defined by the `BOOT_MODE_SELECT` +generic (see <<_processor_top_entity_generics>>). .NEORV32 Boot Configurations -image::neorv32_boot_configurations.png[800] +[cols="^2,^2,^2,<6"] +[options="header",grid="rows"] +|======================= +| `BOOT_MODE_SELECT` | Name | Boot address | Description +| 0 (default) | Bootloader | Base of internal BOOTROM | Implement the processor-internal <<_bootloader_rom_bootrom>> as pre-initialized ROM and boot from there. +| 1 | Custom Address | `BOOT_ADDR_CUSTOM` generic | Start booting at user-defined address (`BOOT_ADDR_CUSTOM` top generic). +| 2 | IMEM Image | Base of internal IMEM | Implement the processor-internal <<_instruction_memory_imem>> as pre-initialized ROM and boot from there. +|======================= + -There are two general boot scenarios: _Indirect Boot_ (1a and 1b) and _Direct Boot_ (2a and 2b) configured via the -`INT_BOOTLOADER_EN` generic. If this generic is `true` the _indirect boot scenario_ is used. This is also the -default boot configuration of the processor. If `INT_BOOTLOADER_EN` is `*false` the _direct boot scenario_ is used. +:sectnums: +==== Booting via Bootloader -:sectnums!: -===== Indirect Boot +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. -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. +If the processor-internal <<_instruction_memory_imem>> is enabled it will be implemented as _blank_ RAM. -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. -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: +==== Boot from Custom Address -:sectnums!: -===== Direct Boot +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>>. -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. +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. -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. -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. <<< diff --git a/docs/datasheet/soc_bootrom.adoc b/docs/datasheet/soc_bootrom.adoc index 4a0932a86..5a1f19a47 100644 --- a/docs/datasheet/soc_bootrom.adoc +++ b/docs/datasheet/soc_bootrom.adoc @@ -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. diff --git a/docs/datasheet/soc_dmem.adoc b/docs/datasheet/soc_dmem.adoc index fc438184a..921c95b33 100644 --- a/docs/datasheet/soc_dmem.adoc +++ b/docs/datasheet/soc_dmem.adoc @@ -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 diff --git a/docs/datasheet/soc_imem.adoc b/docs/datasheet/soc_imem.adoc index 9836a8f4d..d68434fe5 100644 --- a/docs/datasheet/soc_imem.adoc +++ b/docs/datasheet/soc_imem.adoc @@ -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. diff --git a/docs/datasheet/soc_sysinfo.adoc b/docs/datasheet/soc_sysinfo.adoc index 5fe374fec..e87d45b64 100644 --- a/docs/datasheet/soc_sysinfo.adoc +++ b/docs/datasheet/soc_sysinfo.adoc @@ -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) |======================= diff --git a/docs/datasheet/soc_xbus.adoc b/docs/datasheet/soc_xbus.adoc index c92751c8a..837999d42 100644 --- a/docs/datasheet/soc_xbus.adoc +++ b/docs/datasheet/soc_xbus.adoc @@ -44,9 +44,8 @@ see section <<_address_space>>) are **redirected** to the external bus interface .AXI4-Lite Interface Bridge [TIP] -A processor top entity with an AXI4-Lite-compatible bus interface can be found in `rtl/system_inegration`. -More information regarding this alternate top entity can be found in in the user guide: -https://stnolting.github.io/neorv32/ug/#_packaging_the_processor_as_vivado_ip_block +A simple bridge that converts the processor's XBUS into an AXI4-lite-compatible host interface can +be found in in `rtl/system_inegration` (`xbus2axi4lite_bridge.vhd`). .AHB3-Lite Interface Bridge [TIP] diff --git a/docs/datasheet/soc_xirq.adoc b/docs/datasheet/soc_xirq.adoc index b2ebc8377..5cb97b853 100644 --- a/docs/datasheet/soc_xirq.adoc +++ b/docs/datasheet/soc_xirq.adoc @@ -28,22 +28,17 @@ The XIRQ provides up to 32 external interrupt channels configured via the `XIRQ_ `xirq_i` input signal vector represents one interrupt channel. If less than 32 channels are configured, only the LSB-aligned channels are used while the remaining ones are left unconnected internally. -The external interrupt controller features five interface registers: +The external interrupt controller features four interface registers: [start=1] . external interrupt channel enable (`EIE`) -. external interrupt channel pending (`EIP`) . external interrupt source (`ESC`) . trigger type configuration (`TTYP`) . trigger polarity configuration (`TPOL`) -[TIP] -From a functional point of view, the `EIE`, `EIP` and `ESC` registers follow the behavior -of the RISC-V <<_mie>>, <<_mip>> and <<_mcause>> CSRs. - The actual interrupt trigger type can be configured individually for each channel using the `TTYP` and `TPOL` registers. `TTYP` defines the actual trigger type (level-triggered or edge-triggered), while `TPOL` defines -the trigger's polarity (low-level/falling-edge or high-level_/rising-edge). The position of each bit in these +the trigger's polarity (low-level/falling-edge or high-level/rising-edge). The position of each bit in these registers corresponds the according XIRQ channel. .XIRQ Trigger Configuration @@ -57,24 +52,19 @@ registers corresponds the according XIRQ channel. | `1` | `1` | rising-edge |======================= -When the configured trigger of an interrupt channel fires the according interrupt channel becomes _pending_ -which is indicated by the according channel bit being set in the `EIP` register. This pending interrupt can -be manually cleared at any time by writing zero to the according `EIP` bit. - -A pending interrupt can only generate a CPU interrupt if the according channel is enabled by the `EIE` -register. Once triggered, disabled channels that **were already triggered** remain pending until explicitly -(= manually) cleared. The channels are prioritized in a static order, i.e. channel 0 (`xirq_i(0)`) has the -highest priority and channel 31 (`xirq_i(31)`) has the lowest priority. If **any** pending interrupt channel is -also enabled, an interrupt request is sent to the CPU. +Each interrupt channel can be enabled or disabled individually using the `EIE` register. If the trigger of a +disabled channel fires the interrupt request is entirely ignored. -The CPU can determine the most prioritized external interrupt request either by checking the bits in the `EIP` -register or by reading the interrupt source register `ESC`. This register provides a 5-bit wide ID (0..31) -identifying the currently firing external interrupt source channel. Writing _any_ value to this register will -acknowledge and clear the _current_ CPU interrupt (so the XIRQ controller can issue a new CPU interrupt). +If the configured trigger of an _enabled_ channels fires, the according interrupt request is buffered internally +and an interrupt request is sent to the CPU. If more than one trigger fires at one a prioritization is used: +the channels are prioritized in a static order, i.e. channel 0 (`xirq_i(0)`) has the highest priority and channel +31 (`xirq_i(31)`) has the lowest priority. -In order to acknowledge an XIRQ interrupt, the interrupt handler has to... -* clear the pending XIRQ channel by clearing the according `EIP` bit -* writing _any_ value to `ESC` to acknowledge the XIRQ CPU interrupt +The CPU can determine the most prioritized external interrupt request by reading the interrupt source register `ESC`. +This register provides a 5-bit wide ID (0..31) identifying the currently firing external interrupt source channel as +well as a single bit (the MSB) that +Writing _any_ value to this register will acknowledge and clear the _current_ CPU interrupt (so the XIRQ controller +can issue a new CPU interrupt). **Register Map** @@ -85,11 +75,9 @@ In order to acknowledge an XIRQ interrupt, the interrupt handler has to... |======================= | Address | Name [C] | Bit(s) | R/W | Description | `0xfffff300` | `EIE` | `31:0` | r/w | External interrupt enable register (one bit per channel, LSB-aligned) -| `0xfffff304` | `EIP` | `31:0` | r/w | External interrupt pending register (one bit per channel, LSB-aligned); writing 0 to a bit clears the according pending interrupt -| `0xfffff308` | `ESC` | `4:0` | r/w | Interrupt source ID (0..31) of firing IRQ (prioritized!); writing _any_ value will acknowledge the current XIRQ CPU interrupt -| `0xfffff30c` | `TTYP` | `31:0` | r/w | Trigger type select (`0` = level trigger, `1` = edge trigger); each bit corresponds to the according channel number -| `0xfffff310` | `TPOL` | `31:0` | r/w | Trigger polarity select (`0` = low-level/falling-edge, `1` = high-level/rising-edge); each bit corresponds to the according channel number -| `0xfffff314` | - | `31:0` | r/- | _reserved_, read as zero -| `0xfffff318` | - | `31:0` | r/- | _reserved_, read as zero -| `0xfffff31c` | - | `31:0` | r/- | _reserved_, read as zero +.3+^| `0xfffff304` .3+<| `ESC` ^| `31` ^| r/c <| XIRQ interrupt when set; write any value to this register to acknowledge the current XIRQ interrupt + ^| `30:5` ^| r/- <| _reserved_, read as zero + ^| `4:0` ^| r/c <| Interrupt source ID (0..31) of firing IRQ (prioritized!) +| `0xfffff308` | `TTYP` | `31:0` | r/w | Trigger type select (`0` = level trigger, `1` = edge trigger); each bit corresponds to the according channel number +| `0xfffff30c` | `TPOL` | `31:0` | r/w | Trigger polarity select (`0` = low-level/falling-edge, `1` = high-level/rising-edge); each bit corresponds to the according channel number |======================= diff --git a/docs/datasheet/software.adoc b/docs/datasheet/software.adoc index 1917fc8ee..e8e80d2e6 100644 --- a/docs/datasheet/software.adoc +++ b/docs/datasheet/software.adoc @@ -1,34 +1,20 @@ :sectnums: == Software Framework -The NEORV32 project comes with a complete software ecosystem called the "software framework", which +The NEORV32 project comes with a complete software ecosystem called the "software framework" which is based on the C-language RISC-V GCC port and consists of the following parts: * <<_compiler_toolchain>> * <<_core_libraries>> +* <<_system_view_description_file_svd>> * <<_application_makefile>> -* <<_executable_image_format>> -** <<_linker_script>> -** <<_ram_layout>> -** <<_c_standard_library>> -** <<_start_up_code_crt0>> -* <<_bootloader>> +* <<_default_compiler_flags>> +* <<_linker_script>> +* <<_c_standard_library>> +* <<_start_up_code_crt0>> +* <<_executable_image_formats>> * <<_neorv32_runtime_environment>> - -A summarizing list of the most important elements of the software framework and their according -files and folders is shown below: - -[cols="<5,<5"] -[grid="none"] -|======================= -| Application start-up code | `sw/common/crt0.S` -| Application linker script | `sw/common/neorv32.ld` -| Core hardware driver libraries ("HAL") | `sw/lib/include/` & `sw/lib/source/` -| Central application makefile | `sw/common/common.mk` -| Tool for generating NEORV32 executables | `sw/image_gen/` -| Default bootloader | `sw/bootloader` -| Example programs | `sw/example` -|======================= +* <<_bootloader>> .Software Documentation [TIP] @@ -38,26 +24,18 @@ at https://stnolting.github.io/neorv32/sw/files.html. .Example Programs [TIP] -A collection of annotated example programs, which show how to use certain CPU functions -and peripheral/IO modules, can be found in `sw/example`. +A collection of annotated example programs illustrating how to use certain CPU functions +and peripheral/IO modules can be found in `sw/example`. // #################################################################################################################### :sectnums: === Compiler Toolchain -The toolchain for this project is based on the free and open RISC-V GCC-port. You can find the compiler sources and -build instructions on the official RISC-V GNU toolchain GitHub page: https://github.com/riscv/riscv-gnutoolchain. - -The NEORV32 implements a 32-bit RISC-V architecture and uses a 32-bit integer and soft-float ABI by default. -Make sure the toolchain / toolchain build is configured accordingly. - -* `MARCH=rv32i` -* `MABI=ilp32` -* `RISCV_PREFIX=riscv32-unknown-elf-` - -These default configurations can be overridden at any times using <<_application_makefile>> variables. +The toolchain for this project is based on the free and open RISC-V GCC-port. You can find the compiler sources and +build instructions in the official RISC-V GNU toolchain GitHub repository: https://github.com/riscv/riscv-gnutoolchain. +.Toolchain Installation [TIP] More information regarding the toolchain (building from scratch or downloading prebuilt ones) can be found in the user guide section https://stnolting.github.io/neorv32/ug/#_software_toolchain_setup[Software Toolchain Setup]. @@ -77,6 +55,8 @@ The NEORV32 project provides a set of pre-defined C libraries that allow an easy #include // NEORV32 HAL, core and runtime libraries ---- +The NEORV32 HAL consists of the following files. + .NEORV32 Hardware Abstraction Layer File List [cols="<3,<3,<6"] [options="header",grid="rows"] @@ -115,14 +95,16 @@ The NEORV32 project provides a set of pre-defined C libraries that allow an easy .Core Library Documentation [TIP] -The _doxygen_-based documentation of the software framework including all core libraries is available online at +The Doxygen-based documentation of the software framework including all core libraries is available online at https://stnolting.github.io/neorv32/sw/files.html. -.CMSIS System View Description File (SVD) -[TIP] + +<<< +// #################################################################################################################### +:sectnums: +=== System View Description File (SVD) + A CMSIS-SVD-compatible **System View Description (SVD)** file including all peripherals is available in `sw/svd`. -Together with a third-party plugin the processor's SVD file can be imported right into GDB to allow comfortable -debugging of peripheral/IO devices (see https://github.com/stnolting/neorv32/discussions/656). <<< @@ -130,29 +112,76 @@ debugging of peripheral/IO devices (see https://github.com/stnolting/neorv32/dis :sectnums: === Application Makefile -Application compilation is based on a single, centralized GNU makefile (`sw/common/common.mk`). Each project in the -`sw/example` folder provides a makefile that just _includes_ this central makefile. +Application compilation is based on a centralized GNU makefile (`sw/common/common.mk`). Each software project +(for example the ones in `sw/example` folder) should provide a local makefile that just includes the central makefile: +```makefile +# Set path to NEORV32 root directory +NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile +include $(NEORV32_HOME)/sw/common/common.mk +``` + +Thus, the functionality of the central makefile (including all targets) becomes available for the project. +The project-local makefile should be used to define all setup-relevant configuration options instead of changing the +central makefile to keep the code base clean. Setting variables in the project-local makefile will override the default +configuration. Most example projects already provide a makefile that list all relevant configuration options. + +The following example shows all relevant configuration variables: + +```makefile +# Override the default CPU ISA +MARCH = rv32imc_zicsr_zifencei + +# Override the default RISC-V GCC prefix +RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Additional sources +APP_SRC += $(wildcard ./*.c) +APP_INC += -I . + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional compiler flags (append to this variable) +#USER_FLAGS += ... + +# Set path to NEORV32 root directory +NEORV32_HOME ?= ../../.. + +# Include the main NEORV32 makefile +include $(NEORV32_HOME)/sw/common/common.mk +``` + +.New Project [TIP] When creating a new project, copy an existing project folder or at least the makefile to the new project folder. It is recommended to create new projects also in `sw/example` to keep the file dependencies. However, these dependencies can be manually configured via makefile variables if the new project is located somewhere else. -[NOTE] -Before the makefile can be used to compile applications, the RISC-V GCC toolchain needs to be installed and -the compiler's `bin` folder has to be added to the system's `PATH` environment variable. More information can be -found in https://stnolting.github.io/neorv32/ug/#_software_toolchain_setup[User Guide: Software Toolchain Setup]. - :sectnums: ==== Makefile Targets -Just executing `make` (or executing `make help`) will show the help menu listing all available targets. +Invoking a project-local makefile (executing `make` or `make help`) will show the help menu that lists all +available targets as well as all variable including their _current_ setting. [source,makefile] ---- -$ make -NEORV32 Software Application Makefile +neorv32/sw/example/hello_world$ make +NEORV32 Software Makefile Find more information at https://github.com/stnolting/neorv32 Targets: @@ -160,35 +189,36 @@ Targets: help - show this text check - check toolchain info - show makefile/toolchain configuration - gdb - run GNU debugging session + gdb - start GNU debugging session asm - compile and generate assembly listing file for manual debugging elf - compile and generate ELF file - exe - compile and generate executable image file for upload via default bootloader (binary file) - bin - compile and generate RAW executable memory image (binary file) - hex - compile and generate RAW executable memory image (hex char file) - coe - compile and generate RAW executable memory image (COE file) - mem - compile and generate RAW executable memory image (MEM file) - mif - compile and generate RAW executable memory image (MIF file) - image - compile and generate VHDL IMEM boot image (for application, no header) in local folder - install - compile, generate and install VHDL IMEM boot image (for application, no header) + exe - compile and generate executable image file for bootloader upload (includes a HEADER!) + bin - compile and generate executable memory image + hex - compile and generate executable memory image + coe - compile and generate executable memory image + mem - compile and generate executable memory image + mif - compile and generate executable memory image + image - compile and generate VHDL IMEM application boot image in local folder + install - compile, generate and install VHDL IMEM application boot image sim - in-console simulation using default/simple testbench and GHDL - hdl_lists - regenerate HDL file-lists in NEORV32_HOME/rtl + hdl_lists - regenerate HDL file-lists (*.f) in NEORV32_HOME/rtl all - exe + install + hex + bin + asm elf_info - show ELF layout info elf_sections - show ELF sections clean - clean up project home folder clean_all - clean up whole project, core libraries and image generator - bl_image - compile and generate VHDL BOOTROM boot image (for bootloader only, no header) in local folder - bootloader - compile, generate and install VHDL BOOTROM boot image (for bootloader only, no header) + bl_image - compile and generate VHDL BOOTROM bootloader boot image in local folder + bootloader - compile, generate and install VHDL BOOTROM bootloader boot image Variables: - USER_FLAGS - Custom toolchain flags [append only]: "" + USER_FLAGS - Custom toolchain flags [append only]: "-ggdb -gdwarf-3 -Wl,--defsym,__neorv32_rom_size=16k -Wl,--defsym,__neorv32_ram_size=8k" USER_LIBS - Custom libraries [append only]: "" EFFORT - Optimization level: "-Os" MARCH - Machine architecture: "rv32i_zicsr_zifencei" MABI - Machine binary interface: "ilp32" APP_INC - C include folder(s) [append only]: "-I ." + APP_SRC - C source folder(s) [append only]: "./main.c " ASM_INC - ASM include folder(s) [append only]: "-I ." RISCV_PREFIX - Toolchain prefix: "riscv32-unknown-elf-" NEORV32_HOME - NEORV32 home folder: "../../.." @@ -197,289 +227,137 @@ Variables: ---- -:sectnums: -==== Makefile Configuration - -The compilation flow is configured via variables right at the beginning of the central -makefile (`sw/common/common.mk`): - -.Customizing Makefile Variables -[TIP] -The makefile configuration variables can be overridden or extended directly when invoking the makefile. For -example `$ make MARCH=rv32ic_zicsr_zifencei clean_all exe` overrides the default `MARCH` variable definitions. - -.Default Makefile Configuration -[source,makefile] ----- -# ***************************************************************************** -# USER CONFIGURATION -# ***************************************************************************** -# User's application sources (*.c, *.cpp, *.s, *.S); add additional files here -APP_SRC ?= $(wildcard ./*.c) $(wildcard ./*.s) $(wildcard ./*.cpp) $(wildcard ./*.S) -# User's application include folders (don't forget the '-I' before each entry) -APP_INC ?= -I . -# User's application include folders - for assembly files only (don't forget the '-I' before each -entry) -ASM_INC ?= -I . -# Optimization -EFFORT ?= -Os -# Compiler toolchain -RISCV_PREFIX ?= riscv32-unknown-elf- -# CPU architecture and ABI -MARCH ?= rv32i_zicsr_zifencei -MABI ?= ilp32 -# User flags for additional configuration (will be added to compiler flags) -USER_FLAGS ?= -# User libraries (will be included by linker) -USER_LIBS ?= -# Language specific compiler flags: C -CFLAGS ?= -# C++ -CXXFLAGS ?= -# Assembly -ASFLAGS ?= -# Flags passed only to the linker -LDFLAGS ?= -# Relative or absolute path to the NEORV32 home folder -NEORV32_HOME ?= ../../.. -# GDB arguments -GDB_ARGS ?= -ex "target extended-remote localhost:3333" -# ***************************************************************************** ----- - -.Variables Description -[cols="<2,<8"] -[grid="none"] -|======================= -| `APP_SRC` | The source files of the application (`*.c`, `*.cpp`, `*.S` and `*.s` files are allowed; files of these types in the project folder are automatically added via wild cards). Additional files can be added separated by white spaces -| `APP_INC` | Include file folders; separated by white spaces; must be defined with `-I` prefix -| `ASM_INC` | Include file folders that are used only for the assembly source files (`*.S`/`*.s`). -| `EFFORT` | Optimization level, optimize for size (`-Os`) is default; legal values: `-O0`, `-O1`, `-O2`, `-O3`, `-Os`, `-Ofast`, ... -| `RISCV_PREFIX` | The toolchain prefix to be used; follows the triplet naming convention `[architecture]-[host_system]-[output]-...` -| `MARCH` | The targeted RISC-V architecture/ISA -| `MABI` | Application binary interface (default: 32-bit integer ABI `ilp32`) -| `USER_FLAGS` | Additional flags that will be forwarded to the compiler tools -| `USER_LIBS` | Additional libraries to include during linking (`*.a`) -| `CFLAGS` | Additional flags that will be forwarded to the C compiler -| `CXXFLAGS` | Additional flags that will be forwarded to the C++ compiler -| `ASFLAGS` | Additional flags that will be forwarded to the assembler -| `LDFLAGS` | Additional flags that will be forwarded to the linker -| `NEORV32_HOME` | Relative or absolute path to the NEORV32 project home folder; adapt this if the makefile/project is not in the project's default `sw/example` folder -| `GDB_ARGS` | Default GDB arguments when running the `gdb` target -| `GHDL_RUN_FLAGS` | GHDL run arguments (e.g. `--stop-time=1ms`) -|======================= - :sectnums: ==== Default Compiler Flags -The following default compiler flags are used for compiling an application. These flags are defined via the -`CC_OPTS` variable. - -[TIP] -The makefile's `CC_OPTS` is exported as **define** to be available within a C program; for example -`neorv32_uart0_printf("%s\n", CC_OPTS);`. +The central makefile uses specific compiler flags to tune the code to the NEORV32 hardware. Hence, these flags should not +be altered. However, experienced users can modify them to further tune compilation. +.Compiler Options (`CC_OPTS`) [cols="<3,<9"] [grid="none"] |======================= | `-Wall` | Enable all compiler warnings. -| `-ffunction-sections` | Put functions and data segment in independent sections. This allows a code optimization as dead code and unused data can be easily removed. +| `-ffunction-sections` | Put functions in independent sections. This allows a code optimization as dead code can be easily removed. +| `-fdata-sections` | Put data segment in independent sections. This allows a code optimization as unused data can be easily removed. | `-nostartfiles` | Do not use the default start code. Instead, the NEORV32-specific start-up code (`sw/common/crt0.S`) is used (pulled-in by the linker script). -| `-Wl,--gc-sections` | Make the linker perform dead code elimination. -| `-lm` | Include/link with `math.h`. -| `-lc` | Search for the standard C library when linking. -| `-lgcc` | Make sure we have no unresolved references to internal GCC library subroutines. | `-mno-fdiv` | Use built-in software functions for floating-point divisions and square roots (since the according instructions are not supported yet). | `-mstrict-align` | Unaligned memory accesses cannot be resolved by the hardware and require emulation. | `-mbranch-cost=10` | Branching costs a lot of cycles. -| `-ffp-contract=off` | Do not allow contraction of floating-point operations (no fused operations as they are not supported). +| `-Wl,--gc-sections` | Make the linker perform dead code elimination. +| `-ffp-contract=off` | Disable floating-point expression contraction. +| `-g` | Add (simple) debug information. |======================= -.Debug Symbols -[IMPORTANT] -By default, no debug symbols are added to the ELF. -You can add them manually (to your local project's makefile) via `USER_FLAGS+=-g`. -Note that other debug flags may be required depending of the GCC/GDB version -(e.g. `USER_FLAGS += -ggdb -gdwarf-3`). - -:sectnums: -==== Custom (Compiler) Flags - -Custom flags can be _appended_ to the `USER_FLAGS` variable. This allows to customize the entire software framework while -calling `make` without the need to change the makefile(s) or the linker script. The following example will add debug symbols -to the executable (`-g`) and will also re-define the linker script's `__neorv32_heap_size` variable setting the maximal heap -size to 4096 bytes (see sections <<_linker_script>> and <<_ram_layout>>): - -.Using the `USER_FLAGS` Variable for Customization -[source,bash] ----- -$ make USER_FLAGS+="-g -Wl,--__neorv32_heap_size,__heap_size=4096" clean_all exe ----- +.Checking Compiler Flags from a Compiled Program +[TIP] +The makefile's `CC_OPTS` is exported as **define** to be available within a C program; for example +`neorv32_uart0_printf("%s\n", CC_OPTS);`. -The configuration can also be made "permanent" by adapting the application's makefile (make sure to use the -`override` command here): +.Linker Libraries (`LD_LIBS`) +[cols="<2,<9"] +[grid="none"] +|======================= +| `-lm` | Include/link with `math.h`. +| `-lc` | Search for the standard C library when linking. +| `-lgcc` | Make sure we have no unresolved references to internal GCC library subroutines. +|======================= -.Using the `USER_FLAGS` Variable for Permanent Customization -[source,makefile] ----- -override USER_FLAGS += "-g -Wl,--__neorv32_heap_size,__heap_size=4096" ----- +.Advanced Debug Symbols +[IMPORTANT] +By default, only "simple" symbols are added to the ELF (`-g`). Extended debug flags (e.g. for Eclipse) can be added +using the `USER_FLAGS` variable (e.g. `USER_FLAGS += -ggdb -gdwarf-3`). Note that other debug flags may be required +depending of the GCC/GDB version <<< // #################################################################################################################### :sectnums: -=== Executable Image Format - -In order to generate an executable for the processors all source files have to be compiled, linked -and packed into a final executable. This executable can be further converted into several image formats. - -.Memory Image Formats -[TIP] -The NEORV32 software framework includes an <<_executable_image_generator>> than can convert an application -into several different file formats. These include raw hex files, a proprietary format for uploading via the -default <<_bootloader>> as well as several standard FPGA memory initialization file types (e.g. `*.coe`, -`*.mem` and `*.mif`). These image file formats are generated by the according <<_makefile_targets>>. - - -:sectnums: -==== Linker Script +=== Linker Script -After all the application sources have been compiled, they need to be _linked_. -For this purpose the makefile uses the NEORV32-specific linker script. This linker script defines several sections -for the final executable (compare with <<_address_space>>). However, only the `ram` and `rom` sections are -relevant for the executable itself; the remaining sections are just listed for completeness. +The NEORV32-specific linker script (`sw/common/neorv32.ld`) is used to link the compiled sources according to the +processor's <<_address_space>>). For the final executable, only two memory segments are required: -.Linker script - memory sections +.Linker script - Memory Segments [cols="<2,<8"] [options="header",grid="rows"] |======================= | Memory section | Description -| `ram` | Data memory address space (processor-internal <<_data_memory_dmem>> and/or external memory) | `rom` | Instruction memory address space (processor-internal <<_instruction_memory_imem>> and/or external memory) -| `xip` | Address space for the <<_execute_in_place_module_xip>> (accessing an external SPI memory) -| `boot` | Address space for the processor-internal <<_bootloader_rom_bootrom>> -| `io` | Address space for the processor-internal IO/peripheral devices +| `ram` | Data memory address space (processor-internal <<_data_memory_dmem>> and/or external memory) |======================= -[NOTE] -The `rom` section is automatically re-mapped to the processor-internal <<_bootloader_rom_bootrom>> when compiling the -bootloader sources. +These two sections are configured by several variables defined in the linker script and exposed to the build +framework (aka the makefile). Those variable allow to customized the RAM/ROM sizes and base addresses. Additionally, +a certain amount of the RAM can be reserved for the software-managed heap (see <<_ram_layout>>). -Each section has two main attributes: `ORIGIN` and `LENGTH`. `ORIGIN` defines the base address of the according section -while `LENGTH` defines its size in bytes. For the `ram` and `rom` sections these attributes are configured indirectly -via variables that provide default values. - -.Linker script - section configuration -[source] ----- -/* Default rom/ram (IMEM/DMEM) sizes */ -__neorv32_rom_size = DEFINED(__neorv32_rom_size) ? __neorv32_rom_size : 2048M; -__neorv32_ram_size = DEFINED(__neorv32_ram_size) ? __neorv32_ram_size : 8K; - -/* Default section base addresses */ -__neorv32_rom_base = DEFINED(__neorv32_rom_base) ? __neorv32_rom_base : 0x00000000; -__neorv32_ram_base = DEFINED(__neorv32_ram_base) ? __neorv32_ram_base : 0x80000000; ----- +.Linker script - Configuration +[cols="<2,<7,^1"] +[options="header",grid="rows"] +|======================= +| Memory section | Description | Default +| `__neorv32_rom_size` | "ROM" size (instruction memory / IMEM) | 16kB +| `__neorv32_ram_size` | "RAM" size (data memory / DMEM) | 8kB +| `__neorv32_rom_base` | "ROM" base address (instruction memory / IMEM) | `0x00000000` +| `__neorv32_ram_base` | "RAM" base address (data memory / DMEM) | `0x80000000` +| `__neorv32_heap_size` | Maximum heap size; part of the "RAM" | 0kB +|======================= -The region size and base address configuration can be edited by the user - either by explicitly -changing the default values in the linker script or by overriding them when invoking `make`: +Each variable provides a default value (e.g. "16K" for the instruction memory /ROM /IMEM size). These defaults can +be overridden by setup-specific values to take the user-defined processor configuration into account (e.g. a different IMEM +size). The `USER_FLAGS` variable provided by the <<_application_makefile>> can also be used to customize the memory +configuration. For example, the following line can be added to a project-specific local makefile to adjust the memory +sizes: -.Overriding default `rom` size configuration (configuring 4096 bytes) -[source, bash] +.Overriding Default Memory Sizes (configuring 64kB IMEM and 32kB DMEM) +[source, makefile] ---- -$ make USER_FLAGS+="-Wl,--defsym,__neorv32_rom_size=4096" clean_all exe +USER_FLAGS += "-Wl,--defsym,__neorv32_rom_size=64k -Wl,--defsym,__neorv32_ram_size=32k" ---- +.Memory Configuration Constraints [IMPORTANT] -`__neorv32_rom_base` (= `ORIGIN` of the `rom` section) and `__neorv32_ram_base` (= `ORIGIN` of the `ram` section) have to -be sync to the actual memory layout configuration of the processor (see section <<_address_space>>). - -[NOTE] -The default configuration for the `rom` section assumes a maximum of 2GB _logical_ memory address space. This size does not -have to reflect the _actual_ physical size of the entire instruction memory. It just provides a maximum limit. When uploading -a new executable via the bootloader, the bootloader itself checks if sufficient _physical_ instruction memory is available. -If a new executable is embedded right into the internal-IMEM the synthesis tool will check, if the configured instruction memory -size is sufficient. - -The linker maps all the regions from the compiled object files into five final sections: `.text`, -`.rodata`, `.data`, `.bss` and `.heap`: - -.Linker script - memory regions -[cols="<1,<9"] -[options="header",grid="rows"] -|======================= -| Region | Description -| `.text` | Executable instructions generated from the start-up code and all application sources. -| `.rodata` | Constants (like strings) from the application; also the initial data for initialized variables. -| `.data` | This section is required for the address generation of fixed (= global) variables only. -| `.bss` | This section is required for the address generation of dynamic memory constructs only. -| `.heap` | This section is required for the address generation of dynamic memory constructs only. -|======================= - -The `.text` and `.rodata` sections are mapped to processor's instruction memory space and the `.data`, -`.bss` and `heap` sections are mapped to the processor's data memory space. Finally, the `.text`, `.rodata` and `.data` -sections are extracted and concatenated into a single file `main.bin`. - -.Section Alignment -[NOTE] -The default NEORV32 linker script aligns _all_ regions so they start and end on a 32-bit (word) boundaries. The default -NEORV32 start-up code (crt0) makes use of this alignment by using word-level memory instructions to initialize the `.data` -section and to clear the `.bss` section (faster!). +Memory sizes have to be a multiple of 4 bytes. Memory base addresses have to be 32-bit-aligned. :sectnums: ==== RAM Layout -The default NEORV32 linker script uses all of the defined RAM (linker script memory section `ram`) to several sections. +The default NEORV32 linker script uses the defined RAM size to map several sections. Note that depending on the application some sections might have zero size. .Default RAM Layout image::ram_layout.png[400] [start=1] -. **Constant data (`.data`)**: The constant data section is placed right at the beginning of the RAM. For example, this section -contains _explicitly initialized_ global variables. This section is initialized by the executable. -. **Dynamic data (`.bss`)**: The constant data section is followed by the dynamic data section, which contains _uninitialized_ data -like global variables without explicit initialization. This section is cleared by the start-up code `crt0.S`. -. **Heap (`.heap`)**: The heap is used for dynamic memory that is managed by functions like `malloc()` and `free()`. The heap -grows upwards. This section is not initialized at all. -. **Stack**: The stack starts at the very end of the RAM at address `ORIGIN(ram) + LENGTH(ram) - 1`. According to the RISC-V ABI / calling +. **Constant data (`.data`)**: The constant data section is placed right at the beginning of the RAM. For example, this +section contains _explicitly initialized_ global variables. This section is initialized by the <<_start_up_code_crt0>>. +. **Dynamic data (`.bss`)**: The constant data section is followed by the dynamic data section that contains _uninitialized_ +data like global variables without explicit initialization. This section is cleared by the <<_start_up_code_crt0>>. +. **Heap (`.heap`)**: The heap is used for dynamic memory that is managed by functions like `malloc()` and `free()`. +The heap grows upwards. This section is not initialized at all. +. **Stack**: The stack starts at the end of the RAM at the last 16-byte aligned address. According to the RISC-V ABI / calling convention the stack is 128-bit-aligned before procedure entry. The stack grows downwards. -There is _no explicit limit_ for the maximum stack size as this is hard to check. However, a physical memory protection rule could -be used to configure a maximum size by adding a "protection area" between stack and heap (a PMP region without any access rights). - .Heap Size [IMPORTANT] -The maximum size of the heap is defined by the linker script's `__neorv32_heap_size` variable. This variable has to be -**explicitly defined** in order to define a heap size (and to use dynamic memory allocation at all) other than zero. The user -can define the heap size while invoking the application makefile: `$ USER_FLAGS+="-Wl,--defsym,__neorv32_heap_size=4k" make clean_all exe` -(defines a heap size of 4*1024 bytes). +The maximum size of the heap is defined by the `__neorv32_heap_size` variable. This variable has to be +**explicitly defined** in order to define a heap size (and to use dynamic memory allocation at all) other than zero. -.Heap-Stack Collisions +.Heap-Stack Collision [WARNING] -Take care when using dynamic memory to avoid collision of the heap and stack memory areas. There is no compile-time protection -mechanism available as the actual heap and stack size are defined by _runtime_ data. Also beware of fragmentation when -using dynamic memory allocation. +Take care when using dynamic memory to avoid collision of the heap and stack memory areas. There is no compile-time +protection mechanism available as the actual heap and stack size are defined by _runtime_ data. +<<< +// #################################################################################################################### :sectnums: -==== C Standard Library - -The default software framework relies on **newlib** as default C standard library. - -.RTOS Support -[NOTE] -The NEORV32 CPU and processor **do support** embedded RTOS like FreeRTOS and Zephyr. See the User guide section -https://stnolting.github.io/neorv32/ug/#_zephyr_rtos_support[Zephyr RTOS Support] and -https://stnolting.github.io/neorv32/ug/#_freertos_support[FreeRTOS Support] -for more information. + -+ -The FreeRTOS port and demo is available in a separate repository: https://github.com/stnolting/neorv32-freertos +=== C Standard Library -Newlib provides stubs for common "system calls" (like file handling and standard input/output) that are used by other -C libraries like `stdio`. These stubs are available in `sw/source/source/syscalls.c` and were adapted for the NEORV32 processor. +The default software framework relies on **newlib** as default C standard library. Newlib provides hooks for common +"system calls" (like file handling and standard input/output) that are used by other C libraries like `stdio`. +These hooks are available in `sw/lib/source/newlib.c` and were adapted for the NEORV32 processor. .Standard Consoles [NOTE] @@ -494,86 +372,86 @@ See `sw/example/hello_cpp` for a minimal example. .Newlib Test/Demo Program [TIP] -A simple test and demo program, which uses some of newlib's core functions (like `malloc`/`free` and `read`/`write`) -is available in `sw/example/demo_newlib` - - -:sectnums: -==== Executable Image Generator - -The `main.bin` file is packed by the NEORV32 image generator (`sw/image_gen`) to generate the final executable file. -The image generator can generate several types of executable file formats selected by a flag when calling the generator: - -[cols="<2,<8"] -[grid="none"] -|======================= -| `-app_bin` | Generates an executable binary file `neorv32_exe.bin` (including bootloader header) for uploading via the bootloader. -| `-app_img` | Generates an executable VHDL memory initialization image for the processor-internal IMEM. This option regenerates the `rtl/core/neorv32_application_image.vhd` file. -| `-bld_img` | Generates an executable VHDL memory initialization image for the processor-internal BOOT ROM. This option regenerates the `rtl/core/neorv32_bootloader_image.vhd` file. -| `-raw_hex` | Generates a raw 8x ASCII hex-char file `neorv32_raw_exe.hex` for custom purpose. -| `-raw_bin` | Generates a raw binary file `neorv32_raw_exe.bin` for custom purpose. -| `-raw_coe` | Generates a raw COE file `neorv32_raw_exe.coe` for FPGA memory initialization. -| `-raw_mem` | Generates a raw MEM file `neorv32_raw_exe.mem` for FPGA memory initialization. -| `-raw_mif` | Generates a raw MIF file `neorv32_raw_exe.mif` for FPGA memory initialization. -|======================= - -**All these options are managed by the makefile (see <<_makefile_targets>>).** - -.Image Generator Compilation -[NOTE] -The sources of the image generator are automatically compiled when invoking the makefile (requiring a _native_ GCC installation). - -.Executable Header -[NOTE] -The image generator add a small header to the `neorv32_exe.bin` executable, which consists of three 32-bit words located right -at the beginning of the file. The first word of the executable is the signature word and is always `0x4788cafe`. Based on this -word the bootloader can identify a valid image file. The next word represents the size in bytes of the actual program image in -bytes. A simple "complement" checksum of the actual program image is given by the third word. This provides a simple protection -against data transmission or storage errors. **Note that this executable format cannot be used for _direct_ execution (e.g. via -XIP or direct memory access).** +A simple test and demo program that uses some of newlib's system functions (like `malloc`/`free` and `read`/`write`) +is available in `sw/example/demo_newlib`. +<<< +// #################################################################################################################### :sectnums: -==== Start-Up Code (crt0) +=== Start-Up Code (crt0) -The CPU and also the processor require a minimal start-up and initialization code to bring the CPU (and the SoC) -into a stable and initialized state and to initialize the C runtime environment before the actual application can be executed. -This start-up code is located in `sw/common/crt0.S` and is automatically linked _every_ application program -and placed right before the actual application code so it gets executed right after reset. +The CPU and also the processor require a minimal start-up and initialization code to bring the hardware into an +operational state. Furthermore, the C runtime requires an initialization before compiled code can be executed. +This setup is done by the start-up code (`sw/common/crt0.S`) which is automatically linked with _every_ application +program and gets mapped before the actual application code so it gets executed right after boot. The `crt0.S` start-up performs the following operations: [start=1] -. Clear <<_mstatus>>. -. Clear <<_mie>> disabling all interrupt sources. -. Install an <<_early_trap_handler>> to <<_mtvec>>. -. Initialize the global pointer `gp` and the stack pointer `sp` according to the <<_ram_layout>> provided by the linker script. According to the RISC-V ABI the stack pointer gets 128-bit-aligned. +. Clear <<_mstatus>> CSR. +. Clear <<_mie>> CSR disabling all interrupt sources. +. Install an <<_early_trap_handler>> to <<_mtvec>> CSR. +. Initialize the global pointer `gp` and the stack pointer `sp` according to the <<_ram_layout>> provided by the linker script. . Initialize all integer register `x1` - `x31` (only `x1` - `x15` if the `E` CPU extension is enabled). . Setup `.data` section to configure initialized variables. . Clear the `.bss` section. . Call all _constructors_ (if there are any). -. Call the application's `main` function (with no arguments: `argc` = `argv` = 0). -. If `main` returns: -** All interrupt sources are disabled by clearing <<_mie>>. -** The return value of `main` is copied to the <<_mscratch>> CSR to allow inspection by the debugger. -** Call all _destructors_ (if there are any). If any destructor causes an exception the crt0's trap handler is used for handling (= skipping) this. +. Call the application's `main()` function (with no arguments; `argc` = `argv` = 0). +. If `main()` returns: +** All interrupt sources are disabled by clearing <<_mie>> CSR. +** The return value of `main()` is copied to the <<_mscratch>> CSR to allow inspection by the debugger. +** Call all _destructors_ (if there are any). +** Re-install an <<_early_trap_handler>> to <<_mtvec>> CSR. If any destructor causes an exception the <<_early_trap_handler>> is used for handling. ** The CPU enters sleep mode executing the `wfi` instruction in an endless loop. :sectnums: -===== Early Trap Handler - -The start-up code provides a very basic trap handler for the early boot stage. This handler does nothing but trying to move -on to the next linear instruction whenever an interrupt or synchronous exception is encountered. +==== Early Trap Handler +The start-up code provides a very basic trap handler for the early boot phase. This handler does nothing but +trying to move on to the next linear instruction whenever an interrupt or synchronous exception is encountered. This simple trap handler does not interact with the stack at all as it just uses a single register that is backup-ed -using the <<_mscratch>> CSR. Furthermore, the information if the trap-causing instruction is compressed or uncompressed -is **not** determined by loading the instruction from memory. Instead, the transformed instruction word is read from the -<<_mtinst>> CSRs. These two features allow the trap handler to execute with minimal latency and high robustness. +using the <<_mscratch>> CSR. + +<<< +// #################################################################################################################### +:sectnums: +=== Executable Image Formats + +The compiled and linked executable (ELF file) is further processed by the NEORV32 image generator (`sw/image_gen`) to +generate the final executable file. The image generator can generate several types of executable file formats selected +by a flag when calling the generator. +**Note that all these options are managed by the makefile (see <<_makefile_targets>>).** + +[cols="<2,<8"] +[grid="none"] +|======================= +| `-app_bin` | Generates an executable binary file (including a bootloader header) for upload via the bootloader. +| `-app_vhd` | Generates an executable VHDL memory initialization image for the processor-internal IMEM. +| `-bld_vhd` | Generates an executable VHDL memory initialization image for the processor-internal BOOT ROM. +| `-raw_hex` | Generates a raw 8x ASCII hex-char file for custom purpose. +| `-raw_bin` | Generates a raw binary file `for custom purpose. +| `-raw_coe` | Generates a raw COE file for FPGA memory initialization. +| `-raw_mem` | Generates a raw MEM file for FPGA memory initialization. +| `-raw_mif` | Generates a raw MIF file for FPGA memory initialization. +|======================= + +.Image Generator Compilation +[NOTE] +The sources of the image generator are automatically compiled when invoking the makefile +(requiring a _native_ GCC installation). + +.Executable Header [NOTE] -The early-trap handler should be replaced by a more capable / informative one as soon as the application software is started -(for example by using the <<_neorv32_runtime_environment>>). +for the `app_bin` option the image generator adds a small header to the executable. This header is required by the +<<_bootloader>> to identify and manage the executable. The header consists of three 32-bit words located right +at the beginning of the file. The first word of the executable is the signature word and is always `0x4788cafe`. +Based on this word the bootloader can identify a valid image file. The next word represents the size in bytes of the +actual program image in bytes. A simple complement checksum of the actual program image is given by the third word. +This provides a simple protection against data transmission or storage errors. +**Note that this executable format cannot be used for _direct_ execution (e.g. via XIP or direct memory access).** <<< diff --git a/docs/datasheet/software_bootloader.adoc b/docs/datasheet/software_bootloader.adoc index 6eadc2011..acd282789 100644 --- a/docs/datasheet/software_bootloader.adoc +++ b/docs/datasheet/software_bootloader.adoc @@ -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. diff --git a/docs/figures/neorv32_boot_configurations.png b/docs/figures/neorv32_boot_configurations.png deleted file mode 100644 index abb6180ad..000000000 Binary files a/docs/figures/neorv32_boot_configurations.png and /dev/null differ diff --git a/docs/userguide/eclipse_ide.adoc b/docs/userguide/eclipse_ide.adoc index c00c6570b..b00dc747d 100644 --- a/docs/userguide/eclipse_ide.adoc +++ b/docs/userguide/eclipse_ide.adoc @@ -58,6 +58,11 @@ to a different location (makefile, NEORV32 sources, etc.). Make sure to adjust the binaries / installation folders of the RISC-V GCC toolchain and OpenOCD according to your installation. See the following chapter for more information. +.Makefile Adjustment +[IMPORTANT] +Make sure to adjust the variables inside the project's makefile to match your processor +configuration (memory sizes, CPU ISA configuration, etc.). + :sectnums: === Setup a new Eclipse Project from Scratch diff --git a/docs/userguide/packaging_vivado.adoc b/docs/userguide/packaging_vivado.adoc index efbb6a8cf..d741ee5cf 100644 --- a/docs/userguide/packaging_vivado.adoc +++ b/docs/userguide/packaging_vivado.adoc @@ -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. diff --git a/docs/userguide/simulating_the_processor.adoc b/docs/userguide/simulating_the_processor.adoc index 20f26edaa..108cd0f95 100644 --- a/docs/userguide/simulating_the_processor.adoc +++ b/docs/userguide/simulating_the_processor.adoc @@ -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. diff --git a/rtl/core/neorv32_application_image.vhd b/rtl/core/neorv32_application_image.vhd index d2804b224..2412e231b 100644 --- a/rtl/core/neorv32_application_image.vhd +++ b/rtl/core/neorv32_application_image.vhd @@ -1,11 +1,16 @@ --- The NEORV32 RISC-V Processor: https://github.com/stnolting/neorv32 --- Auto-generated memory initialization file (for APPLICATION) from source file +-- 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", diff --git a/rtl/core/neorv32_bootloader_image.vhd b/rtl/core/neorv32_bootloader_image.vhd index ec92bf2cf..18487d5e4 100644 --- a/rtl/core/neorv32_bootloader_image.vhd +++ b/rtl/core/neorv32_bootloader_image.vhd @@ -1,11 +1,16 @@ --- The NEORV32 RISC-V Processor: https://github.com/stnolting/neorv32 --- Auto-generated memory initialization file (for BOOTLOADER) from source file +-- 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", diff --git a/rtl/core/neorv32_bus.vhd b/rtl/core/neorv32_bus.vhd index 6d76f9a5a..b0c5fdd87 100644 --- a/rtl/core/neorv32_bus.vhd +++ b/rtl/core/neorv32_bus.vhd @@ -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'); diff --git a/rtl/core/neorv32_cpu_control.vhd b/rtl/core/neorv32_cpu_control.vhd index 36a5d7186..6eae8ccba 100644 --- a/rtl/core/neorv32_cpu_control.vhd +++ b/rtl/core/neorv32_cpu_control.vhd @@ -150,11 +150,11 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is signal issue_engine : issue_engine_t; -- instruction execution engine -- - type execute_engine_state_t is (DISPATCH, TRAP_ENTER, TRAP_EXIT, RESTART, SLEEP, EXECUTE, - ALU_WAIT, BRANCH, BRANCHED, SYSTEM, MEM_REQ, MEM_WAIT); - type execute_engine_t is record - state : execute_engine_state_t; - state_nxt : execute_engine_state_t; + type exe_engine_state_t is (DISPATCH, TRAP_ENTER, TRAP_EXIT, RESTART, SLEEP, EXECUTE, + ALU_WAIT, BRANCH, BRANCHED, SYSTEM, MEM_REQ, MEM_WAIT); + type exe_engine_t is record + state : exe_engine_state_t; + state_nxt : exe_engine_state_t; ir : std_ulogic_vector(31 downto 0); -- instruction word being executed right now ir_nxt : std_ulogic_vector(31 downto 0); is_ci : std_ulogic; -- current instruction is de-compressed instruction @@ -164,9 +164,9 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is pc_we : std_ulogic; -- PC update enable next_pc : std_ulogic_vector(XLEN-1 downto 0); -- next PC, corresponding to next instruction to be executed end record; - signal execute_engine : execute_engine_t; + signal exe_engine : exe_engine_t; - -- simplified opcode -- + -- simplified opcode (2 LSBs hardwired to "11" to indicate rv32) -- signal opcode : std_ulogic_vector(6 downto 0); -- execution monitor -- @@ -284,7 +284,7 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is -- debug-mode controller -- type debug_ctrl_t is record - running, trig_hw, trig_break, trig_halt, trig_step : std_ulogic; -- single-stepping mode trigger + run, trig_hw, trig_break, trig_halt, trig_step : std_ulogic; end record; signal debug_ctrl : debug_ctrl_t; @@ -345,7 +345,7 @@ begin when others => -- IF_RESTART: set new start address -- ------------------------------------------------------------ - fetch_engine.pc <= execute_engine.next_pc(XLEN-1 downto 1) & '0'; -- initialize from PC incl. 16-bit-alignment bit + fetch_engine.pc <= exe_engine.next_pc(XLEN-1 downto 1) & '0'; -- initialize from PC incl. 16-bit-alignment bit fetch_engine.priv <= csr.privilege_eff; -- set new privilege level fetch_engine.state <= IF_REQUEST; @@ -427,7 +427,7 @@ begin issue_engine.align <= '0'; -- start aligned after reset elsif rising_edge(clk_i) then if (fetch_engine.restart = '1') then - issue_engine.align <= execute_engine.next_pc(1); -- branch to unaligned address? + issue_engine.align <= exe_engine.next_pc(1); -- branch to unaligned address? elsif (issue_engine.ack = '1') then issue_engine.align <= (issue_engine.align and (not issue_engine.align_clr)) or issue_engine.align_set; -- "rs flip-flop" end if; @@ -506,7 +506,7 @@ begin if (rstn_i = '0') then alu_imm_o <= (others => '0'); elsif rising_edge(clk_i) then - if (execute_engine.state = DISPATCH) then -- prepare update of next_pc (using ALU's PC + IMM in EXECUTE state) + if (exe_engine.state = DISPATCH) then -- prepare update of next_pc (using ALU's PC + IMM in EXECUTE state) alu_imm_o <= (others => '0'); if RISCV_ISA_C and (issue_engine.data(33) = '1') then -- is de-compressed C instruction? alu_imm_o(3 downto 0) <= x"2"; @@ -514,16 +514,16 @@ begin alu_imm_o(3 downto 0) <= x"4"; end if; else - alu_imm_o <= replicate_f(execute_engine.ir(31), 21) & execute_engine.ir(30 downto 21) & execute_engine.ir(20); -- default: I-immediate + alu_imm_o <= replicate_f(exe_engine.ir(31), 21) & exe_engine.ir(30 downto 21) & exe_engine.ir(20); -- default: I-immediate case opcode is when opcode_store_c => -- S-immediate - alu_imm_o <= replicate_f(execute_engine.ir(31), 21) & execute_engine.ir(30 downto 25) & execute_engine.ir(11 downto 7); + alu_imm_o <= replicate_f(exe_engine.ir(31), 21) & exe_engine.ir(30 downto 25) & exe_engine.ir(11 downto 7); when opcode_branch_c => -- B-immediate - alu_imm_o <= replicate_f(execute_engine.ir(31), 20) & execute_engine.ir(7) & execute_engine.ir(30 downto 25) & execute_engine.ir(11 downto 8) & '0'; + alu_imm_o <= replicate_f(exe_engine.ir(31), 20) & exe_engine.ir(7) & exe_engine.ir(30 downto 25) & exe_engine.ir(11 downto 8) & '0'; when opcode_lui_c | opcode_auipc_c => -- U-immediate - alu_imm_o <= execute_engine.ir(31 downto 12) & x"000"; + alu_imm_o <= exe_engine.ir(31 downto 12) & x"000"; when opcode_jal_c => -- J-immediate - alu_imm_o <= replicate_f(execute_engine.ir(31), 12) & execute_engine.ir(19 downto 12) & execute_engine.ir(20) & execute_engine.ir(30 downto 21) & '0'; + alu_imm_o <= replicate_f(exe_engine.ir(31), 12) & exe_engine.ir(19 downto 12) & exe_engine.ir(20) & exe_engine.ir(30 downto 21) & '0'; when opcode_amo_c => -- atomic memory access if RISCV_ISA_Zalrsc then alu_imm_o <= (others => '0'); end if; when others => @@ -536,16 +536,16 @@ begin -- Branch Condition Check ----------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - branch_check: process(execute_engine.ir, alu_cmp_i) + branch_check: process(exe_engine.ir, alu_cmp_i) begin - if (execute_engine.ir(instr_opcode_lsb_c+2) = '0') then -- conditional branch - if (execute_engine.ir(instr_funct3_msb_c) = '0') then -- beq / bne - execute_engine.branch_taken <= alu_cmp_i(cmp_equal_c) xor execute_engine.ir(instr_funct3_lsb_c); + if (exe_engine.ir(instr_opcode_lsb_c+2) = '0') then -- conditional branch + if (exe_engine.ir(instr_funct3_msb_c) = '0') then -- beq / bne + exe_engine.branch_taken <= alu_cmp_i(cmp_equal_c) xor exe_engine.ir(instr_funct3_lsb_c); else -- blt(u) / bge(u) - execute_engine.branch_taken <= alu_cmp_i(cmp_less_c) xor execute_engine.ir(instr_funct3_lsb_c); + exe_engine.branch_taken <= alu_cmp_i(cmp_less_c) xor exe_engine.ir(instr_funct3_lsb_c); end if; else -- unconditional branch - execute_engine.branch_taken <= '1'; + exe_engine.branch_taken <= '1'; end if; end process branch_check; @@ -555,63 +555,63 @@ begin execute_engine_fsm_sync: process(rstn_i, clk_i) begin if (rstn_i = '0') then - ctrl <= ctrl_bus_zero_c; - execute_engine.state <= RESTART; - execute_engine.ir <= (others => '0'); - execute_engine.is_ci <= '0'; - execute_engine.pc <= BOOT_ADDR(XLEN-1 downto 2) & "00"; -- 32-bit-aligned boot address - execute_engine.next_pc <= BOOT_ADDR(XLEN-1 downto 2) & "00"; -- 32-bit-aligned boot address - pc_next_o <= (others => '0'); + ctrl <= ctrl_bus_zero_c; + exe_engine.state <= RESTART; + exe_engine.ir <= (others => '0'); + exe_engine.is_ci <= '0'; + exe_engine.pc <= BOOT_ADDR(XLEN-1 downto 2) & "00"; -- 32-bit-aligned boot address + exe_engine.next_pc <= BOOT_ADDR(XLEN-1 downto 2) & "00"; -- 32-bit-aligned boot address + pc_next_o <= (others => '0'); elsif rising_edge(clk_i) then -- control bus -- ctrl <= ctrl_nxt; -- execute engine arbiter -- - execute_engine.state <= execute_engine.state_nxt; - execute_engine.ir <= execute_engine.ir_nxt; - execute_engine.is_ci <= execute_engine.is_ci_nxt; + exe_engine.state <= exe_engine.state_nxt; + exe_engine.ir <= exe_engine.ir_nxt; + exe_engine.is_ci <= exe_engine.is_ci_nxt; -- current PC: address of instruction being executed -- - if (execute_engine.pc_we = '1') then - execute_engine.pc <= execute_engine.next_pc(XLEN-1 downto 1) & '0'; + if (exe_engine.pc_we = '1') then + exe_engine.pc <= exe_engine.next_pc(XLEN-1 downto 1) & '0'; end if; -- next PC: address of next instruction -- pc_next_o <= (others => '0'); -- output zero if not a branch instruction - case execute_engine.state is + case exe_engine.state is when TRAP_ENTER => -- starting trap environment -- ------------------------------------------------------------ if (trap_ctrl.cause(5) = '1') and RISCV_ISA_Sdext then -- debug mode (re-)entry - execute_engine.next_pc <= DEBUG_PARK_ADDR(XLEN-1 downto 2) & "00"; -- debug mode enter; start at "parking loop" - elsif (debug_ctrl.running = '1') and RISCV_ISA_Sdext then -- any other trap INSIDE debug mode - execute_engine.next_pc <= DEBUG_EXC_ADDR(XLEN-1 downto 2) & "00"; -- debug mode enter: start at "parking loop" + exe_engine.next_pc <= DEBUG_PARK_ADDR(XLEN-1 downto 2) & "00"; -- debug mode enter; start at "parking loop" + 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" else -- normal start of trap if (csr.mtvec(0) = '1') and (trap_ctrl.cause(6) = '1') then -- vectored mode + interrupt - execute_engine.next_pc <= csr.mtvec(XLEN-1 downto 7) & trap_ctrl.cause(4 downto 0) & "00"; -- pc = mtvec + 4 * mcause + exe_engine.next_pc <= csr.mtvec(XLEN-1 downto 7) & trap_ctrl.cause(4 downto 0) & "00"; -- pc = mtvec + 4 * mcause else - execute_engine.next_pc <= csr.mtvec(XLEN-1 downto 2) & "00"; -- pc = mtvec + exe_engine.next_pc <= csr.mtvec(XLEN-1 downto 2) & "00"; -- pc = mtvec end if; end if; when TRAP_EXIT => -- leaving trap environment -- ------------------------------------------------------------ - if (debug_ctrl.running = '1') and RISCV_ISA_Sdext then -- debug mode exit - execute_engine.next_pc <= csr.dpc(XLEN-1 downto 1) & '0'; + if (debug_ctrl.run = '1') and RISCV_ISA_Sdext then -- debug mode exit + exe_engine.next_pc <= csr.dpc(XLEN-1 downto 1) & '0'; else -- normal end of trap - execute_engine.next_pc <= csr.mepc(XLEN-1 downto 1) & '0'; + exe_engine.next_pc <= csr.mepc(XLEN-1 downto 1) & '0'; end if; when BRANCH => -- branch instruction -- ------------------------------------------------------------ - pc_next_o <= execute_engine.next_pc(XLEN-1 downto 1) & '0'; -- output as link/return address - if (trap_ctrl.exc_buf(exc_illegal_c) = '0') and (execute_engine.branch_taken = '1') then -- valid taken branch - execute_engine.next_pc <= alu_add_i(XLEN-1 downto 1) & '0'; + pc_next_o <= exe_engine.next_pc(XLEN-1 downto 1) & '0'; -- output as link/return address + if (trap_ctrl.exc_buf(exc_illegal_c) = '0') and (exe_engine.branch_taken = '1') then -- valid taken branch + exe_engine.next_pc <= alu_add_i(XLEN-1 downto 1) & '0'; end if; when EXECUTE => -- linear increment (use ALU's adder to compute next_pc = current_pc + imm (2/4)) -- ------------------------------------------------------------ - execute_engine.next_pc <= alu_add_i(XLEN-1 downto 1) & '0'; + exe_engine.next_pc <= alu_add_i(XLEN-1 downto 1) & '0'; when others => -- no update -- ------------------------------------------------------------ @@ -622,43 +622,43 @@ begin end process execute_engine_fsm_sync; -- check if branch destination is misaligned -- - trap_ctrl.instr_ma <= '1' when (execute_engine.state = BRANCH) and -- branch instruction (can also be INVALID as exc_illegal_c has higher priority) - (execute_engine.branch_taken = '1') and -- branch is taken + trap_ctrl.instr_ma <= '1' when (exe_engine.state = BRANCH) and -- branch instruction (can also be INVALID as exc_illegal_c has higher priority) + (exe_engine.branch_taken = '1') and -- branch is taken (alu_add_i(1) = '1') and (not RISCV_ISA_C) else '0'; -- misaligned destination -- current PC output -- - pc_curr_o <= execute_engine.pc(XLEN-1 downto 1) & '0'; + pc_curr_o <= exe_engine.pc(XLEN-1 downto 1) & '0'; -- simplified rv32 opcode -- - opcode <= execute_engine.ir(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11"; + opcode <= exe_engine.ir(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11"; -- Execute Engine FSM Comb ---------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - execute_engine_fsm_comb: process(execute_engine, debug_ctrl, trap_ctrl, hw_trigger_match, opcode, issue_engine, csr, alu_cp_done_i, lsu_wait_i) + execute_engine_fsm_comb: process(exe_engine, debug_ctrl, trap_ctrl, hw_trigger_match, opcode, issue_engine, csr, alu_cp_done_i, lsu_wait_i) variable funct3_v : std_ulogic_vector(2 downto 0); variable funct7_v : std_ulogic_vector(6 downto 0); begin -- shortcuts -- - funct3_v := execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c); - funct7_v := execute_engine.ir(instr_funct7_msb_c downto instr_funct7_lsb_c); + funct3_v := exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c); + funct7_v := exe_engine.ir(instr_funct7_msb_c downto instr_funct7_lsb_c); -- arbiter defaults -- - execute_engine.state_nxt <= execute_engine.state; - execute_engine.ir_nxt <= execute_engine.ir; - execute_engine.is_ci_nxt <= execute_engine.is_ci; - execute_engine.pc_we <= '0'; - issue_engine.ack <= '0'; - fetch_engine.reset <= '0'; - trap_ctrl.env_enter <= '0'; - trap_ctrl.env_exit <= '0'; - trap_ctrl.instr_be <= '0'; - trap_ctrl.ecall <= '0'; - trap_ctrl.ebreak <= '0'; - trap_ctrl.hwtrig <= '0'; - csr.we_nxt <= '0'; - csr.re_nxt <= '0'; - ctrl_nxt <= ctrl_bus_zero_c; -- all zero/off by default (default ALU operation = ZERO, ALU.adder_out = ADD) + exe_engine.state_nxt <= exe_engine.state; + exe_engine.ir_nxt <= exe_engine.ir; + exe_engine.is_ci_nxt <= exe_engine.is_ci; + exe_engine.pc_we <= '0'; + issue_engine.ack <= '0'; + fetch_engine.reset <= '0'; + trap_ctrl.env_enter <= '0'; + trap_ctrl.env_exit <= '0'; + trap_ctrl.instr_be <= '0'; + trap_ctrl.ecall <= '0'; + trap_ctrl.ebreak <= '0'; + trap_ctrl.hwtrig <= '0'; + csr.we_nxt <= '0'; + csr.re_nxt <= '0'; + ctrl_nxt <= ctrl_bus_zero_c; -- all zero/off by default (ALU operation = ZERO, ALU.adder_out = ADD) -- ALU sign control -- if (opcode(4) = '1') then -- ALU ops @@ -685,13 +685,13 @@ begin -- memory read/write access -- if RISCV_ISA_Zalrsc and (opcode(2) = opcode_amo_c(2)) then -- atomic lr/sc - ctrl_nxt.lsu_rw <= execute_engine.ir(instr_funct7_lsb_c+2); + ctrl_nxt.lsu_rw <= exe_engine.ir(instr_funct7_lsb_c+2); else -- normal load/store - ctrl_nxt.lsu_rw <= execute_engine.ir(5); + ctrl_nxt.lsu_rw <= exe_engine.ir(5); end if; -- state machine -- - case execute_engine.state is + case exe_engine.state is when DISPATCH => -- wait for ISSUE ENGINE to emit a valid instruction word -- ------------------------------------------------------------ @@ -699,37 +699,37 @@ begin ctrl_nxt.alu_opb_mux <= '1'; -- prepare update of next_pc in EXECUTE (opb = imm = +2/4) -- if (trap_ctrl.env_pending = '1') or (trap_ctrl.exc_fire = '1') then -- pending trap or pending exception (fast) - execute_engine.state_nxt <= TRAP_ENTER; + exe_engine.state_nxt <= TRAP_ENTER; elsif RISCV_ISA_Sdtrig and (hw_trigger_match = '1') then -- hardware breakpoint - execute_engine.pc_we <= '1'; -- pc <= next_pc; intercept BEFORE executing the instruction - trap_ctrl.hwtrig <= '1'; - execute_engine.state_nxt <= DISPATCH; -- stay here another round until trap_ctrl.hwtrig arrives in trap_ctrl.env_pending + exe_engine.pc_we <= '1'; -- pc <= next_pc; intercept BEFORE executing the instruction + trap_ctrl.hwtrig <= '1'; + exe_engine.state_nxt <= DISPATCH; -- stay here another round until trap_ctrl.hwtrig arrives in trap_ctrl.env_pending elsif (issue_engine.valid(0) = '1') or (issue_engine.valid(1) = '1') then -- new instruction word available - issue_engine.ack <= '1'; - trap_ctrl.instr_be <= issue_engine.data(32); -- access fault during instruction fetch - execute_engine.is_ci_nxt <= issue_engine.data(33); -- this is a de-compressed instruction - execute_engine.ir_nxt <= issue_engine.data(31 downto 0); -- instruction word - execute_engine.pc_we <= '1'; -- pc <= next_pc - execute_engine.state_nxt <= EXECUTE; + issue_engine.ack <= '1'; + trap_ctrl.instr_be <= issue_engine.data(32); -- access fault during instruction fetch + exe_engine.is_ci_nxt <= issue_engine.data(33); -- this is a de-compressed instruction + exe_engine.ir_nxt <= issue_engine.data(31 downto 0); -- instruction word + exe_engine.pc_we <= '1'; -- pc <= next_pc + exe_engine.state_nxt <= EXECUTE; end if; when TRAP_ENTER => -- enter trap environment and jump to trap vector -- ------------------------------------------------------------ if (trap_ctrl.env_pending = '1') then -- wait for sync. exceptions to become pending - trap_ctrl.env_enter <= '1'; - execute_engine.state_nxt <= RESTART; + trap_ctrl.env_enter <= '1'; + exe_engine.state_nxt <= RESTART; end if; when TRAP_EXIT => -- return from trap environment and jump to trap PC -- ------------------------------------------------------------ - trap_ctrl.env_exit <= '1'; - execute_engine.state_nxt <= RESTART; + trap_ctrl.env_exit <= '1'; + exe_engine.state_nxt <= RESTART; when RESTART => -- reset and restart instruction fetch at -- ------------------------------------------------------------ - ctrl_nxt.rf_zero_we <= not bool_to_ulogic_f(REGFILE_HW_RST); -- house keeping: force writing zero to x0 if it's a phys. register - fetch_engine.reset <= '1'; - execute_engine.state_nxt <= BRANCHED; + ctrl_nxt.rf_zero_we <= not bool_to_ulogic_f(REGFILE_HW_RST); -- house keeping: force writing zero to x0 if it's a phys. register + fetch_engine.reset <= '1'; + exe_engine.state_nxt <= BRANCHED; when EXECUTE => -- decode and execute instruction (control will be here for exactly 1 cycle in any case) -- [NOTE] register file is read in this stage; due to the sync read, data will be available in the _next_ state @@ -741,77 +741,73 @@ begin -- ALU core operation -- case funct3_v is - when funct3_subadd_c => ctrl_nxt.alu_op <= alu_op_add_c; -- ADD(I), SUB - when funct3_slt_c => ctrl_nxt.alu_op <= alu_op_slt_c; -- SLT(I) - when funct3_sltu_c => ctrl_nxt.alu_op <= alu_op_slt_c; -- SLTU(I) - when funct3_xor_c => ctrl_nxt.alu_op <= alu_op_xor_c; -- XOR(I) - when funct3_or_c => ctrl_nxt.alu_op <= alu_op_or_c; -- OR(I) - when funct3_and_c => ctrl_nxt.alu_op <= alu_op_and_c; -- AND(I) - when others => ctrl_nxt.alu_op <= alu_op_zero_c; + when funct3_sadd_c => ctrl_nxt.alu_op <= alu_op_add_c; -- ADD(I), SUB + when funct3_slt_c => ctrl_nxt.alu_op <= alu_op_slt_c; -- SLT(I) + when funct3_sltu_c => ctrl_nxt.alu_op <= alu_op_slt_c; -- SLTU(I) + when funct3_xor_c => ctrl_nxt.alu_op <= alu_op_xor_c; -- XOR(I) + when funct3_or_c => ctrl_nxt.alu_op <= alu_op_or_c; -- OR(I) + when funct3_and_c => ctrl_nxt.alu_op <= alu_op_and_c; -- AND(I) + when others => ctrl_nxt.alu_op <= alu_op_zero_c; end case; -- addition/subtraction control -- if (funct3_v(2 downto 1) = funct3_slt_c(2 downto 1)) or -- SLT(I), SLTU(I) - ((funct3_v = funct3_subadd_c) and (opcode(5) = '1') and (execute_engine.ir(instr_funct7_msb_c-1) = '1')) then -- SUB + ((funct3_v = funct3_sadd_c) and (opcode(5) = '1') and (exe_engine.ir(instr_funct7_msb_c-1) = '1')) then -- SUB ctrl_nxt.alu_sub <= '1'; end if; -- is base rv32i/e ALU[I] instruction (excluding shifts)? -- if ((opcode(5) = '0') and (funct3_v /= funct3_sll_c) and (funct3_v /= funct3_sr_c)) or -- base ALUI instruction (excluding SLLI, SRLI, SRAI) - ((opcode(5) = '1') and (((funct3_v = funct3_subadd_c) and (funct7_v = "0000000")) or - ((funct3_v = funct3_subadd_c) and (funct7_v = "0100000")) or - ((funct3_v = funct3_slt_c) and (funct7_v = "0000000")) or - ((funct3_v = funct3_sltu_c) and (funct7_v = "0000000")) or - ((funct3_v = funct3_xor_c) and (funct7_v = "0000000")) or - ((funct3_v = funct3_or_c) and (funct7_v = "0000000")) or - ((funct3_v = funct3_and_c) and (funct7_v = "0000000")) -- base ALU instruction (excluding SLL, SRL, SRA)? - )) then - ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception) - execute_engine.state_nxt <= DISPATCH; + ((opcode(5) = '1') and (((funct3_v = funct3_sadd_c) and (funct7_v = "0000000")) or ((funct3_v = funct3_sadd_c) and (funct7_v = "0100000")) or + ((funct3_v = funct3_slt_c) and (funct7_v = "0000000")) or ((funct3_v = funct3_sltu_c) and (funct7_v = "0000000")) or + ((funct3_v = funct3_xor_c) and (funct7_v = "0000000")) or ((funct3_v = funct3_or_c) and (funct7_v = "0000000")) or + ((funct3_v = funct3_and_c) and (funct7_v = "0000000")))) then -- base ALU instruction (excluding SLL, SRL, SRA)? + ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception) + exe_engine.state_nxt <= DISPATCH; else -- [NOTE] potential illegal ALU[I] instruction are handled as multi-cycle operations that will time-out if no co-processor responds - ctrl_nxt.alu_cp_alu <= '1'; -- trigger ALU[I] opcode-space co-processor - execute_engine.state_nxt <= ALU_WAIT; + ctrl_nxt.alu_cp_alu <= '1'; -- trigger ALU[I] opcode-space co-processor + exe_engine.state_nxt <= ALU_WAIT; end if; -- load upper immediate -- when opcode_lui_c => - ctrl_nxt.alu_op <= alu_op_movb_c; -- pass immediate - ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception) - execute_engine.state_nxt <= DISPATCH; + ctrl_nxt.alu_op <= alu_op_movb_c; -- pass immediate + ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception) + exe_engine.state_nxt <= DISPATCH; -- add upper immediate to PC -- when opcode_auipc_c => - ctrl_nxt.alu_op <= alu_op_add_c; -- add PC and immediate - ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception) - execute_engine.state_nxt <= DISPATCH; + ctrl_nxt.alu_op <= alu_op_add_c; -- add PC and immediate + ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception) + exe_engine.state_nxt <= DISPATCH; -- memory access -- when opcode_load_c | opcode_store_c | opcode_amo_c => - execute_engine.state_nxt <= MEM_REQ; + exe_engine.state_nxt <= MEM_REQ; -- branch / jump-and-link (with register) -- when opcode_branch_c | opcode_jal_c | opcode_jalr_c => - execute_engine.state_nxt <= BRANCH; + exe_engine.state_nxt <= BRANCH; -- memory fence operations (execute even if illegal funct3) -- when opcode_fence_c => - ctrl_nxt.lsu_fence <= '1'; -- [NOTE] fence == fence.i; ignore all ordering bits - execute_engine.state_nxt <= RESTART; -- reset instruction fetch + IPB (actually only required for fence.i) + ctrl_nxt.lsu_fence <= '1'; -- [NOTE] fence == fence.i; ignore all ordering bits + exe_engine.state_nxt <= RESTART; -- reset instruction fetch + IPB (actually only required for fence.i) -- FPU: floating-point operations -- when opcode_fop_c => - ctrl_nxt.alu_cp_fpu <= '1'; -- trigger FPU co-processor - execute_engine.state_nxt <= ALU_WAIT; -- will be aborted via monitor timeout if FPU is not implemented + ctrl_nxt.alu_cp_fpu <= '1'; -- trigger FPU co-processor + exe_engine.state_nxt <= ALU_WAIT; -- will be aborted via monitor timeout if FPU is not implemented -- CFU: custom RISC-V instructions -- when opcode_cust0_c | opcode_cust1_c => - ctrl_nxt.alu_cp_cfu <= '1'; -- trigger CFU co-processor - execute_engine.state_nxt <= ALU_WAIT; -- will be aborted via monitor timeout if CFU is not implemented + ctrl_nxt.alu_cp_cfu <= '1'; -- trigger CFU co-processor + exe_engine.state_nxt <= ALU_WAIT; -- will be aborted via monitor timeout if CFU is not implemented -- environment/CSR operation or ILLEGAL opcode -- when others => - csr.re_nxt <= '1'; - execute_engine.state_nxt <= SYSTEM; + csr.re_nxt <= '1'; + exe_engine.state_nxt <= SYSTEM; end case; -- /EXECUTE @@ -819,30 +815,30 @@ begin -- ------------------------------------------------------------ ctrl_nxt.alu_op <= alu_op_cp_c; if (alu_cp_done_i = '1') or (trap_ctrl.exc_buf(exc_illegal_c) = '1') then - ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception) - execute_engine.state_nxt <= DISPATCH; + ctrl_nxt.rf_wb_en <= '1'; -- valid RF write-back (won't happen if exception) + exe_engine.state_nxt <= DISPATCH; end if; when BRANCH => -- update next_pc on taken branches and jumps -- ------------------------------------------------------------ ctrl_nxt.rf_wb_en <= opcode(2); -- save return address if link operation (won't happen if exception) - if (trap_ctrl.exc_buf(exc_illegal_c) = '0') and (execute_engine.branch_taken = '1') then -- valid taken branch - fetch_engine.reset <= '1'; -- reset instruction fetch to restart at modified PC - execute_engine.state_nxt <= BRANCHED; -- shortcut (faster than going to RESTART) + if (trap_ctrl.exc_buf(exc_illegal_c) = '0') and (exe_engine.branch_taken = '1') then -- valid taken branch + fetch_engine.reset <= '1'; -- reset instruction fetch to restart at modified PC + exe_engine.state_nxt <= BRANCHED; -- shortcut (faster than going to RESTART) else - execute_engine.state_nxt <= DISPATCH; + exe_engine.state_nxt <= DISPATCH; end if; when BRANCHED => -- delay cycle to wait for reset of pipeline front-end (instruction fetch) -- ------------------------------------------------------------ - execute_engine.state_nxt <= DISPATCH; + exe_engine.state_nxt <= DISPATCH; when MEM_REQ => -- trigger memory request -- ------------------------------------------------------------ if (trap_ctrl.exc_buf(exc_illegal_c) = '0') then -- memory request only if not an illegal instruction ctrl_nxt.lsu_req <= '1'; -- memory access request end if; - execute_engine.state_nxt <= MEM_WAIT; + exe_engine.state_nxt <= MEM_WAIT; when MEM_WAIT => -- wait for bus transaction to finish -- ------------------------------------------------------------ @@ -853,29 +849,29 @@ begin if (RISCV_ISA_Zalrsc and (opcode(2) = opcode_amo_c(2))) or (opcode(5) = '0') then -- atomic operation / normal load ctrl_nxt.rf_wb_en <= '1'; -- allow write-back to register file (won't happen in case of exception) end if; - execute_engine.state_nxt <= DISPATCH; + exe_engine.state_nxt <= DISPATCH; end if; when SLEEP => -- sleep mode -- ------------------------------------------------------------ if (trap_ctrl.wakeup = '1') then - execute_engine.state_nxt <= DISPATCH; + exe_engine.state_nxt <= DISPATCH; end if; when others => -- SYSTEM - CSR/ENVIRONMENT operation; no effect if illegal instruction -- ------------------------------------------------------------ - execute_engine.state_nxt <= DISPATCH; -- default + exe_engine.state_nxt <= DISPATCH; -- default if (funct3_v = funct3_env_c) and (trap_ctrl.exc_buf(exc_illegal_c) = '0') then -- non-illegal ENVIRONMENT - case execute_engine.ir(instr_funct12_lsb_c+2 downto instr_funct12_lsb_c) is -- three LSBs are sufficient here - when "000" => trap_ctrl.ecall <= '1'; -- ecall - when "001" => trap_ctrl.ebreak <= '1'; -- ebreak - when "010" => execute_engine.state_nxt <= TRAP_EXIT; -- xret - when "101" => execute_engine.state_nxt <= SLEEP; -- wfi - when others => execute_engine.state_nxt <= DISPATCH; -- illegal or CSR operation + case exe_engine.ir(instr_funct12_lsb_c+2 downto instr_funct12_lsb_c) is -- three LSBs are sufficient here + when "000" => trap_ctrl.ecall <= '1'; -- ecall + when "001" => trap_ctrl.ebreak <= '1'; -- ebreak + when "010" => exe_engine.state_nxt <= TRAP_EXIT; -- xret + when "101" => exe_engine.state_nxt <= SLEEP; -- wfi + when others => exe_engine.state_nxt <= DISPATCH; -- illegal or CSR operation end case; end if; -- always write to CSR (if CSR instruction); ENVIRONMENT operations have rs1/imm5 = zero so this won't happen then -- - if (funct3_v = funct3_csrrw_c) or (funct3_v = funct3_csrrwi_c) or (execute_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c) /= "00000") then + if (funct3_v = funct3_csrrw_c) or (funct3_v = funct3_csrrwi_c) or (exe_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c) /= "00000") then csr.we_nxt <= '1'; -- CSRRW[I]: always write CSR; CSRR[S/C][I]: write CSR if rs1/imm5 is NOT zero end if; -- always write to RF; ENVIRONMENT operations have rd = zero so this does not hurt -- @@ -890,9 +886,9 @@ begin -- register file -- ctrl_o.rf_wb_en <= ctrl.rf_wb_en and (not trap_ctrl.exc_fire); -- inhibit write-back if exception - ctrl_o.rf_rs1 <= execute_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c); - ctrl_o.rf_rs2 <= execute_engine.ir(instr_rs2_msb_c downto instr_rs2_lsb_c); - ctrl_o.rf_rd <= execute_engine.ir(instr_rd_msb_c downto instr_rd_lsb_c); + ctrl_o.rf_rs1 <= exe_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c); + ctrl_o.rf_rs2 <= exe_engine.ir(instr_rs2_msb_c downto instr_rs2_lsb_c); + ctrl_o.rf_rd <= exe_engine.ir(instr_rd_msb_c downto instr_rd_lsb_c); ctrl_o.rf_zero_we <= ctrl.rf_zero_we; -- alu -- ctrl_o.alu_op <= ctrl.alu_op; @@ -906,18 +902,18 @@ begin -- load/store unit -- ctrl_o.lsu_req <= ctrl.lsu_req; ctrl_o.lsu_rw <= ctrl.lsu_rw; - ctrl_o.lsu_mo_we <= '1' when (execute_engine.state = MEM_REQ) else '0'; -- write memory output registers (data & address) + ctrl_o.lsu_mo_we <= '1' when (exe_engine.state = MEM_REQ) else '0'; -- write memory output registers (data & address) ctrl_o.lsu_fence <= ctrl.lsu_fence; ctrl_o.lsu_priv <= csr.mstatus_mpp when (csr.mstatus_mprv = '1') else csr.privilege_eff; -- effective privilege level for loads/stores in M-mode -- instruction word bit fields -- - ctrl_o.ir_funct3 <= execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c); - ctrl_o.ir_funct12 <= execute_engine.ir(instr_funct12_msb_c downto instr_funct12_lsb_c); + ctrl_o.ir_funct3 <= exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c); + ctrl_o.ir_funct12 <= exe_engine.ir(instr_funct12_msb_c downto instr_funct12_lsb_c); ctrl_o.ir_opcode <= opcode; -- cpu status -- ctrl_o.cpu_priv <= csr.privilege_eff; ctrl_o.cpu_sleep <= sleep_mode; ctrl_o.cpu_trap <= trap_ctrl.env_enter; - ctrl_o.cpu_debug <= debug_ctrl.running; + ctrl_o.cpu_debug <= debug_ctrl.run; -- **************************************************************************************************************************** @@ -936,7 +932,7 @@ begin end process multi_cycle_monitor; -- timeout counter (allow mapping of entire logic into the LUTs in front of the carry-chain) -- - monitor.cnt_add <= monitor.cnt when (execute_engine.state = ALU_WAIT) else (others => '0'); + monitor.cnt_add <= monitor.cnt when (exe_engine.state = ALU_WAIT) else (others => '0'); -- raise illegal instruction exception if a multi-cycle instruction takes longer than a bound amount of time -- monitor.exc <= monitor.cnt(monitor.cnt'left); @@ -944,11 +940,11 @@ begin -- CSR Access Check ----------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - csr_check: process(execute_engine.ir, debug_ctrl.running, csr) + csr_check: process(exe_engine.ir, debug_ctrl.run, csr) variable csr_addr_v : std_ulogic_vector(11 downto 0); begin - -- CSR address right from the instruction word -- - csr_addr_v := execute_engine.ir(instr_imm12_msb_c downto instr_imm12_lsb_c); + -- shortcut: CSR address right from the instruction word -- + csr_addr_v := exe_engine.ir(instr_imm12_msb_c downto instr_imm12_lsb_c); -- ------------------------------------------------------------ -- Available at all @@ -1015,9 +1011,9 @@ begin -- R/W capabilities -- ------------------------------------------------------------ if (csr_addr_v(11 downto 10) = "11") and -- CSR is read-only - ((execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrw_c) or -- will always write to CSR - (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrwi_c) or -- will always write to CSR - (execute_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c) /= "00000")) then -- clear/set instructions: write to CSR only if rs1/imm5 is NOT zero + ((exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrw_c) or -- will always write to CSR + (exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csrrwi_c) or -- will always write to CSR + (exe_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c) /= "00000")) then -- clear/set instructions: write to CSR only if rs1/imm5 is NOT zero csr_valid(1) <= '0'; -- invalid access else csr_valid(1) <= '1'; -- access granted @@ -1027,7 +1023,7 @@ begin -- Privilege level -- ------------------------------------------------------------ if (csr_addr_v(11 downto 2) = csr_dcsr_c(11 downto 2)) and -- debug-mode-only CSR (dcsr, dpc, dscratch)? - RISCV_ISA_Sdext and (debug_ctrl.running = '0') then -- debug-mode implemented and not running? + RISCV_ISA_Sdext and (debug_ctrl.run = '0') then -- debug-mode implemented and not running? csr_valid(0) <= '0'; -- invalid access elsif RISCV_ISA_Zicntr and RISCV_ISA_U and (csr.privilege_eff = '0') and -- any user-mode counters available and in user-mode? (csr_addr_v(11 downto 8) = csr_cycle_c(11 downto 8)) and -- user-mode counter access @@ -1045,40 +1041,40 @@ begin -- Illegal Instruction Check -------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - illegal_check: process(execute_engine, csr, csr_valid, debug_ctrl) + illegal_check: process(exe_engine, csr, csr_valid, debug_ctrl) begin - case execute_engine.ir(instr_opcode_msb_c downto instr_opcode_lsb_c) is -- check entire opcode + case exe_engine.ir(instr_opcode_msb_c downto instr_opcode_lsb_c) is -- check entire opcode when opcode_lui_c | opcode_auipc_c | opcode_jal_c => -- U-instruction type illegal_cmd <= '0'; -- all encodings are valid when opcode_jalr_c => -- unconditional jump-and-link - case execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is + case exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is when "000" => illegal_cmd <= '0'; when others => illegal_cmd <= '1'; end case; when opcode_branch_c => -- conditional branch - case execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is + case exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is when funct3_beq_c | funct3_bne_c | funct3_blt_c | funct3_bge_c | funct3_bltu_c | funct3_bgeu_c => illegal_cmd <= '0'; when others => illegal_cmd <= '1'; end case; when opcode_load_c => -- memory load - case execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is + case exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is when funct3_lb_c | funct3_lh_c | funct3_lw_c | funct3_lbu_c | funct3_lhu_c => illegal_cmd <= '0'; when others => illegal_cmd <= '1'; end case; when opcode_store_c => -- memory store - case execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is + case exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is when funct3_sb_c | funct3_sh_c | funct3_sw_c => illegal_cmd <= '0'; when others => illegal_cmd <= '1'; end case; when opcode_amo_c => -- atomic memory operation (LR/SC) - if RISCV_ISA_Zalrsc and (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = "010") and - (execute_engine.ir(instr_funct7_lsb_c+6 downto instr_funct7_lsb_c+3) = "0001") then -- LR.W/SC.W + if RISCV_ISA_Zalrsc and (exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = "010") and + (exe_engine.ir(instr_funct7_lsb_c+6 downto instr_funct7_lsb_c+3) = "0001") then -- LR.W/SC.W illegal_cmd <= '0'; else illegal_cmd <= '1'; @@ -1088,25 +1084,26 @@ begin illegal_cmd <= '0'; -- [NOTE] valid if not terminated by the "instruction execution monitor" when opcode_fence_c => -- memory ordering - case execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is + case exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) is when funct3_fence_c | funct3_fencei_c => illegal_cmd <= '0'; when others => illegal_cmd <= '1'; end case; when opcode_system_c => -- CSR / system instruction - if (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_env_c) then -- system environment - if (execute_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c) = "00000") and (execute_engine.ir(instr_rd_msb_c downto instr_rd_lsb_c) = "00000") then - case execute_engine.ir(instr_funct12_msb_c downto instr_funct12_lsb_c) is - when funct12_ecall_c | funct12_ebreak_c => illegal_cmd <= '0'; -- ecall and ebreak are always allowed - when funct12_mret_c => illegal_cmd <= (not csr.privilege) or debug_ctrl.running; -- mret allowed in (real/non-debug) M-mode only - when funct12_dret_c => illegal_cmd <= not debug_ctrl.running; -- dret allowed in debug mode only - when funct12_wfi_c => illegal_cmd <= (not csr.privilege) and csr.mstatus_tw; -- wfi allowed in M-mode or if TW is zero - when others => illegal_cmd <= '1'; -- undefined + if (exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_env_c) then -- system environment + if (exe_engine.ir(instr_rs1_msb_c downto instr_rs1_lsb_c) = "00000") and (exe_engine.ir(instr_rd_msb_c downto instr_rd_lsb_c) = "00000") then + case exe_engine.ir(instr_funct12_msb_c downto instr_funct12_lsb_c) is + when funct12_ecall_c => illegal_cmd <= '0'; -- ecall is always allowed + when funct12_ebreak_c => illegal_cmd <= '0'; -- ebreak is always allowed + when funct12_mret_c => illegal_cmd <= (not csr.privilege) or debug_ctrl.run; -- mret allowed in (real/non-debug) M-mode only + when funct12_dret_c => illegal_cmd <= not debug_ctrl.run; -- dret allowed in debug mode only + when funct12_wfi_c => illegal_cmd <= (not csr.privilege) and csr.mstatus_tw; -- wfi allowed in M-mode or if TW is zero + when others => illegal_cmd <= '1'; -- undefined end case; else illegal_cmd <= '1'; end if; - elsif (csr_valid /= "111") or (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csril_c) then -- invalid CSR operation + elsif (csr_valid /= "111") or (exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_csril_c) then -- invalid CSR operation illegal_cmd <= '1'; else illegal_cmd <= '0'; @@ -1121,7 +1118,7 @@ begin -- Illegal Operation Check ---------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - trap_ctrl.instr_il <= '1' when ((execute_engine.state = EXECUTE) or (execute_engine.state = ALU_WAIT)) and -- check in execution states only + trap_ctrl.instr_il <= '1' when ((exe_engine.state = EXECUTE) or (exe_engine.state = ALU_WAIT)) and -- check in execution states only ((monitor.exc = '1') or (illegal_cmd = '1')) else '0'; -- instruction timeout or illegal instruction @@ -1162,8 +1159,8 @@ begin if RISCV_ISA_Sdext then trap_ctrl.exc_buf(exc_ebreak_c) <= (not trap_ctrl.env_enter) and (trap_ctrl.exc_buf(exc_ebreak_c) or (trap_ctrl.hwtrig and (not csr.tdata1_action)) or -- trigger module fires and enter-debug-action is disabled - (trap_ctrl.ebreak and ( csr.privilege) and (not csr.dcsr_ebreakm) and (not debug_ctrl.running)) or -- enter M-mode handler on ebreak in M-mode - (trap_ctrl.ebreak and (not csr.privilege) and (not csr.dcsr_ebreaku) and (not debug_ctrl.running))); -- enter M-mode handler on ebreak in U-mode + (trap_ctrl.ebreak and ( csr.privilege) and (not csr.dcsr_ebreakm) and (not debug_ctrl.run)) or -- enter M-mode handler on ebreak in M-mode + (trap_ctrl.ebreak and (not csr.privilege) and (not csr.dcsr_ebreaku) and (not debug_ctrl.run))); -- enter M-mode handler on ebreak in U-mode else trap_ctrl.exc_buf(exc_ebreak_c) <= (trap_ctrl.exc_buf(exc_ebreak_c) or trap_ctrl.ebreak or (trap_ctrl.hwtrig and (not csr.tdata1_action))) and (not trap_ctrl.env_enter); end if; @@ -1273,7 +1270,7 @@ begin end process trap_priority; -- exception program counter: async. interrupt or sync. exception? -- - trap_ctrl.epc <= execute_engine.next_pc when (trap_ctrl.cause(trap_ctrl.cause'left) = '1') else execute_engine.pc; + trap_ctrl.epc <= exe_engine.next_pc when (trap_ctrl.cause(trap_ctrl.cause'left) = '1') else exe_engine.pc; -- Trap Controller ------------------------------------------------------------------------ @@ -1295,7 +1292,7 @@ begin end if; end if; -- trap environment has just been entered -- - if (execute_engine.state = EXECUTE) then -- first instruction of trap environment is executing + if (exe_engine.state = EXECUTE) then -- first instruction of trap environment is executing trap_ctrl.env_entered <= '0'; elsif (trap_ctrl.env_enter = '1') then trap_ctrl.env_entered <= '1'; @@ -1306,26 +1303,23 @@ begin -- any exception? -- trap_ctrl.exc_fire <= '1' when (or_reduce_f(trap_ctrl.exc_buf) = '1') else '0'; -- sync. exceptions CANNOT be masked - -- any "normal" system interrupt? -- + -- system interrupt? -- trap_ctrl.irq_fire(0) <= '1' when - (execute_engine.state = EXECUTE) and -- trigger system IRQ only in EXECUTE state + (exe_engine.state = EXECUTE) and -- trigger system IRQ only in EXECUTE state (or_reduce_f(trap_ctrl.irq_buf(irq_firq_15_c downto irq_msi_irq_c)) = '1') and -- pending system IRQ ((csr.mstatus_mie = '1') or (csr.privilege = priv_mode_u_c)) and -- IRQ only when in M-mode and MIE=1 OR when in U-mode - (debug_ctrl.running = '0') and (csr.dcsr_step = '0') -- no system IRQs when in debug-mode / during single-stepping - else '0'; + (debug_ctrl.run = '0') and (csr.dcsr_step = '0') else '0'; -- no system IRQs when in debug-mode / during single-stepping -- debug-entry halt interrupt? -- trap_ctrl.irq_fire(1) <= '1' when - ((execute_engine.state = EXECUTE) or (execute_engine.state = BRANCHED)) and -- allow halt also after "reset" (#879) - (trap_ctrl.irq_buf(irq_db_halt_c) = '1') -- pending external halt - else '0'; + ((exe_engine.state = EXECUTE) or (exe_engine.state = BRANCHED)) and -- allow halt also after "reset" (#879) + (trap_ctrl.irq_buf(irq_db_halt_c) = '1') else '0'; -- pending external halt -- debug-entry single-step interrupt? -- trap_ctrl.irq_fire(2) <= '1' when - ((execute_engine.state = EXECUTE) or -- trigger single-step in EXECUTE state - ((trap_ctrl.env_entered = '1') and (execute_engine.state = BRANCHED))) and -- also allow triggering when entering a system trap (#887) - (trap_ctrl.irq_buf(irq_db_step_c) = '1') -- pending single-step halt - else '0'; + ((exe_engine.state = EXECUTE) or -- trigger single-step in EXECUTE state + ((trap_ctrl.env_entered = '1') and (exe_engine.state = BRANCHED))) and -- also allow triggering when entering a system trap (#887) + (trap_ctrl.irq_buf(irq_db_step_c) = '1') else '0'; -- pending single-step halt -- CPU Sleep Mode Control ----------------------------------------------------------------- @@ -1335,7 +1329,7 @@ begin if (rstn_i = '0') then sleep_mode <= '0'; elsif rising_edge(clk_aux_i) then - if (execute_engine.state = SLEEP) and -- instruction execution has halted + if (exe_engine.state = SLEEP) and -- instruction execution has halted (ipb.free /= "11") and -- instruction fetch has halted (trap_ctrl.wakeup = '0') then -- no wake-up request sleep_mode <= '1'; @@ -1346,7 +1340,7 @@ begin end process sleep_control; -- wake-up from / do not enter sleep mode: during debugging or on pending IRQ -- - trap_ctrl.wakeup <= or_reduce_f(trap_ctrl.irq_buf) or debug_ctrl.running or csr.dcsr_step; + trap_ctrl.wakeup <= or_reduce_f(trap_ctrl.irq_buf) or debug_ctrl.run or csr.dcsr_step; -- **************************************************************************************************************************** @@ -1362,9 +1356,9 @@ begin elsif rising_edge(clk_i) then -- update only for actual CSR operations to reduce switching activity on the CSR address net -- if (opcode = opcode_system_c) then - csr.addr(11 downto 10) <= execute_engine.ir(instr_imm12_lsb_c+11 downto instr_imm12_lsb_c+10); - csr.addr(9 downto 8) <= replicate_f(execute_engine.ir(instr_imm12_lsb_c+8), 2); -- M-mode (11) and U-mode (00) CSRs only - csr.addr(7 downto 0) <= execute_engine.ir(instr_imm12_lsb_c+7 downto instr_imm12_lsb_c); + csr.addr(11 downto 10) <= exe_engine.ir(instr_imm12_lsb_c+11 downto instr_imm12_lsb_c+10); + csr.addr(9 downto 8) <= replicate_f(exe_engine.ir(instr_imm12_lsb_c+8), 2); -- M-mode (11) and U-mode (00) CSRs only + csr.addr(7 downto 0) <= exe_engine.ir(instr_imm12_lsb_c+7 downto instr_imm12_lsb_c); end if; end if; end process csr_addr_reg; @@ -1372,18 +1366,18 @@ begin -- CSR Write-Data ALU --------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - csr_write_data: process(execute_engine.ir, csr.rdata, rf_rs1_i) + csr_write_data: process(exe_engine.ir, csr.rdata, rf_rs1_i) variable tmp_v : std_ulogic_vector(XLEN-1 downto 0); begin -- immediate/register operand -- - if (execute_engine.ir(instr_funct3_msb_c) = '1') then + if (exe_engine.ir(instr_funct3_msb_c) = '1') then tmp_v := (others => '0'); - tmp_v(4 downto 0) := execute_engine.ir(19 downto 15); -- uimm5 + tmp_v(4 downto 0) := exe_engine.ir(19 downto 15); -- uimm5 else tmp_v := rf_rs1_i; end if; -- tiny ALU to compute CSR write data -- - case execute_engine.ir(instr_funct3_msb_c-1 downto instr_funct3_lsb_c) is + case exe_engine.ir(instr_funct3_msb_c-1 downto instr_funct3_lsb_c) is when "10" => csr.wdata <= csr.rdata or tmp_v; -- set when "11" => csr.wdata <= csr.rdata and (not tmp_v); -- clear when others => csr.wdata <= tmp_v; -- write @@ -1416,7 +1410,7 @@ begin csr.mie_firq <= (others => '0'); csr.mtvec <= (others => '0'); csr.mscratch <= x"19880704"; - csr.mepc <= (others => '0'); + csr.mepc <= BOOT_ADDR(XLEN-1 downto 2) & "00"; -- 32-bit-aligned boot address csr.mcause <= (others => '0'); csr.mtval <= (others => '0'); csr.mtinst <= (others => '0'); @@ -1530,18 +1524,18 @@ begin -- -------------------------------------------------------------------- when csr_tdata1_c => -- match control if RISCV_ISA_Sdtrig then - if (csr.tdata1_dmode = '0') or (debug_ctrl.running = '1') then -- write access from debug-mode only? + if (csr.tdata1_dmode = '0') or (debug_ctrl.run = '1') then -- write access from debug-mode only? csr.tdata1_execute <= csr.wdata(2); csr.tdata1_action <= csr.wdata(12); end if; - if (debug_ctrl.running = '1') then -- writable from debug-mode only + if (debug_ctrl.run = '1') then -- writable from debug-mode only csr.tdata1_dmode <= csr.wdata(27); end if; end if; when csr_tdata2_c => -- address compare if RISCV_ISA_Sdtrig then - if (csr.tdata1_dmode = '0') or (debug_ctrl.running = '1') then -- write access from debug-mode only? + if (csr.tdata1_dmode = '0') or (debug_ctrl.run = '1') then -- write access from debug-mode only? csr.tdata2 <= csr.wdata(XLEN-1 downto 1) & '0'; end if; end if; @@ -1559,10 +1553,10 @@ begin elsif (trap_ctrl.env_enter = '1') then -- NORMAL trap entry - no CSR update when in debug-mode! -- - if (not RISCV_ISA_Sdext) or ((trap_ctrl.cause(5) = '0') and (debug_ctrl.running = '0')) then + if (not RISCV_ISA_Sdext) or ((trap_ctrl.cause(5) = '0') and (debug_ctrl.run = '0')) then csr.mcause <= trap_ctrl.cause(trap_ctrl.cause'left) & trap_ctrl.cause(4 downto 0); -- trap type & identifier csr.mepc <= trap_ctrl.epc(XLEN-1 downto 1) & '0'; -- trap PC - -- trap value -- + -- trap value (load/store trap address only, permitted by RISC-V priv. spec.) -- if (trap_ctrl.cause(6) = '0') and (trap_ctrl.cause(2) = '1') then -- load/store misaligned/access faults [hacky!] csr.mtval <= lsu_mar_i; -- faulting data access address else -- everything else including all interrupts @@ -1570,8 +1564,8 @@ begin end if; -- trap instruction -- if (trap_ctrl.cause(6) = '0') then -- exception - csr.mtinst <= execute_engine.ir; - if (execute_engine.is_ci = '1') and RISCV_ISA_C then + csr.mtinst <= exe_engine.ir; + if (exe_engine.is_ci = '1') and RISCV_ISA_C then csr.mtinst(1) <= '0'; -- RISC-V priv. spec: clear bit 1 if compressed instruction end if; else -- interrupt @@ -1584,8 +1578,8 @@ begin csr.mstatus_mpp <= csr.privilege; -- backup previous privilege mode end if; - -- DEBUG MODE entry - no CSR update when already in debug-mode! -- - if RISCV_ISA_Sdext and (trap_ctrl.cause(5) = '1') and (debug_ctrl.running = '0') then + -- DEBUG trap entry - no CSR update when already in debug-mode! -- + if RISCV_ISA_Sdext and (trap_ctrl.cause(5) = '1') and (debug_ctrl.run = '0') then csr.dcsr_cause <= trap_ctrl.cause(2 downto 0); -- trap cause csr.dcsr_prv <= csr.privilege; -- current privilege mode when debug mode was entered csr.dpc <= trap_ctrl.epc(XLEN-1 downto 1) & '0'; -- trap PC @@ -1597,7 +1591,7 @@ begin elsif (trap_ctrl.env_exit = '1') then -- return from debug mode -- - if RISCV_ISA_Sdext and (debug_ctrl.running = '1') then + if RISCV_ISA_Sdext and (debug_ctrl.run = '1') then if RISCV_ISA_U then csr.privilege <= csr.dcsr_prv; if (csr.dcsr_prv /= priv_mode_m_c) then @@ -1624,7 +1618,7 @@ begin -- ******************************************************************************** -- hardwired bits -- - csr.mcountinhibit(1) <= '0'; -- "time" not implemented + csr.mcountinhibit(1) <= '0'; -- "time" not defined -- no base counters -- if not RISCV_ISA_Zicntr then @@ -1677,7 +1671,7 @@ begin end process csr_write_access; -- effective privilege mode is MACHINE when in debug mode -- - csr.privilege_eff <= priv_mode_m_c when (debug_ctrl.running = '1') else csr.privilege; + csr.privilege_eff <= priv_mode_m_c when (debug_ctrl.run = '1') else csr.privilege; -- CSR Read Access ------------------------------------------------------------------------ @@ -1911,9 +1905,8 @@ begin csr.rdata(23) <= bool_to_ulogic_f(RISCV_ISA_Zbb); -- Zbb: basic bit-manipulation extension csr.rdata(24) <= bool_to_ulogic_f(RISCV_ISA_Zbs); -- Zbs: single-bit bit-manipulation extension csr.rdata(25) <= bool_to_ulogic_f(RISCV_ISA_Zalrsc); -- Zalrsc: reservation set extension - -- reserved -- - csr.rdata(26) <= '0'; - csr.rdata(27) <= '0'; + csr.rdata(26) <= '0'; -- reserved + csr.rdata(27) <= '0'; -- reserved -- tuning options -- csr.rdata(28) <= bool_to_ulogic_f(REGFILE_HW_RST); -- full hardware reset of register file csr.rdata(29) <= bool_to_ulogic_f(FAST_MUL_EN); -- DSP-based multiplication (M extensions only) @@ -2075,31 +2068,31 @@ begin cnt.inc <= (others => (others => '0')); elsif rising_edge(clk_i) then -- base counters -- - cnt.inc(0) <= (others => (cnt_event(hpmcnt_event_cy_c) and (not csr.mcountinhibit(0)) and (not debug_ctrl.running))); + cnt.inc(0) <= (others => (cnt_event(hpmcnt_event_cy_c) and (not csr.mcountinhibit(0)) and (not debug_ctrl.run))); cnt.inc(1) <= (others => '0'); -- time: not available - cnt.inc(2) <= (others => (cnt_event(hpmcnt_event_ir_c) and (not csr.mcountinhibit(2)) and (not debug_ctrl.running))); + cnt.inc(2) <= (others => (cnt_event(hpmcnt_event_ir_c) and (not csr.mcountinhibit(2)) and (not debug_ctrl.run))); -- hpm counters -- for i in 3 to 15 loop - cnt.inc(i) <= (others => (or_reduce_f(cnt_event and hpmevent_cfg(i)) and (not csr.mcountinhibit(i)) and (not debug_ctrl.running))); + cnt.inc(i) <= (others => (or_reduce_f(cnt_event and hpmevent_cfg(i)) and (not csr.mcountinhibit(i)) and (not debug_ctrl.run))); end loop; end if; end process counter_event; -- RISC-V-compliant counter events -- - cnt_event(hpmcnt_event_cy_c) <= '1' when (sleep_mode = '0') else '0'; -- cycle: active cycle - cnt_event(hpmcnt_event_tm_c) <= '0'; -- time: not available - cnt_event(hpmcnt_event_ir_c) <= '1' when (execute_engine.state = EXECUTE) else '0'; -- instret: retired (==executed) instruction + cnt_event(hpmcnt_event_cy_c) <= '1' when (sleep_mode = '0') else '0'; -- cycle: active cycle + cnt_event(hpmcnt_event_tm_c) <= '0'; -- time: not available + cnt_event(hpmcnt_event_ir_c) <= '1' when (exe_engine.state = EXECUTE) else '0'; -- instret: retired (==executed!) instruction -- NEORV32-specific counter events -- - cnt_event(hpmcnt_event_compr_c) <= '1' when (execute_engine.state = EXECUTE) and (execute_engine.is_ci = '1') else '0'; -- executed compressed instruction - cnt_event(hpmcnt_event_wait_dis_c) <= '1' when (execute_engine.state = DISPATCH) and (issue_engine.valid = "00") else '0'; -- instruction dispatch wait cycle - cnt_event(hpmcnt_event_wait_alu_c) <= '1' when (execute_engine.state = ALU_WAIT) else '0'; -- multi-cycle ALU co-processor wait cycle - cnt_event(hpmcnt_event_branch_c) <= '1' when (execute_engine.state = BRANCH) else '0'; -- executed branch instruction - cnt_event(hpmcnt_event_branched_c) <= '1' when (execute_engine.state = BRANCHED) else '0'; -- control flow transfer - cnt_event(hpmcnt_event_load_c) <= '1' when (ctrl.lsu_req = '1') and (ctrl.lsu_rw = '0') else '0'; -- executed load operation - cnt_event(hpmcnt_event_store_c) <= '1' when (ctrl.lsu_req = '1') and (ctrl.lsu_rw = '1') else '0'; -- executed store operation - cnt_event(hpmcnt_event_wait_lsu_c) <= '1' when (ctrl.lsu_req = '0') and (execute_engine.state = MEM_WAIT) else '0'; -- load/store unit memory wait cycle - cnt_event(hpmcnt_event_trap_c) <= '1' when (trap_ctrl.env_enter = '1') else '0'; -- entered trap + cnt_event(hpmcnt_event_compr_c) <= '1' when (exe_engine.state = EXECUTE) and (exe_engine.is_ci = '1') else '0'; -- executed compressed instruction + cnt_event(hpmcnt_event_wait_dis_c) <= '1' when (exe_engine.state = DISPATCH) and (issue_engine.valid = "00") else '0'; -- instruction dispatch wait cycle + cnt_event(hpmcnt_event_wait_alu_c) <= '1' when (exe_engine.state = ALU_WAIT) else '0'; -- multi-cycle ALU co-processor wait cycle + cnt_event(hpmcnt_event_branch_c) <= '1' when (exe_engine.state = BRANCH) else '0'; -- executed branch instruction + cnt_event(hpmcnt_event_branched_c) <= '1' when (exe_engine.state = BRANCHED) else '0'; -- control flow transfer + cnt_event(hpmcnt_event_load_c) <= '1' when (ctrl.lsu_req = '1') and (ctrl.lsu_rw = '0') else '0'; -- executed load operation + cnt_event(hpmcnt_event_store_c) <= '1' when (ctrl.lsu_req = '1') and (ctrl.lsu_rw = '1') else '0'; -- executed store operation + cnt_event(hpmcnt_event_wait_lsu_c) <= '1' when (ctrl.lsu_req = '0') and (exe_engine.state = MEM_WAIT) else '0'; -- load/store unit memory wait cycle + cnt_event(hpmcnt_event_trap_c) <= '1' when (trap_ctrl.env_enter = '1') else '0'; -- entered trap -- **************************************************************************************************************************** @@ -2114,34 +2107,34 @@ begin debug_control: process(rstn_i, clk_i) begin if (rstn_i = '0') then - debug_ctrl.running <= '0'; + debug_ctrl.run <= '0'; elsif rising_edge(clk_i) then - if (debug_ctrl.running = '0') then -- debug mode OFFLINE + if (debug_ctrl.run = '0') then -- debug mode OFFLINE if (trap_ctrl.env_enter = '1') and (trap_ctrl.cause(5) = '1') then -- waiting for entry event - debug_ctrl.running <= '1'; + debug_ctrl.run <= '1'; end if; else -- debug mode ONLINE if (trap_ctrl.env_exit = '1') then -- waiting for exit event - debug_ctrl.running <= '0'; + debug_ctrl.run <= '0'; end if; end if; end if; end process debug_control; -- debug mode entry triggers -- - debug_ctrl.trig_hw <= trap_ctrl.hwtrig and (not debug_ctrl.running) and csr.tdata1_action and csr.tdata1_dmode; -- enter debug mode by HW trigger module - debug_ctrl.trig_break <= trap_ctrl.ebreak and (debug_ctrl.running or -- re-enter debug mode + debug_ctrl.trig_hw <= trap_ctrl.hwtrig and (not debug_ctrl.run) and csr.tdata1_action and csr.tdata1_dmode; -- enter debug mode by HW trigger module + debug_ctrl.trig_break <= trap_ctrl.ebreak and (debug_ctrl.run or -- re-enter debug mode (( csr.privilege) and csr.dcsr_ebreakm) or -- enabled goto-debug-mode in machine mode on "ebreak" ((not csr.privilege) and csr.dcsr_ebreaku)); -- enabled goto-debug-mode in user mode on "ebreak" - debug_ctrl.trig_halt <= irq_dbg_i and (not debug_ctrl.running); -- external halt request (if not halted already) - debug_ctrl.trig_step <= csr.dcsr_step and (not debug_ctrl.running); -- single-step mode (trigger when NOT CURRENTLY in debug mode) + debug_ctrl.trig_halt <= irq_dbg_i and (not debug_ctrl.run); -- external halt request (if not halted already) + debug_ctrl.trig_step <= csr.dcsr_step and (not debug_ctrl.run); -- single-step mode (trigger when NOT CURRENTLY in debug mode) end generate; -- Sdext ISA extension not enabled -- debug_mode_disable: if not RISCV_ISA_Sdext generate - debug_ctrl.running <= '0'; + debug_ctrl.run <= '0'; debug_ctrl.trig_hw <= '0'; debug_ctrl.trig_break <= '0'; debug_ctrl.trig_halt <= '0'; @@ -2177,7 +2170,7 @@ begin -- trigger on instruction address match (trigger right BEFORE execution) -- hw_trigger_match <= '1' when (csr.tdata1_execute = '1') and -- trigger enabled to match on instruction address (hw_trigger_fired = '0') and -- trigger has not fired yet - (csr.tdata2(XLEN-1 downto 1) = execute_engine.next_pc(XLEN-1 downto 1)) -- address match + (csr.tdata2(XLEN-1 downto 1) = exe_engine.next_pc(XLEN-1 downto 1)) -- address match else '0'; -- status flag - set when trigger has fired -- diff --git a/rtl/core/neorv32_cpu_decompressor.vhd b/rtl/core/neorv32_cpu_decompressor.vhd index 9f9125270..723a3102b 100644 --- a/rtl/core/neorv32_cpu_decompressor.vhd +++ b/rtl/core/neorv32_cpu_decompressor.vhd @@ -72,7 +72,7 @@ begin decoded(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alui_c; decoded(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "00010"; -- stack pointer decoded(instr_rd_msb_c downto instr_rd_lsb_c) <= "01" & instr_i(ci_rd_3_msb_c downto ci_rd_3_lsb_c); - decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_subadd_c; + decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_sadd_c; decoded(instr_imm12_msb_c downto instr_imm12_lsb_c) <= "00" & instr_i(10 downto 7) & instr_i(12 downto 11) & instr_i(5) & instr_i(6) & "00"; if (instr_i(12 downto 5) = "00000000") then -- canonical illegal C instruction or C.ADDI4SPN with nzuimm = 0 illegal <= '1'; @@ -131,7 +131,7 @@ begin when "010" => -- C.LI -- -------------------------------------------------------------------------------------- decoded(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alui_c; - decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_subadd_c; + decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_sadd_c; decoded(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "00000"; -- x0 decoded(instr_rd_msb_c downto instr_rd_lsb_c) <= instr_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c); decoded(instr_imm12_msb_c downto instr_imm12_lsb_c) <= replicate_f(instr_i(12),6) & instr_i(12) & instr_i(6 downto 2); @@ -140,7 +140,7 @@ begin -- -------------------------------------------------------------------------------------- if (instr_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c) = "00010") then -- C.ADDI16SP decoded(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alui_c; - decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_subadd_c; + decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_sadd_c; decoded(instr_rd_msb_c downto instr_rd_lsb_c) <= instr_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c); decoded(instr_rs1_msb_c downto instr_rs1_lsb_c) <= "00010"; -- stack pointer decoded(instr_rd_msb_c downto instr_rd_lsb_c) <= "00010"; -- stack pointer @@ -157,7 +157,7 @@ begin when "000" => -- C.NOP (rd=0) / C.ADDI -- -------------------------------------------------------------------------------------- decoded(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alui_c; - decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_subadd_c; + decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_sadd_c; decoded(instr_rs1_msb_c downto instr_rs1_lsb_c) <= instr_i(ci_rs1_5_msb_c downto ci_rs1_5_lsb_c); decoded(instr_rd_msb_c downto instr_rd_lsb_c) <= instr_i(ci_rd_5_msb_c downto ci_rd_5_lsb_c); decoded(instr_imm12_msb_c downto instr_imm12_lsb_c) <= replicate_f(instr_i(12),7) & instr_i(6 downto 2); @@ -188,7 +188,7 @@ begin decoded(instr_opcode_msb_c downto instr_opcode_lsb_c) <= opcode_alu_c; case instr_i(6 downto 5) is when "00" => -- C.SUB - decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_subadd_c; + decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_sadd_c; decoded(instr_funct7_msb_c downto instr_funct7_lsb_c) <= "0100000"; when "01" => -- C.XOR decoded(instr_funct3_msb_c downto instr_funct3_lsb_c) <= funct3_xor_c; diff --git a/rtl/core/neorv32_debug_dtm.vhd b/rtl/core/neorv32_debug_dtm.vhd index 1e6c8c23a..8b97e53b0 100644 --- a/rtl/core/neorv32_debug_dtm.vhd +++ b/rtl/core/neorv32_debug_dtm.vhd @@ -1,6 +1,8 @@ -- ================================================================================ -- -- NEORV32 SoC - RISC-V-Compatible Debug Transport Module (DTM) -- -- -------------------------------------------------------------------------------- -- +-- Compatible to RISC-V debug spec. versions 0.13 and 1.0. -- +-- -------------------------------------------------------------------------------- -- -- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 -- -- Copyright (c) NEORV32 contributors. -- -- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. -- @@ -24,11 +26,11 @@ entity neorv32_debug_dtm is -- global control -- clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active - -- jtag connection -- - jtag_tck_i : in std_ulogic; - jtag_tdi_i : in std_ulogic; - jtag_tdo_o : out std_ulogic; - jtag_tms_i : in std_ulogic; + -- jtag connection (TAP access) -- + jtag_tck_i : in std_ulogic; -- serial clock + jtag_tdi_i : in std_ulogic; -- serial data input + jtag_tdo_o : out std_ulogic; -- serial data output + jtag_tms_i : in std_ulogic; -- mode select -- debug module interface (DMI) -- dmi_req_o : out dmi_req_t; -- request dmi_rsp_i : in dmi_rsp_t -- response @@ -37,11 +39,6 @@ end neorv32_debug_dtm; architecture neorv32_debug_dtm_rtl of neorv32_debug_dtm is - -- DMI Configuration (fixed!) -- - constant dmi_idle_c : std_ulogic_vector(2 downto 0) := "000"; -- no idle cycles required - constant dmi_version_c : std_ulogic_vector(3 downto 0) := "0001"; -- debug spec. version (0.13 & 1.0) - constant dmi_abits_c : std_ulogic_vector(5 downto 0) := "000111"; -- number of DMI address bits (7) - -- TAP data register addresses -- constant addr_idcode_c : std_ulogic_vector(4 downto 0) := "00001"; -- identifier constant addr_dtmcs_c : std_ulogic_vector(4 downto 0) := "10000"; -- DTM status and control @@ -49,10 +46,8 @@ architecture neorv32_debug_dtm_rtl of neorv32_debug_dtm is -- tap JTAG signal synchronizer -- type tap_sync_t is record - -- internal -- tck_ff, tdi_ff, tms_ff : std_ulogic_vector(2 downto 0); - -- external -- - tck_rising, tck_falling, tdi, tms: std_ulogic; + tck_rising, tck_falling, tdi, tms : std_ulogic; end record; signal tap_sync : tap_sync_t; @@ -85,8 +80,7 @@ architecture neorv32_debug_dtm_rtl of neorv32_debug_dtm is dmihardreset : std_ulogic; dmireset : std_ulogic; err : std_ulogic; - rdata : std_ulogic_vector(31 downto 0); - wdata : std_ulogic_vector(31 downto 0); + rdata, wdata : std_ulogic_vector(31 downto 0); addr : std_ulogic_vector(6 downto 0); end record; signal dmi_ctrl : dmi_ctrl_t; @@ -108,14 +102,12 @@ begin end if; end process tap_synchronizer; - -- JTAG clock edge -- + -- JTAG clock edges -- tap_sync.tck_rising <= '1' when (tap_sync.tck_ff(2 downto 1) = "01") else '0'; tap_sync.tck_falling <= '1' when (tap_sync.tck_ff(2 downto 1) = "10") else '0'; - -- JTAG test mode select -- + -- JTAG inputs -- tap_sync.tms <= tap_sync.tms_ff(2); - - -- JTAG serial data input -- tap_sync.tdi <= tap_sync.tdi_ff(2); @@ -165,6 +157,7 @@ begin end if; end process update_trigger; + -- edge detector -- dr_trigger.valid <= '1' when (dr_trigger.sreg = "01") else '0'; @@ -184,10 +177,8 @@ begin -- serial data input: instruction register -- if (tap_ctrl_state = LOGIC_RESET) or (tap_ctrl_state = IR_CAPTURE) then -- preload phase tap_reg.ireg <= addr_idcode_c; - elsif (tap_ctrl_state = IR_SHIFT) then -- access phase - if (tap_sync.tck_rising = '1') then -- [JTAG-SYNC] evaluate TDI on rising edge of TCK - tap_reg.ireg <= tap_sync.tdi & tap_reg.ireg(tap_reg.ireg'left downto 1); - end if; + elsif (tap_ctrl_state = IR_SHIFT) and (tap_sync.tck_rising = '1') then -- access phase; [JTAG-SYNC] evaluate TDI on rising edge of TCK + tap_reg.ireg <= tap_sync.tdi & tap_reg.ireg(tap_reg.ireg'left downto 1); end if; -- serial data input: data register -- @@ -198,15 +189,13 @@ begin when addr_dmi_c => tap_reg.dmi <= tap_reg.dmi_nxt; -- register interface when others => tap_reg.bypass <= '0'; -- pass through end case; - elsif (tap_ctrl_state = DR_SHIFT) then -- access phase - if (tap_sync.tck_rising = '1') then -- [JTAG-SYNC] evaluate TDI on rising edge of TCK - case tap_reg.ireg is - when addr_idcode_c => tap_reg.idcode <= tap_sync.tdi & tap_reg.idcode(tap_reg.idcode'left downto 1); - when addr_dtmcs_c => tap_reg.dtmcs <= tap_sync.tdi & tap_reg.dtmcs(tap_reg.dtmcs'left downto 1); - when addr_dmi_c => tap_reg.dmi <= tap_sync.tdi & tap_reg.dmi(tap_reg.dmi'left downto 1); - when others => tap_reg.bypass <= tap_sync.tdi; - end case; - end if; + elsif (tap_ctrl_state = DR_SHIFT) and (tap_sync.tck_rising = '1') then -- access phase; [JTAG-SYNC] evaluate TDI on rising edge of TCK + case tap_reg.ireg is + when addr_idcode_c => tap_reg.idcode <= tap_sync.tdi & tap_reg.idcode(tap_reg.idcode'left downto 1); + when addr_dtmcs_c => tap_reg.dtmcs <= tap_sync.tdi & tap_reg.dtmcs(tap_reg.dtmcs'left downto 1); + when addr_dmi_c => tap_reg.dmi <= tap_sync.tdi & tap_reg.dmi(tap_reg.dmi'left downto 1); + when others => tap_reg.bypass <= tap_sync.tdi; + end case; end if; -- serial data output -- @@ -226,20 +215,18 @@ begin end if; end process reg_access; - -- DTM Control and Status Register (dtmcs) -- + -- DTM control and status register (dtmcs) read-back -- tap_reg.dtmcs_nxt(31 downto 18) <= (others => '0'); -- reserved tap_reg.dtmcs_nxt(17) <= dmi_ctrl.dmihardreset; -- dmihardreset tap_reg.dtmcs_nxt(16) <= dmi_ctrl.dmireset; -- dmireset tap_reg.dtmcs_nxt(15) <= '0'; -- reserved - tap_reg.dtmcs_nxt(14 downto 12) <= dmi_idle_c; -- minimum number of idle cycles + tap_reg.dtmcs_nxt(14 downto 12) <= "000"; -- minimum number of idle cycles (= 0) tap_reg.dtmcs_nxt(11 downto 10) <= tap_reg.dmi_nxt(1 downto 0); -- dmistat - tap_reg.dtmcs_nxt(09 downto 04) <= dmi_abits_c; -- number of DMI address bits - tap_reg.dtmcs_nxt(03 downto 00) <= dmi_version_c; -- version + tap_reg.dtmcs_nxt(09 downto 04) <= "000111"; -- number of DMI address bits (7) + tap_reg.dtmcs_nxt(03 downto 00) <= "0001"; -- compatible to debug spec. version (0.13 & 1.0) - -- DMI register read access -- - tap_reg.dmi_nxt(40 downto 34) <= dmi_ctrl.addr; -- address - tap_reg.dmi_nxt(33 downto 02) <= dmi_ctrl.rdata; -- read data - tap_reg.dmi_nxt(01 downto 00) <= (others => dmi_ctrl.err); -- status + -- DMI register (dmi) read-back -- + tap_reg.dmi_nxt <= dmi_ctrl.addr & dmi_ctrl.rdata & replicate_f(dmi_ctrl.err, 2); -- address & read data & status -- Debug Module Interface ----------------------------------------------------------------- @@ -275,14 +262,12 @@ begin -- DMI interface arbiter -- dmi_ctrl.op <= dmi_req_nop_c; -- default if (dmi_ctrl.busy = '0') then -- idle: waiting for new request - if (dmi_ctrl.dmihardreset = '0') then -- no DMI hard reset - if (dr_trigger.valid = '1') and (tap_reg.ireg = addr_dmi_c) then - dmi_ctrl.addr <= tap_reg.dmi(40 downto 34); - dmi_ctrl.wdata <= tap_reg.dmi(33 downto 02); - if (tap_reg.dmi(1 downto 0) = dmi_req_rd_c) or (tap_reg.dmi(1 downto 0) = dmi_req_wr_c) then - dmi_ctrl.op <= tap_reg.dmi(1 downto 0); - dmi_ctrl.busy <= '1'; - end if; + if (dmi_ctrl.dmihardreset = '0') and (dr_trigger.valid = '1') and (tap_reg.ireg = addr_dmi_c) then -- valid non-reset access + dmi_ctrl.addr <= tap_reg.dmi(40 downto 34); + dmi_ctrl.wdata <= tap_reg.dmi(33 downto 02); + if (tap_reg.dmi(1 downto 0) = dmi_req_rd_c) or (tap_reg.dmi(1 downto 0) = dmi_req_wr_c) then + dmi_ctrl.op <= tap_reg.dmi(1 downto 0); + dmi_ctrl.busy <= '1'; end if; end if; else -- busy: read/write access in progress diff --git a/rtl/core/neorv32_dmem.vhd b/rtl/core/neorv32_dmem.vhd index 6c80f6b8a..d28d06712 100644 --- a/rtl/core/neorv32_dmem.vhd +++ b/rtl/core/neorv32_dmem.vhd @@ -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 --------------------------------------------------------------------------- diff --git a/rtl/core/neorv32_imem.vhd b/rtl/core/neorv32_imem.vhd index 090e36018..a68c9b0d7 100644 --- a/rtl/core/neorv32_imem.vhd +++ b/rtl/core/neorv32_imem.vhd @@ -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; diff --git a/rtl/core/neorv32_package.vhd b/rtl/core/neorv32_package.vhd index 5f7891829..5c705c79a 100644 --- a/rtl/core/neorv32_package.vhd +++ b/rtl/core/neorv32_package.vhd @@ -29,7 +29,7 @@ package neorv32_package is -- Architecture Constants ----------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100506"; -- hardware version + constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100602"; -- hardware version constant archid_c : natural := 19; -- official RISC-V architecture ID constant XLEN : natural := 32; -- native data path width @@ -58,7 +58,7 @@ package neorv32_package is constant mem_io_size_c : natural := 8*1024; -- = 32 * iodev_size_c -- Start of uncached memory access (256MB page / 4MSBs only) -- - constant uncached_begin_c : std_ulogic_vector(31 downto 0) := x"f0000000"; + constant mem_uncached_begin_c : std_ulogic_vector(31 downto 0) := x"f0000000"; -- IO Address Map (base address must be aligned to the region's size) -- constant iodev_size_c : natural := 256; -- size of a single IO device (bytes) @@ -254,7 +254,7 @@ package neorv32_package is constant funct3_sh_c : std_ulogic_vector(2 downto 0) := "001"; -- store half word constant funct3_sw_c : std_ulogic_vector(2 downto 0) := "010"; -- store word -- alu -- - constant funct3_subadd_c : std_ulogic_vector(2 downto 0) := "000"; -- sub/add + constant funct3_sadd_c : std_ulogic_vector(2 downto 0) := "000"; -- sub/add constant funct3_sll_c : std_ulogic_vector(2 downto 0) := "001"; -- shift logical left constant funct3_slt_c : std_ulogic_vector(2 downto 0) := "010"; -- set on less constant funct3_sltu_c : std_ulogic_vector(2 downto 0) := "011"; -- set on less unsigned @@ -667,12 +667,15 @@ package neorv32_package is component neorv32_top generic ( - -- General -- + -- Clocking -- CLOCK_FREQUENCY : natural := 0; CLOCK_GATING_EN : boolean := false; + -- Identification -- HART_ID : std_ulogic_vector(31 downto 0) := x"00000000"; JEDEC_ID : std_ulogic_vector(10 downto 0) := "00000000000"; - INT_BOOTLOADER_EN : boolean := false; + -- Boot Configuration -- + BOOT_MODE_SELECT : natural range 0 to 2 := 0; + BOOT_ADDR_CUSTOM : std_ulogic_vector(31 downto 0) := x"00000000"; -- On-Chip Debugger (OCD) -- OCD_EN : boolean := false; OCD_AUTHENTICATION : boolean := false; @@ -1116,40 +1119,3 @@ package body neorv32_package is end function print_version_f; end neorv32_package; - --- ********************************************************************************************************** --- Additional Packages --- ********************************************************************************************************** - - -- Prototype Definition: bootloader_init_image -------------------------------------------- - -- ------------------------------------------------------------------------------------------- - -- > memory content in 'neorv32_bootloader_image.vhd', auto-generated by 'image_gen' - -- > used by 'neorv32_boot_rom.vhd' - -- > enables body-only recompile in case of firmware change (NEORV32 PR #338) - -library ieee; -use ieee.std_logic_1164.all; - -library neorv32; -use neorv32.neorv32_package.all; - -package neorv32_bootloader_image is - constant bootloader_init_image : mem32_t; -end neorv32_bootloader_image; - - - -- Prototype Definition: neorv32_application_image ---------------------------------------- - -- ------------------------------------------------------------------------------------------- - -- > memory content in 'neorv32_application_image.vhd', auto-generated by 'image_gen' - -- > used by 'mem/neorv32_imem.*.vhd' - -- > enables body-only recompile in case of firmware change (NEORV32 PR #338) - -library ieee; -use ieee.std_logic_1164.all; - -library neorv32; -use neorv32.neorv32_package.all; - -package neorv32_application_image is - constant application_init_image : mem32_t; -end neorv32_application_image; diff --git a/rtl/core/neorv32_sysinfo.vhd b/rtl/core/neorv32_sysinfo.vhd index 21dc6db37..06010acc9 100644 --- a/rtl/core/neorv32_sysinfo.vhd +++ b/rtl/core/neorv32_sysinfo.vhd @@ -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? diff --git a/rtl/core/neorv32_top.vhd b/rtl/core/neorv32_top.vhd index 8df7c65c2..952b31749 100644 --- a/rtl/core/neorv32_top.vhd +++ b/rtl/core/neorv32_top.vhd @@ -21,12 +21,17 @@ use neorv32.neorv32_package.all; entity neorv32_top is generic ( - -- General -- + -- Processor Clocking -- CLOCK_FREQUENCY : natural := 0; -- clock frequency of clk_i in Hz CLOCK_GATING_EN : boolean := false; -- enable clock gating when in sleep mode + + -- Core Identification -- HART_ID : std_ulogic_vector(31 downto 0) := x"00000000"; -- hardware thread ID JEDEC_ID : std_ulogic_vector(10 downto 0) := "00000000000"; -- JEDEC ID: continuation codes + vendor ID - INT_BOOTLOADER_EN : boolean := false; -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM + + -- Boot Configuration -- + BOOT_MODE_SELECT : natural range 0 to 2 := 0; -- boot configuration select (default = 0 = bootloader) + BOOT_ADDR_CUSTOM : std_ulogic_vector(31 downto 0) := x"00000000"; -- custom CPU boot address (if boot_config = 1) -- On-Chip Debugger (OCD) -- OCD_EN : boolean := false; -- implement on-chip debugger @@ -244,16 +249,28 @@ end neorv32_top; architecture neorv32_top_rtl of neorv32_top is + -- ---------------------------------------------------------- + -- Boot Configuration (BOOT_MODE_SELECT) + -- ---------------------------------------------------------- + -- 0: Internal bootloader ROM + -- 1: Custom (use BOOT_ADDR_CUSTOM) + -- 2: Internal IMEM initialized with application image + -- ---------------------------------------------------------- + constant bootrom_en_c : boolean := boolean(BOOT_MODE_SELECT = 0); + constant imem_as_rom_c : boolean := boolean(BOOT_MODE_SELECT = 2); + constant cpu_boot_addr_c : std_ulogic_vector(31 downto 0) := + cond_sel_suv_f(boolean(BOOT_MODE_SELECT = 0), mem_boot_base_c, + cond_sel_suv_f(boolean(BOOT_MODE_SELECT = 1), BOOT_ADDR_CUSTOM, + cond_sel_suv_f(boolean(BOOT_MODE_SELECT = 2), mem_imem_base_c, x"00000000"))); + -- auto-configuration -- - constant cpu_boot_addr_c : std_ulogic_vector(31 downto 0) := cond_sel_suv_f(INT_BOOTLOADER_EN, mem_boot_base_c, mem_imem_base_c); - constant imem_as_rom_c : boolean := not INT_BOOTLOADER_EN; constant io_gpio_en_c : boolean := boolean(IO_GPIO_NUM > 0); constant io_xirq_en_c : boolean := boolean(XIRQ_NUM_CH > 0); constant io_pwm_en_c : boolean := boolean(IO_PWM_NUM_CH > 0); constant cpu_smpmp_c : boolean := boolean(PMP_NUM_REGIONS > 0); constant io_sysinfo_en_c : boolean := not IO_DISABLE_SYSINFO; - -- convert JEDEC ID to mvendorid CSR -- + -- convert JEDEC ID to MVENDORID CSR -- constant vendorid_c : std_ulogic_vector(31 downto 0) := x"00000" & "0" & JEDEC_ID; -- make sure physical memory sizes are a power of two -- @@ -282,7 +299,7 @@ architecture neorv32_top_rtl of neorv32_top is signal dmi_rsp : dmi_rsp_t; -- debug core interface (DCI) -- - signal dci_ndmrstn, dci_halt_req : std_ulogic; + signal dci_ndmrstn, dci_haltreq : std_ulogic; -- bus: core complex (CPU + caches) and DMA -- signal cpu_i_req, cpu_d_req, icache_req, dcache_req, core_req, main_req, main2_req, dma_req : bus_req_t; @@ -330,9 +347,9 @@ begin -- show SoC configuration -- assert false report "[NEORV32] Processor Configuration: CPU " & -- cpu core is always enabled - cond_sel_string_f(MEM_INT_IMEM_EN, "IMEM ", "") & + cond_sel_string_f(MEM_INT_IMEM_EN, cond_sel_string_f(imem_as_rom_c, "IMEM_ROM ", "IMEM "), "") & cond_sel_string_f(MEM_INT_DMEM_EN, "DMEM ", "") & - cond_sel_string_f(INT_BOOTLOADER_EN, "BOOTROM ", "") & + cond_sel_string_f(bootrom_en_c, "BOOTROM ", "") & cond_sel_string_f(ICACHE_EN, "I-CACHE ", "") & cond_sel_string_f(DCACHE_EN, "D-CACHE ", "") & cond_sel_string_f(XBUS_EN, "XBUS ", "") & @@ -358,7 +375,7 @@ begin cond_sel_string_f(IO_SLINK_EN, "SLINK ", "") & cond_sel_string_f(IO_CRC_EN, "CRC ", "") & cond_sel_string_f(io_sysinfo_en_c, "SYSINFO ", "") & - cond_sel_string_f(OCD_EN, cond_sel_string_f(OCD_AUTHENTICATION, "OCD-AUTH ", "OCD "), "") & + cond_sel_string_f(OCD_EN, cond_sel_string_f(OCD_AUTHENTICATION, "OCD-AUTH ", "OCD "), "") & "" severity note; @@ -378,6 +395,15 @@ begin assert not (CLOCK_FREQUENCY = 0) report "[NEORV32] CLOCK_FREQUENCY must be configured according to the frequency of clk_i port!" severity warning; + -- Boot configuration notifier -- + assert not (BOOT_MODE_SELECT = 0) report "[NEORV32] BOOT_MODE_SELECT = 0: booting via bootloader" severity note; + assert not (BOOT_MODE_SELECT = 1) report "[NEORV32] BOOT_MODE_SELECT = 1: booting from custom address" severity note; + assert not (BOOT_MODE_SELECT = 2) report "[NEORV32] BOOT_MODE_SELECT = 2: booting IMEM image" severity note; + + -- Boot configuration: boot from initialized IMEM requires the IMEM to be enabled -- + assert not ((BOOT_MODE_SELECT = 2) and (MEM_INT_IMEM_EN = false)) report + "[NEORV32] BOOT_MODE_SELECT = 2 (boot IMEM image) requires the internal instruction memory (IMEM) to be enabled!" severity error; + end generate; -- /sanity_checks @@ -507,7 +533,7 @@ begin mei_i => mext_irq_i, mti_i => mtime_irq, firq_i => cpu_firq, - dbi_i => dci_halt_req, + dbi_i => dci_haltreq, -- instruction bus interface -- ibus_req_o => cpu_i_req, ibus_rsp_i => cpu_i_rsp, @@ -543,7 +569,7 @@ begin generic map ( NUM_BLOCKS => ICACHE_NUM_BLOCKS, BLOCK_SIZE => ICACHE_BLOCK_SIZE, - UC_BEGIN => uncached_begin_c(31 downto 28), + UC_BEGIN => mem_uncached_begin_c(31 downto 28), UC_ENABLE => true, READ_ONLY => true ) @@ -572,7 +598,7 @@ begin generic map ( NUM_BLOCKS => DCACHE_NUM_BLOCKS, BLOCK_SIZE => DCACHE_BLOCK_SIZE, - UC_BEGIN => uncached_begin_c(31 downto 28), + UC_BEGIN => mem_uncached_begin_c(31 downto 28), UC_ENABLE => true, READ_ONLY => false ) @@ -717,7 +743,7 @@ begin C_TMO_EN => false, -- no timeout for XIP accesses C_PRIV => false, -- port D: BOOT ROM -- - D_ENABLE => INT_BOOTLOADER_EN, + D_ENABLE => bootrom_en_c, D_BASE => mem_boot_base_c, D_SIZE => mem_boot_size_c, D_TMO_EN => true, @@ -768,8 +794,8 @@ begin if MEM_INT_IMEM_EN generate neorv32_int_imem_inst: entity neorv32.neorv32_imem generic map ( - IMEM_SIZE => imem_size_c, - IMEM_AS_IROM => imem_as_rom_c + IMEM_SIZE => imem_size_c, + IMEM_INIT => imem_as_rom_c ) port map ( clk_i => clk_i, @@ -810,7 +836,7 @@ begin -- Processor-Internal Bootloader ROM (BOOTROM) -------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_boot_rom_inst_true: - if INT_BOOTLOADER_EN generate + if bootrom_en_c generate neorv32_boot_rom_inst: entity neorv32.neorv32_boot_rom port map ( clk_i => clk_i, @@ -821,7 +847,7 @@ begin end generate; neorv32_boot_rom_inst_false: - if not INT_BOOTLOADER_EN generate + if not bootrom_en_c generate boot_rsp <= rsp_terminate_c; end generate; @@ -927,7 +953,7 @@ begin generic map ( NUM_BLOCKS => XBUS_CACHE_NUM_BLOCKS, BLOCK_SIZE => XBUS_CACHE_BLOCK_SIZE, - UC_BEGIN => uncached_begin_c(31 downto 28), + UC_BEGIN => mem_uncached_begin_c(31 downto 28), UC_ENABLE => true, READ_ONLY => false ) @@ -1551,8 +1577,10 @@ begin generic map ( CLOCK_FREQUENCY => CLOCK_FREQUENCY, CLOCK_GATING_EN => CLOCK_GATING_EN, - INT_BOOTLOADER_EN => INT_BOOTLOADER_EN, + BOOT_MODE_SELECT => BOOT_MODE_SELECT, + INT_BOOTLOADER_EN => bootrom_en_c, MEM_INT_IMEM_EN => MEM_INT_IMEM_EN, + MEM_INT_IMEM_ROM => imem_as_rom_c, MEM_INT_IMEM_SIZE => imem_size_c, MEM_INT_DMEM_EN => MEM_INT_DMEM_EN, MEM_INT_DMEM_SIZE => dmem_size_c, @@ -1649,7 +1677,7 @@ begin bus_req_i => iodev_req(IODEV_OCD), bus_rsp_o => iodev_rsp(IODEV_OCD), cpu_ndmrstn_o => dci_ndmrstn, - cpu_halt_req_o => dci_halt_req + cpu_halt_req_o => dci_haltreq ); end generate; @@ -1659,7 +1687,7 @@ begin iodev_rsp(IODEV_OCD) <= rsp_terminate_c; jtag_tdo_o <= jtag_tdi_i; -- JTAG pass-through dci_ndmrstn <= '1'; - dci_halt_req <= '0'; + dci_haltreq <= '0'; end generate; diff --git a/rtl/core/neorv32_xbus.vhd b/rtl/core/neorv32_xbus.vhd index 1200023cc..e2421e515 100644 --- a/rtl/core/neorv32_xbus.vhd +++ b/rtl/core/neorv32_xbus.vhd @@ -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'; diff --git a/rtl/core/neorv32_xirq.vhd b/rtl/core/neorv32_xirq.vhd index 5ed5b45e5..8841c62c2 100644 --- a/rtl/core/neorv32_xirq.vhd +++ b/rtl/core/neorv32_xirq.vhd @@ -2,8 +2,8 @@ -- NEORV32 SoC - External Interrupt Controller (XIRQ) -- -- -------------------------------------------------------------------------------- -- -- Simple interrupt controller for platform (processor-external) interrupts. Up to -- --- 32 channels are supported that get (optionally) prioritized into a single CPU -- --- interrupt. Trigger type is programmable per channel by configuration registers. -- +-- 32 channels are supported that get prioritized into a single CPU interrupt. -- +-- Trigger type is programmable per-channel by configuration registers. -- -- -------------------------------------------------------------------------------- -- -- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 -- -- Copyright (c) NEORV32 contributors. -- @@ -36,27 +36,29 @@ end neorv32_xirq; architecture neorv32_xirq_rtl of neorv32_xirq is -- register addresses -- - constant addr_enable_c : std_ulogic_vector(2 downto 0) := "000"; -- r/w: channel enable - constant addr_pending_c : std_ulogic_vector(2 downto 0) := "001"; -- r/w: pending IRQs - constant addr_source_c : std_ulogic_vector(2 downto 0) := "010"; -- r/w: source IRQ, ACK on write - constant addr_ttype_c : std_ulogic_vector(2 downto 0) := "011"; -- r/w: trigger type (level/edge) - constant addr_tpolarity_c : std_ulogic_vector(2 downto 0) := "100"; -- r/w: trigger polarity (high/low or rising/falling) - - -- interface registers -- - signal irq_enable, nclr_pending, irq_type, irq_polarity : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0); - signal irq_source : std_ulogic_vector(4 downto 0); + constant addr_eie_c : std_ulogic_vector(1 downto 0) := "00"; -- r/w: channel enable + constant addr_esc_c : std_ulogic_vector(1 downto 0) := "01"; -- r/w: source IRQ, ACK on write + constant addr_ttyp_c : std_ulogic_vector(1 downto 0) := "10"; -- r/w: trigger type (level/edge) + constant addr_tpol_c : std_ulogic_vector(1 downto 0) := "11"; -- r/w: trigger polarity (high/low or rising/falling) + + -- configuration registers -- + signal irq_enable, irq_type, irq_polarity : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0); -- interrupt trigger -- - signal irq_sync, irq_sync2, irq_trig : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0); + signal irq_sync1, irq_sync2, irq_trig : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0); - -- interrupt buffer -- - signal irq_pending, irq_raw : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0); - signal irq_fire, irq_active : std_ulogic; + -- pending interrupt(s) -- + signal irq_pending : std_ulogic_vector(XIRQ_NUM_CH-1 downto 0); -- priority encoder -- type prio_enc_t is array (0 to XIRQ_NUM_CH-1) of std_ulogic_vector(4 downto 0); signal prio_enc : prio_enc_t; + -- interrupt arbiter -- + signal irq_state : std_ulogic_vector(1 downto 0); + signal irq_source : std_ulogic_vector(4 downto 0); + signal irq_clear : std_ulogic_vector(31 downto 0); + begin -- Bus Access ----------------------------------------------------------------------------- @@ -65,7 +67,6 @@ begin begin if (rstn_i = '0') then bus_rsp_o <= rsp_terminate_c; - nclr_pending <= (others => '0'); irq_type <= (others => '0'); irq_polarity <= (others => '0'); irq_enable <= (others => '0'); @@ -74,29 +75,29 @@ begin bus_rsp_o.ack <= bus_req_i.stb; bus_rsp_o.err <= '0'; bus_rsp_o.data <= (others => '0'); - nclr_pending <= (others => '1'); -- bus access -- if (bus_req_i.stb = '1') then if (bus_req_i.rw = '1') then -- write access - if (bus_req_i.addr(4 downto 2) = addr_enable_c) then -- channel-enable + if (bus_req_i.addr(3 downto 2) = addr_eie_c) then -- channel-enable irq_enable <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0); end if; - if (bus_req_i.addr(4 downto 2) = addr_pending_c) then -- clear pending IRQs - nclr_pending <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0); -- set zero to clear pending IRQ - end if; - if (bus_req_i.addr(4 downto 2) = addr_ttype_c) then -- trigger type + if (bus_req_i.addr(3 downto 2) = addr_ttyp_c) then -- trigger type irq_type <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0); end if; - if (bus_req_i.addr(4 downto 2) = addr_tpolarity_c) then -- trigger polarity + if (bus_req_i.addr(3 downto 2) = addr_tpol_c) then -- trigger polarity irq_polarity <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0); end if; else -- read access - case bus_req_i.addr(4 downto 2) is - when addr_enable_c => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_enable; -- channel-enable - when addr_pending_c => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_pending; -- pending IRQs - when addr_source_c => bus_rsp_o.data(4 downto 0) <= irq_source; -- IRQ source - when addr_ttype_c => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_type; -- trigger type - when others => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_polarity; -- trigger polarity + case bus_req_i.addr(3 downto 2) is + when addr_eie_c => -- channel-enable + bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_enable; + when addr_esc_c => + bus_rsp_o.data(31) <= irq_state(1); -- active interrupt waiting for ACK + bus_rsp_o.data(4 downto 0) <= irq_source; -- interrupt source (channel number) + when addr_ttyp_c => -- trigger type + bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_type; + when others => -- trigger polarity + bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_polarity; end case; end if; end if; @@ -109,55 +110,51 @@ begin synchronizer: process(rstn_i, clk_i) begin if (rstn_i = '0') then - irq_sync <= (others => '0'); + irq_sync1 <= (others => '0'); irq_sync2 <= (others => '0'); elsif rising_edge(clk_i) then - irq_sync <= xirq_i(XIRQ_NUM_CH-1 downto 0); - irq_sync2 <= irq_sync; + irq_sync1 <= xirq_i(XIRQ_NUM_CH-1 downto 0); + irq_sync2 <= irq_sync1; end if; end process synchronizer; -- trigger type select -- irq_trigger_gen: for i in 0 to XIRQ_NUM_CH-1 generate - irq_trigger: process(irq_sync, irq_sync2, irq_type, irq_polarity) + irq_trigger: process(irq_sync1, irq_sync2, irq_type, irq_polarity) variable sel_v : std_ulogic_vector(1 downto 0); begin sel_v := irq_type(i) & irq_polarity(i); case sel_v is - when "00" => irq_trig(i) <= not irq_sync(i); -- low-level - when "01" => irq_trig(i) <= irq_sync(i); -- high-level - when "10" => irq_trig(i) <= (not irq_sync(i)) and irq_sync2(i); -- falling-edge - when "11" => irq_trig(i) <= irq_sync(i) and (not irq_sync2(i)); -- rising-edge + when "00" => irq_trig(i) <= not irq_sync1(i); -- low-level + when "01" => irq_trig(i) <= irq_sync1(i); -- high-level + when "10" => irq_trig(i) <= (not irq_sync1(i)) and irq_sync2(i); -- falling-edge + when "11" => irq_trig(i) <= irq_sync1(i) and (not irq_sync2(i)); -- rising-edge when others => irq_trig(i) <= '0'; end case; end process irq_trigger; end generate; - -- IRQ Buffer --------------------------------------------------------------- + -- Interrupt-Pending Buffer ------------------------------------------------- -- ----------------------------------------------------------------------------- irq_buffer: process(rstn_i, clk_i) begin if (rstn_i = '0') then irq_pending <= (others => '0'); elsif rising_edge(clk_i) then - irq_pending <= (irq_pending and nclr_pending) or irq_trig; + irq_pending <= irq_enable and ((irq_pending and (not irq_clear(XIRQ_NUM_CH-1 downto 0))) or irq_trig); end if; end process irq_buffer; - -- filter enabled channels -- - irq_raw <= irq_pending and irq_enable; - - -- anyone firing? -- - irq_fire <= or_reduce_f(irq_raw); - -- encode highest-priority source (structural code: mux-chain) -- + -- Priority Encoder (structural code: mux-chain) ---------------------------- + -- ----------------------------------------------------------------------------- priority_encoder_gen: - for i in 0 to XIRQ_NUM_CH-1 generate -- start with highest priority + for i in 0 to XIRQ_NUM_CH-1 generate -- start with highest priority (=0) priority_encoder_gen_chain: -- inside chain if i < XIRQ_NUM_CH-1 generate - prio_enc(i) <= std_ulogic_vector(to_unsigned(i, 5)) when (irq_raw(i) = '1') else prio_enc(i+1); + prio_enc(i) <= std_ulogic_vector(to_unsigned(i, 5)) when (irq_pending(i) = '1') else prio_enc(i+1); end generate; priority_encoder_gen_last: -- end of chain if i = XIRQ_NUM_CH-1 generate @@ -171,23 +168,34 @@ begin irq_arbiter: process(rstn_i, clk_i) begin if (rstn_i = '0') then - irq_active <= '0'; + irq_clear <= (others => '0'); irq_source <= (others => '0'); + irq_state <= (others => '0'); elsif rising_edge(clk_i) then - if (irq_active = '0') then -- no active IRQ - irq_source <= prio_enc(0); -- get IRQ source - if (irq_fire = '1') then - irq_active <= '1'; - end if; - elsif (bus_req_i.stb = '1') and (bus_req_i.rw = '1') and - (bus_req_i.addr(4 downto 2) = addr_source_c) then -- acknowledge on write access - irq_active <= '0'; - end if; + irq_clear <= (others => '0'); -- default + case irq_state is + + when "00" => -- wait for pending interrupt + irq_source <= prio_enc(0); -- highest-priority channel + if (or_reduce_f(irq_pending) = '1') then + irq_state <= "01"; + end if; + + when "01" => -- clear triggering channel + irq_clear(to_integer(unsigned(irq_source))) <= '1'; -- ACK/clear according pending bit + irq_state <= "11"; + + when others => -- wait for CPU acknowledge + if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') and (bus_req_i.addr(3 downto 2) = addr_esc_c) then -- acknowledge on write access + irq_state <= "00"; + end if; + + end case; end if; end process irq_arbiter; -- CPU interrupt -- - cpu_irq_o <= irq_active; + cpu_irq_o <= irq_state(0); end neorv32_xirq_rtl; diff --git a/rtl/file_list_cpu.f b/rtl/file_list_cpu.f index 55a56fa46..c830a770d 100644 --- a/rtl/file_list_cpu.f +++ b/rtl/file_list_cpu.f @@ -14,5 +14,3 @@ 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 diff --git a/rtl/file_list_soc.f b/rtl/file_list_soc.f index 88cf13f91..e10289f20 100644 --- a/rtl/file_list_soc.f +++ b/rtl/file_list_soc.f @@ -19,8 +19,10 @@ 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_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 diff --git a/rtl/processor_templates/neorv32_ProcessorTop_Minimal.vhd b/rtl/processor_templates/neorv32_ProcessorTop_Minimal.vhd index 07c53a870..4b0b4616d 100644 --- a/rtl/processor_templates/neorv32_ProcessorTop_Minimal.vhd +++ b/rtl/processor_templates/neorv32_ProcessorTop_Minimal.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 diff --git a/rtl/processor_templates/neorv32_ProcessorTop_MinimalBoot.vhd b/rtl/processor_templates/neorv32_ProcessorTop_MinimalBoot.vhd index 84a1aea5b..e968b0baa 100644 --- a/rtl/processor_templates/neorv32_ProcessorTop_MinimalBoot.vhd +++ b/rtl/processor_templates/neorv32_ProcessorTop_MinimalBoot.vhd @@ -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 diff --git a/rtl/processor_templates/neorv32_ProcessorTop_UP5KDemo.vhd b/rtl/processor_templates/neorv32_ProcessorTop_UP5KDemo.vhd index 2c4dccc6e..c7bf2f459 100644 --- a/rtl/processor_templates/neorv32_ProcessorTop_UP5KDemo.vhd +++ b/rtl/processor_templates/neorv32_ProcessorTop_UP5KDemo.vhd @@ -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? diff --git a/rtl/system_integration/neorv32_vivado_ip.tcl b/rtl/system_integration/neorv32_vivado_ip.tcl index 797f0b03e..0ce1d9e8d 100644 --- a/rtl/system_integration/neorv32_vivado_ip.tcl +++ b/rtl/system_integration/neorv32_vivado_ip.tcl @@ -11,6 +11,7 @@ # -- SPDX-License-Identifier: BSD-3-Clause -- # -- ================================================================================ -- + # ************************************************************** # Global configuration # ************************************************************** @@ -20,6 +21,7 @@ set ip_logo docs/figures/neorv32_logo_riscv_small.png set outputdir neorv32_vivado_ip_work set cur_dir [file normalize .] + # ************************************************************** # Create empty (!) output/working directory # ************************************************************** @@ -30,11 +32,13 @@ if {[llength $files] != 0} { file delete -force {*}[glob -directory $outputdir *]; } + # ************************************************************** # Create Vivado project # ************************************************************** create_project "neorv32-ip" $outputdir -#set_property target_language VHDL [current_project] +set_property INCREMENTAL false [get_filesets sim_1] + # ************************************************************** # Import HDL source files @@ -48,12 +52,14 @@ puts $file_list add_files $file_list set_property library neorv32 [get_files $file_list] -# IP top module +# IP top module and AXI4-Lite bridge +add_file $neorv32_home/rtl/system_integration/xbus2axi4lite_bridge.vhd add_file $neorv32_home/rtl/system_integration/$ip_top.vhd set_property top $ip_top [current_fileset] update_compile_order -fileset sources_1 + # ************************************************************** # Package as IP block # ************************************************************** @@ -63,286 +69,338 @@ set_property vendor_display_name "Stephan Nolting" [ipx::current_core] set_property company_url https://github.com/stnolting/neorv32 [ipx::current_core] set_property description "The NEORV32 RISC-V Processor" [ipx::current_core] -# ************************************************************** -# Interfaces: Configuration Dependencies -# ************************************************************** -set_property enablement_dependency {$axi4_stream_en = true} [ipx::get_bus_interfaces s0_axis -of_objects [ipx::current_core]] -set_property enablement_dependency {$axi4_stream_en = true} [ipx::get_bus_interfaces s1_axis -of_objects [ipx::current_core]] -set_property enablement_dependency {$ocd_en = true} [ipx::get_ports jtag_* -of_objects [ipx::current_core]] -set_property enablement_dependency {$xip_en = true} [ipx::get_ports xip_* -of_objects [ipx::current_core]] -set_property enablement_dependency {$io_gpio_en = true} [ipx::get_ports gpio_* -of_objects [ipx::current_core]] -set_property enablement_dependency {$io_uart0_en = true} [ipx::get_ports uart0_* -of_objects [ipx::current_core]] -set_property enablement_dependency {$io_uart1_en = true} [ipx::get_ports uart1_* -of_objects [ipx::current_core]] -set_property enablement_dependency {$io_spi_en = true} [ipx::get_ports spi_* -of_objects [ipx::current_core]] -set_property enablement_dependency {$io_sdi_en = true} [ipx::get_ports sdi_* -of_objects [ipx::current_core]] -set_property enablement_dependency {$io_twi_en = true} [ipx::get_ports twi_* -of_objects [ipx::current_core]] -set_property enablement_dependency {$io_onewire_en = true} [ipx::get_ports onewire_* -of_objects [ipx::current_core]] -set_property enablement_dependency {$io_pwm_en = true} [ipx::get_ports pwm_o -of_objects [ipx::current_core]] -set_property enablement_dependency {$io_cfs_en = true} [ipx::get_ports cfs_* -of_objects [ipx::current_core]] -set_property enablement_dependency {$io_neoled_en = true} [ipx::get_ports neoled_o -of_objects [ipx::current_core]] -set_property enablement_dependency {$xirq_en = true} [ipx::get_ports xirq_i -of_objects [ipx::current_core]] -set_property enablement_dependency {$io_mtime_en = true} [ipx::get_ports mtime_time_o -of_objects [ipx::current_core]] -set_property enablement_dependency {$io_mtime_en = false} [ipx::get_ports mtime_irq_i -of_objects [ipx::current_core]] # ************************************************************** -# Configuration GUI: General +# Setup configuration GUI # ************************************************************** -set_property display_name {Clock frequency (Hz)} [ipgui::get_guiparamspec -name "CLOCK_FREQUENCY" -component [ipx::current_core]] -set_property tooltip {Frequency of the clk signal in Hz} [ipgui::get_guiparamspec -name "CLOCK_FREQUENCY" -component [ipx::current_core]] -set_property display_name {HART ID} [ipgui::get_guiparamspec -name "HART_ID" -component [ipx::current_core]] -set_property tooltip {For mhartid CSR} [ipgui::get_guiparamspec -name "HART_ID" -component [ipx::current_core]] -set_property display_name {JEDEC ID} [ipgui::get_guiparamspec -name "JEDEC_ID" -component [ipx::current_core]] -set_property tooltip {For JTAG tap identification and mvendorid CSR} [ipgui::get_guiparamspec -name "JEDEC_ID" -component [ipx::current_core]] -set_property display_name {RISC-V on-chip debugger} [ipgui::get_guiparamspec -name "OCD_EN" -component [ipx::current_core]] -set_property display_name {RISC-V on-chip debugger authentication} [ipgui::get_guiparamspec -name "OCD_AUTHENTICATION" -component [ipx::current_core]] -set_property display_name {AXI4-Lite (XBUS) timeout} [ipgui::get_guiparamspec -name "XBUS_TIMEOUT" -component [ipx::current_core]] -set_property tooltip {Max number of clock cycles before AXI access times out} [ipgui::get_guiparamspec -name "XBUS_TIMEOUT" -component [ipx::current_core]] -set_property display_name {AXI4-Lite (XBUS) cache} [ipgui::get_guiparamspec -name "XBUS_CACHE_EN" -component [ipx::current_core]] -set_property display_name {AXI4-Lite (XBUS) cache number of blocks} [ipgui::get_guiparamspec -name "XBUS_CACHE_NUM_BLOCKS" -component [ipx::current_core]] -set_property display_name {AXI4-Lite (XBUS) cache block size} [ipgui::get_guiparamspec -name "XBUS_CACHE_BLOCK_SIZE" -component [ipx::current_core]] -set_property tooltip {In bytes (use a power of two)} [ipgui::get_guiparamspec -name "XBUS_CACHE_BLOCK_SIZE" -component [ipx::current_core]] -set_property display_name {AXI4-Stream (SLINK) source and sink} [ipgui::get_guiparamspec -name "AXI4_STREAM_EN" -component [ipx::current_core]] -set_property display_name {AXI4-Stream (SLINK) input FIFO depth} [ipgui::get_guiparamspec -name "IO_SLINK_RX_FIFO" -component [ipx::current_core]] -set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_SLINK_RX_FIFO" -component [ipx::current_core]] -set_property display_name {AXI4-Stream (SLINK) output FIFO depth} [ipgui::get_guiparamspec -name "IO_SLINK_TX_FIFO" -component [ipx::current_core]] -set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_SLINK_TX_FIFO" -component [ipx::current_core]] - -ipgui::add_group -name {General} -component [ipx::current_core] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]] -display_name {General} -ipgui::move_group -component [ipx::current_core] -order 0 [ipgui::get_groupspec -name "General" -component [ipx::current_core]] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 0 [ipgui::get_guiparamspec -name "CLOCK_FREQUENCY" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 1 [ipgui::get_guiparamspec -name "HART_ID" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 2 [ipgui::get_guiparamspec -name "JEDEC_ID" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 3 [ipgui::get_guiparamspec -name "OCD_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 4 [ipgui::get_guiparamspec -name "OCD_AUTHENTICATION" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 5 [ipgui::get_guiparamspec -name "XBUS_TIMEOUT" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 6 [ipgui::get_guiparamspec -name "XBUS_CACHE_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 7 [ipgui::get_guiparamspec -name "XBUS_CACHE_NUM_BLOCKS" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 8 [ipgui::get_guiparamspec -name "XBUS_CACHE_BLOCK_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 9 [ipgui::get_guiparamspec -name "AXI4_STREAM_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 10 [ipgui::get_guiparamspec -name "IO_SLINK_RX_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 11 [ipgui::get_guiparamspec -name "IO_SLINK_TX_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "General" -component [ipx::current_core]] +proc setup_ip_gui {} { + proc set_param_properties {name {display_name ""} {tooltip ""} {enablement_expr ""} {value_expr ""}} { + set param_spec [ipgui::get_guiparamspec -name $name -component [ipx::current_core]] + set user_param [ipx::get_user_parameters $name -of_objects [ipx::current_core]] + if {$display_name ne ""} { + set_property display_name $display_name $param_spec + } + if {$tooltip ne ""} { + set_property tooltip $tooltip $param_spec + } + if {$enablement_expr ne ""} { + set_property enablement_tcl_expr $enablement_expr $user_param + } + if {$value_expr ne ""} { + set_property value_tcl_expr $value_expr $user_param + } + } -# ************************************************************** -# Configuration GUI: CPU -# ************************************************************** -set_property display_name {RISC-V C ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_C" -component [ipx::current_core]] -set_property tooltip {Compressed instructions} [ipgui::get_guiparamspec -name "RISCV_ISA_C" -component [ipx::current_core]] -set_property display_name {RISC-V E ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_E" -component [ipx::current_core]] -set_property tooltip {Reduced register file size (16 registers only)} [ipgui::get_guiparamspec -name "RISCV_ISA_E" -component [ipx::current_core]] -set_property display_name {RISC-V M ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_M" -component [ipx::current_core]] -set_property tooltip {Integer multiplication and division hardware} [ipgui::get_guiparamspec -name "RISCV_ISA_M" -component [ipx::current_core]] -set_property display_name {RISC-V U ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_U" -component [ipx::current_core]] -set_property tooltip {Less-privileged user-mode} [ipgui::get_guiparamspec -name "RISCV_ISA_U" -component [ipx::current_core]] -set_property display_name {RISC-V Zalrsc ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zalrsc" -component [ipx::current_core]] -set_property tooltip {Atomic reservation-set instructions} [ipgui::get_guiparamspec -name "RISCV_ISA_Zalrsc" -component [ipx::current_core]] -set_property display_name {RISC-V Zba ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zba" -component [ipx::current_core]] -set_property tooltip {Shifted-add bit-manipulation instructions} [ipgui::get_guiparamspec -name "RISCV_ISA_Zba" -component [ipx::current_core]] -set_property display_name {RISC-V Zbb ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbb" -component [ipx::current_core]] -set_property tooltip {Basic bit-manipulation instructions} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbb" -component [ipx::current_core]] -set_property display_name {RISC-V Zfinx ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zfinx" -component [ipx::current_core]] -set_property tooltip {Embedded FPU} [ipgui::get_guiparamspec -name "RISCV_ISA_Zfinx" -component [ipx::current_core]] -set_property display_name {RISC-V Zihpm ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zihpm" -component [ipx::current_core]] -set_property tooltip {Hardware performance monitors (HPMs)} [ipgui::get_guiparamspec -name "RISCV_ISA_Zihpm" -component [ipx::current_core]] -set_property display_name {HPM counters} [ipgui::get_guiparamspec -name "HPM_NUM_CNTS" -component [ipx::current_core]] -set_property tooltip {Numer of hardware performance monitor counters} [ipgui::get_guiparamspec -name "HPM_NUM_CNTS" -component [ipx::current_core]] -set_property display_name {HPM width} [ipgui::get_guiparamspec -name "HPM_CNT_WIDTH" -component [ipx::current_core]] -set_property tooltip {Counter width in bits} [ipgui::get_guiparamspec -name "HPM_CNT_WIDTH" -component [ipx::current_core]] -set_property display_name {RISC-V Zicntr ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zicntr" -component [ipx::current_core]] -set_property tooltip {Base counters (cycles and instructions)} [ipgui::get_guiparamspec -name "RISCV_ISA_Zicntr" -component [ipx::current_core]] -set_property display_name {RISC-V Zicond ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zicond" -component [ipx::current_core]] -set_property tooltip {Conditional-move instructions} [ipgui::get_guiparamspec -name "RISCV_ISA_Zicond" -component [ipx::current_core]] -set_property display_name {RISC-V Zmmul ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zmmul" -component [ipx::current_core]] -set_property tooltip {Integer multiplication-only hardware} [ipgui::get_guiparamspec -name "RISCV_ISA_Zmmul" -component [ipx::current_core]] -set_property display_name {NEORV32 Zxcfu ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zxcfu" -component [ipx::current_core]] -set_property tooltip {Custom-instructions unit} [ipgui::get_guiparamspec -name "RISCV_ISA_Zxcfu" -component [ipx::current_core]] -set_property display_name {RISC-V Zbkb ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkb" -component [ipx::current_core]] -set_property tooltip {Bit manipulation instructions for cryptography} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkb" -component [ipx::current_core]] -set_property display_name {RISC-V Zbkc ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkc" -component [ipx::current_core]] -set_property tooltip {Carry-less multiply instr. for cryptography} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkc" -component [ipx::current_core]] -set_property display_name {RISC-V Zbkx ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkx" -component [ipx::current_core]] -set_property tooltip {Scalar cryptographic - crossbar permutations} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkx" -component [ipx::current_core]] -set_property display_name {RISC-V Zbs ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbs" -component [ipx::current_core]] -set_property tooltip {Single-bit bit-manipulation instructions} [ipgui::get_guiparamspec -name "RISCV_ISA_Zbs" -component [ipx::current_core]] -set_property display_name {RISC-V Zknd ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zknd" -component [ipx::current_core]] -set_property tooltip {Scalar cryptographic - NIST AES decryption} [ipgui::get_guiparamspec -name "RISCV_ISA_Zknd" -component [ipx::current_core]] -set_property display_name {RISC-V Zkne ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zkne" -component [ipx::current_core]] -set_property tooltip {Scalar cryptographic - NIST AES encryption} [ipgui::get_guiparamspec -name "RISCV_ISA_Zkne" -component [ipx::current_core]] -set_property display_name {RISC-V Zknh ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zknh" -component [ipx::current_core]] -set_property tooltip {Scalar cryptographic - NIST hash functions} [ipgui::get_guiparamspec -name "RISCV_ISA_Zknh" -component [ipx::current_core]] -set_property display_name {RISC-V Zksed ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zksed" -component [ipx::current_core]] -set_property tooltip {Scalar cryptographic - ShangMi block cyphers} [ipgui::get_guiparamspec -name "RISCV_ISA_Zksed" -component [ipx::current_core]] -set_property display_name {RISC-V Zksh ISA extension} [ipgui::get_guiparamspec -name "RISCV_ISA_Zksh" -component [ipx::current_core]] -set_property tooltip {Scalar cryptographic - ShangMi hash functions} [ipgui::get_guiparamspec -name "RISCV_ISA_Zksh" -component [ipx::current_core]] -set_property display_name {DSP-based multiplier} [ipgui::get_guiparamspec -name "FAST_MUL_EN" -component [ipx::current_core]] -set_property display_name {Barrel shifter} [ipgui::get_guiparamspec -name "FAST_SHIFT_EN" -component [ipx::current_core]] -set_property display_name {FF-based register file with full HW reset} [ipgui::get_guiparamspec -name "REGFILE_HW_RST" -component [ipx::current_core]] -set_property display_name {PMP regions} [ipgui::get_guiparamspec -name "PMP_NUM_REGIONS" -component [ipx::current_core]] -set_property tooltip {Number of physical memory protection regions} [ipgui::get_guiparamspec -name "PMP_NUM_REGIONS" -component [ipx::current_core]] -set_property display_name {PMP minimal granularity} [ipgui::get_guiparamspec -name "PMP_MIN_GRANULARITY" -component [ipx::current_core]] -set_property tooltip {In bytes (min 4 bytes)} [ipgui::get_guiparamspec -name "PMP_MIN_GRANULARITY" -component [ipx::current_core]] -set_property display_name {Enable PMP TOR mode} [ipgui::get_guiparamspec -name "PMP_TOR_MODE_EN" -component [ipx::current_core]] -set_property tooltip {Top-of-region} [ipgui::get_guiparamspec -name "PMP_TOR_MODE_EN" -component [ipx::current_core]] -set_property display_name {Enable PMP NA2 and NAPOT modes} [ipgui::get_guiparamspec -name "PMP_NAP_MODE_EN" -component [ipx::current_core]] -set_property tooltip {Naturally-aligned-power-of-two} [ipgui::get_guiparamspec -name "PMP_NAP_MODE_EN" -component [ipx::current_core]] - -ipgui::add_group -name {CPU Configuration} -component [ipx::current_core] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]] -display_name {CPU Configuration} -ipgui::move_group -component [ipx::current_core] -order 1 [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 0 [ipgui::get_guiparamspec -name "RISCV_ISA_C" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 1 [ipgui::get_guiparamspec -name "RISCV_ISA_E" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 2 [ipgui::get_guiparamspec -name "RISCV_ISA_M" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 3 [ipgui::get_guiparamspec -name "RISCV_ISA_U" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 4 [ipgui::get_guiparamspec -name "RISCV_ISA_Zalrsc" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 5 [ipgui::get_guiparamspec -name "RISCV_ISA_Zba" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 6 [ipgui::get_guiparamspec -name "RISCV_ISA_Zbb" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 7 [ipgui::get_guiparamspec -name "RISCV_ISA_Zfinx" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 8 [ipgui::get_guiparamspec -name "RISCV_ISA_Zihpm" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 9 [ipgui::get_guiparamspec -name "HPM_NUM_CNTS" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 10 [ipgui::get_guiparamspec -name "HPM_CNT_WIDTH" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 11 [ipgui::get_guiparamspec -name "RISCV_ISA_Zicntr" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 12 [ipgui::get_guiparamspec -name "RISCV_ISA_Zicond" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 13 [ipgui::get_guiparamspec -name "RISCV_ISA_Zmmul" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 14 [ipgui::get_guiparamspec -name "RISCV_ISA_Zxcfu" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 15 [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkb" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 16 [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkc" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 17 [ipgui::get_guiparamspec -name "RISCV_ISA_Zbkx" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 18 [ipgui::get_guiparamspec -name "RISCV_ISA_Zbs" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 19 [ipgui::get_guiparamspec -name "RISCV_ISA_Zknd" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 20 [ipgui::get_guiparamspec -name "RISCV_ISA_Zkne" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 21 [ipgui::get_guiparamspec -name "RISCV_ISA_Zknh" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 22 [ipgui::get_guiparamspec -name "RISCV_ISA_Zksed" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 23 [ipgui::get_guiparamspec -name "RISCV_ISA_Zksh" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 24 [ipgui::get_guiparamspec -name "FAST_MUL_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 25 [ipgui::get_guiparamspec -name "FAST_SHIFT_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 26 [ipgui::get_guiparamspec -name "REGFILE_HW_RST" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 27 [ipgui::get_guiparamspec -name "PMP_NUM_REGIONS" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 28 [ipgui::get_guiparamspec -name "PMP_MIN_GRANULARITY" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 29 [ipgui::get_guiparamspec -name "PMP_TOR_MODE_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 30 [ipgui::get_guiparamspec -name "PMP_NAP_MODE_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "CPU Configuration" -component [ipx::current_core]] + proc add_page { name {tooltip ""} } { + set page [ipgui::add_page -name $name -component [ipx::current_core] -display_name $name] + if {$tooltip eq ""} { + set_property tooltip $tooltip $page + } + return $page + } -# ************************************************************** -# Configuration GUI: Memory System -# ************************************************************** -set_property display_name {Internal instruction memory (IMEM)} [ipgui::get_guiparamspec -name "MEM_INT_IMEM_EN" -component [ipx::current_core]] -set_property display_name {Internal instruction memory size} [ipgui::get_guiparamspec -name "MEM_INT_IMEM_SIZE" -component [ipx::current_core]] -set_property tooltip {In bytes (use a power of two)} [ipgui::get_guiparamspec -name "MEM_INT_IMEM_SIZE" -component [ipx::current_core]] -set_property display_name {Internal data memory (DMEM)} [ipgui::get_guiparamspec -name "MEM_INT_DMEM_EN" -component [ipx::current_core]] -set_property display_name {Internal data memory size} [ipgui::get_guiparamspec -name "MEM_INT_DMEM_SIZE" -component [ipx::current_core]] -set_property tooltip {In bytes (use a power of two)} [ipgui::get_guiparamspec -name "MEM_INT_DMEM_SIZE" -component [ipx::current_core]] -set_property display_name {CPU instruction cache (ICACHE)} [ipgui::get_guiparamspec -name "ICACHE_EN" -component [ipx::current_core]] -set_property display_name {CPU instruction cache (ICACHE) number of blocks} [ipgui::get_guiparamspec -name "ICACHE_NUM_BLOCKS" -component [ipx::current_core]] -set_property display_name {CPU instruction cache (ICACHE) block size} [ipgui::get_guiparamspec -name "ICACHE_BLOCK_SIZE" -component [ipx::current_core]] -set_property tooltip {In bytes (use a power of two)} [ipgui::get_guiparamspec -name "ICACHE_BLOCK_SIZE" -component [ipx::current_core]] -set_property display_name {CPU data cache (DCACHE)} [ipgui::get_guiparamspec -name "DCACHE_EN" -component [ipx::current_core]] -set_property display_name {CPU data cache (DCACHE) number of blocks} [ipgui::get_guiparamspec -name "DCACHE_NUM_BLOCKS" -component [ipx::current_core]] -set_property display_name {CPU data cache (DCACHE) block size} [ipgui::get_guiparamspec -name "DCACHE_BLOCK_SIZE" -component [ipx::current_core]] -set_property tooltip {In bytes (use a power of two)} [ipgui::get_guiparamspec -name "DCACHE_BLOCK_SIZE" -component [ipx::current_core]] -set_property display_name {Execute in-place module (XIP)} [ipgui::get_guiparamspec -name "XIP_EN" -component [ipx::current_core]] -set_property display_name {Execute in-place module (XIP) cache} [ipgui::get_guiparamspec -name "XIP_CACHE_EN" -component [ipx::current_core]] -set_property display_name {Execute in-place module (XIP) cache number of blocks} [ipgui::get_guiparamspec -name "XIP_CACHE_NUM_BLOCKS" -component [ipx::current_core]] -set_property display_name {Execute in-place module (XIP) cache block size} [ipgui::get_guiparamspec -name "XIP_CACHE_BLOCK_SIZE" -component [ipx::current_core]] -set_property tooltip {In bytes (use a power of two)} [ipgui::get_guiparamspec -name "XIP_CACHE_BLOCK_SIZE" -component [ipx::current_core]] -set_property display_name {Internal bootloader} [ipgui::get_guiparamspec -name "INT_BOOTLOADER_EN" -component [ipx::current_core]] -set_property tooltip {Start interactive bootloader console after reset} [ipgui::get_guiparamspec -name "INT_BOOTLOADER_EN" -component [ipx::current_core]] - -ipgui::add_group -name {Memory System} -component [ipx::current_core] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]] -display_name {Memory System} -ipgui::move_group -component [ipx::current_core] -order 2 [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 0 [ipgui::get_guiparamspec -name "MEM_INT_IMEM_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 1 [ipgui::get_guiparamspec -name "MEM_INT_IMEM_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 2 [ipgui::get_guiparamspec -name "MEM_INT_DMEM_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 3 [ipgui::get_guiparamspec -name "MEM_INT_DMEM_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 4 [ipgui::get_guiparamspec -name "ICACHE_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 5 [ipgui::get_guiparamspec -name "ICACHE_NUM_BLOCKS" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 6 [ipgui::get_guiparamspec -name "ICACHE_BLOCK_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 7 [ipgui::get_guiparamspec -name "DCACHE_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 8 [ipgui::get_guiparamspec -name "DCACHE_NUM_BLOCKS" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 9 [ipgui::get_guiparamspec -name "DCACHE_BLOCK_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 10 [ipgui::get_guiparamspec -name "XIP_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 11 [ipgui::get_guiparamspec -name "XIP_CACHE_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 12 [ipgui::get_guiparamspec -name "XIP_CACHE_NUM_BLOCKS" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 13 [ipgui::get_guiparamspec -name "XIP_CACHE_BLOCK_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 14 [ipgui::get_guiparamspec -name "INT_BOOTLOADER_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Memory System" -component [ipx::current_core]] + proc add_group { parent name {display_name ""} } { + if {$display_name eq ""} { + set display_name $name + } + ipgui::add_group -name $name -component [ipx::current_core] -parent $parent -display_name $display_name + } + + proc add_params { parent params } { + foreach param $params { + set name [lindex $param 0] + ipgui::add_param -name $name -component [ipx::current_core] -parent $parent + set_param_properties {*}$param + } + } + + + # ************************************************************** + # Interfaces: Configuration Dependencies + # ************************************************************** + set_property enablement_dependency {$IO_SLINK_EN} [ipx::get_bus_interfaces s0_axis -of_objects [ipx::current_core]] + set_property enablement_dependency {$IO_SLINK_EN} [ipx::get_bus_interfaces s1_axis -of_objects [ipx::current_core]] + set_property enablement_dependency {$XBUS_EN} [ipx::get_bus_interfaces m_axi -of_objects [ipx::current_core]] + set_property enablement_dependency {$OCD_EN} [ipx::get_ports jtag_* -of_objects [ipx::current_core]] + set_property enablement_dependency {$XIP_EN} [ipx::get_ports xip_* -of_objects [ipx::current_core]] + set_property enablement_dependency {$IO_GPIO_EN} [ipx::get_ports gpio_* -of_objects [ipx::current_core]] + set_property enablement_dependency {$IO_UART0_EN} [ipx::get_ports uart0_* -of_objects [ipx::current_core]] + set_property enablement_dependency {$IO_UART1_EN} [ipx::get_ports uart1_* -of_objects [ipx::current_core]] + set_property enablement_dependency {$IO_SPI_EN} [ipx::get_ports spi_* -of_objects [ipx::current_core]] + set_property enablement_dependency {$IO_SDI_EN} [ipx::get_ports sdi_* -of_objects [ipx::current_core]] + set_property enablement_dependency {$IO_TWI_EN} [ipx::get_ports twi_* -of_objects [ipx::current_core]] + set_property enablement_dependency {$IO_ONEWIRE_EN} [ipx::get_ports onewire_* -of_objects [ipx::current_core]] + set_property enablement_dependency {$IO_PWM_EN} [ipx::get_ports pwm_o -of_objects [ipx::current_core]] + set_property enablement_dependency {$IO_CFS_EN} [ipx::get_ports cfs_* -of_objects [ipx::current_core]] + set_property enablement_dependency {$IO_NEOLED_EN} [ipx::get_ports neoled_o -of_objects [ipx::current_core]] + set_property enablement_dependency {$XIRQ_EN} [ipx::get_ports xirq_i -of_objects [ipx::current_core]] + set_property enablement_dependency {$IO_MTIME_EN} [ipx::get_ports mtime_time_o -of_objects [ipx::current_core]] + set_property enablement_dependency {!$IO_MTIME_EN} [ipx::get_ports mtime_irq_i -of_objects [ipx::current_core]] + + + # ************************************************************** + # Configuration pages + # ************************************************************** + # Remove default page + set page [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]] + if {$page ne ""} { + ipgui::remove_page -component [ipx::current_core] $page + } + + # ************************************************************** + # GUI Page: General + # ************************************************************** + set page [add_page {General}] + + # { param_name {display_name} {tooltip} {enablement_expr} {value_expr} } + + set group [add_group $page {Clocking}] + add_params $page { + { CLOCK_FREQUENCY {Clock Frequency (Hz)} {Frequency of the clk input signal in Hz} } + } + + set group [add_group $page {Boot Configuration}] + add_params $group { + { BOOT_MODE_SELECT {Boot mode select} {Processor boot configuration} } + { BOOT_ADDR_CUSTOM {Custom boot address} {Available if BOOT_MODE_SELECT = 1; has to be 4-byte aligned} {$BOOT_MODE_SELECT == 1}} + } + set_property widget {comboBox} [ipgui::get_guiparamspec -name "BOOT_MODE_SELECT" -component [ipx::current_core] ] + set_property value_validation_type pairs [ipx::get_user_parameters BOOT_MODE_SELECT -of_objects [ipx::current_core]] + set_property value_validation_pairs {{Internal bootloader} 0 {Custom address} 1 {Internal IMEM image} 2} [ipx::get_user_parameters BOOT_MODE_SELECT -of_objects [ipx::current_core]] + + set group [add_group $page {Core Identification}] + add_params $group { + { HART_ID {HART ID} {The hart thread ID of the CPU (passed to mhartid CSR)} } + { JEDEC_ID {JEDEC ID} {For JTAG tap identification and mvendorid CSR} } + } + + set group [add_group $page {On-Chip Debugger (OCD)}] + add_params $group { + { OCD_EN {Enable OCD} {Implement the on-chip debugger and the CPU debug mode} } + { OCD_AUTHENTICATION {OCD Authentication} {Implement Debug Authentication module} {$OCD_EN} {$OCD_EN ? $OCD_AUTHENTICATION : false}} + } + + set group [add_group $page {External Bus Interface (XBUS / AXI4-Lite-MM Host)}] + add_params $group { + { XBUS_EN {Enable XBUS} {} } + { XBUS_TIMEOUT {Timeout} {Max number of clock cycles before AXI access times out} {$XBUS_EN} } + } + + set sub_group [add_group $group {XBUS Cache}] + add_params $sub_group { + { XBUS_REGSTAGE_EN {Add register stages} {Relaxes timing, but will increase latency} {$XBUS_EN} } + { XBUS_CACHE_EN {Enable XBUS Cache} {} {$XBUS_EN} {$XBUS_EN ? $XBUS_CACHE_EN : false}} + { XBUS_CACHE_NUM_BLOCKS {Number of Blocks} {} {$XBUS_CACHE_EN} } + { XBUS_CACHE_BLOCK_SIZE {Block Size} {In bytes (use a power of two)} {$XBUS_CACHE_EN} } + } + + set group [add_group $page {Stream Link Interface (SLINK / AXI4-Stream Source & Sink)}] + add_params $group { + { IO_SLINK_EN {Enable SLINK} {} } + { IO_SLINK_RX_FIFO {RX FIFO Depth} {Number of entries (use a power of two)} {$IO_SLINK_EN} } + { IO_SLINK_TX_FIFO {TX FIFO Depth} {Number of entries (use a power of two)} {$IO_SLINK_EN} } + } + + + # ************************************************************** + # GUI Page: CPU + # ************************************************************** + set page [add_page {CPU Configuration}] + + set group [add_group $page {RISC-V ISA Extensions}] + add_params $group { + { RISCV_ISA_C {C Extension} {Compressed instructions} } + { RISCV_ISA_E {E Extension} {Reduced register file size (16 registers only)} } + { RISCV_ISA_M {M Extension} {Integer multiplication and division hardware} } + { RISCV_ISA_U {U Extension} {Less-privileged user-mode} } + { RISCV_ISA_Zalrsc {Zalrsc Extension} {Atomic reservation-set instructions} } + { RISCV_ISA_Zba {Zba Extension} {Shifted-add bit-manipulation instructions} } + { RISCV_ISA_Zbb {Zbb Extension} {Basic bit-manipulation instructions} } + { RISCV_ISA_Zbkb {Zbkb Extension} {Bit manipulation instructions for cryptography} } + { RISCV_ISA_Zbkc {Zbkc Extension} {Carry-less multiply instr. for cryptography} } + { RISCV_ISA_Zbkx {Zbkx Extension} {Scalar cryptographic - crossbar permutations} } + { RISCV_ISA_Zbs {Zbs Extension} {Single-bit bit-manipulation instructions} } + { RISCV_ISA_Zfinx {Zfinx Extension} {Embedded FPU} } + { RISCV_ISA_Zicntr {Zicntr Extension} {Base counters (cycles and instructions)} } + { RISCV_ISA_Zicond {Zicond Extension} {Conditional-move instructions} } + { RISCV_ISA_Zihpm {Zihpm Extension} {Hardware performance monitors (HPMs)} } + { HPM_CNT_WIDTH {HPM Width} {Counter width in bits} {$RISCV_ISA_Zihpm}} + { HPM_NUM_CNTS {HPM Counters} {Numer of hardware performance monitor counters} {$RISCV_ISA_Zihpm}} + { RISCV_ISA_Zknd {Zknd Extension} {Scalar cryptographic - NIST AES decryption} } + { RISCV_ISA_Zkne {Zkne Extension} {Scalar cryptographic - NIST AES encryption} } + { RISCV_ISA_Zknh {Zknh Extension} {Scalar cryptographic - NIST hash functions} } + { RISCV_ISA_Zksed {Zksed Extension} {Scalar cryptographic - ShangMi block cyphers} } + { RISCV_ISA_Zksh {Zksh Extension} {Scalar cryptographic - ShangMi hash functions} } + { RISCV_ISA_Zmmul {Zmmul Extension} {Integer multiplication-only hardware} } + { RISCV_ISA_Zxcfu {NEORV32 Zxcfu ISA Extension} {Custom-instructions unit} } + } + + set group [add_group $page {Physical Memory Protection (PMP)}] + add_params $group { + { PMP_NUM_REGIONS {PMP Regions} {Number of physical memory protection regions} } + { PMP_MIN_GRANULARITY {PMP Minimal Granularity} {Minimal region granularity in bytes. Has to be a power of two.} {$PMP_NUM_REGIONS > 0} } + { PMP_TOR_MODE_EN {Enable PMP TOR Mode} {Implement support for top-of-region (TOR) mode} {$PMP_NUM_REGIONS > 0} } + { PMP_NAP_MODE_EN {Enable PMP NAPOT and NA4 Modes} {Implement support for naturally-aligned power-of-two (NAPOT & NA4) modes} {$PMP_NUM_REGIONS > 0} } + } + set_property value_validation_range_minimum 4 [ipx::get_user_parameters PMP_MIN_GRANULARITY -of_objects [ipx::current_core]] + + set group [add_group $page {Tuning Options}] + add_params $group { + { FAST_MUL_EN {DSP-Based Multiplier} } + { FAST_SHIFT_EN {Barrel Shifter} } + { REGFILE_HW_RST {Allow Full HW Reset for Register File} {Implement register file with FFs instead of BRAM to allow full hardware reset} } + } + + + # ************************************************************** + # GUI Page: Memory System + # ************************************************************** + set page [add_page {Memory System}] + + set group [add_group $page {Internal Instruction Memory (IMEM)}] + add_params $group { + { MEM_INT_IMEM_EN {Enable IMEM} } + { MEM_INT_IMEM_SIZE {IMEM Size} {In bytes (use a power of two)} {$MEM_INT_IMEM_EN} } + } + + set group [add_group $page {Internal Data Memory (DMEM)}] + add_params $group { + { MEM_INT_DMEM_EN {Enbale DMEM} } + { MEM_INT_DMEM_SIZE {DMEM Size} {In bytes (use a power of two)} {$MEM_INT_DMEM_EN} } + } + + set group [add_group $page {CPU Instruction Cache (ICACHE)}] + add_params $group { + { ICACHE_EN {Enable ICACHE} } + { ICACHE_NUM_BLOCKS {Number of Blocks} {} {$ICACHE_EN} } + { ICACHE_BLOCK_SIZE {Block Size} {In bytes (use a power of two)} {$ICACHE_EN} } + } + + set group [add_group $page {CPU Data Cache (DCACHE)}] + add_params $group { + { DCACHE_EN {Enable DCACHE} } + { DCACHE_NUM_BLOCKS {Number of Blocks} {} {$DCACHE_EN} } + { DCACHE_BLOCK_SIZE {Block Size} {In bytes (use a power of two)} {$DCACHE_EN} } + } + + set group [add_group $page {Execute In-Place Module (XIP)}] + add_params $group { + { XIP_EN {Enable XIP} } + { XIP_CACHE_EN {Enable XIP Cache} {} {$XIP_EN} {$XIP_EN ? $XIP_CACHE_EN : false} } + { XIP_CACHE_NUM_BLOCKS {Cache Blocks} {} {$XIP_CACHE_EN} } + { XIP_CACHE_BLOCK_SIZE {Cache Block Size} {In bytes (use a power of two)} {$XIP_CACHE_EN} } + } + + + # ************************************************************** + # GUI Page: Peripherals + # ************************************************************** + set page [add_page {Peripherals}] + + set group [add_group $page {External Interrupt Controller (XIRQ)}] + add_params $group { + { XIRQ_EN {Enable XIRQ} } + { XIRQ_NUM_CH {Number of Channels} {} {$XIRQ_EN} } + } + + set group [add_group $page {General-Purpose Input/Output Controller (GPIO)}] + add_params $group { + { IO_GPIO_EN {Enable GPIO} } + { IO_GPIO_IN_NUM {Number of Inputs} {} {$IO_GPIO_EN} } + { IO_GPIO_OUT_NUM {Number of Outputs} {} {$IO_GPIO_EN} } + } + + set group [add_group $page {Machine Timer (MTIME)}] + add_params $group { + { IO_MTIME_EN {Enable Machine Timer} } + } + + set group [add_group $page {Primary UART (UART0)}] + add_params $group { + { IO_UART0_EN {Enable UART0} } + { IO_UART0_RX_FIFO {RX FIFO Depth} {Number of entries (use a power of two)} {$IO_UART0_EN} } + { IO_UART0_TX_FIFO {TX FIFO Depth} {Number of entries (use a power of two)} {$IO_UART0_EN} } + } + + set group [add_group $page {Secondary UART (UART1)}] + add_params $group { + { IO_UART1_EN {Enable UART1} } + { IO_UART1_RX_FIFO {RX FIFO Depth} {Number of entries (use a power of two)} {$IO_UART1_EN} } + { IO_UART1_TX_FIFO {TX FIFO Depth} {Number of entries (use a power of two)} {$IO_UART1_EN} } + } + + set group [add_group $page {SPI Host Controller (SPI)}] + add_params $group { + { IO_SPI_EN {Enable SPI} } + { IO_SPI_FIFO {FIFO Depth} {Number of entries (use a power of two)} {$IO_SPI_EN} } + } + + set group [add_group $page {SPI Device Controller (SDI)}] + add_params $group { + { IO_SDI_EN {Enable SDI} } + { IO_SDI_FIFO {FIFO Depth} {Number of entries (use a power of two)} {$IO_SDI_EN} } + } + + set group [add_group $page {Two-Wire/I2C Interface (TWI)}] + add_params $group { + { IO_TWI_EN {Enable TWI} } + { IO_TWI_FIFO {FIFO Depth} {Number of entries (use a power of two)} {$IO_TWI_EN} } + } + + set group [add_group $page {Pulse-Width Modulation Controller (PWM)}] + add_params $group { + { IO_PWM_EN {Enable PWM} } + { IO_PWM_NUM_CH {Number of Channels} {} {$IO_PWM_EN} } + } + + set group [add_group $page {Watchdog Timer (WDT)}] + add_params $group { + { IO_WDT_EN {Enable WDT} } + } + + set group [add_group $page {True Random-Number Generator (TRNG)}] + add_params $group { + { IO_TRNG_EN {Enable TRNG} } + { IO_TRNG_FIFO {FIFO Depth} {Number of entries (use a power of two)} {$IO_TRNG_EN} } + } + + set group [add_group $page {Custom Functions Subsystem (CFS)}] + add_params $group { + { IO_CFS_EN {Enable CFS} } + { IO_CFS_CONFIG {Configuration Word} {} {$IO_CFS_EN} } + { IO_CFS_IN_SIZE {Input Port Width} {} {$IO_CFS_EN} } + { IO_CFS_OUT_SIZE {Output Port Width} {} {$IO_CFS_EN} } + } + + set group [add_group $page {Smart LED Interface (NEOLED)}] + add_params $group { + { IO_NEOLED_EN {Enable NEOLED} } + { IO_NEOLED_TX_FIFO {FIFO Depth} {Number of entries (use a power of two)} {$IO_NEOLED_EN} } + } + + set group [add_group $page {General Purpose Timer (GPTMR)}] + add_params $group { + { IO_GPTMR_EN {Enable GPTMR} } + } + + set group [add_group $page {One-Wire Interface Controller (ONEWIRE)}] + add_params $group { + { IO_ONEWIRE_EN {Enable ONEWIRE} } + } + + set group [add_group $page {Direct Memory Access Controller (DMA)}] + add_params $group { + { IO_DMA_EN {Enable DMA} } + } + + set group [add_group $page {Cyclic Redundancy Check (CRC)}] + add_params $group { + { IO_CRC_EN {Enable CRC} } + } +} + +setup_ip_gui -# ************************************************************** -# Configuration GUI: Peripherals -# ************************************************************** -set_property display_name {External interrupt controller (XIRQ)} [ipgui::get_guiparamspec -name "XIRQ_EN" -component [ipx::current_core]] -set_property display_name {External interrupt controller (XIRQ) channels} [ipgui::get_guiparamspec -name "XIRQ_NUM_CH" -component [ipx::current_core]] -set_property display_name {General-Purpose Input/Output (GPIO) controller} [ipgui::get_guiparamspec -name "IO_GPIO_EN" -component [ipx::current_core]] -set_property display_name {General-purpose (GPIO) inputs} [ipgui::get_guiparamspec -name "IO_GPIO_IN_NUM" -component [ipx::current_core]] -set_property display_name {General-purpose (GPIO) outputs} [ipgui::get_guiparamspec -name "IO_GPIO_OUT_NUM" -component [ipx::current_core]] -set_property display_name {Machine timer (MTIME)} [ipgui::get_guiparamspec -name "IO_MTIME_EN" -component [ipx::current_core]] -set_property display_name {Primary UART (UART0)} [ipgui::get_guiparamspec -name "IO_UART0_EN" -component [ipx::current_core]] -set_property display_name {Primary UART (UART0) RX FIFO depth} [ipgui::get_guiparamspec -name "IO_UART0_RX_FIFO" -component [ipx::current_core]] -set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_UART0_RX_FIFO" -component [ipx::current_core]] -set_property display_name {Primary UART (UART0) TX FIFO depth} [ipgui::get_guiparamspec -name "IO_UART0_TX_FIFO" -component [ipx::current_core]] -set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_UART0_TX_FIFO" -component [ipx::current_core]] -set_property display_name {Secondary UART (UART1)} [ipgui::get_guiparamspec -name "IO_UART1_EN" -component [ipx::current_core]] -set_property display_name {Secondary UART (UART1) RX FIFO depth} [ipgui::get_guiparamspec -name "IO_UART1_RX_FIFO" -component [ipx::current_core]] -set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_UART1_RX_FIFO" -component [ipx::current_core]] -set_property display_name {Secondary UART (UART1) TX FIFO depth} [ipgui::get_guiparamspec -name "IO_UART1_TX_FIFO" -component [ipx::current_core]] -set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_UART1_TX_FIFO" -component [ipx::current_core]] -set_property display_name {SPI host controller (SPI)} [ipgui::get_guiparamspec -name "IO_SPI_EN" -component [ipx::current_core]] -set_property display_name {SPI host controller (SPI) FIFO depth} [ipgui::get_guiparamspec -name "IO_SPI_FIFO" -component [ipx::current_core]] -set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_SPI_FIFO" -component [ipx::current_core]] -set_property display_name {SPI device controller (SDI)} [ipgui::get_guiparamspec -name "IO_SDI_EN" -component [ipx::current_core]] -set_property display_name {SPI device controller (SDI) FIFO depth} [ipgui::get_guiparamspec -name "IO_SDI_FIFO" -component [ipx::current_core]] -set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_SDI_FIFO" -component [ipx::current_core]] -set_property display_name {Two-Wire/I2C Interface (TWI)} [ipgui::get_guiparamspec -name "IO_TWI_EN" -component [ipx::current_core]] -set_property display_name {Two-Wire/I2C Interface (TWI) FIFO depth} [ipgui::get_guiparamspec -name "IO_TWI_FIFO" -component [ipx::current_core]] -set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_TWI_FIFO" -component [ipx::current_core]] -set_property display_name {Pulse-Width Moduleation (PWM) controller} [ipgui::get_guiparamspec -name "IO_PWM_EN" -component [ipx::current_core]] -set_property display_name {Pulse-Width Moduleation (PWM) channels} [ipgui::get_guiparamspec -name "IO_PWM_NUM_CH" -component [ipx::current_core]] -set_property display_name {Watchdog timer (WDT)} [ipgui::get_guiparamspec -name "IO_WDT_EN" -component [ipx::current_core]] -set_property display_name {True-Random-Number Generator (TRNG)} [ipgui::get_guiparamspec -name "IO_TRNG_EN" -component [ipx::current_core]] -set_property display_name {True-Random-Number Generator (TRNG) FIFO depth} [ipgui::get_guiparamspec -name "IO_TRNG_FIFO" -component [ipx::current_core]] -set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_TRNG_FIFO" -component [ipx::current_core]] -set_property display_name {Custom Functions Subsystem (CFS)} [ipgui::get_guiparamspec -name "IO_CFS_EN" -component [ipx::current_core]] -set_property display_name {Custom Functions Subsystem (CFS) configuration word} [ipgui::get_guiparamspec -name "IO_CFS_CONFIG" -component [ipx::current_core]] -set_property display_name {Custom Functions Subsystem (CFS) input port width} [ipgui::get_guiparamspec -name "IO_CFS_IN_SIZE" -component [ipx::current_core]] -set_property display_name {Custom Functions Subsystem (CFS) output port width} [ipgui::get_guiparamspec -name "IO_CFS_OUT_SIZE" -component [ipx::current_core]] -set_property display_name {Smart LED Interface (NEOLED)} [ipgui::get_guiparamspec -name "IO_NEOLED_EN" -component [ipx::current_core]] -set_property display_name {Smart LED Interface (NEOLED) FIFO depth} [ipgui::get_guiparamspec -name "IO_NEOLED_TX_FIFO" -component [ipx::current_core]] -set_property tooltip {Number of entries (use a power of two)} [ipgui::get_guiparamspec -name "IO_NEOLED_TX_FIFO" -component [ipx::current_core]] -set_property display_name {General Purpose Timer (GPTMR)} [ipgui::get_guiparamspec -name "IO_GPTMR_EN" -component [ipx::current_core]] -set_property display_name {1-Wire (ONEWIRE) controller} [ipgui::get_guiparamspec -name "IO_ONEWIRE_EN" -component [ipx::current_core]] -set_property display_name {Direct Memory Access (DMA) controller} [ipgui::get_guiparamspec -name "IO_DMA_EN" -component [ipx::current_core]] -set_property display_name {Cyclic Redundancy Check (CRC) Unit} [ipgui::get_guiparamspec -name "IO_CRC_EN" -component [ipx::current_core]] - -ipgui::add_group -name {Peripherals} -component [ipx::current_core] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]] -display_name {Peripherals} -ipgui::move_group -component [ipx::current_core] -order 3 [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -parent [ipgui::get_pagespec -name "Page 0" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 0 [ipgui::get_guiparamspec -name "IO_GPIO_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 1 [ipgui::get_guiparamspec -name "IO_GPIO_IN_NUM" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 2 [ipgui::get_guiparamspec -name "IO_GPIO_OUT_NUM" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 3 [ipgui::get_guiparamspec -name "IO_MTIME_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 4 [ipgui::get_guiparamspec -name "IO_UART0_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 5 [ipgui::get_guiparamspec -name "IO_UART0_RX_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 6 [ipgui::get_guiparamspec -name "IO_UART0_TX_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 7 [ipgui::get_guiparamspec -name "IO_UART1_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 8 [ipgui::get_guiparamspec -name "IO_UART1_RX_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 9 [ipgui::get_guiparamspec -name "IO_UART1_TX_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 10 [ipgui::get_guiparamspec -name "IO_SPI_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 11 [ipgui::get_guiparamspec -name "IO_SPI_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 12 [ipgui::get_guiparamspec -name "IO_SDI_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 13 [ipgui::get_guiparamspec -name "IO_SDI_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 14 [ipgui::get_guiparamspec -name "IO_TWI_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 15 [ipgui::get_guiparamspec -name "IO_TWI_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 16 [ipgui::get_guiparamspec -name "IO_PWM_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 17 [ipgui::get_guiparamspec -name "IO_PWM_NUM_CH" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 18 [ipgui::get_guiparamspec -name "IO_WDT_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 19 [ipgui::get_guiparamspec -name "IO_TRNG_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 20 [ipgui::get_guiparamspec -name "IO_TRNG_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 21 [ipgui::get_guiparamspec -name "IO_CFS_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 22 [ipgui::get_guiparamspec -name "IO_CFS_CONFIG" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 23 [ipgui::get_guiparamspec -name "IO_CFS_IN_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 24 [ipgui::get_guiparamspec -name "IO_CFS_OUT_SIZE" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 25 [ipgui::get_guiparamspec -name "IO_NEOLED_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 26 [ipgui::get_guiparamspec -name "IO_NEOLED_TX_FIFO" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 27 [ipgui::get_guiparamspec -name "IO_GPTMR_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 28 [ipgui::get_guiparamspec -name "IO_ONEWIRE_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 29 [ipgui::get_guiparamspec -name "IO_DMA_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 30 [ipgui::get_guiparamspec -name "XIRQ_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 31 [ipgui::get_guiparamspec -name "XIRQ_NUM_CH" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] -ipgui::move_param -component [ipx::current_core] -order 32 [ipgui::get_guiparamspec -name "IO_CRC_EN" -component [ipx::current_core]] -parent [ipgui::get_groupspec -name "Peripherals" -component [ipx::current_core]] # ************************************************************** # Configuration GUI: IP logo @@ -357,6 +415,10 @@ ipx::add_file ../../$neorv32_home/$ip_logo [ipx::get_file_groups xilinx_coreguii set_property type image [ipx::get_files ../../$neorv32_home/$ip_logo -of_objects [ipx::get_file_groups xilinx_coreguiicon -of_objects [ipx::current_core]]] set_property type LOGO [ipx::get_files ../../$neorv32_home/$ip_logo -of_objects [ipx::get_file_groups xilinx_coreguiicon -of_objects [ipx::current_core]]] +ipx::add_file_group -type product_guide {} [ipx::current_core] +ipx::add_file {https://stnolting.github.io/neorv32/} [ipx::get_file_groups xilinx_productguide -of_objects [ipx::current_core]] + + # ************************************************************** # Finalize and add to IP repository # ************************************************************** diff --git a/rtl/system_integration/neorv32_vivado_ip.vhd b/rtl/system_integration/neorv32_vivado_ip.vhd index 652d5dbe7..693a1c564 100644 --- a/rtl/system_integration/neorv32_vivado_ip.vhd +++ b/rtl/system_integration/neorv32_vivado_ip.vhd @@ -25,13 +25,14 @@ entity neorv32_vivado_ip is -- ------------------------------------------------------------ -- Configuration Generics -- ------------------------------------------------------------ - -- AXI-Stream Interfaces -- - AXI4_STREAM_EN : boolean := false; - -- General -- + -- Clocking -- CLOCK_FREQUENCY : natural := 100_000_000; + -- Identification -- HART_ID : std_logic_vector(31 downto 0) := x"00000000"; JEDEC_ID : std_logic_vector(10 downto 0) := "00000000000"; - INT_BOOTLOADER_EN : boolean := false; + -- Boot Configuration -- + BOOT_MODE_SELECT : natural range 0 to 2 := 0; + BOOT_ADDR_CUSTOM : std_ulogic_vector(31 downto 0) := x"00000000"; -- On-Chip Debugger (OCD) -- OCD_EN : boolean := false; OCD_AUTHENTICATION : boolean := false; @@ -85,7 +86,9 @@ entity neorv32_vivado_ip is DCACHE_NUM_BLOCKS : natural range 1 to 256 := 4; DCACHE_BLOCK_SIZE : natural range 4 to 2**16 := 64; -- External Bus Interface -- + XBUS_EN : boolean := true; XBUS_TIMEOUT : natural range 8 to 65536 := 64; + XBUS_REGSTAGE_EN : boolean := false; XBUS_CACHE_EN : boolean := false; XBUS_CACHE_NUM_BLOCKS : natural range 1 to 256 := 8; XBUS_CACHE_BLOCK_SIZE : natural range 1 to 2**16 := 256; @@ -128,6 +131,7 @@ entity neorv32_vivado_ip is IO_GPTMR_EN : boolean := false; IO_ONEWIRE_EN : boolean := false; IO_DMA_EN : boolean := false; + IO_SLINK_EN : boolean := false; IO_SLINK_RX_FIFO : natural range 1 to 2**15 := 1; IO_SLINK_TX_FIFO : natural range 1 to 2**15 := 1; IO_CRC_EN : boolean := false @@ -139,7 +143,7 @@ entity neorv32_vivado_ip is clk : in std_logic; resetn : in std_logic; -- low-active -- ------------------------------------------------------------ - -- AXI4-Lite-Compatible Host Interface (always available) + -- AXI4-Lite Host Interface (available if XBUS_EN = true) -- ------------------------------------------------------------ -- Clock and Reset -- -- m_axi_aclk : in std_logic := '0'; -- just to satisfy Vivado, but not actually used @@ -161,15 +165,15 @@ entity neorv32_vivado_ip is m_axi_arready : in std_logic := '0'; -- Read Data Channel -- m_axi_rdata : in std_logic_vector(31 downto 0) := x"00000000"; - m_axi_rresp : in std_logic_vector(1 downto 0) := "11"; -- error by default + m_axi_rresp : in std_logic_vector(1 downto 0); -- no default here (#1067) m_axi_rvalid : in std_logic := '0'; m_axi_rready : out std_logic; -- Write Response Channel -- - m_axi_bresp : in std_logic_vector(1 downto 0) := "11"; -- error by default + m_axi_bresp : in std_logic_vector(1 downto 0); -- no default here (#1067) m_axi_bvalid : in std_logic := '0'; m_axi_bready : out std_logic; -- ------------------------------------------------------------ - -- AXI4-Stream-Compatible Interfaces (available if AXI4_STREAM_EN = true) + -- AXI4-Stream Interfaces (available if IO_SLINK_EN = true) -- ------------------------------------------------------------ -- Source -- -- s0_axis_aclk : in std_logic := '0'; -- just to satisfy Vivado, but not actually used @@ -256,6 +260,60 @@ architecture neorv32_vivado_ip_rtl of neorv32_vivado_ip is constant num_xirq_c : natural := cond_sel_natural_f(XIRQ_EN, XIRQ_NUM_CH, 0); constant num_pwm_c : natural := cond_sel_natural_f(IO_PWM_EN, IO_PWM_NUM_CH, 0); + -- AXI4-Lite bridge -- + component xbus2axi4lite_bridge + port ( + -- ------------------------------------------------------------ + -- Global Control + -- ------------------------------------------------------------ + clk : in std_logic; + resetn : in std_logic; -- low-active + -- ------------------------------------------------------------ + -- XBUS Device Interface + -- ------------------------------------------------------------ + xbus_adr_i : in std_ulogic_vector(31 downto 0); -- address + xbus_dat_i : in std_ulogic_vector(31 downto 0); -- write data + xbus_tag_i : in std_ulogic_vector(2 downto 0); -- access tag + xbus_we_i : in std_ulogic; -- read/write + xbus_sel_i : in std_ulogic_vector(3 downto 0); -- byte enable + xbus_stb_i : in std_ulogic; -- strobe + xbus_cyc_i : in std_ulogic; -- valid cycle + xbus_ack_o : out std_ulogic; -- transfer acknowledge + xbus_err_o : out std_ulogic; -- transfer error + xbus_dat_o : out std_ulogic_vector(31 downto 0); -- read data + -- ------------------------------------------------------------ + -- AXI4-Lite Host Interface + -- ------------------------------------------------------------ + -- Clock and Reset -- + -- m_axi_aclk : in std_logic; -- just to satisfy Vivado, but not actually used + -- m_axi_aresetn : in std_logic; -- just to satisfy Vivado, but not actually used + -- Write Address Channel -- + m_axi_awaddr : out std_logic_vector(31 downto 0); + m_axi_awprot : out std_logic_vector(2 downto 0); + m_axi_awvalid : out std_logic; + m_axi_awready : in std_logic; + -- Write Data Channel -- + m_axi_wdata : out std_logic_vector(31 downto 0); + m_axi_wstrb : out std_logic_vector(3 downto 0); + m_axi_wvalid : out std_logic; + m_axi_wready : in std_logic; + -- Read Address Channel -- + m_axi_araddr : out std_logic_vector(31 downto 0); + m_axi_arprot : out std_logic_vector(2 downto 0); + m_axi_arvalid : out std_logic; + m_axi_arready : in std_logic; + -- Read Data Channel -- + m_axi_rdata : in std_logic_vector(31 downto 0); + m_axi_rresp : in std_logic_vector(1 downto 0); + m_axi_rvalid : in std_logic; + m_axi_rready : out std_logic; + -- Write Response Channel -- + m_axi_bresp : in std_logic_vector(1 downto 0); + m_axi_bvalid : in std_logic; + m_axi_bready : out std_logic + ); + end component; + -- type conversion -- signal jtag_tdo_aux : std_ulogic; signal s0_axis_tdata_aux : std_ulogic_vector(31 downto 0); @@ -279,21 +337,16 @@ architecture neorv32_vivado_ip_rtl of neorv32_vivado_ip is signal xirq_i_aux : std_ulogic_vector(31 downto 0); -- internal wishbone bus -- - type wb_bus_t is record - adr : std_ulogic_vector(31 downto 0); - di : std_ulogic_vector(31 downto 0); - do : std_ulogic_vector(31 downto 0); - tag : std_ulogic_vector(2 downto 0); - we : std_ulogic; - sel : std_ulogic_vector(3 downto 0); - cyc : std_ulogic; - ack : std_ulogic; - err : std_ulogic; - end record; - signal wb_core : wb_bus_t; - - -- AXI bridge control -- - signal axi_radr_received, axi_wadr_received, axi_wdat_received : std_ulogic; + signal xbus_adr : std_ulogic_vector(31 downto 0); -- address + signal xbus_do : std_ulogic_vector(31 downto 0); -- write data + signal xbus_tag : std_ulogic_vector(2 downto 0); -- access tag + signal xbus_we : std_ulogic; -- read/write + signal xbus_sel : std_ulogic_vector(3 downto 0); -- byte enable + signal xbus_stb : std_ulogic; -- strobe + signal xbus_cyc : std_ulogic; -- valid cycle + signal xbus_di : std_ulogic_vector(31 downto 0); -- read data + signal xbus_ack : std_ulogic; -- transfer acknowledge + signal xbus_err : std_ulogic; -- transfer error begin @@ -301,12 +354,15 @@ begin -- ------------------------------------------------------------------------------------------- neorv32_top_inst: neorv32_top generic map ( - -- General -- + -- Clocking -- CLOCK_FREQUENCY => CLOCK_FREQUENCY, CLOCK_GATING_EN => false, -- clock gating is not supported here + -- Identification -- HART_ID => std_ulogic_vector(HART_ID), JEDEC_ID => std_ulogic_vector(JEDEC_ID), - INT_BOOTLOADER_EN => INT_BOOTLOADER_EN, + -- Boot Configuration -- + BOOT_MODE_SELECT => BOOT_MODE_SELECT, + BOOT_ADDR_CUSTOM => BOOT_ADDR_CUSTOM, -- On-Chip Debugger -- OCD_EN => OCD_EN, OCD_AUTHENTICATION => OCD_AUTHENTICATION, @@ -360,9 +416,9 @@ begin DCACHE_NUM_BLOCKS => DCACHE_NUM_BLOCKS, DCACHE_BLOCK_SIZE => DCACHE_BLOCK_SIZE, -- External bus interface -- - XBUS_EN => true, + XBUS_EN => XBUS_EN, XBUS_TIMEOUT => XBUS_TIMEOUT, - XBUS_REGSTAGE_EN => false, + XBUS_REGSTAGE_EN => XBUS_REGSTAGE_EN, XBUS_CACHE_EN => XBUS_CACHE_EN, XBUS_CACHE_NUM_BLOCKS => XBUS_CACHE_NUM_BLOCKS, XBUS_CACHE_BLOCK_SIZE => XBUS_CACHE_BLOCK_SIZE, @@ -374,6 +430,7 @@ begin -- External Interrupts Controller -- XIRQ_NUM_CH => num_xirq_c, -- Processor peripherals -- + IO_DISABLE_SYSINFO => false, IO_GPIO_NUM => num_gpio_c, IO_MTIME_EN => IO_MTIME_EN, IO_UART0_EN => IO_UART0_EN, @@ -401,7 +458,7 @@ begin IO_GPTMR_EN => IO_GPTMR_EN, IO_ONEWIRE_EN => IO_ONEWIRE_EN, IO_DMA_EN => IO_DMA_EN, - IO_SLINK_EN => AXI4_STREAM_EN, + IO_SLINK_EN => IO_SLINK_EN, IO_SLINK_RX_FIFO => IO_SLINK_RX_FIFO, IO_SLINK_TX_FIFO => IO_SLINK_TX_FIFO, IO_CRC_EN => IO_CRC_EN @@ -416,16 +473,16 @@ begin jtag_tdo_o => jtag_tdo_aux, jtag_tms_i => std_ulogic(jtag_tms_i), -- External bus interface (available if XBUS_EN = true) -- - xbus_adr_o => wb_core.adr, - xbus_dat_o => wb_core.do, - xbus_tag_o => wb_core.tag, - xbus_we_o => wb_core.we, - xbus_sel_o => wb_core.sel, - xbus_stb_o => open, - xbus_cyc_o => wb_core.cyc, - xbus_dat_i => wb_core.di, - xbus_ack_i => wb_core.ack, - xbus_err_i => wb_core.err, + xbus_adr_o => xbus_adr, + xbus_dat_o => xbus_do, + xbus_tag_o => xbus_tag, + xbus_we_o => xbus_we, + xbus_sel_o => xbus_sel, + xbus_stb_o => xbus_stb, + xbus_cyc_o => xbus_cyc, + xbus_dat_i => xbus_di, + xbus_ack_i => xbus_ack, + xbus_err_i => xbus_err, -- Stream Link Interface (available if IO_SLINK_EN = true) -- slink_rx_dat_i => std_ulogic_vector(s1_axis_tdata), slink_rx_src_i => std_ulogic_vector(s1_axis_tid), @@ -564,81 +621,56 @@ begin -- Wishbone-to-AXI4-Lite Bridge ----------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - axi_arbiter: process(resetn, clk) - begin - if (resetn = '0') then - axi_radr_received <= '0'; - axi_wadr_received <= '0'; - axi_wdat_received <= '0'; - elsif rising_edge(clk) then - if (wb_core.cyc = '0') then - axi_radr_received <= '0'; - axi_wadr_received <= '0'; - axi_wdat_received <= '0'; - else -- pending access - if (wb_core.we = '0') then -- read - if (m_axi_arready = '1') then -- read address received by interconnect? - axi_radr_received <= '1'; - end if; - else -- write - if (m_axi_awready = '1') then -- write address received by interconnect? - axi_wadr_received <= '1'; - end if; - if (m_axi_wready = '1') then -- write data received by interconnect? - axi_wdat_received <= '1'; - end if; - end if; - end if; - end if; - end process axi_arbiter; - - - -- read address channel -- - m_axi_araddr <= std_logic_vector(wb_core.adr); - m_axi_arprot <= std_logic_vector(wb_core.tag); - m_axi_arvalid <= std_logic(wb_core.cyc and (not wb_core.we) and (not axi_radr_received)); - - -- read data channel -- - m_axi_rready <= std_logic(wb_core.cyc and (not wb_core.we)); - wb_core.di <= std_ulogic_vector(m_axi_rdata); - - -- write address channel -- - m_axi_awaddr <= std_logic_vector(wb_core.adr); - m_axi_awprot <= std_logic_vector(wb_core.tag); - m_axi_awvalid <= std_logic(wb_core.cyc and wb_core.we and (not axi_wadr_received)); - - -- write data channel -- - m_axi_wdata <= std_logic_vector(wb_core.do); - m_axi_wstrb <= std_logic_vector(wb_core.sel); - m_axi_wvalid <= std_logic(wb_core.cyc and wb_core.we and (not axi_wdat_received)); - - -- write response channel -- - m_axi_bready <= std_logic(wb_core.cyc and wb_core.we); - - - -- read/write response -- - axi_response: process(wb_core, m_axi_bvalid, m_axi_bresp, m_axi_rvalid, m_axi_rresp) - begin - wb_core.ack <= '0'; -- default - wb_core.err <= '0'; -- default - if (wb_core.we = '1') then -- write operation - if (m_axi_bvalid = '1') then -- valid write response - if (m_axi_bresp = "00") then -- status check - wb_core.ack <= '1'; -- OK - else - wb_core.err <= '1'; -- ERROR - end if; - end if; - else -- read operation - if (m_axi_rvalid = '1') then -- valid read response - if (m_axi_rresp = "00") then -- status check - wb_core.ack <= '1'; -- OK - else - wb_core.err <= '1'; -- ERROR - end if; - end if; - end if; - end process axi_response; - + axi4_bridge: + if XBUS_EN generate + axi4_bridge_inst: xbus2axi4lite_bridge + port map ( + -- ------------------------------------------------------------ + -- Global Control + -- ------------------------------------------------------------ + clk => clk, + resetn => resetn, + -- ------------------------------------------------------------ + -- XBUS Device Interface + -- ------------------------------------------------------------ + xbus_adr_i => xbus_adr, + xbus_dat_i => xbus_do, + xbus_tag_i => xbus_tag, + xbus_we_i => xbus_we, + xbus_sel_i => xbus_sel, + xbus_stb_i => xbus_stb, + xbus_cyc_i => xbus_cyc, + xbus_ack_o => xbus_ack, + xbus_err_o => xbus_err, + xbus_dat_o => xbus_di, + -- ------------------------------------------------------------ + -- AXI4-Lite Host Interface + -- ------------------------------------------------------------ + -- Write Address Channel -- + m_axi_awaddr => m_axi_awaddr, + m_axi_awprot => m_axi_awprot, + m_axi_awvalid => m_axi_awvalid, + m_axi_awready => m_axi_awready, + -- Write Data Channel -- + m_axi_wdata => m_axi_wdata, + m_axi_wstrb => m_axi_wstrb, + m_axi_wvalid => m_axi_wvalid, + m_axi_wready => m_axi_wready, + -- Read Address Channel -- + m_axi_araddr => m_axi_araddr, + m_axi_arprot => m_axi_arprot, + m_axi_arvalid => m_axi_arvalid, + m_axi_arready => m_axi_arready, + -- Read Data Channel -- + m_axi_rdata => m_axi_rdata, + m_axi_rresp => m_axi_rresp, + m_axi_rvalid => m_axi_rvalid, + m_axi_rready => m_axi_rready, + -- Write Response Channel -- + m_axi_bresp => m_axi_bresp, + m_axi_bvalid => m_axi_bvalid, + m_axi_bready => m_axi_bready + ); + end generate; end architecture neorv32_vivado_ip_rtl; diff --git a/rtl/system_integration/xbus2ahblite_bridge.vhd b/rtl/system_integration/xbus2ahblite_bridge.vhd index 0287e8dde..b297fc583 100644 --- a/rtl/system_integration/xbus2ahblite_bridge.vhd +++ b/rtl/system_integration/xbus2ahblite_bridge.vhd @@ -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. -- diff --git a/rtl/system_integration/xbus2axi4lite_bridge.vhd b/rtl/system_integration/xbus2axi4lite_bridge.vhd new file mode 100644 index 000000000..e6ec8d72f --- /dev/null +++ b/rtl/system_integration/xbus2axi4lite_bridge.vhd @@ -0,0 +1,152 @@ +-- ================================================================================ -- +-- NEORV32 SoC - XBUS to AXI4-Lite Bridge (non-overlapping single transfers only) -- +-- -------------------------------------------------------------------------------- -- +-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 -- +-- Copyright (c) NEORV32 contributors. -- +-- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. -- +-- Licensed under the BSD-3-Clause license, see LICENSE for details. -- +-- SPDX-License-Identifier: BSD-3-Clause -- +-- ================================================================================ -- + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +entity xbus2axi4lite_bridge is + port ( + -- ------------------------------------------------------------ + -- Global Control + -- ------------------------------------------------------------ + clk : in std_logic; + resetn : in std_logic; -- low-active + -- ------------------------------------------------------------ + -- XBUS Device Interface + -- ------------------------------------------------------------ + xbus_adr_i : in std_ulogic_vector(31 downto 0); -- address + xbus_dat_i : in std_ulogic_vector(31 downto 0); -- write data + xbus_tag_i : in std_ulogic_vector(2 downto 0); -- access tag + xbus_we_i : in std_ulogic; -- read/write + xbus_sel_i : in std_ulogic_vector(3 downto 0); -- byte enable + xbus_stb_i : in std_ulogic; -- strobe + xbus_cyc_i : in std_ulogic; -- valid cycle + xbus_ack_o : out std_ulogic; -- transfer acknowledge + xbus_err_o : out std_ulogic; -- transfer error + xbus_dat_o : out std_ulogic_vector(31 downto 0); -- read data + -- ------------------------------------------------------------ + -- AXI4-Lite Host Interface + -- ------------------------------------------------------------ + -- Clock and Reset -- +-- m_axi_aclk : in std_logic; -- just to satisfy Vivado, but not actually used +-- m_axi_aresetn : in std_logic; -- just to satisfy Vivado, but not actually used + -- Write Address Channel -- + m_axi_awaddr : out std_logic_vector(31 downto 0); + m_axi_awprot : out std_logic_vector(2 downto 0); + m_axi_awvalid : out std_logic; + m_axi_awready : in std_logic; + -- Write Data Channel -- + m_axi_wdata : out std_logic_vector(31 downto 0); + m_axi_wstrb : out std_logic_vector(3 downto 0); + m_axi_wvalid : out std_logic; + m_axi_wready : in std_logic; + -- Read Address Channel -- + m_axi_araddr : out std_logic_vector(31 downto 0); + m_axi_arprot : out std_logic_vector(2 downto 0); + m_axi_arvalid : out std_logic; + m_axi_arready : in std_logic; + -- Read Data Channel -- + m_axi_rdata : in std_logic_vector(31 downto 0); + m_axi_rresp : in std_logic_vector(1 downto 0); + m_axi_rvalid : in std_logic; + m_axi_rready : out std_logic; + -- Write Response Channel -- + m_axi_bresp : in std_logic_vector(1 downto 0); + m_axi_bvalid : in std_logic; + m_axi_bready : out std_logic + ); +end entity; + +architecture xbus2axi4lite_bridge_rtl of xbus2axi4lite_bridge is + + -- AXI bridge control -- + signal axi_radr_received, axi_wadr_received, axi_wdat_received : std_ulogic; + +begin + + -- channel arbiter -- + axi_arbiter: process(resetn, clk) + begin + if (resetn = '0') then + axi_radr_received <= '0'; + axi_wadr_received <= '0'; + axi_wdat_received <= '0'; + elsif rising_edge(clk) then + if (xbus_cyc_i = '0') then + axi_radr_received <= '0'; + axi_wadr_received <= '0'; + axi_wdat_received <= '0'; + else -- pending access + if (xbus_we_i = '0') then -- read + if (m_axi_arready = '1') then -- read address received by interconnect? + axi_radr_received <= '1'; + end if; + else -- write + if (m_axi_awready = '1') then -- write address received by interconnect? + axi_wadr_received <= '1'; + end if; + if (m_axi_wready = '1') then -- write data received by interconnect? + axi_wdat_received <= '1'; + end if; + end if; + end if; + end if; + end process axi_arbiter; + + + -- read address channel -- + m_axi_araddr <= std_logic_vector(xbus_adr_i); + m_axi_arprot <= std_logic_vector(xbus_tag_i); + m_axi_arvalid <= std_logic(xbus_cyc_i and (not xbus_we_i) and (not axi_radr_received)); + + -- read data channel -- + m_axi_rready <= std_logic(xbus_cyc_i and (not xbus_we_i)); + xbus_dat_o <= std_ulogic_vector(m_axi_rdata); + + -- write address channel -- + m_axi_awaddr <= std_logic_vector(xbus_adr_i); + m_axi_awprot <= std_logic_vector(xbus_tag_i); + m_axi_awvalid <= std_logic(xbus_cyc_i and xbus_we_i and (not axi_wadr_received)); + + -- write data channel -- + m_axi_wdata <= std_logic_vector(xbus_dat_i); + m_axi_wstrb <= std_logic_vector(xbus_sel_i); + m_axi_wvalid <= std_logic(xbus_cyc_i and xbus_we_i and (not axi_wdat_received)); + + -- write response channel -- + m_axi_bready <= std_logic(xbus_cyc_i and xbus_we_i); + + + -- read/write response -- + axi_response: process(xbus_we_i, m_axi_bvalid, m_axi_bresp, m_axi_rvalid, m_axi_rresp) + begin + xbus_ack_o <= '0'; -- default + xbus_err_o <= '0'; -- default + if (xbus_we_i = '1') then -- write operation + if (m_axi_bvalid = '1') then -- valid write response + if (m_axi_bresp = "00") then -- status check + xbus_ack_o <= '1'; -- OK + else + xbus_err_o <= '1'; -- ERROR + end if; + end if; + else -- read operation + if (m_axi_rvalid = '1') then -- valid read response + if (m_axi_rresp = "00") then -- status check + xbus_ack_o <= '1'; -- OK + else + xbus_err_o <= '1'; -- ERROR + end if; + end if; + end if; + end process axi_response; + +end architecture xbus2axi4lite_bridge_rtl; diff --git a/rtl/test_setups/neorv32_test_setup_approm.vhd b/rtl/test_setups/neorv32_test_setup_approm.vhd index 8e6cfad6d..a1d965a0a 100644 --- a/rtl/test_setups/neorv32_test_setup_approm.vhd +++ b/rtl/test_setups/neorv32_test_setup_approm.vhd @@ -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? diff --git a/rtl/test_setups/neorv32_test_setup_bootloader.vhd b/rtl/test_setups/neorv32_test_setup_bootloader.vhd index 9407d3b25..9506d41dc 100644 --- a/rtl/test_setups/neorv32_test_setup_bootloader.vhd +++ b/rtl/test_setups/neorv32_test_setup_bootloader.vhd @@ -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? diff --git a/rtl/test_setups/neorv32_test_setup_on_chip_debugger.vhd b/rtl/test_setups/neorv32_test_setup_on_chip_debugger.vhd index 8bf4c2999..dd26836a2 100644 --- a/rtl/test_setups/neorv32_test_setup_on_chip_debugger.vhd +++ b/rtl/test_setups/neorv32_test_setup_on_chip_debugger.vhd @@ -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 -- diff --git a/sim/README.md b/sim/README.md deleted file mode 100644 index ea6f243fb..000000000 --- a/sim/README.md +++ /dev/null @@ -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) diff --git a/sim/simple/ghdl.run.sh b/sim/ghdl.run.sh old mode 100755 new mode 100644 similarity index 88% rename from sim/simple/ghdl.run.sh rename to sim/ghdl.run.sh index 0301d2589..09da93f43 --- a/sim/simple/ghdl.run.sh +++ b/sim/ghdl.run.sh @@ -20,7 +20,7 @@ done GHDL="${GHDL:-ghdl}" -$GHDL -m --work=neorv32 --workdir=build neorv32_tb_simple +$GHDL -m --work=neorv32 --workdir=build neorv32_tb if [ -z "$1" ] then @@ -32,7 +32,7 @@ fi echo "Using simulation run arguments: $GHDL_RUN_ARGS"; -runcmd="$GHDL -r --work=neorv32 --workdir=build neorv32_tb_simple \ +runcmd="$GHDL -r --work=neorv32 --workdir=build neorv32_tb \ --max-stack-alloc=0 \ --ieee-asserts=disable \ --assert-level=error $GHDL_RUN_ARGS" diff --git a/sim/simple/ghdl.setup.sh b/sim/ghdl.setup.sh old mode 100755 new mode 100644 similarity index 80% rename from sim/simple/ghdl.setup.sh rename to sim/ghdl.setup.sh index bdf13627b..af162a09a --- a/sim/simple/ghdl.setup.sh +++ b/sim/ghdl.setup.sh @@ -4,7 +4,7 @@ set -e cd $(dirname "$0") -NEORV32_LOCAL_RTL=${NEORV32_LOCAL_RTL:-../../rtl} +NEORV32_LOCAL_RTL=${NEORV32_LOCAL_RTL:-../rtl} FILE_LIST=`cat $NEORV32_LOCAL_RTL/file_list_soc.f` CORE_SRCS="${FILE_LIST//NEORV32_RTL_PATH_PLACEHOLDER/"$NEORV32_LOCAL_RTL"}" @@ -16,5 +16,5 @@ ghdl -i --work=neorv32 --workdir=build \ "$NEORV32_LOCAL_RTL"/processor_templates/*.vhd \ "$NEORV32_LOCAL_RTL"/system_integration/*.vhd \ "$NEORV32_LOCAL_RTL"/test_setups/*.vhd \ - neorv32_tb.simple.vhd \ - uart_rx.simple.vhd + neorv32_tb.vhd \ + uart_rx.vhd diff --git a/sim/ghdl.sh b/sim/ghdl.sh new file mode 100644 index 000000000..33223f9a7 --- /dev/null +++ b/sim/ghdl.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +# Abort if any command returns != 0 +set -e + +cd $(dirname "$0") + +# Setup simulation +/bin/bash ghdl.setup.sh + +# Run simulation (pass down more than 1 parameter to GHDL) +/bin/bash ghdl.run.sh $@ diff --git a/sim/neorv32_tb.vhd b/sim/neorv32_tb.vhd index 1df4e6e5b..bc15070e8 100644 --- a/sim/neorv32_tb.vhd +++ b/sim/neorv32_tb.vhd @@ -1,5 +1,5 @@ -- ================================================================================ -- --- NEORV32 - VUnit Processor Testbench -- +-- NEORV32 - Default Processor Testbench -- -- -------------------------------------------------------------------------------- -- -- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 -- -- Copyright (c) NEORV32 contributors. -- @@ -8,11 +8,6 @@ -- SPDX-License-Identifier: BSD-3-Clause -- -- ================================================================================ -- -library vunit_lib; -context vunit_lib.vunit_context; -context vunit_lib.com_context; -context vunit_lib.vc_context; - library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; @@ -24,33 +19,55 @@ use neorv32.neorv32_application_image.all; -- this file is generated by the imag use std.textio.all; -library osvvm; -use osvvm.RandomPkg.all; - -use work.uart_rx_pkg.all; - entity neorv32_tb is - generic (runner_cfg : string := runner_cfg_default; - ci_mode : boolean := false); + generic ( + PERFORMANCE_OPTION : natural := 0 -- Set core options for performance measurements + ); end neorv32_tb; architecture neorv32_tb_rtl of neorv32_tb is + -- advanced configuration -- + constant num_configs_c : natural := 3; -- number of pre-defined configurations + + -- helpers -- + type bool_t is array (0 to num_configs_c-1) of boolean; + type natural_t is array (0 to num_configs_c-1) of natural; + type performance_options_type_t is record + fast_mul_en_c : bool_t; + fast_shift_en_c : bool_t; + imem_size_c : natural_t; + icache_en_c : bool_t; + icache_block_size_c : natural_t; + dcache_en_c : bool_t; + dcache_block_size_c : natural_t; + end record; + + -- User Configuration --------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- + -- core performance options -- + constant performance_options_c : performance_options_type_t := ( + -- default fast core area core + fast_mul_en_c => ( true, true, false), -- Fast multiplication, more area + fast_shift_en_c => ( true, true, false), -- Fast shifting, more area + imem_size_c => ( 32*1024, 128*1024, 128*1024), -- Instruction memory size min. 128kB for performance tests + icache_en_c => ( true, false, false), -- I$ disabled for performance tests + icache_block_size_c => ( 32, 32, 32), -- I$ block size + dcache_en_c => ( true, false, false), -- D$ disabled for performance tests + dcache_block_size_c => ( 32, 32, 32) -- D$ block size + ); + -- general -- - constant int_imem_c : boolean := false; -- true: use proc-internal IMEM, false: use external simulated IMEM (ext. mem A) - constant int_dmem_c : boolean := false; -- true: use proc-internal DMEM, false: use external simulated DMEM (ext. mem B) - constant imem_size_c : natural := 32*1024; -- size in bytes of processor-internal IMEM / external mem A + constant int_imem_c : boolean := true; -- true: use proc-internal IMEM, false: use external simulated IMEM (ext. mem A) + constant int_dmem_c : boolean := true; -- true: use proc-internal DMEM, false: use external simulated DMEM (ext. mem B) constant dmem_size_c : natural := 8*1024; -- size in bytes of processor-internal DMEM / external mem B constant f_clock_c : natural := 100000000; -- main clock in Hz constant baud0_rate_c : natural := 19200; -- simulation UART0 (primary UART) baud rate constant baud1_rate_c : natural := 19200; -- simulation UART1 (secondary UART) baud rate - constant icache_en_c : boolean := false; -- implement i-cache - constant icache_block_size_c : natural := 64; -- i-cache block size in bytes -- simulated external Wishbone memory A (can be used as external IMEM) -- constant ext_mem_a_base_addr_c : std_ulogic_vector(31 downto 0) := x"00000000"; -- wishbone memory base address (external IMEM base) - constant ext_mem_a_size_c : natural := imem_size_c; -- wishbone memory size in bytes + constant ext_mem_a_size_c : natural := performance_options_c.imem_size_c(PERFORMANCE_OPTION); -- wishbone memory size in bytes constant ext_mem_a_latency_c : natural := 8; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay -- simulated external Wishbone memory B (can be used as external DMEM) -- constant ext_mem_b_base_addr_c : std_ulogic_vector(31 downto 0) := x"80000000"; -- wishbone memory base address (external DMEM base) @@ -58,7 +75,7 @@ architecture neorv32_tb_rtl of neorv32_tb is constant ext_mem_b_latency_c : natural := 8; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay -- simulated external Wishbone memory C (can be used to simulate external IO access) -- constant ext_mem_c_base_addr_c : std_ulogic_vector(31 downto 0) := x"F0000000"; -- wishbone memory base address (default begin of EXTERNAL IO area) - constant ext_mem_c_size_c : natural := icache_block_size_c/2; -- wishbone memory size in bytes, should be smaller than an iCACHE block + constant ext_mem_c_size_c : natural := performance_options_c.icache_block_size_c(PERFORMANCE_OPTION)/2; -- wishbone memory size in bytes, should be smaller than an iCACHE block constant ext_mem_c_latency_c : natural := 128; -- latency in clock cycles (min 1, max 255), plus 1 cycle initial delay -- simulation interrupt trigger -- constant irq_trigger_base_addr_c : std_ulogic_vector(31 downto 0) := x"FF000000"; @@ -72,6 +89,9 @@ architecture neorv32_tb_rtl of neorv32_tb is -- generators -- signal clk_gen, rst_gen : std_ulogic := '0'; + -- text.io -- + file file_uart0_tx_out : text open write_mode is "neorv32.testbench_uart0.out"; + -- uart -- signal uart0_txd, uart1_txd : std_ulogic; signal uart0_cts, uart1_cts : std_ulogic; @@ -131,55 +151,7 @@ architecture neorv32_tb_rtl of neorv32_tb is end record; signal ext_mem_a, ext_mem_b, ext_mem_c : ext_mem_t; - constant uart0_rx_logger : logger_t := get_logger("UART0.RX"); - constant uart1_rx_logger : logger_t := get_logger("UART1.RX"); - constant uart0_rx_handle : uart_rx_t := new_uart_rx(uart0_baud_val_c, uart0_rx_logger); - constant uart1_rx_handle : uart_rx_t := new_uart_rx(uart1_baud_val_c, uart1_rx_logger); - begin - test_runner : process - variable msg : msg_t; - variable rnd : RandomPType; - begin - test_runner_setup(runner, runner_cfg); - - rnd.InitSeed(test_runner'path_name); - - -- Show passing checks for UART0 on the display (stdout) - show(uart0_rx_logger, display_handler, pass); - show(uart1_rx_logger, display_handler, pass); - - if ci_mode then - check_uart(net, uart0_rx_handle, nul & nul); - else - check_uart(net, uart0_rx_handle, "Blinking LED demo program" & cr & lf); - end if; - - if ci_mode then - -- No need to send the full expectation in one big chunk - check_uart(net, uart1_rx_handle, nul & nul); - check_uart(net, uart1_rx_handle, "0/56" & cr & lf); - end if; - - -- Wait until all expected data has been received - -- - -- wait_until_idle can take the VC actor as argument but - -- the more abstract view is that wait_until_idle is part - -- of the sync VCI and to use it a VC must be cast - -- to a sync VC - wait_until_idle(net, as_sync(uart0_rx_handle)); - wait_until_idle(net, as_sync(uart1_rx_handle)); - - -- Wait a bit more if some extra unexpected data is produced. If so, - -- uart_rx will fail - wait for (20 * (1e9 / baud0_rate_c)) * ns; - - test_runner_cleanup(runner); - end process; - - -- In case we get stuck waiting there is a watchdog timeout to terminate and fail the - -- testbench - test_runner_watchdog(runner, 50 ms); -- Clock/Reset Generator ------------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- @@ -191,189 +163,196 @@ begin -- ------------------------------------------------------------------------------------------- neorv32_top_inst: neorv32_top generic map ( - -- General -- - CLOCK_FREQUENCY => f_clock_c, -- clock frequency of clk_i in Hz - CLOCK_GATING_EN => true, -- enable clock gating when in sleep mode - HART_ID => x"00000000", -- hardware thread ID - JEDEC_ID => "00000000000", -- vendor's JEDEC ID - INT_BOOTLOADER_EN => false, -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM + -- Clocking -- + CLOCK_FREQUENCY => f_clock_c, + CLOCK_GATING_EN => true, + -- Identification -- + HART_ID => x"00000000", + JEDEC_ID => "00000000000", + -- Boot Configuration -- + BOOT_MODE_SELECT => 2, -- boot from pre-initialized internal IMEM + BOOT_ADDR_CUSTOM => x"00000000", -- On-Chip Debugger (OCD) -- - OCD_EN => true, -- implement on-chip debugger - OCD_AUTHENTICATION => true, -- implement on-chip debugger authentication + OCD_EN => true, + OCD_AUTHENTICATION => true, -- RISC-V CPU Extensions -- - RISCV_ISA_C => true, -- implement compressed extension? - RISCV_ISA_E => false, -- implement embedded RF extension? - RISCV_ISA_M => true, -- implement mul/div extension? - RISCV_ISA_U => true, -- implement user mode extension? - RISCV_ISA_Zalrsc => true, -- implement atomic reservation-set extension - RISCV_ISA_Zba => true, -- implement shifted-add bit-manipulation extension - RISCV_ISA_Zbb => true, -- implement basic bit-manipulation extension - RISCV_ISA_Zbkb => true, -- implement bit-manipulation instructions for cryptography - RISCV_ISA_Zbkc => true, -- implement carry-less multiplication instructions? - RISCV_ISA_Zbkx => true, -- implement cryptography crossbar permutation extension? - RISCV_ISA_Zbs => true, -- implement single-bit bit-manipulation extension - RISCV_ISA_Zfinx => true, -- implement 32-bit floating-point extension (using INT reg!) - RISCV_ISA_Zicntr => true, -- implement base counters? - RISCV_ISA_Zicond => true, -- implement integer conditional operations? - RISCV_ISA_Zihpm => true, -- implement hardware performance monitors? - RISCV_ISA_Zknd => true, -- implement cryptography NIST AES decryption extension? - RISCV_ISA_Zkne => true, -- implement cryptography NIST AES encryption extension? - RISCV_ISA_Zknh => true, -- implement cryptography NIST hash extension? - RISCV_ISA_Zksed => true, -- implement ShangMi block cypher extension? - RISCV_ISA_Zksh => true, -- implement ShangMi hash extension? - RISCV_ISA_Zmmul => false, -- implement multiply-only M sub-extension? - RISCV_ISA_Zxcfu => true, -- implement custom (instr.) functions unit? + RISCV_ISA_C => false, + RISCV_ISA_E => false, + RISCV_ISA_M => true, + RISCV_ISA_U => true, + RISCV_ISA_Zalrsc => true, + RISCV_ISA_Zba => true, + RISCV_ISA_Zbb => true, + RISCV_ISA_Zbkb => true, + RISCV_ISA_Zbkc => true, + RISCV_ISA_Zbkx => true, + RISCV_ISA_Zbs => true, + RISCV_ISA_Zfinx => true, + RISCV_ISA_Zicntr => true, + RISCV_ISA_Zicond => true, + RISCV_ISA_Zihpm => true, + RISCV_ISA_Zknd => true, + RISCV_ISA_Zkne => true, + RISCV_ISA_Zknh => true, + RISCV_ISA_Zksed => true, + RISCV_ISA_Zksh => true, + RISCV_ISA_Zmmul => false, + RISCV_ISA_Zxcfu => true, -- Extension Options -- - FAST_MUL_EN => false, -- use DSPs for M extension's multiplier - FAST_SHIFT_EN => false, -- use barrel shifter for shift operations - REGFILE_HW_RST => true, -- full hardware reset + FAST_MUL_EN => performance_options_c.fast_mul_en_c(PERFORMANCE_OPTION), + FAST_SHIFT_EN => performance_options_c.fast_shift_en_c(PERFORMANCE_OPTION), + REGFILE_HW_RST => false, -- Physical Memory Protection (PMP) -- - PMP_NUM_REGIONS => 5, -- number of regions (0..16) - PMP_MIN_GRANULARITY => 4, -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes - PMP_TOR_MODE_EN => true, -- implement TOR mode - PMP_NAP_MODE_EN => true, -- implement NAPOT/NA4 mode + PMP_NUM_REGIONS => 5, + PMP_MIN_GRANULARITY => 4, + PMP_TOR_MODE_EN => true, + PMP_NAP_MODE_EN => true, -- Hardware Performance Monitors (HPM) -- - HPM_NUM_CNTS => 12, -- number of implemented HPM counters (0..29) - HPM_CNT_WIDTH => 40, -- total size of HPM counters (0..64) + HPM_NUM_CNTS => 12, + HPM_CNT_WIDTH => 40, -- Internal Instruction memory -- - MEM_INT_IMEM_EN => int_imem_c , -- implement processor-internal instruction memory - MEM_INT_IMEM_SIZE => imem_size_c, -- size of processor-internal instruction memory in bytes + MEM_INT_IMEM_EN => int_imem_c , + MEM_INT_IMEM_SIZE => performance_options_c.imem_size_c(PERFORMANCE_OPTION), -- Internal Data memory -- - MEM_INT_DMEM_EN => int_dmem_c, -- implement processor-internal data memory - MEM_INT_DMEM_SIZE => dmem_size_c, -- size of processor-internal data memory in bytes + MEM_INT_DMEM_EN => int_dmem_c, + MEM_INT_DMEM_SIZE => dmem_size_c, -- Internal Cache memory -- - ICACHE_EN => false, -- implement instruction cache + ICACHE_EN => performance_options_c.icache_en_c(PERFORMANCE_OPTION), + ICACHE_NUM_BLOCKS => 64, + ICACHE_BLOCK_SIZE => performance_options_c.icache_block_size_c(PERFORMANCE_OPTION), -- Internal Data Cache (dCACHE) -- - DCACHE_EN => false, -- implement data cache + DCACHE_EN => performance_options_c.dcache_en_c(PERFORMANCE_OPTION), + DCACHE_NUM_BLOCKS => 32, + DCACHE_BLOCK_SIZE => performance_options_c.dcache_block_size_c(PERFORMANCE_OPTION), -- External bus interface -- - XBUS_EN => true, -- implement external memory bus interface? - XBUS_TIMEOUT => 256, -- cycles after a pending bus access auto-terminates (0 = disabled) - XBUS_REGSTAGE_EN => false, -- add register stage - XBUS_CACHE_EN => true, -- enable external bus cache (x-cache) - XBUS_CACHE_NUM_BLOCKS => 64, -- x-cache: number of blocks (min 1), has to be a power of 2 - XBUS_CACHE_BLOCK_SIZE => 32, -- x-cache: block size in bytes (min 4), has to be a power of 2 + XBUS_EN => true, + XBUS_TIMEOUT => 256, + XBUS_REGSTAGE_EN => true, + XBUS_CACHE_EN => true, + XBUS_CACHE_NUM_BLOCKS => 4, + XBUS_CACHE_BLOCK_SIZE => 32, -- Execute in-place module (XIP) -- - XIP_EN => true, -- implement execute in place module (XIP)? - XIP_CACHE_EN => true, -- implement XIP cache? - XIP_CACHE_NUM_BLOCKS => 4, -- number of blocks (min 1), has to be a power of 2 - XIP_CACHE_BLOCK_SIZE => 256, -- block size in bytes (min 4), has to be a power of 2 + XIP_EN => true, + XIP_CACHE_EN => true, + XIP_CACHE_NUM_BLOCKS => 4, + XIP_CACHE_BLOCK_SIZE => 256, -- External Interrupts Controller (XIRQ) -- - XIRQ_NUM_CH => 32, -- number of external IRQ channels (0..32) + XIRQ_NUM_CH => 32, -- Processor peripherals -- - IO_GPIO_NUM => 64, -- number of GPIO input/output pairs (0..64) - IO_MTIME_EN => true, -- implement machine system timer (MTIME)? - IO_UART0_EN => true, -- implement primary universal asynchronous receiver/transmitter (UART0)? - IO_UART0_RX_FIFO => 32, -- RX fifo depth, has to be a power of two, min 1 - IO_UART0_TX_FIFO => 32, -- TX fifo depth, has to be a power of two, min 1 - IO_UART1_EN => true, -- implement secondary universal asynchronous receiver/transmitter (UART1)? - IO_UART1_RX_FIFO => 1, -- RX fifo depth, has to be a power of two, min 1 - IO_UART1_TX_FIFO => 1, -- TX fifo depth, has to be a power of two, min 1 - IO_SPI_EN => true, -- implement serial peripheral interface (SPI)? - IO_SPI_FIFO => 4, -- SPI RTX fifo depth, has to be zero or a power of two - IO_SDI_EN => true, -- implement serial data interface (SDI)? - IO_SDI_FIFO => 4, -- SDI RTX fifo depth, has to be zero or a power of two - IO_TWI_EN => true, -- implement two-wire interface (TWI)? - IO_TWI_FIFO => 4, -- RTX fifo depth, has to be zero or a power of two, min 1 - IO_PWM_NUM_CH => 8, -- number of PWM channels to implement (0..16) - IO_WDT_EN => true, -- implement watch dog timer (WDT)? - IO_TRNG_EN => true, -- implement true random number generator (TRNG)? - IO_TRNG_FIFO => 4, -- TRNG fifo depth, has to be a power of two, min 1 - IO_CFS_EN => true, -- implement custom functions subsystem (CFS)? - IO_CFS_CONFIG => (others => '0'), -- custom CFS configuration generic - IO_CFS_IN_SIZE => 32, -- size of CFS input conduit in bits - IO_CFS_OUT_SIZE => 32, -- size of CFS output conduit in bits - IO_NEOLED_EN => true, -- implement NeoPixel-compatible smart LED interface (NEOLED)? - IO_NEOLED_TX_FIFO => 8, -- NEOLED TX FIFO depth, 1..32k, has to be a power of two - IO_GPTMR_EN => true, -- implement general purpose timer (GPTMR)? - IO_ONEWIRE_EN => true, -- implement 1-wire interface (ONEWIRE)? - IO_DMA_EN => true, -- implement direct memory access controller (DMA)? - IO_SLINK_EN => true, -- implement stream link interface (SLINK)? - IO_SLINK_RX_FIFO => 4, -- RX fifo depth, has to be a power of two, min 1 - IO_SLINK_TX_FIFO => 4, -- TX fifo depth, has to be a power of two, min 1 - IO_CRC_EN => true -- implement cyclic redundancy check unit (CRC)? + IO_GPIO_NUM => 64, + IO_MTIME_EN => true, + IO_UART0_EN => true, + IO_UART0_RX_FIFO => 32, + IO_UART0_TX_FIFO => 32, + IO_UART1_EN => true, + IO_UART1_RX_FIFO => 1, + IO_UART1_TX_FIFO => 1, + IO_SPI_EN => true, + IO_SPI_FIFO => 4, + IO_SDI_EN => true, + IO_SDI_FIFO => 4, + IO_TWI_EN => true, + IO_TWI_FIFO => 4, + IO_PWM_NUM_CH => 8, + IO_WDT_EN => true, + IO_TRNG_EN => true, + IO_TRNG_FIFO => 4, + IO_CFS_EN => true, + IO_CFS_CONFIG => (others => '0'), + IO_CFS_IN_SIZE => 32, + IO_CFS_OUT_SIZE => 32, + IO_NEOLED_EN => true, + IO_NEOLED_TX_FIFO => 8, + IO_GPTMR_EN => true, + IO_ONEWIRE_EN => true, + IO_DMA_EN => true, + IO_SLINK_EN => true, + IO_SLINK_RX_FIFO => 4, + IO_SLINK_TX_FIFO => 4, + IO_CRC_EN => true ) port map ( -- Global control -- - clk_i => clk_gen, -- global clock, rising edge - rstn_i => rst_gen, -- global reset, low-active, async + clk_i => clk_gen, + rstn_i => rst_gen, -- JTAG on-chip debugger interface (available if OCD_EN = true) -- - jtag_tck_i => '0', -- serial clock - jtag_tdi_i => '0', -- serial data input - jtag_tdo_o => open, -- serial data output - jtag_tms_i => '0', -- mode select + jtag_tck_i => '0', + jtag_tdi_i => '0', + jtag_tdo_o => open, + jtag_tms_i => '0', -- External bus interface (available if XBUS_EN = true) -- - xbus_adr_o => wb_cpu.addr, -- address - xbus_dat_o => wb_cpu.wdata, -- write data - xbus_tag_o => wb_cpu.tag, -- access tag - xbus_we_o => wb_cpu.we, -- read/write - xbus_sel_o => wb_cpu.sel, -- byte enable - xbus_stb_o => wb_cpu.stb, -- strobe - xbus_cyc_o => wb_cpu.cyc, -- valid cycle - xbus_dat_i => wb_cpu.rdata, -- read data - xbus_ack_i => wb_cpu.ack, -- transfer acknowledge - xbus_err_i => wb_cpu.err, -- transfer error + xbus_adr_o => wb_cpu.addr, + xbus_dat_o => wb_cpu.wdata, + xbus_tag_o => wb_cpu.tag, + xbus_we_o => wb_cpu.we, + xbus_sel_o => wb_cpu.sel, + xbus_stb_o => wb_cpu.stb, + xbus_cyc_o => wb_cpu.cyc, + xbus_dat_i => wb_cpu.rdata, + xbus_ack_i => wb_cpu.ack, + xbus_err_i => wb_cpu.err, -- Stream Link Interface (available if IO_SLINK_EN = true) -- - slink_rx_dat_i => slink_dat, -- RX input data - slink_rx_src_i => slink_id, -- RX source routing information - slink_rx_val_i => slink_val, -- RX valid input - slink_rx_lst_i => slink_lst, -- RX last element of stream - slink_rx_rdy_o => slink_rdy, -- RX ready to receive - slink_tx_dat_o => slink_dat, -- TX output data - slink_tx_dst_o => slink_id, -- TX destination routing information - slink_tx_val_o => slink_val, -- TX valid output - slink_tx_lst_o => slink_lst, -- TX last element of stream - slink_tx_rdy_i => slink_rdy, -- TX ready to send + slink_rx_dat_i => slink_dat, + slink_rx_src_i => slink_id, + slink_rx_val_i => slink_val, + slink_rx_lst_i => slink_lst, + slink_rx_rdy_o => slink_rdy, + slink_tx_dat_o => slink_dat, + slink_tx_dst_o => slink_id, + slink_tx_val_o => slink_val, + slink_tx_lst_o => slink_lst, + slink_tx_rdy_i => slink_rdy, -- XIP (execute in place via SPI) signals (available if XIP_EN = true) -- - xip_csn_o => open, -- chip-select, low-active - xip_clk_o => open, -- serial clock - xip_dat_i => '1', -- device data input - xip_dat_o => open, -- controller data output - -- GPIO (available if IO_GPIO_NUM > 0) -- - gpio_o => gpio, -- parallel output - gpio_i => gpio, -- parallel input + xip_csn_o => open, + xip_clk_o => open, + xip_dat_i => '0', + xip_dat_o => open, + -- GPIO (available if IO_GPIO_NUM > true) -- + gpio_o => gpio, + gpio_i => gpio, -- primary UART0 (available if IO_UART0_EN = true) -- - uart0_txd_o => uart0_txd, -- UART0 send data - uart0_rxd_i => uart0_txd, -- UART0 receive data - uart0_rts_o => uart1_cts, -- HW flow control: UART0.RX ready to receive ("RTR"), low-active, optional - uart0_cts_i => uart0_cts, -- HW flow control: UART0.TX allowed to transmit, low-active, optional + uart0_txd_o => uart0_txd, + uart0_rxd_i => uart0_txd, + uart0_rts_o => uart1_cts, + uart0_cts_i => uart0_cts, -- secondary UART1 (available if IO_UART1_EN = true) -- - uart1_txd_o => uart1_txd, -- UART1 send data - uart1_rxd_i => uart1_txd, -- UART1 receive data - uart1_rts_o => uart0_cts, -- HW flow control: UART0.RX ready to receive ("RTR"), low-active, optional - uart1_cts_i => uart1_cts, -- HW flow control: UART0.TX allowed to transmit, low-active, optional + uart1_txd_o => uart1_txd, + uart1_rxd_i => uart1_txd, + uart1_rts_o => uart0_cts, + uart1_cts_i => uart1_cts, -- SPI (available if IO_SPI_EN = true) -- - spi_clk_o => spi_clk, -- SPI serial clock - spi_dat_o => spi_do, -- controller data out, peripheral data in - spi_dat_i => spi_di, -- controller data in, peripheral data out - spi_csn_o => spi_csn, -- SPI CS + spi_clk_o => spi_clk, + spi_dat_o => spi_do, + spi_dat_i => spi_di, + spi_csn_o => spi_csn, -- SDI (available if IO_SDI_EN = true) -- - sdi_clk_i => sdi_clk, -- SDI serial clock - sdi_dat_o => sdi_do, -- controller data out, peripheral data in - sdi_dat_i => sdi_di, -- controller data in, peripheral data out - sdi_csn_i => sdi_csn, -- chip-select + sdi_clk_i => sdi_clk, + sdi_dat_o => sdi_do, + sdi_dat_i => sdi_di, + sdi_csn_i => sdi_csn, -- TWI (available if IO_TWI_EN = true) -- - twi_sda_i => twi_sda_i, -- serial data line sense input - twi_sda_o => twi_sda_o, -- serial data line output (pull low only) - twi_scl_i => twi_scl_i, -- serial clock line sense input - twi_scl_o => twi_scl_o, -- serial clock line output (pull low only) + twi_sda_i => twi_sda_i, + twi_sda_o => twi_sda_o, + twi_scl_i => twi_scl_i, + twi_scl_o => twi_scl_o, -- 1-Wire Interface (available if IO_ONEWIRE_EN = true) -- - onewire_i => onewire_i, -- 1-wire bus sense input - onewire_o => onewire_o, -- 1-wire bus output (pull low only) + onewire_i => onewire_i, + onewire_o => onewire_o, -- PWM (available if IO_PWM_NUM_CH > 0) -- - pwm_o => open, -- pwm channels + pwm_o => open, -- Custom Functions Subsystem IO -- - cfs_in_i => (others => '0'), -- custom CFS inputs - cfs_out_o => open, -- custom CFS outputs + cfs_in_i => (others => '0'), + cfs_out_o => open, -- NeoPixel-compatible smart LED interface (available if IO_NEOLED_EN = true) -- - neoled_o => open, -- async serial data line + neoled_o => open, -- Machine timer system time (available if IO_MTIME_EN = true) -- mtime_time_o => open, -- External platform interrupts (available if XIRQ_NUM_CH > 0) -- - xirq_i => gpio(31 downto 0), -- IRQ channels + xirq_i => gpio(31 downto 0), -- CPU Interrupts -- - mtime_irq_i => '0', -- machine software interrupt, available if IO_MTIME_EN = false - msw_irq_i => msi_ring, -- machine software interrupt - mext_irq_i => mei_ring -- machine external interrupt + mtime_irq_i => '0', + msw_irq_i => msi_ring, + mext_irq_i => mei_ring ); -- TWI tri-state driver -- @@ -399,17 +378,28 @@ begin sdi_di <= spi_do after 40 ns; spi_di <= sdi_do when (spi_csn(7) = '0') else spi_do after 40 ns; + + -- UART Simulation Receiver --------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- uart0_checker: entity work.uart_rx - generic map (uart0_rx_handle) - port map ( - clk => clk_gen, - uart_txd => uart0_txd); + generic map ( + name => "uart0", + uart_baud_val_c => uart0_baud_val_c + ) + port map ( + clk => clk_gen, + uart_txd => uart0_txd + ); uart1_checker: entity work.uart_rx - generic map (uart1_rx_handle) - port map ( - clk => clk_gen, - uart_txd => uart1_txd); + generic map ( + name => "uart1", + uart_baud_val_c => uart1_baud_val_c + ) + port map ( + clk => clk_gen, + uart_txd => uart1_txd + ); -- Wishbone Fabric ------------------------------------------------------------------------ diff --git a/sim/run.py b/sim/run.py deleted file mode 100755 index 43c85e646..000000000 --- a/sim/run.py +++ /dev/null @@ -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() diff --git a/sim/simple/ghdl.sh b/sim/simple/ghdl.sh deleted file mode 100755 index 835590a45..000000000 --- a/sim/simple/ghdl.sh +++ /dev/null @@ -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 $@ diff --git a/sim/simple/neorv32_tb.simple.vhd b/sim/simple/neorv32_tb.simple.vhd deleted file mode 100644 index af687239f..000000000 --- a/sim/simple/neorv32_tb.simple.vhd +++ /dev/null @@ -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; diff --git a/sim/simple/uart_rx.simple.vhd b/sim/simple/uart_rx.simple.vhd deleted file mode 100644 index 64d82ce55..000000000 --- a/sim/simple/uart_rx.simple.vhd +++ /dev/null @@ -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; diff --git a/sim/uart_rx.vhd b/sim/uart_rx.vhd index 4c9149ce1..84f0fac9e 100644 --- a/sim/uart_rx.vhd +++ b/sim/uart_rx.vhd @@ -5,15 +5,11 @@ use ieee.math_real.all; use std.textio.all; -library vunit_lib; -context vunit_lib.vunit_context; -context vunit_lib.com_context; -context vunit_lib.vc_context; - -use work.uart_rx_pkg.all; - entity uart_rx is - generic (handle : uart_rx_t); + generic ( + name : string; + uart_baud_val_c : real); + port ( clk : in std_ulogic; uart_txd : in std_ulogic @@ -27,49 +23,12 @@ architecture a of uart_rx is signal uart_rx_baud_cnt : real; signal uart_rx_bitcnt : natural; - file file_uart_tx_out : text open write_mode is "neorv32.testbench_" & get_name(handle.p_logger) & ".out"; - constant checker : checker_t := new_checker(handle.p_logger); - constant character_queue : queue_t := new_queue; + file file_uart_tx_out : text open write_mode is "neorv32.testbench_" & name & ".out"; begin - control : process - variable request_msg, reply_msg : msg_t; - variable msg_type : msg_type_t; - - procedure put_characters_in_queue(s : string) is - begin - for idx in s'range loop - push(character_queue, s(idx)); - end loop; - end procedure put_characters_in_queue; - begin - receive(net, handle.p_actor, request_msg); - msg_type := message_type(request_msg); - - -- Standard handling of standard wait_for_time messages = wait for the given time - -- before proceeeding - handle_wait_for_time(net, msg_type, request_msg); - - if msg_type = check_uart_msg then - put_characters_in_queue(pop(request_msg)); - - -- Custom handling of standard wait_until_idle message - elsif msg_type = wait_until_idle_msg then - while not is_empty(character_queue) loop - wait until rising_edge(clk); - end loop; - reply_msg := new_msg(wait_until_idle_reply_msg); - reply(net, request_msg, reply_msg); - - else - unexpected_msg_type(msg_type); - end if; - end process; - uart_rx_console : process(clk) variable i : integer; variable l : line; - variable expected_character : character; begin -- "UART" -- if rising_edge(clk) then @@ -78,7 +37,7 @@ begin -- arbiter -- if (uart_rx_busy = '0') then -- idle uart_rx_busy <= '0'; - uart_rx_baud_cnt <= round(0.5 * handle.p_baud_val); + uart_rx_baud_cnt <= round(0.5 * uart_baud_val_c); uart_rx_bitcnt <= 9; if (uart_rx_sync(4 downto 1) = "1100") then -- start bit? (falling edge) uart_rx_busy <= '1'; @@ -86,19 +45,18 @@ begin else if (uart_rx_baud_cnt <= 0.0) then if (uart_rx_bitcnt = 1) then - uart_rx_baud_cnt <= round(0.5 * handle.p_baud_val); + uart_rx_baud_cnt <= round(0.5 * uart_baud_val_c); else - uart_rx_baud_cnt <= round(handle.p_baud_val); + uart_rx_baud_cnt <= round(uart_baud_val_c); end if; if (uart_rx_bitcnt = 0) then uart_rx_busy <= '0'; -- done i := to_integer(unsigned(uart_rx_sreg(8 downto 1))); - if is_empty(character_queue) then - check_failed(checker, "Extra characters received"); + if (i < 32) or (i > 32+95) then -- printable char? + report name & ".tx: (" & integer'image(i) & ")"; -- print code else - expected_character := pop(character_queue); - check_equal(checker, character'val(i), expected_character); + report name & ".tx: " & character'val(i); -- print ASCII end if; if (i = 10) then -- Linux line break diff --git a/sim/uart_rx_pkg.vhd b/sim/uart_rx_pkg.vhd deleted file mode 100644 index 97cf0caac..000000000 --- a/sim/uart_rx_pkg.vhd +++ /dev/null @@ -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; diff --git a/sw/bootloader/makefile b/sw/bootloader/makefile index b4a86f5c2..bffcb9c76 100644 --- a/sw/bootloader/makefile +++ b/sw/bootloader/makefile @@ -1,4 +1,25 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Bootloader (for BOOTROM) makefile. + +# Minimal RISC-V ISA only +MARCH = rv32i_zicsr_zifencei +MABI = ilp32 + +# Optimize for minimal size +EFFORT = -Os + +# Adjust "rom" memory size and base for BOOTROM +# Just use a minimal "ram" size that should be available on any platform configuration. +# Define MAKE_BOOTLOADER for SW library (reduces footprint) +# Enable link-time-optimization +USER_FLAGS += \ +-Wl,--defsym,__neorv32_rom_size=4k \ +-Wl,--defsym,__neorv32_rom_base=0xFFFFC000 \ +-Wl,--defsym,__neorv32_ram_size=512 \ +-DMAKE_BOOTLOADER \ +-flto + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/common/common.mk b/sw/common/common.mk index 0e0d89ea4..b51c6e610 100644 --- a/sw/common/common.mk +++ b/sw/common/common.mk @@ -1,6 +1,8 @@ # ================================================================================ # # NEORV32 Application Software Makefile # # -------------------------------------------------------------------------------- # +# Do not edit this file! Use the re-defines in the project-local makefile instead. # +# -------------------------------------------------------------------------------- # # The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 # # Copyright (c) NEORV32 contributors. # # Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. # @@ -9,8 +11,8 @@ # ================================================================================ # # ----------------------------------------------------------------------------- -# Default configuration (do not edit this file; override the configuration -# when including this Makefile in the project-specific Makefile) +# Default configuration (DO NOT EDIT THIS FILE! REDEFINE / OVERRIDE THE DEFAULT +# CONFIGURATION WHEN INCLUDING THIS MAKEFILE IN THE PROJECT-SPECIFIC MAKEFILE) # ----------------------------------------------------------------------------- # User's application sources (*.c, *.cpp, *.s, *.S); add additional files here APP_SRC ?= $(wildcard ./*.c) $(wildcard ./*.s) $(wildcard ./*.cpp) $(wildcard ./*.S) @@ -57,7 +59,7 @@ NEORV32_EXG_PATH = $(NEORV32_HOME)/sw/image_gen # Path to NEORV32 rtl folder NEORV32_RTL_PATH = $(NEORV32_LOCAL_RTL) # Path to NEORV32 sim folder -NEORV32_SIM_PATH = $(NEORV32_HOME)/sim/simple +NEORV32_SIM_PATH = $(NEORV32_HOME)/sim # Marker file to check for NEORV32 home folder NEORV32_HOME_MARKER = $(NEORV32_INC_PATH)/neorv32.h @@ -106,7 +108,7 @@ IMAGE_GEN = $(NEORV32_EXG_PATH)/image_gen # Compiler & linker flags CC_OPTS = -march=$(MARCH) -mabi=$(MABI) $(EFFORT) -Wall -ffunction-sections -fdata-sections -nostartfiles -mno-fdiv -CC_OPTS += -mstrict-align -mbranch-cost=10 -Wl,--gc-sections -ffp-contract=off +CC_OPTS += -mstrict-align -mbranch-cost=10 -Wl,--gc-sections -ffp-contract=off -g CC_OPTS += $(USER_FLAGS) LD_LIBS = -lm -lc -lgcc LD_LIBS += $(USER_LIBS) @@ -127,7 +129,7 @@ NEO_ASFLAGS = $(CC_FLAGS) $(ASFLAGS) # ----------------------------------------------------------------------------- # Application output definitions # ----------------------------------------------------------------------------- -.PHONY: check info help elf_info clean clean_all bootloader +.PHONY: check info help elf_info clean clean_all .DEFAULT_GOAL := help asm: $(APP_ASM) @@ -142,12 +144,6 @@ image: $(APP_VHD) install: image install-$(APP_VHD) all: $(APP_ASM) $(APP_EXE) $(APP_HEX) $(APP_BIN) $(APP_COE) $(APP_MEM) $(APP_MIF) $(APP_VHD) install hex bin -# Check if making bootloader -# Use different base address and length for instruction memory/"rom" (BOOTROM instead of IMEM) -# Also define "MAKE_BOOTLOADER" symbol for simplified code when building the bootloader -# Use link-time optimization to further shrink bootloader code size -target bootloader | bl_image: CC_OPTS += -Wl,--defsym=MAKE_BOOTLOADER=1 -DMAKE_BOOTLOADER -flto - # ----------------------------------------------------------------------------- # Image generator targets # ----------------------------------------------------------------------------- @@ -199,14 +195,16 @@ main.bin: $(APP_ELF) # Generate NEORV32 executable image for upload via bootloader $(APP_EXE): main.bin $(IMAGE_GEN) @set -e + @echo "Generating $(APP_EXE)" @$(IMAGE_GEN) -app_bin $< $@ $(shell basename $(CURDIR)) - @echo "Executable ($(APP_EXE)) size in bytes:" + @echo "Executable size in bytes:" @wc -c < $(APP_EXE) # Generate NEORV32 executable VHDL boot image $(APP_VHD): main.bin $(IMAGE_GEN) @set -e - @$(IMAGE_GEN) -app_img $< $@ $(shell basename $(CURDIR)) + @echo "Generating $(APP_VHD)" + @$(IMAGE_GEN) -app_vhd $< $@ $(shell basename $(CURDIR)) # Install VHDL memory initialization file install-$(APP_VHD): $(APP_VHD) @@ -217,48 +215,48 @@ install-$(APP_VHD): $(APP_VHD) # Generate NEORV32 RAW executable image in plain hex format $(APP_HEX): main.bin $(IMAGE_GEN) @set -e + @echo "Generating $(APP_HEX)" @$(IMAGE_GEN) -raw_hex $< $@ $(shell basename $(CURDIR)) # Generate NEORV32 RAW executable image in binary format $(APP_BIN): main.bin $(IMAGE_GEN) @set -e + @echo "Generating $(APP_BIN)" @$(IMAGE_GEN) -raw_bin $< $@ $(shell basename $(CURDIR)) # Generate NEORV32 RAW executable image in COE format $(APP_COE): main.bin $(IMAGE_GEN) @set -e + @echo "Generating $(APP_COE)" @$(IMAGE_GEN) -raw_coe $< $@ $(shell basename $(CURDIR)) # Generate NEORV32 RAW executable image in MIF format $(APP_MIF): main.bin $(IMAGE_GEN) @set -e + @echo "Generating $(APP_MIF)" @$(IMAGE_GEN) -raw_mif $< $@ $(shell basename $(CURDIR)) # Generate NEORV32 RAW executable image in MEM format $(APP_MEM): main.bin $(IMAGE_GEN) @set -e + @echo "Generating $(APP_MEM)" @$(IMAGE_GEN) -raw_mem $< $@ $(shell basename $(CURDIR)) # ----------------------------------------------------------------------------- -# Boot image targets +# BOOTROM / booloader image targets # ----------------------------------------------------------------------------- -# Create VHDL boot image -$(BOOT_VHD): main.bin $(IMAGE_GEN) +# Create local VHDL BOOTROM image +bl_image: main.bin $(IMAGE_GEN) @set -e - @$(IMAGE_GEN) -bld_img $< $(BOOT_VHD) $(shell basename $(CURDIR)) + @echo "Generating $(BOOT_VHD)" + @$(IMAGE_GEN) -bld_vhd $< $(BOOT_VHD) $(shell basename $(CURDIR)) -# Install image to VHDL source directory -install-$(BOOT_VHD): $(BOOT_VHD) +# Install BOOTROM image to VHDL source directory +bootloader: bl_image @set -e @echo "Installing bootloader image to $(NEORV32_RTL_PATH)/core/$(BOOT_VHD)" @cp $(BOOT_VHD) $(NEORV32_RTL_PATH)/core/. -# Just an alias -bl_image: $(BOOT_VHD) - -# Compile and install as VHDL bootloader image -bootloader: bl_image install-$(BOOT_VHD) - # ----------------------------------------------------------------------------- # Check toolchain # ----------------------------------------------------------------------------- @@ -289,10 +287,10 @@ endif @echo "Toolchain check OK" # ----------------------------------------------------------------------------- -# In-console simulation using default/simple testbench and GHDL +# In-console simulation using default testbench and GHDL # ----------------------------------------------------------------------------- sim: $(APP_VHD) install - @echo "Simulating processor using simple testbench..." + @echo "Simulating processor using default testbench..." @sh $(NEORV32_SIM_PATH)/ghdl.sh $(GHDL_RUN_FLAGS) # ----------------------------------------------------------------------------- @@ -374,26 +372,26 @@ help: @echo " help - show this text" @echo " check - check toolchain" @echo " info - show makefile/toolchain configuration" - @echo " gdb - run GNU debugging session" + @echo " gdb - start GNU debugging session" @echo " asm - compile and generate <$(APP_ASM)> assembly listing file for manual debugging" @echo " elf - compile and generate <$(APP_ELF)> ELF file" - @echo " exe - compile and generate <$(APP_EXE)> executable image file for upload via default bootloader (binary file)" - @echo " bin - compile and generate <$(APP_BIN)> RAW executable memory image (binary file)" - @echo " hex - compile and generate <$(APP_HEX)> RAW executable memory image (hex char file)" - @echo " coe - compile and generate <$(APP_COE)> RAW executable memory image (COE file)" - @echo " mem - compile and generate <$(APP_MEM)> RAW executable memory image (MEM file)" - @echo " mif - compile and generate <$(APP_MIF)> RAW executable memory image (MIF file)" - @echo " image - compile and generate VHDL IMEM boot image (for application, no header) in local folder" - @echo " install - compile, generate and install VHDL IMEM boot image (for application, no header)" - @echo " sim - in-console simulation using default/simple testbench and GHDL" + @echo " exe - compile and generate <$(APP_EXE)> executable image file for bootloader upload (includes a HEADER!)" + @echo " bin - compile and generate <$(APP_BIN)> executable memory image" + @echo " hex - compile and generate <$(APP_HEX)> executable memory image" + @echo " coe - compile and generate <$(APP_COE)> executable memory image" + @echo " mem - compile and generate <$(APP_MEM)> executable memory image" + @echo " mif - compile and generate <$(APP_MIF)> executable memory image" + @echo " image - compile and generate VHDL IMEM application boot image <$(APP_VHD)> in local folder" + @echo " install - compile, generate and install VHDL IMEM application boot image <$(APP_VHD)>" + @echo " sim - in-console simulation using default testbench (sim folder) and GHDL" @echo " hdl_lists - regenerate HDL file-lists (*.f) in NEORV32_HOME/rtl" @echo " all - exe + install + hex + bin + asm" @echo " elf_info - show ELF layout info" @echo " elf_sections - show ELF sections" @echo " clean - clean up project home folder" @echo " clean_all - clean up whole project, core libraries and image generator" - @echo " bl_image - compile and generate VHDL BOOTROM boot image (for bootloader only, no header) in local folder" - @echo " bootloader - compile, generate and install VHDL BOOTROM boot image (for bootloader only, no header)" + @echo " bl_image - compile and generate VHDL BOOTROM bootloader boot image <$(BOOT_VHD)> in local folder" + @echo " bootloader - compile, generate and install VHDL BOOTROM bootloader boot image <$(BOOT_VHD)>" @echo "" @echo "Variables:" @echo "" @@ -403,6 +401,7 @@ help: @echo " MARCH - Machine architecture: \"$(MARCH)\"" @echo " MABI - Machine binary interface: \"$(MABI)\"" @echo " APP_INC - C include folder(s) [append only]: \"$(APP_INC)\"" + @echo " APP_SRC - C source folder(s) [append only]: \"$(APP_SRC)\"" @echo " ASM_INC - ASM include folder(s) [append only]: \"$(ASM_INC)\"" @echo " RISCV_PREFIX - Toolchain prefix: \"$(RISCV_PREFIX)\"" @echo " NEORV32_HOME - NEORV32 home folder: \"$(NEORV32_HOME)\"" diff --git a/sw/common/neorv32.ld b/sw/common/neorv32.ld index 41b7a6dac..73423e91e 100644 --- a/sw/common/neorv32.ld +++ b/sw/common/neorv32.ld @@ -1,5 +1,5 @@ /* ================================================================================ */ -/* NEORV32 CPU - RISC-V GCC Linker Script */ +/* NEORV32 - RISC-V GCC Linker Script */ /* -------------------------------------------------------------------------------- */ /* The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 */ /* Copyright (c) NEORV32 contributors. */ @@ -8,12 +8,6 @@ /* SPDX-License-Identifier: BSD-3-Clause */ /* ================================================================================ */ -/* Copyright (C) 2014-2020 Free Software Foundation, Inc. - * Copying and distribution of this script, with or without modification, - * are permitted in any medium without royalty provided the copyright - * notice and this notice are preserved. */ - - OUTPUT_FORMAT("elf32-littleriscv") OUTPUT_ARCH(riscv) ENTRY(_start) @@ -25,34 +19,29 @@ SEARCH_DIR("=/usr/lib") /* ************************************************************************************************* */ /* +++ NEORV32 memory layout configuration +++ */ -/* If the symbols are not explicitly defined the default configurations are used. If required, only */ -/* edit the very last entry in each row. */ +/* If the "__neorv32_*" symbols are not explicitly defined the default configurations are used. */ /* NOTE: section sizes have to be a multiple of 4 bytes; base addresses have to be 32-bit-aligned. */ /* ************************************************************************************************* */ -/* Default rom/ram (IMEM/DMEM) sizes */ -__neorv32_rom_size = DEFINED(__neorv32_rom_size) ? __neorv32_rom_size : 2048M; -__neorv32_ram_size = DEFINED(__neorv32_ram_size) ? __neorv32_ram_size : 8K; - /* Default HEAP size (= 0; no heap at all) */ __neorv32_heap_size = DEFINED(__neorv32_heap_size) ? __neorv32_heap_size : 0; -/* Default section base addresses */ +/* Default rom/ram (IMEM/DMEM) sizes */ +__neorv32_rom_size = DEFINED(__neorv32_rom_size) ? __neorv32_rom_size : 16k; +__neorv32_ram_size = DEFINED(__neorv32_ram_size) ? __neorv32_ram_size : 8K; + +/* Default rom/ram (IMEM/DMEM) base addresses */ __neorv32_rom_base = DEFINED(__neorv32_rom_base) ? __neorv32_rom_base : 0x00000000; __neorv32_ram_base = DEFINED(__neorv32_ram_base) ? __neorv32_ram_base : 0x80000000; /* ************************************************************************************************* */ -/* when compiling the bootloader the ROM section is automatically re-mapped to the */ -/* processor-internal bootloader ROM address space. */ +/* Main memory segments that are relevant for the executable. */ /* ************************************************************************************************* */ MEMORY { - rom (rx) : ORIGIN = DEFINED(MAKE_BOOTLOADER) ? 0xFFFFC000 : __neorv32_rom_base, LENGTH = DEFINED(MAKE_BOOTLOADER) ? 8K : __neorv32_rom_size - ram (rwx) : ORIGIN = __neorv32_ram_base, LENGTH = DEFINED(MAKE_BOOTLOADER) ? 512 : __neorv32_ram_size - xip (rx) : ORIGIN = 0xE0000000, LENGTH = 256M - boot (rx) : ORIGIN = 0xFFFFC000, LENGTH = 8K - io (rwx) : ORIGIN = 0xFFFFE000, LENGTH = 8K + rom (rx) : ORIGIN = __neorv32_rom_base, LENGTH = __neorv32_rom_size + ram (rwx) : ORIGIN = __neorv32_ram_base, LENGTH = __neorv32_ram_size } diff --git a/sw/example/atomic_test/makefile b/sw/example/atomic_test/makefile index 8f9e2fdc0..13c2d50b2 100644 --- a/sw/example/atomic_test/makefile +++ b/sw/example/atomic_test/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32ia_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/bus_explorer/makefile b/sw/example/bus_explorer/makefile index 8f9e2fdc0..81c21d943 100644 --- a/sw/example/bus_explorer/makefile +++ b/sw/example/bus_explorer/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/coremark/makefile b/sw/example/coremark/makefile index 8f9e2fdc0..de0eaf072 100644 --- a/sw/example/coremark/makefile +++ b/sw/example/coremark/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32imc_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -O3 + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=32k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_blink_led/makefile b/sw/example/demo_blink_led/makefile index 8f9e2fdc0..81c21d943 100644 --- a/sw/example/demo_blink_led/makefile +++ b/sw/example/demo_blink_led/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_blink_led_asm/makefile b/sw/example/demo_blink_led_asm/makefile index 8f9e2fdc0..81c21d943 100644 --- a/sw/example/demo_blink_led_asm/makefile +++ b/sw/example/demo_blink_led_asm/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_cfs/makefile b/sw/example/demo_cfs/makefile index 8f9e2fdc0..81c21d943 100644 --- a/sw/example/demo_cfs/makefile +++ b/sw/example/demo_cfs/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_cfu/makefile b/sw/example/demo_cfu/makefile index 8f9e2fdc0..81c21d943 100644 --- a/sw/example/demo_cfu/makefile +++ b/sw/example/demo_cfu/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_crc/makefile b/sw/example/demo_crc/makefile index 8f9e2fdc0..81c21d943 100644 --- a/sw/example/demo_crc/makefile +++ b/sw/example/demo_crc/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_dma/makefile b/sw/example/demo_dma/makefile index 8f9e2fdc0..81c21d943 100644 --- a/sw/example/demo_dma/makefile +++ b/sw/example/demo_dma/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_emulate_unaligned/makefile b/sw/example/demo_emulate_unaligned/makefile index 8f9e2fdc0..81c21d943 100644 --- a/sw/example/demo_emulate_unaligned/makefile +++ b/sw/example/demo_emulate_unaligned/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_gptmr/makefile b/sw/example/demo_gptmr/makefile index 8f9e2fdc0..81c21d943 100644 --- a/sw/example/demo_gptmr/makefile +++ b/sw/example/demo_gptmr/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_hpm/makefile b/sw/example/demo_hpm/makefile index 8f9e2fdc0..81c21d943 100644 --- a/sw/example/demo_hpm/makefile +++ b/sw/example/demo_hpm/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_mtime/makefile b/sw/example/demo_mtime/makefile index 8f9e2fdc0..81c21d943 100644 --- a/sw/example/demo_mtime/makefile +++ b/sw/example/demo_mtime/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_neopixel/makefile b/sw/example/demo_neopixel/makefile index 8f9e2fdc0..81c21d943 100644 --- a/sw/example/demo_neopixel/makefile +++ b/sw/example/demo_neopixel/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_newlib/makefile b/sw/example/demo_newlib/makefile index b7296654c..d622ea030 100644 --- a/sw/example/demo_newlib/makefile +++ b/sw/example/demo_newlib/makefile @@ -1,5 +1,33 @@ -# Configure max HEAP size -override USER_FLAGS += "-Wl,--defsym,__neorv32_heap_size=3072" +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=3072 + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. + +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_onewire/makefile b/sw/example/demo_onewire/makefile index 8f9e2fdc0..c2c0d4f9e 100644 --- a/sw/example/demo_onewire/makefile +++ b/sw/example/demo_onewire/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. -include $(NEORV32_HOME)/sw/common/common.mk +# Include the main NEORV32 makefile +include $(NEORV32_HOME)/sw/common/common.mk \ No newline at end of file diff --git a/sw/example/demo_pwm/makefile b/sw/example/demo_pwm/makefile index 8f9e2fdc0..c2c0d4f9e 100644 --- a/sw/example/demo_pwm/makefile +++ b/sw/example/demo_pwm/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. -include $(NEORV32_HOME)/sw/common/common.mk +# Include the main NEORV32 makefile +include $(NEORV32_HOME)/sw/common/common.mk \ No newline at end of file diff --git a/sw/example/demo_sdi/makefile b/sw/example/demo_sdi/makefile index 8f9e2fdc0..81c21d943 100644 --- a/sw/example/demo_sdi/makefile +++ b/sw/example/demo_sdi/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_slink/makefile b/sw/example/demo_slink/makefile index 8f9e2fdc0..c2c0d4f9e 100644 --- a/sw/example/demo_slink/makefile +++ b/sw/example/demo_slink/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. -include $(NEORV32_HOME)/sw/common/common.mk +# Include the main NEORV32 makefile +include $(NEORV32_HOME)/sw/common/common.mk \ No newline at end of file diff --git a/sw/example/demo_spi/makefile b/sw/example/demo_spi/makefile index 8f9e2fdc0..c2c0d4f9e 100644 --- a/sw/example/demo_spi/makefile +++ b/sw/example/demo_spi/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. -include $(NEORV32_HOME)/sw/common/common.mk +# Include the main NEORV32 makefile +include $(NEORV32_HOME)/sw/common/common.mk \ No newline at end of file diff --git a/sw/example/demo_spi_irq/makefile b/sw/example/demo_spi_irq/makefile index dbb60f018..913222fe5 100644 --- a/sw/example/demo_spi_irq/makefile +++ b/sw/example/demo_spi_irq/makefile @@ -1,7 +1,32 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) -NEORV32_HOME ?= ../../.. +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 -APP_SRC ?= $(wildcard ./*.c) $(wildcard ./*.s) $(wildcard ./*.cpp) $(wildcard ./*.S) $(wildcard ./drv/*.c) -APP_INC ?= -I . -I ./drv +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +APP_SRC += $(wildcard ./*.c) $(wildcard ./*.s) $(wildcard ./*.cpp) $(wildcard ./*.S) $(wildcard ./drv/*.c) +APP_INC += -I . -I ./drv + +# Set path to NEORV32 root directory +NEORV32_HOME ?= ../../.. include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/demo_trng/makefile b/sw/example/demo_trng/makefile index 8f9e2fdc0..c2c0d4f9e 100644 --- a/sw/example/demo_trng/makefile +++ b/sw/example/demo_trng/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. -include $(NEORV32_HOME)/sw/common/common.mk +# Include the main NEORV32 makefile +include $(NEORV32_HOME)/sw/common/common.mk \ No newline at end of file diff --git a/sw/example/demo_twi/makefile b/sw/example/demo_twi/makefile index 8f9e2fdc0..c2c0d4f9e 100644 --- a/sw/example/demo_twi/makefile +++ b/sw/example/demo_twi/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. -include $(NEORV32_HOME)/sw/common/common.mk +# Include the main NEORV32 makefile +include $(NEORV32_HOME)/sw/common/common.mk \ No newline at end of file diff --git a/sw/example/demo_wdt/makefile b/sw/example/demo_wdt/makefile index 8f9e2fdc0..c2c0d4f9e 100644 --- a/sw/example/demo_wdt/makefile +++ b/sw/example/demo_wdt/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. -include $(NEORV32_HOME)/sw/common/common.mk +# Include the main NEORV32 makefile +include $(NEORV32_HOME)/sw/common/common.mk \ No newline at end of file diff --git a/sw/example/demo_xip/makefile b/sw/example/demo_xip/makefile index 8f9e2fdc0..c2c0d4f9e 100644 --- a/sw/example/demo_xip/makefile +++ b/sw/example/demo_xip/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. -include $(NEORV32_HOME)/sw/common/common.mk +# Include the main NEORV32 makefile +include $(NEORV32_HOME)/sw/common/common.mk \ No newline at end of file diff --git a/sw/example/demo_xirq/main.c b/sw/example/demo_xirq/main.c index 9349b6517..ce81d3ca7 100644 --- a/sw/example/demo_xirq/main.c +++ b/sw/example/demo_xirq/main.c @@ -155,8 +155,6 @@ int main() { // All incoming XIRQ interrupt requests are "prioritized" in this example. The XIRQ FIRQ handler // reads the ID of the interrupt with the highest priority from the XIRQ controller ("source" register) and calls the according // handler function (installed via neorv32_xirq_install();). - // Non-prioritized handling of interrupts (or custom prioritization) can be implemented by manually reading the - // XIRQ controller's "pending" register. Then it is up to the software to define which pending IRQ should be serviced first. asm volatile ("nop"); asm volatile ("nop"); @@ -165,15 +163,12 @@ int main() { // just as an example: to disable certain XIRQ interrupt channels, we can - // un-install the according handler. this will also clear a pending interrupt for that channel + // un-install the according handler. this will also disable the according channel. neorv32_xirq_uninstall(0); // disable XIRQ channel 0 and remove associated handler neorv32_xirq_uninstall(1); // disable XIRQ channel 1 and remove associated handler neorv32_xirq_uninstall(2); // disable XIRQ channel 2 and remove associated handler neorv32_xirq_uninstall(3); // disable XIRQ channel 3 and remove associated handler - // you can also manually clear pending interrupts - neorv32_xirq_clear_pending(0); // clear pending interrupt of channel 0 - // manually enable and disable XIRQ channels neorv32_xirq_channel_enable(0); // enable channel 0 neorv32_xirq_channel_disable(0); // disable channel 0 diff --git a/sw/example/demo_xirq/makefile b/sw/example/demo_xirq/makefile index 8f9e2fdc0..c2c0d4f9e 100644 --- a/sw/example/demo_xirq/makefile +++ b/sw/example/demo_xirq/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. -include $(NEORV32_HOME)/sw/common/common.mk +# Include the main NEORV32 makefile +include $(NEORV32_HOME)/sw/common/common.mk \ No newline at end of file diff --git a/sw/example/dhrystone/dhry_1.c b/sw/example/dhrystone/dhry_1.c index ac88fdba3..a53d469e0 100644 --- a/sw/example/dhrystone/dhry_1.c +++ b/sw/example/dhrystone/dhry_1.c @@ -26,6 +26,8 @@ #include #include "dhry.h" +/** UART BAUD rate */ +#define BAUD_RATE 19200 #ifndef DHRY_ITERS #define DHRY_ITERS 10000 @@ -104,7 +106,7 @@ int main (void) { /* ***** NEORV32-SPECIFIC ***** */ neorv32_rte_setup(); neorv32_cpu_csr_write(CSR_MIE, 0); // no interrupts - neorv32_uart0_setup(19200, 0); + neorv32_uart0_setup(BAUD_RATE, 0); neorv32_uart0_printf("NEORV32: Processor running at %u Hz\n", (uint32_t)neorv32_sysinfo_get_clk()); neorv32_uart0_printf("NEORV32: Executing Dhrystone (%u iterations). This may take some time...\n\n", (uint32_t)DHRY_ITERS); diff --git a/sw/example/dhrystone/makefile b/sw/example/dhrystone/makefile index 8f9e2fdc0..c2c0d4f9e 100644 --- a/sw/example/dhrystone/makefile +++ b/sw/example/dhrystone/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. -include $(NEORV32_HOME)/sw/common/common.mk +# Include the main NEORV32 makefile +include $(NEORV32_HOME)/sw/common/common.mk \ No newline at end of file diff --git a/sw/example/eclipse/.settings/language.settings.xml b/sw/example/eclipse/.settings/language.settings.xml index 2fda30404..b55752d6a 100644 --- a/sw/example/eclipse/.settings/language.settings.xml +++ b/sw/example/eclipse/.settings/language.settings.xml @@ -5,7 +5,7 @@ - + diff --git a/sw/example/eclipse/main.c b/sw/example/eclipse/main.c index 01b234eb1..8f75a5572 100644 --- a/sw/example/eclipse/main.c +++ b/sw/example/eclipse/main.c @@ -1,5 +1,5 @@ #include -#include // better use an embedded version of printf +#include // UART baud rate #define BAUD_RATE 19200 @@ -21,7 +21,8 @@ int main() { int cnt = 0; while (1) { - neorv32_gpio_port_set(cnt++ & 0xff); // increment counter and mask for lowest 8 bit + cnt = (cnt + 1) & 0xff; // increment counter and mask for lowest 8 bit + neorv32_gpio_port_set(cnt); // output via GPIO.out neorv32_cpu_delay_ms(250); // wait 250ms using busy wait } diff --git a/sw/example/eclipse/makefile b/sw/example/eclipse/makefile index a85f05dad..326d25f5f 100644 --- a/sw/example/eclipse/makefile +++ b/sw/example/eclipse/makefile @@ -1,16 +1,32 @@ -# Use this makefile to specify all relevant CPU / compiler options -# as these cannot be issued by Eclipse (since this is a makefile-based project). +# Use this makefile to configure all relevant CPU / compiler options +# as these cannot be set by Eclipse (since this is a makefile-based project). # Override the default CPU ISA -#override MARCH = rv32imc_zicsr_zifencei +MARCH = rv32imc_zicsr_zifencei # Override the default RISC-V GCC prefix -RISCV_PREFIX = riscv-none-elf- +RISCV_PREFIX ?= riscv-none-elf- -# Add debug symbols +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols for Eclipse USER_FLAGS += -ggdb -gdwarf-3 -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Additional sources +APP_SRC += $(wildcard ./*.c) +APP_INC += -I . + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. # Include the main NEORV32 makefile diff --git a/sw/example/float_corner_test/makefile b/sw/example/float_corner_test/makefile index 8f9e2fdc0..c2c0d4f9e 100644 --- a/sw/example/float_corner_test/makefile +++ b/sw/example/float_corner_test/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. -include $(NEORV32_HOME)/sw/common/common.mk +# Include the main NEORV32 makefile +include $(NEORV32_HOME)/sw/common/common.mk \ No newline at end of file diff --git a/sw/example/floating_point_test/makefile b/sw/example/floating_point_test/makefile index 8f9e2fdc0..81c21d943 100644 --- a/sw/example/floating_point_test/makefile +++ b/sw/example/floating_point_test/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/game_of_life/makefile b/sw/example/game_of_life/makefile index 8f9e2fdc0..fad5eadb9 100644 --- a/sw/example/game_of_life/makefile +++ b/sw/example/game_of_life/makefile @@ -1,4 +1,33 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +APP_SRC += $(wildcard ./*.c) +APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/hello_cpp/makefile b/sw/example/hello_cpp/makefile index e303f51e0..d3092c735 100644 --- a/sw/example/hello_cpp/makefile +++ b/sw/example/hello_cpp/makefile @@ -1,7 +1,37 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. + +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk # Use c++ compiler and define c++ standard override CC = $(RISCV_PREFIX)g++ -override USER_FLAGS += -std=c++11 +USER_FLAGS += -std=c++11 diff --git a/sw/example/hello_world/makefile b/sw/example/hello_world/makefile index 0ba3e704b..99ad7967d 100644 --- a/sw/example/hello_world/makefile +++ b/sw/example/hello_world/makefile @@ -1,7 +1,36 @@ -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA +MARCH = rv32i_zicsr_zifencei + +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +USER_FLAGS += -ggdb -gdwarf-3 + +# Adjust processor IMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=16k + +# Adjust processor DMEM size +USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#USER_FLAGS += -Wl,--defsym,__neorv32_heap_size=1k + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk sim-check: sim - cat $(NEORV32_HOME)/sim/simple/neorv32.uart0.sim_mode.text.out | grep "Hello world! :)" + cat $(NEORV32_HOME)/sim/neorv32.uart0.sim_mode.text.out | grep "Hello world! :)" diff --git a/sw/example/makefile b/sw/example/makefile index 23541c51a..f7535b7cd 100644 --- a/sw/example/makefile +++ b/sw/example/makefile @@ -1,6 +1,3 @@ -#------------------------------------------------------------------------------- -# Make defaults and targets -#------------------------------------------------------------------------------- .SUFFIXES: .DEFAULT_GOAL := help @@ -20,10 +17,6 @@ $(SUBDIRS): .PHONY: $(TOPTARGETS) $(SUBDIRS) - -#------------------------------------------------------------------------------- -# Help -#------------------------------------------------------------------------------- help: @echo "Build / clean up all projects" @echo "Targets:" diff --git a/sw/example/performance_tests/I/makefile b/sw/example/performance_tests/I/makefile index 7b9872632..c50f10cfc 100644 --- a/sw/example/performance_tests/I/makefile +++ b/sw/example/performance_tests/I/makefile @@ -1,5 +1,8 @@ # Modify this variable to fit your NEORV32 setup (neorv32 home folder) NEORV32_HOME ?= ../../../.. +MARCH ?= rv32i_zicsr_zifencei GHDL_RUN_FLAGS ?= -gPERFORMANCE_OPTION=1 --stop-time=4500us +override USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=128k +override USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=16k include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/performance_tests/M/makefile b/sw/example/performance_tests/M/makefile index 8f681aace..0699433fd 100644 --- a/sw/example/performance_tests/M/makefile +++ b/sw/example/performance_tests/M/makefile @@ -2,5 +2,7 @@ NEORV32_HOME ?= ../../../.. MARCH ?= rv32im_zicsr_zifencei GHDL_RUN_FLAGS ?= -gPERFORMANCE_OPTION=1 --stop-time=1500us +override USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=128k +override USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=16k include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/performance_tests/Zfinx/makefile b/sw/example/performance_tests/Zfinx/makefile index 1a914590c..aa02b51b8 100644 --- a/sw/example/performance_tests/Zfinx/makefile +++ b/sw/example/performance_tests/Zfinx/makefile @@ -2,5 +2,7 @@ NEORV32_HOME ?= ../../../.. MARCH ?= rv32i_zicsr_zifencei_zfinx GHDL_RUN_FLAGS ?= -gPERFORMANCE_OPTION=1 --stop-time=4500us +override USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=64k +override USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=16k include $(NEORV32_HOME)/sw/common/common.mk diff --git a/sw/example/processor_check/main.c b/sw/example/processor_check/main.c index cb687e899..530ec7185 100644 --- a/sw/example/processor_check/main.c +++ b/sw/example/processor_check/main.c @@ -1324,8 +1324,6 @@ int main() { xirq_err_cnt += neorv32_xirq_install(1, xirq_trap_handler1); // install XIRQ IRQ handler channel 1 neorv32_xirq_setup_trigger(0, XIRQ_TRIGGER_EDGE_RISING); // configure channel 0 as rising-edge trigger neorv32_xirq_setup_trigger(1, XIRQ_TRIGGER_EDGE_RISING); // configure channel 1 as rising-edge trigger - neorv32_xirq_clear_pending(0); // clear any pending request - neorv32_xirq_clear_pending(1); // clear any pending request neorv32_xirq_channel_enable(0); // enable XIRQ channel 0 neorv32_xirq_channel_enable(1); // enable XIRQ channel 1 diff --git a/sw/example/processor_check/makefile b/sw/example/processor_check/makefile index f8c7559f3..27d2a844d 100644 --- a/sw/example/processor_check/makefile +++ b/sw/example/processor_check/makefile @@ -1,13 +1,43 @@ -# Override default configuration -override GHDL_RUN_FLAGS ?= --stop-time=15ms -override EFFORT = -Os +# Application makefile. +# Use this makefile to configure all relevant CPU / compiler options. + +# Override the default CPU ISA override MARCH = rv32ima_zba_zbb_zbs_zbkb_zbkc_zbkx_zknd_zkne_zknh_zksh_zksed_zicsr_zfinx_zifencei_zicond -override USER_FLAGS += -flto -Wl,--defsym,__neorv32_heap_size=3096 -# Modify this variable to fit your NEORV32 setup (neorv32 home folder) +# Override the default RISC-V GCC prefix +#RISCV_PREFIX ?= riscv-none-elf- + +# Override default optimization goal +EFFORT = -Os + +# Add extended debug symbols +override USER_FLAGS += -ggdb -gdwarf-3 + +# Enable link time optimization +override USER_FLAGS += -flto + +# Adjust processor IMEM size +override USER_FLAGS += -Wl,--defsym,__neorv32_rom_size=32k + +# Adjust processor DMEM size +override USER_FLAGS += -Wl,--defsym,__neorv32_ram_size=8k + +# Adjust maximum heap size +#SER_FLAGS += -Wl,--defsym,__neorv32_heap_size=3096 + +# Simulation arguments +override GHDL_RUN_FLAGS ?= --stop-time=15ms + +# Additional sources +#APP_SRC += $(wildcard ./*.c) +#APP_INC += -I . + +# Set path to NEORV32 root directory NEORV32_HOME ?= ../../.. + +# Include the main NEORV32 makefile include $(NEORV32_HOME)/sw/common/common.mk # 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.text.out | grep "PROCESSOR TEST COMPLETED SUCCESSFULLY!" diff --git a/sw/image_gen/image_gen.c b/sw/image_gen/image_gen.c index cf5cf06b3..27d0423f0 100644 --- a/sw/image_gen/image_gen.c +++ b/sw/image_gen/image_gen.c @@ -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" + "library neorv32;\n" + "use neorv32.neorv32_package.all;\n" "\n" - "constant application_init_image : mem32_t := (\n", argv[4], argv[2], raw_exe_size, string_march, compile_time); + "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" + "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, string_march, compile_time); + "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); diff --git a/sw/lib/include/neorv32_sysinfo.h b/sw/lib/include/neorv32_sysinfo.h index 2ff1ccc97..d8ca05d7a 100644 --- a/sw/lib/include/neorv32_sysinfo.h +++ b/sw/lib/include/neorv32_sysinfo.h @@ -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) */ diff --git a/sw/lib/include/neorv32_xirq.h b/sw/lib/include/neorv32_xirq.h index 590a6fde0..c160118b8 100644 --- a/sw/lib/include/neorv32_xirq.h +++ b/sw/lib/include/neorv32_xirq.h @@ -25,14 +25,10 @@ /**@{*/ /** XIRQ module prototype */ typedef volatile struct __attribute__((packed,aligned(4))) { - uint32_t EIE; /**< offset 0: external interrupt enable register */ - uint32_t EIP; /**< offset 4: external interrupt pending register */ - uint32_t ESC; /**< offset 8: external interrupt source register */ - uint32_t TTYP; /**< offset 12: external interrupt source register */ - uint32_t TPOL; /**< offset 16: external interrupt source register */ - const uint32_t reserved0; /**< offset 20: reserved */ - const uint32_t reserved1; /**< offset 24: reserved */ - const uint32_t reserved2; /**< offset 28: reserved */ + uint32_t EIE; /**< offset 0: external interrupt enable register */ + uint32_t ESC; /**< offset 4: external interrupt source register */ + uint32_t TTYP; /**< offset 8: external interrupt source register */ + uint32_t TPOL; /**< offset 12: external interrupt source register */ } neorv32_xirq_t; /** XIRQ module hardware access (#neorv32_xirq_t) */ @@ -41,14 +37,14 @@ typedef volatile struct __attribute__((packed,aligned(4))) { /**********************************************************************//** - * XIRQ trigger configuration + * XIRQ trigger type configuration **************************************************************************/ -/**@{*/ -#define XIRQ_TRIGGER_LEVEL_LOW (0b00) // low-level -#define XIRQ_TRIGGER_LEVEL_HIGH (0b01) // high-level -#define XIRQ_TRIGGER_EDGE_FALLING (0b10) // falling-edge -#define XIRQ_TRIGGER_EDGE_RISING (0b11) // rising-edge -/**@}*/ +enum XIRQ_TRIGGER_enum { + XIRQ_TRIGGER_LEVEL_LOW = 0b00, // low-level + XIRQ_TRIGGER_LEVEL_HIGH = 0b01, // high-level + XIRQ_TRIGGER_EDGE_FALLING = 0b10, // falling-edge + XIRQ_TRIGGER_EDGE_RISING = 0b11 // rising-edge +}; /**********************************************************************//** @@ -61,7 +57,6 @@ void neorv32_xirq_global_enable(void); void neorv32_xirq_global_disable(void); int neorv32_xirq_get_num(void); void neorv32_xirq_setup_trigger(int channel, int config); -void neorv32_xirq_clear_pending(int channel); void neorv32_xirq_channel_enable(int channel); void neorv32_xirq_channel_disable(int channel); int neorv32_xirq_install(int channel, void (*handler)(void)); diff --git a/sw/lib/source/neorv32_rte.c b/sw/lib/source/neorv32_rte.c index cba206115..aa0476574 100644 --- a/sw/lib/source/neorv32_rte.c +++ b/sw/lib/source/neorv32_rte.c @@ -493,21 +493,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 +527,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 @@ -620,7 +624,7 @@ void neorv32_rte_print_hw_config(void) { if (tmp & (1 << SYSINFO_SOC_XBUS)) { neorv32_uart0_printf("Wishbone-b4 "); if (tmp & (1 << SYSINFO_SOC_XBUS_CACHE)) { - neorv32_uart0_printf("x-cache\n"); + neorv32_uart0_printf("xbus-cache\n"); } else { neorv32_uart0_printf("\n"); diff --git a/sw/lib/source/neorv32_uart.c b/sw/lib/source/neorv32_uart.c index bd8d35b4c..08a245f6c 100644 --- a/sw/lib/source/neorv32_uart.c +++ b/sw/lib/source/neorv32_uart.c @@ -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; } diff --git a/sw/lib/source/neorv32_xirq.c b/sw/lib/source/neorv32_xirq.c index f2eb4299d..4904f92be 100644 --- a/sw/lib/source/neorv32_xirq.c +++ b/sw/lib/source/neorv32_xirq.c @@ -44,10 +44,8 @@ #include -/**********************************************************************//** - * The >private< trap vector look-up table of the XIRQ. - **************************************************************************/ -static uint32_t __neorv32_xirq_vector_lut[32] __attribute__((unused)); // trap handler vector table +// the private trap vector look-up table +static uint32_t __neorv32_xirq_vector_lut[32] __attribute__((unused)); // private functions static void __neorv32_xirq_core(void); @@ -73,15 +71,14 @@ int neorv32_xirq_available(void) { /**********************************************************************//** * Initialize XIRQ controller. * - * @note All interrupt channels will be deactivated, all pending IRQs will be deleted and all - * handler addresses will be deleted. + * @note All interrupt channels will be deactivated and all installed + * handlers addresses will be deleted. * * @return 0 if success, != 0 if error. **************************************************************************/ int neorv32_xirq_setup(void) { - NEORV32_XIRQ->EIE = 0; // disable all input channels - NEORV32_XIRQ->EIP = 0; // clear all pending IRQs + NEORV32_XIRQ->EIE = 0; // disable all channels NEORV32_XIRQ->ESC = 0; // acknowledge (clear) XIRQ interrupt int i; @@ -160,7 +157,7 @@ int neorv32_xirq_get_num(void) { * Configure a channel's trigger type. * * @param[in] channel XIRQ interrupt channel (0..31). - * @param[in] config Trigger type: 00 = low-level, 01 = high-level, 10 = falling-edge, 11 = rising-edge. + * @param[in] config Trigger type (#XIRQ_TRIGGER_enum). **************************************************************************/ void neorv32_xirq_setup_trigger(int channel, int config) { @@ -185,18 +182,6 @@ void neorv32_xirq_setup_trigger(int channel, int config) { } -/**********************************************************************//** - * Clear pending interrupt. - * - * @param[in] channel XIRQ interrupt channel (0..31). - **************************************************************************/ -void neorv32_xirq_clear_pending(int channel) { - - channel &= 0x1f; - NEORV32_XIRQ->EIP = ~(1 << channel); -} - - /**********************************************************************//** * Enable IRQ channel. * @@ -204,8 +189,7 @@ void neorv32_xirq_clear_pending(int channel) { **************************************************************************/ void neorv32_xirq_channel_enable(int channel) { - channel &= 0x1f; - NEORV32_XIRQ->EIE |= 1 << channel; + NEORV32_XIRQ->EIE |= 1 << (channel & 0x1f); } @@ -216,8 +200,7 @@ void neorv32_xirq_channel_enable(int channel) { **************************************************************************/ void neorv32_xirq_channel_disable(int channel) { - channel &= 0x1f; - NEORV32_XIRQ->EIE &= ~(1 << channel); + NEORV32_XIRQ->EIE &= ~(1 << (channel & 0x1f)); } @@ -226,7 +209,7 @@ void neorv32_xirq_channel_disable(int channel) { * * @param[in] channel XIRQ interrupt channel (0..31). * @param[in] handler The actual handler function for the specified interrupt (function MUST be of type "void function(void);"). - * @return 0 if success, 1 if error. + * @return 0 if success, -1 if invalid channel. **************************************************************************/ int neorv32_xirq_install(int channel, void (*handler)(void)) { @@ -235,7 +218,9 @@ int neorv32_xirq_install(int channel, void (*handler)(void)) { __neorv32_xirq_vector_lut[channel] = (uint32_t)handler; // install handler return 0; } - return 1; + else { + return -1; + } } @@ -245,39 +230,40 @@ int neorv32_xirq_install(int channel, void (*handler)(void)) { * @note This will also deactivate the according XIRQ channel. * * @param[in] channel XIRQ interrupt channel (0..31). - * @return 0 if success, 1 if error. + * @return 0 if success, -1 if invalid channel. **************************************************************************/ int neorv32_xirq_uninstall(int channel) { // channel valid? if (channel < 32) { __neorv32_xirq_vector_lut[channel] = (uint32_t)(&__neorv32_xirq_dummy_handler); // override using dummy handler - uint32_t mask = 1 << channel; - NEORV32_XIRQ->EIE &= ~mask; // disable channel + neorv32_xirq_channel_disable(channel); // disable channel return 0; } - return 1; + else { + return -1; + } } /**********************************************************************//** * This is the actual second-level (F)IRQ handler for the XIRQ. It will * call the previously installed handler if an XIRQ fires. + * + * @note The XIRQ's channel interrupt is acknowledge AFTER the handler has been executed. **************************************************************************/ static void __neorv32_xirq_core(void) { // get highest-priority XIRQ channel - uint32_t src = NEORV32_XIRQ->ESC; - - // clear the currently pending XIRQ interrupt - NEORV32_XIRQ->EIP = ~(1 << src); + uint32_t src = NEORV32_XIRQ->ESC & 0x1f; // mask for channel ID // execute handler typedef void handler_t(); handler_t* handler = (handler_t*)__neorv32_xirq_vector_lut[src]; handler(); - NEORV32_XIRQ->ESC = 0; // acknowledge the current XIRQ interrupt + // acknowledge XIRQ channel interrupt + NEORV32_XIRQ->ESC = 0; } diff --git a/sw/openocd/openocd_neorv32.cfg b/sw/openocd/openocd_neorv32.cfg index cc805eae8..57cb3aeaf 100644 --- a/sw/openocd/openocd_neorv32.cfg +++ b/sw/openocd/openocd_neorv32.cfg @@ -14,10 +14,10 @@ transport select jtag # ------------------------------------------------------------------- # Target configuration # ------------------------------------------------------------------- -set _CHIPNAME neorv32 -jtag newtap $_CHIPNAME cpu -irlen 5 -set _TARGETNAME $_CHIPNAME.cpu -target create $_TARGETNAME.0 riscv -chain-position $_TARGETNAME +set chipname neorv32 +jtag newtap $chipname cpu -irlen 5 +set targetname $chipname.cpu +target create $targetname.0 riscv -chain-position $targetname # expose NEORV32-specific CSRs riscv expose_csrs 2048=cfureg0 diff --git a/sw/svd/neorv32.svd b/sw/svd/neorv32.svd index 52b90a2ce..bab0b9b22 100644 --- a/sw/svd/neorv32.svd +++ b/sw/svd/neorv32.svd @@ -4,7 +4,7 @@ stnolting neorv32 RISC-V - 1.10.5 + 1.10.6 The NEORV32 RISC-V Processor @@ -847,29 +847,24 @@ - IER - IRQ input enable register + EIE + External IRQ channel enable register 0x00 - IPR - IRQ pending/ack/clear register + ESC + External IRQ source register 0x04 - - SCR - IRQ source register - 0x08 - TTYP - IRQ trigger type (level/edge) - 0x0c + External IRQ trigger type (level/edge) + 0x08 TPOL - IRQ trigger polarity (high/low, rising/falling) - 0x10 + External IRQ trigger polarity (high/low, rising/falling) + 0x0c @@ -1596,10 +1591,10 @@ 0x04 read-only - SYSINFO_MEM_0[7:0]log2(IMEM size in bytes) - SYSINFO_MEM_1[15:8]log2(DMEM size in bytes) - SYSINFO_MEM_2[23:16]yet unused - SYSINFO_MEM_3[31:24]yet unused + SYSINFO_MEM_IMEM[7:0]log2(IMEM size in bytes) + SYSINFO_MEM_DMEM[15:8]log2(DMEM size in bytes) + SYSINFO_MEM_res[23:16]yet unused + SYSINFO_MEM_BOOT[31:24]Boot mode configuration select @@ -1620,6 +1615,7 @@ SYSINFO_SOC_XIP[9:9]Execute in place module implemented SYSINFO_SOC_XIP_CACHE[10:10]Execute in place cache implemented SYSINFO_SOC_OCD_AUTH[11:11]On-chip debugger authentication implemented + SYSINFO_SOC_IMEM_ROM[12:12]Processor-internal instruction memory implemented as pre-initialized ROM SYSINFO_SOC_IO_DMA[14:14]Direct memory access controller implemented SYSINFO_SOC_IO_GPIO[15:15]General purpose input/output port unit implemented SYSINFO_SOC_IO_MTIME[16:16]Machine system timer implemented