----------------------------------------------------------------------- -- $Header: /tmp/cvsroot/VHDL/lib/misc/async_port.vhd,v 1.2 2008-10-10 21:25:17 Jens Exp $ ----------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; use work.sys_types.all; ------------------------------------------------------------------ entity async_port is Generic ( addr_width : natural := 32; data_width : natural := 32; async_timespec : async_timespec_t ); Port ( rst : in std_logic; clk : in std_logic; cpu_en : in std_logic; cpu_re : in std_logic; cpu_addr : in unsigned(addr_width-1 downto 0); cpu_din : out unsigned(data_width-1 downto 0); cpu_dout : in unsigned(data_width-1 downto 0); cpu_bsy : out std_logic; cpu_vld : out std_logic; async_a : out unsigned(addr_width-1 downto 0); async_d : inout unsigned(data_width-1 downto 0); async_cs : out std_logic; async_wr : out std_logic; async_rd : out std_logic; async_rst : out std_logic ); end async_port; architecture Behavioral of async_port is type async_t is record cs : std_logic; wr : std_logic; rd : std_logic; rst : std_logic; drive_d : std_logic; end record; type async_state_t is (start, reset, rdy, leadin_rd, read, leadin_wr, write, leadout_rd, leadout_wr, release); signal s, sn : async_state_t; signal as : async_t; signal cc_rst : std_logic; signal cycle_cnt : natural range 0 to 15; signal cycle_reload : natural range 0 to 15; ------------------------------------------------------------------ begin proc_cycle_counter: process(clk) begin if rising_edge(clk) then if cc_rst = '1' then cycle_cnt <= cycle_reload; elsif cycle_cnt /= 0 then cycle_cnt <= cycle_cnt - 1; end if; end if; end process; ------------------------------------------------------------------ proc_state_next: process(clk) begin if rising_edge(clk) then if rst = '1' then s <= start; else s <= sn; end if; end if; end process; proc_state: process(s, cycle_cnt, cpu_en) begin cycle_reload <= async_timespec.ncyc_pulse_rst; cc_rst <= '0'; as.rst <= '0'; as.cs <= '0'; as.wr <= '0'; as.rd <= '0'; as.drive_d <= '0'; cpu_bsy <= '1'; cpu_vld <= '0'; sn <= s; case s is when start => cc_rst <= '1'; sn <= reset; when reset => as.rst <= '1'; if cycle_cnt = 0 then sn <= rdy; end if; when rdy => cpu_bsy <= '0'; if cpu_en = '1' then as.cs <= '1'; cc_rst <= '1'; cycle_reload <= async_timespec.ncyc_access-1; if cpu_re = '1' then sn <= leadin_rd; else sn <= leadin_wr; end if; end if; when leadin_rd => as.cs <= '1'; if cycle_cnt = 0 then cc_rst <= '1'; cycle_reload <= async_timespec.ncyc_pulse_rd-1; as.rd <= '1'; sn <= read; end if; when leadin_wr => as.cs <= '1'; if cycle_cnt = 0 then cc_rst <= '1'; cycle_reload <= async_timespec.ncyc_pulse_wr-1; as.wr <= '1'; as.drive_d <= '1'; sn <= write; end if; when read => as.cs <= '1'; as.rd <= '1'; if cycle_cnt = 0 then cc_rst <= '1'; cycle_reload <= async_timespec.ncyc_cs_hold-1; as.rd <= '0'; sn <= leadout_rd; cpu_vld <= '1'; end if; when write => as.drive_d <= '1'; as.cs <= '1'; as.wr <= '1'; if cycle_cnt = 0 then as.wr <= '0'; cc_rst <= '1'; cycle_reload <= async_timespec.ncyc_cs_hold-1; sn <= leadout_wr; cpu_vld <= '1'; end if; when leadout_rd => as.cs <= '1'; if cycle_cnt = 0 then cc_rst <= '1'; cycle_reload <= async_timespec.ncyc_release-1; sn <= release; as.cs <= '0'; end if; when leadout_wr => as.cs <= '1'; as.drive_d <= '1'; if cycle_cnt = 0 then cc_rst <= '1'; cycle_reload <= async_timespec.ncyc_release-1; sn <= release; as.cs <= '0'; end if; when release => if cycle_cnt = 0 then sn <= rdy; end if; when others => sn <= rdy; end case; end process; ------------------------------------------------------------------ output_ctrl: process(clk) begin if rising_edge(clk) then async_cs <= (not async_timespec.pol_cs) xor as.cs; async_wr <= (not async_timespec.pol_we) xor as.wr; async_rd <= (not async_timespec.pol_oe) xor as.rd; async_rst <= (not async_timespec.pol_rst) xor as.rst; end if; end process; ------------------------------------------------------------------ din_register: process(clk) begin if rising_edge(clk) then if as.rd = '1' then cpu_din <= async_d; end if; end if; end process; ------------------------------------------------------------------ output_addr: process(clk) begin if rising_edge(clk) then if rst = '1' then async_a <= (others => '0'); elsif cpu_en = '1' then async_a <= cpu_addr; end if; end if; end process; ------------------------------------------------------------------ output_data: process(clk) begin if rising_edge(clk) then async_d <= (others => 'Z'); if as.drive_d = '1' then async_d <= cpu_dout; end if; end if; end process; ------------------------------------------------------------------ end Behavioral;