[io] add full hardware reset

This commit is contained in:
stnolting 2023-11-11 07:44:29 +01:00
parent 06e13d5cd3
commit 8f75b3a035
18 changed files with 1024 additions and 880 deletions

View file

@ -165,60 +165,66 @@ begin
-- and is set INSTEAD of the ACK signal. Setting the ERR signal will raise a bus access exception with a "Device Error" qualifier
-- that can be handled by the application software. Note that the current privilege level should not be exposed to software to
-- maintain full virtualization. Hence, CFS-based "privilege escalation" should trigger a bus access exception (e.g. by setting 'err_o').
bus_rsp_o.err <= '0'; -- Tie to zero if not explicitly used.
--
-- Host access example: Read and write access to the interface registers + bus transfer acknowledge. This example only
-- implements four physical r/w register (the four lowest CFS registers). The remaining addresses of the CFS are not associated
-- with any physical registers - any access to those is simply ignored but still acknowledged. Only full-word write accesses are
-- supported (and acknowledged) by this example. Sub-word write access will not alter any CFS register state and will cause
-- a "bus store access" exception (with a "Device Timeout" qualifier as not ACK is generated in that case).
host_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
cfs_reg_wr(0) <= (others => '0');
cfs_reg_wr(1) <= (others => '0');
cfs_reg_wr(2) <= (others => '0');
cfs_reg_wr(3) <= (others => '0');
cfs_reg_wr(0) <= (others => '0');
cfs_reg_wr(1) <= (others => '0');
cfs_reg_wr(2) <= (others => '0');
cfs_reg_wr(3) <= (others => '0');
--
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
elsif rising_edge(clk_i) then -- synchronous interface for read and write accesses
-- transfer/access acknowledge --
bus_rsp_o.ack <= bus_req_i.stb;
-- tie to zero if not explicitly used --
bus_rsp_o.err <= '0';
-- defaults --
bus_rsp_o.data <= (others => '0'); -- the output HAS TO BE ZERO if there is no actual read access
bus_rsp_o.data <= (others => '0'); -- the output HAS TO BE ZERO if there is no actual (read) access
-- bus access --
if (bus_req_i.stb = '1') then -- valid access cycle, STB is high for one cycle
if (bus_req_i.rw = '1') then -- write access
if (bus_req_i.addr(7 downto 2) = "000000") then -- make sure to use the internal "addr" signal for the read/write interface
cfs_reg_wr(0) <= bus_req_i.data; -- some physical register, for example: control register
-- write access --
if (bus_req_i.rw = '1') then
if (bus_req_i.addr(7 downto 2) = "000000") then -- address size is fixed!
cfs_reg_wr(0) <= bus_req_i.data;
end if;
if (bus_req_i.addr(7 downto 2) = "000001") then
cfs_reg_wr(1) <= bus_req_i.data; -- some physical register, for example: data in/out fifo
cfs_reg_wr(1) <= bus_req_i.data;
end if;
if (bus_req_i.addr(7 downto 2) = "000010") then
cfs_reg_wr(2) <= bus_req_i.data; -- some physical register, for example: command fifo
cfs_reg_wr(2) <= bus_req_i.data;
end if;
if (bus_req_i.addr(7 downto 2) = "000011") then
cfs_reg_wr(3) <= bus_req_i.data; -- some physical register, for example: status register
cfs_reg_wr(3) <= bus_req_i.data;
end if;
else -- read access
case bus_req_i.addr(7 downto 2) is -- make sure to use the internal 'addr' signal for the read/write interface
-- read access --
else
case bus_req_i.addr(7 downto 2) is -- address size is fixed!
when "000000" => bus_rsp_o.data <= cfs_reg_rd(0);
when "000001" => bus_rsp_o.data <= cfs_reg_rd(1);
when "000010" => bus_rsp_o.data <= cfs_reg_rd(2);
when "000011" => bus_rsp_o.data <= cfs_reg_rd(3);
when others => bus_rsp_o.data <= (others => '0'); -- the remaining registers are not implemented and will read as zero
when others => bus_rsp_o.data <= (others => '0');
end case;
end if;
end if;
end if;
end process host_access;
end process bus_access;
-- CFS Function Core ----------------------------------------------------------------------

View file

