@@ -7,15 +7,154 @@ t_ext_pin_util_targets::t_ext_pin_util_targets(float default_in_util, float defa
7
7
defaults_.output_pin_util = default_out_util;
8
8
}
9
9
10
- t_ext_pin_util t_ext_pin_util_targets::get_pin_util (std::string block_type_name) const {
10
+ t_ext_pin_util_targets::t_ext_pin_util_targets (const std::vector<std::string>& specs)
11
+ : t_ext_pin_util_targets(1 ., 1 .) {
12
+ if (specs.size () == 1 && specs[0 ] == " auto" ) {
13
+ // No user-specified pin utilizations, infer them automatically.
14
+ //
15
+ // We set a pin utilization target based on the block type, with
16
+ // the logic block having a lower utilization target and other blocks
17
+ // (e.g. hard blocks) having no limit.
18
+
19
+ auto & device_ctx = g_vpr_ctx.device ();
20
+ auto & grid = device_ctx.grid ;
21
+ t_logical_block_type_ptr logic_block_type = infer_logic_block_type (grid);
22
+
23
+ // Allowing 100% pin utilization of the logic block type can harm
24
+ // routability, since it may allow a few (typically outlier) clusters to
25
+ // use a very large number of pins -- causing routability issues. These
26
+ // clusters can cause failed routings where only a handful of routing
27
+ // resource nodes remain overused (and do not resolve) These can be
28
+ // avoided by putting a (soft) limit on the number of input pins which
29
+ // can be used, effectively clipping off the most egregeous outliers.
30
+ //
31
+ // Experiments show that limiting input utilization produces better quality
32
+ // than limiting output utilization (limiting input utilization implicitly
33
+ // also limits output utilization).
34
+ //
35
+ // For relatively high pin utilizations (e.g. > 70%) this has little-to-no
36
+ // impact on the number of clusters required. As a result we set a default
37
+ // input pin utilization target which is high, but less than 100%.
38
+ if (logic_block_type != nullptr ) {
39
+ constexpr float LOGIC_BLOCK_TYPE_AUTO_INPUT_UTIL = 0.8 ;
40
+ constexpr float LOGIC_BLOCK_TYPE_AUTO_OUTPUT_UTIL = 1.0 ;
41
+
42
+ t_ext_pin_util logic_block_ext_pin_util (LOGIC_BLOCK_TYPE_AUTO_INPUT_UTIL, LOGIC_BLOCK_TYPE_AUTO_OUTPUT_UTIL);
43
+
44
+ set_block_pin_util (logic_block_type->name , logic_block_ext_pin_util);
45
+ } else {
46
+ VTR_LOG_WARN (" Unable to identify logic block type to apply default pin utilization targets to; this may result in denser packing than desired\n " );
47
+ }
48
+
49
+ } else {
50
+ // Process user specified overrides
51
+
52
+ bool default_set = false ;
53
+ std::set<std::string> seen_block_types;
54
+
55
+ for (const auto & spec : specs) {
56
+ t_ext_pin_util target_ext_pin_util (1 ., 1 .);
57
+
58
+ auto block_values = vtr::split (spec, " :" );
59
+ std::string block_type;
60
+ std::string values;
61
+ if (block_values.size () == 2 ) {
62
+ block_type = block_values[0 ];
63
+ values = block_values[1 ];
64
+ } else if (block_values.size () == 1 ) {
65
+ values = block_values[0 ];
66
+ } else {
67
+ std::stringstream msg;
68
+ msg << " In valid block pin utilization specification '" << spec << " ' (expected at most one ':' between block name and values" ;
69
+ VPR_FATAL_ERROR (VPR_ERROR_PACK, msg.str ().c_str ());
70
+ }
71
+
72
+ auto elements = vtr::split (values, " ," );
73
+ if (elements.size () == 1 ) {
74
+ target_ext_pin_util.input_pin_util = vtr::atof (elements[0 ]);
75
+ } else if (elements.size () == 2 ) {
76
+ target_ext_pin_util.input_pin_util = vtr::atof (elements[0 ]);
77
+ target_ext_pin_util.output_pin_util = vtr::atof (elements[1 ]);
78
+ } else {
79
+ std::stringstream msg;
80
+ msg << " Invalid conversion from '" << spec << " ' to external pin util (expected either a single float value, or two float values separted by a comma)" ;
81
+ VPR_FATAL_ERROR (VPR_ERROR_PACK, msg.str ().c_str ());
82
+ }
83
+
84
+ if (target_ext_pin_util.input_pin_util < 0 . || target_ext_pin_util.input_pin_util > 1 .) {
85
+ std::stringstream msg;
86
+ msg << " Out of range target input pin utilization '" << target_ext_pin_util.input_pin_util << " ' (expected within range [0.0, 1.0])" ;
87
+ VPR_FATAL_ERROR (VPR_ERROR_PACK, msg.str ().c_str ());
88
+ }
89
+ if (target_ext_pin_util.output_pin_util < 0 . || target_ext_pin_util.output_pin_util > 1 .) {
90
+ std::stringstream msg;
91
+ msg << " Out of range target output pin utilization '" << target_ext_pin_util.output_pin_util << " ' (expected within range [0.0, 1.0])" ;
92
+ VPR_FATAL_ERROR (VPR_ERROR_PACK, msg.str ().c_str ());
93
+ }
94
+
95
+ if (block_type.empty ()) {
96
+ // Default value
97
+ if (default_set) {
98
+ std::stringstream msg;
99
+ msg << " Only one default pin utilization should be specified" ;
100
+ VPR_FATAL_ERROR (VPR_ERROR_PACK, msg.str ().c_str ());
101
+ }
102
+ set_default_pin_util (target_ext_pin_util);
103
+ default_set = true ;
104
+ } else {
105
+ if (seen_block_types.count (block_type)) {
106
+ std::stringstream msg;
107
+ msg << " Only one pin utilization should be specified for block type '" << block_type << " '" ;
108
+ VPR_FATAL_ERROR (VPR_ERROR_PACK, msg.str ().c_str ());
109
+ }
110
+
111
+ set_block_pin_util (block_type, target_ext_pin_util);
112
+ seen_block_types.insert (block_type);
113
+ }
114
+ }
115
+ }
116
+ }
117
+
118
+ t_ext_pin_util_targets& t_ext_pin_util_targets::operator =(t_ext_pin_util_targets&& other) noexcept {
119
+ if (this != &other) {
120
+ defaults_ = std::move (other.defaults_ );
121
+ overrides_ = std::move (other.overrides_ );
122
+ }
123
+ return *this ;
124
+ }
125
+
126
+ t_ext_pin_util t_ext_pin_util_targets::get_pin_util (const std::string& block_type_name) const {
11
127
auto itr = overrides_.find (block_type_name);
12
128
if (itr != overrides_.end ()) {
13
129
return itr->second ;
14
130
}
15
131
return defaults_;
16
132
}
17
133
18
- void t_ext_pin_util_targets::set_block_pin_util (std::string block_type_name, t_ext_pin_util target) {
134
+ std::string t_ext_pin_util_targets::to_string () const {
135
+ std::stringstream ss;
136
+
137
+ auto & device_ctx = g_vpr_ctx.device ();
138
+
139
+ for (unsigned int itype = 0 ; itype < device_ctx.physical_tile_types .size (); ++itype) {
140
+ if (is_empty_type (&device_ctx.physical_tile_types [itype])) continue ;
141
+
142
+ auto blk_name = device_ctx.physical_tile_types [itype].name ;
143
+
144
+ ss << blk_name << " :" ;
145
+
146
+ auto pin_util = get_pin_util (blk_name);
147
+ ss << pin_util.input_pin_util << ' ,' << pin_util.output_pin_util ;
148
+
149
+ if (itype != device_ctx.physical_tile_types .size () - 1 ) {
150
+ ss << " " ;
151
+ }
152
+ }
153
+
154
+ return ss.str ();
155
+ }
156
+
157
+ void t_ext_pin_util_targets::set_block_pin_util (const std::string& block_type_name, t_ext_pin_util target) {
19
158
overrides_[block_type_name] = target;
20
159
}
21
160
@@ -26,22 +165,120 @@ void t_ext_pin_util_targets::set_default_pin_util(t_ext_pin_util default_target)
26
165
t_pack_high_fanout_thresholds::t_pack_high_fanout_thresholds (int threshold)
27
166
: default_(threshold) {}
28
167
168
+ t_pack_high_fanout_thresholds::t_pack_high_fanout_thresholds (const std::vector<std::string>& specs)
169
+ : t_pack_high_fanout_thresholds(128 ) {
170
+ if (specs.size () == 1 && specs[0 ] == " auto" ) {
171
+ // No user-specified high fanout thresholds, infer them automatically.
172
+ //
173
+ // We set the high fanout threshold a based on the block type, with
174
+ // the logic block having a lower threshold than other blocks.
175
+ // (Since logic blocks are the ones which tend to be too densely
176
+ // clustered.)
177
+
178
+ auto & device_ctx = g_vpr_ctx.device ();
179
+ auto & grid = device_ctx.grid ;
180
+ t_logical_block_type_ptr logic_block_type = infer_logic_block_type (grid);
181
+
182
+ if (logic_block_type != nullptr ) {
183
+ constexpr float LOGIC_BLOCK_TYPE_HIGH_FANOUT_THRESHOLD = 32 ;
184
+
185
+ set (logic_block_type->name , LOGIC_BLOCK_TYPE_HIGH_FANOUT_THRESHOLD);
186
+ } else {
187
+ VTR_LOG_WARN (" Unable to identify logic block type to apply default packer high fanout thresholds; this may result in denser packing than desired\n " );
188
+ }
189
+ } else {
190
+ // Process user specified overrides
191
+
192
+ bool default_set = false ;
193
+ std::set<std::string> seen_block_types;
194
+
195
+ for (const auto & spec : specs) {
196
+ auto block_values = vtr::split (spec, " :" );
197
+ std::string block_type;
198
+ std::string value;
199
+ if (block_values.size () == 1 ) {
200
+ value = block_values[0 ];
201
+ } else if (block_values.size () == 2 ) {
202
+ block_type = block_values[0 ];
203
+ value = block_values[1 ];
204
+ } else {
205
+ std::stringstream msg;
206
+ msg << " In valid block high fanout threshold specification '" << spec << " ' (expected at most one ':' between block name and value" ;
207
+ VPR_FATAL_ERROR (VPR_ERROR_PACK, msg.str ().c_str ());
208
+ }
209
+
210
+ int threshold = vtr::atoi (value);
211
+
212
+ if (block_type.empty ()) {
213
+ // Default value
214
+ if (default_set) {
215
+ std::stringstream msg;
216
+ msg << " Only one default high fanout threshold should be specified" ;
217
+ VPR_FATAL_ERROR (VPR_ERROR_PACK, msg.str ().c_str ());
218
+ }
219
+ set_default (threshold);
220
+ default_set = true ;
221
+ } else {
222
+ if (seen_block_types.count (block_type)) {
223
+ std::stringstream msg;
224
+ msg << " Only one high fanout threshold should be specified for block type '" << block_type << " '" ;
225
+ VPR_FATAL_ERROR (VPR_ERROR_PACK, msg.str ().c_str ());
226
+ }
227
+
228
+ set (block_type, threshold);
229
+ seen_block_types.insert (block_type);
230
+ }
231
+ }
232
+ }
233
+ }
234
+
235
+ t_pack_high_fanout_thresholds& t_pack_high_fanout_thresholds::operator =(t_pack_high_fanout_thresholds&& other) noexcept {
236
+ if (this != &other) {
237
+ default_ = std::move (other.default_ );
238
+ overrides_ = std::move (other.overrides_ );
239
+ }
240
+ return *this ;
241
+ }
242
+
29
243
void t_pack_high_fanout_thresholds::set_default (int threshold) {
30
244
default_ = threshold;
31
245
}
32
246
33
- void t_pack_high_fanout_thresholds::set (std::string block_type_name, int threshold) {
247
+ void t_pack_high_fanout_thresholds::set (const std::string& block_type_name, int threshold) {
34
248
overrides_[block_type_name] = threshold;
35
249
}
36
250
37
- int t_pack_high_fanout_thresholds::get_threshold (std::string block_type_name) const {
251
+ int t_pack_high_fanout_thresholds::get_threshold (const std::string& block_type_name) const {
38
252
auto itr = overrides_.find (block_type_name);
39
253
if (itr != overrides_.end ()) {
40
254
return itr->second ;
41
255
}
42
256
return default_;
43
257
}
44
258
259
+ std::string t_pack_high_fanout_thresholds::to_string () const {
260
+ std::stringstream ss;
261
+
262
+ auto & device_ctx = g_vpr_ctx.device ();
263
+
264
+ for (unsigned int itype = 0 ; itype < device_ctx.physical_tile_types .size (); ++itype) {
265
+ if (is_empty_type (&device_ctx.physical_tile_types [itype])) continue ;
266
+
267
+ auto blk_name = device_ctx.physical_tile_types [itype].name ;
268
+
269
+ ss << blk_name << " :" ;
270
+
271
+ auto threshold = get_threshold (blk_name);
272
+ ss << threshold;
273
+
274
+ if (itype != device_ctx.physical_tile_types .size () - 1 ) {
275
+ ss << " " ;
276
+ }
277
+ }
278
+
279
+ return ss.str ();
280
+ }
281
+
45
282
/*
46
283
* t_pb structure function definitions
47
284
*/
0 commit comments