⚠️ [rtl] remove Zalrsc ISA; replace by Zaamo

This commit is contained in:
stnolting 2025-01-03 21:15:57 +01:00
parent c0c5068683
commit e5833c9431
9 changed files with 226 additions and 174 deletions

View file

@ -29,6 +29,7 @@ mimpid = 0x01040312 -> Version 01.04.03.12 -> v1.4.3.12
| Date | Version | Comment | Ticket |
|:----:|:-------:|:--------|:------:|
| 03.01.2025 | 1.10.8.7 | :warning: :sparkles: replace `Zalrsc` ISA extensions (reservation-set operations) by `Zaamo` ISA extension (atomic read-modify-write operations) | [#]() |
| 01.01.2025 | 1.10.8.6 | :sparkles: :test_tube: add smp dual-core option | [#1135](https://github.com/stnolting/neorv32/pull/1135) |
| 29.12.2024 | 1.10.8.5 | :test_tube: add multi-hart support to debug module | [#1132](https://github.com/stnolting/neorv32/pull/1132) |
| 29.12.2024 | 1.10.8.4 | :warning: rename `SYSINFO.MEM -> SYSINFO.MISC`; add new `SYSINFO.MISC` entry for number of CPU cores (hardwired to one) | [#1134](https://github.com/stnolting/neorv32/pull/1134) |

View file

@ -3,7 +3,7 @@
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
-- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. --
-- Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. --
-- Licensed under the BSD-3-Clause license, see LICENSE for details. --
-- SPDX-License-Identifier: BSD-3-Clause --
-- ================================================================================ --
@ -172,7 +172,8 @@ begin
-- Request Switch -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
x_req_o.addr <= a_req_i.addr when (sel = '0') else b_req_i.addr;
x_req_o.rvso <= a_req_i.rvso when (sel = '0') else b_req_i.rvso;
x_req_o.amo <= a_req_i.amo when (sel = '0') else b_req_i.amo;
x_req_o.amoop <= a_req_i.amoop when (sel = '0') else b_req_i.amoop;
x_req_o.priv <= a_req_i.priv when (sel = '0') else b_req_i.priv;
x_req_o.src <= a_req_i.src when (sel = '0') else b_req_i.src;
x_req_o.rw <= a_req_i.rw when (sel = '0') else b_req_i.rw;
@ -738,11 +739,11 @@ end neorv32_bus_io_switch_rtl;
-- ================================================================================ --
-- NEORV32 SoC - Processor Bus Infrastructure: Reservation Set Control --
-- NEORV32 SoC - Processor Bus Infrastructure: Atomic Memory Operations Controller --
-- -------------------------------------------------------------------------------- --
-- Reservation set controller for the A (atomic) ISA extension's LR.W --
-- (load-reservate) and SC.W (store-conditional) instructions. Only a single --
-- reservation set (granularity = 4 bytes) is supported. T --
-- Read-modify-write controller for the RISC-V A/Zaamp ISA extension. --
-- [WARNING] Load-reservate and store-conditional operations (Zalrsc ISA extension) --
-- are NOT supported! --
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
@ -753,136 +754,158 @@ end neorv32_bus_io_switch_rtl;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library neorv32;
use neorv32.neorv32_package.all;
entity neorv32_bus_reservation_set is
entity neorv32_bus_amo_ctrl is
port (
-- global control --
clk_i : in std_ulogic; -- global clock, rising edge
rstn_i : in std_ulogic; -- global reset, low-active, async
-- external status and control --
rvs_addr_o : out std_ulogic_vector(31 downto 0);
rvs_valid_o : out std_ulogic;
rvs_clear_i : in std_ulogic;
clk_i : in std_ulogic; -- global clock, rising edge
rstn_i : in std_ulogic; -- global reset, low-active, async
-- core port --
core_req_i : in bus_req_t;
core_rsp_o : out bus_rsp_t;
core_req_i : in bus_req_t;
core_rsp_o : out bus_rsp_t;
-- system port --
sys_req_o : out bus_req_t;
sys_rsp_i : in bus_rsp_t
sys_req_o : out bus_req_t;
sys_rsp_i : in bus_rsp_t
);
end neorv32_bus_reservation_set;
end neorv32_bus_amo_ctrl;
architecture neorv32_bus_reservation_set_rtl of neorv32_bus_reservation_set is
architecture neorv32_bus_amo_ctrl_rtl of neorv32_bus_amo_ctrl is
-- reservation set --
type rsvs_t is record
state : std_ulogic_vector(1 downto 0);
addr : std_ulogic_vector(31 downto 2); -- reservated address; 4-byte granularity
valid : std_ulogic;
match : std_ulogic;
-- arbiter --
type state_t is (S_IDLE, S_READ_WAIT, S_EXECUTE, S_WRITE, S_WRITE_WAIT);
type arbiter_t is record
state : state_t;
cmd : std_ulogic_vector(3 downto 0);
rdata : std_ulogic_vector(31 downto 0);
wdata : std_ulogic_vector(31 downto 0);
ack : std_ulogic;
end record;
signal rsvs : rsvs_t;
signal arbiter, arbiter_nxt : arbiter_t;
-- ACK override for failed SC.W --
signal ack_local : std_ulogic;
-- internal data ALU --
signal alu_res : std_ulogic_vector(31 downto 0);
-- comparator --
signal cmp_opa : std_ulogic_vector(32 downto 0);
signal cmp_opb : std_ulogic_vector(32 downto 0);
signal cmp_less : std_ulogic;
signal cmp_res : std_ulogic_vector(31 downto 0);
begin
-- Reservation Set Control ----------------------------------------------------------------
-- Arbiter Sync ---------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
rvs_control: process(rstn_i, clk_i)
arbiter_sync: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
rsvs.state <= "00";
rsvs.addr <= (others => '0');
arbiter.state <= S_IDLE;
arbiter.cmd <= (others => '0');
arbiter.rdata <= (others => '0');
arbiter.wdata <= (others => '0');
elsif rising_edge(clk_i) then
case rsvs.state is
arbiter <= arbiter_nxt;
end if;
end process arbiter_sync;
when "10" => -- active reservation: wait for condition to invalidate reservation
-- --------------------------------------------------------------------
if (core_req_i.stb = '1') and (core_req_i.rw = '0') and (core_req_i.rvso = '1') then -- another LR instruction overriding the current reservation
rsvs.addr <= core_req_i.addr(31 downto 2);
end if;
--
if (rvs_clear_i = '1') then -- external clear request (highest priority)
rsvs.state <= "00"; -- invalidate reservation
elsif (core_req_i.stb = '1') and (core_req_i.rw = '1') then -- write access
if (core_req_i.rvso = '1') then -- this is a SC operation
if (rsvs.match = '1') then -- SC to reservated address
rsvs.state <= "11"; -- execute SC instruction (reservation still valid)
else -- SC to any other address
rsvs.state <= "00"; -- invalidate reservation
end if;
-- Arbiter Comb ---------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
arbiter_comb: process(arbiter, core_req_i, sys_rsp_i)
begin
arbiter_nxt <= arbiter; -- defaults
case arbiter.state is
elsif (rsvs.match = '1') then -- normal write to reservated address
rsvs.state <= "00"; -- invalidate reservation
end if;
when S_IDLE => -- wait for AMO request
-- ------------------------------------------------------------
if (core_req_i.stb = '1') and (core_req_i.amo = '1') then
arbiter_nxt.cmd <= core_req_i.amoop;
arbiter_nxt.wdata <= core_req_i.data;
arbiter_nxt.state <= S_READ_WAIT;
end if;
end if;
when S_READ_WAIT => -- wait for device read-access to complete
-- ------------------------------------------------------------
arbiter_nxt.rdata <= sys_rsp_i.data;
if (sys_rsp_i.ack = '1') or (sys_rsp_i.err = '1') then
arbiter_nxt.state <= S_EXECUTE;
end if;
when "11" => -- active reservation: invalidate reservation at the end of bus access
-- --------------------------------------------------------------------
if (sys_rsp_i.ack = '1') or (sys_rsp_i.err = '1') then
rsvs.state <= "00";
end if;
when S_EXECUTE => -- execute atomic data operation
-- ------------------------------------------------------------
arbiter_nxt.state <= S_WRITE;
when others => -- "0-" no active reservation: wait for new registration request
-- --------------------------------------------------------------------
if (core_req_i.stb = '1') and (core_req_i.rw = '0') and (core_req_i.rvso = '1') then -- load-reservate instruction
rsvs.addr <= core_req_i.addr(31 downto 2);
rsvs.state <= "10";
end if;
when S_WRITE => -- wait operation result to device
-- ------------------------------------------------------------
arbiter_nxt.state <= S_WRITE_WAIT;
when S_WRITE_WAIT => -- wait for device write-access to complete
-- ------------------------------------------------------------
if (sys_rsp_i.ack = '1') or (sys_rsp_i.err = '1') then
arbiter_nxt.state <= S_IDLE;
end if;
when others => -- undefined
-- ------------------------------------------------------------
arbiter_nxt.state <= S_IDLE;
end case;
end process arbiter_comb;
-- request switch --
sys_req_o.addr <= core_req_i.addr;
sys_req_o.data <= alu_res when (arbiter.state = S_WRITE) or (arbiter.state = S_WRITE_WAIT) else core_req_i.data;
sys_req_o.ben <= core_req_i.ben;
sys_req_o.stb <= '1' when (arbiter.state = S_WRITE) else core_req_i.stb;
sys_req_o.rw <= '1' when (arbiter.state = S_WRITE) or (arbiter.state = S_WRITE_WAIT) else core_req_i.rw;
sys_req_o.src <= core_req_i.src;
sys_req_o.priv <= core_req_i.priv;
sys_req_o.amo <= core_req_i.amo;
sys_req_o.amoop <= (others => '0'); -- the specific operation type should not matter after this point
sys_req_o.fence <= core_req_i.fence;
sys_req_o.sleep <= core_req_i.sleep;
sys_req_o.debug <= core_req_i.debug;
-- response switch --
core_rsp_o.data <= sys_rsp_i.data when (arbiter.state = S_IDLE) else arbiter.rdata;
core_rsp_o.err <= sys_rsp_i.err when (arbiter.state = S_IDLE) or (arbiter.state = S_WRITE_WAIT) else '0';
core_rsp_o.ack <= sys_rsp_i.ack when (arbiter.state = S_IDLE) or (arbiter.state = S_WRITE_WAIT) else '0';
-- Arbiter Sync ---------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
amo_alu: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
alu_res <= (others => '0');
elsif rising_edge(clk_i) then
case arbiter.cmd(2 downto 0) is
when "000" => alu_res <= arbiter.wdata; -- AMOSWAP
when "001" => alu_res <= std_ulogic_vector(unsigned(arbiter.rdata) + unsigned(arbiter.wdata)); -- AMOADD
when "010" => alu_res <= arbiter.rdata xor arbiter.wdata; -- AMOXOR
when "011" => alu_res <= arbiter.rdata and arbiter.wdata; -- AMOAND
when "100" => alu_res <= arbiter.rdata or arbiter.wdata; -- AMOOR
when others => alu_res <= cmp_res; -- AMOMIN[U] / AMOMAX[U]
end case;
end if;
end process rvs_control;
end process amo_alu;
-- address match? --
rsvs.match <= '1' when (core_req_i.addr(31 downto 2) = rsvs.addr) else '0';
-- -000 : SWAP
-- -001 : ADD
-- -010 : XOR
-- -011 : AND
-- -100 : OR
-- s110 : MIN
-- s111 : MAX
-- reservation valid? --
rsvs.valid <= rsvs.state(1);
-- status for external system --
rvs_valid_o <= rsvs.valid;
rvs_addr_o <= rsvs.addr & "00";
-- comparator logic (min/max and signed/unsigned) --
cmp_opa <= (arbiter.rdata(arbiter.rdata'left) and arbiter.cmd(3)) & arbiter.rdata; -- sign-extend if signed operation
cmp_opb <= (arbiter.wdata(arbiter.wdata'left) and arbiter.cmd(3)) & arbiter.wdata; -- sign-extend if signed operation
cmp_less <= '1' when (signed(cmp_opa) < signed(cmp_opb)) else '0';
cmp_res <= cmp_opa(31 downto 0) when ((cmp_less xor arbiter.cmd(0)) = '1') else cmp_opb(31 downto 0);
-- System Bus Interface -------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- gated request --
bus_request: process(core_req_i, rsvs.valid)
begin
sys_req_o <= core_req_i;
if (core_req_i.rvso = '1') and (core_req_i.rw = '1') then -- SC operation
sys_req_o.stb <= core_req_i.stb and rsvs.valid; -- write allowed if reservation still valid
else -- normal memory request or LR
sys_req_o.stb <= core_req_i.stb;
end if;
end process bus_request;
-- if a SC.W instruction fails there will be no write-request being send to the bus system
-- so we need to provide a local ACK to complete the bus access
ack_override: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
ack_local <= '0';
elsif rising_edge(clk_i) then
ack_local <= core_req_i.rvso and core_req_i.stb and core_req_i.rw and (not rsvs.valid);
end if;
end process ack_override;
-- response --
core_rsp_o.err <= sys_rsp_i.err;
core_rsp_o.ack <= sys_rsp_i.ack or ack_local; -- generate local ACK if SC fails
-- inject 1 into read data's LSB if SC fails --
core_rsp_o.data(31 downto 1) <= sys_rsp_i.data(31 downto 1);
core_rsp_o.data(0) <= sys_rsp_i.data(0) or (core_req_i.rvso and core_req_i.rw and (not rsvs.valid));
end neorv32_bus_reservation_set_rtl;
end neorv32_bus_amo_ctrl_rtl;

View file

@ -26,7 +26,7 @@
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
-- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. --
-- Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. --
-- Licensed under the BSD-3-Clause license, see LICENSE for details. --
-- SPDX-License-Identifier: BSD-3-Clause --
-- ================================================================================ --
@ -178,7 +178,7 @@ begin
-- -------------------------------------------------------------------------------------------
dir_acc_d <= '1' when UC_ENABLE and -- direct accesses implemented
((unsigned(host_req_i.addr(31 downto 28)) >= unsigned(UC_BEGIN)) or -- uncached memory page
(host_req_i.rvso = '1')) else '0'; -- atomic (reservation set) operation
(host_req_i.amo = '1')) else '0'; -- atomic memory operation
-- request splitter: cached or direct access --
req_splitter: process(host_req_i, dir_acc_d)
@ -378,7 +378,7 @@ end neorv32_cache_rtl;
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
-- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. --
-- Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. --
-- Licensed under the BSD-3-Clause license, see LICENSE for details. --
-- SPDX-License-Identifier: BSD-3-Clause --
-- ================================================================================ --
@ -538,7 +538,7 @@ end neorv32_cache_host_rtl;
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
-- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. --
-- Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. --
-- Licensed under the BSD-3-Clause license, see LICENSE for details. --
-- SPDX-License-Identifier: BSD-3-Clause --
-- ================================================================================ --
@ -725,7 +725,7 @@ end neorv32_cache_memory_rtl;
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
-- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. --
-- Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. --
-- Licensed under the BSD-3-Clause license, see LICENSE for details. --
-- SPDX-License-Identifier: BSD-3-Clause --
-- ================================================================================ --
@ -851,7 +851,8 @@ begin
bus_req_o.ben <= (others => '1'); -- full-word writes only
bus_req_o.src <= '0'; -- cache accesses are always data accesses
bus_req_o.priv <= '0'; -- cache accesses are always "unprivileged" accesses
bus_req_o.rvso <= '0'; -- cache accesses can never be a reservation set operation
bus_req_o.amo <= '0'; -- cache accesses can never be an atomic memory operation set operation
bus_req_o.amoop <= (others => '0'); -- cache accesses can never be an atomic memory operation set operation
bus_req_o.debug <= host_req_i.debug;
if (state = S_IDLE) then
bus_req_o.sleep <= host_req_i.sleep;

View file

@ -8,7 +8,7 @@
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
-- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. --
-- Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. --
-- Licensed under the BSD-3-Clause license, see LICENSE for details. --
-- SPDX-License-Identifier: BSD-3-Clause --
-- ================================================================================ --
@ -32,7 +32,7 @@ entity neorv32_cpu is
RISCV_ISA_E : boolean; -- implement embedded RF extension
RISCV_ISA_M : boolean; -- implement mul/div extension
RISCV_ISA_U : boolean; -- implement user mode extension
RISCV_ISA_Zalrsc : boolean; -- implement atomic reservation-set extension
RISCV_ISA_Zaamo : boolean; -- implement atomic memory operations extension
RISCV_ISA_Zba : boolean; -- implement shifted-add bit-manipulation extension
RISCV_ISA_Zbb : boolean; -- implement basic bit-manipulation extension
RISCV_ISA_Zbkb : boolean; -- implement bit-manipulation instructions for cryptography
@ -138,7 +138,7 @@ begin
cond_sel_string_f(RISCV_ISA_M, "m", "" ) &
cond_sel_string_f(RISCV_ISA_U, "u", "" ) &
cond_sel_string_f(true, "x", "" ) & -- always enabled
cond_sel_string_f(RISCV_ISA_Zalrsc, "_zalrsc", "" ) &
cond_sel_string_f(RISCV_ISA_Zaamo, "_zaamo", "" ) &
cond_sel_string_f(RISCV_ISA_Zba, "_zba", "" ) &
cond_sel_string_f(RISCV_ISA_Zbb, "_zbb", "" ) &
cond_sel_string_f(RISCV_ISA_Zbkb, "_zbkb", "" ) &
@ -213,7 +213,7 @@ begin
RISCV_ISA_E => RISCV_ISA_E, -- implement embedded RF extension
RISCV_ISA_M => RISCV_ISA_M, -- implement mul/div extension
RISCV_ISA_U => RISCV_ISA_U, -- implement user mode extension
RISCV_ISA_Zalrsc => RISCV_ISA_Zalrsc, -- implement atomic reservation-set extension
RISCV_ISA_Zaamo => RISCV_ISA_Zaamo, -- implement atomic memory operations extension
RISCV_ISA_Zba => RISCV_ISA_Zba, -- implement shifted-add bit-manipulation extension
RISCV_ISA_Zbb => RISCV_ISA_Zbb, -- implement basic bit-manipulation extension
RISCV_ISA_Zbkb => RISCV_ISA_Zbkb, -- implement bit-manipulation instructions for cryptography
@ -367,24 +367,24 @@ begin
-- -------------------------------------------------------------------------------------------
neorv32_cpu_lsu_inst: entity neorv32.neorv32_cpu_lsu
generic map (
AMO_LRSC_ENABLE => RISCV_ISA_Zalrsc -- enable atomic LR/SC operations
AMO_EN => RISCV_ISA_Zaamo -- enable atomic memory operations
)
port map (
-- global control --
clk_i => clk_gated, -- global clock, rising edge
rstn_i => rstn_i, -- global reset, low-active, async
ctrl_i => ctrl, -- main control bus
clk_i => clk_gated, -- global clock, rising edge
rstn_i => rstn_i, -- global reset, low-active, async
ctrl_i => ctrl, -- main control bus
-- cpu data access interface --
addr_i => alu_add, -- access address
wdata_i => rs2, -- write data
rdata_o => lsu_rdata, -- read data
mar_o => lsu_mar, -- memory address register
wait_o => lsu_wait, -- wait for access to complete
err_o => lsu_err, -- alignment/access errors
pmp_fault_i => pmp_fault, -- PMP read/write access fault
addr_i => alu_add, -- access address
wdata_i => rs2, -- write data
rdata_o => lsu_rdata, -- read data
mar_o => lsu_mar, -- memory address register
wait_o => lsu_wait, -- wait for access to complete
err_o => lsu_err, -- alignment/access errors
pmp_fault_i => pmp_fault, -- PMP read/write access fault
-- data bus --
dbus_req_o => dbus_req_o, -- request
dbus_rsp_i => dbus_rsp_i -- response
dbus_req_o => dbus_req_o, -- request
dbus_rsp_i => dbus_rsp_i -- response
);

View file

@ -14,7 +14,7 @@
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
-- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. --
-- Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. --
-- Licensed under the BSD-3-Clause license, see LICENSE for details. --
-- SPDX-License-Identifier: BSD-3-Clause --
-- ================================================================================ --
@ -40,7 +40,7 @@ entity neorv32_cpu_control is
RISCV_ISA_E : boolean; -- implement embedded-class register file extension
RISCV_ISA_M : boolean; -- implement mul/div extension
RISCV_ISA_U : boolean; -- implement user mode extension
RISCV_ISA_Zalrsc : boolean; -- implement atomic reservation-set extension
RISCV_ISA_Zaamo : boolean; -- implement atomic memory operations extension
RISCV_ISA_Zba : boolean; -- implement shifted-add bit-manipulation extension
RISCV_ISA_Zbb : boolean; -- implement basic bit-manipulation extension
RISCV_ISA_Zbkb : boolean; -- implement bit-manipulation instructions for cryptography
@ -368,7 +368,8 @@ begin
ibus_req_o.ben <= (others => '0'); -- read-only
ibus_req_o.rw <= '0'; -- read-only
ibus_req_o.src <= '1'; -- source = instruction fetch
ibus_req_o.rvso <= '0'; -- cannot be a reservation set operation
ibus_req_o.amo <= '0'; -- cannot be an atomic memory operation
ibus_req_o.amoop <= (others => '0'); -- cannot be an atomic memory operation
ibus_req_o.fence <= ctrl.lsu_fence; -- fence operation, valid without STB being set
ibus_req_o.sleep <= sleep_mode; -- sleep mode, valid without STB being set
ibus_req_o.debug <= debug_ctrl.run; -- debug mode, valid without STB being set
@ -622,8 +623,8 @@ begin
end case;
-- memory read/write access --
if RISCV_ISA_Zalrsc and (opcode(2) = opcode_amo_c(2)) then -- atomic lr/sc
ctrl_nxt.lsu_rw <= exe_engine.ir(instr_funct7_lsb_c+2);
if RISCV_ISA_Zaamo and (opcode(2) = opcode_amo_c(2)) then -- atomic memory operation (executed as single load for the CPU)
ctrl_nxt.lsu_rw <= '0';
else -- normal load/store
ctrl_nxt.lsu_rw <= exe_engine.ir(5);
end if;
@ -806,7 +807,7 @@ begin
(trap_ctrl.exc_buf(exc_saccess_c) = '1') or (trap_ctrl.exc_buf(exc_laccess_c) = '1') or -- access exception
(trap_ctrl.exc_buf(exc_salign_c) = '1') or (trap_ctrl.exc_buf(exc_lalign_c) = '1') or -- alignment exception
(trap_ctrl.exc_buf(exc_illegal_c) = '1') then -- illegal instruction exception
if (RISCV_ISA_Zalrsc and (opcode(2) = opcode_amo_c(2))) or (opcode(5) = '0') then -- atomic operation / normal load
if (RISCV_ISA_Zaamo and (opcode(2) = opcode_amo_c(2))) or (opcode(5) = '0') then -- atomic operation / normal load
ctrl_nxt.rf_wb_en <= '1'; -- allow write-back to register file (won't happen in case of exception)
end if;
exe_engine_nxt.state <= EX_DISPATCH;
@ -1033,10 +1034,12 @@ begin
when others => illegal_cmd <= '1';
end case;
when opcode_amo_c => -- atomic memory operation (LR/SC)
if (exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = "010") and RISCV_ISA_Zalrsc and
(exe_engine.ir(instr_funct7_lsb_c+6 downto instr_funct7_lsb_c+3) = "0001") then -- LR.W/SC.W
illegal_cmd <= '0';
when opcode_amo_c => -- atomic memory operation
if (exe_engine.ir(instr_funct3_msb_c downto instr_funct3_lsb_c) = "010") then
case exe_engine.ir(instr_funct5_msb_c downto instr_funct5_lsb_c) is
when "00001" | "00000" | "00100" | "01100" | "01000" | "10000" | "10100" | "11000" | "11100" => illegal_cmd <= '0';
when others => illegal_cmd <= '1';
end case;
end if;
when opcode_alu_c | opcode_alui_c | opcode_fop_c | opcode_cust0_c | opcode_cust1_c => -- ALU[I] / FPU / custom operations
@ -1852,9 +1855,9 @@ begin
csr.rdata(20) <= bool_to_ulogic_f(RISCV_ISA_Zksed); -- Zksed: ShangMi block cyphers
csr.rdata(21) <= bool_to_ulogic_f(RISCV_ISA_Zks); -- Zks: ShangMi algorithm suite
csr.rdata(22) <= bool_to_ulogic_f(RISCV_ISA_Zba); -- Zba: shifted-add bit-manipulation
csr.rdata(23) <= bool_to_ulogic_f(RISCV_ISA_Zbb); -- Zbb: basic bit-manipulation extension
csr.rdata(24) <= bool_to_ulogic_f(RISCV_ISA_Zbs); -- Zbs: single-bit bit-manipulation extension
csr.rdata(25) <= bool_to_ulogic_f(RISCV_ISA_Zalrsc); -- Zalrsc: reservation set extension
csr.rdata(23) <= bool_to_ulogic_f(RISCV_ISA_Zbb); -- Zbb: basic bit-manipulation
csr.rdata(24) <= bool_to_ulogic_f(RISCV_ISA_Zbs); -- Zbs: single-bit bit-manipulation
csr.rdata(25) <= bool_to_ulogic_f(RISCV_ISA_Zaamo); -- Zaamo: atomic memory operations
csr.rdata(26) <= '0'; -- reserved
csr.rdata(27) <= '0'; -- reserved
-- tuning options --

View file

@ -16,7 +16,7 @@ use neorv32.neorv32_package.all;
entity neorv32_cpu_lsu is
generic (
AMO_LRSC_ENABLE : boolean -- enable atomic LR/SC operations
AMO_EN : boolean -- enable atomic memory operations
);
port (
-- global control --
@ -43,6 +43,7 @@ architecture neorv32_cpu_lsu_rtl of neorv32_cpu_lsu is
signal misaligned : std_ulogic; -- misaligned address
signal arbiter_req : std_ulogic; -- pending bus request
signal arbiter_err : std_ulogic; -- access error
signal amo_cmd : std_ulogic_vector(3 downto 0); -- atomic memory operation type
begin
@ -75,17 +76,19 @@ begin
mem_do_reg: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
dbus_req_o.rw <= '0';
dbus_req_o.priv <= '0';
dbus_req_o.rvso <= '0';
dbus_req_o.data <= (others => '0');
dbus_req_o.ben <= (others => '0');
dbus_req_o.rw <= '0';
dbus_req_o.priv <= '0';
dbus_req_o.amo <= '0';
dbus_req_o.amoop <= (others => '0');
dbus_req_o.data <= (others => '0');
dbus_req_o.ben <= (others => '0');
elsif rising_edge(clk_i) then
if (ctrl_i.lsu_mo_we = '1') then
-- type identifiers --
dbus_req_o.rw <= ctrl_i.lsu_rw; -- read/write
dbus_req_o.priv <= ctrl_i.lsu_priv; -- privilege level
dbus_req_o.rvso <= bool_to_ulogic_f(AMO_LRSC_ENABLE) and ctrl_i.ir_opcode(2); -- reservation set operation
dbus_req_o.rw <= ctrl_i.lsu_rw; -- read/write
dbus_req_o.priv <= ctrl_i.lsu_priv; -- privilege level
dbus_req_o.amo <= bool_to_ulogic_f(AMO_EN) and ctrl_i.ir_opcode(2); -- atomic memory operation
dbus_req_o.amoop <= amo_cmd;
-- data alignment + byte-enable --
case ctrl_i.ir_funct3(1 downto 0) is
when "00" => -- byte
@ -111,6 +114,27 @@ begin
dbus_req_o.debug <= ctrl_i.cpu_debug; -- out-of-band: this is valid without STB being set
-- atomic memory access operation encoding --
amo_encode: process(ctrl_i.ir_funct12)
begin
if AMO_EN then
case ctrl_i.ir_funct12(11 downto 7) is
when "00000" => amo_cmd <= "0001"; -- ADD
when "00100" => amo_cmd <= "0010"; -- XOR
when "01100" => amo_cmd <= "0011"; -- AND
when "01000" => amo_cmd <= "0100"; -- OR
when "10000" => amo_cmd <= "1110"; -- MIN
when "10100" => amo_cmd <= "1111"; -- MAX
when "11000" => amo_cmd <= "0110"; -- MINU
when "11100" => amo_cmd <= "0111"; -- MAXU
when others => amo_cmd <= "0000"; -- SWAP
end case;
else
amo_cmd <= (others => '0');
end if;
end process;
-- Data Input: Alignment and Sign-Extension -----------------------------------------------
-- -------------------------------------------------------------------------------------------
mem_di_reg: process(rstn_i, clk_i)

View file

@ -3,7 +3,7 @@
-- -------------------------------------------------------------------------------- --
-- The NEORV32 RISC-V Processor - https://github.com/stnolting/neorv32 --
-- Copyright (c) NEORV32 contributors. --
-- Copyright (c) 2020 - 2024 Stephan Nolting. All rights reserved. --
-- Copyright (c) 2020 - 2025 Stephan Nolting. All rights reserved. --
-- Licensed under the BSD-3-Clause license, see LICENSE for details. --
-- SPDX-License-Identifier: BSD-3-Clause --
-- ================================================================================ --
@ -308,7 +308,8 @@ begin
dma_req_o.priv <= priv_mode_m_c; -- DMA accesses are always privileged
dma_req_o.src <= '0'; -- source = data access
dma_req_o.addr <= engine.src_addr when (engine.state = S_READ) else engine.dst_addr;
dma_req_o.rvso <= '0'; -- no reservation set operation possible
dma_req_o.amo <= '0'; -- no atomic memory operation possible
dma_req_o.amoop <= (others => '0'); -- no atomic memory operation possible
dma_req_o.fence <= cfg.enable and cfg.fence and engine.done; -- issue FENCE operation when transfer is done
dma_req_o.sleep <= '1' when (engine.state = S_IDLE) else '0'; -- idle = sleep mode
dma_req_o.debug <= '0'; -- can never ever be in debug mode

View file

@ -29,7 +29,7 @@ package neorv32_package is
-- Architecture Constants -----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100806"; -- hardware version
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01100807"; -- hardware version
constant archid_c : natural := 19; -- official RISC-V architecture ID
constant XLEN : natural := 32; -- native data path width
@ -128,7 +128,8 @@ package neorv32_package is
rw : std_ulogic; -- 0=read, 1=write
src : std_ulogic; -- access source (1=instruction fetch, 0=data access)
priv : std_ulogic; -- set if privileged (machine-mode) access
rvso : std_ulogic; -- set if reservation set operation (atomic LR/SC)
amo : std_ulogic; -- set if atomic memory operation
amoop : std_ulogic_vector(3 downto 0); -- type of atomic memory operation
-- out-of-band signals --
fence : std_ulogic; -- set if fence(.i) request by upstream device, single-shot
sleep : std_ulogic; -- set if ALL upstream sources are in sleep mode
@ -151,7 +152,8 @@ package neorv32_package is
rw => '0',
src => '0',
priv => '0',
rvso => '0',
amo => '0',
amoop => (others => '0'),
fence => '0',
sleep => '1',
debug => '0'
@ -736,7 +738,7 @@ package neorv32_package is
RISCV_ISA_E : boolean := false;
RISCV_ISA_M : boolean := false;
RISCV_ISA_U : boolean := false;
RISCV_ISA_Zalrsc : boolean := false;
RISCV_ISA_Zaamo : boolean := false;
RISCV_ISA_Zba : boolean := false;
RISCV_ISA_Zbb : boolean := false;
RISCV_ISA_Zbkb : boolean := false;

View file

@ -43,7 +43,7 @@ entity neorv32_top is
RISCV_ISA_E : boolean := false; -- implement embedded RF extension
RISCV_ISA_M : boolean := false; -- implement mul/div extension
RISCV_ISA_U : boolean := false; -- implement user mode extension
RISCV_ISA_Zalrsc : boolean := false; -- implement atomic reservation-set extension
RISCV_ISA_Zaamo : boolean := false; -- implement atomic memory operations extension
RISCV_ISA_Zba : boolean := false; -- implement shifted-add bit-manipulation extension
RISCV_ISA_Zbb : boolean := false; -- implement basic bit-manipulation extension
RISCV_ISA_Zbkb : boolean := false; -- implement bit-manipulation instructions for cryptography
@ -508,7 +508,7 @@ begin
RISCV_ISA_E => RISCV_ISA_E,
RISCV_ISA_M => RISCV_ISA_M,
RISCV_ISA_U => RISCV_ISA_U,
RISCV_ISA_Zalrsc => RISCV_ISA_Zalrsc,
RISCV_ISA_Zaamo => RISCV_ISA_Zaamo,
RISCV_ISA_Zba => RISCV_ISA_Zba,
RISCV_ISA_Zbb => RISCV_ISA_Zbb,
RISCV_ISA_Zbkb => RISCV_ISA_Zbkb,
@ -727,27 +727,24 @@ begin
-- **************************************************************************************************************************
-- Reservation Set Controller (for atomic LR/SC accesses)
-- Read-Modify-Write Controller for Atomic Memory Operations
-- **************************************************************************************************************************
neorv32_bus_reservation_set_true:
if RISCV_ISA_Zalrsc generate
neorv32_bus_reservation_set_inst: entity neorv32.neorv32_bus_reservation_set
neorv32_bus_amo_ctrl_true:
if RISCV_ISA_Zaamo generate
neorv32_bus_amo_ctrl_inst: entity neorv32.neorv32_bus_amo_ctrl
port map (
clk_i => clk_i,
rstn_i => rstn_sys,
rvs_addr_o => open, -- yet unused
rvs_valid_o => open, -- yet unused
rvs_clear_i => '0', -- yet unused
core_req_i => main_req,
core_rsp_o => main_rsp,
sys_req_o => main2_req,
sys_rsp_i => main2_rsp
clk_i => clk_i,
rstn_i => rstn_sys,
core_req_i => main_req,
core_rsp_o => main_rsp,
sys_req_o => main2_req,
sys_rsp_i => main2_rsp
);
end generate;
neorv32_bus_reservation_set_false:
if not RISCV_ISA_Zalrsc generate
neorv32_bus_amo_ctrl_false:
if not RISCV_ISA_Zaamo generate
main2_req <= main_req;
main_rsp <= main2_rsp;
end generate;