O3PCU: Split loads and stores that cross cache line boundaries.
When each load or store is sent to the LSQ, we check whether it will cross a cache line boundary and, if so, split it in two. This creates two TLB translations and two memory requests. Care has to be taken if the first packet of a split load is sent but the second blocks the cache. Similarly, for a store, if the first packet cannot be sent, we must store the second one somewhere to retry later. This modifies the LSQSenderState class to record both packets in a split load or store. Finally, a new const variable, HasUnalignedMemAcc, is added to each ISA to indicate whether unaligned memory accesses are allowed. This is used throughout the changed code so that compiler can optimise away code dealing with split requests for ISAs that don't need them.
This commit is contained in:
parent
7fe9f92cfc
commit
29e8bcead5
11 changed files with 381 additions and 56 deletions
|
@ -131,6 +131,9 @@ enum {
|
||||||
// Alpha UNOP (ldq_u r31,0(r0))
|
// Alpha UNOP (ldq_u r31,0(r0))
|
||||||
const ExtMachInst NoopMachInst = 0x2ffe0000;
|
const ExtMachInst NoopMachInst = 0x2ffe0000;
|
||||||
|
|
||||||
|
// Memory accesses cannot be unaligned
|
||||||
|
const bool HasUnalignedMemAcc = false;
|
||||||
|
|
||||||
} // namespace AlphaISA
|
} // namespace AlphaISA
|
||||||
|
|
||||||
#endif // __ARCH_ALPHA_ISA_TRAITS_HH__
|
#endif // __ARCH_ALPHA_ISA_TRAITS_HH__
|
||||||
|
|
|
@ -106,6 +106,9 @@ namespace ArmISA
|
||||||
const int ByteBytes = 1;
|
const int ByteBytes = 1;
|
||||||
|
|
||||||
const uint32_t HighVecs = 0xFFFF0000;
|
const uint32_t HighVecs = 0xFFFF0000;
|
||||||
|
|
||||||
|
// Memory accesses cannot be unaligned
|
||||||
|
const bool HasUnalignedMemAcc = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
using namespace ArmISA;
|
using namespace ArmISA;
|
||||||
|
|
|
@ -164,6 +164,9 @@ const int ByteBytes = 1;
|
||||||
const int ANNOTE_NONE = 0;
|
const int ANNOTE_NONE = 0;
|
||||||
const uint32_t ITOUCH_ANNOTE = 0xffffffff;
|
const uint32_t ITOUCH_ANNOTE = 0xffffffff;
|
||||||
|
|
||||||
|
// Memory accesses cannot be unaligned
|
||||||
|
const bool HasUnalignedMemAcc = false;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __ARCH_MIPS_ISA_TRAITS_HH__
|
#endif // __ARCH_MIPS_ISA_TRAITS_HH__
|
||||||
|
|
|
@ -70,6 +70,9 @@ const int MachineBytes = 4;
|
||||||
// This is ori 0, 0, 0
|
// This is ori 0, 0, 0
|
||||||
const ExtMachInst NoopMachInst = 0x60000000;
|
const ExtMachInst NoopMachInst = 0x60000000;
|
||||||
|
|
||||||
|
// Memory accesses can be unaligned
|
||||||
|
const bool HasUnalignedMemAcc = true;
|
||||||
|
|
||||||
} // PowerISA namespace
|
} // PowerISA namespace
|
||||||
|
|
||||||
#endif // __ARCH_POWER_ISA_TRAITS_HH__
|
#endif // __ARCH_POWER_ISA_TRAITS_HH__
|
||||||
|
|
|
@ -98,6 +98,9 @@ namespace SparcISA
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Memory accesses cannot be unaligned
|
||||||
|
const bool HasUnalignedMemAcc = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // __ARCH_SPARC_ISA_TRAITS_HH__
|
#endif // __ARCH_SPARC_ISA_TRAITS_HH__
|
||||||
|
|
|
@ -91,6 +91,9 @@ namespace X86ISA
|
||||||
StaticInstPtr decodeInst(ExtMachInst);
|
StaticInstPtr decodeInst(ExtMachInst);
|
||||||
|
|
||||||
const Addr LoadAddrMask = ULL(-1);
|
const Addr LoadAddrMask = ULL(-1);
|
||||||
|
|
||||||
|
// Memory accesses can be unaligned
|
||||||
|
const bool HasUnalignedMemAcc = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __ARCH_X86_ISATRAITS_HH__
|
#endif // __ARCH_X86_ISATRAITS_HH__
|
||||||
|
|
|
@ -131,8 +131,13 @@ class BaseDynInst : public FastAlloc, public RefCounted
|
||||||
template <class T>
|
template <class T>
|
||||||
Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
|
Fault write(T data, Addr addr, unsigned flags, uint64_t *res);
|
||||||
|
|
||||||
|
/** Splits a request in two if it crosses a dcache block. */
|
||||||
|
void splitRequest(RequestPtr req, RequestPtr &sreqLow,
|
||||||
|
RequestPtr &sreqHigh);
|
||||||
|
|
||||||
/** Initiate a DTB address translation. */
|
/** Initiate a DTB address translation. */
|
||||||
void initiateTranslation(RequestPtr req, uint64_t *res,
|
void initiateTranslation(RequestPtr req, RequestPtr sreqLow,
|
||||||
|
RequestPtr sreqHigh, uint64_t *res,
|
||||||
BaseTLB::Mode mode);
|
BaseTLB::Mode mode);
|
||||||
|
|
||||||
/** Finish a DTB address translation. */
|
/** Finish a DTB address translation. */
|
||||||
|
@ -870,12 +875,19 @@ BaseDynInst<Impl>::read(Addr addr, T &data, unsigned flags)
|
||||||
Request *req = new Request(asid, addr, sizeof(T), flags, this->PC,
|
Request *req = new Request(asid, addr, sizeof(T), flags, this->PC,
|
||||||
thread->contextId(), threadNumber);
|
thread->contextId(), threadNumber);
|
||||||
|
|
||||||
initiateTranslation(req, NULL, BaseTLB::Read);
|
Request *sreqLow = NULL;
|
||||||
|
Request *sreqHigh = NULL;
|
||||||
|
|
||||||
|
// Only split the request if the ISA supports unaligned accesses.
|
||||||
|
if (TheISA::HasUnalignedMemAcc) {
|
||||||
|
splitRequest(req, sreqLow, sreqHigh);
|
||||||
|
}
|
||||||
|
initiateTranslation(req, sreqLow, sreqHigh, NULL, BaseTLB::Read);
|
||||||
|
|
||||||
if (fault == NoFault) {
|
if (fault == NoFault) {
|
||||||
effAddr = req->getVaddr();
|
effAddr = req->getVaddr();
|
||||||
effAddrValid = true;
|
effAddrValid = true;
|
||||||
cpu->read(req, data, lqIdx);
|
cpu->read(req, sreqLow, sreqHigh, data, lqIdx);
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// Return a fixed value to keep simulation deterministic even
|
// Return a fixed value to keep simulation deterministic even
|
||||||
|
@ -909,12 +921,19 @@ BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
|
||||||
Request *req = new Request(asid, addr, sizeof(T), flags, this->PC,
|
Request *req = new Request(asid, addr, sizeof(T), flags, this->PC,
|
||||||
thread->contextId(), threadNumber);
|
thread->contextId(), threadNumber);
|
||||||
|
|
||||||
initiateTranslation(req, res, BaseTLB::Write);
|
Request *sreqLow = NULL;
|
||||||
|
Request *sreqHigh = NULL;
|
||||||
|
|
||||||
|
// Only split the request if the ISA supports unaligned accesses.
|
||||||
|
if (TheISA::HasUnalignedMemAcc) {
|
||||||
|
splitRequest(req, sreqLow, sreqHigh);
|
||||||
|
}
|
||||||
|
initiateTranslation(req, sreqLow, sreqHigh, res, BaseTLB::Write);
|
||||||
|
|
||||||
if (fault == NoFault) {
|
if (fault == NoFault) {
|
||||||
effAddr = req->getVaddr();
|
effAddr = req->getVaddr();
|
||||||
effAddrValid = true;
|
effAddrValid = true;
|
||||||
cpu->write(req, data, sqIdx);
|
cpu->write(req, sreqLow, sreqHigh, data, sqIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fault;
|
return fault;
|
||||||
|
@ -922,14 +941,48 @@ BaseDynInst<Impl>::write(T data, Addr addr, unsigned flags, uint64_t *res)
|
||||||
|
|
||||||
template<class Impl>
|
template<class Impl>
|
||||||
inline void
|
inline void
|
||||||
BaseDynInst<Impl>::initiateTranslation(RequestPtr req, uint64_t *res,
|
BaseDynInst<Impl>::splitRequest(RequestPtr req, RequestPtr &sreqLow,
|
||||||
|
RequestPtr &sreqHigh)
|
||||||
|
{
|
||||||
|
// Check to see if the request crosses the next level block boundary.
|
||||||
|
unsigned block_size = cpu->getDcachePort()->peerBlockSize();
|
||||||
|
Addr addr = req->getVaddr();
|
||||||
|
Addr split_addr = roundDown(addr + req->getSize() - 1, block_size);
|
||||||
|
assert(split_addr <= addr || split_addr - addr < block_size);
|
||||||
|
|
||||||
|
// Spans two blocks.
|
||||||
|
if (split_addr > addr) {
|
||||||
|
req->splitOnVaddr(split_addr, sreqLow, sreqHigh);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Impl>
|
||||||
|
inline void
|
||||||
|
BaseDynInst<Impl>::initiateTranslation(RequestPtr req, RequestPtr sreqLow,
|
||||||
|
RequestPtr sreqHigh, uint64_t *res,
|
||||||
BaseTLB::Mode mode)
|
BaseTLB::Mode mode)
|
||||||
{
|
{
|
||||||
WholeTranslationState *state =
|
if (!TheISA::HasUnalignedMemAcc || sreqLow == NULL) {
|
||||||
new WholeTranslationState(req, NULL, res, mode);
|
WholeTranslationState *state =
|
||||||
DataTranslation<BaseDynInst<Impl> > *trans =
|
new WholeTranslationState(req, NULL, res, mode);
|
||||||
new DataTranslation<BaseDynInst<Impl> >(this, state);
|
|
||||||
cpu->dtb->translateTiming(req, thread->getTC(), trans, mode);
|
// One translation if the request isn't split.
|
||||||
|
DataTranslation<BaseDynInst<Impl> > *trans =
|
||||||
|
new DataTranslation<BaseDynInst<Impl> >(this, state);
|
||||||
|
cpu->dtb->translateTiming(req, thread->getTC(), trans, mode);
|
||||||
|
} else {
|
||||||
|
WholeTranslationState *state =
|
||||||
|
new WholeTranslationState(req, sreqLow, sreqHigh, NULL, res, mode);
|
||||||
|
|
||||||
|
// Two translations when the request is split.
|
||||||
|
DataTranslation<BaseDynInst<Impl> > *stransLow =
|
||||||
|
new DataTranslation<BaseDynInst<Impl> >(this, state, 0);
|
||||||
|
DataTranslation<BaseDynInst<Impl> > *stransHigh =
|
||||||
|
new DataTranslation<BaseDynInst<Impl> >(this, state, 1);
|
||||||
|
|
||||||
|
cpu->dtb->translateTiming(sreqLow, thread->getTC(), stransLow, mode);
|
||||||
|
cpu->dtb->translateTiming(sreqHigh, thread->getTC(), stransHigh, mode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Impl>
|
template<class Impl>
|
||||||
|
|
|
@ -703,18 +703,25 @@ class FullO3CPU : public BaseO3CPU
|
||||||
|
|
||||||
/** CPU read function, forwards read to LSQ. */
|
/** CPU read function, forwards read to LSQ. */
|
||||||
template <class T>
|
template <class T>
|
||||||
Fault read(RequestPtr &req, T &data, int load_idx)
|
Fault read(RequestPtr &req, RequestPtr &sreqLow, RequestPtr &sreqHigh,
|
||||||
|
T &data, int load_idx)
|
||||||
{
|
{
|
||||||
return this->iew.ldstQueue.read(req, data, load_idx);
|
return this->iew.ldstQueue.read(req, sreqLow, sreqHigh,
|
||||||
|
data, load_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** CPU write function, forwards write to LSQ. */
|
/** CPU write function, forwards write to LSQ. */
|
||||||
template <class T>
|
template <class T>
|
||||||
Fault write(RequestPtr &req, T &data, int store_idx)
|
Fault write(RequestPtr &req, RequestPtr &sreqLow, RequestPtr &sreqHigh,
|
||||||
|
T &data, int store_idx)
|
||||||
{
|
{
|
||||||
return this->iew.ldstQueue.write(req, data, store_idx);
|
return this->iew.ldstQueue.write(req, sreqLow, sreqHigh,
|
||||||
|
data, store_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Get the dcache port (used to find block size for translations). */
|
||||||
|
Port *getDcachePort() { return this->iew.ldstQueue.getDcachePort(); }
|
||||||
|
|
||||||
Addr lockAddr;
|
Addr lockAddr;
|
||||||
|
|
||||||
/** Temporary fix for the lock flag, works in the UP case. */
|
/** Temporary fix for the lock flag, works in the UP case. */
|
||||||
|
|
|
@ -270,15 +270,19 @@ class LSQ {
|
||||||
void dumpInsts(ThreadID tid)
|
void dumpInsts(ThreadID tid)
|
||||||
{ thread[tid].dumpInsts(); }
|
{ thread[tid].dumpInsts(); }
|
||||||
|
|
||||||
/** Executes a read operation, using the load specified at the load index. */
|
/** Executes a read operation, using the load specified at the load
|
||||||
template <class T>
|
* index.
|
||||||
Fault read(RequestPtr req, T &data, int load_idx);
|
|
||||||
|
|
||||||
/** Executes a store operation, using the store specified at the store
|
|
||||||
* index.
|
|
||||||
*/
|
*/
|
||||||
template <class T>
|
template <class T>
|
||||||
Fault write(RequestPtr req, T &data, int store_idx);
|
Fault read(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
|
||||||
|
T &data, int load_idx);
|
||||||
|
|
||||||
|
/** Executes a store operation, using the store specified at the store
|
||||||
|
* index.
|
||||||
|
*/
|
||||||
|
template <class T>
|
||||||
|
Fault write(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
|
||||||
|
T &data, int store_idx);
|
||||||
|
|
||||||
/** The CPU pointer. */
|
/** The CPU pointer. */
|
||||||
O3CPU *cpu;
|
O3CPU *cpu;
|
||||||
|
@ -369,21 +373,23 @@ class LSQ {
|
||||||
template <class Impl>
|
template <class Impl>
|
||||||
template <class T>
|
template <class T>
|
||||||
Fault
|
Fault
|
||||||
LSQ<Impl>::read(RequestPtr req, T &data, int load_idx)
|
LSQ<Impl>::read(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
|
||||||
|
T &data, int load_idx)
|
||||||
{
|
{
|
||||||
ThreadID tid = req->threadId();
|
ThreadID tid = req->threadId();
|
||||||
|
|
||||||
return thread[tid].read(req, data, load_idx);
|
return thread[tid].read(req, sreqLow, sreqHigh, data, load_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Impl>
|
template <class Impl>
|
||||||
template <class T>
|
template <class T>
|
||||||
Fault
|
Fault
|
||||||
LSQ<Impl>::write(RequestPtr req, T &data, int store_idx)
|
LSQ<Impl>::write(RequestPtr req, RequestPtr sreqLow, RequestPtr sreqHigh,
|
||||||
|
T &data, int store_idx)
|
||||||
{
|
{
|
||||||
ThreadID tid = req->threadId();
|
ThreadID tid = req->threadId();
|
||||||
|
|
||||||
return thread[tid].write(req, data, store_idx);
|
return thread[tid].write(req, sreqLow, sreqHigh, data, store_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // __CPU_O3_LSQ_HH__
|
#endif // __CPU_O3_LSQ_HH__
|
||||||
|
|
|
@ -216,12 +216,18 @@ class LSQUnit {
|
||||||
/** Writes back the instruction, sending it to IEW. */
|
/** Writes back the instruction, sending it to IEW. */
|
||||||
void writeback(DynInstPtr &inst, PacketPtr pkt);
|
void writeback(DynInstPtr &inst, PacketPtr pkt);
|
||||||
|
|
||||||
|
/** Writes back a store that couldn't be completed the previous cycle. */
|
||||||
|
void writebackPendingStore();
|
||||||
|
|
||||||
/** Handles completing the send of a store to memory. */
|
/** Handles completing the send of a store to memory. */
|
||||||
void storePostSend(PacketPtr pkt);
|
void storePostSend(PacketPtr pkt);
|
||||||
|
|
||||||
/** Completes the store at the specified index. */
|
/** Completes the store at the specified index. */
|
||||||
void completeStore(int store_idx);
|
void completeStore(int store_idx);
|
||||||
|
|
||||||
|
/** Attempts to send a store to the cache. */
|
||||||
|
bool sendStore(PacketPtr data_pkt);
|
||||||
|
|
||||||
/** Increments the given store index (circular queue). */
|
/** Increments the given store index (circular queue). */
|
||||||
inline void incrStIdx(int &store_idx);
|
inline void incrStIdx(int &store_idx);
|
||||||
/** Decrements the given store index (circular queue). */
|
/** Decrements the given store index (circular queue). */
|
||||||
|
@ -254,7 +260,8 @@ class LSQUnit {
|
||||||
public:
|
public:
|
||||||
/** Default constructor. */
|
/** Default constructor. */
|
||||||
LSQSenderState()
|
LSQSenderState()
|
||||||
: noWB(false)
|
: noWB(false), isSplit(false), pktToSend(false), outstanding(1),
|
||||||
|
mainPkt(NULL), pendingPacket(NULL)
|
||||||
{ }
|
{ }
|
||||||
|
|
||||||
/** Instruction who initiated the access to memory. */
|
/** Instruction who initiated the access to memory. */
|
||||||
|
@ -265,6 +272,19 @@ class LSQUnit {
|
||||||
int idx;
|
int idx;
|
||||||
/** Whether or not the instruction will need to writeback. */
|
/** Whether or not the instruction will need to writeback. */
|
||||||
bool noWB;
|
bool noWB;
|
||||||
|
/** Whether or not this access is split in two. */
|
||||||
|
bool isSplit;
|
||||||
|
/** Whether or not there is a packet that needs sending. */
|
||||||
|
bool pktToSend;
|
||||||
|
/** Number of outstanding packets to complete. */
|
||||||
|
int outstanding;
|
||||||
|
/** The main packet from a split load, used during writeback. */
|
||||||
|
PacketPtr mainPkt;
|
||||||
|
/** A second packet from a split store that needs sending. */
|
||||||
|
PacketPtr pendingPacket;
|
||||||
|
|
||||||
|
/** Completes a packet and returns whether the access is finished. */
|
||||||
|
inline bool complete() { return --outstanding == 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Writeback event, specifically for when stores forward data to loads. */
|
/** Writeback event, specifically for when stores forward data to loads. */
|
||||||
|
@ -302,8 +322,8 @@ class LSQUnit {
|
||||||
|
|
||||||
/** Constructs a store queue entry for a given instruction. */
|
/** Constructs a store queue entry for a given instruction. */
|
||||||
SQEntry(DynInstPtr &_inst)
|
SQEntry(DynInstPtr &_inst)
|
||||||
: inst(_inst), req(NULL), size(0),
|
: inst(_inst), req(NULL), sreqLow(NULL), sreqHigh(NULL), size(0),
|
||||||
canWB(0), committed(0), completed(0)
|
isSplit(0), canWB(0), committed(0), completed(0)
|
||||||
{
|
{
|
||||||
std::memset(data, 0, sizeof(data));
|
std::memset(data, 0, sizeof(data));
|
||||||
}
|
}
|
||||||
|
@ -312,10 +332,15 @@ class LSQUnit {
|
||||||
DynInstPtr inst;
|
DynInstPtr inst;
|
||||||
/** The request for the store. */
|
/** The request for the store. */
|
||||||
RequestPtr req;
|
RequestPtr req;
|
||||||
|
/** The split requests for the store. */
|
||||||
|
RequestPtr sreqLow;
|
||||||
|
RequestPtr sreqHigh;
|
||||||
/** The size of the store. */
|
/** The size of the store. */
|
||||||
int size;
|
int size;
|
||||||
/** The store data. */
|
/** The store data. */
|
||||||
char data[sizeof(IntReg)];
|
char data[sizeof(IntReg)];
|
||||||
|
/** Whether or not the store is split into two requests. */
|
||||||
|
bool isSplit;
|
||||||
/** Whether or not the store can writeback. */
|
/** Whether or not the store can writeback. */
|
||||||
bool canWB;
|
bool canWB;
|
||||||
/** Whether or not the store is committed. */
|
/** Whether or not the store is committed. */
|
||||||
|
@ -406,6 +431,13 @@ class LSQUnit {
|
||||||
/** The oldest load that caused a memory ordering violation. */
|
/** The oldest load that caused a memory ordering violation. */
|
||||||
DynInstPtr memDepViolator;
|
DynInstPtr memDepViolator;
|
||||||
|
|
||||||
|
/** Whether or not there is a packet that couldn't be sent because of
|
||||||
|
* a lack of cache ports. */
|
||||||
|
bool hasPendingPkt;
|
||||||
|
|
||||||
|
/** The packet that is pending free cache ports. */
|
||||||
|
PacketPtr pendingPkt;
|
||||||
|
|
||||||
// Will also need how many read/write ports the Dcache has. Or keep track
|
// Will also need how many read/write ports the Dcache has. Or keep track
|
||||||
// of that in stage that is one level up, and only call executeLoad/Store
|
// of that in stage that is one level up, and only call executeLoad/Store
|
||||||
// the appropriate number of times.
|
// the appropriate number of times.
|
||||||
|
@ -443,11 +475,13 @@ class LSQUnit {
|
||||||
public:
|
public:
|
||||||
/** Executes the load at the given index. */
|
/** Executes the load at the given index. */
|
||||||
template <class T>
|
template <class T>
|
||||||
Fault read(Request *req, T &data, int load_idx);
|
Fault read(Request *req, Request *sreqLow, Request *sreqHigh, T &data,
|
||||||
|
int load_idx);
|
||||||
|
|
||||||
/** Executes the store at the given index. */
|
/** Executes the store at the given index. */
|
||||||
template <class T>
|
template <class T>
|
||||||
Fault write(Request *req, T &data, int store_idx);
|
Fault write(Request *req, Request *sreqLow, Request *sreqHigh, T &data,
|
||||||
|
int store_idx);
|
||||||
|
|
||||||
/** Returns the index of the head load instruction. */
|
/** Returns the index of the head load instruction. */
|
||||||
int getLoadHead() { return loadHead; }
|
int getLoadHead() { return loadHead; }
|
||||||
|
@ -482,7 +516,8 @@ class LSQUnit {
|
||||||
template <class Impl>
|
template <class Impl>
|
||||||
template <class T>
|
template <class T>
|
||||||
Fault
|
Fault
|
||||||
LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
|
LSQUnit<Impl>::read(Request *req, Request *sreqLow, Request *sreqHigh,
|
||||||
|
T &data, int load_idx)
|
||||||
{
|
{
|
||||||
DynInstPtr load_inst = loadQueue[load_idx];
|
DynInstPtr load_inst = loadQueue[load_idx];
|
||||||
|
|
||||||
|
@ -503,6 +538,10 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
|
||||||
// memory. This is quite ugly. @todo: Figure out the proper
|
// memory. This is quite ugly. @todo: Figure out the proper
|
||||||
// place to really handle request deletes.
|
// place to really handle request deletes.
|
||||||
delete req;
|
delete req;
|
||||||
|
if (TheISA::HasUnalignedMemAcc && sreqLow) {
|
||||||
|
delete sreqLow;
|
||||||
|
delete sreqHigh;
|
||||||
|
}
|
||||||
return TheISA::genMachineCheckFault();
|
return TheISA::genMachineCheckFault();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -512,10 +551,12 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
|
||||||
int store_size = 0;
|
int store_size = 0;
|
||||||
|
|
||||||
DPRINTF(LSQUnit, "Read called, load idx: %i, store idx: %i, "
|
DPRINTF(LSQUnit, "Read called, load idx: %i, store idx: %i, "
|
||||||
"storeHead: %i addr: %#x\n",
|
"storeHead: %i addr: %#x%s\n",
|
||||||
load_idx, store_idx, storeHead, req->getPaddr());
|
load_idx, store_idx, storeHead, req->getPaddr(),
|
||||||
|
sreqLow ? " split" : "");
|
||||||
|
|
||||||
if (req->isLLSC()) {
|
if (req->isLLSC()) {
|
||||||
|
assert(!sreqLow);
|
||||||
// Disable recording the result temporarily. Writing to misc
|
// Disable recording the result temporarily. Writing to misc
|
||||||
// regs normally updates the result, but this is not the
|
// regs normally updates the result, but this is not the
|
||||||
// desired behavior when handling store conditionals.
|
// desired behavior when handling store conditionals.
|
||||||
|
@ -587,6 +628,12 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
|
||||||
// @todo: Need to make this a parameter.
|
// @todo: Need to make this a parameter.
|
||||||
cpu->schedule(wb, curTick);
|
cpu->schedule(wb, curTick);
|
||||||
|
|
||||||
|
// Don't need to do anything special for split loads.
|
||||||
|
if (TheISA::HasUnalignedMemAcc && sreqLow) {
|
||||||
|
delete sreqLow;
|
||||||
|
delete sreqHigh;
|
||||||
|
}
|
||||||
|
|
||||||
++lsqForwLoads;
|
++lsqForwLoads;
|
||||||
return NoFault;
|
return NoFault;
|
||||||
} else if ((store_has_lower_limit && lower_load_has_store_part) ||
|
} else if ((store_has_lower_limit && lower_load_has_store_part) ||
|
||||||
|
@ -630,6 +677,10 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
|
||||||
// memory. This is quite ugly. @todo: Figure out the
|
// memory. This is quite ugly. @todo: Figure out the
|
||||||
// proper place to really handle request deletes.
|
// proper place to really handle request deletes.
|
||||||
delete req;
|
delete req;
|
||||||
|
if (TheISA::HasUnalignedMemAcc && sreqLow) {
|
||||||
|
delete sreqLow;
|
||||||
|
delete sreqHigh;
|
||||||
|
}
|
||||||
|
|
||||||
return NoFault;
|
return NoFault;
|
||||||
}
|
}
|
||||||
|
@ -645,12 +696,14 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
|
||||||
++usedPorts;
|
++usedPorts;
|
||||||
|
|
||||||
// if we the cache is not blocked, do cache access
|
// if we the cache is not blocked, do cache access
|
||||||
|
bool completedFirst = false;
|
||||||
if (!lsq->cacheBlocked()) {
|
if (!lsq->cacheBlocked()) {
|
||||||
PacketPtr data_pkt =
|
MemCmd command =
|
||||||
new Packet(req,
|
req->isLLSC() ? MemCmd::LoadLockedReq : MemCmd::ReadReq;
|
||||||
(req->isLLSC() ?
|
PacketPtr data_pkt = new Packet(req, command, Packet::Broadcast);
|
||||||
MemCmd::LoadLockedReq : MemCmd::ReadReq),
|
PacketPtr fst_data_pkt = NULL;
|
||||||
Packet::Broadcast);
|
PacketPtr snd_data_pkt = NULL;
|
||||||
|
|
||||||
data_pkt->dataStatic(load_inst->memData);
|
data_pkt->dataStatic(load_inst->memData);
|
||||||
|
|
||||||
LSQSenderState *state = new LSQSenderState;
|
LSQSenderState *state = new LSQSenderState;
|
||||||
|
@ -659,18 +712,66 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
|
||||||
state->inst = load_inst;
|
state->inst = load_inst;
|
||||||
data_pkt->senderState = state;
|
data_pkt->senderState = state;
|
||||||
|
|
||||||
if (!dcachePort->sendTiming(data_pkt)) {
|
if (!TheISA::HasUnalignedMemAcc || !sreqLow) {
|
||||||
|
|
||||||
|
// Point the first packet at the main data packet.
|
||||||
|
fst_data_pkt = data_pkt;
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Create the split packets.
|
||||||
|
fst_data_pkt = new Packet(sreqLow, command, Packet::Broadcast);
|
||||||
|
snd_data_pkt = new Packet(sreqHigh, command, Packet::Broadcast);
|
||||||
|
|
||||||
|
fst_data_pkt->dataStatic(load_inst->memData);
|
||||||
|
snd_data_pkt->dataStatic(load_inst->memData + sreqLow->getSize());
|
||||||
|
|
||||||
|
fst_data_pkt->senderState = state;
|
||||||
|
snd_data_pkt->senderState = state;
|
||||||
|
|
||||||
|
state->isSplit = true;
|
||||||
|
state->outstanding = 2;
|
||||||
|
state->mainPkt = data_pkt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!dcachePort->sendTiming(fst_data_pkt)) {
|
||||||
// Delete state and data packet because a load retry
|
// Delete state and data packet because a load retry
|
||||||
// initiates a pipeline restart; it does not retry.
|
// initiates a pipeline restart; it does not retry.
|
||||||
delete state;
|
delete state;
|
||||||
delete data_pkt->req;
|
delete data_pkt->req;
|
||||||
delete data_pkt;
|
delete data_pkt;
|
||||||
|
if (TheISA::HasUnalignedMemAcc && sreqLow) {
|
||||||
|
delete fst_data_pkt->req;
|
||||||
|
delete fst_data_pkt;
|
||||||
|
delete snd_data_pkt->req;
|
||||||
|
delete snd_data_pkt;
|
||||||
|
}
|
||||||
|
|
||||||
req = NULL;
|
req = NULL;
|
||||||
|
|
||||||
// If the access didn't succeed, tell the LSQ by setting
|
// If the access didn't succeed, tell the LSQ by setting
|
||||||
// the retry thread id.
|
// the retry thread id.
|
||||||
lsq->setRetryTid(lsqID);
|
lsq->setRetryTid(lsqID);
|
||||||
|
} else if (TheISA::HasUnalignedMemAcc && sreqLow) {
|
||||||
|
completedFirst = true;
|
||||||
|
|
||||||
|
// The first packet was sent without problems, so send this one
|
||||||
|
// too. If there is a problem with this packet then the whole
|
||||||
|
// load will be squashed, so indicate this to the state object.
|
||||||
|
// The first packet will return in completeDataAccess and be
|
||||||
|
// handled there.
|
||||||
|
++usedPorts;
|
||||||
|
if (!dcachePort->sendTiming(snd_data_pkt)) {
|
||||||
|
|
||||||
|
// The main packet will be deleted in completeDataAccess.
|
||||||
|
delete snd_data_pkt->req;
|
||||||
|
delete snd_data_pkt;
|
||||||
|
|
||||||
|
state->complete();
|
||||||
|
|
||||||
|
req = NULL;
|
||||||
|
|
||||||
|
lsq->setRetryTid(lsqID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -679,6 +780,10 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
|
||||||
if (lsq->cacheBlocked()) {
|
if (lsq->cacheBlocked()) {
|
||||||
if (req)
|
if (req)
|
||||||
delete req;
|
delete req;
|
||||||
|
if (TheISA::HasUnalignedMemAcc && sreqLow && !completedFirst) {
|
||||||
|
delete sreqLow;
|
||||||
|
delete sreqHigh;
|
||||||
|
}
|
||||||
|
|
||||||
++lsqCacheBlocked;
|
++lsqCacheBlocked;
|
||||||
|
|
||||||
|
@ -703,7 +808,8 @@ LSQUnit<Impl>::read(Request *req, T &data, int load_idx)
|
||||||
template <class Impl>
|
template <class Impl>
|
||||||
template <class T>
|
template <class T>
|
||||||
Fault
|
Fault
|
||||||
LSQUnit<Impl>::write(Request *req, T &data, int store_idx)
|
LSQUnit<Impl>::write(Request *req, Request *sreqLow, Request *sreqHigh,
|
||||||
|
T &data, int store_idx)
|
||||||
{
|
{
|
||||||
assert(storeQueue[store_idx].inst);
|
assert(storeQueue[store_idx].inst);
|
||||||
|
|
||||||
|
@ -713,6 +819,8 @@ LSQUnit<Impl>::write(Request *req, T &data, int store_idx)
|
||||||
storeQueue[store_idx].inst->seqNum);
|
storeQueue[store_idx].inst->seqNum);
|
||||||
|
|
||||||
storeQueue[store_idx].req = req;
|
storeQueue[store_idx].req = req;
|
||||||
|
storeQueue[store_idx].sreqLow = sreqLow;
|
||||||
|
storeQueue[store_idx].sreqHigh = sreqHigh;
|
||||||
storeQueue[store_idx].size = sizeof(T);
|
storeQueue[store_idx].size = sizeof(T);
|
||||||
assert(sizeof(T) <= sizeof(storeQueue[store_idx].data));
|
assert(sizeof(T) <= sizeof(storeQueue[store_idx].data));
|
||||||
|
|
||||||
|
|
|
@ -85,11 +85,23 @@ LSQUnit<Impl>::completeDataAccess(PacketPtr pkt)
|
||||||
|
|
||||||
assert(!pkt->wasNacked());
|
assert(!pkt->wasNacked());
|
||||||
|
|
||||||
|
// If this is a split access, wait until all packets are received.
|
||||||
|
if (TheISA::HasUnalignedMemAcc && !state->complete()) {
|
||||||
|
delete pkt->req;
|
||||||
|
delete pkt;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (isSwitchedOut() || inst->isSquashed()) {
|
if (isSwitchedOut() || inst->isSquashed()) {
|
||||||
iewStage->decrWb(inst->seqNum);
|
iewStage->decrWb(inst->seqNum);
|
||||||
} else {
|
} else {
|
||||||
if (!state->noWB) {
|
if (!state->noWB) {
|
||||||
writeback(inst, pkt);
|
if (!TheISA::HasUnalignedMemAcc || !state->isSplit ||
|
||||||
|
!state->isLoad) {
|
||||||
|
writeback(inst, pkt);
|
||||||
|
} else {
|
||||||
|
writeback(inst, state->mainPkt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (inst->isStore()) {
|
if (inst->isStore()) {
|
||||||
|
@ -97,6 +109,10 @@ LSQUnit<Impl>::completeDataAccess(PacketPtr pkt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (TheISA::HasUnalignedMemAcc && state->isSplit && state->isLoad) {
|
||||||
|
delete state->mainPkt->req;
|
||||||
|
delete state->mainPkt;
|
||||||
|
}
|
||||||
delete state;
|
delete state;
|
||||||
delete pkt->req;
|
delete pkt->req;
|
||||||
delete pkt;
|
delete pkt;
|
||||||
|
@ -106,7 +122,7 @@ template <class Impl>
|
||||||
LSQUnit<Impl>::LSQUnit()
|
LSQUnit<Impl>::LSQUnit()
|
||||||
: loads(0), stores(0), storesToWB(0), stalled(false),
|
: loads(0), stores(0), storesToWB(0), stalled(false),
|
||||||
isStoreBlocked(false), isLoadBlocked(false),
|
isStoreBlocked(false), isLoadBlocked(false),
|
||||||
loadBlockedHandled(false)
|
loadBlockedHandled(false), hasPendingPkt(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -603,10 +619,32 @@ LSQUnit<Impl>::commitStores(InstSeqNum &youngest_inst)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Impl>
|
||||||
|
void
|
||||||
|
LSQUnit<Impl>::writebackPendingStore()
|
||||||
|
{
|
||||||
|
if (hasPendingPkt) {
|
||||||
|
assert(pendingPkt != NULL);
|
||||||
|
|
||||||
|
// If the cache is blocked, this will store the packet for retry.
|
||||||
|
if (sendStore(pendingPkt)) {
|
||||||
|
storePostSend(pendingPkt);
|
||||||
|
}
|
||||||
|
pendingPkt = NULL;
|
||||||
|
hasPendingPkt = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <class Impl>
|
template <class Impl>
|
||||||
void
|
void
|
||||||
LSQUnit<Impl>::writebackStores()
|
LSQUnit<Impl>::writebackStores()
|
||||||
{
|
{
|
||||||
|
// First writeback the second packet from any split store that didn't
|
||||||
|
// complete last cycle because there weren't enough cache ports available.
|
||||||
|
if (TheISA::HasUnalignedMemAcc) {
|
||||||
|
writebackPendingStore();
|
||||||
|
}
|
||||||
|
|
||||||
while (storesToWB > 0 &&
|
while (storesToWB > 0 &&
|
||||||
storeWBIdx != storeTail &&
|
storeWBIdx != storeTail &&
|
||||||
storeQueue[storeWBIdx].inst &&
|
storeQueue[storeWBIdx].inst &&
|
||||||
|
@ -640,6 +678,11 @@ LSQUnit<Impl>::writebackStores()
|
||||||
assert(storeQueue[storeWBIdx].req);
|
assert(storeQueue[storeWBIdx].req);
|
||||||
assert(!storeQueue[storeWBIdx].committed);
|
assert(!storeQueue[storeWBIdx].committed);
|
||||||
|
|
||||||
|
if (TheISA::HasUnalignedMemAcc && storeQueue[storeWBIdx].isSplit) {
|
||||||
|
assert(storeQueue[storeWBIdx].sreqLow);
|
||||||
|
assert(storeQueue[storeWBIdx].sreqHigh);
|
||||||
|
}
|
||||||
|
|
||||||
DynInstPtr inst = storeQueue[storeWBIdx].inst;
|
DynInstPtr inst = storeQueue[storeWBIdx].inst;
|
||||||
|
|
||||||
Request *req = storeQueue[storeWBIdx].req;
|
Request *req = storeQueue[storeWBIdx].req;
|
||||||
|
@ -653,15 +696,41 @@ LSQUnit<Impl>::writebackStores()
|
||||||
MemCmd command =
|
MemCmd command =
|
||||||
req->isSwap() ? MemCmd::SwapReq :
|
req->isSwap() ? MemCmd::SwapReq :
|
||||||
(req->isLLSC() ? MemCmd::StoreCondReq : MemCmd::WriteReq);
|
(req->isLLSC() ? MemCmd::StoreCondReq : MemCmd::WriteReq);
|
||||||
PacketPtr data_pkt = new Packet(req, command,
|
PacketPtr data_pkt;
|
||||||
Packet::Broadcast);
|
PacketPtr snd_data_pkt = NULL;
|
||||||
data_pkt->dataStatic(inst->memData);
|
|
||||||
|
|
||||||
LSQSenderState *state = new LSQSenderState;
|
LSQSenderState *state = new LSQSenderState;
|
||||||
state->isLoad = false;
|
state->isLoad = false;
|
||||||
state->idx = storeWBIdx;
|
state->idx = storeWBIdx;
|
||||||
state->inst = inst;
|
state->inst = inst;
|
||||||
data_pkt->senderState = state;
|
|
||||||
|
if (!TheISA::HasUnalignedMemAcc || !storeQueue[storeWBIdx].isSplit) {
|
||||||
|
|
||||||
|
// Build a single data packet if the store isn't split.
|
||||||
|
data_pkt = new Packet(req, command, Packet::Broadcast);
|
||||||
|
data_pkt->dataStatic(inst->memData);
|
||||||
|
data_pkt->senderState = state;
|
||||||
|
} else {
|
||||||
|
RequestPtr sreqLow = storeQueue[storeWBIdx].sreqLow;
|
||||||
|
RequestPtr sreqHigh = storeQueue[storeWBIdx].sreqHigh;
|
||||||
|
|
||||||
|
// Create two packets if the store is split in two.
|
||||||
|
data_pkt = new Packet(sreqLow, command, Packet::Broadcast);
|
||||||
|
snd_data_pkt = new Packet(sreqHigh, command, Packet::Broadcast);
|
||||||
|
|
||||||
|
data_pkt->dataStatic(inst->memData);
|
||||||
|
snd_data_pkt->dataStatic(inst->memData + sreqLow->getSize());
|
||||||
|
|
||||||
|
data_pkt->senderState = state;
|
||||||
|
snd_data_pkt->senderState = state;
|
||||||
|
|
||||||
|
state->isSplit = true;
|
||||||
|
state->outstanding = 2;
|
||||||
|
|
||||||
|
// Can delete the main request now.
|
||||||
|
delete req;
|
||||||
|
req = sreqLow;
|
||||||
|
}
|
||||||
|
|
||||||
DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
|
DPRINTF(LSQUnit, "D-Cache: Writing back store idx:%i PC:%#x "
|
||||||
"to Addr:%#x, data:%#x [sn:%lli]\n",
|
"to Addr:%#x, data:%#x [sn:%lli]\n",
|
||||||
|
@ -671,6 +740,7 @@ LSQUnit<Impl>::writebackStores()
|
||||||
|
|
||||||
// @todo: Remove this SC hack once the memory system handles it.
|
// @todo: Remove this SC hack once the memory system handles it.
|
||||||
if (inst->isStoreConditional()) {
|
if (inst->isStoreConditional()) {
|
||||||
|
assert(!storeQueue[storeWBIdx].isSplit);
|
||||||
// Disable recording the result temporarily. Writing to
|
// Disable recording the result temporarily. Writing to
|
||||||
// misc regs normally updates the result, but this is not
|
// misc regs normally updates the result, but this is not
|
||||||
// the desired behavior when handling store conditionals.
|
// the desired behavior when handling store conditionals.
|
||||||
|
@ -694,18 +764,44 @@ LSQUnit<Impl>::writebackStores()
|
||||||
state->noWB = true;
|
state->noWB = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dcachePort->sendTiming(data_pkt)) {
|
if (!sendStore(data_pkt)) {
|
||||||
// Need to handle becoming blocked on a store.
|
|
||||||
DPRINTF(IEW, "D-Cache became blocked when writing [sn:%lli], will"
|
DPRINTF(IEW, "D-Cache became blocked when writing [sn:%lli], will"
|
||||||
"retry later\n",
|
"retry later\n",
|
||||||
inst->seqNum);
|
inst->seqNum);
|
||||||
isStoreBlocked = true;
|
|
||||||
++lsqCacheBlocked;
|
// Need to store the second packet, if split.
|
||||||
assert(retryPkt == NULL);
|
if (TheISA::HasUnalignedMemAcc && storeQueue[storeWBIdx].isSplit) {
|
||||||
retryPkt = data_pkt;
|
state->pktToSend = true;
|
||||||
lsq->setRetryTid(lsqID);
|
state->pendingPacket = snd_data_pkt;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
storePostSend(data_pkt);
|
|
||||||
|
// If split, try to send the second packet too
|
||||||
|
if (TheISA::HasUnalignedMemAcc && storeQueue[storeWBIdx].isSplit) {
|
||||||
|
assert(snd_data_pkt);
|
||||||
|
|
||||||
|
// Ensure there are enough ports to use.
|
||||||
|
if (usedPorts < cachePorts) {
|
||||||
|
++usedPorts;
|
||||||
|
if (sendStore(snd_data_pkt)) {
|
||||||
|
storePostSend(snd_data_pkt);
|
||||||
|
} else {
|
||||||
|
DPRINTF(IEW, "D-Cache became blocked when writing"
|
||||||
|
" [sn:%lli] second packet, will retry later\n",
|
||||||
|
inst->seqNum);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Store the packet for when there's free ports.
|
||||||
|
assert(pendingPkt == NULL);
|
||||||
|
pendingPkt = snd_data_pkt;
|
||||||
|
hasPendingPkt = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
|
||||||
|
// Not a split store.
|
||||||
|
storePostSend(data_pkt);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -808,6 +904,13 @@ LSQUnit<Impl>::squash(const InstSeqNum &squashed_num)
|
||||||
// memory. This is quite ugly. @todo: Figure out the proper
|
// memory. This is quite ugly. @todo: Figure out the proper
|
||||||
// place to really handle request deletes.
|
// place to really handle request deletes.
|
||||||
delete storeQueue[store_idx].req;
|
delete storeQueue[store_idx].req;
|
||||||
|
if (TheISA::HasUnalignedMemAcc && storeQueue[store_idx].isSplit) {
|
||||||
|
delete storeQueue[store_idx].sreqLow;
|
||||||
|
delete storeQueue[store_idx].sreqHigh;
|
||||||
|
|
||||||
|
storeQueue[store_idx].sreqLow = NULL;
|
||||||
|
storeQueue[store_idx].sreqHigh = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
storeQueue[store_idx].req = NULL;
|
storeQueue[store_idx].req = NULL;
|
||||||
--stores;
|
--stores;
|
||||||
|
@ -926,6 +1029,22 @@ LSQUnit<Impl>::completeStore(int store_idx)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Impl>
|
||||||
|
bool
|
||||||
|
LSQUnit<Impl>::sendStore(PacketPtr data_pkt)
|
||||||
|
{
|
||||||
|
if (!dcachePort->sendTiming(data_pkt)) {
|
||||||
|
// Need to handle becoming blocked on a store.
|
||||||
|
isStoreBlocked = true;
|
||||||
|
++lsqCacheBlocked;
|
||||||
|
assert(retryPkt == NULL);
|
||||||
|
retryPkt = data_pkt;
|
||||||
|
lsq->setRetryTid(lsqID);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
template <class Impl>
|
template <class Impl>
|
||||||
void
|
void
|
||||||
LSQUnit<Impl>::recvRetry()
|
LSQUnit<Impl>::recvRetry()
|
||||||
|
@ -935,10 +1054,24 @@ LSQUnit<Impl>::recvRetry()
|
||||||
assert(retryPkt != NULL);
|
assert(retryPkt != NULL);
|
||||||
|
|
||||||
if (dcachePort->sendTiming(retryPkt)) {
|
if (dcachePort->sendTiming(retryPkt)) {
|
||||||
storePostSend(retryPkt);
|
LSQSenderState *state =
|
||||||
|
dynamic_cast<LSQSenderState *>(retryPkt->senderState);
|
||||||
|
|
||||||
|
// Don't finish the store unless this is the last packet.
|
||||||
|
if (!TheISA::HasUnalignedMemAcc || !state->pktToSend) {
|
||||||
|
storePostSend(retryPkt);
|
||||||
|
}
|
||||||
retryPkt = NULL;
|
retryPkt = NULL;
|
||||||
isStoreBlocked = false;
|
isStoreBlocked = false;
|
||||||
lsq->setRetryTid(InvalidThreadID);
|
lsq->setRetryTid(InvalidThreadID);
|
||||||
|
|
||||||
|
// Send any outstanding packet.
|
||||||
|
if (TheISA::HasUnalignedMemAcc && state->pktToSend) {
|
||||||
|
assert(state->pendingPacket);
|
||||||
|
if (sendStore(state->pendingPacket)) {
|
||||||
|
storePostSend(state->pendingPacket);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// Still blocked!
|
// Still blocked!
|
||||||
++lsqCacheBlocked;
|
++lsqCacheBlocked;
|
||||||
|
|
Loading…
Reference in a new issue