/// LSU EE 3755 -- Fall 2001 -- Computer Organization // /// Microcoded MIPS // // Time-stamp: <3 December 2001, 16:29:36 CST, koppel@sol> // `define MIPS_PROG "prog1.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 [7:0] exc; // MIPS Registers // reg [31:0] gpr [0:31]; reg [31:0] pc, npc; reg [31:0] ir; // Instruction Fields // wire [4:0] rs, rt, rd, sa; wire [5:0] opcode, func; wire [25:0] ii = ir[25:0]; wire [15:0] immed = ir[15:0]; assign {opcode,rs,rt,rd,sa,func} = ir; // Values From Register File // wire [31:0] rs_val = gpr[rs]; wire [31:0] rt_val = gpr[rt]; // ALU Connections // 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); // Branch Condition // reg branch_cond; // 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; // ALU Operations // parameter op_nop = 5'd0; parameter op_sll = 5'd1; parameter op_srl = 5'd2; parameter op_add = 5'd3; parameter op_sub = 5'd4; parameter op_or = 5'd5; parameter op_and = 5'd6; parameter op_slt = 5'd7; parameter op_seq = 5'd8; parameter op_sne = 5'd9; parameter op_exc = 5'd31; /// /// Control Signal Constants /// // PC/NPC Assignment // parameter PC_000 = 2'd0; // Do nothing. parameter PC_ADV = 2'd1; // npc <- pc parameter PC_BRN = 2'd2; // npc <- alu_out if branch_cond true. parameter PC_ALU = 2'd3; // npc <- alu_out // Memory Address, Write Enable, and Size // parameter ADDR_PC = 1'b0; parameter ADDR_ALU = 1'b1; parameter WE_0 = 1'b0; parameter WE_1 = 1'b1; parameter SIZE_OFF = 2'd0; parameter SIZE_BYTE = 2'd1; parameter SIZE_HALF = 2'd2; parameter SIZE_WORD = 2'd3; // Memory Operations (For compactness combine three constants.) // parameter MEM_IF = {ADDR_PC, WE_0,SIZE_WORD}; parameter MEM_LB = {ADDR_ALU,WE_0,SIZE_BYTE}; parameter MEM_SB = {ADDR_ALU,WE_1,SIZE_BYTE}; parameter MEM_00 = {ADDR_ALU,WE_0,SIZE_OFF}; // IR and branch condition (branch_cond) Register Write Enables // parameter IR_000 = 1'b0; // No change to ir. parameter IR_DIN = 1'b1; // ir <- data_in parameter BR_000 = 1'b0; // No change to branch_cond. parameter BR_ALU = 1'b1; // branch_cond <- alu_out. // GPR Writeback // parameter DEST_00 = 2'd0; // Write register zero. parameter DEST_RD = 2'd1; // Write register specified in rd field. parameter DEST_RT = 2'd2; // Write register specified in rt field. parameter GPR_ALU = 1'b0; // Write register with alu_out. parameter GPR_MEM = 1'b1; // Write register with data_in. // Handy combinations of ir, branch_cond, and GPR control signal constants. // parameter W_RD_ALU = {IR_000, BR_000, DEST_RD, GPR_ALU }; // gpr[rd]=alu_out; parameter W_RT_ALU = {IR_000, BR_000, DEST_RT, GPR_ALU }; // etc. parameter W_RT_MEM = {IR_000, BR_000, DEST_RT, GPR_MEM }; parameter W_IR_DIN = {IR_DIN, BR_000, DEST_00, GPR_MEM }; parameter W_BR_ALU = {IR_000, BR_ALU, DEST_00, GPR_MEM }; parameter W_00_000 = {IR_000, BR_000, DEST_00, GPR_MEM }; // ALU Operation Control Signal Constants // parameter ALU_DSP = 1'b1; // Get alu operation from dispatch table. parameter ALU_ADD = 1'b0; // Nothing fancy, just add. parameter ALU_000 = 1'b0; // Add, but intend to ignore result. // ALU A Input Control Signal Constants // parameter ALU_A_00 = 2'd0; parameter ALU_A_RS = 2'd1; parameter ALU_A_SA = 2'd2; parameter ALU_A_PC = 2'd3; // ALU B Input Control Signal Constants // parameter ALU_B_00 = 3'd0; // rt_val, but intend to ignore result. parameter ALU_B_RT = 3'd0; // Contents of register number rt parameter ALU_B_UI = 3'd1; // Unsigned Immediate parameter ALU_B_SI = 3'd2; // Signed Immediate parameter ALU_B_BI = 3'd3; // Branch Displacement parameter ALU_B_LI = 3'd4; // Upper Immediate parameter ALU_B_PI = 3'd5; // PC to use after a reset. parameter ALU_B_JI = 3'd6; // Jump Target (region, j and jal instructions) parameter ALU_B_04 = 3'd7; // Four // Next Microinstruction Constants // parameter NXT_IF = 2'd1; // Go to instruction fetch microinstruction. parameter NXT_SEQ = 2'd2; // Go to next microinstruction. parameter NXT_DSP = 2'd3; // Use dispatch table to get next micro_pc. // Microinstruction Labels (See micro_rom initialization.) // parameter MPC_IF = 6'd1; parameter MPC_ID = 6'd2; parameter MPC_I1 = 6'd3; parameter MPC_I2 = 6'd4; parameter MPC_I3 = 6'd5; parameter MPC_R2_EX = 6'd6; parameter MPC_R1_EX = 6'd7; parameter MPC_IU_EX = 6'd8; parameter MPC_IS_EX = 6'd9; parameter MPC_IL_EX = 6'd10; parameter MPC_BR_CO = 6'd11; parameter MPC_BR_TA = 6'd12; parameter MPC_LB_EA = 6'd13; parameter MPC_LB_ME = 6'd14; parameter MPC_SB_EA = 6'd15; parameter MPC_SB_ME = 6'd16; parameter MPC_JP_EA = 6'd17; /// Microinstruction ROM and its Program Counter // reg [18:0] micro_rom[0:31]; reg [4:0] micro_pc; // Fetch Microinstruction // wire [22:0] micro_ir = micro_rom[micro_pc]; // Microinstruction Fields // // Sample: { W_RD_ALU, PC_000, MEM_00, ALU_DSP, ALU_A_RS, ALU_B_RT, NXT_IF }; // wire ir_en, br_en; // Clock ir, branch_cond. wire [1:0] dest_field; // Source of register number for gpr write. wire dest_src; // Source of data for gpr write. wire [1:0] pc_op; // How to update pc and npc. wire addr_src; // Source of memory address. wire we; // Memory's we input. wire [1:0] size; // Memory's size input. wire alu_op_src; // Source of alu operation. wire [1:0] alu_a_src; // Source of alu input a. wire [2:0] alu_b_src; // Source of alu input b. wire [1:0] seq; // Source of next microinstruction. // Assign Microinstruction Fields // assign {ir_en, br_en, dest_field, dest_src, pc_op, addr_src, we, size, alu_op_src, alu_a_src, alu_b_src, seq } = micro_ir; /// Dispatch Table ROM // reg [10:0] micro_disp[0:127]; // Dispatch Table Address: Combine opcode and func fields // wire [6:0] d_tab_addr = opcode == o_rfmt ? {1'b0,func} : {1'b1,opcode}; // Dispatch Table Fields // wire [4:0] micro_alu_op; // ALU operation from dispatch table. wire [4:0] micro_disp_pc; // micro_pc value for MIPS instruction. // Read Dispatch Table // assign {micro_disp_pc, micro_alu_op} = micro_disp[d_tab_addr]; // Advance Microprogram Program Counter // always @( posedge clk ) if( reset ) micro_pc = MPC_I1; else case( seq ) NXT_SEQ : micro_pc = micro_pc + 1; NXT_IF : micro_pc = 1; NXT_DSP : micro_pc = micro_disp_pc; default : begin micro_pc = 0; $stop; end endcase // Select ALU A Input // always @( alu_a_src or rs_val or pc or sa or reset ) case( alu_a_src ) ALU_A_00: alu_a = 32'h0; ALU_A_RS: alu_a = rs_val; ALU_A_PC: alu_a = pc; ALU_A_SA: alu_a = sa; default: begin alu_a = sa; if( !reset ) $stop; end endcase // Select ALU B Input // always @( alu_b_src or rt_val or immed or pc or ii or reset ) case( alu_b_src ) ALU_B_RT: alu_b = rt_val; ALU_B_SI: alu_b = { immed[15] ? 16'hffff : 16'h0, immed }; ALU_B_BI: alu_b = { immed[15] ? 14'h3fff : 14'h0, immed, 2'h0 }; ALU_B_UI: alu_b = { 16'h0, immed }; ALU_B_LI: alu_b = { immed, 16'h0 }; ALU_B_JI: alu_b = { pc[31:28], ii, 2'h0 }; ALU_B_PI: alu_b = 32'h400000; ALU_B_04: alu_b = 32'h4; default: begin alu_b = rt_val; if( !reset ) $stop; end endcase // Select ALU Operation Source // always @( alu_op_src or micro_alu_op ) case( alu_op_src ) ALU_ADD: alu_op = op_add; // Add. ALU_DSP: alu_op = micro_alu_op; // Use dispatch table operation. endcase // Set Exception Code (using dispatch table output.) // always @( micro_alu_op or reset ) case( micro_alu_op ) op_exc : exc = 1; default : exc = 0; endcase // Select Memory Address Source // always @( addr_src or pc or alu_out ) case( addr_src ) ADDR_PC: addr = pc; ADDR_ALU: addr = alu_out; endcase assign data_out = rt_val; // /// Register Writes (GPR, pc, ir, etc.) // // Write IR and Branch Condition // always @( posedge clk ) if( ir_en ) ir = data_in; always @( posedge clk ) if( br_en ) branch_cond = alu_out[0]; // Write PC or NPC (or neither). // always @( posedge clk ) case( pc_op ) PC_000: ; PC_ADV: pc = npc; PC_BRN: if( branch_cond ) npc = alu_out; PC_ALU: npc = alu_out; endcase // Write GPR // reg [31:0] wb_data; reg [5:0] wb_rd; always @( posedge clk ) begin case( dest_field ) DEST_00: wb_rd = 0; DEST_RD: wb_rd = rd; DEST_RT: wb_rd = rt; default: begin wb_rd = 0; if( !reset ) $stop; end endcase case( dest_src ) GPR_ALU: wb_data = alu_out; GPR_MEM: wb_data = data_in; endcase if( wb_rd ) gpr[wb_rd] = wb_data; end /// /// Initialize Microprogram ROM and Dispatch Table /// integer i; // The always below is an inelegant way to have the synthesis // program read the micro_rom and micro_disp tables. always @( posedge clk ) if( i !== 128 ) begin // Initialize the dispatch table to exceptions. // Entries that are actually used are re-written further below. // for(i=0; i<127; i=i+1) micro_disp[i] = {MPC_IF,op_exc}; // Instruction Fetch and Decode // micro_rom[MPC_IF] = { W_IR_DIN, PC_ADV, MEM_IF, ALU_000, ALU_A_00, ALU_B_00, NXT_SEQ }; micro_rom[MPC_ID] = { W_00_000, PC_ALU, MEM_00, ALU_ADD, ALU_A_PC, ALU_B_04, NXT_DSP }; // Initialize PC and NPC (Done on Reset) // micro_rom[MPC_I1] = { W_00_000, PC_ALU, MEM_00, ALU_ADD, ALU_A_00, ALU_B_PI, NXT_SEQ }; micro_rom[MPC_I2] = { W_00_000, PC_ADV, MEM_00, ALU_ADD, ALU_A_00, ALU_B_00, NXT_SEQ }; micro_rom[MPC_I3] = { W_00_000, PC_ALU, MEM_00, ALU_ADD, ALU_A_PC, ALU_B_04, NXT_IF }; // Format R, Two-register ALU // micro_disp[{1'b0,f_add}] = { MPC_R2_EX,op_add }; micro_disp[{1'b0,f_sub}] = { MPC_R2_EX,op_sub }; micro_disp[{1'b0,f_or}] = { MPC_R2_EX,op_or }; // micro_rom[MPC_R2_EX] = { W_RD_ALU, PC_000, MEM_00, ALU_DSP, ALU_A_RS, ALU_B_RT, NXT_IF }; // Format R, One-register ALU (sll, slr, etc.) // micro_disp[{1'b0,f_sll}] = { MPC_R1_EX,op_sll }; micro_disp[{1'b0,f_srl}] = { MPC_R1_EX,op_srl }; // micro_rom[MPC_R1_EX] = { W_RD_ALU, PC_000, MEM_00, ALU_DSP, ALU_A_SA, ALU_B_RT, NXT_IF }; // Format I, Unsigned ALU // micro_disp[{1'b1,o_andi}] = { MPC_IU_EX,op_and }; micro_disp[{1'b1,o_ori}] = { MPC_IU_EX,op_or }; // micro_rom[MPC_IU_EX] = { W_RT_ALU, PC_000, MEM_00, ALU_DSP, ALU_A_RS, ALU_B_UI, NXT_IF }; // Format I, Signed ALU // micro_disp[{1'b1,o_addi}] = { MPC_IS_EX,op_add }; micro_disp[{1'b1,o_slti}] = { MPC_IS_EX,op_slt }; // micro_rom[MPC_IS_EX] = { W_RT_ALU, PC_000, MEM_00, ALU_DSP, ALU_A_RS, ALU_B_SI, NXT_IF }; // Format I, Load Upper Immediate // micro_disp[{1'b1,o_lui}] = { MPC_IL_EX,op_add }; // rs = 0. // micro_rom[MPC_IL_EX] = { W_RT_ALU, PC_000, MEM_00, ALU_DSP, ALU_A_RS, ALU_B_LI, NXT_IF }; // Format I, Branch // micro_disp[{1'b1,o_bne}] = { MPC_BR_CO,op_sne }; micro_disp[{1'b1,o_beq}] = { MPC_BR_CO,op_seq }; // micro_rom[MPC_BR_CO] = { W_BR_ALU, PC_000, MEM_00, ALU_DSP, ALU_A_RS, ALU_B_RT, NXT_SEQ }; micro_rom[MPC_BR_TA] = { W_00_000, PC_BRN, MEM_00, ALU_ADD, ALU_A_PC, ALU_B_BI, NXT_IF }; // Format I, Load Unsigned Byte // micro_disp[{1'b1,o_lbu}] = { MPC_LB_EA,op_add }; // micro_rom[MPC_LB_EA] = { W_00_000, PC_000, MEM_00, ALU_DSP, ALU_A_RS, ALU_B_SI, NXT_SEQ }; micro_rom[MPC_LB_ME] = { W_RT_MEM, PC_000, MEM_LB, ALU_ADD, ALU_A_RS, ALU_B_SI, NXT_IF }; // Format I, Store Byte // micro_disp[{1'b1,o_sb}] = { MPC_SB_EA,op_add }; // micro_rom[MPC_SB_EA] = { W_00_000, PC_000, MEM_00, ALU_DSP, ALU_A_RS, ALU_B_SI, NXT_SEQ }; micro_rom[MPC_SB_ME] = { W_00_000, PC_000, MEM_SB, ALU_ADD, ALU_A_RS, ALU_B_SI, NXT_IF }; // Format J, Jump // micro_disp[{1'b1,o_j}] = { MPC_JP_EA,op_add }; // micro_rom[MPC_JP_EA] = { W_00_000, PC_ALU, MEM_00, ALU_DSP, ALU_A_00, ALU_B_JI, NXT_IF }; end 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; parameter op_sne = 9; 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 : alu_out = 0; 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); memory_3 m1(mem_data_out,mem_err_out,addr,size,we,cpu_data_out,clk); endmodule `include "mipsmctb.v"