Commit 5addfc90 by ZhiangWang033

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

parents 0be056e0 bdee239d
'''
This Code converts the BookShelf format to Proto buf format
This Code converts the Bookshelf netlist to Protobuf netlist.
Author: Sayak Kundu email: sakundu@ucsd.edu
Follow the below steps to convert bookshelf netlist to protobuf netlist.
1. bs_design = canvas_object(<design_name>)
2. bs_desing(<bookshelf_dir>, <output_pb_netlist>)
Here it expects <design_name>.scl, <design_name>.nets, <design_name>.nodes,
<design_name>.wts, <design_name>.pl files are present in the <bookshelf_dir>
<output_pb_netlist> is optional. If it is not provided then it will write out
the <design_name>.pb.txt in the <bookshelf_dir> directory.
'''
import re
import os
......@@ -69,14 +78,14 @@ class instance:
self.height = height
self.width = width
return
def update_location(self, x, y, orient, pstatus = "UNPLACED"):
self.llx = float(x)
self.lly = float(y)
self.orient = orient.upper()
self.pstatus = pstatus.upper()
return
def update_center(self):
self.cx = self.llx + self.width/2
self.cy = self.lly + self.height/2
......@@ -909,7 +918,11 @@ class canvas_object:
for port in self.ports:
port.name = port.name.replace("\\","")
return
def __call__(self, bookshelf_dir, output_pb_netlist = None):
self.read_BookShelf(bookshelf_dir)
self.gen_pb_netlist(output_pb_netlist)
return
def read_pb(self, pb_netlist):
fp = open(pb_netlist, 'r')
lines = fp.readlines()
......
########################## Details to use this script ##########################
# Author: Sayak Kundu email: sakundu@ucsd.edu
# Date: 11-22-2022
# This script converts LEF / DEF format to Protobuf format using OpenROAD.
# Follow the below steps to generate protobuf netlist from LEF / DEF in the
# OpenROAD shell:
# 1. read_lef <tech lef>
# 2. read_lef <standard cell and macro lef one by one>
# 3. read_def <design def file>
# 4. source <This script file>
# 5. gen_pb_netlist <path of the output protobuf netlist>
################################################################################
#### Print the design header ####
proc print_header { fp } {
set design [[ord::get_db_block] getName]
......
......@@ -39,7 +39,8 @@ The following screenshot shows the placed Ariane133-NG45 design generated using
## *Baseline Macro Placement Generated by Human*
### Manual macro placement on a gridded canvas
The following screenshots show the placed and routed Ariane133-NG45 design generated using [Flow-2](../../figures/flow-2.PNG), where the macros are placed manually on a gridded canvas.
The following screenshots show the placed and routed Ariane133-NG45 design generated using [Flow-2](../../figures/flow-2.PNG), where the macros are placed manually on a gridded canvas by [Zhiang Wang](mailto:zhw033@eng.ucsd.edu).
<p align="center">
<img height="400" src="./screenshots/Human_Gridded_Placement.png">
<img height="400" src="./screenshots/Human_Gridded_Routing.png">
......
'''
This script can be used to evaluate proxy cost of clustered netlist.
Author: Sayak Kundu email:sakundu@ucsd.edu
Requirements:
This code utilizes Google Circuit Training (CT)
(https://github.com/google-research/circuit_training) code and the plc_wrapper_main
(https://storage.googleapis.com/rl-infra-public/circuit-training/placement_cost/plc_wrapper_main)
binary to evaluate the proxy cost of the clustered netlist.
For more details please look into the README file in CT repo.
Steps to run this script:
1. First install CT
2. export PYTHONPATH=$PYTHONPATH:<CT Path>
3. python evaluate_clustered_netlist.py <pb_netlist> <plc_file> <output_dir/design>
Output:
This will print the initial proxy cost, final proxy cost (cost after FD repel).
It will save the following files:
1. initial placement image <output_dir/design>_init.png
2. final plc_file in as <output_dir/design>_post_repel.plc
3. final placement image (after FD repel) <output_dir/design>_final.png
If you do not provide <output_dir/design> it will only print the initial and
post FD repel proxy cost.
'''
import sys
import os
sys.path.append(os.path.dirname(__file__))
from extract_net import pb_design
from circuit_training.environment import plc_client
from circuit_training.environment import placement_util
import matplotlib.pyplot as plt
def get_plc(plc_file, pb_netlist):
plc = plc_client.PlacementCost(pb_netlist)
design = pb_design('block', pb_netlist)
design.read_netlist()
design.read_plc(plc_file)
plc.make_soft_macros_square()
plc.set_canvas_size(design.plc_info.width, design.plc_info.height)
plc.set_placement_grid(design.plc_info.columns, design.plc_info.rows)
plc.set_routes_per_micron(design.plc_info.route_hor, design.plc_info.route_ver)
plc.set_macro_routing_allocation(design.plc_info.macro_route_hor, design.plc_info.macro_route_ver)
plc.set_congestion_smooth_range(design.plc_info.sm_factor)
plc.set_overlap_threshold(design.plc_info.ovrlp_thrshld)
plc.set_canvas_boundary_check(True)
plc.restore_placement(plc_file)
return plc
def plot_from_plc(plc, png_file = None):
plt.figure(constrained_layout=True,figsize=(8,5),dpi=600)
canvas_width, canvas_height = plc.get_canvas_width_height()
for idx in plc.get_macro_indices():
color = 'blue'
if plc.is_node_soft_macro(idx):
color = 'red'
width, height = plc.get_node_width_height(idx)
cx, cy = plc.get_node_location(idx)
lx, ly = cx - width/2.0, cy - height/2
rectangle = plt.Rectangle((lx, ly), width, height, fc = color, ec = "black")
plt.gca().add_patch(rectangle)
lx, ly, lw = 0.0, 0.0, 1.0
ux, uy = lx + canvas_width, ly + canvas_height
x, y = [lx, ux], [ly, ly]
plt.plot(x,y, '-k', lw = lw)
x, y = [lx, ux], [uy, uy]
plt.plot(x,y, '-k', lw = lw)
x, y = [lx, lx], [ly, uy]
plt.plot(x,y, '-k', lw = lw)
x, y = [ux, ux], [ly, uy]
plt.plot(x,y, '-k', lw = lw)
plt.xlim(lx, ux)
plt.ylim(ly, uy)
plt.axis("scaled")
if png_file != None:
plt.savefig(png_file)
plt.show()
return
def get_cost(plc, isPrint = True):
wl_cost = plc.get_cost()
den_cost = plc.get_density_cost()
cong_cost = plc.get_congestion_cost()
proxy_cost = wl_cost + 0.5*den_cost + 0.5*cong_cost
if isPrint:
print(f'WL Cost:{wl_cost}\nCongestion Cost:{cong_cost}\nDensity Cost:{den_cost}')
print(f"Proxy Cost:{proxy_cost}")
return proxy_cost
## Run Placement schedule only with repeal and plot it again ##
def fix_all_hard_macros(plc):
for idx in plc.get_macro_indices():
if plc.is_node_soft_macro(idx):
plc.unfix_node_coord(idx)
else:
plc.fix_node_coord(idx)
return
def fix_all_ports(plc):
i = 0
while True:
node_type = plc.get_node_type(i)
if node_type == '':
break
elif node_type == 'PORT':
plc.fix_node_coord(i)
i += 1
return
def update_soft_macros_using_repeal(plc, isComplete = False):
if isComplete:
num_steps = (100, 100, 100)
move_distance_factors = (1.0, 1.0, 1.0)
attract_factor = (100, 1.0e-3, 1.0e-5)
repel_factor = (0.0, 1.0e6, 1.0e7)
use_current_loc = False
else:
num_steps = (100, 100)
move_distance_factors = (1.0, 1.0)
attract_factor = (1.0e-3, 1.0e-5)
repel_factor = (1.0e6, 1.0e7)
use_current_loc = True
io_factor = 1.0
move_macros = False
canvas_size = max(plc.get_canvas_width_height())
max_move_distance = [
f * canvas_size / s for s, f in zip(num_steps, move_distance_factors)
]
move_stdcells = True
log_scale_conns = False
use_sizes = False
plc.optimize_stdcells(use_current_loc, move_stdcells, move_macros,
log_scale_conns, use_sizes, io_factor, num_steps,
max_move_distance, attract_factor, repel_factor)
if __name__ == '__main__':
pb_netlist = sys.argv[1]
plc_netlist = sys.argv[2]
png_file = None
png_file_init_path = None
png_file_final_path = None
plc_file_final_path = None
if len(sys.argv) == 4:
png_file = sys.argv[3]
png_file_init_path = f"{png_file}_init.png"
png_file_final_path = f"{png_file}_final.png"
plc_file_final_path = f"{png_file}_post_repel.plc"
plc = get_plc(plc_netlist, pb_netlist)
print("Initial Proxy cost:")
_ = get_cost(plc)
plot_from_plc(plc, png_file_init_path)
fix_all_hard_macros(plc)
fix_all_ports(plc)
update_soft_macros_using_repeal(plc)
print("Final Proxy cost (After FD Repel):")
_ = get_cost(plc)
plot_from_plc(plc, png_file_final_path)
if plc_file_final_path:
placement_util.save_placement(plc, plc_file_final_path, 'Post FD repel placement')
#############################################################################
# This script was written and developed by ABKGroup students at UCSD.
# However, the underlying commands and reports are copyrighted by Cadence.
# We thank Cadence for granting permission to share our research to help
# promote and foster the next generation of innovators.
# Author: Sayak Kundu (sakundu@ucsd.edu), ABKGroup, UCSD.
# Thanks to Matheus Cavalcante, ETH Zürich and Jiantao Liu (jil313@ucsd.edu)
# for providing the pin configuration.
#
# Usage: First source the script in Innovus shell. then use gen_pb_netlist
# command to write out the netlist. The protobuf netlist will be available
# as <design name>.pb.txt.
#############################################################################
setPinAssignMode -pinEditInBatch true
set group_width [dbget top.fplan.box_sizex]
set group_height [dbget top.fplan.box_sizey]
......
#############################################################################
# This script was written and developed by ABKGroup students at UCSD.
# However, the underlying commands and reports are copyrighted by Cadence.
# We thank Cadence for granting permission to share our research to help
# promote and foster the next generation of innovators.
# Author: Sayak Kundu, ABKGroup, UCSD
#################################################################
# minCh: If channel width is less than minCh it will be filled
# with hard blockages.
......
#############################################################################
# This script was written and developed by ABKGroup students at UCSD.
# However, the underlying commands and reports are copyrighted by Cadence.
# We thank Cadence for granting permission to share our research to help
# promote and foster the next generation of innovators.
# Author: Sayak Kundu (sakundu@ucsd.edu), ABKGroup, UCSD.
# Thanks to Matheus Cavalcante, ETH Zürich and Jiantao Liu (jil313@ucsd.edu)
# for providing the tile configuration.
#
# Usage: This script places macros for MemPool Group NG45 design. First source
# the script in the Innovus terminal and then use the following command:
# mempool_group_macro_placement
#############################################################################
# Y Flip
# RO --> MX MY --> R180
# It do not validate if there is enough space to create the macro stack
# For the boundary macros of the cluster always have pin facing towards outside
# Stack size indicates the number of macros will be stacked
# Also it considers all the macro size in the macro list is same
proc place_macro_mem_stack {macro_list stack_size ch_space origin_x origin_y\
isFlip} {
if {$isFlip == 0} {
set orient [list "R0" "MY"]
set stack_dir 1
} else {
set orient [list "MX" "R180"]
set stack_dir -1
}
# Extract macro informations
set macro_width [dbget [dbget top.insts.name [lindex $macro_list 0] -p ].box_sizex]
set macro_height [dbget [dbget top.insts.name [lindex $macro_list 0] -p ].box_sizey]
# i indicates the row number and j indicates the column number
set i 0
set j 0
set llx $origin_x
set lly $origin_y
foreach macro $macro_list {
# For each column all the macros have same orientation
set orientation [lindex $orient [expr $j%2]]
placeInstance $macro $llx $lly $orientation -placed
incr i
if { $i == $stack_size } {
set i 0
incr j
set lly $origin_y
set llx [expr $origin_x + ($j/2)*$ch_space + $j*$macro_width]
} else {
set lly [expr $origin_y + ${stack_dir}*($i*$macro_height)]
}
}
}
proc place_macro_mem_stack_in {macro_list stack_size ch_space origin_x origin_y\
isFlip} {
if {$isFlip == 0} {
set orient [list "R0" "MY"]
set stack_dir 1
} else {
set orient [list "MX" "R180"]
set stack_dir -1
}
# Extract macro informations
set macro_width [dbget [dbget top.insts.name [lindex $macro_list 0] -p ].box_sizex]
set macro_height [dbget [dbget top.insts.name [lindex $macro_list 0] -p ].box_sizey]
# i indicates the row number and j indicates the column number
set i 0
set j 1
set llx $origin_x
set lly $origin_y
foreach macro $macro_list {
# For each column all the macros have same orientation
set orientation [lindex $orient [expr $j%2]]
placeInstance $macro $llx $lly $orientation -placed
incr i
if { $i == $stack_size } {
set i 0
incr j
set lly $origin_y
set llx [expr $origin_x + ($j/2)*$ch_space + ($j-1)*$macro_width]
} else {
set lly [expr $origin_y + ${stack_dir}*($i*$macro_height)]
}
}
}
# Tile origin is always the lower left coordinate of the tile bbox
proc place_tiles {tile_id tile_origin_x tile_origin_y tile_width tile_height \
isFlip {halo_wdith 5} {stack_size 2} } {
# ICACHE
set icache_rams [dbget [dbget top.insts.cell.subClass block -p2\
].name gen_tiles[${tile_id}]*i_tile*i_lookup*i_data*]
set icache_width [dbget [dbget top.insts.name [lindex $icache_rams 0] -p \
].cell.size_x]
set icache_height [dbget [dbget top.insts.name [lindex $icache_rams 0] -p \
].cell.size_y]
set ch_space [expr $halo_wdith*4]
## Place the ICACHE memories on the left boundary
## Stack two memories together
set icache_llx [expr $tile_origin_x + $ch_space]
if { $isFlip == 0 } {
set icache_lly [expr $tile_origin_y + $ch_space]
} else {
set icache_lly [expr $tile_origin_y + $tile_height - $icache_height - $ch_space]
}
place_macro_mem_stack $icache_rams 2 $ch_space $icache_llx $icache_lly $isFlip
# Place the TCDM memories on the right of the boundary
# Stack 4 memories together
# Ensure
set tcdm_rams [dbget [dbget top.insts.cell.subClass block -p2 ].name \
gen_tiles*[${tile_id}]*i_tile*mem_bank*]
set tcdm_width [dbget [dbget top.insts.name [lindex $tcdm_rams 0] -p \
].cell.size_x]
set tcdm_height [dbget [dbget top.insts.name [lindex $tcdm_rams 0] -p \
].cell.size_y]
if { $stack_size == 2 } {
set tcdm_llx [expr $tile_origin_x + $tile_width - 4*$ch_space - 8*$tcdm_width]
} elseif { $stack_size == 4 } {
set tcdm_llx [expr $tile_origin_x + $tile_width - 2*$ch_space - 4*$tcdm_width]
}
if { $isFlip == 0 } {
set tcdm_lly [expr $tile_origin_y + $ch_space]
} else {
set tcdm_lly [expr $tile_origin_y + $tile_height - $ch_space - $tcdm_height]
}
place_macro_mem_stack $tcdm_rams $stack_size $ch_space $tcdm_llx $tcdm_lly $isFlip
}
proc mempool_group_macro_placement { {halo_width 10} {stack_size 2} } {
set core_llx [dbget top.fplan.coreBox_llx]
set core_lly [dbget top.fplan.coreBox_lly]
set core_width [dbget top.fplan.coreBox_sizex]
set core_height [dbget top.fplan.coreBox_sizey]
set tile_height [expr $core_height/4.0]
set tile_width [expr $core_width/4.0]
#set halo_width 10
# Scramble tiles
set toffsets [list \
[list 0 1 4 5]\
[list 2 3 6 7]\
[list 8 9 12 13]\
[list 10 11 14 15]]
# i is row and j is coloum
set isFlip 0
for { set i 0 } { $i < 4 } { incr i } {
if { $i > 1 } {
set isFlip 1
}
set tile_ly [expr $core_lly + $i*$tile_height]
for { set j 0 } { $j < 4 } { incr j } {
set tile_lx [expr $core_llx + $j*$tile_width]
set tile_id [lindex $toffsets $i $j]
puts "Placing Tile:$tile_id Tile lx:$tile_lx ly:$tile_ly Height:$tile_height Width:$tile_width"
place_tiles $tile_id $tile_lx $tile_ly $tile_width $tile_height $isFlip $halo_width $stack_size
}
}
}
#!/usr/bin/env bash
##########################################################################
# Update HMETIS_DIR PLC_WRAPPER_MAIN and CT_PATH
# Author: Sayak Kundu email: sakundu@ucsd.edu
# This script runs Circuit Training (CT) Grouping to generate clustered
# netlist from the Protobuf netlist. For more details please see CT
# Grouping README (Link:
# https://github.com/google-research/circuit_training/blob/main/circuit_training/grouping/README.md)
#
# Update the following environment variables to run CT Grouping using
# this script:
# 1. NETLIST_FILE: Provide the path of the input Protobuf netlist
# 2. HMETIS_DIR: Provide the directory path where the hMETIS executable
# files exist.
# 3. PLC_WRAPPER_MAIN: Provide the path of the plc_wrapper_main binary.
# This binary is downloaded from CT. Link to the binary:
# https://storage.googleapis.com/rl-infra-public/circuit-training/placement_cost/plc_wrapper_main
# 4. CT_PATH: Provide the directory path where CT is cloned.
# 5. OUTPUT_DIR: Provide the directory path where to save the final
# clustered netlist.
#
# Before launching the script make sure that PHY_SYNTH environment variables
# is set to 1.
##########################################################################
if [ $PHY_SYNTH -eq 1 ]; then
export PROJ_DIR=`pwd | grep -o '\S*/MacroPlacement'`
......@@ -8,11 +27,8 @@ if [ $PHY_SYNTH -eq 1 ]; then
export BLOCK_NAME=`basename ${NETLIST_FILE} | sed 's@.pb.txt@@'`
export TECH=`echo $PWD | awk -F'/' '{print $(NF-3)}'`
export OUTPUT_DIR="./output_${BLOCK_NAME}_${TECH}"
export HMETIS_DIR="/home/zf4_projects/DREAMPlace/sakundu/GB/CT/hmetis-1.5-linux"
export PLC_WRAPPER_MAIN="/home/zf4_projects/DREAMPlace/sakundu/GB/CT/plc_wrapper_main"
#export CT_PATH="${PROJ_DIR}/../../../GB/CT/circuit_training"
#export CT_PATH="/home/zf4_projects/DREAMPlace/sakundu/ABK_MP/CT/09092022/circuit_training"
export CT_PATH="/home/zf4_projects/DREAMPlace/sakundu/ABK_MP/CT/11112022/circuit_training"
#export CT_PATH="/home/zf4_projects/macro_placer/google_brain/TILOS_repo/grouping/circuit_training"
bash -i ../../../../util/run_grp.sh 2>&1 | tee log/grouping.log
export HMETIS_DIR="${PROJ_DIR}/../../../GB/CT/hmetis-1.5-linux"
export PLC_WRAPPER_MAIN="${PROJ_DIR}/../../../GB/CT/plc_wrapper_main"
export CT_PATH="${PROJ_DIR}/../../../GB/CT/circuit_training"
bash -i ${PROJ_DIR}/Flows/util/run_grp.sh 2>&1 | tee log/grouping.log
fi
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