mirror of
https://github.com/stnolting/neorv32.git
synced 2025-04-23 21:57:33 -04:00
[rtl] reworks, cleanups and optimizations (#550)
This commit is contained in:
commit
eb6ec2202f
9 changed files with 221 additions and 268 deletions
|
@ -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** |
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 --
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue