From 08af7a09d846cf595ec6b53f222a1b2fb64b26b1 Mon Sep 17 00:00:00 2001 From: Mathias Kreider <m.kreider@gsi.de> Date: Wed, 15 Apr 2015 17:26:17 +0200 Subject: [PATCH] fixed irq loss in edge triggered mode --- modules/wishbone/wb_irq/irqm_core.vhd | 81 ++++++++++++++++++--------- 1 file changed, 56 insertions(+), 25 deletions(-) diff --git a/modules/wishbone/wb_irq/irqm_core.vhd b/modules/wishbone/wb_irq/irqm_core.vhd index f999c94b..7b0c1e69 100644 --- a/modules/wishbone/wb_irq/irqm_core.vhd +++ b/modules/wishbone/wb_irq/irqm_core.vhd @@ -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); -- GitLab