diff --git a/core/Fetch.hpp b/core/Fetch.hpp index 6a34e9ef..8836fc24 100644 --- a/core/Fetch.hpp +++ b/core/Fetch.hpp @@ -92,7 +92,6 @@ namespace olympia // Number of instructions to fetch const uint32_t num_insts_to_fetch_; - // For traces with system instructions, skip them const bool skip_nonuser_mode_; diff --git a/core/Inst.hpp b/core/Inst.hpp index 7aca33c9..4fcd61aa 100644 --- a/core/Inst.hpp +++ b/core/Inst.hpp @@ -136,13 +136,18 @@ namespace olympia return inst_arch_info_->getTargetPipe(); } + // ROB handling -- mark this instruction as the oldest in the machine void setOldest(bool oldest, sparta::Scheduleable * rob_retire_event) { ev_retire_ = rob_retire_event; is_oldest_ = oldest; } - bool isMarkedOldest() const { return is_oldest_; } + // Instruction trace/JSON generation -- mark instruction as + // last in trace/JSON file. + void setLast() { is_last_ = true; } + bool getLast() const { return is_last_; } + // Set the instructions unique ID. This ID in constantly // incremented and does not repeat. The same instruction in a // trace can have different unique IDs (due to flushing) @@ -217,7 +222,8 @@ namespace olympia sparta::memory::addr_t inst_pc_ = 0; // Instruction's PC sparta::memory::addr_t target_vaddr_ = 0; // Instruction's Target PC (for branches, loads/stores) - bool is_oldest_ = false; + bool is_oldest_ = false; + bool is_last_ = false; // Is last intruction of trace uint64_t unique_id_ = 0; // Supplied by Fetch uint64_t program_id_ = 0; // Supplied by a trace Reader or execution backend bool is_speculative_ = false; // Is this instruction soon to be flushed? diff --git a/core/InstGenerator.cpp b/core/InstGenerator.cpp index 096bcd3b..2d5eaba7 100644 --- a/core/InstGenerator.cpp +++ b/core/InstGenerator.cpp @@ -104,9 +104,10 @@ namespace olympia } ++curr_inst_index_; - if (inst != nullptr) { - inst->setUniqueID(++unique_id_); - inst->setProgramID(unique_id_); + inst->setUniqueID(++unique_id_); + inst->setProgramID(unique_id_); + if(isDone()) { + inst->setLast(); } return inst; @@ -176,6 +177,9 @@ namespace olympia //inst->setVAddrVector(std::move(addrs)); } ++next_it_; + if(isDone()) { + inst->setLast(); + } return inst; } catch(std::exception & excpt) { diff --git a/core/LSU.cpp b/core/LSU.cpp index 382a0eb8..630f89bd 100644 --- a/core/LSU.cpp +++ b/core/LSU.cpp @@ -94,6 +94,9 @@ namespace olympia ldst_pipeline_.registerHandlerAtStage(cache_lookup_stage_, CREATE_SPARTA_HANDLER(LSU, handleCacheLookupReq_)); + node->getParent()->registerForNotification( + this, "rob_notif_channel", false /* ROB maybe not be constructed yet */); + ldst_pipeline_.registerHandlerAtStage(cache_read_stage_, CREATE_SPARTA_HANDLER(LSU, handleCacheRead_)); @@ -108,6 +111,8 @@ namespace olympia ILOG("LSU construct: #" << node->getGroupIdx()); } + void LSU::onRobDrained_(const bool & val) { retire_done_ = val; } + LSU::~LSU() { DLOG(getContainer()->getLocation() << ": " << load_store_info_allocator_.getNumAllocated() @@ -116,6 +121,17 @@ namespace olympia << " MemoryAccessInfo objects allocated/created"); } + void LSU::onStartingTeardown_() + { + // If ROB has not stopped the simulation & + // the ldst has entries to process we should fail + if ((false == retire_done_) && (false == ldst_inst_queue_.empty())) + { + dumpDebugContent_(std::cerr); + sparta_assert(false, "Issue queue has pending instructions"); + } + } + //////////////////////////////////////////////////////////////////////////////// // Callbacks //////////////////////////////////////////////////////////////////////////////// @@ -761,6 +777,15 @@ namespace olympia // Otherwise, assertion error is fired inside arbitrateInstIssue_() } + void LSU::dumpDebugContent_(std::ostream & output) const + { + output << "LSU Contents" << std::endl; + for (const auto & entry : ldst_inst_queue_) + { + output << '\t' << entry << std::endl; + } + } + void LSU::replayReady_(const LoadStoreInstInfoPtr & replay_inst_ptr) { ILOG("Replay inst ready " << replay_inst_ptr); diff --git a/core/LSU.hpp b/core/LSU.hpp index 674db63c..b73f6508 100644 --- a/core/LSU.hpp +++ b/core/LSU.hpp @@ -77,14 +77,18 @@ namespace olympia // Type Name/Alias Declaration //////////////////////////////////////////////////////////////////////////////// + bool retire_done_ = false; using LoadStoreInstInfoPtr = sparta::SpartaSharedPointer; + using LoadStoreInstIterator = sparta::Buffer::const_iterator; + using FlushCriteria = FlushManager::FlushingCriteria; - using LoadStoreInstIterator = sparta::Buffer::const_iterator; + void onRobDrained_(const bool & val); private: using ScoreboardViews = std::array, core_types::N_REGFILES>; + ScoreboardViews scoreboard_views_; //////////////////////////////////////////////////////////////////////////////// // Input Ports @@ -190,7 +194,6 @@ namespace olympia //////////////////////////////////////////////////////////////////////////////// // Callbacks //////////////////////////////////////////////////////////////////////////////// - // Send initial credits (ldst_inst_queue_size_) to Dispatch Unit void sendInitialCredits_(); @@ -229,6 +232,7 @@ namespace olympia // Handle instruction flush in LSU void handleFlush_(const FlushCriteria &); + void dumpDebugContent_(std::ostream & output) const override final; // Instructions in the replay ready to issue void replayReady_(const LoadStoreInstInfoPtr &); @@ -319,7 +323,7 @@ namespace olympia // When simulation is ending (error or not), this function // will be called - void onStartingTeardown_() override {} + void onStartingTeardown_() override; bool olderStoresExists_(const InstPtr & inst_ptr); diff --git a/core/ROB.cpp b/core/ROB.cpp index 16dcf3d0..ab9a5032 100644 --- a/core/ROB.cpp +++ b/core/ROB.cpp @@ -49,10 +49,16 @@ namespace olympia registerConsumerHandler(CREATE_SPARTA_HANDLER_WITH_DATA(ROB, handleFlush_, FlushManager::FlushingCriteria)); - // This event is ALWAYS scheduled, but it should not keep - // simulation continuing on. + // Do not allow this event to keep simulation alive ev_ensure_forward_progress_.setContinuing(false); + // Notify other components when ROB stops the simulation + rob_drained_notif_source_.reset(new sparta::NotificationSource( + this->getContainer(), + "rob_notif_channel", + "Notification channel for rob", + "rob_notif_channel" + )); // Send initial credits to anyone that cares. Probably Dispatch. sparta::StartupEvent(node, CREATE_SPARTA_HANDLER(ROB, sendInitialCredits_)); } @@ -133,6 +139,7 @@ namespace olympia // Will be true if the user provides a -i option if (SPARTA_EXPECT_FALSE((num_retired_ == num_insts_to_retire_))) { rob_stopped_simulation_ = true; + rob_drained_notif_source_->postNotification(true); getScheduler()->stopRunning(); break; } @@ -151,6 +158,14 @@ namespace olympia break; } + // Check to see if this is the last instruction of the + // trace + if(ex_inst.getLast()) { + rob_stopped_simulation_ = true; + rob_drained_notif_source_->postNotification(true); + // No need to stop the scheduler -- let simulation + // drain normally. Also, don't need to check forward progress + } } else { break; diff --git a/core/ROB.hpp b/core/ROB.hpp index f6a828cc..89aa83d4 100644 --- a/core/ROB.hpp +++ b/core/ROB.hpp @@ -116,6 +116,8 @@ namespace olympia sparta::Event<> ev_ensure_forward_progress_{&unit_event_set_, "forward_progress_check", CREATE_SPARTA_HANDLER(ROB, checkForwardProgress_)}; + std::unique_ptr> rob_drained_notif_source_; + void sendInitialCredits_(); void retireEvent_(); void robAppended_(const InstGroup &); diff --git a/test/core/rename/Rename_test.cpp b/test/core/rename/Rename_test.cpp index a86b6680..72241ba5 100644 --- a/test/core/rename/Rename_test.cpp +++ b/test/core/rename/Rename_test.cpp @@ -150,6 +150,14 @@ class olympia::LSUTester // while the ADD instruction is running, the STORE instruction should NOT issue EXPECT_TRUE(lsu.lsu_insts_issued_ == 0); } + + void clear_entries(olympia::LSU &lsu){ + auto iter = lsu.ldst_inst_queue_.begin(); + while(iter != lsu.ldst_inst_queue_.end()){ + auto x(iter++); + lsu.ldst_inst_queue_.erase(x); + } + } }; // @@ -444,6 +452,7 @@ void runTest(int argc, char **argv) cls.runSimulator(&sim, 6); executepipe_tester.test_dependent_integer_first_instruction(*my_executepipe); lsu_tester.test_dependent_lsu_instruction(*my_lsu); + lsu_tester.clear_entries(*my_lsu); } else if(input_file == "raw_float_lsu.json"){ // testing RAW dependency for data operand @@ -457,6 +466,7 @@ void runTest(int argc, char **argv) cls.runSimulator(&sim, 6); executepipe_tester.test_dependent_integer_first_instruction(*my_executepipe); lsu_tester.test_dependent_lsu_instruction(*my_lsu); + lsu_tester.clear_entries(*my_lsu); } else if(input_file == "amoadd.json"){ sparta::Scheduler sched;