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.
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:
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.
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 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.
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.
Read this section before writing any Verilog. It provides an overview of the features of the language you will be using in this lab.
In this lab you will use only a subset of Verilog that we call Structural Verilog. This consists of:
wire
constructand
or
not
xor
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.
In this lab we will be building accumulator circuits. In general, an accumulator circuit has the following form:
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.
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 |
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.
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 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>
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.
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.
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.
Write down the following for a 1-, 4-, 8-, and 16-bit accumulator.