add missing tatum file due to the folder name tags is in the git ignore list!!!

This commit is contained in:
tangxifan 2020-01-03 23:13:49 -05:00
parent 60cbcf9104
commit 2901a6eec5
5 changed files with 884 additions and 0 deletions

View File

@ -0,0 +1,156 @@
#pragma once
#include <iosfwd>
#include <limits>
#include "tatum/Time.hpp"
#include "tatum/TimingGraphFwd.hpp"
namespace tatum {
enum class TagType : unsigned char {
CLOCK_LAUNCH,
CLOCK_CAPTURE,
DATA_ARRIVAL,
DATA_REQUIRED,
SLACK,
UNKOWN
};
class TimingTag;
std::ostream& operator<<(std::ostream& os, TagType type);
bool is_const_gen_tag(const TimingTag& tag);
/**
* The 'TimingTag' class represents an individual timing tag: the information associated
* with a node's arrival/required times.
*
*
* This primarily includes the actual arrival and required time, but also
* auxillary metadata such as the clock domain, and launching node.
*
* The clock domain in particular is used to tag arrival/required times from different
* clock domains at a single node. This enables us to perform only a single graph traversal
* and still analyze mulitple clocks.
*
* NOTE: Timing analyzers usually operate on the collection of tags at a particular node.
* This is modelled by the separate 'TimingTags' class.
*/
class TimingTag {
public: //Static
//Returns a tag suitable for use at a constant generator, during
//setup analysis.
//
///In particular it's domains are left invalid (i.e. wildcards),
//and it's arrival time set to -inf (so it will be maxed out by
//any non-constant tag)
static TimingTag CONST_GEN_TAG_SETUP() {
return TimingTag(Time(-std::numeric_limits<float>::infinity()),
DomainId::INVALID(),
DomainId::INVALID(),
NodeId::INVALID(),
TagType::DATA_ARRIVAL);
}
//Returns a tag suitable for use at a constant generator, during
//hold analysis.
//
///In particular it's domains are left invalid (i.e. wildcards),
//and it's arrival time set to +inf (so it will be minned out by
//any non-constant tag)
static TimingTag CONST_GEN_TAG_HOLD() {
return TimingTag(Time(+std::numeric_limits<float>::infinity()),
DomainId::INVALID(),
DomainId::INVALID(),
NodeId::INVALID(),
TagType::DATA_ARRIVAL);
}
public: //Constructors
TimingTag();
///\param arr_time_val The tagged arrival time
///\param req_time_val The tagged required time
///\param launch_domain The clock domain the tag was launched from
///\param capture_domain The clock domain the tag was captured on
///\param node The origin node's id (e.g. source/sink that originally launched/required this tag)
TimingTag(const Time& time_val, DomainId launch_domain, DomainId capture_domain, NodeId node, TagType type);
///\param arr_time_val The tagged arrival time
///\param req_time_val The tagged required time
///\param base_tag The tag from which to copy auxilary meta-data (e.g. domain, launch node)
TimingTag(const Time& time_val, NodeId origin, const TimingTag& base_tag);
public: //Accessors
///\returns This tag's arrival time
const Time& time() const { return time_; }
///\returns This tag's launching clock domain
DomainId launch_clock_domain() const { return launch_clock_domain_; }
DomainId capture_clock_domain() const { return capture_clock_domain_; }
///\returns This tag's launching node's id
NodeId origin_node() const { return origin_node_; }
TagType type() const { return type_; }
public: //Mutators
///\param new_time The new value set as the tag's time
void set_time(const Time& new_time) { time_ = new_time; }
///\param new_clock_domain The new value set as the tag's source clock domain
void set_launch_clock_domain(const DomainId new_clock_domain) { launch_clock_domain_ = new_clock_domain; }
///\param new_clock_domain The new value set as the tag's capture clock domain
void set_capture_clock_domain(const DomainId new_clock_domain) { capture_clock_domain_ = new_clock_domain; }
///\param new_launch_node The new value set as the tag's launching node
void set_origin_node(const NodeId new_origin_node) { origin_node_ = new_origin_node; }
void set_type(const TagType new_type) { type_ = new_type; }
/*
* Modification operations
* For the following the passed in time is maxed/minned with the
* respective arr/req time. If the value of this tag is updated
* the meta-data (domain, launch node etc) are copied from the
* base tag
*/
///Updates the tag's arrival time if new_arr_time is larger than the current arrival time.
///If the arrival time is updated, meta-data is also updated from base_tag
///\param new_arr_time The arrival time to compare against
///\param base_tag The tag from which meta-data is copied
void max(const Time& new_time, const NodeId origin, const TimingTag& base_tag);
///Updates the tag's arrival time if new_arr_time is smaller than the current arrival time.
///If the arrival time is updated, meta-data is also updated from base_tag
///\param new_arr_time The arrival time to compare against
///\param base_tag The tag from which meta-data is copied
void min(const Time& new_time, const NodeId origin, const TimingTag& base_tag);
private:
void update(const Time& new_time, const NodeId origin, const TimingTag& base_tag);
/*
* Data
*/
Time time_; //Required time
NodeId origin_node_; //Node which launched this arr/req time
DomainId launch_clock_domain_; //Clock domain for arr/req times
DomainId capture_clock_domain_; //Clock domain for arr/req times
TagType type_;
};
//For comparing the values of two timing tags
struct TimingTagValueComp {
bool operator()(const tatum::TimingTag& lhs, const tatum::TimingTag& rhs) {
return lhs.time().value() < rhs.time().value();
}
};
} //namepsace
//Implementation
#include "TimingTag.inl"

