| /* |
| * Copyright (c) 2017-2021 Advanced Micro Devices, Inc. |
| * All rights reserved. |
| * |
| * For use for simulation and test purposes only |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * |
| * 2. 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. |
| * |
| * 3. Neither the name of the copyright holder 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 HOLDER 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. |
| */ |
| |
| /* |
| * Tester thread issues requests to and receives responses from Ruby memory |
| */ |
| |
| #ifndef CPU_TESTERS_PROTOCOL_TESTER_TESTER_THREAD_HH_ |
| #define CPU_TESTERS_PROTOCOL_TESTER_TESTER_THREAD_HH_ |
| |
| #include "cpu/testers/gpu_ruby_test/address_manager.hh" |
| #include "cpu/testers/gpu_ruby_test/episode.hh" |
| #include "cpu/testers/gpu_ruby_test/protocol_tester.hh" |
| #include "gpu-compute/gpu_dyn_inst.hh" |
| #include "mem/token_port.hh" |
| #include "sim/clocked_object.hh" |
| |
| namespace gem5 |
| { |
| |
| class TesterThread : public ClockedObject |
| { |
| public: |
| typedef TesterThreadParams Params; |
| TesterThread(const Params &p); |
| virtual ~TesterThread(); |
| |
| typedef AddressManager::Location Location; |
| typedef AddressManager::Value Value; |
| |
| void wakeup(); |
| void scheduleWakeup(); |
| void checkDeadlock(); |
| void scheduleDeadlockCheckEvent(); |
| |
| void attachTesterThreadToPorts(ProtocolTester *_tester, |
| ProtocolTester::SeqPort *_port, |
| ProtocolTester::GMTokenPort *_tokenPort = nullptr, |
| ProtocolTester::SeqPort *_sqcPort = nullptr, |
| ProtocolTester::SeqPort *_scalarPort = nullptr); |
| |
| const std::string& getName() const { return threadName; } |
| |
| // must be implemented by a child class |
| virtual void hitCallback(PacketPtr pkt) = 0; |
| |
| int getTesterThreadId() const { return threadId; } |
| int getNumLanes() const { return numLanes; } |
| // check if the input location would satisfy DRF constraint |
| bool checkDRF(Location atomic_loc, Location loc, bool isStore) const; |
| |
| void printAllOutstandingReqs(std::stringstream& ss) const; |
| |
| protected: |
| class TesterThreadEvent : public Event |
| { |
| private: |
| TesterThread* thread; |
| std::string desc; |
| |
| public: |
| TesterThreadEvent(TesterThread* _thread, std::string _description) |
| : Event(CPU_Tick_Pri), thread(_thread), desc(_description) |
| {} |
| void setDesc(std::string _description) { desc = _description; } |
| void process() override { thread->wakeup(); } |
| const std::string name() const override { return desc; } |
| }; |
| |
| TesterThreadEvent threadEvent; |
| |
| class DeadlockCheckEvent : public Event |
| { |
| private: |
| TesterThread* thread; |
| |
| public: |
| DeadlockCheckEvent(TesterThread* _thread) |
| : Event(CPU_Tick_Pri), thread(_thread) |
| {} |
| void process() override { thread->checkDeadlock(); } |
| |
| const std::string |
| name() const override |
| { |
| return "Tester deadlock check"; |
| } |
| }; |
| |
| DeadlockCheckEvent deadlockCheckEvent; |
| |
| struct OutstandingReq |
| { |
| int lane; |
| Location origLoc; |
| Value storedValue; |
| Cycles issueCycle; |
| |
| OutstandingReq(int _lane, Location _loc, Value _val, Cycles _cycle) |
| : lane(_lane), origLoc(_loc), storedValue(_val), issueCycle(_cycle) |
| {} |
| |
| ~OutstandingReq() |
| {} |
| }; |
| |
| // the unique global id of this thread |
| int threadId; |
| // width of this thread (1 for cpu thread & wf size for gpu wavefront) |
| int numLanes; |
| // thread name |
| std::string threadName; |
| // pointer to the main tester |
| ProtocolTester *tester; |
| // pointer to the address manager |
| AddressManager *addrManager; |
| |
| ProtocolTester::SeqPort *port; // main data port (GPU-vector data) |
| ProtocolTester::GMTokenPort *tokenPort; |
| ProtocolTester::SeqPort *scalarPort; // nullptr for CPU |
| ProtocolTester::SeqPort *sqcPort; // nullptr for CPU |
| |
| // a list of issued episodes sorted by time |
| // the last episode in the list is the current episode |
| typedef std::vector<Episode*> EpisodeHistory; |
| EpisodeHistory episodeHistory; |
| // pointer to the current episode |
| Episode *curEpisode; |
| // pointer to the current action |
| const Episode::Action *curAction; |
| |
| // number of outstanding requests that are waiting for their responses |
| int pendingLdStCount; |
| int pendingFenceCount; |
| int pendingAtomicCount; |
| |
| // last cycle when there is an event in this thread |
| Cycles lastActiveCycle; |
| Cycles deadlockThreshold; |
| |
| // a per-address list of outstanding requests |
| typedef std::vector<OutstandingReq> OutstandingReqList; |
| typedef std::unordered_map<Addr, OutstandingReqList> OutstandingReqTable; |
| OutstandingReqTable outstandingLoads; |
| OutstandingReqTable outstandingStores; |
| OutstandingReqTable outstandingAtomics; |
| |
| void issueNewEpisode(); |
| // check if the next action in the current episode satisfies all wait_cnt |
| // constraints and is ready to issue |
| bool isNextActionReady(); |
| void issueNextAction(); |
| |
| // issue Ops to Ruby memory |
| // must be implemented by a child class |
| virtual void issueLoadOps() = 0; |
| virtual void issueStoreOps() = 0; |
| virtual void issueAtomicOps() = 0; |
| virtual void issueAcquireOp() = 0; |
| virtual void issueReleaseOp() = 0; |
| |
| // add an outstanding request to its corresponding table |
| void addOutstandingReqs(OutstandingReqTable& req_table, Addr addr, |
| int lane, Location loc, |
| Value stored_val = AddressManager::INVALID_VALUE); |
| |
| // pop an outstanding request from the input table |
| OutstandingReq popOutstandingReq(OutstandingReqTable& req_table, |
| Addr address); |
| |
| // validate all atomic responses |
| void validateAtomicResp(Location loc, int lane, Value ret_val); |
| // validate all Load responses |
| void validateLoadResp(Location loc, int lane, Value ret_val); |
| |
| void printOutstandingReqs(const OutstandingReqTable& table, |
| std::stringstream& ss) const; |
| }; |
| |
| } // namespace gem5 |
| |
| #endif /* CPU_TESTERS_PROTOCOL_TESTER_TESTER_THREAD_HH_ */ |