Lab 08
Lab 08
Lab 08
Introduction
In this lab you will build the MIPS single-cycle processor using Verilog. You will combine your ALU from Lab 5 with the code for the rest of the processor taken from the textbook. Then you will load a test program and check that the instructions work. Next, you will implement two new instructions, then write a new test program that confirms the new instructions work as well. By the end of this lab, you should thoroughly understand the internal operation of the MIPS single-cycle processor. Please read and follow the instructions in this lab carefully. In the past, many students have lost points for silly errors like not printing all the signals requested. Before starting this lab, you should be very familiar with the single-cycle implementation of the MIPS processor described in Section 7.3 of your text, Digital Design and Computer Architecture. The single-cycle processor schematic from the text is repeated in Figure 1 for your convenience. This version of the MIPS single-cycle processor can execute the following instructions: add, sub, and, or, slt, lw, sw, beq, addi, and j. Our model of the single-cycle MIPS processor divides the machine into two major units: the control and the datapath. Each unit is constructed from various functional blocks. For example, as shown in the figure on the last page of this lab, the datapath contains the 32bit ALU that you designed in Lab 5, the register file, the sign extension logic, and five multiplexers to choose appropriate operands.
Page 1 of 10
controller module. Correlate signal names in the Verilog code with the wires on the schematic. After you have thoroughly understood the controller module, take a look at the datapath Verilog module. The datapath has quite a few submodules. Make sure you understand why each submodule is there and where each is located on the MIPS single-cycle processor schematic. Youll notice that the alu module has a question mark by it in the Sources window in Xilinx. You will need to add your Verilog module from lab 5. Do so by choosing ProjectAdd Copy of Source and add your alu module. Be sure the module name matches the instance module name (alu), and make sure the inputs and outputs are in the same order as in they are expected in the datapath module. The highest-level module, top, includes the instruction and data memories as well as the processors. Each of the memories is a 64-word 32-bit array. The instruction memory needs to contain some initial values representing the program. The most convenient way to create a memory with initial values is with Xilinxs Core Generator.
2. A Test Program
We will use the following simple program to test that basic instructions work:
# test1.asm # 23 October 2005 David Harris [email protected] # # Test MIPS instructions. #Assembly Code # Machine Code
main:
around:
end:
addi addi addi or and add beq slt beq addi slt add sub j lw sw
$2, $7, $3, $4, $5, $5, $5, $6, $6, $5, $6, $7, $7, end $7, $7,
$0, $0, $0, $7, $3, $5, $7, $3, $0, $0, $7, $6, $7,
0($0) 71($2)
# # # # # # # # # # # # # # # #
20020005 20070003 2003000c 00e22025 00642824 00a42820 10a70008 0064302a 10c00001 2005000a 00e2302a 00c53820 00e23822 0800000f 8c070000 ac470047
Figure 1. MIPS assembly program: test1.asm This code can be found in the supplementary lab material provided on the textbook website under the Lab08 directory. To use this test code, it must be loaded into the MIPS instruction memory. It would be nice to be able to write Verilog code for a memory with some initial values (the test
Page 2 of 10
program), but Synplify Pro and Xilinx do not support this very well yet. Instead, we will use the Xilinx Core Generator feature to produce a memory with initial values. The instruction memory, imem, will be constructed as a CoreGen ROM that will hold the program (the instructions) to execute. Create the ROM by choosing Project->New Source. Select the source type to be IP(CoreGen and Architecture Wizard) and name your memory imem. You can use CoreGen to generate different kinds of modules. In this case, choose Memories and Storage ElementsRAMs & ROMsDistributed Memory. Click NextFinish. It will now ask you to enter the component name (imem), depth (64), width (32) etc. Choose ROM type memory and make sure none of the inputs or outputs are registered. On the left side, a diagram of the symbol will be shown. A is the 6-bit address and SPO is the 32-bit data output. Notice that only a subset of the PC bits (PC7:2) will be used to address the memory. Be sure you understand thoroughly why only these bits are used. When finished, you can click Generate on the lower left corner, and a memory component will be generated and listed in the Generated Modules in the CORE generator. At the same time, a symbol with the same name will be available for use in your Verilog files. To load the ROM with instructions, you need to use Memory Editor in the CORE generator interface to input the contents of the ROM. To do so, highlight your CORE generated module (i.e. imem) in the Sources in Project window in your main Project Navigator window. Then, under the Processes for Source window, expand the Coregen option and double-click on Manage Cores. Choose ToolsMemory Editor, and you will see a window like the one shown in Figure 2. In the case of instruction memory, you will define a 64 word (although you will only use 16 of the available words) 32 bit memory.
Page 3 of 10
Click on Add Block to enter the Memory Block Name. Name it imem. Enter the Depth as 64 and the Data Width as 32. Make sure the Radix for the Data is 16 (i.e. hexadecimal). Under Configure COE File Parameter Names, choose MEMORY_INITIALIZATION_RADIX for Radix and MEMORY_INITIALIZATION_VECTOR for Data. Now enter the instruction codes (given in Figure 2) into the contents of the ROM. For example instruction 20020005 is entered at Address 00 (Indicated as row Address 00, offset +0 in the window) in the ROM, instruction 20070003 is at Address 01, and so forth. The first three entries in the ROM are shown in Figure 4. The full set of entries is given in Figure 1. It is worth proofreading your entries because any typos will be very tedious to debug later. When you finish entering all the machine instructions at the corresponding addresses, save your memory configuration by choosing FileSave Memory Definition. Now choose FileGenerate to generate a .coe file that can be read by CoreGen. Click on the top option, COE File(s), and click OK. It should now inform you that defintion1_imem.coe has been generated. This file can be imported later to set up the complete 64 word 32 bit instruction ROM. Now close the Memory Editor. You can now exit from the Memory Editor window by choosing FileExit. The main Core Generator window should still be open. Click on the Generated IP tab in the main window. Now right-click on imem and select: RecustomizeUnder Current Project Settings. Click twice. In the last window, select Load Coefficients, and click on Load File. This will bring up a window that will allow you to browse for your .coe file that holds the definition of your ROM contents. Highlight the file and click Open. Then click Show Coefficients Next to spot-check that they match your expectations. Now complete the setting of the ROM by clicking the Generate button. By doing so, the ROM imem is created with the stored instructions you entered and a template with the same name will also be ready to use in Verilog files. When you view the imem module in your Processes in Source window, there should now no longer be a question mark next to it. If there is still a question mark, you need fix your errors. You can edit your core generated module by double-clicking on it. You can also look at the equivalent Verilog code by choosing CoreGenView Verilog Functional Model.
3. Synthesis
Synthesize the highest level module, top. Notice that the only necessary inputs to the highest level module are clk and reset. The other signals are there for verification purposes only. View the synthesis report. There should be no errors or warnings (you can confirm this by looking at the errors tab at the bottom of the screen). View the RTL schematic. resynthesize. If it does not look as you expected, fix the errors and
Page 4 of 10
After you have fixed any bugs, print out your final waveform.
$t0, $0, 0x8000 $t1, $0, -32768 $t2, $t0, 0x8001 $t0, $t1, there $t3, $t1, $t0 $t3, $0, here there $t2, $t2, $t0 $t0, $t0, 0xFF $t3, $t3, $t2 $t0, $t2, $t0 $t0, 82($t3)
Figure 3. MIPS assembly program: test2.asm test2.asm can be found in the supplementary lab material on the textbook website under the Lab08 directory. Again, for debugging, you might find it useful to make other signals from sub-modules visible in the ModelSim waveform. However, in the final waveform that you turn in, only include the following signals in this order: clk, reset, pc, instr, aluout, writedata, memwrite, and readdata, in that order. Make sure all your waveforms are readable and show values in hexadecimal.
Page 6 of 10
What to Turn In
Please turn in each of the following items, clearly labeled and in the following order: 1. Please indicate how many hours you spent on this lab. This will not affect your grade, but will be helpful for calibrating the workload for next semesters labs. 2. A completed version of Table 1. 3. Marked up versions of the datapath schematic and decoder tables that adds the ori and bne instructions. 4. A printout of your Verilog code for your modified MIPS computer (including ori and bne functionality) with the changes highlighted: 5. Simulation waveforms of: top.v for test1.asm top.v for test2.asm (with your modified single-cycle MIPS processor)
The simulation waveforms should give the signal values in hexadecimal format and should be in the following order: clk, reset, pc, instr, aluout, writedata, memwrite, and readdata. Do not display any other signals in the waveform. Be sure the waveforms match your expectations. Check that the waveforms are zoomed out enough that the grader can read your bus values. Unreadable waveforms will receive no credit. Use several pages as necessary.
Page 7 of 10
Cycle 1 2 3 4 5 6 7 8 9 10 11 12 13 14
reset 1 0 0 0
pc 00 04 08 0C
instr addi $2,$0,5 20020005 addi $7,$0,3 20070003 addi $3,$0,0xc 2003000c
branch 0 0 0
srca 0 0 0
srcb 5 3 12
aluresult 5 3 12
zero 0 0 0
pcsrc 0 0 0
write data x
mem write 0
read data 0 0
Table 1. First fourteen cycles of executing assembly program test1.asm Remember, branch is asserted (1) when the instruction is a branch (beq) instruction. aluout is the output of the ALU at each cycle. zero is high (1) only if aluout is 0. pcsrc, a signal in the datapath, is low (0) when nextpc should be pc+4. pcsrc is high (1) when the nextpc should be the branch target address (pcbranch). You will notice that all of these signals are not available from the top-level module (mips). For debugging, you might want to look at these signals and others.
Page 8 of 10
Jump
31:26 5:0
MemtoReg Control MemWrite Unit Branch ALUControl2:0 Op Funct ALUSrc RegDst RegWrite
PCSrc
CLK A1 A2 A3 WD3
20:16
CLK WE3 RD1 RD2 Register File 0 WriteReg4:0 1 SrcA Zero ALUResult A WE RD Data Memory WD ReadData 0 Result 1
Instruction Memory
20:16
0 SrcB 1
WriteData
PCJump PCPlus4 4
27:0 31:28
15:11
ImmExt
15:0
Sign Extend
<<2 PCBranch
25:0
<<2
Page 9 of 10
Page 10 of 10