Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ejrh/6ba768499319e9945bd0 to your computer and use it in GitHub Desktop.
Save ejrh/6ba768499319e9945bd0 to your computer and use it in GitHub Desktop.
dpimref.vhdl
----------------------------------------------------------------------------
-- 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
----------------------------------------------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity dpimref is
Port (
mclk : in std_logic;
pdb : inout std_logic_vector(7 downto 0);
astb : in std_logic;
dstb : in std_logic;
pwr : in std_logic;
pwait : out std_logic;
rgLed : out std_logic_vector(7 downto 0);
rgSwt : in std_logic_vector(7 downto 0);
rgBtn : in std_logic_vector(3 downto 0)
);
end dpimref;
architecture Behavioral of dpimref is
------------------------------------------------------------------------
-- Component Declarations
------------------------------------------------------------------------
------------------------------------------------------------------------
-- Local Type Declarations
------------------------------------------------------------------------
------------------------------------------------------------------------
-- Constant Declarations
------------------------------------------------------------------------
-- 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 : std_logic_vector(7 downto 0) := "0000" & "0000";
constant stEppAwrA : std_logic_vector(7 downto 0) := "0001" & "0100";
constant stEppAwrB : std_logic_vector(7 downto 0) := "0010" & "0001";
constant stEppArdA : std_logic_vector(7 downto 0) := "0011" & "0010";
constant stEppArdB : std_logic_vector(7 downto 0) := "0100" & "0011";
constant stEppDwrA : std_logic_vector(7 downto 0) := "0101" & "1000";
constant stEppDwrB : std_logic_vector(7 downto 0) := "0110" & "0001";
constant stEppDrdA : std_logic_vector(7 downto 0) := "0111" & "0010";
constant stEppDrdB : std_logic_vector(7 downto 0) := "1000" & "0011";
------------------------------------------------------------------------
-- Signal Declarations
------------------------------------------------------------------------
-- State machine current state register
signal stEppCur : std_logic_vector(7 downto 0) := stEppReady;
signal stEppNext : std_logic_vector(7 downto 0);
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 ctlEppDwr : std_logic;
signal busEppOut : std_logic_vector(7 downto 0);
signal busEppIn : std_logic_vector(7 downto 0);
signal busEppData : std_logic_vector(7 downto 0);
-- Registers
signal regEppAdr : std_logic_vector(3 downto 0);
signal regData0 : std_logic_vector(7 downto 0);
signal regData1 : std_logic_vector(7 downto 0);
signal regData2 : std_logic_vector(7 downto 0);
signal regData3 : std_logic_vector(7 downto 0);
signal regData4 : std_logic_vector(7 downto 0);
signal regData5 : std_logic_vector(7 downto 0);
signal regData6 : std_logic_vector(7 downto 0);
signal regData7 : std_logic_vector(7 downto 0);
--signal regLed : std_logic_vector(7 downto 0);
signal cntr : std_logic_vector(23 downto 0);
------------------------------------------------------------------------
-- Module Implementation
------------------------------------------------------------------------
begin
------------------------------------------------------------------------
-- Map basic status and control signals
------------------------------------------------------------------------
clkMain <= mclk;
ctlEppAstb <= astb;
ctlEppDstb <= dstb;
ctlEppWr <= pwr;
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;
pdb <= busEppOut when ctlEppWr = '1' and ctlEppDir = '1' else "ZZZZZZZZ";
-- Select either address or data onto the internal output data bus.
busEppOut <= "0000" & regEppAdr when ctlEppAstb = '0' else busEppData;
--rgLed <= regLed;
-- **** Show cnt (mod 256) on the LEDs
rgLed <= cntr(7 downto 0);
-- Decode the address register and select the appropriate data register
busEppData <= regData0 when regEppAdr = "0000" else
regData1 when regEppAdr = "0001" else
regData2 when regEppAdr = "0010" else
regData3 when regEppAdr = "0011" else
regData4 when regEppAdr = "0100" else
regData5 when regEppAdr = "0101" else
regData6 when regEppAdr = "0110" else
regData7 when regEppAdr = "0111" else
rgSwt when regEppAdr = "1000" else
"0000" & rgBtn when regEppAdr = "1001" else
"00000000";
------------------------------------------------------------------------
-- EPP Interface Control State Machine
------------------------------------------------------------------------
-- Map control signals from the current state
ctlEppWait <= stEppCur(0);
ctlEppDir <= stEppCur(1);
ctlEppAwr <= stEppCur(2);
ctlEppDwr <= 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)
begin
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;
end if;
-- Some unknown state
when others =>
stEppNext <= stEppReady;
end case;
end process;
------------------------------------------------------------------------
-- EPP Address register
------------------------------------------------------------------------
process (clkMain, ctlEppAwr)
begin
if clkMain = '1' and clkMain'Event then
if ctlEppAwr = '1' then
regEppAdr <= busEppIn(3 downto 0);
end if;
end if;
end process;
------------------------------------------------------------------------
-- 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, regEppAdr, ctlEppDwr, busEppIn)
begin
if clkMain = '1' and clkMain'Event then
if ctlEppDwr = '1' and regEppAdr = "0000" then
regData0 <= busEppIn;
end if;
end if;
end process;
process (clkMain, regEppAdr, ctlEppDwr, busEppIn)
begin
if clkMain = '1' and clkMain'Event then
if ctlEppDwr = '1' and regEppAdr = "0001" then
regData1 <= busEppIn;
end if;
end if;
end process;
process (clkMain, regEppAdr, ctlEppDwr, busEppIn)
begin
if clkMain = '1' and clkMain'Event then
if ctlEppDwr = '1' and regEppAdr = "0010" then
regData2 <= busEppIn;
end if;
end if;
end process;
process (clkMain, regEppAdr, ctlEppDwr, busEppIn)
begin
if clkMain = '1' and clkMain'Event then
if ctlEppDwr = '1' and regEppAdr = "0011" then
regData3 <= busEppIn;
end if;
end if;
end process;
process (clkMain, regEppAdr, ctlEppDwr, busEppIn)
begin
if clkMain = '1' and clkMain'Event then
if ctlEppDwr = '1' and regEppAdr = "0100" then
regData4 <= busEppIn;
end if;
end if;
end process;
process (clkMain, regEppAdr, ctlEppDwr, busEppIn)
begin
if clkMain = '1' and clkMain'Event then
if ctlEppDwr = '1' and regEppAdr = "0101" then
regData5 <= busEppIn;
end if;
end if;
end process;
process (clkMain, regEppAdr, ctlEppDwr, busEppIn)
begin
if clkMain = '1' and clkMain'Event then
if ctlEppDwr = '1' and regEppAdr = "0110" then
regData6 <= busEppIn;
end if;
end if;
end process;
process (clkMain, regEppAdr, ctlEppDwr, busEppIn)
begin
if clkMain = '1' and clkMain'Event then
if ctlEppDwr = '1' and regEppAdr = "0111" then
regData7 <= busEppIn;
end if;
end if;
end process;
process (clkMain, regEppAdr, ctlEppDwr, busEppIn)
begin
if clkMain = '1' and clkMain'Event then
--if ctlEppDwr = '1' and regEppAdr = "1010" then
-- regLed <= busEppIn;
--end if;
--regLed <= rgSwt;
end if;
end process;
process (clkMain)
begin
if clkMain = '1' and clkMain'Event then
-- ***** Only increment cntr if its a "data write" operation.
if ctlEppDwr = '1' then
cntr <= cntr + 1;
end if;
end if;
end process;
end Behavioral;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment