cpu-minor: Disentangle the PC and fetch address.

The minor CPU was using a PCState object both to track redirects when
taking a branch, etc, and to track where to fetch a line of memory from.
It would need to create a new PCState object, or at least update the
existing one, whenever it needed to advance to the next line.

This is problematic since it means the minor CPU needs to know how to
create or set a PCState object, and since it by necessity only
understands the most basic aspect of a PCState, what the address is, it
can only set that, with all the other potential attributes staying at
their old values or getting set to some default.

Instead, this change separates the two. There is now a PC which is used
for redirects which the later stages will only pick up if there is a
change in "sequence", the same behavior as before. This PC will only
ever be set when changing sequence, and will otherwise not be
meaningful/useful.

There is also now a separate fetch address which is what the fetch stage
uses to get new lines. This was all the PC value that was artificially
updated was used for anyway.

Change-Id: Ia64bbe21e980566ae77786999689c9c8a94e9378
Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/52048
Tested-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: ZHENGRONG WANG <seanyukigeek@gmail.com>
Maintainer: ZHENGRONG WANG <seanyukigeek@gmail.com>
This commit is contained in:
Gabe Black
2021-10-10 14:53:43 -07:00
parent dc8ac3b6ad
commit f9cbef9bf7
3 changed files with 24 additions and 12 deletions

View File

@@ -157,7 +157,7 @@ Fetch1::fetchLine(ThreadID tid)
/* If line_offset != 0, a request is pushed for the remainder of the
* line. */
/* Use a lower, sizeof(MachInst) aligned address for the fetch */
Addr aligned_pc = thread.pc.instAddr() & ~((Addr) lineSnap - 1);
Addr aligned_pc = thread.fetchAddr & ~((Addr) lineSnap - 1);
unsigned int line_offset = aligned_pc % lineSnap;
unsigned int request_size = maxLineWidth - line_offset;
@@ -166,17 +166,18 @@ Fetch1::fetchLine(ThreadID tid)
thread.streamSeqNum, thread.predictionSeqNum,
lineSeqNum);
FetchRequestPtr request = new FetchRequest(*this, request_id, thread.pc);
FetchRequestPtr request = new FetchRequest(*this, request_id,
thread.fetchAddr);
DPRINTF(Fetch, "Inserting fetch into the fetch queue "
"%s addr: 0x%x pc: %s line_offset: %d request_size: %d\n",
request_id, aligned_pc, thread.pc, line_offset, request_size);
request_id, aligned_pc, thread.fetchAddr, line_offset, request_size);
request->request->setContext(cpu.threads[tid]->getTC()->contextId());
request->request->setVirt(
aligned_pc, request_size, Request::INST_FETCH, cpu.instRequestorId(),
/* I've no idea why we need the PC, but give it */
thread.pc.instAddr());
thread.fetchAddr);
DPRINTF(Fetch, "Submitting ITLB request\n");
numFetchesInITLB++;
@@ -200,7 +201,7 @@ Fetch1::fetchLine(ThreadID tid)
/* Step the PC for the next line onto the line aligned next address.
* Note that as instructions can span lines, this PC is only a
* reliable 'new' PC if the next line has a new stream sequence number. */
thread.pc.set(aligned_pc + request_size);
thread.fetchAddr = aligned_pc + request_size;
}
std::ostream &
@@ -511,6 +512,7 @@ Fetch1::changeStream(const BranchData &branch)
break;
}
thread.pc = branch.target;
thread.fetchAddr = thread.pc.instAddr();
}
void
@@ -543,8 +545,10 @@ Fetch1::processResponse(Fetch1::FetchRequestPtr response,
line.setFault(response->fault);
/* Make sequence numbers valid in return */
line.id = response->id;
/* Set PC to virtual address */
line.pc = response->pc;
/* Set the PC in case there was a sequence change */
line.pc = thread.pc;
/* Set fetch address to virtual address */
line.fetchAddr = response->pc;
/* Set the lineBase, which is a sizeof(MachInst) aligned address <=
* pc.instAddr() */
line.lineBaseAddr = response->request->getVaddr();
@@ -712,6 +716,7 @@ Fetch1::wakeupFetch(ThreadID tid)
ThreadContext *thread_ctx = cpu.getContext(tid);
Fetch1ThreadInfo &thread = fetchInfo[tid];
thread.pc = thread_ctx->pcState();
thread.fetchAddr = thread.pc.instAddr();
thread.state = FetchRunning;
thread.wakeupGuard = true;
DPRINTF(Fetch, "[tid:%d]: Changing stream wakeup %s\n",

View File

@@ -139,7 +139,7 @@ class Fetch1 : public Named
RequestPtr request;
/** PC to fixup with line address */
TheISA::PCState pc;
Addr pc;
/** Fill in a fault if one happens during fetch, check this by
* picking apart the response packet */
@@ -173,7 +173,7 @@ class Fetch1 : public Named
ThreadContext *tc, BaseMMU::Mode mode);
public:
FetchRequest(Fetch1 &fetch_, InstId id_, TheISA::PCState pc_) :
FetchRequest(Fetch1 &fetch_, InstId id_, Addr pc_) :
SenderState(),
fetch(fetch_),
state(NotIssued),
@@ -248,6 +248,7 @@ class Fetch1 : public Named
Fetch1ThreadInfo() :
state(FetchWaitingForPC),
pc(TheISA::PCState(0)),
fetchAddr(0),
streamSeqNum(InstId::firstStreamSeqNum),
predictionSeqNum(InstId::firstPredictionSeqNum),
blocked(false),
@@ -265,10 +266,13 @@ class Fetch1 : public Named
FetchState state;
/** Fetch PC value. This is updated by branches from Execute, branch
* prediction targets from Fetch2 and by incrementing it as we fetch
* lines subsequent to those two sources. */
* prediction targets from Fetch2. This is only valid immediately
* following a redirect from one of those two sources. */
TheISA::PCState pc;
/** The address we're currently fetching lines from. */
Addr fetchAddr;
/** Stream sequence number. This changes on request from Execute and is
* used to tag instructions by the fetch stream to which they belong.
* Execute originates new prediction sequence numbers. */

View File

@@ -184,9 +184,12 @@ class ForwardLineData /* : public ReportIF, public BubbleIF */
* <= pc.instAddr() */
Addr lineBaseAddr;
/** PC of the first requested inst within this line */
/** PC of the first inst within this sequence */
TheISA::PCState pc;
/** Address of this line of data */
Addr fetchAddr;
/** Explicit line width, don't rely on data.size */
unsigned int lineWidth;