//////////////////////////////////////////////////////////////////////////////// /// /// Solution to LSU EE 3755 Fall 2001 Homework 6 /// //////////////////////////////////////////////////////////////////////////////// /// Problem 1 and 2 Solution /// `define MEMBASE 'h400000 `define DATABASE 'h10010000 `define TEXTSIZE 'h100 `define MEMSIZE 'h200 `define MEMRANGE `MEMBASE:`MEMBASE+`MEMSIZE-1 `define A(addr) ((addr)-`DATABASE+`MEMBASE+`TEXTSIZE) `define MEM(addr) mem[((addr)-`DATABASE+`MEMBASE+`TEXTSIZE)] module proc(exc,clk); input clk; output exc; reg exc; reg [7:0] mem [`MEMRANGE]; reg [31:0] pc, npc, nnpc, ir; reg [31:0] gpr [0:31]; reg [5:0] opcode, funct; reg [4:0] rs, rt, rd, sa; reg [15:0] immed; reg [25:0] ii; reg [31:0] uimm16, simm16; reg [31:0] branch_target; // Values for funct field. parameter f_sll = 6'h0; parameter f_srl = 6'h2; parameter f_jalr = 6'h9; // HW6: New function code. parameter f_add = 6'h20; parameter f_sub = 6'h22; parameter f_or = 6'h25; parameter f_nor = 6'h27; // HW6: New function code. // Values for opcode field. 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; initial begin exc = 0; pc = 0; npc = 4; end always @( posedge clk ) begin ir = {mem[pc],mem[pc+1],mem[pc+2],mem[pc+3]}; // R Format {opcode,rs,rt,rd,sa,funct} = ir; nnpc = npc + 4; // May be reassigned below. if( !opcode ) begin // // R-Format Instructions case( funct ) f_jalr : {nnpc,gpr[rd]}={gpr[rs],nnpc}; // HW6: jalr f_sll : gpr[rd] = gpr[rt] << sa; f_srl : gpr[rd] = gpr[rt] >> sa; f_add : gpr[rd] = gpr[rs] + gpr[rt]; f_or : gpr[rd] = gpr[rs] | gpr[rt]; f_nor : gpr[rd] = ~( gpr[rs] | gpr[rt] ); // HW6: nor f_sub : gpr[rd] = gpr[rs] - gpr[rt]; default : exc = 1; endcase end else begin // // I- and J-Format Instructions // I Format (Also uses opcode, rs, and rt.) immed = ir[15:0]; // J Format (Also uses opcode.) ii = ir[25:0]; uimm16 = { 16'b0, immed }; simm16 = immed[15] ? { 16'hffff, immed } : uimm16; branch_target = npc + ( simm16 << 2 ); case( opcode ) o_j : nnpc = {npc[31:28],ii,2'b0}; o_beq : if( gpr[rs] == gpr[rt] ) nnpc = branch_target; o_bne : if( gpr[rs] != gpr[rt] ) nnpc = branch_target; o_andi : gpr[rt] = gpr[rs] & uimm16; o_slti : gpr[rt] = gpr[rs] < simm16; o_addi : gpr[rt] = gpr[rs] + simm16; o_ori : gpr[rt] = gpr[rs] | uimm16; o_lui : gpr[rt] = { immed, 16'b0 }; o_lbu : gpr[rt] = { 24'b0, `MEM( gpr[rs] + simm16 ) }; o_sb : `MEM( gpr[rs] + simm16 ) = gpr[rt]; default : exc = 1; endcase end gpr[0] = 0; pc = npc; npc = nnpc; end endmodule module orig_proc(exc,clk); input clk; output exc; reg exc; reg [7:0] mem [`MEMRANGE]; reg [31:0] pc, npc, nnpc, ir; reg [31:0] gpr [0:31]; reg [5:0] opcode, funct; reg [4:0] rs, rt, rd, sa; reg [15:0] immed; reg [25:0] ii; reg [31:0] uimm16, simm16; reg [31:0] branch_target; // Values for 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 opcode field. 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; initial begin exc = 0; pc = 0; npc = 4; end always @( posedge clk ) begin ir = {mem[pc],mem[pc+1],mem[pc+2],mem[pc+3]}; // R Format {opcode,rs,rt,rd,sa,funct} = ir; nnpc = npc + 4; // May be reassigned below. if( !opcode ) begin // // R-Format Instructions case( funct ) f_sll : gpr[rd] = gpr[rt] << sa; f_srl : gpr[rd] = gpr[rt] >> sa; f_add : gpr[rd] = gpr[rs] + gpr[rt]; f_or : gpr[rd] = gpr[rs] | gpr[rt]; f_sub : gpr[rd] = gpr[rs] - gpr[rt]; default : exc = 1; endcase end else begin // // I- and J-Format Instructions // I Format (Also uses opcode, rs, and rt.) immed = ir[15:0]; // J Format (Also uses opcode.) ii = ir[25:0]; uimm16 = { 16'b0, immed }; simm16 = immed[15] ? { 16'hffff, immed } : uimm16; branch_target = npc + ( simm16 << 2 ); case( opcode ) o_j : nnpc = {npc[31:28],ii,2'b0}; o_beq : if( gpr[rs] == gpr[rt] ) nnpc = branch_target; o_bne : if( gpr[rs] != gpr[rt] ) nnpc = branch_target; o_andi : gpr[rt] = gpr[rs] & uimm16; o_slti : gpr[rt] = gpr[rs] < simm16; o_addi : gpr[rt] = gpr[rs] + simm16; o_ori : gpr[rt] = gpr[rs] | uimm16; o_lui : gpr[rt] = { immed, 16'b0 }; o_lbu : gpr[rt] = { 24'b0, `MEM( gpr[rs] + simm16 ) }; o_sb : `MEM( gpr[rs] + simm16 ) = gpr[rt]; default : exc = 1; endcase end gpr[0] = 0; pc = npc; npc = nnpc; end endmodule module test_shell(); test_proc #(1) s(); endmodule module test_sol(); test_proc #(2) s(); endmodule module test_prog(); test_proc #(4) s(); endmodule module test_proc(); parameter mode = 2; parameter mode_test_shell = 1; parameter mode_test_solution = 2; parameter mode_read_trace = 3; parameter mode_write_trace = 4; integer read_trace, write_trace; parameter tr_size = 50; wire exception; reg clk; proc p1(exception,clk); reg [31:0] gpr_shadow [0:31]; reg [319:0] isource[`MEMBASE>>2:((`MEMBASE+`MEMSIZE)>>2)-1]; reg [31:0] regname [0:31]; integer i, reg_old, reg_new; integer icount; reg [31:0] tr_pc [1:tr_size]; reg [31:0] tr_regv [1:tr_size]; reg [4:0] tr_regno [1:tr_size]; integer tr_fd, tr_icount_end; integer changed_reg, changed_reg_count; always begin clk = 0; #10; clk = 1; #10; end task initmem; input [31:0] addr; input [31:0] text; input [319:0] source; begin if( addr & 3 ) begin $display("Unaligned instruction address, 0x%h",addr); $stop; end if( addr < `MEMBASE || addr >= `MEMBASE + `TEXTSIZE ) begin $display("Address 0x%h out of range.",addr); $stop; end {p1.mem[addr],p1.mem[addr+1],p1.mem[addr+2],p1.mem[addr+3]} = text; while( source[319:312] === 8'b0 ) source = {source[311:0]," "}; isource[addr>>2] = source; end endtask task initdmem; input [31:0] addr; input [31:0] word; reg [31:0] daddr; begin if( addr & 3 ) begin $display("Unaligned data address, 0x%h",addr); $stop; end if( addr < `DATABASE || `A(addr) >= `MEMBASE + `MEMSIZE ) begin $display("Data address 0x%h out of range.",addr); $stop; end daddr = `A(addr); {p1.mem[daddr],p1.mem[daddr+1],p1.mem[daddr+2],p1.mem[daddr+3]} = word; end endtask integer rno; task initregs; input [31:0] name; input [3:0] cnt; integer i; for(i=0; i 0x%h (%d)", i, regname[i], gpr_shadow[i], reg_old, p1.gpr[i], reg_new); gpr_shadow[i] = p1.gpr[i]; end if( write_trace ) $fdisplay(tr_fd, " tr_regno[%d] = %d; tr_regv[%d] = 'h%h;", icount, changed_reg, icount, gpr_shadow[changed_reg]); if( !exception && read_trace ) begin if( changed_reg_count > 1 ) begin $display("Too many registers, %d, changed.\n", changed_reg_count); $stop; end if( tr_regno[icount] != changed_reg ) begin $display("FAIL: Wrong register modified %d should change, %d changed.", tr_regno[icount],changed_reg); $stop; end if( tr_regv[icount] != gpr_shadow[changed_reg] ) begin $display("FAIL: Wrong value written. 0x%h (correct) != 0x%h", tr_regv[icount],gpr_shadow[changed_reg]); $stop; end end end if( write_trace ) begin if( icount > tr_size ) $display("WARNING!!! Increase tr_size from %d to at least %d.\n", tr_size,icount); $fdisplay(tr_fd," tr_icount_end = %d;",icount); $fclose(tr_fd); end if( read_trace ) begin if( icount != tr_icount_end ) begin $display("FAIL: Valid instruction unrecognized."); end else begin $display("PASS: Correctly executed %d instructions.",icount); end end if( exception ) begin if( p1.ir == 'hc ) $display("Ending at a syscall instruction."); else $display("Illegal instruction exception at address 0x%h", p1.pc); end $stop; end endmodule