- removed GPIO 1 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@792 cc03376c-175c-47c8-b038-4cd826a8556b
310 lines
7.1 KiB
VHDL
310 lines
7.1 KiB
VHDL
LIBRARY IEEE;
|
|
USE IEEE.STD_LOGIC_1164.ALL;
|
|
USE IEEE.NUMERIC_STD.ALL;
|
|
|
|
ENTITY gpio_wb IS
|
|
Generic
|
|
(
|
|
f_sysclk : real := 100.0
|
|
);
|
|
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_gpi_0 : in unsigned(31 downto 0);
|
|
sys_gpo_0 : out unsigned(31 downto 0)
|
|
|
|
);
|
|
END gpio_wb;
|
|
|
|
ARCHITECTURE behavior OF gpio_wb IS
|
|
|
|
constant num_timers : natural := 2;
|
|
constant ncycles_usec : natural := natural(f_sysclk);
|
|
|
|
signal gpio_0_dout_reg : unsigned(31 downto 0);
|
|
signal gpio_0_dir_reg : unsigned(31 downto 0);
|
|
signal gpio_0_din_reg : unsigned(31 downto 0);
|
|
|
|
-- Signals to form an timer generating an interrupt every microsecond
|
|
subtype tick_usec_t is natural range 0 to ncycles_usec-1;
|
|
signal tick_usec : tick_usec_t := 0;
|
|
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;
|
|
|
|
------------------------------------------------------------------
|
|
gpio_0_out:
|
|
process(gpio_0_dir_reg, gpio_0_dout_reg)
|
|
begin
|
|
for i in 0 to 31 loop
|
|
sys_gpo_0(i) <= 'Z';
|
|
if gpio_0_dir_reg(i) = '1' then
|
|
sys_gpo_0(i) <= gpio_0_dout_reg(i);
|
|
end if;
|
|
end loop;
|
|
end process;
|
|
|
|
------------------------------------------------------------------
|
|
gpio_0_in:
|
|
process(CLK_I)
|
|
begin
|
|
if rising_edge(CLK_I) then
|
|
for i in 0 to 31 loop
|
|
if gpio_0_dir_reg(i) = '1' then
|
|
gpio_0_din_reg(i) <= gpio_0_dout_reg(i);
|
|
else
|
|
gpio_0_din_reg(i) <= sys_gpi_0(i);
|
|
end if;
|
|
end loop;
|
|
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
|
|
gpio_0_dout_reg <= (others => '0');
|
|
gpio_0_dir_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" =>
|
|
gpio_0_dout_reg <= DAT_I;
|
|
|
|
when "00001" =>
|
|
gpio_0_dir_reg <= DAT_I;
|
|
|
|
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 <= gpio_0_din_reg;
|
|
|
|
when "00001" =>
|
|
DAT_O <= gpio_0_dir_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 to_01(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 to_01(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;
|