The Sparta Modeling Framework
|
This page, coupled with the Sparta FAQ can help the modeler develop, debug, contribute and understand how to use Sparta effectively.
Sparta provides a nifty error dumping/handling mechanism triggered when a model throws a C++ exception. By default, when the framework encounters a C++ exception, it will generate a file called error-dump.txt. See 3.7 Post-Run Debug dumps for more information.
The make best use of this functionality, consider using sparta_assert whenever possible to catch errors.
Sparta defines a set of macros called SPARTA_EXPECT_TRUE and SPARTA_EXPECT_FALSE that help tell the compiler expected behavior for a condition. This enables the compiler to put the common execution path inline for best performance. A best practice is to use these macros for logging messages since they are rarely turned on during full simulation.
Since Sparta requires the use of a C++17 compiler, take advantage of the C++17 features. This can help reduce errors and clean up code immensely. As an example, try to initialized as many components directly in the header file of the class. Look at example/CoreExample/src/Dispatch.hpp in the CoreExample for examples on how to do this.
In this section, Sparta phases and general model flow will be discussed/illustrated.
Communication between resources in a user's model occurs via Ports. In SystemC, Ports are used as a mechanism to exchange interfaces between blocks, but in Sparta, Ports are used to exchange data and signals at given time intervals. This follows a cohesive pattern allowing any component to bind to another as long as it understands the shared data type.
A typical modeled block using Sparta looks like the following, with each phase following the next phase in the order listed.
Phase | Intended Use |
---|---|
Construction phase (only once): | Construction, ports and events registered |
Update phase (runtime): | Updating of internal resources (sparta::Pipe for example) |
PortUpdate phase (runtime): | Port delivery of Data (N-cycle ports) |
Flush phase (runtime): | Flushing |
Collection phase (runtime): | Collection Events |
Tick phase (runtime): | Operating Logic/Events |
PostTick phase (runtime): | Operating Logic/Events to process after main logic |
where "Updating of internal resources" are Event objects scheduled/fired that were created in the sparta::SchedulingPhase::Update phase:
"Port delivery of Data" are handlers called that were registered with a Port that has an N-cycle delay:
and "Operating Logic/Events" are those sparta::Event objects that were created in the sparta::SchedulingPhase::Tick phase:
Construction occurs first and only once. During this "phase" the modeler should add sparta::Event, sparta::Port, and sparta::Counter objects to the base class sparta::Unit's sets:
The framework will automatically set precedence between Events (sparta::Event) and Ports (sparta::Port) registered in the sparta::Unit EventSet (sparta::EventSet) and PortSet (sparta::PortSet). However, the framework will not set precedence between events defined directly in the block. I.e. if there is an event called my_first_event_
created in the sparta::SchedulingPhase::Tick phase, and another event called my_second_event_
also created in the sparta::SchedulingPhase::Tick phase, the order in which these events are scheduled is random (however, deterministic between simulation runs of the same binary) unless a precedence is established:
Automatic precedence establishment can be disabled by calling the method sparta::Resource::setAutoPrecedence(false) in the constructor of MyBlock.
After the block is instantiated and the simulator is now running, events will be scheduled based on established operations.
Simulation will terminate when there are no more continuing (see sparta::Scheduleable::setContinuing) events scheduled for execution.