diff --git a/CHANGELOG.md b/CHANGELOG.md index bcd59b5a0..faa66eda1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12 | Date | Version | Comment | Link | |:----:|:-------:|:--------|:----:| +| 09.02.2024 | 1.9.4.6 | :sparkles: add configurable XIP cache | [#799](https://github.com/stnolting/neorv32/pull/799) | | 09.02.2024 | 1.9.4.5 | :bug: close further illegal compressed instruction encoding loopholes | [#797](https://github.com/stnolting/neorv32/pull/797) | | 04.02.2024 | 1.9.4.4 | :bug: fix minor bug: CPU instruction bus privilege signal did not remain stable during the entire request | [#792](https://github.com/stnolting/neorv32/pull/792) | | 03.02.2024 | 1.9.4.3 | :bug: fix minor bug: CPU instruction bus privilege signal was hardwired to "user-mode" | [#790](https://github.com/stnolting/neorv32/pull/790) | diff --git a/docs/datasheet/soc.adoc b/docs/datasheet/soc.adoc index a528aa96e..72fe4330f 100644 --- a/docs/datasheet/soc.adoc +++ b/docs/datasheet/soc.adoc @@ -249,7 +249,7 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt | `ICACHE_ASSOCIATIVITY` | natural | 1 | Associativity (number of sets). Allowed configurations: `1` = 1 set, direct mapped; `2` = 2-way set-associative. 4+^| **<<_processor_internal_data_cache_dcache>>** | `DCACHE_EN` | boolean | false | Implement the data cache. -| `DCACHE_NUM_BLOCKS` | natural | 4 | Number of blocks ("pages" or "lines") Has to be a power of two. +| `DCACHE_NUM_BLOCKS` | natural | 4 | Number of blocks ("pages" or "lines"). Has to be a power of two. | `DCACHE_BLOCK_SIZE` | natural | 64 | Size in bytes of each block. Has to be a power of two. 4+^| **<<_processor_external_memory_interface_wishbone>>** | `MEM_EXT_EN` | boolean | false | Implement the external bus interface. @@ -258,6 +258,11 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt | `MEM_EXT_BIG_ENDIAN` | boolean | false | Use BIG endian data order interface for external bus. | `MEM_EXT_ASYNC_RX` | boolean | false | Disable input registers when true. | `MEM_EXT_ASYNC_TX` | boolean | false | Disable output registers when true. +4+^| **<<_execute_in_place_module_xip>>** +| `XIP_EN` | boolean | false | Implement the execute in-place module. +| `XIP_CACHE_EN` | boolean | false | Implement XIP cache. +| `XIP_CACHE_NUM_BLOCKS` | natural | 8 | Number of blocks in XIP cache. Has to be a power of two. +| `XIP_CACHE_BLOCK_SIZE` | natural | 256 | Number of bytes per XIP cache block. Has to be a power of two, min 4. 4+^| **<<_external_interrupt_controller_xirq>>** | `XIRQ_NUM_CH` | natural | 0 | Number of channels of the external interrupt controller. Valid values are 0..32. | `XIRQ_TRIGGER_TYPE` | suv(31:0) | 0xFFFFFFFF | Trigger type (one bit per channel): `0` = level-triggered, '1' = edge triggered. @@ -287,7 +292,6 @@ The generic type "`suv(x:y)`" is an abbreviation for "`std_ulogic_vector(x downt | `IO_NEOLED_EN` | boolean | false | Implement the <<_smart_led_interface_neoled>>. | `IO_NEOLED_TX_FIFO` | natural | 1 | TX FIFO depth of the the <<_smart_led_interface_neoled>>. Has to be a power of two, min 1, max 32768. | `IO_GPTMR_EN` | boolean | false | Implement the <<_general_purpose_timer_gptmr>>. -| `IO_XIP_EN` | boolean | false | Implement the <<_execute_in_place_module_xip>>. | `IO_ONEWIRE_EN` | boolean | false | Implement the <<_one_wire_serial_interface_controller_onewire>>. | `IO_DMA_EN` | boolean | false | Implement the <<_direct_memory_access_controller_dma>>. | `IO_SLINK_EN` | boolean | false | Implement the <<_stream_link_interface_slink>>. diff --git a/docs/datasheet/soc_sysinfo.adoc b/docs/datasheet/soc_sysinfo.adoc index fcdce0158..7340a3974 100644 --- a/docs/datasheet/soc_sysinfo.adoc +++ b/docs/datasheet/soc_sysinfo.adoc @@ -86,7 +86,7 @@ Bit fields in this register are set to all-zero if the according cache is not im | `26` | `SYSINFO_SOC_IO_NEOLED` | set if the NEOLED is implemented (via top's `IO_NEOLED_EN` generic) | `27` | `SYSINFO_SOC_IO_XIRQ` | set if the XIRQ is implemented (via top's `XIRQ_NUM_CH` generic) | `28` | `SYSINFO_SOC_IO_GPTMR` | set if the GPTMR is implemented (via top's `IO_GPTMR_EN` generic) -| `29` | `SYSINFO_SOC_IO_XIP` | set if the XIP module is implemented (via top's `IO_XIP_EN` generic) +| `29` | `SYSINFO_SOC_XIP` | set if the XIP module is implemented (via top's `XIP_EN` generic) | `30` | `SYSINFO_SOC_IO_ONEWIRE` | set if the ONEWIRE interface is implemented (via top's `IO_ONEWIRE_EN` generic) | `31` | `SYSINFO_SOC_OCD` | set if on-chip debugger is implemented (via top's `ON_CHIP_DEBUGGER_EN` generic) |======================= diff --git a/docs/datasheet/soc_xip.adoc b/docs/datasheet/soc_xip.adoc index 3b5e90b19..cc1e9d200 100644 --- a/docs/datasheet/soc_xip.adoc +++ b/docs/datasheet/soc_xip.adoc @@ -12,7 +12,10 @@ | | `xip_clk_o` | 1-bit serial clock output | | `xip_dat_i` | 1-bit serial data input | | `xip_dat_o` | 1-bit serial data output -| Configuration generics: | `IO_XIP_EN` | implement XIP module when `true` +| Configuration generics: | `XIP_EN` | implement XIP module when `true` +| | `XIP_CACHE_EN` | implement XIP cache when `true` +| | `XIP_CACHE_NUM_BLOCKS` | number of blocks in XIP cache; has to be a power of two +| | `XIP_CACHE_BLOCK_SIZE` | number of bytes per XIP cache block; has to be a power of two, min 4 | CPU interrupts: | none | |======================= @@ -22,17 +25,16 @@ The execute in-place (XIP) module allows to execute code (and read constant data) directly from an external SPI flash memory. The standard serial peripheral interface (SPI) is used as transfer protocol. -From the CPU side, the modules provides two different interfaces: one for transparently accessing the XIP flash and another +From the CPU side, the modules provides two independent interfaces: one for transparently accessing the XIP flash and another one for accessing the module's control and status registers. The first interface provides a _transparent_ gateway to the SPI flash, so the CPU can directly fetch and execute instructions (and/or read constant _data_). -Note that this interface is read-only. Any write access will raise a bus error exception. -The second interface is mapped to the processor's IO space and allows data accesses to the XIP module's -configuration registers. +Note that this interface is read-only. Any write access will raise a bus error exception. The second interface is +mapped to the processor's IO space and allows accesses to the XIP module's configuration registers. .XIP Address Mapping [NOTE] When XIP mode is enabled the flash is mapped to fixed address space region starting at address -`0xE0000000` (see section <<_address_space>>). +`0xE0000000` (see section <<_address_space>>) supporting a maximum flash size of 256MB. .XIP Example Program [TIP] @@ -44,13 +46,15 @@ an external SPI flash to run a program from it. The XIP module accesses external flash using the standard SPI protocol. The module always sends data MSB-first and provides all of the standard four clock modes (0..3), which are configured via the `XIP_CTRL_CPOL` (clock polarity) -and `XIP_CTRL_CPHA` (clock phase) control register bits, respectively. +and `XIP_CTRL_CPHA` (clock phase) control register bits, respectively. The flash's "read command", which initiates +a read access, is defined by the `XIP_CTRL_RD_CMD` control register bits. For most SPI flash memories this is `0x03` +for _normal_ SPI mode. -The SPI clock frequency (`xip_clk_o`) is programmed by the 3-bit `XIP_CTRL_PRSCx` clock prescaler for a coarse clock -selection and a 4-bit clock divider `XPI_CTRL_CDIVx` for a fine clock configuration. +The SPI clock (`xip_clk_o`) frequency is programmed by the 3-bit `XIP_CTRL_PRSCx` clock prescaler for a coarse clock +selection and a 4-bit clock divider `XPI_CTRL_CDIVx` for a fine clock selection. The following clock prescalers (`XIP_CTRL_PRSCx`) are available: -.XIP prescaler configuration +.XIP clock prescaler configuration [cols="<4,^1,^1,^1,^1,^1,^1,^1,^1"] [options="header",grid="rows"] |======================= @@ -78,16 +82,6 @@ _**f~SPI~**_ = _f~main~[Hz]_ / (2 * 1 * (1 + `XPI_CTRL_CDIVx`)) Hence, the maximum SPI clock when in high-speed mode is f~main~ / 2. -.High-Speed SPI mode -[TIP] -The module provides a "high-speed" SPI mode. In this mode the clock prescaler configuration (`XIP_CTRL_PRSCx`) is ignored -and the SPI clock operates at f~main~ / 2 (half of the processor's main clock). High speed SPI mode is enabled by setting -the control register's `XIP_CTRL_HIGHSPEED` bit. - -The flash's "read command", which initiates a read access, is defined by the `XIP_CTRL_RD_CMD` control register bits. -For most SPI flash memories this is `0x03` for normal SPI mode. - - **Direct SPI Access** The XIP module allows to initiate _direct_ SPI transactions. This feature can be used to configure the attached SPI @@ -167,16 +161,19 @@ It is highly recommended to enable the <<_processor_internal_instruction_cache_i of the SPI access latency. -**XIP Burst Mode** +**XIP Cache** + +Since every single instruction fetch request from the CPU is translated into serial SPI transmissions the access latency is +very high resulting in a low throughput. In order to improve performance, the XIP module provides an optional cache that +allows to buffer recently-accessed data. The cache is implemented as a simple direct-mapped read-only cache with a configurable +cache layout: -By default, every XIP access to the flash transmits the read command and the word-aligned address before reading four consecutive -data bytes. Obviously, this introduces a certain transmission overhead. To reduces this overhead, the XIP mode allows to utilize -the flash's _incrmental read_ function, which will return consecutive bytes when continuing to send clock cycles after a read command. -Hence, the XIP module provides an optional "burst mode" to accelerate consecutive read accesses. +* `XIP_CACHE_EN`: when set to `true` the CIP cache is implemented +* `XIP_CACHE_NUM_BLOCKS` defines the number of cache blocks (or lines) +* `XIP_CACHE_BLOCK_SIZE` defines the size in bytes of each cache block -The XIP burst mode is enabled by setting the `XIP_CTRL_BURST_EN` bit in the module's control register. The burst mode only affects -the actual XIP mode and _not_ the direct SPI mode. Hence, it should be enabled right before enabling XIP mode only. -By using the XIP burst mode flash read accesses can be accelerated by up to 50%. +When the cache is implemented, the XIP module operates in **burst mode** utilizing the flash's _incremental read_ capabilities. +Thus, several bytes (= `XIP_CACHE_BLOCK_SIZE`) are read consecutively from the flash using a single read command. **Register Map** @@ -195,12 +192,12 @@ By using the XIP burst mode flash read accesses can be accelerated by up to 50%. <|`12:11` `XIP_CTRL_XIP_ABYTES_MSB : XIP_CTRL_XIP_ABYTES_LSB` ^| r/w <| Number of address bytes for XIP flash (minus 1) <|`20:13` `XIP_CTRL_RD_CMD_MSB : XIP_CTRL_RD_CMD_LSB` ^| r/w <| Flash read command <|`21` `XIP_CTRL_SPI_CSEN` ^| r/w <| Allow SPI chip-select to be actually asserted when set - <|`22` `XIP_CTRL_HIGHSPEED` ^| r/w <| enable SPI high-speed mode (ignoring _XIP_CTRL_PRSC_) - <|`23` `XIP_CTRL_BURST_EN` ^| r/w <| Enable XIP burst mode - <|`24:27` `XIP_CTRL_CDIV3 : XIP_CTRL_CDIV0` ^| r/- <| 4-bit clock divider for fine-tuning - <|`29:28` - ^| r/- <| _reserved_, read as zero - <|`30` `XIP_CTRL_PHY_BUSY` ^| r/- <| SPI PHY busy when set - <|`31` `XIP_CTRL_XIP_BUSY` ^| r/- <| XIP access in progress when set + <|`22` `XIP_CTRL_HIGHSPEED` ^| r/w <| enable SPI high-speed mode (ignoring `XIP_CTRL_PRSCx`) + <|`23:26` `XIP_CTRL_CDIV3 : XIP_CTRL_CDIV0` ^| r/- <| 4-bit clock divider for fine-tuning + <|`27:28` - ^| r/- <| _reserved_, read as zero + <|`29` `XIP_CTRL_BURST_EN` ^| r/- <| XIP burst mode enabled (if XIP cache is implemented) + <|`30` `XIP_CTRL_PHY_BUSY` ^| r/- <| SPI PHY busy when set + <|`31` `XIP_CTRL_XIP_BUSY` ^| r/- <| XIP access in progress when set | `0xffffff44` | _reserved_ |`31:0` | r/- | _reserved_, read as zero | `0xffffff48` | `DATA_LO` |`31:0` | r/w | Direct SPI access - data register low | `0xffffff4C` | `DATA_HI` |`31:0` | -/w | Direct SPI access - data register high; write access triggers SPI transfer diff --git a/rtl/core/neorv32_bootloader_image.vhd b/rtl/core/neorv32_bootloader_image.vhd index f3dda334f..bee3945bb 100644 --- a/rtl/core/neorv32_bootloader_image.vhd +++ b/rtl/core/neorv32_bootloader_image.vhd @@ -1,8 +1,8 @@ -- The NEORV32 RISC-V Processor: https://github.com/stnolting/neorv32 -- Auto-generated memory initialization file (for BOOTLOADER) from source file --- Size: 4060 bytes +-- Size: 4044 bytes -- MARCH: default --- Built: 20.01.2024 22:54:06 +-- Built: 09.02.2024 13:58:53 -- prototype defined in 'neorv32_package.vhd' package body neorv32_bootloader_image is @@ -42,7 +42,7 @@ x"00000e93", x"00000f13", x"00000f93", x"00001597", -x"f5858593", +x"f4858593", x"80004617", x"f7460613", x"80004697", @@ -85,15 +85,15 @@ x"34141073", x"34002473", x"30200073", x"fc010113", -x"02912a23", -x"800004b7", -x"0004a223", +x"03212823", +x"80000937", +x"00092223", x"800007b7", x"0007a023", x"ffffd7b7", x"02112e23", x"02812c23", -x"03212823", +x"02912a23", x"03312623", x"03412423", x"03512223", @@ -103,7 +103,7 @@ x"01812c23", x"01912a23", x"01a12823", x"01b12623", -x"a0c78793", +x"9fc78793", x"30579073", x"e0802783", x"00d79713", @@ -113,7 +113,7 @@ x"10100793", x"80f02023", x"e0802783", x"00279713", -x"06075c63", +x"06075463", x"fffff7b7", x"f007a023", x"f007a423", @@ -132,10 +132,6 @@ x"002006b7", x"00d76733", x"00e7a023", x"0007a703", -x"008006b7", -x"00d76733", -x"00e7a023", -x"0007a703", x"ffffe6b7", x"43f68693", x"00d77733", @@ -186,61 +182,61 @@ x"30479073", x"00800793", x"3007a073", x"ffffd537", -x"d9c50513", +x"d8c50513", x"694000ef", x"f1302573", x"618000ef", x"ffffd537", -x"dd450513", +x"dc450513", x"680000ef", x"e0002503", x"604000ef", x"ffffd537", -x"ddc50513", +x"dcc50513", x"66c000ef", x"30102573", x"5f0000ef", x"ffffd537", -x"de450513", +x"dd450513", x"658000ef", x"fc002573", x"5dc000ef", x"ffffd537", -x"dec50513", +x"ddc50513", x"644000ef", x"e0802503", x"00100413", x"ffffd9b7", x"5c0000ef", x"ffffd537", -x"df450513", +x"de450513", x"628000ef", x"e0404503", x"00a41533", x"ffc57513", x"5a4000ef", x"ffffd537", -x"dfc50513", +x"dec50513", x"60c000ef", x"e0504783", x"00f41533", x"ffc57513", x"588000ef", -x"d9898513", +x"d8898513", x"5f4000ef", x"e0802783", x"00f79713", x"04075c63", x"ffffd537", -x"e0450513", +x"df450513", x"5dc000ef", x"2a8000ef", x"e0002403", x"fffffa37", x"500a0a13", x"00341413", -x"00a40933", -x"00893433", +x"00a404b3", +x"0084b433", x"00b40433", x"e0802783", x"00e79713", @@ -250,28 +246,28 @@ x"00f79713", x"0a075a63", x"ffffd537", x"004a2783", -x"e3050513", +x"e2050513", x"594000ef", x"ffffdab7", -x"e3ca8513", -x"fffff937", +x"e2ca8513", +x"fffff4b7", x"ffffda37", x"580000ef", -x"50090913", +x"50048493", x"03f00b93", x"01300c13", -x"f68a0a13", +x"f58a0a13", x"ffffd7b7", -x"ebc78513", +x"eac78513", x"564000ef", -x"00092783", +x"0004a783", x"00f79713", x"fe075ce3", -x"00492403", +x"0044a403", x"0ff47413", x"00040513", x"4b8000ef", -x"d9898513", +x"d8898513", x"540000ef", x"1f740a63", x"f9b40413", @@ -295,38 +291,38 @@ x"ff5ff06f", x"1c0000ef", x"f285eae3", x"00b41463", -x"f32566e3", +x"f29566e3", x"00100513", x"6fc000ef", -x"d9898513", +x"d8898513", x"4d4000ef", x"00000513", x"041000ef", x"ffffc2b7", x"00028067", -x"e3ca8513", +x"e2ca8513", x"4bc000ef", x"f4dff06f", x"00000513", x"6d0000ef", x"f41ff06f", -x"0044a403", +x"00492403", x"00041863", x"ffffd537", -x"ec450513", +x"eb450513", x"fddff06f", x"ffffd537", -x"ee050513", +x"ed050513", x"48c000ef", x"00040513", x"410000ef", x"ffffd537", -x"ee850513", +x"ed850513", x"478000ef", x"00400537", x"3fc000ef", x"ffffd537", -x"f0050513", +x"ef050513", x"464000ef", x"fffff7b7", x"50078793", @@ -344,7 +340,7 @@ x"00050663", x"00300513", x"480000ef", x"ffffd537", -x"f0c50513", +x"efc50513", x"41c000ef", x"01045b13", x"00400cb7", @@ -387,22 +383,22 @@ x"00850513", x"41a005b3", x"258000ef", x"ffffd537", -x"d8050513", +x"d7050513", x"eb5ff06f", x"00100513", x"eb9ff06f", -x"0044a783", +x"00492783", x"e80798e3", x"ffffd537", -x"f1c50513", +x"f0c50513", x"e99ff06f", x"00100513", x"e81ff06f", x"ffffd537", -x"f2c50513", +x"f1c50513", x"e85ff06f", x"ffffd537", -x"f5c50513", +x"f4c50513", x"e79ff06f", x"fffff7b7", x"40078793", @@ -592,7 +588,7 @@ x"07800513", x"ffffd4b7", x"fb9ff0ef", x"01c00413", -x"fb848493", +x"fa848493", x"ffc00993", x"008957b3", x"00f7f793", @@ -634,13 +630,13 @@ x"ff010113", x"00812423", x"00050413", x"ffffd537", -x"d3850513", +x"d2850513", x"00112623", x"f91ff0ef", x"00241793", x"ffffd537", x"008787b3", -x"fc850513", +x"fb850513", x"00f50533", x"f79ff0ef", x"00800793", @@ -726,7 +722,7 @@ x"e0802783", x"00e79713", x"04075263", x"ffffd537", -x"d4050513", +x"d3050513", x"e25ff0ef", x"00048513", x"da9ff0ef", @@ -739,7 +735,7 @@ x"d75ff0ef", x"34302573", x"d89ff0ef", x"ffffd537", -x"d9850513", +x"d8850513", x"df1ff0ef", x"00440413", x"34141073", @@ -760,7 +756,7 @@ x"00fb2023", x"00050413", x"02051863", x"ffffd537", -x"d4c50513", +x"d3c50513", x"d9dff0ef", x"004005b7", x"00040513", @@ -771,12 +767,12 @@ x"04f50663", x"00000513", x"0340006f", x"ffffd537", -x"d6c50513", +x"d5c50513", x"d71ff0ef", x"00400537", x"cf5ff0ef", x"ffffd537", -x"d7850513", +x"d6850513", x"d5dff0ef", x"e0802783", x"00d79713", @@ -807,7 +803,7 @@ x"014484b3", x"00200513", x"fa0492e3", x"ffffd537", -x"d8050513", +x"d7050513", x"ce1ff0ef", x"02c12083", x"02812403", @@ -838,12 +834,12 @@ x"00000413", x"00050463", x"e0400437", x"ffffd537", -x"d8450513", +x"d7450513", x"c65ff0ef", x"00040513", x"be9ff0ef", x"ffffd537", -x"d9450513", +x"d8450513", x"c51ff0ef", x"9a1ff0ef", x"00050663", @@ -887,9 +883,9 @@ x"6f6c746f", x"72656461", x"0a3e3e20", x"444c420a", -x"4a203a56", -x"32206e61", -x"30322030", +x"46203a56", +x"20206265", +x"30322039", x"480a3432", x"203a5657", x"00000020", @@ -994,26 +990,26 @@ x"00323376", x"61766e49", x"2064696c", x"00444d43", -x"ffffc5fc", -x"ffffc624", -x"ffffc624", -x"ffffc4a0", -x"ffffc624", -x"ffffc624", -x"ffffc624", -x"ffffc5f4", -x"ffffc624", -x"ffffc624", -x"ffffc624", -x"ffffc624", -x"ffffc624", -x"ffffc498", -x"ffffc4b8", -x"ffffc624", -x"ffffc4ac", -x"ffffc624", -x"ffffc624", -x"ffffc610", +x"ffffc5ec", +x"ffffc614", +x"ffffc614", +x"ffffc490", +x"ffffc614", +x"ffffc614", +x"ffffc614", +x"ffffc5e4", +x"ffffc614", +x"ffffc614", +x"ffffc614", +x"ffffc614", +x"ffffc614", +x"ffffc488", +x"ffffc4a8", +x"ffffc614", +x"ffffc49c", +x"ffffc614", +x"ffffc614", +x"ffffc600", x"33323130", x"37363534", x"62613938", diff --git a/rtl/core/neorv32_package.vhd b/rtl/core/neorv32_package.vhd index 1a2f219f9..fa1cca3fd 100644 --- a/rtl/core/neorv32_package.vhd +++ b/rtl/core/neorv32_package.vhd @@ -56,7 +56,7 @@ package neorv32_package is -- Architecture Constants ----------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- - constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01090405"; -- hardware version + constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01090406"; -- hardware version constant archid_c : natural := 19; -- official RISC-V architecture ID constant XLEN : natural := 32; -- native data path width @@ -750,60 +750,65 @@ package neorv32_package is generic ( -- General -- CLOCK_FREQUENCY : natural; - CLOCK_GATING_EN : boolean := false; + CLOCK_GATING_EN : boolean := false; HART_ID : std_ulogic_vector(31 downto 0) := x"00000000"; VENDOR_ID : std_ulogic_vector(31 downto 0) := x"00000000"; - INT_BOOTLOADER_EN : boolean := false; + INT_BOOTLOADER_EN : boolean := false; -- On-Chip Debugger (OCD) -- - ON_CHIP_DEBUGGER_EN : boolean := false; - DM_LEGACY_MODE : boolean := false; + ON_CHIP_DEBUGGER_EN : boolean := false; + DM_LEGACY_MODE : boolean := false; -- RISC-V CPU Extensions -- - CPU_EXTENSION_RISCV_A : boolean := false; - CPU_EXTENSION_RISCV_B : boolean := false; - CPU_EXTENSION_RISCV_C : boolean := false; - CPU_EXTENSION_RISCV_E : boolean := false; - CPU_EXTENSION_RISCV_M : boolean := false; - CPU_EXTENSION_RISCV_U : boolean := false; - CPU_EXTENSION_RISCV_Zfinx : boolean := false; - CPU_EXTENSION_RISCV_Zicntr : boolean := true; - CPU_EXTENSION_RISCV_Zicond : boolean := false; - CPU_EXTENSION_RISCV_Zihpm : boolean := false; - CPU_EXTENSION_RISCV_Zmmul : boolean := false; - CPU_EXTENSION_RISCV_Zxcfu : boolean := false; + CPU_EXTENSION_RISCV_A : boolean := false; + CPU_EXTENSION_RISCV_B : boolean := false; + CPU_EXTENSION_RISCV_C : boolean := false; + CPU_EXTENSION_RISCV_E : boolean := false; + CPU_EXTENSION_RISCV_M : boolean := false; + CPU_EXTENSION_RISCV_U : boolean := false; + CPU_EXTENSION_RISCV_Zfinx : boolean := false; + CPU_EXTENSION_RISCV_Zicntr : boolean := true; + CPU_EXTENSION_RISCV_Zicond : boolean := false; + CPU_EXTENSION_RISCV_Zihpm : boolean := false; + CPU_EXTENSION_RISCV_Zmmul : boolean := false; + CPU_EXTENSION_RISCV_Zxcfu : boolean := false; -- Tuning Options -- - FAST_MUL_EN : boolean := false; - FAST_SHIFT_EN : boolean := false; - REGFILE_HW_RST : boolean := false; + FAST_MUL_EN : boolean := false; + FAST_SHIFT_EN : boolean := false; + REGFILE_HW_RST : boolean := false; -- Physical Memory Protection (PMP) -- - PMP_NUM_REGIONS : natural range 0 to 16 := 0; - PMP_MIN_GRANULARITY : natural := 4; + PMP_NUM_REGIONS : natural range 0 to 16 := 0; + PMP_MIN_GRANULARITY : natural := 4; -- Hardware Performance Monitors (HPM) -- - HPM_NUM_CNTS : natural range 0 to 13 := 0; - HPM_CNT_WIDTH : natural range 0 to 64 := 40; + HPM_NUM_CNTS : natural range 0 to 13 := 0; + HPM_CNT_WIDTH : natural range 0 to 64 := 40; -- Atomic Memory Access - Reservation Set Granularity -- - AMO_RVS_GRANULARITY : natural := 4; + AMO_RVS_GRANULARITY : natural := 4; -- Internal Instruction memory (IMEM) -- - MEM_INT_IMEM_EN : boolean := false; - MEM_INT_IMEM_SIZE : natural := 16*1024; + MEM_INT_IMEM_EN : boolean := false; + MEM_INT_IMEM_SIZE : natural := 16*1024; -- Internal Data memory (DMEM) -- - MEM_INT_DMEM_EN : boolean := false; - MEM_INT_DMEM_SIZE : natural := 8*1024; + MEM_INT_DMEM_EN : boolean := false; + MEM_INT_DMEM_SIZE : natural := 8*1024; -- Internal Instruction Cache (iCACHE) -- - ICACHE_EN : boolean := false; - ICACHE_NUM_BLOCKS : natural range 1 to 256 := 4; - ICACHE_BLOCK_SIZE : natural range 4 to 2**16 := 64; - ICACHE_ASSOCIATIVITY : natural range 1 to 2 := 1; + ICACHE_EN : boolean := false; + ICACHE_NUM_BLOCKS : natural range 1 to 256 := 4; + ICACHE_BLOCK_SIZE : natural range 4 to 2**16 := 64; + ICACHE_ASSOCIATIVITY : natural range 1 to 2 := 1; -- Internal Data Cache (dCACHE) -- - DCACHE_EN : boolean := false; - DCACHE_NUM_BLOCKS : natural range 1 to 256 := 4; - DCACHE_BLOCK_SIZE : natural range 4 to 2**16 := 64; + DCACHE_EN : boolean := false; + DCACHE_NUM_BLOCKS : natural range 1 to 256 := 4; + DCACHE_BLOCK_SIZE : natural range 4 to 2**16 := 64; -- External memory interface (WISHBONE) -- - MEM_EXT_EN : boolean := false; - MEM_EXT_TIMEOUT : natural := 255; - MEM_EXT_PIPE_MODE : boolean := false; - MEM_EXT_BIG_ENDIAN : boolean := false; - MEM_EXT_ASYNC_RX : boolean := false; - MEM_EXT_ASYNC_TX : boolean := false; + MEM_EXT_EN : boolean := false; + MEM_EXT_TIMEOUT : natural := 255; + MEM_EXT_PIPE_MODE : boolean := false; + MEM_EXT_BIG_ENDIAN : boolean := false; + MEM_EXT_ASYNC_RX : boolean := false; + MEM_EXT_ASYNC_TX : boolean := false; + -- Execute in-place module (XIP) -- + XIP_EN : boolean := false; + XIP_CACHE_EN : boolean := false; + XIP_CACHE_NUM_BLOCKS : natural range 1 to 256 := 8; + XIP_CACHE_BLOCK_SIZE : natural range 1 to 2**16 := 256; -- External Interrupts Controller (XIRQ) -- XIRQ_NUM_CH : natural range 0 to 32 := 0; XIRQ_TRIGGER_TYPE : std_ulogic_vector(31 downto 0) := x"ffffffff"; @@ -833,7 +838,6 @@ package neorv32_package is IO_NEOLED_EN : boolean := false; IO_NEOLED_TX_FIFO : natural range 1 to 2**15 := 1; IO_GPTMR_EN : boolean := false; - IO_XIP_EN : boolean := false; IO_ONEWIRE_EN : boolean := false; IO_DMA_EN : boolean := false; IO_SLINK_EN : boolean := false; @@ -872,7 +876,7 @@ package neorv32_package is -- Advanced memory control signals -- fence_o : out std_ulogic; fencei_o : out std_ulogic; - -- XIP (execute in-place via SPI) signals (available if IO_XIP_EN = true) -- + -- XIP (execute in-place via SPI) signals (available if XIP_EN = true) -- xip_csn_o : out std_ulogic; xip_clk_o : out std_ulogic; xip_dat_i : in std_ulogic := 'L'; diff --git a/rtl/core/neorv32_sysinfo.vhd b/rtl/core/neorv32_sysinfo.vhd index a9d401f35..ce5ce881f 100644 --- a/rtl/core/neorv32_sysinfo.vhd +++ b/rtl/core/neorv32_sysinfo.vhd @@ -84,7 +84,7 @@ entity neorv32_sysinfo is IO_NEOLED_EN : boolean; -- implement NeoPixel-compatible smart LED interface (NEOLED)? IO_XIRQ_EN : boolean; -- implement external interrupts controller (XIRQ)? IO_GPTMR_EN : boolean; -- implement general purpose timer (GPTMR)? - IO_XIP_EN : boolean; -- implement execute in place module (XIP)? + XIP_EN : boolean; -- implement execute in place module (XIP)? IO_ONEWIRE_EN : boolean; -- implement 1-wire interface (ONEWIRE)? IO_DMA_EN : boolean; -- implement direct memory access controller (DMA)? IO_SLINK_EN : boolean; -- implement stream link interface (SLINK)? @@ -151,7 +151,7 @@ begin sysinfo(2)(26) <= '1' when IO_NEOLED_EN else '0'; -- NeoPixel-compatible smart LED interface (NEOLED) implemented? sysinfo(2)(27) <= '1' when IO_XIRQ_EN else '0'; -- external interrupt controller (XIRQ) implemented? sysinfo(2)(28) <= '1' when IO_GPTMR_EN else '0'; -- general purpose timer (GPTMR) implemented? - sysinfo(2)(29) <= '1' when IO_XIP_EN else '0'; -- execute in place module (XIP) implemented? + sysinfo(2)(29) <= '1' when XIP_EN else '0'; -- execute in place module (XIP) implemented? sysinfo(2)(30) <= '1' when IO_ONEWIRE_EN else '0'; -- 1-wire interface (ONEWIRE) implemented? sysinfo(2)(31) <= '1' when ON_CHIP_DEBUGGER_EN else '0'; -- on-chip debugger implemented? diff --git a/rtl/core/neorv32_top.vhd b/rtl/core/neorv32_top.vhd index c3e6b05e6..6e94b15ad 100644 --- a/rtl/core/neorv32_top.vhd +++ b/rtl/core/neorv32_top.vhd @@ -47,71 +47,77 @@ entity neorv32_top is generic ( -- General -- CLOCK_FREQUENCY : natural; -- clock frequency of clk_i in Hz - CLOCK_GATING_EN : boolean := false; -- enable clock gating when in sleep mode + CLOCK_GATING_EN : boolean := false; -- enable clock gating when in sleep mode HART_ID : std_ulogic_vector(31 downto 0) := x"00000000"; -- hardware thread ID VENDOR_ID : std_ulogic_vector(31 downto 0) := x"00000000"; -- vendor's JEDEC ID - INT_BOOTLOADER_EN : boolean := false; -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM + INT_BOOTLOADER_EN : boolean := false; -- boot configuration: true = boot explicit bootloader; false = boot from int/ext (I)MEM -- On-Chip Debugger (OCD) -- - ON_CHIP_DEBUGGER_EN : boolean := false; -- implement on-chip debugger - DM_LEGACY_MODE : boolean := false; -- debug module spec version: false = v1.0, true = v0.13 + ON_CHIP_DEBUGGER_EN : boolean := false; -- implement on-chip debugger + DM_LEGACY_MODE : boolean := false; -- debug module spec version: false = v1.0, true = v0.13 -- RISC-V CPU Extensions -- - CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic memory operations extension? - CPU_EXTENSION_RISCV_B : boolean := false; -- implement bit-manipulation extension? - CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension? - CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension? - CPU_EXTENSION_RISCV_M : boolean := false; -- implement mul/div extension? - CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension? - CPU_EXTENSION_RISCV_Zfinx : boolean := false; -- implement 32-bit floating-point extension (using INT regs!) - CPU_EXTENSION_RISCV_Zicntr : boolean := true; -- implement base counters? - CPU_EXTENSION_RISCV_Zicond : boolean := false; -- implement integer conditional operations? - CPU_EXTENSION_RISCV_Zihpm : boolean := false; -- implement hardware performance monitors? - CPU_EXTENSION_RISCV_Zmmul : boolean := false; -- implement multiply-only M sub-extension? - CPU_EXTENSION_RISCV_Zxcfu : boolean := false; -- implement custom (instr.) functions unit? + CPU_EXTENSION_RISCV_A : boolean := false; -- implement atomic memory operations extension? + CPU_EXTENSION_RISCV_B : boolean := false; -- implement bit-manipulation extension? + CPU_EXTENSION_RISCV_C : boolean := false; -- implement compressed extension? + CPU_EXTENSION_RISCV_E : boolean := false; -- implement embedded RF extension? + CPU_EXTENSION_RISCV_M : boolean := false; -- implement mul/div extension? + CPU_EXTENSION_RISCV_U : boolean := false; -- implement user mode extension? + CPU_EXTENSION_RISCV_Zfinx : boolean := false; -- implement 32-bit floating-point extension (using INT regs!) + CPU_EXTENSION_RISCV_Zicntr : boolean := true; -- implement base counters? + CPU_EXTENSION_RISCV_Zicond : boolean := false; -- implement integer conditional operations? + CPU_EXTENSION_RISCV_Zihpm : boolean := false; -- implement hardware performance monitors? + CPU_EXTENSION_RISCV_Zmmul : boolean := false; -- implement multiply-only M sub-extension? + CPU_EXTENSION_RISCV_Zxcfu : boolean := false; -- implement custom (instr.) functions unit? -- Tuning Options -- - FAST_MUL_EN : boolean := false; -- use DSPs for M extension's multiplier - FAST_SHIFT_EN : boolean := false; -- use barrel shifter for shift operations - REGFILE_HW_RST : boolean := false; -- implement full hardware reset for register file + FAST_MUL_EN : boolean := false; -- use DSPs for M extension's multiplier + FAST_SHIFT_EN : boolean := false; -- use barrel shifter for shift operations + REGFILE_HW_RST : boolean := false; -- implement full hardware reset for register file -- Physical Memory Protection (PMP) -- - PMP_NUM_REGIONS : natural range 0 to 16 := 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 + PMP_NUM_REGIONS : natural range 0 to 16 := 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 range 0 to 13 := 0; -- number of implemented HPM counters (0..13) - HPM_CNT_WIDTH : natural range 0 to 64 := 40; -- total size of HPM counters (0..64) + HPM_NUM_CNTS : natural range 0 to 13 := 0; -- number of implemented HPM counters (0..13) + HPM_CNT_WIDTH : natural range 0 to 64 := 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 + AMO_RVS_GRANULARITY : natural := 4; -- size in bytes, has to be a power of 2, min 4 -- Internal Instruction memory (IMEM) -- - MEM_INT_IMEM_EN : boolean := false; -- implement processor-internal instruction memory - MEM_INT_IMEM_SIZE : natural := 16*1024; -- size of processor-internal instruction memory in bytes (use a power of 2) + MEM_INT_IMEM_EN : boolean := false; -- implement processor-internal instruction memory + MEM_INT_IMEM_SIZE : natural := 16*1024; -- size of processor-internal instruction memory in bytes (use a power of 2) -- Internal Data memory (DMEM) -- - MEM_INT_DMEM_EN : boolean := false; -- implement processor-internal data memory - MEM_INT_DMEM_SIZE : natural := 8*1024; -- size of processor-internal data memory in bytes (use a power of 2) + MEM_INT_DMEM_EN : boolean := false; -- implement processor-internal data memory + MEM_INT_DMEM_SIZE : natural := 8*1024; -- size of processor-internal data memory in bytes (use a power of 2) -- Internal Instruction Cache (iCACHE) -- - ICACHE_EN : boolean := false; -- implement instruction cache - ICACHE_NUM_BLOCKS : natural range 1 to 256 := 4; -- i-cache: number of blocks (min 1), has to be a power of 2 - ICACHE_BLOCK_SIZE : natural range 4 to 2**16 := 64; -- i-cache: block size in bytes (min 4), has to be a power of 2 - ICACHE_ASSOCIATIVITY : natural range 1 to 2 := 1; -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2 + ICACHE_EN : boolean := false; -- implement instruction cache + ICACHE_NUM_BLOCKS : natural range 1 to 256 := 4; -- i-cache: number of blocks (min 1), has to be a power of 2 + ICACHE_BLOCK_SIZE : natural range 4 to 2**16 := 64; -- i-cache: block size in bytes (min 4), has to be a power of 2 + ICACHE_ASSOCIATIVITY : natural range 1 to 2 := 1; -- i-cache: associativity / number of sets (1=direct_mapped), has to be a power of 2 -- Internal Data Cache (dCACHE) -- - DCACHE_EN : boolean := false; -- implement data cache - DCACHE_NUM_BLOCKS : natural range 1 to 256 := 4; -- d-cache: number of blocks (min 1), has to be a power of 2 - DCACHE_BLOCK_SIZE : natural range 4 to 2**16 := 64; -- d-cache: block size in bytes (min 4), has to be a power of 2 + DCACHE_EN : boolean := false; -- implement data cache + DCACHE_NUM_BLOCKS : natural range 1 to 256 := 4; -- d-cache: number of blocks (min 1), has to be a power of 2 + DCACHE_BLOCK_SIZE : natural range 4 to 2**16 := 64; -- d-cache: block size in bytes (min 4), has to be a power of 2 -- External memory interface (WISHBONE) -- - MEM_EXT_EN : boolean := false; -- implement external memory bus interface? - MEM_EXT_TIMEOUT : natural := 255; -- cycles after a pending bus access auto-terminates (0 = disabled) - MEM_EXT_PIPE_MODE : boolean := false; -- protocol: false=classic/standard wishbone mode, true=pipelined wishbone mode - MEM_EXT_BIG_ENDIAN : boolean := false; -- byte order: true=big-endian, false=little-endian - MEM_EXT_ASYNC_RX : boolean := false; -- use register buffer for RX data when false - MEM_EXT_ASYNC_TX : boolean := false; -- use register buffer for TX data when false + MEM_EXT_EN : boolean := false; -- implement external memory bus interface? + MEM_EXT_TIMEOUT : natural := 255; -- cycles after a pending bus access auto-terminates (0 = disabled) + MEM_EXT_PIPE_MODE : boolean := false; -- protocol: false=classic/standard wishbone mode, true=pipelined wishbone mode + MEM_EXT_BIG_ENDIAN : boolean := false; -- byte order: true=big-endian, false=little-endian + MEM_EXT_ASYNC_RX : boolean := false; -- use register buffer for RX data when false + MEM_EXT_ASYNC_TX : boolean := false; -- use register buffer for TX data when false + + -- Execute in-place module (XIP) -- + XIP_EN : boolean := false; -- implement execute in place module (XIP)? + XIP_CACHE_EN : boolean := false; -- implement XIP cache? + XIP_CACHE_NUM_BLOCKS : natural range 1 to 256 := 8; -- number of blocks (min 1), has to be a power of 2 + XIP_CACHE_BLOCK_SIZE : natural range 1 to 2**16 := 256; -- block size in bytes (min 4), has to be a power of 2 -- External Interrupts Controller (XIRQ) -- XIRQ_NUM_CH : natural range 0 to 32 := 0; -- number of external IRQ channels (0..32) @@ -143,7 +149,6 @@ entity neorv32_top is IO_NEOLED_EN : boolean := false; -- implement NeoPixel-compatible smart LED interface (NEOLED)? IO_NEOLED_TX_FIFO : natural range 1 to 2**15 := 1; -- NEOLED FIFO depth, has to be a power of two, min 1 IO_GPTMR_EN : boolean := false; -- implement general purpose timer (GPTMR)? - IO_XIP_EN : boolean := false; -- implement execute in place module (XIP)? IO_ONEWIRE_EN : boolean := false; -- implement 1-wire interface (ONEWIRE)? IO_DMA_EN : boolean := false; -- implement direct memory access controller (DMA)? IO_SLINK_EN : boolean := false; -- implement stream link interface (SLINK)? @@ -187,7 +192,7 @@ entity neorv32_top is fence_o : out std_ulogic; -- indicates an executed FENCE operation fencei_o : out std_ulogic; -- indicates an executed FENCEI operation - -- XIP (execute in place via SPI) signals (available if IO_XIP_EN = true) -- + -- XIP (execute in place via SPI) signals (available if XIP_EN = true) -- xip_csn_o : out std_ulogic; -- chip-select, low-active xip_clk_o : out std_ulogic; -- serial clock xip_dat_i : in std_ulogic := 'L'; -- device data input @@ -380,7 +385,7 @@ begin cond_sel_string_f(IO_NEOLED_EN, "NEOLED ", "") & cond_sel_string_f(io_xirq_en_c, "XIRQ ", "") & cond_sel_string_f(IO_GPTMR_EN, "GPTMR ", "") & - cond_sel_string_f(IO_XIP_EN, "XIP ", "") & + cond_sel_string_f(XIP_EN, "XIP ", "") & cond_sel_string_f(IO_ONEWIRE_EN, "ONEWIRE ", "") & cond_sel_string_f(IO_DMA_EN, "DMA ", "") & cond_sel_string_f(IO_SLINK_EN, "SLINK ", "") & @@ -484,7 +489,7 @@ begin -- Clock Gating --------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_clockgate_inst_true: - if (CLOCK_GATING_EN = true) generate + if CLOCK_GATING_EN generate neorv32_clockgate_inst: entity neorv32.neorv32_clockgate port map ( clk_i => clk_i, @@ -495,7 +500,7 @@ begin end generate; neorv32_clockgate_inst_false: - if (CLOCK_GATING_EN = false) generate + if not CLOCK_GATING_EN generate clk_cpu <= clk_i; end generate; @@ -593,7 +598,7 @@ begin -- CPU Instruction Cache ------------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- neorv32_icache_inst_true: - if (ICACHE_EN = true) generate + if ICACHE_EN generate neorv32_icache_inst: entity neorv32.neorv32_icache generic map ( ICACHE_NUM_BLOCKS => ICACHE_NUM_BLOCKS, @@ -613,7 +618,7 @@ begin end generate; neorv32_icache_inst_false: - if (ICACHE_EN = false) generate + if not ICACHE_EN generate icache_req <= cpu_i_req; cpu_i_rsp <= icache_rsp; end generate; @@ -622,7 +627,7 @@ begin -- CPU Data Cache ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_dcache_inst_true: - if (DCACHE_EN = true) generate + if DCACHE_EN generate neorv32_dcache_inst: entity neorv32.neorv32_dcache generic map ( DCACHE_NUM_BLOCKS => DCACHE_NUM_BLOCKS, @@ -641,7 +646,7 @@ begin end generate; neorv32_dcache_inst_false: - if (DCACHE_EN = false) generate + if not DCACHE_EN generate dcache_req <= cpu_d_req; cpu_d_rsp <= dcache_rsp; end generate; @@ -672,7 +677,7 @@ begin -- Direct Memory Access Controller (DMA) Complex -- ************************************************************************************************************************** neorv32_dma_complex_true: - if (IO_DMA_EN = true) generate + if IO_DMA_EN generate -- DMA Controller ------------------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- @@ -710,7 +715,7 @@ begin end generate; -- /neorv32_dma_complex_true neorv32_dma_complex_false: - if (IO_DMA_EN = false) generate + if not IO_DMA_EN generate iodev_rsp(IODEV_DMA) <= rsp_terminate_c; main_req <= core_req; core_rsp <= main_rsp; @@ -722,7 +727,7 @@ begin -- Reservation Set Controller (for atomic LR/SC memory accesses) -- ************************************************************************************************************************** neorv32_bus_reservation_set_true: - if (CPU_EXTENSION_RISCV_A = true) generate + if CPU_EXTENSION_RISCV_A generate neorv32_bus_reservation_set_inst: entity neorv32.neorv32_bus_reservation_set generic map ( GRANULARITY => AMO_RVS_GRANULARITY @@ -741,7 +746,7 @@ begin end generate; neorv32_bus_reservation_set_false: - if (CPU_EXTENSION_RISCV_A = false) generate + if not CPU_EXTENSION_RISCV_A generate main2_req <= main_req; main_rsp <= main2_rsp; end generate; @@ -762,7 +767,7 @@ begin DMEM_BASE => mem_dmem_base_c, DMEM_SIZE => dmem_size_c, -- XIP port -- - XIP_ENABLE => IO_XIP_EN, + XIP_ENABLE => XIP_EN, XIP_BASE => mem_xip_base_c, XIP_SIZE => mem_xip_size_c, -- BOOT ROM port -- @@ -853,7 +858,7 @@ begin -- Processor-Internal Bootloader ROM (BOOTROM) -------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_boot_rom_inst_true: - if (INT_BOOTLOADER_EN = true) generate + if INT_BOOTLOADER_EN generate neorv32_boot_rom_inst: entity neorv32.neorv32_boot_rom port map ( clk_i => clk_i, @@ -864,7 +869,7 @@ begin end generate; neorv32_boot_rom_inst_false: - if (INT_BOOTLOADER_EN = false) generate + if not INT_BOOTLOADER_EN generate boot_rsp <= rsp_terminate_c; end generate; @@ -872,8 +877,13 @@ begin -- Execute In Place Module (XIP) ---------------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_xip_inst_true: - if (IO_XIP_EN = true) generate + if XIP_EN generate neorv32_xip_inst: entity neorv32.neorv32_xip + generic map ( + XIP_CACHE_EN => XIP_CACHE_EN, + XIP_CACHE_NUM_BLOCKS => XIP_CACHE_NUM_BLOCKS, + XIP_CACHE_BLOCK_SIZE => XIP_CACHE_BLOCK_SIZE + ) port map ( -- global control -- clk_i => clk_i, @@ -892,7 +902,7 @@ begin end generate; neorv32_xip_inst_false: - if (IO_XIP_EN = false) generate + if not XIP_EN generate iodev_rsp(IODEV_XIP) <= rsp_terminate_c; xip_rsp <= rsp_terminate_c; cg_en.xip <= '0'; @@ -905,7 +915,7 @@ begin -- External Wishbone Gateway (WISHBONE) --------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_wishbone_inst_true: - if (MEM_EXT_EN = true) generate + if MEM_EXT_EN generate neorv32_wishbone_inst: entity neorv32.neorv32_wishbone generic map ( BUS_TIMEOUT => MEM_EXT_TIMEOUT, @@ -934,7 +944,7 @@ begin end generate; neorv32_wishbone_inst_false: - if (MEM_EXT_EN = false) generate + if not MEM_EXT_EN generate xbus_rsp <= rsp_terminate_c; wb_adr_o <= (others => '0'); wb_dat_o <= (others => '0'); @@ -976,7 +986,7 @@ begin DEV_13_EN => IO_ONEWIRE_EN, DEV_13_BASE => base_io_onewire_c, DEV_14_EN => IO_GPTMR_EN, DEV_14_BASE => base_io_gptmr_c, DEV_15_EN => io_pwm_en_c, DEV_15_BASE => base_io_pwm_c, - DEV_16_EN => IO_XIP_EN, DEV_16_BASE => base_io_xip_c, + DEV_16_EN => XIP_EN, DEV_16_BASE => base_io_xip_c, DEV_17_EN => IO_CRC_EN, DEV_17_BASE => base_io_crc_c, DEV_18_EN => IO_DMA_EN, DEV_18_BASE => base_io_dma_c, DEV_19_EN => IO_SLINK_EN, DEV_19_BASE => base_io_slink_c, @@ -1014,7 +1024,7 @@ begin -- Custom Functions Subsystem (CFS) ------------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_cfs_inst_true: - if (IO_CFS_EN = true) generate + if IO_CFS_EN generate neorv32_cfs_inst: entity neorv32.neorv32_cfs generic map ( CFS_CONFIG => IO_CFS_CONFIG, @@ -1035,7 +1045,7 @@ begin end generate; neorv32_cfs_inst_false: - if (IO_CFS_EN = false) generate + if not IO_CFS_EN generate iodev_rsp(IODEV_CFS) <= rsp_terminate_c; cg_en.cfs <= '0'; firq.cfs <= '0'; @@ -1046,8 +1056,8 @@ begin -- Serial Data Interface (SDI) ------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- neorv32_sdi_inst_true: - if (IO_SDI_EN = true) generate - neorv32_SDI_inst: entity neorv32.neorv32_sdi + if IO_SDI_EN generate + neorv32_sdi_inst: entity neorv32.neorv32_sdi generic map ( RTX_FIFO => IO_SDI_FIFO ) @@ -1065,7 +1075,7 @@ begin end generate; neorv32_sdi_inst_false: - if (IO_SDI_EN = false) generate + if not IO_SDI_EN generate iodev_rsp(IODEV_SDI) <= rsp_terminate_c; sdi_dat_o <= '0'; firq.sdi <= '0'; @@ -1075,7 +1085,7 @@ begin -- General Purpose Input/Output Port (GPIO) ----------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_gpio_inst_true: - if (io_gpio_en_c = true) generate + if io_gpio_en_c generate neorv32_gpio_inst: entity neorv32.neorv32_gpio generic map ( GPIO_NUM => IO_GPIO_NUM @@ -1091,7 +1101,7 @@ begin end generate; neorv32_gpio_inst_false: - if (io_gpio_en_c = false) generate + if not io_gpio_en_c generate iodev_rsp(IODEV_GPIO) <= rsp_terminate_c; gpio_o <= (others => '0'); end generate; @@ -1100,7 +1110,7 @@ begin -- Watch Dog Timer (WDT) ------------------------------------------------------------------ -- ------------------------------------------------------------------------------------------- neorv32_wdt_inst_true: - if (IO_WDT_EN = true) generate + if IO_WDT_EN generate neorv32_wdt_inst: entity neorv32.neorv32_wdt port map ( clk_i => clk_i, @@ -1118,7 +1128,7 @@ begin end generate; neorv32_wdt_inst_false: - if (IO_WDT_EN = false) generate + if not IO_WDT_EN generate iodev_rsp(IODEV_WDT) <= rsp_terminate_c; firq.wdt <= '0'; rstn_wdt <= '1'; @@ -1129,7 +1139,7 @@ begin -- Machine System Timer (MTIME) ----------------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_mtime_inst_true: - if (IO_MTIME_EN = true) generate + if IO_MTIME_EN generate neorv32_mtime_inst: entity neorv32.neorv32_mtime port map ( clk_i => clk_i, @@ -1156,7 +1166,7 @@ begin end generate; neorv32_mtime_inst_false: - if (IO_MTIME_EN = false) generate + if not IO_MTIME_EN generate iodev_rsp(IODEV_MTIME) <= rsp_terminate_c; mtime_irq <= mtime_irq_i; mtime_time_o <= (others => '0'); @@ -1166,7 +1176,7 @@ begin -- Primary Universal Asynchronous Receiver/Transmitter (UART0) ---------------------------- -- ------------------------------------------------------------------------------------------- neorv32_uart0_inst_true: - if (IO_UART0_EN = true) generate + if IO_UART0_EN generate neorv32_uart0_inst: entity neorv32.neorv32_uart generic map ( SIM_LOG_FILE => "neorv32.uart0.sim_mode.text.out", @@ -1190,7 +1200,7 @@ begin end generate; neorv32_uart0_inst_false: - if (IO_UART0_EN = false) generate + if not IO_UART0_EN generate iodev_rsp(IODEV_UART0) <= rsp_terminate_c; uart0_txd_o <= '0'; uart0_rts_o <= '1'; @@ -1203,7 +1213,7 @@ begin -- Secondary Universal Asynchronous Receiver/Transmitter (UART1) -------------------------- -- ------------------------------------------------------------------------------------------- neorv32_uart1_inst_true: - if (IO_UART1_EN = true) generate + if IO_UART1_EN generate neorv32_uart1_inst: entity neorv32.neorv32_uart generic map ( SIM_LOG_FILE => "neorv32.uart1.sim_mode.text.out", @@ -1227,7 +1237,7 @@ begin end generate; neorv32_uart1_inst_false: - if (IO_UART1_EN = false) generate + if not IO_UART1_EN generate iodev_rsp(IODEV_UART1) <= rsp_terminate_c; uart1_txd_o <= '0'; uart1_rts_o <= '1'; @@ -1240,7 +1250,7 @@ begin -- Serial Peripheral Interface (SPI) ------------------------------------------------------ -- ------------------------------------------------------------------------------------------- neorv32_spi_inst_true: - if (IO_SPI_EN = true) generate + if IO_SPI_EN generate neorv32_spi_inst: entity neorv32.neorv32_spi generic map ( IO_SPI_FIFO => IO_SPI_FIFO @@ -1261,7 +1271,7 @@ begin end generate; neorv32_spi_inst_false: - if (IO_SPI_EN = false) generate + if not IO_SPI_EN generate iodev_rsp(IODEV_SPI) <= rsp_terminate_c; spi_clk_o <= '0'; spi_dat_o <= '0'; @@ -1274,7 +1284,7 @@ begin -- Two-Wire Interface (TWI) --------------------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_twi_inst_true: - if (IO_TWI_EN = true) generate + if IO_TWI_EN generate neorv32_twi_inst: entity neorv32.neorv32_twi port map ( clk_i => clk_i, @@ -1292,7 +1302,7 @@ begin end generate; neorv32_twi_inst_false: - if (IO_TWI_EN = false) generate + if not IO_TWI_EN generate iodev_rsp(IODEV_TWI) <= rsp_terminate_c; twi_sda_o <= '1'; twi_scl_o <= '1'; @@ -1304,7 +1314,7 @@ begin -- Pulse-Width Modulation Controller (PWM) ------------------------------------------------ -- ------------------------------------------------------------------------------------------- neorv32_pwm_inst_true: - if (io_pwm_en_c = true) generate + if io_pwm_en_c generate neorv32_pwm_inst: entity neorv32.neorv32_pwm generic map ( NUM_CHANNELS => IO_PWM_NUM_CH @@ -1321,7 +1331,7 @@ begin end generate; neorv32_pwm_inst_false: - if (io_pwm_en_c = false) generate + if not io_pwm_en_c generate iodev_rsp(IODEV_PWM) <= rsp_terminate_c; cg_en.pwm <= '0'; pwm_o <= (others => '0'); @@ -1331,7 +1341,7 @@ begin -- True Random Number Generator (TRNG) ---------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_trng_inst_true: - if (IO_TRNG_EN = true) generate + if IO_TRNG_EN generate neorv32_trng_inst: entity neorv32.neorv32_trng generic map ( IO_TRNG_FIFO => IO_TRNG_FIFO @@ -1346,7 +1356,7 @@ begin end generate; neorv32_trng_inst_false: - if (IO_TRNG_EN = false) generate + if not IO_TRNG_EN generate iodev_rsp(IODEV_TRNG) <= rsp_terminate_c; firq.trng <= '0'; end generate; @@ -1355,7 +1365,7 @@ begin -- Smart LED (WS2811/WS2812) Interface (NEOLED) ------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_neoled_inst_true: - if (IO_NEOLED_EN = true) generate + if IO_NEOLED_EN generate neorv32_neoled_inst: entity neorv32.neorv32_neoled generic map ( FIFO_DEPTH => IO_NEOLED_TX_FIFO @@ -1373,7 +1383,7 @@ begin end generate; neorv32_neoled_inst_false: - if (IO_NEOLED_EN = false) generate + if not IO_NEOLED_EN generate iodev_rsp(IODEV_NEOLED) <= rsp_terminate_c; cg_en.neoled <= '0'; firq.neoled <= '0'; @@ -1384,7 +1394,7 @@ begin -- External Interrupt Controller (XIRQ) --------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_xirq_inst_true: - if (io_xirq_en_c = true) generate + if io_xirq_en_c generate neorv32_xirq_inst: entity neorv32.neorv32_xirq generic map ( XIRQ_NUM_CH => XIRQ_NUM_CH, @@ -1403,7 +1413,7 @@ begin end generate; neorv32_xirq_inst_false: - if (io_xirq_en_c = false) generate + if not io_xirq_en_c generate iodev_rsp(IODEV_XIRQ) <= rsp_terminate_c; firq.xirq <= '0'; end generate; @@ -1412,7 +1422,7 @@ begin -- General Purpose Timer (GPTMR) ---------------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_gptmr_inst_true: - if (IO_GPTMR_EN = true) generate + if IO_GPTMR_EN generate neorv32_gptmr_inst: entity neorv32.neorv32_gptmr port map ( clk_i => clk_i, @@ -1427,7 +1437,7 @@ begin end generate; neorv32_gptmr_inst_false: - if (IO_GPTMR_EN = false) generate + if not IO_GPTMR_EN generate iodev_rsp(IODEV_GPTMR) <= rsp_terminate_c; cg_en.gptmr <= '0'; firq.gptmr <= '0'; @@ -1437,7 +1447,7 @@ begin -- 1-Wire Interface Controller (ONEWIRE) -------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_onewire_inst_true: - if (IO_ONEWIRE_EN = true) generate + if IO_ONEWIRE_EN generate neorv32_onewire_inst: entity neorv32.neorv32_onewire port map ( clk_i => clk_i, @@ -1453,7 +1463,7 @@ begin end generate; neorv32_onewire_inst_false: - if (IO_ONEWIRE_EN = false) generate + if not IO_ONEWIRE_EN generate iodev_rsp(IODEV_ONEWIRE) <= rsp_terminate_c; onewire_o <= '1'; cg_en.onewire <= '0'; @@ -1464,7 +1474,7 @@ begin -- Stream Link Interface (SLINK) ---------------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_slink_inst_true: - if (IO_SLINK_EN = true) generate + if IO_SLINK_EN generate neorv32_slink_inst: entity neorv32.neorv32_slink generic map ( SLINK_RX_FIFO => IO_SLINK_RX_FIFO, @@ -1489,7 +1499,7 @@ begin end generate; neorv32_slink_inst_false: - if (IO_SLINK_EN = false) generate + if not IO_SLINK_EN generate iodev_rsp(IODEV_SLINK) <= rsp_terminate_c; firq.slink <= '0'; slink_rx_rdy_o <= '0'; @@ -1501,7 +1511,7 @@ begin -- Cyclic Redundancy Check Unit (CRC) ----------------------------------------------------- -- ------------------------------------------------------------------------------------------- neorv32_crc_inst_true: - if (IO_CRC_EN = true) generate + if IO_CRC_EN generate neorv32_crc_inst: entity neorv32.neorv32_crc port map ( clk_i => clk_i, @@ -1512,7 +1522,7 @@ begin end generate; neorv32_crc_inst_false: - if (IO_CRC_EN = false) generate + if not IO_CRC_EN generate iodev_rsp(IODEV_CRC) <= rsp_terminate_c; end generate; @@ -1562,7 +1572,7 @@ begin IO_NEOLED_EN => IO_NEOLED_EN, IO_XIRQ_EN => io_xirq_en_c, IO_GPTMR_EN => IO_GPTMR_EN, - IO_XIP_EN => IO_XIP_EN, + XIP_EN => XIP_EN, IO_ONEWIRE_EN => IO_ONEWIRE_EN, IO_DMA_EN => IO_DMA_EN, IO_SLINK_EN => IO_SLINK_EN, @@ -1582,7 +1592,7 @@ begin -- On-Chip Debugger Complex -- ************************************************************************************************************************** neorv32_neorv32_ocd_inst_true: - if (ON_CHIP_DEBUGGER_EN = true) generate + if ON_CHIP_DEBUGGER_EN generate -- On-Chip Debugger - Debug Transport Module (DTM) ---------------------------------------- -- ------------------------------------------------------------------------------------------- @@ -1633,7 +1643,7 @@ begin end generate; neorv32_debug_ocd_inst_false: - if (ON_CHIP_DEBUGGER_EN = false) generate + if not ON_CHIP_DEBUGGER_EN generate iodev_rsp(IODEV_OCD) <= rsp_terminate_c; jtag_tdo_o <= jtag_tdi_i; -- JTAG feed-through dci_ndmrstn <= '1'; diff --git a/rtl/core/neorv32_xip.vhd b/rtl/core/neorv32_xip.vhd index f3da66be0..ca167d3de 100644 --- a/rtl/core/neorv32_xip.vhd +++ b/rtl/core/neorv32_xip.vhd @@ -1,5 +1,5 @@ -- ################################################################################################# --- # << NEORV32 - Execute In Place (XIP) Module >> # +-- # << NEORV32 - Execute In-Place (XIP) Module >> # -- # ********************************************************************************************* # -- # This module allows the CPU to execute code (and read constant data) directly from an SPI # -- # flash memory. Two host ports are implemented: one for accessing the control and status # @@ -45,6 +45,11 @@ library neorv32; use neorv32.neorv32_package.all; entity neorv32_xip is + generic ( + XIP_CACHE_EN : boolean; -- implement XIP cache? + XIP_CACHE_NUM_BLOCKS : natural range 1 to 256; -- number of blocks (min 1), has to be a power of 2 + XIP_CACHE_BLOCK_SIZE : natural range 1 to 2**16 -- block size in bytes (min 4), has to be a power of 2 + ); port ( clk_i : in std_ulogic; -- global clock line rstn_i : in std_ulogic; -- global reset line, low-active @@ -79,16 +84,16 @@ architecture neorv32_xip_rtl of neorv32_xip is constant ctrl_rd_cmd7_c : natural := 20; -- r/w: SPI flash read command - bit 7 constant ctrl_spi_csen_c : natural := 21; -- r/w: SPI chip-select enabled constant ctrl_highspeed_c : natural := 22; -- r/w: SPI high-speed mode enable (ignoring ctrl_spi_prsc) - constant ctrl_burst_en_c : natural := 23; -- r/w: XIP burst mode enable - constant ctrl_cdiv0_c : natural := 24; -- r/w: clock divider bit 0 - constant ctrl_cdiv1_c : natural := 25; -- r/w: clock divider bit 1 - constant ctrl_cdiv2_c : natural := 26; -- r/w: clock divider bit 2 - constant ctrl_cdiv3_c : natural := 27; -- r/w: clock divider bit 3 + constant ctrl_cdiv0_c : natural := 23; -- r/w: clock divider bit 0 + constant ctrl_cdiv1_c : natural := 24; -- r/w: clock divider bit 1 + constant ctrl_cdiv2_c : natural := 25; -- r/w: clock divider bit 2 + constant ctrl_cdiv3_c : natural := 26; -- r/w: clock divider bit 3 -- + constant ctrl_burst_en_c : natural := 29; -- r/-: XIP burst mode enable (when cache is implemented) constant ctrl_phy_busy_c : natural := 30; -- r/-: SPI PHY is busy when set constant ctrl_xip_busy_c : natural := 31; -- r/-: XIP access in progress -- - signal ctrl : std_ulogic_vector(27 downto 0); + signal ctrl : std_ulogic_vector(26 downto 0); -- Direct SPI access registers -- signal spi_data_lo : std_ulogic_vector(31 downto 0); @@ -107,39 +112,61 @@ architecture neorv32_xip_rtl of neorv32_xip is addr_lookahead : std_ulogic_vector(31 downto 0); xip_acc_err : std_ulogic; busy : std_ulogic; - tmo_cnt : std_ulogic_vector(4 downto 0); -- timeout counter for auto CS de-assert (burst mode only) + tmo_cnt : std_ulogic_vector(2 downto 0); -- timeout counter for auto CS de-assert (burst mode only) end record; signal arbiter : arbiter_t; + -- cache access -- + signal cache_clear : std_ulogic; + signal xip_req : bus_req_t; + signal xip_rsp : bus_rsp_t; + -- Clock generator -- signal cdiv_cnt : std_ulogic_vector(3 downto 0); signal spi_clk_en : std_ulogic; + -- Component: XIP cache -- + component neorv32_xip_cache + generic ( + CACHE_NUM_BLOCKS : natural range 1 to 256; -- number of blocks (min 1), has to be a power of 2 + CACHE_BLOCK_SIZE : natural range 1 to 2**16 -- block size in bytes (min 4), has to be a power of 2 + ); + port ( + clk_i : in std_ulogic; -- global clock, rising edge + rstn_i : in std_ulogic; -- global reset, low-active, async + clear_i : in std_ulogic; -- cache clear + cpu_req_i : in bus_req_t; -- request bus + cpu_rsp_o : out bus_rsp_t; -- response bus + bus_req_o : out bus_req_t; -- request bus + bus_rsp_i : in bus_rsp_t -- response bus + ); + end component; + -- Component: SPI PHY -- component neorv32_xip_phy - port ( - -- global control -- - rstn_i : in std_ulogic; -- reset, async, low-active - clk_i : in std_ulogic; -- clock - spi_clk_en_i : in std_ulogic; -- pre-scaled SPI clock-enable - -- operation configuration -- - cf_enable_i : in std_ulogic; -- module enable (reset if low) - cf_cpha_i : in std_ulogic; -- clock phase - cf_cpol_i : in std_ulogic; -- clock idle polarity - -- operation control -- - op_start_i : in std_ulogic; -- trigger new transmission - op_final_i : in std_ulogic; -- end current transmission - op_csen_i : in std_ulogic; -- actually enabled device for transmission - op_busy_o : out std_ulogic; -- transmission in progress when set - op_nbytes_i : in std_ulogic_vector(3 downto 0); -- actual number of bytes to transmit (1..9) - op_wdata_i : in std_ulogic_vector(71 downto 0); -- write data - op_rdata_o : out std_ulogic_vector(31 downto 0); -- read data - -- SPI interface -- - spi_csn_o : out std_ulogic; - spi_clk_o : out std_ulogic; - spi_dat_i : in std_ulogic; - spi_dat_o : out std_ulogic - ); + port ( + -- global control -- + rstn_i : in std_ulogic; -- reset, async, low-active + clk_i : in std_ulogic; -- clock + spi_clk_en_i : in std_ulogic; -- pre-scaled SPI clock-enable + -- operation configuration -- + cf_enable_i : in std_ulogic; -- module enable (reset if low) + cf_cpha_i : in std_ulogic; -- clock phase + cf_cpol_i : in std_ulogic; -- clock idle polarity + -- operation control -- + op_start_i : in std_ulogic; -- trigger new transmission + op_final_i : in std_ulogic; -- end current transmission + op_csen_i : in std_ulogic; -- actually enabled device for transmission + op_busy_o : out std_ulogic; -- transmission in progress when set + op_nbytes_i : in std_ulogic_vector(3 downto 0); -- actual number of bytes to transmit (1..9) + op_wdata_i : in std_ulogic_vector(71 downto 0); -- write data + op_rdata_o : out std_ulogic_vector(31 downto 0); -- read data + -- SPI interface -- + spi_csn_o : out std_ulogic; + spi_clk_o : out std_ulogic; + spi_dat_i : in std_ulogic; + spi_dat_o : out std_ulogic + ); end component; -- SPI PHY interface -- @@ -191,7 +218,6 @@ begin ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c) <= bus_req_i.data(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c); ctrl(ctrl_spi_csen_c) <= bus_req_i.data(ctrl_spi_csen_c); ctrl(ctrl_highspeed_c) <= bus_req_i.data(ctrl_highspeed_c); - ctrl(ctrl_burst_en_c) <= bus_req_i.data(ctrl_burst_en_c); ctrl(ctrl_cdiv3_c downto ctrl_cdiv0_c) <= bus_req_i.data(ctrl_cdiv3_c downto ctrl_cdiv0_c); end if; -- SPI direct data access register lo -- @@ -218,9 +244,9 @@ begin bus_rsp_o.data(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c) <= ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c); bus_rsp_o.data(ctrl_spi_csen_c) <= ctrl(ctrl_spi_csen_c); bus_rsp_o.data(ctrl_highspeed_c) <= ctrl(ctrl_highspeed_c); - bus_rsp_o.data(ctrl_burst_en_c) <= ctrl(ctrl_burst_en_c); bus_rsp_o.data(ctrl_cdiv3_c downto ctrl_cdiv0_c) <= ctrl(ctrl_cdiv3_c downto ctrl_cdiv0_c); -- + bus_rsp_o.data(ctrl_burst_en_c) <= bool_to_ulogic_f(XIP_CACHE_EN); bus_rsp_o.data(ctrl_phy_busy_c) <= phy_if.busy; bus_rsp_o.data(ctrl_xip_busy_c) <= arbiter.busy; when "10" => -- 'xip_data_lo_addr_c' - SPI direct data access register lo @@ -235,6 +261,35 @@ begin end process ctrl_bus_access; + -- XIP Cache ------------------------------------------------------------------------------ + -- ------------------------------------------------------------------------------------------- + neorv32_xip_cache_inst_true: + if XIP_CACHE_EN generate + neorv32_xip_cache_inst: neorv32_xip_cache + generic map ( + CACHE_NUM_BLOCKS => XIP_CACHE_NUM_BLOCKS, + CACHE_BLOCK_SIZE => XIP_CACHE_BLOCK_SIZE + ) + port map ( + clk_i => clk_i, + rstn_i => rstn_i, + clear_i => cache_clear, + cpu_req_i => xip_req_i, + cpu_rsp_o => xip_rsp_o, + bus_req_o => xip_req, + bus_rsp_i => xip_rsp + ); + -- clear cache when entire module or XIP-mode is disabled -- + cache_clear <= '1' when (ctrl(ctrl_enable_c) = '0') or (ctrl(ctrl_xip_enable_c) = '0') else '0'; + end generate; + + neorv32_xip_cache_inst_false: + if not XIP_CACHE_EN generate + xip_req <= xip_req_i; + xip_rsp_o <= xip_rsp; + end generate; + + -- XIP Address Computation Logic ---------------------------------------------------------- -- ------------------------------------------------------------------------------------------- xip_access_logic: process(arbiter.addr, ctrl) @@ -270,13 +325,13 @@ begin arbiter.state <= arbiter.state_nxt; end if; -- address look-ahead -- - if (xip_req_i.stb = '1') and (xip_req_i.rw = '0') then - arbiter.addr <= xip_req_i.addr; -- buffer address (reducing fan-out on CPU's address net) + if (xip_req.stb = '1') and (xip_req.rw = '0') then + arbiter.addr <= xip_req.addr; -- buffer address (reducing fan-out on CPU's address net) end if; arbiter.addr_lookahead <= std_ulogic_vector(unsigned(arbiter.addr) + 4); -- prefetch address of *next* linear access -- XIP access error? -- if (arbiter.state = S_DIRECT) then - arbiter.xip_acc_err <= xip_req_i.stb; + arbiter.xip_acc_err <= xip_req.stb; else arbiter.xip_acc_err <= '0'; end if; @@ -291,19 +346,19 @@ begin -- FSM - combinatorial part -- - arbiter_comb: process(arbiter, ctrl, xip_addr, phy_if, xip_req_i, spi_data_hi, spi_data_lo, spi_trigger) + arbiter_comb: process(arbiter, ctrl, xip_addr, phy_if, xip_req, spi_data_hi, spi_data_lo, spi_trigger) begin -- arbiter defaults -- arbiter.state_nxt <= arbiter.state; -- bus interface defaults -- - xip_rsp_o.data <= (others => '0'); - xip_rsp_o.ack <= '0'; - xip_rsp_o.err <= arbiter.xip_acc_err; + xip_rsp.data <= (others => '0'); + xip_rsp.ack <= '0'; + xip_rsp.err <= arbiter.xip_acc_err; -- SPI PHY interface defaults -- phy_if.start <= '0'; - phy_if.final <= arbiter.tmo_cnt(arbiter.tmo_cnt'left) or (not ctrl(ctrl_burst_en_c)); -- terminate if timeout or if burst mode not enabled + phy_if.final <= arbiter.tmo_cnt(arbiter.tmo_cnt'left) or (not bool_to_ulogic_f(XIP_CACHE_EN)); -- terminate if timeout or if burst mode not enabled phy_if.wdata <= ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c) & xip_addr & x"00000000"; -- MSB-aligned: CMD + address + 32-bit zero data -- fsm -- @@ -318,8 +373,8 @@ begin when S_IDLE => -- wait for new bus request -- ------------------------------------------------------------ - if (xip_req_i.stb = '1') then - if (xip_req_i.rw = '0') then + if (xip_req.stb = '1') then + if (xip_req.rw = '0') then arbiter.state_nxt <= S_CHECK; else arbiter.state_nxt <= S_ERROR; @@ -328,7 +383,7 @@ begin when S_CHECK => -- check if we can resume flash access -- ------------------------------------------------------------ - if (arbiter.addr(27 downto 2) = arbiter.addr_lookahead(27 downto 2)) and (ctrl(ctrl_burst_en_c) = '1') and -- access to *next linear* address + if (arbiter.addr(27 downto 2) = arbiter.addr_lookahead(27 downto 2)) and XIP_CACHE_EN and -- access to *next linear* address (arbiter.tmo_cnt(arbiter.tmo_cnt'left) = '0') then -- no "pending access" timeout yet phy_if.start <= '1'; -- resume flash access arbiter.state_nxt <= S_BUSY; @@ -344,15 +399,15 @@ begin when S_BUSY => -- wait for PHY to complete operation -- ------------------------------------------------------------ - xip_rsp_o.data <= bswap32_f(phy_if.rdata); -- convert incrementing byte-read to little-endian + xip_rsp.data <= bswap32_f(phy_if.rdata); -- convert incrementing byte-read to little-endian if (phy_if.busy = '0') then - xip_rsp_o.ack <= '1'; + xip_rsp.ack <= '1'; arbiter.state_nxt <= S_IDLE; end if; when S_ERROR => -- access error -- ------------------------------------------------------------ - xip_rsp_o.err <= '1'; + xip_rsp.err <= '1'; arbiter.state_nxt <= S_IDLE; when others => -- undefined @@ -433,7 +488,8 @@ end neorv32_xip_rtl; -- # ********************************************************************************************* # -- # BSD 3-Clause License # -- # # --- # Copyright (c) 2023, Stephan Nolting. All rights reserved. # +-- # The NEORV32 RISC-V Processor, https://github.com/stnolting/neorv32 # +-- # Copyright (c) 2024, 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: # @@ -458,8 +514,6 @@ end neorv32_xip_rtl; -- # 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 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # -- ################################################################################################# library ieee; @@ -619,3 +673,276 @@ begin end neorv32_xip_phy_rtl; + + +-- ############################################################################################################################ +-- ############################################################################################################################ + + +-- ################################################################################################# +-- # << NEORV32 - XIP Cache >> # +-- # ********************************************************************************************* # +-- # Simple directed-mapped read-only cache to accelerate XIP (SPI) flash accesses. # +-- # ********************************************************************************************* # +-- # BSD 3-Clause License # +-- # # +-- # The NEORV32 RISC-V Processor, https://github.com/stnolting/neorv32 # +-- # Copyright (c) 2024, 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. # +-- ################################################################################################# + +library ieee; +use ieee.std_logic_1164.all; +use ieee.numeric_std.all; + +library neorv32; +use neorv32.neorv32_package.all; + +entity neorv32_xip_cache is + generic ( + CACHE_NUM_BLOCKS : natural range 1 to 256; -- number of blocks (min 1), has to be a power of 2 + CACHE_BLOCK_SIZE : natural range 1 to 2**16 -- block size in bytes (min 4), has to be a power of 2 + ); + port ( + clk_i : in std_ulogic; -- global clock, rising edge + rstn_i : in std_ulogic; -- global reset, low-active, async + clear_i : in std_ulogic; -- cache clear + cpu_req_i : in bus_req_t; -- request bus + cpu_rsp_o : out bus_rsp_t; -- response bus + bus_req_o : out bus_req_t; -- request bus + bus_rsp_i : in bus_rsp_t -- response bus + ); +end neorv32_xip_cache; + +architecture neorv32_xip_cache_rtl of neorv32_xip_cache is + + -- auto configuration -- + constant block_num_c : natural := cond_sel_natural_f(is_power_of_two_f(CACHE_NUM_BLOCKS), CACHE_NUM_BLOCKS, 2**index_size_f(CACHE_NUM_BLOCKS)); + constant block_size_c : natural := cond_sel_natural_f(is_power_of_two_f(CACHE_BLOCK_SIZE), CACHE_BLOCK_SIZE, 2**index_size_f(CACHE_BLOCK_SIZE)); + constant offset_size_c : natural := index_size_f(block_size_c/4); -- offset addresses full 32-bit words + + -- cache layout -- + constant index_size_c : natural := index_size_f(block_num_c); + constant tag_size_c : natural := 32 - (offset_size_c + index_size_c + 2); -- 2 additional bits for byte offset + constant entries_c : natural := block_num_c * (block_size_c/4); -- number of 32-bit entries (per set) + + -- cache interface -- + type cache_if_t is record + host_rdata : std_ulogic_vector(31 downto 0); -- cpu read data + host_rderr : std_ulogic; -- cpu read error + hit : std_ulogic; -- hit access + ctrl_en : std_ulogic; -- control access enable + ctrl_we : std_ulogic; -- control write enable + end record; + signal cache : cache_if_t; + + -- control engine -- + type ctrl_engine_state_t is (S_IDLE, S_CHECK, S_DOWNLOAD_REQ, S_DOWNLOAD_GET, S_RESYNC, S_ERROR); + signal state, state_nxt : ctrl_engine_state_t; -- FSM state + signal addr_reg, addr_reg_nxt : std_ulogic_vector(31 downto 0); -- address register for block download + + -- cache memory -- + type tag_mem_t is array (0 to block_num_c-1) of std_ulogic_vector(tag_size_c-1 downto 0); + type data_mem_t is array (0 to entries_c-1) of std_ulogic_vector(31+1 downto 0); -- data word + ERR status + signal tag_mem : tag_mem_t; + signal data_mem : data_mem_t; + signal tag_rd : std_ulogic_vector(tag_size_c-1 downto 0); -- tag read data + signal data_rd : std_ulogic_vector(31+1 downto 0); -- data word + ERR status + signal valid_mem : std_ulogic_vector(block_num_c-1 downto 0); + signal valid_rd : std_ulogic; -- valid flag read data + + -- access address decomposition -- + type acc_addr_t is record + tag : std_ulogic_vector(tag_size_c-1 downto 0); + index : std_ulogic_vector(index_size_c-1 downto 0); + offset : std_ulogic_vector(offset_size_c-1 downto 0); + end record; + signal host_acc, ctrl_acc : acc_addr_t; + + -- cache data memory access -- + signal cache_index : std_ulogic_vector(index_size_c-1 downto 0); + signal cache_offset : std_ulogic_vector(offset_size_c-1 downto 0); + signal cache_addr : std_ulogic_vector((index_size_c+offset_size_c)-1 downto 0); -- index & offset + +begin + + -- Control Engine FSM Sync ---------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + ctrl_engine_fsm_sync: process(rstn_i, clk_i) + begin + if (rstn_i = '0') then + state <= S_IDLE; + addr_reg <= (others => '0'); + elsif rising_edge(clk_i) then + state <= state_nxt; + addr_reg <= addr_reg_nxt; + end if; + end process ctrl_engine_fsm_sync; + + + -- Control Engine FSM Comb ---------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + ctrl_engine_fsm_comb: process(state, addr_reg, cache, clear_i, cpu_req_i, bus_rsp_i) + begin + -- control defaults -- + state_nxt <= state; + addr_reg_nxt <= addr_reg; + + -- cache defaults -- + cache.ctrl_en <= '0'; + cache.ctrl_we <= '0'; + + -- host response defaults -- + cpu_rsp_o.ack <= '0'; + cpu_rsp_o.err <= '0'; + cpu_rsp_o.data <= (others => '0'); + + -- bus interface defaults -- + bus_req_o.data <= (others => '0'); + bus_req_o.ben <= (others => '0'); + bus_req_o.src <= cpu_req_i.src; + bus_req_o.priv <= cpu_req_i.priv; + bus_req_o.addr <= addr_reg; + bus_req_o.rw <= '0'; -- read-only + bus_req_o.stb <= '0'; + bus_req_o.rvso <= cpu_req_i.rvso; + + -- fsm -- + case state is + + when S_IDLE => -- wait for host access request or cache control operation + -- ------------------------------------------------------------ + if (cpu_req_i.stb = '1') then + if (cpu_req_i.rw = '1') or (clear_i = '1') then -- write access or cache being cleared + state_nxt <= S_ERROR; + else -- actual cache access + state_nxt <= S_CHECK; + end if; + end if; + + when S_CHECK => -- finalize host access if cache hit + -- ------------------------------------------------------------ + -- calculate block base address in case we need to download it -- + addr_reg_nxt <= cpu_req_i.addr; + addr_reg_nxt((offset_size_c+2)-1 downto 0) <= (others => '0'); -- block-aligned + -- + cpu_rsp_o.data <= cache.host_rdata; -- output read data in case we have a hit + if (cache.hit = '1') then -- cache HIT + cpu_rsp_o.err <= cache.host_rderr; + cpu_rsp_o.ack <= not cache.host_rderr; + state_nxt <= S_IDLE; + else -- cache MISS + state_nxt <= S_DOWNLOAD_REQ; + end if; + + when S_DOWNLOAD_REQ => -- download new cache block: request new word + -- ------------------------------------------------------------ + bus_req_o.stb <= '1'; -- request new read transfer + state_nxt <= S_DOWNLOAD_GET; + + when S_DOWNLOAD_GET => -- download new cache block: wait for bus response + -- ------------------------------------------------------------ + cache.ctrl_en <= '1'; -- cache update operation + if (bus_rsp_i.ack = '1') or (bus_rsp_i.err = '1') then -- ACK or ERROR = write to cache and get next word (store ERROR flag in cache) + cache.ctrl_we <= '1'; -- write to cache + if (and_reduce_f(addr_reg((offset_size_c+2)-1 downto 2)) = '1') then -- block complete? + state_nxt <= S_RESYNC; + else -- get next word + addr_reg_nxt <= std_ulogic_vector(unsigned(addr_reg) + 4); + state_nxt <= S_DOWNLOAD_REQ; + end if; + end if; + + when S_RESYNC => -- re-sync host/cache access: cache read-latency dummy cycle + -- ------------------------------------------------------------ + state_nxt <= S_CHECK; + + when others => -- S_ERROR: error + -- ------------------------------------------------------------ + cpu_rsp_o.err <= '1'; + state_nxt <= S_IDLE; + + end case; + end process ctrl_engine_fsm_comb; + + + -- Access Address Decomposition ----------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + host_acc.tag <= cpu_req_i.addr(31 downto 31-(tag_size_c-1)); + host_acc.index <= cpu_req_i.addr(31-tag_size_c downto 2+offset_size_c); + host_acc.offset <= cpu_req_i.addr(2+(offset_size_c-1) downto 2); -- discard byte offset + + ctrl_acc.tag <= addr_reg(31 downto 31-(tag_size_c-1)); + ctrl_acc.index <= addr_reg(31-tag_size_c downto 2+offset_size_c); + ctrl_acc.offset <= addr_reg(2+(offset_size_c-1) downto 2); -- discard byte offset + + + -- Status Flag Memory --------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + status_memory: process(rstn_i, clk_i) -- single-port RAM + begin + if (rstn_i = '0') then + valid_mem <= (others => '0'); + valid_rd <= '0'; + elsif rising_edge(clk_i) then + if (clear_i = '1') then -- invalidate cache + valid_mem <= (others => '0'); + elsif (cache.ctrl_we = '1') then -- make current block valid + valid_mem(to_integer(unsigned(cache_index))) <= '1'; + end if; + valid_rd <= valid_mem(to_integer(unsigned(cache_index))); + end if; + end process status_memory; + + + -- Cache Data Memory ---------------------------------------------------------------------- + -- ------------------------------------------------------------------------------------------- + cache_memory: process(clk_i) -- single-port RAM + begin + if rising_edge(clk_i) then -- no reset to allow mapping to blockRAM + if (cache.ctrl_we = '1') then -- update cache block + data_mem(to_integer(unsigned(cache_addr))) <= bus_rsp_i.err & bus_rsp_i.data; + tag_mem(to_integer(unsigned(cache_index))) <= ctrl_acc.tag; + end if; + data_rd <= data_mem(to_integer(unsigned(cache_addr))); + tag_rd <= tag_mem(to_integer(unsigned(cache_index))); + end if; + end process cache_memory; + + -- cache access select -- + cache_index <= host_acc.index when (cache.ctrl_en = '0') else ctrl_acc.index; + cache_offset <= host_acc.offset when (cache.ctrl_en = '0') else ctrl_acc.offset; + cache_addr <= cache_index & cache_offset; -- resulting ram access address + + -- hit = tag match and valid entry -- + cache.hit <= '1' when (host_acc.tag = tag_rd) and (valid_rd = '1') else '0'; + + -- data output -- + cache.host_rdata <= data_rd(31 downto 0); + cache.host_rderr <= data_rd(32); + + +end neorv32_xip_cache_rtl; diff --git a/rtl/system_integration/neorv32_SystemTop_AvalonMM.vhd b/rtl/system_integration/neorv32_SystemTop_AvalonMM.vhd index f26ccdd58..f902939ea 100644 --- a/rtl/system_integration/neorv32_SystemTop_AvalonMM.vhd +++ b/rtl/system_integration/neorv32_SystemTop_AvalonMM.vhd @@ -1,12 +1,12 @@ -- ################################################################################################# --- # << NEORV32 - Processor Top Entity with AvalonMM Compatible Master Interface >> # +-- # << NEORV32 - Processor Top Entity with AvalonMM Compatible Host Interface >> # -- # ********************************************************************************************* # --- # (c) "AvalonMM", "NIOS-2", "Qsys", "MegaWizard" and "Platform Designer" # --- # are trademarks of Intel # +-- # (c) "AvalonMM", "Qsys", "MegaWizard" and "Platform Designer" are trademarks of Intel corp. # -- # ********************************************************************************************* # -- # BSD 3-Clause License # -- # # --- # Copyright (c) 2023, Stephan Nolting. All rights reserved. # +-- # The NEORV32 RISC-V Processor, https://github.com/stnolting/neorv32 # +-- # Copyright (c) 2024, 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: # @@ -31,8 +31,6 @@ -- # 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 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # -- ################################################################################################# library ieee; @@ -96,6 +94,12 @@ entity neorv32_top_avalonmm is DCACHE_NUM_BLOCKS : natural := 4; -- d-cache: number of blocks (min 1), has to be a power of 2 DCACHE_BLOCK_SIZE : natural := 64; -- d-cache: block size in bytes (min 4), has to be a power of 2 + -- Execute in-place module (XIP) -- + XIP_EN : boolean := false; -- implement execute in place module (XIP)? + XIP_CACHE_EN : boolean := false; -- implement XIP cache? + XIP_CACHE_NUM_BLOCKS : natural range 1 to 256 := 8; -- number of blocks (min 1), has to be a power of 2 + XIP_CACHE_BLOCK_SIZE : natural range 1 to 2**16 := 256; -- block size in bytes (min 4), has to be a power of 2 + -- External Interrupts Controller (XIRQ) -- XIRQ_NUM_CH : natural := 0; -- number of external IRQ channels (0..32) XIRQ_TRIGGER_TYPE : std_ulogic_vector(31 downto 0) := x"ffffffff"; -- trigger type: 0=level, 1=edge @@ -124,7 +128,6 @@ entity neorv32_top_avalonmm is IO_NEOLED_EN : boolean := false; -- implement NeoPixel-compatible smart LED interface (NEOLED)? IO_NEOLED_TX_FIFO : natural := 1; -- NEOLED TX FIFO depth, 1..32k, has to be a power of two IO_GPTMR_EN : boolean := false; -- implement general purpose timer (GPTMR)? - IO_XIP_EN : boolean := false; -- implement execute in place module (XIP)? IO_ONEWIRE_EN : boolean := false -- implement 1-wire interface (ONEWIRE)? ); port ( @@ -287,6 +290,12 @@ begin MEM_EXT_ASYNC_RX => false, MEM_EXT_ASYNC_TX => false, + -- Execute in-place module (XIP) -- + XIP_EN => XIP_EN, + XIP_CACHE_EN => XIP_CACHE_EN, + XIP_CACHE_NUM_BLOCKS => XIP_CACHE_NUM_BLOCKS, + XIP_CACHE_BLOCK_SIZE => XIP_CACHE_BLOCK_SIZE, + -- External Interrupts Controller (XIRQ) -- XIRQ_NUM_CH => XIRQ_NUM_CH, XIRQ_TRIGGER_TYPE => XIRQ_TRIGGER_TYPE, @@ -315,7 +324,6 @@ begin IO_NEOLED_EN => IO_NEOLED_EN, IO_NEOLED_TX_FIFO => IO_NEOLED_TX_FIFO, IO_GPTMR_EN => IO_GPTMR_EN, - IO_XIP_EN => IO_XIP_EN, IO_ONEWIRE_EN => IO_ONEWIRE_EN ) port map ( diff --git a/rtl/system_integration/neorv32_SystemTop_axi4lite.vhd b/rtl/system_integration/neorv32_SystemTop_axi4lite.vhd index 4f04b0af4..b00877f4d 100644 --- a/rtl/system_integration/neorv32_SystemTop_axi4lite.vhd +++ b/rtl/system_integration/neorv32_SystemTop_axi4lite.vhd @@ -1,11 +1,12 @@ -- ################################################################################################# --- # << NEORV32 - Processor Top Entity with AXI4-Lite Compatible Master Interface >> # +-- # << NEORV32 - Processor Top Entity with AXI4-Lite Compatible Host Interface >> # -- # ********************************************************************************************* # --- # (c) "AXI", "AXI4" and "AXI4-Lite" are trademarks of Arm Holdings plc. # +-- # (c) "AXI", "AXI4" and "AXI4-Lite" are trademarks of ARM Holdings plc. # -- # ********************************************************************************************* # -- # BSD 3-Clause License # -- # # --- # Copyright (c) 2023, Stephan Nolting. All rights reserved. # +-- # The NEORV32 RISC-V Processor, https://github.com/stnolting/neorv32 # +-- # Copyright (c) 2024, 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: # @@ -30,8 +31,6 @@ -- # 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 Processor - https://github.com/stnolting/neorv32 (c) Stephan Nolting # -- ################################################################################################# library ieee; @@ -92,6 +91,11 @@ entity neorv32_SystemTop_axi4lite is DCACHE_EN : boolean := false; -- implement data cache DCACHE_NUM_BLOCKS : natural := 4; -- d-cache: number of blocks (min 1), has to be a power of 2 DCACHE_BLOCK_SIZE : natural := 64; -- d-cache: block size in bytes (min 4), has to be a power of 2 + -- Execute in-place module (XIP) -- + XIP_EN : boolean := false; -- implement execute in place module (XIP)? + XIP_CACHE_EN : boolean := false; -- implement XIP cache? + XIP_CACHE_NUM_BLOCKS : natural range 1 to 256 := 8; -- number of blocks (min 1), has to be a power of 2 + XIP_CACHE_BLOCK_SIZE : natural range 1 to 2**16 := 256; -- block size in bytes (min 4), has to be a power of 2 -- External Interrupts Controller (XIRQ) -- XIRQ_NUM_CH : natural := 0; -- number of external IRQ channels (0..32) XIRQ_TRIGGER_TYPE : std_logic_vector(31 downto 0) := x"FFFFFFFF"; -- trigger type: 0=level, 1=edge @@ -121,7 +125,6 @@ entity neorv32_SystemTop_axi4lite is IO_NEOLED_EN : boolean := true; -- implement NeoPixel-compatible smart LED interface (NEOLED)? IO_NEOLED_TX_FIFO : natural := 1; -- NEOLED TX FIFO depth, 1..32k, has to be a power of two IO_GPTMR_EN : boolean := false; -- implement general purpose timer (GPTMR)? - IO_XIP_EN : boolean := false; -- implement execute in place module (XIP)? IO_ONEWIRE_EN : boolean := false; -- implement 1-wire interface (ONEWIRE)? IO_DMA_EN : boolean := false; -- implement direct memory access controller (DMA)? IO_SLINK_EN : boolean := false; -- implement stream link interface (SLINK)? @@ -386,6 +389,11 @@ begin MEM_EXT_BIG_ENDIAN => false, -- byte order: true=big-endian, false=little-endian MEM_EXT_ASYNC_RX => false, -- use register buffer for RX data when false MEM_EXT_ASYNC_TX => false, -- use register buffer for TX data when false + -- Execute in-place module (XIP) -- + XIP_EN => XIP_EN, -- implement execute in place module (XIP)? + XIP_CACHE_EN => XIP_CACHE_EN, -- implement XIP cache? + XIP_CACHE_NUM_BLOCKS => XIP_CACHE_NUM_BLOCKS, -- number of blocks (min 1), has to be a power of 2 + XIP_CACHE_BLOCK_SIZE => XIP_CACHE_BLOCK_SIZE, -- block size in bytes (min 4), has to be a power of 2 -- External Interrupts Controller (XIRQ) -- XIRQ_NUM_CH => XIRQ_NUM_CH, -- number of external IRQ channels (0..32) XIRQ_TRIGGER_TYPE => XIRQ_TRIGGER_TYPE_INT, -- trigger type: 0=level, 1=edge @@ -415,7 +423,6 @@ begin IO_NEOLED_EN => IO_NEOLED_EN, -- implement NeoPixel-compatible smart LED interface (NEOLED)? IO_NEOLED_TX_FIFO => IO_NEOLED_TX_FIFO, -- NEOLED TX FIFO depth, 1..32k, has to be a power of two IO_GPTMR_EN => IO_GPTMR_EN, -- implement general purpose timer (GPTMR)? - IO_XIP_EN => IO_XIP_EN, -- implement execute in place module (XIP)? IO_ONEWIRE_EN => IO_ONEWIRE_EN, -- implement 1-wire interface (ONEWIRE)? IO_DMA_EN => IO_DMA_EN, -- implement direct memory access controller (DMA)? IO_SLINK_EN => IO_SLINK_EN, -- implement stream link interface (SLINK)? diff --git a/sim/neorv32_tb.vhd b/sim/neorv32_tb.vhd index dada56c3d..9508a50b6 100644 --- a/sim/neorv32_tb.vhd +++ b/sim/neorv32_tb.vhd @@ -267,6 +267,11 @@ begin MEM_EXT_BIG_ENDIAN => false, -- byte order: true=big-endian, false=little-endian MEM_EXT_ASYNC_RX => true, -- use register buffer for RX data when false MEM_EXT_ASYNC_TX => true, -- use register buffer for TX data when false + -- Execute in-place module (XIP) -- + XIP_EN => true, -- implement execute in place module (XIP)? + XIP_CACHE_EN => true, -- implement XIP cache? + XIP_CACHE_NUM_BLOCKS => 4, -- number of blocks (min 1), has to be a power of 2 + XIP_CACHE_BLOCK_SIZE => 256, -- block size in bytes (min 4), has to be a power of 2 -- External Interrupts Controller (XIRQ) -- XIRQ_NUM_CH => 32, -- number of external IRQ channels (0..32) XIRQ_TRIGGER_TYPE => (others => '1'), -- trigger type: 0=level, 1=edge @@ -296,7 +301,6 @@ begin IO_NEOLED_EN => true, -- implement NeoPixel-compatible smart LED interface (NEOLED)? IO_NEOLED_TX_FIFO => 8, -- NEOLED TX FIFO depth, 1..32k, has to be a power of two IO_GPTMR_EN => true, -- implement general purpose timer (GPTMR)? - IO_XIP_EN => true, -- implement execute in place module (XIP)? IO_ONEWIRE_EN => true, -- implement 1-wire interface (ONEWIRE)? IO_DMA_EN => true, -- implement direct memory access controller (DMA)? IO_SLINK_EN => true, -- implement stream link interface (SLINK)? @@ -335,7 +339,7 @@ begin -- Advanced memory control signals (available if MEM_EXT_EN = true) -- fence_o => open, -- indicates an executed FENCE operation fencei_o => open, -- indicates an executed FENCEI operation - -- XIP (execute in place via SPI) signals (available if IO_XIP_EN = true) -- + -- XIP (execute in place via SPI) signals (available if XIP_EN = true) -- xip_csn_o => open, -- chip-select, low-active xip_clk_o => open, -- serial clock xip_dat_i => '1', -- device data input diff --git a/sim/simple/neorv32_tb.simple.vhd b/sim/simple/neorv32_tb.simple.vhd index 7dd8e31d5..1eb91ad1f 100644 --- a/sim/simple/neorv32_tb.simple.vhd +++ b/sim/simple/neorv32_tb.simple.vhd @@ -215,6 +215,11 @@ begin MEM_EXT_BIG_ENDIAN => false, -- byte order: true=big-endian, false=little-endian MEM_EXT_ASYNC_RX => false, -- use register buffer for RX data when false MEM_EXT_ASYNC_TX => false, -- use register buffer for TX data when false + -- Execute in-place module (XIP) -- + XIP_EN => true, -- implement execute in place module (XIP)? + XIP_CACHE_EN => true, -- implement XIP cache? + XIP_CACHE_NUM_BLOCKS => 4, -- number of blocks (min 1), has to be a power of 2 + XIP_CACHE_BLOCK_SIZE => 256, -- block size in bytes (min 4), has to be a power of 2 -- External Interrupts Controller (XIRQ) -- XIRQ_NUM_CH => 32, -- number of external IRQ channels (0..32) XIRQ_TRIGGER_TYPE => (others => '1'), -- trigger type: 0=level, 1=edge @@ -244,7 +249,6 @@ begin IO_NEOLED_EN => true, -- implement NeoPixel-compatible smart LED interface (NEOLED)? IO_NEOLED_TX_FIFO => 8, -- NEOLED TX FIFO depth, 1..32k, has to be a power of two IO_GPTMR_EN => true, -- implement general purpose timer (GPTMR)? - IO_XIP_EN => true, -- implement execute in place module (XIP)? IO_ONEWIRE_EN => true, -- implement 1-wire interface (ONEWIRE)? IO_DMA_EN => true, -- implement direct memory access controller (DMA)? IO_SLINK_EN => true, -- implement stream link interface (SLINK)? @@ -283,7 +287,7 @@ begin -- Advanced memory control signals (available if MEM_EXT_EN = true) -- fence_o => open, -- indicates an executed FENCE operation fencei_o => open, -- indicates an executed FENCEI operation - -- XIP (execute in place via SPI) signals (available if IO_XIP_EN = true) -- + -- XIP (execute in place via SPI) signals (available if XIP_EN = true) -- xip_csn_o => open, -- chip-select, low-active xip_clk_o => open, -- serial clock xip_dat_i => '0', -- device data input diff --git a/sw/bootloader/bootloader.c b/sw/bootloader/bootloader.c index 8d9521e9d..063fb3549 100644 --- a/sw/bootloader/bootloader.c +++ b/sw/bootloader/bootloader.c @@ -293,10 +293,9 @@ int main(void) { #endif #if (XIP_EN != 0) - // setup XIP: clock divider 0, clock mode 0, bursts enabled + // setup XIP: clock divider 0, clock mode 0 if (neorv32_xip_available()) { neorv32_xip_setup(SPI_FLASH_CLK_PRSC, 0, 0, 0, SPI_FLASH_CMD_READ); - neorv32_xip_burst_mode_enable(); neorv32_xip_start(SPI_FLASH_ADDR_BYTES); } #endif diff --git a/sw/example/demo_xip/main.c b/sw/example/demo_xip/main.c index 082fa6eb7..8cf79e112 100644 --- a/sw/example/demo_xip/main.c +++ b/sw/example/demo_xip/main.c @@ -3,7 +3,7 @@ // # ********************************************************************************************* # // # BSD 3-Clause License # // # # -// # Copyright (c) 2023, Stephan Nolting. All rights reserved. # +// # Copyright (c) 2024, 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: # @@ -125,9 +125,9 @@ int main() { "Flash address bytes: %u\n", (uint32_t)FLASH_BASE, (uint32_t)XIP_MEM_BASE_ADDRESS, (uint32_t)FLASH_ABYTES); - // warning if i-cache is not implemented - if ((NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_ICACHE)) == 0) { - neorv32_uart0_printf("WARNING! No instruction cache implemented! The XIP program might run very slow...\n"); + // warning if XIP cache is not implemented + if ((NEORV32_XIP->CTRL & (1 << XIP_CTRL_BURST_EN)) == 0) { + neorv32_uart0_printf("WARNING! No XIP cache implemented! The XIP program might run very slow...\n"); } @@ -145,10 +145,10 @@ int main() { // ---------------------------------------------------------- // Get executable for flash // ---------------------------------------------------------- - neorv32_uart0_printf("Compile a program for the XIP flash: \n" + neorv32_uart0_printf("Compile a program for the XIP flash:\n" "\n" " Navigate to any example program folder (like 'neorv32/sw/example/hello_word').\n" - " Compile the program but relocate the instruction to the beginning of the Flash:\n" + " Compile the program but relocate the executable to the beginning of the XIP flash:\n" " make MARCH=rv32i_zicsr_zifencei USER_FLAGS+=\"-Wl,--defsym,__neorv32_rom_base=0x%x\" clean_all exe\n\n", (uint32_t)(XIP_MEM_BASE_ADDRESS + FLASH_BASE)); @@ -192,12 +192,6 @@ int main() { // Prepare XIP execution // ---------------------------------------------------------- - // Most SPI flash memories support "incremental read" operations - the read command and the start address - // is only transferred once and after that consecutive data is sampled with each new transferred byte. - // This can be sued by the XIP burst mode, which accelerates data fetch by up to 50%. - neorv32_uart0_printf("Enabling XIP burst mode...\n"); - neorv32_xip_burst_mode_enable(); // this has to be called right before starting the XIP mode by neorv32_xip_start() - // configure and enable the actual XIP mode // * configure FLASH_ABYTES address bytes send to the SPI flash for addressing // * map the XIP flash to the address space starting at XIP_MEM_BASE_ADDRESS - only the 4 MSBs are relevant here diff --git a/sw/lib/include/neorv32_sysinfo.h b/sw/lib/include/neorv32_sysinfo.h index e7160705b..eb0c31912 100644 --- a/sw/lib/include/neorv32_sysinfo.h +++ b/sw/lib/include/neorv32_sysinfo.h @@ -92,7 +92,7 @@ enum NEORV32_SYSINFO_SOC_enum { SYSINFO_SOC_IO_NEOLED = 26, /**< SYSINFO_SOC (26) (r/-): NeoPixel-compatible smart LED interface implemented when 1 (via IO_NEOLED_EN generic) */ SYSINFO_SOC_IO_XIRQ = 27, /**< SYSINFO_SOC (27) (r/-): External interrupt controller implemented when 1 (via XIRQ_NUM_IO generic) */ SYSINFO_SOC_IO_GPTMR = 28, /**< SYSINFO_SOC (28) (r/-): General purpose timer implemented when 1 (via IO_GPTMR_EN generic) */ - SYSINFO_SOC_IO_XIP = 29, /**< SYSINFO_SOC (29) (r/-): Execute in place module implemented when 1 (via IO_XIP_EN generic) */ + SYSINFO_SOC_XIP = 29, /**< SYSINFO_SOC (29) (r/-): Execute in-place module implemented when 1 (via XIP_EN generic) */ SYSINFO_SOC_IO_ONEWIRE = 30, /**< SYSINFO_SOC (30) (r/-): 1-wire interface controller implemented when 1 (via IO_ONEWIRE_EN generic) */ SYSINFO_SOC_OCD = 31 /**< SYSINFO_SOC (31) (r/-): On-chip debugger implemented when 1 (via ON_CHIP_DEBUGGER_EN generic) */ }; diff --git a/sw/lib/include/neorv32_xip.h b/sw/lib/include/neorv32_xip.h index b0396b38c..991cb9041 100644 --- a/sw/lib/include/neorv32_xip.h +++ b/sw/lib/include/neorv32_xip.h @@ -3,7 +3,7 @@ // # ********************************************************************************************* # // # BSD 3-Clause License # // # # -// # Copyright (c) 2023, Stephan Nolting. All rights reserved. # +// # Copyright (c) 2024, 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: # @@ -75,13 +75,13 @@ enum NEORV32_XIP_CTRL_enum { XIP_CTRL_RD_CMD_MSB = 20, /**< XIP control register(20) (r/w): SPI flash read command, MSB */ XIP_CTRL_SPI_CSEN = 21, /**< XIP control register(21) (r/w): SPI chip-select enable */ XIP_CTRL_HIGHSPEED = 22, /**< XIP control register(22) (r/w): SPI high-speed mode enable (ignoring XIP_CTRL_PRSC) */ - XIP_CTRL_BURST_EN = 23, /**< XIP control register(23) (r/w): Enable XIP burst mode */ - XIP_CTRL_CDIV0 = 24, /**< XIP control register(24) (r/w): Clock divider bit 0 */ - XIP_CTRL_CDIV1 = 25, /**< XIP control register(25) (r/w): Clock divider bit 1 */ - XIP_CTRL_CDIV2 = 26, /**< XIP control register(26) (r/w): Clock divider bit 2 */ - XIP_CTRL_CDIV3 = 27, /**< XIP control register(27) (r/w): Clock divider bit 3 */ + XIP_CTRL_CDIV0 = 23, /**< XIP control register(23) (r/w): Clock divider bit 0 */ + XIP_CTRL_CDIV1 = 24, /**< XIP control register(24) (r/w): Clock divider bit 1 */ + XIP_CTRL_CDIV2 = 25, /**< XIP control register(25) (r/w): Clock divider bit 2 */ + XIP_CTRL_CDIV3 = 26, /**< XIP control register(26) (r/w): Clock divider bit 3 */ - XIP_CTRL_PHY_BUSY = 30, /**< XIP control register(20) (r/-): SPI PHY is busy */ + XIP_CTRL_BURST_EN = 29, /**< XIP control register(29) (r/-): Burst mode enabled (set if XIP cache is implemented) */ + XIP_CTRL_PHY_BUSY = 30, /**< XIP control register(30) (r/-): SPI PHY is busy */ XIP_CTRL_XIP_BUSY = 31 /**< XIP control register(31) (r/-): XIP access in progress */ }; /**@}*/ @@ -97,8 +97,6 @@ int neorv32_xip_start(int abytes); void neorv32_xip_highspeed_enable(void); void neorv32_xip_highspeed_disable(void); uint32_t neorv32_xip_get_clock_speed(void); -void neorv32_xip_burst_mode_enable(void); -void neorv32_xip_burst_mode_disable(void); void neorv32_xip_spi_trans(int nbytes, uint64_t *rtx_data); /**@}*/ diff --git a/sw/lib/source/neorv32_rte.c b/sw/lib/source/neorv32_rte.c index 459c0f43c..5d0e42329 100644 --- a/sw/lib/source/neorv32_rte.c +++ b/sw/lib/source/neorv32_rte.c @@ -705,7 +705,7 @@ void neorv32_rte_print_hw_config(void) { if (tmp & (1 << SYSINFO_SOC_IO_NEOLED)) { neorv32_uart0_printf("NEOLED "); } if (tmp & (1 << SYSINFO_SOC_IO_XIRQ)) { neorv32_uart0_printf("XIRQ "); } if (tmp & (1 << SYSINFO_SOC_IO_GPTMR)) { neorv32_uart0_printf("GPTMR "); } - if (tmp & (1 << SYSINFO_SOC_IO_XIP)) { neorv32_uart0_printf("XIP "); } + if (tmp & (1 << SYSINFO_SOC_XIP)) { neorv32_uart0_printf("XIP "); } if (tmp & (1 << SYSINFO_SOC_IO_ONEWIRE)) { neorv32_uart0_printf("ONEWIRE "); } if (tmp & (1 << SYSINFO_SOC_IO_DMA)) { neorv32_uart0_printf("DMA "); } if (tmp & (1 << SYSINFO_SOC_IO_SLINK)) { neorv32_uart0_printf("SLINK "); } diff --git a/sw/lib/source/neorv32_xip.c b/sw/lib/source/neorv32_xip.c index bd9e21953..310458120 100644 --- a/sw/lib/source/neorv32_xip.c +++ b/sw/lib/source/neorv32_xip.c @@ -3,7 +3,7 @@ // # ********************************************************************************************* # // # BSD 3-Clause License # // # # -// # Copyright (c) 2023, Stephan Nolting. All rights reserved. # +// # Copyright (c) 2024, 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: # @@ -51,7 +51,7 @@ **************************************************************************/ int neorv32_xip_available(void) { - if (NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_IO_XIP)) { + if (NEORV32_SYSINFO->SOC & (1 << SYSINFO_SOC_XIP)) { return 1; } else { @@ -180,26 +180,6 @@ uint32_t neorv32_xip_get_clock_speed(void) { } -/**********************************************************************//** - * Enable XIP burst mode (incremental reads). - * - * @note Make sure your flash supports this feature (most flash chips do so). - **************************************************************************/ -void neorv32_xip_burst_mode_enable(void) { - - NEORV32_XIP->CTRL |= 1 << XIP_CTRL_BURST_EN; -} - - -/**********************************************************************//** - * Disable XIP burst mode. - **************************************************************************/ -void neorv32_xip_burst_mode_disable(void) { - - NEORV32_XIP->CTRL &= ~(1 << XIP_CTRL_BURST_EN); -} - - /**********************************************************************//** * Direct SPI access to the XIP flash. * diff --git a/sw/svd/neorv32.svd b/sw/svd/neorv32.svd index 2376195cf..1f6f5d928 100644 --- a/sw/svd/neorv32.svd +++ b/sw/svd/neorv32.svd @@ -604,16 +604,17 @@ [22:22] SPI high-speed mode enable (ignoring XIP_CTRL_PRSC) - - XIP_CTRL_BURST_EN - [23:23] - Enable burst mode (for XIP accesses) - XIP_CTRL_CDIV - [24:27] + [23:26] SPI clock divider + + XIP_CTRL_BURST_EN + [29:29] + read-only + Busr mode enabled (when cache is implemented) + XIP_CTRL_PHY_BUSY [30:30] @@ -1609,7 +1610,7 @@ SYSINFO_SOC_IO_NEOLED[26:26]NeoPixel-compatible smart LED interface implemented SYSINFO_SOC_IO_XIRQ[27:27]External interrupt controller implemented SYSINFO_SOC_IO_GPTMR[28:28]General purpose timer implemented - SYSINFO_SOC_IO_XIP[29:29]Execute in place module implemented + SYSINFO_SOC_XIP[29:29]Execute in place module implemented SYSINFO_SOC_IO_ONEWIRE[30:30]1-wire interface controller implemented SYSINFO_SOC_OCD[31:31]On-chip debugger implemented