Skip to content

Commit c8bd8b1

Browse files
authored
Merge pull request #2421 from verilog-to-routing/init_noc_sa
Initial NoC Placement
2 parents 97996a2 + 4357180 commit c8bd8b1

24 files changed

+1091
-449
lines changed

vpr/src/base/read_options.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2823,7 +2823,7 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg
28232823
.help(
28242824
"Sets the minimum fraction of swaps attempted by the placer that are NoC blocks."
28252825
"This value is an integer ranging from 0-100. 0 means NoC blocks will be moved at the same rate as other blocks. 100 means all swaps attempted by the placer are NoC router blocks.")
2826-
.default_value("40")
2826+
.default_value("0")
28272827
.show_in(argparse::ShowIn::HELP_ONLY);
28282828

28292829
noc_grp.add_argument<std::string>(args.noc_placement_file_name, "--noc_placement_file_name")

vpr/src/base/vpr_context.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,11 @@ struct ClusteringHelperContext : public Context {
344344
// the utilization of external input/output pins during packing (between 0 and 1)
345345
t_ext_pin_util_targets target_external_pin_util;
346346

347+
// During clustering, a block is related to un-clustered primitives with nets.
348+
// This relation has three types: low fanout, high fanout, and trasitive
349+
// high_fanout_thresholds stores the threshold for nets to a block type to be considered high fanout
350+
t_pack_high_fanout_thresholds high_fanout_thresholds;
351+
347352
// A vector of unordered_sets of AtomBlockIds that are inside each clustered block [0 .. num_clustered_blocks-1]
348353
// unordered_set for faster insertion/deletion during the iterative improvement process of packing
349354
vtr::vector<ClusterBlockId, std::unordered_set<AtomBlockId>> atoms_lookup;

vpr/src/base/vpr_types.cpp

Lines changed: 241 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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)
26165
t_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+
29243
void 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
*/

vpr/src/base/vpr_types.h

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -194,16 +194,21 @@ class t_ext_pin_util_targets {
194194
public:
195195
t_ext_pin_util_targets() = default;
196196
t_ext_pin_util_targets(float default_in_util, float default_out_util);
197+
t_ext_pin_util_targets(const std::vector<std::string>& specs);
198+
t_ext_pin_util_targets& operator=(t_ext_pin_util_targets&& other) noexcept;
197199

198200
///@brief Returns the input pin util of the specified block (or default if unspecified)
199-
t_ext_pin_util get_pin_util(std::string block_type_name) const;
201+
t_ext_pin_util get_pin_util(const std::string& block_type_name) const;
202+
203+
///@brief Returns a string describing input/output pin utilization targets
204+
std::string to_string() const;
200205

201206
public:
202207
/**
203208
* @brief Sets the pin util for the specified block type
204209
* @return true if non-default was previously set
205210
*/
206-
void set_block_pin_util(std::string block_type_name, t_ext_pin_util target);
211+
void set_block_pin_util(const std::string& block_type_name, t_ext_pin_util target);
207212

208213
/**
209214
* @brief Sets the default pin util
@@ -219,16 +224,22 @@ class t_ext_pin_util_targets {
219224
class t_pack_high_fanout_thresholds {
220225
public:
221226
t_pack_high_fanout_thresholds() = default;
222-
t_pack_high_fanout_thresholds(int threshold);
227+
explicit t_pack_high_fanout_thresholds(int threshold);
228+
explicit t_pack_high_fanout_thresholds(const std::vector<std::string>& specs);
229+
t_pack_high_fanout_thresholds& operator=(t_pack_high_fanout_thresholds&& other) noexcept;
230+
231+
///@brief Returns the high fanout threshold of the specifi ed block
232+
int get_threshold(const std::string& block_type_name) const;
223233

224-
int get_threshold(std::string block_type_name) const;
234+
///@brief Returns a string describing high fanout thresholds for different block types
235+
std::string to_string() const;
225236

226237
public:
227238
/**
228239
* @brief Sets the pin util for the specified block type
229240
* @return true if non-default was previously set
230241
*/
231-
void set(std::string block_type_name, int threshold);
242+
void set(const std::string& block_type_name, int threshold);
232243

233244
/**
234245
* @brief Sets the default pin util
@@ -723,6 +734,11 @@ struct t_pl_loc {
723734
, y(yloc)
724735
, sub_tile(sub_tile_loc)
725736
, layer(layer_num) {}
737+
t_pl_loc(const t_physical_tile_loc& phy_loc, int sub_tile_loc)
738+
: x(phy_loc.x)
739+
, y(phy_loc.y)
740+
, sub_tile(sub_tile_loc)
741+
, layer(phy_loc.layer_num) {}
726742

727743
int x = OPEN;
728744
int y = OPEN;

vpr/src/noc/noc_router.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ int NocRouter::get_router_layer_position(void) const {
2727
return router_layer_position;
2828
}
2929

30+
t_physical_tile_loc NocRouter::get_router_physical_location(void) const {
31+
const int x = get_router_grid_position_x();
32+
const int y = get_router_grid_position_y();
33+
const int layer = get_router_layer_position();
34+
t_physical_tile_loc phy_loc{x, y, layer};
35+
36+
return phy_loc;
37+
}
38+
3039
ClusterBlockId NocRouter::get_router_block_ref(void) const {
3140
return router_block_ref;
3241
}

vpr/src/noc/noc_router.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ class NocRouter {
8686
*/
8787
int get_router_layer_position(void) const;
8888

89+
/**
90+
* @brief Gets the physical location where the the physical router is located
91+
* @return t_physical_tile_loc that contains x-y coordinates and the layer number
92+
*/
93+
t_physical_tile_loc get_router_physical_location(void) const;
94+
8995
/**
9096
* @brief Gets the unique id of the router block that is current placed on the physical router
9197
* @return A ClusterBlockId that identifies a router block in the clustered netlist

0 commit comments

Comments
 (0)