CS152 Computer Architecture and Engineering

Lab #2: Single Cycle Processor

John Lazzaro

Fall 2005

In Lab 2, your group will build a single-cycle processor, like the one
described in Chapter 5 of COD. You will create the design in Verilog.
The processor will run in simulation (ModelSim) and on real hardware
(Xilinx). You will create a test plan for your processor. You will
use the test plan for bug diagnosis, and to verify that your processor
executes a subset of the MIPS instruction set.

Lab 2 has several "checkoffs" and a final deadline:

By Thursday 9/8 by 11:59 PM, your group will submit a
preliminary design document to cs152-st aff@cory (delete the
space in the email address). We describe the
design document (which includes a test plan) later in this document.

On Friday 9/10 in lab section, your TA will review your
design document with you, and suggest changes. A final version of the
document, incorporating these changes, is due to
cs152-st aff@cory by Monday 9/12 by 11:59pm.

On Friday 9/16 in lab section, you will demonstrate an
assembled processor in simulation (ModelSim). The simulation will be
able to run short machine language programs provided by the TAs.

On Friday 9/23 in lab section, you will demonstrate the
processor running on the Calinx board. During this demo, the TA
will provide you with secret test code. If you are able to pass these
tests on your first try, you will receive bonus points. You can also
receive bonus points if you fix your processor to pass the tests
within your section time. If your processor is not fixed by the end
of section, your TA will provide source for the secret test code,
for use in your weekend debugging sessions.

On Monday 9/26 at 11:59 PM the lab (including the lab
report) is due, via the submit program (see below).

On checkoff days, be prepared to demo by the time your section
begins! The sooner you begin, the more time you will have to recover
from problems. Also, be sure to follow the specifications in
this report (and in the MIPS ISA manual in the Resources section). A
working processor that doesn't correctly implement all
of the instructions will fail the checkoff.

Lab Report Submission Policies: To submit your lab report, run
m:\bin\submit-fall2005.exe, or at command prompt type
"submit-fall2005.exe" then follow the instructions. The
required format for lab reports is shown on the resources page, as is the required
format for your design notebook.

Lab 2 Document History:

Thursday 9/15. In Problem 2a, deleted the incorrect
reference to "nPC", a structure that does not exist in the
Single-Cycle Processor. In Problem 2b, the example format
for the monitor now shows correct math. Thanks to everyone
who pointed out these errors!

Tuesday 8/30. Lab 2 posted on website.

Problem 0: Pre-Flight

Do these tasks before your group begins the design.

Problem 0a: Group Formation

During the first week of the course, we will be forming project
groups. After your first checkoff meeting on Friday 9/2, you should
be a member of a group with 4 or 5 members. Once group membership is
set, your group should send email to cs152-st aff@cory
register the group.

Your group will elect a spokesperson for Lab 2. The responsibility of
the spokesperson is to communicate questions to the TA and reply to
questions from the TA. Spokesperson duties rotate with each Lab
assignment; for each lab, your group will elect a different
spokesperson.

Problem 0b: Design Document

Your group will prepare a design document. The design document
will be 2-4 pages in length, and will contain:

The identity of the spokesperson for the lab, and a roster of
group members.

A short description of the structure of the design. The
description will be accompanied by preliminary high-level schematics
of your datapath, and a preliminary discussion of the controller. Use
any tool you like to draw the schematics, its only purpose is to
communicate structural ideas graphically. Visio is available on the
lab machines.

For the five modules described in Problem 1b, create a module
interface specification: a list of the names and sizes of all input
and outputs, and timing diagrams that show how the modules should
work. Also create a small (5 to 10) set of test vectors that a
correct module should meet. For combinational circuits, a test vector
consists of a set of inputs values, and a set of output values one
expects after a short settling time. For testing the clocked
behaviors of circuits, a test vector consists of inputs to apply
before the clock, and the expected output after the clock. (Note: the
module interface specifications and test vectors should go in an
Appendix to the document, and do not count against the 2-4 page
recommendation for the design document length).

A test plan for the processor -- how do you expect to
ensure your processor works as expected? Describe how you will do
unit testing (testing the individual datapath modules for
correctness), how you will test that modules interact correctly
together when you assemble the datapath, how you will test the
complete processor to detect the presence of bugs, and how you will
diagnose the bugs so you can fix them. Use a timeline (following the
calendar, from the start of the project to the due date) to show which
tests will be performed when. Do a rough draft of the test plan based
on the slides for the 9/8 lecture on testing (available on the
calendar website page), then refine the draft after attending the
lecture.

