Skip to content

Commit ec5332a

Browse files
Merge branch 'master' into temp_add_interposer_wires and resolve conflicts
2 parents 1074e27 + 7f0839d commit ec5332a

File tree

41 files changed

+661
-574
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+661
-574
lines changed

doc/src/Images/Overall_view.png

-125 KB
Loading

doc/src/vpr/graphics.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ Manual Moves
308308

309309
The manual moves feature allows the user to specify the next move in placement. If the move is legal, blocks are swapped and the new move is shown on the architecture.
310310

311+
.. _fig-misc-tab:
311312
.. figure:: ../Images/manual_move.png
312313
:align: center
313314
:width: 25%
@@ -335,3 +336,15 @@ If the manual move is legal, the cost summary window will display the delta cost
335336

336337
The user can Accept or Reject the manual move based on the values provided. If accepted the block's new location is shown.
337338

339+
Pause Button
340+
------------
341+
342+
The pause button allows the user to temporarily stop the program during placement or routing.
343+
When clicked during the placement stage, the program will pause at the next temperature update.
344+
When clicked during the routing stage, it will pause at the next router iteration.
345+
346+
The button can be pressed at any time while the program is running. To enable the feature, click the **Pause** button under the **Misc.** tab (see :ref:`fig-misc-tab`).
347+
Once the program reaches the next temperature update or router iteration after the button is pressed, it will automatically pause.
348+
349+
After the program has paused, clicking **Next Step** allows the user to resume execution from the point where the program was paused.
350+
This can be continuing from the current temperature in placement or from the current router iteration in routing.

doc/src/vtr/get_vtr.rst

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ How to Cite
99
Citations are important in academia, as they ensure contributors receive credit for their efforts.
1010
Therefore please use the following paper as a general citation whenever you use VTR:
1111

12-
M. A. Elgammal, A. Mohaghegh, S. G. Shahrouz, F. Mahmoudi, F. Koşar, K. Talaei, J. Fife, D. Khadivi, K. E. Murray, A. Boutros, K.B. Kent, J. Goeders, V. Betz "VTR 9: Open-Source CAD for Fabric and Beyond FPGA Architecture Exploration" ACM TRETS, 2025
12+
M. A. Elgammal, A. Mohaghegh, S. G. Shahrouz, F. Mahmoudi, F. Koşar, K. Talaei, J. Fife, D. Khadivi, K. E. Murray, A. Boutros, K.B. Kent, J. Goeders, V. Betz "VTR 9: Open-Source CAD for Fabric and Beyond FPGA Architecture Exploration" ACM TRETS, Vol. 13, No. 3, Sept. 2025, pp. 1 - 53.
1313

1414
Bibtex:
1515

@@ -19,6 +19,10 @@ Bibtex:
1919
title={VTR 9: Open-Source CAD for Fabric and Beyond FPGA Architecture Exploration},
2020
author={Elgammal, Mohamed A. and Mohaghegh, Amin and Shahrouz, Soheil G. and Mahmoudi, Fatemehsadat and Kosar, Fahrican and Talaei, Kimia and Fife, Joshua and Khadivi, Daniel and Murray, Kevin and Boutros, Andrew and Kent, Kenneth B. and Goeders, Jeff and Betz, Vaughn},
2121
journal={ACM Trans. Reconfigurable Technol. Syst.},
22+
issue_date = {September 2025},
23+
volume = {18},
24+
number = {3},
25+
numpages = {53},
2226
year={2025}
2327
}
2428

vpr/src/analytical_place/detailed_placer.cpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,6 @@ AnnealerDetailedPlacer::AnnealerDetailedPlacer(const BlkLocRegistry& curr_cluste
7575
}
7676
}
7777

