Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
M
macroplacement
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
lvzhengyang
macroplacement
Commits
a9e01189
Commit
a9e01189
authored
Nov 22, 2022
by
Dinple
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
updates
parent
3b030ffd
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
1007 additions
and
58 deletions
+1007
-58
.gitignore
+13
-1
CodeElements/FDPlacement/fd_placement_final.py
+723
-0
CodeElements/Plc_client/plc_client_os.py
+198
-51
CodeElements/Plc_client/plc_client_os_test.py
+54
-2
CodeElements/StatTest/proxy_corr_test.py
+19
-4
No files found.
.gitignore
View file @
a9e01189
...
...
@@ -19,4 +19,16 @@ CodeElements/EvalCT/saved_policy/run_00/111/train/*
CodeElements/EvalCT/saved_policy/run_00/111/snapshot*.plc
CodeElements/EvalCT/saved_policy/run_00/111/rl*.plc
CodeElements/EvalCT/saved_policy/run_os_64128_g657_ub5_nruns10_c5_r3_v3_rc1
CodeElements/epoch_*.plc
CodeElements/FDPlacement/test/*
CodeElements/Plc_client/placement_util*.py
CodeElements/StatTest/test/ariane/*_vs_*
CodeElements/StatTest/test/flow2_68_1.3_ct/*
CodeElements/StatTest/test/ariane/*.plc
CodeElements/*/__pycache__/*
CodeElements/*.png
CodeElements/StatTest/*.csv
CodeElements/os.txt
CodeElements/EvalCT/test/ariane/*.plc
CodeElements/FDPlacement/fd.txt
CodeElements/StatTest/test/ariane/*.pb.txt
CodeElements/FDPlacement/fd_placement_final.py
0 → 100755
View file @
a9e01189
###############################################################################################
# This script is used to place standard-cell clusters using force-directed method
# The input is protocol buffer netlist and plc file
# The input is the updated protocol buffer netlist and plc file
###############################################################################################
import
os
import
time
import
shutil
import
sys
import
argparse
import
matplotlib.pyplot
as
plt
from
math
import
log
from
math
import
sqrt
import
json
import
random
import
math
,
statistics
# sys.path.append('../VisualPlacement/')
# from visual_placement import VisualPlacement
# ***************************************************************
# Define basic classes
# ***************************************************************
# Define the orientation map
'''
python3 -m Plc_client.plc_client_os_test --netlist ./Plc_client/test/ariane_fd/ariane.pb.txt
--plc ./Plc_client/test/ariane_fd/ariane.plc.3 --width 1599.99 --height 1598.8 --col 27 --row 23 --rpmh 70.330 --rpmv 74.510 --marh 51.790 --marv 51.790 --smooth 2
'''
OrientMap
=
{
"N"
:
"R0"
,
"S"
:
"R180"
,
"W"
:
"R90"
,
"E"
:
"R270"
,
"FN"
:
"MY"
,
"FS"
:
"MX"
,
"FW"
:
"MX90"
,
"FE"
:
"MY90"
}
# String Helper #
def
print_placeholder
(
key
,
value
):
line
=
" attr {
\n
"
line
+=
f
' key: "{key}"
\n
'
line
+=
' value {
\n
'
line
+=
f
' placeholder: {value}
\n
'
line
+=
' }
\n
'
line
+=
' }
\n
'
return
line
def
print_float
(
key
,
value
):
value
=
round
(
value
,
6
)
line
=
" attr {
\n
"
line
+=
f
' key: "{key}"
\n
'
line
+=
' value {
\n
'
line
+=
f
' f: {value}
\n
'
line
+=
' }
\n
'
line
+=
' }
\n
'
return
line
# Define the plc object
# This is a superset of attributes for different types of plc objects
# A plc object can only have some or all the attributes
# Please check Circuit Training repo (https://github.com/google-research/circuit_training/blob/main/docs/NETLIST_FORMAT.md) for detailed explanation
class
PlcObject
:
def
__init__
(
self
,
id
):
self
.
name
=
None
self
.
node_id
=
id
self
.
height
=
0
self
.
width
=
0
self
.
weight
=
0
self
.
x
=
-
1
self
.
x_offset
=
0
self
.
y
=
-
1
self
.
y_offset
=
0
self
.
m_name
=
None
# for macro name
self
.
m_node_id
=
-
1
# the node id for macro
self
.
pb_type
=
None
self
.
side
=
None
self
.
orientation
=
None
self
.
inputs
=
[]
self
.
disp_x
=
0.0
self
.
disp_y
=
0.0
def
IsHardMacro
(
self
):
if
(
self
.
pb_type
==
'"MACRO"'
):
return
True
else
:
return
False
def
IsSoftMacro
(
self
):
if
(
self
.
pb_type
==
'"macro"'
):
return
True
else
:
return
False
def
IsFixed
(
self
):
if
(
self
.
IsSoftMacro
()
==
True
):
return
False
else
:
return
True
def
IsPort
(
self
):
if
(
self
.
pb_type
==
'"PORT"'
):
return
True
else
:
return
False
def
IsPin
(
self
):
if
(
self
.
pb_type
==
'"MACRO_PIN"'
or
self
.
pb_type
==
'"macro_pin"'
):
return
True
else
:
return
False
def
GetLocation
(
self
):
return
self
.
x
-
self
.
width
/
2.0
,
self
.
y
-
self
.
height
/
2.0
def
GetPos
(
self
):
return
self
.
x
,
self
.
y
def
GetDisp
(
self
):
return
self
.
disp_x
,
self
.
disp_y
def
SetPos
(
self
,
xp
,
yp
):
self
.
x
=
xp
self
.
y
=
yp
def
InitDisp
(
self
):
self
.
disp_x
=
0.0
self
.
disp_y
=
0.0
def
AddDisp
(
self
,
f_x
,
f_y
):
self
.
disp_x
+=
f_x
self
.
disp_y
+=
f_y
def
SetDisp
(
self
,
f_x
,
f_y
):
self
.
disp_x
=
f_x
self
.
disp_y
=
f_y
# limit the displacement. t is the threshold
def
LimitDisp
(
self
,
t
):
if
(
t
<=
0.0
):
self
.
disp_x
=
0.0
self
.
disp_y
=
0.0
dist
=
sqrt
(
self
.
disp_x
*
self
.
disp_x
+
self
.
disp_y
*
self
.
disp_y
)
if
(
dist
>
t
):
self
.
disp_x
=
self
.
disp_x
/
dist
*
t
self
.
disp_y
=
self
.
disp_y
/
dist
*
t
def
UpdateLocation
(
self
):
self
.
x
+=
self
.
disp_x
self
.
y
+=
self
.
disp_y
def
GetWidth
(
self
):
return
self
.
width
def
GetHeight
(
self
):
return
self
.
height
def
__str__
(
self
):
self
.
str
=
""
if
(
self
.
IsPort
()
==
True
):
self
.
str
+=
"node {
\n
"
self
.
str
+=
' name: '
+
self
.
name
+
'
\n
'
for
sink
in
self
.
inputs
:
self
.
str
+=
' input: '
+
sink
+
'
\n
'
self
.
str
+=
print_placeholder
(
'type'
,
self
.
pb_type
)
self
.
str
+=
print_placeholder
(
'side'
,
self
.
side
)
self
.
str
+=
print_float
(
'x'
,
self
.
x
)
self
.
str
+=
print_float
(
'y'
,
self
.
y
)
self
.
str
+=
"}
\n
"
elif
(
self
.
IsPin
()
==
True
):
self
.
str
+=
"node {
\n
"
self
.
str
+=
' name: '
+
self
.
name
+
'
\n
'
for
sink
in
self
.
inputs
:
self
.
str
+=
' input: '
+
sink
+
'
\n
'
self
.
str
+=
print_placeholder
(
'macro_name'
,
self
.
m_name
)
self
.
str
+=
print_placeholder
(
'type'
,
self
.
pb_type
)
if
(
self
.
weight
>
1
):
self
.
str
+=
print_float
(
'weight'
,
int
(
self
.
weight
))
self
.
str
+=
print_float
(
'x_offset'
,
self
.
x_offset
)
self
.
str
+=
print_float
(
'y_offset'
,
self
.
y_offset
)
self
.
str
+=
print_float
(
'x'
,
self
.
x
)
self
.
str
+=
print_float
(
'y'
,
self
.
y
)
self
.
str
+=
"}
\n
"
else
:
self
.
str
+=
"node {
\n
"
self
.
str
+=
' name: '
+
self
.
name
+
'
\n
'
self
.
str
+=
print_placeholder
(
'type'
,
self
.
pb_type
)
self
.
str
+=
print_placeholder
(
'orientation'
,
self
.
orientation
)
self
.
str
+=
print_float
(
'height'
,
self
.
height
)
self
.
str
+=
print_float
(
'width'
,
self
.
width
)
self
.
str
+=
print_float
(
'x'
,
self
.
x
)
self
.
str
+=
print_float
(
'y'
,
self
.
y
)
self
.
str
+=
"}
\n
"
return
self
.
str
def
SimpleStr
(
self
):
self
.
str
=
""
self
.
str
+=
str
(
self
.
node_id
)
+
" "
self
.
str
+=
str
(
round
(
self
.
x
,
2
))
+
" "
self
.
str
+=
str
(
round
(
self
.
y
,
2
))
+
" "
if
(
self
.
IsPort
()
==
True
):
self
.
str
+=
"- "
else
:
# print("flag", self.orientation, self.node_id)
if
self
.
orientation
:
self
.
str
+=
self
.
orientation
[
1
:
-
1
]
+
" "
else
:
self
.
str
+=
"N "
self
.
str
+=
"0
\n
"
return
self
.
str
class
FDPlacement
:
def
__init__
(
self
,
pb_netlist_file
,
plc_file
):
self
.
pb_netlist_file
=
pb_netlist_file
self
.
plc_file
=
plc_file
self
.
objects
=
[]
# store all the plc objects
self
.
ports
=
[]
# store the node_id for ports
self
.
macros
=
[]
# store the node_id for hard macros
self
.
stdcell_clusters
=
[]
# store the node_id for standard-cell clusters
self
.
adj_matrix
=
{
}
# store the adjacency matrix between nodes
self
.
n_rows
=
0
self
.
n_cols
=
0
self
.
canvas_width
=
0.0
self
.
canvas_height
=
0.0
self
.
grid_width
=
0.0
self
.
grid_height
=
0.0
self
.
grid_width
=
0.0
self
.
grid_height
=
0.0
self
.
init_flag
=
True
# force-related parameters
self
.
attractive_factor
=
0.1
self
.
attractive_exponent
=
1
self
.
repulsive_factor
=
0.1
# self.repulsive_exponent = 4
self
.
max_displacement
=
10.0
self
.
io_factor
=
10.0
### User-specified parameters
self
.
num_steps
=
[]
self
.
move_distance_factors
=
[]
self
.
attract_factor
=
[]
self
.
repel_factor
=
[]
### Read the initial files
self
.
pb_netlist_header
=
""
self
.
plc_header
=
""
self
.
ParseProtocolBufferNetlist
()
self
.
ParsePlcFile
()
# Parse protocol buffer netlist
def
ParseProtocolBufferNetlist
(
self
):
plc_object_id_map
=
{
}
# map name to node_id
# read protocol buffer netlist
float_values
=
[
'"height"'
,
'"weight"'
,
'"width"'
,
'"x"'
,
'"x_offset"'
,
'"y"'
,
'"y_offset"'
]
placeholders
=
[
'"macro_name"'
,
'"orientation"'
,
'"side"'
,
'"type"'
]
with
open
(
self
.
pb_netlist_file
)
as
f
:
content
=
f
.
read
()
.
splitlines
()
f
.
close
()
object_id
=
0
key
=
""
header
=
[]
for
line
in
content
:
header
.
append
(
line
)
words
=
line
.
split
()
if
words
[
0
]
==
'node'
:
if
len
(
self
.
objects
)
>
0
and
self
.
objects
[
-
1
]
.
name
==
'"__metadata__"'
:
self
.
objects
.
pop
(
-
1
)
object_id
-=
1
for
i
in
range
(
len
(
header
)
-
1
):
self
.
pb_netlist_header
+=
header
[
i
]
+
"
\n
"
self
.
objects
.
append
(
PlcObject
(
object_id
))
# add object
object_id
+=
1
elif
words
[
0
]
==
'name:'
:
self
.
objects
[
-
1
]
.
name
=
words
[
1
]
elif
words
[
0
]
==
'input:'
:
self
.
objects
[
-
1
]
.
inputs
.
append
(
words
[
1
])
elif
words
[
0
]
==
'key:'
:
key
=
words
[
1
]
# the attribute name
elif
words
[
0
]
==
'placeholder:'
:
if
key
==
placeholders
[
0
]:
self
.
objects
[
-
1
]
.
m_name
=
words
[
1
]
elif
key
==
placeholders
[
1
]:
# print("flag parse:", words)
self
.
objects
[
-
1
]
.
orientation
=
words
[
1
]
elif
key
==
placeholders
[
2
]:
self
.
objects
[
-
1
]
.
side
=
words
[
1
]
elif
key
==
placeholders
[
3
]:
self
.
objects
[
-
1
]
.
pb_type
=
words
[
1
]
elif
words
[
0
]
==
'f:'
:
if
key
==
float_values
[
0
]:
self
.
objects
[
-
1
]
.
height
=
round
(
float
(
words
[
1
]),
6
)
elif
key
==
float_values
[
1
]:
self
.
objects
[
-
1
]
.
weight
=
round
(
float
(
words
[
1
]),
6
)
elif
key
==
float_values
[
2
]:
self
.
objects
[
-
1
]
.
width
=
round
(
float
(
words
[
1
]),
6
)
elif
key
==
float_values
[
3
]:
self
.
objects
[
-
1
]
.
x
=
round
(
float
(
words
[
1
]),
6
)
elif
key
==
float_values
[
4
]:
self
.
objects
[
-
1
]
.
x_offset
=
round
(
float
(
words
[
1
]),
6
)
elif
key
==
float_values
[
5
]:
self
.
objects
[
-
1
]
.
y
=
round
(
float
(
words
[
1
]),
6
)
elif
key
==
float_values
[
6
]:
self
.
objects
[
-
1
]
.
y_offset
=
round
(
float
(
words
[
1
]),
6
)
# Get all the macros, standard-cell clusters and IO ports
for
plc_object
in
self
.
objects
:
plc_object_id_map
[
plc_object
.
name
]
=
plc_object
.
node_id
if
(
plc_object
.
IsHardMacro
()
==
True
):
self
.
macros
.
append
(
plc_object
.
node_id
)
elif
(
plc_object
.
IsSoftMacro
()
==
True
):
self
.
stdcell_clusters
.
append
(
plc_object
.
node_id
)
elif
(
plc_object
.
IsPort
()
==
True
):
self
.
ports
.
append
(
plc_object
.
node_id
)
else
:
pass
# Map macro pin with its macro
for
plc_object
in
self
.
objects
:
if
(
plc_object
.
IsPin
()
==
True
):
plc_object
.
m_node_id
=
plc_object_id_map
[
plc_object
.
m_name
]
else
:
plc_object
.
m_node_id
=
plc_object
.
node_id
# Calculate adjacency matrix
for
macro
in
self
.
macros
:
self
.
adj_matrix
[
macro
]
=
set
()
for
stdcell_cluster
in
self
.
stdcell_clusters
:
self
.
adj_matrix
[
stdcell_cluster
]
=
set
()
for
port
in
self
.
ports
:
self
.
adj_matrix
[
port
]
=
set
()
# We use star model to calculate adjacent matrix
# Get connections between nodes
for
plc_object
in
self
.
objects
:
driver
=
plc_object
.
m_node_id
sinks
=
set
()
for
sink
in
plc_object
.
inputs
:
sinks
.
add
(
self
.
objects
[
plc_object_id_map
[
sink
]]
.
m_node_id
)
# update adjacency matrix
for
sink
in
sinks
:
self
.
adj_matrix
[
driver
]
.
add
(
sink
)
self
.
adj_matrix
[
sink
]
.
add
(
driver
)
print
(
"***************************************************"
)
print
(
"num_macros = "
,
len
(
self
.
macros
))
print
(
"num_stdcell_clusters = "
,
len
(
self
.
stdcell_clusters
))
print
(
"num_ports = "
,
len
(
self
.
ports
))
# Parse plc file
def
ParsePlcFile
(
self
):
# read plc file for all the plc objects
with
open
(
self
.
plc_file
)
as
f
:
content
=
f
.
read
()
.
splitlines
()
f
.
close
()
# read the canvas and grid information
for
line
in
content
:
items
=
line
.
split
()
if
(
len
(
items
)
>
2
and
items
[
0
]
==
"#"
and
items
[
1
]
==
"Columns"
):
self
.
n_cols
=
int
(
items
[
3
])
self
.
n_rows
=
int
(
items
[
6
])
elif
(
len
(
items
)
>
2
and
items
[
0
]
==
"#"
and
items
[
1
]
==
"Width"
):
self
.
canvas_width
=
float
(
items
[
3
])
self
.
canvas_height
=
float
(
items
[
6
])
if
(
len
(
items
)
>
0
and
items
[
0
]
==
"#"
):
self
.
plc_header
+=
line
+
"
\n
"
print
(
"***************************************************"
)
print
(
"canvas_width = "
,
self
.
canvas_width
)
print
(
"canvas_height = "
,
self
.
canvas_height
)
print
(
"n_cols = "
,
self
.
n_cols
)
print
(
"n_rows = "
,
self
.
n_rows
)
self
.
grid_width
=
self
.
canvas_width
/
self
.
n_cols
self
.
grid_height
=
self
.
canvas_height
/
self
.
n_rows
# if overlap dont do anything
def
ifOverlap
(
self
,
u_i
,
v_i
,
ux
=
0
,
uy
=
0
,
vx
=
0
,
vy
=
0
):
u_side
=
self
.
make_square
(
u_i
)
u_x1
=
self
.
objects
[
u_i
]
.
x
+
ux
-
u_side
/
2
# left
u_x2
=
self
.
objects
[
u_i
]
.
x
+
ux
+
u_side
/
2
# right
u_y1
=
self
.
objects
[
u_i
]
.
y
+
uy
+
u_side
/
2
# top
u_y2
=
self
.
objects
[
u_i
]
.
y
+
uy
-
u_side
/
2
# bottom
v_side
=
self
.
make_square
(
v_i
)
v_x1
=
self
.
objects
[
v_i
]
.
x
+
vx
-
v_side
/
2
# left
v_x2
=
self
.
objects
[
v_i
]
.
x
+
vx
+
v_side
/
2
# right
v_y1
=
self
.
objects
[
v_i
]
.
y
+
vy
+
v_side
/
2
# top
v_y2
=
self
.
objects
[
v_i
]
.
y
+
vy
-
v_side
/
2
# bottom
return
u_x1
<
v_x2
and
u_x2
>
v_x1
and
u_y1
>
v_y2
and
u_y2
<
v_y1
# Define the forces
# Attractive force
# x is the distance between two vertices
def
func_a
(
self
,
x
,
io_flag
=
True
):
if
(
io_flag
==
True
):
return
self
.
io_factor
*
(
x
**
self
.
attractive_exponent
)
else
:
return
self
.
attractive_factor
*
(
x
**
self
.
attractive_exponent
)
# Calculate attractive force between two nodes (u, v are node_ids) (u - v)
def
f_a
(
self
,
u
,
v
,
io_flag
=
True
):
# distance should consider dimension as well
x_dist
=
self
.
objects
[
u
]
.
x
-
self
.
objects
[
v
]
.
x
-
self
.
make_square
(
u
)
/
2
-
self
.
make_square
(
v
)
/
2
y_dist
=
self
.
objects
[
u
]
.
y
-
self
.
objects
[
v
]
.
y
-
self
.
make_square
(
u
)
/
2
-
self
.
make_square
(
v
)
/
2
dist
=
sqrt
(
x_dist
*
x_dist
+
y_dist
*
y_dist
)
if
(
dist
<=
0.0
or
self
.
ifOverlap
(
u
,
v
)):
return
0.0
,
0.0
else
:
f
=
self
.
func_a
(
dist
,
io_flag
)
# enforece distance not as close as we hope
f_x
=
x_dist
/
dist
*
f
f_y
=
y_dist
/
dist
*
f
return
f_x
,
f_y
def
make_square
(
self
,
u
):
return
sqrt
(
self
.
objects
[
u
]
.
width
*
self
.
objects
[
u
]
.
height
)
# Repulsive force
# x is the distance between two vertices
# def func_r(self, x):
# return self.repulsive_factor / (x ** self.repulsive_exponent)
# Calculate repulsive force between two nodes (u, v are node_ids) (u - v)
# def f_r(self, u, v):
# if (self.repulsive_factor == 0.0):
# return 0.0, 0.0
# x_dist = self.objects[u].x - self.objects[v].x - self.make_square(u)/2 - self.make_square(v)/2
# y_dist = self.objects[u].y - self.objects[v].y - self.make_square(u)/2 - self.make_square(v)/2
# dist = sqrt(x_dist * x_dist + y_dist * y_dist)
# if (dist <= 1e-10):
# return sqrt(self.repulsive_factor), sqrt(self.repulsive_factor)
# else:
# return sqrt(self.repulsive_factor) * x_dist * 2, sqrt(self.repulsive_factor) * y_dist * 2
# # else:
def
f_r
(
self
,
u
,
v
):
if
(
self
.
repulsive_factor
==
0.0
):
return
0.0
,
0.0
x_dist
=
self
.
objects
[
u
]
.
x
-
self
.
objects
[
v
]
.
x
y_dist
=
self
.
objects
[
u
]
.
y
-
self
.
objects
[
v
]
.
y
dist
=
sqrt
(
x_dist
*
x_dist
+
y_dist
*
y_dist
)
if
(
dist
<=
1e-10
):
return
sqrt
(
self
.
repulsive_factor
),
sqrt
(
self
.
repulsive_factor
)
else
:
f_x
=
self
.
repulsive_factor
*
x_dist
/
dist
f_y
=
self
.
repulsive_factor
*
y_dist
/
dist
return
f_x
,
f_y
# f_x = self.repulsive_factor * x_dist / dist
# f_y = self.repulsive_factor * y_dist / dist
# return f_x, f_y
def
f_r_m
(
self
,
u
,
v
):
if
(
self
.
repulsive_factor
==
0.0
):
return
0.0
,
0.0
x_dist
=
self
.
objects
[
u
]
.
x
-
self
.
objects
[
v
]
.
x
y_dist
=
self
.
objects
[
u
]
.
y
-
self
.
objects
[
v
]
.
y
dist
=
sqrt
(
x_dist
*
x_dist
+
y_dist
*
y_dist
)
if
(
dist
<=
1e-10
):
# print("dist found", dist)
return
x_dist
/
dist
*
(
self
.
make_square
(
u
)
/
2
+
self
.
make_square
(
v
)
/
2
),
\
y_dist
/
dist
*
(
self
.
make_square
(
u
)
/
2
+
self
.
make_square
(
v
)
/
2
)
elif
self
.
ifOverlap
(
u
,
v
):
# if overlap, double the force? keep x
# print("overlap found", dist)
return
x_dist
/
dist
*
(
self
.
make_square
(
u
)
/
2
+
self
.
make_square
(
v
)
/
2
),
\
y_dist
/
dist
*
(
self
.
make_square
(
u
)
/
2
+
self
.
make_square
(
v
)
/
2
)
else
:
return
0.0
,
0.0
# Pull the objects to the nearest center of the gridcell
def
RoundCenter
(
self
,
object_id
):
col_id
=
round
((
self
.
objects
[
object_id
]
.
x
-
self
.
grid_width
/
2.0
)
/
self
.
grid_width
)
if
(
col_id
<
0
):
col_id
=
0
elif
(
col_id
>
self
.
n_cols
-
1
):
col_id
=
self
.
n_cols
-
1
self
.
objects
[
object_id
]
.
x
=
(
col_id
+
0.5
)
*
self
.
grid_width
row_id
=
round
((
self
.
objects
[
object_id
]
.
y
-
self
.
grid_height
/
2.0
)
/
self
.
grid_height
)
if
(
row_id
<
0
):
row_id
=
0
elif
(
row_id
>
self
.
n_rows
-
1
):
row_id
=
self
.
n_rows
-
1
self
.
objects
[
object_id
]
.
y
=
(
row_id
+
0.5
)
*
self
.
grid_height
def
centeralize
(
self
,
object_id
):
self
.
objects
[
object_id
]
.
SetPos
(
self
.
canvas_width
/
2
,
self
.
canvas_height
/
2
)
def
centeralize_circle
(
self
,
object_id
):
r
=
1
*
sqrt
(
random
.
random
())
theta
=
random
.
random
()
*
2
*
math
.
pi
centerX
=
self
.
canvas_width
/
2
centerY
=
self
.
canvas_height
/
2
self
.
objects
[
object_id
]
.
SetPos
(
centerX
+
r
*
math
.
cos
(
theta
),
centerY
+
r
*
math
.
sin
(
theta
))
# Make sure all the clusters are placed within the canvas
def
FitCanvas
(
self
,
object_id
):
if
(
self
.
objects
[
object_id
]
.
x
<=
0.0
):
self
.
objects
[
object_id
]
.
x
=
0.0
if
(
self
.
objects
[
object_id
]
.
x
>=
self
.
canvas_width
):
self
.
objects
[
object_id
]
.
x
=
self
.
canvas_width
if
(
self
.
objects
[
object_id
]
.
y
<=
0.0
):
self
.
objects
[
object_id
]
.
y
=
0.0
if
(
self
.
objects
[
object_id
]
.
y
>=
self
.
canvas_height
):
self
.
objects
[
object_id
]
.
y
=
self
.
canvas_height
def
shift_sigmoid
(
self
,
x
,
a
=
100
):
return
1
/
(
1
+
math
.
exp
(
-
x
+
a
))
def
shift_elu
(
self
,
x
,
shift
=
100
,
a
=
0.3
):
if
x
>
shift
+
a
:
return
x
else
:
return
a
*
math
.
exp
(
x
-
shift
)
def
piecewise_leaky_relu
(
self
,
x
,
shift
=
100
,
a
=
0.1
):
if
x
>=
0
:
return
max
(
a
*
(
x
-
shift
),
(
x
-
shift
))
+
a
*
shift
else
:
return
-
max
(
a
*
(
x
-
shift
),
(
x
-
shift
))
-
a
*
shift
def
piecewise_sigmoid
(
self
,
x
,
shift
=
50
):
if
x
>=
0
:
return
1
/
(
math
.
exp
(
-
x
+
shift
)
+
1
)
else
:
return
-
1
/
(
math
.
exp
(
x
+
shift
)
+
1
)
# Force-directed Placement for standard-cell clusters
def
Placement
(
self
):
# initialize the displacement for standard-cell clusters
for
cluster
in
self
.
stdcell_clusters
:
self
.
objects
[
cluster
]
.
InitDisp
()
# calculate the repulsive forces
# repulsive forces between stdcell clusters
################################################################################################################
# if False:
if
self
.
repulsive_factor
!=
0.0
:
xr_collection
=
[
0
]
*
len
(
self
.
objects
)
yr_collection
=
[
0
]
*
len
(
self
.
objects
)
for
u
in
self
.
stdcell_clusters
:
# randomize which stdcell to
for
v
in
self
.
stdcell_clusters
:
if
(
u
<=
v
):
# we just need calculate once
continue
f_x
,
f_y
=
self
.
f_r
(
u
,
v
)
# self.objects[u].AddDisp(self.objects[u].height * self.objects[u].width * 200 * f_x, self.objects[u].height * self.objects[u].width * 200 * f_y)
# self.objects[v].AddDisp(self.objects[v].height * self.objects[v].width * -200 * f_x, self.objects[v].height * self.objects[v].width * -200 * f_y)
xr_collection
[
u
]
+=
1.0
*
f_x
yr_collection
[
u
]
+=
1.0
*
f_y
xr_collection
[
v
]
+=
-
1.0
*
f_x
yr_collection
[
v
]
+=
-
1.0
*
f_y
# self.objects[u].AddDisp(1 * f_x, 1 * f_y)
# self.objects[v].AddDisp(-1 * f_x, -1 * f_y)
max_x_disp
,
max_y_disp
=
(
0.0
,
0.0
)
min_x_disp
,
min_y_disp
=
(
0.0
,
0.0
)
# limit max displacement to threshold : self.max_displacement
for
xr
,
yr
in
zip
(
xr_collection
,
yr_collection
):
if
xr
!=
0.0
:
max_x_disp
=
max
(
max_x_disp
,
abs
(
xr
))
min_x_disp
=
min
(
min_x_disp
,
abs
(
xr
))
if
yr
!=
0.0
:
max_y_disp
=
max
(
max_y_disp
,
abs
(
yr
))
min_y_disp
=
min
(
min_y_disp
,
abs
(
yr
))
scaling
=
2.0
for
cluster
in
self
.
stdcell_clusters
:
# self.objects[cluster].AddDisp((2*((xr_collection[cluster]-min_x_disp)/(max_x_disp - min_x_disp)) - 1),
# (2*((yr_collection[cluster]-min_y_disp)/(max_y_disp-min_y_disp)) - 1))
# keeping the sign while normalize
self
.
objects
[
cluster
]
.
AddDisp
(
scaling
*
xr_collection
[
cluster
]
/
max_x_disp
,
scaling
*
yr_collection
[
cluster
]
/
max_y_disp
)
################################################################################################################
# if False:
xr_collection
=
[
0
]
*
len
(
self
.
objects
)
yr_collection
=
[
0
]
*
len
(
self
.
objects
)
# repulsive forces between stdcell clusters and macros
for
u
in
self
.
stdcell_clusters
:
for
v
in
self
.
macros
:
f_x
,
f_y
=
self
.
f_r_m
(
u
,
v
)
# self.objects[u].AddDisp(5 * f_x, 5 * f_y)
xr_collection
[
u
]
+=
1.0
*
f_x
yr_collection
[
u
]
+=
1.0
*
f_y
max_x_disp
,
max_y_disp
=
(
0.0
,
0.0
)
min_x_disp
,
min_y_disp
=
(
0.0
,
0.0
)
# limit max displacement to threshold : self.max_displacement
for
xr
,
yr
in
zip
(
xr_collection
,
yr_collection
):
if
xr
!=
0.0
:
max_x_disp
=
max
(
max_x_disp
,
abs
(
xr
))
min_x_disp
=
min
(
min_x_disp
,
abs
(
xr
))
if
yr
!=
0.0
:
max_y_disp
=
max
(
max_y_disp
,
abs
(
yr
))
min_y_disp
=
min
(
min_y_disp
,
abs
(
yr
))
if
max_x_disp
==
0.0
:
max_x_disp
=
1.0
if
max_y_disp
==
0.0
:
max_y_disp
=
1.0
scaling
=
4.0
for
cluster
in
self
.
stdcell_clusters
:
# self.objects[cluster].AddDisp((2*((xr_collection[cluster]-min_x_disp)/(max_x_disp - min_x_disp)) - 1),
# (2*((yr_collection[cluster]-min_y_disp)/(max_y_disp-min_y_disp)) - 1))
# keeping the sign while normalize
self
.
objects
[
cluster
]
.
AddDisp
(
scaling
*
xr_collection
[
cluster
]
/
max_x_disp
,
scaling
*
yr_collection
[
cluster
]
/
max_y_disp
)
################################################################################################################
# calculate the attractive force traverse each edge
# the adj_matrix is a symmetric matrix
if
self
.
attractive_factor
!=
0
:
# if False:
xr_collection
=
[
0
]
*
len
(
self
.
objects
)
yr_collection
=
[
0
]
*
len
(
self
.
objects
)
for
driver
,
sinks
in
self
.
adj_matrix
.
items
():
if
(
self
.
objects
[
driver
]
.
IsSoftMacro
()
==
False
):
continue
for
sink
in
sinks
:
if
self
.
ifOverlap
(
driver
,
sink
):
# if overlapped, no changes
# print("overlap intially")
continue
f_x
,
f_y
=
self
.
f_a
(
driver
,
sink
)
if
self
.
ifOverlap
(
driver
,
sink
,
self
.
piecewise_sigmoid
(
-
1
*
f_x
),
self
.
piecewise_sigmoid
(
-
1
*
f_y
)):
# if overlapped after moving, no changes
# print("overlap after change")
continue
xr_collection
[
driver
]
+=
self
.
piecewise_sigmoid
(
-
1.0
*
f_x
)
yr_collection
[
driver
]
+=
self
.
piecewise_sigmoid
(
-
1.0
*
f_y
)
max_x_disp
,
max_y_disp
=
(
0.0
,
0.0
)
min_x_disp
,
min_y_disp
=
(
0.0
,
0.0
)
# limit max displacement to threshold : self.max_displacement
for
xr
,
yr
in
zip
(
xr_collection
,
yr_collection
):
if
xr
!=
0.0
:
max_x_disp
=
max
(
max_x_disp
,
abs
(
xr
))
min_x_disp
=
min
(
min_x_disp
,
abs
(
xr
))
if
yr
!=
0.0
:
max_y_disp
=
max
(
max_y_disp
,
abs
(
yr
))
min_y_disp
=
min
(
min_y_disp
,
abs
(
yr
))
# not too much attract
scaling
=
0.1
for
cluster
in
self
.
stdcell_clusters
:
# self.objects[cluster].AddDisp((2*((xr_collection[cluster]-min_x_disp)/(max_x_disp - min_x_disp)) - 1),
# (2*((yr_collection[cluster]-min_y_disp)/(max_y_disp-min_y_disp)) - 1))
# keeping the sign while normalize
# self.objects[cluster].AddDisp(scaling * xr_collection[cluster] / max_x_disp, scaling * yr_collection[cluster]/ max_y_disp)
self
.
objects
[
cluster
]
.
AddDisp
(
scaling
*
xr_collection
[
cluster
]
/
max_x_disp
,
scaling
*
yr_collection
[
cluster
]
/
max_x_disp
)
# self.objects[cluster].LimitDisp(self.max_displacement)
################################################################################################################
# push all the macros to the nearest center of gridcell
for
cluster
in
self
.
stdcell_clusters
:
self
.
objects
[
cluster
]
.
UpdateLocation
()
#self.RoundCenter(cluster)
# Run placement
def
Run
(
self
):
# initialize the position for all the macros and stdcell clusters
if
(
self
.
init_flag
==
True
):
for
cluster
in
self
.
stdcell_clusters
:
# self.RoundCenter(cluster)
# self.centeralize(cluster)
self
.
centeralize_circle
(
cluster
)
for
macro
in
self
.
macros
:
self
.
RoundCenter
(
macro
)
# check the initial parameter setting first
flag
=
True
flag
=
flag
and
(
len
(
self
.
num_steps
)
>
0
)
flag
=
flag
and
(
len
(
self
.
num_steps
)
==
len
(
self
.
move_distance_factors
))
flag
=
flag
and
(
len
(
self
.
num_steps
)
==
len
(
self
.
attract_factor
))
flag
=
flag
and
(
len
(
self
.
num_steps
)
==
len
(
self
.
repel_factor
))
if
(
flag
==
False
):
print
(
"**************************************************"
)
print
(
"Error ! Please check your inputs."
)
exit
()
# Write initial files
self
.
WritePbNetlist
(
self
.
pb_netlist_file
+
".0"
)
self
.
WritePlcFile
(
self
.
plc_file
+
".0"
)
print
(
"*******************************************************"
)
print
(
"Start Force-directed Placement"
)
print
(
"
\n
"
)
for
i
in
range
(
len
(
self
.
num_steps
)):
print
(
"************************************************"
)
print
(
"Start Call - "
,
i
+
1
)
self
.
attractive_factor
=
self
.
attract_factor
[
i
]
self
.
repulsive_factor
=
self
.
repel_factor
[
i
]
factor
=
self
.
move_distance_factors
[
i
]
*
max
(
self
.
canvas_width
,
self
.
canvas_height
)
self
.
num_step
=
self
.
num_steps
[
i
]
self
.
max_displacement
=
factor
/
self
.
num_step
print
(
"[INFO] attractive_factor = "
,
self
.
attractive_factor
)
print
(
"[INFO] repulsive_factor = "
,
self
.
repulsive_factor
)
print
(
"[INFO] max_displaccment = "
,
self
.
max_displacement
)
print
(
"[INFO] num_step = "
,
self
.
num_step
)
print
(
"[INFO] io_factor = "
,
self
.
io_factor
)
for
j
in
range
(
self
.
num_step
):
print
(
"Runing Step "
,
j
)
self
.
Placement
()
# Based on our understanding, the stdcell clusters can be placed
# at any place in the canvas instead of the center of gridcells
#for cluster in self.stdcell_clusters:
# self.RoundCenter(cluster)
for
cluster
in
self
.
stdcell_clusters
:
self
.
FitCanvas
(
cluster
)
self
.
WritePbNetlist
(
self
.
pb_netlist_file
+
"."
+
str
(
i
+
1
))
self
.
WritePlcFile
(
self
.
plc_file
+
"."
+
str
(
i
+
1
))
self
.
WritePbNetlist
(
self
.
pb_netlist_file
+
".final"
)
self
.
WritePlcFile
(
self
.
plc_file
+
".final"
)
# Write the output_file
def
WritePbNetlist
(
self
,
netlist_file
):
f
=
open
(
netlist_file
,
"w"
)
f
.
write
(
self
.
pb_netlist_header
)
for
pb_object
in
self
.
objects
:
f
.
write
(
str
(
pb_object
))
f
.
close
()
def
WritePlcFile
(
self
,
plc_file
):
f
=
open
(
plc_file
,
"w"
)
f
.
write
(
self
.
plc_header
)
for
pb_object
in
self
.
objects
:
if
(
pb_object
.
IsPin
()
==
False
):
f
.
write
(
pb_object
.
SimpleStr
())
f
.
close
()
if
__name__
==
"__main__"
:
parser
=
argparse
.
ArgumentParser
()
parser
.
add_argument
(
"--netlist"
,
help
=
"protocol buffer netlist"
,
type
=
str
,
default
=
"./test/ariane.pb.txt"
)
parser
.
add_argument
(
"--plc"
,
help
=
"plc_file"
,
type
=
str
,
default
=
"./test/ariane.plc"
)
args
=
parser
.
parse_args
()
netlist_file
=
args
.
netlist
plc_file
=
args
.
plc
io_factor
=
1.0
num_steps
=
[
100
,
100
,
100
]
move_distance_factors
=
[
1.0
,
1.0
,
1.0
]
attract_factor
=
[
100.0
,
1.0e-3
,
1.0e-3
]
repel_factor
=
[
0.0
,
1.0e6
,
1.0e7
]
# Run force-directed placement
placement
=
FDPlacement
(
netlist_file
,
plc_file
)
placement
.
io_factor
=
io_factor
placement
.
num_steps
=
num_steps
placement
.
move_distance_factors
=
move_distance_factors
placement
.
attract_factor
=
attract_factor
placement
.
repel_factor
=
repel_factor
placement
.
Run
()
# Visual results
iterations
=
1
+
len
(
num_steps
)
for
i
in
range
(
iterations
):
print
(
"*********************************************"
)
print
(
"Iteration "
,
i
)
print
(
"
\n\n
"
)
tp_netlist_file
=
netlist_file
+
"."
+
str
(
i
)
tp_plc_file
=
plc_file
+
"."
+
str
(
i
)
# VisualPlacement(tp_netlist_file, tp_plc_file)
CodeElements/Plc_client/plc_client_os.py
View file @
a9e01189
...
...
@@ -10,6 +10,7 @@ import matplotlib.pyplot as plt
from
matplotlib.patches
import
Rectangle
import
numpy
as
np
import
traceback
,
sys
import
random
"""plc_client_os docstrings.
...
...
@@ -2385,6 +2386,26 @@ class PlacementCost(object):
'''
FD Placement below shares the same functionality as the FDPlacement/fd_placement.py
'''
def
__ifOverlap
(
self
,
u_i
,
v_i
,
ux
=
0
,
uy
=
0
,
vx
=
0
,
vy
=
0
):
'''
Detect if the two modules are overlapping or not (w/o using block structure)
'''
# extract first macro
u_side
=
self
.
modules_w_pins
[
u_i
]
.
get_height
()
u_x1
=
self
.
modules_w_pins
[
u_i
]
.
get_pos
()[
0
]
+
ux
-
u_side
/
2
# left
u_x2
=
self
.
modules_w_pins
[
u_i
]
.
get_pos
()[
0
]
+
ux
+
u_side
/
2
# right
u_y1
=
self
.
modules_w_pins
[
u_i
]
.
get_pos
()[
1
]
+
uy
+
u_side
/
2
# top
u_y2
=
self
.
modules_w_pins
[
u_i
]
.
get_pos
()[
1
]
+
uy
-
u_side
/
2
# bottom
# extract second macro
v_side
=
self
.
modules_w_pins
[
v_i
]
.
get_height
()
v_x1
=
self
.
modules_w_pins
[
v_i
]
.
get_pos
()[
0
]
+
vx
-
v_side
/
2
# left
v_x2
=
self
.
modules_w_pins
[
v_i
]
.
get_pos
()[
0
]
+
vx
+
v_side
/
2
# right
v_y1
=
self
.
modules_w_pins
[
v_i
]
.
get_pos
()[
1
]
+
vy
+
v_side
/
2
# top
v_y2
=
self
.
modules_w_pins
[
v_i
]
.
get_pos
()[
1
]
+
vy
-
v_side
/
2
# bottom
return
u_x1
<
v_x2
and
u_x2
>
v_x1
and
u_y1
>
v_y2
and
u_y2
<
v_y1
def
__repulsive_force
(
self
,
repel_factor
,
node_i
,
node_j
):
'''
Calculate repulsive force between two nodes node_i, node_j
...
...
@@ -2408,12 +2429,41 @@ class PlacementCost(object):
hypo_dist
=
math
.
sqrt
(
x_dist
**
2
+
y_dist
**
2
)
# compute force in x and y direction
if
hypo_dist
<=
1e-
5
:
if
hypo_dist
<=
1e-
10
:
return
math
.
sqrt
(
repel_factor
),
math
.
sqrt
(
repel_factor
)
else
:
f_x
=
repel_factor
*
x_dist
/
hypo_dist
f_y
=
repel_factor
*
y_dist
/
hypo_dist
return
f_x
,
f_y
def
__repulsive_force_hard_macro
(
self
,
repel_factor
,
h_node_i
,
s_node_j
):
'''
Calculate repulsive force between hard macro and soft macro
'''
if
repel_factor
==
0.0
:
return
0.0
,
0.0
# retrieve module instance
h_mod_i
=
self
.
modules_w_pins
[
h_node_i
]
s_mod_j
=
self
.
modules_w_pins
[
s_node_j
]
# retrieve module position
x_i
,
y_i
=
h_mod_i
.
get_pos
()
x_j
,
y_j
=
s_mod_j
.
get_pos
()
# get dist between x and y
x_dist
=
x_i
-
x_j
y_dist
=
y_i
-
y_j
# get dist of hypotenuse
hypo_dist
=
math
.
sqrt
(
x_dist
**
2
+
y_dist
**
2
)
# compute force in x and y direction
if
hypo_dist
<=
1e-10
or
self
.
__ifOverlap
(
h_node_i
,
s_node_j
):
return
x_dist
/
hypo_dist
*
(
h_mod_i
.
get_height
()
/
2
+
s_mod_j
.
get_height
()
/
2
),
\
y_dist
/
hypo_dist
*
(
h_mod_i
.
get_height
()
/
2
+
s_mod_j
.
get_height
()
/
2
)
else
:
return
0.0
,
0.0
def
__attractive_force
(
self
,
io_factor
,
attract_factor
,
node_i
,
node_j
,
io_flag
=
True
,
attract_exponent
=
1
):
'''
...
...
@@ -2428,14 +2478,14 @@ class PlacementCost(object):
x_j
,
y_j
=
mod_j
.
get_pos
()
# get dist between x and y
x_dist
=
x_i
-
x_j
y_dist
=
y_i
-
y_j
x_dist
=
x_i
-
x_j
-
mod_i
.
get_height
()
/
2
-
mod_j
.
get_height
()
/
2
y_dist
=
y_i
-
y_j
-
mod_i
.
get_height
()
/
2
-
mod_j
.
get_height
()
/
2
# get dist of hypotenuse
hypo_dist
=
math
.
sqrt
(
x_dist
**
2
+
y_dist
**
2
)
# compute force in x and y direction
if
hypo_dist
<=
0.0
:
if
hypo_dist
<=
0.0
or
self
.
__ifOverlap
(
u_i
=
node_i
,
v_i
=
node_j
)
:
return
0.0
,
0.0
else
:
if
io_flag
:
...
...
@@ -2469,6 +2519,16 @@ class PlacementCost(object):
row
=
self
.
grid_row
-
1
mod
.
set_pos
((
col
+
0.5
)
*
self
.
grid_width
,
(
row
+
0.5
)
*
self
.
grid_height
)
def
__centeralize_circle
(
self
,
mod_id
):
'''
Pull the modules to a randomized unit circle in the center of the canvas
'''
r
=
1
*
math
.
sqrt
(
random
.
random
())
theta
=
random
.
random
()
*
2
*
math
.
pi
centerX
=
self
.
width
/
2
centerY
=
self
.
height
/
2
self
.
modules_w_pins
[
mod_id
]
.
set_pos
(
centerX
+
r
*
math
.
cos
(
theta
),
centerY
+
r
*
math
.
sin
(
theta
))
def
__boundary_check
(
self
,
mod_id
):
'''
...
...
@@ -2501,64 +2561,145 @@ class PlacementCost(object):
soft_macro_disp
[
mod_idx
]
=
[
0.0
,
0.0
]
def
add_displace
(
mod_id
,
x_disp
,
y_disp
):
'''
Add the displacement
'''
soft_macro_disp
[
mod_id
][
0
]
+=
x_disp
soft_macro_disp
[
mod_id
][
1
]
+=
y_disp
# limit the displacement. max_displace is the threshold
def
limit_displace
(
max_displace
,
mod_id
):
if
max_displace
<=
0.0
:
soft_macro_disp
[
mod_id
][
0
]
=
0.0
soft_macro_disp
[
mod_id
][
1
]
=
0.0
# get dist of hypotenuse
hypo_dist
=
math
.
sqrt
(
soft_macro_disp
[
mod_id
][
0
]
**
2
+
soft_macro_disp
[
mod_id
][
1
]
**
2
)
if
hypo_dist
>
max_displace
:
soft_macro_disp
[
mod_id
][
0
]
=
soft_macro_disp
[
mod_id
][
0
]
/
hypo_dist
*
max_displace
soft_macro_disp
[
mod_id
][
1
]
=
soft_macro_disp
[
mod_id
][
1
]
/
hypo_dist
*
max_displace
def
update_location
(
mod_id
,
x_disp
,
y_disp
):
'''
Update the displacement to the coordiante
'''
x_pos
,
y_pos
=
self
.
modules_w_pins
[
mod_id
]
.
get_pos
()
# logging.info("{} {} {} {}".format(x_pos, y_pos, x_disp, y_disp))
self
.
modules_w_pins
[
mod_id
]
.
set_pos
(
x_pos
+
x_disp
,
y_pos
+
y_disp
)
def
piecewise_sigmoid
(
x
,
shift
=
50
):
if
x
>=
0
:
return
1
/
(
math
.
exp
(
-
x
+
shift
)
+
1
)
else
:
return
-
1
/
(
math
.
exp
(
x
+
shift
)
+
1
)
##SOFT_SOFT REPEL###############################################################################################
# calculate the repulsive forces
# repulsive forces between stdcell clusters
for
mod_i
in
self
.
soft_macro_indices
:
for
mod_j
in
self
.
soft_macro_indices
:
if
(
mod_i
<=
mod_j
):
continue
repul_x
,
repul_y
=
self
.
__repulsive_force
(
repel_factor
=
repel_factor
,
node_i
=
mod_i
,
node_j
=
mod_j
)
add_displace
(
mod_i
,
repul_x
,
repul_y
)
add_displace
(
mod_j
,
-
1.0
*
repul_x
,
-
1.0
*
repul_y
)
# repulsive forces between stdcell clusters and macros
for
mod_i
in
self
.
soft_macro_indices
:
for
mod_j
in
self
.
hard_macro_indices
:
repul_x
,
repul_y
=
self
.
__repulsive_force
(
repel_factor
=
repel_factor
,
node_i
=
mod_i
,
node_j
=
mod_j
)
add_displace
(
mod_i
,
repul_x
,
repul_y
)
# calculate the attractive force
# traverse each edge
# the adj_matrix is a symmetric matrix
for
driver_pin_idx
,
driver_pin
in
enumerate
(
self
.
modules_w_pins
):
# only for soft macro
if
driver_pin_idx
in
self
.
soft_macro_pin_indices
and
driver_pin
.
get_sink
():
driver_mod_idx
=
self
.
get_ref_node_id
(
driver_pin_idx
)
for
sink_pin_name
in
driver_pin
.
get_sink
()
.
keys
():
sink_mod_idx
=
self
.
mod_name_to_indices
[
sink_pin_name
]
# print(self.modules_w_pins[sink_mod_idx].get_type())
attrac_x
,
attrac_y
=
self
.
__attractive_force
(
io_factor
=
io_factor
,
attract_factor
=
attract_factor
,
node_i
=
driver_mod_idx
,
node_j
=
sink_mod_idx
)
add_displace
(
driver_mod_idx
,
-
1.0
*
attrac_x
,
-
1.0
*
attrac_y
)
if
repel_factor
!=
0.0
:
# temp storing the soft macro count
xr_collection
=
[
0
]
*
len
(
self
.
modules_w_pins
)
yr_collection
=
[
0
]
*
len
(
self
.
modules_w_pins
)
# repulsive forces between stdcell clusters and stdcell clusters
for
mod_i
in
self
.
soft_macro_indices
:
for
mod_j
in
self
.
soft_macro_indices
:
if
(
mod_i
<=
mod_j
):
continue
repul_x
,
repul_y
=
self
.
__repulsive_force
(
repel_factor
=
repel_factor
,
node_i
=
mod_i
,
node_j
=
mod_j
)
xr_collection
[
mod_i
]
+=
1.0
*
repul_x
yr_collection
[
mod_i
]
+=
1.0
*
repul_y
xr_collection
[
mod_j
]
+=
-
1.0
*
repul_x
yr_collection
[
mod_j
]
+=
-
1.0
*
repul_y
# finding max x y displacement
max_x_disp
,
max_y_disp
=
(
0.0
,
0.0
)
for
xr
,
yr
in
zip
(
xr_collection
,
yr_collection
):
if
xr
!=
0.0
:
max_x_disp
=
max
(
max_x_disp
,
abs
(
xr
))
if
yr
!=
0.0
:
max_y_disp
=
max
(
max_y_disp
,
abs
(
yr
))
# prevent zero division
if
max_x_disp
==
0.0
:
max_x_disp
=
1.0
if
max_y_disp
==
0.0
:
max_y_disp
=
1.0
scaling
=
2.0
for
mod_idx
in
self
.
soft_macro_indices
:
add_displace
(
mod_idx
,
scaling
*
xr_collection
[
mod_idx
]
/
max_x_disp
,
scaling
*
yr_collection
[
mod_idx
]
/
max_y_disp
)
##SOFT_HARD REPEL###############################################################################################
if
repel_factor
!=
0.0
:
# temp storing the soft macro count
xr_collection
=
[
0
]
*
len
(
self
.
modules_w_pins
)
yr_collection
=
[
0
]
*
len
(
self
.
modules_w_pins
)
# repulsive forces between stdcell clusters and macros
for
mod_i
in
self
.
soft_macro_indices
:
for
mod_j
in
self
.
hard_macro_indices
:
repul_x
,
repul_y
=
self
.
__repulsive_force_hard_macro
(
repel_factor
=
repel_factor
,
h_node_i
=
mod_i
,
s_node_j
=
mod_j
)
xr_collection
[
mod_i
]
+=
1.0
*
repul_x
yr_collection
[
mod_i
]
+=
1.0
*
repul_y
# finding max x y displacement
max_x_disp
,
max_y_disp
=
(
0.0
,
0.0
)
for
xr
,
yr
in
zip
(
xr_collection
,
yr_collection
):
if
xr
!=
0.0
:
max_x_disp
=
max
(
max_x_disp
,
abs
(
xr
))
if
yr
!=
0.0
:
max_y_disp
=
max
(
max_y_disp
,
abs
(
yr
))
# prevent zero division
if
max_x_disp
==
0.0
:
max_x_disp
=
1.0
if
max_y_disp
==
0.0
:
max_y_disp
=
1.0
scaling
=
4.0
for
mod_idx
in
self
.
soft_macro_indices
:
add_displace
(
mod_idx
,
scaling
*
xr_collection
[
mod_idx
]
/
max_x_disp
,
scaling
*
yr_collection
[
mod_idx
]
/
max_y_disp
)
##NET ATTRACT###################################################################################################
if
attract_factor
!=
0.0
:
# temp storing the soft macro count
xr_collection
=
[
0
]
*
len
(
self
.
modules_w_pins
)
yr_collection
=
[
0
]
*
len
(
self
.
modules_w_pins
)
# calculate the attractive force
# traverse each edge
# the adj_matrix is a symmetric matrix
for
driver_pin_idx
,
driver_pin
in
enumerate
(
self
.
modules_w_pins
):
# only for soft macro
if
driver_pin_idx
in
self
.
soft_macro_pin_indices
and
driver_pin
.
get_sink
():
driver_mod_idx
=
self
.
get_ref_node_id
(
driver_pin_idx
)
for
sink_pin_name
in
driver_pin
.
get_sink
()
.
keys
():
sink_mod_idx
=
self
.
mod_name_to_indices
[
sink_pin_name
]
# if overlapped, dont attract further
if
self
.
__ifOverlap
(
driver_mod_idx
,
sink_mod_idx
):
continue
attrac_x
,
attrac_y
=
self
.
__attractive_force
(
io_factor
=
io_factor
,
attract_factor
=
attract_factor
,
node_i
=
driver_mod_idx
,
node_j
=
sink_mod_idx
)
# if overlapped, dont attract further
if
self
.
__ifOverlap
(
driver_mod_idx
,
sink_mod_idx
,
attrac_x
,
attrac_y
):
continue
xr_collection
[
driver_mod_idx
]
+=
piecewise_sigmoid
(
-
1.0
*
attrac_x
)
yr_collection
[
driver_mod_idx
]
+=
piecewise_sigmoid
(
-
1.0
*
attrac_y
)
# finding max x y displacement
max_x_disp
,
max_y_disp
=
(
0.0
,
0.0
)
for
xr
,
yr
in
zip
(
xr_collection
,
yr_collection
):
if
xr
!=
0.0
:
max_x_disp
=
max
(
max_x_disp
,
abs
(
xr
))
if
yr
!=
0.0
:
max_y_disp
=
max
(
max_y_disp
,
abs
(
yr
))
# prevent zero division
if
max_x_disp
==
0.0
:
max_x_disp
=
1.0
if
max_y_disp
==
0.0
:
max_y_disp
=
1.0
# not too much attract
scaling
=
0.1
for
mod_idx
in
self
.
soft_macro_indices
:
add_displace
(
mod_idx
,
scaling
*
xr_collection
[
mod_idx
]
/
max_x_disp
,
scaling
*
yr_collection
[
mod_idx
]
/
max_y_disp
)
for
mod_idx
in
soft_macro_disp
.
keys
():
# limit max displacement to threshold : max_displacement
limit_displace
(
max_displace
=
max_displacement
,
mod_id
=
mod_idx
)
# push all the macros to the nearest center of gridcell
update_location
(
mod_idx
,
*
soft_macro_disp
[
mod_idx
])
# Moved to here to save a for loop
...
...
@@ -2575,7 +2716,7 @@ class PlacementCost(object):
# initialize the position for all the macros and stdcell clusters
# YW: here I will ignore centering Macros since CT placement does that
for
mod_idx
in
self
.
soft_macro_indices
:
self
.
__cent
raliz
e
(
mod_id
=
mod_idx
)
self
.
__cent
eralize_circl
e
(
mod_id
=
mod_idx
)
for
epoch_id
,
iterations
in
enumerate
(
num_steps
):
logging
.
info
(
"#[OPTIMIZING STDCELs] at num_step {}:"
.
format
(
str
(
epoch_id
)))
...
...
@@ -2611,6 +2752,12 @@ class PlacementCost(object):
def
get_orientation
(
self
):
return
self
.
orientation
def
get_height
(
self
):
return
0
def
get_width
(
self
):
return
0
def
add_connection
(
self
,
module_name
):
# NOTE: assume PORT names does not contain slash
...
...
CodeElements/Plc_client/plc_client_os_test.py
View file @
a9e01189
...
...
@@ -79,6 +79,18 @@ Example:
--marv 5
\
--smooth 2
$ python3 -m Plc_client.plc_client_os_test --netlist ./Plc_client/test/ariane_fd/ariane.pb.txt
\
--plc ./Plc_client/test/ariane_fd/ariane.plc
\
--width 1599.99
\
--height 1598.8
\
--col 27
\
--row 23
\
--rpmh 70.330
\
--rpmv 74.510
\
--marh 51.790
\
--marv 51.790
\
--smooth 2
Todo:
* Clean up code
* Extract argument from command line
...
...
@@ -247,6 +259,7 @@ class PlacementCostTest():
self
.
plc_os
.
set_canvas_size
(
self
.
CANVAS_WIDTH
,
self
.
CANVAS_HEIGHT
)
self
.
plc_os
.
set_placement_grid
(
self
.
GRID_COL
,
self
.
GRID_ROW
)
# show canvas
self
.
plc_os
.
make_soft_macros_square
()
self
.
plc_os
.
display_canvas
(
annotate
=
False
,
amplify
=
False
)
...
...
@@ -854,6 +867,42 @@ class PlacementCostTest():
self
.
plc_util_os
.
display_canvas
(
annotate
=
False
)
def
test_fd
(
self
):
print
(
"############################ TEST GOOGLE's FD Placer ############################"
)
self
.
plc_util
=
placement_util
.
create_placement_cost
(
plc_client
=
plc_client
,
netlist_file
=
self
.
NETLIST_PATH
,
init_placement
=
self
.
PLC_PATH
)
self
.
plc_util_os
=
placement_util
.
create_placement_cost
(
plc_client
=
plc_client_os
,
netlist_file
=
self
.
NETLIST_PATH
,
init_placement
=
self
.
PLC_PATH
)
self
.
plc_util
.
set_routes_per_micron
(
self
.
RPMH
,
self
.
RPMV
)
self
.
plc_util_os
.
set_routes_per_micron
(
self
.
RPMH
,
self
.
RPMV
)
self
.
plc_util
.
set_macro_routing_allocation
(
self
.
MARH
,
self
.
MARV
)
self
.
plc_util_os
.
set_macro_routing_allocation
(
self
.
MARH
,
self
.
MARV
)
self
.
plc_util
.
set_congestion_smooth_range
(
self
.
SMOOTH
)
self
.
plc_util_os
.
set_congestion_smooth_range
(
self
.
SMOOTH
)
self
.
plc_util
.
set_canvas_size
(
self
.
CANVAS_WIDTH
,
self
.
CANVAS_HEIGHT
)
self
.
plc_util
.
set_placement_grid
(
self
.
GRID_COL
,
self
.
GRID_ROW
)
self
.
plc_util_os
.
set_canvas_size
(
self
.
CANVAS_WIDTH
,
self
.
CANVAS_HEIGHT
)
self
.
plc_util_os
.
set_placement_grid
(
self
.
GRID_COL
,
self
.
GRID_ROW
)
placement_util
.
fd_placement_schedule
(
self
.
plc_util
)
for
node_index
in
placement_util
.
nodes_of_types
(
self
.
plc_util
,
[
'MACRO'
]):
x_pos
,
y_pos
=
self
.
plc_util
.
get_node_location
(
node_index
)
self
.
plc_util_os
.
set_soft_macro_position
(
node_index
,
x_pos
,
y_pos
)
self
.
plc_util_os
.
display_canvas
(
annotate
=
False
,
amplify
=
False
)
def
test_environment
(
self
):
print
(
"############################ TEST ENVIRONMENT ############################"
)
env
=
environment
.
CircuitEnv
(
...
...
@@ -942,6 +991,8 @@ class PlacementCostTest():
placement_util
.
fd_placement_schedule
(
self
.
plc_util_os
)
self
.
plc_util_os
.
display_canvas
(
annotate
=
False
,
amplify
=
False
)
def
parse_flags
(
argv
):
parser
=
argparse_flags
.
ArgumentParser
(
description
=
'An argparse + app.run example'
)
...
...
@@ -1007,9 +1058,10 @@ def main(args):
# PCT.test_place_node()
# PCT.test_miscellaneous()
# PCT.test_observation_extractor()
PCT
.
view_canvas
()
# PCT.view_canvas()
# PCT.test_fd()
# PCT.test_environment()
#
PCT.test_fd_placement()
PCT
.
test_fd_placement
()
if
__name__
==
'__main__'
:
...
...
CodeElements/StatTest/proxy_corr_test.py
View file @
a9e01189
...
...
@@ -10,7 +10,22 @@ import pandas as pd
SHEET_ID
=
'1dtG4uHzdw-Lfe_Vcm5uBRNjjxXNA4gmVarTr86hjYVo'
SHEET_NAME
=
'Proxy_Cost_Comparison'
url
=
f
'https://docs.google.com/spreadsheets/d/{SHEET_ID}/gviz/tq?tqx=out:csv&sheet={SHEET_NAME}'
df
=
pd
.
read_csv
(
url
)
print
(
df
.
head
())
proxy_df
=
pd
.
read_csv
(
url
)
proxy_df
=
proxy_df
.
loc
[:,
~
proxy_df
.
isnull
()
.
all
()]
print
(
proxy_df
.
columns
)
proxy_df
[
'postCTS_Congestion (V)'
]
=
proxy_df
[
'postCTS_Congestion (V)'
]
.
str
.
rstrip
(
'
%
'
)
.
astype
(
'float'
)
/
100.0
# compute correlation between postRouteOpt_std_cell_area and density_cost
print
(
"postRoute_std_cell_area VS. Density_Cost"
,
proxy_df
[
"postRoute_std_cell_area (um^2)"
]
.
corr
(
proxy_df
[
"Density_Cost"
]))
print
(
"postRouteOpt_std_cell_area VS. Density_Cost"
,
proxy_df
[
"postRouteOpt_std_cell_area (um^2)"
]
.
corr
(
proxy_df
[
"Density_Cost"
]))
# compute correlation between ???
\ No newline at end of file
# compute correlation between postRouteOpt_wirelength (um) and wirelength_cost
print
(
"postRoute_wirelength VS. Wirelength_Cost"
,
proxy_df
[
"postRoute_wirelength (um)"
]
.
corr
(
proxy_df
[
"Wirelength_Cost"
]))
print
(
"postRouteOpt_wirelength VS. Wirelength_Cost"
,
proxy_df
[
"postRouteOpt_wirelength (um)"
]
.
corr
(
proxy_df
[
"Wirelength_Cost"
]))
# compute correlation between postCTS_Congestion and congestion_cost
print
(
"postCTS_Congestion VS. Congestion_Cost"
,
proxy_df
[
"postCTS_Congestion (V)"
]
.
corr
(
proxy_df
[
"Congestion_Cost"
]))
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment