[rtl] reworks, cleanups and optimizations (#550)

This commit is contained in:
Stephan 2023-03-17 09:45:49 +01:00 committed by GitHub
commit eb6ec2202f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 221 additions and 268 deletions

View file

@ -31,6 +31,7 @@ mimpid = 0x01040312 => Version 01.04.03.12 => v1.4.3.12
| Date (*dd.mm.yyyy*) | Version | Comment |
|:-------------------:|:-------:|:--------|
| 15.03.2023 | 1.8.2.3 | rtl reworks, cleanups and optimizations; [#550](https://github.com/stnolting/neorv32/pull/550) |
| 11.03.2023 | 1.8.2.2 | :sparkles: add support for RISC-V `Zicond` ISA extension (conditional operations); [#546](https://github.com/stnolting/neorv32/pull/546) |
| 10.02.2023 | 1.8.2.1 | rtl code edits, clean-ups and minor optimizations (improve branch prediction); [#545](https://github.com/stnolting/neorv32/pull/545) |
| 10.03.2023 | [**:rocket:1.8.2**](https://github.com/stnolting/neorv32/releases/tag/v1.8.2) | **New release** |

View file

@ -369,7 +369,6 @@ architecture neorv32_cpu_control_rtl of neorv32_cpu_control is
-- illegal instruction check --
signal illegal_cmd : std_ulogic;
signal illegal_reg : std_ulogic; -- illegal register (>x15) - E-extension
-- CSR access/privilege and r/w check --
signal csr_reg_valid : std_ulogic; -- valid CSR access (implemented at all)
@ -494,8 +493,7 @@ begin
FIFO_DEPTH => CPU_IPB_ENTRIES, -- number of fifo entries; has to be a power of two; min 1
FIFO_WIDTH => ipb.wdata(i)'length, -- size of data elements in fifo
FIFO_RSYNC => false, -- we NEED to read data asynchronously
FIFO_SAFE => false, -- no safe access required (ensured by FIFO-external control)
FIFO_GATE => false -- no output gate required
FIFO_SAFE => false -- no safe access required (ensured by FIFO-external control)
)
port map (
-- control --
@ -1334,7 +1332,6 @@ begin
begin
-- defaults --
illegal_cmd <= '0';
illegal_reg <= '0';
-- check instruction word encoding and side effects --
case execute_engine.i_reg(instr_opcode_msb_c downto instr_opcode_lsb_c) is
@ -1342,7 +1339,6 @@ begin
when opcode_lui_c | opcode_auipc_c | opcode_jal_c => -- LUI, UIPC, JAL (only check actual OPCODE)
-- ------------------------------------------------------------
illegal_cmd <= '0';
illegal_reg <= execute_engine.i_reg(instr_rd_msb_c); -- illegal 'E' register?
when opcode_jalr_c => -- check JALR.funct3
-- ------------------------------------------------------------
@ -1350,7 +1346,6 @@ begin
when "000" => illegal_cmd <= '0';
when others => illegal_cmd <= '1';
end case;
illegal_reg <= execute_engine.i_reg(instr_rs1_msb_c) or execute_engine.i_reg(instr_rd_msb_c); -- illegal 'E' register?
when opcode_branch_c => -- check BRANCH.funct3
-- ------------------------------------------------------------
@ -1358,7 +1353,6 @@ begin
when funct3_beq_c | funct3_bne_c | funct3_blt_c | funct3_bge_c | funct3_bltu_c | funct3_bgeu_c => illegal_cmd <= '0';
when others => illegal_cmd <= '1';
end case;
illegal_reg <= execute_engine.i_reg(instr_rs2_msb_c) or execute_engine.i_reg(instr_rs1_msb_c); -- illegal 'E' register?
when opcode_load_c => -- check LOAD.funct3
-- ------------------------------------------------------------
@ -1366,7 +1360,6 @@ begin
when funct3_lb_c | funct3_lh_c | funct3_lw_c | funct3_lbu_c | funct3_lhu_c => illegal_cmd <= '0';
when others => illegal_cmd <= '1';
end case;
illegal_reg <= execute_engine.i_reg(instr_rs1_msb_c) or execute_engine.i_reg(instr_rd_msb_c); -- illegal 'E' register?
when opcode_store_c => -- check STORE.funct3
-- ------------------------------------------------------------
@ -1374,7 +1367,6 @@ begin
when funct3_sb_c | funct3_sh_c | funct3_sw_c => illegal_cmd <= '0';
when others => illegal_cmd <= '1';
end case;
illegal_reg <= execute_engine.i_reg(instr_rs2_msb_c) or execute_engine.i_reg(instr_rs1_msb_c); -- illegal 'E' register?
when opcode_alu_c => -- check ALU.funct3 & ALU.funct7
-- ------------------------------------------------------------
@ -1395,7 +1387,6 @@ begin
else
illegal_cmd <= '1';
end if;
illegal_reg <= execute_engine.i_reg(instr_rd_msb_c) or execute_engine.i_reg(instr_rs1_msb_c) or execute_engine.i_reg(instr_rs2_msb_c); -- illegal 'E' register?
when opcode_alui_c => -- check ALU.funct3 & ALU.funct7
-- ------------------------------------------------------------
@ -1414,7 +1405,6 @@ begin
else
illegal_cmd <= '1';
end if;
illegal_reg <= execute_engine.i_reg(instr_rs1_msb_c) or execute_engine.i_reg(instr_rd_msb_c); -- illegal 'E' register?
when opcode_fence_c => -- check FENCE.funct3, ignore all remaining bit-fields
-- ------------------------------------------------------------
@ -1444,27 +1434,14 @@ begin
else
illegal_cmd <= '0';
end if;
-- illegal E-CPU register? --
if (execute_engine.i_reg(instr_funct3_msb_c) = '0') then -- reg-reg CSR (or ENV where rd=rs1=zero)
illegal_reg <= execute_engine.i_reg(instr_rd_msb_c) or execute_engine.i_reg(instr_rs1_msb_c);
else -- reg-imm CSR
illegal_reg <= execute_engine.i_reg(instr_rd_msb_c);
end if;
when opcode_fop_c => -- floating point operations - single/dual operands
-- ------------------------------------------------------------
if (CPU_EXTENSION_RISCV_Zfinx = true) and (decode_aux.is_f_op = '1') then -- is supported floating-point instruction
illegal_cmd <= '0';
illegal_reg <= execute_engine.i_reg(instr_rs2_msb_c) or execute_engine.i_reg(instr_rs1_msb_c) or execute_engine.i_reg(instr_rd_msb_c); -- illegal 'E' register?
else
illegal_cmd <= '1';
illegal_reg <= '0';
end if;
illegal_cmd <= (not bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zxcfu)) or (not decode_aux.is_f_op);
when opcode_cust0_c | opcode_cust1_c | opcode_cust2_c | opcode_cust3_c => -- custom instructions (CFU)
-- ------------------------------------------------------------
illegal_cmd <= not bool_to_ulogic_f(CPU_EXTENSION_RISCV_Zxcfu); -- CFU extension implemented?
illegal_reg <= '0'; -- custom instruction do not trap if a register above x15 is used when E ISA extension is enabled
when others => -- undefined/illegal opcode
-- ------------------------------------------------------------
@ -1477,9 +1454,8 @@ begin
-- Illegal Operation Check ----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- check in EXECUTE state: any illegal instruction processing condition? --
trap_ctrl.instr_il <= (illegal_cmd or alu_exc_i or -- illegal instruction or ALU processing exception
(bool_to_ulogic_f(CPU_EXTENSION_RISCV_E) and illegal_reg) or -- illegal register access in E extension
(bool_to_ulogic_f(CPU_EXTENSION_RISCV_C) and execute_engine.is_ici)) -- illegal compressed instruction
trap_ctrl.instr_il <= illegal_cmd or alu_exc_i or -- illegal instruction or ALU processing exception
(bool_to_ulogic_f(CPU_EXTENSION_RISCV_C) and execute_engine.is_ici) -- illegal compressed instruction
when ((execute_engine.state = EXECUTE) or (execute_engine.state = ALU_WAIT)) else '0'; -- evaluate in execution stages only
@ -1635,41 +1611,41 @@ begin
begin
if rising_edge(clk_i) then
-- standard RISC-V exceptions --
if (trap_ctrl.exc_buf(exc_ialign_c) = '1') then trap_ctrl.cause <= trap_ima_c; -- instruction address misaligned
elsif (trap_ctrl.exc_buf(exc_iaccess_c) = '1') then trap_ctrl.cause <= trap_iba_c; -- instruction access fault
elsif (trap_ctrl.exc_buf(exc_iillegal_c) = '1') then trap_ctrl.cause <= trap_iil_c; -- illegal instruction
elsif (trap_ctrl.exc_buf(exc_envcall_c) = '1') then trap_ctrl.cause <= trap_env_c(6 downto 2) & csr.privilege & csr.privilege; -- environment call (U/M)
elsif (trap_ctrl.exc_buf(exc_break_c) = '1') then trap_ctrl.cause <= trap_brk_c; -- breakpoint
elsif (trap_ctrl.exc_buf(exc_salign_c) = '1') then trap_ctrl.cause <= trap_sma_c; -- store address misaligned
elsif (trap_ctrl.exc_buf(exc_lalign_c) = '1') then trap_ctrl.cause <= trap_lma_c; -- load address misaligned
elsif (trap_ctrl.exc_buf(exc_saccess_c) = '1') then trap_ctrl.cause <= trap_sbe_c; -- store access fault
elsif (trap_ctrl.exc_buf(exc_laccess_c) = '1') then trap_ctrl.cause <= trap_lbe_c; -- load access fault
if (trap_ctrl.exc_buf(exc_ialign_c) = '1') then trap_ctrl.cause <= trap_ima_c; -- instruction address misaligned
elsif (trap_ctrl.exc_buf(exc_iaccess_c) = '1') then trap_ctrl.cause <= trap_iba_c; -- instruction access fault
elsif (trap_ctrl.exc_buf(exc_iillegal_c) = '1') then trap_ctrl.cause <= trap_iil_c; -- illegal instruction
elsif (trap_ctrl.exc_buf(exc_envcall_c) = '1') then trap_ctrl.cause <= trap_env_c(6 downto 2) & csr.privilege & csr.privilege; -- environment call (U/M)
elsif (trap_ctrl.exc_buf(exc_break_c) = '1') then trap_ctrl.cause <= trap_brk_c; -- breakpoint
elsif (trap_ctrl.exc_buf(exc_salign_c) = '1') then trap_ctrl.cause <= trap_sma_c; -- store address misaligned
elsif (trap_ctrl.exc_buf(exc_lalign_c) = '1') then trap_ctrl.cause <= trap_lma_c; -- load address misaligned
elsif (trap_ctrl.exc_buf(exc_saccess_c) = '1') then trap_ctrl.cause <= trap_sbe_c; -- store access fault
elsif (trap_ctrl.exc_buf(exc_laccess_c) = '1') then trap_ctrl.cause <= trap_lbe_c; -- load access fault
-- debug mode exceptions and interrupts --
elsif (trap_ctrl.irq_buf(irq_db_halt_c) = '1') then trap_ctrl.cause <= trap_db_halt_c; -- external halt request (async)
elsif (trap_ctrl.exc_buf(exc_db_hw_c) = '1') then trap_ctrl.cause <= trap_db_trig_c; -- hardware trigger (sync)
elsif (trap_ctrl.exc_buf(exc_db_break_c) = '1') then trap_ctrl.cause <= trap_db_break_c; -- break instruction (sync)
elsif (trap_ctrl.irq_buf(irq_db_step_c) = '1') then trap_ctrl.cause <= trap_db_step_c; -- single stepping (async)
-- NEORV32-specific fast interrupts --
elsif (trap_ctrl.irq_buf(irq_firq_0_c) = '1') then trap_ctrl.cause <= trap_firq0_c; -- fast interrupt channel 0
elsif (trap_ctrl.irq_buf(irq_firq_1_c) = '1') then trap_ctrl.cause <= trap_firq1_c; -- fast interrupt channel 1
elsif (trap_ctrl.irq_buf(irq_firq_2_c) = '1') then trap_ctrl.cause <= trap_firq2_c; -- fast interrupt channel 2
elsif (trap_ctrl.irq_buf(irq_firq_3_c) = '1') then trap_ctrl.cause <= trap_firq3_c; -- fast interrupt channel 3
elsif (trap_ctrl.irq_buf(irq_firq_4_c) = '1') then trap_ctrl.cause <= trap_firq4_c; -- fast interrupt channel 4
elsif (trap_ctrl.irq_buf(irq_firq_5_c) = '1') then trap_ctrl.cause <= trap_firq5_c; -- fast interrupt channel 5
elsif (trap_ctrl.irq_buf(irq_firq_6_c) = '1') then trap_ctrl.cause <= trap_firq6_c; -- fast interrupt channel 6
elsif (trap_ctrl.irq_buf(irq_firq_7_c) = '1') then trap_ctrl.cause <= trap_firq7_c; -- fast interrupt channel 7
elsif (trap_ctrl.irq_buf(irq_firq_8_c) = '1') then trap_ctrl.cause <= trap_firq8_c; -- fast interrupt channel 8
elsif (trap_ctrl.irq_buf(irq_firq_9_c) = '1') then trap_ctrl.cause <= trap_firq9_c; -- fast interrupt channel 9
elsif (trap_ctrl.irq_buf(irq_firq_10_c) = '1') then trap_ctrl.cause <= trap_firq10_c; -- fast interrupt channel 10
elsif (trap_ctrl.irq_buf(irq_firq_11_c) = '1') then trap_ctrl.cause <= trap_firq11_c; -- fast interrupt channel 11
elsif (trap_ctrl.irq_buf(irq_firq_12_c) = '1') then trap_ctrl.cause <= trap_firq12_c; -- fast interrupt channel 12
elsif (trap_ctrl.irq_buf(irq_firq_13_c) = '1') then trap_ctrl.cause <= trap_firq13_c; -- fast interrupt channel 13
elsif (trap_ctrl.irq_buf(irq_firq_14_c) = '1') then trap_ctrl.cause <= trap_firq14_c; -- fast interrupt channel 14
elsif (trap_ctrl.irq_buf(irq_firq_15_c) = '1') then trap_ctrl.cause <= trap_firq15_c; -- fast interrupt channel 15
elsif (trap_ctrl.irq_buf(irq_firq_0_c) = '1') then trap_ctrl.cause <= trap_firq0_c; -- fast interrupt channel 0
elsif (trap_ctrl.irq_buf(irq_firq_1_c) = '1') then trap_ctrl.cause <= trap_firq1_c; -- fast interrupt channel 1
elsif (trap_ctrl.irq_buf(irq_firq_2_c) = '1') then trap_ctrl.cause <= trap_firq2_c; -- fast interrupt channel 2
elsif (trap_ctrl.irq_buf(irq_firq_3_c) = '1') then trap_ctrl.cause <= trap_firq3_c; -- fast interrupt channel 3
elsif (trap_ctrl.irq_buf(irq_firq_4_c) = '1') then trap_ctrl.cause <= trap_firq4_c; -- fast interrupt channel 4
elsif (trap_ctrl.irq_buf(irq_firq_5_c) = '1') then trap_ctrl.cause <= trap_firq5_c; -- fast interrupt channel 5
elsif (trap_ctrl.irq_buf(irq_firq_6_c) = '1') then trap_ctrl.cause <= trap_firq6_c; -- fast interrupt channel 6
elsif (trap_ctrl.irq_buf(irq_firq_7_c) = '1') then trap_ctrl.cause <= trap_firq7_c; -- fast interrupt channel 7
elsif (trap_ctrl.irq_buf(irq_firq_8_c) = '1') then trap_ctrl.cause <= trap_firq8_c; -- fast interrupt channel 8
elsif (trap_ctrl.irq_buf(irq_firq_9_c) = '1') then trap_ctrl.cause <= trap_firq9_c; -- fast interrupt channel 9
elsif (trap_ctrl.irq_buf(irq_firq_10_c) = '1') then trap_ctrl.cause <= trap_firq10_c; -- fast interrupt channel 10
elsif (trap_ctrl.irq_buf(irq_firq_11_c) = '1') then trap_ctrl.cause <= trap_firq11_c; -- fast interrupt channel 11
elsif (trap_ctrl.irq_buf(irq_firq_12_c) = '1') then trap_ctrl.cause <= trap_firq12_c; -- fast interrupt channel 12
elsif (trap_ctrl.irq_buf(irq_firq_13_c) = '1') then trap_ctrl.cause <= trap_firq13_c; -- fast interrupt channel 13
elsif (trap_ctrl.irq_buf(irq_firq_14_c) = '1') then trap_ctrl.cause <= trap_firq14_c; -- fast interrupt channel 14
elsif (trap_ctrl.irq_buf(irq_firq_15_c) = '1') then trap_ctrl.cause <= trap_firq15_c; -- fast interrupt channel 15
-- standard RISC-V interrupts --
elsif (trap_ctrl.irq_buf(irq_mei_irq_c) = '1') then trap_ctrl.cause <= trap_mei_c; -- machine external interrupt (MEI)
elsif (trap_ctrl.irq_buf(irq_msi_irq_c) = '1') then trap_ctrl.cause <= trap_msi_c; -- machine SW interrupt (MSI)
elsif (trap_ctrl.irq_buf(irq_mti_irq_c) = '1') then trap_ctrl.cause <= trap_mti_c; -- machine timer interrupt (MTI)
elsif (trap_ctrl.irq_buf(irq_mei_irq_c) = '1') then trap_ctrl.cause <= trap_mei_c; -- machine external interrupt (MEI)
elsif (trap_ctrl.irq_buf(irq_msi_irq_c) = '1') then trap_ctrl.cause <= trap_msi_c; -- machine SW interrupt (MSI)
elsif (trap_ctrl.irq_buf(irq_mti_irq_c) = '1') then trap_ctrl.cause <= trap_mti_c; -- machine timer interrupt (MTI)
else trap_ctrl.cause <= trap_mti_c; end if; -- don't care
end if;
end process trap_encoder;

View file

@ -1,5 +1,5 @@
-- #################################################################################################
-- # << NEORV32 - Generic Single-Clock FIFO >> #
-- # << NEORV32 - Generic Single-Clock FIFO Component >> #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License #
-- # #
@ -44,8 +44,7 @@ entity neorv32_fifo is
FIFO_DEPTH : natural; -- number of fifo entries; has to be a power of two; min 1
FIFO_WIDTH : natural; -- size of data elements in fifo
FIFO_RSYNC : boolean; -- false = async read; true = sync read
FIFO_SAFE : boolean; -- true = allow read/write only if entry available
FIFO_GATE : boolean -- true = use output gate (set to zero if no valid data available)
FIFO_SAFE : boolean -- true = allow read/write only if entry available
);
port (
-- control --
@ -78,13 +77,13 @@ architecture neorv32_fifo_rtl of neorv32_fifo is
match : std_ulogic;
empty : std_ulogic;
full : std_ulogic;
half : std_ulogic;
free : std_ulogic;
avail : std_ulogic;
end record;
signal fifo : fifo_t;
-- misc --
signal rdata : std_ulogic_vector(FIFO_WIDTH-1 downto 0);
signal level_diff : std_ulogic_vector(index_size_f(FIFO_DEPTH) downto 0);
begin
@ -98,12 +97,12 @@ begin
-- Access Control -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
fifo.re <= re_i when (FIFO_SAFE = false) else (re_i and fifo.avail); -- SAFE = read only if data available
fifo.we <= we_i when (FIFO_SAFE = false) else (we_i and fifo.free); -- SAFE = write only if space left
fifo.we <= we_i when (FIFO_SAFE = false) else (we_i and fifo.free); -- SAFE = write only if space left
-- FIFO Pointers --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
fifo_pointers: process(rstn_i, clk_i)
process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
fifo.w_pnt <= (others => '0');
@ -122,7 +121,7 @@ begin
fifo.r_pnt <= std_ulogic_vector(unsigned(fifo.r_pnt) + 1);
end if;
end if;
end process fifo_pointers;
end process;
-- FIFO Status ----------------------------------------------------------------------------
@ -132,100 +131,105 @@ begin
fifo.match <= '1' when (fifo.r_pnt(fifo.r_pnt'left-1 downto 0) = fifo.w_pnt(fifo.w_pnt'left-1 downto 0)) else '0';
fifo.full <= '1' when (fifo.r_pnt(fifo.r_pnt'left) /= fifo.w_pnt(fifo.w_pnt'left)) and (fifo.match = '1') else '0';
fifo.empty <= '1' when (fifo.r_pnt(fifo.r_pnt'left) = fifo.w_pnt(fifo.w_pnt'left)) and (fifo.match = '1') else '0';
end generate; -- /check_large
level_diff <= std_ulogic_vector(unsigned(fifo.w_pnt) - unsigned(fifo.r_pnt));
fifo.half <= level_diff(level_diff'left-1) or fifo.full;
end generate;
check_small:
if (FIFO_DEPTH <= 1) generate
if (FIFO_DEPTH = 1) generate
fifo.match <= '1' when (fifo.r_pnt(0) = fifo.w_pnt(0)) else '0';
fifo.full <= not fifo.match;
fifo.empty <= fifo.match;
end generate; -- /check_small
level_diff <= (others => '0'); -- unused
fifo.half <= fifo.full;
end generate;
fifo.free <= not fifo.full;
fifo.avail <= not fifo.empty;
free_o <= fifo.free;
avail_o <= fifo.avail;
fifo_half_level_simple:
if (FIFO_DEPTH = 1) generate
half_o <= fifo.full;
end generate; -- /fifo_half_level_simple
-- Status Output --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
status_async: -- asynchronous
if (FIFO_RSYNC = false) generate
free_o <= fifo.free;
avail_o <= fifo.avail;
half_o <= fifo.half;
end generate;
fifo_half_level_complex:
if (FIFO_DEPTH > 1) generate
level_diff <= std_ulogic_vector(unsigned(fifo.w_pnt) - unsigned(fifo.r_pnt));
half_o <= level_diff(level_diff'left-1) or fifo.full;
end generate; -- /fifo_half_level_complex
status_sync: -- synchronous
if (FIFO_RSYNC = true) generate
process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
free_o <= '0';
avail_o <= '0';
half_o <= '0';
elsif rising_edge(clk_i) then
free_o <= fifo.free;
avail_o <= fifo.avail;
half_o <= fifo.half;
end if;
end process;
end generate;
-- FIFO Memory - Write --------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- "real" FIFO memory (several entries) --
fifo_memory:
fifo_memory: -- real FIFO memory (several entries)
if (FIFO_DEPTH > 1) generate
fifo_write: process(clk_i)
process(clk_i)
begin
if rising_edge(clk_i) then
if (fifo.we = '1') then
fifo.data(to_integer(unsigned(fifo.w_pnt(fifo.w_pnt'left-1 downto 0)))) <= wdata_i;
end if;
end if;
end process fifo_write;
end process;
fifo.buf <= (others => '0'); -- unused
end generate; -- /fifo_memory
end generate;
-- simple register/buffer (single entry) --
fifo_buffer:
fifo_buffer: -- simple register (single entry)
if (FIFO_DEPTH = 1) generate
fifo_write: process(clk_i)
process(clk_i)
begin
if rising_edge(clk_i) then
if (fifo.we = '1') then
fifo.buf <= wdata_i;
end if;
end if;
end process fifo_write;
end process;
fifo.data <= (others => (others => '0')); -- unused
end generate; -- /fifo_buffer
end generate;
-- FIFO Memory - Read ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- "asynchronous" read --
fifo_read_async:
fifo_read_async: -- "asynchronous" read
if (FIFO_RSYNC = false) generate
fifo_read: process(fifo)
process(fifo)
begin
if (FIFO_DEPTH = 1) then
rdata <= fifo.buf;
rdata_o <= fifo.buf;
else
rdata <= fifo.data(to_integer(unsigned(fifo.r_pnt(fifo.r_pnt'left-1 downto 0))));
rdata_o <= fifo.data(to_integer(unsigned(fifo.r_pnt(fifo.r_pnt'left-1 downto 0))));
end if;
end process fifo_read;
end generate; -- /fifo_read_async
end process;
end generate;
-- synchronous read --
fifo_read_sync:
fifo_read_sync: -- synchronous read
if (FIFO_RSYNC = true) generate
fifo_read: process(clk_i)
process(clk_i)
begin
if rising_edge(clk_i) then
if (FIFO_DEPTH = 1) then
rdata <= fifo.buf;
rdata_o <= fifo.buf;
else
rdata <= fifo.data(to_integer(unsigned(fifo.r_pnt(fifo.r_pnt'left-1 downto 0))));
rdata_o <= fifo.data(to_integer(unsigned(fifo.r_pnt(fifo.r_pnt'left-1 downto 0))));
end if;
end if;
end process fifo_read;
end generate; -- /fifo_read_sync
-- Output Gate ----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- Since the FIFO memory (block RAM) does not have a reset, this option can be used to
-- ensure the output data is always *defined* (by setting the output to all-zero if
-- not valid data is available).
rdata_o <= rdata when ((FIFO_GATE = false) or (fifo.avail = '1')) else (others => '0');
end process;
end generate;
end neorv32_fifo_rtl;

View file

@ -154,10 +154,9 @@ architecture neorv32_neoled_rtl of neorv32_neoled is
signal tx_fifo : tx_fifo_t;
-- serial transmission engine --
type serial_state_t is (S_IDLE, S_INIT, S_GETBIT, S_PULSE, S_STROBE);
type serial_t is record
-- state control --
state : serial_state_t;
state : std_ulogic_vector(2 downto 0);
mode : std_ulogic;
done : std_ulogic;
busy : std_ulogic;
@ -170,7 +169,6 @@ architecture neorv32_neoled_rtl of neorv32_neoled is
pulse_cnt : std_ulogic_vector(4 downto 0);
t_high : std_ulogic_vector(4 downto 0);
strobe_cnt : std_ulogic_vector(6 downto 0);
tx_out : std_ulogic;
end record;
signal serial : serial_t;
@ -252,8 +250,7 @@ begin
FIFO_DEPTH => FIFO_DEPTH, -- number of fifo entries; has to be a power of two; min 1
FIFO_WIDTH => 32+2, -- size of data elements in fifo
FIFO_RSYNC => true, -- sync read
FIFO_SAFE => true, -- safe access
FIFO_GATE => false -- no output gate required
FIFO_SAFE => true -- safe access
)
port map (
-- control --
@ -271,7 +268,7 @@ begin
avail_o => tx_fifo.avail -- data available when set
);
tx_fifo.re <= '1' when (serial.state = S_IDLE) else '0';
tx_fifo.re <= '1' when (serial.state = "100") else '0';
tx_fifo.we <= '1' when (wren = '1') and (addr = neoled_data_addr_c) else '0';
tx_fifo.wdata <= ctrl.strobe & ctrl.mode & data_i;
tx_fifo.clear <= not ctrl.enable;
@ -299,99 +296,88 @@ begin
serial.done <= '0';
-- FSM --
if (ctrl.enable = '0') then -- disabled
serial.tx_out <= '0';
serial.state <= S_IDLE;
else
case serial.state is
serial.state(2) <= ctrl.enable;
case serial.state is
when S_IDLE => -- waiting for new TX data
-- ------------------------------------------------------------
serial.tx_out <= '0';
serial.pulse_cnt <= (others => '0');
serial.strobe_cnt <= (others => '0');
if (tx_fifo.avail = '1') then
serial.state <= S_INIT;
end if;
when S_INIT => -- initialize TX shift engine
-- ------------------------------------------------------------
if (tx_fifo.rdata(32) = '0') then -- mode = "RGB"
serial.mode <= '0';
serial.bit_cnt <= "011000"; -- total number of bits to send: 3x8=24
else -- mode = "RGBW"
serial.mode <= '1';
serial.bit_cnt <= "100000"; -- total number of bits to send: 4x8=32
end if;
--
when "100" => -- IDLE: waiting for new TX data, prepare transmission
-- ------------------------------------------------------------
neoled_o <= '0';
serial.pulse_cnt <= (others => '0');
serial.strobe_cnt <= (others => '0');
serial.sreg <= tx_fifo.rdata(31 downto 0);
if (tx_fifo.rdata(32) = '0') then -- "RGB" mode
serial.mode <= '0';
serial.bit_cnt <= "011000"; -- total number of bits to send: 3x8=24
else -- "RGBW" mode
serial.mode <= '1';
serial.bit_cnt <= "100000"; -- total number of bits to send: 4x8=32
end if;
if (tx_fifo.avail = '1') then
if (tx_fifo.rdata(33) = '0') then -- send data
serial.sreg <= tx_fifo.rdata(31 downto 00);
serial.state <= S_GETBIT;
serial.state(1 downto 0) <= "01";
else -- send RESET command
serial.state <= S_STROBE;
serial.state(1 downto 0) <= "11";
end if;
end if;
when S_GETBIT => -- get next TX bit
-- ------------------------------------------------------------
serial.sreg <= serial.sreg(serial.sreg'left-1 downto 0) & '0'; -- shift left by one position (MSB-first)
serial.bit_cnt <= std_ulogic_vector(unsigned(serial.bit_cnt) - 1);
serial.pulse_cnt <= (others => '0');
if (serial.next_bit = '0') then -- send zero-bit
serial.t_high <= ctrl.t0_high;
else -- send one-bit
serial.t_high <= ctrl.t1_high;
end if;
if (serial.bit_cnt = "000000") then -- all done?
serial.tx_out <= '0';
serial.done <= '1'; -- done sending data
serial.state <= S_IDLE;
else -- send current data MSB
serial.tx_out <= '1';
serial.state <= S_PULSE; -- transmit single pulse
end if;
when "101" => -- GETBIT: get next TX bit
-- ------------------------------------------------------------
serial.sreg <= serial.sreg(serial.sreg'left-1 downto 0) & '0'; -- shift left by one position (MSB-first)
serial.bit_cnt <= std_ulogic_vector(unsigned(serial.bit_cnt) - 1);
serial.pulse_cnt <= (others => '0');
if (serial.next_bit = '0') then -- send zero-bit
serial.t_high <= ctrl.t0_high;
else -- send one-bit
serial.t_high <= ctrl.t1_high;
end if;
if (serial.bit_cnt = "000000") then -- all done?
neoled_o <= '0';
serial.done <= '1'; -- done sending data
serial.state(1 downto 0) <= "00";
else -- send current data MSB
neoled_o <= '1';
serial.state(1 downto 0) <= "10"; -- transmit single pulse
end if;
when S_PULSE => -- send pulse with specific duty cycle
-- ------------------------------------------------------------
-- total pulse length = ctrl.t_total
-- pulse high time = serial.t_high
if (serial.pulse_clk = '1') then
when "110" => -- PULSE: send pulse with specific duty cycle
-- ------------------------------------------------------------
-- total pulse length = ctrl.t_total
-- pulse high time = serial.t_high
if (serial.pulse_clk = '1') then
serial.pulse_cnt <= std_ulogic_vector(unsigned(serial.pulse_cnt) + 1);
-- T_high reached? --
if (serial.pulse_cnt = serial.t_high) then
neoled_o <= '0';
end if;
-- T_total reached? --
if (serial.pulse_cnt = ctrl.t_total) then
serial.state(1 downto 0) <= "01"; -- get next bit to send
end if;
end if;
when "111" => -- STROBE: strobe LED data ("RESET" command)
-- ------------------------------------------------------------
-- wait for 127 * ctrl.t_total to ensure RESET
if (serial.pulse_clk = '1') then
-- T_total reached? --
if (serial.pulse_cnt = ctrl.t_total) then
serial.pulse_cnt <= (others => '0');
serial.strobe_cnt <= std_ulogic_vector(unsigned(serial.strobe_cnt) + 1);
else
serial.pulse_cnt <= std_ulogic_vector(unsigned(serial.pulse_cnt) + 1);
-- T_high reached? --
if (serial.pulse_cnt = serial.t_high) then
serial.tx_out <= '0';
end if;
-- T_total reached? --
if (serial.pulse_cnt = ctrl.t_total) then
serial.state <= S_GETBIT; -- get next bit to send
end if;
end if;
end if;
-- number of LOW periods reached for RESET? --
if (and_reduce_f(serial.strobe_cnt) = '1') then
serial.done <= '1'; -- done sending RESET
serial.state(1 downto 0) <= "00";
end if;
when S_STROBE => -- strobe LED data ("RESET" command)
-- ------------------------------------------------------------
-- wait for 127 * ctrl.t_total to _ensure_ RESET
if (serial.pulse_clk = '1') then
-- T_total reached? --
if (serial.pulse_cnt = ctrl.t_total) then
serial.pulse_cnt <= (others => '0');
serial.strobe_cnt <= std_ulogic_vector(unsigned(serial.strobe_cnt) + 1);
else
serial.pulse_cnt <= std_ulogic_vector(unsigned(serial.pulse_cnt) + 1);
end if;
end if;
-- number of LOW periods reached for RESET? --
if (and_reduce_f(serial.strobe_cnt) = '1') then
serial.done <= '1'; -- done sending RESET
serial.state <= S_IDLE;
end if;
when others => -- "0--": disabled
-- ------------------------------------------------------------
serial.state(1 downto 0) <= "00";
when others => -- undefined
-- ------------------------------------------------------------
serial.state <= S_IDLE;
end case;
end if;
-- serial data tx_out --
neoled_o <= serial.tx_out and ctrl.enable;
end case;
end if;
end process serial_engine;
@ -399,7 +385,7 @@ begin
serial.next_bit <= serial.sreg(23) when (serial.mode = '0') else serial.sreg(31);
-- TX engine status --
serial.busy <= '0' when (serial.state = S_IDLE) else '1';
serial.busy <= '0' when (serial.state(1 downto 0) = "00") else '1';
end neorv32_neoled_rtl;

View file

@ -65,7 +65,7 @@ package neorv32_package is
-- Architecture Constants (do not modify!) ------------------------------------------------
-- -------------------------------------------------------------------------------------------
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080202"; -- NEORV32 version
constant hw_version_c : std_ulogic_vector(31 downto 0) := x"01080203"; -- NEORV32 version
constant archid_c : natural := 19; -- official RISC-V architecture ID
-- Check if we're inside the Matrix -------------------------------------------------------
@ -2199,8 +2199,7 @@ package neorv32_package is
FIFO_DEPTH : natural; -- number of fifo entries; has to be a power of two; min 1
FIFO_WIDTH : natural; -- size of data elements in fifo
FIFO_RSYNC : boolean; -- false = async read; true = sync read
FIFO_SAFE : boolean; -- true = allow read/write only if entry available
FIFO_GATE : boolean -- true = use output gate (set to zero if no valid data available)
FIFO_SAFE : boolean -- true = allow read/write only if entry available
);
port (
-- control --

View file

@ -2,7 +2,7 @@
-- # << NEORV32 - Serial Data Interface (SDI) >> #
-- # ********************************************************************************************* #
-- # Byte-oriented serial data interface using the SPI protocol. This device acts as *device* (not #
-- # as a host). Hence, all data transfers are driven/clocked by an external SPI host controller. #
-- # as a host). Hence, all data transfers are driven/clocked by an external SPI host controller. #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License #
-- # #
@ -229,8 +229,7 @@ begin
FIFO_DEPTH => RTX_FIFO, -- number of fifo entries; has to be a power of two; min 1
FIFO_WIDTH => 8, -- size of data elements in fifo (32-bit only for simulation)
FIFO_RSYNC => false, -- async read
FIFO_SAFE => true, -- safe access
FIFO_GATE => true -- output zero if no data available
FIFO_SAFE => true -- safe access
)
port map (
-- control --
@ -262,8 +261,7 @@ begin
FIFO_DEPTH => RTX_FIFO, -- number of fifo entries; has to be a power of two; min 1
FIFO_WIDTH => 8, -- size of data elements in fifo (32-bit only for simulation)
FIFO_RSYNC => false, -- async read
FIFO_SAFE => true, -- safe access
FIFO_GATE => false -- no output gate required
FIFO_SAFE => true -- safe access
)
port map (
-- control --
@ -321,8 +319,12 @@ begin
when "100" => -- enabled but idle, waiting for new transmission trigger
-- ------------------------------------------------------------
serial.sreg <= tx_fifo.rdata;
serial.cnt <= (others => '0');
serial.cnt <= (others => '0');
if (tx_fifo.avail = '0') then -- output zero if no RX data available
serial.sreg <= (others => '0');
else
serial.sreg <= tx_fifo.rdata;
end if;
if (sync.csn = '0') then -- start new transmission on falling edge of chip-select
serial.start <= '1';
serial.state(1 downto 0) <= "10";

View file

@ -103,11 +103,10 @@ architecture neorv32_spi_rtl of neorv32_spi is
constant ctrl_busy_c : natural := 31; -- r/-: spi phy busy or tx fifo not empty yet
-- access control --
signal acc_en : std_ulogic; -- module access enable
signal addr : std_ulogic_vector(31 downto 0); -- access address
signal wren : std_ulogic; -- word write enable
signal rden : std_ulogic; -- read enable
signal rden_ff : std_ulogic;
signal acc_en : std_ulogic; -- module access enable
signal addr : std_ulogic_vector(31 downto 0); -- access address
signal wren : std_ulogic; -- word write enable
signal rden : std_ulogic; -- read enable
-- control register --
type ctrl_t is record
@ -132,7 +131,6 @@ architecture neorv32_spi_rtl of neorv32_spi is
type rtx_engine_t is record
state : std_ulogic_vector(2 downto 0);
busy : std_ulogic;
start : std_ulogic;
sreg : std_ulogic_vector(7 downto 0);
bitcnt : std_ulogic_vector(3 downto 0);
sdi_sync : std_ulogic;
@ -208,10 +206,9 @@ begin
process(clk_i)
begin
if rising_edge(clk_i) then
rden_ff <= rden; -- delay read access by one cycle due to sync FIFO read access (FIXME?)
ack_o <= rden_ff or wren; -- bus access acknowledge
data_o <= (others => '0');
if (rden_ff = '1') then
ack_o <= wren or rden; -- bus access acknowledge
data_o <= (others => '0');
if (rden = '1') then
if (addr = spi_ctrl_addr_c) then -- control register
data_o(ctrl_en_c) <= ctrl.enable;
data_o(ctrl_cpha_c) <= ctrl.cpha;
@ -259,8 +256,7 @@ begin
FIFO_DEPTH => IO_SPI_FIFO, -- number of fifo entries; has to be a power of two; min 1
FIFO_WIDTH => 8, -- size of data elements in fifo
FIFO_RSYNC => true, -- sync read
FIFO_SAFE => true, -- safe access
FIFO_GATE => false -- no output gate required
FIFO_SAFE => true -- safe access
)
port map (
-- control --
@ -281,7 +277,7 @@ begin
tx_fifo.clear <= not ctrl.enable;
tx_fifo.we <= '1' when (wren = '1') and (addr = spi_rtx_addr_c) else '0';
tx_fifo.wdata <= data_i(7 downto 0);
tx_fifo.re <= '1' when (rtx_engine.state = "100") and (tx_fifo.avail = '1') and (rtx_engine.start = '0') else '0';
tx_fifo.re <= '1' when (rtx_engine.state = "100") else '0';
-- RX FIFO --
@ -290,8 +286,7 @@ begin
FIFO_DEPTH => IO_SPI_FIFO, -- number of fifo entries; has to be a power of two; min 1
FIFO_WIDTH => 8, -- size of data elements in fifo
FIFO_RSYNC => true, -- sync read
FIFO_SAFE => true, -- safe access
FIFO_GATE => false -- no output gate required
FIFO_SAFE => true -- safe access
)
port map (
-- control --
@ -333,8 +328,7 @@ begin
begin
if rising_edge(clk_i) then
-- defaults --
rtx_engine.done <= '0';
rtx_engine.start <= tx_fifo.re; -- delay start trigger by one cycle due to sync FIFO read access
rtx_engine.done <= '0';
-- serial engine --
rtx_engine.state(2) <= ctrl.enable;
@ -345,7 +339,7 @@ begin
spi_clk_o <= ctrl.cpol;
rtx_engine.bitcnt <= (others => '0');
rtx_engine.sreg <= tx_fifo.rdata;
if (rtx_engine.start = '1') then -- trigger new transmission
if (tx_fifo.avail = '1') then -- trigger new transmission
rtx_engine.state(1 downto 0) <= "01";
end if;

View file

@ -3,7 +3,7 @@
-- # ********************************************************************************************* #
-- # This processor module instantiates the "neoTRNG" true random number generator. An optional #
-- # "random pool" FIFO can be configured using the TRNG_FIFO generic. #
-- # See the neoTRNG's documentation for more information: https://github.com/stnolting/neoTRNG #
-- # See the neoTRNG documentation for more information: https://github.com/stnolting/neoTRNG #
-- # ********************************************************************************************* #
-- # BSD 3-Clause License #
-- # #
@ -133,16 +133,16 @@ begin
assert not (sim_mode_c = true) report "NEORV32 PROCESSOR CONFIG WARNING: TRNG uses SIMULATION mode!" severity warning;
-- Access Control -------------------------------------------------------------------------
-- Write Access ---------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- access control --
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = trng_base_c(hi_abb_c downto lo_abb_c)) else '0';
wren <= acc_en and wren_i;
rden <= acc_en and rden_i;
-- Write Access ---------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
write_access: process(rstn_i, clk_i)
-- write access --
process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
enable <= '0';
@ -154,25 +154,24 @@ begin
fifo_clr <= data_i(ctrl_fifo_clr_c);
end if;
end if;
end process write_access;
end process;
-- Read Access ----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
read_access: process(clk_i)
-- read access --
process(clk_i)
begin
if rising_edge(clk_i) then
ack_o <= wren or rden; -- host bus acknowledge
data_o <= (others => '0');
if (rden = '1') then
data_o(ctrl_data_msb_c downto ctrl_data_lsb_c) <= fifo.rdata;
--
if (fifo.avail = '1') then -- make sure data byte is zero if no valid data available to prevent it is read twice
data_o(ctrl_data_msb_c downto ctrl_data_lsb_c) <= fifo.rdata;
end if;
data_o(ctrl_sim_mode_c) <= bool_to_ulogic_f(sim_mode_c);
data_o(ctrl_en_c) <= enable;
data_o(ctrl_valid_c) <= fifo.avail;
end if;
end if;
end process read_access;
end process;
-- neoTRNG True Random Number Generator ---------------------------------------------------
@ -201,9 +200,8 @@ begin
generic map (
FIFO_DEPTH => IO_TRNG_FIFO, -- number of fifo entries; has to be a power of two; min 1
FIFO_WIDTH => 8, -- size of data elements in fifo
FIFO_RSYNC => false, -- async read
FIFO_SAFE => true, -- safe access
FIFO_GATE => true -- make sure the same RND data byte cannot be read twice
FIFO_RSYNC => true, -- sync read
FIFO_SAFE => true -- safe access
)
port map (
-- control --
@ -221,11 +219,8 @@ begin
avail_o => fifo.avail -- data available when set
);
-- fifo reset --
fifo.clear <= '1' when (enable = '0') or (fifo_clr = '1') else '0';
-- read access --
fifo.re <= '1' when (rden = '1') else '0';
fifo.re <= '1' when (rden = '1') else '0';
end neorv32_trng_rtl;

View file

@ -149,11 +149,10 @@ architecture neorv32_uart_rtl of neorv32_uart is
constant ctrl_tx_busy_c : natural := 31; -- r/-: UART transmitter is busy and TX FIFO not empty
-- access control --
signal acc_en : std_ulogic; -- module access enable
signal addr : std_ulogic_vector(31 downto 0); -- access address
signal wren : std_ulogic; -- word write enable
signal rden : std_ulogic; -- read enable
signal rden_ff : std_ulogic;
signal acc_en : std_ulogic; -- module access enable
signal addr : std_ulogic_vector(31 downto 0); -- access address
signal wren : std_ulogic; -- word write enable
signal rden : std_ulogic; -- read enable
-- clock generator --
signal uart_clk : std_ulogic;
@ -266,10 +265,9 @@ begin
process(clk_i)
begin
if rising_edge(clk_i) then
rden_ff <= rden; -- delay read access by one cycle due to synchronous FIFO read access
ack_o <= wren or rden_ff; -- bus access acknowledge
data_o <= (others => '0');
if (rden_ff = '1') then
ack_o <= wren or rden; -- bus access acknowledge
data_o <= (others => '0');
if (rden = '1') then
if (addr = uart_id_ctrl_addr_c) then -- control register
data_o(ctrl_en_c) <= ctrl.enable;
data_o(ctrl_sim_en_c) <= ctrl.sim_mode;
@ -313,8 +311,7 @@ begin
FIFO_DEPTH => UART_TX_FIFO, -- number of fifo entries; has to be a power of two; min 1
FIFO_WIDTH => 8, -- size of data elements in fifo (32-bit only for simulation)
FIFO_RSYNC => true, -- sync read
FIFO_SAFE => true, -- safe access
FIFO_GATE => false -- no output gate required
FIFO_SAFE => true -- safe access
)
port map (
-- control --
@ -335,7 +332,7 @@ begin
tx_fifo.clear <= '1' when (ctrl.enable = '0') or (ctrl.sim_mode = '1') else '0';
tx_fifo.wdata <= data_i(7 downto 0);
tx_fifo.we <= '1' when (wren = '1') and (addr = uart_id_rtx_addr_c) else '0';
tx_fifo.re <= '1' when (tx_engine.state = "100") and (tx_fifo.avail = '1') else '0';
tx_fifo.re <= '1' when (tx_engine.state = "100") else '0';
-- TX interrupt generator --
process(clk_i)
@ -354,8 +351,7 @@ begin
FIFO_DEPTH => UART_RX_FIFO, -- number of fifo entries; has to be a power of two; min 1
FIFO_WIDTH => 8, -- size of data elements in fifo
FIFO_RSYNC => true, -- sync read
FIFO_SAFE => true, -- safe access
FIFO_GATE => false -- no output gate required
FIFO_SAFE => true -- safe access
)
port map (
-- control --
@ -392,7 +388,7 @@ begin
-- Transmit Engine ------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
process(clk_i)
transmitter: process(clk_i)
begin
if rising_edge(clk_i) then
-- synchronize clear-to-send --
@ -409,13 +405,13 @@ begin
-- ------------------------------------------------------------
tx_engine.baudcnt <= ctrl.baud;
tx_engine.bitcnt <= "1011"; -- 1 start-bit + 8 data-bits + 1 stop-bit + 1 pause-bit
tx_engine.sreg <= tx_fifo.rdata & '0'; -- data & start-bit
if (tx_fifo.avail = '1') then
tx_engine.state(1 downto 0) <= "01";
end if;
when "101" => -- PREPARE: get data from buffer, check if we are allowed to start sending
when "101" => -- WAIT: check if we are allowed to start sending
-- ------------------------------------------------------------
tx_engine.sreg <= tx_fifo.rdata & '0'; -- data & start-bit
if (tx_engine.cts_sync(1) = '0') or (ctrl.hwfc_en = '0') then -- allowed to send OR flow-control disabled
tx_engine.state(1 downto 0) <= "11";
end if;
@ -442,7 +438,7 @@ begin
end case;
end if;
end process;
end process transmitter;
-- transmitter busy --
tx_engine.busy <= '0' when (tx_engine.state(1 downto 0) = "00") else '1';
@ -453,7 +449,7 @@ begin
-- Receive Engine -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
process(clk_i)
receiver: process(clk_i)
begin
if rising_edge(clk_i) then
-- input synchronizer --
@ -500,7 +496,7 @@ begin
end case;
end if;
end process;
end process receiver;
-- RX overrun flag --
process(clk_i)