// Copyright (c) 2017 Massachusetts Institute of Technology // Portions Copyright (c) 2019-2020 Bluespec, Inc. // //- // RVFI_DII + CHERI modifications: // Copyright (c) 2020 Jessica Clarke // Copyright (c) 2020 Peter Rugg // Copyright (c) 2020 Jonathan Woodruff // All rights reserved. // // This software was developed by SRI International and the University of // Cambridge Computer Laboratory (Department of Computer Science and // Technology) under DARPA contract HR0011-18-C-0016 ("ECATS"), as part of the // DARPA SSITH research programme. // // This work was supported by NCSC programme grant 4212611/RFA 15971 ("SafeBet"). //- // // Permission is hereby granted, free of charge, to any person // obtaining a copy of this software and associated documentation // files (the "Software"), to deal in the Software without // restriction, including without limitation the rights to use, copy, // modify, merge, publish, distribute, sublicense, and/or sell copies // of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS // BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE // SOFTWARE. `include "ProcConfig.bsv" import Vector::*; import BuildVector::*; import DefaultValue::*; import ClientServer::*; import GetPut::*; import Assert::*; import Cntrs::*; import ConfigReg::*; import FIFO::*; import Fifos::*; import Ehr::*; import Connectable::*; import Types::*; import ProcTypes::*; import CacheUtils::*; import TlbTypes::*; import SynthParam::*; import VerificationPacket::*; import Performance::*; `ifdef PERFORMANCE_MONITORING import PerformanceMonitor::*; import BlueUtils::*; import StatCounters::*; import GenerateHPMVector::*; `endif import HasSpecBits::*; import Exec::*; import FetchStage::*; import ITlb::*; import DTlb::*; import L2Tlb::*; import TlbConnect::*; import EpochManager::*; import PhysRFile::*; import RFileSynth::*; import RenamingTable::*; import ReorderBuffer::*; import ReorderBufferSynth::*; import Scoreboard::*; import ScoreboardSynth::*; import SpecTagManager::*; import SpecFifo::*; import Fpu::*; import MulDiv::*; import ReservationStationEhr::*; import ReservationStationAlu::*; import ReservationStationMem::*; import ReservationStationFpuMulDiv::*; import AluExePipeline::*; import FpuMulDivExePipeline::*; import MemExePipeline::*; import SplitLSQ::*; import StoreBuffer::*; import GlobalSpecUpdate::*; import CCTypes::*; import L1CoCache::*; import L1Bank::*; import IBank::*; import MMIOCore::*; import RenameStage::*; import CommitStage::*; import Bypass::*; import CHERICap::*; import CHERICC_Fat::*; import Bag::*; import VnD::*; `ifdef RVFI_DII import Toooba_RVFI_DII_Bridge::*; `endif import CsrFile :: *; // ================================================================ // Toooba import Cur_Cycle :: *; import FIFOF :: *; import GetPut_Aux :: *; `ifdef INCLUDE_GDB_CONTROL import DM_CPU_Req_Rsp :: *; `endif `ifdef INCLUDE_TANDEM_VERIF import Trace_Data2 :: *; `endif // ================================================================ `ifdef SECURITY `define SECURITY_OR_INCLUDE_GDB_CONTROL `elsif INCLUDE_GDB_CONTROL `define SECURITY_OR_INCLUDE_GDB_CONTROL `endif interface CoreReq; method Action start( Bool running, Addr startpc, Addr toHostAddr, Addr fromHostAddr ); method Action perfReq(PerfLocation loc, PerfType t); endinterface interface CoreIndInv; method ActionValue#(ProcPerfResp) perfResp; method ActionValue#(void) terminate; endinterface interface CoreDeadlock; interface Get#(L1DCRqStuck) dCacheCRqStuck; interface Get#(L1DPRqStuck) dCachePRqStuck; interface Get#(L1ICRqStuck) iCacheCRqStuck; interface Get#(L1IPRqStuck) iCachePRqStuck; interface Get#(RenameStuck) renameInstStuck; interface Get#(RenameStuck) renameCorrectPathStuck; interface Get#(CommitStuck) commitInstStuck; interface Get#(CommitStuck) commitUserInstStuck; interface Get#(void) checkStarted; endinterface interface CoreRenameDebug; interface Get#(RenameErrInfo) renameErr; endinterface interface Core; // core request & indication interface CoreReq coreReq; interface CoreIndInv coreIndInv; // coherent caches to LLC interface ChildCacheToParent#(L1Way, void) dCacheToParent; interface ChildCacheToParent#(L1Way, void) iCacheToParent; // DMA to LLC interface TlbMemClient tlbToMem; // MMIO interface MMIOCoreToPlatform mmioToPlatform; // stats enable method ActionValue#(Bool) sendDoStats; method Action recvDoStats(Bool x); // detect deadlock: only in use when macro CHECK_DEADLOCK is defined interface CoreDeadlock deadlock; // debug rename interface CoreRenameDebug renameDebug; // Bluespec: external interrupt requests targeting Machine and Supervisor modes method Action setMEIP (Bit #(1) v); method Action setSEIP (Bit #(1) v); `ifdef RVFI_DII interface Toooba_RVFI_DII_Server rvfi_dii_server; `endif `ifdef INCLUDE_GDB_CONTROL interface Server #(Bool, Bool) hart_run_halt_server; interface Server #(DM_CPU_Req #(5, 64), DM_CPU_Rsp #(64)) hart_gpr_mem_server; `ifdef ISA_F interface Server #(DM_CPU_Req #(5, 64), DM_CPU_Rsp #(64)) hart_fpr_mem_server; `endif interface Server #(DM_CPU_Req #(12, 64), DM_CPU_Rsp #(64)) hart_csr_mem_server; `endif `ifdef INCLUDE_TANDEM_VERIF // Note: this is a SupSize vector of streams of Trace_Data2 structs, // each of which has a serialnum field. Each of the SupSize // streams has serialnums in increasing order. Each serialnum // appears exactly once in exactly one of the streams. Thus, the // channels can easily be merged into a single program-order stream. interface Vector #(SupSize, Get #(Trace_Data2)) v_to_TV; `endif `ifdef PERFORMANCE_MONITORING method Action events_llc(EventsLL events); method Action events_tgc(EventsTGC events); `endif endinterface // fixpoint to instantiate modules interface CoreFixPoint; interface Vector#(AluExeNum, AluExePipeline) aluExeIfc; interface Vector#(FpuMulDivExeNum, FpuMulDivExePipeline) fpuMulDivExeIfc; interface MemExePipeline memExeIfc; method Action killAll; // kill everything: used by commit stage interface Reg#(Bool) doStatsIfc; method Bool pendingIncorrectSpec; endinterface `ifdef CONTRACTS_VERIFY typedef 32 BagSz; `endif typedef enum { `ifdef INCLUDE_GDB_CONTROL CORE_HALTING, CORE_HALTED, `endif CORE_RUNNING } Core_Run_State deriving (Bits, Eq, FShow); (* synthesize *) module mkCore#(CoreId coreId)(Core); let verbose = False; // ================================================================ Integer verbosity = 0; // More levels of verbosity control than 'Bool verbose' Reg#(Bool) outOfReset <- mkReg(False); rule rl_outOfReset if (!outOfReset); $fwrite(stderr, "mkProc came out of reset\n"); outOfReset <= True; endrule Reg#(Bool) started <- mkReg(False); // ================================================================ `ifdef INCLUDE_GDB_CONTROL // Using a ConfigReg since scheduling of reads/writes not critical (TODO: verify this) Reg #(Core_Run_State) rg_core_run_state <- mkConfigReg (CORE_RUNNING); `endif `ifdef INCLUDE_TANDEM_VERIF Vector #(SupSize, FIFOF #(Trace_Data2)) v_f_to_TV <- replicateM (mkFIFOF); `endif `ifdef PERFORMANCE_MONITORING Array #(Reg #(EventsCore)) hpm_core_events <- mkDRegOR (2, unpack (0)); `endif // ================================================================ // front end FetchStage fetchStage <- mkFetchStage; ITlb iTlb = fetchStage.iTlbIfc; ICoCache iMem = fetchStage.iMemIfc; // ================================================================ // If using Direct Instruction Injection then make a // bridge that can insert instructions. `ifdef RVFI_DII Toooba_RVFI_DII_Bridge_IFC rvfi_bridge <- mkTooobaRVFIDIIBridge; mkConnection(rvfi_bridge.dii, fetchStage.diiIfc); `endif // back end RFileSynth rf <- mkRFileSynth; // Bluespec: CsrFile including external interrupt request methods CsrFile csrf <- mkCsrFile(zeroExtend(coreId)); // hartid in CSRF should be core id RegRenamingTable regRenamingTable <- mkRegRenamingTable; EpochManager epochManager <- mkEpochManager; SpecTagManager specTagManager <- mkSpecTagManager; ReorderBufferSynth rob <- mkReorderBufferSynth; `ifdef PERFORMANCE_MONITORING `ifdef CONTRACTS_VERIFY Vector#(SupSize, Bag#(BagSz, CapMem, CapMem)) bags; for(Integer i = 0; i < valueof(SupSize); i=i+1) begin bags[i] <- mkSmallBag; end Vector#(SupSize, Bag#(BagSz, CapMem, CapMem)) returnBags; for(Integer i = 0; i < valueof(SupSize); i=i+1) begin returnBags[i] <- mkSmallBag; end `endif `endif // We have two scoreboards: one conservative and other aggressive // - Aggressive sb is checked at rename stage, so inst after rename may be issued early // - Conservative sb is checked at reg read stage, to ensure correctness // Every pipeline should set both sb if it needs to write reg // - Conservative sb is set when data is written into rf // - Aggressive sb is set when pipeline sends out wakeup for reservation staion // Note that wakeup can be sent early if it knows when the data will be produced ScoreboardCons sbCons <- mkScoreboardCons; // conservative sb ScoreboardAggr sbAggr <- mkScoreboardAggr; // aggressive sb // MMIO: need to track in flight CSR inst or interrupt; note we can at most // 1 CSR inst or 1 interrupt in ROB, so just use 1 bit track it. Commit // stage use port 0 to reset this, and Rename stage use port 1 to set this. Ehr#(2, Bool) csrInstOrInterruptInflight <- mkEhr(False); Reg#(Bool) csrInstOrInterruptInflight_commit = csrInstOrInterruptInflight[0]; Reg#(Bool) csrInstOrInterruptInflight_rename = csrInstOrInterruptInflight[1]; MMIOCoreInput mmioInIfc = (interface MMIOCoreInput; interface fetch = fetchStage.mmioIfc; method getMSIP = csrf.getMSIP; method setMSIP = csrf.setMSIP; method setMTIP = csrf.setMTIP; method noInflightCSRInstOrInterrupt = !csrInstOrInterruptInflight[0]; method setTime = csrf.setTime; endinterface); MMIOCore mmio <- mkMMIOCore(mmioInIfc); // fix point module to instantiate other function units module mkCoreFixPoint#(CoreFixPoint fix)(CoreFixPoint); // spec update Vector#(AluExeNum, SpeculationUpdate) aluSpecUpdate; for(Integer i = 0; i < valueof(AluExeNum); i = i+1) begin aluSpecUpdate[i] = fix.aluExeIfc[i].specUpdate; end Vector#(FpuMulDivExeNum, SpeculationUpdate) fpuMulDivSpecUpdate; for(Integer i = 0; i < valueof(FpuMulDivExeNum); i = i+1) begin fpuMulDivSpecUpdate[i] = fix.fpuMulDivExeIfc[i].specUpdate; end Vector#(AluExeNum, SpecFifo#(TDiv#(`NUM_SPEC_TAGS,2), FetchTrainBP, 1, 1)) trainBPQ <- replicateM(mkSpecFifoUG(True)); Vector#(AluExeNum, SpeculationUpdate) btqSpecUpdate; for(Integer i = 0; i < valueof(AluExeNum); i = i+1) begin btqSpecUpdate[i] = trainBPQ[i].specUpdate; end GlobalSpecUpdate#(CorrectSpecPortNum, ConflictWrongSpecPortNum) globalSpecUpdate <- mkGlobalSpecUpdate( joinSpeculationUpdate( append(append(append(vec(fetchStage.specUpdate, regRenamingTable.specUpdate, specTagManager.specUpdate, fix.memExeIfc.specUpdate), aluSpecUpdate), fpuMulDivSpecUpdate), btqSpecUpdate) ), rob.specUpdate ); // whether perf data is collected Reg#(Bool) doStatsReg <- mkConfigReg(False); // write aggressive elements + wakupe reservation stations function Action writeAggr(Integer wrAggrPort, PhyRIndx dst); action sbAggr.setReady[wrAggrPort].put(dst); for(Integer i = 0; i < valueof(AluExeNum); i = i+1) begin fix.aluExeIfc[i].rsAluIfc.setRegReady[wrAggrPort].put(Valid (dst)); end for(Integer i = 0; i < valueof(FpuMulDivExeNum); i = i+1) begin fix.fpuMulDivExeIfc[i].rsFpuMulDivIfc.setRegReady[wrAggrPort].put(Valid (dst)); end fix.memExeIfc.rsMemIfc.setRegReady[wrAggrPort].put(Valid (dst)); endaction endfunction // write conservative elements function Action writeCons(Integer wrConsPort, PhyRIndx dst, CapPipe data); action rf.write[wrConsPort].wr(dst, cast(data)); sbCons.setReady[wrConsPort].put(dst); endaction endfunction Vector#(AluExeNum, AluExePipeline) aluExe; for(Integer i = 0; i < valueof(AluExeNum); i = i+1) begin Vector#(2, SendBypass) sendBypassIfc; // exe and finish for(Integer sendPort = 0; sendPort < 2; sendPort = sendPort + 1) begin sendBypassIfc[sendPort] = (interface SendBypass; method Action send(PhyRIndx dst, CapPipe data); // broadcast bypass Integer recvPort = valueof(AluExeNum) * sendPort + i; for(Integer j = 0; j < valueof(FpuMulDivExeNum); j = j+1) begin fix.fpuMulDivExeIfc[j].recvBypass[recvPort].recv(dst, data); end fix.memExeIfc.recvBypass[recvPort].recv(dst, data); for(Integer j = 0; j < valueof(AluExeNum); j = j+1) begin fix.aluExeIfc[j].recvBypass[recvPort].recv(dst, data); end endmethod endinterface); end let aluExeInput = (interface AluExeInput; method sbCons_lazyLookup = sbCons.lazyLookup[aluRdPort(i)].get; method rf_rd1 = cast(rf.read[aluRdPort(i)].rd1); method rf_rd2 = cast(rf.read[aluRdPort(i)].rd2); method csrf_rd = csrf.rd; method scaprf_rd = csrf.scrRd; method rob_getPC = rob.getOrigPC[i].get; method rob_getPredPC = rob.getOrigPredPC[i].get; method rob_getOrig_Inst = rob.getOrig_Inst[i].get; method rob_setExecuted = rob.setExecuted_doFinishAlu[i].set; method fetch_train_predictors = trainBPQ[i].enq; method setRegReadyAggr = writeAggr(aluWrAggrPort(i)); interface sendBypass = sendBypassIfc; method writeRegFile = writeCons(aluWrConsPort(i)); method Action redirect(CapMem new_pc, SpecTag spec_tag, InstTag inst_tag, SpecBits spec_bits); if (verbose) begin $display("[ALU redirect - %d] ", i, fshow(new_pc), "; ", fshow(spec_tag), "; ", fshow(inst_tag)); end epochManager.incrementEpoch; fetchStage.redirect(new_pc, spec_bits `ifdef RVFI_DII , inst_tag.dii_next_pid `endif ); globalSpecUpdate.incorrectSpec(False, spec_tag, inst_tag, spec_bits); endmethod method Bool pauseExecute = globalSpecUpdate.pendingIncorrectSpec; method correctSpec = globalSpecUpdate.correctSpec[finishAluCorrectSpecPort(i)].put; method doStats = doStatsReg._read; `ifdef PERFORMANCE_MONITORING `ifdef CONTRACTS_VERIFY method Bool checkTarget(CapMem ppc); Bool ret = False; for(Integer j = 0; j < valueof(SupSize); j=j+1) begin ret = ret || bags[j].isMember(ppc).v; end return ret; endmethod method Bool checkReturnTarget(CapMem ppc); Bool ret = False; for(Integer j = 0; j < valueof(SupSize); j=j+1) begin ret = ret || returnBags[j].isMember(ppc).v; end return ret; endmethod `endif `endif endinterface); aluExe[i] <- mkAluExePipeline(aluExeInput); // truly call fetch method to train branch predictor Bool train_ready = True; `ifdef NO_SPEC_TRAINING train_ready = (trainBPQ[i].first.spec_bits == 0); `endif rule doFetchTrainBP(trainBPQ[i].notEmpty && train_ready); let train = trainBPQ[i].first.data; trainBPQ[i].deq; fetchStage.train_predictors( train.pc, train.nextPc, train.iType, train.taken, train.link, train.trainInfo, train.mispred, train.isCompressed ); endrule end Vector#(FpuMulDivExeNum, FpuMulDivExePipeline) fpuMulDivExe; for(Integer i = 0; i < valueof(FpuMulDivExeNum); i = i+1) begin let fpuMulDivExeInput = (interface FpuMulDivExeInput; method sbCons_lazyLookup = sbCons.lazyLookup[fpuMulDivRdPort(i)].get; method rf_rd1 = compose(getAddr, rf.read[fpuMulDivRdPort(i)].rd1); method rf_rd2 = compose(getAddr, rf.read[fpuMulDivRdPort(i)].rd2); method rf_rd3 = compose(getAddr, rf.read[fpuMulDivRdPort(i)].rd3); method csrf_rd = csrf.rd; method scaprf_rd = csrf.scrRd; method rob_setExecuted = rob.setExecuted_doFinishFpuMulDiv[i].set; method Action writeRegFile(PhyRIndx dst, Data data); writeAggr(fpuMulDivWrAggrPort(i), dst); writeCons(fpuMulDivWrConsPort(i), dst, nullWithAddr(data)); endmethod method conflictWrongSpec = globalSpecUpdate.conflictWrongSpec[finishFpuMulDivConflictWrongSpecPort(i)].put(?); method doStats = doStatsReg._read; endinterface); fpuMulDivExe[i] <- mkFpuMulDivExePipeline(fpuMulDivExeInput); end let memExeInput = (interface MemExeInput; method sbCons_lazyLookup = sbCons.lazyLookup[memRdPort].get; method rf_rd1 = cast(rf.read[memRdPort].rd1); method rf_rd2 = cast(rf.read[memRdPort].rd2); method csrf_rd = csrf.rd; method scaprf_rd = csrf.scrRd; method rob_getPC = rob.getOrigPC[valueof(AluExeNum)].get; // last getPC port method rob_setExecuted_doFinishMem = rob.setExecuted_doFinishMem; `ifdef INCLUDE_TANDEM_VERIF method rob_setExecuted_doFinishMem_RegData = rob.setExecuted_doFinishMem_RegData; `endif method rob_setExecuted_deqLSQ = rob.setExecuted_deqLSQ; method isMMIOAddr = mmio.isMMIOAddr; method mmioReq = mmio.dataReq; method mmioRespVal = mmio.dataRespVal; method mmioRespDeq = mmio.dataRespDeq; method setRegReadyAggr_mem = writeAggr(memWrAggrPort); method setRegReadyAggr_forward = writeAggr(forwardWrAggrPort); method writeRegFile = writeCons(memWrConsPort); method doStats = doStatsReg._read; `ifdef PERFORMANCE_MONITORING `ifdef CONTRACTS_VERIFY method rob_getPredPC = rob.getOrigPredPC[valueof(AluExeNum)].get; // last getOrigPredPC port method rob_getOrig_Inst = rob.getOrig_Inst[valueof(AluExeNum)].get; // last getOrig_Inst port `endif `endif endinterface); let memExe <- mkMemExePipeline(memExeInput); interface aluExeIfc = aluExe; interface fpuMulDivExeIfc = fpuMulDivExe; interface memExeIfc = memExe; method Action killAll; globalSpecUpdate.incorrectSpec(True, ?, ?, 0); endmethod interface doStatsIfc = doStatsReg; method pendingIncorrectSpec = globalSpecUpdate.pendingIncorrectSpec; endmodule CoreFixPoint coreFix <- moduleFix(mkCoreFixPoint); Vector#(AluExeNum, ReservationStationAlu) reservationStationAlu; for(Integer i = 0; i < valueof(AluExeNum); i = i+1) begin reservationStationAlu[i] = coreFix.aluExeIfc[i].rsAluIfc; end Vector#(FpuMulDivExeNum, ReservationStationFpuMulDiv) reservationStationFpuMulDiv; for(Integer i = 0; i < valueof(FpuMulDivExeNum); i = i+1) begin reservationStationFpuMulDiv[i] = coreFix.fpuMulDivExeIfc[i].rsFpuMulDivIfc; end ReservationStationMem reservationStationMem = coreFix.memExeIfc.rsMemIfc; DTlbSynth dTlb = coreFix.memExeIfc.dTlbIfc; SplitLSQ lsq = coreFix.memExeIfc.lsqIfc; StoreBuffer stb = coreFix.memExeIfc.stbIfc; DCoCache dMem = coreFix.memExeIfc.dMemIfc; // L2 TLB L2Tlb l2Tlb <- mkL2Tlb; mkTlbConnect(iTlb.toParent, dTlb.toParent, l2Tlb.toChildren); // flags to flush Reg#(Bool) flush_tlbs <- mkReg(False); Reg#(Bool) update_vm_info <- mkReg(False); Reg#(Bool) flush_reservation <- mkReg(False); `ifdef SECURITY_OR_INCLUDE_GDB_CONTROL Reg#(Bool) flush_caches <- mkReg(False); Reg#(Bool) flush_brpred <- mkReg(False); `else Reg#(Bool) flush_caches <- mkReadOnlyReg(False); Reg#(Bool) flush_brpred <- mkReadOnlyReg(False); `endif `ifdef SELF_INV_CACHE Reg#(Bool) reconcile_i <- mkReg(False); `else Reg#(Bool) reconcile_i <- mkReadOnlyReg(False); `endif `ifdef SELF_INV_CACHE `ifdef SYSTEM_SELF_INV_L1D Reg#(Bool) reconcile_d <- mkReg(False); `else // !SYSTEM_SELF_INV_L1D Reg#(Bool) reconcile_d <- mkReadOnlyReg(False); `endif // SYSTEM_SELF_INV_L1D `else // !SELF_INV_CACHE Reg#(Bool) reconcile_d <- mkReadOnlyReg(False); `endif // SELF_INV_CACHE // performance counters Reg#(Bool) doStats = coreFix.doStatsIfc; // whether data is collected `ifdef PERF_COUNT // OOO execute stag (in AluExePipeline and MemExePipeline) // commit stage (many in CommitStage.bsv) // cycle Count#(Data) cycleCnt <- mkCount(0); // buffer/tags size Count#(Data) ldqFullCycles <- mkCount(0); Count#(Data) stqFullCycles <- mkCount(0); Count#(Data) robFullCycles <- mkCount(0); Count#(Data) aluRS0FullCycles <- mkCount(0); Count#(Data) aluRS1FullCycles <- mkCount(0); Count#(Data) fpuMulDivRSFullCycles <- mkCount(0); Count#(Data) memRSFullCycles <- mkCount(0); Count#(Data) epochFullCycles <- mkCount(0); Count#(Data) specTagFullCycles <- mkCount(0); // FIFOs to connect performance counters FIFO#(ExeStagePerfType) exePerfReqQ <- mkFIFO1; FIFO#(ComStagePerfType) comPerfReqQ <- mkFIFO1; FIFO#(CoreSizePerfType) sizePerfReqQ <- mkFIFO1; Fifo#(1, PerfResp#(ExeStagePerfType)) exePerfRespQ <- mkCFFifo; Fifo#(1, PerfResp#(ComStagePerfType)) comPerfRespQ <- mkCFFifo; Fifo#(1, PerfResp#(CoreSizePerfType)) sizePerfRespQ <- mkCFFifo; // FIFO of perf resp FIFO#(ProcPerfResp) perfRespQ <- mkFIFO1; `endif // FIFO of perf req FIFO#(ProcPerfReq) perfReqQ <- mkFIFO1; // -- End of performance counters `ifdef CHECK_DEADLOCK // when to start deadlock checking Reg#(Bool) startDeadlockCheck <- mkReg(False); FIFO#(void) deadlockCheckStartedQ <- mkFIFO; rule doStartDeadlockCheck(!startDeadlockCheck && started); startDeadlockCheck <= True; deadlockCheckStartedQ.enq(?); endrule `endif // Rename stage let renameInput = (interface RenameInput; interface fetchIfc = fetchStage; interface robIfc = rob; interface rtIfc = regRenamingTable; interface sbConsIfc = sbCons; interface sbAggrIfc = sbAggr; interface csrfIfc = csrf; interface emIfc = epochManager; interface smIfc = specTagManager; interface rsAluIfc = reservationStationAlu; interface rsFpuMulDivIfc = reservationStationFpuMulDiv; interface rsMemIfc = reservationStationMem; interface lsqIfc = lsq; method pendingMMIOPRq = mmio.hasPendingPRq; method issueCsrInstOrInterrupt = csrInstOrInterruptInflight_rename._write(True); method Bool checkDeadlock; `ifdef CHECK_DEADLOCK return startDeadlockCheck; `else return False; `endif endmethod method doStats = coreFix.doStatsIfc._read; `ifdef INCLUDE_GDB_CONTROL method Bool core_is_running = (rg_core_run_state == CORE_RUNNING); `endif endinterface); RenameStage renameStage <- mkRenameStage(renameInput); // commit stage let commitInput = (interface CommitInput; interface robIfc = rob; interface rtIfc = regRenamingTable; interface csrfIfc = csrf; method stbEmpty = stb.isEmpty; method stqEmpty = lsq.stqEmpty; method lsqSetAtCommit = lsq.setAtCommit; method lookupPAddr = lsq.lookupPAddr; method pauseCommit = coreFix.pendingIncorrectSpec; method tlbNoPendingReq = iTlb.noPendingReq && dTlb.noPendingReq; method setFlushTlbs; action flush_tlbs <= True; // $display ("%0d: %m.commitInput.setFlushTlbs", cur_cycle); endaction endmethod method setUpdateVMInfo; action update_vm_info <= True; // $display ("%0d: %m.commitInput.setUpdateVMInfo", cur_cycle); endaction endmethod method setFlushReservation; action flush_reservation <= True; // $display ("%0d: %m.commitInput.setFlushReservation", cur_cycle); endaction endmethod method setFlushBrPred; action flush_brpred <= True; // $display ("%0d: %m.commitInput.setFlushBrPred", cur_cycle); endaction endmethod method setFlushCaches; action flush_caches <= True; // $display ("%0d: %m.commitInput.setFlushCaches", cur_cycle); endaction endmethod method setReconcileI = reconcile_i._write(True); method setReconcileD = reconcile_d._write(True); method killAll = coreFix.killAll; method redirectPc = fetchStage.redirect; method setFetchWaitRedirect = fetchStage.setWaitRedirect; `ifdef INCLUDE_GDB_CONTROL method setFetchWaitFlush = fetchStage.setWaitFlush; `endif method incrementEpoch = epochManager.incrementEpoch; method commitCsrInstOrInterrupt = csrInstOrInterruptInflight_commit._write(False); method doStats = coreFix.doStatsIfc._read; method Bool checkDeadlock; `ifdef CHECK_DEADLOCK return startDeadlockCheck; `else return False; `endif endmethod `ifdef PERFORMANCE_MONITORING `ifdef CONTRACTS_VERIFY method Action updateTargets(Vector#(SupSize, Maybe#(CapMem)) targets); for(Integer i = 0; i < valueof(SupSize); i=i+1) begin if(targets[i] matches tagged Valid .tar) begin bags[i].insert(tar, tar); end end endmethod method Action updateReturnTargets(Vector#(SupSize, Maybe#(CapMem)) returnTargets); for(Integer i = 0; i < valueof(SupSize); i=i+1) begin if(returnTargets[i] matches tagged Valid .retTar) begin returnBags[i].insert(retTar, retTar); end end endmethod `endif `endif `ifdef INCLUDE_TANDEM_VERIF interface v_to_TV = map (toPut, v_f_to_TV); `endif endinterface); CommitStage commitStage <- mkCommitStage(commitInput); `ifdef RVFI // XXX Currently RVFI can only be connected to the outside world // via the RVFI_DII bridge i.e. when DII is also being used. rule drop; let packets <- commitStage.rvfi.get(); for (Integer i = 0; i < valueOf(SupSize); i = i+1) begin if (isValid(packets[i])) $display("%d: RVFI ", cur_cycle, fshow(packets[i].Valid)); end `ifdef RVFI_DII rvfi_bridge.rvfi.put(packets); `endif endrule `endif // send rob enq time to reservation stations (* fire_when_enabled, no_implicit_conditions *) rule sendRobEnqTime; InstTime t = rob.getEnqTime; reservationStationMem.setRobEnqTime(t); for(Integer i = 0; i < valueof(FpuMulDivExeNum); i = i+1) begin reservationStationFpuMulDiv[i].setRobEnqTime(t); end for(Integer i = 0; i < valueof(AluExeNum); i = i+1) begin reservationStationAlu[i].setRobEnqTime(t); end endrule // preempt has 2 functions here // 1. break scheduling cycles // 2. XXX since csrf is configReg now, we should not let this rule fire together with doCommit // because we read csrf here and write csrf in doCommit // TODO We can use wires to catch flush / updateVM enable sigals, because // there cannot be any instruction in pipeline (there can be poisoned inst // which cannot change CSR or link reg in D$), so doCommit cannot fire. // MMIO manager may change pending interrupt bits, but will not affect VM // info. (* preempts = "prepareCachesAndTlbs, commitStage.doCommitTrap_handle" *) (* preempts = "prepareCachesAndTlbs, commitStage.doCommitSystemInst" *) rule prepareCachesAndTlbs(flush_reservation || flush_tlbs || update_vm_info); if (flush_reservation) begin flush_reservation <= False; dMem.resetLinkAddr; // $display ("%0d: %m.rule prepareCachesAndTlbs: flushing reservation", cur_cycle); end if (flush_tlbs) begin flush_tlbs <= False; iTlb.flush; dTlb.flush; // $display ("%0d: %m.rule prepareCachesAndTlbs: flushing iTlb and dTlb", cur_cycle); end if (update_vm_info) begin update_vm_info <= False; let vmI = csrf.vmI; let vmD = csrf.vmD; iTlb.updateVMInfo(vmI); dTlb.updateVMInfo(vmD); l2Tlb.updateVMInfo(vmI, vmD); // $display ("%0d: %m.rule prepareCachesAndTlbs: updating VMInfo", cur_cycle); end endrule `ifdef SECURITY_OR_INCLUDE_GDB_CONTROL // Use wires to capture flush regs and empty signals. This is ok because // there cannot be any activity to make empty -> not-empty or need-flush -> // no-need-flush when we are trying to flush. PulseWire doFlushCaches <- mkPulseWire; PulseWire doFlushBrPred <- mkPulseWire; rule setDoFlushCaches(flush_caches && fetchStage.emptyForFlush && lsq.noWrongPathLoads); doFlushCaches.send; // $display ("%0d: %m.rl_setDoFlushCaches", cur_cycle); endrule rule setDoFlushBrPred(flush_brpred && fetchStage.emptyForFlush); doFlushBrPred.send; endrule // security flush cache: need to wait for wrong path loads or inst fetches // to finish rule flushCaches(doFlushCaches); flush_caches <= False; iMem.flush; dMem.flush; // $display ("%0d: %m.rule flushCaches (imem and dmem)", cur_cycle); endrule // security flush branch predictors: wait for wrong path inst fetches to // finish rule flushBrPred(doFlushBrPred); flush_brpred <= False; fetchStage.flush_predictors; // $display ("%0d: %m.rule flushBrPred", cur_cycle); endrule `endif `ifdef SELF_INV_CACHE // Use wires to capture flush regs and empty signals. This is ok because // there cannot be any activity to make empty -> not-empty or need-flush -> // no-need-flush when we are trying to flush. PulseWire doReconcileI <- mkPulseWire; // We don't really need to wait for fetch to be empty, but just in case we // back pressure I TLB because I$ is reconciling. rule setDoReconcileI(reconcile_i && fetchStage.emptyForFlush); doReconcileI.send; endrule rule reconcileI(doReconcileI); reconcile_i <= False; iMem.reconcile; endrule `ifdef SYSTEM_SELF_INV_L1D PulseWire doReconcileD <- mkPulseWire; Reg#(Bool) waitReconcileD <- mkReg(False); // We don't really need to wait for lsq empty, but just in case rule setDoReconcileD(reconcile_d && lsq.noWrongPathLoads); doReconcileD.send; endrule rule startReconcileD(doReconcileD && !waitReconcileD); coreFix.memExeIfc.reconcile.request.put(?); waitReconcileD <= True; endrule rule completeReconcileD(waitReconcileD); let unused <- coreFix.memExeIfc.reconcile.response.get; waitReconcileD <= False; reconcile_d <= False; endrule `endif // SYSTEM_SELF_INV_L1D `endif // SELF_INV_CACHE rule readyToFetch( !flush_reservation && !flush_tlbs && !update_vm_info && iTlb.flush_done && dTlb.flush_done `ifdef SECURITY_OR_INCLUDE_GDB_CONTROL && !flush_caches && !flush_brpred && iMem.flush_done && dMem.flush_done && fetchStage.flush_predictors_done `endif `ifdef SELF_INV_CACHE && !reconcile_i && iMem.reconcile_done `ifdef SYSTEM_SELF_INV_L1D && !reconcile_d `endif `endif ); fetchStage.done_flushing(); endrule `ifdef INCLUDE_GDB_CONTROL rule readyToHalt( (rg_core_run_state == CORE_RUNNING) && commitStage.is_debug_halted ); started <= False; rg_core_run_state <= CORE_HALTING; if (verbosity >= 1) $display ("%0d: %m.rule readyToHalt: halting for debug mode", cur_cycle); endrule `endif `ifdef PERF_COUNT // incr cycle count (* fire_when_enabled, no_implicit_conditions *) rule incCycleCnt(doStats); cycleCnt.incr(1); endrule // incr buffer full cycles (* fire_when_enabled, no_implicit_conditions *) rule incLdQFull(doStats && lsq.ldqFull_ehrPort0); ldqFullCycles.incr(1); endrule (* fire_when_enabled, no_implicit_conditions *) rule incStQFull(doStats && lsq.stqFull_ehrPort0); stqFullCycles.incr(1); endrule (* fire_when_enabled, no_implicit_conditions *) rule incROBFull(doStats && rob.isFull_ehrPort0); robFullCycles.incr(1); endrule (* fire_when_enabled, no_implicit_conditions *) rule incAluRS0Full(doStats && reservationStationAlu[0].isFull_ehrPort0); aluRS0FullCycles.incr(1); endrule (* fire_when_enabled, no_implicit_conditions *) rule incAluRS1Full(doStats && reservationStationAlu[1].isFull_ehrPort0); aluRS1FullCycles.incr(1); endrule (* fire_when_enabled, no_implicit_conditions *) rule incFpuMulDivRSFull(doStats && reservationStationFpuMulDiv[0].isFull_ehrPort0); fpuMulDivRSFullCycles.incr(1); endrule (* fire_when_enabled, no_implicit_conditions *) rule incMemRSFull(doStats && reservationStationMem.isFull_ehrPort0); memRSFullCycles.incr(1); endrule (* fire_when_enabled, no_implicit_conditions *) rule incEpochFull(doStats && epochManager.isFull_ehrPort0); epochFullCycles.incr(1); endrule (* fire_when_enabled, no_implicit_conditions *) rule incSpecTagFull(doStats && specTagManager.isFull_ehrPort0); specTagFullCycles.incr(1); endrule // broadcast whether we should collect data rule broadcastDoStats; let stats = csrf.doPerfStats; doStats <= stats; iMem.perf.setStatus(stats); dMem.perf.setStatus(stats); iTlb.perf.setStatus(stats); dTlb.perf.setStatus(stats); l2Tlb.perf.setStatus(stats); fetchStage.perf.setStatus(stats); if(stats && !doStats) begin $display("[stats] enabled"); end else if(!stats && doStats) begin $display("[stats] disabled"); end endrule // dispatch perf req rule dispathPerfReq; perfReqQ.deq; let r = perfReqQ.first; case(r.loc) ICache: begin iMem.perf.req(unpack(truncate(r.pType))); end DCache: begin dMem.perf.req(unpack(truncate(r.pType))); end ITlb: begin iTlb.perf.req(unpack(truncate(r.pType))); end DTlb: begin dTlb.perf.req(unpack(truncate(r.pType))); end L2Tlb: begin l2Tlb.perf.req(unpack(truncate(r.pType))); end DecStage: begin fetchStage.perf.req(unpack(truncate(r.pType))); end ExeStage: begin exePerfReqQ.enq(unpack(truncate(r.pType))); end ComStage: begin comPerfReqQ.enq(unpack(truncate(r.pType))); end CoreSize: begin sizePerfReqQ.enq(unpack(truncate(r.pType))); end default: begin $fwrite(stderr, "[WARNING] unrecognzied perf req location ", fshow(r.loc), "\n"); doAssert(False, "unknown perf location"); end endcase endrule // handle perf req: exe stage rule readPerfCnt_Exe; function Data getAluCnt(ExeStagePerfType pType); Data cnt = 0; for(Integer i = 0; i < valueof(AluExeNum); i = i+1) begin cnt = cnt + coreFix.aluExeIfc[i].getPerf(pType); end return cnt; endfunction function Data getFpuMulDivCnt(ExeStagePerfType pType); Data cnt = 0; for(Integer i = 0; i < valueof(FpuMulDivExeNum); i = i+1) begin cnt = cnt + coreFix.fpuMulDivExeIfc[i].getPerf(pType); end return cnt; endfunction let pType <- toGet(exePerfReqQ).get; Data data = (case(pType) SupRenameCnt, SpecNoneCycles, SpecNonMemCycles: renameStage.getPerf(pType); ExeRedirectBr, ExeRedirectJr, ExeRedirectOther: getAluCnt(pType); ExeTlbExcep, ExeScSuccessCnt, ExeLrScAmoAcqCnt, ExeLrScAmoRelCnt, ExeFenceAcqCnt, ExeFenceRelCnt, ExeFenceCnt, ExeLdStallByLd, ExeLdStallBySt, ExeLdStallBySB, ExeLdForward, ExeLdMemLat, ExeStMemLat, ExeLdToUseLat, ExeLdToUseCnt: coreFix.memExeIfc.getPerf(pType); ExeIntMulCnt, ExeIntDivCnt, ExeFpFmaCnt, ExeFpDivCnt, ExeFpSqrtCnt: getFpuMulDivCnt(pType); default: 0; endcase); exePerfRespQ.enq(PerfResp { pType: pType, data: data }); endrule // handle perf req: com stage rule readPerfCnt_Com; let pType <- toGet(comPerfReqQ).get; Data data = (case(pType) CycleCnt: cycleCnt; default: commitStage.getPerf(pType); endcase); comPerfRespQ.enq(PerfResp { pType: pType, data: data }); endrule // handle perf req: core size rule readPerfCnt_Size; let pType <- toGet(sizePerfReqQ).get; Data data = (case(pType) LdQFullCycles: ldqFullCycles; StQFullCycles: stqFullCycles; ROBFullCycles: robFullCycles; AluRS0FullCycles: aluRS0FullCycles; AluRS1FullCycles: aluRS1FullCycles; FpuMulDivRSFullCycles: fpuMulDivRSFullCycles; MemRSFullCycles: memRSFullCycles; EpochFullCycles: epochFullCycles; SpecTagFullCycles: specTagFullCycles; default: 0; endcase); sizePerfRespQ.enq(PerfResp { pType: pType, data: data }); endrule // gather perf resp rule gatherPerfResp; Maybe#(ProcPerfResp) resp = Invalid; if(iMem.perf.respValid) begin let r <- iMem.perf.resp; resp = Valid(ProcPerfResp { loc: ICache, pType: zeroExtend(pack(r.pType)), data: r.data }); end else if(dMem.perf.respValid) begin let r <- dMem.perf.resp; resp = Valid(ProcPerfResp { loc: DCache, pType: zeroExtend(pack(r.pType)), data: r.data }); end else if(iTlb.perf.respValid) begin let r <- iTlb.perf.resp; resp = Valid(ProcPerfResp { loc: ITlb, pType: zeroExtend(pack(r.pType)), data: r.data }); end else if(dTlb.perf.respValid) begin let r <- dTlb.perf.resp; resp = Valid(ProcPerfResp { loc: DTlb, pType: zeroExtend(pack(r.pType)), data: r.data }); end else if(l2Tlb.perf.respValid) begin let r <- l2Tlb.perf.resp; resp = Valid(ProcPerfResp { loc: L2Tlb, pType: zeroExtend(pack(r.pType)), data: r.data }); end else if(fetchStage.perf.respValid) begin let r <- fetchStage.perf.resp; resp = Valid(ProcPerfResp { loc: DecStage, pType: zeroExtend(pack(r.pType)), data: r.data }); end else if(exePerfRespQ.notEmpty) begin let r <- toGet(exePerfRespQ).get; resp = Valid(ProcPerfResp { loc: ExeStage, pType: zeroExtend(pack(r.pType)), data: r.data }); end else if(comPerfRespQ.notEmpty) begin let r <- toGet(comPerfRespQ).get; resp = Valid(ProcPerfResp { loc: ComStage, pType: zeroExtend(pack(r.pType)), data: r.data }); end else if(sizePerfRespQ.notEmpty) begin let r <- toGet(sizePerfRespQ).get; resp = Valid (ProcPerfResp { loc: CoreSize, pType: zeroExtend(pack(r.pType)), data: r.data }); end // enq to resp Q if(resp matches tagged Valid .r) begin perfRespQ.enq(r); end endrule `endif `ifdef PERFORMANCE_MONITORING // ================================================================ // Performance counters // Each cache and TLB pair uses the same struct (EventsCache), but the cache accesses // different fields than the TLB, which makes it safe to combine them Reg#(EventsLL) events_llc_reg <- mkRegU; Reg#(EventsTGC) events_tgc_reg <- mkRegU; rule report_events; EventsCore events = unpack(pack(commitStage.events)); events.evt_REDIRECT = zeroExtend(pack(fetchStage.redirect_evt)); hpm_core_events[1] <= events; endrule EventsCore core_evts = unpack(pack(coreFix.memExeIfc.events) | pack(hpm_core_events[0])); EventsL1I imem_evts = unpack(pack(iMem.events) | pack(iTlb.events)); EventsL1D dmem_evts = unpack(pack(dMem.events) | pack(dTlb.events)); EventsTGC tgc_evts = events_tgc_reg; EventsLL llmem_evts = unpack(pack(events_llc_reg) | pack(l2Tlb.events)); Maybe#(EventsTransExe) mab_trans_exe = tagged Invalid; `ifdef CONTRACTS_VERIFY EventsTransExe texe_evts = renameStage.events; Bit#(Report_Width) wildJumps = 0; Bit#(Report_Width) wildExceptions = texe_evts.evt_WILD_EXCEPTION; for(Integer i = 0; i < valueof(AluExeNum); i = i+1) begin let alu_events = coreFix.aluExeIfc[i].events; wildJumps = wildJumps + alu_events.evt_WILD_JUMP; wildExceptions = wildExceptions + alu_events.evt_WILD_EXCEPTION; end texe_evts.evt_WILD_JUMP = wildJumps; texe_evts.evt_WILD_EXCEPTION = wildExceptions; mab_trans_exe = tagged Valid texe_evts; `endif let ev_struct = HPMEvents{mab_EventsCore: tagged Valid core_evts, mab_EventsL1I: tagged Valid imem_evts, mab_EventsL1D: tagged Valid dmem_evts, mab_EventsLL: tagged Valid llmem_evts, mab_EventsTGC: tagged Valid tgc_evts, mab_EventsTransExe: mab_trans_exe, mab_AXI4_Slave_Events: tagged Invalid, mab_AXI4_Master_Events: tagged Invalid}; let events = generateHPMVector(ev_struct); (* fire_when_enabled, no_implicit_conditions *) rule rl_send_perf_evts; csrf.send_performance_events (events); endrule `endif `ifdef INCLUDE_GDB_CONTROL // ================================================================ // DEBUG MODULE INTERFACE Bool show_DM_interactions = False; // for debugging the interactions // ---------------------------------------------------------------- // Debug Module GPR read/write FIFOF #(DM_CPU_Req #(5, 64)) f_gpr_reqs <- mkFIFOF1; FIFOF #(DM_CPU_Rsp #(64)) f_gpr_rsps <- mkFIFOF1; rule rl_debug_gpr_read ( (rg_core_run_state == CORE_HALTED) && f_gpr_reqs.notEmpty && (! f_gpr_reqs.first.write)); let req <- pop (f_gpr_reqs); Bit #(5) regnum = req.address; let arch_regs = ArchRegs {src1: tagged Valid (tagged Gpr regnum), src2: tagged Invalid, src3: tagged Invalid, dst: tagged Invalid}; let rename_result = regRenamingTable.rename[0].getRename (arch_regs); let phy_rindx = fromMaybe (?, rename_result.phy_regs.src1); let data_out = rf.read [debuggerPort].rd1 (phy_rindx); let rsp = DM_CPU_Rsp {ok: True, data: getAddr(data_out)}; f_gpr_rsps.enq (rsp); if (show_DM_interactions) $display ("%0d: %m.rl_debug_read_gpr: reg %0d => 0x%0h", cur_cycle, regnum, getAddr(data_out)); endrule rule rl_debug_gpr_write ( (rg_core_run_state == CORE_HALTED) && f_gpr_reqs.notEmpty && f_gpr_reqs.first.write); let req <- pop (f_gpr_reqs); Bit #(5) regnum = req.address; let data_in = req.data; let arch_regs = ArchRegs {src1: tagged Valid (tagged Gpr regnum), src2: tagged Invalid, src3: tagged Invalid, dst: tagged Invalid}; let rename_result = regRenamingTable.rename[0].getRename (arch_regs); let phy_rindx = fromMaybe (?, rename_result.phy_regs.src1); rf.write [debuggerPort].wr (phy_rindx, setAddrUnsafe(almightyCap, data_in)); let rsp = DM_CPU_Rsp {ok: True, data: ?}; f_gpr_rsps.enq (rsp); if (show_DM_interactions) $display ("%0d: %m.rl_debug_gpr_write: reg %0d <= 0x%0h (phy_rindx = %0d)", cur_cycle, regnum, data_in, phy_rindx); endrule rule rl_debug_gpr_access_busy (rg_core_run_state == CORE_RUNNING); let req <- pop (f_gpr_reqs); let rsp = DM_CPU_Rsp {ok: False, data: ?}; f_gpr_rsps.enq (rsp); if (show_DM_interactions) $display ("%0d: %m.rl_debug_gpr_access_busy", cur_cycle); endrule `ifdef ISA_F // ---------------------------------------------------------------- // Debug Module FPR read/write FIFOF #(DM_CPU_Req #(5, 64)) f_fpr_reqs <- mkFIFOF1; FIFOF #(DM_CPU_Rsp #(64)) f_fpr_rsps <- mkFIFOF1; rule rl_debug_fpr_read ( (rg_core_run_state == CORE_HALTED) && (! f_gpr_reqs.notEmpty) // prioritize gpr reqs && (! f_fpr_reqs.first.write)); let req <- pop (f_fpr_reqs); Bit #(5) regnum = req.address; let arch_regs = ArchRegs {src1: tagged Valid (tagged Fpu regnum), src2: tagged Invalid, src3: tagged Invalid, dst: tagged Invalid}; let rename_result = regRenamingTable.rename[0].getRename (arch_regs); let phy_rindx = fromMaybe (?, rename_result.phy_regs.src1); let data_out = rf.read [debuggerPort].rd1 (phy_rindx); let rsp = DM_CPU_Rsp {ok: True, data: getAddr(data_out)}; f_fpr_rsps.enq (rsp); if (show_DM_interactions) $display ("%0d: %m.rl_debug_read_fpr: reg %0d => 0x%0h", cur_cycle, regnum, getAddr(data_out)); endrule rule rl_debug_fpr_write ( (rg_core_run_state == CORE_HALTED) && (! f_gpr_reqs.notEmpty) // prioritize gpr reqs && f_fpr_reqs.first.write); let req <- pop (f_fpr_reqs); Bit #(5) regnum = req.address; let data_in = req.data; let arch_regs = ArchRegs {src1: tagged Valid (tagged Fpu regnum), src2: tagged Invalid, src3: tagged Invalid, dst: tagged Invalid}; let rename_result = regRenamingTable.rename[0].getRename (arch_regs); let phy_rindx = fromMaybe (?, rename_result.phy_regs.src1); rf.write [debuggerPort].wr (phy_rindx, nullWithAddr(data_in)); let rsp = DM_CPU_Rsp {ok: True, data: ?}; f_fpr_rsps.enq (rsp); if (show_DM_interactions) $display ("%0d: %m.rl_debug_write_fpr: reg %0d <= 0x%0h (phy_rindx %0d)", cur_cycle, regnum, data_in, phy_rindx); endrule rule rl_debug_fpr_access_busy ( (rg_core_run_state == CORE_RUNNING) && f_fpr_reqs.notEmpty); let req <- pop (f_fpr_reqs); let rsp = DM_CPU_Rsp {ok: False, data: ?}; f_fpr_rsps.enq (rsp); if (show_DM_interactions) $display ("%0d: %m.rl_debug_fpr_access_busy", cur_cycle); endrule `endif // ---------------------------------------------------------------- // Debug Module CSR read/write // Debugger CSR read/write request/response FIFOF #(DM_CPU_Req #(12, 64)) f_csr_reqs <- mkFIFOF1; FIFOF #(DM_CPU_Rsp #(64)) f_csr_rsps <- mkFIFOF1; rule rl_debug_csr_read ( (rg_core_run_state == CORE_HALTED) && (! f_csr_reqs.first.write)); let req <- pop (f_csr_reqs); Bit #(12) csr_addr = req.address; let data_out = csrf.rd (unpack (csr_addr)); let rsp = DM_CPU_Rsp {ok: True, data: data_out}; f_csr_rsps.enq (rsp); if (show_DM_interactions) $display ("%0d: %m.rl_debug_read_csr: csr [%0h] => 0x%0h", cur_cycle, csr_addr, data_out); endrule rule rl_debug_csr_write ( (rg_core_run_state == CORE_HALTED) && f_csr_reqs.first.write); let req <- pop (f_csr_reqs); Bit #(12) csr_addr = req.address; let data_in = req.data; csrf.csrInstWr (unpack (csr_addr), data_in); let rsp = DM_CPU_Rsp {ok: True, data: ?}; f_csr_rsps.enq (rsp); if (show_DM_interactions) $display ("%0d: %m.rl_debug_write_csr: csr [%0h] <= 0x%0h", cur_cycle, csr_addr, data_in); endrule rule rl_debug_csr_access_busy (rg_core_run_state == CORE_RUNNING); let req <- pop (f_csr_reqs); let rsp = DM_CPU_Rsp {ok: False, data: ?}; f_csr_rsps.enq (rsp); if (show_DM_interactions) $display ("%0d: %m.rl_debug_csr_access_busy", cur_cycle); endrule // ---------------------------------------------------------------- // Debug Module run-halt control FIFOF #(Bool) f_run_halt_reqs <- mkFIFOF; FIFOF #(Bool) f_run_halt_rsps <- mkFIFOF; // ---------------- // Debug Module Halt control rule rl_debug_halt_req ( (rg_core_run_state == CORE_RUNNING) && (f_run_halt_reqs.first == False)); f_run_halt_reqs.deq; // Debugger 'halt' request (e.g., GDB '^C' command) // This is initiated just like an interrupt. `ifdef INCLUDE_GDB_CONTROL renameStage.debug_halt_req; `endif if (show_DM_interactions) $display ("%0d: %m.rl_debug_halt_req", cur_cycle); endrule rule rl_debug_halt_req_already_halted ( (rg_core_run_state != CORE_RUNNING) && (f_run_halt_reqs.first == False)); f_run_halt_reqs.deq; // Notify debugger that we're halted, but otherwise ignore the request f_run_halt_rsps.enq (False); if (show_DM_interactions) $display ("%0d: %m.rl_debug_halt_req_already_halted", cur_cycle); endrule // Monitors when we've reached halted state while running // (due to halt, step or EBREAK) and notifies DM rule rl_debug_halted (rg_core_run_state == CORE_HALTING); // Notify debugger that we've halted f_run_halt_rsps.enq (False); rg_core_run_state <= CORE_HALTED; if (show_DM_interactions) $display ("%0d: %m.rl_debug_halted", cur_cycle); endrule // ---------------- // Debug Module Resume (run) control // Resume command when in debug mode rule rl_debug_resume ( (rg_core_run_state == CORE_HALTED) && (f_run_halt_reqs.first == True) // prioritise gpr/fpr/csr read/write requests before resuming && (! f_gpr_reqs.notEmpty) `ifdef ISA_F && (! f_fpr_reqs.notEmpty) `endif && (! f_csr_reqs.notEmpty)); f_run_halt_reqs.deq; // In Debug Mode, debugger may have updated DCSR (hence privilege level, DCSR[1:0]), // and also other VM-related state. // The following TLB actions update to a consistent state. iTlb.flush; dTlb.flush; let vmI = csrf.vmI; let vmD = csrf.vmD; iTlb.updateVMInfo(vmI); dTlb.updateVMInfo(vmD); l2Tlb.updateVMInfo(vmI, vmD); let startpc = csrf.dpc_read; fetchStage.redirect (cast(startpc), 0); renameStage.debug_resume; commitStage.debug_resume; started <= True; rg_core_run_state <= CORE_RUNNING; // Notify debugger that we've started running f_run_halt_rsps.enq (True); if (show_DM_interactions) $display ("%0d: %m.rl_debug_resume, dpc = 0x%0h", cur_cycle, startpc); endrule // Run command when already running rule rl_debug_run_redundant ( (rg_core_run_state == CORE_RUNNING) && (f_run_halt_reqs.first == True)); f_run_halt_reqs.deq; // Notify debugger that we're running f_run_halt_rsps.enq (True); if (show_DM_interactions) $display ("%0d: %m.rl_debug_run_redundant", cur_cycle); endrule // ================================================================ `endif // ================================================================ // INTERFACE interface CoreReq coreReq; method Action start( Bool running, Bit#(64) startpc, Addr toHostAddr, Addr fromHostAddr ); `ifdef INCLUDE_GDB_CONTROL if (!running) renameStage.debug_halt_req; `endif fetchStage.start(setAddrUnsafe(almightyCap, startpc) `ifdef RVFI_DII , 0 `endif ); started <= True; `ifdef INCLUDE_GDB_CONTROL rg_core_run_state <= CORE_RUNNING; `endif mmio.setHtifAddrs(toHostAddr, fromHostAddr); commitStage.startRenameDebug; endmethod method Action perfReq(PerfLocation loc, PerfType t); perfReqQ.enq(ProcPerfReq { loc: loc, pType: t }); endmethod endinterface interface CoreIndInv coreIndInv; method ActionValue#(ProcPerfResp) perfResp; `ifdef PERF_COUNT perfRespQ.deq; return perfRespQ.first; `else perfReqQ.deq; let r = perfReqQ.first; return ProcPerfResp { loc: r.loc, pType: r.pType, data: 0 }; `endif endmethod method terminate = csrf.terminate; endinterface interface dCacheToParent = dMem.to_parent; interface iCacheToParent = iMem.to_parent; interface tlbToMem = l2Tlb.toMem; interface mmioToPlatform = mmio.toP; method sendDoStats = csrf.sendDoStats; method recvDoStats = csrf.recvDoStats; // deadlock check interface CoreDeadlock deadlock; interface dCacheCRqStuck = dMem.cRqStuck; interface dCachePRqStuck = dMem.pRqStuck; interface iCacheCRqStuck = iMem.cRqStuck; interface iCachePRqStuck = iMem.pRqStuck; interface renameInstStuck = renameStage.renameInstStuck; interface renameCorrectPathStuck = renameStage.renameCorrectPathStuck; interface commitInstStuck = commitStage.commitInstStuck; interface commitUserInstStuck = commitStage.commitUserInstStuck; `ifdef CHECK_DEADLOCK interface checkStarted = toGet(deadlockCheckStartedQ); `else interface checkStarted = nullGet; `endif endinterface `ifdef RVFI_DII interface Toooba_RVFI_DII_Server rvfi_dii_server = rvfi_bridge.rvfi_dii_server; `endif // rename debug interface CoreRenameDebug renameDebug; interface renameErr = commitStage.renameErr; endinterface // Bluespec: external interrupt requests targeting Machine and Supervisor modes method Action setMEIP (v) = csrf.setMEIP (v); method Action setSEIP (v) = csrf.setSEIP (v); `ifdef INCLUDE_GDB_CONTROL interface Server hart_run_halt_server = toGPServer (f_run_halt_reqs, f_run_halt_rsps); interface Server hart_gpr_mem_server = toGPServer (f_gpr_reqs, f_gpr_rsps); `ifdef ISA_F interface Server hart_fpr_mem_server = toGPServer (f_fpr_reqs, f_fpr_rsps); `endif interface Server hart_csr_mem_server = toGPServer (f_csr_reqs, f_csr_rsps); `endif `ifdef INCLUDE_TANDEM_VERIF interface v_to_TV = map (toGet, v_f_to_TV); `endif `ifdef PERFORMANCE_MONITORING method events_llc = events_llc_reg._write; method events_tgc = events_tgc_reg._write; `endif endmodule