Skip to content
Snippets Groups Projects
Commit 08af7a09 authored by Mathias Kreider's avatar Mathias Kreider
Browse files

fixed irq loss in edge triggered mode

parent 29db1b2a
Branches
Tags
No related merge requests found
......@@ -34,7 +34,7 @@ use work.wb_irq_pkg.all;
entity irqm_core is
generic( g_channels : natural := 32; -- number of interrupt lines
g_round_rb : boolean := true; -- scheduler true: round robin, false: prioritised
g_det_edge : boolean := true -- edge detection. true: trigger on rising edge of irq lines, false: trigger on high level
g_det_edge : boolean -- edge detection. true: trigger on rising edge of irq lines, false: trigger on high level
);
port (clk_i : in std_logic; -- clock
rst_n_i : in std_logic; -- reset, active LO
......@@ -55,6 +55,11 @@ end entity;
architecture behavioral of irqm_core is
subtype cnt is unsigned(8 downto 0);
type cnt_array is array(natural range <>) of cnt;
signal r_cnt_array : cnt_array(g_channels-1 downto 0);
signal s_msg : t_wishbone_data_array(g_channels-1 downto 0);
signal s_dst : t_wishbone_address_array(g_channels-1 downto 0);
......@@ -68,7 +73,7 @@ signal r_irq0,
signal r_en0,
r_en1 : std_logic;
signal r_pending : std_logic_vector(g_channels-1 downto 0);
signal r_pending, r_wait : std_logic_vector(g_channels-1 downto 0);
signal s_wb_send : std_logic;
......@@ -76,7 +81,7 @@ signal idx : natural range 0 to g_channels-1;
signal idx_robin : natural range 0 to g_channels-1;
signal idx_prio : natural range 0 to g_channels-1;
signal r_cyc : std_logic;
signal r_cyc0, r_cyc1, s_cyc_f_edge : std_logic;
signal r_stb : std_logic;
begin
......@@ -86,11 +91,14 @@ s_msg <= msi_msg_array;
s_dst <= msi_dst_array;
-- always full words, always write
irq_master_o.cyc <= r_cyc;
irq_master_o.cyc <= r_cyc0;
irq_master_o.stb <= r_stb;
irq_master_o.sel <= (others => '1');
irq_master_o.we <= '1';
-------------------------------------------------------------------------
-- registering and counters
-------------------------------------------------------------------------
......@@ -130,6 +138,7 @@ irq_master_o.we <= '1';
s_irq_edge <= r_irqm0;
end generate;
s_cyc_f_edge <= not r_cyc0 and r_cyc1;
-- round robin
idx_round_robin : process(clk_i)
......@@ -138,7 +147,7 @@ irq_master_o.we <= '1';
if(rst_n_i = '0') then
idx_robin <= 0;
else
if(r_cyc = '0' and r_pending(idx_robin) = '0') then
if(r_cyc0 = '0' and r_cyc1 = '0') then
if(idx_robin = g_channels-1) then
idx_robin <= 0;
else
......@@ -164,22 +173,42 @@ irq_master_o.we <= '1';
--------------------------------------------------------------------------------------------
s_wb_send <= r_pending(idx);
-- keep track of what needs sending
queue_mux : process(clk_i)
variable v_set_pending, v_clr_pending : std_logic_vector(r_pending'length-1 downto 0);
begin
if rising_edge(clk_i) then
if((rst_n_i) = '0') then
r_pending <= (others => '0');
else
v_clr_pending := (others => '1');
v_clr_pending(idx) := not r_cyc;
v_set_pending := s_irq_edge;
r_pending <= (r_pending or v_set_pending) and v_clr_pending;
end if;
end if;
end process queue_mux;
GEN_REG:
for i in 0 to g_channels-1 generate
r_pending(i) <= not r_cnt_array(i)(r_cnt_array(i)'high);
-- keep track of what needs sending
queue_mux : process(clk_i)
variable v_inc, v_dec : unsigned(cnt'range);
begin
if rising_edge(clk_i) then
if((rst_n_i) = '0') then
r_cnt_array(i) <= (others => '1');
r_wait(i) <= '0';
else
-- add to each channel count with rising edge
v_inc := (others => '0');
v_inc(0) := s_irq_edge(i);
-- subtract from sending channel count when cycle is finished
v_dec := (others => '0');
-- when my cnt is pending and it's my turn ...
if(r_pending(i) = '1' and i = idx) then
r_wait(i) <= '1';
end if;
if( r_wait(i) = '1' and s_cyc_f_edge = '1') then
v_dec := (others => s_cyc_f_edge);
r_wait(i) <= '0';
end if;
r_cnt_array(i) <= r_cnt_array(i) + v_inc + v_dec;
end if;
end if;
end process queue_mux;
end generate GEN_REG;
-------------------------------------------------------------------------
-- WB master generating IRQ msgs
......@@ -189,18 +218,20 @@ irq_master_o.we <= '1';
begin
if rising_edge(clk_i) then
if(rst_n_i = '0') then
r_cyc <= '0';
r_cyc0 <= '0';
r_cyc1 <= '0';
r_stb <= '0';
else
if r_cyc = '1' then
r_cyc1 <= r_cyc0;
if r_cyc0 = '1' then
if irq_master_i.stall = '0' then
r_stb <= '0';
end if;
if (irq_master_i.ack or irq_master_i.err) = '1' then
r_cyc <= '0';
r_cyc0 <= '0';
end if;
else
r_cyc <= s_wb_send;
r_cyc0 <= s_wb_send;
r_stb <= s_wb_send;
irq_master_o.adr <= s_dst(idx);
irq_master_o.dat <= s_msg(idx);
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment