//////////////////////////////////////////////////////////////////////////////// /// /// 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"