Skip to content

Commit 646dffd

Browse files
committed
Squashed 'libs/EXTERNAL/libtatum/' changes from 072337571..15296d1a4
15296d1a4 Add multiclock test with capture node specific constraints 88da6480e Tweak handling of per-capture node constraints to fix timing reports e387a3f38 Fix --print_sizes option to tatum_test 099e52c26 Fix increment offset in timing reports 9578baa3e Update echo writers/loaders to support per-capture-node constraints 16ed6a760 Update traversals to support per-capture node constraints 7e8bc45cc Fix comment typo b9aa2ab90 Add support for specifying per-capture node setup/hold constraints 68c291551 Simplify comparison operator git-subtree-dir: libs/EXTERNAL/libtatum git-subtree-split: 15296d1a47ecbd2f737db0f3148d870aeef0b01c
1 parent 9fbc440 commit 646dffd

17 files changed

+782
-74
lines changed

libtatum/tatum/TimingConstraints.cpp

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -97,28 +97,49 @@ DomainId TimingConstraints::find_clock_domain(const std::string& name) const {
9797
return DomainId::INVALID();
9898
}
9999

100-
bool TimingConstraints::should_analyze(const DomainId src_domain, const DomainId sink_domain) const {
100+
bool TimingConstraints::should_analyze(const DomainId src_domain, const DomainId sink_domain, const NodeId capture_node) const {
101101
TATUM_ASSERT(src_domain);
102102
TATUM_ASSERT(sink_domain);
103-
return setup_constraints_.count(DomainPair(src_domain, sink_domain))
104-
|| hold_constraints_.count(DomainPair(src_domain, sink_domain));
103+
104+
//If there is a domain pair + capture node or domain pair constraint then it should be analyzed
105+
return setup_constraints_.count(NodeDomainPair(src_domain, sink_domain, capture_node))
106+
|| setup_constraints_.count(NodeDomainPair(src_domain, sink_domain, NodeId::INVALID()))
107+
|| hold_constraints_.count(NodeDomainPair(src_domain, sink_domain, capture_node))
108+
|| hold_constraints_.count(NodeDomainPair(src_domain, sink_domain, NodeId::INVALID()));
105109
}
106110

107-
Time TimingConstraints::hold_constraint(const DomainId src_domain, const DomainId sink_domain) const {
108-
auto iter = hold_constraints_.find(DomainPair(src_domain, sink_domain));
109-
if(iter == hold_constraints_.end()) {
110-
return std::numeric_limits<Time>::quiet_NaN();
111+
Time TimingConstraints::hold_constraint(const DomainId src_domain, const DomainId sink_domain, const NodeId capture_node) const {
112+
//Try to find the capture node-specific constraint
113+
auto iter = hold_constraints_.find(NodeDomainPair(src_domain, sink_domain, capture_node));
114+
if(iter != hold_constraints_.end()) {
115+
return iter->second;
111116
}
112117

113-
return iter->second;
118+
//If no capture node specific constraint was found, fallback to the domain pair constriant
119+
iter = hold_constraints_.find(NodeDomainPair(src_domain, sink_domain, NodeId::INVALID()));
120+
if(iter != hold_constraints_.end()) {
121+
return iter->second;
122+
}
123+
124+
//No constraint found
125+
return std::numeric_limits<Time>::quiet_NaN();
114126
}
115-
Time TimingConstraints::setup_constraint(const DomainId src_domain, const DomainId sink_domain) const {
116-
auto iter = setup_constraints_.find(DomainPair(src_domain, sink_domain));
117-
if(iter == setup_constraints_.end()) {
118-
return std::numeric_limits<Time>::quiet_NaN();
127+
128+
Time TimingConstraints::setup_constraint(const DomainId src_domain, const DomainId sink_domain, const NodeId capture_node) const {
129+
//Try to find the capture node-specific constraint
130+
auto iter = setup_constraints_.find(NodeDomainPair(src_domain, sink_domain, capture_node));
131+
if(iter != setup_constraints_.end()) {
132+
return iter->second;
119133
}
120134

121-
return iter->second;
135+
//If no capture node specific constraint was found, fallback to the domain pair constriant
136+
iter = setup_constraints_.find(NodeDomainPair(src_domain, sink_domain, NodeId::INVALID()));
137+
if(iter != setup_constraints_.end()) {
138+
return iter->second;
139+
}
140+
141+
//No constraint found
142+
return std::numeric_limits<Time>::quiet_NaN();
122143
}
123144

124145
Time TimingConstraints::setup_clock_uncertainty(const DomainId src_domain, const DomainId sink_domain) const {
@@ -283,12 +304,19 @@ DomainId TimingConstraints::create_clock_domain(const std::string name) {
283304
}
284305

285306
void TimingConstraints::set_setup_constraint(const DomainId src_domain, const DomainId sink_domain, const Time constraint) {
286-
auto key = DomainPair(src_domain, sink_domain);
307+
set_setup_constraint(src_domain, sink_domain, NodeId::INVALID(), constraint);
308+
}
309+
void TimingConstraints::set_setup_constraint(const DomainId src_domain, const DomainId sink_domain, const NodeId capture_node, const Time constraint) {
310+
auto key = NodeDomainPair(src_domain, sink_domain, capture_node);
287311
setup_constraints_[key] = constraint;
288312
}
289313

290314
void TimingConstraints::set_hold_constraint(const DomainId src_domain, const DomainId sink_domain, const Time constraint) {
291-
auto key = DomainPair(src_domain, sink_domain);
315+
set_hold_constraint(src_domain, sink_domain, NodeId::INVALID(), constraint);
316+
}
317+
318+
void TimingConstraints::set_hold_constraint(const DomainId src_domain, const DomainId sink_domain, const NodeId capture_node, const Time constraint) {
319+
auto key = NodeDomainPair(src_domain, sink_domain, capture_node);
292320
hold_constraints_[key] = constraint;
293321
}
294322

@@ -432,17 +460,19 @@ void TimingConstraints::print_constraints() const {
432460
for(auto kv : setup_constraints()) {
433461
auto key = kv.first;
434462
Time constraint = kv.second;
435-
cout << "SRC: " << key.src_domain_id;
436-
cout << " SINK: " << key.sink_domain_id;
463+
cout << "SRC: " << key.domain_pair.src_domain_id;
464+
cout << " SINK: " << key.domain_pair.sink_domain_id;
465+
cout << " CAPTURE_NODE: " << key.capture_node;
437466
cout << " Constraint: " << constraint;
438467
cout << endl;
439468
}
440469
cout << "Hold Clock Constraints" << endl;
441470
for(auto kv : hold_constraints()) {
442471
auto key = kv.first;
443472
Time constraint = kv.second;
444-
cout << "SRC: " << key.src_domain_id;
445-
cout << " SINK: " << key.sink_domain_id;
473+
cout << "SRC: " << key.domain_pair.src_domain_id;
474+
cout << " SINK: " << key.domain_pair.sink_domain_id;
475+
cout << " CAPTURE_NODE: " << key.capture_node;
446476
cout << " Constraint: " << constraint;
447477
cout << endl;
448478
}

libtatum/tatum/TimingConstraints.hpp

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ namespace tatum {
2222
class TimingConstraints {
2323
public: //Types
2424
typedef tatum::util::linear_map<DomainId,DomainId>::const_iterator domain_iterator;
25-
typedef std::map<DomainPair,Time>::const_iterator clock_constraint_iterator;
25+
typedef std::map<NodeDomainPair,Time>::const_iterator clock_constraint_iterator;
2626
typedef std::map<DomainPair,Time>::const_iterator clock_uncertainty_iterator;
2727
typedef std::multimap<NodeId,IoConstraint>::const_iterator io_constraint_iterator;
2828
typedef std::map<DomainId,Time>::const_iterator source_latency_iterator;
@@ -63,13 +63,13 @@ class TimingConstraints {
6363
///Indicates whether the paths between src_domain and sink_domain should be analyzed
6464
///\param src_domain The ID of the source (launch) clock domain
6565
///\param sink_domain The ID of the sink (capture) clock domain
66-
bool should_analyze(const DomainId src_domain, const DomainId sink_domain) const;
66+
bool should_analyze(const DomainId src_domain, const DomainId sink_domain, const NodeId capture_node=NodeId::INVALID()) const;
6767

68-
///\returns The setup (max) constraint between src_domain and sink_domain
69-
Time setup_constraint(const DomainId src_domain, const DomainId sink_domain) const;
68+
///\returns The setup (max) constraint between src_domain and sink_domain at the specified capture_node_id
69+
Time setup_constraint(const DomainId src_domain, const DomainId sink_domain, const NodeId capture_node=NodeId::INVALID()) const;
7070

71-
///\returns The hold (min) constraint between src_domain and sink_domain
72-
Time hold_constraint(const DomainId src_domain, const DomainId sink_domain) const;
71+
///\returns The hold (min) constraint between src_domain and sink_domain at the specified capture_node_id
72+
Time hold_constraint(const DomainId src_domain, const DomainId sink_domain, const NodeId capture_node=NodeId::INVALID()) const;
7373

7474
///\returns The setup clock uncertainty between src_domain and sink_domain (defaults to zero if unspecified)
7575
Time setup_clock_uncertainty(const DomainId src_domain, const DomainId sink_domain) const;
@@ -126,9 +126,11 @@ class TimingConstraints {
126126

127127
///Sets the setup constraint between src_domain and sink_domain with value constraint
128128
void set_setup_constraint(const DomainId src_domain, const DomainId sink_domain, const Time constraint);
129+
void set_setup_constraint(const DomainId src_domain, const DomainId sink_domain, const NodeId capture_node, const Time constraint);
129130

130131
///Sets the hold constraint between src_domain and sink_domain with value constraint
131132
void set_hold_constraint(const DomainId src_domain, const DomainId sink_domain, const Time constraint);
133+
void set_hold_constraint(const DomainId src_domain, const DomainId sink_domain, const NodeId capture_node, const Time constraint);
132134

133135
///Sets the setup clock uncertainty between src_domain and sink_domain with value uncertainty
134136
void set_setup_clock_uncertainty(const DomainId src_domain, const DomainId sink_domain, const Time uncertainty);
@@ -172,8 +174,11 @@ class TimingConstraints {
172174

173175
std::unordered_set<NodeId> constant_generators_;
174176

175-
std::map<DomainPair,Time> setup_constraints_;
176-
std::map<DomainPair,Time> hold_constraints_;
177+
//The setup/hold constraints between clock domains and sink nodes
178+
//If the key's capture_node is INVALID() it is treated as a wildcard (i.e. default)
179+
//constraint
180+
std::map<NodeDomainPair,Time> setup_constraints_;
181+
std::map<NodeDomainPair,Time> hold_constraints_;
177182

178183
std::map<DomainPair,Time> setup_clock_uncertainties_;
179184
std::map<DomainPair,Time> hold_clock_uncertainties_;
@@ -195,19 +200,25 @@ struct DomainPair {
195200
DomainPair(DomainId src, DomainId sink): src_domain_id(src), sink_domain_id(sink) {}
196201

197202
friend bool operator<(const DomainPair& lhs, const DomainPair& rhs) {
198-
if(lhs.src_domain_id < rhs.src_domain_id) {
199-
return true;
200-
} else if(lhs.src_domain_id == rhs.src_domain_id
201-
&& lhs.sink_domain_id < rhs.sink_domain_id) {
202-
return true;
203-
}
204-
return false;
203+
return std::tie(lhs.src_domain_id, lhs.sink_domain_id) < std::tie(rhs.src_domain_id, rhs.sink_domain_id);
205204
}
206205

207206
DomainId src_domain_id;
208207
DomainId sink_domain_id;
209208
};
210209

210+
struct NodeDomainPair {
211+
NodeDomainPair(DomainId src, DomainId sink, NodeId to_node)
212+
: domain_pair(src, sink), capture_node(to_node) {}
213+
214+
friend bool operator<(const NodeDomainPair& lhs, const NodeDomainPair& rhs) {
215+
return std::tie(lhs.capture_node, lhs.domain_pair) < std::tie(rhs.capture_node, rhs.domain_pair);
216+
}
217+
218+
DomainPair domain_pair;
219+
NodeId capture_node; //Should be treated as a wild-card if capture_node is NodeId::INVALID()
220+
};
221+
211222
struct IoConstraint {
212223
IoConstraint(DomainId domain_id, Time constraint_val): domain(domain_id), constraint(constraint_val) {}
213224

libtatum/tatum/TimingConstraintsFwd.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ namespace tatum {
44

55
//Forward delcaration
66
struct DomainPair;
7+
struct NodeDomainPair;
78
struct IoConstraint;
89
class TimingConstraints;
910

libtatum/tatum/TimingReporter.cpp

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -286,7 +286,9 @@ void TimingReporter::report_timing_path(std::ostream& os, const TimingPath& timi
286286
path_helper.reset_path();
287287

288288
req_path = report_timing_clock_capture_subpath(os, path_helper, timing_path.clock_capture_path(),
289-
path_info.launch_domain(), path_info.capture_domain(), path_info.type());
289+
path_info.launch_domain(), path_info.capture_domain(),
290+
path_info.endpoint(),
291+
path_info.type());
290292

291293
const TimingPathElem& path_elem = timing_path.data_required_element();
292294

@@ -427,7 +429,7 @@ void TimingReporter::report_skew_path(std::ostream& os, const SkewPath& skew_pat
427429

428430
path_helper.reset_path();
429431

430-
Time data_capture_time = report_timing_clock_capture_subpath(os, path_helper, capture_path, skew_path.launch_domain, skew_path.capture_domain, timing_type);
432+
Time data_capture_time = report_timing_clock_capture_subpath(os, path_helper, capture_path, skew_path.launch_domain, skew_path.capture_domain, skew_path.data_capture_node, timing_type);
431433
TATUM_ASSERT(nearly_equal(data_capture_time, skew_path.clock_capture_arrival));
432434

433435
path_helper.update_print_path_no_incr(os, "data capture", data_capture_time);
@@ -463,30 +465,40 @@ Time TimingReporter::report_timing_clock_launch_subpath(std::ostream& os,
463465
path_helper.update_print_path(os, point, path);
464466
}
465467

466-
return report_timing_clock_subpath(os, path_helper, subpath, domain, timing_type, path);
468+
return report_timing_clock_subpath(os, path_helper, subpath, domain, timing_type, path, Time(0.));
467469
}
468470

469471
Time TimingReporter::report_timing_clock_capture_subpath(std::ostream& os,
470472
detail::ReportTimingPathHelper& path_helper,
471473
const TimingSubPath& subpath,
472474
DomainId launch_domain,
473475
DomainId capture_domain,
476+
NodeId capture_node,
474477
TimingType timing_type) const {
475478
Time path(0.);
476-
479+
Time offset(0.); //Offset required since the clock launch tag doesn't have the actual (potentially
480+
//capture node dependent) constraint annotated. We determine this up front by
481+
//looking up the actual constraint and add it into the subpath printed as an offset.
482+
//Note that the required times 'path' values are correct it is only the increments
483+
//which need to be offset when being reported (with the exception of the original
484+
//rising edge).
477485
{
478486
//Launch clock origin
479487
if (timing_type == TimingType::SETUP) {
480-
path += timing_constraints_.setup_constraint(launch_domain, capture_domain);
488+
path = timing_constraints_.setup_constraint(launch_domain, capture_domain, capture_node);
489+
offset = path - timing_constraints_.setup_constraint(launch_domain, capture_domain);
481490
} else {
482491
TATUM_ASSERT(timing_type == TimingType::HOLD);
483-
path += timing_constraints_.hold_constraint(launch_domain, capture_domain);
492+
path = timing_constraints_.hold_constraint(launch_domain, capture_domain, capture_node);
493+
offset = path - timing_constraints_.hold_constraint(launch_domain, capture_domain);
484494
}
495+
496+
//os << "[offset]" << tatum::detail::to_printable_string(offset, 1e-9,3) << "\n";
485497
std::string point = "clock " + timing_constraints_.clock_domain_name(capture_domain) + " (rise edge)";
486498
path_helper.update_print_path(os, point, path);
487499
}
488500

489-
path = report_timing_clock_subpath(os, path_helper, subpath, capture_domain, timing_type, path);
501+
path = report_timing_clock_subpath(os, path_helper, subpath, capture_domain, timing_type, path, offset);
490502

491503
{
492504
//Uncertainty
@@ -498,7 +510,7 @@ Time TimingReporter::report_timing_clock_capture_subpath(std::ostream& os,
498510
uncertainty = Time(timing_constraints_.hold_clock_uncertainty(launch_domain, capture_domain));
499511
}
500512
path += uncertainty;
501-
path_helper.update_print_path(os, "clock uncertainty", path);
513+
path_helper.update_print_path(os, "clock uncertainty", path + offset);
502514
}
503515

504516
return path;
@@ -509,7 +521,8 @@ Time TimingReporter::report_timing_clock_subpath(std::ostream& os,
509521
const TimingSubPath& subpath,
510522
DomainId domain,
511523
TimingType timing_type,
512-
Time path) const {
524+
Time path,
525+
Time offset) const {
513526
{
514527
//Launch clock latency
515528
Time latency;
@@ -560,7 +573,7 @@ Time TimingReporter::report_timing_clock_subpath(std::ostream& os,
560573

561574
path = path_elem.tag().time();
562575

563-
path_helper.update_print_path(os, point, path);
576+
path_helper.update_print_path(os, point, path + offset);
564577
}
565578

566579
return path;

libtatum/tatum/TimingReporter.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ class TimingReporter {
115115
const TimingSubPath& subpath,
116116
DomainId launch_domain,
117117
DomainId capture_domain,
118+
NodeId capture_node,
118119
TimingType timing_type) const;
119120

120121
Time report_timing_data_arrival_subpath(std::ostream& os,
@@ -137,7 +138,8 @@ class TimingReporter {
137138
const TimingSubPath& subpath,
138139
DomainId domain,
139140
TimingType timing_type,
140-
Time path) const;
141+
Time path,
142+
Time offset) const;
141143

142144
bool nearly_equal(const tatum::Time& lhs, const tatum::Time& rhs) const;
143145

libtatum/tatum/echo_writer.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,13 @@ void write_timing_constraints(std::ostream& os, const TimingConstraints& tc) {
160160
auto constraint = kv.second;
161161
if(constraint.valid()) {
162162
os << " type: SETUP_CONSTRAINT";
163-
os << " launch_domain: " << size_t(key.src_domain_id);
164-
os << " capture_domain: " << size_t(key.sink_domain_id);
163+
os << " launch_domain: " << size_t(key.domain_pair.src_domain_id);
164+
os << " capture_domain: " << size_t(key.domain_pair.sink_domain_id);
165+
if (key.capture_node) {
166+
os << " capture_node: " << size_t(key.capture_node);
167+
} else {
168+
os << " capture_node: -1";
169+
}
165170
os << " constraint: " << constraint;
166171
os << "\n";
167172
}
@@ -172,8 +177,13 @@ void write_timing_constraints(std::ostream& os, const TimingConstraints& tc) {
172177
auto constraint = kv.second;
173178
if(constraint.valid()) {
174179
os << " type: HOLD_CONSTRAINT";
175-
os << " launch_domain: " << size_t(key.src_domain_id);
176-
os << " capture_domain: " << size_t(key.sink_domain_id);
180+
os << " launch_domain: " << size_t(key.domain_pair.src_domain_id);
181+
os << " capture_domain: " << size_t(key.domain_pair.sink_domain_id);
182+
if (key.capture_node) {
183+
os << " capture_node: " << size_t(key.capture_node);
184+
} else {
185+
os << " capture_node: -1";
186+
}
177187
os << " constraint: " << constraint;
178188
os << "\n";
179189
}

0 commit comments

Comments
 (0)