Skip to content

Commit

Permalink
[rtl] reworked register file x0 logic
Browse files Browse the repository at this point in the history
* any write access to x0 will be masked to actually write zero
* no special treatment by the CPU control unit required anymore
* first instruction after hardware reset should write _any_ value to x0 (implemented in start-up code crt0.S)
  • Loading branch information
stnolting committed Aug 8, 2021
1 parent 1610281 commit 7cbcec9
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 86 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ defined by the `hw_version_c` constant in the main VHDL package file [`rtl/core/

| Date (*dd.mm.yyyy*) | Version | Comment |
|:----------:|:-------:|:--------|
| 08.08.2021 | 1.5.8.9 | reworked CPU register file logic: any write access to `x0` will be masked to actually write zero - no special treatment by the CPU control unit required anymore; slighlty less hardware ressources required; first instruction after hardware reset should write `x0` (implemented in start-up code `crt0.S`) |
| 07.08.2021 | 1.5.8.8 | :bug: fixed bug in execution (trapping) of `xRET` instructions: `dret` (return from debug-mode handler) has to raise an illegal instruction exception if executed outside of debug-mode, `mret` (return from machine-mode handler) has to raise an illegal instruction exception if executed in lower-privileged modes (lower than machine-mode) |
| 05.08.2021 | 1.5.8.7 | :sparkles: added `mstatus.FS` and `mstatus.SD` CSR bits: control the state of the FPU (`Zfinx`) extension; supported states for `mstatus.FS`: `00` = _off_, `11` = _dirty_; writing other states will always set _dirty_ state; note that all FPU instructions including FPU CSR access instructions will raise an illegal instrution exception if `mstatus.FS` = _off_ |
| 03.08.2021 | 1.5.8.6 | :bug: fixed bug in linker script [#134](https://github.com/stnolting/neorv32/issues/134): `.rodata.*` "sub"-sections were missing, caused wrong linking of implicit constants (like strings); added `mconfigptr` CSR (RISC-V priv. ISA spec. v1.12-draft ;read-only): holds a pointer to a platfrom/system configuration structure - not actually used yet |
Expand Down
8 changes: 1 addition & 7 deletions rtl/core/neorv32_cpu_control.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -920,14 +920,8 @@ begin
-- state machine --
case execute_engine.state is

when SYS_WAIT => -- System delay cycle (used to wait for side effects to kick in) [and to init r0 with zero if it is a physical register]
when SYS_WAIT => -- System delay cycle (to let side effects kick in)
-- ------------------------------------------------------------
-- set reg_file's r0 to zero --
if (rf_r0_is_reg_c = true) then -- is r0 implemented as physical register, which has to be set to zero?
ctrl_nxt(ctrl_alu_func1_c downto ctrl_alu_func0_c) <= alu_func_cmd_csrr_c; -- hacky! CSR read-access without a valid CSR-read -> results zero
ctrl_nxt(ctrl_rf_r0_we_c) <= '1'; -- force RF write access and force rd=r0
end if;
--
execute_engine.state_nxt <= DISPATCH;


Expand Down
34 changes: 20 additions & 14 deletions rtl/core/neorv32_cpu_regfile.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,10 @@ architecture neorv32_cpu_regfile_rtl of neorv32_cpu_regfile is
signal reg_file_emb : reg_file_emb_t;
signal rf_wdata : std_ulogic_vector(data_width_c-1 downto 0); -- actual write-back data
signal rd_is_r0 : std_ulogic; -- writing to r0?
signal rf_we : std_ulogic;
signal dst_addr : std_ulogic_vector(4 downto 0); -- destination address
signal opa_addr : std_ulogic_vector(4 downto 0); -- rs1/dst address
signal opb_addr : std_ulogic_vector(4 downto 0); -- rs2 address
signal rs1, rs2 : std_ulogic_vector(data_width_c-1 downto 0);
signal rs1, rs2 : std_ulogic_vector(data_width_c-1 downto 0); -- read data

-- comparator --
signal cmp_opx : std_ulogic_vector(data_width_c downto 0);
Expand All @@ -90,7 +89,21 @@ begin

-- Data Input Mux -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
rf_wdata <= alu_i when (ctrl_i(ctrl_rf_in_mux_c) = '0') else mem_i;
input_mux: process(rd_is_r0, ctrl_i, alu_i, mem_i)
begin
if (rd_is_r0 = '1') then -- write zero if accessing x0 to "emulate" it is hardwired to zero
rf_wdata <= (others => '0');
else
if (ctrl_i(ctrl_rf_in_mux_c) = '0') then
rf_wdata <= alu_i;
else
rf_wdata <= mem_i;
end if;
end if;
end process input_mux;

-- check if we are writing to x0 --
rd_is_r0 <= (not or_reduce_f(dst_addr(4 downto 0))) when (CPU_EXTENSION_RISCV_E = false) else (not or_reduce_f(dst_addr(3 downto 0)));


-- Register File Access -------------------------------------------------------------------
Expand All @@ -99,13 +112,13 @@ begin
begin
if rising_edge(clk_i) then -- sync read and write
if (CPU_EXTENSION_RISCV_E = false) then -- normal register file with 32 entries
if (rf_we = '1') then
if (ctrl_i(ctrl_rf_wb_en_c) = '1') then
reg_file(to_integer(unsigned(opa_addr(4 downto 0)))) <= rf_wdata;
end if;
rs1 <= reg_file(to_integer(unsigned(opa_addr(4 downto 0))));
rs2 <= reg_file(to_integer(unsigned(opb_addr(4 downto 0))));
else -- embedded register file with 16 entries
if (rf_we = '1') then
if (ctrl_i(ctrl_rf_wb_en_c) = '1') then
reg_file_emb(to_integer(unsigned(opa_addr(3 downto 0)))) <= rf_wdata;
end if;
rs1 <= reg_file_emb(to_integer(unsigned(opa_addr(3 downto 0))));
Expand All @@ -114,16 +127,9 @@ begin
end if;
end process rf_access;

-- check if we are writing to x0 --
rd_is_r0 <= not or_reduce_f(ctrl_i(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c)) when (CPU_EXTENSION_RISCV_E = false) else
not or_reduce_f(ctrl_i(ctrl_rf_rd_adr3_c downto ctrl_rf_rd_adr0_c));

-- valid RF write access? --
rf_we <= (ctrl_i(ctrl_rf_wb_en_c) and (not rd_is_r0)) or ctrl_i(ctrl_rf_r0_we_c);

-- access addresses --
dst_addr <= ctrl_i(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c) when (ctrl_i(ctrl_rf_r0_we_c) = '0') else (others => '0'); -- force dst=r0?
opa_addr <= dst_addr when (rf_we = '1') else ctrl_i(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c); -- rd/rs1
dst_addr <= ctrl_i(ctrl_rf_rd_adr4_c downto ctrl_rf_rd_adr0_c);
opa_addr <= dst_addr when (ctrl_i(ctrl_rf_wb_en_c) = '1') else ctrl_i(ctrl_rf_rs1_adr4_c downto ctrl_rf_rs1_adr0_c); -- rd/rs1
opb_addr <= ctrl_i(ctrl_rf_rs2_adr4_c downto ctrl_rf_rs2_adr0_c); -- rs2

-- data output --
Expand Down
126 changes: 62 additions & 64 deletions rtl/core/neorv32_package.vhd
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,9 @@ package neorv32_package is

-- Architecture Constants (do not modify!) ------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant data_width_c : natural := 32; -- native data path width - do not change!
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01050808"; -- no touchy!
constant archid_c : natural := 19; -- official NEORV32 architecture ID - hands off!
constant rf_r0_is_reg_c : boolean := true; -- x0 is a *physical register* (FPGA BRAM) that has to be initialized to zero by the CPU
constant data_width_c : natural := 32; -- native data path width - do not change!
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01050809"; -- no touchy!
constant archid_c : natural := 19; -- official NEORV32 architecture ID - hands off!

-- External Interface Types ---------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
Expand Down Expand Up @@ -286,72 +285,71 @@ package neorv32_package is
constant ctrl_rf_rd_adr3_c : natural := 14; -- destination register address bit 3
constant ctrl_rf_rd_adr4_c : natural := 15; -- destination register address bit 4
constant ctrl_rf_wb_en_c : natural := 16; -- write back enable
constant ctrl_rf_r0_we_c : natural := 17; -- force write access and force rd=r0
-- alu --
constant ctrl_alu_arith_c : natural := 18; -- ALU arithmetic command
constant ctrl_alu_logic0_c : natural := 19; -- ALU logic command bit 0
constant ctrl_alu_logic1_c : natural := 20; -- ALU logic command bit 1
constant ctrl_alu_func0_c : natural := 21; -- ALU function select command bit 0
constant ctrl_alu_func1_c : natural := 22; -- ALU function select command bit 1
constant ctrl_alu_addsub_c : natural := 23; -- 0=ADD, 1=SUB
constant ctrl_alu_opa_mux_c : natural := 24; -- operand A select (0=rs1, 1=PC)
constant ctrl_alu_opb_mux_c : natural := 25; -- operand B select (0=rs2, 1=IMM)
constant ctrl_alu_unsigned_c : natural := 26; -- is unsigned ALU operation
constant ctrl_alu_shift_dir_c : natural := 27; -- shift direction (0=left, 1=right)
constant ctrl_alu_shift_ar_c : natural := 28; -- is arithmetic shift
constant ctrl_alu_frm0_c : natural := 29; -- FPU rounding mode bit 0
constant ctrl_alu_frm1_c : natural := 30; -- FPU rounding mode bit 1
constant ctrl_alu_frm2_c : natural := 31; -- FPU rounding mode bit 2
constant ctrl_alu_arith_c : natural := 17; -- ALU arithmetic command
constant ctrl_alu_logic0_c : natural := 18; -- ALU logic command bit 0
constant ctrl_alu_logic1_c : natural := 19; -- ALU logic command bit 1
constant ctrl_alu_func0_c : natural := 20; -- ALU function select command bit 0
constant ctrl_alu_func1_c : natural := 21; -- ALU function select command bit 1
constant ctrl_alu_addsub_c : natural := 22; -- 0=ADD, 1=SUB
constant ctrl_alu_opa_mux_c : natural := 23; -- operand A select (0=rs1, 1=PC)
constant ctrl_alu_opb_mux_c : natural := 24; -- operand B select (0=rs2, 1=IMM)
constant ctrl_alu_unsigned_c : natural := 25; -- is unsigned ALU operation
constant ctrl_alu_shift_dir_c : natural := 26; -- shift direction (0=left, 1=right)
constant ctrl_alu_shift_ar_c : natural := 27; -- is arithmetic shift
constant ctrl_alu_frm0_c : natural := 28; -- FPU rounding mode bit 0
constant ctrl_alu_frm1_c : natural := 29; -- FPU rounding mode bit 1
constant ctrl_alu_frm2_c : natural := 30; -- FPU rounding mode bit 2
-- bus interface --
constant ctrl_bus_size_lsb_c : natural := 32; -- transfer size lsb (00=byte, 01=half-word)
constant ctrl_bus_size_msb_c : natural := 33; -- transfer size msb (10=word, 11=?)
constant ctrl_bus_rd_c : natural := 34; -- read data request
constant ctrl_bus_wr_c : natural := 35; -- write data request
constant ctrl_bus_if_c : natural := 36; -- instruction fetch request
constant ctrl_bus_mo_we_c : natural := 37; -- memory address and data output register write enable
constant ctrl_bus_mi_we_c : natural := 38; -- memory data input register write enable
constant ctrl_bus_unsigned_c : natural := 39; -- is unsigned load
constant ctrl_bus_ierr_ack_c : natural := 40; -- acknowledge instruction fetch bus exceptions
constant ctrl_bus_derr_ack_c : natural := 41; -- acknowledge data access bus exceptions
constant ctrl_bus_fence_c : natural := 42; -- executed fence operation
constant ctrl_bus_fencei_c : natural := 43; -- executed fencei operation
constant ctrl_bus_lock_c : natural := 44; -- make atomic/exclusive access lock
constant ctrl_bus_de_lock_c : natural := 45; -- remove atomic/exclusive access
constant ctrl_bus_ch_lock_c : natural := 46; -- evaluate atomic/exclusive lock (SC operation)
constant ctrl_bus_size_lsb_c : natural := 31; -- transfer size lsb (00=byte, 01=half-word)
constant ctrl_bus_size_msb_c : natural := 32; -- transfer size msb (10=word, 11=?)
constant ctrl_bus_rd_c : natural := 33; -- read data request
constant ctrl_bus_wr_c : natural := 34; -- write data request
constant ctrl_bus_if_c : natural := 35; -- instruction fetch request
constant ctrl_bus_mo_we_c : natural := 36; -- memory address and data output register write enable
constant ctrl_bus_mi_we_c : natural := 37; -- memory data input register write enable
constant ctrl_bus_unsigned_c : natural := 38; -- is unsigned load
constant ctrl_bus_ierr_ack_c : natural := 39; -- acknowledge instruction fetch bus exceptions
constant ctrl_bus_derr_ack_c : natural := 40; -- acknowledge data access bus exceptions
constant ctrl_bus_fence_c : natural := 41; -- executed fence operation
constant ctrl_bus_fencei_c : natural := 42; -- executed fencei operation
constant ctrl_bus_lock_c : natural := 43; -- make atomic/exclusive access lock
constant ctrl_bus_de_lock_c : natural := 44; -- remove atomic/exclusive access
constant ctrl_bus_ch_lock_c : natural := 45; -- evaluate atomic/exclusive lock (SC operation)
-- co-processors --
constant ctrl_cp_id_lsb_c : natural := 47; -- cp select ID lsb
constant ctrl_cp_id_msb_c : natural := 48; -- cp select ID msb
constant ctrl_cp_id_lsb_c : natural := 46; -- cp select ID lsb
constant ctrl_cp_id_msb_c : natural := 47; -- cp select ID msb
-- instruction's control blocks (used by cpu co-processors) --
constant ctrl_ir_funct3_0_c : natural := 49; -- funct3 bit 0
constant ctrl_ir_funct3_1_c : natural := 50; -- funct3 bit 1
constant ctrl_ir_funct3_2_c : natural := 51; -- funct3 bit 2
constant ctrl_ir_funct12_0_c : natural := 52; -- funct12 bit 0
constant ctrl_ir_funct12_1_c : natural := 53; -- funct12 bit 1
constant ctrl_ir_funct12_2_c : natural := 54; -- funct12 bit 2
constant ctrl_ir_funct12_3_c : natural := 55; -- funct12 bit 3
constant ctrl_ir_funct12_4_c : natural := 56; -- funct12 bit 4
constant ctrl_ir_funct12_5_c : natural := 57; -- funct12 bit 5
constant ctrl_ir_funct12_6_c : natural := 58; -- funct12 bit 6
constant ctrl_ir_funct12_7_c : natural := 59; -- funct12 bit 7
constant ctrl_ir_funct12_8_c : natural := 60; -- funct12 bit 8
constant ctrl_ir_funct12_9_c : natural := 61; -- funct12 bit 9
constant ctrl_ir_funct12_10_c : natural := 62; -- funct12 bit 10
constant ctrl_ir_funct12_11_c : natural := 63; -- funct12 bit 11
constant ctrl_ir_opcode7_0_c : natural := 64; -- opcode7 bit 0
constant ctrl_ir_opcode7_1_c : natural := 65; -- opcode7 bit 1
constant ctrl_ir_opcode7_2_c : natural := 66; -- opcode7 bit 2
constant ctrl_ir_opcode7_3_c : natural := 67; -- opcode7 bit 3
constant ctrl_ir_opcode7_4_c : natural := 68; -- opcode7 bit 4
constant ctrl_ir_opcode7_5_c : natural := 69; -- opcode7 bit 5
constant ctrl_ir_opcode7_6_c : natural := 70; -- opcode7 bit 6
constant ctrl_ir_funct3_0_c : natural := 48; -- funct3 bit 0
constant ctrl_ir_funct3_1_c : natural := 49; -- funct3 bit 1
constant ctrl_ir_funct3_2_c : natural := 50; -- funct3 bit 2
constant ctrl_ir_funct12_0_c : natural := 51; -- funct12 bit 0
constant ctrl_ir_funct12_1_c : natural := 52; -- funct12 bit 1
constant ctrl_ir_funct12_2_c : natural := 53; -- funct12 bit 2
constant ctrl_ir_funct12_3_c : natural := 54; -- funct12 bit 3
constant ctrl_ir_funct12_4_c : natural := 55; -- funct12 bit 4
constant ctrl_ir_funct12_5_c : natural := 56; -- funct12 bit 5
constant ctrl_ir_funct12_6_c : natural := 57; -- funct12 bit 6
constant ctrl_ir_funct12_7_c : natural := 58; -- funct12 bit 7
constant ctrl_ir_funct12_8_c : natural := 59; -- funct12 bit 8
constant ctrl_ir_funct12_9_c : natural := 60; -- funct12 bit 9
constant ctrl_ir_funct12_10_c : natural := 61; -- funct12 bit 10
constant ctrl_ir_funct12_11_c : natural := 62; -- funct12 bit 11
constant ctrl_ir_opcode7_0_c : natural := 63; -- opcode7 bit 0
constant ctrl_ir_opcode7_1_c : natural := 64; -- opcode7 bit 1
constant ctrl_ir_opcode7_2_c : natural := 65; -- opcode7 bit 2
constant ctrl_ir_opcode7_3_c : natural := 66; -- opcode7 bit 3
constant ctrl_ir_opcode7_4_c : natural := 67; -- opcode7 bit 4
constant ctrl_ir_opcode7_5_c : natural := 68; -- opcode7 bit 5
constant ctrl_ir_opcode7_6_c : natural := 69; -- opcode7 bit 6
-- CPU status --
constant ctrl_priv_lvl_lsb_c : natural := 71; -- privilege level lsb
constant ctrl_priv_lvl_msb_c : natural := 72; -- privilege level msb
constant ctrl_sleep_c : natural := 73; -- set when CPU is in sleep mode
constant ctrl_trap_c : natural := 74; -- set when CPU is entering trap execution
constant ctrl_debug_running_c : natural := 75; -- CPU is in debug mode when set
constant ctrl_priv_lvl_lsb_c : natural := 70; -- privilege level lsb
constant ctrl_priv_lvl_msb_c : natural := 71; -- privilege level msb
constant ctrl_sleep_c : natural := 72; -- set when CPU is in sleep mode
constant ctrl_trap_c : natural := 73; -- set when CPU is entering trap execution
constant ctrl_debug_running_c : natural := 74; -- CPU is in debug mode when set
-- control bus size --
constant ctrl_width_c : natural := 76; -- control bus size
constant ctrl_width_c : natural := 75; -- control bus size

-- Comparator Bus -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
Expand Down
7 changes: 6 additions & 1 deletion sw/common/crt0.S
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,12 @@ _start:
.cfi_startproc
.cfi_undefined ra

lui zero, 0 // dummy instruction that uses no reg-file operands at all

// ************************************************************************************************
// This is the very first instruction that is executed after hardware reset. It ensures that x0 is
// written at least once - the CPU HW will ensure it is always set to zero on any write access.
// ************************************************************************************************
lui zero, 0 // "dummy" instruction that uses no reg-file input operands at all


// ************************************************************************************************
Expand Down

0 comments on commit 7cbcec9

Please sign in to comment.