78-
// The solution produced by the AP flow is significantly better than the
79-
// initial placement solution produced by the initial placer in the default
80-
// flow. Even though the annealer auto-selects its initial temperature based
81-
// on the quality of the placement, we found that the initial temperatute was
82-
// still too high and it was hurting quality. This scales down the initial
83-
// temperature auto-selected by the annealer to prevent this and improve
84-
// runtime.
85-
// Here we still scale by whatever the user passed in to scale the initial
86-
// temperature by, but we also scale it down further. This allows AP to scale
87-
// the initial temperature down by default, while still allowing the user
88-
// some control.
89-
float anneal_auto_init_t_scale = vpr_setup.PlacerOpts.place_auto_init_t_scale * 0.5f;
90-
9178
placer_ = std::make_unique<Placer>((const Netlist<>&)clustered_netlist,
9279
curr_clustered_placement,
9380
vpr_setup.PlacerOpts,
@@ -97,7 +84,7 @@ AnnealerDetailedPlacer::AnnealerDetailedPlacer(const BlkLocRegistry& curr_cluste
9784
netlist_pin_lookup_,
9885
FlatPlacementInfo(),
9986
place_delay_model,
100-
anneal_auto_init_t_scale,
87+
vpr_setup.PlacerOpts.place_auto_init_t_scale,
10188
g_vpr_ctx.placement().cube_bb,
10289
false /*is_flat*/,
10390
false /*quiet*/);

vpr/src/base/stats.cpp

Lines changed: 119 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -30,34 +30,34 @@
3030
* channel segments in the FPGA.
3131
*/
3232
static void load_channel_occupancies(const Netlist<>& net_list,
33-
vtr::Matrix<int>& chanx_occ,
34-
vtr::Matrix<int>& chany_occ);
33+
vtr::NdMatrix<int, 3>& chanx_occ,
34+
vtr::NdMatrix<int, 3>& chany_occ);
3535

3636
/**
3737
* @brief Writes channel occupancy data to a file.
3838
*
3939
* Each row contains:
40-
* - (x, y) coordinate
40+
* - (layer, x, y) coordinate
4141
* - Occupancy count
4242
* - Occupancy percentage (occupancy / capacity)
4343
* - Channel capacity
4444
*
4545
* @param filename Output file path.
4646
* @param occupancy Matrix of occupancy counts.
47-
* @param capacity_list List of channel capacities (per y for chanx, per x for chany).
47+
* @param capacity Channel capacities.
4848
*/
49-
static void write_channel_occupancy_table(const std::string_view filename,
50-
const vtr::Matrix<int>& occupancy,
51-
const std::vector<int>& capacity_list);
49+
static void write_channel_occupancy_table(std::string_view filename,
50+
const vtr::NdMatrix<int, 3>& occupancy,
51+
const vtr::NdMatrix<int, 3>& capacity);
5252

5353
/**
5454
* @brief Figures out maximum, minimum and average number of bends
5555
* and net length in the routing.
5656
*/
5757
static void length_and_bends_stats(const Netlist<>& net_list, bool is_flat);
5858

59-
///@brief Determines how many tracks are used in each channel.
60-
static void get_channel_occupancy_stats(const Netlist<>& net_list, bool /***/);
59+
///@brief Determines how many tracks are used in each channel and prints out statistics
60+
static void get_channel_occupancy_stats(const Netlist<>& net_list);
6161

6262
/************************* Subroutine definitions ****************************/
6363

