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 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; 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; signal reg_data_wr : unsigned(31 downto 0); begin SRDY_O <= CYC_I; INT_TIM_O <= cnt_timer_irq; ------------------------------------------------------------------ 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_we <= '0'; timer_cmp_we <= '0'; timer_irq_ack <= '0'; if RST_I = '1' then gpo0_reg <= (others => '0'); gpo1_reg <= (others => '0'); cnt_timer_en <= '0'; cnt_timer_inten <= '0'; elsif (STB_I and CYC_I and WE_I) = '1' then reg_data_wr <= DAT_I; case ADDR_I(5 downto 2) is when "0000" => 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 "0001" => 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 "0010" => cnt_usec_we <= '1'; when "0011" => cnt_sec_we <= '1'; when "0100" => -- timer control cnt_timer_en <= DAT_I(0); cnt_timer_inten <= DAT_I(1); when "0101" => -- timer status timer_irq_ack <= DAT_I(0); -- IRQ acknowledge when "0110" => -- timer count timer_we <= '1'; when "0111" => -- timer compare timer_cmp_we <= '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(5 downto 2) is when "0000" => DAT_O <= gpi0_reg; when "0001" => DAT_O <= gpi1_reg; when "0010" => DAT_O <= cnt_usec; when "0011" => DAT_O <= cnt_sec; when "0100" => -- timer control DAT_O(0) <= cnt_timer_en; DAT_O(1) <= cnt_timer_inten; when "0101" => -- timer status DAT_O(0) <= cnt_timer_irq; DAT_O(1) <= cnt_timer_ovl; when "0110" => -- timer count DAT_O <= cnt_timer; when "0111" => -- timer compare DAT_O <= cnt_timer_cmp; 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 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'; end if; cnt_timer_irq <= '1'; end if; else cnt_timer <= cnt_timer + 1; end if; end if; end if; end process; 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; end if; end process; ------------------------------------------------------------------ end behavior;