The Sparta Modeling Framework
Loading...
Searching...
No Matches
Precedence.hpp
Go to the documentation of this file.
1// <Precedence.hpp> -*- C++ -*-
2
3#pragma once
4
5#include <type_traits>
6
7#include "sparta/utils/MetaStructs.hpp"
13#include "sparta/events/GlobalOrderingPoint.hpp"
14#include "sparta/ports/Port.hpp"
15#include "sparta/ports/Bus.hpp"
16
24namespace sparta
25{
27
104
106 // GOP -> EventNode types
108
136 template<class ScheduleableTypeA>
137 typename std::enable_if<std::is_base_of<EventNode, ScheduleableTypeA>::value, const GlobalOrderingPoint>::
138 type & operator>>(ScheduleableTypeA & producer, const GlobalOrderingPoint & consumer)
139 {
140 producer.getScheduleable().precedes(*consumer.getGOPoint());
141 return consumer;
142 }
143
171 template<class ScheduleableTypeA>
172 typename std::enable_if<std::is_base_of<EventNode, ScheduleableTypeA>::value, ScheduleableTypeA>::
173 type & operator>>(const GlobalOrderingPoint & producer, ScheduleableTypeA & consumer)
174 {
175 producer.getGOPoint()->precedes(consumer.getScheduleable());
176 return consumer;
177 }
178
206 inline InPort & operator>>(const GlobalOrderingPoint & producer, InPort & consumer) {
207 producer.getGOPoint()->precedes(consumer.getScheduleable_());
208 return consumer;
209 }
210
238 inline const GlobalOrderingPoint & operator>>(InPort & producer, const GlobalOrderingPoint & consumer) {
239 producer.getScheduleable_().precedes(*consumer.getGOPoint());
240 return consumer;
241 }
242
243#ifndef DO_NOT_DOCUMENT
244#define __SPARTA_PHASE_ERROR_MSG \
245 "\nERROR: You cannot set a precedence on two Scheduleable types" \
246 " that are on different phases. This will happen automatically by the framework."
247#endif
248
250 // Start with easy, concrete, derived types
252
254 // payloadevent_precedence PayloadEvent Precedence
255 // Examples of PayloadEvent precedence
256 //
257 // PayloadEvent<T, P> >> PayloadEvent<T, P>;
258 // PayloadEvent<T, P> >> UniqueEvent<P>;
259 // PayloadEvent<T, P> >> SingleCycleUniqueEvent<P>;
260 // PayloadEvent<T, P> >> Event<P>;
261 // UniqueEvent<P> >> PayloadEvent<T, P>;
262 // SingleCycleUniqueEvent<P> >> PayloadEvent<T, P>;
263 // Event<P> >> PayloadEvent<T, P>;
264 //
265
293 template<class DataT1, SchedulingPhase PayloadPhaseT1,
294 class DataT2, SchedulingPhase PayloadPhaseT2>
297 {
298 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
299 producer.getScheduleable().precedes(consumer.getScheduleable());
300 return consumer;
301 }
302
330 template<class DataT1,
331 SchedulingPhase PayloadPhaseT1,
332 SchedulingPhase PayloadPhaseT2>
335 {
336 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
337 producer.getScheduleable().precedes(consumer.getScheduleable());
338 return consumer;
339 }
340
368 template<class DataT1,
369 SchedulingPhase PayloadPhaseT1,
370 SchedulingPhase PayloadPhaseT2>
373 {
374 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
375 producer.getScheduleable().precedes(consumer.getScheduleable());
376 return consumer;
377 }
378
406 template<class DataT1,
407 SchedulingPhase PayloadPhaseT1,
408 SchedulingPhase PayloadPhaseT2>
410 Event<PayloadPhaseT2> & consumer)
411 {
412 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
413 producer.getScheduleable().precedes(consumer.getScheduleable());
414 return consumer;
415 }
416
444 template<SchedulingPhase PayloadPhaseT1,
445 class DataT2,
446 SchedulingPhase PayloadPhaseT2>
449 {
450 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
451 producer.precedes(consumer.getScheduleable());
452 return consumer;
453 }
454
482 template<SchedulingPhase PayloadPhaseT1,
483 class DataT2,
484 SchedulingPhase PayloadPhaseT2>
487 {
488 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
489 producer.precedes(consumer.getScheduleable());
490 return consumer;
491 }
492
520 template<SchedulingPhase PayloadPhaseT1,
521 class DataT2,
522 SchedulingPhase PayloadPhaseT2>
525 {
526 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
527 producer.precedes(consumer.getScheduleable());
528 return consumer;
529 }
530
532 // UniqueEvent Precedence
533 //
534 // UniqueEvent<P> >> UniqueEvent<P>;
535 // UniqueEvent<P> >> SingleCycleUniqueEvent<P>;
536 // SingleCycleUniqueEvent<P> >> UniqueEvent<P>;
537 //
538
566 template<SchedulingPhase PayloadPhaseT1,
567 SchedulingPhase PayloadPhaseT2>
570 {
571 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
572 producer.precedes(consumer.getScheduleable());
573 return consumer;
574 }
575
603 template<SchedulingPhase PayloadPhaseT1,
604 SchedulingPhase PayloadPhaseT2>
607 {
608 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
609 producer.precedes(consumer.getScheduleable());
610 return consumer;
611 }
612
640 template<SchedulingPhase PayloadPhaseT1,
641 SchedulingPhase PayloadPhaseT2>
644 {
645 static_assert(PayloadPhaseT1 == PayloadPhaseT2, __SPARTA_PHASE_ERROR_MSG);
646 producer.precedes(consumer.getScheduleable());
647 return consumer;
648 }
649
651 // SingleCycleUniqueEvent Precedence
652 //
680 template<SchedulingPhase PhaseT1, SchedulingPhase PhaseT2>
683 {
684 static_assert(PhaseT1 == PhaseT2, __SPARTA_PHASE_ERROR_MSG);
685 producer.getScheduleable().precedes(consumer.getScheduleable());
686 return consumer;
687 }
688
690 // Event Precedence
691 //
719 template<SchedulingPhase PhaseT1, SchedulingPhase PhaseT2>
721 {
722 static_assert(PhaseT1 == PhaseT2, __SPARTA_PHASE_ERROR_MSG);
723 producer.precedes(consumer.getScheduleable());
724 return consumer;
725 }
726
728 // // Unique Ptrs
729 // std::unique_ptr<eventT> >> std::unique_ptr<eventT>;
730 // std::unique_ptr<eventT> >> concrete_event;
731 // std::unique_ptr<eventT> >> event_pointer;
732 // concrete_event >> std::unique_ptr<eventT>;
733 // event_pointer >> std::unique_ptr<eventT>;
734
762 template<class EventT1, class EventT2>
763 std::unique_ptr<EventT2> & operator>>(std::unique_ptr<EventT1> & producer,
764 std::unique_ptr<EventT2> & consumer)
765 {
766 (*producer) >> (*consumer);
767 return consumer;
768 }
769
797 template<class EventT1, class EventT2>
798 std::unique_ptr<EventT2> & operator>>(EventT1 & producer, std::unique_ptr<EventT2> & consumer)
799 {
800 producer >> (*consumer);
801 return consumer;
802 }
803
831 template<class EventT1, class EventT2>
832 EventT2 & operator>>(std::unique_ptr<EventT1> & producer, EventT2 & consumer)
833 {
834 (*producer) >> consumer;
835 return consumer;
836 }
837
839 // Scheduleable <-> PayloadEvent
841
869 template<class DataT2, SchedulingPhase phase>
872 {
873 sparta_assert(producer.getSchedulingPhase() == consumer.getSchedulingPhase(),
874 __SPARTA_PHASE_ERROR_MSG);
875 producer.precedes(consumer.getScheduleable());
876 return consumer;
877 }
878
906 template<class DataT1, SchedulingPhase phase>
908 Scheduleable & consumer)
909 {
910 sparta_assert(consumer.getSchedulingPhase() == producer.getSchedulingPhase(),
911 __SPARTA_PHASE_ERROR_MSG);
912 producer.getScheduleable().precedes(consumer);
913 return consumer;
914 }
915
917 // Bus Support
919
920 // This is where an event must be scheduled before any events
921 // scheduled as a results of OutPorts on the Bus.
922
950 template<class ScheduleableType>
951 typename
952 std::enable_if<std::is_base_of<Scheduleable, ScheduleableType>::value, Bus>::
953 type & operator>>(ScheduleableType & producer, Bus & consumer)
954 {
955 consumer.outportsSucceed(producer);
956 return consumer;
957 }
958
959 // This is where an event must be scheduled after data arrival on
960 // InPorts within the Bus:
961 //
962 // my_incoming_bus >> ev_tick;
963 //
964
992 template<class ScheduleableType>
993 typename
994 std::enable_if<std::is_base_of<Scheduleable, ScheduleableType>::value, ScheduleableType>::
995 type & operator>>(Bus & producer, ScheduleableType & consumer)
996 {
997 producer.inportsPrecede(consumer);
998 return consumer;
999 }
1000
1002 // Add support for a group of event types
1004
1041 class EventGroup : public std::vector<Scheduleable *>
1042 {
1043 // Make sure no one is adding a Port in the mix (this was the
1044 // old framework)
1045 template<SchedulingPhase phase, class ScheduleableT, class ...ArgsT>
1046 typename std::enable_if<std::is_base_of<Port, ScheduleableT>::value, void>::
1047 type addScheduable_(ScheduleableT & /*port*/, ArgsT&... /*scheds*/) {
1048 static_assert(std::is_base_of<Port, ScheduleableT>::value,
1049 "\nERROR: You cannot set up a precedence between an Scheduleable type and a Port. "
1050 "\n\tIf you want to do this, register the Scheduleable with the Port using the "
1051 "registerConsumerEvent/registerProducingEvent method on the Port."
1052 "\n\tSee the SPARTA documentation for more information."
1053 "\n\tBTW, in this particular error, there is a Port type in the EventGroup that's bad");
1054 }
1055
1056 // Add a Scheduable type, not a PayloadEventType
1057 template<SchedulingPhase phase, class ScheduleableT, class ...ArgsT>
1058 typename std::enable_if<std::is_base_of<sparta::Scheduleable, ScheduleableT>::value, void>::
1059 type addScheduable_(ScheduleableT & sched, ArgsT&... scheds) {
1060 static_assert(phase == ScheduleableT::event_phase,
1061 "\nERROR: You cannot set a precedence on two Scheduleable types"
1062 " that are on different phases. This will happen automatically by the framework."
1063 "\n\tIn this particular error, there is a Scheduleable type in the EventGroup that's bad");
1064 emplace_back(&sched);
1065 addScheduable_<ScheduleableT::event_phase>(scheds...);
1066 }
1067
1068 // Need a specialization for PayloadEvents since they are not direct Scheduleables
1069 template<SchedulingPhase phase, class DataT, SchedulingPhase PLEPhase, class ...ArgsT>
1070 void addScheduable_(PayloadEvent<DataT, PLEPhase> & sched, ArgsT&... scheds) {
1071 static_assert(phase == PLEPhase,
1072 "\nERROR: You cannot set a precedence on two Scheduleable types"
1073 " that are on different phases. This will happen automatically by the framework."
1074 "\n\tIn this particular error, there is a PayloadEvent type in the EventGroup that's bad");
1075 emplace_back(&sched.getScheduleable());
1076 addScheduable_<PLEPhase>(scheds...);
1077 }
1078
1079 // end of list
1080 template<SchedulingPhase phase>
1081 void addScheduable_() {}
1082
1083 public:
1084
1098 template<class ScheduleableT, class ...ArgsT>
1099 explicit EventGroup(ScheduleableT & sched, ArgsT&...scheds) {
1100 static_assert(std::is_same<Port, ScheduleableT>::value == false,
1101 "\nERROR: You cannot add Ports to a precedence group as Ports do not support precedence. "
1102 "If you have a zero-cycle Port and a receiving event, register that event with the Port instead."
1103 "\n\tIn this particular error, there is a Port type in the EventGroup that's bad");
1104 static_assert(std::is_same<Bus, ScheduleableT>::value == false,
1105 "\nERROR: You cannot add a Bus to a precedence group as Buses do not support precedence directly. "
1106 "\n\tInstead, use Bus' inportsPrecede(event) or outportsSucceed(event) methods OR the >> operator.");
1107 addScheduable_<ScheduleableT::event_phase>(sched, scheds...);
1108 }
1109
1123 template<class DataT, SchedulingPhase PhaseT, class ...ArgsT>
1124 explicit EventGroup(PayloadEvent<DataT, PhaseT> & sched, ArgsT&...scheds) {
1125 addScheduable_<PhaseT>(sched, scheds...);
1126 }
1127
1128 };
1129
1143 template<class ScheduleableTypeB>
1144 ScheduleableTypeB & operator>>(const EventGroup & producers,
1145 ScheduleableTypeB & consumer)
1146 {
1147 for(auto & prod : producers) {
1148 prod->precedes(consumer);
1149 }
1150 return consumer;
1151 }
1152
1164 template<class ScheduleableTypeA>
1165 const EventGroup & operator>>(ScheduleableTypeA & producer,
1166 const EventGroup & consumers)
1167 {
1168 for(auto & cons : consumers) {
1169 producer.precedes(*cons);
1170 }
1171 return consumers;
1172 }
1173
1188 inline const EventGroup & operator>>(const EventGroup & producers,
1189 const EventGroup & consumers)
1190 {
1191 for(auto & prod : producers) {
1192 for(auto & cons : consumers) {
1193 sparta_assert(prod->getSchedulingPhase() == cons->getSchedulingPhase(),
1194 "The scheduling phase of '"
1195 << prod->getLabel() << "' phase '" << prod->getSchedulingPhase()
1196 << "' does not equal the scheduling phase of '"
1197 << cons->getLabel() << "' phase '" << cons->getSchedulingPhase()
1198 <<"'");
1199
1200 prod->precedes(cons);
1201 }
1202 }
1203 return consumers;
1204 }
1205
1206}
File that defines the Bus, BusSet and helper binding classes.
File that defines the Event class.
File that defines the PayloadEvent class.
File that defines the Port base class.
File that defines the Scheduleable class.
File that defines the SingleCycleUniqueEvent class.
#define sparta_assert(...)
Simple variadic assertion that will throw a sparta_exception if the condition fails.
File that defines the UniqueEvent class.
Class that defines a Bus type.
Definition Bus.hpp:46
void inportsPrecede(EventT &event)
Make all inports precede the given event.
Definition Bus.hpp:194
void outportsSucceed(EventT &event)
Make all outports succeed the given event.
Definition Bus.hpp:209
Group a series of events together for precedence establishment.
EventGroup(ScheduleableT &sched, ArgsT &...scheds)
Construct the EventGroup.
EventGroup(PayloadEvent< DataT, PhaseT > &sched, ArgsT &...scheds)
Construct the EventGroup.
sparta::SchedulingPhase getSchedulingPhase() const
Get the scheduling phase of this event node.
Definition EventNode.hpp:93
virtual Scheduleable & getScheduleable()=0
Get the scheduleable associated with this event node.
Event is a simple class for scheduling random events on the Scheduler.
Definition Event.hpp:42
Scheduleable & getScheduleable() override
Get the scheduleable associated with this event node.
Definition Event.hpp:111
Used to set precedence between Scheduleable types across simulation.
DAG::GOPoint * getGOPoint() const
Used by the precedence rules.
Base class for all InPort types.
Definition Port.hpp:297
virtual Scheduleable & getScheduleable_()=0
Return the internally used Scheduleable for precedence.
Class to schedule a Scheduleable in the future with a payload, typed on both the data type and the sc...
Scheduleable & getScheduleable() override
Get the scheduleable associated with this event node.
void precedes(ScheduleableT &consumer, const std::string &reason="")
Have this SingleCycleUniqueEvent precede another.
A class that defines the basic scheduling interface to the Scheduler. Not intended to be used by mode...
void precedes(Scheduleable &consumer, const std::string &reason="")
Have this Scheduleable precede another.
SchedulingPhase getSchedulingPhase() const
Get the internal phase number.
An event that can only be schedule one cycle into the future.
A type of Event that uniquely schedules itself on the schedule within a single time quantum....
Macros for handling exponential backoff.
std::enable_if< std::is_base_of< EventNode, ScheduleableTypeA >::value, constGlobalOrderingPoint >::type & operator>>(ScheduleableTypeA &producer, const GlobalOrderingPoint &consumer)
Place a precedence between a Scheduleable object and a GlobalOrderingPoint.
SchedulingPhase
The SchedulingPhases used for events (Tick, Update, PortUpdate, etc)