@@ -71,16 +71,16 @@ void routing_stats(const Netlist<>& net_list,
7171
e_directionality directionality,
7272
RRSwitchId wire_to_ipin_switch,
7373
bool is_flat) {
74-
auto& device_ctx = g_vpr_ctx.device();
74+
const DeviceContext& device_ctx = g_vpr_ctx.device();
7575
auto& rr_graph = device_ctx.rr_graph;
76-
auto& cluster_ctx = g_vpr_ctx.clustering();
76+
const ClusteringContext& cluster_ctx = g_vpr_ctx.clustering();
7777
const auto& block_locs = g_vpr_ctx.placement().block_locs();
7878

7979
int num_rr_switch = rr_graph.num_rr_switches();
8080

8181
length_and_bends_stats(net_list, is_flat);
8282
print_channel_stats(is_flat);
83-
get_channel_occupancy_stats(net_list, is_flat);
83+
get_channel_occupancy_stats(net_list);
8484

8585
VTR_LOG("Logic area (in minimum width transistor areas, excludes I/Os and empty grid tiles)...\n");
8686

@@ -185,69 +185,99 @@ void length_and_bends_stats(const Netlist<>& net_list, bool is_flat) {
185185
VTR_LOG("Total number of nets absorbed: %d\n", num_absorbed_nets);
186186
}
187187

188-
static void get_channel_occupancy_stats(const Netlist<>& net_list, bool /***/) {
188+
static void get_channel_occupancy_stats(const Netlist<>& net_list) {
189189
const auto& device_ctx = g_vpr_ctx.device();
190190

191-
auto chanx_occ = vtr::Matrix<int>({{
192-
device_ctx.grid.width(), //[0 .. device_ctx.grid.width() - 1] (length of x channel)
193-
device_ctx.grid.height() - 1 //[0 .. device_ctx.grid.height() - 2] (# x channels)
194-
}},
195-
0);
191+
auto chanx_occ = vtr::NdMatrix<int, 3>({{
192+
device_ctx.grid.get_num_layers(),
193+
device_ctx.grid.width(), // Length of each x channel
194+
device_ctx.grid.height() - 1 // Total number of x channels. There is no CHANX above the top row.
195+
}},
196+
0);
196197

197-
auto chany_occ = vtr::Matrix<int>({{
198-
device_ctx.grid.width() - 1, //[0 .. device_ctx.grid.width() - 2] (# y channels)
199-
device_ctx.grid.height() //[0 .. device_ctx.grid.height() - 1] (length of y channel)
200-
}},
201-
0);
198+
auto chany_occ = vtr::NdMatrix<int, 3>({{
199+
device_ctx.grid.get_num_layers(),
200+
device_ctx.grid.width() - 1, // Total number of y channels. There is no CHANY to the right of the most right column.
201+
device_ctx.grid.height() // Length of each y channel.
202+
}},
203+
0);
202204

203205
load_channel_occupancies(net_list, chanx_occ, chany_occ);
204206

205-
write_channel_occupancy_table("chanx_occupancy.txt", chanx_occ, device_ctx.chan_width.x_list);
206-
write_channel_occupancy_table("chany_occupancy.txt", chany_occ, device_ctx.chan_width.y_list);
207+
write_channel_occupancy_table("chanx_occupancy.txt", chanx_occ, device_ctx.rr_chanx_segment_width);
208+
write_channel_occupancy_table("chany_occupancy.txt", chany_occ, device_ctx.rr_chany_segment_width);
209+
210+
int total_cap_x = 0;
211+
int total_used_x = 0;
212+
int total_cap_y = 0;
213+
int total_used_y = 0;
207214

208215
VTR_LOG("\n");
209-
VTR_LOG("X - Directed channels: j max occ ave occ capacity\n");
210-
VTR_LOG(" ---- ------- ------- --------\n");
211-
212-
int total_x = 0;
213-
for (size_t j = 0; j < device_ctx.grid.height() - 1; ++j) {
214-
total_x += device_ctx.chan_width.x_list[j];
215-
float ave_occ = 0.0;
216-
int max_occ = -1;
217-
218-
for (size_t i = 1; i < device_ctx.grid.width(); ++i) {
219-
max_occ = std::max(chanx_occ[i][j], max_occ);
220-
ave_occ += chanx_occ[i][j];
216+
VTR_LOG("X - Directed channels: layer y max occ ave occ ave cap\n");
217+
VTR_LOG(" ----- ---- -------- -------- --------\n");
218+
219+
for (size_t layer = 0; layer < device_ctx.grid.get_num_layers(); ++layer) {
220+
for (size_t y = 0; y < device_ctx.grid.height() - 1; y++) {
221+
float ave_occ = 0.0f;
222+
float ave_cap = 0.0f;
223+
int max_occ = -1;
224+
225+
// It is assumed that there is no CHANX at x=0
226+
for (size_t x = 1; x < device_ctx.grid.width(); x++) {
227+
max_occ = std::max(chanx_occ[layer][x][y], max_occ);
228+
ave_occ += chanx_occ[layer][x][y];
229+
ave_cap += device_ctx.rr_chanx_segment_width[layer][x][y];
230+
231+
total_cap_x += chanx_occ[layer][x][y];
232+
total_used_x += chanx_occ[layer][x][y];
233+
}
234+
ave_occ /= device_ctx.grid.width() - 2;
235+
ave_cap /= device_ctx.grid.width() - 2;
236+
VTR_LOG(" %5zu %4zu %8d %8.3f %8.0f\n",
237+
layer, y, max_occ, ave_occ, ave_cap);
221238
}
222-
ave_occ /= device_ctx.grid.width();
223-
VTR_LOG(" %4d %7d %7.3f %8d\n", j, max_occ, ave_occ, device_ctx.chan_width.x_list[j]);
224239
}
225240

226-
VTR_LOG("Y - Directed channels: i max occ ave occ capacity\n");
227-
VTR_LOG(" ---- ------- ------- --------\n");
241+
VTR_LOG("Y - Directed channels: layer x max occ ave occ ave cap\n");
242+
VTR_LOG(" ----- ---- -------- -------- --------\n");
228243

229-
int total_y = 0;
230-
for (size_t i = 0; i < device_ctx.grid.width() - 1; ++i) {
231-
total_y += device_ctx.chan_width.y_list[i];
232-
float ave_occ = 0.0;
233-
int max_occ = -1;
244+
for (size_t layer = 0; layer < device_ctx.grid.get_num_layers(); ++layer) {
245+
for (size_t x = 0; x < device_ctx.grid.width() - 1; x++) {
246+
float ave_occ = 0.0;
247+
float ave_cap = 0.0;
248+
int max_occ = -1;
234249

235-
for (size_t j = 1; j < device_ctx.grid.height(); ++j) {
236-
max_occ = std::max(chany_occ[i][j], max_occ);
237-
ave_occ += chany_occ[i][j];
250+
// It is assumed that there is no CHANY at y=0
251+
for (size_t y = 1; y < device_ctx.grid.height(); y++) {
252+
max_occ = std::max(chany_occ[layer][x][y], max_occ);
253+
ave_occ += chany_occ[layer][x][y];
254+
ave_cap += device_ctx.rr_chany_segment_width[layer][x][y];
255+
256+
total_cap_y += chany_occ[layer][x][y];
257+
total_used_y += chany_occ[layer][x][y];
258+
}
259+
ave_occ /= device_ctx.grid.height() - 2;
260+
ave_cap /= device_ctx.grid.height() - 2;
261+
VTR_LOG(" %5zu %4zu %8d %8.3f %8.0f\n",
262+
layer, x, max_occ, ave_occ, ave_cap);
238263
}
239-
ave_occ /= device_ctx.grid.height();
240-
VTR_LOG(" %4d %7d %7.3f %8d\n", i, max_occ, ave_occ, device_ctx.chan_width.y_list[i]);
241264
}
242265

243266
VTR_LOG("\n");
244-
VTR_LOG("Total tracks in x-direction: %d, in y-direction: %d\n", total_x, total_y);
267+
268+
VTR_LOG("Total existing wires segments: CHANX %d, CHANY %d, ALL %d\n",
269+
total_cap_x, total_cap_y, total_cap_x + total_cap_y);
270+
VTR_LOG("Total used wires segments: CHANX %d, CHANY %d, ALL %d\n",
271+
total_used_x, total_used_y, total_used_x + total_used_y);
272+
VTR_LOG("Usage percentage: CHANX %d%%, CHANY %d%%, ALL %d%%\n",
273+
(float)total_used_x / total_cap_x, (float)total_used_y / total_cap_y, (float)(total_used_x + total_used_y) / (total_cap_x + total_cap_y));
274+
245275
VTR_LOG("\n");
246276
}
247277

248-
static void write_channel_occupancy_table(const std::string_view filename,
249-
const vtr::Matrix<int>& occupancy,
250-
const std::vector<int>& capacity_list) {
278+
static void write_channel_occupancy_table(std::string_view filename,
279+
const vtr::NdMatrix<int, 3>& occupancy,
280+
const vtr::NdMatrix<int, 3>& capacity) {
251281
constexpr int w_coord = 6;
252282
constexpr int w_value = 12;
253283
constexpr int w_percent = 12;
@@ -258,64 +288,72 @@ static void write_channel_occupancy_table(const std::string_view filename,
258288
return;
259289
}
260290

261-
file << std::setw(w_coord) << "x"
291+
file << std::setw(w_coord) << "layer"
292+
<< std::setw(w_coord) << "x"
262293
<< std::setw(w_coord) << "y"
263294
<< std::setw(w_value) << "occupancy"
264295
<< std::setw(w_percent) << "%"
265296
<< std::setw(w_value) << "capacity"
266297
<< "\n";
267298

268-
for (size_t y = 0; y < occupancy.dim_size(1); ++y) {
269-
int capacity = capacity_list[y];
270-
for (size_t x = 0; x < occupancy.dim_size(0); ++x) {
271-
int occ = occupancy[x][y];
272-
float percent = capacity > 0 ? static_cast<float>(occ) / capacity * 100.0f : 0.0f;
273-
274-
file << std::setw(w_coord) << x
275-
<< std::setw(w_coord) << y
276-
<< std::setw(w_value) << occ
277-
<< std::setw(w_percent) << std::fixed << std::setprecision(3) << percent
278-
<< std::setw(w_value) << capacity
279-
<< "\n";
299+
for (size_t layer = 0; layer < occupancy.dim_size(0); ++layer) {
300+
for (size_t x = 0; x < occupancy.dim_size(1); ++x) {
301+
for (size_t y = 0; y < occupancy.dim_size(2); ++y) {
302+
int occ = occupancy[layer][x][y];
303+
int cap = capacity[layer][x][y];
304+
float percent = (cap > 0) ? static_cast<float>(occ) / cap * 100.0f : 0.0f;
305+
306+
file << std::setw(w_coord) << layer
307+
<< std::setw(w_coord) << x
308+
<< std::setw(w_coord) << y
309+
<< std::setw(w_value) << occ
310+
<< std::setw(w_percent) << std::fixed << std::setprecision(3) << percent
311+
<< std::setw(w_value) << cap
312+
<< "\n";
313+
}
280314
}
281315
}
282316

283317
file.close();
284318
}
285319

286320
static void load_channel_occupancies(const Netlist<>& net_list,
287-
vtr::Matrix<int>& chanx_occ,
288-
vtr::Matrix<int>& chany_occ) {
289-
const auto& device_ctx = g_vpr_ctx.device();
321+
vtr::NdMatrix<int, 3>& chanx_occ,
322+
vtr::NdMatrix<int, 3>& chany_occ) {
323+
const DeviceContext& device_ctx = g_vpr_ctx.device();
290324
const auto& rr_graph = device_ctx.rr_graph;
291-
const auto& route_ctx = g_vpr_ctx.routing();
325+
const RoutingContext& route_ctx = g_vpr_ctx.routing();
292326

293-
/* First set the occupancy of everything to zero. */
327+
// First set the occupancy of everything to zero.
294328
chanx_occ.fill(0);
295329
chany_occ.fill(0);
296330

297-
/* Now go through each net and count the tracks and pins used everywhere */
298-
for (auto net_id : net_list.nets()) {
299-
/* Skip global and empty nets. */
300-
if (net_list.net_is_ignored(net_id) && net_list.net_sinks(net_id).size() != 0)
331+
// Now go through each net and count the tracks and pins used everywhere
332+
for (ParentNetId net_id : net_list.nets()) {
333+
// Skip global and empty nets.
334+
if (net_list.net_is_ignored(net_id) && net_list.net_sinks(net_id).size() != 0) {
301335
continue;
336+
}
302337

303-
auto& tree = route_ctx.route_trees[net_id];
304-
if (!tree)
338+
const vtr::optional<RouteTree>& tree = route_ctx.route_trees[net_id];
339+
if (!tree) {
305340
continue;
341+
}
306342

307343
for (const RouteTreeNode& rt_node : tree.value().all_nodes()) {
308344
RRNodeId inode = rt_node.inode;
309345
e_rr_type rr_type = rr_graph.node_type(inode);
310346

311347
if (rr_type == e_rr_type::CHANX) {
312348
int j = rr_graph.node_ylow(inode);
349+
int layer = rr_graph.node_layer_low(inode);
313350
for (int i = rr_graph.node_xlow(inode); i <= rr_graph.node_xhigh(inode); i++)
314-
chanx_occ[i][j]++;
351+
chanx_occ[layer][i][j]++;
315352
} else if (rr_type == e_rr_type::CHANY) {
316353
int i = rr_graph.node_xlow(inode);
354+
int layer = rr_graph.node_layer_low(inode);
317355
for (int j = rr_graph.node_ylow(inode); j <= rr_graph.node_yhigh(inode); j++)
318-
chany_occ[i][j]++;
356+
chany_occ[layer][i][j]++;
319357
}
320358
}
321359
}

vpr/src/base/vpr_context.h

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,15 @@ struct DeviceContext : public Context {
263263

264264
int delayless_switch_idx = UNDEFINED;
265265

266-
/// Stores the number of CHANX wire segments in each routing channel at [layer][x][y]
267-
vtr::NdMatrix<int, 3> rr_chanx_width;
268-
/// Stores the number of CHANY wire segments in each routing channel at [layer][x][y]
269-
vtr::NdMatrix<int, 3> rr_chany_width;
266+
/// Stores the number of CHANX wire segments in each routing channel segment at [layer][x][y]
267+
vtr::NdMatrix<int, 3> rr_chanx_segment_width;
268+
/// Stores the number of CHANY wire segments in each routing channel segment at [layer][x][y]
269+
vtr::NdMatrix<int, 3> rr_chany_segment_width;
270+
271+
/// Stores the maximum channel segment width in each horizontal channel
272+
std::vector<int> rr_chanx_width;
273+
/// Stores the maximum channel segment width in each vertical channel
274+
std::vector<int> rr_chany_width;
270275

271276
bool rr_graph_is_flat = false;
272277

0 commit comments

Comments
 (0)