Skip to content

Commit ebf2e84

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 ebf2e84

File tree

5 files changed

+225
-6
lines changed

5 files changed

+225
-6
lines changed

vpr/src/analytical_place/analytical_placement_flow.cpp

Lines changed: 8 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"
1011
#include "globals.h"
1112
#include "prepack.h"
13+
#include "read_atom_netlist.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,16 @@ 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 = read_atom_netlist(atom_nlist, prepacker, constraints);
37+
3038
// AP is currently under-construction. Fail gracefully just in case this
3139
// is somehow being called.
3240
VPR_FATAL_ERROR(VPR_ERROR_AP,

vpr/src/analytical_place/ap_netlist.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,11 @@ 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

6568
block_locs_[id] = loc;

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 read_atom_netlist method, used for generating an
6+
* APNetlist from the results of the Prepacker.
7+
*/
8+
9+
#include "read_atom_netlist.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 read_atom_netlist(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+
VTR_ASSERT(partition_pr.get_regions().size() == 1 && "Each partition should contain only one region!");
84+
const Region& region = partition_pr.get_regions()[0];
85+
// Get the x and y.
86+
const vtr::Rect<int>& region_rect = region.get_rect();
87+
VTR_ASSERT(region_rect.xmin() == region_rect.xmax() && "Expect each region to be a single point in x!");
88+
VTR_ASSERT(region_rect.ymin() == region_rect.ymax() && "Expect each region to be a single point in y!");
89+
int blk_x_loc = region_rect.xmin();
90+
int blk_y_loc = region_rect.ymin();
91+
// Get the layer.
92+
VTR_ASSERT(region.get_layer_range().first == region.get_layer_range().second && "Expect each region to be a single point in layer!");
93+
int blk_layer_num = region.get_layer_range().first;
94+
// Get the sub_tile (if fixed).
95+
int blk_sub_tile = APFixedBlockLoc::UNFIXED_DIM;
96+
if (region.get_sub_tile() != NO_SUBTILE)
97+
blk_sub_tile = region.get_sub_tile();
98+
// Set the fixed block location.
99+
APFixedBlockLoc loc = {blk_x_loc, blk_y_loc, blk_layer_num, blk_sub_tile};
100+
ap_netlist.set_block_loc(ap_blk_id, loc);
101+
}
102+
}
103+
104+
// Cleanup the netlist by removing undesirable nets.
105+
// Currently undesirable nets are nets that are:
106+
// - ignored for placement
107+
// - a global net
108+
// - connected to 1 or fewer unique blocks
109+
// - connected to only fixed blocks
110+
// TODO: Allow the user to pass a threshold so we can remove high-fanout nets.
111+
auto remove_net = [&](APNetId net_id) {
112+
// Remove all pins associated with this net
113+
for (APPinId pin_id : ap_netlist.net_pins(net_id))
114+
ap_netlist.remove_pin(pin_id);
115+
// Remove the net
116+
ap_netlist.remove_net(net_id);
117+
};
118+
for (APNetId ap_net_id : ap_netlist.nets()) {
119+
// Is the net ignored for placement, if so remove
120+
const std::string& net_name = ap_netlist.net_name(ap_net_id);
121+
AtomNetId atom_net_id = atom_netlist.find_net(net_name);
122+
VTR_ASSERT(atom_net_id.is_valid());
123+
if (atom_netlist.net_is_ignored(atom_net_id)) {
124+
remove_net(ap_net_id);
125+
continue;
126+
}
127+
// Is the net global, if so remove
128+
if (atom_netlist.net_is_global(atom_net_id)) {
129+
remove_net(ap_net_id);
130+
continue;
131+
}
132+
// Get the unique blocks connectioned to this net
133+
std::unordered_set<APBlockId> net_blocks;
134+
for (APPinId ap_pin_id : ap_netlist.net_pins(ap_net_id)) {
135+
net_blocks.insert(ap_netlist.pin_block(ap_pin_id));
136+
}
137+
// If connected to 1 or fewer unique blocks, remove
138+
if (net_blocks.size() <= 1) {
139+
remove_net(ap_net_id);
140+
continue;
141+
}
142+
// If all the connected blocks are fixed, remove
143+
bool is_all_fixed = true;
144+
for (APBlockId ap_blk_id : net_blocks) {
145+
if (ap_netlist.block_mobility(ap_blk_id) == APBlockMobility::MOVEABLE) {
146+
is_all_fixed = false;
147+
break;
148+
}
149+
}
150+
if (is_all_fixed) {
151+
remove_net(ap_net_id);
152+
continue;
153+
}
154+
}
155+
ap_netlist.remove_and_compress();
156+
157+
// TODO: Some nets may go to the same block mutliple times. Should that be
158+
// fixed? Maybe we want nets to be strongly attracted towards some
159+
// blocks over others.
160+
161+
// TODO: Should we cleanup the blocks? For example if there is no path
162+
// from a fixed block to a given moveable block, then that moveable
163+
// block can be removed (since it can literally go anywhere).
164+
// - This would be useful to detect and use throughout; but may cause some
165+
// issues if we just remove them. When and where will they eventually
166+
// be placed?
167+
// - Perhaps we can add a flag in the netlist to each of these blocks and
168+
// during the solving stage we can ignore them.
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 read_atom_netlist function which uses the results
6+
* 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 read_atom_netlist(const AtomNetlist& atom_netlist,
28+
const Prepacker& prepacker,
29+
const UserPlaceConstraints& constraints);
30+

0 commit comments

Comments
 (0)