Alan Kay once said, "People who are really serious about software should make their own hardware." I'm not sure that I agree, but I'm definitely one of those software engineers who would like to make his own hardware. This tutorial will lay the foundations for designing hardware using relatively low-cost tools.

Why design your own hardware? That really depends on you. A few possible reasons:

  • It gives you even more flexibility to create what you want
  • Algorithms implemented in hardware are typically faster and/or more energy efficient than the same algorithm in software
  • It's yet another outlet for creativity, and creating stuff is fun

The hardware designed in this tutorial will be incredibly simple; it'll flash an LED. We've got enough to learn as-is, without trying to tackle something big.

The Tools

Hardware is typically designed with the help of specialised software. There's a mind-boggling array of options out there. We're going to use a hardware design language called Cx. It's designed specifically "to bring digital hardware design within reach of any developer," and that sounds great for us! 

We also need a way to test the designed hardware. This used to be a very expensive and time-consuming process. Thankfully, Field Programmable Gate Arrays FPGAs) make this much easier and cheaper. FPGAs are chips containing a large array of logic gates (the building blocks of digital circuits). These gates can be connected up in many different ways thanks to a set of programmable interconnections. This allows us to upload our hardware design into the FPGA, and run it using real logic. Even better, the chip is reprogrammable, so if something doesn't work as intended, then we can fix the design, generate a new "bitfile," and upload the new design to the chip.

What You'll Need

There are a few things that you'll need:

  • A computer capable of running the necessary software
  • An internet connection to download the software
  • A Papilio Pro FPGA development board
    NOTE: A different FPGA board will work too (especially other Papilio boards), but you'll have to figure out certain details on your own
  • A willingness to learn, and some persistence

It'll also help a lot if you have programming experience (especially in C, Java, or hardware languages such as Verilog and VHDL). Failing that, an understanding of boolean logic is highly recommended.

Step One: Installing the Software

You will need to download and install the following:

You will also need a "constraints" file for the development board. This file describes how the FPGA's I/O pins connect to other devices on the development board. The Papilio Pro's generic constraints file can be found at: http://forum.gadgetfactory.net/index.php?/files/file/4-papilio-pro-generic-ucf/ (for other Papilio boards, look here).

Step Two: Set Up the Project