A tentative division of labor, showing the tasks each group
member intends to do.

The "paranoia" section: discuss potential areas of
difficulty in the lab.

See the start of this document for the deadlines associated with the
design document (preliminary submission, TA review, and final
submission).

Problem 0c: Design Notebook

As part of this lab, your group will keep an on-line notebook. An
example notebook appears in the resource section of the class website,
and in the slides for the 9/8 lecture (available on the calendar
website page). Each member should keep a separate notebook,
stored as files (or subdirectories of files) under a global notebook
directory.

Be sure to follow these steps when keeping your notebook:

Open the editor of your choice (emacs, vi, Notepad, Word, ...) and
keep it running while you work. This editor should only be used to
maintain your online notebook.

When starting a new entry, be sure to record the time and date of
that entry. You may type "date" at a unix prompt and copy and paste that
in.

Write down your goal for that entry.

Make notes of any accomplishments, bugs, or insights you may develop
as you work. MAKE SURE YOU CAN UNDERSTAND YOUR OWN NOTES!! Students will
often write an entry that makes sense to them as they write it, but is
incomprehensible a few days later. Write your entry so that you will still
be able to understand it in a month. This will be important in later labs
as you may want to reference back to old labs.

You may want to copy and/or save key waveforms that you get from
simulation.

At the end of the session, record the time and date. Again, you may
type "date" at a unix prompt and copy and paste that in.

The most important thing to put in your design notebook is
documentation of how to do things, where files are, etc. Without
documentation of this kind, your group members may need to find you
(wake you up, force you to come into the lab, etc) in order to
continue working on the project -- perhaps in the middle of the night!

Problem 0d: Source Code Control

For this lab (and all future labs) you should use cvs (a source
code control system). We have included cvs on the instructional
machines in M:\bin\cvs.exe (version 1.11.12). (Watch out, there is
another version of cvs (1.11.5) that has been compiled for cygwin that
is in c:\cygwin\bin. This version will not work if you are not
running in the cygwin environment; it will complain about
windows-style paths. So make sure that you are running the version in
M:\bin.) If you have no idea how to use cvs then feel free to look at
a couple of tutorials on how to use cvs:
one for windows and
one for unix (plus general usage).

We require you to use CVS keyword substitution in your Verilog source
files (don't try to use keywords in things like project files or
schematics, as the keywords are not preserved by the CAD tools). You
should place the keywords at the top of the file. You should
include the author as well as the version number and the check-in
time. We also recommend using either $Id$ or $Header$.

CVS is not perfect -- in some situations, it may damage or lose
files due to corruption issues.

To prevent lost work, be paranoid! Source code control should not be
your only tool to protect the integrity of your project. Back up your
design files at regular intervals, and store them off-site -- for
example, last semester one group sent all of their Verilog to a gmail
account every night, and used the gmail search facility to recover
files.

Problem 0e: ChipScope

In this lab, you will be synthesizing ChipScope into your
Xilinx design, so that you can monitor the operation of
your processor on the board. To learn about ChipScope,
see the "Tutorial For the Xilinx Tool Flow" paper on
the Resources section of the website. You may wish to
do a simple test design using ChipScope at this time, so
that you don't have to learn about it as you are debugging
your processor.

