Commit 168fc2ed by sakundu

Updated Bookshelf to Protobuf translator. Added utility script for flat placement evaluation.

Signed-off-by: sakundu <sakundu@ucsd.edu>
parent 01109df1
'''
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
......@@ -909,6 +918,10 @@ 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')
......
########################## 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')
import shutil
import re
import os
from datetime import date, datetime
import matplotlib.pyplot as plt
class node:
def __init__(self, id):
self.name = None
self.sinks = set()
self.sink_ids = set()
self.node_id = id
self.height = 0
self.width = 0
self.weight = None
self.x = -1
self.x_offset = None
self.y = -1
self.y_offset = None
self.macro_name = None
self.macro_id = None
self.type = None
self.side = None
self.orientation = None
class plc_info:
def __init__(self, design):
self.design = design
self.date = datetime.now()
self.columns = 0
self.rows = 0
self.width = 0.0
self.height = 0.0
self.area = 0.0
self.route_hor = 0.0
self.route_ver = 0.0
self.macro_route_hor = 0.0
self.macro_route_ver = 0.0
self.sm_factor = 0
self.ovrlp_thrshld = 0.0
def plc_info_print(self, out_plc_fp):
out_plc_fp.write("# Placement file for Circuit Training\n")
out_plc_fp.write(f"# Date : {self.date}\n")
out_plc_fp.write(f"# Columns : {self.columns} Rows : {self.rows}\n")
out_plc_fp.write(f"# Width : {self.width} Height : {self.height}\n")
out_plc_fp.write(f"# Area : {self.area}\n")
out_plc_fp.write(f"# Block : {self.design}\n")
out_plc_fp.write(f"# Routes per micron, hor : {self.route_hor} ver : {self.route_ver}\n")
out_plc_fp.write(f"# Routes used by macros, hor : {self.macro_route_hor} ver : {self.macro_route_ver}\n")
out_plc_fp.write(f"# Smoothing factor : {self.sm_factor}\n")
out_plc_fp.write(f"# Overlap threshold : {self.ovrlp_thrshld}\n")
class pb_design:
def __init__(self, design, netlist, unit = 100, site_height = 16, \
site_width = 1):
self.design = design
self.netlist_path = netlist
self.node_list = []
self.node_name_to_id = {}
self.key1 = ['"height"', '"weight"', '"width"', '"x"', '"x_offset"', \
'"y"', '"y_offset"']
self.key2 = ['"macro_name"', '"orientation"', '"side"', '"type"']
self.node_count = 0
self.net_weights = []
self.unit = unit ## For bookshelf
self.site_height = site_height
self.site_width = site_width
self.plc_info = plc_info(design)
def read_netlist(self):
fp = open(self.netlist_path, "r")
lines = fp.readlines()
fp.close()
node_id = 0
key = ""
for line in lines:
words = line.split()
if words[0] == 'node':
## TODO: Check if the node name is __metadata__ then remove it ##
if len(self.node_list) > 0 and \
self.node_list[-1].name == '__metadata__':
self.node_list.pop(-1)
self.node_list.append(node(node_id))
node_id += 1
elif words[0] == 'name:':
self.node_list[-1].name = words[1].replace('"', '')
elif words[0] == 'input:':
self.node_list[-1].sinks.add(words[1].replace('"', ''))
elif words[0] == 'key:':
key = words[1]
elif words[0] == 'placeholder:' :
words[1] = words[1].replace('"', '')
if key == self.key2[0]:
self.node_list[-1].macro_name = words[1]
elif key == self.key2[1]:
self.node_list[-1].orientation = words[1]
elif key == self.key2[2]:
self.node_list[-1].side = words[1]
elif key == self.key2[3]:
self.node_list[-1].type = words[1]
else:
print(f'Do not support Key: {key}')
elif words[0] == "f:":
if key == self.key1[0]:
self.node_list[-1].height = float(words[1])
elif key == self.key1[1]:
self.node_list[-1].weight = int(float(words[1]))
elif key == self.key1[2]:
self.node_list[-1].width = float(words[1])
elif key == self.key1[3]:
self.node_list[-1].x = float(words[1])
elif key == self.key1[4]:
self.node_list[-1].x_offset = float(words[1])
elif key == self.key1[5]:
self.node_list[-1].y = float(words[1])
elif key == self.key1[6]:
self.node_list[-1].y_offset = float(words[1])
## Update the Name to id map ##
self.node_count = len(self.node_list)
for i in range(self.node_count):
self.node_name_to_id[self.node_list[i].name] = i
## Update sink list and sink id ##
self.read_netlist_post_processing()
return
def read_netlist_post_processing(self):
for i in range(self.node_count):
## Update the sink list ##
for sink in self.node_list[i].sinks:
self.node_list[i].sink_ids.add(self.node_name_to_id[sink])
## Update the macro id ##
if self.node_list[i].type in {'MACRO_PIN', 'macro_pin'}:
self.node_list[i].macro_id = \
self.node_name_to_id[self.node_list[i].macro_name]
## TODO: Update the macro pin location based on macro orientation ##
return
def print_helper (self, fp, key, value, isPlaceHolder):
fp.write(" attr {\n")
fp.write(f" key: \"{key}\"\n")
fp.write(" value {\n")
if isPlaceHolder:
fp.write(f" placeholder: \"{value}\"\n")
else:
fp.write(f" f: {value}\n")
fp.write(" }\n")
fp.write(" }\n")
return
def print_float(self, fp, key, value):
self.print_helper(fp, key, value, 0)
def print_placeholder(self, fp, key, value):
self.print_helper(fp, key, value, 1)
def print_macro(self, fp, node: node):
if node.type not in {'MACRO', 'macro'}:
return
fp.write("node {\n")
fp.write(f" name: \"{node.name}\"\n")
self.print_placeholder(fp, "type", node.type)
self.print_float(fp, "width", node.width)
self.print_float(fp, "height", node.height)
self.print_float(fp, "x", node.x)
self.print_float(fp, "y", node.y)
if node.orientation != None:
self.print_placeholder(fp, "orientation", node.orientation)
fp.write("}\n")
return
def print_macro_pin(self, fp, node: node):
if node.type not in {'MACRO_PIN', 'macro_pin'}:
return
fp.write("node {\n")
fp.write(f" name: \"{node.name}\"\n")
for sink in node.sinks:
fp.write(f" input: \"{sink}\"\n")
self.print_placeholder(fp, "macro_name", f"{node.macro_name}")
self.print_placeholder(fp, "type", f"{node.type}")
self.print_float(fp, "x_offset", node.x_offset)
self.print_float(fp, "y_offset", node.y_offset)
self.print_float(fp, "x", node.x)
self.print_float(fp, "y", node.y)
if node.weight != None:
self.print_float(fp, "weight", node.weight)
fp.write("}\n")
return
def print_port(self, fp, node: node):
if node.type not in {'PORT', 'port'}:
return
fp.write("node {\n")
fp.write(f" name: \"{node.name}\"\n")
for sink in node.sinks:
fp.write(f" input: \"{sink}\"\n")
self.print_placeholder(fp, "side", node.side)
self.print_placeholder(fp, "type", node.type)
self.print_float(fp, "x", node.x)
self.print_float(fp, "y", node.y)
fp.write("}\n")
return
def get_net_counts(self):
net_count = 0
pin_count = 0
for node in self.node_list:
if node.sinks:
net_count += 1
pin_count += len(node.sinks) + 1
return net_count, pin_count
def print_node(self, fp, node):
if node.type in {'MACRO', 'macro'}:
self.print_macro(fp, node)
elif node.type == 'PORT':
self.print_port(fp, node)
elif node.type in {'MACRO_PIN', 'macro_pin'}:
self.print_macro_pin(fp, node)
return
def write_nets(self, out_dir):
if not os.path.exists(out_dir):
os.makedirs(out_dir)
net_id = 0
for node in self.node_list:
if not node.sinks:
continue
fp = open(f'{out_dir}/net{net_id}.pb.txt', "w")
pnodes = []
pnodes.append(node)
self.print_node(fp, node)
for sink_id in node.sink_ids:
sink_node = self.node_list[sink_id]
if sink_node not in pnodes:
pnodes.append(sink_node)
self.print_node(fp, sink_node)
if sink_node.type in {'MACRO_PIN', 'macro_pin'}:
macro_node = self.node_list[sink_node.macro_id]
if macro_node not in pnodes:
pnodes.append(macro_node)
self.print_node(fp, macro_node)
net_id += 1
if net_id % 1000 == 0:
print(f'{net_id}..', end=" ")
return
def write_hard_macro(self, out_dir):
if not os.path.exists(out_dir):
os.makedirs(out_dir)
fp = open(f'{out_dir}/macro.pb.txt', "w")
for node in self.node_list:
if node.type == 'MACRO':
self.print_node(fp, node)
fp.close()
return
def read_bookshelf_pl_and_update_top_ports(self, pl_file, updatePort = True,\
updateMacro = False ):
if not os.path.exists(pl_file):
print("[ERROR] pl file does not exists. Check the below file path:"\
f"\n{pl_file}")
return
pl_fp = open(pl_file, 'r')
for line in pl_fp.readlines():
if re.match(r"(^\s*#)|(^\s*UCLA\s*pl\s*1.0\s*$)|(^\s*$)", line):
continue
items = line.split()
name = items[0]
_x = float(items[1])/self.unit
_y = float(items[2])/self.unit
if name in self.node_name_to_id:
node_id = self.node_name_to_id[name]
if updatePort and self.node_list[node_id].type == "PORT":
self.node_list[node_id].x = _x
self.node_list[node_id].y = _y
elif updateMacro and self.node_list[node_id].type in ['MACRO', 'macro']:
self.node_list[node_id].x = _x + self.node_list[node_id].width/2
self.node_list[node_id].y = _y + self.node_list[node_id].height/2
pl_fp.close()
return
def update_plc_info(self, line):
items = line.split()
if len(items) > 6 and items[1] == 'Columns':
self.plc_info.columns = int(items[3])
self.plc_info.rows = int(items[6])
elif len(items) > 6 and items[1] == 'Width':
self.plc_info.width = float(items[3])
self.plc_info.height = float(items[6])
elif len(items) > 3 and items[1] == 'Area':
self.plc_info.area = float(items[3])
elif len(items) > 9 and items[1] == 'Routes' and items[2] == 'per':
self.plc_info.route_hor = float(items[6])
self.plc_info.route_ver = float(items[9])
elif len(items) > 10 and items[1] == 'Routes' and items[2] == 'used':
self.plc_info.macro_route_hor = float(items[7])
self.plc_info.macro_route_ver = float(items[10])
elif len(items) > 4 and items[1] == 'Smoothing':
self.plc_info.sm_factor = int(items[4])
elif len(items) > 4 and items[1] == 'Overlap':
self.plc_info.ovrlp_thrshld = float(items[4])
return
def read_plc(self, plc_file, updatePort = False, updateMacro = True):
if not os.path.exists(plc_file):
print("[ERROR] *.plc file does not exist. Chec the file path:\n"\
f"{plc_file}")
return
plc_fp = open(plc_file, 'r')
for line in plc_fp.readlines():
## If the line starts with # the ignore it. Also ignore empty lines
if re.match(r"(^\s*#)|(^\s*$)", line):
self.update_plc_info(line)
continue
items = line.split()
node_id = int(items[0])
if updatePort and self.node_list[node_id].type in ["PORT", "port"]:
self.node_list[node_id].x = float(items[1])
self.node_list[node_id].y = float(items[2])
## Update only soft macro and hardmacro locations ##
elif updateMacro and self.node_list[node_id].type in ["MACRO", "macro"]:
self.node_list[node_id].x = float(items[1])
self.node_list[node_id].y = float(items[2])
self.node_list[node_id].orientation = items[3]
plc_fp.close()
return
def write_plc(self, output_plc_file):
plc_fp = open(output_plc_file, 'w')
self.plc_info.plc_info_print(plc_fp)
idx = 0
for node in self.node_list:
x = round(node.x, 6)
y = round(node.y, 6)
if node.type in ['PORT', 'port']:
plc_fp.write(f"{idx} {x} {y} - 1\n")
elif node.type in ['MACRO', 'macro']:
if node.orientation != None:
plc_fp.write(f"{idx} {x} {y} {node.orientation} 0\n")
else:
plc_fp.write(f"{idx} {x} {y} N 0\n")
idx += 1
plc_fp.close()
return
def write_bookshelf_nodes(self, node_file):
fp = open(node_file, "w")
today = date.today()
user = user = os.environ["USER"]
fp.write("UCLA nodes 1.0\n")
fp.write(f"# Created : {today}\n")
fp.write(f"# User: {user}\n\n")
total_nodes = 0
total_terminals = 0
## Here we consider only ports as the fixed terminals
for node in self.node_list:
if node.type in ['MACRO', 'macro', 'PORT', 'port']:
total_nodes += 1
if node.type in ['PORT', 'port']:
total_terminals += 1
fp.write(f"NumNodes : {total_nodes}\nNumTerminals : {total_terminals}\n")
for node in self.node_list:
if node.type in ['PORT', 'port']:
fp.write(f" {node.name} 1 1 terminal\n")
elif node.type == 'MACRO':
height = round(node.height * self.unit, 6)
width = round(node.width * self.unit, 6)
fp.write(f" {node.name} {width} {height}\n")
elif node.type == 'macro':
height = round(node.height * self.unit, 6)
width = round(node.width * self.unit, 6)
area = height*width
ack_height = round(height/self.site_height, 0)*self.site_height
ack_height = round(ack_height, 6)
if ack_height == 0:
ack_height = self.site_height
#print(f"Name:{node.name} Width:{node.width} Height:{node.height}")
ack_width = round(area/ack_height, 6)
node.height = ack_height/self.unit
node.width = ack_width/self.unit
fp.write(f" {node.name} {ack_width} {ack_height}\n")
fp.close()
return
def get_node_name(self, node):
if node.type in ['PORT', 'port']:
return node.name, None, None
if node.type in ['macro_pin', 'MACRO_PIN']:
return node.macro_name, round(node.x_offset*self.unit, 6), \
round(node.y_offset*self.unit, 6)
return None, None, None
def write_bookshelf_nets(self, net_file):
fp = open(net_file, 'w')
today = date.today()
user = os.environ["USER"]
fp.write("UCLA nets 1.0\n")
fp.write(f"# Created : {today}\n")
fp.write(f"# User: {user}\n\n")
net_count, pin_count = self.get_net_counts()
fp.write(f"NumNets : {net_count}\nNumPins : {pin_count}\n")
net_id = 0
for node in self.node_list:
if node.sinks:
net_w = 1
net_degree = len(node.sinks) + 1
if node.weight != None:
net_w = node.weight
for _ in range(net_w):
## Print the driver ##
fp.write(f"NetDegree : {net_degree} net{net_id}\n")
driver_name, x_offset, y_offset = self.get_node_name(node)
if x_offset != None and y_offset != None:
fp.write(f" {driver_name} O : {x_offset} {y_offset}\n")
else:
fp.write(f" {driver_name} O\n")
## Print the sinks ##
for sink_name in node.sinks:
sink_node = self.node_list[self.node_name_to_id[sink_name]]
sink_name, x_offset, y_offset = self.get_node_name(sink_node)
if x_offset != None and y_offset != None:
fp.write(f" {sink_name} I : {x_offset} {y_offset}\n")
else:
fp.write(f" {sink_name} I\n")
net_id += 1
fp.close()
return
def write_bookshelf_pl(self, pl_file):
fp = open(pl_file, 'w')
today = date.today()
user = os.environ["USER"]
fp.write("UCLA pl 1.0\n")
fp.write(f"# Created : {today}\n")
fp.write(f"# User: {user}\n\n")
for node in self.node_list:
if node.type in ['PORT', 'port']:
px = round(node.x * self.unit, 6)
py = round(node.y * self.unit, 6)
fp.write(f" {node.name} {px} {py} : N /FIXED\n")
elif node.type in ['MACRO', 'macro']:
width = node.width
height = node.height
x = (node.x - width/2) * self.unit
y = (node.y - height/2) * self.unit
x = round(x, 6)
y = round(y, 6)
fp.write(f" {node.name} {x} {y} : N\n")
fp.close()
return
def write_bookshelf_wts(self, wts_file):
fp = open(wts_file, 'w')
today = date.today()
user = os.environ["USER"]
fp.write("UCLA wts 1.0\n")
fp.write(f"# Created : {today}\n")
fp.write(f"# User: {user}\n\n")
for node in self.node_list:
if node.type in ['PORT', 'port']:
fp.write(f" {node.name} 0\n")
elif node.type in ['MACRO', 'macro']:
area = round(node.height * node.width * self.unit * self.unit, 0)
fp.write(f" {node.name} {area}\n")
fp.close()
return
## Create output_dir/design directory and write out *nets, *.nodes, *.pl
## *.wts and copy *.aux and *.scl to the output_dir/design directory
def write_bookshelf(self, input_bookshelf_dir, output_dir):
if not os.path.exists(input_bookshelf_dir):
print("[ERROR] The input Bookshelf directory path does not"\
f"exists.\nPath:{input_bookshelf_dir}")
return
## Read the *.pl file and update the port locations
pl_input = f"{input_bookshelf_dir}/{self.design}.pl"
self.read_bookshelf_pl_and_update_top_ports(pl_input)
output_bookshelf_dir = f"{output_dir}/{self.design}"
if not os.path.exists(output_bookshelf_dir):
os.makedirs(output_bookshelf_dir)
## Copy the *.aux, *.scl and *.wts files ##
src_pref = f"{input_bookshelf_dir}/{self.design}"
dst_pref = f"{output_bookshelf_dir}/{self.design}"
shutil.copy(f"{src_pref}.aux", f"{dst_pref}.aux")
shutil.copy(f"{src_pref}.scl", f"{dst_pref}.scl")
## Write out the *.nets *.nodes and *.pl file ##
nets_file = f"{dst_pref}.nets"
nodes_file = f"{dst_pref}.nodes"
pl_file = f"{dst_pref}.pl"
wts_file = f"{dst_pref}.wts"
self.write_bookshelf_nodes(nodes_file)
self.write_bookshelf_nets(nets_file)
self.write_bookshelf_pl(pl_file)
self.write_bookshelf_wts(wts_file)
return
def visualize_placement(self):
plt.figure(constrained_layout=True,figsize=(8,5),dpi=600)
for node in self.node_list:
if node.type == 'macro':
color = 'red'
elif node.type == 'MACRO':
color = 'blue'
else:
continue
lx = node.x - node.width/2.0
ly = node.y - node.height/2.0
width = node.width
height = node.height
rectangle = plt.Rectangle((lx, ly), width, height, fc = color, ec = "black")
plt.gca().add_patch(rectangle)
canvas_width = self.plc_info.width
canvas_height = self.plc_info.height
# Add boundries
lx = 0.0
ly = 0.0
ux = lx + canvas_width
uy = ly + canvas_height
lw = 5.0
x = []
y = []
x.append(lx)
y.append(ly)
x.append(ux)
y.append(ly)
plt.plot(x,y, '-k', lw = lw)
x = []
y = []
x.append(lx)
y.append(uy)
x.append(ux)
y.append(uy)
plt.plot(x,y, '-k', lw = lw)
x = []
y = []
x.append(lx)
y.append(ly)
x.append(lx)
y.append(uy)
plt.plot(x,y, '-k', lw = lw)
x = []
y = []
x.append(ux)
y.append(ly)
x.append(ux)
y.append(uy)
plt.plot(x,y, '-k', lw = lw)
plt.xlim(lx, ux)
plt.ylim(ly, uy)
plt.axis("scaled")
plt.show()
return
##############################################################################
if __name__ == "__main__":
pb_file = ''
plc = pb_design(pb_file)
plc.read_netlist()
plc.write_hard_macro('ariane_macro')
\ No newline at end of file
#!/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