/// EE 3755 -- Spring 2002 -- Computer Organization
//
/// Example used in class 8 May 2002
//
/// Hardwired Control, Multicycle MIPS, Day 5
//
//
// Will be added to each day.
//
/// Day 1: 29 April 2002
//
// Started moving memory out of the processor by adding ports for an
// external memory. The module system (at the end of this file)
// connects cpu to the memory. Not in a working state.
//
// Copied functional simulator code.
// Added system module that instantiates cpu and memory.
// Added new ports.
//
/// Day 2: 1 May 2002
//
// Removed old mem code.
// Added states for instruction fetch, decode, and execute.
// Was working during class, but by the end of class was in a
// non-working state.
//
/// Day 3: 3 May 2002
//
// Got states working.
// Re-wrote ID to take advantage of separate ALU for arithmetic and log. inst.
// Re-wrote ID to take advantage of separate ALU for branches.
//
/// Day 4: 6 May 2002
//
// Added load instruction.
// Started store instruction.
//
/// Day 5: 8 May 2002
//
// Got lb working.
// Finished store instruction.
// This file does not include changes to overlap IF and ID.
`define MIPS_PROG "tthird.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;
wire [31:0] data_out;
reg [31:0] addr;
reg [1:0] size;
reg we;
reg [7:0] exc;
reg [31:0] pc, npc, nnpc;
reg [31:0] ir;
wire [5:0] opcode, func;
wire [4:0] rs, rt, rd, sa;
wire [15:0] immed;
wire [25:0] ii;
reg [31:0] gpr [0:31];
wire [31:0] simmed, uimmed;
reg [7:0] temp;
reg [2:0] state;
reg [4:0] dst;
reg [74:0] bndl;
wire [31:0]limmed;
reg [31:0] bimmed;
reg [31:0] rs_val, rt_val, sa_val;
parameter F_add = 6'h20;
parameter F_sll = 6'h0;
parameter F_srl = 6'h2;
parameter F_sub = 6'h22;
parameter F_or = 6'h25;
parameter F_jr = 6'h8;
parameter O_tyr = 6'h0;
parameter O_addi = 6'h8;
parameter O_j = 6'h2;
parameter O_jal = 6'h3;
parameter O_beq = 6'h4;
parameter O_bne = 6'h5;
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_lb = 6'h20;
parameter O_sw = 6'h2b;
parameter O_sb = 6'h28;
// Control Signal Value Names
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;
parameter OP_sne = 6'd9;
parameter ST_if = 1; // Instruction Fetch
parameter ST_id = 2; // Instruction Decode
parameter ST_ex = 3; // Executing Arithmetic or Logical Instruction
parameter ST_eb = 4; // Executing Branch (Computing condition.)
parameter ST_ea = 5; // Executing Memory (Computing address.)
parameter ST_me = 6; // Performing load or store.
wire [31:0] alu_out;
reg [31:0] alu_a, alu_b;
reg [5:0] alu_op;
alu our_alu(alu_out, alu_a, alu_b, alu_op);
reg [1:0] me_size;
reg me_we, me_se;
assign data_out = rt_val;
always @( state or pc or alu_out )
case( state )
ST_if:
begin
addr = pc;
size = 3;
we = 0;
end
ST_me:
begin
addr = alu_out;
size = me_size;
we = me_we;
end
default:
begin
size = 0;
addr = pc;
we = 0;
end
endcase
assign immed = ir[15:0];
assign {opcode, rs, rt, rd, sa, func} = ir;
assign ii = ir[25:0];
assign simmed = {immed[15] ? 16'hffff : 16'h0, immed};
assign uimmed = { 16'h0, immed };
assign limmed = { immed, 16'h0 };
always @( posedge clk )
if( reset ) begin
state = ST_if;
pc = 'h400000;
npc = pc + 4;
exc = 0;
end else
case( state )
/// IF: Instruction Fetch
ST_if:
begin
ir = data_in;
state = ST_id;
end
/// Instruction Decode
ST_id:
begin
nnpc = npc + 4; // Reassigned below.
rs_val = gpr[rs];
rt_val = gpr[rt];
sa_val = { 27'd0, sa };
bndl = 75'bx;
case( opcode )
O_tyr:
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 };
F_jr: nnpc = rs_val;
default: exc = 1;
endcase
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_lui: bndl = {rt, rs_val, OP_or, limmed };
O_bne: bndl = {5'd0, rs_val, OP_sne, rt_val };
O_beq: bndl = {5'd0, rs_val, OP_seq, rt_val };
O_j: nnpc = {npc[31:28],ii,2'd0};
O_jal: begin gpr[31] = nnpc; nnpc = {npc[31:28],ii,2'd0}; end
O_lb,O_lbu: bndl = {rt, rs_val, OP_add, simmed };
O_sb: bndl = {5'd0, rs_val, OP_add, simmed };
// O_lbu: gpr[rt] = {24'b0, mem[`A(gpr[rs]+simmed)]};
// O_sb: mem[`A(gpr[rs]+simmed)]= gpr[rt];
default: exc = 1;
endcase
if( bndl !== 75'bx ) {dst, alu_a, alu_op, alu_b } = bndl;
case( opcode )
O_lb: begin me_size = 1; me_se = 1; me_we = 0; end
O_lbu: begin me_size = 1; me_se = 0; me_we = 0; end
O_sb: begin me_size = 1; me_se = 0; me_we = 1; end
default: begin me_size = 0; me_se = 0; me_we = 0; end
endcase
case( opcode )
O_beq,O_bne: state = ST_eb;
O_sb,O_lb,O_lbu: state = ST_ea;
O_j: state = ST_if;
default: state = bndl === 75'bx ? ST_if : ST_ex;
endcase
bimmed = npc + ( simmed << 2 );
pc = npc;
npc = nnpc;
end
/// EX: Execute
ST_ex:
begin
if( dst ) gpr[dst] = alu_out;
state = ST_if;
end
/// EXB: Execute Branch
ST_eb:
begin
if( alu_out[0] ) npc = bimmed;
state = ST_if;
end
/// EA: Effective Address
ST_ea:
begin
state = ST_me;
end
/// ME: Memory
ST_me:
begin
if( dst != 0 )
case( size )
1: gpr[dst] = { me_se & data_in[7] ? 24'hffffff : 24'h0,
data_in[7:0] };
2: gpr[dst] = { me_se & data_in[15] ? 16'hffff : 16'h0,
data_in[15:0] };
endcase
state = ST_if;
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 = 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;
parameter OP_sne = 6'd9;
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_sne : alu_out = alu_a != alu_b;
OP_nop : alu_out = 0;
default : begin alu_out = 0; $stop; end
endcase
endmodule
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"