Showing posts with label fpga. Show all posts
Showing posts with label fpga. 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.



Communicating with the Basys2 using the Adept SDK

Writing code for development boards is fun: LEDs flash, respond to button presses, etc. Eventually though, we would like to be able to communicate with our boards using a PC. Many boards include a RS-232 (serial) port for just this purpose. RS-232 has a few drawbacks though, most notably that if your computer was purchased this millennium, you will probably have to use a USB-serial converter. These are cheap and prevalent, but it is just another thing to clutter up your workspace. Also, transferring large amounts of non-ASCII data (i.e. raw hex) can be challenging and time consuming. Since legacy ports are going the way of the Dodo bird, many developers are omitting the serial port from their development boards, and instead including a USB controller. The Basys2 from Digilent is one such board. This leaves us in a lurch, unless we can find a way to interact with the device through its USB controller. And that's were the Adept SDK comes in.

Instead of having to look up the specifics of the USB chip on the board, the Adept SDK provides APIs to interact with the board. In this post, I'll cover just 2 of the libraries: the device access management library (DMGR) and the asynchronous parallel port library (DEPP). Note that DEPP is so named for the similarity to the Enhanced Parallel Port (EPP) protocol used by parallel ports.

The Adept SDK provides code samples for each of the libraries. For the DMGR library, there are 2 examples: EnumDemo and GetInfoDemo. To get started, download the Adept SDK and Adept Runtime from Digilent. Install the runtime, and decompress the SDK somewhere you can find it. The SDK contains:
  • Documentation: PDF files describing how to use the libraries in the doc folder
  • Header Files: The include folder contains header files
  • Static Libraries: The APIs are provided as precompiled libraries
  • Code Samples: Example code for each library is included in the samples folders

After downloading the SDK for Windows, I set about to compiling some of the samples. There are introductions on how to do this in the samples directory, but they are specific to Visual Studio. In my case, I am using MinGW's toolchain. The linkers in the two toolchains expect library files to be named differently. Visual Studio expects a library file named <library name>.lib, and this is how the libraries are provided by Digilent. MinGW's linker, ld, only accepts library files in the format lib<library name>.a. Similarly, ld running under Linux expects a file lib<library name>.so. So, in order to use the Windows libraries provided by Digilent, I had to rename all of the files. dmgr.lib had to be renamed libdmgr.a, for example. The Windows version of the SDK contains the libraries in the lib or lib64 directories. The Linux version installs the libraries with the runtime.

In order to get g++ to compile the examples, I had to specify the include directory using -I, specify the library directory using -L, and specify which libraries to use AFTER the filename. For example, a project that uses only the DMGR library would have -ldmgr after the file name.

I compiled and executed the DMGR examples EnumDemo and GetInfoDemo. These confirmed that there was in fact a Basys2 attached to my system, and that it supported the DEPP library. I then instantiated a DEPP interface on the FPGA that included 2 operand registers and a result register. The operand registers can be written by the PC, and the result register can be read. Actually creating those structures on the FPGA will be covered in another post, but project files can be found here.

I wanted to write some code to write values to the operand registers, then read the result out. Here's what it looks like (full file here):
 #if defined(WIN32)
