//********************************************************************** // Reference processor implementation //---------------------------------------------------------------------- // $Id: mkProc.bsv,v 1.1 2007/03/21 22:27:21 jrk Exp $ // package mkProc; import EHR2::*; import Vector :: * ; import Trace::*; import MemTypes::*; import IProc::*; import ProcTypes::*; import RegFile::*; import FIFO::*; import BFIFO::*; import SFIFO_EHR::*; import SFIFO::*; import Assert::*; import GetPut::*; import GetPutExt::*; import ClientServer::*; import IBHT::*; import mkBHT::*; typedef enum { PCgen, Exec, Writeback } Stage deriving(Eq,Bits); typedef union tagged { struct {Rindx dest; Bit#(32) data;} WB_ALU; //Bit#(32) WB_Host; Rindx WB_Load; void WB_Store; } WBResult deriving (Eq,Bits); //----------------------------------------------------------- // Register file module //----------------------------------------------------------- interface RFile; method Action wr( Rindx rindx, Bit#(32) data ); method Bit#(32) rd1( Rindx rindx ); method Bit#(32) rd2( Rindx rindx ); endinterface module mkRFile( RFile ); RegFile#(Rindx,Bit#(32)) rfile <- mkRegFileFull(); method Action wr( Rindx rindx, Bit#(32) data ); rfile.upd( rindx, data ); endmethod method Bit#(32) rd1( Rindx rindx ); return ( rindx == 0 ) ? 0 : rfile.sub(rindx); endmethod method Bit#(32) rd2( Rindx rindx ); return ( rindx == 0 ) ? 0 : rfile.sub(rindx); endmethod endmodule module mkEHRFile( RFile ); Vector#(32,EHR2_Reg#(Bit#(32))) rvec = newVector(); for ( Integer x = 0; x < 32; x = x + 1 ) rvec[x] <- mkEHR2_Reg(0); method Action wr( Rindx rindx, Bit#(32) data ); select(rvec,rindx).write_0(data); endmethod method Bit#(32) rd1( Rindx rindx ); return ( rindx == 0 ) ? 0 : select(rvec,rindx).read_1(); endmethod method Bit#(32) rd2( Rindx rindx ); return ( rindx == 0 ) ? 0 : select(rvec,rindx).read_1(); endmethod endmodule //----------------------------------------------------------- // Helper functions //----------------------------------------------------------- function Bit#(32) slt( Bit#(32) val1, Bit#(32) val2 ); return zeroExtend( pack( signedLT(val1,val2) ) ); endfunction function Bit#(32) sltu( Bit#(32) val1, Bit#(32) val2 ); return zeroExtend( pack( val1 < val2 ) ); endfunction function Bit#(32) rshft( Bit#(32) val ); return zeroExtend(val[4:0]); endfunction function Bool findf( Rindx searchval, WBResult val ); return case ( val ) matches tagged WB_ALU .alu : return alu.dest == searchval; tagged WB_Load .ld : return ld == searchval; default : return False; endcase; endfunction function Bool nilFindB( Bool searchval, Bool val ); return False; endfunction function Bool nilFindA( Bool searchval, Addr val ); return False; endfunction function Bool stallfunc( Instr inst, SFIFO#(WBResult, Rindx) f ); Bool raw = case ( inst ) matches tagged LW .i : return f.find(i.rbase); tagged SW .i : return (f.find(i.rbase) || f.find2(i.rsrc)); tagged ADDIU .i : return f.find(i.rsrc); tagged SLTI .i : return f.find(i.rsrc); tagged SLTIU .i : return f.find(i.rsrc); tagged ANDI .i : return f.find(i.rsrc); tagged ORI .i : return f.find(i.rsrc); tagged XORI .i : return f.find(i.rsrc); tagged BEQ .i : return (f.find(i.rsrc1) || f.find2(i.rsrc2)); tagged BNE .i : return (f.find(i.rsrc1) || f.find2(i.rsrc2)); tagged BLEZ .i : return f.find(i.rsrc); tagged BGTZ .i : return f.find(i.rsrc); tagged SLL .i : return f.find(i.rsrc); tagged SRL .i : return f.find(i.rsrc); tagged SRA .i : return f.find(i.rsrc); tagged SLLV .i : return (f.find(i.rsrc) || f.find2(i.rshamt)); tagged SRLV .i : return (f.find(i.rsrc) || f.find2(i.rshamt)); tagged SRAV .i : return (f.find(i.rsrc) || f.find2(i.rshamt)); tagged ADDU .i : return (f.find(i.rsrc1) || f.find2(i.rsrc2)); tagged SUBU .i : return (f.find(i.rsrc1) || f.find2(i.rsrc2)); tagged AND .i : return (f.find(i.rsrc1) || f.find2(i.rsrc2)); tagged OR .i : return (f.find(i.rsrc1) || f.find2(i.rsrc2)); tagged XOR .i : return (f.find(i.rsrc1) || f.find2(i.rsrc2)); tagged NOR .i : return (f.find(i.rsrc1) || f.find2(i.rsrc2)); tagged SLT .i : return (f.find(i.rsrc1) || f.find2(i.rsrc2)); tagged SLTU .i : return (f.find(i.rsrc1) || f.find2(i.rsrc2)); tagged JR .i : return f.find(i.rsrc); tagged JALR .i : return f.find(i.rsrc); tagged BLTZ .i : return f.find(i.rsrc); tagged BGEZ .i : return f.find(i.rsrc); tagged MTC0 .i : return f.find(i.rsrc); default : return False; endcase; return raw; endfunction function Bool isBranch( Instr inst ); Bool raw = case ( inst ) matches tagged BLEZ .it : return True; tagged BGTZ .it : return True; tagged BLTZ .it : return True; tagged BGEZ .it : return True; tagged BEQ .it : return True; tagged BNE .it : return True; tagged J .it : return True; tagged JR .it : return True; tagged JAL .it : return True; tagged JALR .it : return True; default : return False; endcase; return raw; //return False; endfunction //----------------------------------------------------------- // Reference processor //----------------------------------------------------------- (* synthesize *) (* descending_urgency = "writeback, exec, exec_br, pcgen" *) module mkProc( IProc ); //----------------------------------------------------------- // State // Standard processor state //Reg#(Addr) pc <- mkReg(32'h00001000); EHR2_Reg#(Addr) pc <- mkEHR2_Reg(32'h00001000); //FIFO#(Addr) pcQ <- mkFIFO(); //FIFO#(Bool) takenQ <- mkFIFO(); SFIFO#(Addr,Bool) pcQ <- mkSFIFO2_Psched(nilFindA); SFIFO#(Bool,Bool) takenQ <- mkSFIFO2_Psched(nilFindB); //FIFO#(Addr) pcQ <- mkSizedFIFO(2); Reg#(Stage) stage <- mkReg(PCgen); RFile rf <- mkEHRFile; //SFIFO#(WBResult, Rindx) wbQ <- mkSizedSFIFO(2, findf); //SFIFO#(WBResult, Rindx) wbQ <- mkSFIFO(findf); SFIFO#(WBResult, Rindx) wbQ <- mkSFIFO2_Psched(findf); // Coprocessor state Reg#(Bit#(8)) cp0_tohost <- mkReg(0); Reg#(Bit#(8)) cp0_fromhost <- mkReg(0); Reg#(Bool) cp0_statsEn <- mkReg(False); // Memory request/response state EHR2_Reg#(Bit#(8)) epoch <- mkEHR2_Reg(8'h0); //Reg#(Bit#(8)) epoch <- mkReg(8'h0); FIFO#(InstReq) instReqQ <- mkBFIFO1(); FIFO#(InstResp) instRespQ <- mkBFIFO1(); FIFO#(DataReq) dataReqQ <- mkBFIFO1(); FIFO#(DataResp) dataRespQ <- mkFIFO(); // Statistics state Reg#(Int#(25)) num_cycles <- mkReg(25'h0); Reg#(Int#(25)) num_inst <- mkReg(25'h0); // Branch Predictor IBHT bht <- mkBHT(); //----------------------------------------------------------- // Rules //let pc_plus4 = pc.read_1() + 4; let pc1 = pc.read_1(); let pc0 = pc.read_0(); let epoch1 = epoch.read_1(); let epoch0 = epoch.read_0(); /* let pc1 = pc; let pc0 = pc; let epoch1 = epoch; let epoch0 = epoch; */ let pc_plus4 = pc1 + 4; //rule pcgen ( stage == PCgen ); rule pcgen ( True ); traceTiny("pc",pc1); traceTiny("stage","P"); instReqQ.enq( LoadReq{ addr:pc1, tag:epoch1 } ); NextPC nextPC = bht.nextPC(pc_plus4); pcQ.enq( pc_plus4 ); takenQ.enq( nextPC.branchTaken ); pc.write_1(nextPC.target); //pc <= nextPC.target; //stage <= Exec; endrule rule discard ( instRespQ.first() matches tagged LoadResp .ld &&& ld.tag != epoch0); traceTiny("stage","D"); instRespQ.deq(); endrule rule exec_br ( instRespQ.first() matches tagged LoadResp .ld &&& ld.tag == epoch0 &&& unpack(ld.data) matches .inst &&& !stallfunc(inst, wbQ) &&& isBranch(inst) ); // Some abbreviations let sext = signExtend; let zext = zeroExtend; let sra = signedShiftRight; // Some default variables Stage next_stage = Writeback; Addr next_pc = pcQ.first(); Bool predictedTaken = takenQ.first(); Bool branchTaken = False; Addr newPC = next_pc; Bool isJumpReg = False; // Tracing traceTiny("stage","X"); traceTiny("exInstTiny",inst); traceFull("exInstFull",inst); case ( inst ) matches // -- Branches -------------------------------------------------- tagged BLEZ .it : begin if ( signedLE( rf.rd1(it.rsrc), 0 ) ) begin newPC = next_pc + (sext(it.offset) << 2); branchTaken = True; end next_stage = PCgen; end tagged BGTZ .it : begin if ( signedGT( rf.rd1(it.rsrc), 0 ) ) begin newPC = next_pc + (sext(it.offset) << 2); branchTaken = True; end next_stage = PCgen; end tagged BLTZ .it : begin if ( signedLT( rf.rd1(it.rsrc), 0 ) ) begin newPC = next_pc + (sext(it.offset) << 2); branchTaken = True; end next_stage = PCgen; end tagged BGEZ .it : begin if ( signedGE( rf.rd1(it.rsrc), 0 ) ) begin newPC = next_pc + (sext(it.offset) << 2); branchTaken = True; end next_stage = PCgen; end tagged BEQ .it : begin if ( rf.rd1(it.rsrc1) == rf.rd2(it.rsrc2) ) begin newPC = next_pc + (sext(it.offset) << 2); branchTaken = True; end next_stage = PCgen; end tagged BNE .it : begin if ( rf.rd1(it.rsrc1) != rf.rd2(it.rsrc2) ) begin newPC = next_pc + (sext(it.offset) << 2); branchTaken = True; end next_stage = PCgen; end // -- Jumps ----------------------------------------------------- tagged J .it : begin newPC = { next_pc[31:28], it.target, 2'b0 }; next_stage = PCgen; branchTaken = True; end tagged JR .it : begin newPC = rf.rd1(it.rsrc); next_stage = PCgen; branchTaken = True; isJumpReg = True; end tagged JAL .it : begin wbQ.enq( WB_ALU{dest:31, data:next_pc} ); newPC = { next_pc[31:28], it.target, 2'b0 }; branchTaken = True; end tagged JALR .it : begin wbQ.enq( WB_ALU{dest:it.rdst, data:next_pc} ); newPC = rf.rd1(it.rsrc); branchTaken = True; isJumpReg = True; end // -- Illegal --------------------------------------------------- default : $display( " RTL-ERROR : %m : Illegal instruction !" ); endcase Bool mispredict = (branchTaken != predictedTaken); if (!predictedTaken && mispredict && !isJumpReg) begin bht.update(next_pc, newPC); end stage <= next_stage; if (mispredict || isJumpReg) begin // TODO: clear FIFOs instReqQ.clear(); instRespQ.clear(); pcQ.clear(); takenQ.clear(); epoch.write_0(epoch0 + 1); pc.write_0(newPC); //epoch <= epoch0 + 1; //pc <= newPC; end else begin // Dequeue the instruction instRespQ.deq(); pcQ.deq(); takenQ.deq(); end if ( cp0_statsEn ) num_inst <= num_inst + 1; endrule rule exec ( instRespQ.first() matches tagged LoadResp .ld &&& ld.tag == epoch0 &&& unpack(ld.data) matches .inst &&& !stallfunc(inst, wbQ) &&& !isBranch(inst) ); // Some abbreviations let sext = signExtend; let zext = zeroExtend; let sra = signedShiftRight; // Some default variables Stage next_stage = Writeback; Addr next_pc = pcQ.first(); Bool predictedTaken = takenQ.first(); Bool branchTaken = False; Addr newPC = next_pc; Bool isJumpReg = False; // Tracing traceTiny("stage","X"); traceTiny("exInstTiny",inst); traceFull("exInstFull",inst); case ( inst ) matches // -- Memory Ops ------------------------------------------------ tagged LW .it : begin Addr addr = rf.rd1(it.rbase) + sext(it.offset); dataReqQ.enq( LoadReq{ addr:addr, tag:zeroExtend(it.rdst) } ); wbQ.enq( WB_Load(it.rdst) ); end tagged SW .it : begin Addr addr = rf.rd1(it.rbase) + sext(it.offset); dataReqQ.enq( StoreReq{ tag:0, addr:addr, data:rf.rd1(it.rsrc) } ); wbQ.enq( WB_Store() ); end // -- Simple Ops ------------------------------------------------ tagged ADDIU .it : wbQ.enq( WB_ALU{dest:it.rdst, data:(rf.rd1(it.rsrc) + sext(it.imm))} ); tagged SLTI .it : wbQ.enq( WB_ALU{dest:it.rdst, data:(slt( rf.rd1(it.rsrc), sext(it.imm) ))} ); tagged SLTIU .it : wbQ.enq( WB_ALU{dest:it.rdst, data:(sltu( rf.rd1(it.rsrc), sext(it.imm) ))} ); tagged ANDI .it : begin Bit#(32) zext_it_imm = zext(it.imm); wbQ.enq( WB_ALU{dest:it.rdst, data:(rf.rd1(it.rsrc) & zext_it_imm)} ); end tagged ORI .it : begin Bit#(32) zext_it_imm = zext(it.imm); wbQ.enq( WB_ALU{dest:it.rdst, data:(rf.rd1(it.rsrc) | zext_it_imm)} ); end tagged XORI .it : begin Bit#(32) zext_it_imm = zext(it.imm); wbQ.enq( WB_ALU{dest:it.rdst, data:(rf.rd1(it.rsrc) ^ zext_it_imm)} ); end tagged LUI .it : begin Bit#(32) zext_it_imm = zext(it.imm); wbQ.enq( WB_ALU{dest:it.rdst, data:(zext_it_imm << 32'd16)} ); end tagged SLL .it : begin Bit#(32) zext_it_shamt = zext(it.shamt); wbQ.enq( WB_ALU{dest:it.rdst, data:(rf.rd1(it.rsrc) << zext_it_shamt)} ); end tagged SRL .it : begin Bit#(32) zext_it_shamt = zext(it.shamt); wbQ.enq( WB_ALU{dest:it.rdst, data:(rf.rd1(it.rsrc) >> zext_it_shamt)} ); end tagged SRA .it : begin Bit#(32) zext_it_shamt = zext(it.shamt); wbQ.enq( WB_ALU{dest:it.rdst, data:(sra( rf.rd1(it.rsrc), zext_it_shamt ))}); end tagged SLLV .it : wbQ.enq( WB_ALU{dest:it.rdst, data:(rf.rd1(it.rsrc) << rshft(rf.rd2(it.rshamt)))} ); tagged SRLV .it : wbQ.enq( WB_ALU{dest:it.rdst, data:(rf.rd1(it.rsrc) >> rshft(rf.rd2(it.rshamt)))} ); tagged SRAV .it : wbQ.enq( WB_ALU{dest:it.rdst, data:(sra( rf.rd1(it.rsrc), rshft(rf.rd2(it.rshamt)) ))} ); tagged ADDU .it : wbQ.enq( WB_ALU{dest:it.rdst, data:(rf.rd1(it.rsrc1) + rf.rd2(it.rsrc2))} ); tagged SUBU .it : wbQ.enq( WB_ALU{dest:it.rdst, data:(rf.rd1(it.rsrc1) - rf.rd2(it.rsrc2))} ); tagged AND .it : wbQ.enq( WB_ALU{dest:it.rdst, data:(rf.rd1(it.rsrc1) & rf.rd2(it.rsrc2))} ); tagged OR .it : wbQ.enq( WB_ALU{dest:it.rdst, data:(rf.rd1(it.rsrc1) | rf.rd2(it.rsrc2))} ); tagged XOR .it : wbQ.enq( WB_ALU{dest:it.rdst, data:(rf.rd1(it.rsrc1) ^ rf.rd2(it.rsrc2))} ); tagged NOR .it : wbQ.enq( WB_ALU{dest:it.rdst, data:(~(rf.rd1(it.rsrc1) | rf.rd2(it.rsrc2)))} ); tagged SLT .it : wbQ.enq( WB_ALU{dest:it.rdst, data:(slt( rf.rd1(it.rsrc1), rf.rd2(it.rsrc2) ))} ); tagged SLTU .it : wbQ.enq( WB_ALU{dest:it.rdst, data:(sltu( rf.rd1(it.rsrc1), rf.rd2(it.rsrc2) ))} ); // -- Branches -------------------------------------------------- /* tagged BLEZ .it : begin if ( signedLE( rf.rd1(it.rsrc), 0 ) ) begin newPC = next_pc + (sext(it.offset) << 2); branchTaken = True; end next_stage = PCgen; end tagged BGTZ .it : begin if ( signedGT( rf.rd1(it.rsrc), 0 ) ) begin newPC = next_pc + (sext(it.offset) << 2); branchTaken = True; end next_stage = PCgen; end tagged BLTZ .it : begin if ( signedLT( rf.rd1(it.rsrc), 0 ) ) begin newPC = next_pc + (sext(it.offset) << 2); branchTaken = True; end next_stage = PCgen; end tagged BGEZ .it : begin if ( signedGE( rf.rd1(it.rsrc), 0 ) ) begin newPC = next_pc + (sext(it.offset) << 2); branchTaken = True; end next_stage = PCgen; end tagged BEQ .it : begin if ( rf.rd1(it.rsrc1) == rf.rd2(it.rsrc2) ) begin newPC = next_pc + (sext(it.offset) << 2); branchTaken = True; end next_stage = PCgen; end tagged BNE .it : begin if ( rf.rd1(it.rsrc1) != rf.rd2(it.rsrc2) ) begin newPC = next_pc + (sext(it.offset) << 2); branchTaken = True; end next_stage = PCgen; end // -- Jumps ----------------------------------------------------- tagged J .it : begin newPC = { next_pc[31:28], it.target, 2'b0 }; next_stage = PCgen; branchTaken = True; end tagged JR .it : begin newPC = rf.rd1(it.rsrc); next_stage = PCgen; branchTaken = True; isJumpReg = True; end tagged JAL .it : begin wbQ.enq( WB_ALU{dest:31, data:next_pc} ); newPC = { next_pc[31:28], it.target, 2'b0 }; branchTaken = True; end tagged JALR .it : begin wbQ.enq( WB_ALU{dest:it.rdst, data:next_pc} ); newPC = rf.rd1(it.rsrc); branchTaken = True; isJumpReg = True; end */ // -- Cop0 ------------------------------------------------------ tagged MTC0 .it : begin case ( it.cop0dst ) 5'd10 : cp0_statsEn <= unpack(truncate(rf.rd1(it.rsrc))); 5'd21 : cp0_tohost <= truncate(rf.rd1(it.rsrc)); default : $display( " RTL-ERROR : %m : Illegal MTC0 cop0dst register!" ); endcase next_stage = PCgen; end tagged MFC0 .it : begin case ( it.cop0src ) 5'd10 : wbQ.enq( WB_ALU{dest:it.rdst, data:(zext(pack(cp0_statsEn)) )}); 5'd20 : wbQ.enq( WB_ALU{dest:it.rdst, data:(zext(cp0_fromhost) )}); 5'd21 : wbQ.enq( WB_ALU{dest:it.rdst, data:(zext(cp0_tohost) )}); default : $display( " RTL-ERROR : %m : Illegal MFC0 cop0src register!" ); endcase end // -- Illegal --------------------------------------------------- default : $display( " RTL-ERROR : %m : Illegal instruction !" ); endcase Bool mispredict = (branchTaken != predictedTaken); if (!predictedTaken && mispredict && !isJumpReg) begin bht.update(next_pc, newPC); end stage <= next_stage; if (mispredict || isJumpReg) begin // TODO: clear FIFOs instReqQ.clear(); instRespQ.clear(); pcQ.clear(); takenQ.clear(); epoch.write_0(epoch0 + 1); pc.write_0(newPC); //epoch <= epoch0 + 1; //pc <= newPC; end else begin // Dequeue the instruction instRespQ.deq(); pcQ.deq(); takenQ.deq(); end if ( cp0_statsEn ) num_inst <= num_inst + 1; endrule //rule writeback ( stage == Writeback ); rule writeback ( True ); traceTiny("stage","W"); wbQ.deq(); case ( wbQ.first() ) matches tagged WB_ALU .alureq : rf.wr( alureq.dest, alureq.data ); //TODO: tagged WB_Host : ?? tagged WB_Load .ldrindx : begin dataRespQ.deq(); case ( dataRespQ.first() ) matches tagged LoadResp .ld : rf.wr( ldrindx, ld.data ); tagged StoreResp .st : $display(" RTL-ERROR : %m : Got StoreResp with WB_Load!"); endcase end tagged WB_Store .streq : begin dataRespQ.deq(); case ( dataRespQ.first() ) matches tagged LoadResp .ld : $display(" RTL-ERROR : %m : Got LoadResp with WB_Store!"); tagged StoreResp .st : noAction; endcase end default : $display( " RTL-ERROR : %m : Unknown WBResult tag!"); endcase stage <= PCgen; endrule rule inc_num_cycles; if ( cp0_statsEn ) num_cycles <= num_cycles + 1; endrule //----------------------------------------------------------- // Methods interface Client imem_client; interface Get request = fifoToGet(instReqQ); interface Put response = fifoToPut(instRespQ); endinterface interface Client dmem_client; interface Get request = fifoToGet(dataReqQ); interface Put response = fifoToPut(dataRespQ); endinterface interface Get testrig_tohost = regToGet(cp0_tohost); interface Put testrig_fromhost = regToPut(cp0_fromhost); interface Get statsEn_get = regToGet(cp0_statsEn); endmodule endpackage