View File

@ -0,0 +1,99 @@
#include "tatum/util/tatum_assert.hpp"
namespace tatum {
/*
* TimingTag implementation
*/
inline TimingTag::TimingTag()
: time_(NAN)
, origin_node_(NodeId::INVALID())
, launch_clock_domain_(DomainId::INVALID())
, capture_clock_domain_(DomainId::INVALID())
, type_(TagType::UNKOWN)
{}
inline TimingTag::TimingTag(const Time& time_val,
const DomainId launch_domain,
const DomainId capture_domain,
const NodeId node,
const TagType new_type)
: time_(time_val)
, origin_node_(node)
, launch_clock_domain_(launch_domain)
, capture_clock_domain_(capture_domain)
, type_(new_type)
{}
inline TimingTag::TimingTag(const Time& time_val, NodeId origin, const TimingTag& base_tag)
: time_(time_val)
, origin_node_(origin)
, launch_clock_domain_(base_tag.launch_clock_domain())
, capture_clock_domain_(base_tag.capture_clock_domain())
, type_(base_tag.type())
{}
inline void TimingTag::update(const Time& new_time, const NodeId origin, const TimingTag& base_tag) {
TATUM_ASSERT(type() == base_tag.type()); //Type must be the same
//Note that we check for a constant tag first, since we might
//update the time (which is used to verify whether the tag is a constant
if(is_const_gen_tag(*this)) {
//If the tag is a constant, then we want to replace it with the
//first non-constant tag which comes along. This ensures that
//any constant tags get 'swallowed' by real tags and do not
//continue to propagate through the timing graph
set_launch_clock_domain(base_tag.launch_clock_domain());
set_capture_clock_domain(base_tag.capture_clock_domain());
}
TATUM_ASSERT(( launch_clock_domain() == base_tag.launch_clock_domain())
&& capture_clock_domain() == base_tag.capture_clock_domain()); //Same domains
//Update the tag
set_time(new_time);
set_origin_node(origin);
}
inline void TimingTag::max(const Time& new_time, const NodeId origin, const TimingTag& base_tag) {
//Need to min with existing value
if(!time().valid() || new_time > time()) {
//New value is smaller, or no previous valid value existed
//Update min
update(new_time, origin, base_tag);
}
}
inline void TimingTag::min(const Time& new_time, const NodeId origin, const TimingTag& base_tag) {
//Need to min with existing value
if(!time().valid() || new_time < time()) {
//New value is smaller, or no previous valid value existed
//Update min
update(new_time, origin, base_tag);
}
}
inline std::ostream& operator<<(std::ostream& os, TagType type) {
if(type == TagType::DATA_ARRIVAL) os << "DATA_ARRIVAL";
else if(type == TagType::DATA_REQUIRED) os << "DATA_REQUIRED";
else if(type == TagType::CLOCK_LAUNCH) os << "CLOCK_LAUNCH";
else if(type == TagType::CLOCK_CAPTURE) os << "CLOCK_CAPTURE";
else if(type == TagType::SLACK) os << "SLACK";
else TATUM_ASSERT_MSG(false, "Unrecognized TagType");
return os;
}
//Returns true, if tag is a tag from a constant generator
inline bool is_const_gen_tag(const TimingTag& tag) {
return !tag.launch_clock_domain() //Wildcard launch
&& !tag.capture_clock_domain() //Wildcard capture
&& std::isinf(tag.time().value()); //inf arrival, we allow +/- inf since different values may be used for setup/hold
}
} //namepsace

