////////////////////////////////////////////////////////////////////////////////
///
/// Solution to LSU EE 3755 Fall 2001 Homework 7
///
// Assignment: http://www.ece.lsu.edu/ee3755/2001f/hw07.pdf
////////////////////////////////////////////////////////////////////////////////
/// Solutions to Problem 1 and 2
//
// Look for "Prob 1" and "Prob 2" comments starting in the 70th column.
`define MIPS_PROG "/home/classes/ee3755/com/v/hw07test.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;
reg [4:0] ss;
// 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
reg ex_alu;
// Shifter Declarations Prob 1
//
wire [31:0] shifter_out;
reg [4:0] shift_amt;
reg shift_dir;
alu our_alu(alu_out, alu_a, alu_b, alu_op);
shifter our_shifter(shifter_out, rt_val, shift_amt, shift_dir);
// Values for the MIPS funct field.
//
parameter f_sll = 6'h0; // Prob 1
parameter f_srl = 6'h2;
parameter f_sllv = 6'h4;
parameter f_srlv = 6'h6;
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 = 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;
/// Set Memory Connection Values: addr, we, and size.
//
always @( state or pc or alu_out or me_size or me_we or npc )
case( state )
st_if : begin addr = pc; we = 0; size = 3; end
st_id : begin addr = npc; we = 0; size = 3; end // Prb 2
st_me : begin addr = alu_out; we = me_we; size = me_size; end
default : begin addr = npc; 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;
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];
// Get shift amount from low five bits of rs register value.
//
ss = rs_val[4:0]; // Prob 1
// Assign shifter control signals. // Prob 1
//
// For readability the shift control signals are set
// separately from the alu control signals.
//
// To simplify the synthesized logic signals are set in
// every case.
//
if( opcode == o_rfmt ) begin
case( func )
f_sll: begin shift_dir = 1; shift_amt = sa; ex_alu = 0; end
f_srl: begin shift_dir = 0; shift_amt = sa; ex_alu = 0; end
f_sllv: begin shift_dir = 1; shift_amt = ss; ex_alu = 0; end
f_srlv: begin shift_dir = 0; shift_amt = ss; ex_alu = 0; end
default: begin shift_dir = 0; shift_amt = 0; ex_alu = 1; end
endcase
end else begin shift_dir = 0; shift_amt = 0; ex_alu = 1; end
// Set alu_a, alu_b, alu_op, and wb_rd.
//
case( opcode )
o_rfmt:
// R-Format Instructions
case ( func )
f_add : begin alu_a = rs_val; alu_op = op_add;
alu_b = rt_val; wb_rd = rd; end
f_sub : begin alu_a = rs_val; alu_op = op_sub;
alu_b = rt_val; wb_rd = rd; end
// Prob 1
// ALU is not used for shifts, but assign anyway to
// simplify synthesized logic.
f_srl, f_sllv, f_srlv,
f_sll : begin alu_a = sa; alu_op = op_nop;
alu_b = rt_val; wb_rd = rd; end
default : begin alu_a = rs_val; alu_op = op_nop;
alu_b = rt_val; wb_rd = 0; exc = 1; end
endcase
// I- and J-Format Instructions
o_lbu: begin alu_a = rs_val; alu_op = op_add;
alu_b = simmed; wb_rd = rt; end
o_sb: begin alu_a = rs_val; alu_op = op_add;
alu_b = simmed; wb_rd = 0; end
o_lui: begin alu_a = rs_val; alu_op = op_or;
alu_b = limmed; wb_rd = rt; end
o_addi: begin alu_a = rs_val; alu_op = op_add;
alu_b = simmed; wb_rd = rt; end
o_andi: begin alu_a = rs_val; alu_op = op_and;
alu_b = uimmed; wb_rd = rt; end
o_ori: begin alu_a = rs_val; alu_op = op_or;
alu_b = uimmed; wb_rd = rt; end
o_slti: begin alu_a = rs_val; alu_op = op_slt;
alu_b = simmed; wb_rd = rt; end
o_j: begin alu_a = rs_val; alu_op = op_nop;
alu_b = simmed; wb_rd = 0; end
o_bne, o_beq:
begin alu_a = rs_val; alu_op = op_seq;
alu_b = rt_val; wb_rd = 0; end
default:begin alu_a = rs_val; alu_op = op_nop;
alu_b = simmed; wb_rd = 0; exc = 1; end
endcase
// 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_id; // Prob 2
default : state = st_ex;
endcase
ir = data_in; // Prob 2
end
/// Execute (ALU instructions)
st_ex:
begin
if( wb_rd ) gpr[wb_rd] = ex_alu ? alu_out : shifter_out; // Prob 1
state = st_id; // Prob 2
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_id; // Prob 2
end
end
/// Execute (Compute Branch Target)
st_ex_targ:
begin
npc = alu_out;
state = st_id; // Prob 2
end
/// Memory
st_me:
begin
if( wb_rd ) gpr[wb_rd] = data_in;
state = st_id; // Prob 2
end
default:
begin
$display("Unexpected state.");
$stop;
end
endcase
endmodule
////////////////////////////////////////////////////////////////////////////////
/// Shifter and ALU Modules
//
module shifter(shift_out,val,amt,direction);
output [31:0] shift_out;
input [31:0] val;
input [4:0] amt;
input direction;
assign shift_out = direction ? val << amt : val >> amt;
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_add = 3;
parameter op_sub = 4;
parameter op_or = 5;
parameter op_and = 6;
parameter op_slt = 7;
parameter op_seq = 8;
// DO NOT add shift operations to this module.
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} >> 32;
op_seq : alu_out = alu_a == alu_b;
op_nop : alu_out = 0;
default :
begin
alu_out = 0;
// exemplar translate_off
$display("Unrecognized alu operation, %d", alu_op);
// exemplar translate_on
end
endcase
endmodule
////////////////////////////////////////////////////////////////////////////////
/// System Module and Testbench Include
// 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);
memory_3 m1(mem_data_out,mem_err_out,addr,size,we,cpu_data_out,clk);
endmodule
// Include the testbench.
`include "/home/classes/ee3755/com/v/hw07sup.v"