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.
This commit is contained in:
Jonathan Woodruff
2023-12-12 17:29:27 +00:00
parent 8cd6e8db87
commit 2d05514b66
2 changed files with 7 additions and 80 deletions

View File

@@ -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

View File

@@ -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.