View File

@ -0,0 +1,79 @@
#include "tatum/tags/TimingTags.hpp"
#include "tatum/TimingGraphFwd.hpp"
#include "tatum/error.hpp"
namespace tatum {
/*
* Tag utilities
*/
//Return the tag from the range [first,last) which has the lowest value
TimingTags::const_iterator find_minimum_tag(TimingTags::tag_range tags) {
return std::min_element(tags.begin(), tags.end(), TimingTagValueComp());
}
//Return the tag from the range [first,last) which has the highest value
TimingTags::const_iterator find_maximum_tag(TimingTags::tag_range tags) {
return std::max_element(tags.begin(), tags.end(), TimingTagValueComp());
}
TimingTags::const_iterator find_tag(TimingTags::tag_range tags,
DomainId launch_domain,
DomainId capture_domain) {
for(auto iter = tags.begin(); iter != tags.end(); ++iter) {
if(iter->launch_clock_domain() == launch_domain && iter->capture_clock_domain() == capture_domain) {
return iter;
}
}
return tags.end();
}
//Returns true of the specified set of tags would constrain a node of type node_type
bool is_constrained(NodeType node_type, TimingTags::tag_range tags) {
bool has_clock_launch = false;
bool has_clock_capture = false;
bool has_data_required = false;
for(const auto& tag : tags) {
if(tag.type() == TagType::CLOCK_LAUNCH) {
has_clock_launch = true;
} else if (tag.type() == TagType::CLOCK_CAPTURE) {
has_clock_capture = true;
} else if (tag.type() == TagType::DATA_REQUIRED) {
has_data_required = true;
}
}
bool constrained = false;
if(node_type == NodeType::SINK) {
//Constrained data nodes should have required times
//
//However, if a clock is generated on-chip (e.g. PLL) it may
//be driven off-chip so a primary-output sink may have only
//clock launch tags
constrained = has_data_required || has_clock_launch;
} else if(node_type == NodeType::SOURCE) {
//Constrained data nodes should have required times
//
//However, clock sources may have only clock tags
constrained = has_data_required || (has_clock_launch && has_clock_capture);
} else if(node_type == NodeType::IPIN || node_type == NodeType::OPIN) {
//Required time indicates a datapath node is constrained
constrained = has_data_required;
} else if(node_type == NodeType::CPIN) {
//Clock pins should have both launch and capture to be constrained
constrained = has_clock_launch && has_clock_capture;
} else {
throw Error("Unrecognized node type");
}
return constrained;
}
}

View File

