rlm@8: import CBusUtils::*; rlm@8: import Register::*; rlm@8: rlm@8: import Trace::*; rlm@8: import MemTypes::*; rlm@8: import IProc::*; rlm@8: import ProcTypes::*; rlm@8: import FPGATypes::*; rlm@8: import RegFile::*; rlm@8: import FIFO::*; rlm@8: import BFIFO::*; rlm@8: import Assert::*; rlm@8: rlm@8: import GetPut::*; rlm@8: import GetPutExt::*; rlm@8: import ClientServer::*; rlm@8: import CBus::*; rlm@8: rlm@8: rlm@8: interface IProc; rlm@8: rlm@8: // Interface for testrig rlm@8: interface Put#(Bit#(8)) testrig_fromhost; rlm@8: interface Get#(Bit#(8)) testrig_tohost; rlm@8: rlm@8: // Interface from processor to caches rlm@8: interface Client#(DataReq,DataResp) dmem_client; rlm@8: interface Client#(InstReq,InstResp) imem_client; rlm@8: rlm@8: // Interface for enabling/disabling statistics on the rest of the core rlm@8: interface Get#(Bool) statsEn_get; rlm@8: rlm@8: endinterface rlm@8: rlm@8: rlm@8: typedef enum { PCgen, Exec, Writeback } Stage deriving(Eq,Bits); rlm@8: rlm@8: //----------------------------------------------------------- rlm@8: // Register file module rlm@8: //----------------------------------------------------------- rlm@8: rlm@8: interface RFile; rlm@8: method Action wr( Rindx rindx, Bit#(32) data ); rlm@8: method Bit#(32) rd1( Rindx rindx ); rlm@8: method Bit#(32) rd2( Rindx rindx ); rlm@8: endinterface rlm@8: rlm@8: module mkRFile( RFile ); rlm@8: rlm@8: RegFile#(Rindx,Bit#(32)) rfile <- mkRegFileFull(); rlm@8: rlm@8: method Action wr( Rindx rindx, Bit#(32) data ); rlm@8: rfile.upd( rindx, data ); rlm@8: endmethod rlm@8: rlm@8: method Bit#(32) rd1( Rindx rindx ); rlm@8: return ( rindx == 0 ) ? 0 : rfile.sub(rindx); rlm@8: endmethod rlm@8: rlm@8: method Bit#(32) rd2( Rindx rindx ); rlm@8: return ( rindx == 0 ) ? 0 : rfile.sub(rindx); rlm@8: endmethod rlm@8: rlm@8: endmodule rlm@8: rlm@8: //----------------------------------------------------------- rlm@8: // Helper functions rlm@8: //----------------------------------------------------------- rlm@8: rlm@8: function Bit#(32) slt( Bit#(32) val1, Bit#(32) val2 ); rlm@8: return zeroExtend( pack( signedLT(val1,val2) ) ); rlm@8: endfunction rlm@8: rlm@8: function Bit#(32) sltu( Bit#(32) val1, Bit#(32) val2 ); rlm@8: return zeroExtend( pack( val1 < val2 ) ); rlm@8: endfunction rlm@8: rlm@8: function Bit#(32) rshft( Bit#(32) val ); rlm@8: return zeroExtend(val[4:0]); rlm@8: endfunction rlm@8: rlm@8: //----------------------------------------------------------- rlm@8: // Reference processor rlm@8: //----------------------------------------------------------- rlm@8: rlm@8: rlm@8: module [ModWithCBus#(AvalonAddressWidth,AvalonDataWidth)] mkProc( IProc ); rlm@8: rlm@8: //----------------------------------------------------------- rlm@8: // State rlm@8: rlm@8: // Standard processor state rlm@8: rlm@8: Reg#(Addr) pc <- mkReg(32'h00001000); rlm@8: Reg#(Stage) stage <- mkReg(PCgen); rlm@8: RFile rf <- mkRFile; rlm@8: rlm@8: // Coprocessor state rlm@8: rlm@8: Reg#(Bit#(8)) cp0_tohost <- mkReg(0); rlm@8: mkCBusWideRegRW(valueof(ToHostRegAddr),cp0_tohost); rlm@8: Reg#(Bit#(8)) cp0_fromhost <- mkReg(0); rlm@8: mkCBusWideRegRW(valueof(FromHostRegAddr),cp0_fromhost); rlm@8: Reg#(Bool) cp0_statsEn <- mkReg(False); rlm@8: mkCBusWideRegRW(valueof(StatsEnRegAddr),cp0_statsEn); rlm@8: // Memory request/response state rlm@8: rlm@8: FIFO#(InstReq) instReqQ <- mkBFIFO1(); rlm@8: FIFO#(InstResp) instRespQ <- mkFIFO(); rlm@8: rlm@8: FIFO#(DataReq) dataReqQ <- mkBFIFO1(); rlm@8: FIFO#(DataResp) dataRespQ <- mkFIFO(); rlm@8: rlm@8: // Statistics state rlm@8: rlm@8: Reg#(Int#(25)) num_cycles <- mkReg(25'h0); rlm@8: Reg#(Int#(25)) num_inst <- mkReg(25'h0); rlm@8: rlm@8: //----------------------------------------------------------- rlm@8: // Rules rlm@8: rlm@8: let pc_plus4 = pc + 4; rlm@8: rlm@8: rule pcgen ( stage == PCgen ); rlm@8: traceTiny("pc",pc); rlm@8: traceTiny("stage","P"); rlm@8: instReqQ.enq( LoadReq{ addr:pc, tag:0 } ); rlm@8: stage <= Exec; rlm@8: endrule rlm@8: rlm@8: rule exec ( stage == Exec ); rlm@8: rlm@8: // Some abbreviations rlm@8: let sext = signExtend; rlm@8: let zext = zeroExtend; rlm@8: let sra = signedShiftRight; rlm@8: rlm@8: // Get the instruction rlm@8: rlm@8: instRespQ.deq(); rlm@8: Instr inst rlm@8: = case ( instRespQ.first() ) matches rlm@8: tagged LoadResp .ld : return unpack(ld.data); rlm@8: tagged StoreResp .st : return ?; rlm@8: endcase; rlm@8: rlm@8: // Some default variables rlm@8: Stage next_stage = PCgen; rlm@8: Addr next_pc = pc_plus4; rlm@8: rlm@8: // Tracing rlm@8: traceTiny("stage","X"); rlm@8: traceTiny("exInstTiny",inst); rlm@8: traceFull("exInstFull",inst); rlm@8: rlm@8: case ( inst ) matches rlm@8: rlm@8: // -- Memory Ops ------------------------------------------------ rlm@8: rlm@8: tagged LW .it : rlm@8: begin rlm@8: Addr addr = rf.rd1(it.rbase) + sext(it.offset); rlm@8: dataReqQ.enq( LoadReq{ addr:addr, tag:zeroExtend(it.rdst) } ); rlm@8: next_stage = Writeback; rlm@8: end rlm@8: rlm@8: tagged SW .it : rlm@8: begin rlm@8: Addr addr = rf.rd1(it.rbase) + sext(it.offset); rlm@8: dataReqQ.enq( StoreReq{ tag:0, addr:addr, data:rf.rd1(it.rsrc) } ); rlm@8: next_stage = Writeback; rlm@8: end rlm@8: rlm@8: // -- Simple Ops ------------------------------------------------ rlm@8: rlm@8: tagged ADDIU .it : rf.wr( it.rdst, rf.rd1(it.rsrc) + sext(it.imm) ); rlm@8: tagged SLTI .it : rf.wr( it.rdst, slt( rf.rd1(it.rsrc), sext(it.imm) ) ); rlm@8: tagged SLTIU .it : rf.wr( it.rdst, sltu( rf.rd1(it.rsrc), sext(it.imm) ) ); rlm@8: tagged ANDI .it : rlm@8: begin rlm@8: Bit#(32) zext_it_imm = zext(it.imm); rlm@8: rf.wr( it.rdst, rf.rd1(it.rsrc) & zext_it_imm ); rlm@8: end rlm@8: tagged ORI .it : rlm@8: begin rlm@8: Bit#(32) zext_it_imm = zext(it.imm); rlm@8: rf.wr( it.rdst, rf.rd1(it.rsrc) | zext_it_imm ); rlm@8: end rlm@8: tagged XORI .it : rlm@8: begin rlm@8: Bit#(32) zext_it_imm = zext(it.imm); rlm@8: rf.wr( it.rdst, rf.rd1(it.rsrc) ^ zext_it_imm ); rlm@8: end rlm@8: tagged LUI .it : rlm@8: begin rlm@8: Bit#(32) zext_it_imm = zext(it.imm); rlm@8: rf.wr( it.rdst, (zext_it_imm << 32'd16) ); rlm@8: end rlm@8: rlm@8: tagged SLL .it : rlm@8: begin rlm@8: Bit#(32) zext_it_shamt = zext(it.shamt); rlm@8: rf.wr( it.rdst, rf.rd1(it.rsrc) << zext_it_shamt ); rlm@8: end rlm@8: tagged SRL .it : rlm@8: begin rlm@8: Bit#(32) zext_it_shamt = zext(it.shamt); rlm@8: rf.wr( it.rdst, rf.rd1(it.rsrc) >> zext_it_shamt ); rlm@8: end rlm@8: tagged SRA .it : rlm@8: begin rlm@8: Bit#(32) zext_it_shamt = zext(it.shamt); rlm@8: rf.wr( it.rdst, sra( rf.rd1(it.rsrc), zext_it_shamt )); rlm@8: end rlm@8: tagged SLLV .it : rf.wr( it.rdst, rf.rd1(it.rsrc) << rshft(rf.rd2(it.rshamt)) ); rlm@8: tagged SRLV .it : rf.wr( it.rdst, rf.rd1(it.rsrc) >> rshft(rf.rd2(it.rshamt)) ); rlm@8: tagged SRAV .it : rf.wr( it.rdst, sra( rf.rd1(it.rsrc), rshft(rf.rd2(it.rshamt)) ) ); rlm@8: tagged ADDU .it : rf.wr( it.rdst, rf.rd1(it.rsrc1) + rf.rd2(it.rsrc2) ); rlm@8: tagged SUBU .it : rf.wr( it.rdst, rf.rd1(it.rsrc1) - rf.rd2(it.rsrc2) ); rlm@8: tagged AND .it : rf.wr( it.rdst, rf.rd1(it.rsrc1) & rf.rd2(it.rsrc2) ); rlm@8: tagged OR .it : rf.wr( it.rdst, rf.rd1(it.rsrc1) | rf.rd2(it.rsrc2) ); rlm@8: tagged XOR .it : rf.wr( it.rdst, rf.rd1(it.rsrc1) ^ rf.rd2(it.rsrc2) ); rlm@8: tagged NOR .it : rf.wr( it.rdst, ~(rf.rd1(it.rsrc1) | rf.rd2(it.rsrc2)) ); rlm@8: tagged SLT .it : rf.wr( it.rdst, slt( rf.rd1(it.rsrc1), rf.rd2(it.rsrc2) ) ); rlm@8: tagged SLTU .it : rf.wr( it.rdst, sltu( rf.rd1(it.rsrc1), rf.rd2(it.rsrc2) ) ); rlm@8: rlm@8: // -- Branches -------------------------------------------------- rlm@8: rlm@8: tagged BLEZ .it : rlm@8: if ( signedLE( rf.rd1(it.rsrc), 0 ) ) rlm@8: next_pc = pc_plus4 + (sext(it.offset) << 2); rlm@8: rlm@8: tagged BGTZ .it : rlm@8: if ( signedGT( rf.rd1(it.rsrc), 0 ) ) rlm@8: next_pc = pc_plus4 + (sext(it.offset) << 2); rlm@8: rlm@8: tagged BLTZ .it : rlm@8: if ( signedLT( rf.rd1(it.rsrc), 0 ) ) rlm@8: next_pc = pc_plus4 + (sext(it.offset) << 2); rlm@8: rlm@8: tagged BGEZ .it : rlm@8: if ( signedGE( rf.rd1(it.rsrc), 0 ) ) rlm@8: next_pc = pc_plus4 + (sext(it.offset) << 2); rlm@8: rlm@8: tagged BEQ .it : rlm@8: if ( rf.rd1(it.rsrc1) == rf.rd2(it.rsrc2) ) rlm@8: next_pc = pc_plus4 + (sext(it.offset) << 2); rlm@8: rlm@8: tagged BNE .it : rlm@8: if ( rf.rd1(it.rsrc1) != rf.rd2(it.rsrc2) ) rlm@8: next_pc = pc_plus4 + (sext(it.offset) << 2); rlm@8: rlm@8: // -- Jumps ----------------------------------------------------- rlm@8: rlm@8: tagged J .it : rlm@8: next_pc = { pc_plus4[31:28], it.target, 2'b0 }; rlm@8: rlm@8: tagged JR .it : rlm@8: next_pc = rf.rd1(it.rsrc); rlm@8: rlm@8: tagged JAL .it : rlm@8: begin rlm@8: rf.wr( 31, pc_plus4 ); rlm@8: next_pc = { pc_plus4[31:28], it.target, 2'b0 }; rlm@8: end rlm@8: rlm@8: tagged JALR .it : rlm@8: begin rlm@8: rf.wr( it.rdst, pc_plus4 ); rlm@8: next_pc = rf.rd1(it.rsrc); rlm@8: end rlm@8: rlm@8: // -- Cop0 ------------------------------------------------------ rlm@8: rlm@8: tagged MTC0 .it : rlm@8: case ( it.cop0dst ) rlm@8: 5'd10 : cp0_statsEn <= unpack(truncate(rf.rd1(it.rsrc))); rlm@8: 5'd21 : cp0_tohost <= truncate(rf.rd1(it.rsrc)); rlm@8: default : rlm@8: $display( " RTL-ERROR : %m : Illegal MTC0 cop0dst register!" ); rlm@8: endcase rlm@8: rlm@8: tagged MFC0 .it : rlm@8: case ( it.cop0src ) rlm@8: 5'd10 : rf.wr( it.rdst, zext(pack(cp0_statsEn)) ); rlm@8: 5'd20 : rf.wr( it.rdst, zext(cp0_fromhost) ); rlm@8: 5'd21 : rf.wr( it.rdst, zext(cp0_tohost) ); rlm@8: default : rlm@8: $display( " RTL-ERROR : %m : Illegal MFC0 cop0src register!" ); rlm@8: endcase rlm@8: rlm@8: // -- Illegal --------------------------------------------------- rlm@8: rlm@8: default : rlm@8: $display( " RTL-ERROR : %m : Illegal instruction !" ); rlm@8: rlm@8: endcase rlm@8: rlm@8: stage <= next_stage; rlm@8: pc <= next_pc; rlm@8: rlm@8: if ( cp0_statsEn ) rlm@8: num_inst <= num_inst + 1; rlm@8: rlm@8: endrule rlm@8: rlm@8: rule writeback ( stage == Writeback ); rlm@8: traceTiny("stage","W"); rlm@8: rlm@8: dataRespQ.deq(); rlm@8: case ( dataRespQ.first() ) matches rlm@8: tagged LoadResp .ld : rf.wr( truncate(ld.tag), ld.data ); rlm@8: tagged StoreResp .st : noAction; rlm@8: endcase rlm@8: rlm@8: stage <= PCgen; rlm@8: endrule rlm@8: rlm@8: rule inc_num_cycles; rlm@8: if ( cp0_statsEn ) rlm@8: num_cycles <= num_cycles + 1; rlm@8: endrule rlm@8: rlm@8: //----------------------------------------------------------- rlm@8: // Methods rlm@8: rlm@8: interface Client imem_client; rlm@8: interface Get request = fifoToGet(instReqQ); rlm@8: interface Put response = fifoToPut(instRespQ); rlm@8: endinterface rlm@8: rlm@8: interface Client dmem_client; rlm@8: interface Get request = fifoToGet(dataReqQ); rlm@8: interface Put response = fifoToPut(dataRespQ); rlm@8: endinterface rlm@8: rlm@8: interface Get testrig_tohost = regToGet(cp0_tohost); rlm@8: interface Put testrig_fromhost = regToPut(cp0_fromhost); rlm@8: interface Get statsEn_get = regToGet(cp0_statsEn); rlm@8: rlm@8: endmodule rlm@8: