111 template<
class DataT>
131 bool presume_zero_delay =
true) :
132 OutPort(portset, name, presume_zero_delay),
133 clk_(clk), info_logger_(this,
"pinfo",
getLocation() +
"_info")
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);
150 throw SpartaException(
"ERROR: Attempt to bind SyncInPort of a disparate types: '" +
161 bound_in_ports_.push_back(inp);
184 return sync_in_port_->couldAccept_(clk_);
194 return sync_in_port_->getRawReady_();
206 bool isDriven(Clock::Cycle rel_cycle)
const override {
208 if(itr->isDriven(rel_cycle, clk_)) {
221 if(itr->isDriven(clk_)) {
234 uint64_t
send(
const DataT & dat)
236 return send(dat,0,
false);
246 uint64_t
send(
const DataT & dat, sparta::Clock::Cycle send_delay_cycles)
248 return send(dat, send_delay_cycles,
false);
259 return send(dat, 0,
true);
274 return send(dat, send_delay_cycles,
true);
290 uint64_t
send(
const DataT & dat, sparta::Clock::Cycle send_delay_cycles,
const bool allow_slide)
298 info_logger_ <<
"SEND @" << send_cycle
299 <<
" allow_slide=" << allow_slide
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);
307 collector_->collectWithDuration(dat, send_delay_cycles, 1);
310 sparta_assert(send_cycle > prev_data_send_cycle_ || prev_data_send_cycle_ == PREV_DATA_SEND_CYCLE_INIT,
312 <<
": trying to send at 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;
341 sync_in_port_->getPrevDataArrivalTick_();
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,
349 prev_data_arrival_tick);
350 prev_data_arrival_tick = current_tick + sched_delay_ticks;
356 uint64_t num_ticks_before_arrival =
357 sync_in_port_->computeReverseSendToReceiveTickDelay_(clk_,
359 prev_data_arrival_tick);
360 uint64_t send_tick = prev_data_arrival_tick - num_ticks_before_arrival;
364 Clock::Cycle next_send_cycle = clk_->
getCycle(send_tick) + send_delay_cycles;
366 return next_send_cycle;
379 "Data being sent out on this SyncOutPort"));
391 std::unique_ptr<CollectorType> collector_;
394 Clock::Cycle PREV_DATA_SEND_CYCLE_INIT = 0xffffffffffffffff;
395 Clock::Cycle prev_data_send_cycle_ = PREV_DATA_SEND_CYCLE_INIT;
401 std::vector <SyncInPort<DataT>*> bound_in_ports_;
410 template<
class DataT>
428 InPort(portset, name, delivery_phase),
430 sync_port_events_(this),
431 info_logger_(this,
"pinfo",
getLocation() +
"_info")
436 sparta_assert(name.length() != 0,
"You cannot have an unnamed port.");
441 (&sync_port_events_, name +
"_forward_event",
466 throw SpartaException(
"ERROR: Attempt to bind SyncOutPort of a disparate types: '" +
484 bool isDriven(Clock::Cycle rel_cycle)
const override {
485 return forward_event_->isScheduled(rel_cycle);
494 return forward_event_->isScheduled();
509 computeSendToReceiveTickDelay_(send_clk, rel_cycle,
false, prev_data_arrival_tick_);
514 bool is_already_driven =
515 !( prev_data_arrival_tick_ < abs_scheduled_tick ||
516 prev_data_arrival_tick_ == PREV_DATA_ARRIVAL_TICK_INIT );
518 return is_already_driven;
529 computeSendToReceiveTickDelay_(send_clk, 0,
false, prev_data_arrival_tick_);
534 bool is_already_driven =
535 !( prev_data_arrival_tick_ < abs_scheduled_tick ||
536 prev_data_arrival_tick_ == PREV_DATA_ARRIVAL_TICK_INIT );
538 return is_already_driven;
546 return receive_delay_cycles_;
555 "This can adversely affect precedence rules. If possible call setPortDelay BEFORE\n"
558 "Attempt to set port delay twice (that's not expected) for: " <<
getLocation());
559 receive_delay_cycles_ = delay_cycles;
561 delay_was_set_ =
true;
563 info_logger_ <<
"setPortDelay [cycles]: "
564 <<
" delay_cycles=" << delay_cycles
565 <<
" => receive_delay_ticks_=" << receive_delay_ticks_
566 <<
" receive_delay_cycles_=" << receive_delay_cycles_
577 "This can adversely affect precedence rules. If possible call setPortDelay BEFORE\n"
580 "Attempt to set port delay twice (that's not expected) for: " <<
getLocation());
583 delay_was_set_ =
true;
585 info_logger_ <<
"setPortDelay [double]: "
586 <<
" delay_cycles=" << delay_cycles
587 <<
" => receive_delay_ticks_=" << receive_delay_ticks_
588 <<
" receive_delay_cycles_=" << receive_delay_cycles_
597 "Data being recirculated on this SyncInPort"));
604 cur_is_ready_ = is_ready;
605 prev_is_ready_ = is_ready;
623 info_logger_ <<
"setting ready to: " << is_ready <<
"; num_in_flight = " << num_in_flight_ <<
"\n";
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;
633 "Unexpected set-ready in the past for: " <<
getLocation());
635 "Double-ready setting must be of the same value for: " <<
getLocation());
645 return (cur_is_ready_);
652 forward_event_->setContinuing(continuing);
666 template<
class ConsDataT, sparta::SchedulingPhase PhaseT>
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().
685 template<sparta::SchedulingPhase PhaseT>
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);
704 return forward_event_;
710 return forward_event_->getScheduleable();
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");
720 void registerConsumerHandler_(
const SpartaHandler & handler)
final
723 "The handler associated with the SyncInPort must take at least one argument");
727 forward_event_->getScheduleable().setLabel(handler_name_.c_str());
730 void bind_(Port * outp)
override final
735 if(consumer->getSchedulingPhase() == forward_event_->getSchedulingPhase()) {
736 forward_event_->getScheduleable().precedes(consumer,
"Port::bind(" +
getName() +
"->" + outp->getName() +
"),'"
737 + consumer->getLabel() +
"' is registered driver");
753 bool internal_ready =
true;
754 if ((set_ready_tick_ == cur_tick && !prev_is_ready_) ||
755 (set_ready_tick_ < cur_tick && !cur_is_ready_))
757 internal_ready =
false;
759 return internal_ready;
765 bool getRawReady_()
const {
767 "Only expected raw-ready to be returned for 0-cycle connections");
768 return cur_is_ready_;
778 void forwardData_(
const DataT & dat)
789 if (getLatchedReady_(cur_tick) ==
false) {
792 <<
"(" << num_in_flight_ <<
") "
795 bool allow_slide =
false;
796 bool is_fwd_progress =
false;
798 send_(dat,
receiver_clock_, sparta::Clock::Cycle(1), allow_slide, is_fwd_progress);
815 collector_->collectWithDuration(dat, 1);
820 <<
"(" << num_in_flight_ <<
") "
830 std::unique_ptr<PhasedPayloadEvent<DataT>> forward_event_;
856 bool couldAccept_(
const Clock *send_clk)
const {
865 num_delay_ticks + cur_tick;
867 bool retval = (abs_scheduled_tick > prev_data_arrival_tick_ || prev_data_arrival_tick_ == PREV_DATA_ARRIVAL_TICK_INIT);
873 if (getLatchedReady_(cur_tick) ==
false) {
876 "Ready/Valid only tested for zero and one cycle delays (not "<<
getPortDelay() <<
"); relax this assert once more testing is done; location=" <<
getLocation());
896 return prev_data_arrival_tick_;
908 uint64_t computeSendToReceiveTickDelay_(
const Clock *send_clk,
909 const double send_delay_cycles,
910 const bool allow_slide,
914 calculateClockCrossingDelay(send_clk->getTick(send_delay_cycles), send_clk, receive_delay_ticks_,
receiver_clock_);
922 ( abs_scheduled_tick <= prev_data_arrival_tick &&
923 prev_data_arrival_tick != PREV_DATA_ARRIVAL_TICK_INIT)) {
927 num_delay_ticks = abs_scheduled_tick - current_tick;
933 return num_delay_ticks;
945 uint64_t computeReverseSendToReceiveTickDelay_(
const Clock *send_clk,
946 const double send_delay_cycles,
951 sparta_assert(data_arrival_tick == raw_dst_clk_posedge_tick);
954 calculateReverseClockCrossingDelay(data_arrival_tick,
955 send_clk->getTick(send_delay_cycles),
959 return num_delay_ticks;
963 void bind_(SyncOutPort<DataT> * inp) {
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)
979 return send_(dat, send_clk,
static_cast<double>(send_delay_cycles), allow_slide, is_fwd_progress);
991 uint64_t send_(
const DataT & dat,
const Clock *send_clk,
double send_delay_cycles,
992 const bool allow_slide,
bool is_fwd_progress)
995 computeSendToReceiveTickDelay_(send_clk, send_delay_cycles, allow_slide, prev_data_arrival_tick_);
1006 <<
"(" << num_in_flight_ <<
") "
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);
1018 prev_data_arrival_tick_ = abs_scheduled_tick;
1020 if(num_delay_ticks == 0) {
1023 forward_event_->preparePayload(dat)->scheduleRelativeTick(num_delay_ticks,
scheduler_);
1030 return num_delay_ticks;
1037 std::string handler_name_;
1041 bool delay_was_set_ =
false;
1042 Clock::Cycle receive_delay_cycles_ = 0;
1046 const Scheduler::Tick PREV_DATA_ARRIVAL_TICK_INIT = 0xffffffffffffffff;
1047 Scheduler::Tick prev_data_arrival_tick_ = PREV_DATA_ARRIVAL_TICK_INIT;
1050 bool cur_is_ready_ =
true;
1051 bool prev_is_ready_ =
true;
1054 bool is_continuing_ =
true;
1057 uint32_t num_in_flight_ = 0;
1064 std::unique_ptr<CollectorType> collector_;
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.
Cycle currentCycle() const
Get the current cycle (uses current tick from the Scheduler)
Scheduler::Tick currentTick() const
Get the current scheduler tick.
Period getPeriod() const
Returns the period of this clock in scheduler ticks.
double getFrequencyMhz() const
Get the clock frequency.
Scheduler * getScheduler() const
Scheduler::Tick getTick(const Cycle &cycle) const
Return the tick corresponding to the given cycle.
bool isPosedge() const
Return true if the current tick aligns with a positive edge of this Clock.
Cycle getCycle(const Scheduler::Tick &tick) const
Given the tick, convert to a Clock::Cycle.
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 ...
Base class for all InPort types.
Scheduler * scheduler_
The scheduler used.
void bind(Port *out) override
Bind to an OutPort.
void checkSchedulerPhaseForZeroCycleDelivery_(const sparta::SchedulingPhase &user_callback_phase)
Common method for checking phasing.
void precedes(InPort &consumer)
Ensure data entering this Port is handled before data on another.
virtual void bind_(Port *outp)
Called by the OutPort, remember the binding.
ScheduleableList port_consumers_
const Clock * receiver_clock_
The receiving clock.
Base class for all OutPort types.
void bind(Port *in) override
Bind to an InPort.
bool sync_port_
Is this port a syncport?
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.
const std::string name_
The name of this port.
std::vector< Port * > bound_ports_
List of bound ports.
virtual bool isBound() const
Is this port bound to another port?
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.
virtual void setContinuing(bool continuing)
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.
void setPortDelay(sparta::Clock::Cycle delay_cycles) override
Set the port delay associated with this port.
bool isDriven(const Clock *send_clk)
Is this Port driven at all?
void setPortDelay(double delay_cycles) override
Set the port delay associated with this port.
void precedes(PayloadEvent< ConsDataT, PhaseT > &consumer)
Ensure data entering this Port is handled before a payload is delivered.
bool isDriven(Clock::Cycle rel_cycle) const override
Determine if this SyncInPort is driven on the given cycle.
bool isDriven(Clock::Cycle rel_cycle, const Clock *send_clk)
Determine if this SyncInPort is driven on the given cycle.
void setInitialReadyState(bool is_ready)
Set the ready state for the port before simulation begins.
void bind(Port *out) override
Bind to an SyncOutPort.
DataT DataType
Expected typedef for DataT.
std::unique_ptr< PhasedPayloadEvent< DataT > > & getForwardingEvent()
Return the internal forwarding event.
bool isDriven() const override
Is this Port driven at all?
void setReady(bool is_ready)
void setContinuing(bool continuing) final
SyncInPort(const SyncInPort &)=delete
No making copies.
void precedes(UniqueEvent< PhaseT > &consumer)
Ensure data entering this Port is handled before the given UniqueEvent.
Clock::Cycle getPortDelay() const final
Get the port delay associated with this port.
SyncInPort(TreeNode *portset, const std::string &name, const Clock *clk, sparta::SchedulingPhase delivery_phase=sparta::SchedulingPhase::PortUpdate)
Create an SyncInPort with the given name.
void enableCollection(TreeNode *node) override
Enable pipeline collection.
SyncInPort & operator=(const SyncInPort &)=delete
No assignments.
Class that defines a synchronized SyncOutPort for data writes on different clocks.
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.
void bind(Port *in) override
Bind to an SyncInPort.
bool isDriven() const override
Does this SyncOutPort have any SyncInPort's where the data is not yet delivered?
uint64_t sendAndAllowSlide(const DataT &dat)
Send data on the output port and allow slide.
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...
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...
uint64_t send(const DataT &dat)
Send data on the output port.
SyncOutPort(TreeNode *portset, const std::string &name, const Clock *clk, bool presume_zero_delay=true)
Construct a synchronized output port.
DataT DataType
A typedef for the type of data this port passes.
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...
uint64_t send(const DataT &dat, sparta::Clock::Cycle send_delay_cycles)
Send data on the output port.
void enableCollection(TreeNode *node) override
Enable pipeline collection.
Node in a composite tree representing a sparta Tree item.
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.