------------------------------------------------------------------------------- -- Title : xemac_host_shim_if -- Project : ------------------------------------------------------------------------------- -- File : xemac_host_shim_if.vhd -- Author : Marc Kelly -- Company : University of Manchester (Particle Physics Group) -- Created : 2008-04-02 -- Last update: 2009/08/12 -- Platform : -- Standard : VHDL'93/02 ------------------------------------------------------------------------------- -- Description: -- -- This deals with the HOST interface and does the read or write operation. -- States. -- Idle, Host Write, Host Read1, Host Read2, MDIO Write, MDIO Wait, MDIO -- Read, MDIO Read_Wait, MDIO Read_Latch -- -- Transactions that happen. -- IDLE -> Host Write -> IDLE -- IDLE -> Host Read1 -> Host Read2 -> IDLE -- IDLE -> MDIO Write -> MDIO Wait -> IDLE -- IDLE -> MDIO Read -> MDIO Read_Wait -> MDIO Read_Latch -> IDLE -- ------------------------------------------------------------------------------- -- Copyright (c) 2008 University of Manchester (Particle Physics Group) ------------------------------------------------------------------------------- -- Revisions : -- Date Version Author Description -- 2008-04-02 1.0 mpkelly Created ------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; entity xemac_host_shim_if is port ( clk : in std_logic; rst : in std_logic; -- Data interface ADDR : in std_logic_vector(9 downto 0); WR_DATA : in std_logic_vector(31 downto 0); RD_DATA : out std_logic_vector(31 downto 0); STROBE : in std_logic; MDIO_ACCESS : in std_logic; WR_ACCESS : in std_logic; ACCESS_DONE : out std_logic; -- EMAC interface -- HOSTADDR : out std_logic_vector(9 downto 0); HOSTMIIMSEL : out std_logic; HOSTOPCODE : out std_logic_vector(1 downto 0); HOSTREQ : out std_logic; HOSTMIIMRDY : in std_logic; HOSTWRDATA : out std_logic_vector(31 downto 0); HOSTRDDATA : in std_logic_vector(31 downto 0) ); end entity xemac_host_shim_if; architecture rtl of xemac_host_shim_if is type interface_states is (idle, host_write, host_read1, host_read2, mdio_write, mdio_wait, mdio_read, mdio_readwait, mdio_readlatch); signal statemachine : interface_states := idle; signal start_strobe_i : std_logic; -- Stobe line SM Start signal strobe_del_i : std_logic; -- Stobe line for the host port. signal strobe_del2_i : std_logic; -- Stobe line for the host port. signal host_inuse_i : std_logic; -- we're doing a transaction signal host_inuse1_i : std_logic; -- we're doing a transaction signal RD_DATA_i : std_logic_vector(31 downto 0); begin -- architecture rtl -- Delay some signals, and find falling edge of the host in use flag. delayer_edgefind : process (clk, rst) is begin -- process delayer_edgefind if rst = '1' then -- asynchronous reset (active high) strobe_del2_i <= '0'; strobe_del_i <= '0'; start_strobe_i <= '0'; host_inuse1_i <= '0'; ACCESS_DONE <= '0'; elsif clk'event and clk = '1' then -- rising clock edge strobe_del_i <= STROBE; strobe_del2_i <= strobe_del_i; host_inuse1_i <= host_inuse_i; -- Pulse on the falling edge of the Access done if host_inuse_i = '0' and host_inuse1_i = '1' then ACCESS_DONE <= '1'; else ACCESS_DONE <= '0'; end if; -- PULSE on rising edge of STROBE if (STROBE = '1' and strobe_del_i = '0') then start_strobe_i <= '1'; else start_strobe_i <= '0'; end if; end if; end process delayer_edgefind; transaction_state : process (clk, rst) begin -- process transaction_state if rst = '1' then -- asynchronous rst (active high) statemachine <= idle; elsif clk'event and clk = '1' then -- rising clock edge case statemachine is when idle => if start_strobe_i = '1' then -- Start your engines.. if MDIO_ACCESS = '1' then -- Check the MDIO is available.. if HOSTMIIMRDY = '1' then -- Its an MDIO transaction if WR_ACCESS = '1' then -- Its a write statemachine <= mdio_write; else -- Its a read statemachine <= mdio_read; end if; -- host_write_i = '1' else -- System is busy, user should never see this?!? -- as we never go to idle when its busy.. -- but checking just in case. statemachine <= idle; -- stay as we are. end if; -- HOSTMIIMRDY = '1' else -- Host I/F transaction if WR_ACCESS = '1' then -- Write statemachine <= host_write; else -- Read statemachine <= host_read1; end if; -- host_write_i = '1' end if; -- host_mdio_i = '1' else statemachine <= idle; -- stay as we are. end if; -- host_strobe_i = '1' when host_write => statemachine <= idle; when host_read1 => statemachine <= host_read2; when host_read2 => statemachine <= idle; when mdio_write => statemachine <= mdio_wait; when mdio_wait => if HOSTMIIMRDY = '1' then -- Transaction is finished. statemachine <= idle; else -- still waiting statemachine <= mdio_wait; end if; when mdio_read => statemachine <= mdio_readwait; when mdio_readwait => if HOSTMIIMRDY = '1' then -- Transaction is finished. statemachine <= mdio_readlatch; else -- still waiting statemachine <= mdio_readwait; end if; when mdio_readlatch => statemachine <= idle; when others => statemachine <= idle; end case; end if; end process transaction_state; -- Add the output part of the state machine here. statemachine_output : process (ADDR, HOSTRDDATA, WR_DATA, rst, statemachine) begin -- process statemachine_output if rst = '1' then HOSTADDR <= (others => '0'); HOSTMIIMSEL <= '1'; HOSTOPCODE <= (others => '0'); HOSTREQ <= '0'; HOSTWRDATA <= (others => '0'); RD_DATA_i <= (others => '0'); host_inuse_i <= '0'; else case statemachine is when idle => -- default mode if no strobe HOSTWRDATA <= WR_DATA; HOSTADDR <= ADDR; HOSTOPCODE <= "10"; HOSTMIIMSEL <= '1'; -- ENABLE Line HOSTREQ <= '0'; -- MDIO strobe line host_inuse_i <= '0'; -- Host is free, MDIO and host available RD_DATA_i <= RD_DATA_i; when host_write => -- Ping the write lines. HOSTWRDATA <= WR_DATA; HOSTADDR <= ADDR; HOSTOPCODE <= "00"; -- upper bit is a wr enable, active low. HOSTMIIMSEL <= '0'; -- ENABLE Line HOSTREQ <= '0'; -- MDIO strobe line host_inuse_i <= '1'; RD_DATA_i <= RD_DATA_i; when host_read1 => HOSTWRDATA <= WR_DATA; HOSTADDR <= ADDR; HOSTOPCODE <= "10"; -- write is disabled HOSTMIIMSEL <= '0'; -- ENABLE Line HOSTREQ <= '0'; -- MDIO strobe line host_inuse_i <= '1'; RD_DATA_i <= RD_DATA_i; when host_read2 => -- Latch the read data. HOSTWRDATA <= WR_DATA; HOSTADDR <= ADDR; HOSTOPCODE <= "10"; HOSTMIIMSEL <= '0'; -- Keep Low for host data HOSTREQ <= '0'; host_inuse_i <= '1'; RD_DATA_i <= HOSTRDDATA; -- get the data off the bus. -- Now we do the MDIO stuff.. crazy when mdio_write => HOSTWRDATA <= WR_DATA; HOSTADDR <= ADDR; HOSTOPCODE <= "01"; -- Write mode HOSTMIIMSEL <= '1'; -- MDIO HOSTREQ <= '1'; -- Enable pulse host_inuse_i <= '1'; RD_DATA_i <= RD_DATA_i; when mdio_wait => HOSTWRDATA <= WR_DATA; HOSTADDR <= ADDR; HOSTOPCODE <= "01"; -- Write Mode HOSTMIIMSEL <= '1'; -- MDIO mode. HOSTREQ <= '0'; host_inuse_i <= '1'; RD_DATA_i <= RD_DATA_i; when mdio_read => HOSTWRDATA <= WR_DATA; HOSTADDR <= ADDR; HOSTOPCODE <= "10"; -- Read mode HOSTMIIMSEL <= '1'; -- MDIO HOSTREQ <= '1'; -- Enable pulse host_inuse_i <= '1'; RD_DATA_i <= RD_DATA_i; when mdio_readwait|mdio_readlatch => HOSTWRDATA <= WR_DATA; HOSTADDR <= ADDR; HOSTOPCODE <= "10"; -- Read mode HOSTMIIMSEL <= '1'; -- MDIO HOSTREQ <= '0'; -- Enable pulse host_inuse_i <= '1'; RD_DATA_i <= HOSTRDDATA; -- get the data off the bus. when others => -- default mode if no strobe HOSTWRDATA <= WR_DATA; RD_DATA_i <= RD_DATA_i; HOSTADDR <= ADDR; HOSTOPCODE <= "10"; HOSTMIIMSEL <= '1'; -- ENABLE Line host_inuse_i <= '0'; end case; end if; end process statemachine_output; RD_DATA <= RD_DATA_i; end architecture rtl;