The Sparta Modeling Framework
Loading...
Searching...
No Matches
SyncPort.hpp
Go to the documentation of this file.
1// <SyncPort.h> -*- C++ -*-
2
71#pragma once
72
76#include "sparta/ports/Port.hpp"
79
80namespace sparta
81{
82
83 // Forward declaration
84 template<class DataT>
85 class SyncInPort;
86
111 template<class DataT>
112 class SyncOutPort final : public OutPort
113 {
115
116 public:
118 typedef DataT DataType;
119
130 SyncOutPort(TreeNode * portset, const std::string & name, const Clock * clk,
131 bool presume_zero_delay = true) :
132 OutPort(portset, name, presume_zero_delay),
133 clk_(clk), info_logger_(this, "pinfo", getLocation() + "_info")
134 {
135 sparta_assert(name.length() != 0, "You cannot have an unnamed port.");
136 sparta_assert(clk_ != 0, "Clock ptr cannot be null in port: " << name);
137
138 OutPort::sync_port_ = true; // prevent clock mismatch asserts
139 }
140
146 void bind(Port * in) override
147 {
148 SyncInPort<DataT> * inp;
149 if((inp = dynamic_cast<SyncInPort<DataT> *>(in)) == 0) {
150 throw SpartaException("ERROR: Attempt to bind SyncInPort of a disparate types: '" +
151 in->getLocation() + "' to '" + getLocation() + "'");
152 }
153
154 // Sync ports only support one binding for now.
155 sparta_assert(sync_in_port_ == 0, "Multiple bind attempts on port:" << getLocation());
156 sync_in_port_ = inp;
157 sparta_assert(sync_in_port_ != 0, "Cannot bind to null input port in:" << getLocation());
158
159 OutPort::bind(in);
160
161 bound_in_ports_.push_back(inp);
162 }
163
165 using Port::bind;
166
182 bool isReady() const {
183 sparta_assert(sync_in_port_ != 0, "isReady() check on unbound port:" << getLocation());
184 return sync_in_port_->couldAccept_(clk_);
185 }
186
192 bool isReadyPS() const {
193 sparta_assert(sync_in_port_ != 0, "isReadyPS() check on unbound port:" << getLocation());
194 return sync_in_port_->getRawReady_();
195 }
196
206 bool isDriven(Clock::Cycle rel_cycle) const override {
207 for(SyncInPort<DataT>* itr : bound_in_ports_) {
208 if(itr->isDriven(rel_cycle, clk_)) {
209 return true;
210 }
211 }
212 return false;
213 }
214
219 bool isDriven() const override {
220 for(SyncInPort<DataT>* itr : bound_in_ports_) {
221 if(itr->isDriven(clk_)) {
222 return true;
223 }
224 }
225 return false;
226 }
227
234 uint64_t send(const DataT & dat)
235 {
236 return send(dat,0,false);
237 }
238
246 uint64_t send(const DataT & dat, sparta::Clock::Cycle send_delay_cycles)
247 {
248 return send(dat, send_delay_cycles, false);
249 }
250
257 uint64_t sendAndAllowSlide(const DataT & dat)
258 {
259 return send(dat, 0, true);
260 }
261
272 uint64_t sendAndAllowSlide(const DataT & dat, sparta::Clock::Cycle send_delay_cycles)
273 {
274 return send(dat, send_delay_cycles, true);
275 }
276
290 uint64_t send(const DataT & dat, sparta::Clock::Cycle send_delay_cycles, const bool allow_slide)
291 {
292 sparta_assert(sync_in_port_ != 0, "Attempting to send data on unbound port:" << getLocation());
293 sparta_assert(clk_->isPosedge(), "Posedge check failed in port:" << getLocation());
294
295 Clock::Cycle send_cycle = computeNextAvailableCycleForSend(send_delay_cycles, 0);
296
297 if (SPARTA_EXPECT_FALSE(info_logger_)) {
298 info_logger_ << "SEND @" << send_cycle
299 << " allow_slide=" << allow_slide
300 << " # " << dat;
301 }
302 bool is_fwd_progress = true;
303 uint64_t sched_delay_ticks = sync_in_port_->send_(dat, clk_, send_delay_cycles,
304 allow_slide, is_fwd_progress);
305
306 if(SPARTA_EXPECT_FALSE(collector_ != nullptr)) {
307 collector_->collectWithDuration(dat, send_delay_cycles, 1);
308 }
309
310 sparta_assert(send_cycle > prev_data_send_cycle_ || prev_data_send_cycle_ == PREV_DATA_SEND_CYCLE_INIT, //init tick 0
312 << ": trying to send at cycle "
313 << send_cycle
314 << ", which is not later than the previous send cycle: "
315 << prev_data_send_cycle_
316 << "; SyncOutPorts are expected to send at most once per cycle");
317 prev_data_send_cycle_ = send_cycle;
318 return sched_delay_ticks;
319 }
320
330 Clock::Cycle computeNextAvailableCycleForSend(sparta::Clock::Cycle send_delay_cycles, const uint32_t num_beats)
331 {
332 sparta_assert(sync_in_port_ != 0, "Attempting to send data on unbound port:" << getLocation());
333 sparta_assert(clk_->isPosedge(), "Posedge check failed in port:" << getLocation());
334
335 // Start at the current clock with the specified delay
336 Clock::Cycle current_cycle = clk_->currentCycle();
337 Scheduler::Tick current_tick = clk_->currentTick();
338
339 // Send each beat of data with a slide, so know previous slide
340 Scheduler::Tick prev_data_arrival_tick =
341 sync_in_port_->getPrevDataArrivalTick_();
342
343 // Send one extra beat (<=) to represent the N+1 beat to be sent
344 for(uint32_t beat_count = 0; beat_count <= num_beats; ++beat_count) {
345 uint64_t sched_delay_ticks =
346 sync_in_port_->computeSendToReceiveTickDelay_(clk_,
347 send_delay_cycles + beat_count,
348 true /*allow_slide*/,
349 prev_data_arrival_tick);
350 prev_data_arrival_tick = current_tick + sched_delay_ticks;
351 }
352
353 // At this point, the prev_data_arrival_tick is the absolute
354 // tick at which an N+1 beat would arrive. Now, find when that
355 // would have been sent to have that arrival time.
356 uint64_t num_ticks_before_arrival =
357 sync_in_port_->computeReverseSendToReceiveTickDelay_(clk_,
358 send_delay_cycles,
359 prev_data_arrival_tick);
360 uint64_t send_tick = prev_data_arrival_tick - num_ticks_before_arrival;
361
362 // Convert the absolute tick of the send event into a current
363 // cycle relative cycle and return that value
364 Clock::Cycle next_send_cycle = clk_->getCycle(send_tick) + send_delay_cycles;
365 sparta_assert(next_send_cycle >= current_cycle);
366 return next_send_cycle;
367 }
368
369
371 SyncOutPort(const SyncOutPort &) = delete;
372
374 SyncOutPort & operator=(const SyncOutPort &) = delete;
375
377 void enableCollection(TreeNode* node) override {
378 collector_.reset(new CollectorType(node, Port::name_, 0,
379 "Data being sent out on this SyncOutPort"));
380 }
381
382 private:
383
385 const sparta::Clock * clk_ = nullptr;
386
388 SyncInPort<DataT> * sync_in_port_ = nullptr;
389
391 std::unique_ptr<CollectorType> collector_;
392
394 Clock::Cycle PREV_DATA_SEND_CYCLE_INIT = 0xffffffffffffffff; //init tick 0
395 Clock::Cycle prev_data_send_cycle_ = PREV_DATA_SEND_CYCLE_INIT; //init tick 0
396
398 sparta::log::MessageSource info_logger_;
399
401 std::vector <SyncInPort<DataT>*> bound_in_ports_;
402 };
403
404
410 template<class DataT>
411 class SyncInPort final : public InPort, public DataContainer<DataT>
412 {
414 public:
416 typedef DataT DataType;
417
426 SyncInPort(TreeNode* portset, const std::string & name, const Clock * clk,
428 InPort(portset, name, delivery_phase),
429 DataContainer<DataT>(clk),
430 sync_port_events_(this),
431 info_logger_(this, "pinfo", getLocation() + "_info")
432 {
435
436 sparta_assert(name.length() != 0, "You cannot have an unnamed port.");
437 sparta_assert(receiver_clock_ != 0, "Clock ptr cannot be null in port: " << name);
438
439 //sync_port_events_.setClock(clk);
440 forward_event_.reset(new PhasedPayloadEvent<DataT>
441 (&sync_port_events_, name + "_forward_event",
442 delivery_phase,
444 }
445
447 SyncInPort(const SyncInPort &) = delete;
448
450 SyncInPort & operator=(const SyncInPort &) = delete;
451
455 { }
456
462 void bind(Port * out) override
463 {
464 SyncOutPort<DataT> * outp;
465 if((outp = dynamic_cast<SyncOutPort<DataT> *>(out)) == 0) {
466 throw SpartaException("ERROR: Attempt to bind SyncOutPort of a disparate types: '" +
467 out->getLocation() + "' to '" + getLocation() + "'");
468 }
469 InPort::bind(out);
470 }
471
473 using Port::bind;
474
484 bool isDriven(Clock::Cycle rel_cycle) const override {
485 return forward_event_->isScheduled(rel_cycle);
486 }
487
493 bool isDriven() const override {
494 return forward_event_->isScheduled();
495 }
496
507 bool isDriven(Clock::Cycle rel_cycle, const Clock * send_clk) {
508 Scheduler::Tick num_delay_ticks =
509 computeSendToReceiveTickDelay_(send_clk, rel_cycle, false, prev_data_arrival_tick_);
510
512 sparta::Scheduler::Tick abs_scheduled_tick = num_delay_ticks + current_tick;
513
514 bool is_already_driven =
515 !( prev_data_arrival_tick_ < abs_scheduled_tick ||
516 prev_data_arrival_tick_ == PREV_DATA_ARRIVAL_TICK_INIT );
517
518 return is_already_driven;
519 }
520
527 bool isDriven(const Clock * send_clk) {
528 Scheduler::Tick num_delay_ticks =
529 computeSendToReceiveTickDelay_(send_clk, 0, false, prev_data_arrival_tick_);
530
532 sparta::Scheduler::Tick abs_scheduled_tick = num_delay_ticks + current_tick;
533
534 bool is_already_driven =
535 !( prev_data_arrival_tick_ < abs_scheduled_tick ||
536 prev_data_arrival_tick_ == PREV_DATA_ARRIVAL_TICK_INIT );
537
538 return is_already_driven;
539 }
540
545 Clock::Cycle getPortDelay() const final {
546 return receive_delay_cycles_;
547 }
548
553 void setPortDelay(sparta::Clock::Cycle delay_cycles) override {
554 sparta_assert(isBound() == false, "Attempt to set a port delay after binding. \n"
555 "This can adversely affect precedence rules. If possible call setPortDelay BEFORE\n"
556 "binding the port");
557 sparta_assert(delay_was_set_ == false,
558 "Attempt to set port delay twice (that's not expected) for: " << getLocation());
559 receive_delay_cycles_ = delay_cycles;
560 receive_delay_ticks_ = receiver_clock_->getTick(delay_cycles);
561 delay_was_set_ = true;
562 if (SPARTA_EXPECT_FALSE(info_logger_)) {
563 info_logger_ << "setPortDelay [cycles]: "
564 << " delay_cycles=" << delay_cycles
565 << " => receive_delay_ticks_=" << receive_delay_ticks_
566 << " receive_delay_cycles_=" << receive_delay_cycles_
567 << std::endl;
568 }
569 }
570
575 void setPortDelay(double delay_cycles) override {
576 sparta_assert(isBound() == false, "Attempt to set a port delay after binding. \n"
577 "This can adversely affect precedence rules. If possible call setPortDelay BEFORE\n"
578 "binding the port");
579 sparta_assert(delay_was_set_ == false,
580 "Attempt to set port delay twice (that's not expected) for: " << getLocation());
581 receive_delay_ticks_ = receiver_clock_->getTick(delay_cycles);
582 receive_delay_cycles_ = (receive_delay_ticks_ + (receiver_clock_->getPeriod() - 1)) / receiver_clock_->getPeriod();
583 delay_was_set_ = true;
584 if (SPARTA_EXPECT_FALSE(info_logger_)) {
585 info_logger_ << "setPortDelay [double]: "
586 << " delay_cycles=" << delay_cycles
587 << " => receive_delay_ticks_=" << receive_delay_ticks_
588 << " receive_delay_cycles_=" << receive_delay_cycles_
589 << std::endl;
590 }
591 }
592
594 void enableCollection(TreeNode* node) override
595 {
596 collector_.reset(new CollectorType(node, Port::name_, 0,
597 "Data being recirculated on this SyncInPort"));
598 }
599
601 void setInitialReadyState(bool is_ready) {
603 sparta_assert(scheduler_->getCurrentTick() == 0); //sched init 0
604 cur_is_ready_ = is_ready;
605 prev_is_ready_ = is_ready;
606 }
607
621 void setReady(bool is_ready) {
622 if (SPARTA_EXPECT_FALSE(info_logger_)) {
623 info_logger_ << "setting ready to: " << is_ready << "; num_in_flight = " << num_in_flight_ << "\n";
624 }
625
627 if (cur_tick > set_ready_tick_) {
628 set_ready_tick_ = cur_tick;
629 prev_is_ready_ = cur_is_ready_;
630 cur_is_ready_ = is_ready;
631 } else {
632 sparta_assert(cur_tick == set_ready_tick_,
633 "Unexpected set-ready in the past for: " << getLocation());
634 sparta_assert(is_ready == cur_is_ready_,
635 "Double-ready setting must be of the same value for: " << getLocation());
636 }
637
638
639 }
640
644 bool getReady() const {
645 return (cur_is_ready_);
646 }
647
650 void setContinuing(bool continuing) final {
651 Port::setContinuing(continuing);
652 forward_event_->setContinuing(continuing);
653 }
654
666 template<class ConsDataT, sparta::SchedulingPhase PhaseT>
668 {
669 sparta_assert(PhaseT >= forward_event_->getSchedulingPhase(),
670 "The phase of the PayloadEvent is less than this Port's -- you cannot "
671 "force the Port to come before the PayloadEvent due to this constraint");
672 if(PhaseT == forward_event_->getSchedulingPhase()) {
673 forward_event_->getScheduleable().
674 precedes(consumer.getScheduleable());
675 }
676 }
677
685 template<sparta::SchedulingPhase PhaseT>
687 {
688 sparta_assert(PhaseT >= forward_event_->getSchedulingPhase(),
689 "The phase of the PayloadEvent is less than this Port's -- you cannot "
690 "force the Port to come before the PayloadEvent due to this constraint");
691 if(PhaseT == forward_event_->getSchedulingPhase()) {
692 forward_event_->getScheduleable().precedes(consumer);
693 }
694 }
695
697 using InPort::precedes;
698
703 std::unique_ptr<PhasedPayloadEvent<DataT>> & getForwardingEvent() {
704 return forward_event_;
705 }
706
707 private:
708
709 Scheduleable & getScheduleable_() final {
710 return forward_event_->getScheduleable();
711 }
712
713 void setProducerPrecedence_(Scheduleable * pd) final {
714 if(pd->getSchedulingPhase() == forward_event_->getSchedulingPhase()) {
715 pd->precedes(forward_event_->getScheduleable(), "Port::bind of OutPort to " + getName() + ": '" +
716 pd->getLabel() + "' is a registered driver");
717 }
718 }
719
720 void registerConsumerHandler_(const SpartaHandler & handler) final
721 {
722 sparta_assert(handler.argCount() == 1,
723 "The handler associated with the SyncInPort must take at least one argument");
724
725 // Help the user identify their events/callbacks from the Scheduler debug
726 handler_name_ = getName() + "<SyncInPort>[" + explicit_consumer_handler_.getName() + "]";
727 forward_event_->getScheduleable().setLabel(handler_name_.c_str());
728 }
729
730 void bind_(Port * outp) override final
731 {
732 InPort::bind_(outp);
733 for(auto & consumer : port_consumers_)
734 {
735 if(consumer->getSchedulingPhase() == forward_event_->getSchedulingPhase()) {
736 forward_event_->getScheduleable().precedes(consumer, "Port::bind(" + getName() + "->" + outp->getName() + "),'"
737 + consumer->getLabel() + "' is registered driver");
738 }
739 }
740 }
741
752 bool getLatchedReady_(sparta::Scheduler::Tick cur_tick) const {
753 bool internal_ready = true;
754 if ((set_ready_tick_ == cur_tick && !prev_is_ready_) || // 'ready' was set this cycle and the previous value of 'ready' was false OR
755 (set_ready_tick_ < cur_tick && !cur_is_ready_)) // 'ready' was set in a previous cycle and the current value of 'ready' is false
756 {
757 internal_ready = false;
758 }
759 return internal_ready;
760 }
761
762 /*
763 * Return the actual, non-latched ready value.
764 */
765 bool getRawReady_() const {
767 "Only expected raw-ready to be returned for 0-cycle connections");
768 return cur_is_ready_;
769 }
770
778 void forwardData_(const DataT & dat)
779 {
780 sparta::Scheduler::Tick cur_tick =
782
783 sparta_assert(set_ready_tick_ <= cur_tick, "Assert in port: " << getLocation());
784
785 // If the owner of the Inport isn't ready, then re-send the
786 // data to ourself until the owner is ready to accept.
787 sparta_assert(num_in_flight_ > 0);
788 num_in_flight_--;
789 if (getLatchedReady_(cur_tick) == false) {
790 if (SPARTA_EXPECT_FALSE(info_logger_)) {
791 info_logger_ << "RESENDING @" << receiver_clock_->currentCycle()
792 << "(" << num_in_flight_ << ") "
793 << " # " << dat;
794 }
795 bool allow_slide = false;
796 bool is_fwd_progress = false;
797
798 send_(dat, receiver_clock_, sparta::Clock::Cycle(1), allow_slide, is_fwd_progress);
799 sparta_assert(num_in_flight_ > 0);
800 }
801
802 // Else, forward the data to the original handler
803 else {
805
806 // Always call the consumer_handler BEFORE scheduling
807 // listeners.
809 explicit_consumer_handler_((const void*)&dat);
810 }
811
812 // Show the data that has arrived on this OutPort that
813 // the receiver now sees
814 if(SPARTA_EXPECT_FALSE(collector_ != nullptr)) {
815 collector_->collectWithDuration(dat, 1);
816 }
817
818 if (SPARTA_EXPECT_FALSE(info_logger_)) {
819 info_logger_ << "DELIVERING @" << receiver_clock_->currentCycle()
820 << "(" << num_in_flight_ << ") "
821 << " # " << dat;
822 }
823 }
824 }
825
827 sparta::EventSet sync_port_events_;
828
830 std::unique_ptr<PhasedPayloadEvent<DataT>> forward_event_;
831
834
836 friend uint64_t SyncOutPort<DataT>::send(const DataT &, uint64_t, const bool);
837
839 friend bool SyncOutPort<DataT>::isReady() const;
840
842 friend bool SyncOutPort<DataT>::isReadyPS() const;
843
847 friend uint64_t SyncOutPort<DataT>::computeNextAvailableCycleForSend(sparta::Clock::Cycle, const uint32_t);
848
856 bool couldAccept_(const Clock *send_clk) const {
857
858 Scheduler::Tick num_delay_ticks =
859 calculateClockCrossingDelay(send_clk->currentTick(), send_clk, receive_delay_ticks_, receiver_clock_);
860
861 sparta::Scheduler::Tick cur_tick =
863
864 sparta::Scheduler::Tick abs_scheduled_tick =
865 num_delay_ticks + cur_tick;
866
867 bool retval = (abs_scheduled_tick > prev_data_arrival_tick_ || prev_data_arrival_tick_ == PREV_DATA_ARRIVAL_TICK_INIT);
868
869 sparta_assert(cur_tick >= set_ready_tick_, "Someone drove setReady() in the future in" << getLocation());
870
871 // Check for sync-port ready/valid backpressure and override
872 // 'ready' if downstream indicated it couldn't take data
873 if (getLatchedReady_(cur_tick) == false) {
874 sparta_assert(send_clk->getFrequencyMhz() == receiver_clock_->getFrequencyMhz(), "Error in port:" << getLocation());
875 sparta_assert(getPortDelay() == 1 || getPortDelay() == 0,
876 "Ready/Valid only tested for zero and one cycle delays (not "<< getPortDelay() <<"); relax this assert once more testing is done; location=" << getLocation());
877
878 // Can't accept anything if there's already one request
879 // waiting to be delivered OR if this is a 0-cycle delay
880 // (since we need to deliver on the same cycle its sent)
881 if (num_in_flight_ > 0 || getPortDelay() == 0) {
882 retval = false;
883 }
884 }
885
886 return retval;
887 }
888
894 Scheduler::Tick getPrevDataArrivalTick_() const
895 {
896 return prev_data_arrival_tick_;
897 }
898
908 uint64_t computeSendToReceiveTickDelay_(const Clock *send_clk,
909 const double send_delay_cycles,
910 const bool allow_slide,
911 const Scheduler::Tick prev_data_arrival_tick) const
912 {
913 Scheduler::Tick num_delay_ticks =
914 calculateClockCrossingDelay(send_clk->getTick(send_delay_cycles), send_clk, receive_delay_ticks_, receiver_clock_);
915
917 sparta::Scheduler::Tick abs_scheduled_tick = num_delay_ticks + current_tick;
918
919 // Slide pushes this send out past the previous arrival,
920 // rather than faulting as user error on sending too early
921 if (allow_slide &&
922 ( abs_scheduled_tick <= prev_data_arrival_tick &&
923 prev_data_arrival_tick != PREV_DATA_ARRIVAL_TICK_INIT)) {
924 abs_scheduled_tick = prev_data_arrival_tick + receiver_clock_->getPeriod();
925 }
926
927 num_delay_ticks = abs_scheduled_tick - current_tick;
928
929 // Underlying assumption is that all destinations get their
930 // event at the same time.
931 sparta_assert((abs_scheduled_tick % receiver_clock_->getPeriod()) == 0, "Failed posedge check in:" << getLocation()); // posedge check
932
933 return num_delay_ticks;
934 }
935
936
945 uint64_t computeReverseSendToReceiveTickDelay_(const Clock *send_clk,
946 const double send_delay_cycles,
947 const Scheduler::Tick data_arrival_tick) const
948 {
949 sparta::Scheduler::Tick raw_dst_clk_posedge_tick =
950 data_arrival_tick / receiver_clock_->getPeriod() * receiver_clock_->getPeriod();
951 sparta_assert(data_arrival_tick == raw_dst_clk_posedge_tick);
952
953 Scheduler::Tick num_delay_ticks =
954 calculateReverseClockCrossingDelay(data_arrival_tick,
955 send_clk->getTick(send_delay_cycles),
956 send_clk, receive_delay_ticks_, receiver_clock_);
957
958 sparta_assert( data_arrival_tick >= num_delay_ticks );
959 return num_delay_ticks;
960 }
961
963 void bind_(SyncOutPort<DataT> * inp) {
964 bound_ports_.push_back(inp);
965 }
966
976 uint64_t send_(const DataT & dat, const Clock *send_clk, Clock::Cycle send_delay_cycles,
977 const bool allow_slide, bool is_fwd_progress)
978 {
979 return send_(dat, send_clk, static_cast<double>(send_delay_cycles), allow_slide, is_fwd_progress);
980 }
981
991 uint64_t send_(const DataT & dat, const Clock *send_clk, double send_delay_cycles,
992 const bool allow_slide, bool is_fwd_progress)
993 {
994 Scheduler::Tick num_delay_ticks =
995 computeSendToReceiveTickDelay_(send_clk, send_delay_cycles, allow_slide, prev_data_arrival_tick_);
996
998 sparta::Scheduler::Tick abs_scheduled_tick = num_delay_ticks + current_tick;
999
1000 // Underlying assumption is that all destinations get their
1001 // event at the same time.
1002 sparta_assert((abs_scheduled_tick % receiver_clock_->getPeriod()) == 0, "Failed posedge check in:" << getLocation()); // posedge check
1003
1004 if (SPARTA_EXPECT_FALSE(info_logger_)) {
1005 info_logger_ << "RECEIVE SCHEDULED @" << receiver_clock_->getCycle(abs_scheduled_tick)
1006 << "(" << num_in_flight_ << ") "
1007 << " # " << dat;
1008 }
1009
1010 // Only one item can be received per cycle
1011 sparta_assert(prev_data_arrival_tick_ < abs_scheduled_tick || prev_data_arrival_tick_ == PREV_DATA_ARRIVAL_TICK_INIT,
1012 getLocation() << ": attempt to schedule send for tick "
1013 << abs_scheduled_tick
1014 << ", which is not later than the previous data at tick "
1015 << prev_data_arrival_tick_
1016 << "; SyncInPorts should only get data once per cycle; data was: " << dat);
1017
1018 prev_data_arrival_tick_ = abs_scheduled_tick;
1019
1020 if(num_delay_ticks == 0) {
1021 checkSchedulerPhaseForZeroCycleDelivery_(forward_event_->getSchedulingPhase());
1022 }
1023 forward_event_->preparePayload(dat)->scheduleRelativeTick(num_delay_ticks, scheduler_);
1024 num_in_flight_++;
1025
1026 if (SPARTA_EXPECT_TRUE(is_fwd_progress && is_continuing_)) {
1028 }
1029
1030 return num_delay_ticks;
1031 }
1032
1033
1034 private:
1035
1037 std::string handler_name_;
1038
1041 bool delay_was_set_ = false;
1042 Clock::Cycle receive_delay_cycles_ = 0;
1043 sparta::Scheduler::Tick receive_delay_ticks_ = 0;
1044
1046 const Scheduler::Tick PREV_DATA_ARRIVAL_TICK_INIT = 0xffffffffffffffff;
1047 Scheduler::Tick prev_data_arrival_tick_ = PREV_DATA_ARRIVAL_TICK_INIT;
1048
1050 bool cur_is_ready_ = true;
1051 bool prev_is_ready_ = true;
1052
1054 bool is_continuing_ = true;
1055
1057 uint32_t num_in_flight_ = 0;
1058
1061 Scheduler::Tick set_ready_tick_ = 0;
1062
1064 std::unique_ptr<CollectorType> collector_;
1065
1067 sparta::log::MessageSource info_logger_;
1068 };
1069}
1070
File that defines the DataContainer class.
Implementation of the DelayedCollectable class that allows a user to collect an object into an pipeVi...
File that defines the EventSet class.
File that defines the Port base class.
File that defines Precedence operator>> rules between EventNode types.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
#define SPARTA_EXPECT_TRUE(x)
A macro for hinting to the compiler a particular condition should be considered most likely true.
#define SPARTA_EXPECT_FALSE(x)
A macro for hinting to the compiler a particular condition should be considered most likely false.
#define CREATE_SPARTA_HANDLER_WITH_DATA(clname, meth, dataT)
Basic Node framework in sparta device tree composite pattern.
A representation of simulated time.
Definition Clock.hpp:51
Cycle currentCycle() const
Get the current cycle (uses current tick from the Scheduler)
Definition Clock.hpp:176
Scheduler::Tick currentTick() const
Get the current scheduler tick.
Definition Clock.hpp:185
Period getPeriod() const
Returns the period of this clock in scheduler ticks.
Definition Clock.hpp:156
double getFrequencyMhz() const
Get the clock frequency.
Definition Clock.hpp:115
Scheduler * getScheduler() const
Definition Clock.hpp:302
Scheduler::Tick getTick(const Cycle &cycle) const
Return the tick corresponding to the given cycle.
Definition Clock.hpp:214
bool isPosedge() const
Return true if the current tick aligns with a positive edge of this Clock.
Definition Clock.hpp:247
Cycle getCycle(const Scheduler::Tick &tick) const
Given the tick, convert to a Clock::Cycle.
Definition Clock.hpp:166
Used by DataInPort and SyncInPort, this class holds received data from these ports and remembers the ...
void setData_(const DataT &dat)
Set the data received.
Set of Events that a unit (or sparta::TreeNode, sparta::Resource) contains and are visible through a ...
Definition EventSet.hpp:26
Base class for all InPort types.
Definition Port.hpp:297
Scheduler * scheduler_
The scheduler used.
Definition Port.hpp:481
void bind(Port *out) override
Bind to an OutPort.
Definition Port.hpp:386
void checkSchedulerPhaseForZeroCycleDelivery_(const sparta::SchedulingPhase &user_callback_phase)
Common method for checking phasing.
Definition Port.hpp:456
void precedes(InPort &consumer)
Ensure data entering this Port is handled before data on another.
Definition Port.hpp:421
virtual void bind_(Port *outp)
Called by the OutPort, remember the binding.
Definition Port.hpp:451
ScheduleableList port_consumers_
Definition Port.hpp:478
const Clock * receiver_clock_
The receiving clock.
Definition Port.hpp:484
Base class for all OutPort types.
Definition Port.hpp:493
void bind(Port *in) override
Bind to an InPort.
Definition Port.hpp:575
bool sync_port_
Is this port a syncport?
Definition Port.hpp:653
Class to schedule a Scheduleable in the future with a payload, typed on both the data type and the sc...
Class to schedule a Scheduleable in the future with a payload, but the class itself is not typed on t...
Scheduleable & getScheduleable() override
Get the scheduleable associated with this event node.
The port interface used to bind port types together and defines a port behavior.
Definition Port.hpp:59
const std::string name_
The name of this port.
Definition Port.hpp:282
std::vector< Port * > bound_ports_
List of bound ports.
Definition Port.hpp:285
virtual bool isBound() const
Is this port bound to another port?
Definition Port.hpp:126
virtual void bind(Port *port)=0
Method to bind this Port to another, pointer style.
SpartaHandler explicit_consumer_handler_
Explicit consumer handler registered via registerConsumerHandler.
Definition Port.hpp:288
virtual void setContinuing(bool continuing)
Definition Port.hpp:218
A class that defines the basic scheduling interface to the Scheduler. Not intended to be used by mode...
Tick getCurrentTick() const noexcept
The current tick the Scheduler is working on or just finished.
bool isRunning() const noexcept
Query if the scheduler is running.
void kickTheDog() noexcept
Reset the watchdog timer.
uint64_t Tick
Typedef for our unit of time.
Used to construct and throw a standard C++ exception. Inherits from std::exception.
Class that defines an synchronized input port on modules on two different clocks.
Definition SyncPort.hpp:412
void setPortDelay(sparta::Clock::Cycle delay_cycles) override
Set the port delay associated with this port.
Definition SyncPort.hpp:553
bool isDriven(const Clock *send_clk)
Is this Port driven at all?
Definition SyncPort.hpp:527
void setPortDelay(double delay_cycles) override
Set the port delay associated with this port.
Definition SyncPort.hpp:575
void precedes(PayloadEvent< ConsDataT, PhaseT > &consumer)
Ensure data entering this Port is handled before a payload is delivered.
Definition SyncPort.hpp:667
bool isDriven(Clock::Cycle rel_cycle) const override
Determine if this SyncInPort is driven on the given cycle.
Definition SyncPort.hpp:484
bool isDriven(Clock::Cycle rel_cycle, const Clock *send_clk)
Determine if this SyncInPort is driven on the given cycle.
Definition SyncPort.hpp:507
void setInitialReadyState(bool is_ready)
Set the ready state for the port before simulation begins.
Definition SyncPort.hpp:601
void bind(Port *out) override
Bind to an SyncOutPort.
Definition SyncPort.hpp:462
DataT DataType
Expected typedef for DataT.
Definition SyncPort.hpp:416
std::unique_ptr< PhasedPayloadEvent< DataT > > & getForwardingEvent()
Return the internal forwarding event.
Definition SyncPort.hpp:703
bool isDriven() const override
Is this Port driven at all?
Definition SyncPort.hpp:493
void setReady(bool is_ready)
Definition SyncPort.hpp:621
void setContinuing(bool continuing) final
Definition SyncPort.hpp:650
bool getReady() const
Definition SyncPort.hpp:644
SyncInPort(const SyncInPort &)=delete
No making copies.
void precedes(UniqueEvent< PhaseT > &consumer)
Ensure data entering this Port is handled before the given UniqueEvent.
Definition SyncPort.hpp:686
Clock::Cycle getPortDelay() const final
Get the port delay associated with this port.
Definition SyncPort.hpp:545
SyncInPort(TreeNode *portset, const std::string &name, const Clock *clk, sparta::SchedulingPhase delivery_phase=sparta::SchedulingPhase::PortUpdate)
Create an SyncInPort with the given name.
Definition SyncPort.hpp:426
void enableCollection(TreeNode *node) override
Enable pipeline collection.
Definition SyncPort.hpp:594
SyncInPort & operator=(const SyncInPort &)=delete
No assignments.
Class that defines a synchronized SyncOutPort for data writes on different clocks.
Definition SyncPort.hpp:113
SyncOutPort & operator=(const SyncOutPort &)=delete
No making assignments!
SyncOutPort(const SyncOutPort &)=delete
No making copies!
uint64_t send(const DataT &dat, sparta::Clock::Cycle send_delay_cycles, const bool allow_slide)
Send data on the output port.
Definition SyncPort.hpp:290
void bind(Port *in) override
Bind to an SyncInPort.
Definition SyncPort.hpp:146
bool isDriven() const override
Does this SyncOutPort have any SyncInPort's where the data is not yet delivered?
Definition SyncPort.hpp:219
uint64_t sendAndAllowSlide(const DataT &dat)
Send data on the output port and allow slide.
Definition SyncPort.hpp:257
bool isReadyPS() const
Definition SyncPort.hpp:192
uint64_t sendAndAllowSlide(const DataT &dat, sparta::Clock::Cycle send_delay_cycles)
Send data on the output port. In case of a conflict (multiple packets scheduled to be received within...
Definition SyncPort.hpp:272
bool isDriven(Clock::Cycle rel_cycle) const override
Determine if this SyncOutPort has any connected SyncInPort where the data is to be delivered on the g...
Definition SyncPort.hpp:206
uint64_t send(const DataT &dat)
Send data on the output port.
Definition SyncPort.hpp:234
SyncOutPort(TreeNode *portset, const std::string &name, const Clock *clk, bool presume_zero_delay=true)
Construct a synchronized output port.
Definition SyncPort.hpp:130
DataT DataType
A typedef for the type of data this port passes.
Definition SyncPort.hpp:118
Clock::Cycle computeNextAvailableCycleForSend(sparta::Clock::Cycle send_delay_cycles, const uint32_t num_beats)
Compute the next available relative cycle for sending data, assuming all of the specified number of b...
Definition SyncPort.hpp:330
bool isReady() const
Definition SyncPort.hpp:182
uint64_t send(const DataT &dat, sparta::Clock::Cycle send_delay_cycles)
Send data on the output port.
Definition SyncPort.hpp:246
void enableCollection(TreeNode *node) override
Enable pipeline collection.
Definition SyncPort.hpp:377
Node in a composite tree representing a sparta Tree item.
Definition TreeNode.hpp:205
std::string getLocation() const override final
const Clock * getClock() override
Walks up parents (starting with self) until a parent with an associated local clock is found,...
const std::string & getName() const override
Gets the name of this node.
A type of Event that uniquely schedules itself on the schedule within a single time quantum....
Class used to either manually or auto-collect an Annotation String object in a pipeline database.
Class used to record data in pipeline collection, but recorded in a delayed fashion.
Message source object associated with a sparta TreeNode through which messages can be sent.
Macros for handling exponential backoff.
SchedulingPhase
The SchedulingPhases used for events (Tick, Update, PortUpdate, etc)
@ PortUpdate
N-cycle Ports are updated in this phase.