Line 124... |
Line 124... |
-- bus access control --
|
-- bus access control --
|
signal ack_read : std_ulogic;
|
signal ack_read : std_ulogic;
|
signal ack_write : std_ulogic;
|
signal ack_write : std_ulogic;
|
signal acc_en : std_ulogic;
|
signal acc_en : std_ulogic;
|
signal addr : std_ulogic_vector(31 downto 0);
|
signal addr : std_ulogic_vector(31 downto 0);
|
|
signal wren : std_ulogic; -- word write enable
|
|
signal rden : std_ulogic; -- read enable
|
|
|
-- control register --
|
-- control register --
|
signal enable : std_ulogic; -- global enable
|
signal enable : std_ulogic; -- global enable
|
|
|
-- IRQ configuration register --
|
-- IRQ configuration register --
|
Line 146... |
Line 148... |
signal rx_fifo_avail : std_ulogic_vector(7 downto 0);
|
signal rx_fifo_avail : std_ulogic_vector(7 downto 0);
|
signal tx_fifo_free : std_ulogic_vector(7 downto 0);
|
signal tx_fifo_free : std_ulogic_vector(7 downto 0);
|
signal rx_fifo_half : std_ulogic_vector(7 downto 0);
|
signal rx_fifo_half : std_ulogic_vector(7 downto 0);
|
signal tx_fifo_half : std_ulogic_vector(7 downto 0);
|
signal tx_fifo_half : std_ulogic_vector(7 downto 0);
|
|
|
|
-- interrupt generator --
|
|
type detect_t is array (0 to 7) of std_ulogic_vector(1 downto 0);
|
|
type irq_t is record
|
|
pending : std_ulogic; -- pending interrupt request
|
|
detect : detect_t; -- rising-edge detector
|
|
trigger : std_ulogic_vector(7 downto 0);
|
|
set : std_ulogic_vector(7 downto 0);
|
|
clr : std_ulogic;
|
|
end record;
|
|
signal rx_irq, tx_irq : irq_t;
|
|
|
begin
|
begin
|
|
|
-- Sanity Checks --------------------------------------------------------------------------
|
-- Sanity Checks --------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
assert not (is_power_of_two_f(SLINK_TX_FIFO) = false) report "NEORV32 PROCESSOR CONFIG ERROR: SLINK <SLINK_TX_FIFO> has to be a power of two." severity error;
|
assert not (is_power_of_two_f(SLINK_TX_FIFO) = false) report "NEORV32 PROCESSOR CONFIG ERROR: SLINK <SLINK_TX_FIFO> has to be a power of two." severity error;
|
Line 167... |
Line 180... |
|
|
-- Access Control -------------------------------------------------------------------------
|
-- Access Control -------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = slink_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
acc_en <= '1' when (addr_i(hi_abb_c downto lo_abb_c) = slink_base_c(hi_abb_c downto lo_abb_c)) else '0';
|
addr <= slink_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned
|
addr <= slink_base_c(31 downto lo_abb_c) & addr_i(lo_abb_c-1 downto 2) & "00"; -- word aligned
|
|
wren <= acc_en and wren_i;
|
|
rden <= acc_en and rden_i;
|
|
|
|
|
-- Read/Write Access ----------------------------------------------------------------------
|
-- Read/Write Access ----------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
rw_access: process(clk_i)
|
rw_access: process(clk_i)
|
begin
|
begin
|
if rising_edge(clk_i) then
|
if rising_edge(clk_i) then
|
-- write access --
|
-- write access --
|
ack_write <= '0';
|
ack_write <= '0';
|
if (acc_en = '1') and (wren_i = '1') then
|
if (wren = '1') then
|
if (addr(5) = '0') then -- control/status/irq
|
if (addr(5) = '0') then -- control/status/irq
|
if (addr(4 downto 3) = "00") then -- control register
|
if (addr(4 downto 3) = "00") then -- control register
|
enable <= data_i(ctrl_en_c);
|
enable <= data_i(ctrl_en_c);
|
end if;
|
end if;
|
if (addr(4 downto 3) = "01") then -- IRQ configuration register
|
if (addr(4 downto 3) = "01") then -- IRQ configuration register
|
Line 200... |
Line 215... |
end if;
|
end if;
|
|
|
-- read access --
|
-- read access --
|
data_o <= (others => '0');
|
data_o <= (others => '0');
|
ack_read <= '0';
|
ack_read <= '0';
|
if (acc_en = '1') and (rden_i = '1') then
|
if (rden = '1') then
|
if (addr(5) = '0') then -- control/status registers
|
if (addr(5) = '0') then -- control/status registers
|
ack_read <= '1';
|
ack_read <= '1';
|
case addr(4 downto 3) is
|
case addr(4 downto 3) is
|
when "00" => -- control register
|
when "00" => -- control register
|
data_o(ctrl_rx_num_msb_c downto ctrl_rx_num_lsb_c) <= std_ulogic_vector(to_unsigned(SLINK_NUM_RX, 4));
|
data_o(ctrl_rx_num_msb_c downto ctrl_rx_num_lsb_c) <= std_ulogic_vector(to_unsigned(SLINK_NUM_RX, 4));
|
Line 244... |
Line 259... |
fifo_clear <= not enable;
|
fifo_clear <= not enable;
|
|
|
|
|
-- Interrupt Generator --------------------------------------------------------------------
|
-- Interrupt Generator --------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
irq_arbiter: process(clk_i)
|
irq_type: process(irq_rx_mode, rx_fifo_avail, rx_fifo_half,
|
variable rx_tmp_v : std_ulogic_vector(SLINK_NUM_RX-1 downto 0);
|
irq_tx_mode, tx_fifo_free, tx_fifo_half)
|
variable tx_tmp_v : std_ulogic_vector(SLINK_NUM_TX-1 downto 0);
|
|
begin
|
begin
|
if rising_edge(clk_i) then
|
|
if (enable = '0') then -- no interrupts if unit is disabled
|
|
irq_rx_o <= '0';
|
|
irq_tx_o <= '0';
|
|
else
|
|
|
|
-- RX interrupt --
|
-- RX interrupt --
|
|
rx_irq.trigger <= (others => '0');
|
|
for i in 0 to SLINK_NUM_RX-1 loop
|
if (SLINK_RX_FIFO = 1) then
|
if (SLINK_RX_FIFO = 1) then
|
irq_rx_o <= or_reduce_f(irq_rx_en and rx_fifo_avail); -- fire if any RX_FIFO is not empty
|
rx_irq.trigger(i) <= rx_fifo_avail(i); -- fire if any RX_FIFO is not empty
|
else
|
else
|
rx_tmp_v := (others => '0');
|
|
for i in 0 to SLINK_NUM_RX-1 loop
|
|
if (irq_rx_mode(i) = '0') then -- fire if any RX_FIFO is at least half-full
|
if (irq_rx_mode(i) = '0') then -- fire if any RX_FIFO is at least half-full
|
rx_tmp_v(i) := rx_fifo_half(i);
|
rx_irq.trigger(i) <= rx_fifo_half(i);
|
else -- fire if any RX_FIFO is not empty (= data available)
|
else -- fire if any RX_FIFO is not empty (= data available)
|
rx_tmp_v(i) := rx_fifo_avail(i);
|
rx_irq.trigger(i) <= rx_fifo_avail(i);
|
end if;
|
end if;
|
end loop;
|
|
irq_rx_o <= or_reduce_f(irq_rx_en and rx_tmp_v);
|
|
end if;
|
end if;
|
|
end loop;
|
-- TX interrupt --
|
-- TX interrupt --
|
|
tx_irq.trigger <= (others => '0');
|
|
for i in 0 to SLINK_NUM_TX-1 loop
|
if (SLINK_TX_FIFO = 1) then
|
if (SLINK_TX_FIFO = 1) then
|
irq_tx_o <= or_reduce_f(irq_tx_en and tx_fifo_free); -- fire if any TX_FIFO is not full
|
tx_irq.trigger(i) <= tx_fifo_free(i); -- fire if any TX_FIFO is not full
|
else
|
else
|
tx_tmp_v := (others => '0');
|
if (irq_tx_mode(i) = '0') then -- fire if any TX_FIFO is less than half-full
|
|
tx_irq.trigger(i) <= not tx_fifo_half(i);
|
|
else -- fire if any TX_FIFO is not full (= free buffer space available)
|
|
tx_irq.trigger(i) <= tx_fifo_free(i);
|
|
end if;
|
|
end if;
|
|
end loop;
|
|
end process irq_type;
|
|
|
|
-- interrupt trigger --
|
|
irq_trigger_sync: process(clk_i)
|
|
begin
|
|
if rising_edge(clk_i) then
|
|
-- RX --
|
|
rx_irq.detect <= (others => (others => '0')); -- default
|
|
if (enable = '1') then
|
|
for i in 0 to SLINK_NUM_RX-1 loop
|
|
rx_irq.detect(i) <= rx_irq.detect(i)(0) & rx_irq.trigger(i);
|
|
end loop;
|
|
end if;
|
|
-- TX --
|
|
tx_irq.detect <= (others => (others => '0')); -- default
|
|
if (enable = '1') then
|
for i in 0 to SLINK_NUM_TX-1 loop
|
for i in 0 to SLINK_NUM_TX-1 loop
|
if (irq_tx_mode(i) = '0') then -- fire if any RX_FIFO is less than half-full
|
tx_irq.detect(i) <= tx_irq.detect(i)(0) & tx_irq.trigger(i);
|
tx_tmp_v(i) := not rx_fifo_half(i);
|
end loop;
|
else -- fire if any RX_FIFO is not full (= free buffer space available)
|
end if;
|
tx_tmp_v(i) := tx_fifo_free(i);
|
end if;
|
|
end process irq_trigger_sync;
|
|
|
|
-- interrupt trigger --
|
|
irq_trigger_comb: process(rx_irq, irq_rx_en, tx_irq, irq_tx_en)
|
|
begin
|
|
-- RX --
|
|
rx_irq.set <= (others => '0');
|
|
for i in 0 to SLINK_NUM_RX-1 loop
|
|
if (rx_irq.detect(i) = "01") and (irq_rx_en(i) = '1') then -- rising-edge
|
|
rx_irq.set(i) <= '1';
|
end if;
|
end if;
|
end loop;
|
end loop;
|
irq_tx_o <= or_reduce_f(irq_tx_en and tx_tmp_v);
|
-- TX --
|
|
tx_irq.set <= (others => '0');
|
|
for i in 0 to SLINK_NUM_TX-1 loop
|
|
if (tx_irq.detect(i) = "01") and (irq_tx_en(i) = '1') then -- rising-edge
|
|
tx_irq.set(i) <= '1';
|
end if;
|
end if;
|
|
end loop;
|
|
end process irq_trigger_comb;
|
|
|
|
-- interrupt arbiter --
|
|
irq_generator: process(clk_i)
|
|
begin
|
|
if rising_edge(clk_i) then
|
|
if (enable = '0') then
|
|
rx_irq.pending <= '0';
|
|
tx_irq.pending <= '0';
|
|
else
|
|
-- RX --
|
|
if (or_reduce_f(rx_irq.set) = '1') then
|
|
rx_irq.pending <= '1';
|
|
elsif (rx_irq.clr = '1') then
|
|
rx_irq.pending <= '0';
|
end if;
|
end if;
|
|
-- TX --
|
|
if (or_reduce_f(tx_irq.set) = '1') then
|
|
tx_irq.pending <= '1';
|
|
elsif (tx_irq.clr = '1') then
|
|
tx_irq.pending <= '0';
|
end if;
|
end if;
|
end process irq_arbiter;
|
end if;
|
|
end if;
|
|
end process irq_generator;
|
|
|
|
-- IRQ requests to CPU --
|
|
irq_rx_o <= rx_irq.pending;
|
|
irq_tx_o <= tx_irq.pending;
|
|
|
|
-- IRQ acknowledge --
|
|
rx_irq.clr <= '1' when ((rden = '1') and (addr(5) = '1')) or ((wren = '1') and (addr(5 downto 3) = "000")) else '0'; -- read from data FIFO OR write to control register
|
|
tx_irq.clr <= '1' when ((wren = '1') and (addr(5) = '1')) or ((wren = '1') and (addr(5 downto 3) = "000")) else '0'; -- write to data FIFO OR write to control register
|
|
|
|
|
-- Link Select ----------------------------------------------------------------------------
|
-- Link Select ----------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
link_select: process(addr)
|
link_select: process(addr)
|
Line 307... |
Line 382... |
end case;
|
end case;
|
end process link_select;
|
end process link_select;
|
|
|
fifo_access_gen:
|
fifo_access_gen:
|
for i in 0 to 7 generate
|
for i in 0 to 7 generate
|
tx_fifo_we(i) <= link_sel(i) and acc_en and wren_i;
|
tx_fifo_we(i) <= link_sel(i) and wren;
|
rx_fifo_re(i) <= link_sel(i) and acc_en and rden_i;
|
rx_fifo_re(i) <= link_sel(i) and rden;
|
end generate;
|
end generate;
|
|
|
|
|
-- TX Link FIFOs --------------------------------------------------------------------------
|
-- TX Link FIFOs --------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|
-- -------------------------------------------------------------------------------------------
|