Commit b87955ca by sakundu

Merge branch 'main' of github.com:TILOS-AI-Institute/MacroPlacement into main

parents b6210de9 dbd074f1
......@@ -610,7 +610,9 @@ class PlcObject:
elif (self.orientation == None):
self.str += "N "
else:
self.str += str(self.orientation) + " "
string = str(self.orientation).split('"')[0]
#self.str += str(self.orientation) + " "
self.str += string + " "
self.str += "0\n"
return self.str
......@@ -1054,22 +1056,23 @@ class PBFNetlist:
x_dir = 0
y_dir = 0
if (src_lx >= target_ux or src_ux <= target_lx or src_ly >= target_uy or src_uy <= target_ly):
# there is no overlap
return None, None
else:
src_cx = (src_lx + src_ux) / 2.0
src_cy = (src_ly + src_uy) / 2.0
target_cx = (target_lx + target_ux) / 2.0
target_cy = (target_ly + target_uy) / 2.0
x_dir = src_cx - target_cx
y_dir = src_cy - target_cy
# set the minimum value to 1e-12
min_dist = 1e-2
if (abs(x_dir) <= min_dist):
x_dir = -1 * min_dist
if (abs(y_dir) <= min_dist):
y_dir = -1 * min_dist
return x_dir, y_dir
if (src_cx == target_cx and src_cy == target_cy):
# fully overlap
x_dir = -1.0 / sqrt(2.0)
y_dir = -1.0 / sqrt(2.0)
return x_dir, y_dir
else:
x_dir = src_cx - target_cx
y_dir = src_cy - target_cy
dist = sqrt(x_dir * x_dir + y_dir * y_dir)
return x_dir / dist, y_dir / dist
# check the relative position
# This is for attractive force
......@@ -1092,11 +1095,11 @@ class PBFNetlist:
if (x_dir == None): # No overlap
f_r_x = 0.0
else:
f_r_x = repulsive_factor * 1.0 / x_dir
f_r_x = repulsive_factor * 1.0 * max_displacement * x_dir
if (y_dir == None): # No overlap
f_r_y = 0.0
else:
f_r_y = repulsive_factor * 1.0 / y_dir
f_r_y = repulsive_factor * 1.0 * max_displacement * y_dir
self.objects[src_macro].AddForce(f_r_x, f_r_y)
self.objects[target_macro].AddForce(-1 * f_r_x, -1 * f_r_y)
......@@ -1214,25 +1217,60 @@ class FDPlacer:
#self.plc.restore_placement(self.temp_plc_file)
self.plc.set_canvas_size(self.design.canvas_width, self.design.canvas_height)
self.PlotFromPlc(self.open_source_flag)
#self.PlotFromPlc(self.open_source_flag)
start_time = time.time()
self.FDPlacer(self.open_source_flag)
end_time = time.time()
self.final_netlist_pbf_file = self.run_dir + "/" + self.design_name + ".pb.txt.final"
self.final_plc_file = self.run_dir + "/" + self.design_name + ".plc.final"
self.final_plc_fig = self.run_dir + "/" + self.design_name + ".plc.final.png"
self.design.WriteNetlist(self.final_netlist_pbf_file, self.final_plc_file)
self.WritePlcFile(self.final_plc_file)
print("************************************************")
print("The results from Circuit Training")
self.CalCostPlc(self.final_plc_file, isPrint = True)
print("runtime : ", end_time - start_time)
print("\n")
self.PlotFromPlc(self.open_source_flag, self.final_plc_fig)
start_time = time.time()
self.FDPlacer(not self.open_source_flag)
end_time = time.time()
self.final_netlist_pbf_file = self.run_dir + "/" + self.design_name + ".os.pb.txt.final"
self.final_plc_file = self.run_dir + "/" + self.design_name + ".os.plc.final"
self.final_plc_fig = self.run_dir + "/" + self.design_name + ".os.plc.final.png"
self.design.WriteNetlist(self.final_netlist_pbf_file, self.final_plc_file)
print("************************************************")
print("The results from Our Implementation")
self.CalCostPlc(self.final_plc_file, isPrint = True)
print("runtime : ", end_time - start_time)
print("\n")
self.PlotFromPlc(not self.open_source_flag, self.final_plc_fig)
### Call the plc client for cost evulation
def CalCostPlc(self, plc_file, isPrint = True):
self.plc.restore_placement(plc_file)
self.plc.set_canvas_boundary_check(False)
self.plc.make_soft_macros_square()
self.plc.set_placement_grid(self.design.n_cols, self.design.n_rows)
self.plc.set_routes_per_micron(self.design.hroute_per_micro, self.design.vroute_per_micro)
self.plc.set_macro_routing_allocation(self.design.hrouting_alloc, self.design.vrouting_alloc)
self.plc.set_congestion_smooth_range(self.design.smooth_factor)
self.plc.set_overlap_threshold(self.design.overlap_threshold)
self.plc.set_canvas_size(self.design.canvas_width, self.design.canvas_height)
wl_cost = self.plc.get_cost()
den_cost = self.plc.get_density_cost()
cong_cost = self.plc.get_congestion_cost()
# the weight parameters are given by Circuit Training
proxy_cost = wl_cost + 0.5 * den_cost + 0.5 * cong_cost
if (isPrint == True):
print("WL cost : ", wl_cost, "Density cost : ", den_cost, "Congestion Cost : ", cong_cost, "Proxy cost : ", proxy_cost)
return proxy_cost
def PlotFromPlc(self, open_source_flag = True, figure_file = None):
plt.figure(constrained_layout= True, figsize=(8,5), dpi=600)
if (open_source_flag == True):
......@@ -1334,7 +1372,7 @@ if __name__ == "__main__":
io_factor = 0
num_steps = [1]
attract_factor = [0.0]
repel_factor = [1.0]
repel_factor = [10.0]
move_distance_factors = [0.1] # set the max_displacement to 50
use_current_loc = True
placer = FDPlacer(design_name, run_dir, netlist_file, plc_file, io_factor, num_steps, attract_factor, repel_factor, move_distance_factors, use_current_loc)
......
......@@ -2,7 +2,7 @@
**Force-directed placement** is used to place center of standard cell clusters onto
the center of the grid cells.
## **Information provided by Google.**
## **Information provided by Google**
The Methods section of the [Nature paper](https://www.nature.com/articles/s41586-021-03544-w.epdf?sharing_token=tYaxh2mR5EozfsSL0WHZLdRgN0jAjWel9jnR3ZoTv0PW0K0NmVrRsFPaMa9Y5We9O4Hqf_liatg-lvhiVcYpHL_YQpqkurA31sxqtmA-E1yNUWVMMVSBxWSp7ZFFIWawYQYnEXoBE4esRDSWqubhDFWUPyI5wK_5B_YIO-D_kS8%3D) provides the following information.
* “(1) We group millions of standard cells into a few thousand clusters using hMETIS, a partitioning technique based
......@@ -17,11 +17,32 @@ according to the weight×distance formula, causing tightly connected nodes to be
We also introduce a repulsive force between overlapping nodes to reduce placement density.
After applying all forces, we move nodes in the direction of their force vector. To reduce oscillations, we set a maximum distance for each move.”
For each pair of nodes $(u, v)$, there are two types of forces between them : attractive force $f_a(u,v)$ and repulsive force $f_r(u,v)$. The magnitude of attractive force can be expressed as $f_a(u, v) = k_a * distance(u, v)$, where $k_a$ is the attractive factor and $distance$ is the euclidean distance between node $u$ and node $v$; the magnitude of repulsive force can be expressed as $f_r(u, v) = k_r$. Both attracive force and repulsive force are along the straight line joining the node $u$ and node $v$.
## **Our implementation**
Our force-directed placer takes a clustered netlist as input and generates the locations for standard-cell clusters. During the force-directed placement, all the hard macros and IO ports are fixed. Only the standard-cell clusters can be moved but the standard-cell clusters are not necessarily placed onto the centers of gridcells. At the beginning, all the standard-cell clusters will be placed at the center of the canvas. \[[code](https://github.com/TILOS-AI-Institute/MacroPlacement/blob/5addfc904527d764ee67429811c868c5eeb605d4/CodeElements/FDPlacement/FD.py#L1130)\]
During force-directed placement, all the hard macros and IO ports are fixed. Only the stanard-cell clusters can be moved. Note that we need to consider the contribution from hard macros and IO ports when we calculate the total force exerted on a standard-cell cluster.
In the force-directed placement, there are two types of forces between nodes: attractive force and repulsive force.
* The attractive force is ONLY applied to the nodes connected by nets. For the two-pin net connecting pin $P1$ of macro $M1$ and $P2$ of macro $M2$, the attractive force applied to $M1$ and $M2$ is calculated as $f_x = k_a * abs(P1.x - P2.x)$ and $f_y = k_a * abs(P1.y - P2.y)$, where $k_a$ is the attractive factor. If one of pins is an IO port, $k_a$ is the attractive factor times io factor. The attractive force is along the straight line joining $P1$ and $P2$. All the multi-pin nets are decomposied into two-pin nets using the start model. \[[code](https://github.com/TILOS-AI-Institute/MacroPlacement/blob/5addfc904527d764ee67429811c868c5eeb605d4/CodeElements/FDPlacement/FD.py#L1105)\]
* The repulsive force is ONLY applied to the nodes overlapped with each other. If two macros are not overlapped, there is no repulsive force between them. For the two macros $M1$ and $M2$ overlapped with each other, the repulsive force applied to $M1$ and $M2$ is calculated as $f_x = F * abs(M1.x - M2.x) / distance(M1, M2)$ and $f_y = F * abs(M1.y - M2.y) / distance(M1, M2)$, where $F$ is the maximum move distance specified by the users. The repulsive force is along the straight line joining $M1$ and $M2$. For the cases where multiple macros are overlapped together, we calculate the repulsive forces between each pair of macros in sequence. \[[code](https://github.com/TILOS-AI-Institute/MacroPlacement/blob/5addfc904527d764ee67429811c868c5eeb605d4/CodeElements/FDPlacement/FD.py#L1082)\]
After calculating all the attractive forces and repulsive forces, all the forces are normalized as following:
* f_x = f_x / f_x_max * max_move_distance
* f_y = f_y / f_y_max * max_move_distance
Here f_x_max (f_y_max) is the absolute value of f_x (f_y) which has the maximum absolute value. max_move_distance is the maximum move distance specified by users. \[[code](https://github.com/TILOS-AI-Institute/MacroPlacement/blob/5addfc904527d764ee67429811c868c5eeb605d4/CodeElements/FDPlacement/FD.py#L1137)\]
After normalization, the standard-cell clusters are moved based on the forces exerted on them. The move which will push the standard-cell clusters outside of canvas will be canceled.
## **Experimental results**
We have tested our codes on the Ariane133 (NanGate45). The experimental results are presented below.
<p align="center">
<img src="./ariane133/FD_result.png" width= "1200"/>
</p>
<p align="center">
Figure 1. results for Ariane133 (NanGate45).
</p>
The standard-cell clusters are not placed onto the centers of gridcells.
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -60,13 +60,13 @@ node {
attr {
key: "x"
value {
f: 265.306122
f: 300.0
}
}
attr {
key: "y"
value {
f: 265.306122
f: 300.0
}
}
}
......
......@@ -45,7 +45,7 @@
#
#
# node_index x y orientation fixed
0 201.0 201.0 "N" 0
1 265.30612244898 265.30612244898 N 0
0 201.0 201.0 0
1 300.0 300.0 N 0
2 285.0 285.0 N 0
3 400.0 400.0 N 0
......@@ -46,6 +46,6 @@
#
# node_index x y orientation fixed
0 201 201 N 0
1 250 250 N 0
2 335 335 N 0
3 350 350 N 0
1 300 300 N 0
2 285 285 N 0
3 400 400 N 0
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment