diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d5630ade..2e38c5ed0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12 | Date (*dd.mm.yyyy*) | Version | Comment | |:-------------------:|:-------:|:--------| +| 04.08.2023 | 1.8.7.5 | :warning: major code edits/cleanups and file renaming; #664 | | 29.07.2023 | 1.8.7.4 | RTL cleanup and optimizations (less synthesis warnings, less resource requirements); [#660](https://github.com/stnolting/neorv32/pull/660) | | 28.07.2023 | 1.8.7.3 | :warning: reworked **SYSINFO** module; clean-up address space layout; clean-up assertion notes; [#659](https://github.com/stnolting/neorv32/pull/659) | | 27.07.2023 | 1.8.7.2 | :bug: make sure that IMEM/DMEM size is always a power of two; [#658](https://github.com/stnolting/neorv32/pull/658) | diff --git a/docs/datasheet/cpu.adoc b/docs/datasheet/cpu.adoc index df20769ea..12bba88ec 100644 --- a/docs/datasheet/cpu.adoc +++ b/docs/datasheet/cpu.adoc @@ -112,10 +112,6 @@ The co-processors are implemented as iterative units that require several cycles the co-processors are used to implement all further processing-based ISA extensions (e.g. <<_m_isa_extension>> and <<_b_isa_extension>>). -Once triggered, the selected co-processor is required to complete processing within a bound time window. Otherwise the co-processor -operation is terminated by the hardware and an illegal instruction exception is raised. The time window is 2^T^ clock cycles -wide; _T_ is defined by the `cp_timeout_c` VHDL package constant (default = 7 -> 128 cycles). - :sectnums: ==== CPU Bus Unit @@ -680,7 +676,7 @@ will raise an illegal instruction exception if <<_mstatus>>`.TW` is set. ==== `Zihpm` ISA Extension -In additions to the base counters the NEORV32 CPU provides up to 29 hardware performance monitors (HPM 3..31), +In additions to the base counters the NEORV32 CPU provides up to 13 hardware performance monitors (HPM 3..15), which can be used to benchmark applications. Each HPM consists of an N-bit wide counter (split in a high-word 32-bit CSR and a low-word 32-bit CSR), where N is defined via the top's `HPM_CNT_WIDTH` generic and a corresponding event configuration CSR. The event configuration diff --git a/docs/datasheet/cpu_csr.adoc b/docs/datasheet/cpu_csr.adoc index a1eb83423..14468b9e2 100644 --- a/docs/datasheet/cpu_csr.adoc +++ b/docs/datasheet/cpu_csr.adoc @@ -5,7 +5,7 @@ The following table shows a summary of all available NEORV32 CSRs. The address field defines the CSR address for the CSR access instructions. The "Name [ASM]" column provides the CSR name aliases that can be used in (inline) assembly. The "Name [C]" column lists the name aliases that are defined by the NEORV32 core library. These can be used in plain C code. -The "ACC" column shows the minimal required privilege level required for accessing the according CSR (`M` = machine-mode, +The "ACC" column shows the minimal required privilege mode required for accessing the according CSR (`M` = machine-mode, `U` = user-mode, `D` = debug-mode) and the read/write capabilities (`RW` = read-write, `RO` = read-only) .Unused, Reserved and Excluded CSRs @@ -32,8 +32,8 @@ Any illegal read access to a CSR will return zero in the operation's destination | 0x002 | <<_frm>> | `CSR_FRM` | URW | Floating-point dynamic rounding mode | 0x003 | <<_fcsr>> | `CSR_FCSR` | URW | Floating-point control and status (`frm` + `fflags`) 5+^| **<<_machine_configuration_csrs>>** -| 0x30A | <<_menvcfg>> | `CSR_MENVCFG` | MRW | Machine environment configuration register - low word -| 0x31A | <<_menvcfgh>> | `CSR_MENVCFGH` | MRW | Machine environment configuration register - low word +| 0x30a | <<_menvcfg>> | `CSR_MENVCFG` | MRW | Machine environment configuration register - low word +| 0x31a | <<_menvcfgh>> | `CSR_MENVCFGH` | MRW | Machine environment configuration register - low word 5+^| **<<_machine_trap_setup_csrs>>** | 0x300 | <<_mstatus>> | `CSR_MSTATUS` | MRW | Machine status register - low word | 0x301 | <<_misa>> | `CSR_MISA` | MRW | Machine CPU ISA and extensions @@ -48,46 +48,46 @@ Any illegal read access to a CSR will return zero in the operation's destination | 0x343 | <<_mtval>> | `CSR_MTVAL` | MRW | Machine bad address or instruction | 0x344 | <<_mip>> | `CSR_MIP` | MRW | Machine interrupt pending register 5+^| **<<_machine_physical_memory_protection_csrs>>** -| 0x3A0 .. 0x3AF | <<_pmpcfg, `pmpcfg0`>> .. <<_pmpcfg, `pmpcfg15`>> | `CSR_PMPCFG0` .. `CSR_PMPCFG15` | MRW | Physical memory protection configuration for region 0..15 -| 0x3B0 .. 0x3EF | <<_pmpaddr, `pmpaddr0`>> .. <<_pmpaddr, `pmpaddr63`>> | `CSR_PMPADDR0` .. `CSR_PMPADDR63` | MRW | Physical memory protection address register region 0..15 +| 0x3a0 .. 0x303 | <<_pmpcfg, `pmpcfg0`>> .. <<_pmpcfg, `pmpcfg3`>> | `CSR_PMPCFG0` .. `CSR_PMPCFG3` | MRW | Physical memory protection configuration registers +| 0x3b0 .. 0x3BF | <<_pmpaddr, `pmpaddr0`>> .. <<_pmpaddr, `pmpaddr15`>> | `CSR_PMPADDR0` .. `CSR_PMPADDR15` | MRW | Physical memory protection address registers 5+^| **<<_trigger_module_csrs>>** -| 0x7A0 | <<_tselect>> | `CSR_TSELECT` | MRW | Trigger select register -| 0x7A1 | <<_tdata1>> | `CSR_TDATA1` | MRW | Trigger data register 1 -| 0x7A2 | <<_tdata2>> | `CSR_TDATA2` | MRW | Trigger data register 2 -| 0x7A3 | <<_tdata3>> | `CSR_TDATA3` | MRW | Trigger data register 3 -| 0x7A4 | <<_tinfo>> | `CSR_TINFO` | MRW | Trigger information register -| 0x7A5 | <<_tcontrol>> | `CSR_TCONTROL` | MRW | Trigger control register -| 0x7A8 | <<_mcontext>> | `CSR_MCONTEXT` | MRW | Machine context register -| 0x7AA | <<_scontext>> | `CSR_SCONTEXT` | MRW | Supervisor context register +| 0x7a0 | <<_tselect>> | `CSR_TSELECT` | MRW | Trigger select register +| 0x7a1 | <<_tdata1>> | `CSR_TDATA1` | MRW | Trigger data register 1 +| 0x7a2 | <<_tdata2>> | `CSR_TDATA2` | MRW | Trigger data register 2 +| 0x7a3 | <<_tdata3>> | `CSR_TDATA3` | MRW | Trigger data register 3 +| 0x7a4 | <<_tinfo>> | `CSR_TINFO` | MRW | Trigger information register +| 0x7a5 | <<_tcontrol>> | `CSR_TCONTROL` | MRW | Trigger control register +| 0x7a8 | <<_mcontext>> | `CSR_MCONTEXT` | MRW | Machine context register +| 0x7aa | <<_scontext>> | `CSR_SCONTEXT` | MRW | Supervisor context register 5+^| **<<_cpu_debug_mode_csrs>>** -| 0x7B0 | <<_dcsr>> | - | DRW | Debug control and status register -| 0x7B1 | <<_dpc>> | - | DRW | Debug program counter -| 0x7B2 | <<_dscratch0>> | - | DRW | Debug scratch register 0 +| 0x7b0 | <<_dcsr>> | - | DRW | Debug control and status register +| 0x7b1 | <<_dpc>> | - | DRW | Debug program counter +| 0x7b2 | <<_dscratch0>> | - | DRW | Debug scratch register 0 5+^| **<<_machine_counter_and_timer_csrs>>** -| 0xB00 | <<_mcycleh, `mcycle`>> | `CSR_MCYCLE` | MRW | Machine cycle counter low word -| 0xB02 | <<_minstreth, `minstret`>> | `CSR_MINSTRET` | MRW | Machine instruction-retired counter low word -| 0xB80 | <<_mcycleh, `mcycleh`>> | `CSR_MCYCLEH` | MRW | Machine cycle counter high word -| 0xB82 | <<_minstreth, `minstreth`>> | `CSR_MINSTRETH` | MRW | Machine instruction-retired counter high word -| 0xC00 | <<_cycleh, `cycle`>> | `CSR_CYCLE` | URO | Cycle counter low word -| 0xC02 | <<_instreth, `instret`>> | `CSR_INSTRET` | URO | Instruction-retired counter low word -| 0xC80 | <<_cycleh, `cycleh`>> | `CSR_CYCLEH` | URO | Cycle counter high word -| 0xC82 | <<_instreth, `instreth`>> | `CSR_INSTRETH` | URO | Instruction-retired counter high word +| 0xb00 | <<_mcycleh, `mcycle`>> | `CSR_MCYCLE` | MRW | Machine cycle counter low word +| 0xb02 | <<_minstreth, `minstret`>> | `CSR_MINSTRET` | MRW | Machine instruction-retired counter low word +| 0xb80 | <<_mcycleh, `mcycleh`>> | `CSR_MCYCLEH` | MRW | Machine cycle counter high word +| 0xb82 | <<_minstreth, `minstreth`>> | `CSR_MINSTRETH` | MRW | Machine instruction-retired counter high word +| 0xc00 | <<_cycleh, `cycle`>> | `CSR_CYCLE` | URO | Cycle counter low word +| 0xc02 | <<_instreth, `instret`>> | `CSR_INSTRET` | URO | Instruction-retired counter low word +| 0xc80 | <<_cycleh, `cycleh`>> | `CSR_CYCLEH` | URO | Cycle counter high word +| 0xc82 | <<_instreth, `instreth`>> | `CSR_INSTRETH` | URO | Instruction-retired counter high word 5+^| **<<_hardware_performance_monitors_hpm_csrs>>** -| 0x323 .. 0x33F | <<_mhpmevent, `mhpmevent3`>> .. <<_mhpmevent, `mhpmevent31`>> | `CSR_MHPMEVENT3` .. `CSR_MHPMEVENT31` | MRW | Machine performance-monitoring event select for counter 3..31 -| 0xB03 .. 0xB1F | <<_mhpmcounterh, `mhpmcounter3`>> .. <<_mhpmcounterh, `mhpmcounter31`>> | `CSR_MHPMCOUNTER3` .. `CSR_MHPMCOUNTER3H` | MRW | Machine performance-monitoring counter 3..31 low word -| 0xB83 .. 0xB9F | <<_mhpmcounterh, `mhpmcounter3h`>> .. <<_mhpmcounterh, `mhpmcounter31h`>> | `CSR_MHPMCOUNTER3H` .. `CSR_MHPMCOUNTER31H` | MRW | Machine performance-monitoring counter 3..31 high word -| 0xC03 .. 0xC1F | <<_hpmcounterh, `hpmcounter3`>> .. <<_hpmcounterh, `hpmcounter31`>> | `CSR_HPMCOUNTER3` .. `CSR_HPMCOUNTER3H` | URO | User performance-monitoring counter 3..31 low word -| 0xC83 .. 0xC9F | <<_hpmcounterh, `hpmcounter3h`>> .. <<_hpmcounterh, `hpmcounter31h`>> | `CSR_HPMCOUNTER3H` .. `CSR_HPMCOUNTER31H` | URO | User performance-monitoring counter 3..31 high word +| 0x323 .. 0x32F | <<_mhpmevent, `mhpmevent3`>> .. <<_mhpmevent, `mhpmevent15`>> | `CSR_MHPMEVENT3` .. `CSR_MHPMEVENT15` | MRW | Machine performance-monitoring event select for counter 3..15 +| 0xb03 .. 0xB0F | <<_mhpmcounterh, `mhpmcounter3`>> .. <<_mhpmcounterh, `mhpmcounter15`>> | `CSR_MHPMCOUNTER3` .. `CSR_MHPMCOUNTER15` | MRW | Machine performance-monitoring counter 3..15 low word +| 0xb83 .. 0xB8F | <<_mhpmcounterh, `mhpmcounter3h`>> .. <<_mhpmcounterh, `mhpmcounter15h`>> | `CSR_MHPMCOUNTER3H` .. `CSR_MHPMCOUNTER15H` | MRW | Machine performance-monitoring counter 3..15 high word +| 0xc03 .. 0xC0F | <<_hpmcounterh, `hpmcounter3`>> .. <<_hpmcounterh, `hpmcounter15`>> | `CSR_HPMCOUNTER3` .. `CSR_HPMCOUNTER15H` | URO | User performance-monitoring counter 3..15 low word +| 0xc83 .. 0xC8F | <<_hpmcounterh, `hpmcounter3h`>> .. <<_hpmcounterh, `hpmcounter15h`>> | `CSR_HPMCOUNTER3H` .. `CSR_HPMCOUNTER15H` | URO | User performance-monitoring counter 3..15 high word 5+^| **<<_machine_counter_setup_csrs>>** | 0x320 | <<_mcountinhibit>> | `CSR_MCOUNTINHIBIT` | MRW | Machine counter-inhibit register 5+^| **<<_machine_information_csrs>>** -| 0xF11 | <<_mvendorid>> | `CSR_MVENDORID` | MRO | Machine vendor ID -| 0xF12 | <<_marchid>> | `CSR_MARCHID` | MRO | Machine architecture ID -| 0xF13 | <<_mimpid>> | `CSR_MIMPID` | MRO | Machine implementation ID / version -| 0xF14 | <<_mhartid>> | `CSR_MHARTID` | MRO | Machine hardware thread ID -| 0xF15 | <<_mconfigptr>> | `CSR_MCONFIGPTR` | MRO | Machine configuration pointer register +| 0xf11 | <<_mvendorid>> | `CSR_MVENDORID` | MRO | Machine vendor ID +| 0xf12 | <<_marchid>> | `CSR_MARCHID` | MRO | Machine architecture ID +| 0xf13 | <<_mimpid>> | `CSR_MIMPID` | MRO | Machine implementation ID / version +| 0xf14 | <<_mhartid>> | `CSR_MHARTID` | MRO | Machine hardware thread ID +| 0xf15 | <<_mconfigptr>> | `CSR_MCONFIGPTR` | MRO | Machine configuration pointer register 5+^| **<<_neorv32_specific_csrs>>** -| 0xFC0 | <<_mxisa>> | `CSR_MXISA` | MRO | NEORV32-specific "extended" machine CPU ISA and extensions +| 0xfc0 | <<_mxisa>> | `CSR_MXISA` | MRO | NEORV32-specific "extended" machine CPU ISA and extensions |======================= @@ -230,8 +230,8 @@ Any illegal read access to a CSR will return zero in the operation's destination | Bit | Name [C] | R/W | Function | 3 | `CSR_MSTATUS_MIE` | r/w | **MIE**: Machine global interrupt enable flag | 7 | `CSR_MSTATUS_MPIE` | r/w | **MPIE**: Previous machine global interrupt enable flag state -| 12:11 | `CSR_MSTATUS_MPP_H` : `CSR_MSTATUS_MPP_L` | r/w | **MPP**: Previous machine privilege level, 11 = machine (M) level, 00 = user (U) level -| 17 | `CSR_MSTATUS_MPRV` | r/w | **MPRV**: Effective privilege level for load/stores in machine mode; use `MPP`'s as effective privilege level when set; hardwired to zero if user-mode not implemented +| 12:11 | `CSR_MSTATUS_MPP_H` : `CSR_MSTATUS_MPP_L` | r/w | **MPP**: Previous machine privilege mode, 11 = machine (M) mode, 00 = user (U) mode +| 17 | `CSR_MSTATUS_MPRV` | r/w | **MPRV**: Effective privilege mode for load/stores in machine mode; use `MPP`'s as effective privilege mode when set; hardwired to zero if user-mode not implemented | 21 | `CSR_MSTATUS_TW` | r/w | **TW**: Trap on execution of `wfi` instruction in user mode when set; hardwired to zero if user-mode not implemented |======================= @@ -343,7 +343,7 @@ interrupt is triggered or an exception is raised. | Address | `0x306` | Reset value | `0x00000000` | ISA | `Zicsr` + `U` -| Description | The `mcounteren` CSR is used to constrain user-level access to the CPU's counter CSRs. +| Description | The `mcounteren` CSR is used to constrain user-mode access to the CPU's counter CSRs. This CSR is also available if U mode is disabled, but the register is hardwired to all-zero in this case. |======================= @@ -352,10 +352,10 @@ This CSR is also available if U mode is disabled, but the register is hardwired [options="header",grid="rows"] |======================= | Bit | R/W | Function -| 0 | r/w | **CY**: User-level code is allowed to read <<_cycleh>> CSRs when set +| 0 | r/w | **CY**: User-mode code is allowed to read <<_cycleh>> CSRs when set | 1 | r/- | **TM**: Hardwired to zero as `time[h]` CSRs are not implemented -| 2 | r/w | **IR**: User-level code is allowed to read <<_instreth>> CSRs when set -| 31:3 | r/w | **HPM**: user-level code is allowed to read <<_hpmcounterh>> CSRs when set +| 2 | r/w | **IR**: User-mode code is allowed to read <<_instreth>> CSRs when set +| 15:3 | r/w | **HPM**: user-mode code is allowed to read <<_hpmcounterh>> CSRs when set |======================= @@ -477,8 +477,8 @@ maintain RISC-V compatibility. | Address | `0x344` | Reset value | `0x00000000` | ISA | `Zicsr` -| Description | The `mip` CSR shows currently _pending_ machine-level interrupt requests. The bits for the standard RISC-V -machine-level interrupts (`MEIP`, `MTIP`, `MSIP`) are read-only. Hence, these interrupts cannot be +| Description | The `mip` CSR shows currently _pending_ machine-mode interrupt requests. The bits for the standard RISC-V +machine-mode interrupts (`MEIP`, `MTIP`, `MSIP`) are read-only. Hence, these interrupts cannot be cleared/set using the `mip` register. These interrupts are cleared/acknowledged by mechanism that are specific for the interrupt-causing modules. the according interrupt-generating device. |======================= @@ -518,16 +518,12 @@ See section <<_pmp_isa_extension>> for more information. [frame="topbot",grid="none"] |======================= | Name | PMP region configuration registers -| Address | `0x3a0` (`pmpcfg0`) ... `0x3af` (`pmpcfg15`) +| Address | `0x3a0` (`pmpcfg0`) ... `0x3a3` (`pmpcfg3`) | Reset value | `0x00000000` | ISA | `Zicsr` + `PMP` | Description | Configuration of physical memory protection regions. Each region provides an individual 8-bit array in these CSRs. |======================= -[IMPORTANT] -Note that only PMP configuration registers `pmpcfg0` to `pmpcfg3` will be implemented if `PMP_NUM_REGIONS` is set to its -maximum value (=16). The remaining `pmpcfg4` to `pmpcfg15` CSRs are read-only and will always read as zero. - .`pmpcfg0` CSR Bits [cols="^1,^2,^1,<11"] [options="header",grid="rows"] @@ -552,16 +548,12 @@ The `pmpaddr*` CSRs are used to configure the region's address boundaries. [frame="topbot",grid="none"] |======================= | Name | Physical memory protection address registers -| Address | `0x3b0` (`pmpaddr0`) ... `0x3ef` (`pmpaddr63`) +| Address | `0x3b0` (`pmpaddr0`) ... `0x3bf` (`pmpaddr15`) | Reset value | `0x00000000` | ISA | `Zicsr` + `PMP` | Description | Region address configuration. The two MSBs of each CSR are hardwired to zero (= bits 33:32 of the physical address). |======================= -[IMPORTANT] -Note that only PMP address registers `pmpaddr0` to `pmpaddr15` will be implemented if `PMP_NUM_REGIONS` is set to its -maximum value (=16). The remaining `pmpaddr16` to `pmpaddr63` CSRs are read-only and will always read as zero. - .Address Register Update Latency [IMPORTANT] After writing a `pmpaddr` CSR the hardware requires up to 32 clock cycles to compute the according @@ -595,7 +587,7 @@ if this instruction is actually going to retire or if it causes an exception. | Address | `0xc00` (`cycle`), `0xc80` (`cycleh`) | Reset value | `0x00000000` | ISA | `Zicsr` + `Zicntr` -| Description | The `cycle[h]` CSRs are user-mode shadow copies of the according <<_mcycleh>> CSRs. The user-level +| Description | The `cycle[h]` CSRs are user-mode shadow copies of the according <<_mcycleh>> CSRs. The user-mode counter are read-only. Any write access will raise an illegal instruction exception. |======================= @@ -611,7 +603,7 @@ counter are read-only. Any write access will raise an illegal instruction except | Address | `0xc02` (`instret`), `0xc82` (`instreth`) | Reset value | `0x00000000` | ISA | `Zicsr` + `Zicntr` -| Description | The `instret[h]` CSRs are user-mode shadow copies of the according <<_minstreth>> CSRs. The user-level +| Description | The `instret[h]` CSRs are user-mode shadow copies of the according <<_minstreth>> CSRs. The user-mode counter are read-only. Any write access will raise an illegal instruction exception. |======================= @@ -654,7 +646,7 @@ These registers are read/write only for machine-mode software ==== Hardware Performance Monitors (HPM) CSRs The actual number of implemented hardware performance monitors is configured via the `HPM_NUM_CNTS` top entity generic, -Note that always all 28 HPM counter and configuration registers (`mhpmcounter*[h]` and `mhpmevent*`) are implemented, but +Note that always all 13 HPM counter and configuration registers (`mhpmcounter*[h]` and `mhpmevent*`) are implemented, but only the actually configured ones are implemented as "real" physical registers - the remaining ones will be hardwired to zero. If trying to access an HPM-related CSR beyond `HPM_NUM_CNTS` **no illegal instruction exception is @@ -671,7 +663,7 @@ If `HPM_NUM_CNTS` is less than 64, all remaining MSB-aligned bits are hardwired [frame="topbot",grid="none"] |======================= | Name | Machine hardware performance monitor event select -| Address | `0x232` (`mhpmevent3`) ... `0x33f` (`mhpmevent31`) +| Address | `0x233` (`mhpmevent3`) ... `0x32f` (`mhpmevent15`) | Reset value | `0x00000000` | ISA | `Zicsr` + `Zihpm` | Description | The value in these CSRs define the architectural events that cause an increment of the according `mhpmcounter*[h]` counter(s). @@ -712,8 +704,8 @@ cycle even if more than one trigger event is observed. [frame="topbot",grid="none"] |======================= | Name | Machine hardware performance monitor -| Address | `0xb03` (`mhpmcounter3`) ... `0xb1f` (mhpmcounter31) -| | `0xb83` (`mhpmcounter3h`) ... `0xb9f` (`mhpmcounter31h`) +| Address | `0xb03` (`mhpmcounter3`) ... `0xb0f` (mhpmcounter15) +| | `0xb83` (`mhpmcounter3h`) ... `0xb8f` (`mhpmcounter15h`) | Reset value | `0x00000000` | ISA | `Zicsr` + `Zihpm` | Description | If not halted via the <<_mcountinhibit>> CSR the HPM counter CSR(s) increment whenever a @@ -730,11 +722,11 @@ and are not accessible for lower-privileged software. [frame="topbot",grid="none"] |======================= | Name | User hardware performance monitor -| Address | `0xc03` (`hpmcounter3`) ... `0xc1f` (hpmcounter31) -| | `0xc83` (`hpmcounter3h`) ... `0xc9f` (`hpmcounter31h`) +| Address | `0xc03` (`hpmcounter3`) ... `0xc0f` (hpmcounter15) +| | `0xc83` (`hpmcounter3h`) ... `0xc8f` (`hpmcounter15h`) | Reset value | `0x00000000` | ISA | `Zicsr` + `Zihpm` -| Description | The `hpmcounter*[h]` are user-level shadow copies of the according <<_mhpmcounterh>> CSRs. The user level +| Description | The `hpmcounter*[h]` are user-mode shadow copies of the according <<_mhpmcounterh>> CSRs. The user mode counter CSRs are read-only. Any write access will raise an illegal instruction exception. |======================= @@ -766,7 +758,7 @@ counter CSRs are read-only. Any write access will raise an illegal instruction e | 0 | `CSR_MCOUNTINHIBIT_IR` | r/w | **IR**: Set to `1` to halt `[m]instret[h]`; hardwired to zero if `Zicntr` ISA extension is disabled | 1 | - | r/- | **TM**: Hardwired to zero as `time[h]` CSRs are not implemented | 2 | `CSR_MCOUNTINHIBIT_CY` | r/w | **CY**: Set to `1` to halt `[m]cycle[h]`; hardwired to zero if `Zicntr` ISA extension is disabled -| 3:31 | `CSR_MCOUNTINHIBIT_HPM3` : `CSR_MCOUNTINHIBIT_HPM31` | r/w | **HPMx**: Set to `1` to halt `[m]hpmcount*[h]`; hardwired to zero if `Zihpm` ISA extension is disabled +| 15:3 | `CSR_MCOUNTINHIBIT_HPM3` : `CSR_MCOUNTINHIBIT_HPM31` | r/w | **HPMx**: Set to `1` to halt `[m]hpmcount*[h]`; hardwired to zero if `Zihpm` ISA extension is disabled |======================= diff --git a/docs/datasheet/overview.adoc b/docs/datasheet/overview.adoc index d959612de..77cb06a86 100644 --- a/docs/datasheet/overview.adoc +++ b/docs/datasheet/overview.adoc @@ -192,7 +192,8 @@ All core VHDL files from the list below have to be assigned to a new design libr │ ├-neorv32_cpu_cp_shifter.vhd - Bit-shift co-processor (base ISA) │ ├-neorv32_cpu_cp_muldiv.vhd - Mul/Div co-processor (M ext.) │ ┌-neorv32_cpu_alu.vhd - Arithmetic/logic unit -│ ├-neorv32_cpu_bus.vhd - Load/store unit + physical memory protection +│ ├-neorv32_cpu_pmp.vhd - Physical memory protection unit +│ ├-neorv32_cpu_lsu.vhd - Load/store unit │ │ ┌-neorv32_cpu_decompressor.vhd - Compressed instructions decoder │ ├-neorv32_cpu_control.vhd - CPU control, exception system and CSRs │ ├-neorv32_cpu_regfile.vhd - Data register file diff --git a/docs/datasheet/soc.adoc b/docs/datasheet/soc.adoc index b7addc4c3..1e81a5d7f 100644 --- a/docs/datasheet/soc.adoc +++ b/docs/datasheet/soc.adoc @@ -225,7 +225,7 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt | `PMP_NUM_REGIONS` | natural | 0 | Number of implemented PMP regions (0..16). | `PMP_MIN_GRANULARITY` | natural | 4 | Minimal region granularity in bytes. Has to be a power of two, min 4. 4+^| **Hardware Performance Monitors (<<_zihpm_isa_extension>>)** -| `HPM_NUM_CNTS` | natural | 0 | Number of implemented hardware performance monitor counters (0..29). +| `HPM_NUM_CNTS` | natural | 0 | Number of implemented hardware performance monitor counters (0..13). | `HPM_CNT_WIDTH` | natural | 40 | Total LSB-aligned size of each HPM counter. Min 0, max 64. 4+^| **Atomic Memory Access Reservation Set Granularity (<<_a_isa_extension>>)** | `AMO_RVS_GRANULARITY` | natural | 4 | Size in bytes, has to be a power of 2, min 4. diff --git a/rtl/core/neorv32_cpu.vhd b/rtl/core/neorv32_cpu.vhd index 3268e60df..0ad13d952 100644 --- a/rtl/core/neorv32_cpu.vhd +++ b/rtl/core/neorv32_cpu.vhd @@ -70,7 +70,7 @@ entity neorv32_cpu is PMP_NUM_REGIONS : natural; -- number of regions (0..16) PMP_MIN_GRANULARITY : natural; -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes -- Hardware Performance Monitors (HPM) -- - HPM_NUM_CNTS : natural; -- number of implemented HPM counters (0..29) + HPM_NUM_CNTS : natural; -- number of implemented HPM counters (0..13) HPM_CNT_WIDTH : natural -- total size of HPM counters (0..64) ); port ( @@ -101,6 +101,15 @@ architecture neorv32_cpu_rtl of neorv32_cpu is -- auto-configuration -- constant regfile_rs3_en_c : boolean := CPU_EXTENSION_RISCV_Zxcfu or CPU_EXTENSION_RISCV_Zfinx; -- 3rd register file read port (rs3) constant regfile_rs4_en_c : boolean := CPU_EXTENSION_RISCV_Zxcfu; -- 4th register file read port (rs4) + constant pmp_enable_c : boolean := boolean(PMP_NUM_REGIONS > 0); + + -- external CSR interface -- + signal xcsr_we : std_ulogic; + signal xcsr_addr : std_ulogic_vector(11 downto 0); + signal xcsr_wdata : std_ulogic_vector(XLEN-1 downto 0); + signal xcsr_rdata_pmp : std_ulogic_vector(XLEN-1 downto 0); + signal xcsr_rdata_alu : std_ulogic_vector(XLEN-1 downto 0); + signal xcsr_rdata_res : std_ulogic_vector(XLEN-1 downto 0); -- local signals -- signal ctrl : ctrl_bus_t; -- main control bus @@ -114,7 +123,6 @@ architecture neorv32_cpu_rtl of neorv32_cpu is signal alu_cmp : std_ulogic_vector(1 downto 0); -- comparator result signal mem_rdata : std_ulogic_vector(XLEN-1 downto 0); -- memory read data signal cp_done : std_ulogic; -- ALU co-processor operation done - signal alu_exc : std_ulogic; -- ALU exception signal bus_d_wait : std_ulogic; -- wait for current data bus access signal csr_rdata : std_ulogic_vector(XLEN-1 downto 0); -- csr read data signal mar : std_ulogic_vector(XLEN-1 downto 0); -- memory address register @@ -125,12 +133,9 @@ architecture neorv32_cpu_rtl of neorv32_cpu is signal fetch_pc : std_ulogic_vector(XLEN-1 downto 0); -- pc for instruction fetch signal curr_pc : std_ulogic_vector(XLEN-1 downto 0); -- current pc (for currently executed instruction) signal next_pc : std_ulogic_vector(XLEN-1 downto 0); -- next pc (for next executed instruction) - signal fpu_flags : std_ulogic_vector(4 downto 0); -- FPU exception flags - signal i_pmp_fault : std_ulogic; -- instruction fetch PMP fault - - -- pmp interface -- - signal pmp_addr : pmp_addr_if_t; - signal pmp_ctrl : pmp_ctrl_if_t; + signal pmp_i_fault : std_ulogic; -- PMP instruction fetch fault + signal pmp_r_fault : std_ulogic; -- PMP read fault + signal pmp_w_fault : std_ulogic; -- PMP write fault begin @@ -138,7 +143,7 @@ begin -- ------------------------------------------------------------------------------------------- -- say hello -- assert false report - "The NEORV32 RISC-V Processor Version 0x" & to_hstring32_f(hw_version_c) & " - github.com/stnolting/neorv32" severity note; + "The NEORV32 RISC-V Processor, Version 0x" & to_hstring32_f(hw_version_c) & " - github.com/stnolting/neorv32" severity note; -- CPU ISA configuration -- assert false report @@ -159,7 +164,7 @@ begin cond_sel_string_f(CPU_EXTENSION_RISCV_Zxcfu, "_Zxcfu", "") & cond_sel_string_f(CPU_EXTENSION_RISCV_Sdext, "_Sdext", "") & cond_sel_string_f(CPU_EXTENSION_RISCV_Sdtrig, "_Sdtrig", "") & - "" + cond_sel_string_f(pmp_enable_c, "_Smpmp", "") severity note; -- simulation notifier -- @@ -170,17 +175,9 @@ begin assert not (CPU_BOOT_ADDR(1 downto 0) /= "00") report "NEORV32 CPU CONFIG ERROR! has to be 32-bit aligned." severity error; - -- PMP -- - assert not (PMP_NUM_REGIONS > 16) report - "NEORV32 CPU CONFIG ERROR! Number of PMP regions out of valid range (0..16)." severity error; - assert not ((is_power_of_two_f(PMP_MIN_GRANULARITY) = false) and (PMP_NUM_REGIONS > 0)) report - "NEORV32 CPU CONFIG ERROR! has to be a power of two." severity error; - assert not ((PMP_MIN_GRANULARITY < 4) and (PMP_NUM_REGIONS > 0)) report - "NEORV32 CPU CONFIG ERROR! has to be >= 4 bytes." severity error; - -- HPM counters -- - assert not ((CPU_EXTENSION_RISCV_Zihpm = true) and (HPM_NUM_CNTS > 29)) report - "NEORV32 CPU CONFIG ERROR! Number of HPM counters out of valid range (0..29)." severity error; + assert not ((CPU_EXTENSION_RISCV_Zihpm = true) and (HPM_NUM_CNTS > 13)) report + "NEORV32 CPU CONFIG ERROR! Number of HPM counters out of valid range (0..13)." severity error; assert not ((CPU_EXTENSION_RISCV_Zihpm = true) and ((HPM_CNT_WIDTH < 0) or (HPM_CNT_WIDTH > 64))) report "NEORV32 CPU CONFIG ERROR! HPM counter width has to be 0..64 bit." severity error; @@ -223,10 +220,9 @@ begin FAST_MUL_EN => FAST_MUL_EN, -- use DSPs for M extension's multiplier FAST_SHIFT_EN => FAST_SHIFT_EN, -- use barrel shifter for shift operations -- Physical memory protection (PMP) -- - PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (0..16) - PMP_MIN_GRANULARITY => PMP_MIN_GRANULARITY, -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes + PMP_EN => pmp_enable_c, -- physical memory protection enabled -- Hardware Performance Monitors (HPM) -- - HPM_NUM_CNTS => HPM_NUM_CNTS, -- number of implemented HPM counters (0..29) + HPM_NUM_CNTS => HPM_NUM_CNTS, -- number of implemented HPM counters (0..13) HPM_CNT_WIDTH => HPM_CNT_WIDTH -- total size of HPM counters ) port map ( @@ -240,10 +236,9 @@ begin i_bus_re_o => ibus_req_o.re, -- read enable i_bus_ack_i => ibus_rsp_i.ack, -- bus transfer acknowledge i_bus_err_i => ibus_rsp_i.err, -- bus transfer error - i_pmp_fault_i => i_pmp_fault, -- instruction fetch pmp fault + i_pmp_fault_i => pmp_i_fault, -- instruction fetch pmp fault -- status input -- alu_cp_done_i => cp_done, -- ALU iterative operation done - alu_exc_i => alu_exc, -- ALU exception bus_d_wait_i => bus_d_wait, -- wait for bus -- data input -- cmp_i => alu_cmp, -- comparator status @@ -254,8 +249,11 @@ begin curr_pc_o => curr_pc, -- current PC (corresponding to current instruction) next_pc_o => next_pc, -- next PC (corresponding to next instruction) csr_rdata_o => csr_rdata, -- CSR read data - -- FPU interface -- - fpu_flags_i => fpu_flags, -- exception flags + -- external CSR interface -- + xcsr_we_o => xcsr_we, -- global write enable + xcsr_addr_o => xcsr_addr, -- address + xcsr_wdata_o => xcsr_wdata, -- write data + xcsr_rdata_i => xcsr_rdata_res, -- read data -- debug mode (halt) request -- db_halt_req_i => dbi_i, -- interrupts (risc-v compliant) -- @@ -264,9 +262,6 @@ begin mti_i => mti_i, -- machine timer interrupt -- fast interrupts (custom) -- firq_i => firq_i, -- fast interrupt trigger - -- physical memory protection -- - pmp_addr_o => pmp_addr, -- addresses - pmp_ctrl_o => pmp_ctrl, -- configs -- bus access exceptions -- mar_i => mar, -- memory address register ma_load_i => ma_load, -- misaligned load data address @@ -275,19 +270,22 @@ begin be_store_i => be_store -- bus error on store data access ); + -- external CSR read-back -- + xcsr_rdata_res <= xcsr_rdata_pmp or xcsr_rdata_alu; + -- CPU state -- sleep_o <= ctrl.cpu_sleep; -- set when CPU is sleeping (after WFI) debug_o <= ctrl.cpu_debug; -- set when CPU is in debug mode -- instruction/data fence -- - ifence_o <= ctrl.bus_fencei; - dfence_o <= ctrl.bus_fence; + ifence_o <= ctrl.lsu_fencei; + dfence_o <= ctrl.lsu_fence; -- instruction fetch interface -- ibus_req_o.addr <= fetch_pc; ibus_req_o.priv <= ctrl.cpu_priv; - ibus_req_o.data <= (others => '0'); - ibus_req_o.ben <= (others => '0'); + ibus_req_o.data <= (others => '0'); -- read-only + ibus_req_o.ben <= (others => '0'); -- read-only ibus_req_o.we <= '0'; -- read-only ibus_req_o.src <= '1'; -- source = instruction fetch ibus_req_o.rvso <= '0'; -- cannot be a reservation set operation @@ -335,45 +333,43 @@ begin ) port map ( -- global control -- - clk_i => clk_i, -- global clock, rising edge - rstn_i => rstn_i, -- global reset, low-active, async - ctrl_i => ctrl, -- main control bus + clk_i => clk_i, -- global clock, rising edge + rstn_i => rstn_i, -- global reset, low-active, async + ctrl_i => ctrl, -- main control bus + -- CSR interface -- + csr_we_i => xcsr_we, -- global write enable + csr_addr_i => xcsr_addr, -- address + csr_wdata_i => xcsr_wdata, -- write data + csr_rdata_o => xcsr_rdata_alu, -- read data -- data input -- - rs1_i => rs1, -- rf source 1 - rs2_i => rs2, -- rf source 2 - rs3_i => rs3, -- rf source 3 - rs4_i => rs4, -- rf source 4 - pc_i => curr_pc, -- current PC - imm_i => imm, -- immediate + rs1_i => rs1, -- rf source 1 + rs2_i => rs2, -- rf source 2 + rs3_i => rs3, -- rf source 3 + rs4_i => rs4, -- rf source 4 + pc_i => curr_pc, -- current PC + imm_i => imm, -- immediate -- data output -- - cmp_o => alu_cmp, -- comparator status - res_o => alu_res, -- ALU result - add_o => alu_add, -- address computation result - fpu_flags_o => fpu_flags, -- FPU exception flags + cmp_o => alu_cmp, -- comparator status + res_o => alu_res, -- ALU result + add_o => alu_add, -- address computation result -- status -- - exc_o => alu_exc, -- ALU exception - cp_done_o => cp_done -- iterative processing units done? + cp_done_o => cp_done -- iterative processing units done? ); - -- Bus Interface (Load/Store Unit) -------------------------------------------------------- + -- Load/Store Unit ------------------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- - neorv32_cpu_bus_inst: entity neorv32.neorv32_cpu_bus + neorv32_cpu_lsu_inst: entity neorv32.neorv32_cpu_lsu generic map ( - AMO_LRSC_ENABLE => CPU_EXTENSION_RISCV_A, -- enable atomic LR/SC operations - PMP_NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (0..16) - PMP_MIN_GRANULARITY => PMP_MIN_GRANULARITY -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes + AMO_LRSC_ENABLE => CPU_EXTENSION_RISCV_A -- enable atomic LR/SC operations ) port map ( -- global control -- clk_i => clk_i, -- global clock, rising edge rstn_i => rstn_i, -- global reset, low-active, async ctrl_i => ctrl, -- main control bus - -- cpu instruction fetch interface -- - fetch_pc_i => fetch_pc, -- PC for instruction fetch - i_pmp_fault_o => i_pmp_fault, -- instruction fetch pmp fault -- cpu data access interface -- - addr_i => alu_add, -- ALU.add result -> access address + addr_i => alu_add, -- access address wdata_i => rs2, -- write data rdata_o => mem_rdata, -- read data mar_o => mar, -- current memory address register @@ -382,9 +378,8 @@ begin ma_store_o => ma_store, -- misaligned store data address be_load_o => be_load, -- bus error on load data access be_store_o => be_store, -- bus error on store data access - -- physical memory protection -- - pmp_addr_i => pmp_addr, -- addresses - pmp_ctrl_i => pmp_ctrl, -- configurations + pmp_r_fault_i => pmp_r_fault, -- PMP read fault + pmp_w_fault_i => pmp_w_fault, -- PMP write fault -- data bus -- d_bus_addr_o => dbus_req_o.addr, -- bus access address d_bus_rdata_i => dbus_rsp_i.data, -- bus read data @@ -396,9 +391,48 @@ begin d_bus_err_i => dbus_rsp_i.err -- bus transfer error ); - dbus_req_o.priv <= ctrl.bus_priv; + -- data access interface -- + dbus_req_o.priv <= ctrl.lsu_priv; dbus_req_o.src <= '0'; -- source = data access - dbus_req_o.rvso <= ctrl.bus_rvso when (CPU_EXTENSION_RISCV_A = true) else '0'; -- is LR/SC reservation set operation + dbus_req_o.rvso <= ctrl.lsu_rvso when (CPU_EXTENSION_RISCV_A = true) else '0'; -- is LR/SC reservation set operation + + + -- Physical Memory Protection ------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + pmp_inst_true: + if (pmp_enable_c = true) generate + neorv32_cpu_pmp_inst: entity neorv32.neorv32_cpu_pmp + generic map ( + NUM_REGIONS => PMP_NUM_REGIONS, -- number of regions (0..16) + GRANULARITY => PMP_MIN_GRANULARITY -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes + ) + port map ( + -- global control -- + clk_i => clk_i, -- global clock, rising edge + rstn_i => rstn_i, -- global reset, low-active, async + ctrl_i => ctrl, -- main control bus + -- CSR interface -- + csr_we_i => xcsr_we, -- global write enable + csr_addr_i => xcsr_addr, -- address + csr_wdata_i => xcsr_wdata, -- write data + csr_rdata_o => xcsr_rdata_pmp, -- read data + -- address input -- + addr_if_i => fetch_pc, -- instruction fetch address + addr_ls_i => alu_add, -- load/store address + -- faults -- + fault_if_o => pmp_i_fault, -- instruction fetch fault + fault_ld_o => pmp_r_fault, -- data load fault + fault_st_o => pmp_w_fault -- data store fault + ); + end generate; + + pmp_inst_false: + if (pmp_enable_c = false) generate + xcsr_rdata_pmp <= (others => '0'); + pmp_i_fault <= '0'; + pmp_r_fault <= '0'; + pmp_w_fault <= '0'; + end generate; end neorv32_cpu_rtl; diff --git a/rtl/core/neorv32_cpu_alu.vhd b/rtl/core/neorv32_cpu_alu.vhd index 064f094f2..97ddc465e 100644 --- a/rtl/core/neorv32_cpu_alu.vhd +++ b/rtl/core/neorv32_cpu_alu.vhd @@ -1,5 +1,5 @@ -- ################################################################################################# --- # << NEORV32 - Arithmetical/Logical Unit >> # +-- # << NEORV32 CPU - Arithmetic/Logic Unit >> # -- # ********************************************************************************************* # -- # Main data/address ALU and ALU co-processors (= multi-cycle function units). # -- # ********************************************************************************************* # @@ -59,6 +59,11 @@ entity neorv32_cpu_alu is clk_i : in std_ulogic; -- global clock, rising edge rstn_i : in std_ulogic; -- global reset, low-active, async ctrl_i : in ctrl_bus_t; -- main control bus + -- CSR interface -- + csr_we_i : in std_ulogic; -- global write enable + csr_addr_i : in std_ulogic_vector(11 downto 0); -- address + csr_wdata_i : in std_ulogic_vector(XLEN-1 downto 0); -- write data + csr_rdata_o : out std_ulogic_vector(XLEN-1 downto 0); -- read data -- data input -- rs1_i : in std_ulogic_vector(XLEN-1 downto 0); -- rf source 1 rs2_i : in std_ulogic_vector(XLEN-1 downto 0); -- rf source 2 @@ -70,9 +75,7 @@ entity neorv32_cpu_alu is cmp_o : out std_ulogic_vector(1 downto 0); -- comparator status res_o : out std_ulogic_vector(XLEN-1 downto 0); -- ALU result add_o : out std_ulogic_vector(XLEN-1 downto 0); -- address computation result - fpu_flags_o : out std_ulogic_vector(4 downto 0); -- FPU exception flags -- status -- - exc_o : out std_ulogic; -- ALU exception cp_done_o : out std_ulogic -- co-processor operation done? ); end neorv32_cpu_alu; @@ -92,15 +95,6 @@ architecture neorv32_cpu_cpu_rtl of neorv32_cpu_alu is signal addsub_res : std_ulogic_vector(XLEN downto 0); signal cp_res : std_ulogic_vector(XLEN-1 downto 0); - -- co-processor monitor -- - type cp_monitor_t is record - run : std_ulogic; - fin : std_ulogic; - exc : std_ulogic; - cnt : std_ulogic_vector(cp_timeout_c downto 0); -- timeout counter - end record; - signal cp_monitor : cp_monitor_t; - -- co-processor interface -- type cp_data_t is array (0 to 5) of std_ulogic_vector(XLEN-1 downto 0); signal cp_result : cp_data_t; -- co-processor result @@ -158,41 +152,9 @@ begin -- ALU Co-Processors -- ************************************************************************************************************************** - -- Co-Processor Control ------------------------------------------------------------------- - -- ------------------------------------------------------------------------------------------- - coprocessor_monitor: process(rstn_i, clk_i) - begin - -- make sure that no co-processor iterates forever stalling the entire CPU; - -- an illegal instruction exception is raised if a co-processor operation - -- takes longer than 2^cp_timeout_c cycles (package constant) - if (rstn_i = '0') then - cp_monitor.run <= '0'; - cp_monitor.fin <= '0'; - cp_monitor.exc <= '0'; - cp_monitor.cnt <= (others => '0'); - elsif rising_edge(clk_i) then - cp_monitor.exc <= cp_monitor.run and cp_monitor.cnt(cp_monitor.cnt'left) and (not cp_monitor.fin); - cp_monitor.fin <= or_reduce_f(cp_valid); - if (cp_monitor.run = '0') then -- co-processors are idle - cp_monitor.cnt <= (others => '0'); - if (or_reduce_f(ctrl_i.alu_cp_trig) = '1') then -- start - cp_monitor.run <= '1'; - end if; - else -- co-processor operation in progress - cp_monitor.cnt <= std_ulogic_vector(unsigned(cp_monitor.cnt) + 1); - if (cp_monitor.fin = '1') or (ctrl_i.cpu_trap = '1') then -- done or abort - cp_monitor.run <= '0'; - end if; - end if; - end if; - end process coprocessor_monitor; - - -- ALU processing exception -- - exc_o <= cp_monitor.exc; - -- co-processor select / start trigger -- -- > "cp_start" is high for one cycle to trigger operation of the according co-processor - cp_start(5 downto 0) <= ctrl_i.alu_cp_trig; + cp_start <= ctrl_i.alu_cp_trig; -- (iterative) co-processor operation done? -- -- > "cp_valid" signal has to be set (for one cycle) one cycle before CP output data (cp_result) is valid @@ -294,26 +256,30 @@ begin neorv32_cpu_cp_fpu_inst: entity neorv32.neorv32_cpu_cp_fpu port map ( -- global control -- - clk_i => clk_i, -- global clock, rising edge - rstn_i => rstn_i, -- global reset, low-active, async - ctrl_i => ctrl_i, -- main control bus - start_i => cp_start(3), -- trigger operation + clk_i => clk_i, -- global clock, rising edge + rstn_i => rstn_i, -- global reset, low-active, async + ctrl_i => ctrl_i, -- main control bus + start_i => cp_start(3), -- trigger operation + -- CSR interface -- + csr_we_i => csr_we_i, -- global write enable + csr_addr_i => csr_addr_i, -- address + csr_wdata_i => csr_wdata_i, -- write data + csr_rdata_o => csr_rdata_o, -- read data -- data input -- - cmp_i => cmp, -- comparator status - rs1_i => rs1_i, -- rf source 1 - rs2_i => rs2_i, -- rf source 2 - rs3_i => rs3_i, -- rf source 3 + cmp_i => cmp, -- comparator status + rs1_i => rs1_i, -- rf source 1 + rs2_i => rs2_i, -- rf source 2 + rs3_i => rs3_i, -- rf source 3 -- result and status -- - res_o => cp_result(3), -- operation result - fflags_o => fpu_flags_o, -- exception flags - valid_o => cp_valid(3) -- data output valid + res_o => cp_result(3), -- operation result + valid_o => cp_valid(3) -- data output valid ); end generate; neorv32_cpu_cp_fpu_inst_false: if (CPU_EXTENSION_RISCV_Zfinx = false) generate + csr_rdata_o <= (others => '0'); cp_result(3) <= (others => '0'); - fpu_flags_o <= (others => '0'); cp_valid(3) <= '0'; end generate; diff --git a/rtl/core/neorv32_cpu_control.vhd b/rtl/core/neorv32_cpu_control.vhd index 9fdfb4798..7302ac1f6 100644 --- a/rtl/core/neorv32_cpu_control.vhd +++ b/rtl/core/neorv32_cpu_control.vhd @@ -1,5 +1,5 @@ -- ################################################################################################# --- # << NEORV32 - CPU Operations Control Unit >> # +-- # << NEORV32 CPU - Central Operation Control Unit >> # -- # ********************************************************************************************* # -- # CPU operations are controlled by several "engines" (modules). These engines operate in # -- # parallel to implement a simple pipeline: # @@ -8,6 +8,7 @@ -- # + Execute engine: Multi-cycle execution of instructions (generate control signals) # -- # + Trap controller: Handles interrupts and exceptions # -- # + CSR module: Read/write access to control and status registers # +-- # + CPU counters: Base and HPM counters # -- # + Debug module: CPU debug mode handling (on-chip debugger) # -- # + Trigger module: Hardware-assisted breakpoints (on-chip debugger) # -- # ********************************************************************************************* # @@ -77,10 +78,9 @@ entity neorv32_cpu_control is FAST_MUL_EN : boolean; -- use DSPs for M extension's multiplier FAST_SHIFT_EN : boolean; -- use barrel shifter for shift operations -- Physical memory protection (PMP) -- - PMP_NUM_REGIONS : natural; -- number of regions (0..16) - PMP_MIN_GRANULARITY : natural; -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes + PMP_EN : boolean; -- physical memory protection enabled -- Hardware Performance Monitors (HPM) -- - HPM_NUM_CNTS : natural; -- number of implemented HPM counters (0..29) + HPM_NUM_CNTS : natural; -- number of implemented HPM counters (0..13) HPM_CNT_WIDTH : natural -- total size of HPM counters (0..64) ); port ( @@ -97,7 +97,6 @@ entity neorv32_cpu_control is i_pmp_fault_i : in std_ulogic; -- instruction fetch pmp fault -- status input -- alu_cp_done_i : in std_ulogic; -- ALU iterative operation done - alu_exc_i : in std_ulogic; -- ALU exception bus_d_wait_i : in std_ulogic; -- wait for bus -- data input -- cmp_i : in std_ulogic_vector(1 downto 0); -- comparator status @@ -108,17 +107,17 @@ entity neorv32_cpu_control is curr_pc_o : out std_ulogic_vector(XLEN-1 downto 0); -- current PC (corresponding to current instruction) next_pc_o : out std_ulogic_vector(XLEN-1 downto 0); -- next PC (corresponding to next instruction) csr_rdata_o : out std_ulogic_vector(XLEN-1 downto 0); -- CSR read data - -- FPU interface -- - fpu_flags_i : in std_ulogic_vector(4 downto 0); -- exception flags + -- external CSR interface -- + xcsr_we_o : out std_ulogic; -- global write enable + xcsr_addr_o : out std_ulogic_vector(11 downto 0); -- address + xcsr_wdata_o : out std_ulogic_vector(XLEN-1 downto 0); -- write data + xcsr_rdata_i : in std_ulogic_vector(XLEN-1 downto 0); -- read data -- interrupts -- db_halt_req_i : in std_ulogic; -- debug mode (halt) request msi_i : in std_ulogic; -- machine software interrupt mei_i : in std_ulogic; -- machine external interrupt mti_i : in std_ulogic; -- machine timer interrupt firq_i : in std_ulogic_vector(15 downto 0); -- fast interrupts - -- physical memory protection -- - pmp_addr_o : out pmp_addr_if_t; -- addresses - pmp_ctrl_o : out pmp_ctrl_if_t; -- configs -- bus access exceptions -- mar_i : in std_ulogic_vector(XLEN-1 downto 0); -- memory address register ma_load_i : in std_ulogic; -- misaligned load data address @@ -142,11 +141,10 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is state_prev : fetch_engine_state_t; restart : std_ulogic; unaligned : std_ulogic; - pc : std_ulogic_vector(XLEN-1 downto 0); + pc : std_ulogic_vector(XLEN-1 downto 2); -- word-aligned reset : std_ulogic; resp : std_ulogic; -- bus response a_err : std_ulogic; -- alignment error - pmp_err : std_ulogic; -- PMP error end record; signal fetch_engine : fetch_engine_t; @@ -244,7 +242,7 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is -- RISC-V control and status registers (CSRs) -- type csr_t is record addr : std_ulogic_vector(11 downto 0); -- csr address - raddr : std_ulogic_vector(11 downto 0); -- csr read address (gated from csr.addr) + raddr : std_ulogic_vector(11 downto 0); -- simplified csr read address we : std_ulogic; -- csr write enable we_nxt : std_ulogic; re : std_ulogic; -- csr read enable @@ -272,11 +270,8 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is mtvec : std_ulogic_vector(XLEN-1 downto 0); -- machine trap-handler base address mtval : std_ulogic_vector(XLEN-1 downto 0); -- machine bad address or instruction mscratch : std_ulogic_vector(XLEN-1 downto 0); -- machine scratch register - mcounteren : std_ulogic_vector(XLEN-1 downto 0); -- machine counter access enable - mcountinhibit : std_ulogic_vector(XLEN-1 downto 0); -- inhibit counter auto-increment - -- - frm : std_ulogic_vector(2 downto 0); -- FPU rounding mode - fflags : std_ulogic_vector(4 downto 0); -- FPU exception flags + mcounteren : std_ulogic_vector(15 downto 0); -- machine counter access enable + mcountinhibit : std_ulogic_vector(15 downto 0); -- inhibit counter auto-increment -- dcsr_ebreakm : std_ulogic; -- behavior of ebreak instruction in m-mode dcsr_ebreaku : std_ulogic; -- behavior of ebreak instruction in u-mode @@ -295,39 +290,24 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is end record; signal csr : csr_t; - -- hpm event configuration CSRs (first 3 entries are just dummies) -- - type hpmevent_cfg_t is array (0 to hpm_num_c-1) of std_ulogic_vector(hpmcnt_event_size_c-1 downto 0); - type hpmevent_rd_t is array (0 to 31) of std_ulogic_vector(XLEN-1 downto 0); + -- hpm event configuration CSRs -- + type hpmevent_cfg_t is array (3 to (hpm_num_c+3)-1) of std_ulogic_vector(hpmcnt_event_size_c-1 downto 0); + type hpmevent_rd_t is array (3 to 15) of std_ulogic_vector(XLEN-1 downto 0); type hpmevent_t is record - we : std_ulogic_vector(31 downto 0); + we : std_ulogic_vector(15 downto 0); cfg : hpmevent_cfg_t; end record; signal hpmevent : hpmevent_t; signal hpmevent_rd : hpmevent_rd_t; - -- physical memory protection CSRs -- - type pmp_cfg_t is array (0 to PMP_NUM_REGIONS-1) of std_ulogic_vector(7 downto 0); - type pmp_addr_t is array (0 to PMP_NUM_REGIONS-1) of std_ulogic_vector(XLEN-1 downto 0); - type pmp_cfg_rd_t is array (0 to 03) of std_ulogic_vector(XLEN-1 downto 0); - type pmp_addr_rd_t is array (0 to 15) of std_ulogic_vector(XLEN-1 downto 0); - type pmp_t is record - we_cfg : std_ulogic_vector(03 downto 0); - we_addr : std_ulogic_vector(15 downto 0); - cfg : pmp_cfg_t; - addr : pmp_addr_t; - end record; - signal pmp : pmp_t; - signal pmp_cfg_rd : pmp_cfg_rd_t; - signal pmp_addr_rd : pmp_addr_rd_t; - -- counter CSRs -- - type cnt_dat_t is array (0 to 31) of std_ulogic_vector(XLEN-1 downto 0); - type cnt_nxt_t is array (0 to 31) of std_ulogic_vector(XLEN downto 0); - type cnt_ovf_t is array (0 to 31) of std_ulogic_vector(0 downto 0); + type cnt_dat_t is array (0 to 2+hpm_num_c) of std_ulogic_vector(XLEN-1 downto 0); + type cnt_nxt_t is array (0 to 2+hpm_num_c) of std_ulogic_vector(XLEN downto 0); + type cnt_ovf_t is array (0 to 2+hpm_num_c) of std_ulogic_vector(0 downto 0); type cnt_t is record - we_lo : std_ulogic_vector(31 downto 0); - we_hi : std_ulogic_vector(31 downto 0); - inc : std_ulogic_vector(31 downto 0); + we_lo : std_ulogic_vector(15 downto 0); + we_hi : std_ulogic_vector(15 downto 0); + inc : std_ulogic_vector(15 downto 0); lo : cnt_dat_t; -- counter word low hi : cnt_dat_t; -- counter word high nxt : cnt_nxt_t; -- increment, including carry bit @@ -365,6 +345,9 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is -- hardware trigger module -- signal hw_trigger_fire : std_ulogic; + -- CSr read-back data helpers -- + signal csr_rdata, csr_rdata_pmp : std_ulogic_vector(XLEN-1 downto 0); + begin -- **************************************************************************************************************************** @@ -381,7 +364,6 @@ begin fetch_engine.restart <= '1'; -- set to reset IPB fetch_engine.unaligned <= '0'; -- always start at aligned address after reset fetch_engine.pc <= (others => '0'); - fetch_engine.pmp_err <= '0'; elsif rising_edge(clk_i) then -- previous state (for HPM) -- fetch_engine.state_prev <= fetch_engine.state; @@ -393,15 +375,12 @@ begin fetch_engine.restart <= fetch_engine.restart or fetch_engine.reset; end if; - -- register PMP fault -- - fetch_engine.pmp_err <= i_pmp_fault_i; - -- fsm -- case fetch_engine.state is when IF_RESTART => -- set new fetch start address -- ------------------------------------------------------------ - fetch_engine.pc <= execute_engine.pc(XLEN-1 downto 2) & "00"; -- initialize with "real" PC, 32-bit aligned + fetch_engine.pc <= execute_engine.pc(XLEN-1 downto 2); -- initialize with logical PC, word aligned fetch_engine.unaligned <= execute_engine.pc(1); fetch_engine.state <= IF_REQUEST; @@ -414,7 +393,7 @@ begin when IF_PENDING => -- wait for bus response and write instruction data to prefetch buffer -- ------------------------------------------------------------ if (fetch_engine.resp = '1') then -- wait for bus response - fetch_engine.pc <= std_ulogic_vector(unsigned(fetch_engine.pc) + 4); -- next word + fetch_engine.pc <= std_ulogic_vector(unsigned(fetch_engine.pc) + 1); -- next word fetch_engine.unaligned <= '0'; if (fetch_engine.restart = '1') or (fetch_engine.reset = '1') then -- restart request (fast) fetch_engine.state <= IF_RESTART; @@ -445,7 +424,7 @@ begin end process fetch_engine_fsm; -- PC output for instruction fetch -- - i_bus_addr_o <= fetch_engine.pc(XLEN-1 downto 2) & "00"; -- 32-bit aligned + i_bus_addr_o <= fetch_engine.pc & "00"; -- word aligned -- instruction fetch (read) request if IPB not full -- i_bus_re_o <= '1' when (fetch_engine.state = IF_REQUEST) and (ipb.free = "11") else '0'; @@ -458,8 +437,8 @@ begin fetch_engine.resp <= '1' when (i_bus_ack_i = '1') or (i_bus_err_i = '1') else '0'; -- IPB instruction data and status -- - ipb.wdata(0) <= (i_bus_err_i or fetch_engine.pmp_err) & fetch_engine.a_err & i_bus_rdata_i(15 downto 00); - ipb.wdata(1) <= (i_bus_err_i or fetch_engine.pmp_err) & fetch_engine.a_err & i_bus_rdata_i(31 downto 16); + ipb.wdata(0) <= (i_bus_err_i or i_pmp_fault_i) & fetch_engine.a_err & i_bus_rdata_i(15 downto 00); + ipb.wdata(1) <= (i_bus_err_i or i_pmp_fault_i) & fetch_engine.a_err & i_bus_rdata_i(31 downto 16); -- IPB write enable -- ipb.we(0) <= '1' when (fetch_engine.state = IF_PENDING) and (fetch_engine.resp = '1') and @@ -814,9 +793,6 @@ begin -- simplified opcode -- decode_aux.opcode <= execute_engine.ir(instr_opcode_msb_c downto instr_opcode_lsb_c+2) & "11"; - -- CSR access address -- - csr.addr <= execute_engine.ir(instr_imm12_msb_c downto instr_imm12_lsb_c); - -- Execute Engine FSM Comb ---------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- @@ -846,7 +822,7 @@ begin csr.re_nxt <= '0'; -- control defaults -- - ctrl_nxt <= ctrl_bus_zero_c; -- all zero/off by default + ctrl_nxt <= ctrl_bus_zero_c; -- all zero by default ctrl_nxt.alu_op <= alu_op_add_c; -- default ALU operation: ADD ctrl_nxt.rf_mux <= rf_mux_alu_c; -- default RF input: ALU @@ -984,7 +960,7 @@ begin when opcode_load_c | opcode_store_c | opcode_amo_c => -- memory access -- ------------------------------------------------------------ - ctrl_nxt.bus_mo_we <= '1'; -- write memory output registers (data & address) + ctrl_nxt.lsu_mo_we <= '1'; -- write memory output registers (data & address) execute_engine.state_nxt <= MEM_REQ; when opcode_branch_c | opcode_jal_c | opcode_jalr_c => -- branch / jump and link (with register) @@ -996,11 +972,11 @@ begin when opcode_fence_c => -- fence operations -- ------------------------------------------------------------ if (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fencei_c) and (CPU_EXTENSION_RISCV_Zifencei = true) then - ctrl_nxt.bus_fencei <= '1'; -- fence.i + ctrl_nxt.lsu_fencei <= '1'; -- fence.i execute_engine.state_nxt <= TRAP_EXECUTE; -- use TRAP_EXECUTE to "modify" PC (PC <= PC) else if (execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = funct3_fence_c) then - ctrl_nxt.bus_fence <= '1'; -- fence + ctrl_nxt.lsu_fence <= '1'; -- fence end if; execute_engine.state_nxt <= DISPATCH; end if; @@ -1070,12 +1046,12 @@ begin execute_engine.state_nxt <= DISPATCH; else if (CPU_EXTENSION_RISCV_A = true) and (decode_aux.opcode(2) = opcode_amo_c(2)) then -- atomic operation - ctrl_nxt.bus_req_rd <= decode_aux.is_a_lr; -- LR.W - ctrl_nxt.bus_req_wr <= decode_aux.is_a_sc; -- SC.W - ctrl_nxt.bus_rvso <= '1'; -- this is a reservation set operation + ctrl_nxt.lsu_req_rd <= decode_aux.is_a_lr; -- LR.W + ctrl_nxt.lsu_req_wr <= decode_aux.is_a_sc; -- SC.W + ctrl_nxt.lsu_rvso <= '1'; -- this is a reservation set operation else -- normal load/store - ctrl_nxt.bus_req_rd <= not execute_engine.ir(5); -- load - ctrl_nxt.bus_req_wr <= execute_engine.ir(5); -- store + ctrl_nxt.lsu_req_rd <= not execute_engine.ir(5); -- load + ctrl_nxt.lsu_req_wr <= execute_engine.ir(5); -- store end if; execute_engine.state_nxt <= MEM_WAIT; end if; @@ -1083,7 +1059,7 @@ begin when MEM_WAIT => -- wait for bus transaction to finish -- ------------------------------------------------------------ if (CPU_EXTENSION_RISCV_A = true) and (decode_aux.opcode(2) = opcode_amo_c(2)) then - ctrl_nxt.bus_rvso <= '1'; -- this is a reservation set operation + ctrl_nxt.lsu_rvso <= '1'; -- this is a reservation set operation end if; ctrl_nxt.rf_mux <= rf_mux_mem_c; -- memory read data if (trap_ctrl.exc_buf(exc_laccess_c) = '1') or (trap_ctrl.exc_buf(exc_saccess_c) = '1') or -- bus access error @@ -1149,17 +1125,16 @@ begin ctrl_o.alu_opa_mux <= ctrl.alu_opa_mux; ctrl_o.alu_opb_mux <= ctrl.alu_opb_mux; ctrl_o.alu_unsigned <= ctrl.alu_unsigned; - ctrl_o.alu_frm <= csr.frm; ctrl_o.alu_cp_trig <= ctrl.alu_cp_trig; -- data bus interface -- - ctrl_o.bus_req_rd <= ctrl.bus_req_rd; - ctrl_o.bus_req_wr <= ctrl.bus_req_wr; - ctrl_o.bus_mo_we <= ctrl.bus_mo_we; - ctrl_o.bus_fence <= ctrl.bus_fence; - ctrl_o.bus_fencei <= ctrl.bus_fencei; - ctrl_o.bus_priv <= csr.mstatus_mpp when (csr.mstatus_mprv = '1') else csr.privilege_eff; -- effective privilege level for loads/stores in M-mode - ctrl_o.bus_rvso <= ctrl.bus_rvso; + ctrl_o.lsu_req_rd <= ctrl.lsu_req_rd; + ctrl_o.lsu_req_wr <= ctrl.lsu_req_wr; + ctrl_o.lsu_mo_we <= ctrl.lsu_mo_we; + ctrl_o.lsu_fence <= ctrl.lsu_fence; + ctrl_o.lsu_fencei <= ctrl.lsu_fencei; + 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 + ctrl_o.lsu_rvso <= ctrl.lsu_rvso; -- instruction word bit fields -- ctrl_o.ir_funct3 <= execute_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c); @@ -1196,44 +1171,29 @@ begin csr_reg_valid <= '1'; -- physical memory protection (PMP) -- - when csr_pmpcfg0_c | csr_pmpcfg1_c | csr_pmpcfg2_c | csr_pmpcfg3_c | csr_pmpcfg4_c | csr_pmpcfg5_c | csr_pmpcfg6_c | csr_pmpcfg7_c | -- configuration - csr_pmpcfg8_c | csr_pmpcfg9_c | csr_pmpcfg10_c | csr_pmpcfg11_c | csr_pmpcfg12_c | csr_pmpcfg13_c | csr_pmpcfg14_c | csr_pmpcfg15_c | - csr_pmpaddr0_c | csr_pmpaddr1_c | csr_pmpaddr2_c | csr_pmpaddr3_c | csr_pmpaddr4_c | csr_pmpaddr5_c | csr_pmpaddr6_c | csr_pmpaddr7_c | -- address - csr_pmpaddr8_c | csr_pmpaddr9_c | csr_pmpaddr10_c | csr_pmpaddr11_c | csr_pmpaddr12_c | csr_pmpaddr13_c | csr_pmpaddr14_c | csr_pmpaddr15_c | - csr_pmpaddr16_c | csr_pmpaddr17_c | csr_pmpaddr18_c | csr_pmpaddr19_c | csr_pmpaddr20_c | csr_pmpaddr21_c | csr_pmpaddr22_c | csr_pmpaddr23_c | - csr_pmpaddr24_c | csr_pmpaddr25_c | csr_pmpaddr26_c | csr_pmpaddr27_c | csr_pmpaddr28_c | csr_pmpaddr29_c | csr_pmpaddr30_c | csr_pmpaddr31_c | - csr_pmpaddr32_c | csr_pmpaddr33_c | csr_pmpaddr34_c | csr_pmpaddr35_c | csr_pmpaddr36_c | csr_pmpaddr37_c | csr_pmpaddr38_c | csr_pmpaddr39_c | - csr_pmpaddr40_c | csr_pmpaddr41_c | csr_pmpaddr42_c | csr_pmpaddr43_c | csr_pmpaddr44_c | csr_pmpaddr45_c | csr_pmpaddr46_c | csr_pmpaddr47_c | - csr_pmpaddr48_c | csr_pmpaddr49_c | csr_pmpaddr50_c | csr_pmpaddr51_c | csr_pmpaddr52_c | csr_pmpaddr53_c | csr_pmpaddr54_c | csr_pmpaddr55_c | - csr_pmpaddr56_c | csr_pmpaddr57_c | csr_pmpaddr58_c | csr_pmpaddr59_c | csr_pmpaddr60_c | csr_pmpaddr61_c | csr_pmpaddr62_c | csr_pmpaddr63_c => - csr_reg_valid <= bool_to_ulogic_f(boolean(PMP_NUM_REGIONS > 0)); -- valid if PMP implemented + when csr_pmpcfg0_c | csr_pmpcfg1_c | csr_pmpcfg2_c | csr_pmpcfg3_c | -- configuration + csr_pmpaddr0_c | csr_pmpaddr1_c | csr_pmpaddr2_c | csr_pmpaddr3_c | + csr_pmpaddr4_c | csr_pmpaddr5_c | csr_pmpaddr6_c | csr_pmpaddr7_c | -- address + csr_pmpaddr8_c | csr_pmpaddr9_c | csr_pmpaddr10_c | csr_pmpaddr11_c | + csr_pmpaddr12_c | csr_pmpaddr13_c | csr_pmpaddr14_c | csr_pmpaddr15_c => + csr_reg_valid <= bool_to_ulogic_f(PMP_EN); -- valid if PMP implemented -- hardware performance monitors (HPM) -- - when csr_hpmcounter3_c | csr_hpmcounter4_c | csr_hpmcounter5_c | csr_hpmcounter6_c | csr_hpmcounter7_c | csr_hpmcounter8_c | -- user counters LOW - csr_hpmcounter9_c | csr_hpmcounter10_c | csr_hpmcounter11_c | csr_hpmcounter12_c | csr_hpmcounter13_c | csr_hpmcounter14_c | - csr_hpmcounter15_c | csr_hpmcounter16_c | csr_hpmcounter17_c | csr_hpmcounter18_c | csr_hpmcounter19_c | csr_hpmcounter20_c | - csr_hpmcounter21_c | csr_hpmcounter22_c | csr_hpmcounter23_c | csr_hpmcounter24_c | csr_hpmcounter25_c | csr_hpmcounter26_c | - csr_hpmcounter27_c | csr_hpmcounter28_c | csr_hpmcounter29_c | csr_hpmcounter30_c | csr_hpmcounter31_c | - csr_hpmcounter3h_c | csr_hpmcounter4h_c | csr_hpmcounter5h_c | csr_hpmcounter6h_c | csr_hpmcounter7h_c | csr_hpmcounter8h_c | -- user counters HIGH - csr_hpmcounter9h_c | csr_hpmcounter10h_c | csr_hpmcounter11h_c | csr_hpmcounter12h_c | csr_hpmcounter13h_c | csr_hpmcounter14h_c | - csr_hpmcounter15h_c | csr_hpmcounter16h_c | csr_hpmcounter17h_c | csr_hpmcounter18h_c | csr_hpmcounter19h_c | csr_hpmcounter20h_c | - csr_hpmcounter21h_c | csr_hpmcounter22h_c | csr_hpmcounter23h_c | csr_hpmcounter24h_c | csr_hpmcounter25h_c | csr_hpmcounter26h_c | - csr_hpmcounter27h_c | csr_hpmcounter28h_c | csr_hpmcounter29h_c | csr_hpmcounter30h_c | csr_hpmcounter31h_c | - csr_mhpmcounter3_c | csr_mhpmcounter4_c | csr_mhpmcounter5_c | csr_mhpmcounter6_c | csr_mhpmcounter7_c | csr_mhpmcounter8_c | -- machine counters LOW - csr_mhpmcounter9_c | csr_mhpmcounter10_c | csr_mhpmcounter11_c | csr_mhpmcounter12_c | csr_mhpmcounter13_c | csr_mhpmcounter14_c | - csr_mhpmcounter15_c | csr_mhpmcounter16_c | csr_mhpmcounter17_c | csr_mhpmcounter18_c | csr_mhpmcounter19_c | csr_mhpmcounter20_c | - csr_mhpmcounter21_c | csr_mhpmcounter22_c | csr_mhpmcounter23_c | csr_mhpmcounter24_c | csr_mhpmcounter25_c | csr_mhpmcounter26_c | - csr_mhpmcounter27_c | csr_mhpmcounter28_c | csr_mhpmcounter29_c | csr_mhpmcounter30_c | csr_mhpmcounter31_c | - csr_mhpmcounter3h_c | csr_mhpmcounter4h_c | csr_mhpmcounter5h_c | csr_mhpmcounter6h_c | csr_mhpmcounter7h_c | csr_mhpmcounter8h_c | -- machine counters HIGH - csr_mhpmcounter9h_c | csr_mhpmcounter10h_c | csr_mhpmcounter11h_c | csr_mhpmcounter12h_c | csr_mhpmcounter13h_c | csr_mhpmcounter14h_c | - csr_mhpmcounter15h_c | csr_mhpmcounter16h_c | csr_mhpmcounter17h_c | csr_mhpmcounter18h_c | csr_mhpmcounter19h_c | csr_mhpmcounter20h_c | - csr_mhpmcounter21h_c | csr_mhpmcounter22h_c | csr_mhpmcounter23h_c | csr_mhpmcounter24h_c | csr_mhpmcounter25h_c | csr_mhpmcounter26h_c | - csr_mhpmcounter27h_c | csr_mhpmcounter28h_c | csr_mhpmcounter29h_c | csr_mhpmcounter30h_c | csr_mhpmcounter31h_c | - csr_mhpmevent3_c | csr_mhpmevent4_c | csr_mhpmevent5_c | csr_mhpmevent6_c | csr_mhpmevent7_c | csr_mhpmevent8_c | -- event configuration - csr_mhpmevent9_c | csr_mhpmevent10_c | csr_mhpmevent11_c | csr_mhpmevent12_c | csr_mhpmevent13_c | csr_mhpmevent14_c | - csr_mhpmevent15_c | csr_mhpmevent16_c | csr_mhpmevent17_c | csr_mhpmevent18_c | csr_mhpmevent19_c | csr_mhpmevent20_c | - csr_mhpmevent21_c | csr_mhpmevent22_c | csr_mhpmevent23_c | csr_mhpmevent24_c | csr_mhpmevent25_c | csr_mhpmevent26_c | - csr_mhpmevent27_c | csr_mhpmevent28_c | csr_mhpmevent29_c | csr_mhpmevent30_c | csr_mhpmevent31_c => + when csr_hpmcounter3_c | csr_hpmcounter4_c | csr_hpmcounter5_c | csr_hpmcounter6_c | csr_hpmcounter7_c | + csr_hpmcounter8_c | csr_hpmcounter9_c | csr_hpmcounter10_c | csr_hpmcounter11_c | csr_hpmcounter12_c | + csr_hpmcounter13_c | csr_hpmcounter14_c | csr_hpmcounter15_c | -- user counters LOW + csr_hpmcounter3h_c | csr_hpmcounter4h_c | csr_hpmcounter5h_c | csr_hpmcounter6h_c | csr_hpmcounter7h_c | + csr_hpmcounter8h_c | csr_hpmcounter9h_c | csr_hpmcounter10h_c | csr_hpmcounter11h_c | csr_hpmcounter12h_c | + csr_hpmcounter13h_c | csr_hpmcounter14h_c | csr_hpmcounter15h_c | -- user counters HIGH + csr_mhpmcounter3_c | csr_mhpmcounter4_c | csr_mhpmcounter5_c | csr_mhpmcounter6_c | csr_mhpmcounter7_c | + csr_mhpmcounter8_c | csr_mhpmcounter9_c | csr_mhpmcounter10_c | csr_mhpmcounter11_c | csr_mhpmcounter12_c | + csr_mhpmcounter13_c | csr_mhpmcounter14_c | csr_mhpmcounter15_c | -- machine counters LOW + csr_mhpmcounter3h_c | csr_mhpmcounter4h_c | csr_mhpmcounter5h_c | csr_mhpmcounter6h_c | csr_mhpmcounter7h_c | + csr_mhpmcounter8h_c | csr_mhpmcounter9h_c | csr_mhpmcounter10h_c | csr_mhpmcounter11h_c | csr_mhpmcounter12h_c | + csr_mhpmcounter13h_c | csr_mhpmcounter14h_c | csr_mhpmcounter15h_c | -- machine counters HIGH + csr_mhpmevent3_c | csr_mhpmevent4_c | csr_mhpmevent5_c | csr_mhpmevent6_c | csr_mhpmevent7_c | + csr_mhpmevent8_c | csr_mhpmevent9_c | csr_mhpmevent10_c | csr_mhpmevent11_c | csr_mhpmevent12_c | + csr_mhpmevent13_c | csr_mhpmevent14_c | csr_mhpmevent15_c => -- event configuration csr_reg_valid <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zihpm); -- valid if Zihpm implemented -- counter and timer CSRs -- @@ -1246,7 +1206,8 @@ begin csr_reg_valid <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Sdext); -- valid if debug-mode implemented -- trigger module CSRs -- - when csr_tselect_c | csr_tdata1_c | csr_tdata2_c | csr_tdata3_c | csr_tinfo_c | csr_tcontrol_c | csr_mcontext_c | csr_scontext_c => + when csr_tselect_c | csr_tdata1_c | csr_tdata2_c | csr_tdata3_c | + csr_tinfo_c | csr_tcontrol_c | csr_mcontext_c | csr_scontext_c => csr_reg_valid <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Sdtrig); -- valid if trigger module implemented -- undefined / not implemented -- @@ -1282,7 +1243,7 @@ begin elsif (csr.addr(11 downto 8) = csr_cycle_c(11 downto 8)) and -- user counter access ((CPU_EXTENSION_RISCV_Zicntr = true) or (CPU_EXTENSION_RISCV_Zihpm = true)) and -- any counters available? (CPU_EXTENSION_RISCV_U = true) and (csr.privilege_eff = '0') and -- user mode enabled and active - (csr.mcounteren(to_integer(unsigned(csr.addr(4 downto 0)))) = '0') then -- access not allowed? + (csr.mcounteren(to_integer(unsigned(csr.addr(3 downto 0)))) = '0') then -- access not allowed? csr_priv_valid <= '0'; -- invalid access elsif (csr.addr(9 downto 8) /= "00") and (csr.privilege_eff = '0') then -- invalid privilege level csr_priv_valid <= '0'; -- invalid access @@ -1427,7 +1388,6 @@ begin trap_ctrl.instr_il <= '1' when ((execute_engine.state = EXECUTE) or (execute_engine.state = ALU_WAIT)) and -- check in execution states only ( (illegal_cmd = '1') or -- illegal instruction? - (alu_exc_i = '1') or -- invalid ALU operation? (execute_engine.ir(instr_opcode_lsb_c+1 downto instr_opcode_lsb_c) /= "11") -- illegal opcode LSBs? ) else '0'; @@ -1624,7 +1584,15 @@ begin -- Control and Status Registers (CSRs) -- **************************************************************************************************************************** - -- Control and Status Registers - Write Data ---------------------------------------------- + -- CSR Access Address --------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + -- CSR access address (for validation check only) -- + csr.addr <= execute_engine.ir(instr_imm12_msb_c downto instr_imm12_lsb_c); + -- simplified CSR read address - [WARNING] M-mode (9:8 = 11) and U-mode (9:8 = 00) CSRs only! -- + csr.raddr <= csr.addr(11 downto 10) & csr.addr(8) & csr.addr(8) & csr.addr(7 downto 0); + + + -- CSR Write Data ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- csr_write_data: process(execute_engine.ir, csr.rdata, rs1_i) variable tmp_v : std_ulogic_vector(XLEN-1 downto 0); @@ -1645,7 +1613,15 @@ begin end process csr_write_data; - -- Control and Status Registers - Write Access -------------------------------------------- + -- External CSR Interface ----------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + xcsr_we_o <= csr.we; + xcsr_addr_o <= csr.addr; + xcsr_wdata_o <= csr.wdata; + csr_rdata_pmp <= xcsr_rdata_i; + + + -- CSR Write Access ----------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- csr_write_access: process(rstn_i, clk_i) begin @@ -1669,8 +1645,6 @@ begin csr.mcounteren <= (others => '0'); csr.mcountinhibit <= (others => '0'); csr.mip_firq_nclr <= (others => '0'); - csr.fflags <= (others => '0'); - csr.frm <= (others => '0'); csr.dcsr_ebreakm <= '0'; csr.dcsr_ebreaku <= '0'; csr.dcsr_step <= '0'; @@ -1691,29 +1665,11 @@ begin csr.mip_firq_nclr <= (others => '1'); -- active low -- ******************************************************************************** - -- Manual CSR access by application software + -- CSR access by application software -- ******************************************************************************** - if (csr.we = '1') then -- manual write access and not illegal instruction + if (csr.we = '1') then case csr.addr is - -- user floating-point CSRs -- - -- -------------------------------------------------------------------- - when csr_fflags_c => -- floating-point exception flags - if (CPU_EXTENSION_RISCV_Zfinx = true) then - csr.fflags <= csr.wdata(4 downto 0); - end if; - - when csr_frm_c => -- floating-point rounding mode - if (CPU_EXTENSION_RISCV_Zfinx = true) then - csr.frm <= csr.wdata(2 downto 0); - end if; - - when csr_fcsr_c => -- floating-point control/status (frm & fflags) - if (CPU_EXTENSION_RISCV_Zfinx = true) then - csr.frm <= csr.wdata(7 downto 5); - csr.fflags <= csr.wdata(4 downto 0); - end if; - -- machine trap setup -- -- -------------------------------------------------------------------- when csr_mstatus_c => -- machine status register @@ -1726,13 +1682,13 @@ begin end if; when csr_mie_c => -- machine interrupt enable register - csr.mie_msi <= csr.wdata(03); -- machine SW IRQ - csr.mie_mti <= csr.wdata(07); -- machine TIMER IRQ - csr.mie_mei <= csr.wdata(11); -- machine EXT IRQ - csr.mie_firq <= csr.wdata(31 downto 16); -- FIRQ channels 0..15 + csr.mie_msi <= csr.wdata(03); + csr.mie_mti <= csr.wdata(07); + csr.mie_mei <= csr.wdata(11); + csr.mie_firq <= csr.wdata(31 downto 16); when csr_mtvec_c => -- machine trap-handler base address - csr.mtvec <= csr.wdata(XLEN-1 downto 2) & "00"; -- mtvec.MODE=0 + csr.mtvec <= csr.wdata(XLEN-1 downto 2) & "00"; -- mtvec.MODE=0 (direct) when csr_mcounteren_c => -- machine counter access enable if (CPU_EXTENSION_RISCV_U = true) then @@ -1740,8 +1696,10 @@ begin csr.mcounteren(0) <= csr.wdata(0); csr.mcounteren(2) <= csr.wdata(2); end if; - if (CPU_EXTENSION_RISCV_Zihpm = true) then -- any HPMs available? - csr.mcounteren(XLEN-1 downto 3) <= csr.wdata(XLEN-1 downto 3); + if (CPU_EXTENSION_RISCV_Zihpm = true) then + for i in 3 to (hpm_num_c+3)-1 loop + csr.mcounteren(i) <= csr.wdata(i); + end loop; end if; end if; @@ -1763,11 +1721,13 @@ begin -- -------------------------------------------------------------------- when csr_mcountinhibit_c => -- machine counter-inhibit register if (CPU_EXTENSION_RISCV_Zicntr = true) then - csr.mcountinhibit(0) <= csr.wdata(0); -- inhibit auto-increment of [m]cycle[h] counter - csr.mcountinhibit(2) <= csr.wdata(2); -- inhibit auto-increment of [m]instret[h] counter + csr.mcountinhibit(0) <= csr.wdata(0); + csr.mcountinhibit(2) <= csr.wdata(2); end if; - if (CPU_EXTENSION_RISCV_Zihpm = true) then -- any HPMs available? - csr.mcountinhibit(XLEN-1 downto 3) <= csr.wdata(XLEN-1 downto 3); -- inhibit auto-increment of [m]hpmcounter*[h] counter + if (CPU_EXTENSION_RISCV_Zihpm = true) then + for i in 3 to (hpm_num_c+3)-1 loop + csr.mcountinhibit(i) <= csr.wdata(i); + end loop; end if; -- debug mode CSRs -- @@ -1776,7 +1736,7 @@ begin if (CPU_EXTENSION_RISCV_Sdext = true) then csr.dcsr_ebreakm <= csr.wdata(15); csr.dcsr_step <= csr.wdata(2); - if (CPU_EXTENSION_RISCV_U = true) then -- user mode implemented + if (CPU_EXTENSION_RISCV_U = true) then csr.dcsr_ebreaku <= csr.wdata(12); csr.dcsr_prv <= csr.wdata(1) or csr.wdata(0); -- everything /= U will fall back to M end if; @@ -1818,13 +1778,6 @@ begin -- ******************************************************************************** else - -- -------------------------------------------------------------------- - -- floating-point (FPU) exception flags - -- -------------------------------------------------------------------- - if (CPU_EXTENSION_RISCV_Zfinx = true) and (trap_ctrl.exc_buf(exc_iillegal_c) = '0') then -- no illegal instruction - csr.fflags <= csr.fflags or fpu_flags_i; -- accumulate flags ("accrued exception flags") - end if; - -- -------------------------------------------------------------------- -- TRAP ENTER -- -------------------------------------------------------------------- @@ -1895,23 +1848,17 @@ begin end if; - end if; -- /hardware csr access + end if; -- ******************************************************************************** - -- Override - hardwire unimplemented registers to all-zero + -- Override - hardwire/terminate unimplemented registers/bits -- ******************************************************************************** -- hardwired bits -- csr.mcounteren(1) <= '0'; -- time[h] not implemented csr.mcountinhibit(1) <= '0'; -- time[h] not implemented - -- no FPU -- - if (CPU_EXTENSION_RISCV_Zfinx = false) then - csr.frm <= (others => '0'); - csr.fflags <= (others => '0'); - end if; - -- no base counters -- if (CPU_EXTENSION_RISCV_Zicntr = false) then csr.mcounteren(2 downto 0) <= (others => '0'); @@ -1920,8 +1867,8 @@ begin -- no hardware performance monitors -- if (CPU_EXTENSION_RISCV_Zihpm = false) then - csr.mcounteren(XLEN-1 downto 3) <= (others => '0'); - csr.mcountinhibit(XLEN-1 downto 3) <= (others => '0'); + csr.mcounteren((hpm_num_c+3)-1 downto 3) <= (others => '0'); + csr.mcountinhibit((hpm_num_c+3)-1 downto 3) <= (others => '0'); end if; -- no user mode -- @@ -1958,444 +1905,219 @@ begin end process csr_write_access; -- effective privilege mode is MACHINE when in debug mode -- - csr.privilege_eff <= priv_mode_m_c when (CPU_EXTENSION_RISCV_Sdext = true) and (debug_ctrl.running = '1') else csr.privilege; + csr.privilege_eff <= priv_mode_m_c when (debug_ctrl.running = '1') else csr.privilege; - -- Physical Memory Protection (PMP) CSRs -------------------------------------------------- + -- CSR Read Access ------------------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- - pmp_gen_enable: - if (PMP_NUM_REGIONS > 0) generate - - -- write enable decoder -- - pmp_we: process(csr) - begin - -- Configuration registers -- - pmp.we_cfg <= (others => '0'); - if (csr.addr(11 downto 2) = csr_pmpcfg0_c(11 downto 2)) and (csr.we = '1') then - pmp.we_cfg(to_integer(unsigned(csr.addr(1 downto 0)))) <= '1'; - end if; - -- Address registers -- - pmp.we_addr <= (others => '0'); - if (csr.addr(11 downto 4) = csr_pmpaddr0_c(11 downto 4)) and (csr.we = '1') then - pmp.we_addr(to_integer(unsigned(csr.addr(3 downto 0)))) <= '1'; - end if; - end process pmp_we; - - -- PMP registers -- - pmp_reg_gen: - for i in 0 to PMP_NUM_REGIONS-1 generate - pmp_reg: process(rstn_i, clk_i) - begin - if (rstn_i = '0') then - pmp.cfg(i) <= (others => '0'); - pmp.addr(i) <= (others => '0'); - elsif rising_edge(clk_i) then - - -- configuration -- - if (pmp.we_cfg(i/4) = '1') and (pmp.cfg(i)(7) = '0') then -- unlocked write access - pmp.cfg(i)(2 downto 0) <= csr.wdata((i mod 4)*8+2 downto (i mod 4)*8+0); -- X (execute), W (write), R (read) - if (PMP_MIN_GRANULARITY > 4) and (csr.wdata((i mod 4)*8+4 downto (i mod 4)*8+3) = pmp_mode_na4_c) then - pmp.cfg(i)(4 downto 3) <= pmp_mode_off_c; -- NA4 not available, fall back to OFF - else - pmp.cfg(i)(4 downto 3) <= csr.wdata((i mod 4)*8+4 downto (i mod 4)*8+3); -- A (mode) - end if; - pmp.cfg(i)(6 downto 5) <= "00"; -- reserved - pmp.cfg(i)(7) <= csr.wdata((i mod 4)*8+7); -- L (locked) - end if; - - -- address -- - if (pmp.we_addr(i) = '1') and (pmp.cfg(i)(7) = '0') then -- unlocked write access - if (i < PMP_NUM_REGIONS-1) then - if (pmp.cfg(i+1)(7) = '0') or (pmp.cfg(i+1)(4 downto 3) /= pmp_mode_tor_c) then -- cfg(i+1) not "LOCKED TOR" - pmp.addr(i) <= "00" & csr.wdata(XLEN-3 downto 0); - end if; - else -- very last entry - pmp.addr(i) <= "00" & csr.wdata(XLEN-3 downto 0); - end if; + csr_read_access: process(csr, trap_ctrl.irq_pnd, hpmevent_rd, cnt_lo_rd, cnt_hi_rd) + begin + csr_rdata <= (others => '0'); -- default + case csr.raddr is + + -- machine trap setup -- + -- -------------------------------------------------------------------- + when csr_mstatus_c => -- machine status register - low word + csr_rdata(03) <= csr.mstatus_mie; + csr_rdata(07) <= csr.mstatus_mpie; + csr_rdata(12 downto 11) <= (others => csr.mstatus_mpp); + csr_rdata(17) <= csr.mstatus_mprv; + csr_rdata(21) <= csr.mstatus_tw and bool_to_ulogic_f(CPU_EXTENSION_RISCV_U); + +-- when csr_mstatush_c => csr_rdata <= (others => '0'); -- machine status register - hardwired to zero + + when csr_misa_c => -- ISA and extensions + csr_rdata(00) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_A); -- A CPU extension + csr_rdata(01) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B); -- B CPU extension + csr_rdata(02) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_C); -- C CPU extension + csr_rdata(04) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E); -- E CPU extension + csr_rdata(08) <= bool_to_ulogic_f(not CPU_EXTENSION_RISCV_E); -- I CPU extension (if not E) + csr_rdata(12) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_M); -- M CPU extension + csr_rdata(20) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_U); -- U CPU extension + csr_rdata(23) <= '1'; -- X CPU extension (non-standard extensions / NEORV32-specific) + csr_rdata(31 downto 30) <= "01"; -- MXL = 32 + + when csr_mie_c => -- machine interrupt-enable register + csr_rdata(03) <= csr.mie_msi; + csr_rdata(07) <= csr.mie_mti; + csr_rdata(11) <= csr.mie_mei; + csr_rdata(31 downto 16) <= csr.mie_firq; + + when csr_mtvec_c => -- machine trap-handler base address + csr_rdata <= csr.mtvec(XLEN-1 downto 2) & "00"; -- mtvec.MODE=0 (direct) + + when csr_mcounteren_c => -- machine counter enable register + if (CPU_EXTENSION_RISCV_U = true) then + csr_rdata(0) <= csr.mcounteren(0); -- cycle[h] + csr_rdata(2) <= csr.mcounteren(2); -- instret[h] + if (CPU_EXTENSION_RISCV_Zihpm = true) and (hpm_num_c > 0) then + for i in 3 to (hpm_num_c+3)-1 loop + csr_rdata(i) <= csr.mcounteren(i); -- hpmcounter*[h] + end loop; end if; - end if; - end process pmp_reg; - end generate; - -- PMP output to bus unit and CSR read-back -- - pmp_connect: process(pmp) - begin - pmp_ctrl_o <= (others => (others => '0')); - pmp_addr_o <= (others => (others => '0')); - pmp_cfg_rd <= (others => (others => '0')); - pmp_addr_rd <= (others => (others => '0')); - for i in 0 to PMP_NUM_REGIONS-1 loop - pmp_ctrl_o(i) <= pmp.cfg(i); - pmp_addr_o(i) <= pmp.addr(i) & "00"; -- word aligned address - pmp_cfg_rd(i/4)(8*(i mod 4)+7 downto 8*(i mod 4)+0) <= pmp.cfg(i); - pmp_addr_rd(i)(XLEN-1 downto index_size_f(PMP_MIN_GRANULARITY)-2) <= pmp.addr(i)(XLEN-1 downto index_size_f(PMP_MIN_GRANULARITY)-2); - if (PMP_MIN_GRANULARITY = 8) then -- bit [G-1] reads as zero in TOR or OFF mode - if (pmp.cfg(i)(4) = '0') then -- TOR/OFF - pmp_addr_rd(i)(index_size_f(PMP_MIN_GRANULARITY)-1) <= '0'; - end if; - elsif (PMP_MIN_GRANULARITY > 8) then - -- in NAPOT mode, bits [G-2:0] must read as one - pmp_addr_rd(i)(index_size_f(PMP_MIN_GRANULARITY)-2 downto 0) <= (others => '1'); - -- in TOR or OFF mode, bits [G-1:0] must read as zero - if (pmp.cfg(i)(4) = '0') then -- TOR/OFF - pmp_addr_rd(i)(index_size_f(PMP_MIN_GRANULARITY)-1 downto 0) <= (others => '0'); - end if; + -- machine configuration -- + -- -------------------------------------------------------------------- +-- when csr_menvcfg_c => csr_rdata <= (others => '0'); -- hardwired to zero +-- when csr_menvcfgh_c => csr_rdata <= (others => '0'); -- hardwired to zero + + -- machine trap handling -- + -- -------------------------------------------------------------------- + when csr_mscratch_c => -- machine scratch register + csr_rdata <= csr.mscratch; + + when csr_mepc_c => -- machine exception program counter + csr_rdata <= csr.mepc(XLEN-1 downto 1) & '0'; + + when csr_mcause_c => -- machine trap cause + csr_rdata(31) <= csr.mcause(5); + csr_rdata(4 downto 0) <= csr.mcause(4 downto 0); + + when csr_mtval_c => -- machine bad address or instruction + csr_rdata <= csr.mtval; + + when csr_mip_c => -- machine interrupt pending + csr_rdata(03) <= trap_ctrl.irq_pnd(irq_msi_irq_c); + csr_rdata(07) <= trap_ctrl.irq_pnd(irq_mti_irq_c); + csr_rdata(11) <= trap_ctrl.irq_pnd(irq_mei_irq_c); + csr_rdata(31 downto 16) <= trap_ctrl.irq_pnd(irq_firq_15_c downto irq_firq_0_c); + + -- machine counter setup -- + -- -------------------------------------------------------------------- + when csr_mcountinhibit_c => -- machine counter-inhibit register + if (CPU_EXTENSION_RISCV_Zicntr = true) then + csr_rdata(0) <= csr.mcountinhibit(0); -- [m]cycle[h] + csr_rdata(2) <= csr.mcountinhibit(2); -- [m]instret[h] end if; - end loop; - end process pmp_connect; - - end generate; -- /pmp_gen_enable - - - -- no PMP implemented -- - pmp_gen_disable: - if (PMP_NUM_REGIONS = 0) generate - pmp_ctrl_o <= (others => (others => '0')); - pmp_addr_o <= (others => (others => '0')); - pmp_cfg_rd <= (others => (others => '0')); - pmp_addr_rd <= (others => (others => '0')); - end generate; -- /pmp_gen_disable - - - -- Hardware Performance Monitors (HPM) - Counter Event Configuration CSRs ----------------- - -- ------------------------------------------------------------------------------------------- - hpm_gen_enable: - if (CPU_EXTENSION_RISCV_Zihpm = true) generate - - -- write enable decoder -- - hpmevent_we: process(csr) - begin - hpmevent.we <= (others => '0'); - if (csr.addr(11 downto 5) = csr_cnt_setup_c) and (csr.we = '1') then - hpmevent.we(to_integer(unsigned(csr.addr(4 downto 0)))) <= '1'; - end if; - end process hpmevent_we; - - -- HPM event registers -- - hpmevent_reg_gen: - for i in 0 to hpm_num_c-1 generate - hpmevent_reg: process(rstn_i, clk_i) - begin - if (rstn_i = '0') then - hpmevent.cfg(i) <= (others => '0'); - elsif rising_edge(clk_i) then - if (hpmevent.we(3+i) = '1') then - hpmevent.cfg(i) <= csr.wdata(hpmcnt_event_size_c-1 downto 0); - end if; + if (CPU_EXTENSION_RISCV_Zihpm = true) and (hpm_num_c > 0) then + for i in 3 to (hpm_num_c+3)-1 loop + csr_rdata(i) <= csr.mcountinhibit(i); -- [m]hpmcounter*[h] + end loop; end if; - end process hpmevent_reg; - end generate; - -- HPM event CSR read-back -- - hpm_event_connect: process(hpmevent) - begin - hpmevent_rd <= (others => (others => '0')); - for i in 3 to (hpm_num_c+3)-1 loop - hpmevent_rd(i)(hpmcnt_event_size_c-1 downto 0) <= hpmevent.cfg(i-3); - hpmevent_rd(i)(hpmcnt_event_tm_c) <= '0'; -- time, unused/reserved - end loop; - end process hpm_event_connect; - - end generate; -- /hpm_gen_enable + -- HPM event select -- + when csr_mhpmevent3_c => if (hpm_num_c > 00) then csr_rdata <= hpmevent_rd(03); end if; + when csr_mhpmevent4_c => if (hpm_num_c > 01) then csr_rdata <= hpmevent_rd(04); end if; + when csr_mhpmevent5_c => if (hpm_num_c > 02) then csr_rdata <= hpmevent_rd(05); end if; + when csr_mhpmevent6_c => if (hpm_num_c > 03) then csr_rdata <= hpmevent_rd(06); end if; + when csr_mhpmevent7_c => if (hpm_num_c > 04) then csr_rdata <= hpmevent_rd(07); end if; + when csr_mhpmevent8_c => if (hpm_num_c > 05) then csr_rdata <= hpmevent_rd(08); end if; + when csr_mhpmevent9_c => if (hpm_num_c > 06) then csr_rdata <= hpmevent_rd(09); end if; + when csr_mhpmevent10_c => if (hpm_num_c > 07) then csr_rdata <= hpmevent_rd(10); end if; + when csr_mhpmevent11_c => if (hpm_num_c > 08) then csr_rdata <= hpmevent_rd(11); end if; + when csr_mhpmevent12_c => if (hpm_num_c > 09) then csr_rdata <= hpmevent_rd(12); end if; + when csr_mhpmevent13_c => if (hpm_num_c > 10) then csr_rdata <= hpmevent_rd(13); end if; + when csr_mhpmevent14_c => if (hpm_num_c > 11) then csr_rdata <= hpmevent_rd(14); end if; + when csr_mhpmevent15_c => if (hpm_num_c > 12) then csr_rdata <= hpmevent_rd(15); end if; + + -- counters and timers -- + -- -------------------------------------------------------------------- + -- low word -- + when csr_mcycle_c | csr_cycle_c => if (CPU_EXTENSION_RISCV_Zicntr) then csr_rdata <= cnt_lo_rd(00); end if; + when csr_minstret_c | csr_instret_c => if (CPU_EXTENSION_RISCV_Zicntr) then csr_rdata <= cnt_lo_rd(02); end if; + when csr_mhpmcounter3_c | csr_hpmcounter3_c => if (hpm_num_c > 00) then csr_rdata <= cnt_lo_rd(03); end if; + when csr_mhpmcounter4_c | csr_hpmcounter4_c => if (hpm_num_c > 01) then csr_rdata <= cnt_lo_rd(04); end if; + when csr_mhpmcounter5_c | csr_hpmcounter5_c => if (hpm_num_c > 02) then csr_rdata <= cnt_lo_rd(05); end if; + when csr_mhpmcounter6_c | csr_hpmcounter6_c => if (hpm_num_c > 03) then csr_rdata <= cnt_lo_rd(06); end if; + when csr_mhpmcounter7_c | csr_hpmcounter7_c => if (hpm_num_c > 04) then csr_rdata <= cnt_lo_rd(07); end if; + when csr_mhpmcounter8_c | csr_hpmcounter8_c => if (hpm_num_c > 05) then csr_rdata <= cnt_lo_rd(08); end if; + when csr_mhpmcounter9_c | csr_hpmcounter9_c => if (hpm_num_c > 06) then csr_rdata <= cnt_lo_rd(09); end if; + when csr_mhpmcounter10_c | csr_hpmcounter10_c => if (hpm_num_c > 07) then csr_rdata <= cnt_lo_rd(10); end if; + when csr_mhpmcounter11_c | csr_hpmcounter11_c => if (hpm_num_c > 08) then csr_rdata <= cnt_lo_rd(11); end if; + when csr_mhpmcounter12_c | csr_hpmcounter12_c => if (hpm_num_c > 09) then csr_rdata <= cnt_lo_rd(12); end if; + when csr_mhpmcounter13_c | csr_hpmcounter13_c => if (hpm_num_c > 10) then csr_rdata <= cnt_lo_rd(13); end if; + when csr_mhpmcounter14_c | csr_hpmcounter14_c => if (hpm_num_c > 11) then csr_rdata <= cnt_lo_rd(14); end if; + when csr_mhpmcounter15_c | csr_hpmcounter15_c => if (hpm_num_c > 12) then csr_rdata <= cnt_lo_rd(15); end if; + + -- high word -- + when csr_mcycleh_c | csr_cycleh_c => if (CPU_EXTENSION_RISCV_Zicntr) then csr_rdata <= cnt_hi_rd(00); end if; + when csr_minstreth_c | csr_instreth_c => if (CPU_EXTENSION_RISCV_Zicntr) then csr_rdata <= cnt_hi_rd(02); end if; + when csr_mhpmcounter3h_c | csr_hpmcounter3h_c => if (hpm_num_c > 00) then csr_rdata <= cnt_hi_rd(03); end if; + when csr_mhpmcounter4h_c | csr_hpmcounter4h_c => if (hpm_num_c > 01) then csr_rdata <= cnt_hi_rd(04); end if; + when csr_mhpmcounter5h_c | csr_hpmcounter5h_c => if (hpm_num_c > 02) then csr_rdata <= cnt_hi_rd(05); end if; + when csr_mhpmcounter6h_c | csr_hpmcounter6h_c => if (hpm_num_c > 03) then csr_rdata <= cnt_hi_rd(06); end if; + when csr_mhpmcounter7h_c | csr_hpmcounter7h_c => if (hpm_num_c > 04) then csr_rdata <= cnt_hi_rd(07); end if; + when csr_mhpmcounter8h_c | csr_hpmcounter8h_c => if (hpm_num_c > 05) then csr_rdata <= cnt_hi_rd(08); end if; + when csr_mhpmcounter9h_c | csr_hpmcounter9h_c => if (hpm_num_c > 06) then csr_rdata <= cnt_hi_rd(09); end if; + when csr_mhpmcounter10h_c | csr_hpmcounter10h_c => if (hpm_num_c > 07) then csr_rdata <= cnt_hi_rd(10); end if; + when csr_mhpmcounter11h_c | csr_hpmcounter11h_c => if (hpm_num_c > 08) then csr_rdata <= cnt_hi_rd(11); end if; + when csr_mhpmcounter12h_c | csr_hpmcounter12h_c => if (hpm_num_c > 09) then csr_rdata <= cnt_hi_rd(12); end if; + when csr_mhpmcounter13h_c | csr_hpmcounter13h_c => if (hpm_num_c > 10) then csr_rdata <= cnt_hi_rd(13); end if; + when csr_mhpmcounter14h_c | csr_hpmcounter14h_c => if (hpm_num_c > 11) then csr_rdata <= cnt_hi_rd(14); end if; + when csr_mhpmcounter15h_c | csr_hpmcounter15h_c => if (hpm_num_c > 12) then csr_rdata <= cnt_hi_rd(15); end if; + + -- machine information registers -- + -- -------------------------------------------------------------------- + when csr_mvendorid_c => csr_rdata <= VENDOR_ID; -- vendor's JEDEC ID + when csr_marchid_c => csr_rdata(4 downto 0) <= "10011"; -- architecture ID - official RISC-V open-source arch ID + when csr_mimpid_c => csr_rdata <= hw_version_c; -- implementation ID -- NEORV32 hardware version + when csr_mhartid_c => csr_rdata <= HART_ID; -- hardware thread ID +-- when csr_mconfigptr_c => csr_rdata <= (others => '0'); -- machine configuration pointer register - hardwired to zero + + -- debug mode CSRs -- + -- -------------------------------------------------------------------- + when csr_dcsr_c => if (CPU_EXTENSION_RISCV_Sdext) then csr_rdata <= csr.dcsr_rd; end if; -- debug mode control and status + when csr_dpc_c => if (CPU_EXTENSION_RISCV_Sdext) then csr_rdata <= csr.dpc; end if; -- debug mode program counter + when csr_dscratch0_c => if (CPU_EXTENSION_RISCV_Sdext) then csr_rdata <= csr.dscratch0; end if; -- debug mode scratch register 0 + -- trigger module CSRs -- + -- -------------------------------------------------------------------- +-- when csr_tselect_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr_rdata <= (others => '0'); end if; -- hardwired to zero = only 1 trigger available + when csr_tdata1_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr_rdata <= csr.tdata1_rd; end if; -- match control + when csr_tdata2_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr_rdata <= csr.tdata2; end if; -- address-compare +-- when csr_tdata3_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr_rdata <= (others => '0'); end if; -- hardwired to zero + when csr_tinfo_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr_rdata <= x"00000004"; end if; -- address-match trigger only +-- when csr_tcontrol_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr_rdata <= (others => '0'); end if; -- hardwired to zero +-- when csr_mcontext_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr_rdata <= (others => '0'); end if; -- hardwired to zero +-- when csr_scontext_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr_rdata <= (others => '0'); end if; -- hardwired to zero + + -- NEORV32-specific (RISC-V "custom") read-only CSRs -- + -- -------------------------------------------------------------------- + -- machine extended ISA extensions information -- + when csr_mxisa_c => + -- extended ISA (sub-)extensions -- + csr_rdata(00) <= '1'; -- Zicsr: CSR access (always enabled) + csr_rdata(01) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zifencei); -- Zifencei: instruction stream sync. + csr_rdata(02) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zmmul); -- Zmmul: mul/div + csr_rdata(03) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zxcfu); -- Zxcfu: custom RISC-V instructions + csr_rdata(04) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicond); -- Zicond: conditional operations + csr_rdata(05) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zfinx); -- Zfinx: FPU using x registers +-- csr_rdata(06) <= '0'; -- reserved + csr_rdata(07) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicntr); -- Zicntr: base counters + csr_rdata(08) <= bool_to_ulogic_f(PMP_EN); -- PMP: physical memory protection (Smpmp) + csr_rdata(09) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zihpm); -- Zihpm: hardware performance monitors + csr_rdata(10) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Sdext); -- Sdext: RISC-V (external) debug mode + csr_rdata(11) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Sdtrig); -- Sdtrig: trigger module + -- misc -- + csr_rdata(20) <= bool_to_ulogic_f(is_simulation_c); -- is this a simulation? + -- tuning options -- + csr_rdata(30) <= bool_to_ulogic_f(FAST_MUL_EN); -- DSP-based multiplication (M extensions only) + csr_rdata(31) <= bool_to_ulogic_f(FAST_SHIFT_EN); -- parallel logic for shifts (barrel shifters) + + -- undefined/unavailable -- + -- -------------------------------------------------------------------- + when others => NULL; -- read as zero - -- no HPMs implemented -- - hpm_gen_disable: - if (CPU_EXTENSION_RISCV_Zihpm = false) generate - hpmevent.we <= (others => '0'); - hpmevent.cfg <= (others => (others => '0')); - hpmevent_rd <= (others => (others => '0')); - end generate; -- /hpm_gen_disable + end case; + end process csr_read_access; - -- Control and Status Registers - Read Access --------------------------------------------- - -- ------------------------------------------------------------------------------------------- - csr_read_access: process(clk_i) + -- CSR read-data gate -- + csr_read_reg: process(rstn_i, clk_i) begin - if rising_edge(clk_i) then - csr.re <= csr.re_nxt; -- read access? - csr.rdata <= (others => '0'); -- default output, unimplemented CSR/bits read as zero - case csr.raddr is - - -- hardware-only CSRs -- - -- -------------------------------------------------------------------- --- when csr_zero_c => -- zero: always returns zero, only relevant for hardware-access, not visible to ISA --- csr.rdata <= (others => '0'); - - -- floating-point CSRs -- - -- -------------------------------------------------------------------- - when csr_fflags_c => -- floating-point (FPU) exception flags - if (CPU_EXTENSION_RISCV_Zfinx) then csr.rdata(4 downto 0) <= csr.fflags; end if; - - when csr_frm_c => -- floating-point (FPU) rounding mode - if (CPU_EXTENSION_RISCV_Zfinx) then csr.rdata(2 downto 0) <= csr.frm; end if; - - when csr_fcsr_c => -- floating-point (FPU) control/status (frm & fflags) - if (CPU_EXTENSION_RISCV_Zfinx) then csr.rdata(7 downto 0) <= csr.frm & csr.fflags; end if; - - -- machine trap setup -- - -- -------------------------------------------------------------------- - when csr_mstatus_c => -- machine status register - low word - csr.rdata(03) <= csr.mstatus_mie; -- MIE - csr.rdata(07) <= csr.mstatus_mpie; -- MPIE - csr.rdata(12 downto 11) <= (others => csr.mstatus_mpp); -- MPP: machine previous privilege mode - csr.rdata(17) <= csr.mstatus_mprv; - csr.rdata(21) <= csr.mstatus_tw and bool_to_ulogic_f(CPU_EXTENSION_RISCV_U); -- TW - --- when csr_mstatush_c => -- machine status register - high word, implemented but always zero --- csr.rdata <= (others => '0'); - - when csr_misa_c => -- ISA and extensions - csr.rdata(00) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_A); -- A CPU extension - csr.rdata(01) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_B); -- B CPU extension - csr.rdata(02) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_C); -- C CPU extension - csr.rdata(04) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_E); -- E CPU extension - csr.rdata(08) <= bool_to_ulogic_f(not CPU_EXTENSION_RISCV_E); -- I CPU extension (if not E) - csr.rdata(12) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_M); -- M CPU extension - csr.rdata(20) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_U); -- U CPU extension - csr.rdata(23) <= '1'; -- X CPU extension (non-standard extensions / NEORV32-specific) - csr.rdata(31 downto 30) <= "01"; -- machine XLEN = 32 - - when csr_mie_c => -- machine interrupt-enable register - csr.rdata(03) <= csr.mie_msi; - csr.rdata(07) <= csr.mie_mti; - csr.rdata(11) <= csr.mie_mei; - csr.rdata(31 downto 16) <= csr.mie_firq; - - when csr_mtvec_c => --machine trap-handler base address (for ALL exceptions) - csr.rdata <= csr.mtvec(XLEN-1 downto 2) & "00"; -- mtvec.MODE=0 - - when csr_mcounteren_c => -- machine counter enable register - if (CPU_EXTENSION_RISCV_U = true) then - csr.rdata(0) <= csr.mcounteren(0); -- allow user-level access to cycle[h] - csr.rdata(2) <= csr.mcounteren(2); -- allow user-level access to instret[h] - if (CPU_EXTENSION_RISCV_Zihpm = true) and (hpm_num_c > 0) then -- any HPMs implemented? - csr.rdata((hpm_num_c+3)-1 downto 3) <= csr.mcounteren((hpm_num_c+3)-1 downto 3); -- allow user-level access to all available hpmcounter*[h] CSRs - end if; - end if; - - -- machine configuration -- - -- -------------------------------------------------------------------- --- when csr_menvcfg_c => csr.rdata <= (others => '0'); -- hardwired to zero --- when csr_menvcfgh_c => csr.rdata <= (others => '0'); -- hardwired to zero - - -- machine trap handling -- - -- -------------------------------------------------------------------- - when csr_mscratch_c => -- machine scratch register - csr.rdata <= csr.mscratch; - - when csr_mepc_c => -- machine exception program counter - csr.rdata <= csr.mepc(XLEN-1 downto 1) & '0'; - - when csr_mcause_c => -- machine trap cause - csr.rdata(31) <= csr.mcause(5); - csr.rdata(4 downto 0) <= csr.mcause(4 downto 0); - - when csr_mtval_c => -- machine bad address or instruction - csr.rdata <= csr.mtval; - - when csr_mip_c => -- machine interrupt pending - csr.rdata(03) <= trap_ctrl.irq_pnd(irq_msi_irq_c); - csr.rdata(07) <= trap_ctrl.irq_pnd(irq_mti_irq_c); - csr.rdata(11) <= trap_ctrl.irq_pnd(irq_mei_irq_c); - csr.rdata(31 downto 16) <= trap_ctrl.irq_pnd(irq_firq_15_c downto irq_firq_0_c); - - -- physical memory protection -- - -- -------------------------------------------------------------------- - -- region configuration -- - when csr_pmpcfg0_c => if (PMP_NUM_REGIONS > 00) then csr.rdata <= pmp_cfg_rd(0); end if; - when csr_pmpcfg1_c => if (PMP_NUM_REGIONS > 04) then csr.rdata <= pmp_cfg_rd(1); end if; - when csr_pmpcfg2_c => if (PMP_NUM_REGIONS > 08) then csr.rdata <= pmp_cfg_rd(2); end if; - when csr_pmpcfg3_c => if (PMP_NUM_REGIONS > 12) then csr.rdata <= pmp_cfg_rd(3); end if; - - -- region address -- - when csr_pmpaddr0_c => if (PMP_NUM_REGIONS > 00) then csr.rdata <= pmp_addr_rd(00); end if; - when csr_pmpaddr1_c => if (PMP_NUM_REGIONS > 01) then csr.rdata <= pmp_addr_rd(01); end if; - when csr_pmpaddr2_c => if (PMP_NUM_REGIONS > 02) then csr.rdata <= pmp_addr_rd(02); end if; - when csr_pmpaddr3_c => if (PMP_NUM_REGIONS > 03) then csr.rdata <= pmp_addr_rd(03); end if; - when csr_pmpaddr4_c => if (PMP_NUM_REGIONS > 04) then csr.rdata <= pmp_addr_rd(04); end if; - when csr_pmpaddr5_c => if (PMP_NUM_REGIONS > 05) then csr.rdata <= pmp_addr_rd(05); end if; - when csr_pmpaddr6_c => if (PMP_NUM_REGIONS > 06) then csr.rdata <= pmp_addr_rd(06); end if; - when csr_pmpaddr7_c => if (PMP_NUM_REGIONS > 07) then csr.rdata <= pmp_addr_rd(07); end if; - when csr_pmpaddr8_c => if (PMP_NUM_REGIONS > 08) then csr.rdata <= pmp_addr_rd(08); end if; - when csr_pmpaddr9_c => if (PMP_NUM_REGIONS > 09) then csr.rdata <= pmp_addr_rd(09); end if; - when csr_pmpaddr10_c => if (PMP_NUM_REGIONS > 10) then csr.rdata <= pmp_addr_rd(10); end if; - when csr_pmpaddr11_c => if (PMP_NUM_REGIONS > 11) then csr.rdata <= pmp_addr_rd(11); end if; - when csr_pmpaddr12_c => if (PMP_NUM_REGIONS > 12) then csr.rdata <= pmp_addr_rd(12); end if; - when csr_pmpaddr13_c => if (PMP_NUM_REGIONS > 13) then csr.rdata <= pmp_addr_rd(13); end if; - when csr_pmpaddr14_c => if (PMP_NUM_REGIONS > 14) then csr.rdata <= pmp_addr_rd(14); end if; - when csr_pmpaddr15_c => if (PMP_NUM_REGIONS > 15) then csr.rdata <= pmp_addr_rd(15); end if; - - -- machine counter setup -- - -- -------------------------------------------------------------------- - when csr_mcountinhibit_c => -- machine counter-inhibit register - if (CPU_EXTENSION_RISCV_Zicntr = true) then - csr.rdata(0) <= csr.mcountinhibit(0); -- inhibit [m]cycle[h] counter - csr.rdata(2) <= csr.mcountinhibit(2); -- inhibit [m]instret[h] counter - end if; - if (CPU_EXTENSION_RISCV_Zihpm = true) and (hpm_num_c > 0) then -- any HPMs implemented? - csr.rdata((hpm_num_c+3)-1 downto 3) <= csr.mcountinhibit((hpm_num_c+3)-1 downto 3); -- inhibit [m]hpmcounter*[h] counter - end if; - - -- HPM event select -- - when csr_mhpmevent3_c => if (hpm_num_c > 00) then csr.rdata <= hpmevent_rd(03); end if; - when csr_mhpmevent4_c => if (hpm_num_c > 01) then csr.rdata <= hpmevent_rd(04); end if; - when csr_mhpmevent5_c => if (hpm_num_c > 02) then csr.rdata <= hpmevent_rd(05); end if; - when csr_mhpmevent6_c => if (hpm_num_c > 03) then csr.rdata <= hpmevent_rd(06); end if; - when csr_mhpmevent7_c => if (hpm_num_c > 04) then csr.rdata <= hpmevent_rd(07); end if; - when csr_mhpmevent8_c => if (hpm_num_c > 05) then csr.rdata <= hpmevent_rd(08); end if; - when csr_mhpmevent9_c => if (hpm_num_c > 06) then csr.rdata <= hpmevent_rd(09); end if; - when csr_mhpmevent10_c => if (hpm_num_c > 07) then csr.rdata <= hpmevent_rd(10); end if; - when csr_mhpmevent11_c => if (hpm_num_c > 08) then csr.rdata <= hpmevent_rd(11); end if; - when csr_mhpmevent12_c => if (hpm_num_c > 09) then csr.rdata <= hpmevent_rd(12); end if; - when csr_mhpmevent13_c => if (hpm_num_c > 10) then csr.rdata <= hpmevent_rd(13); end if; - when csr_mhpmevent14_c => if (hpm_num_c > 11) then csr.rdata <= hpmevent_rd(14); end if; - when csr_mhpmevent15_c => if (hpm_num_c > 12) then csr.rdata <= hpmevent_rd(15); end if; - when csr_mhpmevent16_c => if (hpm_num_c > 13) then csr.rdata <= hpmevent_rd(16); end if; - when csr_mhpmevent17_c => if (hpm_num_c > 14) then csr.rdata <= hpmevent_rd(17); end if; - when csr_mhpmevent18_c => if (hpm_num_c > 15) then csr.rdata <= hpmevent_rd(18); end if; - when csr_mhpmevent19_c => if (hpm_num_c > 16) then csr.rdata <= hpmevent_rd(19); end if; - when csr_mhpmevent20_c => if (hpm_num_c > 17) then csr.rdata <= hpmevent_rd(20); end if; - when csr_mhpmevent21_c => if (hpm_num_c > 18) then csr.rdata <= hpmevent_rd(21); end if; - when csr_mhpmevent22_c => if (hpm_num_c > 19) then csr.rdata <= hpmevent_rd(22); end if; - when csr_mhpmevent23_c => if (hpm_num_c > 20) then csr.rdata <= hpmevent_rd(23); end if; - when csr_mhpmevent24_c => if (hpm_num_c > 21) then csr.rdata <= hpmevent_rd(24); end if; - when csr_mhpmevent25_c => if (hpm_num_c > 22) then csr.rdata <= hpmevent_rd(25); end if; - when csr_mhpmevent26_c => if (hpm_num_c > 23) then csr.rdata <= hpmevent_rd(26); end if; - when csr_mhpmevent27_c => if (hpm_num_c > 24) then csr.rdata <= hpmevent_rd(27); end if; - when csr_mhpmevent28_c => if (hpm_num_c > 25) then csr.rdata <= hpmevent_rd(28); end if; - when csr_mhpmevent29_c => if (hpm_num_c > 26) then csr.rdata <= hpmevent_rd(29); end if; - when csr_mhpmevent30_c => if (hpm_num_c > 27) then csr.rdata <= hpmevent_rd(30); end if; - when csr_mhpmevent31_c => if (hpm_num_c > 28) then csr.rdata <= hpmevent_rd(31); end if; - - -- counters and timers -- - -- -------------------------------------------------------------------- - -- low word -- - when csr_mcycle_c | csr_cycle_c => if (CPU_EXTENSION_RISCV_Zicntr) then csr.rdata <= cnt_lo_rd(00); end if; - when csr_minstret_c | csr_instret_c => if (CPU_EXTENSION_RISCV_Zicntr) then csr.rdata <= cnt_lo_rd(02); end if; - when csr_mhpmcounter3_c | csr_hpmcounter3_c => if (hpm_num_c > 00) then csr.rdata <= cnt_lo_rd(03); end if; - when csr_mhpmcounter4_c | csr_hpmcounter4_c => if (hpm_num_c > 01) then csr.rdata <= cnt_lo_rd(04); end if; - when csr_mhpmcounter5_c | csr_hpmcounter5_c => if (hpm_num_c > 02) then csr.rdata <= cnt_lo_rd(05); end if; - when csr_mhpmcounter6_c | csr_hpmcounter6_c => if (hpm_num_c > 03) then csr.rdata <= cnt_lo_rd(06); end if; - when csr_mhpmcounter7_c | csr_hpmcounter7_c => if (hpm_num_c > 04) then csr.rdata <= cnt_lo_rd(07); end if; - when csr_mhpmcounter8_c | csr_hpmcounter8_c => if (hpm_num_c > 05) then csr.rdata <= cnt_lo_rd(08); end if; - when csr_mhpmcounter9_c | csr_hpmcounter9_c => if (hpm_num_c > 06) then csr.rdata <= cnt_lo_rd(09); end if; - when csr_mhpmcounter10_c | csr_hpmcounter10_c => if (hpm_num_c > 07) then csr.rdata <= cnt_lo_rd(10); end if; - when csr_mhpmcounter11_c | csr_hpmcounter11_c => if (hpm_num_c > 08) then csr.rdata <= cnt_lo_rd(11); end if; - when csr_mhpmcounter12_c | csr_hpmcounter12_c => if (hpm_num_c > 09) then csr.rdata <= cnt_lo_rd(12); end if; - when csr_mhpmcounter13_c | csr_hpmcounter13_c => if (hpm_num_c > 10) then csr.rdata <= cnt_lo_rd(13); end if; - when csr_mhpmcounter14_c | csr_hpmcounter14_c => if (hpm_num_c > 11) then csr.rdata <= cnt_lo_rd(14); end if; - when csr_mhpmcounter15_c | csr_hpmcounter15_c => if (hpm_num_c > 12) then csr.rdata <= cnt_lo_rd(15); end if; - when csr_mhpmcounter16_c | csr_hpmcounter16_c => if (hpm_num_c > 13) then csr.rdata <= cnt_lo_rd(16); end if; - when csr_mhpmcounter17_c | csr_hpmcounter17_c => if (hpm_num_c > 14) then csr.rdata <= cnt_lo_rd(17); end if; - when csr_mhpmcounter18_c | csr_hpmcounter18_c => if (hpm_num_c > 15) then csr.rdata <= cnt_lo_rd(18); end if; - when csr_mhpmcounter19_c | csr_hpmcounter19_c => if (hpm_num_c > 16) then csr.rdata <= cnt_lo_rd(19); end if; - when csr_mhpmcounter20_c | csr_hpmcounter20_c => if (hpm_num_c > 17) then csr.rdata <= cnt_lo_rd(20); end if; - when csr_mhpmcounter21_c | csr_hpmcounter21_c => if (hpm_num_c > 18) then csr.rdata <= cnt_lo_rd(21); end if; - when csr_mhpmcounter22_c | csr_hpmcounter22_c => if (hpm_num_c > 19) then csr.rdata <= cnt_lo_rd(22); end if; - when csr_mhpmcounter23_c | csr_hpmcounter23_c => if (hpm_num_c > 20) then csr.rdata <= cnt_lo_rd(23); end if; - when csr_mhpmcounter24_c | csr_hpmcounter24_c => if (hpm_num_c > 21) then csr.rdata <= cnt_lo_rd(24); end if; - when csr_mhpmcounter25_c | csr_hpmcounter25_c => if (hpm_num_c > 22) then csr.rdata <= cnt_lo_rd(25); end if; - when csr_mhpmcounter26_c | csr_hpmcounter26_c => if (hpm_num_c > 23) then csr.rdata <= cnt_lo_rd(26); end if; - when csr_mhpmcounter27_c | csr_hpmcounter27_c => if (hpm_num_c > 24) then csr.rdata <= cnt_lo_rd(27); end if; - when csr_mhpmcounter28_c | csr_hpmcounter28_c => if (hpm_num_c > 25) then csr.rdata <= cnt_lo_rd(28); end if; - when csr_mhpmcounter29_c | csr_hpmcounter29_c => if (hpm_num_c > 26) then csr.rdata <= cnt_lo_rd(29); end if; - when csr_mhpmcounter30_c | csr_hpmcounter30_c => if (hpm_num_c > 27) then csr.rdata <= cnt_lo_rd(30); end if; - when csr_mhpmcounter31_c | csr_hpmcounter31_c => if (hpm_num_c > 28) then csr.rdata <= cnt_lo_rd(31); end if; - - -- high word -- - when csr_mcycleh_c | csr_cycleh_c => if (CPU_EXTENSION_RISCV_Zicntr) then csr.rdata <= cnt_hi_rd(00); end if; - when csr_minstreth_c | csr_instreth_c => if (CPU_EXTENSION_RISCV_Zicntr) then csr.rdata <= cnt_hi_rd(02); end if; - when csr_mhpmcounter3h_c | csr_hpmcounter3h_c => if (hpm_num_c > 00) then csr.rdata <= cnt_hi_rd(03); end if; - when csr_mhpmcounter4h_c | csr_hpmcounter4h_c => if (hpm_num_c > 01) then csr.rdata <= cnt_hi_rd(04); end if; - when csr_mhpmcounter5h_c | csr_hpmcounter5h_c => if (hpm_num_c > 02) then csr.rdata <= cnt_hi_rd(05); end if; - when csr_mhpmcounter6h_c | csr_hpmcounter6h_c => if (hpm_num_c > 03) then csr.rdata <= cnt_hi_rd(06); end if; - when csr_mhpmcounter7h_c | csr_hpmcounter7h_c => if (hpm_num_c > 04) then csr.rdata <= cnt_hi_rd(07); end if; - when csr_mhpmcounter8h_c | csr_hpmcounter8h_c => if (hpm_num_c > 05) then csr.rdata <= cnt_hi_rd(08); end if; - when csr_mhpmcounter9h_c | csr_hpmcounter9h_c => if (hpm_num_c > 06) then csr.rdata <= cnt_hi_rd(09); end if; - when csr_mhpmcounter10h_c | csr_hpmcounter10h_c => if (hpm_num_c > 07) then csr.rdata <= cnt_hi_rd(10); end if; - when csr_mhpmcounter11h_c | csr_hpmcounter11h_c => if (hpm_num_c > 08) then csr.rdata <= cnt_hi_rd(11); end if; - when csr_mhpmcounter12h_c | csr_hpmcounter12h_c => if (hpm_num_c > 09) then csr.rdata <= cnt_hi_rd(12); end if; - when csr_mhpmcounter13h_c | csr_hpmcounter13h_c => if (hpm_num_c > 10) then csr.rdata <= cnt_hi_rd(13); end if; - when csr_mhpmcounter14h_c | csr_hpmcounter14h_c => if (hpm_num_c > 11) then csr.rdata <= cnt_hi_rd(14); end if; - when csr_mhpmcounter15h_c | csr_hpmcounter15h_c => if (hpm_num_c > 12) then csr.rdata <= cnt_hi_rd(15); end if; - when csr_mhpmcounter16h_c | csr_hpmcounter16h_c => if (hpm_num_c > 13) then csr.rdata <= cnt_hi_rd(16); end if; - when csr_mhpmcounter17h_c | csr_hpmcounter17h_c => if (hpm_num_c > 14) then csr.rdata <= cnt_hi_rd(17); end if; - when csr_mhpmcounter18h_c | csr_hpmcounter18h_c => if (hpm_num_c > 15) then csr.rdata <= cnt_hi_rd(18); end if; - when csr_mhpmcounter19h_c | csr_hpmcounter19h_c => if (hpm_num_c > 16) then csr.rdata <= cnt_hi_rd(19); end if; - when csr_mhpmcounter20h_c | csr_hpmcounter20h_c => if (hpm_num_c > 17) then csr.rdata <= cnt_hi_rd(20); end if; - when csr_mhpmcounter21h_c | csr_hpmcounter21h_c => if (hpm_num_c > 18) then csr.rdata <= cnt_hi_rd(21); end if; - when csr_mhpmcounter22h_c | csr_hpmcounter22h_c => if (hpm_num_c > 19) then csr.rdata <= cnt_hi_rd(22); end if; - when csr_mhpmcounter23h_c | csr_hpmcounter23h_c => if (hpm_num_c > 20) then csr.rdata <= cnt_hi_rd(23); end if; - when csr_mhpmcounter24h_c | csr_hpmcounter24h_c => if (hpm_num_c > 21) then csr.rdata <= cnt_hi_rd(24); end if; - when csr_mhpmcounter25h_c | csr_hpmcounter25h_c => if (hpm_num_c > 22) then csr.rdata <= cnt_hi_rd(25); end if; - when csr_mhpmcounter26h_c | csr_hpmcounter26h_c => if (hpm_num_c > 23) then csr.rdata <= cnt_hi_rd(26); end if; - when csr_mhpmcounter27h_c | csr_hpmcounter27h_c => if (hpm_num_c > 24) then csr.rdata <= cnt_hi_rd(27); end if; - when csr_mhpmcounter28h_c | csr_hpmcounter28h_c => if (hpm_num_c > 25) then csr.rdata <= cnt_hi_rd(28); end if; - when csr_mhpmcounter29h_c | csr_hpmcounter29h_c => if (hpm_num_c > 26) then csr.rdata <= cnt_hi_rd(29); end if; - when csr_mhpmcounter30h_c | csr_hpmcounter30h_c => if (hpm_num_c > 27) then csr.rdata <= cnt_hi_rd(30); end if; - when csr_mhpmcounter31h_c | csr_hpmcounter31h_c => if (hpm_num_c > 28) then csr.rdata <= cnt_hi_rd(31); end if; - - -- machine information registers -- - -- -------------------------------------------------------------------- - when csr_mvendorid_c => csr.rdata <= VENDOR_ID; -- vendor's JEDEC ID - when csr_marchid_c => csr.rdata(4 downto 0) <= "10011"; -- architecture ID - official RISC-V open-source arch ID - when csr_mimpid_c => csr.rdata <= hw_version_c; -- implementation ID -- NEORV32 hardware version - when csr_mhartid_c => csr.rdata <= HART_ID; -- hardware thread ID --- when csr_mconfigptr_c => csr.rdata <= (others => '0'); -- machine configuration pointer register, implemented but always zero - - -- debug mode CSRs -- - -- -------------------------------------------------------------------- - when csr_dcsr_c => if (CPU_EXTENSION_RISCV_Sdext) then csr.rdata <= csr.dcsr_rd; end if; -- debug mode control and status - when csr_dpc_c => if (CPU_EXTENSION_RISCV_Sdext) then csr.rdata <= csr.dpc; end if; -- debug mode program counter - when csr_dscratch0_c => if (CPU_EXTENSION_RISCV_Sdext) then csr.rdata <= csr.dscratch0; end if; -- debug mode scratch register 0 - - -- trigger module CSRs -- - -- -------------------------------------------------------------------- --- when csr_tselect_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr.rdata <= (others => '0'); end if; -- always zero = only 1 trigger available - when csr_tdata1_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr.rdata <= csr.tdata1_rd; end if; -- match control - when csr_tdata2_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr.rdata <= csr.tdata2; end if; -- address-compare --- when csr_tdata3_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr.rdata <= (others => '0'); end if; -- implemented but always zero - when csr_tinfo_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr.rdata <= x"00000004"; end if; -- address-match trigger only --- when csr_tcontrol_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr.rdata <= (others => '0'); end if; -- implemented but always zero --- when csr_mcontext_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr.rdata <= (others => '0'); end if; -- implemented but always zero --- when csr_scontext_c => if (CPU_EXTENSION_RISCV_Sdtrig) then csr.rdata <= (others => '0'); end if; -- implemented but always zero - - -- NEORV32-specific (RISC-V "custom") read-only CSRs -- - -- -------------------------------------------------------------------- - -- machine extended ISA extensions information -- - when csr_mxisa_c => - -- extended ISA (sub-)extensions -- - csr.rdata(00) <= '1'; -- Zicsr: CSR access (always enabled) - csr.rdata(01) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zifencei); -- Zifencei: instruction stream sync. - csr.rdata(02) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zmmul); -- Zmmul: mul/div - csr.rdata(03) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zxcfu); -- Zxcfu: custom RISC-V instructions - csr.rdata(04) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicond); -- Zicond: conditional operations - csr.rdata(05) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zfinx); -- Zfinx: FPU using x registers --- csr.rdata(06) <= '0'; -- reserved - csr.rdata(07) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zicntr); -- Zicntr: base counters - csr.rdata(08) <= bool_to_ulogic_f(boolean(PMP_NUM_REGIONS > 0)); -- PMP: physical memory protection (Zspmp) - csr.rdata(09) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zihpm); -- Zihpm: hardware performance monitors - csr.rdata(10) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Sdext); -- Sdext: RISC-V (external) debug mode - csr.rdata(11) <= bool_to_ulogic_f(CPU_EXTENSION_RISCV_Sdtrig); -- Sdtrig: trigger module - -- misc -- - csr.rdata(20) <= bool_to_ulogic_f(is_simulation_c); -- is this a simulation? - -- tuning options -- - csr.rdata(30) <= bool_to_ulogic_f(FAST_MUL_EN); -- DSP-based multiplication (M extensions only) - csr.rdata(31) <= bool_to_ulogic_f(FAST_SHIFT_EN); -- parallel logic for shifts (barrel shifters) - - -- undefined/unavailable -- - -- -------------------------------------------------------------------- - when others => NULL; -- not implemented, read as zero - - end case; + if (rstn_i = '0') then + csr.re <= '0'; + csr.rdata <= (others => '0'); + elsif rising_edge(clk_i) then + csr.re <= csr.re_nxt; + if (csr.re = '1') then + csr.rdata <= csr_rdata or csr_rdata_pmp; + else + csr.rdata <= (others => '0'); + end if; end if; - end process csr_read_access; - - -- AND-gate CSR read address: csr.rdata is zero if csr.re is not set -- - -- [WARNING] M-mode (9:8 = 11) and U-mode (9:8 = 00) CSRs only! - csr.raddr <= (csr.addr(11 downto 10) & csr.addr(8) & csr.addr(8) & csr.addr(7 downto 0)) when (csr.re = '1') else (others => '0'); + end process csr_read_reg; -- CSR read data output -- csr_rdata_o <= csr.rdata; @@ -2412,12 +2134,12 @@ begin begin cnt.we_lo <= (others => '0'); cnt.we_hi <= (others => '0'); - -- no need to check bits 6:5 of the address as they're always zero (checked by illegal CSR logic) + -- [NOTE] no need to check bits 6:4 of the address as they're always zero (checked by illegal CSR logic) if (csr.we = '1') and (csr.addr(11 downto 8) = csr_mcycle_c(11 downto 8)) then if (csr.addr(7) = '0') then -- low word - cnt.we_lo(to_integer(unsigned(csr.addr(4 downto 0)))) <= '1'; + cnt.we_lo(to_integer(unsigned(csr.addr(3 downto 0)))) <= '1'; else -- high word - cnt.we_hi(to_integer(unsigned(csr.addr(4 downto 0)))) <= '1'; + cnt.we_hi(to_integer(unsigned(csr.addr(3 downto 0)))) <= '1'; end if; end if; end process cnt_we; @@ -2425,7 +2147,8 @@ begin -- hardware counters -- cpu_counter_gen: - for i in 0 to 31 generate + for i in 0 to 2+hpm_num_c generate + -- counter CSRs -- cnt_reg: process(rstn_i, clk_i) begin @@ -2451,16 +2174,18 @@ begin end process cnt_reg; -- low-word increment -- - cnt.nxt(i) <= std_ulogic_vector(unsigned('0' & cnt.lo(i)) + 1) when (cnt.inc(i) = '1') else std_ulogic_vector(unsigned('0' & cnt.lo(i)) + 0); + cnt.nxt(i) <= std_ulogic_vector(unsigned('0' & cnt.lo(i)) + 1) when (cnt.inc(i) = '1') else + std_ulogic_vector(unsigned('0' & cnt.lo(i)) + 0); + end generate; - -- counter CSR read-back -- + -- read-back -- cnt_connect: process(cnt) begin cnt_lo_rd <= (others => (others => '0')); cnt_hi_rd <= (others => (others => '0')); - -- basic counters -- + -- base counters -- if (CPU_EXTENSION_RISCV_Zicntr = true) then cnt_lo_rd(0) <= cnt.lo(0); -- cycle cnt_hi_rd(0) <= cnt.hi(0); -- cycleh @@ -2469,31 +2194,83 @@ begin end if; -- hpm counters -- if (CPU_EXTENSION_RISCV_Zihpm = true) then - for i in 0 to hpm_num_c-1 loop + for i in 3 to (hpm_num_c+3)-1 loop if (hpm_cnt_lo_width_c > 0) then -- constrain low word size - cnt_lo_rd(3+i)(hpm_cnt_lo_width_c-1 downto 0) <= cnt.lo(3+i)(hpm_cnt_lo_width_c-1 downto 0); + cnt_lo_rd(i)(hpm_cnt_lo_width_c-1 downto 0) <= cnt.lo(i)(hpm_cnt_lo_width_c-1 downto 0); end if; if (hpm_cnt_hi_width_c > 0) then -- constrain high word size - cnt_hi_rd(3+i)(hpm_cnt_hi_width_c-1 downto 0) <= cnt.hi(3+i)(hpm_cnt_hi_width_c-1 downto 0); + cnt_hi_rd(i)(hpm_cnt_hi_width_c-1 downto 0) <= cnt.hi(i)(hpm_cnt_hi_width_c-1 downto 0); end if; end loop; end if; end process cnt_connect; + -- Hardware Performance Monitors (HPM) - Counter Event Configuration CSRs ----------------- + -- ------------------------------------------------------------------------------------------- + hpmevent_gen_enable: + if (CPU_EXTENSION_RISCV_Zihpm = true) generate + + -- write enable decoder -- + hpmevent_we: process(csr) + begin + hpmevent.we <= (others => '0'); + -- [NOTE] no need to check bit 4 of the address as it's always zero (checked by illegal CSR logic) + if (csr.addr(11 downto 5) = csr_mcountinhibit_c(11 downto 5)) and (csr.we = '1') then + hpmevent.we(to_integer(unsigned(csr.addr(3 downto 0)))) <= '1'; + end if; + end process hpmevent_we; + + -- event registers -- + hpmevent_reg_gen: + for i in 3 to (hpm_num_c+3)-1 generate + hpmevent_reg: process(rstn_i, clk_i) + begin + if (rstn_i = '0') then + hpmevent.cfg(i) <= (others => '0'); + elsif rising_edge(clk_i) then + if (hpmevent.we(i) = '1') then + hpmevent.cfg(i) <= csr.wdata(hpmcnt_event_size_c-1 downto 0); + end if; + hpmevent.cfg(i)(hpmcnt_event_tm_c) <= '0'; -- time, unused/reserved + end if; + end process hpmevent_reg; + -- read-back -- + hpmevent_rd(i)(XLEN-1 downto hpmcnt_event_size_c) <= (others => '0'); + hpmevent_rd(i)(hpmcnt_event_size_c-1 downto 0) <= hpmevent.cfg(i); + end generate; + + -- terminate unused entries -- + hpmevent_terminate_gen: + for i in hpm_num_c+3 to 15 generate + hpmevent_rd(i) <= (others => '0'); + end generate; + + end generate; + + + -- no HPMs implemented -- + hpm_gen_disable: + if (CPU_EXTENSION_RISCV_Zihpm = false) generate + hpmevent.we <= (others => '0'); + hpmevent.cfg <= (others => (others => '0')); + hpmevent_rd <= (others => (others => '0')); + end generate; + + -- Counter Increment Control (Trigger Events) --------------------------------------------- -- ------------------------------------------------------------------------------------------- counter_event: process(clk_i) begin - -- increment if any enabled event fires, do not increment if CPU is in debug mode or if counter is inhibited if rising_edge(clk_i) then + -- increment if any enabled event fires, do not increment if CPU is in debug mode or if counter is inhibited -- cnt.inc <= (others => '0'); -- default -- base counters -- cnt.inc(0) <= cnt_event(hpmcnt_event_cy_c) and (not csr.mcountinhibit(0)) and (not debug_ctrl.running); -- cycle cnt.inc(2) <= cnt_event(hpmcnt_event_ir_c) and (not csr.mcountinhibit(2)) and (not debug_ctrl.running); -- instret -- HPM counters -- - for i in 0 to hpm_num_c-1 loop - cnt.inc(3+i) <= or_reduce_f(cnt_event and hpmevent.cfg(i)) and (not csr.mcountinhibit(3+i)) and (not debug_ctrl.running); + for i in 3 to (hpm_num_c+3)-1 loop + cnt.inc(i) <= or_reduce_f(cnt_event and hpmevent.cfg(i)) and (not csr.mcountinhibit(i)) and (not debug_ctrl.running); end loop; end if; end process counter_event; @@ -2509,8 +2286,8 @@ begin cnt_event(hpmcnt_event_wait_ii_c) <= '1' when (execute_engine.state = DISPATCH) and (execute_engine.state_prev = DISPATCH) else '0'; -- instruction issue wait cycle cnt_event(hpmcnt_event_wait_mc_c) <= '1' when (execute_engine.state = ALU_WAIT) else '0'; -- multi-cycle alu-operation wait cycle - cnt_event(hpmcnt_event_load_c) <= '1' when (ctrl.bus_req_rd = '1') else '0'; -- load operation - cnt_event(hpmcnt_event_store_c) <= '1' when (ctrl.bus_req_wr = '1') else '0'; -- store operation + cnt_event(hpmcnt_event_load_c) <= '1' when (ctrl.lsu_req_rd = '1') else '0'; -- load operation + cnt_event(hpmcnt_event_store_c) <= '1' when (ctrl.lsu_req_wr = '1') else '0'; -- store operation cnt_event(hpmcnt_event_wait_ls_c) <= '1' when (execute_engine.state = MEM_WAIT) and (execute_engine.state_prev2 = MEM_WAIT) else '0'; -- load/store memory wait cycle cnt_event(hpmcnt_event_jump_c) <= '1' when (execute_engine.state = BRANCH) and (execute_engine.ir(instr_opcode_lsb_c+2) = '1') else '0'; -- jump (unconditional) diff --git a/rtl/core/neorv32_cpu_cp_bitmanip.vhd b/rtl/core/neorv32_cpu_cp_bitmanip.vhd index 03707b328..38afc5386 100644 --- a/rtl/core/neorv32_cpu_cp_bitmanip.vhd +++ b/rtl/core/neorv32_cpu_cp_bitmanip.vhd @@ -1,5 +1,5 @@ -- ################################################################################################# --- # << NEORV32 - CPU Co-Processor: Bit-Manipulation Co-Processor Unit (RISC-V "B" Extension) >> # +-- # << NEORV32 CPU - Co-Processor: Bit-Manipulation Co-Processor Unit (RISC-V "B" Extension) >> # -- # ********************************************************************************************* # -- # Supported B sub-extensions (Zb*): # -- # - Zba: Address-generation instructions # diff --git a/rtl/core/neorv32_cpu_cp_cfu.vhd b/rtl/core/neorv32_cpu_cp_cfu.vhd index 36ec61330..547f35018 100644 --- a/rtl/core/neorv32_cpu_cp_cfu.vhd +++ b/rtl/core/neorv32_cpu_cp_cfu.vhd @@ -1,5 +1,5 @@ -- ################################################################################################# --- # << NEORV32 - CPU Co-Processor: Custom (Instructions) Functions Unit >> # +-- # << NEORV32 CPU - Co-Processor: Custom (Instructions) Functions Unit >> # -- # ********************************************************************************************* # -- # For user-defined custom RISC-V instructions (R3-type, R4-type and R5-type formats). # -- # See the CPU's documentation for more information. # diff --git a/rtl/core/neorv32_cpu_cp_cond.vhd b/rtl/core/neorv32_cpu_cp_cond.vhd index d0aa9b82e..de94c123d 100644 --- a/rtl/core/neorv32_cpu_cp_cond.vhd +++ b/rtl/core/neorv32_cpu_cp_cond.vhd @@ -1,5 +1,5 @@ -- ################################################################################################# --- # << NEORV32 - CPU Co-Processor: RISC-V Conditional Operations ('Zicond') ISA Extension >> # +-- # << NEORV32 CPU - Co-Processor: RISC-V Conditional Operations ('Zicond') ISA Extension >> # -- # ********************************************************************************************* # -- # BSD 3-Clause License # -- # # diff --git a/rtl/core/neorv32_cpu_cp_fpu.vhd b/rtl/core/neorv32_cpu_cp_fpu.vhd index 0089bc58d..967167fea 100644 --- a/rtl/core/neorv32_cpu_cp_fpu.vhd +++ b/rtl/core/neorv32_cpu_cp_fpu.vhd @@ -1,5 +1,5 @@ -- ################################################################################################# --- # << NEORV32 - CPU Co-Processor: Single-Prec. Floating Point Unit (RISC-V "Zfinx" Extension) >> # +-- # << NEORV32 CPU - Co-Processor: Single-Prec. Floating Point Unit (RISC-V "Zfinx" Extension) >> # -- # ********************************************************************************************* # -- # The Zfinx floating-point extension uses the integer register file (x) for all FP operations. # -- # See the official RISC-V specs (https://github.com/riscv/riscv-zfinx) for more information. # @@ -58,19 +58,23 @@ use neorv32.neorv32_package.all; entity neorv32_cpu_cp_fpu is port ( -- global control -- - clk_i : in std_ulogic; -- global clock, rising edge - rstn_i : in std_ulogic; -- global reset, low-active, async - ctrl_i : in ctrl_bus_t; -- main control bus - start_i : in std_ulogic; -- trigger operation + clk_i : in std_ulogic; -- global clock, rising edge + rstn_i : in std_ulogic; -- global reset, low-active, async + ctrl_i : in ctrl_bus_t; -- main control bus + start_i : in std_ulogic; -- trigger operation + -- CSR interface -- + csr_we_i : in std_ulogic; -- global write enable + csr_addr_i : in std_ulogic_vector(11 downto 0); -- address + csr_wdata_i : in std_ulogic_vector(XLEN-1 downto 0); -- write data + csr_rdata_o : out std_ulogic_vector(XLEN-1 downto 0); -- read data -- data input -- - cmp_i : in std_ulogic_vector(1 downto 0); -- comparator status - rs1_i : in std_ulogic_vector(XLEN-1 downto 0); -- rf source 1 - rs2_i : in std_ulogic_vector(XLEN-1 downto 0); -- rf source 2 - rs3_i : in std_ulogic_vector(XLEN-1 downto 0); -- rf source 3 + cmp_i : in std_ulogic_vector(1 downto 0); -- comparator status + rs1_i : in std_ulogic_vector(XLEN-1 downto 0); -- rf source 1 + rs2_i : in std_ulogic_vector(XLEN-1 downto 0); -- rf source 2 + rs3_i : in std_ulogic_vector(XLEN-1 downto 0); -- rf source 3 -- result and status -- - res_o : out std_ulogic_vector(XLEN-1 downto 0); -- operation result - fflags_o : out std_ulogic_vector(4 downto 0); -- exception flags - valid_o : out std_ulogic -- data output valid + res_o : out std_ulogic_vector(XLEN-1 downto 0); -- operation result + valid_o : out std_ulogic -- data output valid ); end neorv32_cpu_cp_fpu; @@ -86,6 +90,11 @@ architecture neorv32_cpu_cp_fpu_rtl of neorv32_cpu_cp_fpu is constant op_addsub_c : std_ulogic_vector(2 downto 0) := "110"; constant op_mul_c : std_ulogic_vector(2 downto 0) := "111"; + -- FPU CSRs -- + signal csr_frm : std_ulogic_vector(2 downto 0); -- FPU rounding mode + signal csr_fflags : std_ulogic_vector(4 downto 0); -- FPU exception flags + signal fflags : std_ulogic_vector(4 downto 0); -- exception flags + -- float-to-integer unit -- component neorv32_cpu_cp_fpu_f2i port ( @@ -224,9 +233,9 @@ architecture neorv32_cpu_cp_fpu_rtl of neorv32_cpu_cp_fpu is -- input comparison -- exp_comp : std_ulogic_vector(01 downto 0); -- equal & less small_exp : std_ulogic_vector(07 downto 0); - small_man : std_ulogic_vector(23 downto 0); -- mantissa + hiden one + small_man : std_ulogic_vector(23 downto 0); -- mantissa + hidden one large_exp : std_ulogic_vector(07 downto 0); - large_man : std_ulogic_vector(23 downto 0); -- mantissa + hiden one + large_man : std_ulogic_vector(23 downto 0); -- mantissa + hidden one -- smaller mantissa alginment -- man_sreg : std_ulogic_vector(23 downto 0); -- mantissa + hidden one man_g_ext : std_ulogic; @@ -235,8 +244,8 @@ architecture neorv32_cpu_cp_fpu_rtl of neorv32_cpu_cp_fpu is exp_cnt : std_ulogic_vector(08 downto 0); -- adder/subtractor stage -- man_comp : std_ulogic; - man_s : std_ulogic_vector(26 downto 0); -- mantissa + hiden one + GRS - man_l : std_ulogic_vector(26 downto 0); -- mantissa + hiden one + GRS + man_s : std_ulogic_vector(26 downto 0); -- mantissa + hidden one + GRS + man_l : std_ulogic_vector(26 downto 0); -- mantissa + hidden one + GRS add_stage : std_ulogic_vector(27 downto 0); -- adder result incl. overflow -- result -- res_sign : std_ulogic; @@ -271,6 +280,52 @@ begin -- Control -- **************************************************************************************************************************** + -- CSR Access ----------------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + + -- write access -- + csr_write: process(rstn_i, clk_i) + begin + if (rstn_i = '0') then + csr_frm <= (others => '0'); + csr_fflags <= (others => '0'); + elsif rising_edge(clk_i) then + if (csr_we_i = '1') then + if (csr_addr_i(11 downto 2) = csr_fflags_c(11 downto 2)) then + -- exception flags -- + if (csr_addr_i(1 downto 0) = csr_fflags_c(1 downto 0)) then + csr_fflags <= csr_wdata_i(4 downto 0); + end if; + -- rounding mode -- + if (csr_addr_i(1 downto 0) = csr_frm_c(1 downto 0)) then + csr_frm <= csr_wdata_i(2 downto 0); + end if; + -- control/status (frm & fflags) -- + if (csr_addr_i(1 downto 0) = csr_fcsr_c(1 downto 0)) then + csr_frm <= csr_wdata_i(7 downto 5); + csr_fflags <= csr_wdata_i(4 downto 0); + end if; + end if; + else -- auto-update + csr_fflags <= csr_fflags or fflags; + end if; + end if; + end process csr_write; + + + -- read access -- + csr_read: process(csr_addr_i, csr_fflags, csr_frm) + begin + csr_rdata_o <= (others => '0'); -- default + case csr_addr_i is + when csr_fflags_c => csr_rdata_o(4 downto 0) <= csr_fflags; -- exception flags + when csr_frm_c => csr_rdata_o(2 downto 0) <= csr_frm; -- rounding mode + when csr_fcsr_c => csr_rdata_o(7 downto 0) <= csr_frm & csr_fflags; -- control/status (frm & fflags) + when others => NULL; + end case; + end process csr_read; + + -- Instruction Decoding ------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- -- one-hot re-encoding -- @@ -379,7 +434,7 @@ begin -- rounding mode -- -- TODO / FIXME "round to nearest, ties to max magnitude" (0b100) is not supported yet if (ctrl_i.ir_funct3 = "111") then - fpu_operands.frm <= '0' & ctrl_i.alu_frm(1 downto 0); + fpu_operands.frm <= '0' & csr_frm(1 downto 0); else fpu_operands.frm <= '0' & ctrl_i.ir_funct3(1 downto 0); end if; @@ -1114,27 +1169,27 @@ begin if (ctrl_engine.valid = '1') then case funct_ff is when op_class_c => - res_o <= fu_classify.result; - fflags_o <= fu_classify.flags; + res_o <= fu_classify.result; + fflags <= fu_classify.flags; when op_comp_c => - res_o <= fu_compare.result; - fflags_o <= fu_compare.flags; + res_o <= fu_compare.result; + fflags <= fu_compare.flags; when op_f2i_c => - res_o <= fu_conv_f2i.result; - fflags_o <= fu_conv_f2i.flags; + res_o <= fu_conv_f2i.result; + fflags <= fu_conv_f2i.flags; when op_sgnj_c => - res_o <= fu_sign_inject.result; - fflags_o <= fu_sign_inject.flags; + res_o <= fu_sign_inject.result; + fflags <= fu_sign_inject.flags; when op_minmax_c => - res_o <= fu_min_max.result; - fflags_o <= fu_min_max.flags; + res_o <= fu_min_max.result; + fflags <= fu_min_max.flags; when others => -- op_mul_c, op_addsub_c, op_i2f_c, ... - res_o <= normalizer.result; - fflags_o <= normalizer.flags_out; + res_o <= normalizer.result; + fflags <= normalizer.flags_out; end case; else - res_o <= (others => '0'); - fflags_o <= (others => '0'); + res_o <= (others => '0'); + fflags <= (others => '0'); end if; end if; end process output_gate; diff --git a/rtl/core/neorv32_cpu_cp_muldiv.vhd b/rtl/core/neorv32_cpu_cp_muldiv.vhd index 4e6070a77..c5f9a032c 100644 --- a/rtl/core/neorv32_cpu_cp_muldiv.vhd +++ b/rtl/core/neorv32_cpu_cp_muldiv.vhd @@ -1,5 +1,5 @@ -- ################################################################################################# --- # << NEORV32 - CPU Co-Processor: Integer Multiplier/Divider Unit (RISC-V "M" Extension) >> # +-- # << NEORV32 CPU - Co-Processor: Integer Multiplier/Divider Unit (RISC-V "M" Extension) >> # -- # ********************************************************************************************* # -- # Multiplier core (signed/unsigned) uses serial add-and-shift algorithm. Multiplications can be # -- # mapped to DSP blocks (faster!) when FAST_MUL_EN = true. Divider core (unsigned-only; pre and # diff --git a/rtl/core/neorv32_cpu_cp_shifter.vhd b/rtl/core/neorv32_cpu_cp_shifter.vhd index 0839e195e..650dc6081 100644 --- a/rtl/core/neorv32_cpu_cp_shifter.vhd +++ b/rtl/core/neorv32_cpu_cp_shifter.vhd @@ -1,5 +1,5 @@ -- ################################################################################################# --- # << NEORV32 - CPU Co-Processor: Shifter (CPU Base ISA) >> # +-- # << NEORV32 CPU - Co-Processor: Shifter (CPU Base ISA) >> # -- # ********************************************************************************************* # -- # FAST_SHIFT_EN = false (default) : Use bit-serial shifter architecture (small but slow) # -- # FAST_SHIFT_EN = true : Use barrel shifter architecture (large but fast) # diff --git a/rtl/core/neorv32_cpu_decompressor.vhd b/rtl/core/neorv32_cpu_decompressor.vhd index afc5b2386..fe5f5d7b2 100644 --- a/rtl/core/neorv32_cpu_decompressor.vhd +++ b/rtl/core/neorv32_cpu_decompressor.vhd @@ -1,5 +1,5 @@ -- ################################################################################################# --- # << NEORV32 - CPU: Compressed Instructions Decoder (RISC-V "C" Extension) >> # +-- # << NEORV32 CPU - Compressed Instructions Decoder (RISC-V "C" Extension) >> # -- # ********************************************************************************************* # -- # Compressed instructions decoder compatible to the RISC-V C ISA extensions. Illegal compressed # -- # instructions are output "as-is". # @@ -180,7 +180,7 @@ begin if (ci_instr16_i(12 downto 5) = "00000000") or -- canonical illegal C instruction or C.ADDI4SPN with nzuimm = 0 (ci_instr16_i(ci_funct3_msb_c downto ci_funct3_lsb_c) = "001") or -- C.FLS / C.LQ (ci_instr16_i(ci_funct3_msb_c downto ci_funct3_lsb_c) = "100") or -- reserved - (ci_instr16_i(ci_funct3_msb_c downto ci_funct3_lsb_c) = "101") then -- C.C.FSD / C.SQ + (ci_instr16_i(ci_funct3_msb_c downto ci_funct3_lsb_c) = "101") then -- C.FSD / C.SQ illegal <= '1'; end if; diff --git a/rtl/core/neorv32_cpu_bus.vhd b/rtl/core/neorv32_cpu_lsu.vhd similarity index 50% rename from rtl/core/neorv32_cpu_bus.vhd rename to rtl/core/neorv32_cpu_lsu.vhd index 062a795f7..e266d9107 100644 --- a/rtl/core/neorv32_cpu_bus.vhd +++ b/rtl/core/neorv32_cpu_lsu.vhd @@ -1,7 +1,5 @@ -- ################################################################################################# --- # << NEORV32 - (Data) Bus Interface Unit >> # --- # ********************************************************************************************* # --- # Data bus interface (load/store unit) and physical memory protection (PMP). # +-- # << NEORV32 CPU - Load/Store Unit >> # -- # ********************************************************************************************* # -- # BSD 3-Clause License # -- # # @@ -41,20 +39,15 @@ use ieee.numeric_std.all; library neorv32; use neorv32.neorv32_package.all; -entity neorv32_cpu_bus is +entity neorv32_cpu_lsu is generic ( - AMO_LRSC_ENABLE : boolean; -- enable atomic LR/SC operations - PMP_NUM_REGIONS : natural; -- number of regions (0..16) - PMP_MIN_GRANULARITY : natural -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes + AMO_LRSC_ENABLE : boolean -- enable atomic LR/SC operations ); port ( -- global control -- clk_i : in std_ulogic; -- global clock, rising edge rstn_i : in std_ulogic := '0'; -- global reset, low-active, async ctrl_i : in ctrl_bus_t; -- main control bus - -- cpu instruction fetch interface -- - fetch_pc_i : in std_ulogic_vector(XLEN-1 downto 0); -- PC for instruction fetch - i_pmp_fault_o : out std_ulogic; -- instruction fetch pmp fault -- cpu data access interface -- addr_i : in std_ulogic_vector(XLEN-1 downto 0); -- ALU result -> access address wdata_i : in std_ulogic_vector(XLEN-1 downto 0); -- write data @@ -65,9 +58,8 @@ entity neorv32_cpu_bus is ma_store_o : out std_ulogic; -- misaligned store data address be_load_o : out std_ulogic; -- bus error on load data access be_store_o : out std_ulogic; -- bus error on store data access - -- physical memory protection -- - pmp_addr_i : in pmp_addr_if_t; -- addresses - pmp_ctrl_i : in pmp_ctrl_if_t; -- configs + pmp_r_fault_i : in std_ulogic; -- PMP read fault + pmp_w_fault_i : in std_ulogic; -- PMP write fault -- data bus -- d_bus_addr_o : out std_ulogic_vector(XLEN-1 downto 0); -- bus access address d_bus_rdata_i : in std_ulogic_vector(XLEN-1 downto 0); -- bus read data @@ -78,61 +70,21 @@ entity neorv32_cpu_bus is d_bus_ack_i : in std_ulogic; -- bus transfer acknowledge d_bus_err_i : in std_ulogic -- bus transfer error ); -end neorv32_cpu_bus; - -architecture neorv32_cpu_bus_rtl of neorv32_cpu_bus is - - -- PMP configuration register bits -- - constant pmp_cfg_r_c : natural := 0; -- read permit - constant pmp_cfg_w_c : natural := 1; -- write permit - constant pmp_cfg_x_c : natural := 2; -- execute permit - constant pmp_cfg_al_c : natural := 3; -- mode bit low - constant pmp_cfg_ah_c : natural := 4; -- mode bit high - constant pmp_cfg_l_c : natural := 7; -- locked entry - - -- PMP helpers -- - constant pmp_lsb_c : natural := index_size_f(PMP_MIN_GRANULARITY); -- min = 2 - constant pmp_zero_c : std_ulogic_vector(XLEN-1 downto pmp_lsb_c) := (others => '0'); +end neorv32_cpu_lsu; - -- misc -- - signal mar : std_ulogic_vector(XLEN-1 downto 0); -- data memory address register - signal misaligned : std_ulogic; -- misaligned address +architecture neorv32_cpu_lsu_rtl of neorv32_cpu_lsu is -- bus arbiter -- type bus_arbiter_t is record - pend_rd : std_ulogic; -- pending bus read access - pend_wr : std_ulogic; -- pending bus write access - acc_err : std_ulogic; -- bus access error - pmp_r_err : std_ulogic; -- pmp load fault - pmp_w_err : std_ulogic; -- pmp store fault + pend_rd : std_ulogic; -- pending bus read access + pend_wr : std_ulogic; -- pending bus write access + bus_err : std_ulogic; -- bus access error end record; signal arbiter : bus_arbiter_t; - -- physical memory protection -- - type pmp_mask_t is array (0 to PMP_NUM_REGIONS-1) of std_ulogic_vector(XLEN-1 downto pmp_lsb_c); - type pmp_t is record - i_cmp_mm : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); - i_cmp_ge : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); - i_cmp_lt : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); - d_cmp_mm : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); - d_cmp_ge : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); - d_cmp_lt : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); - i_match : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); - d_match : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); - perm_ex : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); - perm_rd : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); - perm_wr : std_ulogic_vector(PMP_NUM_REGIONS-1 downto 0); - fail_ex : std_ulogic_vector(PMP_NUM_REGIONS downto 0); - fail_rd : std_ulogic_vector(PMP_NUM_REGIONS downto 0); - fail_wr : std_ulogic_vector(PMP_NUM_REGIONS downto 0); - end record; - signal pmp_mask : pmp_mask_t; - signal pmp : pmp_t; - - -- pmp faults -- - signal if_pmp_fault : std_ulogic; -- pmp instruction access fault - signal ld_pmp_fault : std_ulogic; -- pmp load access fault - signal st_pmp_fault : std_ulogic; -- pmp store access fault + -- misc -- + signal mar : std_ulogic_vector(XLEN-1 downto 0); -- data memory address register + signal misaligned : std_ulogic; -- misaligned address begin @@ -144,7 +96,7 @@ begin mar <= (others => '0'); misaligned <= '0'; elsif rising_edge(clk_i) then - if (ctrl_i.bus_mo_we = '1') then + if (ctrl_i.lsu_mo_we = '1') then mar <= addr_i; -- memory address register case ctrl_i.ir_funct3(1 downto 0) is -- alignment check when "00" => misaligned <= '0'; -- byte @@ -161,7 +113,7 @@ begin mar_o <= mar; -- for MTVAL CSR - -- Write Data: Byte Enable and Alignment -------------------------------------------------- + -- Write Data: Alignment and Byte Enable -------------------------------------------------- -- ------------------------------------------------------------------------------------------- mem_do_reg: process(rstn_i, clk_i) begin @@ -169,7 +121,7 @@ begin d_bus_wdata_o <= (others => '0'); d_bus_ben_o <= (others => '0'); elsif rising_edge(clk_i) then - if (ctrl_i.bus_mo_we = '1') then + if (ctrl_i.lsu_mo_we = '1') then d_bus_ben_o <= (others => '0'); -- default case ctrl_i.ir_funct3(1 downto 0) is when "00" => -- byte @@ -237,154 +189,36 @@ begin -- Access Arbiter ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - data_access_arbiter: process(rstn_i, clk_i) + access_arbiter: process(rstn_i, clk_i) begin if (rstn_i = '0') then - arbiter.pmp_r_err <= '0'; - arbiter.pmp_w_err <= '0'; - arbiter.acc_err <= '0'; - arbiter.pend_rd <= '0'; - arbiter.pend_wr <= '0'; + arbiter.bus_err <= '0'; + arbiter.pend_rd <= '0'; + arbiter.pend_wr <= '0'; elsif rising_edge(clk_i) then - -- PMP error buffer -- - if (ctrl_i.bus_mo_we = '1') then -- sample PMP errors only once - arbiter.pmp_r_err <= ld_pmp_fault; - arbiter.pmp_w_err <= st_pmp_fault; - end if; - -- access error buffer -- - arbiter.acc_err <= d_bus_err_i or -- bus error - (arbiter.pend_rd and arbiter.pmp_r_err) or -- PMP load fault - (arbiter.pend_wr and arbiter.pmp_w_err); -- PMP store fault - -- arbiter -- + arbiter.bus_err <= d_bus_err_i and (arbiter.pend_rd or arbiter.pend_wr); -- bus error during access if (arbiter.pend_rd = '0') and (arbiter.pend_wr = '0') then -- idle - arbiter.pend_rd <= ctrl_i.bus_req_rd; - arbiter.pend_wr <= ctrl_i.bus_req_wr; + arbiter.pend_rd <= ctrl_i.lsu_req_rd; + arbiter.pend_wr <= ctrl_i.lsu_req_wr; elsif (d_bus_ack_i = '1') or (ctrl_i.cpu_trap = '1') then -- normal termination or start of trap handling arbiter.pend_rd <= '0'; arbiter.pend_wr <= '0'; end if; end if; - end process data_access_arbiter; + end process access_arbiter; -- wait for bus response -- d_wait_o <= not d_bus_ack_i; - -- output data access error to control unit -- + -- output data access/alignment errors to control unit -- ma_load_o <= arbiter.pend_rd and misaligned; - be_load_o <= arbiter.pend_rd and arbiter.acc_err; + be_load_o <= arbiter.pend_rd and (arbiter.bus_err or pmp_r_fault_i); ma_store_o <= arbiter.pend_wr and misaligned; - be_store_o <= arbiter.pend_wr and arbiter.acc_err; + be_store_o <= arbiter.pend_wr and (arbiter.bus_err or pmp_w_fault_i); -- access requests (all source signals are driven by registers!) -- - d_bus_re_o <= ctrl_i.bus_req_rd and (not misaligned) and (not arbiter.pmp_r_err); - d_bus_we_o <= ctrl_i.bus_req_wr and (not misaligned) and (not arbiter.pmp_w_err); - - - -- RISC-V Physical Memory Protection (PMP) ------------------------------------------------ - -- ------------------------------------------------------------------------------------------- - - -- compute address masks for NAPOT modes (iterative!) -- - pmp_masking_gen: - for r in 0 to PMP_NUM_REGIONS-1 generate - pmp_masking: process(rstn_i, clk_i) - begin - if (rstn_i = '0') then - pmp_mask(r) <= (others => '0'); - elsif rising_edge(clk_i) then -- address mask computation has a latency of max 32 cycles - if (pmp_ctrl_i(r)(pmp_cfg_al_c) = '1') then -- NAPOT (or TOR, but that's irrelevant here) - pmp_mask(r)(pmp_lsb_c) <= '0'; - for i in pmp_lsb_c+1 to XLEN-1 loop - pmp_mask(r)(i) <= pmp_mask(r)(i-1) or (not pmp_addr_i(r)(i-1)); -- skip address byte offset - end loop; -- i - else -- NA4 - pmp_mask(r) <= (others => '1'); - end if; - end if; - end process pmp_masking; - end generate; - - - -- check address -- - pmp_check_address: - for r in 0 to PMP_NUM_REGIONS-1 generate - -- NA4 and NAPOT -- - pmp.i_cmp_mm(r) <= '1' when ((fetch_pc_i(XLEN-1 downto pmp_lsb_c) and pmp_mask(r)) = (pmp_addr_i(r)(XLEN-1 downto pmp_lsb_c) and pmp_mask(r))) else '0'; - pmp.d_cmp_mm(r) <= '1' when (( addr_i(XLEN-1 downto pmp_lsb_c) and pmp_mask(r)) = (pmp_addr_i(r)(XLEN-1 downto pmp_lsb_c) and pmp_mask(r))) else '0'; - -- TOR region 0 -- - pmp_check_address_r0: - if (r = 0) generate -- first entry: use ZERO as base and current entry as bound - pmp.i_cmp_ge(r) <= '1'; -- address is always greater than or equal to zero - pmp.i_cmp_lt(r) <= '0'; -- unused - pmp.d_cmp_ge(r) <= '1'; -- address is always greater than or equal to zero - pmp.d_cmp_lt(r) <= '0'; -- unused - end generate; - -- TOR region any -- - pmp_check_address_rany: - if (r > 0) generate -- use previous entry as base and current entry as bound - pmp.i_cmp_ge(r) <= '1' when (unsigned(fetch_pc_i(XLEN-1 downto pmp_lsb_c)) >= unsigned(pmp_addr_i(r-1)(XLEN-1 downto pmp_lsb_c))) else '0'; - pmp.i_cmp_lt(r) <= '1' when (unsigned(fetch_pc_i(XLEN-1 downto pmp_lsb_c)) < unsigned(pmp_addr_i(r )(XLEN-1 downto pmp_lsb_c))) else '0'; - pmp.d_cmp_ge(r) <= '1' when (unsigned( addr_i(XLEN-1 downto pmp_lsb_c)) >= unsigned(pmp_addr_i(r-1)(XLEN-1 downto pmp_lsb_c))) else '0'; - pmp.d_cmp_lt(r) <= '1' when (unsigned( addr_i(XLEN-1 downto pmp_lsb_c)) < unsigned(pmp_addr_i(r )(XLEN-1 downto pmp_lsb_c))) else '0'; - end generate; - end generate; - - - -- check region matching according to configured mode -- - pmp_check_match_gen: - for r in 0 to PMP_NUM_REGIONS-1 generate - pmp_check_match: process(pmp_ctrl_i, pmp) - begin - case pmp_ctrl_i(r)(pmp_cfg_ah_c downto pmp_cfg_al_c) is - when pmp_mode_off_c => -- entry disabled - pmp.i_match(r) <= '0'; - pmp.d_match(r) <= '0'; - when pmp_mode_tor_c => -- top of region - if (r = (PMP_NUM_REGIONS-1)) then -- very last entry - pmp.i_match(r) <= pmp.i_cmp_ge(r) and pmp.i_cmp_lt(r); - pmp.d_match(r) <= pmp.d_cmp_ge(r) and pmp.d_cmp_lt(r); - else -- this saves a LOT of comparators - pmp.i_match(r) <= pmp.i_cmp_ge(r) and (not pmp.i_cmp_ge(r+1)); - pmp.d_match(r) <= pmp.d_cmp_ge(r) and (not pmp.d_cmp_ge(r+1)); - end if; - when others => -- naturally-aligned region - pmp.i_match(r) <= pmp.i_cmp_mm(r); - pmp.d_match(r) <= pmp.d_cmp_mm(r); - end case; - end process pmp_check_match; - end generate; - - - -- generate permission bits -- - -- M mode: always allow if lock bit not set, otherwise check permission - pmp_permission_gen: - for r in 0 to PMP_NUM_REGIONS-1 generate - pmp.perm_ex(r) <= pmp_ctrl_i(r)(pmp_cfg_x_c) or (not pmp_ctrl_i(r)(pmp_cfg_l_c)) when (ctrl_i.cpu_priv = priv_mode_m_c) else pmp_ctrl_i(r)(pmp_cfg_x_c); - pmp.perm_rd(r) <= pmp_ctrl_i(r)(pmp_cfg_r_c) or (not pmp_ctrl_i(r)(pmp_cfg_l_c)) when (ctrl_i.bus_priv = priv_mode_m_c) else pmp_ctrl_i(r)(pmp_cfg_r_c); - pmp.perm_wr(r) <= pmp_ctrl_i(r)(pmp_cfg_w_c) or (not pmp_ctrl_i(r)(pmp_cfg_l_c)) when (ctrl_i.bus_priv = priv_mode_m_c) else pmp_ctrl_i(r)(pmp_cfg_w_c); - end generate; - - - -- check for access fault (using static prioritization) -- - -- default: fault if not M-mode -- - pmp.fail_ex(PMP_NUM_REGIONS) <= '1' when (ctrl_i.cpu_priv /= priv_mode_m_c) else '0'; - pmp.fail_rd(PMP_NUM_REGIONS) <= '1' when (ctrl_i.bus_priv /= priv_mode_m_c) else '0'; - pmp.fail_wr(PMP_NUM_REGIONS) <= '1' when (ctrl_i.bus_priv /= priv_mode_m_c) else '0'; - -- this is a *structural* description of a prioritization logic implemented as a multiplexer chain -- - pmp_chech_fault: - for r in PMP_NUM_REGIONS-1 downto 0 generate -- start with lowest priority - pmp.fail_ex(r) <= not pmp.perm_ex(r) when (pmp.i_match(r) = '1') else pmp.fail_ex(r+1); - pmp.fail_rd(r) <= not pmp.perm_rd(r) when (pmp.d_match(r) = '1') else pmp.fail_rd(r+1); - pmp.fail_wr(r) <= not pmp.perm_wr(r) when (pmp.d_match(r) = '1') else pmp.fail_wr(r+1); - end generate; - - - -- final PMP access fault signals (ignore PMP rules when in debug mode) -- - if_pmp_fault <= '1' when (pmp.fail_ex(0) = '1') and (PMP_NUM_REGIONS > 0) and (ctrl_i.cpu_debug = '0') else '0'; - ld_pmp_fault <= '1' when (pmp.fail_rd(0) = '1') and (PMP_NUM_REGIONS > 0) and (ctrl_i.cpu_debug = '0') else '0'; - st_pmp_fault <= '1' when (pmp.fail_wr(0) = '1') and (PMP_NUM_REGIONS > 0) and (ctrl_i.cpu_debug = '0') else '0'; - - -- instruction fetch PMP fault -- - i_pmp_fault_o <= if_pmp_fault; + d_bus_re_o <= ctrl_i.lsu_req_rd and (not misaligned) and (not pmp_r_fault_i); + d_bus_we_o <= ctrl_i.lsu_req_wr and (not misaligned) and (not pmp_w_fault_i); -end neorv32_cpu_bus_rtl; +end neorv32_cpu_lsu_rtl; diff --git a/rtl/core/neorv32_cpu_pmp.vhd b/rtl/core/neorv32_cpu_pmp.vhd new file mode 100644 index 000000000..010ab6108 --- /dev/null +++ b/rtl/core/neorv32_cpu_pmp.vhd @@ -0,0 +1,368 @@ +-- ################################################################################################# +-- # << NEORV32 CPU - Physical Memory Protection Unit >> # +-- # ********************************************************************************************* # +-- # BSD 3-Clause License # +-- # # +-- # Copyright (c) 2023, Stephan Nolting. All rights reserved. # +-- # # +-- # Redistribution and use in source and binary forms, with or without modification, are # +-- # permitted provided that the following conditions are met: # +-- # # +-- # 1. Redistributions of source code must retain the above copyright notice, this list of # +-- # conditions and the following disclaimer. # +-- # # +-- # 2. Redistributions in binary form must reproduce the above copyright notice, this list of # +-- # conditions and the following disclaimer in the documentation and/or other materials # +-- # provided with the distribution. # +-- # # +-- # 3. Neither the name of the copyright holder nor the names of its contributors may be used to # +-- # endorse or promote products derived from this software without specific prior written # +-- # permission. # +-- # # +-- # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS # +-- # OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF # +-- # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE # +-- # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, # +-- # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # +-- # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED # +-- # AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING # +-- # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED # +-- # OF THE POSSIBILITY OF SUCH DAMAGE. # +-- # ********************************************************************************************* # +-- # The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # +-- ################################################################################################# + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library neorv32; +use neorv32.neorv32_package.all; + +entity neorv32_cpu_pmp is + generic ( + NUM_REGIONS : natural; -- number of regions (0..16) + GRANULARITY : natural -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes + ); + port ( + -- global control -- + clk_i : in std_ulogic; -- global clock, rising edge + rstn_i : in std_ulogic; -- global reset, low-active, async + ctrl_i : in ctrl_bus_t; -- main control bus + -- CSR interface -- + csr_we_i : in std_ulogic; -- global write enable + csr_addr_i : in std_ulogic_vector(11 downto 0); -- address + csr_wdata_i : in std_ulogic_vector(XLEN-1 downto 0); -- write data + csr_rdata_o : out std_ulogic_vector(XLEN-1 downto 0); -- read data + -- address input -- + addr_if_i : in std_ulogic_vector(XLEN-1 downto 0); -- instruction fetch address + addr_ls_i : in std_ulogic_vector(XLEN-1 downto 0); -- load/store address + -- faults -- + fault_if_o : out std_ulogic; -- instruction fetch fault + fault_ld_o : out std_ulogic; -- data load fault + fault_st_o : out std_ulogic -- data store fault + ); +end neorv32_cpu_pmp; + +architecture neorv32_cpu_pmp_rtl of neorv32_cpu_pmp is + + -- PMP configuration register bits -- + constant cfg_r_c : natural := 0; -- read permit + constant cfg_w_c : natural := 1; -- write permit + constant cfg_x_c : natural := 2; -- execute permit + constant cfg_al_c : natural := 3; -- mode bit low + constant cfg_ah_c : natural := 4; -- mode bit high + constant cfg_rl_c : natural := 5; -- reserved + constant cfg_rh_c : natural := 6; -- reserved + constant cfg_l_c : natural := 7; -- locked entry + + -- PMP modes -- + constant mode_off_c : std_ulogic_vector(1 downto 0) := "00"; -- null region (disabled) + constant mode_tor_c : std_ulogic_vector(1 downto 0) := "01"; -- top of range + constant mode_na4_c : std_ulogic_vector(1 downto 0) := "10"; -- naturally aligned four-byte region + constant mode_napot_c : std_ulogic_vector(1 downto 0) := "11"; -- naturally aligned power-of-two region (>= 8 bytes) + + -- PMP helpers -- + constant pmp_lsb_c : natural := index_size_f(GRANULARITY); -- min = 2 + constant pmp_zero_c : std_ulogic_vector(XLEN-1 downto pmp_lsb_c) := (others => '0'); + + -- PMP CSRs -- + type csr_cfg_t is array (0 to NUM_REGIONS-1) of std_ulogic_vector(7 downto 0); + type csr_addr_t is array (0 to NUM_REGIONS-1) of std_ulogic_vector(XLEN-1 downto 0); + type csr_cfg_rd_t is array (0 to 15) of std_ulogic_vector(7 downto 0); + type csr_cfg_rd32_t is array (0 to 03) of std_ulogic_vector(XLEN-1 downto 0); + type csr_addr_rd_t is array (0 to 15) of std_ulogic_vector(XLEN-1 downto 0); + type csr_t is record + we_cfg : std_ulogic_vector(03 downto 0); + we_addr : std_ulogic_vector(15 downto 0); + cfg : csr_cfg_t; + addr : csr_addr_t; + end record; + signal csr : csr_t; + signal cfg_rd : csr_cfg_rd_t; + signal cfg_rd32 : csr_cfg_rd32_t; + signal addr_rd : csr_addr_rd_t; + + -- PMP address extension to 34 bit -- + type xaddr_t is array (0 to NUM_REGIONS-1) of std_ulogic_vector(XLEN+1 downto 0); + signal xaddr : xaddr_t; + + -- access permission check -- + type addr_mask_t is array (0 to NUM_REGIONS-1) of std_ulogic_vector(XLEN-1 downto pmp_lsb_c); + signal addr_mask_napot, addr_mask : addr_mask_t; + type check_t is record + i_cmp_mm : std_ulogic_vector(NUM_REGIONS-1 downto 0); + i_cmp_ge : std_ulogic_vector(NUM_REGIONS-1 downto 0); + i_cmp_lt : std_ulogic_vector(NUM_REGIONS-1 downto 0); + d_cmp_mm : std_ulogic_vector(NUM_REGIONS-1 downto 0); + d_cmp_ge : std_ulogic_vector(NUM_REGIONS-1 downto 0); + d_cmp_lt : std_ulogic_vector(NUM_REGIONS-1 downto 0); + i_match : std_ulogic_vector(NUM_REGIONS-1 downto 0); + d_match : std_ulogic_vector(NUM_REGIONS-1 downto 0); + perm_ex : std_ulogic_vector(NUM_REGIONS-1 downto 0); + perm_rd : std_ulogic_vector(NUM_REGIONS-1 downto 0); + perm_wr : std_ulogic_vector(NUM_REGIONS-1 downto 0); + fail_ex : std_ulogic_vector(NUM_REGIONS downto 0); + fail_rd : std_ulogic_vector(NUM_REGIONS downto 0); + fail_wr : std_ulogic_vector(NUM_REGIONS downto 0); + end record; + signal check : check_t; + +begin + + -- Sanity Checks -------------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + assert not (NUM_REGIONS > 16) report + "NEORV32 CPU CONFIG ERROR! Number of PMP regions out of valid range (0..16)." severity error; + + assert not (is_power_of_two_f(GRANULARITY) = false) report + "NEORV32 CPU CONFIG ERROR! PMP granularity has to be a power of two." severity error; + + assert not (GRANULARITY < 4) report + "NEORV32 CPU CONFIG ERROR! PMP granularity has to be at least 4 bytes." severity error; + + + -- CSR Write Access ----------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + csr_we: process(csr_we_i, csr_addr_i) -- write enable decoder + begin + -- Configuration registers -- + csr.we_cfg <= (others => '0'); + if (csr_addr_i(11 downto 2) = csr_pmpcfg0_c(11 downto 2)) and (csr_we_i = '1') then + csr.we_cfg(to_integer(unsigned(csr_addr_i(1 downto 0)))) <= '1'; + end if; + -- Address registers -- + csr.we_addr <= (others => '0'); + if (csr_addr_i(11 downto 4) = csr_pmpaddr0_c(11 downto 4)) and (csr_we_i = '1') then + csr.we_addr(to_integer(unsigned(csr_addr_i(3 downto 0)))) <= '1'; + end if; + end process csr_we; + + + -- PMP CSR registers -- + csr_reg_gen: + for i in 0 to NUM_REGIONS-1 generate + csr_reg: process(rstn_i, clk_i) + begin + if (rstn_i = '0') then + csr.cfg(i) <= (others => '0'); + csr.addr(i) <= (others => '0'); + elsif rising_edge(clk_i) then + + -- configuration -- + if (csr.we_cfg(i/4) = '1') and (csr.cfg(i)(7) = '0') then -- unlocked write access + csr.cfg(i)(cfg_r_c) <= csr_wdata_i((i mod 4)*8+0); -- R (read) + csr.cfg(i)(cfg_w_c) <= csr_wdata_i((i mod 4)*8+1); -- W (write) + csr.cfg(i)(cfg_x_c) <= csr_wdata_i((i mod 4)*8+2); -- X (execute) + if (GRANULARITY > 4) and (csr_wdata_i((i mod 4)*8+4 downto (i mod 4)*8+3) = mode_na4_c) then + csr.cfg(i)(cfg_ah_c downto cfg_al_c) <= mode_off_c; -- NA4 not available, fall back to OFF + else + csr.cfg(i)(cfg_ah_c downto cfg_al_c) <= csr_wdata_i((i mod 4)*8+4 downto (i mod 4)*8+3); -- A (mode) + end if; + csr.cfg(i)(cfg_rl_c) <= '0'; -- reserved + csr.cfg(i)(cfg_rh_c) <= '0'; -- reserved + csr.cfg(i)(cfg_l_c) <= csr_wdata_i((i mod 4)*8+7); -- L (locked) + end if; + + -- address -- + if (csr.we_addr(i) = '1') and (csr.cfg(i)(cfg_l_c) = '0') then -- unlocked write access + if (i < NUM_REGIONS-1) then + if (csr.cfg(i+1)(cfg_l_c) = '0') or (csr.cfg(i+1)(cfg_ah_c downto cfg_al_c) /= mode_tor_c) then -- cfg(i+1) not "LOCKED TOR" + csr.addr(i) <= "00" & csr_wdata_i(XLEN-3 downto 0); + end if; + else -- very last entry + csr.addr(i) <= "00" & csr_wdata_i(XLEN-3 downto 0); + end if; + end if; + + end if; + end process csr_reg; + end generate; + + + -- CSR Read Access ------------------------------------------------------------------------ + -- ------------------------------------------------------------------------------------------- + csr_read_access: process(csr_addr_i, cfg_rd32, addr_rd) + begin + if (csr_addr_i(11 downto 5) = csr_pmpcfg0_c(11 downto 5)) then -- PMP CSR + if (csr_addr_i(4) = '0') then -- PMP configuration CSR + csr_rdata_o <= cfg_rd32(to_integer(unsigned(csr_addr_i(1 downto 0)))); + else -- PMP address CSR + csr_rdata_o <= addr_rd(to_integer(unsigned(csr_addr_i(3 downto 0)))); + end if; + else + csr_rdata_o <= (others => '0'); + end if; + end process csr_read_access; + + + -- CSR read-back -- + csr_read_back_gen: + for i in 0 to NUM_REGIONS-1 generate + -- configuration -- + cfg_rd(i) <= csr.cfg(i); + -- address -- + address_read_back: process(csr) + begin + addr_rd(i) <= (others => '0'); + addr_rd(i)(XLEN-1 downto pmp_lsb_c-2) <= csr.addr(i)(XLEN-1 downto pmp_lsb_c-2); + if (GRANULARITY = 8) then -- bit [G-1] reads as zero in TOR or OFF mode + if (csr.cfg(i)(cfg_ah_c) = '0') then -- TOR/OFF mode + addr_rd(i)(pmp_lsb_c) <= '0'; + end if; + elsif (GRANULARITY > 8) then + addr_rd(i)(pmp_lsb_c-2 downto 0) <= (others => '1'); -- in NAPOT mode bits [G-2:0] must read as one + if (csr.cfg(i)(cfg_ah_c) = '0') then -- TOR/OFF mode + addr_rd(i)(pmp_lsb_c-1 downto 0) <= (others => '0'); -- in TOR or OFF mode bits [G-1:0] must read as zero + end if; + end if; + end process address_read_back; + end generate; + + -- terminate unused CSR read-backs -- + csr_read_back_terminate: + for i in NUM_REGIONS to 15 generate + cfg_rd(i) <= (others => '0'); + addr_rd(i) <= (others => '0'); + end generate; + + -- pack configuration read-back -- + cfg_rd32(0) <= cfg_rd(03) & cfg_rd(02) & cfg_rd(01) & cfg_rd(00); + cfg_rd32(1) <= cfg_rd(07) & cfg_rd(06) & cfg_rd(05) & cfg_rd(04); + cfg_rd32(2) <= cfg_rd(11) & cfg_rd(10) & cfg_rd(09) & cfg_rd(08); + cfg_rd32(3) <= cfg_rd(15) & cfg_rd(14) & cfg_rd(13) & cfg_rd(12); + + + -- Access Check Logic --------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + region_gen: + for r in 0 to NUM_REGIONS-1 generate + + -- extend region addresses to 34-bit -- + xaddr(r) <= csr.addr(r) & "00"; -- mask byte offset + + + -- compute address masks for NAPOT mode -- + addr_mask_napot(r)(pmp_lsb_c) <= '0'; + addr_mask_napot_gen: + for i in pmp_lsb_c+1 to XLEN-1 generate + addr_mask_napot(r)(i) <= addr_mask_napot(r)(i-1) or (not xaddr(r)(i-1)); + end generate; + + -- address mask select -- + addr_masking: process(rstn_i, clk_i) + begin + if (rstn_i = '0') then + addr_mask(r) <= (others => '0'); + elsif rising_edge(clk_i) then -- register output to relax timing of the (huge!) comparator logic + if (csr.cfg(r)(cfg_al_c) = '1') then -- NAPOT + addr_mask(r) <= addr_mask_napot(r); + else -- NA4 + addr_mask(r) <= (others => '1'); + end if; + end if; + end process addr_masking; + + + -- check region address match -- + -- NA4 and NAPOT -- + check.i_cmp_mm(r) <= '1' when ((addr_if_i(XLEN-1 downto pmp_lsb_c) and addr_mask(r)) = (xaddr(r)(XLEN-1 downto pmp_lsb_c) and addr_mask(r))) else '0'; + check.d_cmp_mm(r) <= '1' when ((addr_ls_i(XLEN-1 downto pmp_lsb_c) and addr_mask(r)) = (xaddr(r)(XLEN-1 downto pmp_lsb_c) and addr_mask(r))) else '0'; + -- TOR region 0 -- + addr_check_r0_gen: + if (r = 0) generate -- first entry: use ZERO as base and current entry as bound + check.i_cmp_ge(r) <= '1'; -- address is always greater than or equal to zero + check.i_cmp_lt(r) <= '0'; -- unused + check.d_cmp_ge(r) <= '1'; -- address is always greater than or equal to zero + check.d_cmp_lt(r) <= '0'; -- unused + end generate; + -- TOR region any -- + addr_check_rx_gen: + if (r > 0) generate -- use previous entry as base and current entry as bound + check.i_cmp_ge(r) <= '1' when (unsigned(addr_if_i(XLEN-1 downto pmp_lsb_c)) >= unsigned(xaddr(r-1)(XLEN-1 downto pmp_lsb_c))) else '0'; + check.i_cmp_lt(r) <= '1' when (unsigned(addr_if_i(XLEN-1 downto pmp_lsb_c)) < unsigned(xaddr(r )(XLEN-1 downto pmp_lsb_c))) else '0'; + check.d_cmp_ge(r) <= '1' when (unsigned(addr_ls_i(XLEN-1 downto pmp_lsb_c)) >= unsigned(xaddr(r-1)(XLEN-1 downto pmp_lsb_c))) else '0'; + check.d_cmp_lt(r) <= '1' when (unsigned(addr_ls_i(XLEN-1 downto pmp_lsb_c)) < unsigned(xaddr(r )(XLEN-1 downto pmp_lsb_c))) else '0'; + end generate; + + + -- check region match according to configured mode -- + match_check: process(csr, check) + begin + case csr.cfg(r)(cfg_ah_c downto cfg_al_c) is + when mode_off_c => -- entry disabled + check.i_match(r) <= '0'; + check.d_match(r) <= '0'; + when mode_tor_c => -- top of region + if (r = (NUM_REGIONS-1)) then -- very last entry + check.i_match(r) <= check.i_cmp_ge(r) and check.i_cmp_lt(r); + check.d_match(r) <= check.d_cmp_ge(r) and check.d_cmp_lt(r); + else -- this saves a LOT of comparators + check.i_match(r) <= check.i_cmp_ge(r) and (not check.i_cmp_ge(r+1)); + check.d_match(r) <= check.d_cmp_ge(r) and (not check.d_cmp_ge(r+1)); + end if; + when others => -- naturally-aligned region + check.i_match(r) <= check.i_cmp_mm(r); + check.d_match(r) <= check.d_cmp_mm(r); + end case; + end process match_check; + + + -- generate permission bits -- + -- M mode: always allow if lock bit not set, otherwise check permission + check.perm_ex(r) <= csr.cfg(r)(cfg_x_c) or (not csr.cfg(r)(cfg_l_c)) when (ctrl_i.cpu_priv = priv_mode_m_c) else csr.cfg(r)(cfg_x_c); + check.perm_rd(r) <= csr.cfg(r)(cfg_r_c) or (not csr.cfg(r)(cfg_l_c)) when (ctrl_i.lsu_priv = priv_mode_m_c) else csr.cfg(r)(cfg_r_c); + check.perm_wr(r) <= csr.cfg(r)(cfg_w_c) or (not csr.cfg(r)(cfg_l_c)) when (ctrl_i.lsu_priv = priv_mode_m_c) else csr.cfg(r)(cfg_w_c); + + end generate; + + + -- check for access fault (using static prioritization) -- + check.fail_ex(NUM_REGIONS) <= '1' when (ctrl_i.cpu_priv /= priv_mode_m_c) else '0'; -- default: fault if not M-mode + check.fail_rd(NUM_REGIONS) <= '1' when (ctrl_i.lsu_priv /= priv_mode_m_c) else '0'; -- default: fault if not M-mode + check.fail_wr(NUM_REGIONS) <= '1' when (ctrl_i.lsu_priv /= priv_mode_m_c) else '0'; -- default: fault if not M-mode + -- this is a *structural* description of a prioritization logic implemented as a multiplexer chain -- + fault_check_gen: + for r in NUM_REGIONS-1 downto 0 generate -- start with lowest priority + check.fail_ex(r) <= not check.perm_ex(r) when (check.i_match(r) = '1') else check.fail_ex(r+1); + check.fail_rd(r) <= not check.perm_rd(r) when (check.d_match(r) = '1') else check.fail_rd(r+1); + check.fail_wr(r) <= not check.perm_wr(r) when (check.d_match(r) = '1') else check.fail_wr(r+1); + end generate; + + + -- final PMP access fault signals (bypass PMP rules when in debug mode) -- + fault_reg: process(rstn_i, clk_i) + begin + if (rstn_i = '0') then + fault_if_o <= '0'; + fault_ld_o <= '0'; + fault_st_o <= '0'; + elsif rising_edge(clk_i) then + fault_if_o <= (not ctrl_i.cpu_debug) and check.fail_ex(0); + fault_ld_o <= (not ctrl_i.cpu_debug) and check.fail_rd(0); + fault_st_o <= (not ctrl_i.cpu_debug) and check.fail_wr(0); + end if; + end process fault_reg; + + +end neorv32_cpu_pmp_rtl; diff --git a/rtl/core/neorv32_cpu_regfile.vhd b/rtl/core/neorv32_cpu_regfile.vhd index 9838c65ba..ee52f0d79 100644 --- a/rtl/core/neorv32_cpu_regfile.vhd +++ b/rtl/core/neorv32_cpu_regfile.vhd @@ -1,5 +1,5 @@ -- ################################################################################################# --- # << NEORV32 - CPU General Purpose Data Register File >> # +-- # << NEORV32 CPU - General Purpose Data Register File >> # -- # ********************************************************************************************* # -- # Data register file. 32 entries (= 1024 bit) for RV32I ISA (default), 16 entries (= 512 bit) # -- # for RV32E ISA (when RISC-V "E" extension is enabled). # @@ -108,7 +108,7 @@ begin end process wb_select; - -- Register File Access ------------------------------------------------------------------- + -- Access Logic --------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- -- access addresses -- opa_addr <= "00000" when (ctrl_i.rf_zero_we = '1') else -- force rd = zero diff --git a/rtl/core/neorv32_intercon.vhd b/rtl/core/neorv32_intercon.vhd index e0e97bca0..ddf07afa5 100644 --- a/rtl/core/neorv32_intercon.vhd +++ b/rtl/core/neorv32_intercon.vhd @@ -604,52 +604,22 @@ architecture neorv32_bus_io_switch_rtl of neorv32_bus_io_switch is -- list of device base addresses -- type dev_base_list_t is array (0 to num_devs_physical_c-1) of std_ulogic_vector(31 downto 0); constant dev_base_list_c : dev_base_list_t := ( - DEV_00_BASE, - DEV_01_BASE, - DEV_02_BASE, - DEV_03_BASE, - DEV_04_BASE, - DEV_05_BASE, - DEV_06_BASE, - DEV_07_BASE, - DEV_08_BASE, - DEV_09_BASE, - DEV_10_BASE, - DEV_11_BASE, - DEV_12_BASE, - DEV_13_BASE, - DEV_14_BASE, - DEV_15_BASE, - DEV_16_BASE, - DEV_17_BASE, - DEV_18_BASE, - DEV_19_BASE, + DEV_00_BASE, DEV_01_BASE, DEV_02_BASE, DEV_03_BASE, + DEV_04_BASE, DEV_05_BASE, DEV_06_BASE, DEV_07_BASE, + DEV_08_BASE, DEV_09_BASE, DEV_10_BASE, DEV_11_BASE, + DEV_12_BASE, DEV_13_BASE, DEV_14_BASE, DEV_15_BASE, + DEV_16_BASE, DEV_17_BASE, DEV_18_BASE, DEV_19_BASE, DEV_20_BASE ); -- list of enabled device ports -- type dev_en_list_t is array (0 to num_devs_physical_c-1) of boolean; constant dev_en_list_c : dev_en_list_t := ( - DEV_00_EN, - DEV_01_EN, - DEV_02_EN, - DEV_03_EN, - DEV_04_EN, - DEV_05_EN, - DEV_06_EN, - DEV_07_EN, - DEV_08_EN, - DEV_09_EN, - DEV_10_EN, - DEV_11_EN, - DEV_12_EN, - DEV_13_EN, - DEV_14_EN, - DEV_15_EN, - DEV_16_EN, - DEV_17_EN, - DEV_18_EN, - DEV_19_EN, + DEV_00_EN, DEV_01_EN, DEV_02_EN, DEV_03_EN, + DEV_04_EN, DEV_05_EN, DEV_06_EN, DEV_07_EN, + DEV_08_EN, DEV_09_EN, DEV_10_EN, DEV_11_EN, + DEV_12_EN, DEV_13_EN, DEV_14_EN, DEV_15_EN, + DEV_16_EN, DEV_17_EN, DEV_18_EN, DEV_19_EN, DEV_20_EN ); diff --git a/rtl/core/neorv32_package.vhd b/rtl/core/neorv32_package.vhd index 2d5a1f34f..ba1e0f82e 100644 --- a/rtl/core/neorv32_package.vhd +++ b/rtl/core/neorv32_package.vhd @@ -51,15 +51,12 @@ package neorv32_package is -- = cycles after which an *unacknowledged* internal bus access will timeout and trigger a bus fault exception constant max_proc_int_response_time_c : natural := 15; -- default = 15 - -- log2 of co-processor timeout cycles -- - constant cp_timeout_c : natural := 7; -- default = 7 (= 128 cycles) - -- instruction prefetch buffer depth -- constant ipb_depth_c : natural := 2; -- hast to be a power of two, min 2, default 2 -- Architecture Constants ----------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080704"; -- hardware version + constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080705"; -- hardware version constant archid_c : natural := 19; -- official RISC-V architecture ID constant XLEN : natural := 32; -- native data path width, do not change! @@ -335,7 +332,6 @@ package neorv32_package is -- RISC-V CSR Addresses ------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - constant csr_zero_c : std_ulogic_vector(11 downto 0) := x"000"; -- always returns zero, only relevant for hardware access -- <<< standard read/write CSRs >>> -- -- user floating-point CSRs -- constant csr_fflags_c : std_ulogic_vector(11 downto 0) := x"001"; @@ -353,7 +349,6 @@ package neorv32_package is constant csr_menvcfg_c : std_ulogic_vector(11 downto 0) := x"30a"; constant csr_menvcfgh_c : std_ulogic_vector(11 downto 0) := x"31a"; -- machine counter setup -- - constant csr_cnt_setup_c : std_ulogic_vector(06 downto 0) := x"3" & "001"; -- counter setup constant csr_mcountinhibit_c : std_ulogic_vector(11 downto 0) := x"320"; constant csr_mhpmevent3_c : std_ulogic_vector(11 downto 0) := x"323"; constant csr_mhpmevent4_c : std_ulogic_vector(11 downto 0) := x"324"; @@ -368,22 +363,6 @@ package neorv32_package is constant csr_mhpmevent13_c : std_ulogic_vector(11 downto 0) := x"32d"; constant csr_mhpmevent14_c : std_ulogic_vector(11 downto 0) := x"32e"; constant csr_mhpmevent15_c : std_ulogic_vector(11 downto 0) := x"32f"; - constant csr_mhpmevent16_c : std_ulogic_vector(11 downto 0) := x"330"; - constant csr_mhpmevent17_c : std_ulogic_vector(11 downto 0) := x"331"; - constant csr_mhpmevent18_c : std_ulogic_vector(11 downto 0) := x"332"; - constant csr_mhpmevent19_c : std_ulogic_vector(11 downto 0) := x"333"; - constant csr_mhpmevent20_c : std_ulogic_vector(11 downto 0) := x"334"; - constant csr_mhpmevent21_c : std_ulogic_vector(11 downto 0) := x"335"; - constant csr_mhpmevent22_c : std_ulogic_vector(11 downto 0) := x"336"; - constant csr_mhpmevent23_c : std_ulogic_vector(11 downto 0) := x"337"; - constant csr_mhpmevent24_c : std_ulogic_vector(11 downto 0) := x"338"; - constant csr_mhpmevent25_c : std_ulogic_vector(11 downto 0) := x"339"; - constant csr_mhpmevent26_c : std_ulogic_vector(11 downto 0) := x"33a"; - constant csr_mhpmevent27_c : std_ulogic_vector(11 downto 0) := x"33b"; - constant csr_mhpmevent28_c : std_ulogic_vector(11 downto 0) := x"33c"; - constant csr_mhpmevent29_c : std_ulogic_vector(11 downto 0) := x"33d"; - constant csr_mhpmevent30_c : std_ulogic_vector(11 downto 0) := x"33e"; - constant csr_mhpmevent31_c : std_ulogic_vector(11 downto 0) := x"33f"; -- machine trap handling -- constant csr_mscratch_c : std_ulogic_vector(11 downto 0) := x"340"; constant csr_mepc_c : std_ulogic_vector(11 downto 0) := x"341"; @@ -395,18 +374,6 @@ package neorv32_package is constant csr_pmpcfg1_c : std_ulogic_vector(11 downto 0) := x"3a1"; constant csr_pmpcfg2_c : std_ulogic_vector(11 downto 0) := x"3a2"; constant csr_pmpcfg3_c : std_ulogic_vector(11 downto 0) := x"3a3"; - constant csr_pmpcfg4_c : std_ulogic_vector(11 downto 0) := x"3a4"; - constant csr_pmpcfg5_c : std_ulogic_vector(11 downto 0) := x"3a5"; - constant csr_pmpcfg6_c : std_ulogic_vector(11 downto 0) := x"3a6"; - constant csr_pmpcfg7_c : std_ulogic_vector(11 downto 0) := x"3a7"; - constant csr_pmpcfg8_c : std_ulogic_vector(11 downto 0) := x"3a8"; - constant csr_pmpcfg9_c : std_ulogic_vector(11 downto 0) := x"3a9"; - constant csr_pmpcfg10_c : std_ulogic_vector(11 downto 0) := x"3aa"; - constant csr_pmpcfg11_c : std_ulogic_vector(11 downto 0) := x"3ab"; - constant csr_pmpcfg12_c : std_ulogic_vector(11 downto 0) := x"3ac"; - constant csr_pmpcfg13_c : std_ulogic_vector(11 downto 0) := x"3ad"; - constant csr_pmpcfg14_c : std_ulogic_vector(11 downto 0) := x"3ae"; - constant csr_pmpcfg15_c : std_ulogic_vector(11 downto 0) := x"3af"; -- physical memory protection - address -- constant csr_pmpaddr0_c : std_ulogic_vector(11 downto 0) := x"3b0"; constant csr_pmpaddr1_c : std_ulogic_vector(11 downto 0) := x"3b1"; @@ -424,54 +391,6 @@ package neorv32_package is constant csr_pmpaddr13_c : std_ulogic_vector(11 downto 0) := x"3bd"; constant csr_pmpaddr14_c : std_ulogic_vector(11 downto 0) := x"3be"; constant csr_pmpaddr15_c : std_ulogic_vector(11 downto 0) := x"3bf"; - constant csr_pmpaddr16_c : std_ulogic_vector(11 downto 0) := x"3c0"; - constant csr_pmpaddr17_c : std_ulogic_vector(11 downto 0) := x"3c1"; - constant csr_pmpaddr18_c : std_ulogic_vector(11 downto 0) := x"3c2"; - constant csr_pmpaddr19_c : std_ulogic_vector(11 downto 0) := x"3c3"; - constant csr_pmpaddr20_c : std_ulogic_vector(11 downto 0) := x"3c4"; - constant csr_pmpaddr21_c : std_ulogic_vector(11 downto 0) := x"3c5"; - constant csr_pmpaddr22_c : std_ulogic_vector(11 downto 0) := x"3c6"; - constant csr_pmpaddr23_c : std_ulogic_vector(11 downto 0) := x"3c7"; - constant csr_pmpaddr24_c : std_ulogic_vector(11 downto 0) := x"3c8"; - constant csr_pmpaddr25_c : std_ulogic_vector(11 downto 0) := x"3c9"; - constant csr_pmpaddr26_c : std_ulogic_vector(11 downto 0) := x"3ca"; - constant csr_pmpaddr27_c : std_ulogic_vector(11 downto 0) := x"3cb"; - constant csr_pmpaddr28_c : std_ulogic_vector(11 downto 0) := x"3cc"; - constant csr_pmpaddr29_c : std_ulogic_vector(11 downto 0) := x"3cd"; - constant csr_pmpaddr30_c : std_ulogic_vector(11 downto 0) := x"3ce"; - constant csr_pmpaddr31_c : std_ulogic_vector(11 downto 0) := x"3cf"; - constant csr_pmpaddr32_c : std_ulogic_vector(11 downto 0) := x"3d0"; - constant csr_pmpaddr33_c : std_ulogic_vector(11 downto 0) := x"3d1"; - constant csr_pmpaddr34_c : std_ulogic_vector(11 downto 0) := x"3d2"; - constant csr_pmpaddr35_c : std_ulogic_vector(11 downto 0) := x"3d3"; - constant csr_pmpaddr36_c : std_ulogic_vector(11 downto 0) := x"3d4"; - constant csr_pmpaddr37_c : std_ulogic_vector(11 downto 0) := x"3d5"; - constant csr_pmpaddr38_c : std_ulogic_vector(11 downto 0) := x"3d6"; - constant csr_pmpaddr39_c : std_ulogic_vector(11 downto 0) := x"3d7"; - constant csr_pmpaddr40_c : std_ulogic_vector(11 downto 0) := x"3d8"; - constant csr_pmpaddr41_c : std_ulogic_vector(11 downto 0) := x"3d9"; - constant csr_pmpaddr42_c : std_ulogic_vector(11 downto 0) := x"3da"; - constant csr_pmpaddr43_c : std_ulogic_vector(11 downto 0) := x"3db"; - constant csr_pmpaddr44_c : std_ulogic_vector(11 downto 0) := x"3dc"; - constant csr_pmpaddr45_c : std_ulogic_vector(11 downto 0) := x"3dd"; - constant csr_pmpaddr46_c : std_ulogic_vector(11 downto 0) := x"3de"; - constant csr_pmpaddr47_c : std_ulogic_vector(11 downto 0) := x"3df"; - constant csr_pmpaddr48_c : std_ulogic_vector(11 downto 0) := x"3e0"; - constant csr_pmpaddr49_c : std_ulogic_vector(11 downto 0) := x"3e1"; - constant csr_pmpaddr50_c : std_ulogic_vector(11 downto 0) := x"3e2"; - constant csr_pmpaddr51_c : std_ulogic_vector(11 downto 0) := x"3e3"; - constant csr_pmpaddr52_c : std_ulogic_vector(11 downto 0) := x"3e4"; - constant csr_pmpaddr53_c : std_ulogic_vector(11 downto 0) := x"3e5"; - constant csr_pmpaddr54_c : std_ulogic_vector(11 downto 0) := x"3e6"; - constant csr_pmpaddr55_c : std_ulogic_vector(11 downto 0) := x"3e7"; - constant csr_pmpaddr56_c : std_ulogic_vector(11 downto 0) := x"3e8"; - constant csr_pmpaddr57_c : std_ulogic_vector(11 downto 0) := x"3e9"; - constant csr_pmpaddr58_c : std_ulogic_vector(11 downto 0) := x"3ea"; - constant csr_pmpaddr59_c : std_ulogic_vector(11 downto 0) := x"3eb"; - constant csr_pmpaddr60_c : std_ulogic_vector(11 downto 0) := x"3ec"; - constant csr_pmpaddr61_c : std_ulogic_vector(11 downto 0) := x"3ed"; - constant csr_pmpaddr62_c : std_ulogic_vector(11 downto 0) := x"3ee"; - constant csr_pmpaddr63_c : std_ulogic_vector(11 downto 0) := x"3ef"; -- trigger module registers -- constant csr_tselect_c : std_ulogic_vector(11 downto 0) := x"7a0"; constant csr_tdata1_c : std_ulogic_vector(11 downto 0) := x"7a1"; @@ -487,7 +406,7 @@ package neorv32_package is constant csr_dscratch0_c : std_ulogic_vector(11 downto 0) := x"7b2"; -- machine counters/timers -- constant csr_mcycle_c : std_ulogic_vector(11 downto 0) := x"b00"; - constant csr_mtime_c : std_ulogic_vector(11 downto 0) := x"b01"; -- dummy address +--constant csr_mtime_c : std_ulogic_vector(11 downto 0) := x"b01"; constant csr_minstret_c : std_ulogic_vector(11 downto 0) := x"b02"; constant csr_mhpmcounter3_c : std_ulogic_vector(11 downto 0) := x"b03"; constant csr_mhpmcounter4_c : std_ulogic_vector(11 downto 0) := x"b04"; @@ -502,25 +421,9 @@ package neorv32_package is constant csr_mhpmcounter13_c : std_ulogic_vector(11 downto 0) := x"b0d"; constant csr_mhpmcounter14_c : std_ulogic_vector(11 downto 0) := x"b0e"; constant csr_mhpmcounter15_c : std_ulogic_vector(11 downto 0) := x"b0f"; - constant csr_mhpmcounter16_c : std_ulogic_vector(11 downto 0) := x"b10"; - constant csr_mhpmcounter17_c : std_ulogic_vector(11 downto 0) := x"b11"; - constant csr_mhpmcounter18_c : std_ulogic_vector(11 downto 0) := x"b12"; - constant csr_mhpmcounter19_c : std_ulogic_vector(11 downto 0) := x"b13"; - constant csr_mhpmcounter20_c : std_ulogic_vector(11 downto 0) := x"b14"; - constant csr_mhpmcounter21_c : std_ulogic_vector(11 downto 0) := x"b15"; - constant csr_mhpmcounter22_c : std_ulogic_vector(11 downto 0) := x"b16"; - constant csr_mhpmcounter23_c : std_ulogic_vector(11 downto 0) := x"b17"; - constant csr_mhpmcounter24_c : std_ulogic_vector(11 downto 0) := x"b18"; - constant csr_mhpmcounter25_c : std_ulogic_vector(11 downto 0) := x"b19"; - constant csr_mhpmcounter26_c : std_ulogic_vector(11 downto 0) := x"b1a"; - constant csr_mhpmcounter27_c : std_ulogic_vector(11 downto 0) := x"b1b"; - constant csr_mhpmcounter28_c : std_ulogic_vector(11 downto 0) := x"b1c"; - constant csr_mhpmcounter29_c : std_ulogic_vector(11 downto 0) := x"b1d"; - constant csr_mhpmcounter30_c : std_ulogic_vector(11 downto 0) := x"b1e"; - constant csr_mhpmcounter31_c : std_ulogic_vector(11 downto 0) := x"b1f"; -- constant csr_mcycleh_c : std_ulogic_vector(11 downto 0) := x"b80"; - constant csr_mtimeh_c : std_ulogic_vector(11 downto 0) := x"b81"; -- dummy address +--constant csr_mtimeh_c : std_ulogic_vector(11 downto 0) := x"b81"; constant csr_minstreth_c : std_ulogic_vector(11 downto 0) := x"b82"; constant csr_mhpmcounter3h_c : std_ulogic_vector(11 downto 0) := x"b83"; constant csr_mhpmcounter4h_c : std_ulogic_vector(11 downto 0) := x"b84"; @@ -535,22 +438,6 @@ package neorv32_package is constant csr_mhpmcounter13h_c : std_ulogic_vector(11 downto 0) := x"b8d"; constant csr_mhpmcounter14h_c : std_ulogic_vector(11 downto 0) := x"b8e"; constant csr_mhpmcounter15h_c : std_ulogic_vector(11 downto 0) := x"b8f"; - constant csr_mhpmcounter16h_c : std_ulogic_vector(11 downto 0) := x"b90"; - constant csr_mhpmcounter17h_c : std_ulogic_vector(11 downto 0) := x"b91"; - constant csr_mhpmcounter18h_c : std_ulogic_vector(11 downto 0) := x"b92"; - constant csr_mhpmcounter19h_c : std_ulogic_vector(11 downto 0) := x"b93"; - constant csr_mhpmcounter20h_c : std_ulogic_vector(11 downto 0) := x"b94"; - constant csr_mhpmcounter21h_c : std_ulogic_vector(11 downto 0) := x"b95"; - constant csr_mhpmcounter22h_c : std_ulogic_vector(11 downto 0) := x"b96"; - constant csr_mhpmcounter23h_c : std_ulogic_vector(11 downto 0) := x"b97"; - constant csr_mhpmcounter24h_c : std_ulogic_vector(11 downto 0) := x"b98"; - constant csr_mhpmcounter25h_c : std_ulogic_vector(11 downto 0) := x"b99"; - constant csr_mhpmcounter26h_c : std_ulogic_vector(11 downto 0) := x"b9a"; - constant csr_mhpmcounter27h_c : std_ulogic_vector(11 downto 0) := x"b9b"; - constant csr_mhpmcounter28h_c : std_ulogic_vector(11 downto 0) := x"b9c"; - constant csr_mhpmcounter29h_c : std_ulogic_vector(11 downto 0) := x"b9d"; - constant csr_mhpmcounter30h_c : std_ulogic_vector(11 downto 0) := x"b9e"; - constant csr_mhpmcounter31h_c : std_ulogic_vector(11 downto 0) := x"b9f"; -- <<< standard read-only CSRs >>> -- -- user counters/timers -- constant csr_cycle_c : std_ulogic_vector(11 downto 0) := x"c00"; @@ -569,22 +456,6 @@ package neorv32_package is constant csr_hpmcounter13_c : std_ulogic_vector(11 downto 0) := x"c0d"; constant csr_hpmcounter14_c : std_ulogic_vector(11 downto 0) := x"c0e"; constant csr_hpmcounter15_c : std_ulogic_vector(11 downto 0) := x"c0f"; - constant csr_hpmcounter16_c : std_ulogic_vector(11 downto 0) := x"c10"; - constant csr_hpmcounter17_c : std_ulogic_vector(11 downto 0) := x"c11"; - constant csr_hpmcounter18_c : std_ulogic_vector(11 downto 0) := x"c12"; - constant csr_hpmcounter19_c : std_ulogic_vector(11 downto 0) := x"c13"; - constant csr_hpmcounter20_c : std_ulogic_vector(11 downto 0) := x"c14"; - constant csr_hpmcounter21_c : std_ulogic_vector(11 downto 0) := x"c15"; - constant csr_hpmcounter22_c : std_ulogic_vector(11 downto 0) := x"c16"; - constant csr_hpmcounter23_c : std_ulogic_vector(11 downto 0) := x"c17"; - constant csr_hpmcounter24_c : std_ulogic_vector(11 downto 0) := x"c18"; - constant csr_hpmcounter25_c : std_ulogic_vector(11 downto 0) := x"c19"; - constant csr_hpmcounter26_c : std_ulogic_vector(11 downto 0) := x"c1a"; - constant csr_hpmcounter27_c : std_ulogic_vector(11 downto 0) := x"c1b"; - constant csr_hpmcounter28_c : std_ulogic_vector(11 downto 0) := x"c1c"; - constant csr_hpmcounter29_c : std_ulogic_vector(11 downto 0) := x"c1d"; - constant csr_hpmcounter30_c : std_ulogic_vector(11 downto 0) := x"c1e"; - constant csr_hpmcounter31_c : std_ulogic_vector(11 downto 0) := x"c1f"; -- constant csr_cycleh_c : std_ulogic_vector(11 downto 0) := x"c80"; constant csr_timeh_c : std_ulogic_vector(11 downto 0) := x"c81"; @@ -602,22 +473,6 @@ package neorv32_package is constant csr_hpmcounter13h_c : std_ulogic_vector(11 downto 0) := x"c8d"; constant csr_hpmcounter14h_c : std_ulogic_vector(11 downto 0) := x"c8e"; constant csr_hpmcounter15h_c : std_ulogic_vector(11 downto 0) := x"c8f"; - constant csr_hpmcounter16h_c : std_ulogic_vector(11 downto 0) := x"c90"; - constant csr_hpmcounter17h_c : std_ulogic_vector(11 downto 0) := x"c91"; - constant csr_hpmcounter18h_c : std_ulogic_vector(11 downto 0) := x"c92"; - constant csr_hpmcounter19h_c : std_ulogic_vector(11 downto 0) := x"c93"; - constant csr_hpmcounter20h_c : std_ulogic_vector(11 downto 0) := x"c94"; - constant csr_hpmcounter21h_c : std_ulogic_vector(11 downto 0) := x"c95"; - constant csr_hpmcounter22h_c : std_ulogic_vector(11 downto 0) := x"c96"; - constant csr_hpmcounter23h_c : std_ulogic_vector(11 downto 0) := x"c97"; - constant csr_hpmcounter24h_c : std_ulogic_vector(11 downto 0) := x"c98"; - constant csr_hpmcounter25h_c : std_ulogic_vector(11 downto 0) := x"c99"; - constant csr_hpmcounter26h_c : std_ulogic_vector(11 downto 0) := x"c9a"; - constant csr_hpmcounter27h_c : std_ulogic_vector(11 downto 0) := x"c9b"; - constant csr_hpmcounter28h_c : std_ulogic_vector(11 downto 0) := x"c9c"; - constant csr_hpmcounter29h_c : std_ulogic_vector(11 downto 0) := x"c9d"; - constant csr_hpmcounter30h_c : std_ulogic_vector(11 downto 0) := x"c9e"; - constant csr_hpmcounter31h_c : std_ulogic_vector(11 downto 0) := x"c9f"; -- machine information registers -- constant csr_mvendorid_c : std_ulogic_vector(11 downto 0) := x"f11"; constant csr_marchid_c : std_ulogic_vector(11 downto 0) := x"f12"; @@ -628,13 +483,6 @@ package neorv32_package is -- machine extended ISA extensions information -- constant csr_mxisa_c : std_ulogic_vector(11 downto 0) := x"fc0"; - -- PMP Modes ------------------------------------------------------------------------------ - -- ------------------------------------------------------------------------------------------- - constant pmp_mode_off_c : std_ulogic_vector(1 downto 0) := "00"; -- null region (disabled) - constant pmp_mode_tor_c : std_ulogic_vector(1 downto 0) := "01"; -- top of range - constant pmp_mode_na4_c : std_ulogic_vector(1 downto 0) := "10"; -- naturally aligned four-byte region - constant pmp_mode_napot_c : std_ulogic_vector(1 downto 0) := "11"; -- naturally aligned power-of-two region (>= 8 bytes) - -- **************************************************************************************************************************** -- CPU Control -- **************************************************************************************************************************** @@ -655,16 +503,15 @@ package neorv32_package is alu_opa_mux : std_ulogic; -- operand A select (0=rs1, 1=PC) alu_opb_mux : std_ulogic; -- operand B select (0=rs2, 1=IMM) alu_unsigned : std_ulogic; -- is unsigned ALU operation - alu_frm : std_ulogic_vector(02 downto 0); -- FPU rounding mode alu_cp_trig : std_ulogic_vector(05 downto 0); -- co-processor trigger (one-hot) - -- data bus interface -- - bus_req_rd : std_ulogic; -- trigger memory read request - bus_req_wr : std_ulogic; -- trigger memory write request - bus_mo_we : std_ulogic; -- memory address and data output register write enable - bus_fence : std_ulogic; -- fence operation - bus_fencei : std_ulogic; -- fence.i operation - bus_priv : std_ulogic; -- effective privilege level for load/store - bus_rvso : std_ulogic; -- reservation set operation (atomic LR/SC) + -- load/store unit -- + lsu_req_rd : std_ulogic; -- trigger memory read request + lsu_req_wr : std_ulogic; -- trigger memory write request + lsu_mo_we : std_ulogic; -- memory address and data output register write enable + lsu_fence : std_ulogic; -- fence operation + lsu_fencei : std_ulogic; -- fence.i operation + lsu_priv : std_ulogic; -- effective privilege level for load/store + lsu_rvso : std_ulogic; -- reservation set operation (atomic LR/SC) -- instruction word -- ir_funct3 : std_ulogic_vector(02 downto 0); -- funct3 bit field ir_funct12 : std_ulogic_vector(11 downto 0); -- funct12 bit field @@ -689,15 +536,14 @@ package neorv32_package is alu_opa_mux => '0', alu_opb_mux => '0', alu_unsigned => '0', - alu_frm => (others => '0'), alu_cp_trig => (others => '0'), - bus_req_rd => '0', - bus_req_wr => '0', - bus_mo_we => '0', - bus_fence => '0', - bus_fencei => '0', - bus_priv => '0', - bus_rvso => '0', + lsu_req_rd => '0', + lsu_req_wr => '0', + lsu_mo_we => '0', + lsu_fence => '0', + lsu_fencei => '0', + lsu_priv => '0', + lsu_rvso => '0', ir_funct3 => (others => '0'), ir_funct12 => (others => '0'), ir_opcode => (others => '0'), @@ -707,11 +553,6 @@ package neorv32_package is cpu_debug => '0' ); - -- PMP Interface -------------------------------------------------------------------------- - -- ------------------------------------------------------------------------------------------- - type pmp_ctrl_if_t is array (0 to 15) of std_ulogic_vector(07 downto 0); - type pmp_addr_if_t is array (0 to 15) of std_ulogic_vector(33 downto 0); - -- Comparator Bus ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- constant cmp_equal_c : natural := 0; @@ -867,6 +708,7 @@ package neorv32_package is function or_reduce_f(input : std_ulogic_vector) return std_ulogic; function and_reduce_f(input : std_ulogic_vector) return std_ulogic; function xor_reduce_f(input : std_ulogic_vector) return std_ulogic; + function su_undefined_f(input : std_ulogic) return boolean; function to_hexchar_f(input : std_ulogic_vector(3 downto 0)) return character; function to_hstring32_f(input : std_ulogic_vector(31 downto 0)) return string; function bit_rev_f(input : std_ulogic_vector) return std_ulogic_vector; @@ -910,7 +752,7 @@ package neorv32_package is PMP_NUM_REGIONS : natural := 0; -- number of regions (0..16) PMP_MIN_GRANULARITY : natural := 4; -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes -- Hardware Performance Monitors (HPM) -- - HPM_NUM_CNTS : natural := 0; -- number of implemented HPM counters (0..29) + HPM_NUM_CNTS : natural := 0; -- number of implemented HPM counters (0..13) HPM_CNT_WIDTH : natural := 40; -- total size of HPM counters (0..64) -- Atomic Memory Access - Reservation Set Granularity -- AMO_RVS_GRANULARITY : natural := 4; -- size in bytes, has to be a power of 2, min 4 @@ -1180,13 +1022,24 @@ package body neorv32_package is return tmp_v; end function xor_reduce_f; + -- Check if std_ulogic is not '1' or '0' -------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + function su_undefined_f(input : std_ulogic) return boolean is + begin + case input is + when '1' | '0' => return false; + when others => return true; + end case; + end function su_undefined_f; + -- Convert std_ulogic_vector to lowercase HEX char ---------------------------------------- -- ------------------------------------------------------------------------------------------- function to_hexchar_f(input : std_ulogic_vector(3 downto 0)) return character is variable hex_v : string(1 to 16); begin hex_v := "0123456789abcdef"; - if (to_integer(unsigned(input)) > 15) then + if (su_undefined_f(input(3)) = true) or (su_undefined_f(input(2)) = true) or + (su_undefined_f(input(1)) = true) or (su_undefined_f(input(0)) = true) then return '?'; else return hex_v(to_integer(unsigned(input)) + 1); diff --git a/rtl/core/neorv32_top.vhd b/rtl/core/neorv32_top.vhd index 59218cf5e..9072e1607 100644 --- a/rtl/core/neorv32_top.vhd +++ b/rtl/core/neorv32_top.vhd @@ -79,7 +79,7 @@ entity neorv32_top is PMP_MIN_GRANULARITY : natural := 4; -- minimal region granularity in bytes, has to be a power of 2, min 4 bytes -- Hardware Performance Monitors (HPM) -- - HPM_NUM_CNTS : natural := 0; -- number of implemented HPM counters (0..29) + HPM_NUM_CNTS : natural := 0; -- number of implemented HPM counters (0..13) HPM_CNT_WIDTH : natural := 40; -- total size of HPM counters (0..64) -- Atomic Memory Access - Reservation Set Granularity -- @@ -940,8 +940,8 @@ begin ) port map ( -- host port -- - main_req_i => io_req, - main_rsp_o => io_rsp, + main_req_i => io_req, + main_rsp_o => io_rsp, -- device ports -- dev_00_req_o => io_dev_req(IODEV_OCD), dev_00_rsp_i => io_dev_rsp(IODEV_OCD), dev_01_req_o => io_dev_req(IODEV_SYSINFO), dev_01_rsp_i => io_dev_rsp(IODEV_SYSINFO), diff --git a/sw/example/floating_point_test/main.c b/sw/example/floating_point_test/main.c index 222573708..8a216ad8d 100644 --- a/sw/example/floating_point_test/main.c +++ b/sw/example/floating_point_test/main.c @@ -36,7 +36,8 @@ /**********************************************************************//** * @file floating_point_test/main.c * @author Stephan Nolting - * @brief Verification program for the NEORV32 'Zfinx' extension (floating-point in x registers) using pseudo-random data as input; compares results from hardware against pure-sw reference functions. + * @brief Verification program for the NEORV32 'Zfinx' extension (floating-point in x registers) using + * pseudo-random data as input; compares results from hardware against pure-sw reference functions. **************************************************************************/ #include @@ -66,6 +67,8 @@ #define NUM_TEST_CASES (1000000) //** Silent mode (only show actual errors when != 0) */ #define SILENT_MODE (1) +//** Run FPU CSR tests when != 0 */ +#define RUN_CSR_TESTS (1) //** Run conversion tests when != 0 */ #define RUN_CONV_TESTS (1) //** Run add/sub tests when != 0 */ @@ -95,7 +98,8 @@ void print_report(uint32_t num_err); /**********************************************************************//** - * Main function; test all available operations of the NEORV32 'Zfinx' extensions using bit floating-point hardware intrinsics and software-only reference functions (emulation). + * Main function; test all available operations of the NEORV32 'Zfinx' extensions using bit floating-point + * hardware intrinsics and software-only reference functions (emulation). * * @note This program requires the Zfinx CPU extension. * @@ -147,6 +151,51 @@ int main() { neorv32_uart0_printf("Test cases per instruction: %u\n", (uint32_t)NUM_TEST_CASES); neorv32_uart0_printf("NOTE: The NEORV32 FPU does not support subnormal numbers yet. Subnormal numbers are flushed to zero.\n\n"); + +// ---------------------------------------------------------------------------- +// CSR Read/Write Tests +// ---------------------------------------------------------------------------- +#if (RUN_CSR_TESTS != 0) + neorv32_uart0_printf("\n#%u: FFLAGS CSR...\n", test_cnt); + err_cnt = 0; + for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { + opa.binary_value = get_test_vector() & 0x1F; + neorv32_cpu_csr_write(CSR_FFLAGS, opa.binary_value); + res_hw.binary_value = neorv32_cpu_csr_read(CSR_FFLAGS); + res_sw.binary_value = opa.binary_value; + err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value); + } + print_report(err_cnt); + err_cnt_total += err_cnt; + test_cnt++; + + neorv32_uart0_printf("\n#%u: FRM CSR...\n", test_cnt); + err_cnt = 0; + for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { + opa.binary_value = get_test_vector() & 0x07; + neorv32_cpu_csr_write(CSR_FRM, opa.binary_value); + res_hw.binary_value = neorv32_cpu_csr_read(CSR_FRM); + res_sw.binary_value = opa.binary_value; + err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value); + } + print_report(err_cnt); + err_cnt_total += err_cnt; + test_cnt++; + + neorv32_uart0_printf("\n#%u: FCSR CSR...\n", test_cnt); + err_cnt = 0; + for (i=0;i<(uint32_t)NUM_TEST_CASES; i++) { + opa.binary_value = get_test_vector() & 0xFF; + neorv32_cpu_csr_write(CSR_FCSR, opa.binary_value); + res_hw.binary_value = neorv32_cpu_csr_read(CSR_FCSR); + res_sw.binary_value = opa.binary_value; + err_cnt += verify_result(i, opa.binary_value, 0, res_sw.binary_value, res_hw.binary_value); + } + print_report(err_cnt); + err_cnt_total += err_cnt; + test_cnt++; +#endif + // clear FPU status/control word neorv32_cpu_csr_write(CSR_FCSR, 0); @@ -402,7 +451,7 @@ int main() { test_cnt++; #endif - + // ---------------------------------------------------------------------------- // UNSUPPORTED Instructions Tests - Execution should raise illegal instruction exception // ---------------------------------------------------------------------------- diff --git a/sw/lib/include/neorv32_cpu_csr.h b/sw/lib/include/neorv32_cpu_csr.h index 4ac9b9e90..6f72df241 100644 --- a/sw/lib/include/neorv32_cpu_csr.h +++ b/sw/lib/include/neorv32_cpu_csr.h @@ -83,22 +83,6 @@ enum NEORV32_CSR_enum { CSR_MHPMEVENT13 = 0x32d, /**< 0x32d - mhpmevent13: Machine hardware performance monitor event selector 13 */ CSR_MHPMEVENT14 = 0x32e, /**< 0x32e - mhpmevent14: Machine hardware performance monitor event selector 14 */ CSR_MHPMEVENT15 = 0x32f, /**< 0x32f - mhpmevent15: Machine hardware performance monitor event selector 15 */ - CSR_MHPMEVENT16 = 0x330, /**< 0x330 - mhpmevent16: Machine hardware performance monitor event selector 16 */ - CSR_MHPMEVENT17 = 0x331, /**< 0x331 - mhpmevent17: Machine hardware performance monitor event selector 17 */ - CSR_MHPMEVENT18 = 0x332, /**< 0x332 - mhpmevent18: Machine hardware performance monitor event selector 18 */ - CSR_MHPMEVENT19 = 0x333, /**< 0x333 - mhpmevent19: Machine hardware performance monitor event selector 19 */ - CSR_MHPMEVENT20 = 0x334, /**< 0x334 - mhpmevent20: Machine hardware performance monitor event selector 20 */ - CSR_MHPMEVENT21 = 0x335, /**< 0x335 - mhpmevent21: Machine hardware performance monitor event selector 21 */ - CSR_MHPMEVENT22 = 0x336, /**< 0x336 - mhpmevent22: Machine hardware performance monitor event selector 22 */ - CSR_MHPMEVENT23 = 0x337, /**< 0x337 - mhpmevent23: Machine hardware performance monitor event selector 23 */ - CSR_MHPMEVENT24 = 0x338, /**< 0x338 - mhpmevent24: Machine hardware performance monitor event selector 24 */ - CSR_MHPMEVENT25 = 0x339, /**< 0x339 - mhpmevent25: Machine hardware performance monitor event selector 25 */ - CSR_MHPMEVENT26 = 0x33a, /**< 0x33a - mhpmevent26: Machine hardware performance monitor event selector 26 */ - CSR_MHPMEVENT27 = 0x33b, /**< 0x33b - mhpmevent27: Machine hardware performance monitor event selector 27 */ - CSR_MHPMEVENT28 = 0x33c, /**< 0x33c - mhpmevent28: Machine hardware performance monitor event selector 28 */ - CSR_MHPMEVENT29 = 0x33d, /**< 0x33d - mhpmevent29: Machine hardware performance monitor event selector 29 */ - CSR_MHPMEVENT30 = 0x33e, /**< 0x33e - mhpmevent30: Machine hardware performance monitor event selector 30 */ - CSR_MHPMEVENT31 = 0x33f, /**< 0x33f - mhpmevent31: Machine hardware performance monitor event selector 31 */ /* machine trap control */ CSR_MSCRATCH = 0x340, /**< 0x340 - mscratch: Machine scratch register */ @@ -108,10 +92,10 @@ enum NEORV32_CSR_enum { CSR_MIP = 0x344, /**< 0x344 - mip: Machine interrupt pending register */ /* physical memory protection */ - CSR_PMPCFG0 = 0x3a0, /**< 0x3a0 - pmpcfg0: Physical memory protection configuration register 0 (entries 0..3) */ - CSR_PMPCFG1 = 0x3a1, /**< 0x3a1 - pmpcfg1: Physical memory protection configuration register 1 (entries 4..7) */ - CSR_PMPCFG2 = 0x3a2, /**< 0x3a2 - pmpcfg2: Physical memory protection configuration register 2 (entries 8..11) */ - CSR_PMPCFG3 = 0x3a3, /**< 0x3a3 - pmpcfg3: Physical memory protection configuration register 3 (entries 12..15) */ + CSR_PMPCFG0 = 0x3a0, /**< 0x3a0 - pmpcfg0: Physical memory protection configuration register 0 (regions 0..3) */ + CSR_PMPCFG1 = 0x3a1, /**< 0x3a1 - pmpcfg1: Physical memory protection configuration register 1 (regions 4..7) */ + CSR_PMPCFG2 = 0x3a2, /**< 0x3a2 - pmpcfg2: Physical memory protection configuration register 2 (regions 8..11) */ + CSR_PMPCFG3 = 0x3a3, /**< 0x3a3 - pmpcfg3: Physical memory protection configuration register 3 (regions 12..15) */ CSR_PMPADDR0 = 0x3b0, /**< 0x3b0 - pmpaddr0: Physical memory protection address register 0 */ CSR_PMPADDR1 = 0x3b1, /**< 0x3b1 - pmpaddr1: Physical memory protection address register 1 */ @@ -162,22 +146,6 @@ enum NEORV32_CSR_enum { CSR_MHPMCOUNTER13 = 0xb0d, /**< 0xb0d - mhpmcounter13: Machine hardware performance monitor 13 counter low word */ CSR_MHPMCOUNTER14 = 0xb0e, /**< 0xb0e - mhpmcounter14: Machine hardware performance monitor 14 counter low word */ CSR_MHPMCOUNTER15 = 0xb0f, /**< 0xb0f - mhpmcounter15: Machine hardware performance monitor 15 counter low word */ - CSR_MHPMCOUNTER16 = 0xb10, /**< 0xb10 - mhpmcounter16: Machine hardware performance monitor 16 counter low word */ - CSR_MHPMCOUNTER17 = 0xb11, /**< 0xb11 - mhpmcounter17: Machine hardware performance monitor 17 counter low word */ - CSR_MHPMCOUNTER18 = 0xb12, /**< 0xb12 - mhpmcounter18: Machine hardware performance monitor 18 counter low word */ - CSR_MHPMCOUNTER19 = 0xb13, /**< 0xb13 - mhpmcounter19: Machine hardware performance monitor 19 counter low word */ - CSR_MHPMCOUNTER20 = 0xb14, /**< 0xb14 - mhpmcounter20: Machine hardware performance monitor 20 counter low word */ - CSR_MHPMCOUNTER21 = 0xb15, /**< 0xb15 - mhpmcounter21: Machine hardware performance monitor 21 counter low word */ - CSR_MHPMCOUNTER22 = 0xb16, /**< 0xb16 - mhpmcounter22: Machine hardware performance monitor 22 counter low word */ - CSR_MHPMCOUNTER23 = 0xb17, /**< 0xb17 - mhpmcounter23: Machine hardware performance monitor 23 counter low word */ - CSR_MHPMCOUNTER24 = 0xb18, /**< 0xb18 - mhpmcounter24: Machine hardware performance monitor 24 counter low word */ - CSR_MHPMCOUNTER25 = 0xb19, /**< 0xb19 - mhpmcounter25: Machine hardware performance monitor 25 counter low word */ - CSR_MHPMCOUNTER26 = 0xb1a, /**< 0xb1a - mhpmcounter26: Machine hardware performance monitor 26 counter low word */ - CSR_MHPMCOUNTER27 = 0xb1b, /**< 0xb1b - mhpmcounter27: Machine hardware performance monitor 27 counter low word */ - CSR_MHPMCOUNTER28 = 0xb1c, /**< 0xb1c - mhpmcounter28: Machine hardware performance monitor 28 counter low word */ - CSR_MHPMCOUNTER29 = 0xb1d, /**< 0xb1d - mhpmcounter29: Machine hardware performance monitor 29 counter low word */ - CSR_MHPMCOUNTER30 = 0xb1e, /**< 0xb1e - mhpmcounter30: Machine hardware performance monitor 30 counter low word */ - CSR_MHPMCOUNTER31 = 0xb1f, /**< 0xb1f - mhpmcounter31: Machine hardware performance monitor 31 counter low word */ CSR_MCYCLEH = 0xb80, /**< 0xb80 - mcycleh: Machine cycle counter high word */ // @@ -195,22 +163,6 @@ enum NEORV32_CSR_enum { CSR_MHPMCOUNTER13H = 0xb8d, /**< 0xb8d - mhpmcounter13h: Machine hardware performance monitor 13 counter high word */ CSR_MHPMCOUNTER14H = 0xb8e, /**< 0xb8e - mhpmcounter14h: Machine hardware performance monitor 14 counter high word */ CSR_MHPMCOUNTER15H = 0xb8f, /**< 0xb8f - mhpmcounter15h: Machine hardware performance monitor 15 counter high word */ - CSR_MHPMCOUNTER16H = 0xb90, /**< 0xb90 - mhpmcounter16h: Machine hardware performance monitor 16 counter high word */ - CSR_MHPMCOUNTER17H = 0xb91, /**< 0xb91 - mhpmcounter17h: Machine hardware performance monitor 17 counter high word */ - CSR_MHPMCOUNTER18H = 0xb92, /**< 0xb92 - mhpmcounter18h: Machine hardware performance monitor 18 counter high word */ - CSR_MHPMCOUNTER19H = 0xb93, /**< 0xb93 - mhpmcounter19h: Machine hardware performance monitor 19 counter high word */ - CSR_MHPMCOUNTER20H = 0xb94, /**< 0xb94 - mhpmcounter20h: Machine hardware performance monitor 20 counter high word */ - CSR_MHPMCOUNTER21H = 0xb95, /**< 0xb95 - mhpmcounter21h: Machine hardware performance monitor 21 counter high word */ - CSR_MHPMCOUNTER22H = 0xb96, /**< 0xb96 - mhpmcounter22h: Machine hardware performance monitor 22 counter high word */ - CSR_MHPMCOUNTER23H = 0xb97, /**< 0xb97 - mhpmcounter23h: Machine hardware performance monitor 23 counter high word */ - CSR_MHPMCOUNTER24H = 0xb98, /**< 0xb98 - mhpmcounter24h: Machine hardware performance monitor 24 counter high word */ - CSR_MHPMCOUNTER25H = 0xb99, /**< 0xb99 - mhpmcounter25h: Machine hardware performance monitor 25 counter high word */ - CSR_MHPMCOUNTER26H = 0xb9a, /**< 0xb9a - mhpmcounter26h: Machine hardware performance monitor 26 counter high word */ - CSR_MHPMCOUNTER27H = 0xb9b, /**< 0xb9b - mhpmcounter27h: Machine hardware performance monitor 27 counter high word */ - CSR_MHPMCOUNTER28H = 0xb9c, /**< 0xb9c - mhpmcounter28h: Machine hardware performance monitor 28 counter high word */ - CSR_MHPMCOUNTER29H = 0xb9d, /**< 0xb9d - mhpmcounter29h: Machine hardware performance monitor 29 counter high word */ - CSR_MHPMCOUNTER30H = 0xb9e, /**< 0xb9e - mhpmcounter30h: Machine hardware performance monitor 30 counter high word */ - CSR_MHPMCOUNTER31H = 0xb9f, /**< 0xb9f - mhpmcounter31h: Machine hardware performance monitor 31 counter high word */ /* user counters and timers */ CSR_CYCLE = 0xc00, /**< 0xc00 - cycle: Cycle counter low word (from MCYCLE) */ @@ -229,22 +181,6 @@ enum NEORV32_CSR_enum { CSR_HPMCOUNTER13 = 0xc0d, /**< 0xc0d - hpmcounter13: User hardware performance monitor 13 counter low word */ CSR_HPMCOUNTER14 = 0xc0e, /**< 0xc0e - hpmcounter14: User hardware performance monitor 14 counter low word */ CSR_HPMCOUNTER15 = 0xc0f, /**< 0xc0f - hpmcounter15: User hardware performance monitor 15 counter low word */ - CSR_HPMCOUNTER16 = 0xc10, /**< 0xc10 - hpmcounter16: User hardware performance monitor 16 counter low word */ - CSR_HPMCOUNTER17 = 0xc11, /**< 0xc11 - hpmcounter17: User hardware performance monitor 17 counter low word */ - CSR_HPMCOUNTER18 = 0xc12, /**< 0xc12 - hpmcounter18: User hardware performance monitor 18 counter low word */ - CSR_HPMCOUNTER19 = 0xc13, /**< 0xc13 - hpmcounter19: User hardware performance monitor 19 counter low word */ - CSR_HPMCOUNTER20 = 0xc14, /**< 0xc14 - hpmcounter20: User hardware performance monitor 20 counter low word */ - CSR_HPMCOUNTER21 = 0xc15, /**< 0xc15 - hpmcounter21: User hardware performance monitor 21 counter low word */ - CSR_HPMCOUNTER22 = 0xc16, /**< 0xc16 - hpmcounter22: User hardware performance monitor 22 counter low word */ - CSR_HPMCOUNTER23 = 0xc17, /**< 0xc17 - hpmcounter23: User hardware performance monitor 23 counter low word */ - CSR_HPMCOUNTER24 = 0xc18, /**< 0xc18 - hpmcounter24: User hardware performance monitor 24 counter low word */ - CSR_HPMCOUNTER25 = 0xc19, /**< 0xc19 - hpmcounter25: User hardware performance monitor 25 counter low word */ - CSR_HPMCOUNTER26 = 0xc1a, /**< 0xc1a - hpmcounter26: User hardware performance monitor 26 counter low word */ - CSR_HPMCOUNTER27 = 0xc1b, /**< 0xc1b - hpmcounter27: User hardware performance monitor 27 counter low word */ - CSR_HPMCOUNTER28 = 0xc1c, /**< 0xc1c - hpmcounter28: User hardware performance monitor 28 counter low word */ - CSR_HPMCOUNTER29 = 0xc1d, /**< 0xc1d - hpmcounter29: User hardware performance monitor 29 counter low word */ - CSR_HPMCOUNTER30 = 0xc1e, /**< 0xc1e - hpmcounter30: User hardware performance monitor 30 counter low word */ - CSR_HPMCOUNTER31 = 0xc1f, /**< 0xc1f - hpmcounter31: User hardware performance monitor 31 counter low word */ CSR_CYCLEH = 0xc80, /**< 0xc80 - cycleh: Cycle counter high word (from MCYCLEH) */ // @@ -262,22 +198,6 @@ enum NEORV32_CSR_enum { CSR_HPMCOUNTER13H = 0xc8d, /**< 0xc8d - hpmcounter13h: User hardware performance monitor 13 counter high word */ CSR_HPMCOUNTER14H = 0xc8e, /**< 0xc8e - hpmcounter14h: User hardware performance monitor 14 counter high word */ CSR_HPMCOUNTER15H = 0xc8f, /**< 0xc8f - hpmcounter15h: User hardware performance monitor 15 counter high word */ - CSR_HPMCOUNTER16H = 0xc90, /**< 0xc90 - hpmcounter16h: User hardware performance monitor 16 counter high word */ - CSR_HPMCOUNTER17H = 0xc91, /**< 0xc91 - hpmcounter17h: User hardware performance monitor 17 counter high word */ - CSR_HPMCOUNTER18H = 0xc92, /**< 0xc92 - hpmcounter18h: User hardware performance monitor 18 counter high word */ - CSR_HPMCOUNTER19H = 0xc93, /**< 0xc93 - hpmcounter19h: User hardware performance monitor 19 counter high word */ - CSR_HPMCOUNTER20H = 0xc94, /**< 0xc94 - hpmcounter20h: User hardware performance monitor 20 counter high word */ - CSR_HPMCOUNTER21H = 0xc95, /**< 0xc95 - hpmcounter21h: User hardware performance monitor 21 counter high word */ - CSR_HPMCOUNTER22H = 0xc96, /**< 0xc96 - hpmcounter22h: User hardware performance monitor 22 counter high word */ - CSR_HPMCOUNTER23H = 0xc97, /**< 0xc97 - hpmcounter23h: User hardware performance monitor 23 counter high word */ - CSR_HPMCOUNTER24H = 0xc98, /**< 0xc98 - hpmcounter24h: User hardware performance monitor 24 counter high word */ - CSR_HPMCOUNTER25H = 0xc99, /**< 0xc99 - hpmcounter25h: User hardware performance monitor 25 counter high word */ - CSR_HPMCOUNTER26H = 0xc9a, /**< 0xc9a - hpmcounter26h: User hardware performance monitor 26 counter high word */ - CSR_HPMCOUNTER27H = 0xc9b, /**< 0xc9b - hpmcounter27h: User hardware performance monitor 27 counter high word */ - CSR_HPMCOUNTER28H = 0xc9c, /**< 0xc9c - hpmcounter28h: User hardware performance monitor 28 counter high word */ - CSR_HPMCOUNTER29H = 0xc9d, /**< 0xc9d - hpmcounter29h: User hardware performance monitor 29 counter high word */ - CSR_HPMCOUNTER30H = 0xc9e, /**< 0xc9e - hpmcounter30h: User hardware performance monitor 30 counter high word */ - CSR_HPMCOUNTER31H = 0xc9f, /**< 0xc9f - hpmcounter31h: User hardware performance monitor 31 counter high word */ /* machine information registers */ CSR_MVENDORID = 0xf11, /**< 0xf11 - mvendorid: Vendor ID */ diff --git a/sw/lib/source/neorv32_cpu.c b/sw/lib/source/neorv32_cpu.c index 2cd03bf47..f8d51e7c9 100644 --- a/sw/lib/source/neorv32_cpu.c +++ b/sw/lib/source/neorv32_cpu.c @@ -394,12 +394,6 @@ int neorv32_cpu_pmp_configure_region(int index, uint32_t addr, uint8_t config) { default: break; } - // wait for hardware to compute address masks - int i; - for (i=0; i<16; i++) { - asm volatile ("nop"); - } - // set configuration uint32_t clr_mask = 0xff; uint32_t set_mask = (uint32_t)config; @@ -422,7 +416,7 @@ int neorv32_cpu_pmp_configure_region(int index, uint32_t addr, uint8_t config) { /**********************************************************************//** * Hardware performance monitors (HPM): Get number of available HPM counters. * - * @return Returns number of available HPM counters (0..29). + * @return Returns number of available HPM counters. **************************************************************************/ uint32_t neorv32_cpu_hpm_get_num_counters(void) { diff --git a/sw/lib/source/neorv32_cpu_amo.c b/sw/lib/source/neorv32_cpu_amo.c index df27d0759..f6849cbdc 100644 --- a/sw/lib/source/neorv32_cpu_amo.c +++ b/sw/lib/source/neorv32_cpu_amo.c @@ -261,7 +261,7 @@ uint32_t neorv32_cpu_amomaxuw(uint32_t addr, uint32_t wdata) { * @note This function requires the CPU A ISA extension. * * @param[in] addr 32-bit memory address, word-aligned. - * @param[in] wdata Data word to be atomically MAX-ed with original data at address (signed 32-bit). + * @param[in] wdata Data word to be atomically MIN-ed with original data at address (signed 32-bit). * @return Pre-operation data loaded from address (signed 32-bit) **************************************************************************/ int32_t neorv32_cpu_amominw(uint32_t addr, int32_t wdata) { @@ -290,7 +290,7 @@ int32_t neorv32_cpu_amominw(uint32_t addr, int32_t wdata) { * @note This function requires the CPU A ISA extension. * * @param[in] addr 32-bit memory address, word-aligned. - * @param[in] wdata Data word to be atomically MAX-ed with original data at address (unsigned 32-bit). + * @param[in] wdata Data word to be atomically MIN-ed with original data at address (unsigned 32-bit). * @return Pre-operation data loaded from address (unsigned 32-bit) **************************************************************************/ uint32_t neorv32_cpu_amominuw(uint32_t addr, uint32_t wdata) { diff --git a/sw/lib/source/neorv32_rte.c b/sw/lib/source/neorv32_rte.c index 5db8bf3c0..68e3400a4 100644 --- a/sw/lib/source/neorv32_rte.c +++ b/sw/lib/source/neorv32_rte.c @@ -340,7 +340,7 @@ void neorv32_rte_print_hw_config(void) { } } - // Z* CPU extensions + // CPU sub-extensions tmp = neorv32_cpu_csr_read(CSR_MXISA); if (tmp & (1<SOC & (1 << SYSINFO_SOC_MEM_INT_DMEM)) { + neorv32_uart0_printf("%u bytes\n", (uint32_t)(1 << NEORV32_SYSINFO->MEM[SYSINFO_MEM_DMEM]) & 0xFFFFFFFCUL); + } + else { + neorv32_uart0_printf("none\n"); + } + // internal i-cache neorv32_uart0_printf("Internal i-cache: "); if (NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_ICACHE)) { @@ -451,15 +463,6 @@ void neorv32_rte_print_hw_config(void) { neorv32_uart0_printf("none\n"); } - // internal DMEM - neorv32_uart0_printf("Internal DMEM: "); - if (NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_MEM_INT_DMEM)) { - neorv32_uart0_printf("%u bytes\n", (uint32_t)(1 << NEORV32_SYSINFO->MEM[SYSINFO_MEM_DMEM]) & 0xFFFFFFFCUL); - } - else { - neorv32_uart0_printf("none\n"); - } - // internal d-cache neorv32_uart0_printf("Internal d-cache: "); if (NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_DCACHE)) {