----------------------------------------------------------------------- -- $Header: /tmp/cvsroot/VHDL/lib/misc/async_port_wb.vhd,v 1.3 2008-10-12 14:12:14 Jens Exp $ ----------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; use work.sys_types.all; ------------------------------------------------------------------ entity async_port_wb is Generic ( addr_width : natural := 32; data_width : natural := 32; async_timespec : async_timespec_t ); Port ( CLK_I : in STD_LOGIC; RST_I : in STD_LOGIC; CYC_I : in STD_LOGIC; STB_I : in STD_LOGIC; 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); 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_wb; architecture Behavioral of async_port_wb 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, idle, leadin_rd, read, leadin_wr, write, leadout_rd, leadout_wr, release); signal s, sn : async_state_t; signal as : async_t; signal ack : std_logic; signal cc_rst : std_logic; signal cycle_cnt : natural range 0 to 15; signal cycle_reload : natural range 0 to 15; signal rdy : std_logic; signal rdyo : std_logic; signal en : std_logic; signal data_reg : unsigned(data_width-1 downto 0); ------------------------------------------------------------------ begin SRDY_O <= CYC_I and rdyo; en <= CYC_I and STB_I; proc_cycle_counter: process(CLK_I) begin if rising_edge(CLK_I) 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_I) begin if rising_edge(CLK_I) then if RST_I = '1' then s <= start; else s <= sn; end if; end if; end process; proc_state: process(s, cycle_cnt, en, WE_I) 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'; ack <= '0'; rdy <= '0'; sn <= s; case s is when start => cc_rst <= '1'; sn <= reset; when reset => as.rst <= '1'; if cycle_cnt = 0 then sn <= idle; end if; when idle => rdy <= '1'; if en = '1' then as.cs <= '1'; cc_rst <= '1'; cycle_reload <= async_timespec.ncyc_access-1; if WE_I = '0' 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; ack <= '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; -- ack <= '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 <= idle; end if; when others => sn <= idle; end case; end process; ------------------------------------------------------------------ output_ctrl: process(CLK_I) begin if rising_edge(CLK_I) 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_I) begin if rising_edge(CLK_I) then if as.rd = '1' then DAT_O(data_width-1 downto 0) <= async_d; end if; end if; end process; ------------------------------------------------------------------ output_addr: process(CLK_I) begin if rising_edge(CLK_I) then if RST_I = '1' then async_a <= (others => '0'); elsif en = '1' and rdy = '1' then async_a <= ADDR_I(addr_width-1 downto 0); end if; end if; end process; ------------------------------------------------------------------ data_register: process(CLK_I) begin if rising_edge(CLK_I) then if en = '1' and rdy = '1' then data_reg <= DAT_I(data_width-1 downto 0); end if; end if; end process; ------------------------------------------------------------------ output_SRDY: process(CLK_I) begin if rising_edge(CLK_I) then if RST_I = '1' then rdyo <= '1'; elsif en = '1' then rdyo <= rdy and not rdyo; end if; end if; end process; ------------------------------------------------------------------ output_ACK: process(CLK_I) begin if rising_edge(CLK_I) then if RST_I = '1' then ACK_O <= '0'; else ACK_O <= ack; end if; end if; end process; ------------------------------------------------------------------ output_data: process(CLK_I) begin if rising_edge(CLK_I) then async_d <= (others => 'Z'); if as.drive_d = '1' then async_d <= data_reg; end if; end if; end process; ------------------------------------------------------------------ end Behavioral;