Files
vhdl/lib/misc/gpio_wb.vhd
T
jens 2761d5926b - added timer inrterrupt
Committed on the Free edition of March Hare Software CVSNT Server.
Upgrade to CVS Suite for more features and support:
http://march-hare.com/cvsnt/


git-svn-id: http://moon:8086/svn/vhdl/trunk@411 cc03376c-175c-47c8-b038-4cd826a8556b
2009-03-27 11:16:54 +00:00

284 lines
6.4 KiB
VHDL

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;