Skip to content

Commit ae9f809

Browse files
authored
Add Virtual SQ (#991)
* mem: add VirtualSQ simulation set physicalSQ size as 64 and VirtualSQ size as 128. Change-Id: I40e142d3591f040bc10f8e504562a90455dcef06 * mem: enable phySQFullCheckAtReplay Change-Id: I0b34a3c8bba373c6b0f94fa203f5942e30b39d78
1 parent d9b033c commit ae9f809

16 files changed

Lines changed: 452 additions & 11 deletions

File tree

configs/example/idealkmhv3.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ def setKmhV3IdealParams(args, system):
9494
# lsq
9595
cpu.LQEntries = 120
9696
cpu.SQEntries = 64
97+
cpu.StoreQueueMultiple = 2
9798
cpu.RARQEntries = 96
9899
cpu.RAWQEntries = 56
99100
cpu.LoadCompletionWidth = 8

configs/example/kmhv3.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ def setKmhV3Params(args, system):
9696
# lsq
9797
cpu.LQEntries = 120
9898
cpu.SQEntries = 64
99+
cpu.StoreQueueMultiple = 2
99100
cpu.RARQEntries = 96
100101
cpu.RAWQEntries = 56
101102
cpu.LoadCompletionWidth = 8

src/arch/riscv/insts/mem.cc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include "arch/riscv/insts/static_inst.hh"
3636
#include "arch/riscv/utility.hh"
3737
#include "cpu/o3/dyn_inst.hh"
38+
#include "cpu/o3/inst_queue.hh"
3839
#include "cpu/o3/lsq_unit.hh"
3940
#include "cpu/static_inst.hh"
4041

@@ -66,6 +67,23 @@ Fault
6667
StoreData::execute(ExecContext *xc, Trace::InstRecord *) const
6768
{
6869
auto inst = dynamic_cast<o3::DynInst *>(xc);
70+
71+
// STD does not enter the STA store-pipe S0. Consume the physical-SQ
72+
// replay marker at the start of each retry before checking the window.
73+
if (inst->needPhysicalSQFullReplay()) {
74+
inst->clearReplayType();
75+
inst->clearReplayFlags();
76+
inst->clearNeedReplay();
77+
}
78+
79+
// If no space left in the physical SQ,
80+
// then defer the STD operation, will be replayed by IQ.
81+
if (!inst->instQueue->storeQueueWriteReady(inst)) {
82+
inst->setPhysicalSQFullReplay();
83+
inst->instQueue->deferPhysicalSQFullReplay(inst);
84+
return NoFault;
85+
}
86+
6987
auto data = inst->getRegOperand(inst->staticInst.get(), 0);
7088

7189
if (inst->sqIt->instruction()->getFault() == NoFault) {
@@ -77,6 +95,7 @@ StoreData::execute(ExecContext *xc, Trace::InstRecord *) const
7795
memcpy(inst->sqIt->instruction()->memData, &data, memsize);
7896
memcpy(inst->sqIt->data(), &data, memsize);
7997
inst->sqIt->setStatus(o3::SplitStoreStatus::DataReady);
98+
inst->instQueue->recordAddrOrDataReady(inst);
8099
inst->sqIt->setStatus(o3::SplitStoreStatus::StdPipeFinish);
81100
}
82101

src/cpu/o3/BaseO3CPU.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,11 @@ def support_take_over(cls):
177177
"Time buffer size for forward communication")
178178

179179
LQEntries = Param.Unsigned(72, "Number of load queue entries")
180-
SQEntries = Param.Unsigned(56, "Number of store queue entries")
180+
SQEntries = Param.Unsigned(56, "Number of physical store queue entries")
181+
StoreQueueMultiple = Param.Unsigned(1,
182+
"Virtual-to-physical store queue capacity multiplier (power of two)")
183+
phySQFullCheckAtReplay = Param.Bool(True,
184+
"Wait for physical store queue space before starting a full-SQ replay")
181185

182186
LdPipeStages = Param.Unsigned(4, "Number of load pipeline stages")
183187
StPipeStages = Param.Unsigned(5, "Number of store pipeline stages")

src/cpu/o3/dyn_inst.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,7 @@ DynInstPtr DynInst::createStoreDataUop()
474474
stduop->setPredTaken(this->readPredTaken());
475475
stduop->setTid(this->threadNumber);
476476
stduop->setThreadState(this->thread);
477+
stduop->instQueue = this->instQueue;
477478

478479
// The store-data uop's only source is the original store's data source.
479480
// For RISC-V stores, src0 is the address base and src1 is the data value.

src/cpu/o3/dyn_inst.hh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ namespace o3
8686
{
8787

8888
class IssueQue;
89+
class InstructionQueue;
8990

9091
class DynInst : public ExecContext, public RefCounted
9192
{
@@ -496,6 +497,7 @@ class DynInst : public ExecContext, public RefCounted
496497
RequestPtr reqToVerify;
497498

498499
IssueQue* issueQue = nullptr;
500+
InstructionQueue* instQueue = nullptr;
499501
int issueportid = -1;
500502
int iqtag = -1;
501503

@@ -1174,6 +1176,11 @@ class DynInst : public ExecContext, public RefCounted
11741176
void setRescheduleReplay() { setReplay(LdStReplayType::RescheduleReplay); }
11751177
bool needRescheduleReplay() const { return getReplayType() == LdStReplayType::RescheduleReplay; }
11761178

1179+
void setPhysicalSQFullReplay() { setReplay(LdStReplayType::PhysicalSQFullReplay); }
1180+
bool needPhysicalSQFullReplay() const {
1181+
return getReplayType() == LdStReplayType::PhysicalSQFullReplay;
1182+
}
1183+
11771184
void setSTLFReplay() { setReplay(LdStReplayType::STLFReplay); }
11781185
bool needSTLFReplay() const { return getReplayType() == LdStReplayType::STLFReplay; }
11791186

src/cpu/o3/fetch.cc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,8 @@ Fetch::Fetch(CPU *_cpu, const BaseO3CPUParams &params)
144144
smtLdstqHighWater = params.smtBorrowLdstqHighWater;
145145
if (smtLdstqHighWater == 0) {
146146
smtLdstqHighWater =
147-
(params.LQEntries + params.SQEntries) *
147+
(params.LQEntries +
148+
params.SQEntries * params.StoreQueueMultiple) *
148149
params.smtBorrowLdstqHighWaterPercent / 100;
149150
}
150151

src/cpu/o3/inst_queue.cc

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,13 @@ InstructionQueue::MdpAddrReplayLdInst::MdpAddrReplayLdInst(
119119
{
120120
}
121121

122+
bool
123+
InstructionQueue::PhysicalSQFullReplayOrder::operator()(
124+
const DynInstPtr &lhs, const DynInstPtr &rhs) const
125+
{
126+
return lhs->seqNum > rhs->seqNum;
127+
}
128+
122129
bool
123130
InstructionQueue::hasMdpAddrReplayInsts() const
124131
{
@@ -397,6 +404,9 @@ InstructionQueue::resetState()
397404
for (auto &replay_ld_insts : mdpAddrReplayLdInsts) {
398405
replay_ld_insts.clear();
399406
}
407+
for (auto &replay_q : physicalSQFullReplayQs) {
408+
replay_q = PhysicalSQFullReplayQueue();
409+
}
400410
blockedMemInsts.clear();
401411
retryMemInsts.clear();
402412
wbOutstanding = 0;
@@ -434,6 +444,7 @@ InstructionQueue::isDrained() const
434444
bool drained = scheduler->isDrained() &&
435445
instsToExecute.empty() &&
436446
wbOutstanding == 0;
447+
drained = drained && !hasPhysicalSQFullReplayInsts();
437448
for (ThreadID tid = 0; tid < numThreads; ++tid)
438449
drained = drained && memDepUnit[tid].isDrained();
439450

@@ -444,6 +455,7 @@ void
444455
InstructionQueue::drainSanityCheck() const
445456
{
446457
assert(instsToExecute.empty());
458+
assert(!hasPhysicalSQFullReplayInsts());
447459
for (ThreadID tid = 0; tid < numThreads; ++tid)
448460
memDepUnit[tid].drainSanityCheck();
449461
}
@@ -472,6 +484,7 @@ InstructionQueue::insert(const DynInstPtr &new_inst, int disp_seq)
472484
}
473485
// Make sure the instruction is valid
474486
assert(new_inst);
487+
new_inst->instQueue = this;
475488

476489
DPRINTF(IQ, "Adding instruction [sn:%llu] PC %s to the IQ.\n",
477490
new_inst->seqNum, new_inst->pcState());
@@ -495,6 +508,7 @@ InstructionQueue::insertNonSpec(const DynInstPtr &new_inst)
495508
}
496509

497510
assert(new_inst);
511+
new_inst->instQueue = this;
498512

499513
scheduler->insertNonSpec(new_inst);
500514
nonSpecInsts[new_inst->seqNum] = new_inst;
@@ -632,6 +646,10 @@ InstructionQueue::scheduleReadyInsts()
632646
mem_inst->issueQue->retryMem(mem_inst);
633647
}
634648

649+
while ((mem_inst = getPhysicalSQFullReplayInstToExecute())) {
650+
mem_inst->issueQue->retryMem(mem_inst);
651+
}
652+
635653
// Have iterator to head of the list
636654
// While I haven't exceeded bandwidth or reached the end of the list,
637655
// Try to get a FU that can do what this op needs.
@@ -1108,6 +1126,68 @@ InstructionQueue::getBlockedMemInstToExecute()
11081126
}
11091127
}
11101128

1129+
void
1130+
InstructionQueue::deferPhysicalSQFullReplay(const DynInstPtr &inst)
1131+
{
1132+
assert(inst);
1133+
assert(inst->needPhysicalSQFullReplay());
1134+
iewStage->ldstQueue.recordStoreQueueReplay(inst);
1135+
physicalSQFullReplayQs[inst->threadNumber].push(inst);
1136+
DPRINTF(Schedule,
1137+
"Physical SQ replay waits in dedicated IQ queue [sn:%llu] "
1138+
"sqIdx=%llu\n",
1139+
inst->seqNum, static_cast<unsigned long long>(inst->sqIdx));
1140+
}
1141+
1142+
bool
1143+
InstructionQueue::storeQueueWriteReady(const DynInstPtr &inst) const
1144+
{
1145+
return iewStage->ldstQueue.storeQueueWriteReady(inst);
1146+
}
1147+
1148+
void
1149+
InstructionQueue::recordAddrOrDataReady(const DynInstPtr &inst)
1150+
{
1151+
iewStage->ldstQueue.recordAddrOrDataReady(inst);
1152+
}
1153+
1154+
DynInstPtr
1155+
InstructionQueue::getPhysicalSQFullReplayInstToExecute()
1156+
{
1157+
for (ThreadID tid = 0; tid < MaxThreads; ++tid) {
1158+
auto &replay_q = physicalSQFullReplayQs[tid];
1159+
while (!replay_q.empty()) {
1160+
const auto inst = replay_q.top();
1161+
if (!inst || inst->isSquashed()) {
1162+
replay_q.pop();
1163+
continue;
1164+
}
1165+
if (!iewStage->ldstQueue.phySQFullReplayReady(inst)) {
1166+
break;
1167+
}
1168+
1169+
replay_q.pop();
1170+
DPRINTF(Schedule,
1171+
"Physical SQ replay wakes from IQ queue [sn:%llu] "
1172+
"sqIdx=%llu\n",
1173+
inst->seqNum, static_cast<unsigned long long>(inst->sqIdx));
1174+
return inst;
1175+
}
1176+
}
1177+
return nullptr;
1178+
}
1179+
1180+
bool
1181+
InstructionQueue::hasPhysicalSQFullReplayInsts() const
1182+
{
1183+
for (const auto &replay_q : physicalSQFullReplayQs) {
1184+
if (!replay_q.empty()) {
1185+
return true;
1186+
}
1187+
}
1188+
return false;
1189+
}
1190+
11111191
void
11121192
InstructionQueue::violation(const DynInstPtr &store,
11131193
const DynInstPtr &faulting_load)

src/cpu/o3/inst_queue.hh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,15 @@ class InstructionQueue
226226
*/
227227
DynInstPtr getBlockedMemInstToExecute();
228228

229+
/** Insert a failed STA/STD into the physical-SQ replay wait queue. */
230+
void deferPhysicalSQFullReplay(const DynInstPtr &inst);
231+
232+
/** Whether an STA/STD may write its current physical SQ window. */
233+
bool storeQueueWriteReady(const DynInstPtr &inst) const;
234+
235+
/** Record the first address/data-ready transition for an SQ entry. */
236+
void recordAddrOrDataReady(const DynInstPtr &inst);
237+
229238
/** Process FU completion event. */
230239
void processFUCompletion(const DynInstPtr &inst, int fu_idx);
231240

@@ -380,6 +389,20 @@ class InstructionQueue
380389

381390
bool hasMdpAddrReplayInsts() const;
382391

392+
struct PhysicalSQFullReplayOrder
393+
{
394+
bool operator()(const DynInstPtr &lhs, const DynInstPtr &rhs) const;
395+
};
396+
397+
using PhysicalSQFullReplayQueue = std::priority_queue<
398+
DynInstPtr, std::vector<DynInstPtr>, PhysicalSQFullReplayOrder>;
399+
400+
std::array<PhysicalSQFullReplayQueue, MaxThreads>
401+
physicalSQFullReplayQs;
402+
403+
DynInstPtr getPhysicalSQFullReplayInstToExecute();
404+
bool hasPhysicalSQFullReplayInsts() const;
405+
383406
/** List of instructions that have been cache blocked. */
384407
std::list<DynInstPtr> blockedMemInsts;
385408

