LIBRARY IEEE; USE IEEE.STD_LOGIC_1164.ALL; USE IEEE.NUMERIC_STD.ALL; ENTITY gpio_wb IS Port ( CLK_I : in STD_LOGIC; RST_I : in STD_LOGIC; CYC_I : in STD_LOGIC; STB_I : in STD_LOGIC; SEL_I : in unsigned(3 downto 0); WE_I : in STD_LOGIC; ACK_O : out STD_LOGIC; SRDY_O : out STD_LOGIC; MRDY_I : in STD_LOGIC; ADDR_I : in unsigned(31 downto 0); DAT_I : in unsigned(31 downto 0); DAT_O : out unsigned(31 downto 0); INT_TIM_O : out STD_LOGIC; sys_gpo0 : out unsigned(31 downto 0); sys_gpo1 : out unsigned(31 downto 0); sys_gpi0 : in unsigned(31 downto 0); sys_gpi1 : in unsigned(31 downto 0) ); 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); signal gpi1_reg : unsigned(31 downto 0); -- Signals to form an timer generating an interrupt every microsecond subtype tick_usec_t is natural range 0 to 99; signal tick_usec : tick_usec_t; signal cnt_usec : unsigned(31 downto 0); signal cnt_sec : unsigned(31 downto 0); signal cnt_usec_preset : unsigned(31 downto 0); signal cnt_sec_preset : unsigned(31 downto 0); signal cnt_usec_en : std_logic; signal cnt_usec_we : std_logic; signal cnt_sec_en : std_logic; signal cnt_sec_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; 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) begin if rising_edge(CLK_I) then sys_gpo0 <= gpo0_reg; sys_gpo1 <= gpo1_reg; end if; end process; ------------------------------------------------------------------ btn_ps2_in: process(CLK_I) begin if rising_edge(CLK_I) then gpi0_reg <= sys_gpi0; gpi1_reg <= sys_gpi1; end if; end process; ------------------------------------------------------------------ registers_write: process(CLK_I) begin if rising_edge(CLK_I) then cnt_usec_we <= '0'; cnt_sec_we <= '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'); 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(6 downto 2) is when "00000" => if SEL_I(0) = '1' then gpo0_reg(7 downto 0) <= DAT_I(7 downto 0); end if; if SEL_I(1) = '1' then gpo0_reg(15 downto 8) <= DAT_I(15 downto 8); end if; if SEL_I(2) = '1' then gpo0_reg(23 downto 16) <= DAT_I(23 downto 16); end if; if SEL_I(3) = '1' then gpo0_reg(31 downto 24) <= DAT_I(31 downto 24); end if; when "00001" => if SEL_I(0) = '1' then gpo1_reg(7 downto 0) <= DAT_I(7 downto 0); end if; if SEL_I(1) = '1' then gpo1_reg(15 downto 8) <= DAT_I(15 downto 8); end if; if SEL_I(2) = '1' then gpo1_reg(23 downto 16) <= DAT_I(23 downto 16); end if; if SEL_I(3) = '1' then gpo1_reg(31 downto 24) <= DAT_I(31 downto 24); end if; when "00010" => cnt_usec_we <= '1'; when "00011" => cnt_sec_we <= '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 "01000" => -- timer count 0 timer_cnt_we(0) <= '1'; when "01001" => -- timer count 1 timer_cnt_we(1) <= '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; end if; end if; end process; registers_read: process(CLK_I) begin if rising_edge(CLK_I) then ACK_O <= '0'; if (STB_I and CYC_I) = '1' then ACK_O <= not WE_I; DAT_O <= (others => '0'); case ADDR_I(6 downto 2) is when "00000" => DAT_O <= gpi0_reg; when "00001" => DAT_O <= gpi1_reg; when "00010" => DAT_O <= cnt_usec; when "00011" => DAT_O <= cnt_sec; 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 "01000" => -- timer count 0 DAT_O <= timer_cnt(0); when "01001" => -- timer count 1 DAT_O <= timer_cnt(1); 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; end if; end if; end process; cnt_usec_tick: process(CLK_I) begin if rising_edge(CLK_I) then cnt_usec_en <= '0'; if tick_usec >= tick_usec_t'high then tick_usec <= 0; cnt_usec_en <= '1'; else tick_usec <= tick_usec + 1; end if; end if; end process; -- H/W Clock cnt_usec_clock: process(CLK_I) begin if rising_edge(CLK_I) then cnt_sec_en <= '0'; if cnt_usec_we = '1' then cnt_usec <= reg_data_wr; elsif cnt_usec_en = '1' then if cnt_usec >= to_unsigned(1E6 - 1, 32) then cnt_usec <= (others => '0'); cnt_sec_en <= '1'; else cnt_usec <= cnt_usec + 1; end if; end if; end if; end process; cnt_sec_clock: process(CLK_I) begin if rising_edge(CLK_I) then if cnt_sec_we = '1' then cnt_sec <= reg_data_wr; elsif cnt_sec_en = '1' then cnt_sec <= cnt_sec + 1; end if; end if; end process; -- Interrupt timer proc_int_timer: process(CLK_I) begin if rising_edge(CLK_I) then 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; else timer_cnt(i) <= timer_cnt(i) + 1; end if; end if; end loop; end if; end process; proc_int_timer_reload: process(CLK_I) begin if rising_edge(CLK_I) then 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; ------------------------------------------------------------------ end behavior;