The Sparta Modeling Framework
Loading...
Searching...
No Matches
Pipe.hpp
Go to the documentation of this file.
1// <Pipe.hpp> -*- C++ -*-
2
3
11#pragma once
12
13#include <cinttypes>
14#include <memory>
15#include <functional>
17#include "sparta/ports/Port.hpp"
19#include "sparta/utils/MathUtils.hpp"
20#include "sparta/collection/IterableCollector.hpp"
23
24namespace sparta
25{
26
43template <typename DataT>
44class Pipe
45{
46
47private:
48
49 struct PipeEntry
50 {
52 };
53
54 uint32_t getPhysicalStage_ (int32_t stage) const
55 {
56 sparta_assert (stage < static_cast<int32_t>(num_entries_));
57 return (tail_ + stage) & stage_mask_;
58 }
59
60 void initPipe_(uint32_t num_entries)
61 {
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_]);
68 }
69
70public:
71
73 typedef DataT value_type;
74
76 typedef uint32_t size_type;
77
78 template <bool is_const_iterator = true>
79 class PipeIterator : public utils::IteratorTraits<std::forward_iterator_tag, value_type>
80 {
81 typedef typename std::conditional<is_const_iterator,
82 const value_type &,
83 value_type &>::type DataReferenceType;
84
85 typedef typename std::conditional<is_const_iterator,
86 const Pipe<DataT> *,
87 Pipe<DataT> *>::type PipePointerType;
89 DataReferenceType getAccess_(std::false_type) {
90 return pipe_->access(index_);
91 }
92
94 DataReferenceType getAccess_(std::true_type) {
95 return pipe_->read(index_);
96 }
97
98 public:
99
104 PipeIterator(PipePointerType pipe) : pipe_(pipe) {}
105
111 PipeIterator(PipePointerType pipe, uint32_t index) : pipe_(pipe), index_(index) {}
112
114 PipeIterator(const PipeIterator &) = default;
115
118
120 DataReferenceType operator*() {
121 sparta_assert(index_ != uint32_t(-1));
122 sparta_assert(pipe_->isValid(index_));
123 return getAccess_(std::integral_constant<bool, is_const_iterator>());
124 }
125
126
128 DataReferenceType operator->()
129 {
130 return operator*();
131 }
132
135 if(++index_ > pipe_->capacity()) {
136 index_ = pipe_->capacity();
137 }
138 return *this;
139 }
140
143 PipeIterator it(*this);
144 this->operator++();
145 return it;
146 }
147
149 bool operator==(const PipeIterator & it) const {
150 return ((pipe_ == it.pipe_) && (index_ == it.index_));
151 }
152
154 bool operator!=(const PipeIterator & it) const {
155 return !operator==(it);
156 }
157
159 bool isValid() const {
160 return pipe_->isValid(index_);
161 }
162
163 private:
164 PipePointerType pipe_;
165 uint32_t index_{0};
166 };
167
170
173
176 iterator begin(){ return iterator(this);}
177
180 iterator end() { return iterator(this, num_entries_);}
181
184 const_iterator begin() const { return const_iterator(this);}
185
188 const_iterator end() const { return const_iterator(this, num_entries_);}
189
191 Pipe (const Pipe <DataT> &) = delete;
192
194 Pipe & operator= (const Pipe <DataT> &) = delete;
195
203 Pipe (const std::string & name,
204 uint32_t num_entries,
205 const Clock * clk) :
206 name_(name),
207 ev_update_(&es_, name+"_pipe_update_event",
208 CREATE_SPARTA_HANDLER(Pipe, internalUpdate_), 1)
209 {
210 initPipe_(num_entries);
211 ev_update_.setScheduleableClock(clk);
212 ev_update_.setScheduler(clk->getScheduler());
213 ev_update_.setContinuing(false);
214 }
215
223 void resize(uint32_t new_size) {
224 sparta_assert(collector_ == nullptr);
225 //sparta_assert(!getClock()->isFinalized());
226 initPipe_(new_size);
227 }
228
232 if(!perform_own_updates_ && isAnyValid()) {
233 ev_update_.schedule();
234 }
235 perform_own_updates_ = true;
236 }
237
240 return num_entries_;
241 }
242
246 return num_valid_;
247 }
248
250 size_type size() const {
251 return numValid();
252 }
253
255 bool empty() const {
256 return numValid() == 0;
257 }
258
260 void append (const DataT & data)
261 {
262 appendImpl_(data);
263 }
264
266 void append (DataT && data)
267 {
268 return appendImpl_(std::move(data));
269 }
270
272 bool isAppended() const
273 {
274 const PipeEntry & pe = pipe_[getPhysicalStage_(-1)];
275 return pe.data.isValid();
276 }
277
279 void push_front (const DataT & data)
280 {
281 append(data);
282 }
283
285 void push_front (DataT && data)
286 {
287 append(std::move(data));
288 }
289
298 void writePS (uint32_t stage, const DataT & data)
299 {
300 writePSImpl_(stage, data);
301 }
302
311 void writePS (uint32_t stage, DataT && data)
312 {
313 writePSImpl_(stage, std::move(data));
314 }
315
318 void invalidatePS (uint32_t stage)
319 {
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()) {
325 --num_valid_;
326 }
327 pe.data.clearValid();
328 if(perform_own_updates_) {
329 ev_update_.schedule();
330 }
331 }
332
336 void clear() {
337 pipe_.reset (new PipeEntry[physical_size_]);
338 num_valid_ = 0;
339 }
340
344 invalidatePS(num_entries_ - 1);
345 }
346
348 void flushPS (uint32_t stage)
349 {
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()) {
353 --num_valid_;
354 }
355 pe.data.clearValid();
356 }
357
360 {
361 PipeEntry & pe = pipe_[getPhysicalStage_(-1)];
362 pe.data.clearValid();
363 }
364
366 void flushAll ()
367 {
368 for (int32_t i = -1; i < static_cast<int32_t>(num_entries_); ++i) {
369 PipeEntry & pe = pipe_[getPhysicalStage_(i)];
370 pe.data.clearValid();
371 }
372 num_valid_ = 0;
373 }
374
383 void flushIf(const DataT& criteria){
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()) {
389 --num_valid_;
390 }
391 pe.data.clearValid();
392 }
393 }
394 }
395 }
396
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()) {
412 --num_valid_;
413 }
414 pe.data.clearValid();
415 }
416 }
417 }
418 }
419
423 const std::string & getName() const {
424 return name_;
425 }
426
428 bool isValid (uint32_t stage) const
429 {
430 const PipeEntry & pe = pipe_[getPhysicalStage_(stage)];
431 return pe.data.isValid();
432 }
433
435 bool isAnyValid () const
436 {
437 return (num_valid_ > 0) || isValid(uint32_t(-1));
438 }
439
441 bool isLastValid () const
442 {
443 const PipeEntry & pe = pipe_[getPhysicalStage_(num_entries_ - 1)];
444 return pe.data.isValid();
445 }
446
448 const DataT & read (uint32_t stage) const
449 {
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();
454 }
455
457 DataT & access(uint32_t stage)
458 {
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();
463 }
464
466 const DataT & readLast() const
467 {
468 return read(num_entries_ - 1);
469 }
470
473 const DataT & readAppendedData() const
474 {
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();
479 }
480
482 void update () {
483 sparta_assert(perform_own_updates_ == false,
484 "HEY! You said you wanted the pipe to do it's own updates. Liar.");
485 internalUpdate_();
486 }
487
491 {
492 PipeEntry & pe_neg1 = pipe_[getPhysicalStage_(-1)];
493 if(!pe_neg1.data.isValid()) {
494 return false; // nothing to move
495 }
496 const PipeEntry & pe_zero = pipe_[getPhysicalStage_(0)];
497 if(pe_zero.data.isValid()) {
498 return false;// can't move
499 }
500 writePS(0, pe_neg1.data.getValue());
501 pe_neg1.data.clearValid();
502 return true;
503 }
504
514 template<sparta::SchedulingPhase phase = SchedulingPhase::Collection>
515 void enableCollection(TreeNode * parent) {
516 collector_.reset (new collection::IterableCollector<Pipe<DataT>, phase, true>
517 (parent, name_, this, capacity()));
518 }
519
523 bool isCollected() const {
524 return collector_ && collector_->isCollected();
525 }
526
527private:
528
529 size_type num_entries_ = 0;
530 size_type physical_size_ = 0;
531 size_type stage_mask_ = 0;
532 size_type num_valid_ = 0;
533 size_type tail_ = 0;
534
535 std::unique_ptr<PipeEntry[]> pipe_;
536
537 const std::string name_;
538
540 // Internal use only
541
542 // Process appends, invalidates, etc, timed only
543 sparta::EventSet es_{nullptr};
544 UniqueEvent<SchedulingPhase::Update> ev_update_;
545 bool perform_own_updates_ = false;
546
547 void internalUpdate_() {
548 // Remove the head object
549 PipeEntry & pe_head = pipe_[getPhysicalStage_(num_entries_ - 1)];
550 if(pe_head.data.isValid()) {
551 --num_valid_;
552 }
553 pe_head.data.clearValid();
554
555 // Shift the pipe
556 tail_ = getPhysicalStage_(-1);
557
558 // Add the tail object
559 const PipeEntry & pe_tail = pipe_[tail_];
560 if(pe_tail.data.isValid()) {
561 ++num_valid_;
562 }
563 if((num_valid_ > 0) && perform_own_updates_) {
564 ev_update_.schedule();
565 }
566 }
567
568 template<typename U>
569 void appendImpl_ (U && data)
570 {
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();
577 }
578 }
579
580 template<typename U>
581 void writePSImpl_ (uint32_t stage, U && data)
582 {
583 PipeEntry & pe = pipe_[getPhysicalStage_(stage)];
584 if(pe.data.isValid()) {
585 --num_valid_;
586 }
587 pe.data = std::forward<U>(data);
588 ++num_valid_;
589 if(perform_own_updates_) {
590 ev_update_.schedule();
591 }
592 }
593
595 // Collectors
596 std::unique_ptr<collection::CollectableTreeNode> collector_;
597
598};
599
600}
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.
Definition Clock.hpp:51
Scheduler * getScheduler() const
Definition Clock.hpp:302
Set of Events that a unit (or sparta::TreeNode, sparta::Resource) contains and are visible through a ...
Definition EventSet.hpp:26
PipeIterator & operator++()
override Pre-increment operator
Definition Pipe.hpp:134
PipeIterator(PipePointerType pipe, uint32_t index)
construct.
Definition Pipe.hpp:111
DataReferenceType operator*()
Override derefrence operator.
Definition Pipe.hpp:120
bool operator!=(const PipeIterator &it) const
Not Equals comparision operator.
Definition Pipe.hpp:154
PipeIterator operator++(int)
override post-increment operator
Definition Pipe.hpp:142
bool isValid() const
Checks validity of iterator.
Definition Pipe.hpp:159
DataReferenceType operator->()
support -> operator
Definition Pipe.hpp:128
PipeIterator(PipePointerType pipe)
construct.
Definition Pipe.hpp:104
bool operator==(const PipeIterator &it) const
Equals comparision operator.
Definition Pipe.hpp:149
PipeIterator(const PipeIterator &)=default
Default copy constructor.
PipeIterator(PipeIterator &&)=default
Default move constructor.
A very simple pipe, not part of the DES paradigm.
Definition Pipe.hpp:45
void update()
Update the pipe – shift data appended/invalidated.
Definition Pipe.hpp:482
void resize(uint32_t new_size)
Resize the pipe immediately after construction.
Definition Pipe.hpp:223
bool shiftAppend()
Definition Pipe.hpp:490
void writePS(uint32_t stage, DataT &&data)
Append data to the specified stage. Will clobber what's there.
Definition Pipe.hpp:311
void performOwnUpdates()
Definition Pipe.hpp:231
bool isAnyValid() const
Are any entries valid, including ones appended THIS cycle.
Definition Pipe.hpp:435
void push_front(DataT &&data)
Append data to the beginning of the Pipe.
Definition Pipe.hpp:285
void writePS(uint32_t stage, const DataT &data)
Append data to the specified stage. Will clobber what's there.
Definition Pipe.hpp:298
size_type capacity() const
What is the capacity of the pipe? I.e. Entry count.
Definition Pipe.hpp:239
DataT & access(uint32_t stage)
Read the entry at the given stage (non-const)
Definition Pipe.hpp:457
void append(const DataT &data)
Append data to the beginning of the Pipe.
Definition Pipe.hpp:260
void clear()
Clear the pipe.
Definition Pipe.hpp:336
Pipe(const Pipe< DataT > &)=delete
No copies.
const DataT & readLast() const
Read the last entry.
Definition Pipe.hpp:466
const DataT & readAppendedData() const
Definition Pipe.hpp:473
Pipe & operator=(const Pipe< DataT > &)=delete
No copies.
const_iterator end() const
STL-like begin operation,.
Definition Pipe.hpp:188
PipeIterator< true > const_iterator
Typedef for constant iterator.
Definition Pipe.hpp:172
void invalidateLastPS()
Definition Pipe.hpp:343
void flushIf(const DataT &criteria)
Flush any item that matches the given criteria.
Definition Pipe.hpp:383
void flushIf(std::function< bool(const DataT &)> compare)
Flush any item that matches the given function.
Definition Pipe.hpp:406
Pipe(const std::string &name, uint32_t num_entries, const Clock *clk)
Construct a pipe, 0-size not supported.
Definition Pipe.hpp:203
bool isLastValid() const
Is the last entry valid?
Definition Pipe.hpp:441
void flushPS(uint32_t stage)
Flush the item at the given stage, even if not valid.
Definition Pipe.hpp:348
const DataT & read(uint32_t stage) const
Read the entry at the given stage.
Definition Pipe.hpp:448
void invalidatePS(uint32_t stage)
Definition Pipe.hpp:318
DataT value_type
A typedef for this type of pipe.
Definition Pipe.hpp:73
void enableCollection(TreeNode *parent)
Request that this queue begin collecting its contents for pipeline collection.
Definition Pipe.hpp:515
void flushAll()
Flush everything, RIGHT NOW.
Definition Pipe.hpp:366
bool isAppended() const
Is the pipe already appended data?
Definition Pipe.hpp:272
iterator begin()
STL-like begin operation,.
Definition Pipe.hpp:176
size_type size() const
Resturns numValid – useful for STL iteration.
Definition Pipe.hpp:250
void flushAppend()
Flush the item that was appended.
Definition Pipe.hpp:359
uint32_t size_type
Typedef for size_type.
Definition Pipe.hpp:76
PipeIterator< false > iterator
Typedef for regular iterator.
Definition Pipe.hpp:169
bool isCollected() const
Check if pipe is collecting.
Definition Pipe.hpp:523
const std::string & getName() const
Name of this resource.
Definition Pipe.hpp:423
bool empty() const
Return whether the pipe is empty.
Definition Pipe.hpp:255
bool isValid(uint32_t stage) const
See if there is something at the given stage.
Definition Pipe.hpp:428
size_type numValid() const
Definition Pipe.hpp:245
const_iterator begin() const
STL-like begin operation,.
Definition Pipe.hpp:184
iterator end()
STL-like begin operation,.
Definition Pipe.hpp:180
void push_front(const DataT &data)
Append data to the beginning of the Pipe.
Definition Pipe.hpp:279
void append(DataT &&data)
Append data to the beginning of the Pipe.
Definition Pipe.hpp:266
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.
Definition TreeNode.hpp:205
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.