@ -0,0 +1,223 @@
#pragma once
#include <iterator>
#include <memory>
#include "tatum/tags/TimingTag.hpp"
#include "tatum/util/tatum_range.hpp"
namespace tatum {
/**
* The 'TimingTags' class represents a collection of timing tags (see the 'TimingTag' class)
* that belong to a particular node in the timing graph.
*
* Any operations performed using this task generally consider *all* associated tags.
* For example, preforming a max_arr() call will apply the max accross all tags with matching
* clock domain. If no matching tag is found, the tag will be added to the set of tags.
*
* Implementation
* ====================
* Since each node in the timing graph typically has only a few tags (usually 1 or 2), we
* perform linear searches to find match tags and tag ranges.
*
* Note that to allow efficient iteration of tag ranges (by type) we ensure that tags of the
* same type are adjacent in the storage vector (i.e. the vector is sorted by type)
*/
class TimingTags {
public:
template<class T>
class Iterator;
private:
//In practice the vast majority of nodes have only a handful of tags,
//so we reserve space for some to avoid costly memory allocations
constexpr static size_t DEFAULT_TAGS_TO_RESERVE = 3;
constexpr static size_t GROWTH_FACTOR = 2;
public:
typedef Iterator<TimingTag> iterator;
typedef Iterator<const TimingTag> const_iterator;
typedef tatum::util::Range<const_iterator> tag_range;
public:
//Constructors
TimingTags(size_t num_reserve=DEFAULT_TAGS_TO_RESERVE);
TimingTags(const TimingTags&);
TimingTags(TimingTags&&);
TimingTags& operator=(TimingTags);
~TimingTags() = default;
friend void swap(TimingTags& lhs, TimingTags& rhs);
/*
* Getters
*/
///\returns The number of timing tags in this set
size_t size() const;
bool empty() const { return size() == 0; }
///\returns A range of all tags
tag_range tags() const;
///\returns A range of all tags matching type
tag_range tags(const TagType type) const;
/*
* Modifiers
*/
///Adds a TimingTag to the current set provided it has a valid clock domain
///\param tag_pool The pool memory allocator used to allocate the tag
///\param src_tag The source tag who is inserted. Note that the src_tag is copied when inserted (the original is unchanged)
void add_tag(const TimingTag& src_tag);
/*
* Operations
*/
///Updates the arrival time of this set of tags to be the maximum.
///\param new_time The new arrival time to compare against
///\param base_tag The associated metat-data for new_time
///\remark Finds (or creates) the tag with the same clock domain as base_tag and update the arrival time if new_time is larger
void max(const Time& new_time, const NodeId origin, const TimingTag& base_tag, bool arr_must_be_valid=false);
///Updates the required time of this set of tags to be the minimum.
///\param new_time The new arrival time to compare against
///\param base_tag The associated metat-data for new_time
///\remark Finds (or creates) the tag with the same clock domain as base_tag and update the required time if new_time is smaller
void min(const Time& new_time, const NodeId origin, const TimingTag& base_tag, bool arr_must_be_valid=false);
///Clears the tags in the current set
void clear();
public:
//Iterator definition
template<class T>
class Iterator : public std::iterator<std::random_access_iterator_tag, T> {
friend TimingTags;
public:
using value_type = typename std::iterator<std::random_access_iterator_tag, T>::value_type;
using difference_type = typename std::iterator<std::random_access_iterator_tag, T>::difference_type;
using pointer = typename std::iterator<std::random_access_iterator_tag, T>::pointer;
using reference = typename std::iterator<std::random_access_iterator_tag, T>::reference;
using iterator_category = typename std::iterator<std::random_access_iterator_tag, T>::iterator_category;
public:
Iterator(): p_(nullptr) {}
Iterator(pointer p): p_(p) {}
Iterator(const Iterator& other): p_(other.p_) {}
Iterator& operator=(const Iterator& other) { p_ = other.p_; return *this; }
friend bool operator==(Iterator a, Iterator b) { return a.p_ == b.p_; }
friend bool operator!=(Iterator a, Iterator b) { return a.p_ != b.p_; }
reference operator*() { return *p_; }
const reference operator*() const { return *p_; } //Required for MSVC (gcc/clang are fine with only the non-cost version)
pointer operator->() { return p_; }
reference operator[](size_t n) { return *(p_ + n); }
Iterator& operator++() { ++p_; return *this; }
Iterator operator++(int) { Iterator old = *this; ++p_; return old; }
Iterator& operator--() { --p_; return *this; }
Iterator operator--(int) { Iterator old = *this; --p_; return old; }
Iterator& operator+=(size_t n) { p_ += n; return *this; }
Iterator& operator-=(size_t n) { p_ -= n; return *this; }
friend Iterator operator+(Iterator lhs, size_t rhs) { return lhs += rhs; }
friend Iterator operator-(Iterator lhs, size_t rhs) { return lhs -= rhs; }
friend difference_type operator-(const Iterator lhs, const Iterator rhs) { return lhs.p_ - rhs.p_; }
friend bool operator<(Iterator lhs, Iterator rhs) { return lhs.p_ < rhs.p_; }
friend bool operator>(Iterator lhs, Iterator rhs) { return lhs.p_ > rhs.p_; }
friend bool operator<=(Iterator lhs, Iterator rhs) { return lhs.p_ <= rhs.p_; }
friend bool operator>=(Iterator lhs, Iterator rhs) { return lhs.p_ >= rhs.p_; }
friend void swap(Iterator lhs, Iterator rhs) { std::swap(lhs.p_, rhs.p_); }
private:
T* p_ = nullptr;
};
private:
///\returns An iterator to the first tag in the current set
iterator begin();
const_iterator begin() const;
iterator begin(TagType type);
const_iterator begin(TagType type) const;
///\returns An iterator 'one-past-the-end' of the current set
iterator end();
const_iterator end() const;
iterator end(TagType type);
const_iterator end(TagType type) const;
size_t capacity() const;
///Finds a timing tag in the current set which matches tag
///\returns A pair of bool and iterator.
// The bool is true if it is valid for iterator to be processed.
// The iterator is not equal to end(tag.type()) if a matching tag was found
std::pair<bool,iterator> find_matching_tag(const TimingTag& tag, bool arr_must_be_valid);
///Finds a TimingTag in the current set that matches the launch and capture clocks of tag
///\returns An iterator to the tag if found, or end(type) if not found
iterator find_matching_tag(TagType type, DomainId launch_domain, DomainId capture_domain);
///Find a TimingTag matching the specified DATA_REQUIRED tag provided there is
//a valid associated DATA_ARRIVAL tag
///\returns A a pair of bool and iterator. The bool indicates if a valid arrival was found,
/// the iterator is the required tag matching launch and capture which has a valid
// corresponding arrival time, or end(TagType::DATA_REQUIRED)
std::pair<bool,iterator> find_data_required_with_valid_data_arrival(DomainId launch_domain, DomainId capture_domain);
iterator insert(iterator iter, const TimingTag& tag);
void grow_insert(size_t index, const TimingTag& tag);
void increment_size(TagType type);
private:
//We don't expect many tags in a node so unsigned short's/unsigned char's
//should be more than sufficient. This also allows the class
//to be packed down to 16 bytes (8 for counters, 8 for pointer)
//
//In its current configuration we can store at most:
// 65536 total tags (size_ and capacity_)
// 256 clock launch tags (num_clock_launch_tags_)
// 256 clock capture tags (num_clock_capture_tags_)
// 256 data arrival tags (num_data_arrival_tags_)
// 256 data required tags (num_data_required_tags_)
// (65536 - 4*256) slack tags (size_ - num_*)
unsigned short size_ = 0;
unsigned short capacity_ = 0;
unsigned char num_clock_launch_tags_ = 0;
unsigned char num_clock_capture_tags_ = 0;
unsigned char num_data_arrival_tags_ = 0;
unsigned char num_data_required_tags_ = 0;
std::unique_ptr<TimingTag[]> tags_;
};
/*
* Tag utilities
*/
//Return the tag from the range [first,last) which has the lowest value
TimingTags::const_iterator find_minimum_tag(TimingTags::tag_range tags);
//Return the tag from the range [first,last) which has the highest value
TimingTags::const_iterator find_maximum_tag(TimingTags::tag_range tags);
//Return the tag for the specified clock domains
TimingTags::const_iterator find_tag(TimingTags::tag_range tags,
DomainId launch_domain,
DomainId capture_domain);
//Returns true of the specified set of tags would constrain a node of type node_type
bool is_constrained(NodeType node_type, TimingTags::tag_range tags);
} //namepsace
//Implementation
#include "TimingTags.inl"

