Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[rtl] minor optimizations/cleanups of processor bus system #591

Merged
merged 6 commits into from
Apr 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 9 additions & 6 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
## Project Change Log

The most recent version of the **NEORV32** project can be found at the top of this list.
"Stable releases" are linked and highlighted :rocket:.
The latest release is [![release](https://img.shields.io/github/v/release/stnolting/neorv32)](https://github.com/stnolting/neorv32/releases).
"Stable releases" are linked and highlighted :rocket:. The latest release is
[![release](https://img.shields.io/github/v/release/stnolting/neorv32)](https://github.com/stnolting/neorv32/releases).
A list of all releases can be found [here](https://github.com/stnolting/neorv32/releases).

Starting with version `1.5.7` this project uses [semantic versioning](https://semver.org).
The _hardware version identifier_ uses an additional custom element (`MAJOR.MINOR.PATCH.custom`) to track _individual_ changes.
The identifier number is incremented with every core RTL modification and also by major framework modifications.
The _version identifier_ uses an additional **custom** element (`MAJOR.MINOR.PATCH.custom`)
to track _individual_ changes. The identifier number is incremented with every core RTL
modification and also by major framework modifications.

The version number is globally defined by the `hw_version_c` constant in the main VHDL
[package file](https://github.com/stnolting/neorv32/blob/main/rtl/core/neorv32_package.vhd).
The processor can determine its version by reading the `mimpid` CSR (at CSR address 0xf13).
A 8x4-bit BCD representation is used. Leading zeros are optional. Example:
The processor can determine this version by reading the RISC-V-compatible `mimpid` CSR.
A 8x4-bit BCD representation is used. Examples:

```
mimpid = 0x01040312 => Version 01.04.03.12 => v1.4.3.12
mimpid = 0x01080200 => Version 01.08.02.00 => v1.8.2
```


Expand All @@ -31,6 +33,7 @@ mimpid = 0x01040312 => Version 01.04.03.12 => v1.4.3.12

| Date (*dd.mm.yyyy*) | Version | Comment |
|:-------------------:|:-------:|:--------|
| 19.04.2023 | 1.8.3.8 | minor processor bus system optimizations and clean-ups; [#591](https://github.com/stnolting/neorv32/pull/591) |
| 15.04.2023 | 1.8.3.7 | :bug: :warning: `wfi` and XIRQ bug fixes; massive RTL code cleanup and optimization of CPU control; [#586](https://github.com/stnolting/neorv32/pull/586) |
| 14.04.2023 | 1.8.3.6 | [UARTs] software can now retrieve the configured RX/TX FIFO sizes from the `DATA` register; [#581](https://github.com/stnolting/neorv32/pull/581) |
| 13.04.2023 | 1.8.3.5 | :bug: fixed bug in FPU control logic (introduced in some earlier clean-up commit); minor code edits and optimizations; [#578](https://github.com/stnolting/neorv32/pull/578) |
Expand Down
8 changes: 3 additions & 5 deletions docs/datasheet/cpu.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -229,14 +229,12 @@ direction as seen from the CPU.
| `d_bus_err_i` | 1 | in | Bus transfer terminate from accessed peripheral
| `d_bus_fence_o` | 1 | out | Indicates an executed `fence` instruction
| `d_bus_priv_o` | 1 | out | Current _effective_ CPU privilege level (`0` = user, `1` = machine)
4+^| **Interrupts, RISC-V-compatible (<<_traps_exceptions_and_interrupts>>)**
4+^| **Interrupts (<<_traps_exceptions_and_interrupts>>)**
| `msw_irq_i` | 1 | in | RISC-V machine software interrupt
| `mext_irq_i` | 1 | in | RISC-V machine external interrupt
| `mtime_irq_i` | 1 | in | RISC-V machine timer interrupt
4+^| **Interrupts, NEORV32-specific (<<_traps_exceptions_and_interrupts>>)**
| `firq_i` | 16 | in | Fast interrupt request signals
4+^| **Enter Debug Mode Request (<<_on_chip_debugger_ocd>>)**
| `db_halt_req_i` | 1 | in | Request CPU to halt and enter debug mode
| `firq_i` | 16 | in | Custom fast interrupt request signals
| `db_halt_req_i` | 1 | in | Request CPU to halt and enter debug mode (RISC-V <<_on_chip_debugger_ocd>>)
|=======================

.Bus Interface Protocol
Expand Down
14 changes: 6 additions & 8 deletions rtl/core/neorv32_cpu.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -98,14 +98,12 @@ entity neorv32_cpu is
d_bus_err_i : in std_ulogic; -- bus transfer error
d_bus_fence_o : out std_ulogic; -- executed FENCE operation
d_bus_priv_o : out std_ulogic; -- current effective privilege level
-- interrupts (risc-v compliant) --
msw_irq_i : in std_ulogic;-- machine software interrupt
mext_irq_i : in std_ulogic;-- machine external interrupt
mtime_irq_i : in std_ulogic;-- machine timer interrupt
-- fast interrupts (custom) --
firq_i : in std_ulogic_vector(15 downto 0);
-- debug mode (halt) request --
db_halt_req_i : in std_ulogic
-- interrupts --
msw_irq_i : in std_ulogic; -- risc-v: machine software interrupt
mext_irq_i : in std_ulogic; -- risc-v: machine external interrupt
mtime_irq_i : in std_ulogic; -- risc-v: machine timer interrupt
firq_i : in std_ulogic_vector(15 downto 0); -- custom: fast interrupts
db_halt_req_i : in std_ulogic -- risc-v: halt request (debug mode)
);
end neorv32_cpu;

Expand Down
18 changes: 8 additions & 10 deletions rtl/core/neorv32_cpu_bus.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -168,24 +168,22 @@ begin
d_bus_ben_o <= (others => '0'); -- default
case ctrl_i.ir_funct3(1 downto 0) is
when "00" => -- byte
for i in 0 to (XLEN/8)-1 loop
d_bus_wdata_o(i*8+7 downto i*8) <= wdata_i(7 downto 0);
end loop;
d_bus_wdata_o(07 downto 00) <= wdata_i(7 downto 0);
d_bus_wdata_o(15 downto 08) <= wdata_i(7 downto 0);
d_bus_wdata_o(23 downto 16) <= wdata_i(7 downto 0);
d_bus_wdata_o(31 downto 24) <= wdata_i(7 downto 0);
d_bus_ben_o(to_integer(unsigned(addr_i(1 downto 0)))) <= '1';
when "01" => -- half-word
for i in 0 to (XLEN/16)-1 loop
d_bus_wdata_o(i*16+15 downto i*16) <= wdata_i(15 downto 0);
end loop;
d_bus_wdata_o(15 downto 00) <= wdata_i(15 downto 0);
d_bus_wdata_o(31 downto 16) <= wdata_i(15 downto 0);
if (addr_i(1) = '0') then
d_bus_ben_o <= "0011"; -- low half-word
else
d_bus_ben_o <= "1100"; -- high half-word
end if;
when others => -- word
for i in 0 to (XLEN/32)-1 loop
d_bus_wdata_o(i*32+31 downto i*32) <= wdata_i(31 downto 0);
end loop;
d_bus_ben_o <= (others => '1'); -- full word
d_bus_wdata_o <= wdata_i;
d_bus_ben_o <= "1111";
end case;
end if;
end if;
Expand Down
17 changes: 8 additions & 9 deletions rtl/core/neorv32_dcache.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ begin
host_rdata_o <= cache.host_rdata;

-- peripheral bus interface defaults --
bus_addr_o <= host_addr_i;
bus_addr_o <= ctrl.addr_reg;
bus_wdata_o <= host_wdata_i;
bus_ben_o <= host_ben_i;
bus_re_o <= '0';
Expand All @@ -212,6 +212,7 @@ begin

when S_IDLE => -- wait for host access request or cache control operation
-- ------------------------------------------------------------
ctrl.addr_reg_nxt <= host_addr_i;
if (ctrl.clear_buf = '1') then -- invalidate cache
ctrl.state_nxt <= S_CLEAR;
elsif (host_re_i = '1') or (ctrl.re_buf = '1') or (host_we_i = '1') or (ctrl.we_buf = '1') then
Expand All @@ -224,12 +225,11 @@ begin

when S_CHECK => -- check if cache hit
-- ------------------------------------------------------------
-- calculate block base address (in case we need to download it) --
ctrl.addr_reg_nxt <= host_addr_i;
ctrl.addr_reg_nxt((cache_offset_size_c+2)-1 downto 2) <= (others => '0'); -- block-aligned
ctrl.addr_reg_nxt(1 downto 0) <= "00"; -- word-aligned
--
if (ctrl.re_buf = '1') then -- read access
-- calculate block base address (in case we need to download it) --
ctrl.addr_reg_nxt((cache_offset_size_c+2)-1 downto 2) <= (others => '0'); -- block-aligned
ctrl.addr_reg_nxt(1 downto 0) <= "00"; -- word-aligned
--
if (cache.hit = '1') then -- HIT -> done
ctrl.re_buf_nxt <= '0';
ctrl.we_buf_nxt <= '0';
Expand All @@ -254,13 +254,11 @@ begin

when S_DOWNLOAD_REQ => -- download new cache block: request new word
-- ------------------------------------------------------------
bus_addr_o <= ctrl.addr_reg;
bus_re_o <= '1'; -- request new read transfer
ctrl.state_nxt <= S_DOWNLOAD_WAIT;

when S_DOWNLOAD_WAIT => -- download new cache block: wait for bus response
-- ------------------------------------------------------------
bus_addr_o <= ctrl.addr_reg;
if (bus_ack_i = '1') or (bus_err_i = '1') then -- ACK or ERROR -> write to cache and get next word (store ERROR flag in cache)
cache.ctrl_we <= '1'; -- write to cache
ctrl.addr_reg_nxt <= std_ulogic_vector(unsigned(ctrl.addr_reg) + 4);
Expand Down Expand Up @@ -294,6 +292,7 @@ begin

when S_RESYNC => -- re-sync host/cache access
-- ------------------------------------------------------------
ctrl.addr_reg_nxt <= host_addr_i; -- restore original access address
if (ctrl.we_buf = '1') then -- write access
ctrl.state_nxt <= S_RESYNC_WRITE;
else -- read access
Expand Down Expand Up @@ -325,7 +324,7 @@ begin
end process ctrl_engine_comb;

-- cached access? --
bus_cached_o <= '1' when (ctrl.state = S_DOWNLOAD_REQ) or (ctrl.state = S_DOWNLOAD_WAIT) else '1';
bus_cached_o <= '1' when (ctrl.state = S_DOWNLOAD_REQ) or (ctrl.state = S_DOWNLOAD_WAIT) else '0';


-- Cache Memory ---------------------------------------------------------------------------
Expand Down
16 changes: 7 additions & 9 deletions rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ package neorv32_package is

-- Architecture Constants -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080307"; -- hardware version
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080308"; -- hardware version
constant archid_c : natural := 19; -- official RISC-V architecture ID
constant XLEN : natural := 32; -- native data path width, do not change!

Expand Down Expand Up @@ -1238,14 +1238,12 @@ package neorv32_package is
d_bus_err_i : in std_ulogic; -- bus transfer error
d_bus_fence_o : out std_ulogic; -- executed FENCE operation
d_bus_priv_o : out std_ulogic; -- current effective privilege level
-- interrupts (risc-v compliant) --
msw_irq_i : in std_ulogic; -- machine software interrupt
mext_irq_i : in std_ulogic; -- machine external interrupt
mtime_irq_i : in std_ulogic; -- machine timer interrupt
-- fast interrupts (custom) --
firq_i : in std_ulogic_vector(15 downto 0);
-- debug mode (halt) request --
db_halt_req_i : in std_ulogic
-- interrupts --
msw_irq_i : in std_ulogic; -- risc-v: machine software interrupt
mext_irq_i : in std_ulogic; -- risc-v: machine external interrupt
mtime_irq_i : in std_ulogic; -- risc-v: machine timer interrupt
firq_i : in std_ulogic_vector(15 downto 0); -- custom: fast interrupts
db_halt_req_i : in std_ulogic -- risc-v: halt request (debug mode)
);
end component;

Expand Down
74 changes: 30 additions & 44 deletions rtl/core/neorv32_top.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -273,22 +273,8 @@ architecture neorv32_top_rtl of neorv32_top is
end record;
signal cpu_s : cpu_status_t;

-- bus interface - instruction fetch --
type bus_i_interface_t is record
addr : std_ulogic_vector(31 downto 0); -- bus access address
rdata : std_ulogic_vector(31 downto 0); -- bus read data
re : std_ulogic; -- read request
ack : std_ulogic; -- bus transfer acknowledge
err : std_ulogic; -- bus transfer error
fence : std_ulogic; -- fence.i instruction executed
src : std_ulogic; -- access source (1=instruction fetch, 0=data access)
cached : std_ulogic; -- cached transfer
priv : std_ulogic; -- set when in privileged machine mode
end record;
signal cpu_i, i_cache : bus_i_interface_t;

-- bus interface - data access --
type bus_d_interface_t is record
-- bus interface --
type bus_interface_t is record
addr : std_ulogic_vector(31 downto 0); -- bus access address
rdata : std_ulogic_vector(31 downto 0); -- bus read data
wdata : std_ulogic_vector(31 downto 0); -- bus write data
Expand All @@ -297,12 +283,12 @@ architecture neorv32_top_rtl of neorv32_top is
re : std_ulogic; -- read request
ack : std_ulogic; -- bus transfer acknowledge
err : std_ulogic; -- bus transfer error
fence : std_ulogic; -- fence instruction executed
src : std_ulogic; -- access source (1=instruction fetch, 0=data access)
cached : std_ulogic; -- cached transfer
priv : std_ulogic; -- set when in privileged machine mode
end record;
signal cpu_d, d_cache, p_bus : bus_d_interface_t;
signal cpu_i, cpu_d, i_cache, d_cache, p_bus : bus_interface_t;
signal d_fence, i_fence : std_ulogic;

-- bus access error (from BUSKEEPER) --
signal bus_error : std_ulogic;
Expand Down Expand Up @@ -557,7 +543,7 @@ begin
i_bus_re_o => cpu_i.re, -- read request
i_bus_ack_i => cpu_i.ack, -- bus transfer acknowledge
i_bus_err_i => cpu_i.err, -- bus transfer error
i_bus_fence_o => cpu_i.fence, -- executed FENCEI operation
i_bus_fence_o => i_fence, -- executed FENCEI operation
i_bus_priv_o => cpu_i.priv, -- current effective privilege level
-- data bus interface --
d_bus_addr_o => cpu_d.addr, -- bus access address
Expand All @@ -568,27 +554,28 @@ begin
d_bus_re_o => cpu_d.re, -- read request
d_bus_ack_i => cpu_d.ack, -- bus transfer acknowledge
d_bus_err_i => cpu_d.err, -- bus transfer error
d_bus_fence_o => cpu_d.fence, -- executed FENCE operation
d_bus_fence_o => d_fence, -- executed FENCE operation
d_bus_priv_o => cpu_d.priv, -- current effective privilege level
-- non-maskable interrupt --
msw_irq_i => msw_irq_i, -- machine software interrupt
mext_irq_i => mext_irq_i, -- machine external interrupt request
mtime_irq_i => mtime_irq, -- machine timer interrupt
-- fast interrupts (custom) --
firq_i => fast_irq, -- fast interrupt trigger
-- debug mode (halt) request --
db_halt_req_i => dci_halt_req
-- interrupts --
msw_irq_i => msw_irq_i, -- risc-v: machine software interrupt
mext_irq_i => mext_irq_i, -- risc-v: machine external interrupt
mtime_irq_i => mtime_irq, -- risc-v: machine timer interrupt
firq_i => fast_irq, -- custom: fast interrupts
db_halt_req_i => dci_halt_req -- risc-v: halt request (debug mode)
);

-- initialized but unused --
cpu_i.src <= '1';
cpu_d.src <= '0';
cpu_i.wdata <= (others => '0');
cpu_i.ben <= (others => '0');
cpu_i.we <= '0'; -- read-only
cpu_i.src <= '1'; -- 1 = instruction fetch
cpu_i.cached <= '0';
cpu_d.src <= '0'; -- 0 = data access
cpu_d.cached <= '0';

-- advanced memory control --
fence_o <= cpu_d.fence; -- indicates an executed FENCE operation
fencei_o <= cpu_i.fence; -- indicates an executed FENCE.I operation
fence_o <= d_fence; -- indicates an executed FENCE operation
fencei_o <= i_fence; -- indicates an executed FENCE.I operation

-- fast interrupt requests (FIRQs) - triggers are SINGLE-SHOT --
fast_irq(00) <= wdt_irq; -- HIGHEST PRIORITY - watchdog
Expand Down Expand Up @@ -623,7 +610,7 @@ begin
-- global control --
clk_i => clk_i, -- global clock, rising edge
rstn_i => rstn_int, -- global reset, low-active, async
clear_i => cpu_i.fence, -- cache clear
clear_i => i_fence, -- cache clear
-- host controller interface --
host_addr_i => cpu_i.addr, -- bus access address
host_rdata_o => cpu_i.rdata, -- bus read data
Expand All @@ -650,8 +637,10 @@ begin
cpu_i.err <= i_cache.err;
end generate;

i_cache.wdata <= (others => '0');
i_cache.ben <= (others => '0');
i_cache.we <= '0';
i_cache.priv <= cpu_i.priv;
i_cache.fence <= '0'; -- not used
i_cache.src <= '0'; -- not used


Expand All @@ -669,7 +658,7 @@ begin
-- global control --
clk_i => clk_i, -- global clock, rising edge
rstn_i => rstn_int, -- global reset, low-active, async
clear_i => cpu_d.fence, -- cache clear
clear_i => d_fence, -- cache clear
-- host controller interface --
host_addr_i => cpu_d.addr, -- bus access address
host_rdata_o => cpu_d.rdata, -- bus read data
Expand Down Expand Up @@ -705,9 +694,8 @@ begin
cpu_d.err <= d_cache.err;
end generate;

d_cache.priv <= cpu_d.priv;
d_cache.fence <= '0'; -- not used
d_cache.src <= '0'; -- not used
d_cache.priv <= cpu_d.priv;
d_cache.src <= '0';


-- CPU Bus Switch -------------------------------------------------------------------------
Expand Down Expand Up @@ -757,17 +745,15 @@ begin
p_bus_err_i => bus_error -- bus transfer error
);

-- any fence operation? --
p_bus.fence <= cpu_i.fence or cpu_d.fence;

-- bus response --
-- Bus Response ---------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
bus_response: process(resp_bus)
variable rdata_v : std_ulogic_vector(31 downto 0);
variable ack_v : std_ulogic;
variable err_v : std_ulogic;
begin
-- OR all response signals: only the module that has actually
-- been accessed is allowed to *set* its bus output signals
-- OR all response signals: only the module that has actually been accessed may set its bus output signals
rdata_v := (others => '0');
ack_v := '0';
err_v := '0';
Expand Down Expand Up @@ -807,7 +793,7 @@ begin
bus_xip_i => xip_access -- pending XIP access
);

-- unused, BUSKEEPER issues error to **directly** the CPU --
-- unused, BUSKEEPER issues error **directly** to the CPU --
resp_bus(RESP_BUSKEEPER).err <= '0';


Expand Down