/* Include Windows specific headers here.*/
#include <windows.h>
#endif
This makes the necessary types available on a Windows.
#include <stdio.h>
#include "dpcdecl.h"
#include "dmgr.h"
#include "depp.h"
All of the header files needed for this project.
#define OP1ADDR         0x00
#define OP2ADDR         0x01
#define RESADDR         0x00
I chose to use text substitutions to define the register locations, to make my code easier to read. And then we start with main():
int main()
{
        HIF deviceHandle;
        int status = fTrue;
        char deviceName[32] = "Basys2";
        unsigned char result;
The type HIF is defined in dpcdecl.h, and is a structure that holds a handle to a device. This handle is used to interact with the Basys2. The status variable will be used for error detection/error handling. The device name is the UserName of the device. I found the UserName using EnumDemo. result will hold the result of the arithmetic that we read back from the device.
//Open a handle to the device
status = DmgrOpen(&deviceHandle,deviceName);
if (status)
printf("Successfully opened a handle to %s\n", deviceName);
else
{
status = DmgrGetLastError();
printf("Error code: %d\n", status);
}
 The first step in interacting with the device is to open a handle to it. Note that the API functions return FALSE if there is an error, and TRUE if they are successful.
//Enable the default port (Port 0) on the device
status = DeppEnable(deviceHandle);
if (status)
printf("Successfully enabled Port 0\n");
else
{
status = DmgrGetLastError();
printf("Error code: %d\n", status);
}
The EPP port must be enabled before reading or writing.
//Do some math
DeppPutReg(deviceHandle, OP1ADDR, 0x00, fFalse);
DeppPutReg(deviceHandle, OP2ADDR, 0x00, fFalse);
DeppGetReg(deviceHandle, RESADDR, &result, fFalse);
printf("0x00 + 0x00 = 0x%02X\n", result);
//...
DeppPutReg(deviceHandle, OP1ADDR, 0xFF, fFalse);
DeppPutReg(deviceHandle, OP2ADDR, 0x01, fFalse);
DeppGetReg(deviceHandle, RESADDR, &result, fFalse);
printf("0xFF + 0x01 = 0x%02X\n", result);
Here's where I actually transfer some data to and from the device. I write to the operand registers using DeppPutReg(), and then read the result register using DeppGetReg(). I ran through several scenarios to make sure that the adder was working properly.
//Disable the active port on the device
status = DeppDisable(deviceHandle);
if (status)
printf("Successfully disabled DEPP port\n");
else
{
status = DmgrGetLastError();
printf("Error code: %d\n", status);
}

//Close our handle to the devicestatus = DmgrClose(deviceHandle);
if (status)
printf("Successfully closed device handle\n");
else
{
status = DmgrGetLastError();
printf("Error code: %d\n", status);
} 
This is all cleanup to make sure that I gracefully release the device.

When it was all said and done, the output looked like this:
Successfully opened a handle to Basys2
Successfully enabled Port 0
0x00 + 0x00 = 0x00
0x01 + 0x00 = 0x01
0x01 + 0x01 = 0x02
0xA5 + 0x5A = 0xFF
0xFF + 0x01 = 0x00
Successfully disabled DEPP port
Successfully closed device handle

And so, I successfully moved raw data to the device, and read a result. While an unsigned 8-bit adder is trivial, this gives me all of the building blocks to do something more interesting, like cryptographic work.

Monday, January 23, 2012

Using Xilinx ISE WebPack IDE With Digilent Basys2

Prologue:
Presently the bulk of our focus has laid in configuring a Linux machine to have the capacity to act as a development environment for the Digilent Basys2 Development board. In this document we will walk through the process of loading the basic default program into the Basys2 board.

This document assumes that you’ve erased your Basys2’s Electrically Erasable Programmable Read Only Memory (EEPROM) data or is running some design other than the design shipped with the Basys2. If this is not the case, to ensure that the Basys2 is erased you may execute the following while your Basys2 is connected via USB and is TURNED ON (make sure the power switch is in the ON position):
djtgcfg erase -d Basys2 -i 1

Instructions:
First and foremost we must start the Xilinx ISE WebPack Integrated Development Environment (IDE). To do so, assuming you have used the default installation path, you may execute (similar for different versions) the following:
cd /opt/Xilinx/13.3/ISE_DS/ISE/bin/lin/
./ise &
Minimizing the IDE and opening a web browser, we may goto the following location: http://www.digilentinc.com/Products/Detail.cfm?NavPath=2,400,790&Prod=BASYS2

Locate the “Basys2 User Demo project” and download it.

In a terminal you may unzip the downloaded file using the unzip program:
unzip Basys2UserDemo.zip
This creates a pdf and a folder “Basys2UserDemo”. Let’s give focus back to the ISE WebPack IDE (Maximize it) and then select:

  1. File -> Open Project
    1. Browse to the unzipped folder location / “UncompiledBasys2UserDemo”
    2. Change “Files of Type” from “ISE Project Files (*.xise)” to “Old ISE Project Files (*.ise)”
    3. Select “Basys2UserDemo.ise” and Click “Open”
    4. When prompted to to mirgate the project, Click “Migrate Only”
  2. On the left there is a “Panel” called “Design” this may be toggled using “View -> Panels -> Design” though we will ensure this is checked and visible.
  3. Identify the Basys2UserDemo - Stuctural node in the Design Panel “Hierarchy,” select it and then right click on it.
  4. Select “Design Properties...”
  5. Ensure the following:
    1. Top-Level Source type: “HDL”
    2. Evaluation Development Board: “None Specified”
    3. Product Category: “All”
    4. Family: “Spartan 3E”
    5. Select “Device” to match if you have a 100K die or 250K die, 100K dies use XC3S100E and 250K dies use XC3S250E
    6. Package: “CP132”
    7. Speed: “-5”
    8. Click “OK”
  6. Identify the Basys2UserDemo - Stuctural node in the Design Panel “Hierarchy,” select it and then right click on it.
  7. Select “Implement Top-Module”
  8. Wait until all processing is complete...
  9. Identify “Generate Programming File” in the Design Panel under “Processes: Basys2UserDemo”, right click and select “Process Properties”
    1. Select “Startup Options” Category
    2. Ensure:
      1. FPGA Start-Up Clock: “JTAG Clock”
      2. Click “OK”
  10. Identify “Generate Programming File” in the Design Panel under “Processes: Basys2UserDemo”, right click and select “Run”
    1. This Generates a .BIT file which can be used to program the FPGA.
  11. From a terminal enter into the location enter the Basys2UserDemo/UncompiledBasys2UserDemo” folder and execute the following
    1. djtgcfg prog -d Basys2 -i 0 -f Basys2UserDemo.bit
    2. -i 0 : is the FPGA’s Random Access memory (RAM), this will not permanently load the User Demo to the Board.
    3. (Read the “Linux: Getting Started, Using Digilent Adept 2“ for more information if necessary)
Congratulations you should now have the user demo running on your Basys2! To Confirm this the 7-Segment displays on the bottom of the Basys2 will be counting from 0 to F in Hexadecimal and repeat.

Friday, January 20, 2012

Installing Digilent Adept 2 on Linux Workstations

So in my previous post I walk through the somewhat long, boring, but important steps, for installing the Xilinx ISE WebPack software. This is the software used for creating hardware designs, compiling them, optimizing them, routing them, and eventually it spits out a '.bit' file.


So in theory, once you've compiled a design, or have a .bit file for your particular Field Programmable Gate Array (FPGA) or Complex Programmable Logic Device (CPLD), you'll be ready to load it onto your device of choice! To do these we use Digilent Adept 2.


Digilent Adept 2: The Adept Runtime & Utilities consists of the shared libraries, firmware images, and configuration files necessary to communicate with Digilent's devices.
  1. Goto: http://www.digilentinc.com/Products/Detail.cfm?Prod=ADEPT2 and download the Run time software for your Linux architecture (32 or 64 bit)
  2. Decompress the downloaded file, this requires gzip
    1. eg. “gzip -d digilent.adept.runtime_2.8.2-i686.tar.gz”
  3. Untar the the decompressed file, this requires tar
    1. eg. “tar -xvf digilent.adept.runtime_2.8.2-i686.tar”
  4. Enter the directory which contains the run time installer
  5. *Execute the install.sh script, this will require superuser privileges (speak with your system administrator)
    1. eg. “sudo ./install.sh”
    2. Press [enter], press [Enter]
*As of this writing the Digilent Adept 2 runtime install.sh encounters an error on 3.x.x kernels that use udev. It should be fixed soon.

  1. Goto: http://www.digilentinc.com/Products/Detail.cfm?Prod=ADEPT2 and downlaod the Utilities software for your Linux architecture(32 or 64 bit)
  2. Decompress the downloaded file, this requires gzip
    1. eg. “gzip -d digilent.adept.utilities_2.1.1-i686.tar.gz”
  3. Untar the decompressed file, this requires tar
    1. eg. “tar -xvf digilent.adept.utilities_2.1.1-i686.tar”
  4. Enter the directory which contains the utilities installer
  5. Execute the install.sh script, this will require superuser privileges (speak with your system administrator)
    1. eg. “sudo ./install.sh”
    2. Press [enter], press [Enter]
I use a Digilent Basys 2 Development Board because it's cheap enough for me to afford, I also have a C-MOD which I have not used yet but will likely utilize at sometime this year. If you've done both the ISE WebPack install and the Adept 2 installation you should now have the necessary software to load new designs to devices of your choice!

Tuesday, January 17, 2012

Installing Xilinx ISE Webpack on Linux workstations

Recently I pulled out the old Field Programmable Gate Array (FPGA) from my desk and dusted it off to get it ready for some small projects. I'd just like to get a little more into digital design, etc. My experimenter board of choice is the Digilent Basys2 Spartan 3E FPGA Board. This is my board of choice because it's not very expensive and though many people tell me the Spartan 3E are obsolete/deprecated. However, this is what I have so it's the board and chip I'll use.

But before I can go off and put any designs on the board I need to pick up some digital design software. I'll be using Xilinx's ISE WebPack (currently version 13.3).

The following outlines the steps to getting started with Xilinx ISE WebPack on Linux based machines.

  1. Goto: http://www.xilinx.com/support/download/index.html/content/xilinx/en/downloadNav/design-tools.html and download the latest version of Xilinx ISE WebPack for your platform (Linux Full Installer).
    1. You will need to register a Username/Password in order to get the download, this registration will also be used when getting the Licensing file to activate ISE WebPack, so keep a copy safe and available!
  2. Confirm the download was successful by comparing MD5 checksums on the archive to the information at the above location.
    1. This requires openssl
      1. eg. “openssl md5 Xilinx_ISE_DS_Lin_13.3_O.76xd.1.0.tar”
  3. Untar the archive
    1. This requires tar
      1. eg. “tar -xvf Xilinx_ISE_DS_Lin_13.3_O.76xd.1.0.tar”
  4. Enter the directory for the Xilinx installer:
    1. eg. “cd Xilinx_ISE_DS_Lin_13.3_O.76xd.1.0”
* ISE WebPack will ask for an installation directory during execution, the default is “/opt/Xilinx/13.3” (for the latest version as of 1/5/2011). The effective user must have write access to “/opt/” in order to install to this location. Speak to your system administrator for more information.
  1. Execute xsetup
    1. ./xsetup
  2. Click “Next”
  3. Review 1 of 2 License Agreement, click “I accept...” followed by “Next”
  4. Review 2 of 2 License Agreement, click “I accept...” followed by “Next”
  5. Select ISE WebPack, click “Next”
  6. Check the following:
    1. “Acquire or Manage a License Key”
    2. “Enable WebTalk to send software...”
    3. “Ensure Linux System Generator Symlinks”
    4. Click “Next”
  7. Check “Import tool preferences from previous version,” click “Next”
  8. Click “Install”
  9. Select “Get Free ISE WebPack License,” followed by “Next”
  10. Click “Connect Now”
    1. A browser should open redirecting you to login to register your ISE WebPack OR
    2. If this does not occur, you may follow the following link:http://www.xilinx.com/getlicense/
  11. Login using your credentials acquired through the registration process in Step 1.
  12. Confirm or Modify any registration information and click “Next” in your web browser.
  13. Continue any on screen instructions for generating a License Key [Unfortunately: I did this a while ago and no longer need to do it again. I merely managed my existing license and had a new copy of the Xilinx.lic file (the license) to me.]
  14. Once you have your Xiling.lic file emailed to you, download it to any directory and Select “Copy License File”
  15. Browse to the file location select the file, you will be prompted with a successful message, click “OK” followed by “Close”
  16. Click “Finish”
This concludes the installation of Xilinx ISE WebPack.

Coming soon, a quick intro to using ISE WebPack to load the default program...