View File

@ -0,0 +1,327 @@
#include <algorithm>
#include "tatum/util/tatum_assert.hpp"
namespace tatum {
/*
* TimingTags implementation
*/
//TODO: given that we know we typically add tags in CLOCK_LAUNCH, DATA_ARRIVAL, CLOCK_CAPTURE, DATA_REQUIRED
// order, we should probably order their storage that way
inline TimingTags::TimingTags(size_t num_reserve)
: size_(0)
, capacity_(num_reserve)
, num_clock_launch_tags_(0)
, num_clock_capture_tags_(0)
, num_data_arrival_tags_(0)
, num_data_required_tags_(0)
, tags_(capacity_ ? new TimingTag[capacity_] : nullptr)
{}
inline TimingTags::TimingTags(const TimingTags& other)
: size_(other.size())
, capacity_(size_)
, num_clock_launch_tags_(other.num_clock_launch_tags_)
, num_clock_capture_tags_(other.num_clock_capture_tags_)
, num_data_arrival_tags_(other.num_data_arrival_tags_)
, num_data_required_tags_(other.num_data_required_tags_)
, tags_(capacity_ ? new TimingTag[capacity_] : nullptr) {
std::copy(other.tags_.get(), other.tags_.get() + other.size(), tags_.get());
}
inline TimingTags::TimingTags(TimingTags&& other)
: TimingTags(0) {
swap(*this, other);
}
inline TimingTags& TimingTags::operator=(TimingTags other) {
swap(*this, other);
return *this;
}
inline size_t TimingTags::size() const {
return size_;
}
inline TimingTags::iterator TimingTags::begin() {
auto iter = iterator(tags_.get());
return iter;
}
inline TimingTags::const_iterator TimingTags::begin() const {
return const_iterator(tags_.get());
}
inline TimingTags::iterator TimingTags::begin(TagType type) {
const_iterator const_iter = const_cast<const TimingTags*>(this)->begin(type);
return iterator(const_cast<TimingTag*>(const_iter.p_));
}
inline TimingTags::const_iterator TimingTags::begin(TagType type) const {
const_iterator iter;
switch(type) {
case TagType::CLOCK_LAUNCH:
iter = begin();
break;
case TagType::CLOCK_CAPTURE:
iter = begin() + num_clock_launch_tags_;
break;
case TagType::DATA_ARRIVAL:
iter = begin() + num_clock_launch_tags_ + num_clock_capture_tags_;
break;
case TagType::DATA_REQUIRED:
iter = begin() + num_clock_launch_tags_ + num_clock_capture_tags_ + num_data_arrival_tags_;
break;
case TagType::SLACK:
iter = begin() + num_clock_launch_tags_ + num_clock_capture_tags_ + num_data_arrival_tags_ + num_data_required_tags_;
break;
default:
TATUM_ASSERT_MSG(false, "Invalid tag type");
}
return iter;
}
inline TimingTags::iterator TimingTags::end() {
const_iterator const_iter = const_cast<const TimingTags*>(this)->end();
return iterator(const_cast<TimingTag*>(const_iter.p_));
}
inline TimingTags::const_iterator TimingTags::end() const {
auto iter = const_iterator(tags_.get() + size_);
TATUM_ASSERT_SAFE(iter.p_ >= tags_.get() && iter.p_ <= tags_.get() + size());
return iter;
}
inline TimingTags::iterator TimingTags::end(TagType type) {
const_iterator const_iter = const_cast<const TimingTags*>(this)->end(type);
return iterator(const_cast<TimingTag*>(const_iter.p_));
}
inline TimingTags::const_iterator TimingTags::end(TagType type) const {
const_iterator iter;
switch(type) {
case TagType::CLOCK_LAUNCH:
iter = begin(TagType::CLOCK_CAPTURE);
break;
case TagType::CLOCK_CAPTURE:
iter = begin(TagType::DATA_ARRIVAL);
break;
case TagType::DATA_ARRIVAL:
iter = begin(TagType::DATA_REQUIRED);
break;
case TagType::DATA_REQUIRED:
iter = begin(TagType::SLACK);
break;
case TagType::SLACK:
//Pass the true end
iter = end();
break;
default:
TATUM_ASSERT_MSG(false, "Invalid tag type");
}
TATUM_ASSERT_SAFE(iter.p_ >= tags_.get() && iter.p_ <= tags_.get() + size());
return iter;
}
inline TimingTags::tag_range TimingTags::tags() const {
return tatum::util::make_range(begin(), end());
}
inline TimingTags::tag_range TimingTags::tags(const TagType type) const {
return tatum::util::make_range(begin(type), end(type));
}
//Modifiers
inline void TimingTags::add_tag(const TimingTag& tag) {
//Find the position to insert this tag
//
//We keep tags of the same type together.
//We also prefer to insert new tags at the end if possible
//(since this is more efficient for the underlying vector storage)
auto iter = end(tag.type());
//Insert the tag before the upper bound position
// This ensures tags_ is always in sorted order
insert(iter, tag);
}
inline void TimingTags::max(const Time& new_time, const NodeId origin, const TimingTag& base_tag, bool arr_must_be_valid) {
auto bool_iter = find_matching_tag(base_tag, arr_must_be_valid);
bool valid = bool_iter.first;
if(valid) {
auto iter = bool_iter.second;
if(iter == end(base_tag.type())) {
//An exact match was not found
//First time we've seen this domain
TimingTag tag = TimingTag(new_time, origin, base_tag);
add_tag(tag);
} else {
iter->max(new_time, origin, base_tag);
}
}
}
inline void TimingTags::min(const Time& new_time, const NodeId origin, const TimingTag& base_tag, bool arr_must_be_valid) {
auto bool_iter = find_matching_tag(base_tag, arr_must_be_valid);
bool valid = bool_iter.first;
if(valid) {
auto iter = bool_iter.second;
if(iter == end(base_tag.type())) {
//An exact match was not found
//First time we've seen this domain
TimingTag tag = TimingTag(new_time, origin, base_tag);
add_tag(tag);
} else {
iter->min(new_time, origin, base_tag);
}
}
}
inline void TimingTags::clear() {
size_ = 0;
num_clock_launch_tags_ = 0;
num_clock_capture_tags_ = 0;
num_data_arrival_tags_ = 0;
num_data_required_tags_ = 0;
}
inline std::pair<bool,TimingTags::iterator> TimingTags::find_matching_tag(const TimingTag& tag, bool arr_must_be_valid) {
if(arr_must_be_valid) {
TATUM_ASSERT(tag.type() == TagType::DATA_REQUIRED);
auto bool_iter = find_data_required_with_valid_data_arrival(tag.launch_clock_domain(), tag.capture_clock_domain());
return bool_iter;
} else {
auto iter = find_matching_tag(tag.type(), tag.launch_clock_domain(), tag.capture_clock_domain());
return {true, iter};
}
}
inline TimingTags::iterator TimingTags::find_matching_tag(TagType type, DomainId launch_domain, DomainId capture_domain) {
//Linear search for matching tag
auto b = begin(type);
auto e = end(type);
for(auto iter = b; iter != e; ++iter) {
bool match_launch = !launch_domain //Search wildcard
|| !iter->launch_clock_domain() //Match wildcard
|| launch_domain == iter->launch_clock_domain(); //Exact match
bool match_capture = !capture_domain //Search wildcard
|| !iter->capture_clock_domain() //Match wildcard
|| capture_domain == iter->capture_clock_domain(); //Exact match
if(match_launch && match_capture) {
return iter;
}
}
return e;
}
inline std::pair<bool,TimingTags::iterator> TimingTags::find_data_required_with_valid_data_arrival(DomainId launch_domain, DomainId capture_domain) {
//Look for the matching arrival
auto arr_iter = find_matching_tag(TagType::DATA_ARRIVAL, launch_domain, DomainId::INVALID());
if(arr_iter == end(TagType::DATA_ARRIVAL) || !arr_iter->time().valid()) {
//No valid arrival
return {false, end(TagType::DATA_REQUIRED)};
}
//Find the matching required
return {true, find_matching_tag(TagType::DATA_REQUIRED, launch_domain, capture_domain)};
}
inline size_t TimingTags::capacity() const { return capacity_; }
inline TimingTags::iterator TimingTags::insert(iterator iter, const TimingTag& tag) {
size_t index = std::distance(begin(), iter);
TATUM_ASSERT(index <= size());
if(capacity() == 0 || capacity() == size()) {
//Grow and insert simultaneously
grow_insert(index, tag);
} else {
//Insert into existing capacity
TATUM_ASSERT(size() + 1 <= capacity());
//Shift everything one position right from end to index
//TODO: use std::copy_backward?
for(size_t i = size(); i != index; --i) {
tags_[i] = tags_[i - 1];
}
//Insert the new value in the hole at index created by shifting
tags_[index] = tag;
//Update the sizes
increment_size(tag.type());
}
return begin() + index;
}
inline void TimingTags::grow_insert(size_t index, const TimingTag& tag) {
size_t new_capacity = (capacity() == 0) ? 1 : GROWTH_FACTOR * capacity();
//We construct a new copy of ourselves at the new capacity and with the new
//tag inserted
TimingTags new_tags(new_capacity);
std::copy_n(tags_.get(), index, new_tags.tags_.get()); //Copy before index
new_tags.tags_[index] = tag; //Insert the new value
std::copy_n(tags_.get() + index, size() - index, new_tags.tags_.get() + index + 1); //Copy after index
//Copy the sizes
new_tags.size_ = size_;
new_tags.num_clock_launch_tags_ = num_clock_launch_tags_;
new_tags.num_clock_capture_tags_ = num_clock_capture_tags_;
new_tags.num_data_arrival_tags_ = num_data_arrival_tags_;
new_tags.num_data_required_tags_ = num_data_required_tags_;
//Increment to account for the inserted tag
new_tags.increment_size(tag.type());
//Update ourselves
swap(*this, new_tags);
}
inline void TimingTags::increment_size(TagType type) {
++size_;
switch(type) {
case TagType::CLOCK_LAUNCH:
++num_clock_launch_tags_;
break;
case TagType::CLOCK_CAPTURE:
++num_clock_capture_tags_;
break;
case TagType::DATA_ARRIVAL:
++num_data_arrival_tags_;
break;
case TagType::DATA_REQUIRED:
++num_data_required_tags_;
break;
case TagType::SLACK:
//Pass
break;
default:
TATUM_ASSERT_MSG(false, "Invalid tag type");
}
}
inline void swap(TimingTags& lhs, TimingTags& rhs) {
std::swap(lhs.tags_, rhs.tags_);
std::swap(lhs.num_clock_launch_tags_, rhs.num_clock_launch_tags_);
std::swap(lhs.num_clock_capture_tags_, rhs.num_clock_capture_tags_);
std::swap(lhs.num_data_arrival_tags_, rhs.num_data_arrival_tags_);
std::swap(lhs.num_data_required_tags_, rhs.num_data_required_tags_);
std::swap(lhs.size_, rhs.size_);
std::swap(lhs.capacity_, rhs.capacity_);
}
} //namepsace