From 2d05514b669be2be2b3bfa5b805cac4d0bca201b Mon Sep 17 00:00:00 2001 From: Jonathan Woodruff Date: Tue, 12 Dec 2023 17:29:27 +0000 Subject: [PATCH] An experimental simplification of the SplitLSQ, which I think works because the Memory pipeline only ever reads the getIssueLd interface in the same rule that it calls issueLd. --- .../procs/RV64G_OOO/MemExePipeline.bsv | 3 +- src_Core/RISCY_OOO/procs/lib/SplitLSQ.bsv | 84 ++----------------- 2 files changed, 7 insertions(+), 80 deletions(-) diff --git a/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv b/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv index 46ed78a..662889d 100644 --- a/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv +++ b/src_Core/RISCY_OOO/procs/RV64G_OOO/MemExePipeline.bsv @@ -808,8 +808,7 @@ module mkMemExePipeline#(MemExeInput inIfc)(MemExePipeline); rule doIssueLdFromIssueQ; // get issue entry from LSQ - LSQIssueLdInfo info <- lsq.getIssueLd; - doIssueLd(info, True); + doIssueLd(lsq.getIssueLd, True); endrule // we have ordered setRegReadyAggr_forward < setRegReadyAggr_mem to make diff --git a/src_Core/RISCY_OOO/procs/lib/SplitLSQ.bsv b/src_Core/RISCY_OOO/procs/lib/SplitLSQ.bsv index c570cb1..d0fc251 100644 --- a/src_Core/RISCY_OOO/procs/lib/SplitLSQ.bsv +++ b/src_Core/RISCY_OOO/procs/lib/SplitLSQ.bsv @@ -383,7 +383,7 @@ interface SplitLSQ; LdQTag lsqTag, Addr paddr, ByteOrTagEn shiftedBE, SBSearchRes sbRes ); // Get the load to issue - method ActionValue#(LSQIssueLdInfo) getIssueLd; + method LSQIssueLdInfo getIssueLd; // Get load resp method ActionValue#(LSQRespLdResult) respLd(LdQTag t, MemTaggedData alignedData); // Deq LQ entry, and wakeup stalled loads. The guard checks the following: @@ -578,7 +578,6 @@ module mkSplitLSQ(SplitLSQ); // cacheEvict < // updateAddr < // issueLd, getIssueLd < - // enqIssueQ < // (wakeupLdStalledBySB (Weak only) CF deqSt) < // setAtCommit < // respLd < @@ -673,7 +672,6 @@ module mkSplitLSQ(SplitLSQ); Vector#(LdQSize, Ehr#(2, ByteOrTagEn)) ld_shiftedBE <- replicateM(mkEhr(?)); Vector#(LdQSize, Ehr#(2, Maybe#(Trap))) ld_fault <- replicateM(mkEhr(?)); Vector#(LdQSize, Ehr#(2, Bool)) ld_computed <- replicateM(mkEhr(?)); - Vector#(LdQSize, Ehr#(3, Bool)) ld_inIssueQ <- replicateM(mkEhr(?)); Vector#(LdQSize, Ehr#(2, Bool)) ld_executing <- replicateM(mkEhr(?)); Vector#(LdQSize, Ehr#(2, Bool)) ld_done <- replicateM(mkEhr(?)); Vector#(LdQSize, Ehr#(3, Maybe#(LdKilledBy))) ld_killed <- replicateM(mkEhr(?)); @@ -746,12 +744,6 @@ module mkSplitLSQ(SplitLSQ); let ld_computed_resp = getVEhrPort(ld_computed, 1); // assert let ld_computed_enq = getVEhrPort(ld_computed, 1); // write - let ld_inIssueQ_findIss = getVEhrPort(ld_inIssueQ, 0); - let ld_inIssueQ_updAddr = getVEhrPort(ld_inIssueQ, 0); // assert - let ld_inIssueQ_issue = getVEhrPort(ld_inIssueQ, 0); // write - let ld_inIssueQ_enqIss = getVEhrPort(ld_inIssueQ, 1); // write - let ld_inIssueQ_enq = getVEhrPort(ld_inIssueQ, 2); // write - let ld_executing_findIss = getVEhrPort(ld_executing, 0); let ld_executing_wrongSpec = getVEhrPort(ld_executing, 0); let ld_executing_deqLd = getVEhrPort(ld_executing, 0); @@ -940,16 +932,14 @@ module mkSplitLSQ(SplitLSQ); Reg#(StQTag) st_verifyP_verify = st_verifyP[0]; // write, C with wrongSpec Reg#(StQTag) st_verifyP_deqSt = st_verifyP[1]; // write, C with wrongSpec - // FIFO of LSQ tags that try to issue, there should be no replication in it - LSQIssueLdQ issueLdQ <- mkLSQIssueLdQ; // XXX We split the search for ready to issue entry into two phases. Phase // 1: rule findIssue: find a ready-to-issue entry at the beginning of the - // cycle. Phase 2: rule enqIssueQ: enq the one found in findIssue into + // cycle. Phase 2: method issueLd: enq the one found in findIssue into // issueQ and set ldInIssueQ We do the split because enq to issueQ must be // ordered after getIssueLd method which deq issueQ. This split is fine // because at phase 2, the entry found in phase one should not be changed // by any other method. This is because findIssue < update < issue < - // enqIssueQ, i.e. update and issue will not affect the entry found in + // issueLd, i.e. update and issue will not affect the entry found in // findIssue We use a wire to pass phase 1 result to phase 2. It is fine // that phase 2 dose not fire when phase 1 has fired, next cycle phase 1 // will redo the work. @@ -1108,8 +1098,7 @@ module mkSplitLSQ(SplitLSQ); return ( ld_valid_findIss[i] && ld_memFunc[i] == Ld && // (1) valid load ld_computed_findIss[i] && // (2) computed - !ld_inIssueQ_findIss[i] && // (3) not in issueQ - !ld_executing_findIss[i] && // (4) not executing (or done) + !ld_executing_findIss[i] && // (3) not executing (or done) !isValid(ld_depLdQDeq_findIss[i]) && !(ld_waitForOlderSt[i] && isValid(ld_olderSt_findIss[i])) && `ifndef TSO_MM @@ -1140,50 +1129,6 @@ module mkSplitLSQ(SplitLSQ); end endrule - rule enqIssueQ(issueLdInfo.wget matches tagged Valid .info &&& !wrongSpec_conflict); - if(verbose) begin - $display("[LSQ - enqIss] ", fshow(info)); - end - // sanity check - doAssert(ld_valid_enqIss[info.tag], - "enq issueQ entry is valid"); - doAssert(ld_memFunc[info.tag] == Ld, - "enq issueQ entry is Ld"); - doAssert(!isValid(ld_fault_enqIss[info.tag]), - "enq issueQ entry cannot have fault"); - doAssert(ld_computed_enqIss[info.tag], - "enq issueQ entry is computed"); - doAssert(!ld_executing_enqIss[info.tag], - "enq issueQ entry cannot be executing"); - doAssert(!ld_done_enqIss[info.tag], - "enq issueQ entry cannot be done"); - doAssert(!ld_inIssueQ_enqIss[info.tag], - "enq issueQ entry cannot be in issueQ"); - doAssert(!isValid(ld_killed_enqIss[info.tag]), - "enq issueQ entry cannot be killed"); - doAssert(!ld_waitWPResp_enqIss[info.tag], - "enq issueQ entry cannot wait for wrong path resp"); - doAssert(!ld_isMMIO_enqIss[info.tag], - "enq issueQ entry cannot be MMIO"); - doAssert(!isValid(ld_depLdQDeq_enqIss[info.tag]) && -`ifndef TSO_MM - !isValid(ld_depLdEx_enqIss[info.tag]) && - !isValid(ld_depSBDeq_enqIss[info.tag]) && -`endif - !isValid(ld_depStQDeq_enqIss[info.tag]), - "enq issueQ entry cannot have dependency"); - doAssert(info.shiftedBE == ld_shiftedBE_enqIss[info.tag], - "BE should match"); - doAssert(info.paddr == ld_paddr_enqIss[info.tag], - "paddr should match"); - // enq to issueQ & change state (prevent enq this tag again) - issueLdQ.enq(ToSpecFifo { - data: info, - spec_bits: ld_specBits_enqIss[info.tag] - }); - ld_inIssueQ_enqIss[info.tag] <= True; - endrule - // Verify SQ entry one by one // - TSO verify requires: // (1) all older loads are dequeued @@ -1488,7 +1433,6 @@ module mkSplitLSQ(SplitLSQ); ld_dst[ld_enqP] <= dst; ld_fault_enq[ld_enqP] <= Invalid; ld_computed_enq[ld_enqP] <= False; - ld_inIssueQ_enq[ld_enqP] <= False; ld_executing_enq[ld_enqP] <= False; ld_done_enq[ld_enqP] <= False; ld_killed_enq[ld_enqP] <= Invalid; @@ -1596,7 +1540,6 @@ module mkSplitLSQ(SplitLSQ); doAssert(ld_valid_updAddr[tag], "updating entry must be valid"); doAssert(!ld_computed_updAddr[tag] && - !ld_inIssueQ_updAddr[tag] && !ld_executing_updAddr[tag] && !ld_done_updAddr[tag] && !isValid(ld_killed_updAddr[tag]), @@ -2018,17 +1961,8 @@ module mkSplitLSQ(SplitLSQ); return issRes; endmethod - method ActionValue#(LSQIssueLdInfo) getIssueLd; - if(verbose) begin - $display("[LSQ - getIssueLd] ", fshow(issueLdQ.first)); - end - issueLdQ.deq; - // reset inIssueQ - let tag = issueLdQ.first.data.tag; - ld_inIssueQ_issue[tag] <= False; - doAssert(ld_inIssueQ_issue[tag], "Ld should be in issueQ"); - doAssert(ld_memFunc[tag] == Ld, "must be Ld"); - return issueLdQ.first.data; + method LSQIssueLdInfo getIssueLd if (issueLdInfo.wget matches tagged Valid .info &&& !wrongSpec_conflict); + return info; endmethod method ActionValue#(LSQRespLdResult) respLd(LdQTag t, MemTaggedData alignedData) if (!wrongSpec_conflict); @@ -2299,9 +2233,6 @@ module mkSplitLSQ(SplitLSQ); endfunction Vector#(StQSize, StQTag) stIdxVec = genWith(fromInteger); joinActions(map(correctSpecSt, stIdxVec)); - - // clear spec bits for issueQ - issueLdQ.specUpdate.correctSpeculation(mask); endmethod method Action incorrectSpeculation(Bool killAll, SpecTag specTag); @@ -2353,9 +2284,6 @@ module mkSplitLSQ(SplitLSQ); endfunction joinActions(map(killStQ, stIdxVec)); - // kill entries in issueQ - issueLdQ.specUpdate.incorrectSpeculation(killAll, specTag); - // change enqP: make valid entries always consecutive: new enqP is // the oldest **VALID** entry that gets killed. If such entry does // not exists, then enqP remains the same.