MIPS Single-cycle Processor
MIPS Single-cycle Processor
Assignment Outline
This assignment is to test your understanding of the MIPS-Lite single-cycle processor design presented in the lectures.
A sample Verilog code is available at Appendix A. You will need to add an Instruction memory to the design and initialise it with your assembly code. The procedure for process is given in the Appendix B.
Currently the memory initialization file of the instruction memory ROM is empty. You can write the machine code of your instructions into the memory locations of the initialisation file.
The assignment is to be undertaken in a series of steps which you should complete in order. To ensure that it is your own work that is being assessed, Appendix C shows the specific requirements for each student.
Appendix C: Requirements
Memory locations (X,Y,Z,T)
Data bus size
Design
6,7,1,2
24
Ori
1. Write a programme to: [15 Marks]
a. Load the data stored in the X and Y locations of the data memory into the X and Y registers.
b. Add the X and Y registers and store the result in the Z register.
c. Store the data from the Z register into the Z memory location.
d. Load the data in the Z memory location into the T register.
2. Simulate your program to show the contents of the X, Y, and T registers. [10 Marks]
3. Modify the program.mif file to simulate the operation of the BEQ instruction. [10 Marks]
4. Modify the design of the processor so that the Jump (J) instruction is implemented. [15 Marks] Modify the program.mif file to simulate the operation of the Jump instruction. [10 Marks]
5. Modify the designs so that the additional instructions given in the column “Design 1” is correctly executed. [15 Marks]
6. Modify the program.mif file to simulate the operation of the additional instruction. [10 Marks]
7. Change the processor’s data bus width from 32 to the one indicated in the table. Repeat the simulation of step 2 using your new processor. [15 Marks]
MIPS instructions’ reference data is provided.
Reports
Your report should include the following contents:
1. The MIPS code and how the corresponding machine code is decided.
2. Simulation waveforms for the PC, opcode, ALUResultOut, DReadData and relevant registers (X, Y, T) must be annotated. You should clearly indicate why the simulations show that the operation is correct or incorrect.
2. Description of the modifications made to the Verilog code for implementing the Jump instruction. Highlight the changes made in the code.
3. Description of the modifications made to implement the additional instruction. Highlight the changes made in the code.
4. Description of the modifications made to change the data bus width.
Appendix A
// MIPS single Cycle processor originaly developed for simulation by Patterson and Hennesy
// Modified for synthesis using the QuartusII package by Dr. S. Ami-Nejad. Feb. 2009
// Register File
module RegisterFile (Read1,Read2,Writereg,WriteData,RegWrite, Data1, Data2,clock,reset);
input [4:0] Read1,Read2,Writereg; // the registers numbers to read or write
input [31:0] WriteData; // data to write
input RegWrite; // The write control
input clock, reset; // The clock to trigger writes
output [31:0] Data1, Data2; // the register values read;
reg [31:0] RF[31:0]; // 32 registers each 32 bits long
integer k;
// Read from registers independent of clock
assign Data1 = RF[Read1];
assign Data2 = RF[Read2];
// write the register with new value on the falling edge of the clock if RegWrite is high
always @(posedge clock or posedge reset)
if (reset) for(k=0;k<32;k=k+1) RF[k]<=32'h00000000;
// Register 0 is a read only register with the content of 0
else if (RegWrite & (Writereg!=0)) RF[Writereg] <= WriteData;
endmodule
//ALU Control
module ALUControl (ALUOp, FuncCode, ALUCtl);
input [1:0] ALUOp;
input [5:0] FuncCode;
output [3:0] ALUCtl;
reg [3:0] ALUCtl;
always@( ALUOp, FuncCode)
begin
case(ALUOp)
2'b00: ALUCtl = 4'b0010;
2'b01: ALUCtl = 4'b0110;
2'b10: case(FuncCode)
6'b 100000: ALUCtl = 4'b 0010;
6'b 100010: ALUCtl = 4'b 0110;
6'b 100100: ALUCtl = 4'b 0000;
6'b 100101: ALUCtl = 4'b 0001;
6'b 101010: ALUCtl = 4'b 0111;
default: ALUCtl = 4'b xxxx;
endcase
default: ALUCtl = 4'b xxxx;
endcase
end
endmodule
//ALU
module MIPSALU (ALUctl, A, B, ALUOut, Zero);
input [3:0] ALUctl;
input [31:0] A,B;
output [31:0] ALUOut;
output Zero;
reg [31:0] ALUOut;
assign Zero = (ALUOut==0); //Zero is true if ALUOut is 0
always @(ALUctl, A, B) begin //reevaluate if these change
case (ALUctl)
0: ALUOut <= A & B;
1: ALUOut <= A | B;
2: ALUOut <= A + B;
6: ALUOut <= A - B;
7: ALUOut <= A < B ? 1:0;
// .... Add more ALU operations here
default: ALUOut <= A;
endcase
end
endmodule
// Data Memory
module DataMemory(Address, DWriteData, MemRead, MemWrite, clock, reset, DReadData);
input [31:0] Address, DWriteData;
input MemRead, MemWrite, clock, reset;
output [31:0] DReadData;
reg [31:0] DMem[7:0];
assign DReadData = DMem[Address[2:0]];
always @(posedge clock or posedge reset)begin
if (reset) begin
DMem[0]=32'h00000005;
DMem[1]=32'h0000000A;
DMem[2]=32'h00000055;
DMem[3]=32'h000000AA;
DMem[4]=32'h00005555;
DMem[5]=32'h00008888;
DMem[6]=32'h00550000;
DMem[7]=32'h00004444;
end else
if (MemWrite) DMem[Address[2:0]] <= DWriteData;
end
endmodule
// Main Controller
module Control (opcode,RegDst,Branch,MemRead,MemtoReg,ALUOp,MemWrite,ALUSrc,RegWrite);
input [5:0] opcode;
output [1:0] ALUOp;
output RegDst,Branch,MemRead,MemtoReg,MemWrite,ALUSrc,RegWrite;
reg [1:0] ALUOp;
reg RegDst,Branch,MemRead,MemtoReg,MemWrite,ALUSrc,RegWrite;
parameter R_Format = 6'b000000, LW = 6'b100011, SW = 6'b101011, BEQ=6'b000100;
always @(opcode)begin
case(opcode)
R_Format:{RegDst,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,ALUOp}= 9'b 100100010;
LW: {RegDst,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,ALUOp}= 9'b 011110000;
SW: {RegDst,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,ALUOp}= 9'b x1x001000;
BEQ: {RegDst,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,ALUOp}= 9'b x0x000101;
// .... Add more instructions here
default: {RegDst,ALUSrc,MemtoReg,RegWrite,MemRead,MemWrite,Branch,ALUOp}= 9'b xxxxxxxxx;
endcase
end
endmodule
// Datapath
module DataPath(RegDst, Branch, MemRead, MemtoReg, ALUOp, MemWrite,
ALUSrc, RegWrite, clock, reset, opcode,/* RF1, RF2, RF3,*/ALUResultOut ,DReadData);
input RegDst,Branch,MemRead,MemtoReg,MemWrite,ALUSrc,RegWrite,clock, reset;
input [1:0] ALUOp;
output [5:0] opcode;
output [31:0] /*RF1, RF2, RF3,*/ ALUResultOut ,DReadData;
reg [31:0] PC, IMemory[0:31];
wire [31:0] SignExtendOffset, PCOffset, PCValue, ALUResultOut,
IAddress, DAddress, IMemOut, DmemOut, DWriteData, Instruction,
RWriteData, DReadData, ALUAin, ALUBin;
wire [3:0] ALUctl;
wire Zero;
wire [4:0] WriteReg;
//Instruction fields, to improve code readability
wire [5:0] funct;
wire [4:0] rs, rt, rd, shamt;
wire [15:0] offset;
//Instantiate local ALU controller
ALUControl alucontroller(ALUOp,funct,ALUctl);
// Instantiate ALU
MIPSALU ALU(ALUctl, ALUAin, ALUBin, ALUResultOut, Zero);
// Instantiate Register File
RegisterFile REG(rs, rt, WriteReg, RWriteData, RegWrite, ALUAin, DWriteData,clock,reset);
// Instantiate Data Memory
DataMemory datamemory(ALUResultOut, DWriteData, MemRead, MemWrite, clock, reset, DReadData);
// Instantiate Instruction Memory
IMemory IMemory_inst (
.address ( PC[6:2] ),
.q ( Instruction )
);
// Synthesize multiplexers
assign WriteReg = (RegDst) ? rd : rt;
assign ALUBin = (ALUSrc) ? SignExtendOffset : DWriteData;
assign PCValue = (Branch & Zero) ? PC+4+PCOffset : PC+4;
assign RWriteData = (MemtoReg) ? DReadData : ALUResultOut;
// Acquire the fields of the R_Format Instruction for clarity
assign {opcode, rs, rt, rd, shamt, funct} = Instruction;
// Acquire the immediate field of the I_Format instructions
assign offset = Instruction[15:0];
//sign-extend lower 16 bits
assign SignExtendOffset = { {16{offset[15]}} , offset[15:0]};
// Multiply by 4 the PC offset
assign PCOffset = SignExtendOffset << 2;
// Write the address of the next instruction into the program counter
always @(posedge clock ) begin
if (reset) PC<=32'h00000000; else
PC <= PCValue;
end
endmodule
module MIPS1CYCLE(clock, reset,opcode, ALUResultOut ,DReadData);
input clock, reset;
output [5:0] opcode;
output [31:0] ALUResultOut ,DReadData; // For simulation purposes
wire [1:0] ALUOp;
wire [5:0] opcode;
wire [31:0] SignExtend,ALUResultOut ,DReadData;
wire RegDst,Branch,MemRead,MemtoReg,MemWrite,ALUSrc,RegWrite;
// Instantiate the Datapath
DataPath MIPSDP (RegDst,Branch,MemRead,MemtoReg,ALUOp,
MemWrite,ALUSrc,RegWrite,clock, reset, opcode, ALUResultOut ,DReadData);
//Instantiate the combinational control unit
Control MIPSControl (opcode,RegDst,Branch,MemRead,MemtoReg,ALUOp,MemWrite,ALUSrc,RegWrite);
endmodule
Appdendix B
Inserting LPM ROM
Select MegaWizard Plug-In Manager from the tools menu and click on the Next button.
Select the ROM: 1-PORT and give a name to the output file. This name should be the same as the one which has been used for Instruction memory instantiation in your Verilog code.
Select the width and depth of the memory.
Deselect the input and output registers.
Give a name to the memory initialisation file, e.g. Instruction.mif. You can use your name as the file name. In this case you should edit the Verilog module name in the provided code.
Deselect the creation of the optional files and click on Finish button.
Click on the New icon and select the Memory Initialization File.
Input 32 for the Number of words and 32 for the Word size.
Now you can insert your machine code into the Instruction memory locations. You should be noted that this memory is not byte oriented and addresses are incremented by one not by 4.