2c2
< * Copyright (c) 2011-2012, 2014 ARM Limited
---
> * Copyright (c) 2011-2012, 2014, 2018 ARM Limited
50c50
< #include "cpu/o3/lsq_unit.hh"
---
> #include "arch/generic/tlb.hh"
51a52
> #include "cpu/o3/lsq_unit.hh"
59c60,62
< class LSQ {
---
> class LSQ
>
> {
65a69,712
> class LSQRequest;
> /** Derived class to hold any sender state the LSQ needs. */
> class LSQSenderState : public Packet::SenderState
> {
> protected:
> /** The senderState needs to know the LSQRequest who owns it. */
> LSQRequest* _request;
>
> /** Default constructor. */
> LSQSenderState(LSQRequest* request, bool isLoad_)
> : _request(request), mainPkt(nullptr), pendingPacket(nullptr),
> outstanding(0), isLoad(isLoad_), needWB(isLoad_), isSplit(false),
> pktToSend(false), deleted(false)
> { }
> public:
>
> /** Instruction which initiated the access to memory. */
> DynInstPtr inst;
> /** The main packet from a split load, used during writeback. */
> PacketPtr mainPkt;
> /** A second packet from a split store that needs sending. */
> PacketPtr pendingPacket;
> /** Number of outstanding packets to complete. */
> uint8_t outstanding;
> /** Whether or not it is a load. */
> bool isLoad;
> /** Whether or not the instruction will need to writeback. */
> bool needWB;
> /** Whether or not this access is split in two. */
> bool isSplit;
> /** Whether or not there is a packet that needs sending. */
> bool pktToSend;
> /** Has the request been deleted?
> * LSQ entries can be squashed before the response comes back. in that
> * case the SenderState knows.
> */
> bool deleted;
> ContextID contextId() { return inst->contextId(); }
>
> /** Completes a packet and returns whether the access is finished. */
> inline bool isComplete() { return outstanding == 0; }
> inline void deleteRequest() { deleted = true; }
> inline bool alive() { return !deleted; }
> LSQRequest* request() { return _request; }
> virtual void complete() = 0;
> void writebackDone() { _request->writebackDone(); }
> };
>
> /** Memory operation metadata.
> * This class holds the information about a memory operation. It lives
> * from initiateAcc to resource deallocation at commit or squash.
> * LSQRequest objects are owned by the LQ/SQ Entry in the LSQUnit that
> * holds the operation. It is also used by the LSQSenderState. In addition,
> * the LSQRequest is a TranslationState, therefore, upon squash, there must
> * be a defined ownership transferal in case the LSQ resources are
> * deallocated before the TLB is done using the TranslationState. If that
> * happens, the LSQRequest will be self-owned, and responsible to detect
> * that its services are no longer required and self-destruct.
> *
> * Lifetime of a LSQRequest:
> * +--------------------+
> * |LSQ creates and owns|
> * +--------------------+
> * |
> * +--------------------+
> * | Initate translation|
> * +--------------------+
> * |
> * ___^___
> * ___/ \___
> * ______/ Squashed? \
> * | \___ ___/
> * | \___ ___/
> * | v
> * | |
> * | +--------------------+
> * | | Translation done |
> * | +--------------------+
> * | |
> * | +--------------------+
> * | | Send packet |<------+
> * | +--------------------+ |
> * | | |
> * | ___^___ |
> * | ___/ \___ |
> * | ____/ Squashed? \ |
> * | | \___ ___/ |
> * | | \___ ___/ |
> * | | v |
> * | | | |
> * | | ___^___ |
> * | | ___/ \___ |
> * | | / Done? \__________|
> * | | \___ ___/
> * | | \___ ___/
> * | | v
> * | | |
> * | | +--------------------+
> * | | | Manage stuff |
> * | | | Free resources |
> * | | +--------------------+
> * | |
> * | | +--------------------+
> * | | | senderState owns |
> * | +->| onRecvTimingResp |
> * | | free resources |
> * | +--------------------+
> * |
> * | +----------------------+
> * | | self owned (Trans) |
> * +-->| on TranslationFinish |
> * | free resources |
> * +----------------------+
> *
> *
> */
> class LSQRequest : public BaseTLB::Translation
> {
> protected:
> typedef uint32_t FlagsStorage;
> typedef ::Flags<FlagsStorage> FlagsType;
>
> enum Flag : FlagsStorage
> {
> IsLoad = 0x00000001,
> /** True if this is a store that writes registers (SC). */
> WbStore = 0x00000002,
> Delayed = 0x00000004,
> IsSplit = 0x00000008,
> /** True if any translation has been sent to TLB. */
> TranslationStarted = 0x00000010,
> /** True if there are un-replied outbound translations.. */
> TranslationFinished = 0x00000020,
> Sent = 0x00000040,
> Retry = 0x00000080,
> Complete = 0x00000100,
> /** Ownership tracking flags. */
> /** Translation squashed. */
> TranslationSquashed = 0x00000200,
> /** Request discarded */
> Discarded = 0x00000400,
> /** LSQ resources freed. */
> LSQEntryFreed = 0x00000800,
> /** Store written back. */
> WritebackScheduled = 0x00001000,
> WritebackDone = 0x00002000
> };
> FlagsType flags;
>
> enum class State
> {
> NotIssued,
> Translation,
> Request,
> Complete,
> Squashed,
> Fault,
> };
> State _state;
> LSQSenderState* _senderState;
> void setState(const State& newState) { _state = newState; }
>
> uint32_t numTranslatedFragments;
> uint32_t numInTranslationFragments;
>
> /** LQ/SQ entry idx. */
> uint32_t _entryIdx;
>
> void markDelayed() { flags.set(Flag::Delayed); }
> bool isDelayed() { return flags.isSet(Flag::Delayed); }
>
> public:
> LSQUnit& _port;
> const DynInstPtr _inst;
> uint32_t _taskId;
> PacketDataPtr _data;
> std::vector<PacketPtr> _packets;
> std::vector<RequestPtr> _requests;
> std::vector<Fault> _fault;
> uint64_t* _res;
> const Addr _addr;
> const uint32_t _size;
> const Request::Flags _flags;
> uint32_t _numOutstandingPackets;
> protected:
> LSQUnit* lsqUnit() { return &_port; }
> LSQRequest(LSQUnit* port, const DynInstPtr& inst, bool isLoad) :
> _state(State::NotIssued), _senderState(nullptr),
> _port(*port), _inst(inst), _data(nullptr),
> _res(nullptr), _addr(0), _size(0), _flags(0),
> _numOutstandingPackets(0)
> {
> flags.set(Flag::IsLoad, isLoad);
> flags.set(Flag::WbStore, _inst->isStoreConditional());
> install();
> }
> LSQRequest(LSQUnit* port, const DynInstPtr& inst, bool isLoad,
> const Addr& addr, const uint32_t& size,
> const Request::Flags& flags_,
> PacketDataPtr data = nullptr, uint64_t* res = nullptr)
> : _state(State::NotIssued), _senderState(nullptr),
> numTranslatedFragments(0),
> numInTranslationFragments(0),
> _port(*port), _inst(inst), _data(data),
> _res(res), _addr(addr), _size(size),
> _flags(flags_),
> _numOutstandingPackets(0)
> {
> flags.set(Flag::IsLoad, isLoad);
> flags.set(Flag::WbStore, _inst->isStoreConditional());
> install();
> }
>
> bool
> isLoad() const
> {
> return flags.isSet(Flag::IsLoad);
> }
>
> /** Install the request in the LQ/SQ. */
> void install()
> {
> if (isLoad()) {
> _port.loadQueue[_inst->lqIdx].setRequest(this);
> } else {
> _port.storeQueue[_inst->sqIdx].setRequest(this);
> }
> }
> virtual bool
> squashed() const override
> {
> return _inst->isSquashed();
> }
>
> /**
> * Test if the LSQRequest has been released, i.e. self-owned.
> * An LSQRequest manages itself when the resources on the LSQ are freed
> * but the translation is still going on and the LSQEntry was freed.
> */
> bool
> isReleased()
> {
> return flags.isSet(Flag::LSQEntryFreed) ||
> flags.isSet(Flag::Discarded);
> }
>
> /** Release the LSQRequest.
> * Notify the sender state that the request it points to is not valid
> * anymore. Understand if the request is orphan (self-managed) and if
> * so, mark it as freed, else destroy it, as this means
> * the end of its life cycle.
> * An LSQRequest is orphan when its resources are released
> * but there is any in-flight translation request to the TLB or access
> * request to the memory.
> */
> void release(Flag reason)
> {
> assert(reason == Flag::LSQEntryFreed || reason == Flag::Discarded);
> if (!isAnyOutstandingRequest()) {
> delete this;
> } else {
> if (_senderState) {
> _senderState->deleteRequest();
> }
> flags.set(reason);
> }
> }
>
> /** Destructor.
> * The LSQRequest owns the request. If the packet has already been
> * sent, the sender state will be deleted upon receiving the reply.
> */
> virtual ~LSQRequest()
> {
> assert(!isAnyOutstandingRequest());
> _inst->savedReq = nullptr;
> if (_senderState)
> delete _senderState;
>
> for (auto r: _packets)
> delete r;
> };
>
>
> public:
> /** Convenience getters/setters. */
> /** @{ */
> /** Set up Context numbers. */
> void
> setContext(const ContextID& context_id)
> {
> request()->setContext(context_id);
> }
>
> const DynInstPtr&
> instruction()
> {
> return _inst;
> }
>
> /** Set up virtual request.
> * For a previously allocated Request objects.
> */
> void
> setVirt(int asid, Addr vaddr, unsigned size, Request::Flags flags_,
> MasterID mid, Addr pc)
> {
> request()->setVirt(asid, vaddr, size, flags_, mid, pc);
> }
>
> void
> taskId(const uint32_t& v)
> {
> _taskId = v;
> for (auto& r: _requests)
> r->taskId(v);
> }
>
> uint32_t taskId() const { return _taskId; }
> RequestPtr request(int idx = 0) { return _requests.at(idx); }
>
> const RequestPtr
> request(int idx = 0) const
> {
> return _requests.at(idx);
> }
>
> Addr getVaddr(int idx = 0) const { return request(idx)->getVaddr(); }
> virtual void initiateTranslation() = 0;
>
> PacketPtr packet(int idx = 0) { return _packets.at(idx); }
>
> virtual PacketPtr
> mainPacket()
> {
> assert (_packets.size() == 1);
> return packet();
> }
>
> virtual RequestPtr
> mainRequest()
> {
> assert (_requests.size() == 1);
> return request();
> }
>
> void
> senderState(LSQSenderState* st)
> {
> _senderState = st;
> for (auto& pkt: _packets) {
> if (pkt)
> pkt->senderState = st;
> }
> }
>
> const LSQSenderState*
> senderState() const
> {
> return _senderState;
> }
>
> /**
> * Mark senderState as discarded. This will cause to discard response
> * packets from the cache.
> */
> void
> discardSenderState()
> {
> assert(_senderState);
> _senderState->deleteRequest();
> }
>
> /**
> * Test if there is any in-flight translation or mem access request
> */
> bool
> isAnyOutstandingRequest()
> {
> return numInTranslationFragments > 0 ||
> _numOutstandingPackets > 0 ||
> (flags.isSet(Flag::WritebackScheduled) &&
> !flags.isSet(Flag::WritebackDone));
> }
>
> bool
> isSplit() const
> {
> return flags.isSet(Flag::IsSplit);
> }
> /** @} */
> virtual bool recvTimingResp(PacketPtr pkt) = 0;
> virtual void sendPacketToCache() = 0;
> virtual void buildPackets() = 0;
>
> /**
> * Memory mapped IPR accesses
> */
> virtual void handleIprWrite(ThreadContext *thread, PacketPtr pkt) = 0;
> virtual Cycles handleIprRead(ThreadContext *thread, PacketPtr pkt) = 0;
>
> /**
> * Test if the request accesses a particular cache line.
> */
> virtual bool isCacheBlockHit(Addr blockAddr, Addr cacheBlockMask) = 0;
>
> /** Update the status to reflect that a packet was sent. */
> void
> packetSent()
> {
> flags.set(Flag::Sent);
> }
> /** Update the status to reflect that a packet was not sent.
> * When a packet fails to be sent, we mark the request as needing a
> * retry. Note that Retry flag is sticky.
> */
> void
> packetNotSent()
> {
> flags.set(Flag::Retry);
> flags.clear(Flag::Sent);
> }
>
> void sendFragmentToTranslation(int i);
> bool
> isComplete()
> {
> return flags.isSet(Flag::Complete);
> }
>
> bool
> isInTranslation()
> {
> return _state == State::Translation;
> }
>
> bool
> isTranslationComplete()
> {
> return flags.isSet(Flag::TranslationStarted) &&
> !isInTranslation();
> }
>
> bool
> isTranslationBlocked()
> {
> return _state == State::Translation &&
> flags.isSet(Flag::TranslationStarted) &&
> !flags.isSet(Flag::TranslationFinished);
> }
>
> bool
> isSent()
> {
> return flags.isSet(Flag::Sent);
> }
>
> /**
> * The LSQ entry is cleared
> */
> void
> freeLSQEntry()
> {
> release(Flag::LSQEntryFreed);
> }
>
> /**
> * The request is discarded (e.g. partial store-load forwarding)
> */
> void
> discard()
> {
> release(Flag::Discarded);
> }
>
> void
> packetReplied()
> {
> assert(_numOutstandingPackets > 0);
> _numOutstandingPackets--;
> if (_numOutstandingPackets == 0 && isReleased())
> delete this;
> }
>
> void
> writebackScheduled()
> {
> assert(!flags.isSet(Flag::WritebackScheduled));
> flags.set(Flag::WritebackScheduled);
> }
>
> void
> writebackDone()
> {
> flags.set(Flag::WritebackDone);
> /* If the lsq resources are already free */
> if (isReleased()) {
> delete this;
> }
> }
>
> void
> squashTranslation()
> {
> assert(numInTranslationFragments == 0);
> flags.set(Flag::TranslationSquashed);
> /* If we are on our own, self-destruct. */
> if (isReleased()) {
> delete this;
> }
> }
>
> void
> complete()
> {
> flags.set(Flag::Complete);
> }
> };
>
> class SingleDataRequest : public LSQRequest
> {
> protected:
> /* Given that we are inside templates, children need explicit
> * declaration of the names in the parent class. */
> using Flag = typename LSQRequest::Flag;
> using State = typename LSQRequest::State;
> using LSQRequest::_fault;
> using LSQRequest::_inst;
> using LSQRequest::_packets;
> using LSQRequest::_port;
> using LSQRequest::_res;
> using LSQRequest::_senderState;
> using LSQRequest::_state;
> using LSQRequest::flags;
> using LSQRequest::isLoad;
> using LSQRequest::isTranslationComplete;
> using LSQRequest::lsqUnit;
> using LSQRequest::request;
> using LSQRequest::sendFragmentToTranslation;
> using LSQRequest::setState;
> using LSQRequest::numInTranslationFragments;
> using LSQRequest::numTranslatedFragments;
> using LSQRequest::_numOutstandingPackets;
> public:
> SingleDataRequest(LSQUnit* port, const DynInstPtr& inst, bool isLoad,
> const Addr& addr, const uint32_t& size,
> const Request::Flags& flags_,
> PacketDataPtr data = nullptr,
> uint64_t* res = nullptr) :
> LSQRequest(port, inst, isLoad, addr, size, flags_, data, res)
> {
> LSQRequest::_requests.push_back(
> std::make_shared<Request>(inst->getASID(), addr, size, flags_,
> inst->masterId(), inst->instAddr(), inst->contextId()));
> LSQRequest::_requests.back()->setReqInstSeqNum(inst->seqNum);
> }
> inline virtual ~SingleDataRequest() {}
> virtual void initiateTranslation();
> virtual void finish(const Fault &fault, const RequestPtr &req,
> ThreadContext* tc, BaseTLB::Mode mode);
> virtual bool recvTimingResp(PacketPtr pkt);
> virtual void sendPacketToCache();
> virtual void buildPackets();
> virtual void handleIprWrite(ThreadContext *thread, PacketPtr pkt);
> virtual Cycles handleIprRead(ThreadContext *thread, PacketPtr pkt);
> virtual bool isCacheBlockHit(Addr blockAddr, Addr cacheBlockMask);
> };
>
> class SplitDataRequest : public LSQRequest
> {
> protected:
> /* Given that we are inside templates, children need explicit
> * declaration of the names in the parent class. */
> using Flag = typename LSQRequest::Flag;
> using State = typename LSQRequest::State;
> using LSQRequest::_addr;
> using LSQRequest::_data;
> using LSQRequest::_fault;
> using LSQRequest::_flags;
> using LSQRequest::_inst;
> using LSQRequest::_packets;
> using LSQRequest::_port;
> using LSQRequest::_requests;
> using LSQRequest::_res;
> using LSQRequest::_senderState;
> using LSQRequest::_size;
> using LSQRequest::_state;
> using LSQRequest::_taskId;
> using LSQRequest::flags;
> using LSQRequest::isLoad;
> using LSQRequest::isTranslationComplete;
> using LSQRequest::lsqUnit;
> using LSQRequest::numInTranslationFragments;
> using LSQRequest::numTranslatedFragments;
> using LSQRequest::request;
> using LSQRequest::sendFragmentToTranslation;
> using LSQRequest::setState;
> using LSQRequest::_numOutstandingPackets;
>
> uint32_t numFragments;
> uint32_t numReceivedPackets;
> RequestPtr mainReq;
> PacketPtr _mainPacket;
>
>
> public:
> SplitDataRequest(LSQUnit* port, const DynInstPtr& inst, bool isLoad,
> const Addr& addr, const uint32_t& size,
> const Request::Flags & flags_,
> PacketDataPtr data = nullptr,
> uint64_t* res = nullptr) :
> LSQRequest(port, inst, isLoad, addr, size, flags_, data, res),
> numFragments(0),
> numReceivedPackets(0),
> mainReq(nullptr),
> _mainPacket(nullptr)
> {
> flags.set(Flag::IsSplit);
> }
> virtual ~SplitDataRequest()
> {
> if (mainReq) {
> mainReq = nullptr;
> }
> if (_mainPacket) {
> delete _mainPacket;
> _mainPacket = nullptr;
> }
> }
> virtual void finish(const Fault &fault, const RequestPtr &req,
> ThreadContext* tc, BaseTLB::Mode mode);
> virtual bool recvTimingResp(PacketPtr pkt);
> virtual void initiateTranslation();
> virtual void sendPacketToCache();
> virtual void buildPackets();
>
> virtual void handleIprWrite(ThreadContext *thread, PacketPtr pkt);
> virtual Cycles handleIprRead(ThreadContext *thread, PacketPtr pkt);
> virtual bool isCacheBlockHit(Addr blockAddr, Addr cacheBlockMask);
>
> virtual RequestPtr mainRequest();
> virtual PacketPtr mainPacket();
> };
>
88,92d734
< void removeEntries(ThreadID tid);
< /** Reset the max entries for each thread. */
< void resetEntries();
< /** Resize the max entries for a thread. */
< void resizeEntries(unsigned size, ThreadID tid);
95,98c737
< void tick();
< /** Ticks a specific LSQ Unit. */
< void tick(ThreadID tid)
< { thread[tid].tick(); }
---
> void tick() { usedStorePorts = 0; }
115c754
< { thread[tid].commitLoads(youngest_inst); }
---
> { thread.at(tid).commitLoads(youngest_inst); }
121c760
< { thread[tid].commitStores(youngest_inst); }
---
> { thread.at(tid).commitStores(youngest_inst); }
134,135c773,777
< void squash(const InstSeqNum &squashed_num, ThreadID tid)
< { thread[tid].squash(squashed_num); }
---
> void
> squash(const InstSeqNum &squashed_num, ThreadID tid)
> {
> thread.at(tid).squash(squashed_num);
> }
143,144c785
< bool violation(ThreadID tid)
< { return thread[tid].violation(); }
---
> bool violation(ThreadID tid) { return thread.at(tid).violation(); }
147,148c788,792
< DynInstPtr getMemDepViolator(ThreadID tid)
< { return thread[tid].getMemDepViolator(); }
---
> DynInstPtr
> getMemDepViolator(ThreadID tid)
> {
> return thread.at(tid).getMemDepViolator();
> }
151,152c795
< int getLoadHead(ThreadID tid)
< { return thread[tid].getLoadHead(); }
---
> int getLoadHead(ThreadID tid) { return thread.at(tid).getLoadHead(); }
155c798,799
< InstSeqNum getLoadHeadSeqNum(ThreadID tid)
---
> InstSeqNum
> getLoadHeadSeqNum(ThreadID tid)
157c801
< return thread[tid].getLoadHeadSeqNum();
---
> return thread.at(tid).getLoadHeadSeqNum();
161,162c805
< int getStoreHead(ThreadID tid)
< { return thread[tid].getStoreHead(); }
---
> int getStoreHead(ThreadID tid) { return thread.at(tid).getStoreHead(); }
165c808,809
< InstSeqNum getStoreHeadSeqNum(ThreadID tid)
---
> InstSeqNum
> getStoreHeadSeqNum(ThreadID tid)
167c811
< return thread[tid].getStoreHeadSeqNum();
---
> return thread.at(tid).getStoreHeadSeqNum();
173,174c817
< int getCount(ThreadID tid)
< { return thread[tid].getCount(); }
---
> int getCount(ThreadID tid) { return thread.at(tid).getCount(); }
179,180c822
< int numLoads(ThreadID tid)
< { return thread[tid].numLoads(); }
---
> int numLoads(ThreadID tid) { return thread.at(tid).numLoads(); }
185,186c827
< int numStores(ThreadID tid)
< { return thread[tid].numStores(); }
---
> int numStores(ThreadID tid) { return thread.at(tid).numStores(); }
245,246c886
< bool hasStoresToWB(ThreadID tid)
< { return thread[tid].hasStoresToWB(); }
---
> bool hasStoresToWB(ThreadID tid) { return thread.at(tid).hasStoresToWB(); }
249,250c889
< int numStoresToWB(ThreadID tid)
< { return thread[tid].numStoresToWB(); }
---
> int numStoresToWB(ThreadID tid) { return thread.at(tid).numStoresToWB(); }
257,258c896
< bool willWB(ThreadID tid)
< { return thread[tid].willWB(); }
---
> bool willWB(ThreadID tid) { return thread.at(tid).willWB(); }
263,264c901
< void dumpInsts(ThreadID tid) const
< { thread[tid].dumpInsts(); }
---
> void dumpInsts(ThreadID tid) const { thread.at(tid).dumpInsts(); }
269,271c906
< Fault read(const RequestPtr &req,
< RequestPtr &sreqLow, RequestPtr &sreqHigh,
< int load_idx);
---
> Fault read(LSQRequest* req, int load_idx);
276,278c911
< Fault write(const RequestPtr &req,
< const RequestPtr &sreqLow, const RequestPtr &sreqHigh,
< uint8_t *data, int store_idx);
---
> Fault write(LSQRequest* req, uint8_t *data, int store_idx);
284a918
> void completeDataAccess(PacketPtr pkt);
294a929,932
> Fault pushRequest(const DynInstPtr& inst, bool isLoad, uint8_t *data,
> unsigned int size, Addr addr, Request::Flags flags,
> uint64_t *res);
>
300a939,947
> /** Is D-cache blocked? */
> bool cacheBlocked() const;
> /** Set D-cache blocked status */
> void cacheBlocked(bool v);
> /** Is any store port available to use? */
> bool storePortAvailable() const;
> /** Another store port is in use */
> void storePortBusy();
>
301a949,956
> /** D-cache is blocked */
> bool _cacheBlocked;
> /** The number of cache ports available each cycle (stores only). */
> int cacheStorePorts;
> /** The number of used cache ports in this cycle by stores. */
> int usedStorePorts;
>
>
310,311c965,968
< static uint32_t maxLSQAllocation(SMTQueuePolicy pol, uint32_t entries,
< uint32_t numThreads, uint32_t SMTThreshold) {
---
> static uint32_t
> maxLSQAllocation(SMTQueuePolicy pol, uint32_t entries,
> uint32_t numThreads, uint32_t SMTThreshold)
> {
349,351c1006
< LSQ<Impl>::read(const RequestPtr &req,
< RequestPtr &sreqLow, RequestPtr &sreqHigh,
< int load_idx)
---
> LSQ<Impl>::read(LSQRequest* req, int load_idx)
353c1008
< ThreadID tid = cpu->contextToThread(req->contextId());
---
> ThreadID tid = cpu->contextToThread(req->request()->contextId());
355c1010
< return thread[tid].read(req, sreqLow, sreqHigh, load_idx);
---
> return thread.at(tid).read(req, load_idx);
360,362c1015
< LSQ<Impl>::write(const RequestPtr &req,
< const RequestPtr &sreqLow, const RequestPtr &sreqHigh,
< uint8_t *data, int store_idx)
---
> LSQ<Impl>::write(LSQRequest* req, uint8_t *data, int store_idx)
364c1017
< ThreadID tid = cpu->contextToThread(req->contextId());
---
> ThreadID tid = cpu->contextToThread(req->request()->contextId());
366c1019
< return thread[tid].write(req, sreqLow, sreqHigh, data, store_idx);
---
> return thread.at(tid).write(req, data, store_idx);