Showing posts with label vhdl. Show all posts
Showing posts with label vhdl. Show all posts

Wednesday, September 12, 2012

Implementing a DEPP interface on a Basys2, part 2

Previously, I described how to interface with a DEPP peripheral using the Adept SDK, and how to construct such a peripheral that will also interface with an adder. Here, I describe how to construct such an adder using Xilinx IP, and then how to connect everything together.

My first component is a DEPP peripheral, which is described in an earlier post.

Next, I want an 8-bit unsigned adder. Because I do not need to optimize for space on the FPGA, I'm going to instantiate a combinational adder. I do this by clicking the New Source button in ISE, then selecting IP (CORE Generator & Architecture Wizard). I give it a file name, in this case Adder8Bit, and click Next. I expanded the Math Functions folder, then Adders & Subtracters, and finally selected Adder Subtracter. I clicked Next again, then Finish.

The next screen allows you to configure the adder. I configured mine as shown here:

As previously described, I want an 8-bit unsigned adder, so I select unsigned for both input types, and 8 for the width of each input. I selected Add mode, with an output width of 8 (I'm ignoring the carry-out in this case). In order to create a combinational adder that doesn't depend on a clock signal, I selected Manual latency configuration with a latency of 0. As I selected options, the symbol on the left changed. When I was complete, I had only the two inputs and one output. When I had all of my options properly set, I clicked Generate, and let ISE crank away for a little while.

The core generator only creates a definition of something, not an instance. To actually make my components useful, I needed to create a single instance of my DEPP peripheral and a single instance of the adder. To do this, I created a new VHDL source file, then right-clicked on it and clicked "Set as Top Module." This tells ISE to that this is the module that interacts with the outside world (in this case, the pins on the FPGA package.

This project only utilizes the EPP pins on the FPGA, so the black-box entity description is fairly simple.

entity DeppAdder is
port(
--EPP Signals
EppAstb : in std_logic;
EppDstb : in  std_logic;
EppWr : in  std_logic;
EppWait : out  std_logic;
EppDB : inout std_logic_vector (7 downto 0)
);
end DeppAdder;

Within this entity, I need to create two components, and "wire them up" appropriately. To do this, I used a structural architecture.

architecture structural of DeppAdder is
component 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 component;
COMPONENT Adder8Bit
PORT (a : IN STD_LOGIC_VECTOR (7 downto 0);
b : IN  STD_LOGIC_VECTOR  (7 downto 0);
s : OUT  STD_LOGIC_VECTOR  (7 downto 0));
END COMPONENT;
signal Op1, Op2, Result : std_logic_vector  (7 downto 0);

The component declarations here just tell the compiler the inputs and outputs of the components I want to instantiate, not how they work. I still haven't instantiated any components, just the signals! To instantiate the components, I need to define the architecture.

begin
EppModule1 : EppModule port map (
Astb => EppAstb,
Dstb => EppDstb,
Wr => EppWr,
Wt => EppWait,
DataBus => EppDB,
Op1 => Op1,
Op2 => Op2,
Result => Result
);
Adder8Bit1 : Adder8Bit port map (
a => Op1,
b => Op2,
s => Result
);
end structural;

My top level entity instantiates two components, an EppModule named EppModule1 and an Adder8Bit named Adder8Bit1, and connect them using 3 intermediate signals, Op1, Op2, and Result. To test out my architecture, I ran the program described in my earlier post.

While adding two unsigned 8-bit values together is very mundane, this architecture can be expanded. For example, an audio file could be downloaded to the FPGA for post-processing, or a key could be stored, and then the FPGA could be used to perform cryptographic operations.


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.
begin
-- 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)
    begin
      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)
    begin
      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.