module alu(ctl, a, b, result, zero);
input [2:0] ctl;
input [31:0] a, b;
output [31:0] result;
output zero;
reg [31:0] result;
reg zero;
always @(a or b or ctl)
begin
case (ctl)
3'b000 : result = a & b; // AND
3'b001 : result = a | b; // OR
3'b010 : result = a + b; // ADD
3'b110 : result = a - b; // SUBTRACT
3'b111 : if (a < b) result = 32'd1;
else result = 32'd0; //SLT
default : result = 32'hxxxxxxxx;
endcase
if (result == 32'd0) zero = 1;
else zero = 0;
end
endmodule
module add32(a, b, result);
input [31:0] a, b;
output [31:0] result;
assign result = a + b;
endmodule
module alu_ctl(ALUOp, Funct, ALUOperation);
input [1:0] ALUOp;
input [5:0] Funct;
output [2:0] ALUOperation;
reg [2:0] ALUOperation;
// symbolic constants for instruction function code
parameter F_add = 6'd32;
parameter F_sub = 6'd34;
parameter F_and = 6'd36;
parameter F_or = 6'd37;
parameter F_slt = 6'd42;
// symbolic constants for ALU Operations
parameter ALU_add = 3'b010;
parameter ALU_sub = 3'b110;
parameter ALU_and = 3'b000;
parameter ALU_or = 3'b001;
parameter ALU_slt = 3'b111;
always @(ALUOp or Funct)
begin
case (ALUOp)
2'b00 : ALUOperation = ALU_add;
2'b01 : ALUOperation = ALU_sub;
2'b10 : case (Funct)
F_add : ALUOperation = ALU_add;
F_sub : ALUOperation = ALU_sub;
F_and : ALUOperation = ALU_and;
F_or : ALUOperation = ALU_or;
F_slt : ALUOperation = ALU_slt;
default ALUOperation = 3'bxxx;
endcase
default ALUOperation = 3'bxxx;
endcase
end
endmodule
//-----------------------------------------------------------------------------
// Title : MIPS Single-Cycle Control Unit
// Project : ECE 313 - Computer Organization
//-----------------------------------------------------------------------------
// File : control_single.v
// Author : John Nestor
// Organization : Lafayette College
//
// Created : November 2002
// Last modified : 7 January 2005
//-----------------------------------------------------------------------------
// Description :
// Control unit for the MIPS pipelined processor implementation described
// Section 6.3 of "Computer Organization and Design, 3rd ed."
// by David Patterson & John Hennessey, Morgan Kaufmann, 2004 (COD3e).
//
// It implements the function specified in Figure 6.25 on p. 401 of COD3e.
//
//-----------------------------------------------------------------------------
module control_pipeline(opcode, RegDst, ALUSrc, MemtoReg, RegWrite, MemRead, MemWrite, Branch, ALUOp);
input [5:0] opcode;
output RegDst, ALUSrc, MemtoReg, RegWrite, MemRead, MemWrite, Branch;
output [1:0] ALUOp;
reg RegDst, ALUSrc, MemtoReg, RegWrite, MemRead, MemWrite, Branch;
reg [1:0] ALUOp;
parameter R_FORMAT = 6'd0;
parameter LW = 6'd35;
parameter SW = 6'd43;
parameter BEQ = 6'd4;
always @(opcode)
begin
case (opcode)
R_FORMAT :
begin
RegDst=1'b1; ALUSrc=1'b0; MemtoReg=1'b0; RegWrite=1'b1; MemRead=1'b0;
MemWrite=1'b0; Branch=1'b0; ALUOp = 2'b10;
end
LW :
begin
RegDst=1'b0; ALUSrc=1'b1; MemtoReg=1'b1; RegWrite=1'b1; MemRead=1'b1;
MemWrite=1'b0; Branch=1'b0; ALUOp = 2'b00;
end
SW :
begin
RegDst=1'bx; ALUSrc=1'b1; MemtoReg=1'bx; RegWrite=1'b0; MemRead=1'b0;
MemWrite=1'b1; Branch=1'b0; ALUOp = 2'b00;
end
BEQ :
begin
RegDst=1'bx; ALUSrc=1'b0; MemtoReg=1'bx; RegWrite=1'b0; MemRead=1'b0;
MemWrite=1'b0; Branch=1'b1; ALUOp = 2'b01;
end
default
begin
$display("control_single unimplemented opcode %d", opcode);
RegDst=1'b0; ALUSrc=1'b0; MemtoReg=1'b0; RegWrite=1'b0; MemRead=1'b0;
MemWrite=1'b0; Branch=1'b0; ALUOp = 2'b00;
end
endcase
end
endmodule
module mem32(clk, mem_read, mem_write, address, data_in, data_out);
input clk, mem_read, mem_write;
input [31:0] address, data_in;
output [31:0] data_out;
reg [31:0] data_out;
parameter BASE_ADDRESS = 25'd0; // address that applies to this memory - change if desired
reg [31:0] mem_array [0:31];
wire [4:0] mem_offset;
wire address_select;
assign mem_offset = address[6:2]; // drop 2 LSBs to get word offset
assign address_select = (address[31:7] == BASE_ADDRESS); // address decoding
always @(mem_read or address_select or mem_offset or mem_array[mem_offset])
begin
if (mem_read == 1'b1 && address_select == 1'b1)
begin
if ((address % 4) != 0)
$display($time, " rom32 error: unaligned address %d", address);
data_out = mem_array[mem_offset];
$display($time, " reading data: Mem[%h] => %h", address, data_out);
end
else data_out = 32'hxxxxxxxx;
end
// for WRITE operations
always @(posedge clk)
begin
if (mem_write == 1'b1 && address_select == 1'b1)
begin
$display($time, " writing data: Mem[%h] <= %h", address,data_in);
mem_array[mem_offset] <= data_in;
end
end
// initialize with some arbitrary values
integer i;
initial begin
for (i=0; i<7; i=i+1) mem_array[i] = i;
end
endmodule
module reg_file(clk, RegWrite, RN1, RN2, WN, RD1, RD2, WD);
input clk;
input RegWrite;
input [4:0] RN1, RN2, WN;
input [31:0] WD;
output [31:0] RD1, RD2;
reg [31:0] RD1, RD2;
reg [31:0] file_array [31:1];
always @(RN1 or file_array[RN1])
begin
if (RN1 == 0) RD1 = 32'd0;
else RD1 = file_array[RN1];
$display($time, " reg_file[%d] => %d (Port 1)", RN1, RD1);
end
always @(RN2 or file_array[RN2])
begin
if (RN2 == 0) RD2 = 32'd0;
else RD2 = file_array[RN2];
$display($time, " reg_file[%d] => %d (Port 2)", RN2, RD2);
end
always @(posedge clk)
if (RegWrite && (WN != 0))
begin
file_array[WN] <= WD;
$display($time, " reg_file[%d] <= %d (Write)", WN, WD);
end
endmodule
module mux2( sel, a, b, y );
parameter bitwidth=32;
input sel;
input [bitwidth-1:0] a, b;
output [bitwidth-1:0] y;
assign y = sel ? b : a;
endmodule
module rom32(address, data_out);
input [31:0] address;
output [31:0] data_out;
reg [31:0] data_out;
parameter BASE_ADDRESS = 25'd0; // address that applies to this memory
wire [5:0] mem_offset;
wire address_select;
assign mem_offset = address[7:2]; // drop 2 LSBs to get word offset
assign address_select = (address[31:8] == BASE_ADDRESS); // address decoding
always @(address_select or mem_offset)
begin
if ((address % 4) != 0) $display($time, " rom32 error: unaligned address %d", address);
if (address_select == 1)
begin
case (mem_offset)
5'd0 : data_out = { 6'd35, 5'd0, 5'd2, 16'd4 }; // lw $2, 4($0) r2=1
5'd1 : data_out = { 6'd35, 5'd0, 5'd3, 16'd8 }; // lw $3, 8($0) r3=2
5'd2 : data_out = { 6'd35, 5'd0, 5'd4, 16'd20 }; // lw $4, 20($0) r4=5
5'd3 : data_out = { 6'd0, 5'd0, 5'd0, 5'd5, 5'd0, 6'd32 }; // add $5, $0, $0 r5=0
5'd4 : data_out = 0; // no-op to stall until add is done
5'd5 : data_out = 0; // no-op to stall until add is done
5'd6 : data_out = 0; // no-op to stall until add is done
5'd7 : data_out = { 6'd0, 5'd5, 5'd2, 5'd5, 5'd0, 6'd32 }; // add $5, $5, $1 r5 = r6 + 1
5'd8 : data_out = 0; // no-op to stall until add is done
5'd9 : data_out = 0; // no-op to stall until add is done
5'd10 : data_out = 0; // no-op to stall until add is done
5'd11 : data_out = { 6'd0, 5'd4, 5'd5, 5'd6, 5'd0, 6'd42 }; // slt $6, $4, $5 is $5 > 54?
5'd12 : data_out = 0; // no-op to stall until slt is done
5'd13 : data_out = 0; // no-op to stall until slt is done
5'd14 : data_out = 0; // no-op to stall until slt is done
5'd15 : data_out = { 6'd4, 5'd6, 5'd0, -16'd9 }; // beq $6, $zero, -9 if not, go back 2
5'd16 : data_out = 32'b0; // no-op after branch
5'd17 : data_out = 32'b0; // no-op after branch
5'd18 : data_out = 32'b0; // no-op after branch
5'd19 : data_out = { 6'd43, 5'd0, 5'd5, 16'd0 }; // MEM[0] = $5
5'd20 : data_out = { 6'd4, 5'd0, 5'd0, -16'd18 }; // beq $0, $0, -18 restart loop at word 3
// add more cases here as desired
default data_out = 32'hxxxx;
endcase
$display($time, " reading data: rom32[%h] => %h", address, data_out);
end
end
endmodule
module reg32 (clk, reset, d_in, d_out);
input clk, reset;
input [31:0] d_in;
output [31:0] d_out;
reg [31:0] d_out;
always @(posedge clk)
begin
if (reset) d_out <= 0;
else d_out <= d_in;
end
endmodule
module mips_pipeline(clk, reset);
input clk, reset;
// ********************************************************************
// Signal Declarations
// ********************************************************************
// IF Signal Declarations
wire [31:0] IF_instr, IF_pc, IF_pc_next, IF_pc4;
// ID Signal Declarations
reg [31:0] ID_instr, ID_pc4; // pipeline register values from EX
wire [5:0] ID_op, ID_funct;
wire [4:0] ID_rs, ID_rt, ID_rd;
wire [15:0] ID_immed;
wire [31:0] ID_extend, ID_rd1, ID_rd2;
assign ID_op = ID_instr[31:26];
assign ID_rs = ID_instr[25:21];
assign ID_rt = ID_instr[20:16];
assign ID_rd = ID_instr[15:11];
assign ID_immed = ID_instr[15:0];
wire ID_RegWrite, ID_Branch, ID_RegDst, ID_MemtoReg, // ID Control signals
ID_MemRead, ID_MemWrite, ID_ALUSrc;
wire [1:0] ID_ALUOp;
// EX Signals
reg [31:0] EX_pc4, EX_extend, EX_rd1, EX_rd2;
wire [31:0] EX_offset, EX_btgt, EX_alub, EX_ALUOut;
reg [4:0] EX_rt, EX_rd;
wire [4:0] EX_RegRd;
wire [5:0] EX_funct;
reg EX_RegWrite, EX_Branch, EX_RegDst, EX_MemtoReg, // EX Control Signals
EX_MemRead, EX_MemWrite, EX_ALUSrc;
wire EX_Zero;
reg [1:0] EX_ALUOp;
wire [2:0] EX_Operation;
// MEM Signals
wire MEM_PCSrc;
reg MEM_RegWrite, MEM_Branch, MEM_MemtoReg,
MEM_MemRead, MEM_MemWrite, MEM_Zero;
reg [31:0] MEM_btgt, MEM_ALUOut, MEM_rd2;
wire [31:0] MEM_memout;
reg [5:0] MEM_RegRd;
// WB Signals
reg WB_RegWrite, WB_MemtoReg; // WB Control Signals
reg [31:0] WB_memout, WB_ALUOut;
wire [31:0] WB_wd;
reg [4:0] WB_RegRd;
// ********************************************************************
// IF Stage
// ********************************************************************
// IF Hardware
reg32 IF_PC(clk, reset, IF_pc_next, IF_pc);
add32 IF_PCADD(IF_pc, 32'd4, IF_pc4);
mux2 #(32) IF_PCMUX(MEM_PCSrc, IF_pc4, MEM_btgt, IF_pc_next);
rom32 IMEM(IF_pc, IF_instr);
always @(posedge clk) // IF/ID Pipeline Register
begin
if (reset)
begin
ID_instr <= 0;
ID_pc4 <= 0;
end
else begin
ID_instr <= IF_instr;
ID_pc4 <= IF_pc4;
end
end
// ********************************************************************
// ID Stage
// ********************************************************************
reg_file RFILE(clk, WB_RegWrite, ID_rs, ID_rt, WB_RegRd, ID_rd1, ID_rd2, WB_wd);
// sign-extender
assign ID_extend = { {16{ID_immed[15]}}, ID_immed };
control_pipeline CTL(.opcode(ID_op), .RegDst(ID_RegDst),
.ALUSrc(ID_ALUSrc), .MemtoReg(ID_MemtoReg),
.RegWrite(ID_RegWrite), .MemRead(ID_MemRead),
.MemWrite(ID_MemWrite), .Branch(ID_Branch),
.ALUOp(ID_ALUOp));
always @(posedge clk) // ID/EX Pipeline Register
begin
if (reset)
begin
EX_RegDst <= 0;
EX_ALUOp <= 0;
EX_ALUSrc <= 0;
EX_Branch <= 0;
EX_MemRead <= 0;
EX_MemWrite <= 0;
EX_RegWrite <= 0;
EX_MemtoReg <= 0;
EX_RegDst <= 0;
EX_ALUOp <= 0;
EX_ALUSrc <= 0;
EX_Branch <= 0;
EX_MemRead <= 0;
EX_MemWrite <= 0;
EX_RegWrite <= 0;
EX_MemtoReg <= 0;
EX_pc4 <= 0;
EX_rd1 <= 0;
EX_rd2 <= 0;
EX_extend <= 0;
EX_rt <= 0;
EX_rd <= 0;
end
else begin
EX_RegDst <= ID_RegDst;
EX_ALUOp <= ID_ALUOp;
EX_ALUSrc <= ID_ALUSrc;
EX_Branch <= ID_Branch;
EX_MemRead <= ID_MemRead;
EX_MemWrite <= ID_MemWrite;
EX_RegWrite <= ID_RegWrite;
EX_MemtoReg <= ID_MemtoReg;
EX_RegDst <= ID_RegDst;
EX_ALUOp <= ID_ALUOp;
EX_ALUSrc <= ID_ALUSrc;
EX_Branch <= ID_Branch;
EX_MemRead <= ID_MemRead;
EX_MemWrite <= ID_MemWrite;
EX_RegWrite <= ID_RegWrite;
EX_MemtoReg <= ID_MemtoReg;
EX_pc4 <= ID_pc4;
EX_rd1 <= ID_rd1;
EX_rd2 <= ID_rd2;
EX_extend <= ID_extend;
EX_rt <= ID_rt;
EX_rd <= ID_rd;
end
end
// ********************************************************************
// EX Stage
// ********************************************************************
// branch offset shifter
assign EX_offset = EX_extend << 2;
assign EX_funct = EX_extend[5:0];
add32 EX_BRADD(EX_pc4, EX_offset, EX_btgt);
mux2 #(32) ALUMUX(EX_ALUSrc, EX_rd2, EX_extend, EX_alub);
alu EX_ALU(EX_Operation, EX_rd1, EX_alub, EX_ALUOut, EX_Zero);
mux2 #(5) EX_RFMUX(EX_RegDst, EX_rt, EX_rd, EX_RegRd);
alu_ctl EX_ALUCTL(EX_ALUOp, EX_funct, EX_Operation);
always @(posedge clk) // EX/MEM Pipeline Register
begin
if (reset)
begin
MEM_Branch <= 0;
MEM_MemRead <= 0;
MEM_MemWrite <= 0;
MEM_RegWrite <= 0;
MEM_MemtoReg <= 0;
MEM_Zero <= 0;
MEM_btgt <= 0;
MEM_ALUOut <= 0;
MEM_rd2 <= 0;
MEM_RegRd <= 0;
end
else begin
MEM_Branch <= EX_Branch;
MEM_MemRead <= EX_MemRead;
MEM_MemWrite <= EX_MemWrite;
MEM_RegWrite <= EX_RegWrite;
MEM_MemtoReg <= EX_MemtoReg;
MEM_Zero <= EX_Zero;
MEM_btgt <= EX_btgt;
MEM_ALUOut <= EX_ALUOut;
MEM_rd2 <= EX_rd2;
MEM_RegRd <= EX_RegRd;
end
end
// ********************************************************************
// MEM Stage
// ********************************************************************
mem32 MEM_DMEM(clk, MEM_MemRead, MEM_MemWrite, MEM_ALUOut, MEM_rd2, MEM_memout);
and MEM_BR_AND(MEM_PCSrc, MEM_Branch, MEM_Zero);
always @(posedge clk) // MEM/WB Pipeline Register
begin
if (reset)
begin
WB_RegWrite <= 0;
WB_MemtoReg <= 0;
WB_ALUOut <= 0;
WB_memout <= 0;
WB_RegRd <= 0;
end
else begin
WB_RegWrite <= MEM_RegWrite;
WB_MemtoReg <= MEM_MemtoReg;
WB_ALUOut <= MEM_ALUOut;
WB_memout <= MEM_memout;
WB_RegRd <= MEM_RegRd;
end
end
// ********************************************************************
// WB Stage
// ********************************************************************
mux2 #(32) WB_WRMUX(WB_MemtoReg, WB_ALUOut, WB_memout, WB_wd);
endmodule