The tool flow tutorial also contains other information about the tools
that may be helpful in Lab 2, and which did not appear in CS 150 lab
lectures. In particular, be sure to read the final section ("5. Tips
and Hints").

Problem 1: Datapath Design

Problem 1a: High-Level Components

The following components are provided for this assignment and future
ones. The Verilog descriptions of these components are located in
the lab 2 directory (M:\lab2).

A description of these components, LAB2_Help, also appears in the
directory.

You may use the MIPSASM program
to transfer MIPS machine code into the memory component, for both
simulation and Xilinx execution.

To use the components,
begin by copying scram.v and C_REG_FD_V6_0.v
to your working directory. Make two new top-level ramblocks, called
"instmem()" and "datamem()" as shown in LAB2_Help.
For your instruction memory, use an initialization file called
"instmem.smallcontents". For your data memory, use a file
called "datamem.smallcontents".

A .smallcontents file consists of up to 128 lines of 8 hexadecimal
characters. Each line of the file will be loaded into the memory in
the order that it appears in the file. (eg. line 1 will be placed in
mem[0], line 2 will be placed in mem[1], etc.) An example file
(example.smallcontents) has been placed in M:\lab2 for your
perusal. It initializes the RAM with ascending numbers beginning at
0. Note that .smallcontents files are used for simulation only.

Problem 1b: Datapath Components

For this first part of the lab, you should design the following components.
Try to divide this work evenly among the various partners in your groups:

extend: sign/zero extender

m16x2, m32x2, m32x3, m32x5, m5x2:
MUXes with various widths and number of inputs.

reg32: 32-bit register

regfile: register file

shifter: arithmetic logical multibit
shifting unit

All the components should be implemented in Verilog. We suggest that you
adhere to standards when building your modules -- it will make your life
easier. Make schematic symbols for each of your high-level components.

For instance, you should do the following:

In all the components the label DOUT refers to the data output, and if
there is only one data input (e.g., reg32), it is called DIN.

If there is more than one data input, they are labeled A, B, C, ....
MUX output selectors are labeled SEL. A is routed to the output when
the select bits represent 0, B when they represent 1, and so on.

Control signals, such as the write enable on reg32, have a suffix H or
L to indicate whether they are active high or active low.

All clock inputs to the modules are called CLK.

All modules that require a clock should be rising-edge triggered (posedge
triggered). Please look through the comments at the beginning of the
Verilog description for the components you have been given.

Problem 1c: Component Unit Test Benches

Design unit test benches (described in the testing lecture) for each
of component listed in Problem 1b. Depending on the complexity of the
component, your test benches may use a mix of random, directed, and
directed random tests. Your directed (or directed random) tests
should test a wide range of corner cases. You may wish to use Verilog
file I/O primitives to log errors caught by your test benches (look at
section 17.2 of the IEEE spec on the resources page).

A test bench for a component should not be written by the person who
wrote that component. Hopefully, the unit test bench author will
think of corner conditions that the designer did not. Note that a
unit test bench is only used during the unit testing phase for a
component, and is not wired into your processor.

Turn in the output from your test benches that illustrate that your
components are working.

Problem 1d: Assemble the Data Path

Using the components listed above, build a single cycle datapath in
Verilog that implements the following subset of MIPS instructions:
addu, addiu, subu, ori, lw, lui, sll, srl, slt, sw, jr, beq (these are a
subset of the instructions you used in Lab #1--you will implement the remainder
during lab 3). Note that the CPU design in this lab does not use delay slots
(i.e. branch delay slots, jump delay slots, or load delay slots).
Make sure that your design is clean -- you will be breaking it apart
to build a pipelined processor in future assignments. At this time, do
not implement the PC and the instruction memory.
Note that unlike commercial implementations, your processor does not
implement exception handling. So, if an instruction other than the
ones listed above appears in the instruction stream, what your
processor does is undefined by this spec (a practical option is to
treat undefined instructions as no-ops).

Problem 1e: Test the Data Path

This file is a top-level Verilog file that instantiates your datapath,
along with a test bench. Conceptually, the test bench is a single
initial block with an inline list of test cases. In practice,
it may be cleaner to use file I/O for test data from separate files.

The test bench drives the datapath control signals, the instruction
value, and in some cases, the result signals (the destination
register, the equal? signal, etc). Each of these test cases takes the
form:

Turn in a copy of your multi-unit test bench, and a log of your
simulation showing that the instructions worked. The objective of this
problem is to make sure that you have all the parts of the datapath in
place to execute all the instructions, and that you have a clear idea
of what the control signals have to be for each instruction.

Problem 2: Verilog Controller for the Datapath

Problem 2a: Building the Controller

In this section, you will build the controller for your datapath. You
will use Verilog to create the control module. Label the pins of the
control module appropriately, and connect it to the datapath you
built in problem 1. This controller receives the bits from the
32-bit instruction as input, and uses a combinational circuit to
generate the control signals.

Also, add the instruction memory, PC, and the next instruction logic
to your design, by modifying your schematic.

Problem 2b: The Disassembly Monitor Module

Next, build a special Verilog entity that takes as input the clock, the
instruction address, the output of the instruction memory, the output of
the registers, and the destination register. This will be a monitor
module which will monitor the execution your processor. It should
output information in textual format, using the "$display" statement or
using file I/O to output to a diagnostic trace file. In the interests
of making grading and checkoff easier, we are asking everybody to have
the exact same monitor module format. Please follow the format below:

Your monitor should be able to disassemble the complete set of
instructions above and print out the course of execution. This
monitor will show you in graphical form that your processor is "doing
the right thing". It should print a new line at the falling edge
of the clock (this is the only thing that should run off the negedge).
Note that $display statements are much like C printf() statements, and
include support string formatting.

Design your monitor module in a flexible and structured way; later in
the term, you will modify the module to add pipelining support.

Note that this module is used in simulation only. You should
instantiate the monitor module in your complete processor test bench,
not in your processor Verilog file. Use Verilog's hierarchal
referencing feature to access registers/wires of the processor from
the test bench. We prefer this method over "hardwiring" the monitor
module into the processor, because the more you edit your processor
Verilog post-simulation (to "un-hardwire" the monitor), the greater
the odds of introducing new bugs on the way to the Calinx board!

Problem 2c: Top-level Driver

Wire together your datapath, control path, and memory modules. Make
sure to keep track of the instance names for your
memory modules. These will form a complete path that you can use
in the simulator to examine memory during simulation.

For instance, let's say that you called the scram in yourinstmem() module "tempBlock" and then called the
block "MyInstMem" at the data path level. Then, you
will be able to refer to the memory block as
"MyInstMem/tempBlock/inst/ram_data" in ModelSim. Note
that the middle "inst" and "ram_data" pieces are not under
your control (they are inside the "scram" and "
C_DIST_MEM_V6_0" blocks.

Also assemble a "processor with self-checks" module at this time. The
module may be simple, and check for conditions that should never happen
in the datapath and control (easy to do), or may be more sophisticated
and check aspects of correctness. Don't over-do it: it is easy to add
more checks to a well-written "processor with self checks". However, it
is harder to create one from scratch after debugging begins, which is
why we recommend you do it now.

Make a top-level testing module to drive your processor. Make it easy
to switch between you "normal" processor and your self-checking
processor. Remember to instantiate your monitor module into the
testing module.

The top-level testing module should have a clearly-defined clock
generator defined as an always loop with a delay statement (like
#100). For example:

always
begin
#clock-half-period
CLK = ~CLK;
end

Problem 2d: Debugging the Processor

Follow the directions in LAB2_Help for loading your memory
blocks into simulation. (The loader may have problems if your initial
clock phase is a "1" -- if so, try initializing your clock to
"0"). Recall that in 1a we made the memory contents be
"instmem.smallcontents" and
"datamem.smallcontents". You should be able to go into the
command mode of ModelSim to set breakpoints at points of your clock
cycle and thereby step cycle by cycle.

Write a suite of test programs to run on your "complete processor
testing" and "processor testing with self-checks" test bench.
You may reuse code from the programs you wrote in Lab 1. However,
remember that a single cycle processor does not have delay
slots, and you have not implemented the complete subset of
instructions from Lab 1. In later Labs, you will be adding more
instructions to your processor and will be able to use all of the code
from Lab 1.

Note that unlike spim, your ModelSim simulation won't be able to
show the contents of the registers in a constantly updating GUI.
However, you may use ModelSim to monitor waveforms.

Turn in a copy of your Verilog code, a schematic drawing of your
datapath (to assist the TAs in understanding your design), test bench
Verilog, your mini-MIPS test program suite, a simulation log that
shows the correct execution of the program, and your Design Notebooks.

Problem 3: Pushing to Board

After you have finished debugging your processor it is time to push to
board. You will have to generate a special ram file for use on board,
see LAB2_Help.pdf for more information on how to do this.

You may be wondering how to determine if your processor actually works
on the board. You should use ChipScope to inspect the register file as
the program runs to figure out what is happening. In particular your
ChipScope module should trigger on the PC and capture the status of
registers 1 to 6 in your register file as well as the output from the
instruction register. You may use other ChipScope modules to debug
your processor, but you should have at least one setup in this manner
so that you can be checked off.

Note that you will need to directly add ChipScope to your processor
Verilog, and this will impact your ability to go back and do more
ModelSim simulation. If possible, add ChipScope to your processor
in a way that minimizes the amount of hand-editing needed to enable
and disable ChipScope.

You should not have to worry about your clock rate, because the
clock that we are providing you with has a frequency of several
hundred KHz.

You should use the MIPSASM tool
to generate synchronous write / asynchronous read RAM data for use on
the board (you can find these options under "Advanced"). Define a
flow to incorporate the output of this program into your processor
that is resistant to manual errors (copy/paste into a Verilog file may
be inevitable, but a file should be dedicated to this purpose, so
that editing bugs do not wreak havoc with your design files!).

Problem 4: Critical Path

Investigate the performance of this processor. Find the critical
path for your processor. What would happen if you run your processor
such that your clock rate was faster than your critical path? How
do you think it would fail? Try it to test your hypothesis.

Final Step: Lab Report

Please turn in a lab report that is easy to read. Think about
the document structure before you start assembling it.
If you have really complicated listings or schematics, you
should include them in an appendix. Make sure to discuss the
execution of your test plan in detail. Also, turn in a copy of your
laboratory notebook.