| /* |
| * Copyright (c) 2013-2014 ARM Limited |
| * All rights reserved |
| * |
| * The license below extends only to copyright in the software and shall |
| * not be construed as granting a license to any other intellectual |
| * property including but not limited to intellectual property relating |
| * to a hardware implementation of the functionality of the software |
| * licensed hereunder. You may use the software subject to the license |
| * terms below provided that you ensure that this notice is replicated |
| * unmodified and in its entirety in all distributions of the software, |
| * modified or unmodified, in source code or in binary form. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer; |
| * redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution; |
| * neither the name of the copyright holders nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * Authors: Andrew Bardsley |
| */ |
| |
| /** |
| * @file |
| * |
| * A load/store queue that allows outstanding reads and writes. |
| * |
| */ |
| |
| #ifndef __CPU_MINOR_NEW_LSQ_HH__ |
| #define __CPU_MINOR_NEW_LSQ_HH__ |
| |
| #include "cpu/minor/buffers.hh" |
| #include "cpu/minor/cpu.hh" |
| #include "cpu/minor/pipe_data.hh" |
| #include "cpu/minor/trace.hh" |
| |
| namespace Minor |
| { |
| |
| /* Forward declaration */ |
| class Execute; |
| |
| class LSQ : public Named |
| { |
| protected: |
| /** My owner(s) */ |
| MinorCPU &cpu; |
| Execute &execute; |
| |
| protected: |
| /** State of memory access for head access. */ |
| enum MemoryState |
| { |
| MemoryRunning, /* Default. Step dcache queues when possible. */ |
| MemoryNeedsRetry /* Request rejected, will be asked to retry */ |
| }; |
| |
| /** Print MemoryState values as shown in the enum definition */ |
| friend std::ostream &operator <<(std::ostream &os, |
| MemoryState state); |
| |
| /** Coverage of one address range with another */ |
| enum AddrRangeCoverage |
| { |
| PartialAddrRangeCoverage, /* Two ranges partly overlap */ |
| FullAddrRangeCoverage, /* One range fully covers another */ |
| NoAddrRangeCoverage /* Two ranges are disjoint */ |
| }; |
| |
| /** Exposable data port */ |
| class DcachePort : public MinorCPU::MinorCPUPort |
| { |
| protected: |
| /** My owner */ |
| LSQ &lsq; |
| |
| public: |
| DcachePort(std::string name, LSQ &lsq_, MinorCPU &cpu) : |
| MinorCPU::MinorCPUPort(name, cpu), lsq(lsq_) |
| { } |
| |
| protected: |
| bool recvTimingResp(PacketPtr pkt) override |
| { return lsq.recvTimingResp(pkt); } |
| |
| void recvReqRetry() override { lsq.recvReqRetry(); } |
| |
| bool isSnooping() const override { return true; } |
| |
| void recvTimingSnoopReq(PacketPtr pkt) override |
| { return lsq.recvTimingSnoopReq(pkt); } |
| |
| void recvFunctionalSnoop(PacketPtr pkt) override { } |
| }; |
| |
| DcachePort dcachePort; |
| |
| public: |
| /** Derived SenderState to carry data access info. through address |
| * translation, the queues in this port and back from the memory |
| * system. */ |
| class LSQRequest : |
| public BaseTLB::Translation, /* For TLB lookups */ |
| public Packet::SenderState /* For packing into a Packet */ |
| { |
| public: |
| /** Owning port */ |
| LSQ &port; |
| |
| /** Instruction which made this request */ |
| MinorDynInstPtr inst; |
| |
| /** Load/store indication used for building packet. This isn't |
| * carried by Request so we need to keep it here */ |
| bool isLoad; |
| |
| /** Dynamically allocated and populated data carried for |
| * building write packets */ |
| PacketDataPtr data; |
| |
| /* Requests carry packets on their way to the memory system. |
| * When a Packet returns from the memory system, its |
| * request needs to have its packet updated as this |
| * may have changed in flight */ |
| PacketPtr packet; |
| |
| /** The underlying request of this LSQRequest */ |
| Request request; |
| |
| /** Fault generated performing this request */ |
| Fault fault; |
| |
| /** Res from pushRequest */ |
| uint64_t *res; |
| |
| /** Was skipped. Set to indicate any reason (faulted, bad |
| * stream sequence number, in a fault shadow) that this |
| * request did not perform a memory transfer */ |
| bool skipped; |
| |
| /** This in an access other than a normal cacheable load |
| * that's visited the memory system */ |
| bool issuedToMemory; |
| |
| enum LSQRequestState |
| { |
| NotIssued, /* Newly created */ |
| InTranslation, /* TLB accessed, no reply yet */ |
| Translated, /* Finished address translation */ |
| Failed, /* The starting start of FailedDataRequests */ |
| RequestIssuing, /* Load/store issued to memory in the requests |
| queue */ |
| StoreToStoreBuffer, /* Store in transfers on its way to the |
| store buffer */ |
| RequestNeedsRetry, /* Retry needed for load */ |
| StoreInStoreBuffer, /* Store in the store buffer, before issuing |
| a memory transfer */ |
| StoreBufferIssuing, /* Store in store buffer and has been |
| issued */ |
| StoreBufferNeedsRetry, /* Retry needed for store */ |
| /* All completed states. Includes |
| completed loads, TLB faults and skipped requests whose |
| seqNum's no longer match */ |
| Complete |
| }; |
| |
| LSQRequestState state; |
| |
| protected: |
| /** BaseTLB::Translation interface */ |
| void markDelayed() { } |
| |
| public: |
| LSQRequest(LSQ &port_, MinorDynInstPtr inst_, bool isLoad_, |
| PacketDataPtr data_ = NULL, uint64_t *res_ = NULL); |
| |
| virtual ~LSQRequest(); |
| |
| public: |
| /** Make a packet to use with the memory transaction */ |
| void makePacket(); |
| |
| /** Was no memory access attempted for this request? */ |
| bool skippedMemAccess() { return skipped; } |
| |
| /** Set this request as having been skipped before a memory |
| * transfer was attempt */ |
| void setSkipped() { skipped = true; } |
| |
| /** Does address range req1 (req1_addr to req1_addr + req1_size - 1) |
| * fully cover, partially cover or not cover at all the range req2 */ |
| static AddrRangeCoverage containsAddrRangeOf( |
| Addr req1_addr, unsigned int req1_size, |
| Addr req2_addr, unsigned int req2_size); |
| |
| /** Does this request's address range fully cover the range |
| * of other_request? */ |
| AddrRangeCoverage containsAddrRangeOf(LSQRequest *other_request); |
| |
| /** Start the address translation process for this request. This |
| * will issue a translation request to the TLB. */ |
| virtual void startAddrTranslation() = 0; |
| |
| /** Get the next packet to issue for this request. For split |
| * transfers, it will be necessary to step through the available |
| * packets by calling do { getHeadPacket ; stepToNextPacket } while |
| * (!sentAllPackets) and by retiring response using retireResponse */ |
| virtual PacketPtr getHeadPacket() = 0; |
| |
| /** Step to the next packet for the next call to getHeadPacket */ |
| virtual void stepToNextPacket() = 0; |
| |
| /** Have all packets been sent? */ |
| virtual bool sentAllPackets() = 0; |
| |
| /** True if this request has any issued packets in the memory |
| * system and so can't be interrupted until it gets responses */ |
| virtual bool hasPacketsInMemSystem() = 0; |
| |
| /** Retire a response packet into the LSQRequest packet possibly |
| * completing this transfer */ |
| virtual void retireResponse(PacketPtr packet_) = 0; |
| |
| /** Is this a request a barrier? */ |
| virtual bool isBarrier(); |
| |
| /** This request, once processed by the requests/transfers |
| * queues, will need to go to the store buffer */ |
| bool needsToBeSentToStoreBuffer(); |
| |
| /** Set state and output trace output */ |
| void setState(LSQRequestState new_state); |
| |
| /** Has this request been completed. This includes *all* reasons |
| * for completion: successful transfers, faults, skipped because |
| * of preceding faults */ |
| bool isComplete() const; |
| |
| /** MinorTrace report interface */ |
| void reportData(std::ostream &os) const; |
| }; |
| |
| typedef LSQRequest *LSQRequestPtr; |
| |
| friend std::ostream & operator <<(std::ostream &os, |
| AddrRangeCoverage state); |
| |
| friend std::ostream & operator <<(std::ostream &os, |
| LSQRequest::LSQRequestState state); |
| |
| protected: |
| /** Special request types that don't actually issue memory requests */ |
| class SpecialDataRequest : public LSQRequest |
| { |
| protected: |
| /** TLB interace */ |
| void finish(const Fault &fault_, RequestPtr request_, |
| ThreadContext *tc, BaseTLB::Mode mode) |
| { } |
| |
| public: |
| /** Send single translation request */ |
| void startAddrTranslation() { } |
| |
| /** Get the head packet as counted by numIssuedFragments */ |
| PacketPtr getHeadPacket() |
| { fatal("No packets in a SpecialDataRequest"); } |
| |
| /** Step on numIssuedFragments */ |
| void stepToNextPacket() { } |
| |
| /** Has no packets to send */ |
| bool sentAllPackets() { return true; } |
| |
| /** Never sends any requests */ |
| bool hasPacketsInMemSystem() { return false; } |
| |
| /** Keep the given packet as the response packet |
| * LSQRequest::packet */ |
| void retireResponse(PacketPtr packet_) { } |
| |
| public: |
| SpecialDataRequest(LSQ &port_, MinorDynInstPtr inst_) : |
| /* Say this is a load, not actually relevant */ |
| LSQRequest(port_, inst_, true, NULL, 0) |
| { } |
| }; |
| |
| /** FailedDataRequest represents requests from instructions that |
| * failed their predicates but need to ride the requests/transfers |
| * queues to maintain trace ordering */ |
| class FailedDataRequest : public SpecialDataRequest |
| { |
| public: |
| FailedDataRequest(LSQ &port_, MinorDynInstPtr inst_) : |
| SpecialDataRequest(port_, inst_) |
| { state = Failed; } |
| }; |
| |
| /** Request for doing barrier accounting in the store buffer. Not |
| * for use outside that unit */ |
| class BarrierDataRequest : public SpecialDataRequest |
| { |
| public: |
| bool isBarrier() { return true; } |
| |
| public: |
| BarrierDataRequest(LSQ &port_, MinorDynInstPtr inst_) : |
| SpecialDataRequest(port_, inst_) |
| { state = Complete; } |
| }; |
| |
| /** SingleDataRequest is used for requests that don't fragment */ |
| class SingleDataRequest : public LSQRequest |
| { |
| protected: |
| /** TLB interace */ |
| void finish(const Fault &fault_, RequestPtr request_, |
| ThreadContext *tc, BaseTLB::Mode mode); |
| |
| /** Has my only packet been sent to the memory system but has not |
| * yet been responded to */ |
| bool packetInFlight; |
| |
| /** Has the packet been at least sent to the memory system? */ |
| bool packetSent; |
| |
| public: |
| /** Send single translation request */ |
| void startAddrTranslation(); |
| |
| /** Get the head packet as counted by numIssuedFragments */ |
| PacketPtr getHeadPacket() { return packet; } |
| |
| /** Remember that the packet has been sent */ |
| void stepToNextPacket() { packetInFlight = true; packetSent = true; } |
| |
| /** Has packet been sent */ |
| bool hasPacketsInMemSystem() { return packetInFlight; } |
| |
| /** packetInFlight can become false again, so need to check |
| * packetSent */ |
| bool sentAllPackets() { return packetSent; } |
| |
| /** Keep the given packet as the response packet |
| * LSQRequest::packet */ |
| void retireResponse(PacketPtr packet_); |
| |
| public: |
| SingleDataRequest(LSQ &port_, MinorDynInstPtr inst_, |
| bool isLoad_, PacketDataPtr data_ = NULL, uint64_t *res_ = NULL) : |
| LSQRequest(port_, inst_, isLoad_, data_, res_), |
| packetInFlight(false), |
| packetSent(false) |
| { } |
| }; |
| |
| class SplitDataRequest : public LSQRequest |
| { |
| protected: |
| /** Event to step between translations */ |
| EventFunctionWrapper translationEvent; |
| protected: |
| /** Number of fragments this request is split into */ |
| unsigned int numFragments; |
| |
| /** Number of fragments in the address translation mechanism */ |
| unsigned int numInTranslationFragments; |
| |
| /** Number of fragments that have completed address translation, |
| * (numTranslatedFragments + numInTranslationFragments) <= |
| * numFragments. When numTranslatedFramgents == numFragments, |
| * translation is complete */ |
| unsigned int numTranslatedFragments; |
| |
| /** Number of fragments already issued (<= numFragments) */ |
| unsigned int numIssuedFragments; |
| |
| /** Number of fragments retired back to this request */ |
| unsigned int numRetiredFragments; |
| |
| /** Fragment Requests corresponding to the address ranges of |
| * each fragment */ |
| std::vector<Request *> fragmentRequests; |
| |
| /** Packets matching fragmentRequests to issue fragments to memory */ |
| std::vector<Packet *> fragmentPackets; |
| |
| protected: |
| /** TLB response interface */ |
| void finish(const Fault &fault_, RequestPtr request_, |
| ThreadContext *tc, BaseTLB::Mode mode); |
| |
| public: |
| SplitDataRequest(LSQ &port_, MinorDynInstPtr inst_, |
| bool isLoad_, PacketDataPtr data_ = NULL, |
| uint64_t *res_ = NULL); |
| |
| ~SplitDataRequest(); |
| |
| public: |
| /** Make all the Requests for this transfer's fragments so that those |
| * requests can be sent for address translation */ |
| void makeFragmentRequests(); |
| |
| /** Make the packets to go with the requests so they can be sent to |
| * the memory system */ |
| void makeFragmentPackets(); |
| |
| /** Start a loop of do { sendNextFragmentToTranslation ; |
| * translateTiming ; finish } while (numTranslatedFragments != |
| * numFragments) to complete all this requests' fragments' address |
| * translations */ |
| void startAddrTranslation(); |
| |
| /** Get the head packet as counted by numIssuedFragments */ |
| PacketPtr getHeadPacket(); |
| |
| /** Step on numIssuedFragments */ |
| void stepToNextPacket(); |
| |
| bool hasPacketsInMemSystem() |
| { return numIssuedFragments != numRetiredFragments; } |
| |
| /** Have we stepped past the end of fragmentPackets? */ |
| bool sentAllPackets() { return numIssuedFragments == numFragments; } |
| |
| /** For loads, paste the response data into the main |
| * response packet */ |
| void retireResponse(PacketPtr packet_); |
| |
| /** Part of the address translation loop, see startAddTranslation */ |
| void sendNextFragmentToTranslation(); |
| }; |
| |
| /** Store buffer. This contains stores which have been committed |
| * but whose memory transfers have not yet been issued. Load data |
| * can be forwarded out of the store buffer */ |
| class StoreBuffer : public Named |
| { |
| public: |
| /** My owner */ |
| LSQ &lsq; |
| |
| /** Number of slots, this is a bound on the size of slots */ |
| const unsigned int numSlots; |
| |
| /** Maximum number of stores that can be issued per cycle */ |
| const unsigned int storeLimitPerCycle; |
| |
| public: |
| /** Queue of store requests on their way to memory */ |
| std::deque<LSQRequestPtr> slots; |
| |
| /** Number of occupied slots which have not yet issued a |
| * memory access */ |
| unsigned int numUnissuedAccesses; |
| |
| public: |
| StoreBuffer(std::string name_, LSQ &lsq_, |
| unsigned int store_buffer_size, |
| unsigned int store_limit_per_cycle); |
| |
| public: |
| /** Can a new request be inserted into the queue? */ |
| bool canInsert() const; |
| |
| /** Delete the given request and free the slot it occupied */ |
| void deleteRequest(LSQRequestPtr request); |
| |
| /** Insert a request at the back of the queue */ |
| void insert(LSQRequestPtr request); |
| |
| /** Look for a store which satisfies the given load. Returns an |
| * indication whether the forwarding request can be wholly, |
| * partly or not all all satisfied. If the request can be |
| * wholly satisfied, the store buffer slot number which can be used |
| * is returned in found_slot */ |
| AddrRangeCoverage canForwardDataToLoad(LSQRequestPtr request, |
| unsigned int &found_slot); |
| |
| /** Fill the given packet with appropriate date from slot |
| * slot_number */ |
| void forwardStoreData(LSQRequestPtr load, unsigned int slot_number); |
| |
| /** Number of stores in the store buffer which have not been |
| * completely issued to the memory system */ |
| unsigned int numUnissuedStores() { return numUnissuedAccesses; } |
| |
| /** Count a store being issued to memory by decrementing |
| * numUnissuedAccesses. Does not count barrier requests as they |
| * will be handles as barriers are cleared from the buffer */ |
| void countIssuedStore(LSQRequestPtr request); |
| |
| /** Drained if there is absolutely nothing left in the buffer */ |
| bool isDrained() const { return slots.empty(); } |
| |
| /** Try to issue more stores to memory */ |
| void step(); |
| |
| /** Report queue contents for MinorTrace */ |
| void minorTrace() const; |
| }; |
| |
| protected: |
| /** Most recent execSeqNum of a memory barrier instruction or |
| * 0 if there are no in-flight barriers. Useful as a |
| * dependency for early-issued memory operations */ |
| std::vector<InstSeqNum> lastMemBarrier; |
| |
| public: |
| /** Retry state of last issued memory transfer */ |
| MemoryState state; |
| |
| /** Maximum number of in-flight accesses issued to the memory system */ |
| const unsigned int inMemorySystemLimit; |
| |
| /** Memory system access width (and snap) in bytes */ |
| const unsigned int lineWidth; |
| |
| public: |
| /** The LSQ consists of three queues: requests, transfers and the |
| * store buffer storeBuffer. */ |
| |
| typedef Queue<LSQRequestPtr, |
| ReportTraitsPtrAdaptor<LSQRequestPtr>, |
| NoBubbleTraits<LSQRequestPtr> > |
| LSQQueue; |
| |
| /** requests contains LSQRequests which have been issued to the TLB by |
| * calling ExecContext::readMem/writeMem (which in turn calls |
| * LSQ::pushRequest and LSQRequest::startAddrTranslation). Once they |
| * have a physical address, requests at the head of requests can be |
| * issued to the memory system. At this stage, it cannot be clear that |
| * memory accesses *must* happen (that there are no preceding faults or |
| * changes of flow of control) and so only cacheable reads are issued |
| * to memory. |
| * Cacheable stores are not issued at all (and just pass through |
| * 'transfers' in order) and all other transfers are stalled in requests |
| * until their corresponding instructions are at the head of the |
| * inMemInsts instruction queue and have the right streamSeqNum. */ |
| LSQQueue requests; |
| |
| /** Once issued to memory (or, for stores, just had their |
| * state changed to StoreToStoreBuffer) LSQRequests pass through |
| * transfers waiting for memory responses. At the head of transfers, |
| * Execute::commitInst can pick up the memory response for a request |
| * using LSQ::findResponse. Responses to be committed can then |
| * have ExecContext::completeAcc on them. Stores can then be pushed |
| * into the store buffer. All other transfers will then be complete. */ |
| LSQQueue transfers; |
| |
| /* The store buffer contains committed cacheable stores on |
| * their way to memory decoupled from subsequence instruction execution. |
| * Before trying to issue a cacheable read from 'requests' to memory, |
| * the store buffer is checked to see if a previous store contains the |
| * needed data (StoreBuffer::canForwardDataToLoad) which can be |
| * forwarded in lieu of a memory access. If there are outstanding |
| * stores in the transfers queue, they must be promoted to the store |
| * buffer (and so be commited) before they can be correctly checked |
| * for forwarding. */ |
| StoreBuffer storeBuffer; |
| |
| protected: |
| /** Count of the number of mem. accesses which have left the |
| * requests queue and are in the 'wild' in the memory system and who |
| * *must not* be interrupted as they are not normal cacheable |
| * accesses. This is a count of the number of in-flight requests |
| * with issuedToMemory set who have visited tryToSendRequest at least |
| * once */ |
| unsigned int numAccessesInMemorySystem; |
| |
| /** Number of requests in the DTLB in the requests queue */ |
| unsigned int numAccessesInDTLB; |
| |
| /** The number of stores in the transfers queue. Useful when |
| * testing if the store buffer contains all the forwardable stores */ |
| unsigned int numStoresInTransfers; |
| |
| /** The number of accesses which have been issued to the memory |
| * system but have not been committed/discarded *excluding* |
| * cacheable normal loads which don't need to be tracked */ |
| unsigned int numAccessesIssuedToMemory; |
| |
| /** The request (from either requests or the store buffer) which is |
| * currently waiting have its memory access retried */ |
| LSQRequestPtr retryRequest; |
| |
| /** Address Mask for a cache block (e.g. ~(cache_block_size-1)) */ |
| Addr cacheBlockMask; |
| |
| protected: |
| /** Try and issue a memory access for a translated request at the |
| * head of the requests queue. Also tries to move the request |
| * between queues */ |
| void tryToSendToTransfers(LSQRequestPtr request); |
| |
| /** Try to send (or resend) a memory request's next/only packet to |
| * the memory system. Returns true if the request was successfully |
| * sent to memory (and was also the last packet in a transfer) */ |
| bool tryToSend(LSQRequestPtr request); |
| |
| /** Clear a barrier (if it's the last one marked up in lastMemBarrier) */ |
| void clearMemBarrier(MinorDynInstPtr inst); |
| |
| /** Move a request between queues */ |
| void moveFromRequestsToTransfers(LSQRequestPtr request); |
| |
| /** Can a request be sent to the memory system */ |
| bool canSendToMemorySystem(); |
| |
| /** Snoop other threads monitors on memory system accesses */ |
| void threadSnoop(LSQRequestPtr request); |
| |
| public: |
| LSQ(std::string name_, std::string dcache_port_name_, |
| MinorCPU &cpu_, Execute &execute_, |
| unsigned int max_accesses_in_memory_system, unsigned int line_width, |
| unsigned int requests_queue_size, unsigned int transfers_queue_size, |
| unsigned int store_buffer_size, |
| unsigned int store_buffer_cycle_store_limit); |
| |
| virtual ~LSQ(); |
| |
| public: |
| /** Step checks the queues to see if their are issuable transfers |
| * which were not otherwise picked up by tests at the end of other |
| * events. |
| * |
| * Steppable actions include deferred actions which couldn't be |
| * cascaded on the end of a memory response/TLB response event |
| * because of resource congestion. */ |
| void step(); |
| |
| /** Is their space in the request queue to be able to push a request by |
| * issuing an isMemRef instruction */ |
| bool canRequest() { return requests.unreservedRemainingSpace() != 0; } |
| |
| /** Returns a response if it's at the head of the transfers queue and |
| * it's either complete or can be sent on to the store buffer. After |
| * calling, the request still remains on the transfer queue until |
| * popResponse is called */ |
| LSQRequestPtr findResponse(MinorDynInstPtr inst); |
| |
| /** Sanity check and pop the head response */ |
| void popResponse(LSQRequestPtr response); |
| |
| /** Must check this before trying to insert into the store buffer */ |
| bool canPushIntoStoreBuffer() const { return storeBuffer.canInsert(); } |
| |
| /** A store has been committed, please move it to the store buffer */ |
| void sendStoreToStoreBuffer(LSQRequestPtr request); |
| |
| /** Are there any accesses other than normal cached loads in the |
| * memory system or having received responses which need to be |
| * handled for their instruction's to be completed */ |
| bool accessesInFlight() const |
| { return numAccessesIssuedToMemory != 0; } |
| |
| /** A memory barrier instruction has been issued, remember its |
| * execSeqNum that we can avoid issuing memory ops until it is |
| * committed */ |
| void issuedMemBarrierInst(MinorDynInstPtr inst); |
| |
| /** Get the execSeqNum of the last issued memory barrier */ |
| InstSeqNum getLastMemBarrier(ThreadID thread_id) const |
| { return lastMemBarrier[thread_id]; } |
| |
| /** Is there nothing left in the LSQ */ |
| bool isDrained(); |
| |
| /** May need to be ticked next cycle as one of the queues contains |
| * an actionable transfers or address translation */ |
| bool needsToTick(); |
| |
| /** Complete a barrier instruction. Where committed, makes a |
| * BarrierDataRequest and pushed it into the store buffer */ |
| void completeMemBarrierInst(MinorDynInstPtr inst, |
| bool committed); |
| |
| /** Single interface for readMem/writeMem to issue requests into |
| * the LSQ */ |
| void pushRequest(MinorDynInstPtr inst, bool isLoad, uint8_t *data, |
| unsigned int size, Addr addr, Request::Flags flags, |
| uint64_t *res); |
| |
| /** Push a predicate failed-representing request into the queues just |
| * to maintain commit order */ |
| void pushFailedRequest(MinorDynInstPtr inst); |
| |
| /** Memory interface */ |
| bool recvTimingResp(PacketPtr pkt); |
| void recvReqRetry(); |
| void recvTimingSnoopReq(PacketPtr pkt); |
| |
| /** Return the raw-bindable port */ |
| MinorCPU::MinorCPUPort &getDcachePort() { return dcachePort; } |
| |
| void minorTrace() const; |
| }; |
| |
| /** Make a suitable packet for the given request. If the request is a store, |
| * data will be the payload data. If sender_state is NULL, it won't be |
| * pushed into the packet as senderState */ |
| PacketPtr makePacketForRequest(Request &request, bool isLoad, |
| Packet::SenderState *sender_state = NULL, PacketDataPtr data = NULL); |
| } |
| |
| #endif /* __CPU_MINOR_NEW_LSQ_HH__ */ |