@ -77,18 +77,25 @@ architecture neorv32_crc_rtl of neorv32_crc is
begin
-- Host Access ----------------------------------------------------------------------------
-- Bus Access- ----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- write access --
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
crc.mode <= (others => '0');
crc.poly <= (others => '0');
crc.data <= (others => '0');
we_ack <= (others => '0');
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.data <= (others => '0');
bus_rsp_o.err <= '0';
bus_rsp_o.ack <= we_ack(we_ack'left) or (bus_req_i.stb and (not bus_req_i.rw));
-- write access --
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
if (bus_req_i.addr(3 downto 2) = mode_addr_c) then -- mode select
crc.mode <= bus_req_i.data(01 downto 0);
@ -100,17 +107,11 @@ begin
crc.data <= bus_req_i.data(07 downto 0);
end if;
end if;
-- delayed write ACK --
we_ack <= we_ack(we_ack'left-1 downto 0) & (bus_req_i.stb and bus_req_i.rw);
end if;
end process write_access;
-- read access --
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
bus_rsp_o.data <= (others => '0');
bus_rsp_o.ack <= we_ack(we_ack'left) or (bus_req_i.stb and (not bus_req_i.rw));
-- read access --
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
case bus_req_i.addr(3 downto 2) is
when mode_addr_c => bus_rsp_o.data(01 downto 0) <= crc.mode; -- mode select
@ -118,11 +119,11 @@ begin
when others => bus_rsp_o.data(31 downto 0) <= crc.sreg; -- CRC result
end case;
end if;
end if;
end process read_access;
end process bus_access;
-- no access error possible --
bus_rsp_o.err <= '0';
-- Bit-Serial CRC Core --------------------------------------------------------------------

View file

@ -130,13 +130,14 @@ architecture neorv32_dma_rtl of neorv32_dma is
begin
-- Control Interface -------------------------------------------------------------------
-- Bus Access -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- write access --
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
config.enable <= '0';
config.auto <= '0';
config.firq_mask <= (others => '0');
@ -150,73 +151,78 @@ begin
config.start <= '0';
config.done <= '0';
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
-- defaults --
config.start <= '0'; -- default
config.done <= config.enable and (config.done or engine.done); -- set if enabled and transfer done
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
if (bus_req_i.addr(3 downto 2) = "00") then -- control and status register
config.enable <= bus_req_i.data(ctrl_en_c);
config.auto <= bus_req_i.data(ctrl_auto_c);
config.done <= '0'; -- clear on write access
config.firq_mask <= bus_req_i.data(ctrl_firq_mask_msb_c downto ctrl_firq_mask_lsb_c);
end if;
if (bus_req_i.addr(3 downto 2) = "01") then -- source base address
config.src_base <= bus_req_i.data;
end if;
if (bus_req_i.addr(3 downto 2) = "10") then -- destination base address
config.dst_base <= bus_req_i.data;
end if;
if (bus_req_i.addr(3 downto 2) = "11") then -- transfer type register
config.num <= bus_req_i.data(type_num_hi_c downto type_num_lo_c);
config.qsel <= bus_req_i.data(type_qsel_hi_c downto type_qsel_lo_c);
config.src_inc <= bus_req_i.data(type_src_inc_c);
config.dst_inc <= bus_req_i.data(type_dst_inc_c);
config.endian <= bus_req_i.data(type_endian_c);
config.start <= '1'; -- trigger DMA operation
if (bus_req_i.stb = '1') then
-- write access --
if (bus_req_i.rw = '1') then
if (bus_req_i.addr(3 downto 2) = "00") then -- control and status register
config.enable <= bus_req_i.data(ctrl_en_c);
config.auto <= bus_req_i.data(ctrl_auto_c);
config.done <= '0'; -- clear on write access
config.firq_mask <= bus_req_i.data(ctrl_firq_mask_msb_c downto ctrl_firq_mask_lsb_c);
end if;
if (bus_req_i.addr(3 downto 2) = "01") then -- source base address
config.src_base <= bus_req_i.data;
end if;
if (bus_req_i.addr(3 downto 2) = "10") then -- destination base address
config.dst_base <= bus_req_i.data;
end if;
if (bus_req_i.addr(3 downto 2) = "11") then -- transfer type register
config.num <= bus_req_i.data(type_num_hi_c downto type_num_lo_c);
config.qsel <= bus_req_i.data(type_qsel_hi_c downto type_qsel_lo_c);
config.src_inc <= bus_req_i.data(type_src_inc_c);
config.dst_inc <= bus_req_i.data(type_dst_inc_c);
config.endian <= bus_req_i.data(type_endian_c);
config.start <= '1'; -- trigger DMA operation
end if;
-- read access --
else
case bus_req_i.addr(3 downto 2) is
when "00" => -- control and status register
bus_rsp_o.data(ctrl_en_c) <= config.enable;
bus_rsp_o.data(ctrl_auto_c) <= config.auto;
bus_rsp_o.data(ctrl_error_rd_c) <= engine.err_rd;
bus_rsp_o.data(ctrl_error_wr_c) <= engine.err_wr;
bus_rsp_o.data(ctrl_busy_c) <= engine.busy;
bus_rsp_o.data(ctrl_done_c) <= config.done;
bus_rsp_o.data(ctrl_firq_mask_msb_c downto ctrl_firq_mask_lsb_c) <= config.firq_mask;
when "01" => -- address of last read access
bus_rsp_o.data <= engine.src_addr;
when "10" => -- address of last write access
bus_rsp_o.data <= engine.dst_addr;
when others => -- transfer type register
bus_rsp_o.data(type_num_hi_c downto type_num_lo_c) <= engine.num;
bus_rsp_o.data(type_qsel_hi_c downto type_qsel_lo_c) <= config.qsel;
bus_rsp_o.data(type_src_inc_c) <= config.src_inc;
bus_rsp_o.data(type_dst_inc_c) <= config.dst_inc;
bus_rsp_o.data(type_endian_c) <= config.endian;
end case;
end if;
end if;
end if;
end process write_access;
-- read access --
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
bus_rsp_o.ack <= bus_req_i.stb; -- bus access acknowledge
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
case bus_req_i.addr(3 downto 2) is
when "00" => -- control and status register
bus_rsp_o.data(ctrl_en_c) <= config.enable;
bus_rsp_o.data(ctrl_auto_c) <= config.auto;
bus_rsp_o.data(ctrl_error_rd_c) <= engine.err_rd;
bus_rsp_o.data(ctrl_error_wr_c) <= engine.err_wr;
bus_rsp_o.data(ctrl_busy_c) <= engine.busy;
bus_rsp_o.data(ctrl_done_c) <= config.done;
bus_rsp_o.data(ctrl_firq_mask_msb_c downto ctrl_firq_mask_lsb_c) <= config.firq_mask;
when "01" => -- address of last read access
bus_rsp_o.data <= engine.src_addr;
when "10" => -- address of last write access
bus_rsp_o.data <= engine.dst_addr;
when others => -- transfer type register
bus_rsp_o.data(type_num_hi_c downto type_num_lo_c) <= engine.num;
bus_rsp_o.data(type_qsel_hi_c downto type_qsel_lo_c) <= config.qsel;
bus_rsp_o.data(type_src_inc_c) <= config.src_inc;
bus_rsp_o.data(type_dst_inc_c) <= config.dst_inc;
bus_rsp_o.data(type_endian_c) <= config.endian;
end case;
end if;
end if;
end process read_access;
-- no access error possible --
bus_rsp_o.err <= '0';
end process bus_access;
-- Automatic Trigger ----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
automatic_trigger: process(clk_i)
automatic_trigger: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
firq_buf <= (others => '0');
match_ff <= '0';
atrigger <= '0';
elsif rising_edge(clk_i) then
firq_buf <= firq_i;
match_ff <= match;
atrigger <= match and (not match_ff); -- trigger on rising edge of FIRQ

View file

@ -59,45 +59,44 @@ architecture neorv32_gpio_rtl of neorv32_gpio is
begin
-- Host Access ----------------------------------------------------------------------------
-- Bus Access -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- write access --
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
dout <= (others => '0');
elsif rising_edge(clk_i) then
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
if (bus_req_i.addr(3 downto 2) = "10") then
dout(31 downto 00) <= bus_req_i.data;
end if;
if (bus_req_i.addr(3 downto 2) = "11") then
dout(63 downto 32) <= bus_req_i.data;
end if;
end if;
end if;
end process write_access;
-- read access --
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
case bus_req_i.addr(3 downto 2) is
when "00" => bus_rsp_o.data <= din_rd(31 downto 00);
when "01" => bus_rsp_o.data <= din_rd(63 downto 32);
when "10" => bus_rsp_o.data <= dout_rd(31 downto 00);
when others => bus_rsp_o.data <= dout_rd(63 downto 32);
end case;
dout <= (others => '0');
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') then
-- write access --
if (bus_req_i.rw = '1') then
if (bus_req_i.addr(3 downto 2) = "10") then
dout(31 downto 00) <= bus_req_i.data;
end if;
if (bus_req_i.addr(3 downto 2) = "11") then
dout(63 downto 32) <= bus_req_i.data;
end if;
-- read access --
else
case bus_req_i.addr(3 downto 2) is
when "00" => bus_rsp_o.data <= din_rd(31 downto 00);
when "01" => bus_rsp_o.data <= din_rd(63 downto 32);
when "10" => bus_rsp_o.data <= dout_rd(31 downto 00);
when others => bus_rsp_o.data <= dout_rd(63 downto 32);
end case;
end if;
end if;
end if;
end process read_access;
-- no access error possible --
bus_rsp_o.err <= '0';
end process bus_access;
-- Physical Pin Mapping -------------------------------------------------------------------
@ -117,9 +116,11 @@ begin
gpio_o <= dout_rd;
-- synchronize input --
input_sync: process(clk_i)
input_sync: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
din <= (others => '0');
elsif rising_edge(clk_i) then
din <= gpio_i; -- to prevent metastability
end if;
end process input_sync;

View file

@ -79,61 +79,63 @@ architecture neorv32_gptmr_rtl of neorv32_gptmr is
begin
-- Host Access ----------------------------------------------------------------------------
-- Bus Access -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- write access --
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
timer.cnt_we <= '0';
ctrl <= (others => '0');
timer.thres <= (others => '0');
elsif rising_edge(clk_i) then
timer.cnt_we <= '0'; -- default
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
if (bus_req_i.addr(3 downto 2) = "00") then -- control register
ctrl(ctrl_en_c) <= bus_req_i.data(ctrl_en_c);
ctrl(ctrl_prsc0_c) <= bus_req_i.data(ctrl_prsc0_c);
ctrl(ctrl_prsc1_c) <= bus_req_i.data(ctrl_prsc1_c);
ctrl(ctrl_prsc2_c) <= bus_req_i.data(ctrl_prsc2_c);
ctrl(ctrl_mode_c) <= bus_req_i.data(ctrl_mode_c);
end if;
if (bus_req_i.addr(3 downto 2) = "01") then -- threshold register
timer.thres <= bus_req_i.data;
end if;
if (bus_req_i.addr(3 downto 2) = "10") then -- counter register
timer.cnt_we <= '1';
end if;
end if;
end if;
end process write_access;
-- read access --
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
bus_rsp_o.ack <= bus_req_i.stb; -- bus access acknowledge
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
case bus_req_i.addr(3 downto 2) is
when "00" => -- control register
bus_rsp_o.data(ctrl_en_c) <= ctrl(ctrl_en_c);
bus_rsp_o.data(ctrl_prsc0_c) <= ctrl(ctrl_prsc0_c);
bus_rsp_o.data(ctrl_prsc1_c) <= ctrl(ctrl_prsc1_c);
bus_rsp_o.data(ctrl_prsc2_c) <= ctrl(ctrl_prsc2_c);
bus_rsp_o.data(ctrl_mode_c) <= ctrl(ctrl_mode_c);
when "01" => -- threshold register
bus_rsp_o.data <= timer.thres;
when others => -- counter register
bus_rsp_o.data <= timer.count;
end case;
timer.cnt_we <= '0';
ctrl <= (others => '0');
timer.thres <= (others => '0');
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
-- defaults --
timer.cnt_we <= '0';
if (bus_req_i.stb = '1') then
-- write access --
if (bus_req_i.rw = '1') then
if (bus_req_i.addr(3 downto 2) = "00") then -- control register
ctrl(ctrl_en_c) <= bus_req_i.data(ctrl_en_c);
ctrl(ctrl_prsc0_c) <= bus_req_i.data(ctrl_prsc0_c);
ctrl(ctrl_prsc1_c) <= bus_req_i.data(ctrl_prsc1_c);
ctrl(ctrl_prsc2_c) <= bus_req_i.data(ctrl_prsc2_c);
ctrl(ctrl_mode_c) <= bus_req_i.data(ctrl_mode_c);
end if;
if (bus_req_i.addr(3 downto 2) = "01") then -- threshold register
timer.thres <= bus_req_i.data;
end if;
if (bus_req_i.addr(3 downto 2) = "10") then -- counter register
timer.cnt_we <= '1';
end if;
-- read access --
else
case bus_req_i.addr(3 downto 2) is
when "00" => -- control register
bus_rsp_o.data(ctrl_en_c) <= ctrl(ctrl_en_c);
bus_rsp_o.data(ctrl_prsc0_c) <= ctrl(ctrl_prsc0_c);
bus_rsp_o.data(ctrl_prsc1_c) <= ctrl(ctrl_prsc1_c);
bus_rsp_o.data(ctrl_prsc2_c) <= ctrl(ctrl_prsc2_c);
bus_rsp_o.data(ctrl_mode_c) <= ctrl(ctrl_mode_c);
when "01" => -- threshold register
bus_rsp_o.data <= timer.thres;
when others => -- counter register
bus_rsp_o.data <= timer.count;
end case;
end if;
end if;
end if;
end process read_access;
-- no access error possible --
bus_rsp_o.err <= '0';
end process bus_access;
-- Timer Core -----------------------------------------------------------------------------
@ -164,17 +166,21 @@ begin
clkgen_en_o <= ctrl(ctrl_en_c);
-- clock select --
clock_select: process(clk_i)
clock_select: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
timer.tick <= '0';
elsif rising_edge(clk_i) then
timer.tick <= clkgen_i(to_integer(unsigned(ctrl(ctrl_prsc2_c downto ctrl_prsc0_c))));
end if;
end process clock_select;
-- interrupt --
irq_generator: process(clk_i)
irq_generator: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
irq_o <= '0';
elsif rising_edge(clk_i) then
irq_o <= ctrl(ctrl_en_c) and timer.match;
end if;
end process irq_generator;

View file

@ -74,18 +74,22 @@ architecture neorv32_mtime_rtl of neorv32_mtime is
begin
-- Write Access ---------------------------------------------------------------------------
-- Bus Access -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
mtimecmp_lo <= (others => '0');
mtimecmp_hi <= (others => '0');
mtime_lo_we <= '0';
mtime_hi_we <= '0';
mtime_lo <= (others => '0');
mtime_lo_ovfl <= (others => '0');
mtime_hi <= (others => '0');
mtimecmp_lo <= (others => '0');
mtimecmp_hi <= (others => '0');
mtime_lo_we <= '0';
mtime_hi_we <= '0';
mtime_lo <= (others => '0');
mtime_lo_ovfl <= (others => '0');
mtime_hi <= (others => '0');
--
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
elsif rising_edge(clk_i) then
-- mtimecmp --
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
@ -122,19 +126,10 @@ begin
else -- auto increment (if mtime.low overflows)
mtime_hi <= std_ulogic_vector(unsigned(mtime_hi) + unsigned(mtime_lo_ovfl));
end if;
end if;
end process write_access;
-- mtime.time_LO increment --
mtime_lo_nxt <= std_ulogic_vector(unsigned('0' & mtime_lo) + 1);
-- Read Access ----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
-- read access --
bus_rsp_o.ack <= bus_req_i.stb; -- bus handshake
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0'); -- default
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
case bus_req_i.addr(3 downto 2) is
@ -145,17 +140,20 @@ begin
end case;
end if;
end if;
end process read_access;
end process bus_access;
-- no access error possible --
bus_rsp_o.err <= '0';
-- mtime.time_LO increment --
mtime_lo_nxt <= std_ulogic_vector(unsigned('0' & mtime_lo) + 1);
-- Comparator -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
cmp_sync: process(clk_i)
cmp_sync: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
cmp_lo_ge_ff <= '0';
irq_o <= '0';
elsif rising_edge(clk_i) then
cmp_lo_ge_ff <= cmp_lo_ge; -- there is one cycle delay between low (earlier) and high (later) word
irq_o <= cmp_hi_gt or (cmp_hi_eq and cmp_lo_ge_ff);
end if;

View file

@ -156,62 +156,64 @@ architecture neorv32_neoled_rtl of neorv32_neoled is
begin
-- Host Access ----------------------------------------------------------------------------
-- Bus Access -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- write access --
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
ctrl.enable <= '0';
ctrl.mode <= '0';
ctrl.strobe <= '0';
ctrl.clk_prsc <= (others => '0');
ctrl.irq_conf <= '0';
ctrl.t_total <= (others => '0');
ctrl.t0_high <= (others => '0');
ctrl.t1_high <= (others => '0');
elsif rising_edge(clk_i) then
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') and (bus_req_i.addr(2) = '0') then
ctrl.enable <= bus_req_i.data(ctrl_en_c);
ctrl.mode <= bus_req_i.data(ctrl_mode_c);
ctrl.strobe <= bus_req_i.data(ctrl_strobe_c);
ctrl.clk_prsc <= bus_req_i.data(ctrl_clksel2_c downto ctrl_clksel0_c);
ctrl.irq_conf <= bus_req_i.data(ctrl_irq_conf_c);
ctrl.t_total <= bus_req_i.data(ctrl_t_tot_4_c downto ctrl_t_tot_0_c);
ctrl.t0_high <= bus_req_i.data(ctrl_t_0h_4_c downto ctrl_t_0h_0_c);
ctrl.t1_high <= bus_req_i.data(ctrl_t_1h_4_c downto ctrl_t_1h_0_c);
end if;
end if;
end process write_access;
-- read access --
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
bus_rsp_o.ack <= bus_req_i.stb; -- access acknowledge
ctrl.enable <= '0';
ctrl.mode <= '0';
ctrl.strobe <= '0';
ctrl.clk_prsc <= (others => '0');
ctrl.irq_conf <= '0';
ctrl.t_total <= (others => '0');
ctrl.t0_high <= (others => '0');
ctrl.t1_high <= (others => '0');
--
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
bus_rsp_o.data(ctrl_en_c) <= ctrl.enable;
bus_rsp_o.data(ctrl_mode_c) <= ctrl.mode;
bus_rsp_o.data(ctrl_strobe_c) <= ctrl.strobe;
bus_rsp_o.data(ctrl_clksel2_c downto ctrl_clksel0_c) <= ctrl.clk_prsc;
bus_rsp_o.data(ctrl_irq_conf_c) <= ctrl.irq_conf or bool_to_ulogic_f(boolean(FIFO_DEPTH = 1)); -- tie to one if FIFO_DEPTH is 1
bus_rsp_o.data(ctrl_bufs_3_c downto ctrl_bufs_0_c) <= std_ulogic_vector(to_unsigned(index_size_f(FIFO_DEPTH), 4));
bus_rsp_o.data(ctrl_t_tot_4_c downto ctrl_t_tot_0_c) <= ctrl.t_total;
bus_rsp_o.data(ctrl_t_0h_4_c downto ctrl_t_0h_0_c) <= ctrl.t0_high;
bus_rsp_o.data(ctrl_t_1h_4_c downto ctrl_t_1h_0_c) <= ctrl.t1_high;
--
bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail;
bus_rsp_o.data(ctrl_tx_half_c) <= tx_fifo.half;
bus_rsp_o.data(ctrl_tx_full_c) <= not tx_fifo.free;
bus_rsp_o.data(ctrl_tx_busy_c) <= serial.busy;
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') then
-- write access --
if (bus_req_i.rw = '1') then
if (bus_req_i.addr(2) = '0') then
ctrl.enable <= bus_req_i.data(ctrl_en_c);
ctrl.mode <= bus_req_i.data(ctrl_mode_c);
ctrl.strobe <= bus_req_i.data(ctrl_strobe_c);
ctrl.clk_prsc <= bus_req_i.data(ctrl_clksel2_c downto ctrl_clksel0_c);
ctrl.irq_conf <= bus_req_i.data(ctrl_irq_conf_c);
ctrl.t_total <= bus_req_i.data(ctrl_t_tot_4_c downto ctrl_t_tot_0_c);
ctrl.t0_high <= bus_req_i.data(ctrl_t_0h_4_c downto ctrl_t_0h_0_c);
ctrl.t1_high <= bus_req_i.data(ctrl_t_1h_4_c downto ctrl_t_1h_0_c);
end if;
-- read access --
else
bus_rsp_o.data(ctrl_en_c) <= ctrl.enable;
bus_rsp_o.data(ctrl_mode_c) <= ctrl.mode;
bus_rsp_o.data(ctrl_strobe_c) <= ctrl.strobe;
bus_rsp_o.data(ctrl_clksel2_c downto ctrl_clksel0_c) <= ctrl.clk_prsc;
bus_rsp_o.data(ctrl_irq_conf_c) <= ctrl.irq_conf or bool_to_ulogic_f(boolean(FIFO_DEPTH = 1)); -- tie to one if FIFO_DEPTH is 1
bus_rsp_o.data(ctrl_bufs_3_c downto ctrl_bufs_0_c) <= std_ulogic_vector(to_unsigned(index_size_f(FIFO_DEPTH), 4));
bus_rsp_o.data(ctrl_t_tot_4_c downto ctrl_t_tot_0_c) <= ctrl.t_total;
bus_rsp_o.data(ctrl_t_0h_4_c downto ctrl_t_0h_0_c) <= ctrl.t0_high;
bus_rsp_o.data(ctrl_t_1h_4_c downto ctrl_t_1h_0_c) <= ctrl.t1_high;
--
bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail;
bus_rsp_o.data(ctrl_tx_half_c) <= tx_fifo.half;
bus_rsp_o.data(ctrl_tx_full_c) <= not tx_fifo.free;
bus_rsp_o.data(ctrl_tx_busy_c) <= serial.busy;
end if;
end if;
end if;
end process read_access;
-- no access error possible --
bus_rsp_o.err <= '0';
end process bus_access;
-- enable external clock generator --
clkgen_en_o <= ctrl.enable;
@ -248,9 +250,11 @@ begin
tx_fifo.clear <= not ctrl.enable;
-- IRQ generator --
irq_generator: process(clk_i)
irq_generator: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
irq_o <= '0';
elsif rising_edge(clk_i) then
irq_o <= ctrl.enable and (
((not ctrl.irq_conf) and (not tx_fifo.avail)) or -- fire IRQ if FIFO is empty
(( ctrl.irq_conf) and (not tx_fifo.half))); -- fire IRQ if FIFO is less than half full
@ -260,9 +264,20 @@ begin
-- Serial TX Engine -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
serial_engine: process(clk_i)
serial_engine: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
serial.pulse_clk <= '0';
serial.done <= '0';
serial.state <= (others => '0');
serial.pulse_cnt <= (others => '0');
serial.strobe_cnt <= (others => '0');
serial.sreg <= (others => '0');
serial.mode <= '0';
serial.bit_cnt <= (others => '0');
serial.t_high <= (others => '0');
neoled_o <= '0';
elsif rising_edge(clk_i) then
-- clock generator --
serial.pulse_clk <= clkgen_i(to_integer(unsigned(ctrl.clk_prsc)));

View file

@ -133,13 +133,14 @@ architecture neorv32_onewire_rtl of neorv32_onewire is
begin
-- Write Access ---------------------------------------------------------------------------
-- Bus Access ---------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- write access --
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
ctrl.enable <= '0';
ctrl.clk_prsc <= (others => '0');
ctrl.clk_div <= (others => '0');
@ -148,6 +149,11 @@ begin
ctrl.trig_byte <= '0';
tx_data <= (others => '0');
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
-- write access --
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
-- control register --
@ -172,15 +178,8 @@ begin
ctrl.trig_bit <= '0';
ctrl.trig_byte <= '0';
end if;
end if;
end process write_access;
-- read access --
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
bus_rsp_o.ack <= bus_req_i.stb; -- bus handshake
bus_rsp_o.data <= (others => '0');
-- read access --
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
-- control register --
if (bus_req_i.addr(2) = '0') then
@ -196,18 +195,21 @@ begin
bus_rsp_o.data(7 downto 0) <= serial.sreg;
end if;
end if;
end if;
end process read_access;
-- no access error possible --
bus_rsp_o.err <= '0';
end if;
end process bus_access;
-- Tick Generator -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
tick_generator: process(clk_i)
tick_generator: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
clk_tick <= '0';
clk_cnt <= (others => '0');
serial.tick <= '0';
serial.tick_ff <= '0';
elsif rising_edge(clk_i) then
clk_tick <= clk_sel(to_integer(unsigned(ctrl.clk_prsc)));
serial.tick <= '0'; -- default
if (ctrl.enable = '0') then
@ -233,9 +235,20 @@ begin
-- Serial Engine --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
serial_engine: process(clk_i)
serial_engine: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
serial.wire_in <= (others => '0');
serial.done <= '0';
serial.wire_lo <= '0';
serial.wire_hi <= '0';
serial.state <= (others => '0');
serial.tick_cnt <= (others => '0');
serial.bit_cnt <= (others => '0');
serial.sreg <= (others => '0');
serial.sample <= '0';
onewire_o <= '0';
elsif rising_edge(clk_i) then
-- input synchronizer --
serial.wire_in <= serial.wire_in(0) & to_stdulogic(to_bit(onewire_i)); -- "to_bit" to avoid hardware-vs-simulation mismatch

View file

@ -82,68 +82,67 @@ architecture neorv32_pwm_rtl of neorv32_pwm is
begin
-- Host Access ----------------------------------------------------------------------------
-- Bus Access -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- write access --
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
enable <= '0';
prsc <= (others => '0');
pwm_ch <= (others => (others => '0'));
elsif rising_edge(clk_i) then
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
-- control register --
if (bus_req_i.addr(3 downto 2) = "00") then
enable <= bus_req_i.data(ctrl_enable_c);
prsc <= bus_req_i.data(ctrl_prsc2_bit_c downto ctrl_prsc0_bit_c);
end if;
-- duty cycle register 0 --
if (bus_req_i.addr(3 downto 2) = "01") then
pwm_ch(00) <= bus_req_i.data(07 downto 00);
pwm_ch(01) <= bus_req_i.data(15 downto 08);
pwm_ch(02) <= bus_req_i.data(23 downto 16);
pwm_ch(03) <= bus_req_i.data(31 downto 24);
end if;
-- duty cycle register 1 --
if (bus_req_i.addr(3 downto 2) = "10") then
pwm_ch(04) <= bus_req_i.data(07 downto 00);
pwm_ch(05) <= bus_req_i.data(15 downto 08);
pwm_ch(06) <= bus_req_i.data(23 downto 16);
pwm_ch(07) <= bus_req_i.data(31 downto 24);
end if;
-- duty cycle register 2 --
if (bus_req_i.addr(3 downto 2) = "11") then
pwm_ch(08) <= bus_req_i.data(07 downto 00);
pwm_ch(09) <= bus_req_i.data(15 downto 08);
pwm_ch(10) <= bus_req_i.data(23 downto 16);
pwm_ch(11) <= bus_req_i.data(31 downto 24);
end if;
end if;
end if;
end process write_access;
-- read access --
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
bus_rsp_o.ack <= bus_req_i.stb; -- bus handshake
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
case bus_req_i.addr(3 downto 2) is
when "00" => bus_rsp_o.data(ctrl_enable_c) <= enable; bus_rsp_o.data(ctrl_prsc2_bit_c downto ctrl_prsc0_bit_c) <= prsc;
when "01" => bus_rsp_o.data <= pwm_ch_rd(03) & pwm_ch_rd(02) & pwm_ch_rd(01) & pwm_ch_rd(00);
when "10" => bus_rsp_o.data <= pwm_ch_rd(07) & pwm_ch_rd(06) & pwm_ch_rd(05) & pwm_ch_rd(04);
when "11" => bus_rsp_o.data <= pwm_ch_rd(11) & pwm_ch_rd(10) & pwm_ch_rd(09) & pwm_ch_rd(08);
when others => bus_rsp_o.data <= (others => '0');
end case;
enable <= '0';
prsc <= (others => '0');
pwm_ch <= (others => (others => '0'));
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') then
-- write access --
if (bus_req_i.rw = '1') then
-- control register --
if (bus_req_i.addr(3 downto 2) = "00") then
enable <= bus_req_i.data(ctrl_enable_c);
prsc <= bus_req_i.data(ctrl_prsc2_bit_c downto ctrl_prsc0_bit_c);
end if;
-- duty cycle register 0 --
if (bus_req_i.addr(3 downto 2) = "01") then
pwm_ch(00) <= bus_req_i.data(07 downto 00);
pwm_ch(01) <= bus_req_i.data(15 downto 08);
pwm_ch(02) <= bus_req_i.data(23 downto 16);
pwm_ch(03) <= bus_req_i.data(31 downto 24);
end if;
-- duty cycle register 1 --
if (bus_req_i.addr(3 downto 2) = "10") then
pwm_ch(04) <= bus_req_i.data(07 downto 00);
pwm_ch(05) <= bus_req_i.data(15 downto 08);
pwm_ch(06) <= bus_req_i.data(23 downto 16);
pwm_ch(07) <= bus_req_i.data(31 downto 24);
end if;
-- duty cycle register 2 --
if (bus_req_i.addr(3 downto 2) = "11") then
pwm_ch(08) <= bus_req_i.data(07 downto 00);
pwm_ch(09) <= bus_req_i.data(15 downto 08);
pwm_ch(10) <= bus_req_i.data(23 downto 16);
pwm_ch(11) <= bus_req_i.data(31 downto 24);
end if;
-- read access --
else
case bus_req_i.addr(3 downto 2) is
when "00" => bus_rsp_o.data(ctrl_enable_c) <= enable; bus_rsp_o.data(ctrl_prsc2_bit_c downto ctrl_prsc0_bit_c) <= prsc;
when "01" => bus_rsp_o.data <= pwm_ch_rd(03) & pwm_ch_rd(02) & pwm_ch_rd(01) & pwm_ch_rd(00);
when "10" => bus_rsp_o.data <= pwm_ch_rd(07) & pwm_ch_rd(06) & pwm_ch_rd(05) & pwm_ch_rd(04);
when "11" => bus_rsp_o.data <= pwm_ch_rd(11) & pwm_ch_rd(10) & pwm_ch_rd(09) & pwm_ch_rd(08);
when others => bus_rsp_o.data <= (others => '0');
end case;
end if;
end if;
end if;
end process read_access;
-- no access error possible --
bus_rsp_o.err <= '0';
end process bus_access;
-- duty cycle read-back --
pwm_dc_rd_gen: process(pwm_ch)
@ -157,9 +156,12 @@ begin
-- PWM Core -------------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
pwm_core: process(clk_i)
pwm_core: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
pwm_cnt <= (others => '0');
pwm_o <= (others => '0');
elsif rising_edge(clk_i) then
-- pwm base counter --
if (enable = '0') then
pwm_cnt <= (others => '0');

View file

@ -130,13 +130,14 @@ architecture neorv32_sdi_rtl of neorv32_sdi is
begin
-- Host Access ----------------------------------------------------------------------------
-- Bus Access -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- write access --
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
ctrl.enable <= '0';
ctrl.clr_rx <= '0';
ctrl.irq_rx_avail <= '0';
@ -144,52 +145,53 @@ begin
ctrl.irq_rx_full <= '0';
ctrl.irq_tx_empty <= '0';
elsif rising_edge(clk_i) then
ctrl.clr_rx <= '0';
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
if (bus_req_i.addr(2) = '0') then -- control register
ctrl.enable <= bus_req_i.data(ctrl_en_c);
ctrl.clr_rx <= bus_req_i.data(ctrl_clr_rx_c);
--
ctrl.irq_rx_avail <= bus_req_i.data(ctrl_irq_rx_avail_c);
ctrl.irq_rx_half <= bus_req_i.data(ctrl_irq_rx_half_c);
ctrl.irq_rx_full <= bus_req_i.data(ctrl_irq_rx_full_c);
ctrl.irq_tx_empty <= bus_req_i.data(ctrl_irq_tx_empty_c);
end if;
end if;
end if;
end process write_access;
-- read access --
read_aceess: process(clk_i)
begin
if rising_edge(clk_i) then
bus_rsp_o.ack <= bus_req_i.stb; -- bus access acknowledge
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
if (bus_req_i.addr(2) = '0') then -- control register
bus_rsp_o.data(ctrl_en_c) <= ctrl.enable;
--
bus_rsp_o.data(ctrl_fifo_size3_c downto ctrl_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(RTX_FIFO), 4));
--
bus_rsp_o.data(ctrl_irq_rx_avail_c) <= ctrl.irq_rx_avail;
bus_rsp_o.data(ctrl_irq_rx_half_c) <= ctrl.irq_rx_half;
bus_rsp_o.data(ctrl_irq_rx_full_c) <= ctrl.irq_rx_full;
bus_rsp_o.data(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty;
--
bus_rsp_o.data(ctrl_rx_avail_c) <= rx_fifo.avail;
bus_rsp_o.data(ctrl_rx_half_c) <= rx_fifo.half;
bus_rsp_o.data(ctrl_rx_full_c) <= not rx_fifo.free;
bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail;
bus_rsp_o.data(ctrl_tx_full_c) <= not tx_fifo.free;
else -- data register
bus_rsp_o.data(7 downto 0) <= rx_fifo.rdata;
-- defaults --
ctrl.clr_rx <= '0';
if (bus_req_i.stb = '1') then
-- write access --
if (bus_req_i.rw = '1') then
if (bus_req_i.addr(2) = '0') then -- control register
ctrl.enable <= bus_req_i.data(ctrl_en_c);
ctrl.clr_rx <= bus_req_i.data(ctrl_clr_rx_c);
--
ctrl.irq_rx_avail <= bus_req_i.data(ctrl_irq_rx_avail_c);
ctrl.irq_rx_half <= bus_req_i.data(ctrl_irq_rx_half_c);
ctrl.irq_rx_full <= bus_req_i.data(ctrl_irq_rx_full_c);
ctrl.irq_tx_empty <= bus_req_i.data(ctrl_irq_tx_empty_c);
end if;
-- read access --
else
if (bus_req_i.addr(2) = '0') then -- control register
bus_rsp_o.data(ctrl_en_c) <= ctrl.enable;
--
bus_rsp_o.data(ctrl_fifo_size3_c downto ctrl_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(RTX_FIFO), 4));
--
bus_rsp_o.data(ctrl_irq_rx_avail_c) <= ctrl.irq_rx_avail;
bus_rsp_o.data(ctrl_irq_rx_half_c) <= ctrl.irq_rx_half;
bus_rsp_o.data(ctrl_irq_rx_full_c) <= ctrl.irq_rx_full;
bus_rsp_o.data(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty;
--
bus_rsp_o.data(ctrl_rx_avail_c) <= rx_fifo.avail;
bus_rsp_o.data(ctrl_rx_half_c) <= rx_fifo.half;
bus_rsp_o.data(ctrl_rx_full_c) <= not rx_fifo.free;
bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail;
bus_rsp_o.data(ctrl_tx_full_c) <= not tx_fifo.free;
else -- data register
bus_rsp_o.data(7 downto 0) <= rx_fifo.rdata;
end if;
end if;
end if;
end if;
end process read_aceess;
-- no access error possible --
bus_rsp_o.err <= '0';
end process bus_access;
-- Data FIFO ("Ring Buffer") --------------------------------------------------------------
@ -262,9 +264,13 @@ begin
-- Input Synchronizer ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
synchronizer: process(clk_i)
synchronizer: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
sync.sck_ff <= (others => '0');
sync.csn_ff <= (others => '0');
sync.sdi_ff <= (others => '0');
elsif rising_edge(clk_i) then
sync.sck_ff <= sync.sck_ff(1 downto 0) & sdi_clk_i;
sync.csn_ff <= sync.csn_ff(0) & sdi_csn_i;
sync.sdi_ff <= sync.sdi_ff(0) & sdi_dat_i;
@ -278,9 +284,16 @@ begin
-- Serial Engine --------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
serial_engine: process(clk_i)
serial_engine: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
serial.start <= '0';
serial.done <= '0';
serial.state <= (others => '0');
serial.cnt <= (others => '0');
serial.sreg <= (others => '0');
serial.sdi_ff <= '0';
elsif rising_edge(clk_i) then
-- defaults --
serial.start <= '0';
serial.done <= '0';
@ -340,9 +353,11 @@ begin
-- Interrupt Generator --------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
irq_generator: process(clk_i)
irq_generator: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
irq_o <= '0';
elsif rising_edge(clk_i) then
irq_o <= ctrl.enable and (
(ctrl.irq_rx_avail and rx_fifo.avail) or -- RX FIFO not empty
(ctrl.irq_rx_half and rx_fifo.half) or -- RX FIFO at least half full

View file

@ -124,13 +124,14 @@ architecture neorv32_slink_rtl of neorv32_slink is
begin
-- Host Access ----------------------------------------------------------------------------
-- Bus Access -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- write access --
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
ctrl.enable <= '0';
ctrl.rx_clr <= '0';
ctrl.tx_clr <= '0';
@ -141,60 +142,61 @@ begin
ctrl.irq_tx_nhalf <= '0';
ctrl.irq_tx_nfull <= '0';
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
-- defaults --
ctrl.rx_clr <= '0'; -- auto-clear
ctrl.tx_clr <= '0'; -- auto-clear
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
if (bus_req_i.addr(2) = '0') then -- control register
ctrl.enable <= bus_req_i.data(ctrl_en_c);
ctrl.rx_clr <= bus_req_i.data(ctrl_rx_clr_c);
ctrl.tx_clr <= bus_req_i.data(ctrl_tx_clr_c);
--
ctrl.irq_rx_nempty <= bus_req_i.data(ctrl_irq_rx_nempty_c);
ctrl.irq_rx_half <= bus_req_i.data(ctrl_irq_rx_half_c);
ctrl.irq_rx_full <= bus_req_i.data(ctrl_irq_rx_full_c);
ctrl.irq_tx_empty <= bus_req_i.data(ctrl_irq_tx_empty_c);
ctrl.irq_tx_nhalf <= bus_req_i.data(ctrl_irq_tx_nhalf_c);
ctrl.irq_tx_nfull <= bus_req_i.data(ctrl_irq_tx_nfull_c);
if (bus_req_i.stb = '1') then
-- write access --
if (bus_req_i.rw = '1') then
if (bus_req_i.addr(2) = '0') then -- control register
ctrl.enable <= bus_req_i.data(ctrl_en_c);
ctrl.rx_clr <= bus_req_i.data(ctrl_rx_clr_c);
ctrl.tx_clr <= bus_req_i.data(ctrl_tx_clr_c);
--
ctrl.irq_rx_nempty <= bus_req_i.data(ctrl_irq_rx_nempty_c);
ctrl.irq_rx_half <= bus_req_i.data(ctrl_irq_rx_half_c);
ctrl.irq_rx_full <= bus_req_i.data(ctrl_irq_rx_full_c);
ctrl.irq_tx_empty <= bus_req_i.data(ctrl_irq_tx_empty_c);
ctrl.irq_tx_nhalf <= bus_req_i.data(ctrl_irq_tx_nhalf_c);
ctrl.irq_tx_nfull <= bus_req_i.data(ctrl_irq_tx_nfull_c);
end if;
-- read access --
else
if (bus_req_i.addr(2) = '0') then -- control register
bus_rsp_o.data(ctrl_en_c) <= ctrl.enable;
--
bus_rsp_o.data(ctrl_rx_empty_c) <= not rx_fifo.avail;
bus_rsp_o.data(ctrl_rx_half_c) <= rx_fifo.half;
bus_rsp_o.data(ctrl_rx_full_c) <= not rx_fifo.free;
bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail;
bus_rsp_o.data(ctrl_tx_half_c) <= tx_fifo.half;
bus_rsp_o.data(ctrl_tx_full_c) <= not tx_fifo.free;
--
bus_rsp_o.data(ctrl_irq_rx_nempty_c) <= ctrl.irq_rx_nempty;
bus_rsp_o.data(ctrl_irq_rx_half_c) <= ctrl.irq_rx_half;
bus_rsp_o.data(ctrl_irq_rx_full_c) <= ctrl.irq_rx_full;
bus_rsp_o.data(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty;
bus_rsp_o.data(ctrl_irq_tx_nhalf_c) <= ctrl.irq_tx_nhalf;
bus_rsp_o.data(ctrl_irq_tx_nfull_c) <= ctrl.irq_tx_nfull;
--
bus_rsp_o.data(ctrl_rx_fifo_size3_c downto ctrl_rx_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(SLINK_RX_FIFO), 4));
bus_rsp_o.data(ctrl_tx_fifo_size3_c downto ctrl_tx_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(SLINK_TX_FIFO), 4));
else -- RX/TX data register
bus_rsp_o.data <= rx_fifo.rdata(31 downto 0);
end if;
end if;
end if;
end if;
end process write_access;
-- read access --
read_aceess: process(clk_i)
begin
if rising_edge(clk_i) then
bus_rsp_o.ack <= bus_req_i.stb; -- bus access acknowledge
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
if (bus_req_i.addr(2) = '0') then -- control register
bus_rsp_o.data(ctrl_en_c) <= ctrl.enable;
--
bus_rsp_o.data(ctrl_rx_empty_c) <= not rx_fifo.avail;
bus_rsp_o.data(ctrl_rx_half_c) <= rx_fifo.half;
bus_rsp_o.data(ctrl_rx_full_c) <= not rx_fifo.free;
bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail;
bus_rsp_o.data(ctrl_tx_half_c) <= tx_fifo.half;
bus_rsp_o.data(ctrl_tx_full_c) <= not tx_fifo.free;
--
bus_rsp_o.data(ctrl_irq_rx_nempty_c) <= ctrl.irq_rx_nempty;
bus_rsp_o.data(ctrl_irq_rx_half_c) <= ctrl.irq_rx_half;
bus_rsp_o.data(ctrl_irq_rx_full_c) <= ctrl.irq_rx_full;
bus_rsp_o.data(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty;
bus_rsp_o.data(ctrl_irq_tx_nhalf_c) <= ctrl.irq_tx_nhalf;
bus_rsp_o.data(ctrl_irq_tx_nfull_c) <= ctrl.irq_tx_nfull;
--
bus_rsp_o.data(ctrl_rx_fifo_size3_c downto ctrl_rx_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(SLINK_RX_FIFO), 4));
bus_rsp_o.data(ctrl_tx_fifo_size3_c downto ctrl_tx_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(SLINK_TX_FIFO), 4));
else -- RX/TX data register
bus_rsp_o.data <= rx_fifo.rdata(31 downto 0);
end if;
end if;
end if;
end process read_aceess;
-- no access error possible --
bus_rsp_o.err <= '0';
end process bus_access;
-- RX Data FIFO ---------------------------------------------------------------------------
@ -266,9 +268,11 @@ begin
-- Interrupt Generator --------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
irq_generator: process(clk_i)
irq_generator: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
irq_o <= '0';
elsif rising_edge(clk_i) then
irq_o <= ctrl.enable and ( -- IRQ if enabled and ...
(ctrl.irq_tx_empty and (not tx_fifo.avail)) or -- TX FIFO is empty
(ctrl.irq_tx_nhalf and (not tx_fifo.half)) or -- TX FIFO is not at least half full

View file

@ -116,6 +116,7 @@ architecture neorv32_spi_rtl of neorv32_spi is
sreg : std_ulogic_vector(7 downto 0);
bitcnt : std_ulogic_vector(3 downto 0);
sdi_sync : std_ulogic;
sck : std_ulogic;
done : std_ulogic;
end record;
signal rtx_engine : rtx_engine_t;
@ -135,13 +136,14 @@ architecture neorv32_spi_rtl of neorv32_spi is
begin
-- Host Access ----------------------------------------------------------------------------
-- Bus Access -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- write access --
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
ctrl.enable <= '0';
ctrl.cpha <= '0';
ctrl.cpol <= '0';
@ -153,59 +155,57 @@ begin
ctrl.irq_tx_empty <= '0';
ctrl.irq_tx_nhalf <= '0';
elsif rising_edge(clk_i) then
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
if (bus_req_i.addr(2) = '0') then -- control register
ctrl.enable <= bus_req_i.data(ctrl_en_c);
ctrl.cpha <= bus_req_i.data(ctrl_cpha_c);
ctrl.cpol <= bus_req_i.data(ctrl_cpol_c);
ctrl.cs_sel <= bus_req_i.data(ctrl_cs_sel2_c downto ctrl_cs_sel0_c);
ctrl.cs_en <= bus_req_i.data(ctrl_cs_en_c);
ctrl.prsc <= bus_req_i.data(ctrl_prsc2_c downto ctrl_prsc0_c);
ctrl.cdiv <= bus_req_i.data(ctrl_cdiv3_c downto ctrl_cdiv0_c);
ctrl.irq_rx_avail <= bus_req_i.data(ctrl_irq_rx_avail_c);
ctrl.irq_tx_empty <= bus_req_i.data(ctrl_irq_tx_empty_c);
ctrl.irq_tx_nhalf <= bus_req_i.data(ctrl_irq_tx_nhalf_c);
end if;
end if;
end if;
end process write_access;
-- read access --
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
bus_rsp_o.ack <= bus_req_i.stb; -- bus access acknowledge
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
if (bus_req_i.addr(2) = '0') then -- control register
bus_rsp_o.data(ctrl_en_c) <= ctrl.enable;
bus_rsp_o.data(ctrl_cpha_c) <= ctrl.cpha;
bus_rsp_o.data(ctrl_cpol_c) <= ctrl.cpol;
bus_rsp_o.data(ctrl_cs_sel2_c downto ctrl_cs_sel0_c) <= ctrl.cs_sel;
bus_rsp_o.data(ctrl_cs_en_c) <= ctrl.cs_en;
bus_rsp_o.data(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl.prsc;
bus_rsp_o.data(ctrl_cdiv3_c downto ctrl_cdiv0_c) <= ctrl.cdiv;
--
bus_rsp_o.data(ctrl_rx_avail_c) <= rx_fifo.avail;
bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail;
bus_rsp_o.data(ctrl_tx_nhalf_c) <= not tx_fifo.half;
bus_rsp_o.data(ctrl_tx_full_c) <= not tx_fifo.free;
bus_rsp_o.data(ctrl_irq_rx_avail_c) <= ctrl.irq_rx_avail;
bus_rsp_o.data(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty;
bus_rsp_o.data(ctrl_irq_tx_nhalf_c) <= ctrl.irq_tx_nhalf;
--
bus_rsp_o.data(ctrl_fifo_size3_c downto ctrl_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(IO_SPI_FIFO), 4));
--
bus_rsp_o.data(ctrl_busy_c) <= rtx_engine.busy or tx_fifo.avail;
if (bus_req_i.stb = '1') then
-- write access --
if (bus_req_i.rw = '1') then
if (bus_req_i.addr(2) = '0') then -- control register
ctrl.enable <= bus_req_i.data(ctrl_en_c);
ctrl.cpha <= bus_req_i.data(ctrl_cpha_c);
ctrl.cpol <= bus_req_i.data(ctrl_cpol_c);
ctrl.cs_sel <= bus_req_i.data(ctrl_cs_sel2_c downto ctrl_cs_sel0_c);
ctrl.cs_en <= bus_req_i.data(ctrl_cs_en_c);
ctrl.prsc <= bus_req_i.data(ctrl_prsc2_c downto ctrl_prsc0_c);
ctrl.cdiv <= bus_req_i.data(ctrl_cdiv3_c downto ctrl_cdiv0_c);
ctrl.irq_rx_avail <= bus_req_i.data(ctrl_irq_rx_avail_c);
ctrl.irq_tx_empty <= bus_req_i.data(ctrl_irq_tx_empty_c);
ctrl.irq_tx_nhalf <= bus_req_i.data(ctrl_irq_tx_nhalf_c);
end if;
-- read access --
else
bus_rsp_o.data(7 downto 0) <= rx_fifo.rdata;
if (bus_req_i.addr(2) = '0') then -- control register
bus_rsp_o.data(ctrl_en_c) <= ctrl.enable;
bus_rsp_o.data(ctrl_cpha_c) <= ctrl.cpha;
bus_rsp_o.data(ctrl_cpol_c) <= ctrl.cpol;
bus_rsp_o.data(ctrl_cs_sel2_c downto ctrl_cs_sel0_c) <= ctrl.cs_sel;
bus_rsp_o.data(ctrl_cs_en_c) <= ctrl.cs_en;
bus_rsp_o.data(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl.prsc;
bus_rsp_o.data(ctrl_cdiv3_c downto ctrl_cdiv0_c) <= ctrl.cdiv;
--
bus_rsp_o.data(ctrl_rx_avail_c) <= rx_fifo.avail;
bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail;
bus_rsp_o.data(ctrl_tx_nhalf_c) <= not tx_fifo.half;
bus_rsp_o.data(ctrl_tx_full_c) <= not tx_fifo.free;
bus_rsp_o.data(ctrl_irq_rx_avail_c) <= ctrl.irq_rx_avail;
bus_rsp_o.data(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty;
bus_rsp_o.data(ctrl_irq_tx_nhalf_c) <= ctrl.irq_tx_nhalf;
--
bus_rsp_o.data(ctrl_fifo_size3_c downto ctrl_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(IO_SPI_FIFO), 4));
--
bus_rsp_o.data(ctrl_busy_c) <= rtx_engine.busy or tx_fifo.avail;
else
bus_rsp_o.data(7 downto 0) <= rx_fifo.rdata;
end if;
end if;
end if;
end if;
end process read_access;
-- no access error possible --
bus_rsp_o.err <= '0';
end process bus_access;
-- direct chip-select (low-active) --
chip_select: process(ctrl)
@ -281,9 +281,11 @@ begin
-- IRQ generator --
irq_generator: process(clk_i)
irq_generator: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
irq_o <= '0';
elsif rising_edge(clk_i) then
irq_o <= ctrl.enable and (
(ctrl.irq_rx_avail and rx_fifo.avail) or -- IRQ if RX FIFO is not empty
(ctrl.irq_tx_empty and (not tx_fifo.avail)) or -- IRQ if TX FIFO is empty
@ -294,9 +296,16 @@ begin
-- SPI Transceiver ------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
transceiver: process(clk_i)
transceiver: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
rtx_engine.done <= '0';
rtx_engine.state <= (others => '0');
rtx_engine.bitcnt <= (others => '0');
rtx_engine.sreg <= (others => '0');
rtx_engine.sdi_sync <= '0';
rtx_engine.sck <= '0';
elsif rising_edge(clk_i) then
-- defaults --
rtx_engine.done <= '0';
@ -306,7 +315,7 @@ begin
when "100" => -- enabled but idle, waiting for new transmission trigger
-- ------------------------------------------------------------
spi_clk_o <= ctrl.cpol;
rtx_engine.sck <= ctrl.cpol;
rtx_engine.bitcnt <= (others => '0');
rtx_engine.sreg <= tx_fifo.rdata;
if (tx_fifo.avail = '1') then -- trigger new transmission
@ -317,7 +326,7 @@ begin
-- ------------------------------------------------------------
if (spi_clk_en = '1') then
if (ctrl.cpha = '1') then -- clock phase shift
spi_clk_o <= not ctrl.cpol;
rtx_engine.sck <= not ctrl.cpol;
end if;
rtx_engine.state(1 downto 0) <= "10";
end if;
@ -325,7 +334,7 @@ begin
when "110" => -- first phase of bit transmission
-- ------------------------------------------------------------
if (spi_clk_en = '1') then
spi_clk_o <= not (ctrl.cpha xor ctrl.cpol);
rtx_engine.sck <= not (ctrl.cpha xor ctrl.cpol);
rtx_engine.sdi_sync <= spi_dat_i; -- sample data input
rtx_engine.bitcnt <= std_ulogic_vector(unsigned(rtx_engine.bitcnt) + 1);
rtx_engine.state(1 downto 0) <= "11";
@ -336,19 +345,18 @@ begin
if (spi_clk_en = '1') then
rtx_engine.sreg <= rtx_engine.sreg(6 downto 0) & rtx_engine.sdi_sync; -- shift and set output
if (rtx_engine.bitcnt(3) = '1') then -- all bits transferred?
spi_clk_o <= ctrl.cpol;
rtx_engine.sck <= ctrl.cpol;
rtx_engine.done <= '1'; -- done!
rtx_engine.state(1 downto 0) <= "00"; -- transmission done
else
spi_clk_o <= ctrl.cpha xor ctrl.cpol;
rtx_engine.sck <= ctrl.cpha xor ctrl.cpol;
rtx_engine.state(1 downto 0) <= "10";
end if;
end if;
when others => -- "0--": SPI deactivated
-- ------------------------------------------------------------
spi_clk_o <= ctrl.cpol;
rtx_engine.sreg <= (others => '0');
rtx_engine.sck <= ctrl.cpol;
rtx_engine.state(1 downto 0) <= "00";
end case;
@ -358,14 +366,18 @@ begin
-- PHY busy flag --
rtx_engine.busy <= '0' when (rtx_engine.state(1 downto 0) = "00") else '1';
-- data output --
-- SPI output --
spi_dat_o <= rtx_engine.sreg(7); -- MSB first
spi_clk_o <= rtx_engine.sck;
-- clock generator --
clock_generator: process(clk_i)
clock_generator: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
spi_clk_en <= '0';
cdiv_cnt <= (others => '0');
elsif rising_edge(clk_i) then
if (ctrl.enable = '0') then -- reset/disabled
spi_clk_en <= '0';
cdiv_cnt <= (others => '0');

View file

@ -121,53 +121,55 @@ architecture neorv32_trng_rtl of neorv32_trng is
begin
-- Write Access ---------------------------------------------------------------------------
-- Bus Access ----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- write access --
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
enable <= '0';
fifo_clr <= '0';
irq_fifo_nempty <= '0';
irq_fifo_half <= '0';
irq_fifo_full <= '0';
elsif rising_edge(clk_i) then
fifo_clr <= '0'; -- auto-clear
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
enable <= bus_req_i.data(ctrl_en_c);
fifo_clr <= bus_req_i.data(ctrl_fifo_clr_c);
irq_fifo_nempty <= bus_req_i.data(ctrl_irq_fifo_nempty);
irq_fifo_half <= bus_req_i.data(ctrl_irq_fifo_half);
irq_fifo_full <= bus_req_i.data(ctrl_irq_fifo_full);
end if;
end if;
end process write_access;
-- read access --
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
bus_rsp_o.data(ctrl_data_msb_c downto ctrl_data_lsb_c) <= fifo.rdata;
--
bus_rsp_o.data(ctrl_fifo_size3_c downto ctrl_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(IO_TRNG_FIFO), 4));
--
bus_rsp_o.data(ctrl_irq_fifo_nempty) <= irq_fifo_nempty;
bus_rsp_o.data(ctrl_irq_fifo_half) <= irq_fifo_half;
bus_rsp_o.data(ctrl_irq_fifo_full) <= irq_fifo_full;
bus_rsp_o.data(ctrl_sim_mode_c) <= bool_to_ulogic_f(sim_mode_c);
bus_rsp_o.data(ctrl_en_c) <= enable;
bus_rsp_o.data(ctrl_valid_c) <= fifo.avail;
-- defaults --
fifo_clr <= '0'; -- auto-clear
if (bus_req_i.stb = '1') then
-- write access --
if (bus_req_i.rw = '1') then
enable <= bus_req_i.data(ctrl_en_c);
fifo_clr <= bus_req_i.data(ctrl_fifo_clr_c);
irq_fifo_nempty <= bus_req_i.data(ctrl_irq_fifo_nempty);
irq_fifo_half <= bus_req_i.data(ctrl_irq_fifo_half);
irq_fifo_full <= bus_req_i.data(ctrl_irq_fifo_full);
-- read access --
else
bus_rsp_o.data(ctrl_data_msb_c downto ctrl_data_lsb_c) <= fifo.rdata;
--
bus_rsp_o.data(ctrl_fifo_size3_c downto ctrl_fifo_size0_c) <= std_ulogic_vector(to_unsigned(index_size_f(IO_TRNG_FIFO), 4));
--
bus_rsp_o.data(ctrl_irq_fifo_nempty) <= irq_fifo_nempty;
bus_rsp_o.data(ctrl_irq_fifo_half) <= irq_fifo_half;
bus_rsp_o.data(ctrl_irq_fifo_full) <= irq_fifo_full;
bus_rsp_o.data(ctrl_sim_mode_c) <= bool_to_ulogic_f(sim_mode_c);
bus_rsp_o.data(ctrl_en_c) <= enable;
bus_rsp_o.data(ctrl_valid_c) <= fifo.avail;
end if;
end if;
end if;
end process read_access;
-- no access error possible --
bus_rsp_o.err <= '0';
end process bus_access;
-- neoTRNG True Random Number Generator ---------------------------------------------------
@ -216,9 +218,11 @@ begin
fifo.re <= '1' when (bus_req_i.stb = '1') and (bus_req_i.rw = '0') else '0';
-- FIFO-level interrupt generator --
irq_generator: process(clk_i)
irq_generator: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
irq_o <= '0';
elsif rising_edge(clk_i) then
irq_o <= enable and (
(irq_fifo_nempty and fifo.avail) or -- IRQ if FIFO not empty
(irq_fifo_half and fifo.half) or -- IRQ if FIFO at least half full

View file

@ -131,76 +131,79 @@ architecture neorv32_twi_rtl of neorv32_twi is
begin
-- Host Access ----------------------------------------------------------------------------
-- Bus Access -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- write access --
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
ctrl.enable <= '0';
ctrl.mack <= '0';
ctrl.csen <= '0';
ctrl.prsc <= (others => '0');
ctrl.cdiv <= (others => '0');
trig_start <= '0';
trig_stop <= '0';
trig_data <= '0';
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
ctrl.enable <= '0';
ctrl.mack <= '0';
ctrl.csen <= '0';
ctrl.prsc <= (others => '0');
ctrl.cdiv <= (others => '0');
trig_start <= '0';
trig_stop <= '0';
trig_data <= '0';
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
-- defaults --
trig_start <= '0';
trig_stop <= '0';
trig_data <= '0';
-- bus access --
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
if (bus_req_i.addr(2) = '0') then -- control register
ctrl.enable <= bus_req_i.data(ctrl_en_c);
ctrl.mack <= bus_req_i.data(ctrl_mack_c);
ctrl.csen <= bus_req_i.data(ctrl_csen_c);
ctrl.prsc <= bus_req_i.data(ctrl_prsc2_c downto ctrl_prsc0_c);
ctrl.cdiv <= bus_req_i.data(ctrl_cdiv3_c downto ctrl_cdiv0_c);
trig_start <= bus_req_i.data(ctrl_start_c); -- issue START condition
trig_stop <= bus_req_i.data(ctrl_stop_c); -- issue STOP condition
else -- data register
trig_data <= '1'; -- start data transmission
if (bus_req_i.stb = '1') then
-- write access --
if (bus_req_i.rw = '1') then
if (bus_req_i.addr(2) = '0') then -- control register
ctrl.enable <= bus_req_i.data(ctrl_en_c);
ctrl.mack <= bus_req_i.data(ctrl_mack_c);
ctrl.csen <= bus_req_i.data(ctrl_csen_c);
ctrl.prsc <= bus_req_i.data(ctrl_prsc2_c downto ctrl_prsc0_c);
ctrl.cdiv <= bus_req_i.data(ctrl_cdiv3_c downto ctrl_cdiv0_c);
trig_start <= bus_req_i.data(ctrl_start_c); -- issue START condition
trig_stop <= bus_req_i.data(ctrl_stop_c); -- issue STOP condition
else -- data register
trig_data <= '1'; -- start data transmission
end if;
-- read access --
else
if (bus_req_i.addr(2) = '0') then -- control register
bus_rsp_o.data(ctrl_en_c) <= ctrl.enable;
bus_rsp_o.data(ctrl_mack_c) <= ctrl.mack;
bus_rsp_o.data(ctrl_csen_c) <= ctrl.csen;
bus_rsp_o.data(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl.prsc;
bus_rsp_o.data(ctrl_cdiv3_c downto ctrl_cdiv0_c) <= ctrl.cdiv;
--
bus_rsp_o.data(ctrl_claimed_c) <= arbiter.claimed;
bus_rsp_o.data(ctrl_ack_c) <= not arbiter.rtx_sreg(0);
bus_rsp_o.data(ctrl_busy_c) <= arbiter.busy;
else -- data register
bus_rsp_o.data(7 downto 0) <= arbiter.rtx_sreg(8 downto 1);
end if;
end if;
end if;
end if;
end process write_access;
-- read access --
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
bus_rsp_o.ack <= bus_req_i.stb; -- bus handshake
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
if (bus_req_i.addr(2) = '0') then -- control register
bus_rsp_o.data(ctrl_en_c) <= ctrl.enable;
bus_rsp_o.data(ctrl_mack_c) <= ctrl.mack;
bus_rsp_o.data(ctrl_csen_c) <= ctrl.csen;
bus_rsp_o.data(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl.prsc;
bus_rsp_o.data(ctrl_cdiv3_c downto ctrl_cdiv0_c) <= ctrl.cdiv;
--
bus_rsp_o.data(ctrl_claimed_c) <= arbiter.claimed;
bus_rsp_o.data(ctrl_ack_c) <= not arbiter.rtx_sreg(0);
bus_rsp_o.data(ctrl_busy_c) <= arbiter.busy;
else -- data register
bus_rsp_o.data(7 downto 0) <= arbiter.rtx_sreg(8 downto 1);
end if;
end if;
end if;
end process read_access;
-- no access error possible --
bus_rsp_o.err <= '0';
end process bus_access;
-- Clock Generation -----------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
clock_generator: process(clk_i)
clock_generator: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
clk_gen.tick <= '0';
clk_gen.cnt <= (others => '0');
elsif rising_edge(clk_i) then
if (ctrl.enable = '0') then -- reset/disabled
clk_gen.tick <= '0';
clk_gen.cnt <= (others => '0');
@ -222,9 +225,12 @@ begin
clkgen_en_o <= ctrl.enable;
-- generate four non-overlapping clock phases --
phase_generator: process(clk_i)
phase_generator: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
clk_gen.phase_gen <= (others => '0');
clk_gen.phase_gen_ff <= (others => '0');
elsif rising_edge(clk_i) then
clk_gen.phase_gen_ff <= clk_gen.phase_gen;
if (arbiter.state(2) = '0') or (arbiter.state(1 downto 0) = "00") then -- offline or idle
clk_gen.phase_gen <= "0001"; -- make sure to start with a new phase
@ -249,9 +255,19 @@ begin
-- TWI Transceiver ------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
twi_engine: process(clk_i)
twi_engine: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
io_con.sda_in_ff <= (others => '0');
io_con.scl_in_ff <= (others => '0');
io_con.sda_out <= '0';
io_con.scl_out <= '0';
irq_o <= '0';
arbiter.state <= (others => '0');
arbiter.bitcnt <= (others => '0');
arbiter.state_nxt <= (others => '0');
arbiter.rtx_sreg <= (others => '0');
elsif rising_edge(clk_i) then
-- input synchronizer --
io_con.sda_in_ff <= io_con.sda_in_ff(0) & io_con.sda_in;
io_con.scl_in_ff <= io_con.scl_in_ff(0) & io_con.scl_in;

View file

@ -149,6 +149,7 @@ architecture neorv32_uart_rtl of neorv32_uart is
done : std_ulogic;
busy : std_ulogic;
cts_sync : std_ulogic_vector(1 downto 0);
txd : std_ulogic;
end record;
signal tx_engine : tx_engine_t;
@ -179,13 +180,14 @@ architecture neorv32_uart_rtl of neorv32_uart is
begin
-- Host Access ----------------------------------------------------------------------------
-- Bus Access -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- write access --
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
ctrl.enable <= '0';
ctrl.sim_mode <= '0';
ctrl.hwfc_en <= '0';
@ -197,95 +199,89 @@ begin
ctrl.irq_tx_empty <= '0';
ctrl.irq_tx_nhalf <= '0';
elsif rising_edge(clk_i) then
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
if (bus_req_i.addr(2) = '0') then -- control register
ctrl.enable <= bus_req_i.data(ctrl_en_c);
ctrl.sim_mode <= bus_req_i.data(ctrl_sim_en_c);
ctrl.hwfc_en <= bus_req_i.data(ctrl_hwfc_en_c);
ctrl.prsc <= bus_req_i.data(ctrl_prsc2_c downto ctrl_prsc0_c);
ctrl.baud <= bus_req_i.data(ctrl_baud9_c downto ctrl_baud0_c);
--
ctrl.irq_rx_nempty <= bus_req_i.data(ctrl_irq_rx_nempty_c);
ctrl.irq_rx_half <= bus_req_i.data(ctrl_irq_rx_half_c);
ctrl.irq_rx_full <= bus_req_i.data(ctrl_irq_rx_full_c);
ctrl.irq_tx_empty <= bus_req_i.data(ctrl_irq_tx_empty_c);
ctrl.irq_tx_nhalf <= bus_req_i.data(ctrl_irq_tx_nhalf_c);
end if;
end if;
end if;
end process write_access;
-- read access --
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
bus_rsp_o.ack <= bus_req_i.stb; -- bus access acknowledge
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
if (bus_req_i.addr(2) = '0') then -- control register
bus_rsp_o.data(ctrl_en_c) <= ctrl.enable;
bus_rsp_o.data(ctrl_sim_en_c) <= ctrl.sim_mode;
bus_rsp_o.data(ctrl_hwfc_en_c) <= ctrl.hwfc_en;
bus_rsp_o.data(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl.prsc;
bus_rsp_o.data(ctrl_baud9_c downto ctrl_baud0_c) <= ctrl.baud;
--
bus_rsp_o.data(ctrl_rx_nempty_c) <= rx_fifo.avail;
bus_rsp_o.data(ctrl_rx_half_c) <= rx_fifo.half;
bus_rsp_o.data(ctrl_rx_full_c) <= not rx_fifo.free;
bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail;
bus_rsp_o.data(ctrl_tx_nhalf_c) <= not tx_fifo.half;
bus_rsp_o.data(ctrl_tx_full_c) <= not tx_fifo.free;
--
bus_rsp_o.data(ctrl_irq_rx_nempty_c) <= ctrl.irq_rx_nempty;
bus_rsp_o.data(ctrl_irq_rx_half_c) <= ctrl.irq_rx_half;
bus_rsp_o.data(ctrl_irq_rx_full_c) <= ctrl.irq_rx_full;
bus_rsp_o.data(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty;
bus_rsp_o.data(ctrl_irq_tx_nhalf_c) <= ctrl.irq_tx_nhalf;
--
bus_rsp_o.data(ctrl_rx_over_c) <= rx_engine.over;
bus_rsp_o.data(ctrl_tx_busy_c) <= tx_engine.busy or tx_fifo.avail;
else -- data register
bus_rsp_o.data(data_rtx_msb_c downto data_rtx_lsb_c) <= rx_fifo.rdata;
bus_rsp_o.data(data_rx_fifo_size_msb downto data_rx_fifo_size_lsb) <= std_ulogic_vector(to_unsigned(index_size_f(UART_RX_FIFO), 4));
bus_rsp_o.data(data_tx_fifo_size_msb downto data_tx_fifo_size_lsb) <= std_ulogic_vector(to_unsigned(index_size_f(UART_TX_FIFO), 4));
if (bus_req_i.stb = '1') then
-- write access --
if (bus_req_i.rw = '1') then
if (bus_req_i.addr(2) = '0') then -- control register
ctrl.enable <= bus_req_i.data(ctrl_en_c);
ctrl.sim_mode <= bus_req_i.data(ctrl_sim_en_c);
ctrl.hwfc_en <= bus_req_i.data(ctrl_hwfc_en_c);
ctrl.prsc <= bus_req_i.data(ctrl_prsc2_c downto ctrl_prsc0_c);
ctrl.baud <= bus_req_i.data(ctrl_baud9_c downto ctrl_baud0_c);
--
ctrl.irq_rx_nempty <= bus_req_i.data(ctrl_irq_rx_nempty_c);
ctrl.irq_rx_half <= bus_req_i.data(ctrl_irq_rx_half_c);
ctrl.irq_rx_full <= bus_req_i.data(ctrl_irq_rx_full_c);
ctrl.irq_tx_empty <= bus_req_i.data(ctrl_irq_tx_empty_c);
ctrl.irq_tx_nhalf <= bus_req_i.data(ctrl_irq_tx_nhalf_c);
end if;
-- read access --
else
if (bus_req_i.addr(2) = '0') then -- control register
bus_rsp_o.data(ctrl_en_c) <= ctrl.enable;
bus_rsp_o.data(ctrl_sim_en_c) <= ctrl.sim_mode;
bus_rsp_o.data(ctrl_hwfc_en_c) <= ctrl.hwfc_en;
bus_rsp_o.data(ctrl_prsc2_c downto ctrl_prsc0_c) <= ctrl.prsc;
bus_rsp_o.data(ctrl_baud9_c downto ctrl_baud0_c) <= ctrl.baud;
--
bus_rsp_o.data(ctrl_rx_nempty_c) <= rx_fifo.avail;
bus_rsp_o.data(ctrl_rx_half_c) <= rx_fifo.half;
bus_rsp_o.data(ctrl_rx_full_c) <= not rx_fifo.free;
bus_rsp_o.data(ctrl_tx_empty_c) <= not tx_fifo.avail;
bus_rsp_o.data(ctrl_tx_nhalf_c) <= not tx_fifo.half;
bus_rsp_o.data(ctrl_tx_full_c) <= not tx_fifo.free;
--
bus_rsp_o.data(ctrl_irq_rx_nempty_c) <= ctrl.irq_rx_nempty;
bus_rsp_o.data(ctrl_irq_rx_half_c) <= ctrl.irq_rx_half;
bus_rsp_o.data(ctrl_irq_rx_full_c) <= ctrl.irq_rx_full;
bus_rsp_o.data(ctrl_irq_tx_empty_c) <= ctrl.irq_tx_empty;
bus_rsp_o.data(ctrl_irq_tx_nhalf_c) <= ctrl.irq_tx_nhalf;
--
bus_rsp_o.data(ctrl_rx_over_c) <= rx_engine.over;
bus_rsp_o.data(ctrl_tx_busy_c) <= tx_engine.busy or tx_fifo.avail;
else -- data register
bus_rsp_o.data(data_rtx_msb_c downto data_rtx_lsb_c) <= rx_fifo.rdata;
bus_rsp_o.data(data_rx_fifo_size_msb downto data_rx_fifo_size_lsb) <= std_ulogic_vector(to_unsigned(index_size_f(UART_RX_FIFO), 4));
bus_rsp_o.data(data_tx_fifo_size_msb downto data_tx_fifo_size_lsb) <= std_ulogic_vector(to_unsigned(index_size_f(UART_TX_FIFO), 4));
end if;
end if;
end if;
end if;
end process read_access;
-- no access error possible --
bus_rsp_o.err <= '0';
end process bus_access;
-- UART clock enable --
clkgen_en_o <= ctrl.enable;
uart_clk <= clkgen_i(to_integer(unsigned(ctrl.prsc)));
-- Data Buffers ---------------------------------------------------------------------------
-- TX FIFO --------------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- TX FIFO --
tx_engine_fifo_inst: entity neorv32.neorv32_fifo
generic map (
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_DEPTH => UART_TX_FIFO,
FIFO_WIDTH => 8,
FIFO_RSYNC => true,
FIFO_SAFE => true
)
port map (
-- control --
clk_i => clk_i, -- clock, rising edge
rstn_i => rstn_i, -- async reset, low-active
clear_i => tx_fifo.clear, -- sync reset, high-active
half_o => tx_fifo.half, -- FIFO at least half-full
-- write port --
wdata_i => tx_fifo.wdata, -- write data
we_i => tx_fifo.we, -- write enable
free_o => tx_fifo.free, -- at least one entry is free when set
-- read port --
re_i => tx_fifo.re, -- read enable
rdata_o => tx_fifo.rdata, -- read data
avail_o => tx_fifo.avail -- data available when set
clk_i => clk_i,
rstn_i => rstn_i,
clear_i => tx_fifo.clear,
half_o => tx_fifo.half,
wdata_i => tx_fifo.wdata,
we_i => tx_fifo.we,
free_o => tx_fifo.free,
re_i => tx_fifo.re,
rdata_o => tx_fifo.rdata,
avail_o => tx_fifo.avail
);
tx_fifo.clear <= '1' when (ctrl.enable = '0') or (ctrl.sim_mode = '1') else '0';
@ -294,9 +290,11 @@ begin
tx_fifo.re <= '1' when (tx_engine.state = "100") else '0';
-- TX interrupt generator --
tx_irq_generator: process(clk_i)
tx_irq_generator: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
irq_tx_o <= '0';
elsif rising_edge(clk_i) then
irq_tx_o <= ctrl.enable and (
(ctrl.irq_tx_empty and (not tx_fifo.avail)) or -- fire IRQ if TX FIFO empty
(ctrl.irq_tx_nhalf and (not tx_fifo.half))); -- fire IRQ if TX FIFO not at least half full
@ -304,28 +302,26 @@ begin
end process tx_irq_generator;
-- RX FIFO --
-- RX FIFO --------------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
rx_engine_fifo_inst: entity neorv32.neorv32_fifo
generic map (
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_DEPTH => UART_RX_FIFO,
FIFO_WIDTH => 8,
FIFO_RSYNC => true,
FIFO_SAFE => true
)
port map (
-- control --
clk_i => clk_i, -- clock, rising edge
rstn_i => rstn_i, -- async reset, low-active
clear_i => rx_fifo.clear, -- sync reset, high-active
half_o => rx_fifo.half, -- FIFO at least half-full
-- write port --
wdata_i => rx_fifo.wdata, -- write data
we_i => rx_fifo.we, -- write enable
free_o => rx_fifo.free, -- at least one entry is free when set
-- read port --
re_i => rx_fifo.re, -- read enable
rdata_o => rx_fifo.rdata, -- read data
avail_o => rx_fifo.avail -- data available when set
clk_i => clk_i,
rstn_i => rstn_i,
clear_i => rx_fifo.clear,
half_o => rx_fifo.half,
wdata_i => rx_fifo.wdata,
we_i => rx_fifo.we,
free_o => rx_fifo.free,
re_i => rx_fifo.re,
rdata_o => rx_fifo.rdata,
avail_o => rx_fifo.avail
);
rx_fifo.clear <= '1' when (ctrl.enable = '0') or (ctrl.sim_mode = '1') else '0';
@ -334,9 +330,11 @@ begin
rx_fifo.re <= '1' when (bus_req_i.stb = '1') and (bus_req_i.rw = '0') and (bus_req_i.addr(2) = '1') else '0';
-- RX interrupt generator --
rx_irq_generator: process(clk_i)
rx_irq_generator: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
irq_rx_o <= '0';
elsif rising_edge(clk_i) then
irq_rx_o <= ctrl.enable and (
(ctrl.irq_rx_nempty and rx_fifo.avail) or -- fire IRQ if RX FIFO not empty
(ctrl.irq_rx_half and rx_fifo.half) or -- fire IRQ if RX FIFO at least half full
@ -347,14 +345,23 @@ begin
-- Transmit Engine ------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
transmitter: process(clk_i)
transmitter: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
tx_engine.cts_sync <= (others => '0');
tx_engine.done <= '0';
tx_engine.state <= (others => '0');
tx_engine.baudcnt <= (others => '0');
tx_engine.bitcnt <= (others => '0');
tx_engine.sreg <= (others => '0');
tx_engine.txd <= '1';
elsif rising_edge(clk_i) then
-- synchronize clear-to-send --
tx_engine.cts_sync <= tx_engine.cts_sync(0) & uart_cts_i;
-- defaults --
tx_engine.done <= '0';
tx_engine.txd <= '1';
-- FSM --
tx_engine.state(2) <= ctrl.enable;
@ -377,6 +384,7 @@ begin
when "111" => -- SEND: transmit data
-- ------------------------------------------------------------
tx_engine.txd <= tx_engine.sreg(0);
if (uart_clk = '1') then
if (or_reduce_f(tx_engine.baudcnt) = '0') then -- bit done?
tx_engine.baudcnt <= ctrl.baud;
@ -403,14 +411,21 @@ begin
tx_engine.busy <= '0' when (tx_engine.state(1 downto 0) = "00") else '1';
-- serial data output --
uart_txd_o <= tx_engine.sreg(0) when (tx_engine.state = "111") else '1'; -- data is sent LSB-first
uart_txd_o <= tx_engine.txd;
-- Receive Engine -------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
receiver: process(clk_i)
receiver: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
rx_engine.sync <= (others => '0');
rx_engine.done <= '0';
rx_engine.state <= (others => '0');
rx_engine.baudcnt <= (others => '0');
rx_engine.bitcnt <= (others => '0');
rx_engine.sreg <= (others => '0');
elsif rising_edge(clk_i) then
-- input synchronizer --
rx_engine.sync(2) <= uart_rxd_i;
if (uart_clk = '1') then
@ -458,9 +473,11 @@ begin
end process receiver;
-- RX overrun flag --
fifo_overrun: process(clk_i)
fifo_overrun: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
rx_engine.over <= '0';
elsif rising_edge(clk_i) then
if ((bus_req_i.stb = '1') and (bus_req_i.rw = '0') and (bus_req_i.addr(2) = '1')) or (ctrl.enable = '0') then -- clear when reading data register
rx_engine.over <= '0';
elsif (rx_fifo.we = '1') and (rx_fifo.free = '0') then -- writing to full FIFO
@ -470,9 +487,11 @@ begin
end process fifo_overrun;
-- HW flow-control: ready to receive? --
rtr_control: process(clk_i)
rtr_control: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
uart_rts_o <= '0';
elsif rising_edge(clk_i) then
if (ctrl.hwfc_en = '1') then
if (ctrl.enable = '0') or -- UART disabled
(rx_fifo.half = '1') then -- RX FIFO at least half-full: no "safe space" left in RX FIFO
@ -494,10 +513,10 @@ begin
sim_tx: process(clk_i)
file file_out : text open write_mode is SIM_LOG_FILE;
variable char_v : integer;
variable line_screen_v : line; -- we need several line variables here since "writeline" seems to flush the source variable
variable line_screen_v : line;
variable line_file_v : line;
begin
if rising_edge(clk_i) then
if rising_edge(clk_i) then -- no reset required
if (ctrl.enable = '1') and (ctrl.sim_mode = '1') and (bus_req_i.stb = '1') and (bus_req_i.rw = '1') and (bus_req_i.addr(2) = '1') then
-- convert lowest byte to ASCII char --
char_v := to_integer(unsigned(bus_req_i.data(7 downto 0)));

View file

@ -108,69 +108,69 @@ architecture neorv32_wdt_rtl of neorv32_wdt is
begin
-- Host Access ----------------------------------------------------------------------------
-- Bus Access -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- write access --
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
ctrl.enable <= '0'; -- disable WDT after reset
ctrl.lock <= '0'; -- unlock after reset
ctrl.dben <= '0';
ctrl.sen <= '0';
ctrl.strict <= '0';
ctrl.timeout <= (others => '0');
reset_wdt <= '0';
reset_force <= '0';
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
ctrl.enable <= '0'; -- disable WDT after reset
ctrl.lock <= '0'; -- unlock after reset
ctrl.dben <= '0';
ctrl.sen <= '0';
ctrl.strict <= '0';
ctrl.timeout <= (others => '0');
reset_wdt <= '0';
reset_force <= '0';
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
-- defaults --
reset_wdt <= '0';
reset_force <= '0';
-- bus access --
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
if (bus_req_i.addr(2) = '0') then -- control register
if (ctrl.lock = '0') then -- update configuration only if not locked
ctrl.enable <= bus_req_i.data(ctrl_enable_c);
ctrl.lock <= bus_req_i.data(ctrl_lock_c) and ctrl.enable; -- lock only if already enabled
ctrl.dben <= bus_req_i.data(ctrl_dben_c);
ctrl.sen <= bus_req_i.data(ctrl_sen_c);
ctrl.strict <= bus_req_i.data(ctrl_strict_c);
ctrl.timeout <= bus_req_i.data(ctrl_timeout_msb_c downto ctrl_timeout_lsb_c);
else -- write access attempt to locked CTRL register
reset_force <= '1';
end if;
else -- reset timeout counter - password check
if (bus_req_i.data(31 downto 0) = reset_pwd_c) then
reset_wdt <= '1'; -- password correct
else
reset_force <= '1'; -- password incorrect
if (bus_req_i.stb = '1') then
-- write access --
if (bus_req_i.rw = '1') then
if (bus_req_i.addr(2) = '0') then -- control register
if (ctrl.lock = '0') then -- update configuration only if not locked
ctrl.enable <= bus_req_i.data(ctrl_enable_c);
ctrl.lock <= bus_req_i.data(ctrl_lock_c) and ctrl.enable; -- lock only if already enabled
ctrl.dben <= bus_req_i.data(ctrl_dben_c);
ctrl.sen <= bus_req_i.data(ctrl_sen_c);
ctrl.strict <= bus_req_i.data(ctrl_strict_c);
ctrl.timeout <= bus_req_i.data(ctrl_timeout_msb_c downto ctrl_timeout_lsb_c);
else -- write access attempt to locked CTRL register
reset_force <= '1';
end if;
else -- reset timeout counter - password check
if (bus_req_i.data(31 downto 0) = reset_pwd_c) then
reset_wdt <= '1'; -- password correct
else
reset_force <= '1'; -- password incorrect
end if;
end if;
-- read access --
else
bus_rsp_o.data(ctrl_enable_c) <= ctrl.enable;
bus_rsp_o.data(ctrl_lock_c) <= ctrl.lock;
bus_rsp_o.data(ctrl_dben_c) <= ctrl.dben;
bus_rsp_o.data(ctrl_sen_c) <= ctrl.sen;
bus_rsp_o.data(ctrl_rcause_hi_c downto ctrl_rcause_lo_c) <= rst_cause_i;
bus_rsp_o.data(ctrl_strict_c) <= ctrl.strict;
bus_rsp_o.data(ctrl_timeout_msb_c downto ctrl_timeout_lsb_c) <= ctrl.timeout;
end if;
end if;
end if;
end process write_access;
-- read access --
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
bus_rsp_o.data(ctrl_enable_c) <= ctrl.enable;
bus_rsp_o.data(ctrl_lock_c) <= ctrl.lock;
bus_rsp_o.data(ctrl_dben_c) <= ctrl.dben;
bus_rsp_o.data(ctrl_sen_c) <= ctrl.sen;
bus_rsp_o.data(ctrl_rcause_hi_c downto ctrl_rcause_lo_c) <= rst_cause_i;
bus_rsp_o.data(ctrl_strict_c) <= ctrl.strict;
bus_rsp_o.data(ctrl_timeout_msb_c downto ctrl_timeout_lsb_c) <= ctrl.timeout;
end if;
end if;
end process read_access;
-- no access error possible --
bus_rsp_o.err <= '0';
end process bus_access;
-- Timeout Counter ------------------------------------------------------------------------

View file

@ -115,6 +115,7 @@ architecture neorv32_xip_rtl of neorv32_xip is
component neorv32_xip_phy
port (
-- global control --
rstn_i : in std_ulogic; -- reset, async, low-active
clk_i : in std_ulogic; -- clock
spi_clk_en_i : in std_ulogic; -- pre-scaled SPI clock-enable
-- operation configuration --
@ -149,81 +150,83 @@ architecture neorv32_xip_rtl of neorv32_xip is
begin
-- Control Write Access -------------------------------------------------------------------
-- Control Bus Access ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
ctrl_write_access : process(rstn_i, clk_i)
ctrl_bus_access : process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
ctrl <= (others => '0');
spi_data_lo <= (others => '0');
spi_data_hi <= (others => '0');
spi_trigger <= '0';
elsif rising_edge(clk_i) then
spi_trigger <= '0';
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
-- control register --
if (bus_req_i.addr(3 downto 2) = "00") then
ctrl(ctrl_enable_c) <= bus_req_i.data(ctrl_enable_c);
ctrl(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c) <= bus_req_i.data(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c);
ctrl(ctrl_spi_cpol_c) <= bus_req_i.data(ctrl_spi_cpol_c);
ctrl(ctrl_spi_cpha_c) <= bus_req_i.data(ctrl_spi_cpha_c);
ctrl(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c) <= bus_req_i.data(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c);
ctrl(ctrl_xip_enable_c) <= bus_req_i.data(ctrl_xip_enable_c);
ctrl(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c) <= bus_req_i.data(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c);
ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c) <= bus_req_i.data(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c);
ctrl(ctrl_spi_csen_c) <= bus_req_i.data(ctrl_spi_csen_c);
ctrl(ctrl_highspeed_c) <= bus_req_i.data(ctrl_highspeed_c);
ctrl(ctrl_burst_en_c) <= bus_req_i.data(ctrl_burst_en_c);
end if;
-- SPI direct data access register lo --
if (bus_req_i.addr(3 downto 2) = "10") then
spi_data_lo <= bus_req_i.data;
end if;
-- SPI direct data access register hi --
if (bus_req_i.addr(3 downto 2) = "11") then
spi_data_hi <= bus_req_i.data;
spi_trigger <= '1'; -- trigger direct SPI transaction
end if;
end if;
end if;
end process ctrl_write_access;
-- Control Read Access --------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
ctrl_read_access : process(clk_i)
begin
if rising_edge(clk_i) then
bus_rsp_o.ack <= bus_req_i.stb; -- access acknowledge
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
case bus_req_i.addr(3 downto 2) is
when "00" => -- 'xip_ctrl_addr_c' - control register
bus_rsp_o.data(ctrl_enable_c) <= ctrl(ctrl_enable_c);
bus_rsp_o.data(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c) <= ctrl(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c);
bus_rsp_o.data(ctrl_spi_cpol_c) <= ctrl(ctrl_spi_cpol_c);
bus_rsp_o.data(ctrl_spi_cpha_c) <= ctrl(ctrl_spi_cpha_c);
bus_rsp_o.data(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c) <= ctrl(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c);
bus_rsp_o.data(ctrl_xip_enable_c) <= ctrl(ctrl_xip_enable_c);
bus_rsp_o.data(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c) <= ctrl(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c);
bus_rsp_o.data(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c) <= ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c);
bus_rsp_o.data(ctrl_spi_csen_c) <= ctrl(ctrl_spi_csen_c);
bus_rsp_o.data(ctrl_highspeed_c) <= ctrl(ctrl_highspeed_c);
bus_rsp_o.data(ctrl_burst_en_c) <= ctrl(ctrl_burst_en_c);
--
bus_rsp_o.data(ctrl_phy_busy_c) <= phy_if.busy;
bus_rsp_o.data(ctrl_xip_busy_c) <= arbiter.busy;
when "10" => -- 'xip_data_lo_addr_c' - SPI direct data access register lo
bus_rsp_o.data <= phy_if.rdata;
when others => -- unavailable (not implemented or write-only)
bus_rsp_o.data <= (others => '0');
end case;
ctrl <= (others => '0');
spi_data_lo <= (others => '0');
spi_data_hi <= (others => '0');
spi_trigger <= '0';
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
-- defaults --
spi_trigger <= '0';
if (bus_req_i.stb = '1') then
-- write access --
if (bus_req_i.rw = '1') then
-- control register --
if (bus_req_i.addr(3 downto 2) = "00") then
ctrl(ctrl_enable_c) <= bus_req_i.data(ctrl_enable_c);
ctrl(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c) <= bus_req_i.data(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c);
ctrl(ctrl_spi_cpol_c) <= bus_req_i.data(ctrl_spi_cpol_c);
ctrl(ctrl_spi_cpha_c) <= bus_req_i.data(ctrl_spi_cpha_c);
ctrl(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c) <= bus_req_i.data(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c);
ctrl(ctrl_xip_enable_c) <= bus_req_i.data(ctrl_xip_enable_c);
ctrl(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c) <= bus_req_i.data(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c);
ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c) <= bus_req_i.data(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c);
ctrl(ctrl_spi_csen_c) <= bus_req_i.data(ctrl_spi_csen_c);
ctrl(ctrl_highspeed_c) <= bus_req_i.data(ctrl_highspeed_c);
ctrl(ctrl_burst_en_c) <= bus_req_i.data(ctrl_burst_en_c);
end if;
-- SPI direct data access register lo --
if (bus_req_i.addr(3 downto 2) = "10") then
spi_data_lo <= bus_req_i.data;
end if;
-- SPI direct data access register hi --
if (bus_req_i.addr(3 downto 2) = "11") then
spi_data_hi <= bus_req_i.data;
spi_trigger <= '1'; -- trigger direct SPI transaction
end if;
-- read access --
else
case bus_req_i.addr(3 downto 2) is
when "00" => -- 'xip_ctrl_addr_c' - control register
bus_rsp_o.data(ctrl_enable_c) <= ctrl(ctrl_enable_c);
bus_rsp_o.data(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c) <= ctrl(ctrl_spi_prsc2_c downto ctrl_spi_prsc0_c);
bus_rsp_o.data(ctrl_spi_cpol_c) <= ctrl(ctrl_spi_cpol_c);
bus_rsp_o.data(ctrl_spi_cpha_c) <= ctrl(ctrl_spi_cpha_c);
bus_rsp_o.data(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c) <= ctrl(ctrl_spi_nbytes3_c downto ctrl_spi_nbytes0_c);
bus_rsp_o.data(ctrl_xip_enable_c) <= ctrl(ctrl_xip_enable_c);
bus_rsp_o.data(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c) <= ctrl(ctrl_xip_abytes1_c downto ctrl_xip_abytes0_c);
bus_rsp_o.data(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c) <= ctrl(ctrl_rd_cmd7_c downto ctrl_rd_cmd0_c);
bus_rsp_o.data(ctrl_spi_csen_c) <= ctrl(ctrl_spi_csen_c);
bus_rsp_o.data(ctrl_highspeed_c) <= ctrl(ctrl_highspeed_c);
bus_rsp_o.data(ctrl_burst_en_c) <= ctrl(ctrl_burst_en_c);
--
bus_rsp_o.data(ctrl_phy_busy_c) <= phy_if.busy;
bus_rsp_o.data(ctrl_xip_busy_c) <= arbiter.busy;
when "10" => -- 'xip_data_lo_addr_c' - SPI direct data access register lo
bus_rsp_o.data <= phy_if.rdata;
when others => -- unavailable (not implemented or write-only)
bus_rsp_o.data <= (others => '0');
end case;
end if;
end if;
end if;
end process ctrl_read_access;
-- no access error possible --
bus_rsp_o.err <= '0';
end process ctrl_bus_access;
-- XIP Address Computation Logic ----------------------------------------------------------
@ -245,9 +248,15 @@ begin
-- SPI Access Arbiter ---------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
arbiter_sync: process(clk_i)
arbiter_sync: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
arbiter.state <= S_DIRECT;
arbiter.addr <= (others => '0');
arbiter.addr_lookahead <= (others => '0');
arbiter.xip_acc_err <= '0';
arbiter.tmo_cnt <= (others => '0');
elsif rising_edge(clk_i) then
-- state control --
if (ctrl(ctrl_enable_c) = '0') or (ctrl(ctrl_xip_enable_c) = '0') then -- sync reset
arbiter.state <= S_DIRECT;
@ -365,6 +374,7 @@ begin
neorv32_xip_phy_inst: neorv32_xip_phy
port map (
-- global control --
rstn_i => rstn_i,
clk_i => clk_i,
spi_clk_en_i => spi_clk_en,
-- operation configuration --
@ -438,6 +448,7 @@ use neorv32.neorv32_package.all;
entity neorv32_xip_phy is
port (
-- global control --
rstn_i : in std_ulogic; -- reset, async, low-active
clk_i : in std_ulogic; -- clock
spi_clk_en_i : in std_ulogic; -- pre-scaled SPI clock-enable
-- operation configuration --
@ -477,9 +488,17 @@ begin
-- Serial Interface Engine ----------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
serial_engine: process(clk_i)
serial_engine: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
spi_clk_o <= '0';
spi_csn_o <= '1';
ctrl.state <= S_IDLE;
ctrl.csen <= '0';
ctrl.sreg <= (others => '0');
ctrl.bitcnt <= (others => '0');
ctrl.di_sync <= '0';
elsif rising_edge(clk_i) then
if (cf_enable_i = '0') then -- sync reset
spi_clk_o <= '0';
spi_csn_o <= '1';

View file

@ -85,53 +85,58 @@ architecture neorv32_xirq_rtl of neorv32_xirq is
begin
-- Host Access ----------------------------------------------------------------------------
-- Bus Access -----------------------------------------------------------------------------
-- -------------------------------------------------------------------------------------------
-- write access --
write_access: process(rstn_i, clk_i)
bus_access: process(rstn_i, clk_i)
begin
if (rstn_i = '0') then
nclr_pending <= (others => '0'); -- clear all pending interrupts on reset
irq_enable <= (others => '0');
elsif rising_edge(clk_i) then
nclr_pending <= (others => '1');
if (bus_req_i.stb = '1') and (bus_req_i.rw = '1') then
if (bus_req_i.addr(3 downto 2) = "00") then -- channel-enable
irq_enable <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0);
end if;
if (bus_req_i.addr(3 downto 2) = "01") then -- clear pending IRQs
nclr_pending <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0); -- set zero to clear pending IRQ
end if;
end if;
end if;
end process write_access;
-- read access --
read_access: process(clk_i)
begin
if rising_edge(clk_i) then
bus_rsp_o.ack <= bus_req_i.stb; -- bus handshake
bus_rsp_o.ack <= '0';
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
if (bus_req_i.stb = '1') and (bus_req_i.rw = '0') then
case bus_req_i.addr(3 downto 2) is
when "00" => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_enable; -- channel-enable
when "01" => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_pending; -- pending IRQs
when others => bus_rsp_o.data(4 downto 0) <= irq_source; -- IRQ source
end case;
nclr_pending <= (others => '0');
irq_enable <= (others => '0');
elsif rising_edge(clk_i) then
-- bus handshake --
bus_rsp_o.ack <= bus_req_i.stb;
bus_rsp_o.err <= '0';
bus_rsp_o.data <= (others => '0');
-- defaults --
nclr_pending <= (others => '1');
if (bus_req_i.stb = '1') then
-- write access --
if (bus_req_i.rw = '1') then
if (bus_req_i.addr(3 downto 2) = "00") then -- channel-enable
irq_enable <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0);
end if;
if (bus_req_i.addr(3 downto 2) = "01") then -- clear pending IRQs
nclr_pending <= bus_req_i.data(XIRQ_NUM_CH-1 downto 0); -- set zero to clear pending IRQ
end if;
-- read access --
else
case bus_req_i.addr(3 downto 2) is
when "00" => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_enable; -- channel-enable
when "01" => bus_rsp_o.data(XIRQ_NUM_CH-1 downto 0) <= irq_pending; -- pending IRQs
when others => bus_rsp_o.data(4 downto 0) <= irq_source; -- IRQ source
end case;
end if;
end if;
end if;
end process read_access;
-- no access error possible --
bus_rsp_o.err <= '0';
end process bus_access;
-- IRQ Trigger --------------------------------------------------------------
-- -----------------------------------------------------------------------------
synchronizer: process(clk_i)
synchronizer: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
irq_sync <= (others => '0');
irq_sync2 <= (others => '0');
elsif rising_edge(clk_i) then
irq_sync <= xirq_i(XIRQ_NUM_CH-1 downto 0);
irq_sync2 <= irq_sync;
end if;
@ -157,9 +162,11 @@ begin
-- IRQ Buffer ---------------------------------------------------------------
-- -----------------------------------------------------------------------------
irq_buffer: process(clk_i)
irq_buffer: process(rstn_i, clk_i)
begin
if rising_edge(clk_i) then
if (rstn_i = '0') then
irq_pending <= (others => '0');
elsif rising_edge(clk_i) then
irq_pending <= (irq_pending and nclr_pending) or irq_trig;
end if;
end process irq_buffer;