src/cpu/o3/issue_queue.cc

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -627,10 +627,17 @@ IssueQue::issueToFu()
627627

628628
bool incTagRefillBlockStats = false;
629629

630-
// replay first
631630
for (; !replayQ.empty() && replayed < outports; replayed++) {
632631
auto& inst = replayQ.front();
633632

633+
// Do not let replay requests starve the older issuing requests
634+
if (issueHasOlderInsts(inst)) {
635+
DPRINTF(Schedule,
636+
"replay [sn:%llu] detected an older issuing request, delay this replay.\n",
637+
inst->seqNum);
638+
break;
639+
}
640+
634641
if (inst->isLoad()) {
635642
// Loads selected here enter loadpipe S0 next cycle, so block on
636643
// the mainpipe tag-write state predicted for that admission point.
@@ -669,12 +676,16 @@ IssueQue::issueToFu()
669676
incTagRefillBlockStats = true;
670677
}
671678

672-
if ((issued >= outports) || (inst->isLoad() && (issuedLoad >= numLoadPipe)) ||
673-
(inst->isStore() && (issuedStore >= numStorePipe)) || blockLoad) {
679+
const bool issueOccupied =
680+
(issued >= outports) ||
681+
(inst->isLoad() && (issuedLoad >= numLoadPipe)) ||
682+
(inst->isStore() && (issuedStore >= numStorePipe)) || blockLoad;
683+
if (issueOccupied) {
674684
inst->clearScheduled();
675685
// only for load/store
676686
READYQ_PUSH(inst);
677-
DPRINTF(Schedule, "[sn:%llu] issue failed due to being occupied\n", inst->seqNum);
687+
DPRINTF(Schedule, "[sn:%llu] issue failed due to being occupied\n",
688+
inst->seqNum);
678689
continue;
679690
}
680691
if (!checkScoreboard(inst)) {
@@ -729,6 +740,24 @@ IssueQue::retryMem(const DynInstPtr& inst)
729740
replayQ.push(inst);
730741
}
731742

743+
bool
744+
IssueQue::issueHasOlderInsts(const DynInstPtr& replay_inst) const
745+
{
746+
if (!replay_inst) {
747+
return false;
748+
}
749+
750+
for (int i = 0; i < toFu->size; ++i) {
751+
const auto &selected = toFu->insts[i];
752+
if (selected &&
753+
selected->threadNumber == replay_inst->threadNumber &&
754+
selected->seqNum < replay_inst->seqNum) {
755+
return true;
756+
}
757+
}
758+
return false;
759+
}
760+
732761
bool
733762
IssueQue::idle()
734763
{

0 commit comments

Comments
 (0)