UC Berkeley CS150

Lab 2: Mapping Circuit Elements to FPGAs

Objectives

The primary purpose of this lab is to teach you the basics of using a Hardware Description Language (HDL) to design circuits. In this lab, and for the rest of CS150, we will be using Verilog as our HDL. You will learn to use the tools that map your HDL description of a circuit to FPGAs. In addition, you will learn how to use extra hardware to debug and verify your design. Finally, you will conduct a resource and timing analysis to give you a better idea of how exactly your design was implemented on the FPGA.

The Tools

We will be using a number of CAD (Computer Aided Design) tools to translate your HDL into a working circuit on the FPGA. These tools will pass your design through several stages, each one bringing it closer to a concrete implementation. Brief descriptions of these stages follows:

Synthesis/Partitioning

The Synthesis tool (in the case of this lab, XST) is the first program that processes your design. Among other tasks, it is responsible for design partitioning, which is the process of transforming the primitive gates and flip-flops that you wrote in Verilog into LUTs and other primitive FPGA elements. For example, if you described a circuit composed of many gates, but ultimately of 6 inputs and 1 output, XST will map your circuit down to a single 6LUT. Likewise, if you described a flip-flop it will be mapped to a specific type of flip-flop which actually exists on the FPGA. The final product of the design partitioning phase is a netlist file, a text file that contains a list of all the instances of primitive components in the translated circuit and a description of how they are connected.

Translate & Map

The translate & map stages are responsible for taking the generic netlist produced by the synthesis stage and translating each component to an equivalent on the specific Xilinx xc5vlx110t FPGAs we have in the lab.

Placement

Placement takes a mapped design and determines the specific location of each component in the design on the FPGA. For example, each slice in the mapped designed is assigned to a specific site.

Routing

Once placement is done, all of the connections specified in the netlist must be made. In general, routing is one of the most time-consuming parts of computer-aided circuit design. Optimizing placement can help speed up the process.

Structural Verilog

Read this section before writing any Verilog. It provides an overview of the features of the language you will be using in this lab.

Allowed Constructs

In this lab you will use only a subset of Verilog that we call Structural Verilog. This consists of:

Additionally, you will be allowed to use the generate and parameter statements.

Examples of the style of Verilog you will be using in this lab can be found in the ALU.v and Mux21.v files included in this lab.

Prelab

Structural Accumulator

In this lab we will be building accumulator circuits. In general, an accumulator circuit has the following form:

Figure 1

The Accumulator has a Clock, a data input In and an additional input ALUOp that specifics its operation (eg. and, or, or +). There is a register that holds the value of the accumulator, and a ALU circuit that computes the next value.

The diagram leaves the width of In and Result (and therefore the ALU and register) unspecified. That is because you will first create a "bit-slice" that implements a 1-bit wide accumulator, and later chain these slices together using the Verilog generate statement to create parameterizable N-bit wide accumulators as shown in figure 2.

Figure 2

In this lab, you will be building an accumulator that supports the following operations:

Binary Encoding Operation
000 Result = A + B
001 Result = A - B
010 Result = A & B
011 Result = A | B
100 Result = A ^ B
101 Result = ~A
110 Result = A
111 Unspecified

Prelab Requirements

First, read the "FDRSE" section in the Virtex-5 Libraries Guide for HDL Designs.

As part of the prelab, you will have to implement:

We have written the following modules for you:

Feel free to modify the verilog we have provided you. Note, however, that you must not alter the interfaces (module port names and types) we have specified or you will break the testing modules.

The implementation we provide for the ALU module is a good example of how to use the Verilog generate statement to combine bit slices. Consider using this module as a pattern when implementing the Accumulator module.

Remember that part of the interface you must conform to includes the ALUOp encoding. See the Structural Accumulator section for the encoding table.

Checkoff Questions

Lab Procedure

Getting Set Up

Note about shell commands: The remainder of this lab document will feature a handful of example shell commands that you may want to run verbatim at your workstation. To facilitate copying and pasting, you may want to first issue the command

alias %=''

This will cause your shell to ignore the % characters that are used to indicate a shell prompt. You may want to add this line to one of your shell startup scripts.

Now that you have written your verilog, it is time to attempt to run it through the tools. We assume that you have the src directory from the prelab at ~/src. First you need to get the latest version of the lab. During this step please be careful not to clobber your source files. You may want to make a copy of them first.

% curl 'http://inst.eecs.berkeley.edu/~cs150/sp11/lab_2/lab2.tar.gz' \
| tar -xzv
% rm -rf ~/lab2/src
% mv src ~/lab2

