---------------------------------------------------------------------------- -- DPIMREF.VHD -- Digilent Parallel Interface Module Reference Design ---------------------------------------------------------------------------- -- Author: Gene Apperson -- Copyright 2004 Digilent, Inc. ---------------------------------------------------------------------------- -- IMPORTANT NOTE ABOUT BUILDING THIS LOGIC IN ISE -- -- Before building the Dpimref logic in ISE: -- 1. In Project Navigator, right-click on "Synthesize-XST" -- (in the Process View Tab) and select "Properties" -- 2. Click the "HDL Options" tab -- 3. Set the "FSM Encoding Algorithm" to "None" ---------------------------------------------------------------------------- -- ---------------------------------------------------------------------------- -- This module contains an example implementation of Digilent Parallel -- Interface Module logic. This interface is used in conjunction with the -- DPCUTIL DLL and a Digilent Communications Module (USB, EtherNet, Serial) -- to exchange data with an application running on a host PC and the logic -- implemented in a gate array. -- -- See the Digilent document, Digilent Parallel Interface Model Reference -- Manual (doc # 560-000) for a description of the interface. -- -- This design uses a state machine implementation to respond to transfer -- cycles. It implements an address register, 8 internal data registers -- that merely hold a value written, and interface registers to communicate -- with a Digilent DIO4 board. There is an LED output register whose value -- drives the 8 discrete leds on the DIO4. There are two input registers. -- One reads the switches on the DIO4 and the other reads the buttons. -- -- Interface signals used in top level entity port: -- mclk - master clock, generally 50Mhz osc on system board -- pdb - port data bus -- astb - address strobe -- dstb - data strobe -- pwr - data direction (described in reference manual as WRITE) -- pwait - transfer synchronization (described in reference manual -- as WAIT) -- rgLed - LED outputs to the DIO4 -- rgSwt - switch inputs from the DIO4 -- ldb - led gate signal for the DIO4 -- rgBtn - button inputs from the DIO4 -- btn - button on system board (D2SB or D2FT) -- led - led on the system board -- ---------------------------------------------------------------------------- -- Revision History: -- 06/09/2004(GeneA): created -- 08/10/2004(GeneA): initial public release -- 04/25/2006(JoshP): comment addition ---------------------------------------------------------------------------- -- $Id$: library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity epp2usr is Port ( mclk : in std_logic; mrst : in std_logic; -- interface to the cypress USB chip pdb : inout std_logic_vector(7 downto 0); astb : in std_logic; dstb : in std_logic; pwr : in std_logic; pwait : out std_logic; -- interface to the user logic din : in std_logic_vector(7 downto 0); dout : out std_logic_vector(7 downto 0); addr : out std_logic_vector(7 downto 0); we : out std_logic; rd_fin : out std_logic ); end epp2usr; architecture Behavioral of epp2usr is ------------------------------------------------------------------------ -- Component Declarations ------------------------------------------------------------------------ ------------------------------------------------------------------------ -- Local Type Declarations ------------------------------------------------------------------------ ------------------------------------------------------------------------ -- Constant Declarations ------------------------------------------------------------------------ subtype state_type is std_logic_vector(4 downto 0); subtype data_type is std_logic_vector(7 downto 0); -- The following constants define state codes for the EPP port interface -- state machine. The high order bits of the state number give a unique -- state identifier. The low order bits are the state machine outputs for -- that state. This type of state machine implementation uses no -- combination logic to generate outputs which should produce glitch -- free outputs. constant stEppReady : state_type := "00000"; constant stEppAwrA : state_type := "00100"; constant stEppAwrB : state_type := "00001"; constant stEppArdA : state_type := "00010"; constant stEppArdB : state_type := "00011"; constant stEppDwrA : state_type := "01000"; constant stEppDwrB : state_type := "10001"; constant stEppDrdA : state_type := "10010"; constant stEppDrdB : state_type := "10011"; ------------------------------------------------------------------------ -- Signal Declarations ------------------------------------------------------------------------ -- State machine current state register signal stEppCur : state_type := stEppReady; signal stEppNext : state_type; signal clkMain : std_logic; -- Internal control signales signal ctlEppWait : std_logic; signal ctlEppAstb : std_logic; signal ctlEppDstb : std_logic; signal ctlEppDir : std_logic; signal ctlEppWr : std_logic; signal ctlEppAwr : std_logic; signal busEppOut : data_type; signal busEppIn : data_type; signal regEppAdr : std_logic_vector(7 downto 0); ------------------------------------------------------------------------ -- Module Implementation ------------------------------------------------------------------------ begin ------------------------------------------------------------------------ -- Map basic status and control signals ------------------------------------------------------------------------ clkMain <= mclk; pwait <= ctlEppWait; -- drive WAIT from state machine output -- Data bus direction control. The internal input data bus always -- gets the port data bus. The port data bus drives the internal -- output data bus onto the pins when the interface says we are doing -- a read cycle and we are in one of the read cycles states in the -- state machine. busEppIn <= pdb; dout <= busEppIn; pdb <= busEppOut when pwr = '1' and ctlEppDir = '1' else "ZZZZZZZZ"; -- Select either address or data onto the internal output data bus. busEppOut <= regEppAdr when ctlEppAstb = '0' else din; ------------------------------------------------------------------------ -- EPP Interface Control State Machine ------------------------------------------------------------------------ -- Map control signals from the current state ctlEppWait <= stEppCur(0); ctlEppDir <= stEppCur(1); ctlEppAwr <= stEppCur(2); we <= stEppCur(3); -- This process moves the state machine to the next state -- on each clock cycle process (clkMain) begin if clkMain = '1' and clkMain'Event then stEppCur <= stEppNext; end if; end process; -- This process determines the next state machine state based -- on the current state and the state machine inputs. process (stEppCur, stEppNext, ctlEppAstb, ctlEppDstb, ctlEppWr, mrst) begin rd_fin <= '0'; if mrst='1' then stEppNext<=stEppReady; else case stEppCur is -- Idle state waiting for the beginning of an EPP cycle when stEppReady => if ctlEppAstb = '0' then -- Address read or write cycle if ctlEppWr = '0' then stEppNext <= stEppAwrA; else stEppNext <= stEppArdA; end if; elsif ctlEppDstb = '0' then -- Data read or write cycle if ctlEppWr = '0' then stEppNext <= stEppDwrA; else stEppNext <= stEppDrdA; end if; else -- Remain in ready state stEppNext <= stEppReady; end if; -- Write address register when stEppAwrA => stEppNext <= stEppAwrB; when stEppAwrB => if ctlEppAstb = '0' then stEppNext <= stEppAwrB; else stEppNext <= stEppReady; end if; -- Read address register when stEppArdA => stEppNext <= stEppArdB; when stEppArdB => if ctlEppAstb = '0' then stEppNext <= stEppArdB; else stEppNext <= stEppReady; end if; -- Write data register when stEppDwrA => stEppNext <= stEppDwrB; when stEppDwrB => if ctlEppDstb = '0' then stEppNext <= stEppDwrB; else stEppNext <= stEppReady; end if; -- Read data register when stEppDrdA => stEppNext <= stEppDrdB; when stEppDrdB => if ctlEppDstb = '0' then stEppNext <= stEppDrdB; else stEppNext <= stEppReady; rd_fin <= '1'; end if; -- Some unknown state when others => stEppNext <= stEppReady; end case; end if; end process; ------------------------------------------------------------------------ -- EPP Address register ------------------------------------------------------------------------ process (clkMain) begin if clkMain = '1' and clkMain'Event then if ctlEppAwr = '1' then regEppAdr <= busEppIn; end if; end if; end process; addr <= regEppAdr; ------------------------------------------------------------------------ -- EPP Data registers ------------------------------------------------------------------------ -- The following processes implement the interface registers. These -- registers just hold the value written so that it can be read back. -- In a real design, the contents of these registers would drive additional -- logic. -- The ctlEppDwr signal is an output from the state machine that says -- we are in a 'write data register' state. This is combined with the -- address in the address register to determine which register to write. process (clkMain) begin if clkMain = '1' and clkMain'Event then ctlEppAstb <= astb; ctlEppDstb <= dstb; ctlEppWr <= pwr; end if; end process; end Behavioral;