Start ngDesign. The first time round it will ask you where to put your workspace. Create a workspace wherever you like. Next, right-click in "Project Explorer" (ngDesign's left column), and select New => Synflow Project. Call the new project LEDFlasher.

New Synflow Project Menu

NgDesign stores source files in "packages" (rather like Java does). Within the new LEDFlasher project is a "src" directory, right-click on that, ans select New => package. Create a new ledflasher package. Synflow (Cx's creator) recommends naming packages using Java's convention, so I'll name mine "com.keasigmadelta.ledflasher". Replace "com.keasigmadelta" with whatever you wish.

NOTE: The naming convention makes it easier to use code from multiple people/organisations in the same design. Don't get hung up on the naming; you can always change it later.

Step Three: The Design

As I said earlier, we're designing a simple LED flasher circuit. The circuit is structured as follows:

LEDFlasher Network Block Diagram

The clock divider takes an input clock, and divides it down to produce two pulses per second (so a 2 Hz clock/enable signal). This 2 Hz signal is then input into the "ledDriver" that toggles the LED on and off once per second.

NOTE: The clock and reset signals have been left off the block diagram above for simplicity.

Create the LEDDriver Task

Cx divides circuits/processes into multiple tasks. These tasks are connected together in networks. So, lets create the first task, the LEDDriver. Right-click on the "ledflasher" package that was created in Step Two above, and select New => Cx Task. Call this task LEDDriver.

NgDesign will create a skeleton task for you. Enter the following code:

package com.keasigmadelta.ledflasher;

task LEDDriver {
	// Enables toggling the LED's state
	in bool toggle;
	
	// output to the LED
	out bool led;
	
	// The LED's current state
	bool ledState;
	
	void setup() {
		ledState = false;
	}
	
	void loop() {
		if(toggle == true) {
			ledState = !ledState;
			led.write(ledState);
		}
	}
}

Let's go through the important additions. First, we declare an input signal called toggle, and an output signal called led:

// Enables toggling the LED's state
in bool toggle;
	
// output to the LED
out bool led;

These are both booleans, which mean that they can be either true, or false (a.k.a., a 1, or 0). The input (toggle) receives the pulse from the divider task, while the output (led) will drive an LED.

Next, we have a task variable called ledState:

// The LED's current state
bool ledState;

This stores whether the LED is currently on (true/1), or off (false/0).

The setup() function sets the LED's initial state to off:

void setup() {
	ledState = false;
}

Next comes the loop() function. This is the task's core, and is "executed" continually:

void loop() {
	if(toggle == true) {
		ledState = !ledState;
		led.write(ledState);
	}
}

In plain English, this code says: if the toggle input is true, then set ledState to the opposite of what it is now (!ledState means "not ledState"). Finally, write ledState to the led output.

NOTE: Digital circuits are kept in step using a clock. The clock signals when variables (a.k.a., registers) can change state. Cx tasks implicitly use a clock, so the loop() code above is executed every clock cycle.

Create the Clock Divider

The LED driver needs something to drive its toggle input. Since the Papilio Pro's clock runs at 32 MHz (32 million cycles-per-second) and we want the LED to flash once per second, we need something to slow it down. That's a job for a counter/divider.

Create a new task called Divider. Enter the following code:

package com.keasigmadelta.ledflasher;

task Divider {
	typedef u24 ClkCounter_t;
	const unsigned CLOCK_FREQ = 32000000; // 32 MHz
	const unsigned TARGET_FREQ = 2; // 2 Hz
	const ClkCounter_t DIVIDER = CLOCK_FREQ / TARGET_FREQ;
	
	// The output signal
	out bool enable;
	
	// The internal counter
	ClkCounter_t counter;
	
	void setup() {
		counter = 0;
	}
	
	void loop() {
		if(counter == DIVIDER) {
			// Send an enable signal (for 1 clock cycle)
			enable.write(0b1); 
			
			// Reset the counter
			counter = 0;
		} else {
			// The enable signal is normally 0
			enable.write(0b0);
			
			// Increment the counter once each clock cycle
			counter++;
		}
	}
}

This task will count up to DIVIDER clock cycles, and then set the output enable to 1 (true) for one clock cycle. The target frequency (TARGET_FREQ) is set to 2 Hz, which will signal LEDDriver to switch the LED on (pulse one) and off (pulse two) once per second.

Some key things to look at in the code above:

  • CLOCK_FREQ is the input clock frequency. If you're using another board, then you'll have to adjust this
  • The line "typedef u24 ClkCounter_t" sets ClkCounter_t to be an unsigned integer that's 24 bits wide. This can hold values from 0 through to 224 - 1 = 16,777,215
    IMPORTANT: If your development board uses a faster clock, then make sure that the counter is large enough to hold the value of DIVIDER. If in doubt, change "u24" to "u32." This will ensure that the counter is large enough. The FPGA synthesizer will trim away the unnecessary extra bits (and spit out warnings)
  • You may notice that the code uses "counter == DIVIDER." Software developers generally use >= (greater than or equals) just in case the number gets corrupted. However, in hardware design, an equals comparison (i.e., ==) uses less logic than >=, <=, >, or < comparisons. Less logic means a smaller and faster design, and that's a good thing

Connecting the Tasks Together in a Network

Now it's time to connect the individual tasks together to create a full circuit. Right-click on your ledflasher package, and select New => Cx network. Call the network LEDFlasher.

The code is as follows:

package com.keasigmadelta.ledflasher;
import com.keasigmadelta.ledflasher.LEDDriver;
import com.keasigmadelta.ledflasher.Divider;


network LEDFlasher {
	// One output, to the LED that we're flashing
	out bool led;
	
	// Need one divider	
	divider = new Divider();
	
	// Create an LED driver, and connect it to the divider
	ledDriver = new LEDDriver();
	ledDriver.reads(divider.enable);
	
	// Connect the LED's output to led
	this.reads(ledDriver.led);
}

In brief, the LEDFlasher network has one output called led.

// One output, to the LED that we're flashing
out bool led;

The code creates one Divider and one LEDDriver:

// Need one divider	
divider = new Divider();
	
// Create an LED driver, and connect it to the divider
ledDriver = new LEDDriver();

The Divider's enable output is connected to the LEDDriver's toggle input:

ledDriver.reads(divider.enable);

Finally, the LEDDriver's output (led) is connected to the led output:

// Connect the LED's output to led
this.reads(ledDriver.led);

That's it! Everything is connected.

NOTE: In Cx the clock signals are connected by default, so we don't need to write code that connects them.

Why Use an "Enable" Signal Instead of Dividing the Clock Directly?

You may be wondering, why not feed the divided clock straight into the LEDDriver's clock input. After all, it's also a clock signal and using an enable signal looks like overkill. While that's true for this very simple design, having separate clock signals in a design requires careful synchronization between the parts that are clocked differently. Otherwise ugly problems can occur. I had a sigma-delta DAC design generate a lot of random noise due to this exact problem. One clock reached the DAC just as its input signals were switching, leading to random results.

The bottom line is, unless there's a very good reason for having multiple clocks, it's better to use one global clock for all logic and use "enable" signals to run different parts at different speeds.

Step Four: Generate Verilog Code

Xilinx's circuit synthesis software doesn't understand Cx, so we need to convert our Cx code into Verilog (or VHDL). NgDesign has a compiler that does this for us. Right-click on LEDFlasher in the project explorer (in the left-column), and select Run As => Hardware on FPGA.

LEDFlasher Generate Verilog

Since this is the first time that we run the compiler, it will pop up a configuration dialog. Set the "Target Vendor" to Xilinx (or the vendor for your board's FPGA)

LEDFlasher Select FPGA Vendor

Next, click the "Run" button. This will generate the Verilog code, and you'll notice a few new folders in the project.

LEDFlasher Generated Project File

Step Five: Synthesizing the Hardware

We're finally ready to take our design, and turn it into hardware. At this point we have to switch to Xilinx ISE. NgDesign has taken us as far as it can. Future versions will hopefully be able to synthesize hardware directly, but right now it can't (as at version 0.84).

Setting Up the Hardware Project

Open up Xilinx ISE. Select File => New Project from the menu bar. Set the project's location to be inside your LEDFlasher project (we want to keep stuff together), and give it a name. I called mine LEDFlasher_PapilioPro to match the hardware.

LEDFlasher New Project

Click Next. The software will ask you what kind of FPGA you want to synthesize logic for. The details for the Papilio Pro are:

  • Family: Spartan6
  • Device XC6SLX9
  • Package: TQG144
  • Speed: -2

Click Next, and then Finish.

Now, add the generated Verilog files to the project. Right-click in the "hierarchy panel" (top-left column), and select "Add source." The source files are within LEDFlasher/verilog-gen. Find them, and add them to the project. Once you're done then your project hierarchy should look like this:

LEDFlasher Added Files

NOTE: NgDesign may generate a Xilinx project file for you, but it will be overwritten every time that you recompile the code. So, don't use it.

Wiring the LED Flasher to the FPGA's I/O Pins

The hardware synthesizer needs to know which of the FPGA's pins our design should be connected to. There are three signals that connect to the outside world: the LED output, a clock input, and also a reset signal (that the Cx library automatically generates by default).

Right-click in the project hierarchy (left column) again, and select "New Source." Next, select "Implementation Constraints File" from the list, and give the file a name. I called mine "PapilioPro.ucf."

Remember the "constraints file" that was downloaded earlier? It's time to put it to use. Open up the downloaded constraints file. You want to find and copy the following details into your new *.ucf file:

  • Any comments at the top (e.g., comments explaining the board's layout). Comments start with a # symbol
  • Any "prohibit" entries (very important)
  • The line for the clock signal (search for "CLK")
  • The line for the pin connected to the LED (search for "LED1")
  • Finally, choose a pin for the reset signal. If you have a reset button, use the pin that the switch is connected to. Me, I chose the A0 pin

Now, rename the pin signals to match those in LEDFlasher.v:

  • "CLK" becomes "clock"
  • "LED1" becomes "led"
  • "A0" (or your chosen reset pin) becomes "reset_n"

The reset_n signal generated by Cx is "active low." This means that the reset occurs when that signal is pulled down to ground voltage (a.k.a., a logic 0). So, we need this reset signal to be held high unless someone pushes the reset button (which I'm too lazy to connect).  Xilinx's I/O pins have internal resistors that can be connected to to weakly pull the pin up to the supply voltage (a.k.a., VCC or a logic 1). A "weak" pull-up resistor sets the default logic value, but still allows external hardware (such as a reset switch) to pull the signal low when needed. The pull-up resistor can be enabled by adding PULLUP to the reset_n pin's line:

NET reset_n        LOC="P48"  | IOSTANDARD=LVTTL | PULLUP;                       # A0

The final file should look something like this:

# Main board wing pin [] to FPGA pin Pxx map
# -------C-------    -------B-------    -------A-------
# [GND] [C00] P114   [GND] [B00] P99    P100 [A15]
# [2V5] [C01] P115   [2V5] [B01] P97    P98 [A14]
# [3V3] [C02] P116   [3V3] [B02] P92    P93 [A13]
# [5V0] [C03] P117   [5V0] [B03] P87    P88 [A12]
#       [C04] P118         [B04] P84    P85 [A11] [5V0]
#       [C05] P119         [B05] P82    P83 [A10] [3V3]
#       [C06] P120         [B06] P80    P81 [A09] [2V5]
#       [C07] P121         [B07] P78    P79 [A08] [GND]
# [GND] [C08] P123   [GND] [B08] P74    P75 [A07]
# [2V5] [C09] P124   [2V5] [B09] P95    P67 [A06]
# [3V3] [C10] P126   [3V3] [B10] P62    P66 [A05]
# [5V0] [C11] P127   [5V0] [B11] P59    P61 [A04]
#       [C12] P131         [B12] P57    P58 [A03] [5V0]
#       [C13] P132         [B13] P55    P56 [A02] [3V3]
#       [C14] P133         [B14] P50    P51 [A01] [2V5]
#       [C15] P134         [B15] P47    P48 [A00] [GND]

## Prohibit the automatic placement of pins that are connected to VCC or GND for configuration.
CONFIG PROHIBIT=P144;
CONFIG PROHIBIT=P69;
CONFIG PROHIBIT=P60;

NET clock          LOC="P94"  | IOSTANDARD=LVTTL | PERIOD=31.25ns;               # CLK
NET led            LOC="P112" | IOSTANDARD=LVTTL | DRIVE=8 | SLEW=SLOW;          # LED1
NET reset_n        LOC="P48"  | IOSTANDARD=LVTTL | PULLUP;                       # A0

Synthesizing the Design

In the project hierarchy pane, click on the design's top-level file: LEDFlasher.v. Below, you'll see the "processes pane." Double-click on "Generate Programming File." The software will now go through the process of synthesizing the logic, mapping your design onto the FPGA, and generating the final bitfile.

If you've done everything right, then there will be a green tick next to "Generate Programming File" (see below). If not, check the errors in the console pane at the bottom of the window.

LEDFlasher Generate Programming File

Step Six: Upload the Design to the FPGA Board

The final step is to upload the bitfile to the FPGA. Plug the Papilio development board into a USB port. In windows explorer, navigate to your LEDFlasher's Xilinx ISE project directory.

Right-click on ledflasher.bit, and select "Write to Papilio board." This will start the Papilio Loader, and upload the design to the FPGA. Once this is done, you will see LED1 flash on and off once per second. Congratulations! You have your first hardware design working.

NOTE: The "Write permanently to Papilio board" option writes the design to onboard SPI flash. This means that the design will automatically be loaded into the FPGA after it is powered up or reset. However, there's no point in doing that for this simple test. Keep uploading to flash for designs that you're actually planning to use.

What's Next

Phew, that was a long process. It always take long the first time round. With a little practise you'll get faster.

In a future tutorial I'll show you how to make something a bit more interesting. In the meantime, a good resource to learn more about the Cx language, is Synflow's own course (here). Also take a look at the documentation.

If you get stuck in this tutorial and need help, feel free to contact me. Feedback and comments are also welcome (there's a comments box below).