Older versions of the lab tarball had a small bug in the Verilog files. Check if you have a file called ~/src/Accumulator.v. If you do you need to rename your Accumulator module to StructuralAccumulator. The following commands will do this for you:

% cd ~/lab2/src
% sed -i -e 's/\(Accumulator(\)/Structural\1/' Accumulator.v
% sed -i -e 's/ Accumulator / StructuralAccumulator /' TestHarnessAccumulator.v
% mv Accumulator.v StructuralAccumulator.v

The Build System

The lab distribution contains a Makefile that lets you easily build and debug your designs. For those unfamiliar with make, you use it by invoking the program make with a target passed in as an argument. For instance, make synth will run the toolchain up to synthesis. Several important targets will be described later in the lab.

The Makefile has several variables defined at the very top of the file that let you control the behavior of the build system.

TOP := FPGA_TOP_ML505
UCF := src/$(TOP).ucf
PART := xc5vlx110t-ff1136-1
SRCS := $(wildcard src/*.v)

The most important one for this lab will be the definition of TOP. You use it to change the top level module for hardware synthesis. You can change it either by editing the Makefile (and remembering to change it back afterwards) or by invoking make like this:

% make TOP=<your top module here>

Sanity Check

The first thing you want to do after writing new verilog modules (like you did in the prelab) is check that it at least makes basic sense. The synth make target is very useful for this purpose. Run it like this:

% cd ~/lab2
% make synth

The Xilinx tools that this target invokes generate a huge amount of output. Sometimes warnings and errors are obvious, sometimes they are not. The report make target launches a program that makes it much easier to view the output of the synthesis tool. Do this now, and select the Synthesis Messages item on the left to see what messages the synthesizer generated. Errors must be addressed before continuing. In this lab you will inevitably see warnings about black box modules being used, and some of the carry out signals not being connected, but you shouldn't see many other warnings. Ask your TA if you are unsure if you should be worried about a warning you see at this stage.

Once you have cleared all errors from the synthesis stage, you know your verilog is at least syntactically correct. Unfortunately this doesn't mean much because verilog compilers are often very willing to accept complete nonsense (and give you complete nonsense in return). Another useful step to take is checking a diagram of the generated circuit. There is another make target for this: schematic. This will launch the ISE project navigator. Once inside ISE, go to File > Open and select FPGA_TOP_ML505.ngr. Choose Start with a schematic of the top-level block in the dialog that pops up. This will give you a fairly straight-forward hierarchal block-level view of your design. You will find your circuit by drilling down in the following modules: FPGA_TOP_ML505, TestHarnessAccumulator, StructuralAccumulator. Check to see that your accumulator module is hooked up properly and looks sane.

Verification

Once your circuit looks correct, it is time to verify it using the TestHarness module module. The TestHarness, or more accurately the Tester that is instantiated within TestHarness, works by comparing the output of your circuit with the output of a known-working circuit. In this lab there are two TestHarness modules, one for the ALU and one for the Accumulator (this is purely for your convenience, as it is useful to be able to verify the ALU without the Accumulator). Both work in exactly the same way: your circuit, alongside the "black box" circuit the TAs have provided you, is fed a stream of inputs from a simple up-counter. When the counter reaches its maximum value it stops. At this point, if your circuit passes all tests, a success LED turns on. If there was an error, an error LED turns on to indicate failure.

This particular testing method provides very little visibility in to what is going wrong in circuit. You may find it helpful to pull various signals out to unused LEDs to help you debug.

To push this design to the board, start by issuing a make command in your lab directory. This should build your entire design all the way through to the bitfile. At this point you can issue the make impact command to program the board.

The test harness uses DIP switches 1, 2, and 3 to choose the ALU Operation, and uses LEDs for output. LED 0 indicates success for the accumulator module; LED 1 indicates failure. LEDs 2 and 3 are the same, put they are for the part of the test harness that only tests the ALU. You can use "N" compass switch to reset the testers.

Circuit Analysis

Now that your circuit is fully functional, we will perform a resource analysis. This will give you a better idea of what the tools actually produced from your HDL.

In the PreLab questions, you were asked to find out how many resources a 1-bit ALU mapped to on the FPGA. We would like to extend this concept to the N-bit accumulator.

For the lab checkoff, you will need the following information about the N-bit Accumulator:

You will be able to find these numbers by running make report after mapping your design:

% make TOP=StructuralAccumulator map
% make TOP=StructuralAccumulator report

This will generate numbers for the default width StructuralAccumulator (it should be 1). For the checkoff, you will also need these measurements for a 4-, 8-, and 16-bit accumulator. You can find these by changing the width parameter in StructuralAccumulator.v and then running map and report again.

Checkoff

Write down the following for a 1-, 4-, 8-, and 16-bit accumulator.