----------------------------------------------------------------------- -- $Header: /tmp/cvsroot/VHDL/lib/misc/async_port_wb.vhd,v 1.9 2009-10-30 10:49:15 Jens Exp $ ----------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.NUMERIC_STD.ALL; use work.async_types.all; ------------------------------------------------------------------ entity async_port_wb is Generic ( addr_width : natural := 32; data_width : natural := 32; byte_sel_width : natural := 4; 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; SEL_I : in unsigned(3 downto 0); ADDR_I : in unsigned(31 downto 0); DAT_I : in unsigned(31 downto 0); DAT_O : out unsigned(31 downto 0); page_mode_en : in 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_be : out unsigned(byte_sel_width-1 downto 0); 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, pulse, leadout, 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 is_idle : std_logic; signal DAT_I_r : unsigned(data_width-1 downto 0); signal SEL_I_r : unsigned(byte_sel_width-1 downto 0); signal WE_I_r : std_logic; signal ADDR_I_r : unsigned(addr_width-1 downto 0); signal page_mode_en_r : std_logic; signal do_page_read : std_logic; ------------------------------------------------------------------ begin ASSERT async_timespec.ncyc_pulse_rd > 0 report "Read pulse length must be greater than zero!" severity failure; ASSERT async_timespec.ncyc_pulse_wr > 0 report "Write pulse length must be greater than zero!" severity failure; ASSERT (not async_timespec.can_page_rd OR (async_timespec.ncyc_pulse_page_rd > 1)) report "Read page pulse length must be greater than one!" severity failure; SRDY_O <= CYC_I and rdyo; en <= CYC_I and STB_I; do_page_read <= '1' when (async_timespec.can_page_rd and (WE_I = WE_I_r) and (WE_I = '0') and (ADDR_I(addr_width-1 downto async_timespec.nbits_page_rd) = ADDR_I_r(addr_width-1 downto async_timespec.nbits_page_rd))) else '0'; 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, WE_I_r, do_page_read) 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'; is_idle <= '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'; is_idle <= '1'; if en = '1' then as.cs <= '1'; cc_rst <= '1'; if async_timespec.ncyc_leadin = 0 then sn <= pulse; if WE_I = '1' then cycle_reload <= async_timespec.ncyc_pulse_wr-1; as.wr <= '1'; as.drive_d <= '1'; else cycle_reload <= async_timespec.ncyc_pulse_rd-1; as.rd <= '1'; end if; else cycle_reload <= async_timespec.ncyc_leadin-1; sn <= leadin; end if; end if; when leadin => as.cs <= '1'; if cycle_cnt = 0 then cc_rst <= '1'; sn <= pulse; if WE_I_r = '1' then cycle_reload <= async_timespec.ncyc_pulse_wr-1; as.wr <= '1'; as.drive_d <= '1'; else cycle_reload <= async_timespec.ncyc_pulse_rd-1; as.rd <= '1'; end if; end if; when pulse => as.cs <= '1'; as.rd <= not WE_I_r; as.drive_d <= WE_I_r; as.wr <= WE_I_r; if cycle_cnt = 0 then as.wr <= '0'; cc_rst <= '1'; ack <= not WE_I_r; rdy <= do_page_read; if en = '1' and do_page_read = '1' then cycle_reload <= async_timespec.ncyc_pulse_page_rd-1; sn <= pulse; elsif async_timespec.ncyc_leadout = 0 then if async_timespec.ncyc_release = 0 then sn <= idle; else cycle_reload <= async_timespec.ncyc_release-1; sn <= release; end if; else cycle_reload <= async_timespec.ncyc_leadout-1; sn <= leadout; end if; end if; when leadout => as.cs <= '1'; as.drive_d <= WE_I_r; if cycle_cnt = 0 then cc_rst <= '1'; rdy <= '1'; if en = '1' then sn <= idle; elsif async_timespec.ncyc_release = 0 then sn <= idle; else cycle_reload <= async_timespec.ncyc_release-1; sn <= release; end if; 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_be <= (byte_sel_width-1 downto 0 => not async_timespec.pol_be) xor ((byte_sel_width-1 downto 0 => as.cs) and SEL_I_r); 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'); SEL_I_r <= (others => '0'); elsif en = '1' and rdy = '1' then async_a <= ADDR_I(addr_width-1 downto 0); SEL_I_r <= SEL_I(byte_sel_width-1 downto 0); if is_idle = '1' then ADDR_I_r <= ADDR_I(addr_width-1 downto 0); end if; end if; end if; end process; ------------------------------------------------------------------ data_register: process(CLK_I) begin if rising_edge(CLK_I) then page_mode_en_r <= page_mode_en; if en = '1' and rdy = '1' then DAT_I_r <= DAT_I(data_width-1 downto 0); WE_I_r <= WE_I; 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 <= DAT_I_r; end if; end if; end process; ------------------------------------------------------------------ end Behavioral;