/// LSU EE 3755 -- Spring 2002 -- Computer Organization
//
/// Hardwired Control, Multicycle MIPS
//
// Time-stamp: <29 April 2002, 11:44:25 CDT, koppel@sol>
//
`define MIPS_PROG "uc.v"
module cpu(exc,data_out,addr,size,we,data_in,mem_error_in,reset,clk);
input [31:0] data_in;
input [2:0] mem_error_in;
input reset,clk;
output [7:0] exc;
output [31:0] data_out, addr;
output [1:0] size;
output we;
reg [31:0] data_out, addr;
reg [1:0] size;
reg we;
reg [7:0] exc;
// MIPS Registers
//
reg [31:0] gpr [0:31];
reg [31:0] pc, npc;
reg [31:0] ir;
// Instruction Fields
//
reg [4:0] rs, rt, rd, sa;
reg [5:0] opcode, func;
reg [25:0] ii;
reg [15:0] immed;
// Values Derived From Immediates and Read From Register File
//
reg [31:0] simmed, uimmed, limmed;
reg [31:0] rs_val, rt_val, sa_val;
reg [75:0] bndl;
// ALU Connections
//
wire [31:0] alu_out;
reg [31:0] alu_a, alu_b;
reg [5:0] alu_op;
// Processor Control Logic State
//
reg [2:0] state;
reg [4:0] wb_rd; // Register number to write.
reg me_we; // we value to use in state st_me
reg [1:0] me_size; // size value to use in state st_me
alu our_alu(alu_out, alu_a, alu_b, alu_op);
// Values for the MIPS funct field.
//
parameter F_sll = 6'h0;
parameter F_srl = 6'h2;
parameter F_add = 6'h20;
parameter F_sub = 6'h22;
parameter F_or = 6'h25;
// Values for the MIPS opcode field.
//
parameter O_rfmt = 6'h0;
parameter O_j = 6'h2;
parameter O_beq = 6'h4;
parameter O_bne = 6'h5;
parameter O_addi = 6'h8;
parameter O_slti = 6'ha;
parameter O_andi = 6'hc;
parameter O_ori = 6'hd;
parameter O_lui = 6'hf;
parameter O_lw = 6'h23;
parameter O_lbu = 6'h24;
parameter O_sw = 6'h2b;
parameter O_sb = 6'h28;
// Processor Control Logic States
//
parameter ST_if = 1;
parameter ST_id = 2;
parameter ST_ex = 3;
parameter ST_ex_addr = 5;
parameter ST_ex_cond = 6;
parameter ST_ex_targ = 7;
parameter ST_me = 4;
// ALU Operations
//
parameter OP_nop = 6'd0;
parameter OP_sll = 6'd1;
parameter OP_srl = 6'd2;
parameter OP_add = 6'd3;
parameter OP_sub = 6'd4;
parameter OP_or = 6'd5;
parameter OP_and = 6'd6;
parameter OP_slt = 6'd7;
parameter OP_seq = 6'd8;
// Handy Constant
//
parameter R0 = 5'd0;
/// Set Memory Connection Values: addr, we, and size.
//
always @( state or pc or alu_out or me_size or me_we )
case( state )
ST_if : begin addr = pc; we = 0; size = 3; end
ST_me : begin addr = alu_out; we = me_we; size = me_size; end
default : begin addr = pc; we = 0; size = 0; end
// Note: addr is set for default case to simplify synthesized hardware.
endcase
always @( posedge clk )
if( reset ) begin
state = ST_if;
exc = 0;
pc = 32'h400000;
npc = pc + 4;
end else
case ( state )
/// Instruction Fetch
ST_if:
begin
ir = data_in;
state = ST_id;
end
/// Instruction Decode (and Register Read)
ST_id:
begin
{opcode,rs,rt,rd,sa,func} = ir;
ii = ir[25:0];
immed = ir[15:0];
simmed = { immed[15] ? 16'hffff : 16'h0, immed };
uimmed = { 16'h0, immed };
limmed = { immed, 16'h0 };
rs_val = gpr[rs];
rt_val = gpr[rt];
sa_val = {26'd0,sa};
// Set alu_a, alu_b, alu_op, and wb_rd.
//
case( opcode )
O_rfmt:
// R-Format Instructions
case ( func )
F_add: bndl = {rd, rs_val, OP_add, rt_val};
F_sub: bndl = {rd, rs_val, OP_sub, rt_val};
F_sll: bndl = {rd, sa_val, OP_sll, rt_val};
default:
begin bndl = {rd, sa_val, OP_sll, rt_val}; exc = 1; end
endcase
// I- and J-Format Instructions
O_lbu: bndl = {rt, rs_val, OP_add, simmed };
O_sb: bndl = {R0, rs_val, OP_add, simmed };
O_lui: bndl = {rt, rs_val, OP_or, limmed };
O_addi: bndl = {rt, rs_val, OP_add, simmed };
O_andi: bndl = {rt, rs_val, OP_and, uimmed };
O_ori: bndl = {rt, rs_val, OP_or, uimmed };
O_slti: bndl = {rt, rs_val, OP_slt, simmed };
O_j: bndl = {R0, rs_val, OP_nop, simmed };
O_bne, O_beq: bndl = {R0, rs_val, OP_seq, rt_val };
default: begin bndl = {R0, rs_val, OP_seq, rt_val }; exc = 1; end
endcase
{wb_rd,alu_a,alu_op,alu_b} = bndl;
// Needed for a store instruction, doesn't hurt others.
data_out = rt_val;
// Set me_size and me_wb
//
case( opcode )
O_lbu : begin me_size = 1; me_we = 0; end
O_sb : begin me_size = 1; me_we = 1; end
default : begin me_size = 0; me_we = 0; end
endcase
pc = npc;
// Set npc, branch instruction may change npc.
//
case( opcode )
O_j : npc = { pc[31:28], ii, 2'b0 };
default : npc = pc + 4;
endcase
case( opcode )
O_lbu, O_sb : state = ST_ex_addr;
O_bne, O_beq : state = ST_ex_cond;
O_j : state = ST_if;
default : state = ST_ex;
endcase
end
/// Execute (ALU instructions)
ST_ex:
begin
if( wb_rd ) gpr[wb_rd] = alu_out;
state = ST_if;
end
/// Execute (Compute Effective Address for Loads and Stores)
ST_ex_addr:
begin
state = ST_me;
end
/// Execute (Compute Branch Condition)
ST_ex_cond:
begin
if( opcode == O_beq == alu_out ) begin
alu_a = pc;
alu_b = simmed << 2;
alu_op = OP_add;
state = ST_ex_targ;
end else begin
state = ST_if;
end
end
/// Execute (Compute Branch Target)
ST_ex_targ:
begin
npc = alu_out;
state = ST_if;
end
/// Memory
ST_me:
begin
if( wb_rd ) gpr[wb_rd] = data_in;
state = ST_if;
end
default:
begin
$display("Unexpected state.");
$stop;
end
endcase
endmodule
module alu(alu_out,alu_a,alu_b,alu_op);
output [31:0] alu_out;
input [31:0] alu_a, alu_b;
input [5:0] alu_op;
reg [31:0] alu_out;
// Control Signal Value Names
parameter OP_nop = 0;
parameter OP_sll = 1;
parameter OP_srl = 2;
parameter OP_add = 3;
parameter OP_sub = 4;
parameter OP_or = 5;
parameter OP_and = 6;
parameter OP_slt = 7;
parameter OP_seq = 8;
always @( alu_a or alu_b or alu_op )
case( alu_op )
OP_add : alu_out = alu_a + alu_b;
OP_and : alu_out = alu_a & alu_b;
OP_or : alu_out = alu_a | alu_b;
OP_sub : alu_out = alu_a - alu_b;
OP_slt : alu_out = {alu_a[31],alu_a} < {alu_b[31],alu_b};
OP_sll : alu_out = alu_b << alu_a;
OP_srl : alu_out = alu_b >> alu_a;
OP_seq : alu_out = alu_a == alu_b;
OP_nop : alu_out = 0;
default : begin alu_out = 0; $stop; end
endcase
endmodule
// exemplar translate_off
module system(exc,reset,clk);
input reset,clk;
output [7:0] exc;
wire [31:0] cpu_data_out, addr, mem_data_out;
wire [2:0] mem_err_out;
wire [1:0] size;
wire we;
cpu cpu1(exc,cpu_data_out,addr,size,we,mem_data_out,mem_err_out,reset,clk);
mips_memory_1p m1(mem_data_out,mem_err_out,addr,size,we,cpu_data_out,clk);
endmodule
`include "mips_hc_tb.v"