The Sparta Modeling Framework
Loading...
Searching...
No Matches
Pipeline.hpp
Go to the documentation of this file.
1// <Pipeline> -*- C++ -*-
2
3
9#pragma once
10
11#include <cinttypes>
12#include <memory>
13#include <array>
14#include <list>
15#include <type_traits>
16#include <vector>
17
20#include "sparta/utils/MathUtils.hpp"
21#include "sparta/collection/IterableCollector.hpp"
22
29
30namespace sparta
31{
32
61 template <typename DataT, typename EventT=PhasedUniqueEvent>
63 {
64 public:
65 using size_type = uint32_t;
66 using value_type = DataT;
67 using EventHandle = std::unique_ptr<EventT>;
68 using EventHandleList = std::list<EventHandle>;
69 using EventList = std::list<EventT*>;
70 using EventMatrix = std::array<EventList, NUM_SCHEDULING_PHASES>;
71
76 enum class Precedence {
77 NONE,
78 FORWARD,
79 BACKWARD,
80 NUM_OF_PRECEDENCE
81 };
82
83 template<typename DataT2, typename EventT2>
84 friend class Pipeline;
85
100 template<bool is_const_iterator = true>
101 class PipelineIterator : public utils::IteratorTraits<std::forward_iterator_tag, DataT>
102 {
103 using DataReferenceType =
104 typename std::conditional<is_const_iterator, const DataT &, DataT &>::type;
105
106 using DataPointerType =
107 typename std::conditional<is_const_iterator, const DataT *, DataT *>::type;
108
109 using PipelinePointerType =
110 typename std::conditional<is_const_iterator,
112
113 public:
114 friend class PipelineIterator<true>;
115 friend class Pipeline;
116
122 PipelineIterator(PipelinePointerType ptr) : pipelinePtr_(ptr) {}
123
130 PipelineIterator(PipelinePointerType ptr, uint32_t i) : pipelinePtr_(ptr), index_(i) {}
131
140 pipelinePtr_(rhs.pipelinePtr_),
141 index_(rhs.index_)
142 {
143 }
144
152 pipelinePtr_(rhs.pipelinePtr_),
153 index_(rhs.index_)
154 {
155 }
156
157
164
166 DataReferenceType operator*()
167 {
168 sparta_assert(isValid(), "Iterator is not valid for dereferencing!");
169 return pipelinePtr_->operator[](index_);
170 }
171
173 DataPointerType operator->()
174 {
175 sparta_assert(isValid(), "Iterator is not valid for dereferencing!");
176 return &(this->operator*());
177 }
178
181 {
182 index_++;
183 if (index_ > pipelinePtr_->capacity()) {
184 index_ = pipelinePtr_->capacity();
185 }
186 return *this;
187 }
188
191 {
192 PipelineIterator temp(*this);
193 this->operator++();
194 return temp;
195 }
196
198 bool operator==(const PipelineIterator & rhs) const
199 {
200 return ((pipelinePtr_ == rhs.pipelinePtr_) && (index_ == rhs.index_));
201 }
202
204 bool operator!=(const PipelineIterator & rhs) const { return !this->operator==(rhs); }
205
211 bool isValid() const { return pipelinePtr_->isValid(index_); }
212
213 private:
214 PipelinePointerType pipelinePtr_;
215 uint32_t index_ = 0;
216 };
217
218 using iterator = PipelineIterator<false>;
219 using const_iterator = PipelineIterator<true>;
220
221 iterator begin() { return iterator(this); }
222 const_iterator begin() const { return const_iterator(this); }
223 const_iterator cbegin() const { return const_iterator(this); }
224
225 iterator end() { return iterator(this, capacity()); }
226 const_iterator end() const { return const_iterator(this, capacity()); }
227 const_iterator cend() const { return const_iterator(this, capacity()); }
228
238 const std::string & name,
239 const uint32_t num_stages,
240 const Clock * clk) :
241 name_(name),
242 clock_(clk),
243 pipe_(name, num_stages, clk),
244 event_list_at_stage_(num_stages),
245 event_matrix_at_stage_(num_stages),
246 es_((es == nullptr) ? &dummy_es_ : es),
247 ev_pipeline_update_
248 (es_, name + "_update_event", CREATE_SPARTA_HANDLER(Pipeline, internalUpdate_), 1),
249 num_stages_(num_stages)
250 {
251 sparta_assert(clk != nullptr, "Pipeline requires a clock");
252 dummy_es_.setClock(clk);
253
254 // Only support the following Event types:
255 // 1. PhasedUniqueEvent
256 // 2. PhasedPayloadEvent<DataT>
257 static_assert(std::is_same_v<EventT, PhasedUniqueEvent> || std::is_same_v<EventT, PhasedPayloadEvent<DataT>>,
258 "Error: Pipeline is templated on a unsupported Event type. Supported Event types: "
259 "UniqueEvent, PayloaodEvent (where DataT == DataT of the Pipeline).");
260 events_valid_at_stage_.resize(num_stages, false);
261 advance_into_stage_.resize(num_stages, true);
262
263 ev_pipeline_update_.setScheduleableClock(clk);
264 ev_pipeline_update_.setScheduler(clk->getScheduler());
265 ev_pipeline_update_.setContinuing(false);
266 }
267
275 Pipeline(const std::string & name,
276 const uint32_t num_stages,
277 const Clock * clk) :
278 Pipeline(nullptr, name, num_stages, clk)
279 {}
280
292 template<SchedulingPhase sched_phase = SchedulingPhase::Tick>
293 void registerHandlerAtStage(const uint32_t & id, const SpartaHandler & handler)
294 {
295 sparta_assert(static_cast<uint32_t>(default_precedence_) == static_cast<uint32_t>(Precedence::NONE),
296 "You have specified a default precedence (" << static_cast<uint32_t>(default_precedence_)
297 << ") between stages. No new handlers can be registered any more!");
298 sparta_assert(id < event_list_at_stage_.size(),
299 "Attempt to register handler for invalid pipeline stage[" << id << "]!");
300
301 // Create a new stage event handler, and add it to its event list
302 auto & event_list = event_list_at_stage_[id];
303 if constexpr (std::is_same_v<EventT, PhasedPayloadEvent<DataT>>) {
304 sparta_assert(handler.argCount() == 1, "Expecting Sparta Handler with 1 data parameter!");
305 event_list.emplace_back(new EventT(es_,
306 "pev_" + name_ + "_stage_" + std::to_string(id) + "_" + std::to_string(event_list_at_stage_[id].size()),
307 sched_phase,
308 handler));
309 } else {
310 sparta_assert(handler.argCount() == 0, "Expecting Sparta Handler with no data parameter!");
311 event_list.emplace_back(new EventT(es_,
312 "uev_" + name_ + "_stage_" + std::to_string(id) + "_" + std::to_string(event_list_at_stage_[id].size()),
313 sched_phase,
314 handler));
315 }
316 auto new_event = event_list.back().get();
317
318 // Set clock for this new event handler
319 if constexpr (std::is_same_v<EventT, PhasedPayloadEvent<DataT>>) {
320 new_event->getScheduleable().setScheduleableClock(clock_);
321 new_event->getScheduleable().setScheduler(clock_->getScheduler());
322 } else {
323 new_event->setScheduleableClock(clock_);
324 new_event->setScheduler(clock_->getScheduler());
325 }
326
327 // Update event matrix
328 auto & event_list_per_phase = event_matrix_at_stage_[id][static_cast<uint32_t>(sched_phase)];
329 if (event_list_per_phase.size() > 0) {
330 auto & producer_event = event_list_per_phase.back();
331
332 // Set the latest registered event (in this 'sched_phase') to precedes this new event
333 if constexpr (std::is_same_v<EventT, PhasedPayloadEvent<DataT>>) {
334 producer_event->getScheduleable().precedes(new_event->getScheduleable());
335 } else {
336 producer_event->precedes(*new_event);
337 }
338 } else {
339 events_valid_at_stage_[id] = true;
340 }
341
342 // Add the raw pointer of newly added event to the stage event list on 'sched_phase'
343 event_list_per_phase.push_back( new_event );
344 }
345
354 void setPrecedenceBetweenStage(const uint32_t & pid, const uint32_t & cid)
355 {
356 sparta_assert(static_cast<uint32_t>(default_precedence_) == static_cast<uint32_t>(Precedence::NONE),
357 "You have specified a default precedence (" << static_cast<uint32_t>(default_precedence_)
358 << "). No more precedence between stages can be set!");
359 sparta_assert(pid != cid, "Cannot specify precedence with yourself!");
360 sparta_assert((pid < event_list_at_stage_.size()) && (event_list_at_stage_[pid].size() > 0),
361 "Precedence setup fails: No handler for pipeline stage[" << pid << "]!");
362 sparta_assert((cid < event_list_at_stage_.size()) && (event_list_at_stage_[cid].size() > 0),
363 "Precedence setup fails: No handler for pipeline stage[" << cid << "]!");
364
365 for (uint32_t phase_id = 0; phase_id < NUM_SCHEDULING_PHASES; phase_id++) {
366 auto & pstage_event_list = event_matrix_at_stage_[pid][phase_id];
367 auto & cstage_event_list = event_matrix_at_stage_[cid][phase_id];
368
369 if (pstage_event_list.empty() || cstage_event_list.empty()) {
370 continue;
371 }
372
373 // The last event in producer pipeline stage(#pid) is
374 // scheduled earlier than the first event in consumer
375 // pipeline stage(#cid)
376 if constexpr (std::is_same_v<EventT, PhasedPayloadEvent<DataT>>) {
377 (pstage_event_list.back())->getScheduleable().precedes((cstage_event_list.front())->getScheduleable());
378 } else {
379 (pstage_event_list.back())->precedes(*(cstage_event_list.front()));
380 }
381 }
382 }
383
391 template<class DataT2, class EventT2>
392 void setPrecedenceBetweenPipeline(const uint32_t & pid, Pipeline<DataT2, EventT2> & c_pipeline, const uint32_t & cid)
393 {
394 sparta_assert(static_cast<void*>(&c_pipeline) != static_cast<void*>(this),
395 "Cannot use this function to set precedence between stages within the same pipeline instance!");
396 sparta_assert((pid < event_list_at_stage_.size()) && (event_list_at_stage_[pid].size() > 0),
397 "Precedence setup fails: No handler for pipeline stage[" << pid << "]!");
398 sparta_assert((cid < c_pipeline.event_list_at_stage_.size()) && (c_pipeline.event_list_at_stage_[cid].size() > 0),
399 "Precedence setup fails: No handler for pipeline stage[" << cid << "]!");
400
401 for (uint32_t phase_id = 0; phase_id < NUM_SCHEDULING_PHASES; phase_id++) {
402 auto & pstage_event_list = event_matrix_at_stage_[pid][phase_id];
403 auto & cstage_event_list = c_pipeline.event_matrix_at_stage_[cid][phase_id];
404
405 if (pstage_event_list.empty() || cstage_event_list.empty()) {
406 continue;
407 }
408
409 // The last event in producer pipeline stage(#pid) is
410 // scheduled earlier than the first event in consumer
411 // pipeline stage(#cid)
412 if constexpr (std::is_same_v<EventT, PhasedPayloadEvent<DataT>>) {
413 (pstage_event_list.back())->getScheduleable().precedes((cstage_event_list.front())->getScheduleable());
414 } else {
415 (pstage_event_list.back())->precedes(*(cstage_event_list.front()));
416 }
417 }
418 }
419
425 void setDefaultStagePrecedence(const Precedence & default_precedence)
426 {
427 sparta_assert(static_cast<uint32_t>(default_precedence) < static_cast<uint32_t>(Precedence::NUM_OF_PRECEDENCE),
428 "Unknown default precedence is specified for sparta::Pipeline!");
429
430 if (static_cast<uint32_t>(default_precedence) == static_cast<uint32_t>(Precedence::NONE)) {
431 return;
432 }
433
434 bool forward = (static_cast<uint32_t>(default_precedence) == static_cast<uint32_t>(Precedence::FORWARD));
435
436 uint32_t pid = 0;
437 uint32_t cid = pid + 1;
438 while (cid < event_list_at_stage_.size()) {
439 if (event_list_at_stage_[pid].empty()) {
440 ++pid;
441 } else if (event_list_at_stage_[cid].empty()) {
442 ++cid;
443 } else {
444 if (forward) {
445 // This function can only be called when 'default_precedence_' is Precedence::NONE
447 } else {
449 }
450
451 // Skip the empty stages between producer and consumer to avoid duplicated checking
452 pid = cid;
453 }
454
455 if (pid == cid) {
456 ++cid;
457 }
458 }
459
460 default_precedence_ = default_precedence;
461 }
462
470 template<typename EventType>
471 void setProducerForPipelineUpdate(EventType & ev_handler)
472 {
473 auto phase = ev_handler.getScheduleable().getSchedulingPhase();
475 "Cannot set producer event for pipeline update event, it's not on the Update phase!");
476 ev_handler.getScheduleable().precedes(ev_pipeline_update_.getScheduleable());
477 }
478
486 template<typename EventType>
487 void setConsumerForPipelineUpdate(EventType & ev_handler)
488 {
489 auto phase = ev_handler.getScheduleable().getSchedulingPhase();
491 "Cannot set consumer event for pipeline update event, it's not on the Update phase!");
492 ev_pipeline_update_.getScheduleable().precedes(ev_handler.getScheduleable());
493 }
494
501 template<typename EventType>
502 void setProducerForStage(const uint32_t & id, EventType & ev_handler)
503 {
504 sparta_assert((id < event_list_at_stage_.size()) && (event_list_at_stage_[id].size() > 0),
505 "Precedence setup fails: No handler for pipeline stage[" << id << "]!");
506
507 auto phase_id = static_cast<uint32_t>(ev_handler.getScheduleable().getSchedulingPhase());
508 auto & event_list = event_matrix_at_stage_[id][phase_id];
509
510 sparta_assert(!event_list.empty(),
511 "Cannot set producer event for pipeline stage[" << id << "]. No registered stage event on the SAME phase!");
512 if constexpr (std::is_same_v<EventT, PhasedPayloadEvent<DataT>>) {
513 ev_handler.getScheduleable().precedes((event_list.front())->getScheduleable());
514 } else {
515 ev_handler.getScheduleable().precedes(*(event_list.front()));
516 }
517 }
518
525 template<typename EventType>
526 void setConsumerForStage(const uint32_t & id, EventType & ev_handler)
527 {
528 sparta_assert((id < event_list_at_stage_.size()) && (event_list_at_stage_[id].size() > 0),
529 "Precedence setup fails: No handler for pipeline stage[" << id << "]!");
530
531 auto phase_id = static_cast<uint32_t>(ev_handler.getScheduleable().getSchedulingPhase());
532 auto & event_list = event_matrix_at_stage_[id][phase_id];
533
534 sparta_assert(!event_list.empty(),
535 "Cannot set consumer event for pipeline stage[" << id
536 << "]. No registered stage event on the SAME phase!");
537 if constexpr (std::is_same_v<EventT, PhasedPayloadEvent<DataT>>) {
538 (event_list.back())->getScheduleable().precedes(ev_handler.getScheduleable());
539 } else {
540 (event_list.back())->precedes(ev_handler.getScheduleable());
541 }
542 }
543
550 EventList & getEventsAtStage(const uint32_t & id,
552 {
553 sparta_assert(id < event_matrix_at_stage_.size(),
554 "Attempt to get events at an invalid pipeline stage["
555 << id << "]!");
556 using SchedUType = std::underlying_type<SchedulingPhase>::type;
557 auto & event_list = event_matrix_at_stage_[id][static_cast<SchedUType>(phase)];
558 sparta_assert(!event_list.empty(),
559 "No registered events at stage[" << id << "]!");
560 return event_list;
561 }
562
573 bool isEventRegisteredAtStage(const uint32_t & id) const {
574 sparta_assert(id < event_list_at_stage_.size(),
575 "Attempt to check event handler for invalid pipeline stage[" << id << "]!");
576
577 return (event_list_at_stage_[id].size() > 0);
578 }
579
589 void activateEventAtStage(const uint32_t & id)
590 {
591 sparta_assert(id < event_list_at_stage_.size(),
592 "Attempt to activate event handler for invalid pipeline stage[" << id << "]!");
593 sparta_assert((event_list_at_stage_[id].size() > 0),
594 "Activation fails: No registered event handler for stage[" << id << "]!");
595
596 events_valid_at_stage_[id] = true;
597 }
598
607 void deactivateEventAtStage(const uint32_t & id)
608 {
609 sparta_assert(id < event_list_at_stage_.size(),
610 "Attempt to deactivate event handler for invalid pipeline stage[" << id << "]!");
611 sparta_assert((event_list_at_stage_[id].size() > 0),
612 "Deactivation fails: No registered event handler for stage[" << id << "]!");
613
614 events_valid_at_stage_[id] = false;
615 }
616
622 void append(const DataT & item)
623 {
624 appendImpl_(item);
625 }
626
632 void append(DataT && item)
633 {
634 return appendImpl_(std::move(item));
635 }
636
640 bool isAppended() const
641 {
642 return pipe_.isAppended();
643 }
644
649 const DataT& readAppendedData() const
650 {
651 return pipe_.readAppendedData();
652 }
653
660 void writeStage(const uint32_t & stage_id, const DataT & item)
661 {
662 writeStageImpl_(stage_id, item);
663 }
664
671 void writeStage(const uint32_t & stage_id, DataT && item)
672 {
673 writeStageImpl_(stage_id, std::move(item));
674 }
675
681 void invalidateStage(const uint32_t & stage_id)
682 {
683 pipe_.invalidatePS(stage_id);
684
685 if (perform_own_update_) {
686 ev_pipeline_update_.schedule();
687 }
688 }
689
699 void stall(const uint32_t & stall_stage_id,
700 const uint32_t & stall_cycles,
701 const bool crush_bubbles=false,
702 const bool suppress_events=true)
703 {
704 sparta_assert(pipe_.isValid(stall_stage_id), "Try to stall an empty pipeline stage!");
705 sparta_assert(!isStalledOrStalling(), "Try to stall a pipeline that is stalling or already stalled!");
706
707 if (stall_cycles == 0) {
708 return;
709 }
710
711 stall_cycles_ = stall_cycles;
712 stall_stage_id_ = stall_stage_id;
713 deactivate_(stall_stage_id_, crush_bubbles, suppress_events);
714 }
715
722 bool isStalledOrStalling() const {
723 return (stall_cycles_ > 0) || (stall_stage_id_ < std::numeric_limits<uint32_t>::max());
724 }
725
732 bool isStalledOrStallingAtStage(const uint32_t & stage_id) const {
733 return (isStalledOrStalling() && stage_id <= stall_stage_id_);
734 }
735
743 void flushStage(const uint32_t & flush_stage_id) {
744 cancelEventsAtStage_(flush_stage_id);
745
746 if (flush_stage_id == stall_stage_id_) {
748 restart_(stall_stage_id_);
749
750 stall_cycles_ = 0;
751 stall_stage_id_ = std::numeric_limits<uint32_t>::max();
752 }
753
754 pipe_.flushPS(flush_stage_id);
755 }
756
761 void flushStage(const const_iterator & const_iter) {
762 flushStage(const_iter.index_);
763 }
764
770 void flushStage(const iterator & iter) {
771 flushStage(iter.index_);
772 }
773
778 for (uint32_t stage_id = 0; stage_id < num_stages_; stage_id++) {
779 flushStage(stage_id);
780 }
781 }
782
786 void flushAppend() {
787 pipe_.flushAppend();
788 }
789
799 void setContinuing(const bool value) {
800 ev_pipeline_update_.setContinuing(value);
801 }
802
808 const DataT & operator[](const uint32_t & stage_id) const { return pipe_.read(stage_id); }
809
815 DataT & operator[](const uint32_t & stage_id) { return pipe_.access(stage_id); }
816
822 const DataT & at(const uint32_t & stage_id) const { return pipe_.read(stage_id); }
823
829 DataT & at(const uint32_t & stage_id) { return pipe_.access(stage_id); }
830
836 bool isValid(const uint32_t & stage_id) const { return pipe_.isValid(stage_id); }
837
839 bool isLastValid() const { return pipe_.isLastValid(); }
840
842 bool isAnyValid() const { return pipe_.isAnyValid(); }
843
845 uint32_t numValid() const { return pipe_.numValid(); }
846
848 bool empty() const { return (numValid() == 0); }
849
851 uint32_t size() const { return pipe_.size(); }
852
854 uint32_t capacity() const { return num_stages_; }
855
866 {
867 if (!perform_own_update_) {
868 perform_own_update_ = true;
869
870 if (pipe_.isAnyValid()) {
871 ev_pipeline_update_.schedule();
872 }
873 }
874 }
875
886 void update()
887 {
888 sparta_assert(perform_own_update_ == false, "You asked me to perform my own update!");
889
890 internalUpdate_();
891 }
892
902 template<SchedulingPhase phase = SchedulingPhase::Collection>
903 void enableCollection(TreeNode * parent) { pipe_.template enableCollection<phase>(parent); }
904
908 bool isCollected() const { return pipe_.isCollected(); }
909
910 private:
911 template<typename U>
912 void appendImpl_(U && item)
913 {
914 pipe_.append(std::forward<U>(item));
915
916 if (perform_own_update_) {
917 ev_pipeline_update_.schedule();
918 }
919 }
920
921 template<typename U>
922 void writeStageImpl_(const uint32_t & stage_id, U && item)
923 {
924 pipe_.writePS(stage_id, std::forward<U>(item));
925
926 if (perform_own_update_) {
927 ev_pipeline_update_.schedule();
928 }
929 }
930
932 void internalUpdate_()
933 {
934 if (!isStalledOrStalling()) {
935 pipe_.update();
936 scheduleEventForEachStage_();
937 } else {
938 drain_(stall_stage_id_ + 1);
939 scheduleEventForEachStage_();
940
941 --stall_cycles_;
942 if (stall_cycles_ == 0) {
943 restart_(stall_stage_id_);
944 stall_stage_id_ = std::numeric_limits<uint32_t>::max();
945 }
946 }
947
948 if (pipe_.isAnyValid() && perform_own_update_) {
949 ev_pipeline_update_.schedule();
950 }
951 }
952
954 void drain_(const uint32_t start_id)
955 {
956 uint32_t stage_id = num_stages_ - 1;
957
958 // remove last item from pipe
959 if (start_id <= stage_id && pipe_.isValid(stage_id)) {
960 pipe_.invalidatePS(stage_id);
961 }
962
963 // advance stages after stall point
964 while (stage_id > start_id) {
965 if (pipe_.isValid(stage_id - 1)) {
966 pipe_.writePS(stage_id, pipe_.access(stage_id - 1));
967 pipe_.invalidatePS(stage_id - 1);
968 }
969
970 --stage_id;
971 }
972
973 // check stages up to stall point for bubbles
974 // NOTE: stage_id now points to 1 past the stall point
975 // The stall point cannot advance because its events are disabled
976 // The stage before the stall cannot advance because the stall stage is occupied
977 // So, there are two useless loops here
978 while (stage_id > 0) {
979 if (advance_into_stage_[stage_id - 1] &&
980 !pipe_.isValid(stage_id) && pipe_.isValid(stage_id - 1)) {
981 pipe_.writePS(stage_id, pipe_.access(stage_id - 1));
982 pipe_.invalidatePS(stage_id - 1);
983 }
984
985 --stage_id;
986 }
987
988 // try advancement from insertion point
989 pipe_.shiftAppend();
990 }
991
997 void cancelEventsAtStage_(const uint32_t & stage_id)
998 {
999 sparta_assert(stage_id < num_stages_,
1000 "Try to cancel events for invalid pipeline stage[" << stage_id << "]");
1001 if (pipe_.isValid(stage_id) && events_valid_at_stage_[stage_id]) {
1002 sparta_assert(event_list_at_stage_[stage_id].size());
1003 for (const auto & ev_ptr : event_list_at_stage_[stage_id]) {
1004 ev_ptr->cancel(sparta::Clock::Cycle(0));
1005 }
1006 }
1007 }
1008
1010 void scheduleEventForEachStage_()
1011 {
1012 sparta_assert(num_stages_ == event_list_at_stage_.size());
1013
1014 for (uint32_t i = 0; i < num_stages_; i++) {
1015 if (pipe_.isValid(i) && events_valid_at_stage_[i]) {
1016 sparta_assert(event_list_at_stage_[i].size());
1017 for (const auto & ev_ptr : event_list_at_stage_[i]) {
1018 if constexpr (std::is_same_v<EventT, PhasedPayloadEvent<DataT>>) {
1019 ev_ptr->preparePayload(at(i))->schedule(sparta::Clock::Cycle(0));
1020 } else {
1021 ev_ptr->schedule(sparta::Clock::Cycle(0));
1022 }
1023 }
1024 }
1025 }
1026 }
1027
1029 void deactivate_(const uint32_t & stall_stage_id,
1030 const bool crush_bubbles,
1031 const bool suppress_events)
1032 {
1033 sparta_assert(stall_stage_id < num_stages_,
1034 "Try to deactivate events for invalid pipeline stage[" << stall_stage_id << "]");
1035
1036 for (int32_t stage_id = stall_stage_id; stage_id >= 0; stage_id--) {
1037
1038 if (crush_bubbles && !pipe_.isValid(stage_id)) {
1039 return; // bubble, crush it by allowing earlier stages to advance
1040 }
1041
1042 if (suppress_events && event_list_at_stage_[stage_id].size() > 0) {
1043 events_valid_at_stage_[stage_id] = false;
1044 }
1045 advance_into_stage_[stage_id] = false;
1046 }
1047 }
1048
1050 void restart_(const uint32_t & stall_stage_id)
1051 {
1052 for (uint32_t stage_id = 0; stage_id <= stall_stage_id; stage_id++) {
1053 sparta_assert(stage_id < num_stages_,
1054 "Try to restart invalid pipeline stage[" << stage_id << "]");
1055 if (event_list_at_stage_[stage_id].size() > 0) {
1056 events_valid_at_stage_[stage_id] = true;
1057 }
1058 advance_into_stage_[stage_id] = true;
1059 }
1060 }
1061
1063 const std::string name_;
1064
1066 const Clock * clock_;
1067
1069 sparta::Pipe<DataT> pipe_;
1070
1072 std::vector<EventHandleList> event_list_at_stage_;
1073 // NOTE:
1074 // (1) One advantage of using PhasedUniqueEvent instead of UnqiueEvent is:
1075 // The pipeline stage events could potentially be scheduled in different phases.
1076 // (2) Scheduleable also works, but EventNode doesn't work (no scheduleable)
1077 // std::vector<std::unique_ptr<Scheduleable>> event_list_at_stage_; // OK
1078 // std::vector<std::unique_ptr<EventNode>> event_list_at_stage_; // oops
1079
1081 std::vector<bool> events_valid_at_stage_;
1082 std::vector<bool> advance_into_stage_;
1083
1085 std::vector<EventMatrix> event_matrix_at_stage_;
1086
1088 sparta::EventSet dummy_es_{nullptr};
1089 sparta::EventSet * es_;
1090
1092 UniqueEvent<SchedulingPhase::Update> ev_pipeline_update_;
1093
1095 bool perform_own_update_ = false;
1096
1098 const uint32_t num_stages_ = 0;
1099
1101 Precedence default_precedence_ = Precedence::NONE;
1102
1104 uint32_t stall_cycles_ = 0;
1105
1107 uint32_t stall_stage_id_ = std::numeric_limits<uint32_t>::max();
1108 };
1109
1110}
File that defines the Clock class.
Defines a few handy (and now deprecated) C++ iterator traits.
File that defines the PhasedPayloadEvent class. Suggest using sparta::PayloadEvent instead.
File that defines the PhasedUniqueEvent class.
Defines the Pipe class.
File that defines the Scheduleable class.
Set of macros for Sparta assertions. Caught by the framework.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
File that contains the macro used to generate the class callbacks.
#define CREATE_SPARTA_HANDLER(clname, meth)
Specify the default event scheduling precedence between pipeline stages.
A representation of simulated time.
Definition Clock.hpp:51
Scheduler * getScheduler() const
Definition Clock.hpp:302
virtual Scheduleable & getScheduleable()=0
Get the scheduleable associated with this event node.
Set of Events that a unit (or sparta::TreeNode, sparta::Resource) contains and are visible through a ...
Definition EventSet.hpp:26
A very simple pipe, not part of the DES paradigm.
Definition Pipe.hpp:45
An iterator class for Pipeline class.
Definition Pipeline.hpp:102
PipelineIterator(const PipelineIterator< false > &rhs)
Copy constructor.
Definition Pipeline.hpp:139
DataPointerType operator->()
Override the dereferencing operator->
Definition Pipeline.hpp:173
PipelineIterator operator++(int)
Override the pre-increment operator.
Definition Pipeline.hpp:190
PipelineIterator operator++()
Override the pre-increment operator.
Definition Pipeline.hpp:180
PipelineIterator(const PipelineIterator< true > &rhs)
Copy constructor.
Definition Pipeline.hpp:151
PipelineIterator(PipelinePointerType ptr, uint32_t i)
Constructor.
Definition Pipeline.hpp:130
bool operator!=(const PipelineIterator &rhs) const
Override the comparison(not equal) operator.
Definition Pipeline.hpp:204
DataReferenceType operator*()
Override the dereferencing operator*.
Definition Pipeline.hpp:166
PipelineIterator(PipelinePointerType ptr)
Constructor.
Definition Pipeline.hpp:122
PipelineIterator & operator=(const PipelineIterator &rhs)=default
Copy assignment operator.
bool operator==(const PipelineIterator &rhs) const
Override the comparison(equal) operator.
Definition Pipeline.hpp:198
bool isValid() const
Check the validity of the iterator.
Definition Pipeline.hpp:211
A simple pipeline.
Definition Pipeline.hpp:63
bool isValid(const uint32_t &stage_id) const
Indicate the validity of a specific pipeline stage.
Definition Pipeline.hpp:836
void registerHandlerAtStage(const uint32_t &id, const SpartaHandler &handler)
Register event handler for a designated pipeline stage.
Definition Pipeline.hpp:293
void setPrecedenceBetweenStage(const uint32_t &pid, const uint32_t &cid)
Specify precedence between two different stages within the same pipeline instance.
Definition Pipeline.hpp:354
bool isAppended() const
Is the pipe already appended data?
Definition Pipeline.hpp:640
void deactivateEventAtStage(const uint32_t &id)
Deactivate event for a designated pipeline stage.
Definition Pipeline.hpp:607
bool isLastValid() const
Indicate the validity of the last pipeline stage.
Definition Pipeline.hpp:839
void setConsumerForStage(const uint32_t &id, EventType &ev_handler)
Specify consumer event for a designated pipeline stage.
Definition Pipeline.hpp:526
const DataT & readAppendedData() const
Get the data just appended; it will assert if no data appended.
Definition Pipeline.hpp:649
uint32_t capacity() const
Indicate the pipeline capacity.
Definition Pipeline.hpp:854
const DataT & at(const uint32_t &stage_id) const
Access (read-only) a specific stage of the pipeline.
Definition Pipeline.hpp:822
bool isCollected() const
Check if pipeline is collecting.
Definition Pipeline.hpp:908
void activateEventAtStage(const uint32_t &id)
Activate event for a designated pipeline stage.
Definition Pipeline.hpp:589
DataT & at(const uint32_t &stage_id)
Access a specific stage of the pipeline.
Definition Pipeline.hpp:829
void setProducerForPipelineUpdate(EventType &ev_handler)
Specify producer event for the pipeline update event.
Definition Pipeline.hpp:471
void writeStage(const uint32_t &stage_id, const DataT &item)
Modify a specific stage of the pipeline.
Definition Pipeline.hpp:660
void append(const DataT &item)
Append data to the beginning of the pipeline.
Definition Pipeline.hpp:622
void update()
Manually update pipeline (i.e. data-movement and event-scheduling)
Definition Pipeline.hpp:886
uint32_t numValid() const
Indicate the number of valid pipeline stages.
Definition Pipeline.hpp:845
Pipeline(const std::string &name, const uint32_t num_stages, const Clock *clk)
Construct a Pipeline object.
Definition Pipeline.hpp:275
void flushStage(const const_iterator &const_iter)
Flush a specific stage of the pipeline using const iterator.
Definition Pipeline.hpp:761
void flushAllStages()
Flush all stages of the pipeline.
Definition Pipeline.hpp:777
void setContinuing(const bool value)
set whether the update event is continuing or not
Definition Pipeline.hpp:799
void setConsumerForPipelineUpdate(EventType &ev_handler)
Specify consumer event for the pipeline update event.
Definition Pipeline.hpp:487
void performOwnUpdates()
Ask pipeline to perform its own update.
Definition Pipeline.hpp:865
void enableCollection(TreeNode *parent)
Enable pipeline collection.
Definition Pipeline.hpp:903
void setDefaultStagePrecedence(const Precedence &default_precedence)
Specify precedence of pipeline stage-handling events as forward/backward stage order.
Definition Pipeline.hpp:425
void stall(const uint32_t &stall_stage_id, const uint32_t &stall_cycles, const bool crush_bubbles=false, const bool suppress_events=true)
Stall the pipeline up to designated stage for a specified number of cycles.
Definition Pipeline.hpp:699
Pipeline(EventSet *es, const std::string &name, const uint32_t num_stages, const Clock *clk)
Construct a Pipeline object by existed event set.
Definition Pipeline.hpp:237
void flushStage(const uint32_t &flush_stage_id)
Flush a specific stage of the pipeline using stage id.
Definition Pipeline.hpp:743
EventList & getEventsAtStage(const uint32_t &id, const SchedulingPhase phase=SchedulingPhase::Tick)
Get events at a stage for a particular scheduling phase.
Definition Pipeline.hpp:550
void append(DataT &&item)
Append data to the beginning of the pipeline.
Definition Pipeline.hpp:632
void writeStage(const uint32_t &stage_id, DataT &&item)
Modify a specific stage of the pipeline.
Definition Pipeline.hpp:671
bool isStalledOrStallingAtStage(const uint32_t &stage_id) const
Check if the designated pipeline stage will be stalled the very next cycle.
Definition Pipeline.hpp:732
bool isEventRegisteredAtStage(const uint32_t &id) const
Check if any event is registered at a designated pipeline stage.
Definition Pipeline.hpp:573
void invalidateStage(const uint32_t &stage_id)
Invalidate a specific stage of the pipeline.
Definition Pipeline.hpp:681
bool empty() const
Indicate no valid pipeline stages.
Definition Pipeline.hpp:848
void flushAppend()
Flush the data just appended.
Definition Pipeline.hpp:786
void setPrecedenceBetweenPipeline(const uint32_t &pid, Pipeline< DataT2, EventT2 > &c_pipeline, const uint32_t &cid)
Specify precedence between two stages from different pipeline instances.
Definition Pipeline.hpp:392
uint32_t size() const
Indicate the pipeline size.
Definition Pipeline.hpp:851
const DataT & operator[](const uint32_t &stage_id) const
Access (read-only) a specific stage of the pipeline.
Definition Pipeline.hpp:808
bool isStalledOrStalling() const
Check if the pipeline will be stalled the very next cycle.
Definition Pipeline.hpp:722
bool isAnyValid() const
Indicate the validity of the whole pipeline.
Definition Pipeline.hpp:842
DataT & operator[](const uint32_t &stage_id)
Access a specific stage of the pipeline.
Definition Pipeline.hpp:815
void flushStage(const iterator &iter)
Flush a specific stage of the pipeline using non-const iterator.
Definition Pipeline.hpp:770
void setProducerForStage(const uint32_t &id, EventType &ev_handler)
Specify producer event for a designated pipeline stage.
Definition Pipeline.hpp:502
void setContinuing(bool continuing)
This event, if continuing == true, will keep the simulation running.
void setScheduler(Scheduler *sched)
Set the Scheduler of this Scheduleable, and set the local vertex_ to a new vertex from the Vertex Fac...
void precedes(Scheduleable &consumer, const std::string &reason="")
Have this Scheduleable precede another.
void setScheduleableClock(const Clock *clk)
Set the clock and scheduler of this Scheduleable.
Node in a composite tree representing a sparta Tree item.
Definition TreeNode.hpp:205
virtual void setClock(const Clock *clk)
Assigns a clock to this node. This clock will then be accessed by any descendant which has no assigne...
void schedule()
Schedule this event with its pre-set delay using the pre-set Clock.
Macros for handling exponential backoff.
const uint32_t NUM_SCHEDULING_PHASES
The number of phases.
SchedulingPhase
The SchedulingPhases used for events (Tick, Update, PortUpdate, etc)
@ Update
Resources are updated in this phase.
@ Tick
Most operations (combinational logic) occurs in this phase.