Skip to content

Commit 86f8af1

Browse files
[AP] Added Ability to Read The Atom Netlist
This method reads the atom netlist and uses the results of the prepacker to generate an APNetlist. It also fixes the block locations based on the user place constraints.
1 parent 13f37a6 commit 86f8af1

File tree

5 files changed

+234
-6
lines changed

5 files changed

+234
-6
lines changed

vpr/src/analytical_place/analytical_placement_flow.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66
*/
77

88
#include "analytical_placement_flow.h"
9+
#include "ap_netlist.h"
910
#include "atom_netlist.h"
11+
#include "gen_ap_netlist_from_atoms.h"
1012
#include "globals.h"
1113
#include "prepack.h"
14+
#include "user_place_constraints.h"
1215
#include "vpr_context.h"
1316
#include "vpr_error.h"
1417
#include "vpr_types.h"
@@ -22,11 +25,18 @@ void run_analytical_placement_flow(t_vpr_setup& vpr_setup) {
2225
// The global state used/modified by this flow.
2326
const AtomNetlist& atom_nlist = g_vpr_ctx.atom().nlist;
2427
const DeviceContext& device_ctx = g_vpr_ctx.device();
28+
const UserPlaceConstraints& constraints = g_vpr_ctx.floorplanning().constraints;
2529

2630
// Run the prepacker
2731
Prepacker prepacker;
2832
prepacker.init(atom_nlist, device_ctx.logical_block_types);
2933

34+
// Create the ap netlist from the atom netlist using the result from the
35+
// prepacker.
36+
APNetlist ap_netlist = gen_ap_netlist_from_atoms(atom_nlist,
37+
prepacker,
38+
constraints);
39+
3040
// AP is currently under-construction. Fail gracefully just in case this
3141
// is somehow being called.
3242
VPR_FATAL_ERROR(VPR_ERROR_AP,

vpr/src/analytical_place/ap_netlist.cpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,20 @@ APBlockId APNetlist::create_block(const std::string& name, const t_pack_molecule
5858
void APNetlist::set_block_loc(const APBlockId id, const APFixedBlockLoc& loc) {
5959
VTR_ASSERT_SAFE(valid_block_id(id));
6060

61-
// Check that the location is fixed, if all values are -1 then it is not fixed.
62-
if (loc.x == -1 && loc.y == -1 && loc.sub_tile == -1 && loc.layer_num == -1)
61+
// Check that the location is fixed; if all dims are unfixed then it is not fixed.
62+
if (loc.x == APFixedBlockLoc::UNFIXED_DIM &&
63+
loc.y == APFixedBlockLoc::UNFIXED_DIM &&
64+
loc.sub_tile == APFixedBlockLoc::UNFIXED_DIM &&
65+
loc.layer_num == APFixedBlockLoc::UNFIXED_DIM)
6366
return;
6467

68+
// Ensure that the block is fixed to a single position on the grid (x, y, layer).
69+
// sub-tile is allowed to be unfixed.
70+
VTR_ASSERT(loc.x != APFixedBlockLoc::UNFIXED_DIM &&
71+
loc.y != APFixedBlockLoc::UNFIXED_DIM &&
72+
loc.layer_num != APFixedBlockLoc::UNFIXED_DIM &&
73+
"AP: Currently, AP assumes block is locked down to a single position on the device grid.");
74+
6575
block_locs_[id] = loc;
6676
block_mobilities_[id] = APBlockMobility::FIXED;
6777
}

vpr/src/analytical_place/ap_netlist.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,13 @@ class t_pack_molecule;
3636
* -1 implies that the block is not fixed in that dimension.
3737
*/
3838
struct APFixedBlockLoc {
39-
int x = -1;
40-
int y = -1;
41-
int layer_num = -1;
42-
int sub_tile = -1;
39+
// Value that represents an unfixed dimension.
40+
static constexpr int UNFIXED_DIM = -1;
41+
// The dimensions to fix.
42+
int x = UNFIXED_DIM;
43+
int y = UNFIXED_DIM;
44+
int layer_num = UNFIXED_DIM;
45+
int sub_tile = UNFIXED_DIM;
4346
};
4447

4548
/**
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/**
2+
* @file
3+
* @author Alex Singer
4+
* @date September 2024
5+
* @brief Definition of the gen_ap_netlist_from_atoms method, used for
6+
* generating an APNetlist from the results of the Prepacker.
7+
*/
8+
9+
#include "gen_ap_netlist_from_atoms.h"
10+
#include "ap_netlist.h"
11+
#include "atom_netlist.h"
12+
#include "atom_netlist_fwd.h"
13+
#include "netlist_fwd.h"
14+
#include "partition.h"
15+
#include "partition_region.h"
16+
#include "prepack.h"
17+
#include "region.h"
18+
#include "user_place_constraints.h"
19+
#include "vpr_types.h"
20+
#include "vtr_assert.h"
21+
#include "vtr_geometry.h"
22+
#include "vtr_time.h"
23+
#include <unordered_set>
24+
#include <vector>
25+
26+
APNetlist gen_ap_netlist_from_atoms(const AtomNetlist& atom_netlist,
27+
const Prepacker& prepacker,
28+
const UserPlaceConstraints& constraints) {
29+
// Create a scoped timer for reading the atom netlist.
30+
vtr::ScopedStartFinishTimer timer("Read Atom Netlist to AP Netlist");
31+
32+
// FIXME: What to do about the name and ID in this context? For now just
33+
// using empty strings.
34+
APNetlist ap_netlist;
35+
36+
// Add the APBlocks based on the atom block molecules. This essentially
37+
// creates supernodes.
38+
// Each AP block has the name of the first atom block in the molecule.
39+
// Each port is named "<atom_blk_name>_<atom_port_name>"
40+
// Each net has the exact same name as in the atom netlist
41+
for (AtomBlockId atom_blk_id : atom_netlist.blocks()) {
42+
// Get the molecule of this block
43+
t_pack_molecule* mol = prepacker.get_atom_molecule(atom_blk_id);
44+
// Create the AP block (if not already done)
45+
const std::string& first_blk_name = atom_netlist.block_name(mol->atom_block_ids[0]);
46+
APBlockId ap_blk_id = ap_netlist.create_block(first_blk_name, mol);
47+
// Add the ports and pins of this block to the supernode
48+
for (AtomPortId atom_port_id : atom_netlist.block_ports(atom_blk_id)) {
49+
BitIndex port_width = atom_netlist.port_width(atom_port_id);
50+
PortType port_type = atom_netlist.port_type(atom_port_id);
51+
const std::string& port_name = atom_netlist.port_name(atom_port_id);
52+
const std::string& block_name = atom_netlist.block_name(atom_blk_id);
53+
// The port name needs to be made unique for the supernode (two
54+
// joined blocks may have the same port name)
55+
std::string ap_port_name = block_name + "_" + port_name;
56+
APPortId ap_port_id = ap_netlist.create_port(ap_blk_id, ap_port_name, port_width, port_type);
57+
for (AtomPinId atom_pin_id : atom_netlist.port_pins(atom_port_id)) {
58+
BitIndex port_bit = atom_netlist.pin_port_bit(atom_pin_id);
59+
PinType pin_type = atom_netlist.pin_type(atom_pin_id);
60+
bool pin_is_const = atom_netlist.pin_is_constant(atom_pin_id);
61+
AtomNetId pin_atom_net_id = atom_netlist.pin_net(atom_pin_id);
62+
const std::string& pin_atom_net_name = atom_netlist.net_name(pin_atom_net_id);
63+
APNetId pin_ap_net_id = ap_netlist.create_net(pin_atom_net_name);
64+
ap_netlist.create_pin(ap_port_id, port_bit, pin_ap_net_id, pin_type, pin_is_const);
65+
}
66+
}
67+
}
68+
69+
// Fix the block locations given by the VPR constraints
70+
for (APBlockId ap_blk_id : ap_netlist.blocks()) {
71+
const t_pack_molecule* mol = ap_netlist.block_molecule(ap_blk_id);
72+
for (AtomBlockId mol_atom_blk_id : mol->atom_block_ids) {
73+
PartitionId part_id = constraints.get_atom_partition(mol_atom_blk_id);
74+
if (!part_id.is_valid())
75+
continue;
76+
// We should not fix a block twice. This would imply that a molecule
77+
// contains two fixed blocks. This would only make sense if the blocks
78+
// were fixed to the same location. I am not sure if that is even
79+
// possible.
80+
VTR_ASSERT(ap_netlist.block_mobility(ap_blk_id) == APBlockMobility::MOVEABLE);
81+
// Get the partition region.
82+
const PartitionRegion& partition_pr = constraints.get_partition_pr(part_id);
83+
// TODO: Either handle the union of legal locations or turn into a
84+
// proper error.
85+
VTR_ASSERT(partition_pr.get_regions().size() == 1 && "AP: Each partition should contain only one region for AP right now.");
86+
const Region& region = partition_pr.get_regions()[0];
87+
// Get the x and y.
88+
const vtr::Rect<int>& region_rect = region.get_rect();
89+
VTR_ASSERT(region_rect.xmin() == region_rect.xmax() && "AP: Expect each region to be a single point in x!");
90+
VTR_ASSERT(region_rect.ymin() == region_rect.ymax() && "AP: Expect each region to be a single point in y!");
91+
int blk_x_loc = region_rect.xmin();
92+
int blk_y_loc = region_rect.ymin();
93+
// Get the layer.
94+
VTR_ASSERT(region.get_layer_range().first == region.get_layer_range().second && "AP: Expect each region to be a single point in layer!");
95+
int blk_layer_num = region.get_layer_range().first;
96+
// Get the sub_tile (if fixed).
97+
int blk_sub_tile = APFixedBlockLoc::UNFIXED_DIM;
98+
if (region.get_sub_tile() != NO_SUBTILE)
99+
blk_sub_tile = region.get_sub_tile();
100+
// Set the fixed block location.
101+
APFixedBlockLoc loc = {blk_x_loc, blk_y_loc, blk_layer_num, blk_sub_tile};
102+
ap_netlist.set_block_loc(ap_blk_id, loc);
103+
}
104+
}
105+
106+
// Cleanup the netlist by removing undesirable nets.
107+
// Currently undesirable nets are nets that are:
108+
// - ignored for placement
109+
// - a global net
110+
// - connected to 1 or fewer unique blocks
111+
// - connected to only fixed blocks
112+
// TODO: Allow the user to pass a threshold so we can remove high-fanout nets.
113+
auto remove_net = [&](APNetId net_id) {
114+
// Remove all pins associated with this net
115+
for (APPinId pin_id : ap_netlist.net_pins(net_id))
116+
ap_netlist.remove_pin(pin_id);
117+
// Remove the net
118+
ap_netlist.remove_net(net_id);
119+
};
120+
for (APNetId ap_net_id : ap_netlist.nets()) {
121+
// Is the net ignored for placement, if so remove
122+
const std::string& net_name = ap_netlist.net_name(ap_net_id);
123+
AtomNetId atom_net_id = atom_netlist.find_net(net_name);
124+
VTR_ASSERT(atom_net_id.is_valid());
125+
if (atom_netlist.net_is_ignored(atom_net_id)) {
126+
remove_net(ap_net_id);
127+
continue;
128+
}
129+
// Is the net global, if so remove
130+
if (atom_netlist.net_is_global(atom_net_id)) {
131+
remove_net(ap_net_id);
132+
continue;
133+
}
134+
// Get the unique blocks connectioned to this net
135+
std::unordered_set<APBlockId> net_blocks;
136+
for (APPinId ap_pin_id : ap_netlist.net_pins(ap_net_id)) {
137+
net_blocks.insert(ap_netlist.pin_block(ap_pin_id));
138+
}
139+
// If connected to 1 or fewer unique blocks, remove
140+
if (net_blocks.size() <= 1) {
141+
remove_net(ap_net_id);
142+
continue;
143+
}
144+
// If all the connected blocks are fixed, remove
145+
bool is_all_fixed = true;
146+
for (APBlockId ap_blk_id : net_blocks) {
147+
if (ap_netlist.block_mobility(ap_blk_id) == APBlockMobility::MOVEABLE) {
148+
is_all_fixed = false;
149+
break;
150+
}
151+
}
152+
if (is_all_fixed) {
153+
remove_net(ap_net_id);
154+
continue;
155+
}
156+
}
157+
ap_netlist.remove_and_compress();
158+
159+
// TODO: Should we cleanup the blocks? For example if there is no path
160+
// from a fixed block to a given moveable block, then that moveable
161+
// block can be removed (since it can literally go anywhere).
162+
// - This would be useful to detect and use throughout; but may cause some
163+
// issues if we just remove them. When and where will they eventually
164+
// be placed?
165+
// - Perhaps we can add a flag in the netlist to each of these blocks and
166+
// during the solving stage we can ignore them.
167+
// For now, leave this alone; but should check if the matrix becomes
168+
// ill-formed and causes problems.
169+
170+
// Verify that the netlist was created correctly.
171+
VTR_ASSERT(ap_netlist.verify());
172+
173+
return ap_netlist;
174+
}
175+
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* @file
3+
* @author Alex Singer
4+
* @date September 2024
5+
* @brief Declaration of the gen_ap_netlist_from_atoms function which uses the
6+
* results of the prepacker to generate an APNetlist.
7+
*/
8+
9+
#pragma once
10+
11+
// Forward declarations
12+
class APNetlist;
13+
class AtomNetlist;
14+
class Prepacker;
15+
class UserPlaceConstraints;
16+
17+
/**
18+
* @brief Use the results from prepacking the atom netlist to generate an APNetlist.
19+
*
20+
* @param atom_netlist The atom netlist for the input design.
21+
* @param prepacker The prepacker, initialized on the provided atom netlist.
22+
* @param constraints The placement constraints on the Atom blocks, provided
23+
* by the user.
24+
*
25+
* @return An APNetlist object, generated from the prepacker results.
26+
*/
27+
APNetlist gen_ap_netlist_from_atoms(const AtomNetlist& atom_netlist,
28+
const Prepacker& prepacker,
29+
const UserPlaceConstraints& constraints);
30+

0 commit comments

Comments
 (0)