diff --git a/lib/misc/gpio_wb.vhd b/lib/misc/gpio_wb.vhd index 0d2e151..6df62c0 100644 --- a/lib/misc/gpio_wb.vhd +++ b/lib/misc/gpio_wb.vhd @@ -29,6 +29,8 @@ END gpio_wb; ARCHITECTURE behavior OF gpio_wb IS + constant num_timers : natural := 2; + signal gpo0_reg : unsigned(31 downto 0); signal gpo1_reg : unsigned(31 downto 0); signal gpi0_reg : unsigned(31 downto 0); @@ -45,22 +47,34 @@ ARCHITECTURE behavior OF gpio_wb IS signal cnt_sec_en : std_logic; signal cnt_sec_we : std_logic; - signal cnt_timer : unsigned(31 downto 0); - signal cnt_timer_cmp : unsigned(31 downto 0); - signal cnt_timer_en : std_logic; - signal cnt_timer_inten : std_logic; - signal cnt_timer_irq : std_logic; - signal cnt_timer_ovl : std_logic; - signal timer_irq_ack : std_logic; - signal timer_we : std_logic; - signal timer_cmp_we : std_logic; + type timer_array_t is array (0 to num_timers-1) of unsigned(31 downto 0); + signal timer_cnt : timer_array_t; + signal timer_cmp : timer_array_t; + signal timer_en : unsigned(0 to num_timers-1); + signal timer_inten : unsigned(0 to num_timers-1); + signal timer_irq : unsigned(0 to num_timers-1); + signal timer_ovl : unsigned(0 to num_timers-1); + signal timer_irq_ack : unsigned(0 to num_timers-1); + signal timer_cnt_we : unsigned(0 to num_timers-1); + signal timer_cmp_we : unsigned(0 to num_timers-1); + signal reg_data_wr : unsigned(31 downto 0); begin SRDY_O <= CYC_I; - INT_TIM_O <= cnt_timer_irq; +tim_irq: + process(timer_irq) + variable irq : std_logic; + begin + irq := '0'; + for i in 0 to num_timers-1 loop + irq := irq or timer_irq(i); + end loop; + INT_TIM_O <= irq; + end process; + ------------------------------------------------------------------ led_out: process(CLK_I) @@ -88,19 +102,19 @@ registers_write: if rising_edge(CLK_I) then cnt_usec_we <= '0'; cnt_sec_we <= '0'; - timer_we <= '0'; - timer_cmp_we <= '0'; - timer_irq_ack <= '0'; + timer_cnt_we <= (others => '0'); + timer_cmp_we <= (others => '0'); + timer_irq_ack <= (others => '0'); if RST_I = '1' then gpo0_reg <= (others => '0'); gpo1_reg <= (others => '0'); - cnt_timer_en <= '0'; - cnt_timer_inten <= '0'; + timer_en <= (others => '0'); + timer_inten <= (others => '0'); elsif (STB_I and CYC_I and WE_I) = '1' then reg_data_wr <= DAT_I; - case ADDR_I(5 downto 2) is + case ADDR_I(6 downto 2) is - when "0000" => + when "00000" => if SEL_I(0) = '1' then gpo0_reg(7 downto 0) <= DAT_I(7 downto 0); end if; @@ -114,7 +128,7 @@ registers_write: gpo0_reg(31 downto 24) <= DAT_I(31 downto 24); end if; - when "0001" => + when "00001" => if SEL_I(0) = '1' then gpo1_reg(7 downto 0) <= DAT_I(7 downto 0); end if; @@ -128,24 +142,33 @@ registers_write: gpo1_reg(31 downto 24) <= DAT_I(31 downto 24); end if; - when "0010" => + when "00010" => cnt_usec_we <= '1'; - when "0011" => + when "00011" => cnt_sec_we <= '1'; - when "0100" => -- timer control - cnt_timer_en <= DAT_I(0); - cnt_timer_inten <= DAT_I(1); + when "00110" => -- timer control + for i in 0 to num_timers-1 loop + timer_en(i) <= DAT_I(2*i+0); + timer_inten(i) <= DAT_I(2*i+1); + end loop; + when "00111" => -- timer status + for i in 0 to num_timers-1 loop + timer_irq_ack(i) <= DAT_I(2*i); -- IRQ acknowledge + end loop; - when "0101" => -- timer status - timer_irq_ack <= DAT_I(0); -- IRQ acknowledge + when "01000" => -- timer count 0 + timer_cnt_we(0) <= '1'; - when "0110" => -- timer count - timer_we <= '1'; + when "01001" => -- timer count 1 + timer_cnt_we(1) <= '1'; - when "0111" => -- timer compare - timer_cmp_we <= '1'; + when "01100" => -- timer compare 0 + timer_cmp_we(0) <= '1'; + + when "01101" => -- timer compare 1 + timer_cmp_we(1) <= '1'; when others => null; end case; @@ -161,33 +184,43 @@ registers_read: if (STB_I and CYC_I) = '1' then ACK_O <= not WE_I; DAT_O <= (others => '0'); - case ADDR_I(5 downto 2) is + case ADDR_I(6 downto 2) is - when "0000" => + when "00000" => DAT_O <= gpi0_reg; - when "0001" => + when "00001" => DAT_O <= gpi1_reg; - when "0010" => + when "00010" => DAT_O <= cnt_usec; - when "0011" => + when "00011" => DAT_O <= cnt_sec; - when "0100" => -- timer control - DAT_O(0) <= cnt_timer_en; - DAT_O(1) <= cnt_timer_inten; + when "00110" => -- timer control + for i in 0 to num_timers-1 loop + DAT_O(2*i+0) <= timer_en(i); + DAT_O(2*i+1) <= timer_inten(i); + end loop; + + when "00111" => -- timer status + for i in 0 to num_timers-1 loop + DAT_O(2*i+0) <= timer_irq(i); + DAT_O(2*i+1) <= timer_ovl(i); + end loop; - when "0101" => -- timer status - DAT_O(0) <= cnt_timer_irq; - DAT_O(1) <= cnt_timer_ovl; + when "01000" => -- timer count 0 + DAT_O <= timer_cnt(0); - when "0110" => -- timer count - DAT_O <= cnt_timer; + when "01001" => -- timer count 1 + DAT_O <= timer_cnt(1); - when "0111" => -- timer compare - DAT_O <= cnt_timer_cmp; + when "01100" => -- timer compare 0 + DAT_O <= timer_cmp(0); + + when "01101" => -- timer compare 1 + DAT_O <= timer_cmp(1); when others => null; end case; @@ -245,27 +278,29 @@ proc_int_timer: process(CLK_I) begin if rising_edge(CLK_I) then - if RST_I = '1' then - cnt_timer_ovl <= '0'; - cnt_timer_irq <= '0'; - elsif timer_irq_ack = '1' then - cnt_timer_ovl <= '0'; - cnt_timer_irq <= '0'; - elsif timer_we = '1' then - cnt_timer <= reg_data_wr; - elsif cnt_timer_en = '1' then - if cnt_timer >= cnt_timer_cmp then - cnt_timer <= (others => '0'); - if cnt_timer_inten = '1' then - if cnt_timer_irq = '1' then - cnt_timer_ovl <= '1'; + for i in 0 to num_timers-1 loop + if RST_I = '1' then + timer_ovl(i) <= '0'; + timer_irq(i) <= '0'; + elsif timer_irq_ack(i) = '1' then + timer_ovl(i) <= '0'; + timer_irq(i) <= '0'; + elsif timer_cnt_we(i) = '1' then + timer_cnt(i) <= reg_data_wr; + elsif timer_en(i) = '1' then + if timer_cnt(i) >= timer_cmp(i) then + timer_cnt(i) <= (others => '0'); + if timer_inten(i) = '1' then + if timer_irq(i) = '1' then + timer_ovl(i) <= '1'; + end if; + timer_irq(i) <= '1'; end if; - cnt_timer_irq <= '1'; - end if; - else - cnt_timer <= cnt_timer + 1; - end if; - end if; + else + timer_cnt(i) <= timer_cnt(i) + 1; + end if; + end if; + end loop; end if; end process; @@ -273,9 +308,11 @@ proc_int_timer_reload: process(CLK_I) begin if rising_edge(CLK_I) then - if timer_cmp_we = '1' then - cnt_timer_cmp <= reg_data_wr; - end if; + for i in 0 to num_timers-1 loop + if timer_cmp_we(i) = '1' then + timer_cmp(i) <= reg_data_wr; + end if; + end loop; end if; end process;