@@ -7,15 +7,154 @@ t_ext_pin_util_targets::t_ext_pin_util_targets(float default_in_util, float defa
77 defaults_.output_pin_util = default_out_util;
88}
99
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 {
11127 auto itr = overrides_.find (block_type_name);
12128 if (itr != overrides_.end ()) {
13129 return itr->second ;
14130 }
15131 return defaults_;
16132}
17133
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) {
19158 overrides_[block_type_name] = target;
20159}
21160
@@ -26,22 +165,120 @@ void t_ext_pin_util_targets::set_default_pin_util(t_ext_pin_util default_target)
26165t_pack_high_fanout_thresholds::t_pack_high_fanout_thresholds (int threshold)
27166 : default_(threshold) {}
28167
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+
29243void t_pack_high_fanout_thresholds::set_default (int threshold) {
30244 default_ = threshold;
31245}
32246
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) {
34248 overrides_[block_type_name] = threshold;
35249}
36250
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 {
38252 auto itr = overrides_.find (block_type_name);
39253 if (itr != overrides_.end ()) {
40254 return itr->second ;
41255 }
42256 return default_;
43257}
44258
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+
45282/*
46283 * t_pb structure function definitions
47284 */
0 commit comments