19#include "sparta/utils/MathUtils.hpp"
20#include "sparta/collection/IterableCollector.hpp"
43template <
typename DataT>
54 uint32_t getPhysicalStage_ (int32_t stage)
const
57 return (tail_ + stage) & stage_mask_;
60 void initPipe_(uint32_t num_entries)
62 sparta_assert(num_entries > 0,
"ERROR: sparta::Pipe '" << name_
63 <<
"' Cannot be created with 0 stages");
64 num_entries_ = num_entries;
65 physical_size_ = sparta::utils::pow2 (sparta::utils::ceil_log2 (num_entries + 1));
66 stage_mask_ = physical_size_ - 1;
67 pipe_.reset(
new PipeEntry[physical_size_]);
78 template <
bool is_const_iterator = true>
81 typedef typename std::conditional<is_const_iterator,
83 value_type &>::type DataReferenceType;
85 typedef typename std::conditional<is_const_iterator,
89 DataReferenceType getAccess_(std::false_type) {
90 return pipe_->access(index_);
94 DataReferenceType getAccess_(std::true_type) {
95 return pipe_->read(index_);
111 PipeIterator(PipePointerType pipe, uint32_t index) : pipe_(pipe), index_(index) {}
123 return getAccess_(std::integral_constant<bool, is_const_iterator>());
135 if(++index_ > pipe_->capacity()) {
136 index_ = pipe_->capacity();
150 return ((pipe_ == it.pipe_) && (index_ == it.index_));
160 return pipe_->isValid(index_);
164 PipePointerType pipe_;
191 Pipe (
const Pipe <DataT> &) =
delete;
203 Pipe (
const std::string & name,
204 uint32_t num_entries,
207 ev_update_(&es_, name+
"_pipe_update_event",
210 initPipe_(num_entries);
235 perform_own_updates_ =
true;
268 return appendImpl_(std::move(data));
274 const PipeEntry & pe = pipe_[getPhysicalStage_(-1)];
275 return pe.data.isValid();
298 void writePS (uint32_t stage,
const DataT & data)
300 writePSImpl_(stage, data);
313 writePSImpl_(stage, std::move(data));
320 PipeEntry & pe = pipe_[getPhysicalStage_(stage)];
321 sparta_assert(pe.data.isValid(),
"ERROR: In sparta::Pipe '" << name_
322 <<
"' invalidatePS at stage " << stage <<
" is not valid");
323 sparta_assert(stage != uint32_t(-1),
"Do not refer to stage -1 directly, use flushAppend()");
324 if(pe.data.isValid()) {
327 pe.data.clearValid();
328 if(perform_own_updates_) {
337 pipe_.reset (
new PipeEntry[physical_size_]);
350 PipeEntry & pe = pipe_[getPhysicalStage_(stage)];
351 sparta_assert(stage != uint32_t(-1),
"Do not refer to stage -1 directly, use flushAppend()");
352 if(pe.data.isValid()) {
355 pe.data.clearValid();
361 PipeEntry & pe = pipe_[getPhysicalStage_(-1)];
362 pe.data.clearValid();
368 for (int32_t i = -1; i < static_cast<int32_t>(num_entries_); ++i) {
369 PipeEntry & pe = pipe_[getPhysicalStage_(i)];
370 pe.data.clearValid();
384 for(int32_t i = -1; i < static_cast<int32_t>(num_entries_); ++i){
385 PipeEntry & pe = pipe_[getPhysicalStage_(i)];
386 if(pe.data.isValid()) {
387 if(pe.data.getValue() == criteria){
388 if(pe.data.isValid()) {
391 pe.data.clearValid();
406 void flushIf(std::function<
bool(
const DataT&)> compare){
407 for(int32_t i = -1; i < static_cast<int32_t>(num_entries_); ++i){
408 PipeEntry & pe = pipe_[getPhysicalStage_(i)];
409 if(pe.data.isValid()) {
410 if(compare(pe.data.getValue())){
411 if(pe.data.isValid()) {
414 pe.data.clearValid();
430 const PipeEntry & pe = pipe_[getPhysicalStage_(stage)];
431 return pe.data.isValid();
437 return (num_valid_ > 0) ||
isValid(uint32_t(-1));
443 const PipeEntry & pe = pipe_[getPhysicalStage_(num_entries_ - 1)];
444 return pe.data.isValid();
448 const DataT &
read (uint32_t stage)
const
450 const PipeEntry & pe = pipe_[getPhysicalStage_(stage)];
451 sparta_assert(pe.data.isValid(),
"ERROR: In sparta::Pipe '" << name_
452 <<
"' read at stage " << stage <<
" is not valid");
453 return pe.data.getValue();
459 PipeEntry & pe = pipe_[getPhysicalStage_(stage)];
460 sparta_assert(pe.data.isValid(),
"ERROR: In sparta::Pipe '" << name_
461 <<
"' read at stage " << stage <<
" is not valid");
462 return pe.data.getValue();
468 return read(num_entries_ - 1);
475 const PipeEntry & pe = pipe_[getPhysicalStage_(-1)];
476 sparta_assert(pe.data.isValid(),
"ERROR: In sparta::Pipe '" << name_
477 <<
"' reading appended data is not valid");
478 return pe.data.getValue();
484 "HEY! You said you wanted the pipe to do it's own updates. Liar.");
492 PipeEntry & pe_neg1 = pipe_[getPhysicalStage_(-1)];
493 if(!pe_neg1.data.isValid()) {
496 const PipeEntry & pe_zero = pipe_[getPhysicalStage_(0)];
497 if(pe_zero.data.isValid()) {
500 writePS(0, pe_neg1.data.getValue());
501 pe_neg1.data.clearValid();
514 template<sparta::SchedulingPhase phase = SchedulingPhase::Collection>
524 return collector_ && collector_->isCollected();
535 std::unique_ptr<PipeEntry[]> pipe_;
537 const std::string name_;
544 UniqueEvent<SchedulingPhase::Update> ev_update_;
545 bool perform_own_updates_ =
false;
547 void internalUpdate_() {
549 PipeEntry & pe_head = pipe_[getPhysicalStage_(num_entries_ - 1)];
550 if(pe_head.data.isValid()) {
553 pe_head.data.clearValid();
556 tail_ = getPhysicalStage_(-1);
559 const PipeEntry & pe_tail = pipe_[tail_];
560 if(pe_tail.data.isValid()) {
563 if((num_valid_ > 0) && perform_own_updates_) {
564 ev_update_.schedule();
569 void appendImpl_ (U && data)
571 PipeEntry & pe = pipe_[getPhysicalStage_(-1)];
572 sparta_assert(pe.data.isValid() ==
false,
"ERROR: sparta::Pipe '" << name_
573 <<
"' Double append of data before update");
574 pe.data = std::forward<U>(data);
575 if(perform_own_updates_) {
576 ev_update_.schedule();
581 void writePSImpl_ (uint32_t stage, U && data)
583 PipeEntry & pe = pipe_[getPhysicalStage_(stage)];
584 if(pe.data.isValid()) {
587 pe.data = std::forward<U>(data);
589 if(perform_own_updates_) {
590 ev_update_.schedule();
596 std::unique_ptr<collection::CollectableTreeNode> collector_;
File that defines the Clock class.
Defines a few handy (and now deprecated) C++ iterator traits.
File that defines the Port base 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.
#define CREATE_SPARTA_HANDLER(clname, meth)
File that defines a ValidValue.
A representation of simulated time.
Scheduler * getScheduler() const
Set of Events that a unit (or sparta::TreeNode, sparta::Resource) contains and are visible through a ...
PipeIterator & operator++()
override Pre-increment operator
PipeIterator(PipePointerType pipe, uint32_t index)
construct.
DataReferenceType operator*()
Override derefrence operator.
bool operator!=(const PipeIterator &it) const
Not Equals comparision operator.
PipeIterator operator++(int)
override post-increment operator
bool isValid() const
Checks validity of iterator.
DataReferenceType operator->()
support -> operator
PipeIterator(PipePointerType pipe)
construct.
bool operator==(const PipeIterator &it) const
Equals comparision operator.
PipeIterator(const PipeIterator &)=default
Default copy constructor.
PipeIterator(PipeIterator &&)=default
Default move constructor.
A very simple pipe, not part of the DES paradigm.
void update()
Update the pipe – shift data appended/invalidated.
void resize(uint32_t new_size)
Resize the pipe immediately after construction.
void writePS(uint32_t stage, DataT &&data)
Append data to the specified stage. Will clobber what's there.
bool isAnyValid() const
Are any entries valid, including ones appended THIS cycle.
void push_front(DataT &&data)
Append data to the beginning of the Pipe.
void writePS(uint32_t stage, const DataT &data)
Append data to the specified stage. Will clobber what's there.
size_type capacity() const
What is the capacity of the pipe? I.e. Entry count.
DataT & access(uint32_t stage)
Read the entry at the given stage (non-const)
void append(const DataT &data)
Append data to the beginning of the Pipe.
void clear()
Clear the pipe.
Pipe(const Pipe< DataT > &)=delete
No copies.
const DataT & readLast() const
Read the last entry.
const DataT & readAppendedData() const
Pipe & operator=(const Pipe< DataT > &)=delete
No copies.
const_iterator end() const
STL-like begin operation,.
PipeIterator< true > const_iterator
Typedef for constant iterator.
void flushIf(const DataT &criteria)
Flush any item that matches the given criteria.
void flushIf(std::function< bool(const DataT &)> compare)
Flush any item that matches the given function.
Pipe(const std::string &name, uint32_t num_entries, const Clock *clk)
Construct a pipe, 0-size not supported.
bool isLastValid() const
Is the last entry valid?
void flushPS(uint32_t stage)
Flush the item at the given stage, even if not valid.
const DataT & read(uint32_t stage) const
Read the entry at the given stage.
void invalidatePS(uint32_t stage)
DataT value_type
A typedef for this type of pipe.
void enableCollection(TreeNode *parent)
Request that this queue begin collecting its contents for pipeline collection.
void flushAll()
Flush everything, RIGHT NOW.
bool isAppended() const
Is the pipe already appended data?
iterator begin()
STL-like begin operation,.
size_type size() const
Resturns numValid – useful for STL iteration.
void flushAppend()
Flush the item that was appended.
uint32_t size_type
Typedef for size_type.
PipeIterator< false > iterator
Typedef for regular iterator.
bool isCollected() const
Check if pipe is collecting.
const std::string & getName() const
Name of this resource.
bool empty() const
Return whether the pipe is empty.
bool isValid(uint32_t stage) const
See if there is something at the given stage.
size_type numValid() const
const_iterator begin() const
STL-like begin operation,.
iterator end()
STL-like begin operation,.
void push_front(const DataT &data)
Append data to the beginning of the Pipe.
void append(DataT &&data)
Append data to the beginning of the Pipe.
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 setScheduleableClock(const Clock *clk)
Set the clock and scheduler of this Scheduleable.
Node in a composite tree representing a sparta Tree item.
void schedule()
Schedule this event with its pre-set delay using the pre-set Clock.
A collector of any iterable type (std::vector, std::list, sparta::Buffer, etc)
Provides a wrapper around a value to ensure that the value is assigned.
Macros for handling exponential backoff.