This project is due November 14.
This is an individual assignment; you must work alone. Submit your solution, files named
ALUControl.v as proj4.
We will be testing your solution in ModelSim using a variety of testbenches.
We will also be examining your solution for use of forbidden behavioral Verilog
constructs, for example, always, initial, and $display; occurrences of these constructs
in your submitted modules will lose you a significant amount of points. Please read the Verilog
Circuit Rules carefully.
Finally we will be running the autograder (or at least a subset of it) at least
once on solutions submitted early. This will be our chance to test the autograder
and your chance to test the project. We are hoping to run the autograder on
Nov 7th, and e-mail you the logs, allowing you an extra chance to debug your code.
Copy the directory contents of ~cs61c/files/proj/4 to ~/proj4 or some other
It includes several files: CPU.v,
Blocks.v, shells for the modules you must implement
and several data files for testing your code.
These are described below.
Appropriate background material is found in sections 5.1-5.4 and C.1-C.2 in P&H.
In this project you implement, in Verilog, and simulate a simple MIPS processor.
You will build the datapath from a library of predesigned blocks
and the controller from primitive gates.
Your implementation will be done in structural Verilog. Below
is a specific list of the allowed Verilog constructs for the circuits in this project.
You are not allowed to use any behavioral constructs (always or initial) except in the testbench. You
will find a list of the generally disallowed Verilog constructs in the
Verilog Circuit Rules. You will find a partial list of allowed constructs on the
Verilog Green Card. Note that some of the blocks we have given you
are written in ways which make them invalid circuits, and so are not good examples
for your code. Following are the allowed
constructs for this project:
The motivation behind this project is to help you understand the
detailed operation of processors. Processor implementations are complex,
even the simple MIPS; a good understanding of their operation comes only
after the experience you will gain by implementing and simulating a
processor for yourself. By understanding the
inner workings of a processor, you will become far better equipped to understand
operating systems, compilers, computer architecture, parallel programming, and in
general this will help you be a better programmer, even if you never design another
This project is based on the design presented in chapter 5 of P&H.
Except for a few simple modifications, mentioned below, your
implementation should match the one presented in the book.
You will design a module named CPU whose parameters are as follows:
module CPU(Clock, Reset, Break, BreakCode, Dump);
input Clock, Reset, Dump;
output [19:0] BreakCode;
Clock and Reset are the clock and reset signals; use of Reset
is described in
the "Sub-blocks" section. Break is asserted when the break instruction is
encountered (see below). Dump should be connected to the
Memory and RegFile
modules (see the "Sub-blocks" section).
Your processor must correctly execute the
lw, sw, beq, and, or, addu,
subu, slt, j, jal, jr, lui,
ori, and break instructions.
j, jal, jr, lui,
ori, and break are not part of the design of P&H Figure 5.17; the
addition of a jump to the design is described on P&H pages 313 and 314.
The break instruction simplifies testing the processor. The break
instruction is listed on the back of the green card, in Appendix A of P&H and
in the MARS (mars-cs61c) help. The break instruction has a opcode of 6'b000000, and a funct field 6'b001101
and the 20bits in the middle
should be output on the BreakCode output of your CPU.
Upon execution of the break instruction, your processor will
simply assert the Break port on the CPU module, output the middle 20bits of the break
instruction on the BreakCode output of CPU.v and stop executing. The testbench module will
use this signal to dump memory and stop the simulation.
We provide you with a file Blocks.v that contains
behavioral Verilog definitions for modules that you can use for some of the blocks shown in P&H Figure 5.17. (The section "Sub-blocks" below
provides some details about the modules in this file.) The exceptions
are the blocks labeled Control,
ALUControl and ALU, which you will have to implement
for yourself using primitive gates or 1-bit assign statements (which are trivially equivalent to primitive gates).
See section C.2 (in the appendix)
for additional information on the control blocks. Note that you may make any necessary
changes to the code in Control.v including adding ports or changing port widths, but you should not need to change the
ports on CPU.v,
ALUControl.v. Let us know if you think otherwise, we are open to new ideas. Finally, beware of relying
strictly on Appendix C of P&H, as we are implementing a slightly different instruction
set (e.g. addu instead of add).
Consider implementing and testing the break instruction before you work on anything
else. You should also write testbenches for all of the modules you implement,
not just the complete ALU.
The basic strategy for running programs on your simulated processor is as follows.
At startup the contents of both the instruction and data
memories are read from files by the Verilog runtime system. Simulated
processor execution proceeds until a break instruction is executed, at
which point the data memory is dumped to a different file. You can then
inspect the file to see if the program executed correctly. Of course,
this scenario assumes that all is well with your processor. For debugging, you should display internal signals of your circuit in the
ModelSim Wave window as described in the ModelSim Tutorial.
There are several files in the ~cs61c/files/proj/4 directory that you may
find useful for testing your simulation.
Consider writing a program with a single break instruction for your first test. You will do this in lab10.
You can use the break instruction, with a code, to help debug the control
flow of a program with multiple jumps if you want. For example, by putting
several break instructions with different BreakCode values
into your program, you can easily see as a result of the $display in
our CPUTestBench.v what the BreakCode is, telling you
which break instruction you reached. You might find this helpful
when writing your test code.
For this project you are implementing exactly the same instructions as proj3,
with the exceptions of bne, sll, srl, andi and addiu which
were implemented for proj3 but not proj4. Note
that this project includes initialized data memory, so you can use the .data directive
The file inc-loop-test.s contains a simple test program.
The hex listing of the machine code was copied into the file
with the hex listing of the data in
inc-loop-test.data. Together these can be
used for simulation
The file lw-sw-test.s tests the lw and sw instructions.
The file simple-beq-test.s tests lw, sw, and beq.
The file simple-rfmt-test.s tests R-format instructions.
The tests in this files will probably not reveal all your bugs.
In particular, they contain only instructions implemented in Figure 5.17 of P&H.
You can create your own test files by loading .s files into MARS (mars-cs61c)
and then clicking the "Save Dump" button as you did for proj3,
sure to select the .text or .data segment as appropriate, and the Hexadecimal Listing format
before dumping. If you wish to dump files for your proj3, you should use the Binary format. Also, do not forget to terminate your programs with a break instruction.
These files will be read in by the RAM and ROM modules in
Blocks.v. See the "Sub-blocks"
section below for more information.
In CPUTestBench.v you will find the basic testbench which we will be using to autograde your project.
Feel free to use it as a starting point for writing your own testbenches.
Note that you will need to name your test files properly, as the Memory and ROM
modules always load their contents from certain filenames. See below for more
The file Blocks.v contains behavioral
definitions of the modules that you should instantiate to implement your
processor. Although these could have been implemented at the gate level,
we have used behavioral constructs to speed up the simulation. The
comments preceding each module describe its operation. In particular,
notice the various uses of the Dump and Reset signals:
The RAM module initializes data memory from the file named dump.data when
Reset is asserted. It dumps memory to the file dump.out when
asserted. You can generate the dump.data files by loading
a .s file into mars-cs61c and dumping the .data segment in the Hex Listing format. Note that the
dump.* files must be in the same directory as your ModelSim
project (where the vsim.wlf and transcript files are).
The ROM module initializes instruction memory (which is read-only) from
the file named dump.text when Reset is asserted. You can generate these files by loading a .s file into
and dumping the .text segment in the Hex Listing format.
Note that the dump.* files must be in the same directory as your ModelSim
project (where the vsim.wlf and transcript files are).
The machine code dumped by MARS will start at address 0 in the instruction memory,
meaning that your PC should start at 0.
The RegFile module dumps registers to the console when Dump is asserted.
Submit the Verilog files CPU.v, ALU.v, Control.v
and ALUControl.v that contains your CPU module, the ALU and the
control modules. We will instantiate and test your CPU module as shown
above in the testbench in CPUTestBench.v. Make sure that the port names in your module
match those used above, and that you haven't used any forbidden Verilog constructs.