CPU: Implement translateTiming which defers to translateAtomic, and convert the timing simple CPU to use it.
This commit is contained in:
@@ -317,7 +317,7 @@ ITB::regStats()
|
||||
}
|
||||
|
||||
Fault
|
||||
ITB::translateAtomic(RequestPtr &req, ThreadContext *tc)
|
||||
ITB::translateAtomic(RequestPtr req, ThreadContext *tc)
|
||||
{
|
||||
//If this is a pal pc, then set PHYSICAL
|
||||
if (FULL_SYSTEM && PcPAL(req->getPC()))
|
||||
@@ -401,6 +401,14 @@ ITB::translateAtomic(RequestPtr &req, ThreadContext *tc)
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
ITB::translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation)
|
||||
{
|
||||
assert(translation);
|
||||
translation->finish(translateAtomic(req, tc), req, tc, false);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Alpha DTB
|
||||
@@ -479,7 +487,7 @@ DTB::regStats()
|
||||
}
|
||||
|
||||
Fault
|
||||
DTB::translateAtomic(RequestPtr &req, ThreadContext *tc, bool write)
|
||||
DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write)
|
||||
{
|
||||
Addr pc = tc->readPC();
|
||||
|
||||
@@ -616,6 +624,14 @@ DTB::translateAtomic(RequestPtr &req, ThreadContext *tc, bool write)
|
||||
return checkCacheability(req);
|
||||
}
|
||||
|
||||
void
|
||||
DTB::translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation, bool write)
|
||||
{
|
||||
assert(translation);
|
||||
translation->finish(translateAtomic(req, tc, write), req, tc, write);
|
||||
}
|
||||
|
||||
TlbEntry &
|
||||
TLB::index(bool advance)
|
||||
{
|
||||
|
||||
@@ -131,7 +131,9 @@ class ITB : public TLB
|
||||
ITB(const Params *p);
|
||||
virtual void regStats();
|
||||
|
||||
Fault translateAtomic(RequestPtr &req, ThreadContext *tc);
|
||||
Fault translateAtomic(RequestPtr req, ThreadContext *tc);
|
||||
void translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation);
|
||||
};
|
||||
|
||||
class DTB : public TLB
|
||||
@@ -155,7 +157,9 @@ class DTB : public TLB
|
||||
DTB(const Params *p);
|
||||
virtual void regStats();
|
||||
|
||||
Fault translateAtomic(RequestPtr &req, ThreadContext *tc, bool write);
|
||||
Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool write);
|
||||
void translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation, bool write);
|
||||
};
|
||||
|
||||
} // namespace AlphaISA
|
||||
|
||||
@@ -310,7 +310,7 @@ TLB::regStats()
|
||||
}
|
||||
|
||||
Fault
|
||||
ITB::translateAtomic(RequestPtr &req, ThreadContext *tc)
|
||||
ITB::translateAtomic(RequestPtr req, ThreadContext *tc)
|
||||
{
|
||||
#if !FULL_SYSTEM
|
||||
Process * p = tc->getProcessPtr();
|
||||
@@ -426,8 +426,16 @@ ITB::translateAtomic(RequestPtr &req, ThreadContext *tc)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
ITB::translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation)
|
||||
{
|
||||
assert(translation);
|
||||
translation->finish(translateAtomic(req, tc), req, tc, false);
|
||||
}
|
||||
|
||||
Fault
|
||||
DTB::translateAtomic(RequestPtr &req, ThreadContext *tc, bool write)
|
||||
DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write)
|
||||
{
|
||||
#if !FULL_SYSTEM
|
||||
Process * p = tc->getProcessPtr();
|
||||
@@ -564,6 +572,14 @@ DTB::translateAtomic(RequestPtr &req, ThreadContext *tc, bool write)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
DTB::translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation, bool write)
|
||||
{
|
||||
assert(translation);
|
||||
translation->finish(translateAtomic(req, tc, write), req, tc, write);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Mips ITB
|
||||
|
||||
@@ -145,7 +145,9 @@ class ITB : public TLB {
|
||||
typedef MipsTLBParams Params;
|
||||
ITB(const Params *p);
|
||||
|
||||
Fault translateAtomic(RequestPtr &req, ThreadContext *tc);
|
||||
Fault translateAtomic(RequestPtr req, ThreadContext *tc);
|
||||
void translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation);
|
||||
};
|
||||
|
||||
class DTB : public TLB {
|
||||
@@ -153,8 +155,10 @@ class DTB : public TLB {
|
||||
typedef MipsTLBParams Params;
|
||||
DTB(const Params *p);
|
||||
|
||||
Fault translateAtomic(RequestPtr &req, ThreadContext *tc,
|
||||
Fault translateAtomic(RequestPtr req, ThreadContext *tc,
|
||||
bool write = false);
|
||||
void translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation, bool write = false);
|
||||
};
|
||||
|
||||
class UTB : public ITB, public DTB {
|
||||
|
||||
@@ -436,7 +436,7 @@ DTB::writeSfsr(Addr a, bool write, ContextType ct,
|
||||
}
|
||||
|
||||
Fault
|
||||
ITB::translateAtomic(RequestPtr &req, ThreadContext *tc)
|
||||
ITB::translateAtomic(RequestPtr req, ThreadContext *tc)
|
||||
{
|
||||
uint64_t tlbdata = tc->readMiscRegNoEffect(MISCREG_TLB_DATA);
|
||||
|
||||
@@ -548,8 +548,16 @@ ITB::translateAtomic(RequestPtr &req, ThreadContext *tc)
|
||||
return NoFault;
|
||||
}
|
||||
|
||||
void
|
||||
ITB::translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation)
|
||||
{
|
||||
assert(translation);
|
||||
translation->finish(translateAtomic(req, tc), req, tc, false);
|
||||
}
|
||||
|
||||
Fault
|
||||
DTB::translateAtomic(RequestPtr &req, ThreadContext *tc, bool write)
|
||||
DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write)
|
||||
{
|
||||
/*
|
||||
* @todo this could really use some profiling and fixing to make
|
||||
@@ -847,6 +855,14 @@ handleMmuRegAccess:
|
||||
return NoFault;
|
||||
};
|
||||
|
||||
void
|
||||
DTB::translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation, bool write)
|
||||
{
|
||||
assert(translation);
|
||||
translation->finish(translateAtomic(req, tc, write), req, tc, write);
|
||||
}
|
||||
|
||||
#if FULL_SYSTEM
|
||||
|
||||
Tick
|
||||
|
||||
@@ -177,7 +177,9 @@ class ITB : public TLB
|
||||
cacheEntry = NULL;
|
||||
}
|
||||
|
||||
Fault translateAtomic(RequestPtr &req, ThreadContext *tc);
|
||||
Fault translateAtomic(RequestPtr req, ThreadContext *tc);
|
||||
void translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation);
|
||||
private:
|
||||
void writeSfsr(bool write, ContextType ct,
|
||||
bool se, FaultTypes ft, int asi);
|
||||
@@ -199,7 +201,10 @@ class DTB : public TLB
|
||||
cacheEntry[1] = NULL;
|
||||
}
|
||||
|
||||
Fault translateAtomic(RequestPtr &req, ThreadContext *tc, bool write);
|
||||
Fault translateAtomic(RequestPtr req,
|
||||
ThreadContext *tc, bool write=false);
|
||||
void translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation, bool write=false);
|
||||
#if FULL_SYSTEM
|
||||
Tick doMmuRegRead(ThreadContext *tc, Packet *pkt);
|
||||
Tick doMmuRegWrite(ThreadContext *tc, Packet *pkt);
|
||||
|
||||
@@ -190,7 +190,7 @@ TLB::demapPage(Addr va, uint64_t asn)
|
||||
|
||||
template<class TlbFault>
|
||||
Fault
|
||||
TLB::translateAtomic(RequestPtr &req, ThreadContext *tc,
|
||||
TLB::translateAtomic(RequestPtr req, ThreadContext *tc,
|
||||
bool write, bool execute)
|
||||
{
|
||||
Addr vaddr = req->getVaddr();
|
||||
@@ -663,17 +663,33 @@ TLB::translateAtomic(RequestPtr &req, ThreadContext *tc,
|
||||
};
|
||||
|
||||
Fault
|
||||
DTB::translateAtomic(RequestPtr &req, ThreadContext *tc, bool write)
|
||||
DTB::translateAtomic(RequestPtr req, ThreadContext *tc, bool write)
|
||||
{
|
||||
return TLB::translateAtomic<FakeDTLBFault>(req, tc, write, false);
|
||||
}
|
||||
|
||||
void
|
||||
DTB::translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation, bool write)
|
||||
{
|
||||
assert(translation);
|
||||
translation->finish(translateAtomic(req, tc, write), req, tc, write);
|
||||
}
|
||||
|
||||
Fault
|
||||
ITB::translateAtomic(RequestPtr &req, ThreadContext *tc)
|
||||
ITB::translateAtomic(RequestPtr req, ThreadContext *tc)
|
||||
{
|
||||
return TLB::translateAtomic<FakeITLBFault>(req, tc, false, true);
|
||||
}
|
||||
|
||||
void
|
||||
ITB::translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation)
|
||||
{
|
||||
assert(translation);
|
||||
translation->finish(translateAtomic(req, tc), req, tc, false);
|
||||
}
|
||||
|
||||
#if FULL_SYSTEM
|
||||
|
||||
Tick
|
||||
|
||||
@@ -138,8 +138,10 @@ namespace X86ISA
|
||||
EntryList entryList;
|
||||
|
||||
template<class TlbFault>
|
||||
Fault translateAtomic(RequestPtr &req, ThreadContext *tc,
|
||||
Fault translateAtomic(RequestPtr req, ThreadContext *tc,
|
||||
bool write, bool execute);
|
||||
void translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation, bool write, bool execute);
|
||||
|
||||
public:
|
||||
|
||||
@@ -159,7 +161,9 @@ namespace X86ISA
|
||||
_allowNX = false;
|
||||
}
|
||||
|
||||
Fault translateAtomic(RequestPtr &req, ThreadContext *tc);
|
||||
Fault translateAtomic(RequestPtr req, ThreadContext *tc);
|
||||
void translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation);
|
||||
|
||||
friend class DTB;
|
||||
};
|
||||
@@ -172,7 +176,9 @@ namespace X86ISA
|
||||
{
|
||||
_allowNX = true;
|
||||
}
|
||||
Fault translateAtomic(RequestPtr &req, ThreadContext *tc, bool write);
|
||||
Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool write);
|
||||
void translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation, bool write);
|
||||
#if FULL_SYSTEM
|
||||
Tick doMmuRegRead(ThreadContext *tc, Packet *pkt);
|
||||
Tick doMmuRegWrite(ThreadContext *tc, Packet *pkt);
|
||||
|
||||
@@ -607,8 +607,10 @@ AtomicSimpleCPU::tick()
|
||||
Fault fault = NoFault;
|
||||
|
||||
bool fromRom = isRomMicroPC(thread->readMicroPC());
|
||||
if (!fromRom)
|
||||
fault = setupFetchRequest(&ifetch_req);
|
||||
if (!fromRom) {
|
||||
setupFetchRequest(&ifetch_req);
|
||||
fault = thread->itb->translateAtomic(&ifetch_req, tc);
|
||||
}
|
||||
|
||||
if (fault == NoFault) {
|
||||
Tick icache_latency = 0;
|
||||
|
||||
@@ -330,7 +330,7 @@ BaseSimpleCPU::checkForInterrupts()
|
||||
}
|
||||
|
||||
|
||||
Fault
|
||||
void
|
||||
BaseSimpleCPU::setupFetchRequest(Request *req)
|
||||
{
|
||||
Addr threadPC = thread->readPC();
|
||||
@@ -346,10 +346,6 @@ BaseSimpleCPU::setupFetchRequest(Request *req)
|
||||
|
||||
Addr fetchPC = (threadPC & PCMask) + fetchOffset;
|
||||
req->setVirt(0, fetchPC, sizeof(MachInst), 0, threadPC);
|
||||
|
||||
Fault fault = thread->itb->translateAtomic(req, tc);
|
||||
|
||||
return fault;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -125,9 +125,11 @@ class BaseSimpleCPU : public BaseCPU
|
||||
enum Status {
|
||||
Idle,
|
||||
Running,
|
||||
ITBWaitResponse,
|
||||
IcacheRetry,
|
||||
IcacheWaitResponse,
|
||||
IcacheWaitSwitch,
|
||||
DTBWaitResponse,
|
||||
DcacheRetry,
|
||||
DcacheWaitResponse,
|
||||
DcacheWaitSwitch,
|
||||
@@ -160,7 +162,7 @@ class BaseSimpleCPU : public BaseCPU
|
||||
bool stayAtPC;
|
||||
|
||||
void checkForInterrupts();
|
||||
Fault setupFetchRequest(Request *req);
|
||||
void setupFetchRequest(Request *req);
|
||||
void preExecute();
|
||||
void postExecute();
|
||||
void advancePC(Fault fault);
|
||||
|
||||
@@ -104,7 +104,8 @@ TimingSimpleCPU::CpuPort::TickEvent::schedule(PacketPtr _pkt, Tick t)
|
||||
}
|
||||
|
||||
TimingSimpleCPU::TimingSimpleCPU(TimingSimpleCPUParams *p)
|
||||
: BaseSimpleCPU(p), icachePort(this, p->clock), dcachePort(this, p->clock), fetchEvent(this)
|
||||
: BaseSimpleCPU(p), fetchTranslation(this), icachePort(this, p->clock),
|
||||
dcachePort(this, p->clock), fetchEvent(this)
|
||||
{
|
||||
_status = Idle;
|
||||
|
||||
@@ -262,66 +263,123 @@ TimingSimpleCPU::handleReadPacket(PacketPtr pkt)
|
||||
return dcache_pkt == NULL;
|
||||
}
|
||||
|
||||
Fault
|
||||
TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
|
||||
RequestPtr &req, Addr split_addr, uint8_t *data, bool read)
|
||||
void
|
||||
TimingSimpleCPU::sendData(Fault fault, RequestPtr req,
|
||||
uint8_t *data, uint64_t *res, bool read)
|
||||
{
|
||||
Fault fault;
|
||||
RequestPtr req1, req2;
|
||||
assert(!req->isLocked() && !req->isSwap());
|
||||
req->splitOnVaddr(split_addr, req1, req2);
|
||||
|
||||
pkt1 = pkt2 = NULL;
|
||||
if ((fault = buildPacket(pkt1, req1, read)) != NoFault ||
|
||||
(fault = buildPacket(pkt2, req2, read)) != NoFault) {
|
||||
_status = Running;
|
||||
if (fault != NoFault) {
|
||||
delete data;
|
||||
delete req;
|
||||
delete req1;
|
||||
delete pkt1;
|
||||
req = NULL;
|
||||
pkt1 = NULL;
|
||||
return fault;
|
||||
|
||||
translationFault(fault);
|
||||
return;
|
||||
}
|
||||
|
||||
assert(!req1->isMmapedIpr() && !req2->isMmapedIpr());
|
||||
|
||||
req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags());
|
||||
PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(),
|
||||
Packet::Broadcast);
|
||||
if (req->getFlags().isSet(Request::NO_ACCESS)) {
|
||||
delete req1;
|
||||
delete pkt1;
|
||||
delete req2;
|
||||
delete pkt2;
|
||||
pkt1 = pkt;
|
||||
pkt2 = NULL;
|
||||
return NoFault;
|
||||
}
|
||||
|
||||
PacketPtr pkt;
|
||||
buildPacket(pkt, req, read);
|
||||
pkt->dataDynamic<uint8_t>(data);
|
||||
pkt1->dataStatic<uint8_t>(data);
|
||||
pkt2->dataStatic<uint8_t>(data + req1->getSize());
|
||||
if (req->getFlags().isSet(Request::NO_ACCESS)) {
|
||||
assert(!dcache_pkt);
|
||||
pkt->makeResponse();
|
||||
completeDataAccess(pkt);
|
||||
} else if (read) {
|
||||
handleReadPacket(pkt);
|
||||
} else {
|
||||
bool do_access = true; // flag to suppress cache access
|
||||
|
||||
SplitMainSenderState * main_send_state = new SplitMainSenderState;
|
||||
pkt->senderState = main_send_state;
|
||||
main_send_state->fragments[0] = pkt1;
|
||||
main_send_state->fragments[1] = pkt2;
|
||||
main_send_state->outstanding = 2;
|
||||
pkt1->senderState = new SplitFragmentSenderState(pkt, 0);
|
||||
pkt2->senderState = new SplitFragmentSenderState(pkt, 1);
|
||||
return fault;
|
||||
if (req->isLocked()) {
|
||||
do_access = TheISA::handleLockedWrite(thread, req);
|
||||
} else if (req->isCondSwap()) {
|
||||
assert(res);
|
||||
req->setExtraData(*res);
|
||||
}
|
||||
|
||||
if (do_access) {
|
||||
dcache_pkt = pkt;
|
||||
handleWritePacket();
|
||||
} else {
|
||||
_status = DcacheWaitResponse;
|
||||
completeDataAccess(pkt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Fault
|
||||
TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr &req, bool read)
|
||||
void
|
||||
TimingSimpleCPU::sendSplitData(Fault fault1, Fault fault2,
|
||||
RequestPtr req1, RequestPtr req2, RequestPtr req,
|
||||
uint8_t *data, bool read)
|
||||
{
|
||||
Fault fault = thread->dtb->translateAtomic(req, tc, !read);
|
||||
MemCmd cmd;
|
||||
if (fault != NoFault) {
|
||||
delete req;
|
||||
req = NULL;
|
||||
pkt = NULL;
|
||||
return fault;
|
||||
_status = Running;
|
||||
if (fault1 != NoFault || fault2 != NoFault) {
|
||||
delete data;
|
||||
delete req1;
|
||||
delete req2;
|
||||
if (fault1 != NoFault)
|
||||
translationFault(fault1);
|
||||
else if (fault2 != NoFault)
|
||||
translationFault(fault2);
|
||||
return;
|
||||
}
|
||||
PacketPtr pkt1, pkt2;
|
||||
buildSplitPacket(pkt1, pkt2, req1, req2, req, data, read);
|
||||
if (req->getFlags().isSet(Request::NO_ACCESS)) {
|
||||
assert(!dcache_pkt);
|
||||
pkt1->makeResponse();
|
||||
completeDataAccess(pkt1);
|
||||
} else if (read) {
|
||||
if (handleReadPacket(pkt1)) {
|
||||
SplitFragmentSenderState * send_state =
|
||||
dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
|
||||
send_state->clearFromParent();
|
||||
if (handleReadPacket(pkt2)) {
|
||||
send_state = dynamic_cast<SplitFragmentSenderState *>(
|
||||
pkt1->senderState);
|
||||
send_state->clearFromParent();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dcache_pkt = pkt1;
|
||||
if (handleWritePacket()) {
|
||||
SplitFragmentSenderState * send_state =
|
||||
dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
|
||||
send_state->clearFromParent();
|
||||
dcache_pkt = pkt2;
|
||||
if (handleWritePacket()) {
|
||||
send_state = dynamic_cast<SplitFragmentSenderState *>(
|
||||
pkt1->senderState);
|
||||
send_state->clearFromParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TimingSimpleCPU::translationFault(Fault fault)
|
||||
{
|
||||
numCycles += tickToCycles(curTick - previousTick);
|
||||
previousTick = curTick;
|
||||
|
||||
if (traceData) {
|
||||
// Since there was a fault, we shouldn't trace this instruction.
|
||||
delete traceData;
|
||||
traceData = NULL;
|
||||
}
|
||||
|
||||
postExecute();
|
||||
|
||||
if (getState() == SimObject::Draining) {
|
||||
advancePC(fault);
|
||||
completeDrain();
|
||||
} else {
|
||||
advanceInst(fault);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr req, bool read)
|
||||
{
|
||||
MemCmd cmd;
|
||||
if (read) {
|
||||
cmd = MemCmd::ReadReq;
|
||||
if (req->isLocked())
|
||||
cmd = MemCmd::LoadLockedReq;
|
||||
@@ -334,7 +392,40 @@ TimingSimpleCPU::buildPacket(PacketPtr &pkt, RequestPtr &req, bool read)
|
||||
}
|
||||
}
|
||||
pkt = new Packet(req, cmd, Packet::Broadcast);
|
||||
return NoFault;
|
||||
}
|
||||
|
||||
void
|
||||
TimingSimpleCPU::buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
|
||||
RequestPtr req1, RequestPtr req2, RequestPtr req,
|
||||
uint8_t *data, bool read)
|
||||
{
|
||||
pkt1 = pkt2 = NULL;
|
||||
|
||||
assert(!req1->isMmapedIpr() && !req2->isMmapedIpr());
|
||||
|
||||
if (req->getFlags().isSet(Request::NO_ACCESS)) {
|
||||
buildPacket(pkt1, req, read);
|
||||
return;
|
||||
}
|
||||
|
||||
buildPacket(pkt1, req1, read);
|
||||
buildPacket(pkt2, req2, read);
|
||||
|
||||
req->setPhys(req1->getPaddr(), req->getSize(), req1->getFlags());
|
||||
PacketPtr pkt = new Packet(req, pkt1->cmd.responseCommand(),
|
||||
Packet::Broadcast);
|
||||
|
||||
pkt->dataDynamic<uint8_t>(data);
|
||||
pkt1->dataStatic<uint8_t>(data);
|
||||
pkt2->dataStatic<uint8_t>(data + req1->getSize());
|
||||
|
||||
SplitMainSenderState * main_send_state = new SplitMainSenderState;
|
||||
pkt->senderState = main_send_state;
|
||||
main_send_state->fragments[0] = pkt1;
|
||||
main_send_state->fragments[1] = pkt2;
|
||||
main_send_state->outstanding = 2;
|
||||
pkt1->senderState = new SplitFragmentSenderState(pkt, 0);
|
||||
pkt2->senderState = new SplitFragmentSenderState(pkt, 1);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -348,42 +439,30 @@ TimingSimpleCPU::read(Addr addr, T &data, unsigned flags)
|
||||
int block_size = dcachePort.peerBlockSize();
|
||||
int data_size = sizeof(T);
|
||||
|
||||
PacketPtr pkt;
|
||||
RequestPtr req = new Request(asid, addr, data_size,
|
||||
flags, pc, _cpuId, thread_id);
|
||||
|
||||
Addr split_addr = roundDown(addr + data_size - 1, block_size);
|
||||
assert(split_addr <= addr || split_addr - addr < block_size);
|
||||
|
||||
|
||||
_status = DTBWaitResponse;
|
||||
if (split_addr > addr) {
|
||||
PacketPtr pkt1, pkt2;
|
||||
Fault fault = this->buildSplitPacket(pkt1, pkt2, req,
|
||||
split_addr, (uint8_t *)(new T), true);
|
||||
if (fault != NoFault)
|
||||
return fault;
|
||||
if (req->getFlags().isSet(Request::NO_ACCESS)) {
|
||||
dcache_pkt = pkt1;
|
||||
} else if (handleReadPacket(pkt1)) {
|
||||
SplitFragmentSenderState * send_state =
|
||||
dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
|
||||
send_state->clearFromParent();
|
||||
if (handleReadPacket(pkt2)) {
|
||||
send_state =
|
||||
dynamic_cast<SplitFragmentSenderState *>(pkt1->senderState);
|
||||
send_state->clearFromParent();
|
||||
}
|
||||
}
|
||||
RequestPtr req1, req2;
|
||||
assert(!req->isLocked() && !req->isSwap());
|
||||
req->splitOnVaddr(split_addr, req1, req2);
|
||||
|
||||
typedef SplitDataTranslation::WholeTranslationState WholeState;
|
||||
WholeState *state = new WholeState(req1, req2, req,
|
||||
(uint8_t *)(new T), true);
|
||||
thread->dtb->translateTiming(req1, tc,
|
||||
new SplitDataTranslation(this, 0, state), false);
|
||||
thread->dtb->translateTiming(req2, tc,
|
||||
new SplitDataTranslation(this, 1, state), false);
|
||||
} else {
|
||||
Fault fault = buildPacket(pkt, req, true);
|
||||
if (fault != NoFault) {
|
||||
return fault;
|
||||
}
|
||||
if (req->getFlags().isSet(Request::NO_ACCESS)) {
|
||||
dcache_pkt = pkt;
|
||||
} else {
|
||||
pkt->dataDynamic<T>(new T);
|
||||
handleReadPacket(pkt);
|
||||
}
|
||||
thread->dtb->translateTiming(req, tc,
|
||||
new DataTranslation(this, (uint8_t *)(new T), NULL, true),
|
||||
false);
|
||||
}
|
||||
|
||||
if (traceData) {
|
||||
@@ -484,54 +563,25 @@ TimingSimpleCPU::write(T data, Addr addr, unsigned flags, uint64_t *res)
|
||||
Addr split_addr = roundDown(addr + data_size - 1, block_size);
|
||||
assert(split_addr <= addr || split_addr - addr < block_size);
|
||||
|
||||
T *dataP = new T;
|
||||
*dataP = TheISA::gtoh(data);
|
||||
_status = DTBWaitResponse;
|
||||
if (split_addr > addr) {
|
||||
PacketPtr pkt1, pkt2;
|
||||
T *dataP = new T;
|
||||
*dataP = data;
|
||||
Fault fault = this->buildSplitPacket(pkt1, pkt2, req, split_addr,
|
||||
(uint8_t *)dataP, false);
|
||||
if (fault != NoFault)
|
||||
return fault;
|
||||
dcache_pkt = pkt1;
|
||||
if (!req->getFlags().isSet(Request::NO_ACCESS)) {
|
||||
if (handleWritePacket()) {
|
||||
SplitFragmentSenderState * send_state =
|
||||
dynamic_cast<SplitFragmentSenderState *>(
|
||||
pkt1->senderState);
|
||||
send_state->clearFromParent();
|
||||
dcache_pkt = pkt2;
|
||||
if (handleReadPacket(pkt2)) {
|
||||
send_state =
|
||||
dynamic_cast<SplitFragmentSenderState *>(
|
||||
pkt1->senderState);
|
||||
send_state->clearFromParent();
|
||||
}
|
||||
}
|
||||
}
|
||||
RequestPtr req1, req2;
|
||||
assert(!req->isLocked() && !req->isSwap());
|
||||
req->splitOnVaddr(split_addr, req1, req2);
|
||||
|
||||
typedef SplitDataTranslation::WholeTranslationState WholeState;
|
||||
WholeState *state = new WholeState(req1, req2, req,
|
||||
(uint8_t *)dataP, false);
|
||||
thread->dtb->translateTiming(req1, tc,
|
||||
new SplitDataTranslation(this, 0, state), true);
|
||||
thread->dtb->translateTiming(req2, tc,
|
||||
new SplitDataTranslation(this, 1, state), true);
|
||||
} else {
|
||||
bool do_access = true; // flag to suppress cache access
|
||||
|
||||
Fault fault = buildPacket(dcache_pkt, req, false);
|
||||
if (fault != NoFault)
|
||||
return fault;
|
||||
|
||||
if (!req->getFlags().isSet(Request::NO_ACCESS)) {
|
||||
if (req->isLocked()) {
|
||||
do_access = TheISA::handleLockedWrite(thread, req);
|
||||
} else if (req->isCondSwap()) {
|
||||
assert(res);
|
||||
req->setExtraData(*res);
|
||||
}
|
||||
|
||||
dcache_pkt->allocate();
|
||||
if (req->isMmapedIpr())
|
||||
dcache_pkt->set(htog(data));
|
||||
else
|
||||
dcache_pkt->set(data);
|
||||
|
||||
if (do_access)
|
||||
handleWritePacket();
|
||||
}
|
||||
thread->dtb->translateTiming(req, tc,
|
||||
new DataTranslation(this, (uint8_t *)dataP, res, false),
|
||||
true);
|
||||
}
|
||||
|
||||
if (traceData) {
|
||||
@@ -620,30 +670,39 @@ TimingSimpleCPU::fetch()
|
||||
if (!fromRom) {
|
||||
Request *ifetch_req = new Request();
|
||||
ifetch_req->setThreadContext(_cpuId, /* thread ID */ 0);
|
||||
Fault fault = setupFetchRequest(ifetch_req);
|
||||
|
||||
ifetch_pkt = new Packet(ifetch_req, MemCmd::ReadReq, Packet::Broadcast);
|
||||
ifetch_pkt->dataStatic(&inst);
|
||||
|
||||
if (fault == NoFault) {
|
||||
if (!icachePort.sendTiming(ifetch_pkt)) {
|
||||
// Need to wait for retry
|
||||
_status = IcacheRetry;
|
||||
} else {
|
||||
// Need to wait for cache to respond
|
||||
_status = IcacheWaitResponse;
|
||||
// ownership of packet transferred to memory system
|
||||
ifetch_pkt = NULL;
|
||||
}
|
||||
} else {
|
||||
delete ifetch_req;
|
||||
delete ifetch_pkt;
|
||||
// fetch fault: advance directly to next instruction (fault handler)
|
||||
advanceInst(fault);
|
||||
}
|
||||
setupFetchRequest(ifetch_req);
|
||||
thread->itb->translateTiming(ifetch_req, tc,
|
||||
&fetchTranslation);
|
||||
} else {
|
||||
_status = IcacheWaitResponse;
|
||||
completeIfetch(NULL);
|
||||
|
||||
numCycles += tickToCycles(curTick - previousTick);
|
||||
previousTick = curTick;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TimingSimpleCPU::sendFetch(Fault fault, RequestPtr req, ThreadContext *tc)
|
||||
{
|
||||
if (fault == NoFault) {
|
||||
ifetch_pkt = new Packet(req, MemCmd::ReadReq, Packet::Broadcast);
|
||||
ifetch_pkt->dataStatic(&inst);
|
||||
|
||||
if (!icachePort.sendTiming(ifetch_pkt)) {
|
||||
// Need to wait for retry
|
||||
_status = IcacheRetry;
|
||||
} else {
|
||||
// Need to wait for cache to respond
|
||||
_status = IcacheWaitResponse;
|
||||
// ownership of packet transferred to memory system
|
||||
ifetch_pkt = NULL;
|
||||
}
|
||||
} else {
|
||||
delete req;
|
||||
// fetch fault: advance directly to next instruction (fault handler)
|
||||
advanceInst(fault);
|
||||
}
|
||||
|
||||
numCycles += tickToCycles(curTick - previousTick);
|
||||
@@ -699,28 +758,11 @@ TimingSimpleCPU::completeIfetch(PacketPtr pkt)
|
||||
Fault fault = curStaticInst->initiateAcc(this, traceData);
|
||||
if (_status != Running) {
|
||||
// instruction will complete in dcache response callback
|
||||
assert(_status == DcacheWaitResponse || _status == DcacheRetry);
|
||||
assert(_status == DcacheWaitResponse ||
|
||||
_status == DcacheRetry || DTBWaitResponse);
|
||||
assert(fault == NoFault);
|
||||
} else {
|
||||
if (fault == NoFault) {
|
||||
// Note that ARM can have NULL packets if the instruction gets
|
||||
// squashed due to predication
|
||||
// early fail on store conditional: complete now
|
||||
assert(dcache_pkt != NULL || THE_ISA == ARM_ISA);
|
||||
|
||||
fault = curStaticInst->completeAcc(dcache_pkt, this,
|
||||
traceData);
|
||||
if (dcache_pkt != NULL)
|
||||
{
|
||||
delete dcache_pkt->req;
|
||||
delete dcache_pkt;
|
||||
dcache_pkt = NULL;
|
||||
}
|
||||
|
||||
// keep an instruction count
|
||||
if (fault == NoFault)
|
||||
countInst();
|
||||
} else if (traceData) {
|
||||
if (fault != NoFault && traceData) {
|
||||
// If there was a fault, we shouldn't trace this instruction.
|
||||
delete traceData;
|
||||
traceData = NULL;
|
||||
@@ -843,7 +885,7 @@ TimingSimpleCPU::completeDataAccess(PacketPtr pkt)
|
||||
}
|
||||
}
|
||||
|
||||
assert(_status == DcacheWaitResponse);
|
||||
assert(_status == DcacheWaitResponse || _status == DTBWaitResponse);
|
||||
_status = Running;
|
||||
|
||||
Fault fault = curStaticInst->completeAcc(pkt, this, traceData);
|
||||
|
||||
@@ -96,9 +96,114 @@ class TimingSimpleCPU : public BaseSimpleCPU
|
||||
}
|
||||
};
|
||||
|
||||
Fault buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2, RequestPtr &req,
|
||||
Addr split_addr, uint8_t *data, bool read);
|
||||
Fault buildPacket(PacketPtr &pkt, RequestPtr &req, bool read);
|
||||
class FetchTranslation : public BaseTLB::Translation
|
||||
{
|
||||
protected:
|
||||
TimingSimpleCPU *cpu;
|
||||
|
||||
public:
|
||||
FetchTranslation(TimingSimpleCPU *_cpu) : cpu(_cpu)
|
||||
{}
|
||||
|
||||
void finish(Fault fault, RequestPtr req,
|
||||
ThreadContext *tc, bool write)
|
||||
{
|
||||
cpu->sendFetch(fault, req, tc);
|
||||
}
|
||||
};
|
||||
FetchTranslation fetchTranslation;
|
||||
|
||||
class DataTranslation : public BaseTLB::Translation
|
||||
{
|
||||
protected:
|
||||
TimingSimpleCPU *cpu;
|
||||
uint8_t *data;
|
||||
uint64_t *res;
|
||||
bool read;
|
||||
|
||||
public:
|
||||
DataTranslation(TimingSimpleCPU *_cpu,
|
||||
uint8_t *_data, uint64_t *_res, bool _read) :
|
||||
cpu(_cpu), data(_data), res(_res), read(_read)
|
||||
{}
|
||||
|
||||
void
|
||||
finish(Fault fault, RequestPtr req,
|
||||
ThreadContext *tc, bool write)
|
||||
{
|
||||
cpu->sendData(fault, req, data, res, read);
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
class SplitDataTranslation : public BaseTLB::Translation
|
||||
{
|
||||
public:
|
||||
struct WholeTranslationState
|
||||
{
|
||||
public:
|
||||
int outstanding;
|
||||
RequestPtr requests[2];
|
||||
RequestPtr mainReq;
|
||||
Fault faults[2];
|
||||
uint8_t *data;
|
||||
bool read;
|
||||
|
||||
WholeTranslationState(RequestPtr req1, RequestPtr req2,
|
||||
RequestPtr main, uint8_t *_data, bool _read)
|
||||
{
|
||||
outstanding = 2;
|
||||
requests[0] = req1;
|
||||
requests[1] = req2;
|
||||
mainReq = main;
|
||||
faults[0] = faults[1] = NoFault;
|
||||
data = _data;
|
||||
read = _read;
|
||||
}
|
||||
};
|
||||
|
||||
TimingSimpleCPU *cpu;
|
||||
int index;
|
||||
WholeTranslationState *state;
|
||||
|
||||
SplitDataTranslation(TimingSimpleCPU *_cpu, int _index,
|
||||
WholeTranslationState *_state) :
|
||||
cpu(_cpu), index(_index), state(_state)
|
||||
{}
|
||||
|
||||
void
|
||||
finish(Fault fault, RequestPtr req,
|
||||
ThreadContext *tc, bool write)
|
||||
{
|
||||
assert(state);
|
||||
assert(state->outstanding);
|
||||
state->faults[index] = fault;
|
||||
if (--state->outstanding == 0) {
|
||||
cpu->sendSplitData(state->faults[0],
|
||||
state->faults[1],
|
||||
state->requests[0],
|
||||
state->requests[1],
|
||||
state->mainReq,
|
||||
state->data,
|
||||
state->read);
|
||||
delete state;
|
||||
}
|
||||
delete this;
|
||||
}
|
||||
};
|
||||
|
||||
void sendData(Fault fault, RequestPtr req,
|
||||
uint8_t *data, uint64_t *res, bool read);
|
||||
void sendSplitData(Fault fault1, Fault fault2,
|
||||
RequestPtr req1, RequestPtr req2, RequestPtr req,
|
||||
uint8_t *data, bool read);
|
||||
|
||||
void translationFault(Fault fault);
|
||||
|
||||
void buildPacket(PacketPtr &pkt, RequestPtr req, bool read);
|
||||
void buildSplitPacket(PacketPtr &pkt1, PacketPtr &pkt2,
|
||||
RequestPtr req1, RequestPtr req2, RequestPtr req,
|
||||
uint8_t *data, bool read);
|
||||
|
||||
bool handleReadPacket(PacketPtr pkt);
|
||||
// This function always implicitly uses dcache_pkt.
|
||||
@@ -228,8 +333,9 @@ class TimingSimpleCPU : public BaseSimpleCPU
|
||||
Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
|
||||
|
||||
void fetch();
|
||||
void sendFetch(Fault fault, RequestPtr req, ThreadContext *tc);
|
||||
void completeIfetch(PacketPtr );
|
||||
void completeDataAccess(PacketPtr );
|
||||
void completeDataAccess(PacketPtr pkt);
|
||||
void advanceInst(Fault fault);
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,6 +49,14 @@ GenericTLB::translateAtomic(RequestPtr req, ThreadContext * tc, bool)
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
GenericTLB::translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation, bool write)
|
||||
{
|
||||
assert(translation);
|
||||
translation->finish(translateAtomic(req, tc, write), req, tc, write);
|
||||
}
|
||||
|
||||
void
|
||||
GenericTLB::demapPage(Addr vaddr, uint64_t asn)
|
||||
{
|
||||
|
||||
@@ -47,6 +47,21 @@ class BaseTLB : public SimObject
|
||||
|
||||
public:
|
||||
virtual void demapPage(Addr vaddr, uint64_t asn) = 0;
|
||||
|
||||
class Translation
|
||||
{
|
||||
public:
|
||||
virtual ~Translation()
|
||||
{}
|
||||
|
||||
/*
|
||||
* The memory for this object may be dynamically allocated, and it may
|
||||
* be responsible for cleaning itself up which will happen in this
|
||||
* function. Once it's called, the object is no longer valid.
|
||||
*/
|
||||
virtual void finish(Fault fault, RequestPtr req,
|
||||
ThreadContext *tc, bool write=false) = 0;
|
||||
};
|
||||
};
|
||||
|
||||
class GenericTLB : public BaseTLB
|
||||
@@ -59,6 +74,8 @@ class GenericTLB : public BaseTLB
|
||||
void demapPage(Addr vaddr, uint64_t asn);
|
||||
|
||||
Fault translateAtomic(RequestPtr req, ThreadContext *tc, bool=false);
|
||||
void translateTiming(RequestPtr req, ThreadContext *tc,
|
||||
Translation *translation, bool=false);
|
||||
};
|
||||
|
||||
#endif // __ARCH_SPARC_TLB_HH__
|
||||
|
||||
Reference in New Issue
Block a user