Commit 08af7a09 authored by Mathias Kreider's avatar Mathias Kreider

fixed irq loss in edge triggered mode

parent 29db1b2a
......@@ -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);
......
Markdown is supported
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