Wednesday, September 12, 2012

Implementing a DEPP interface on a Basys2, part 1

In a previous post, I discussed the use of Digilent's Adept SDK to move data between a PC and the Basys2 board. This requires instantiating an interface on the FPGA. Here, I will go through the interface one piece at a time. My code is based on Digilent's example code.

The Enhanced Parallel Port (EPP) interface consists of an 8-bit data bus and control signals. The data bus is bi-directional, and data flow is controlled by the host (in this case, the PC) using the write signal. When write is high, the host is reading from the data bus. The timing of data on the data bus is controlled using the astb (address strobe) and dstb (data strobe) signals. These signals are asserted by the host, and indicate that an address should be written or that data should be read/written respectively. The peripheral asserts a single signal, wait, which is used to indicate that the peripheral is ready to accept data or has data available. For more information on these signals, and the EPP interface, see the documentation available from Digilent.

In this case, I need a peripheral that can read two operands, and write a single result. The black-box description of this is:
entity EppModule is
    Port ( Astb : in  STD_LOGIC;
           Dstb : in   STD_LOGIC;
           Wr : in   STD_LOGIC;
           Wt : out   STD_LOGIC;
           DataBus : inout  STD_LOGIC_VECTOR (7 downto 0);
 Op1 : out std_logic_vector  (7 downto 0);
 Op2 : out std_logic_vector  (7 downto 0);
 Result : in std_logic_vector  (7 downto 0));
end EppModule;
Because only one 8-bit value can be sent across the data bus at a time, the address must be sent before data is read or written. Therefore, the peripheral needs a single signal to store the address value.

architecture Behavioral of EppModule is
signal addressReg : std_logic_vector  (7 downto 0);
The wait signal must be asserted after one of the strobe signals is asserted, or a timeout will happen. In my design, there are no constraints to when the device is ready to read or write data, so the wait signal should be asserted as soon as possible after every read or write strobe.
-- Epp signals
   -- Port signals
   Wt <= '1' when Astb = '0' or Dstb = '0' else '0';
When the host wants the peripheral to write data to the data bus, the write signal is asserted. I only have a single result that will be read so there is no need to verify the address before writing to the data bus.
DataBus <= Result when (Wr = '1') else "ZZZZZZZZ";
Next, I define the behavior of the address register. This register will be written when a write strobe occurs.
  -- EPP Address register
  process (Astb)
      if rising_edge(Astb) then  -- Astb end edge
        if Wr = '0' then -- Epp Addr write cycle
     addressReg <= DataBus;  -- Update the address register
        end if;
      end if;
    end process;
The operand registers are similar, but in this case there are 2 registers, so the action to be taken depends on the contents of the address register.
  -- EPP Write registers register
  process (Dstb)
      if rising_edge(Dstb) then  -- Astb end edge
        if Wr = '0' then -- Epp Data write cycle
       if addressReg = "00000000" then
Op1 <= DataBus;
elsif addressReg = "00000001" then
Op2 <= DataBus;
end if;
        end if;
      end if;
    end process;

end Behavioral;
And that completes the description of my EppModule. The full file can be found for download here. My next write-up will describe how to combine this with an adder so that the whole thing works.


  1. Hello!
    This is an amazing post. I have downloaded the files from Digilent Inc but I can not undertand how can I send more data from peripheral to host. In this post I would like to know how do you send Result1,Result2...etc.

    1. Camdon, the author, is having issues replying so I'm proxying his message for him:

      Hello Danyel,

      I'm glad you found the post useful. The way I see it, there are a couple of different ways to accomplish what you want to do:

      1. If you just want to be able to read a few result registers, say R0, R1, and R2, then you would instantiate those registers and then modify the EPP module so that you would remove this line:

      DataBus <= Result when (Wr = '1') else "ZZZZZZZZ";

      and replace it with a process block that decodes the address lines when Wr = '1', similar to the process block that exists for the writing to the registers, or a series of conditional assignments like

      DataBus <= R0 when (Wr = '1' and addressReg = '00000000') else
      R1 when (Wr = '1' and addressReg = '00000001') else
      R2 when (Wr = '1' and addressReg = '00000010') else

      2. Your other option would be to write new data to the result register based on the data strobe. This would be the way to do it if you want to move large amounts of sequential data, like dumping the entire contents of memory, or something like that. You could then use a library function like DpcGetRegRepeat() to read data very quickly.
      Please let us know if you have any more questions or if this is not clear. If it is & everything works out, please let us know that too! It helps others find solutions to similar questions.

  2. This comment has been removed by the author.