diff --git a/core/Decode.cpp b/core/Decode.cpp index df1970a5..5510f55e 100644 --- a/core/Decode.cpp +++ b/core/Decode.cpp @@ -170,7 +170,7 @@ namespace olympia uop_queue_.pop(); } else{ - const auto & inst = fetch_queue_.read(0); + auto & inst = fetch_queue_.read(0); // if we're waiting on a vset, but it's a scalar instruction // we can process all scalars after the vset until we reach a vset the decode queue if(inst->isVset() && inst->getSourceOpInfoList()[0].field_value == 0 && inst->getDestOpInfoList()[0].field_value != 0){ @@ -184,6 +184,9 @@ namespace olympia } if (inst->getLMUL() > 1 && !inst->isVset()) { + // update num_decode based on UOp count as well + num_decode = std::min(uop_queue_credits_, fetch_queue_.size() + uop_queue_.size() + inst->getLMUL()-1); + num_decode = std::min(num_decode, num_to_decode_); // lmul > 1, fracture instruction into UOps inst->setUOp(true); // mark instruction to denote it has UOPs // turn this into a state machine @@ -195,6 +198,7 @@ namespace olympia // which doesn't factor in the uop amount per instruction insts->emplace_back(inst); inst->setStatus(Inst::Status::DECODED); + inst->setUOpCount(VCSRs_.lmul); fetch_queue_.pop(); for (uint32_t j = 1; j < VCSRs_.lmul; ++j) { @@ -227,7 +231,8 @@ namespace olympia InstPtr inst_uop_ptr(new Inst(*new_inst)); inst_uop_ptr->setVCSRs(VCSRs_); inst_uop_ptr->setUOpID(j); - inst->appendUOp(inst_uop_ptr); + sparta::SpartaWeakPointer weak_ptr_inst = inst; + inst_uop_ptr->setUOpParent(weak_ptr_inst); if(i < num_decode){ insts->emplace_back(inst_uop_ptr); inst_uop_ptr->setStatus(Inst::Status::DECODED); @@ -295,7 +300,7 @@ namespace olympia // If we still have credits to send instructions as well as // instructions in the queue, schedule another decode session - if (uop_queue_credits_ > 0 && fetch_queue_.size() > 0) + if (uop_queue_credits_ > 0 && (fetch_queue_.size() + uop_queue_.size()) > 0) { ev_decode_insts_event_.schedule(1); } diff --git a/core/ExecutePipe.cpp b/core/ExecutePipe.cpp index a3051e2f..2247fe15 100644 --- a/core/ExecutePipe.cpp +++ b/core/ExecutePipe.cpp @@ -165,6 +165,11 @@ namespace olympia ex_inst->setStatus(Inst::Status::COMPLETED); complete_event_.collect(*ex_inst); ILOG("Completing inst: " << ex_inst); + if(ex_inst->isUOp()){ + sparta_assert(!ex_inst->getUOpParent().expired(), "UOp instruction parent shared pointer is expired"); + auto shared_ex_inst = ex_inst->getUOpParent().lock(); + shared_ex_inst->incrementUOpDoneCount(); + } out_execute_pipe_.send(1); } diff --git a/core/Fetch.cpp b/core/Fetch.cpp index 01a59d04..f5b8d28a 100644 --- a/core/Fetch.cpp +++ b/core/Fetch.cpp @@ -98,13 +98,13 @@ namespace olympia ILOG("Sending: " << ex_inst << " down the pipe"); } else{ + ILOG("Stalling due to waiting on vset"); // store fetched instruction in queue fetched_queue_.push((ex_inst)); break; } } else{ - ILOG("Stalling due to waiting on vset"); break; } } diff --git a/core/Inst.hpp b/core/Inst.hpp index d8f6ce8e..90ec371c 100644 --- a/core/Inst.hpp +++ b/core/Inst.hpp @@ -201,10 +201,6 @@ namespace olympia // UOpIDs start at 1, because we use 0 as default UOpID on initialization bool isUOp() const { return uopid_ > 0; } - void appendUOp(PtrType & inst) { uop_insts_.emplace_back(inst); } - - std::vector getUOpInsts() { return uop_insts_; } - // Set the instruction's Program ID. This ID is specific to // an instruction's retire pointer. The same instruction in a // trace will have the same program ID (as compared to @@ -246,6 +242,16 @@ namespace olympia VCSRs_.vl = inputVCSRs.vl; } + void setUOpParent(sparta::SpartaWeakPointer & uop_parent){ + uop_parent_ = uop_parent; + } + + void setUOpCount(uint64_t uop_count){ + uop_count_ = uop_count; + } + + void incrementUOpDoneCount(){ uop_done_count_++; } + sparta::memory::addr_t getTargetVAddr() const { return target_vaddr_; } uint32_t getSEW() const { return VCSRs_.sew; } @@ -254,6 +260,11 @@ namespace olympia uint32_t getVL() const { return VCSRs_.vl; } + uint64_t getUOpDoneCount(){ return uop_done_count_; } + + sparta::SpartaWeakPointer getUOpParent() { return uop_parent_; } + + uint64_t getUOpCount() const { return uop_count_; } // Branch instruction was taken (always set for JAL/JALR) void setTakenBranch(bool taken) { is_taken_branch_ = taken; } @@ -403,9 +414,11 @@ namespace olympia const bool is_call_; const bool is_return_; bool has_uops_; - std::vector uop_insts_; + uint64_t uop_done_count_ = 1; // start at 1 because the uop count includes the parent instruction + uint64_t uop_count_ = 0; VCSRs VCSRs_; + sparta::SpartaWeakPointer uop_parent_; // Did this instruction mispredict? bool is_mispredicted_ = false; bool is_taken_branch_ = false; diff --git a/core/ROB.cpp b/core/ROB.cpp index 35473a43..5c11dab5 100644 --- a/core/ROB.cpp +++ b/core/ROB.cpp @@ -137,20 +137,13 @@ namespace olympia sparta_assert(ex_inst.isSpeculative() == false, "Uh, oh! A speculative instruction is being retired: " << ex_inst); bool uops_done = true; - if (ex_inst.hasUOps()) + + if (ex_inst_ptr->hasUOps() && ex_inst_ptr->getUOpDoneCount() < ex_inst_ptr->getUOpCount()) { - // check if UOps are done - // for(auto & i : *in_reorder_buffer_write_.pullData()) { - // weakptr from child to parent instruction, increment when done - for (const auto & inst : ex_inst.getUOpInsts()) - { - if (inst->getStatus() != Inst::Status::COMPLETED) - { - uops_done = false; - ILOG("UOP: " << inst << " is not done for instruction: " << ex_inst); - break; - } - } + // if UOps are all done, you can retire parent + uops_done = false; + ILOG("UOP: " << ex_inst << " is not done for instruction: " << ex_inst); + break; } if ((ex_inst.getStatus() == Inst::Status::COMPLETED) && uops_done) {