Commit 47067a5f by sakundu

Added Bookshelf to Protobuf format translator. LEF / DEF to Protobuf format…

Added Bookshelf to Protobuf format translator. LEF / DEF to Protobuf format translator using OpenROAD. Scripts for shuffling experiment

Signed-off-by: sakundu <sakundu@ucsd.edu>
parent e8b8636d
......@@ -12,6 +12,7 @@ CodeElements/Plc_client/plc_client.py
CodeElements/Plc_client/failed_proxy_plc/*
__pycache__/
__pycache__
try.ipynb
run
run-*
GF12/
......
'''
This Code converts the BookShelf format to Proto buf format
'''
import re
import os
from datetime import date
def find_pin_act_loc(cx, cy, x_offset, y_offset, orient):
if orient in ["E", "FE", "W", "FW"]:
x_offset, y_offset = y_offset, x_offset
if orient in ["FN", "S", "FE", "W"]:
x_offset *= -1
if orient in ["S", "FS", "E", "FE"]:
y_offset *= -1
pin_x = cx + x_offset
pin_y = cy + y_offset
return pin_x, pin_y
def print_placeholder(fp, key, value):
fp.write(" attr {\n")
fp.write(f" key: \"{key}\"\n")
fp.write(" value {\n")
fp.write(f" placeholder: \"{value}\"\n")
fp.write(" }\n")
fp.write(" }\n")
return
def print_float(fp, key, value):
fp.write(" attr {\n")
fp.write(f" key: \"{key}\"\n")
fp.write(" value {\n")
fp.write(f" f: {value}\n")
fp.write(" }\n")
fp.write(" }\n")
return
class instance:
def __init__(self, idx, name):
self.id = idx
self.master_id = None
self.name = name
self.width = None
self.height = None
self.llx = None
self.lly = None
self.cx = None
self.cy = None
self.orient = None
self.isMacro = None # Considers macro if heigh is more than row height
self.ipins = []
self.opins = []
self.ipin_x = []
self.ipin_y = []
self.opin_x = []
self.opin_y = []
self.ipin_net_id = []
self.opin_net_id = []
self.pstatus = None
self.ipin_act_x_offset = []
self.ipin_act_y_offset = []
self.opin_act_y_offset = []
self.opin_act_x_offset = []
return
def update_size(self, height, width):
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
return
def connect_net(self, net_name, net_id, isInput, x_offset = 0.0, \
y_offset = 0.0 ):
# If isInput is 1 means the connected pin is input pin
# Check if the net exists:
if isInput:
if net_id in self.ipin_net_id:
print(f"[INFO] [ERROR-1] Inst: {self.name} Net: {net_name}"\
" is alerady connected")
return
else:
if net_id in self.opin_net_id:
print(f"[INFO] [ERROR-2] Inst: {self.name} Net: {net_name}"\
" is alerady connected")
return
if isInput:
pin_id = len(self.ipins) + 1
self.ipins.append(f'IP{pin_id}')
self.ipin_act_x_offset.append(x_offset)
self.ipin_act_y_offset.append(y_offset)
self.ipin_net_id.append(net_id)
else:
pin_id = len(self.opins) + 1
self.opins.append(f'OP{pin_id}')
self.opin_act_x_offset.append(x_offset)
self.opin_act_y_offset.append(y_offset)
self.opin_net_id.append(net_id)
def update_pin_loc(self):
for i in range(len(self.ipins)):
pin_x, pin_y = find_pin_act_loc(self.cx, self.cy, \
self.ipin_act_x_offset[i], \
self.ipin_act_y_offset[i], \
self.orient)
self.ipin_x.append(pin_x)
self.ipin_y.append(pin_y)
for i in range(len(self.opins)):
pin_x, pin_y = find_pin_act_loc(self.cx, self.cy, \
self.opin_act_x_offset[i], \
self.opin_act_y_offset[i], \
self.orient)
self.opin_x.append(pin_x)
self.opin_y.append(pin_y)
return
def check_pins(self):
for x_offset in self.ipin_act_x_offset + self.opin_act_x_offset:
if round(x_offset,6) < round(-1*self.width/2.0,6) \
or round(x_offset,6) > round(self.width/2,6):
print(f"[INFO][ERROR] Cell:{self.name} Orient:{self.orient} has pin out of bbox")
return
for y_offset in self.ipin_act_y_offset + self.opin_act_y_offset:
if round(y_offset,6) < round(-1*self.height/2.0,6) \
or round(y_offset,6) > round(self.height/2,6):
print(f"[INFO][ERROR] Cell:{self.name} Orient:{self.orient} has pin out of bbox")
return
return
def update_isMacro(self, site_height):
if self.height != site_height:
self.isMacro = True
else:
self.isMacro = False
return
def update_master_id(self, idx):
self.master_id = idx
return
class master:
def __init__(self, idx, name):
self.id = idx
self.name = name
self.width = None
self.height = None
self.isMacro = None # Considers macro if heigh is more than row height
self.ipins = []
self.opins = []
self.ipin_act_x_offset = []
self.ipin_act_y_offset = []
self.opin_act_y_offset = []
self.opin_act_x_offset = []
return
def update_master(self, inst):
self.width = inst.width
self.height = inst.height
self.isMacro = inst.isMacro
self.ipins = [x for x in inst.ipins]
self.opins = [x for x in inst.opins]
self.ipin_act_x_offset = [x for x in inst.ipin_act_x_offset]
self.ipin_act_y_offset = [y for y in inst.ipin_act_y_offset]
self.opin_act_x_offset = [x for x in inst.opin_act_x_offset]
self.opin_act_y_offset = [y for y in inst.opin_act_y_offset]
return
class port:
def __init__(self, name):
self.id = None
self.name = name
self.x = None
self.y = None
self.isInput = None
self.net_id = None
self.side = None
self.px = None # Protobuf location
self.py = None # Protobuf location
def connect_net(self, net_id, net_name, isInput):
if self.net_id != None:
print(f"[INFO] [ERROR-3] {self.name} is connected. Check Net: {net_name}")
self.net_id = net_id
self.isInput = isInput
return
def update_id(self, idx):
self.id = idx
return
def update_location(self, x, y):
self.x = x
self.y = y
return
def update_side(self, pt_x, pt_y, dx, dy):
cond1 = pt_x - pt_y
cond2 = pt_x/dx + pt_y/dy - 1
if cond1 > 0:
if cond2 > 0:
self.side = "right"
return
else:
self.side = "bottom"
return
else:
if cond2 > 0:
self.side = "top"
return
else:
self.side = "left"
return
def update_protobuf_location(self, c2dx, c2dy, cox, coy, dx, dy, dd = 0):
'''
c2dx = core to die spacing along x axix
c2dy = core to die spacing along y axix
cox = core origin x
coy = core origin y
dx = core widht
dy = core height
'''
die_llx = cox - c2dx[0]
die_lly = coy - c2dy[0]
die_dx = dx + sum(c2dx)
die_dy = dy + sum(c2dy)
X = self.x - die_llx
Y = self.y - die_lly
if self.side == None:
self.update_side(X, Y, die_dx, die_dy)
co_urx = cox + dx
co_ury = coy + dy
if self.side == "left":
self.px = dd
elif self.side == "right":
self.px = dx - dd
if self.side in ["left", "right"]:
if self.y <= coy:
## Directly print py Considering Core origin (0, 0)
self.py = dd
elif self.y >= co_ury:
self.py = dy - dd
else:
self.py = self.y - coy
if self.side == "top":
self.py = dy - dd
elif self.side == "bottom":
self.py = dd
if self.side in ["top", "bottom"]:
if self.x <= cox:
self.px = dd
elif self.x >= co_urx:
self.px = dx - dd
else:
self.px = self.x - cox
return
class net:
def __init__(self, idx, name) -> None:
self.id = idx
self.name = name
self.dtype = None
self.did = None
self.stypes = []
self.sids = []
return
def add_driver(self, dtype, did):
if self.did == None:
self.dtype = dtype
self.did = did
else:
print(f"[INFO][ERROR-4] Net has the driver id:{did} type:{dtype}")
return
def add_sink(self, stype, sid):
if sid not in self.sids:
self.sids.append(sid)
self.stypes.append(stype)
else:
print(f"[INFO][ERROR-5] Net:{self.name} has the sink id:{sid} type:{stype}")
return
class row:
def __init__(self, idx):
self.id = idx
self.llx = None
self.lly = None
self.urx = None
self.ury = None
self.orient = None
self.site_count = None
self.inst_ids = []
return
def update_llx(self, llx):
self.llx = llx
return
def update_lly(self, lly):
self.lly = lly
return
def update_site_count(self, count):
if self.site_count == None:
self.site_count = int(count)
self.inst_ids = [None]*int(count)
elif self.site_count != int(count):
print(f"[INFO][ERROR-6] Row id: {self.id} check site count")
return
def update_orient(self, orient):
if self.orient == None:
self.orient = orient
elif self.orient != orient:
print(f"[INFO][ERROR-7] Row id: {self.id} multiple orient")
return
def update_size(self, swidth, sheight):
self.urx = self.llx + self.site_count*swidth
self.ury = self.lly + sheight
return
class canvas_object:
def __init__(self, name, unit = 100):
self.design = name
self.unit = float(unit)
self.site_width = None
self.site_height = None
self.site_spacing = None
self.core_llx = None
self.core_lly = None
self.core_urx = None
self.core_ury = None
self.core_dx = None
self.core_dy = None
self.die_llx = None
self.die_lly = None
self.die_urx = None
self.die_ury = None
self.die_dx = None
self.die_dy = None
self.row_count = None
self.port_count = None
self.inst_count = None
self.pin_count = None
self.net_count = None
self.BookShelf_dir = None
self.c2dx = []
self.c2dy = []
self.nets = []
self.insts = []
self.masters = []
self.ports = []
self.netMap = {}
self.instMap = {}
self.masterMap = {}
self.portMap = {}
self.pb_id = {}
self.pb_type = {}
self.rows = []
return
def init_core(self):
self.core_llx = self.rows[0].llx
self.core_lly = self.rows[0].lly
self.core_urx = self.rows[0].urx
self.core_ury = self.rows[0].ury
return
def init_die(self):
self.die_llx = self.core_llx
self.die_lly = self.core_lly
self.die_urx = self.core_urx
self.die_ury = self.core_ury
return
def update_c2d_spacing(self):
self.c2dx.append(self.core_llx - self.die_llx)
self.c2dx.append(self.die_urx - self.core_urx)
self.c2dy.append(self.core_lly - self.die_lly)
self.c2dy.append(self.die_ury - self.core_ury)
return
def print_core_details(self):
print(f"Core llx:{self.core_llx} Core lly:{self.core_lly}")
print(f"Core urx:{self.core_urx} Core ury:{self.core_ury}")
print(f"Core dx:{self.core_dx} Core dy:{self.core_dy}")
return
def print_die_details(self):
print(f"Die llx:{self.die_llx} Die lly:{self.die_lly}")
print(f"Die urx:{self.die_urx} Die ury:{self.die_ury}")
print(f"Die dx:{self.die_dx} Die dy:{self.die_dy}")
return
def check_inst_op(self, count, isPrint = False):
_count = 0
for _inst in self.insts:
if len(_inst.opins) == count:
_count += 1
if isPrint:
print(f"Inst Name:{_inst.name} id:{_inst.id} Macro:{_inst.isMacro}")
print(f"Total number of instances with {count} output pins is {_count}")
return
def report_macros(self, isPrint = False):
_count = 0
for _inst in self.insts:
if _inst.isMacro:
if isPrint:
print(f"Inst id:{_inst.id} name:{_inst.name}")
_count += 1
print(f"Total number of macro instances is {_count}")
return
def update_port_side(self):
for _port in self.ports:
_port.update_protobuf_location(self.c2dx, self.c2dy, self.core_llx,\
self.core_lly, self.core_dx, self.core_dy, 0.5/self.unit)
return
def update_inst_type(self):
for _inst in self.insts:
_inst.update_isMacro(self.site_height)
return
def update_inst_pin_loc(self):
for _inst in self.insts:
_inst.update_pin_loc()
return
def check_inst_pins(self):
for _inst in self.insts:
_inst.check_pins()
def read_scl(self, scl_file):
'''
This reads the design.scl file and updates the core information.
This function updates the row information.
'''
scl_fp = open(scl_file, 'r')
row_id = 0
crow = None
for line in scl_fp.readlines():
if re.match(r"(^\s*#)|(^\s*UCLA\s*scl\s*1.0$)|(^\s*$)|(^\sEnd\s*$)", line):
continue
if re.match("^\s*CoreRow\s*Horizontal\s*$", line):
self.rows.append(row(row_id))
crow = self.rows[row_id]
row_id += 1
continue
lly = re.findall(r"^\s*Coordinate\s*:\s*([0-9,-,\.]*)", line)
sheight = re.findall(r"\s*Height\s*:\s*([0-9,-,\.]*)", line)
swidth = re.findall(r"^\s*Sitewidth\s*:\s*([0-9,-,\.]*)", line)
sorient = re.findall(r"^\s*Siteorient\s*:\s*([F, S, E, W, N]*)", line)
llx = re.findall(r"^\s*SubrowOrigin\s*:\s*([0-9,-,\.]*)", line)
sspacing = re.findall(r"^\s*Sitespacing\s*:\s*([0-9,-,\.]*)", line)
numsites = re.findall(r"\s\s*Num[S,s]ites\s*:\s*([0-9]*)", line)
if lly and lly[0] != "" :
_lly = float(lly[0])/self.unit
crow.update_lly(_lly)
if sheight and sheight[0] != "":
if self.site_height == None:
self.site_height = float(sheight[0])/self.unit
elif self.site_height != float(sheight[0])/self.unit:
print(f"[INFO][ERROR-8] Row id:{row_id-1} site height is different")
if swidth and swidth[0] != "":
if self.site_width == None:
self.site_width = float(swidth[0])/self.unit
elif self.site_width != float(swidth[0])/self.unit:
print(f"[INFO][ERROR-9] Row id:{row_id-1} site width is different")
if sorient and sorient[0] != "":
crow.update_orient(sorient[0])
if llx and llx[0] != "":
_llx = float(llx[0])/self.unit
crow.update_llx(_llx)
if sspacing and sspacing[0] != "":
if self.site_spacing == None:
self.site_spacing = float(sspacing[0])/self.unit
elif self.site_spacing != float(sspacing[0])/self.unit:
print(f"[INFO][ERROR-10] Row id:{row_id-1} site spacing is different")
if numsites and numsites[0] != "":
crow.update_site_count(numsites[0])
self.rows[0].update_size(self.site_width, self.site_height)
self.init_core()
for _row in self.rows:
_row.update_size(self.site_width, self.site_height)
self.core_llx = min(self.core_llx, _row.llx)
self.core_lly = min(self.core_lly, _row.lly)
self.core_urx = max(self.core_urx, _row.urx)
self.core_ury = max(self.core_ury, _row.ury)
self.core_dx = self.core_urx - self.core_llx
self.core_dy = self.core_ury - self.core_lly
scl_fp.close()
return
def read_nodes(self, nodes_file):
'''
Read design.nodes file and updated the terminals and instances
'''
nodes_fp = open(nodes_file, 'r')
node_count = None
port_id = 0
inst_id = 0
terminal_count = None
fixed_inst_count = 0
for line in nodes_fp.readlines():
if re.match(r"(^\s*#)|(^\s*UCLA\s*nodes\s*1.0$)|(^\s*$)", line):
continue
num_nodes = re.findall(r"^\s*NumNodes\s*:\s*([0-9]*)", line)
if num_nodes and num_nodes[0] != "":
node_count = int(num_nodes[0])
if self.port_count != None:
self.inst_count = node_count - self.port_count
continue
num_terminal = re.findall(r"^\s*NumTerminals\s*:\s*([0-9]*)", line)
if num_terminal and num_terminal[0] != "":
terminal_count = int(num_terminal[0])
continue
items = line.split()
# By default ports has 1 width and 1 height
if len(items) == 4 and items[1] == "1" and items[2] == "1" and \
items[3] in ['terminal', 'terminal_NI']:
self.ports.append(port(items[0]))
self.ports[-1].update_id(port_id)
self.portMap[items[0]] = port_id
port_id += 1
elif (len(items) == 4 and items[3] == 'terminal') or \
len(items) == 3:
self.insts.append(instance(inst_id, items[0]))
_height = float(items[2])/self.unit
_width = float(items[1])/self.unit
self.insts[-1].update_size(_height, _width)
self.instMap[items[0]] = inst_id
inst_id += 1
if len(items) == 4 and items[3] == 'terminal':
fixed_inst_count += 1
self.inst_count = inst_id
self.port_count = port_id
if port_id + inst_id != node_count:
print(f"[INFO][ERROR-11] Mismatch in total number of nodes and read nodes")
if terminal_count - fixed_inst_count != port_id:
print(f"[INFO][ERROR-12] Mismatch in the port count and fixed instance count")
nodes_fp.close()
return
def read_pl(self, pl_file):
'''
Read design.pl file and update the terminal and isntance locations
'''
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*$)", line):
continue
items = line.split()
_x = float(items[1])/self.unit
_y = float(items[2])/self.unit
_orient = items[4]
if items[0] in self.portMap:
port_id = self.portMap[items[0]]
_port = self.ports[port_id]
_port.update_location(_x, _y)
elif items[0] in self.instMap:
inst_id = self.instMap[items[0]]
_inst = self.insts[inst_id]
_pstatus = "UNPLACED"
if len(items) == 6:
_pstatus = items[5]
_inst.update_location(_x, _y, _orient, _pstatus)
_inst.update_center()
self.init_die()
for _port in self.ports:
self.die_llx = min(self.die_llx, _port.x)
self.die_lly = min(self.die_lly, _port.y)
self.die_urx = max(self.die_urx, _port.x)
self.die_ury = max(self.die_ury, _port.y)
self.die_dx = self.die_urx - self.die_llx
self.die_dy = self.die_ury - self.die_lly
self.update_c2d_spacing()
self.update_port_side()
self.update_inst_type()
pl_fp.close()
return
def read_net_healper(self, line, net_name, net_id, isDriver):
items = line.split()
pname = items[0]
ptype = None
idx = None
if items[0] in self.portMap:
ptype = "port"
idx = self.portMap[pname]
self.ports[idx].connect_net(net_id, net_name, isDriver)
else:
ptype = "inst"
idx = self.instMap[pname]
_x_offset = float(items[3])/self.unit
_y_offset = float(items[4])/self.unit
self.insts[idx].connect_net(net_name, net_id, not isDriver, \
_x_offset, _y_offset)
if isDriver:
self.nets[net_id].add_driver(ptype, idx)
else:
self.nets[net_id].add_sink(ptype, idx)
return
def read_nets(self, nets_file):
'''
Read design.nets file and add nets, pins and pin locations and pin typs.
For each net we consider the first pin is the driver.
'''
nets_fp = open(nets_file, 'r')
net_id = 0
lines = nets_fp.readlines()
no_lines = len(lines)
i = 0
while i < no_lines:
if re.match(r"(^\s*#)|(^\s*UCLA\s*nets\s*1.0$)|(^\s*$)", lines[i]):
i += 1
continue
num_nets = re.findall(r"^\s*NumNets\s*:\s*([0-9]*)", lines[i])
num_pins = re.findall(r"^\s*NumPins\s*:\s*([0-9]*)", lines[i])
if num_nets and num_nets[0] != "":
self.net_count = int(num_nets[0])
i += 1
continue
if num_pins and num_pins[0] != "":
self.pin_count = int(num_pins[0])
i += 1
continue
items = lines[i].split()
net_degree = 0
if items[0] == "NetDegree":
## Add net details ##
net_degree = int(items[2])
net_name = items[3]
self.nets.append(net(net_id, net_name))
self.netMap[net_name] = net_id
i += 1
## SPins = Sinks DPins = Drivers BiPins = Bidrections ##
SPins = []
DPins = []
BiPins = []
for _ in range(net_degree):
items = lines[i].split()
if items[1] == 'I':
SPins.append(i)
elif items[1] == 'O':
DPins.append(i)
elif items[1] == 'B':
BiPins.append(i)
else:
print(f"[INFO][ERROR] Check net:{net_name} sink/driver not defined")
i += 1
AckDriver = None
if len(DPins) > 0:
AckDriver = DPins[0]
del DPins[0]
elif len(BiPins) > 0:
AckDriver = BiPins[0]
del BiPins[0]
elif len(SPins) > 0:
AckDriver = SPins[0]
del SPins[0]
else:
print(f"[INFO][ERROR] Check net:{net_name} does not have driver and sink")
self.read_net_healper(lines[AckDriver], net_name, net_id, True)
for j in DPins + SPins + BiPins:
self.read_net_healper(lines[j], net_name, net_id, False)
net_id += 1
del lines
nets_fp.close()
self.update_inst_pin_loc()
return
def write_header(self, fp):
user = os.environ["USER"]
if self.BookShelf_dir == None:
run_dir = os.environ["PWD"]
else:
run_dir = self.BookShelf_dir
today = date.today()
fp.write(f"# User: {user}\n")
fp.write(f"# Date: {today}\n")
fp.write(f"# Run area: {run_dir}\n")
fp.write(f"# Block: {self.design}\n")
fp.write("# FP bbox: {0.0 0.0} {" f"{self.core_dx} {self.core_dy}" "}\n")
fp.write("# Columns : 10 Rows : 10\n")
return
def print_net(self, net_id, fp):
no_sink = len(self.nets[net_id].sids)
for i in range(no_sink):
stype = self.nets[net_id].stypes[i]
sid = self.nets[net_id].sids[i]
if stype == "inst":
inst_name = self.insts[sid].name
if self.insts[sid].isMacro:
# print(f"inst id:{sid} net id:{net_id}")
idx = self.insts[sid].ipin_net_id.index(net_id)
pin_name = self.insts[sid].ipins[idx]
fp.write(f" input: \"{inst_name}/{pin_name}\"\n")
else:
fp.write(f" input: \"{inst_name}\"\n")
else:
port_name = self.ports[sid].name
fp.write(f" input: \"{port_name}\"\n")
return
def write_node_port(self, port_id, fp):
fp.write("node {\n")
_port = self.ports[port_id]
port_name = _port.name
fp.write(f" name: \"{port_name}\"\n")
if _port.isInput:
self.print_net(_port.net_id, fp)
print_placeholder(fp, "type", "port")
print_placeholder(fp, "side", _port.side)
print_float(fp, "x", _port.px)
print_float(fp, "y", _port.py)
fp.write("}\n")
return
def write_node_macro(self, macro_id, fp):
fp.write("node {\n")
_macro = self.insts[macro_id]
macro_name = _macro.name
fp.write(f" name: \"{macro_name}\"\n")
print_float(fp, "width", _macro.width)
print_float(fp, "height", _macro.height)
print_placeholder(fp, "type", "macro")
print_float(fp, "x", _macro.cx)
print_float(fp, "y", _macro.cy)
fp.write("}\n")
return
def write_node_macro_ipin(self, macro_id, pin_id, fp):
fp.write("node {\n")
_macro = self.insts[macro_id]
macro_name = _macro.name
pin_name = _macro.ipins[pin_id]
fp.write(f" name: \"{macro_name}/{pin_name}\"\n")
print_placeholder(fp, "macro_name", macro_name)
print_placeholder(fp, "type", "macro_pin")
print_float(fp, "x_offset", _macro.ipin_act_x_offset[pin_id])
print_float(fp, "y_offset", _macro.ipin_act_y_offset[pin_id])
if len(_macro.ipin_x) > pin_id:
print_float(fp, "x", _macro.ipin_x[pin_id])
print_float(fp, "y", _macro.ipin_y[pin_id])
fp.write("}\n")
return
def write_node_macro_opin(self, macro_id, pin_id, fp):
fp.write("node {\n")
_macro = self.insts[macro_id]
macro_name = _macro.name
pin_name = _macro.opins[pin_id]
fp.write(f" name: \"{macro_name}/{pin_name}\"\n")
net_id = _macro.opin_net_id[pin_id]
self.print_net(net_id, fp)
print_placeholder(fp, "macro_name", macro_name)
print_placeholder(fp, "type", "macro_pin")
print_float(fp, "x_offset", _macro.opin_act_x_offset[pin_id])
print_float(fp, "y_offset", _macro.opin_act_y_offset[pin_id])
if len(_macro.opin_x) > pin_id:
print_float(fp, "x", _macro.opin_x[pin_id])
print_float(fp, "y", _macro.opin_y[pin_id])
fp.write("}\n")
return
def write_node_stdcell(self, inst_id, fp):
fp.write("node {\n")
_inst = self.insts[inst_id]
inst_name = _inst.name
fp.write(f" name: \"{inst_name}\"\n")
for net_id in _inst.opin_net_id:
self.print_net(net_id, fp)
print_placeholder(fp, "type", "stdcell")
print_float(fp, "width", _inst.width)
print_float(fp, "height", _inst.height)
print_float(fp, "x", _inst.cx)
print_float(fp, "y", _inst.cy)
fp.write("}\n")
return
def gen_pb_netlist(self, file_name=None):
if file_name == None:
if self.BookShelf_dir == None:
file_name = f"{self.design}.pb.txt"
else:
file_name = f"{self.BookShelf_dir}/{self.design}.pb.txt"
fp = open(file_name, "w")
self.write_header(fp)
for _port in self.ports:
self.write_node_port(_port.id, fp)
for _inst in self.insts:
if _inst.isMacro:
self.write_node_macro(_inst.id, fp)
for i in range(len(_inst.ipins)):
self.write_node_macro_ipin(_inst.id, i, fp)
for i in range(len(_inst.opins)):
self.write_node_macro_opin(_inst.id, i, fp)
else:
self.write_node_stdcell(_inst.id, fp)
fp.close()
print(f"Output protobuf netlist: {file_name}")
return
def read_BookShelf(self, dir, design = None):
if design == None:
design = self.design
if os.path.exists(dir):
self.BookShelf_dir = dir
else:
print(f"[INFO][ERROR-13] BookShelf dir does not exists.\nDIR:{dir}")
return
scl_file = f"{dir}/{design}.scl"
if os.path.isfile(scl_file):
print(f"Parsing: {scl_file}")
self.read_scl(scl_file)
else:
print(f"[INFO][ERROR-14] Check file: \n{scl_file}")
nodes_file = f"{dir}/{design}.nodes"
if os.path.isfile(nodes_file):
print(f"Parsing: {nodes_file}")
self.read_nodes(nodes_file)
else:
print(f"[INFO][ERROR-15] Check file: \n{nodes_file}")
pl_file = f"{dir}/{design}.pl"
if os.path.isfile(pl_file):
print(f"Parsing: {pl_file}")
self.read_pl(pl_file)
else:
print(f"[INFO][ERROR-16] Check file: \n{pl_file}")
nets_file = f"{dir}/{design}.nets"
if os.path.isfile(nets_file):
print(f"Parsing: {nets_file}")
self.read_nets(nets_file)
else:
print(f"[INFO][ERROR-17] Check file: \n{nets_file}")
for inst in self.insts:
inst.name = inst.name.replace("\\","")
for port in self.ports:
port.name = port.name.replace("\\","")
return
def read_pb(self, pb_netlist):
fp = open(pb_netlist, 'r')
lines = fp.readlines()
node_id = 0
for line in lines:
words = line.split()
if words[0] == 'name:':
node_name = words[1].replace('"','')
if node_name == "__metadata__":
continue
if node_name in self.portMap:
self.pb_id[node_id] = self.portMap[node_name]
self.pb_type[node_id] = "port"
elif node_name in self.instMap:
self.pb_id[node_id] = self.instMap[node_name]
self.pb_type[node_id] = "inst"
else:
self.pb_type[node_id] = "other"
node_id += 1
return
def read_plc(self, plc_file):
fp = open(plc_file, 'r')
lines = fp.readlines()
id_pattern = re.compile("[0-9]+")
for line in lines:
words = line.split()
if id_pattern.match(words[0]) and (len(words) == 5):
idx = int(words[0])
if self.pb_type[idx] == "inst":
if self.insts[self.pb_id[idx]].isMacro:
self.insts[self.pb_id[idx]].cx = float(words[1])
self.insts[self.pb_id[idx]].cy = float(words[2])
self.insts[self.pb_id[idx]].pstatus = "FIXED"
return
def write_node(self, node_file = None):
if node_file == None:
node_file = f"{self.BookShelf_dir}/{self.design}.updated.nodes"
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 = len(self.insts) + len(self.ports)
total_fixed_instance = 0
for inst in self.insts:
if inst.pstatus == "FIXED":
total_fixed_instance += 1
total_terminals = len(self.ports) + total_fixed_instance
fp.write(f"NumNodes : {total_nodes}\nNumTerminals : {total_terminals}\n")
for port in self.ports:
fp.write(f" {port.name} 1 1 terminal\n")
for inst in self.insts:
height = round(inst.height * self.unit, 6)
width = round(inst.width * self.unit, 6)
eol = ""
if inst.pstatus == "FIXED":
eol = "terminal"
fp.write(f" {inst.name} {width} {height} {eol}\n")
fp.close()
return
def write_pl(self, pl_file = None):
if pl_file == None:
pl_file = f"{self.BookShelf_dir}/{self.design}.updated.pl"
fp = open(pl_file, "w")
today = date.today()
user = 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 port in self.ports:
px = port.x * self.unit
py = port.y * self.unit
fp.write(f" {port.name} {px} {py} : N /FIXED\n")
for inst in self.insts:
px = (inst.cx - (inst.width * 0.5)) * self.unit
py = (inst.cy - (inst.height * 0.5)) * self.unit
eol = ""
if inst.pstatus == "FIXED":
eol = "/FIXED"
else:
px = (self.core_dx*0.5 - (inst.width * 0.5)) * self.unit
px = (self.core_dy*0.5 - (inst.width * 0.5)) * self.unit
px = round(px, 6)
py = round(py, 6)
fp.write(f" {inst.name} {px} {py} : N {eol}\n")
fp.close()
#### Print the design header ####
proc print_header { fp } {
set design [[ord::get_db_block] getName]
set user [exec whoami]
set date [exec date]
set run_dir [exec pwd]
set canvas_width [ord::dbu_to_microns [[[ord::get_db_block] getCoreArea] dx]]
set canvas_height [ord::dbu_to_microns [[[ord::get_db_block] getCoreArea] dy]]
puts $fp "# User: $user"
puts $fp "# Date: $date"
puts $fp "# Run area: $run_dir"
puts $fp "# Block : $design"
puts $fp "# FP bbox: {0.0 0.0} {$canvas_width $canvas_height}"
## Add dummy Column and Row info ##
puts $fp "# Columns : 10 Rows : 10"
}
#### Print helper ####
proc print_placeholder { fp key value } {
puts $fp " attr {"
puts $fp " key: \"$key\""
puts $fp " value {"
puts $fp " placeholder: \"$value\""
puts $fp " }"
puts $fp " }"
}
proc print_float { fp key value } {
puts $fp " attr {"
puts $fp " key: \"$key\""
puts $fp " value {"
puts $fp " f: $value"
puts $fp " }"
puts $fp " }"
}
### Helper to convert Orientation format ###
proc get_orient { tmp_orient } {
set orient "N"
if { $tmp_orient == "R0"} {
set orient "N"
} elseif { $tmp_orient == "R180" } {
set orient "S"
} elseif { $tmp_orient == "R90" } {
set orient "W"
} elseif { $tmp_orient == "R270" } {
set orient "E"
} elseif { $tmp_orient == "MY" } {
set oreint "FN"
} elseif { $tmp_orient == "MX" } {
set oreint "FS"
} elseif { $tmp_orient == "MX90" } {
set orient "FW"
} elseif { $tmp_orient == "MY90" } {
set orient "FE"
}
return $orient
}
#### Procedure to print the sinks ####
proc print_net { net_ptr fp } {
### Print Terms ###
foreach bterm [$net_ptr getBTerms] {
set type [$bterm getIoType]
if { $type == "OUTPUT" } {
set btermName [$bterm getName]
puts $fp " input: \"${btermName}\""
}
}
### For each inst pins ###
foreach iterm [$net_ptr getITerms] {
if { [$iterm isInputSignal] } {
set inst [ $iterm getInst ]
set isBlock [ $inst isBlock]
set instName [$inst getName]
if { $isBlock } {
set pinName [[$iterm getMTerm] getName]
puts $fp " input: \"${instName}\/${pinName}\""
} else {
puts $fp " input: \"${instName}\""
}
}
}
}
### Procedure Find Side ###
proc find_bterm_side { pt_x pt_y dx dy} {
set cond1 [expr $pt_x - $pt_y]
set cond2 [expr ($pt_x/$dx) + ($pt_y/$dy) - 1]
if { $cond1 > 0 } {
if { $cond2 > 0 } {
return "right"
} else {
return "bottom"
}
} else {
if { $cond2 > 0 } {
return "top"
} else {
return "left"
}
}
}
### Procedure Find Mid Point ###
proc find_mid_point { rect } {
set xmin [$rect xMin]
set ymin [$rect yMin]
set dx [$rect dx]
set dy [$rect dy]
set pt_x [expr $xmin + $dx/2]
set pt_y [expr $ymin + $dy/2]
return [list $pt_x $pt_y]
}
proc find_mid_point_bbox { rect } {
set xmin [$rect xMin]
set ymin [$rect yMin]
set dx [$rect getDX]
set dy [$rect getDY]
set pt_x [expr $xmin + $dx/2]
set pt_y [expr $ymin + $dy/2]
return [list $pt_x $pt_y]
}
#### Procedure to write Ports ####
proc write_node_port { port_ptr fp } {
puts $fp "node {"
set name [$port_ptr getName]
puts $fp " name: \"${name}\""
if { [$port_ptr getIoType] == "INPUT" } {
set net_ptr [$port_ptr getNet]
print_net $net_ptr $fp
}
### Attribute: type ###
print_placeholder $fp "type" "port"
### Adjusting Core and Die ###
set term_box [$port_ptr getBBox]
set mid_pts [find_mid_point $term_box]
set X [ord::dbu_to_microns [lindex $mid_pts 0]]
set Y [ord::dbu_to_microns [lindex $mid_pts 1]]
set dx [ord::dbu_to_microns [[[ord::get_db_block] getDieArea] dx]]
set dy [ord::dbu_to_microns [[[ord::get_db_block] getDieArea] dy]]
set die_llx [ord::dbu_to_microns [[[ord::get_db_block] getDieArea] xMin]]
set die_lly [ord::dbu_to_microns [[[ord::get_db_block] getDieArea] yMin]]
set side [find_bterm_side [expr $X - $die_llx] [expr $Y - $die_lly]\
$dx $dy]
### Attribute: X, Y and Side ###
print_placeholder $fp "side" $side
set origin_x [ord::dbu_to_microns [[[ord::get_db_block] getCoreArea] xMin]]
set origin_y [ord::dbu_to_microns [[[ord::get_db_block] getCoreArea] yMin]]
### Attribute: X ###
if {$side == "top" || $side == "bottom"} {
set X [expr $X - $origin_x]
} elseif { $side == "right" } {
set X [expr $X - 2*$origin_x]
}
print_float $fp "x" $X
### Attribute: Y ###
if {$side == "left" || $side == "right"} {
set Y [expr $Y - $origin_y]
} elseif { $side == "top" } {
set Y [expr $Y - 2*$origin_y]
}
print_float $fp "y" $Y
puts $fp "}"
}
#### Procedure to write Macros ####
proc write_node_macro { macro_ptr fp } {
puts $fp "node {"
set name [$macro_ptr getName]
puts $fp " name: \"${name}\""
### Attribute: ref_name ###
set master_ptr [$macro_ptr getMaster]
set ref_name [$master_ptr getName]
print_placeholder $fp "ref_name" ${ref_name}
### Attribute: Width ###
set width [ord::dbu_to_microns [$master_ptr getWidth]]
print_float $fp "width" $width
### Attribute: Height ###
set height [ord::dbu_to_microns [$master_ptr getHeight]]
print_float $fp "height" $height
### Attribute: type ###
print_placeholder $fp "type" "macro"
set inst_box [$macro_ptr getBBox]
set pts [find_mid_point_bbox $inst_box]
set origin_x [ord::dbu_to_microns [[[ord::get_db_block] getCoreArea] xMin]]
set origin_y [ord::dbu_to_microns [[[ord::get_db_block] getCoreArea] yMin]]
### Attribute: X ###
set X [ord::dbu_to_microns [lindex $pts 0]]
set X [expr $X - $origin_x]
print_float $fp "x" $X
### Attribute: Y ###
set Y [ord::dbu_to_microns [lindex $pts 1]]
set Y [expr $Y - $origin_y]
print_float $fp "y" $Y
### Attribute: Orient ###
set tmp_orient [${macro_ptr} getOrient]
set orient [get_orient $tmp_orient]
print_placeholder $fp "orientation" $orient
puts $fp "}"
}
#### Procedure to Write Macro Pins ####
proc write_node_macro_pin { macro_pin_ptr fp } {
puts $fp "node {"
set macro_ptr [ ${macro_pin_ptr} getInst]
set macro_name [ ${macro_ptr} getName ]
set pin_name [ [${macro_pin_ptr} getMTerm] getName ]
set name "${macro_name}\/${pin_name}"
puts $fp " name: \"${name}\""
### Print all the sinks ###
if { [${macro_pin_ptr} isOutputSignal] } {
set net_ptr [${macro_pin_ptr} getNet]
print_net $net_ptr $fp
}
### Attribute: Macro Name ###
print_placeholder $fp "macro_name" $macro_name
### Attribute: type ###
print_placeholder $fp "type" "macro_pin"
set origin_x [ord::dbu_to_microns [[[ord::get_db_block] getCoreArea] xMin]]
set origin_y [ord::dbu_to_microns [[[ord::get_db_block] getCoreArea] yMin]]
set macro_master [${macro_ptr} getMaster]
set cell_height [${macro_master} getHeight]
set cell_width [ ${macro_master} getWidth]
set mterm_ptr [${macro_pin_ptr} getMTerm]
set pin_box [${mterm_ptr} getBBox]
set pts [find_mid_point $pin_box]
set x_offset [expr [lindex $pts 0] - $cell_width/2]
set y_offset [expr [lindex $pts 1] - $cell_height/2]
### Attribute: x_offset ###
set x_offset [ord::dbu_to_microns $x_offset]
print_float $fp "x_offset" $x_offset
### Attribute: y_offset ###
set y_offset [ord::dbu_to_microns $y_offset]
print_float $fp "y_offset" $y_offset
set pin_box [${macro_pin_ptr} getBBox]
set pts [find_mid_point $pin_box]
### Attribute: X ###
set X [ord::dbu_to_microns [lindex $pts 0]]
set X [expr $X - $origin_x]
print_float $fp "x" $X
### Attribute: Y ###
set Y [ord::dbu_to_microns [lindex $pts 1]]
set Y [expr $Y - $origin_y]
print_float $fp "y" $Y
puts $fp "}"
}
#### Procedure to Write Std-cell ###
proc write_node_stdcell { inst_ptr fp } {
puts $fp "node {"
set name [${inst_ptr} getName]
puts $fp " name: \"${name}\""
### Print all the sinks ###
foreach iterm_ptr [${inst_ptr} getITerms] {
if { [${iterm_ptr} isOutputSignal] } {
set net_ptr [${iterm_ptr} getNet]
print_net $net_ptr $fp
}
}
### Attribute: ref_name ###
set master_ptr [${inst_ptr} getMaster]
set ref_name [${master_ptr} getName]
print_placeholder $fp "ref_name" $ref_name
### Attribute: Width ###
set width [ord::dbu_to_microns [${master_ptr} getWidth]]
print_float $fp "width" $width
### Attribute: Height ###
set height [ord::dbu_to_microns [${master_ptr} getHeight]]
print_float $fp "height" $height
### Attribute: type ###
print_placeholder $fp "type" "stdcell"
set inst_box [$inst_ptr getBBox]
set pts [find_mid_point_bbox $inst_box]
set origin_x [ord::dbu_to_microns [[[ord::get_db_block] getCoreArea] xMin]]
set origin_y [ord::dbu_to_microns [[[ord::get_db_block] getCoreArea] yMin]]
### Attribute: X ###
set X [ord::dbu_to_microns [lindex $pts 0]]
set X [expr $X - $origin_x]
print_float $fp "x" $X
### Attribute: Y ###
set Y [ord::dbu_to_microns [lindex $pts 1]]
set Y [expr $Y - $origin_y]
print_float $fp "y" $Y
puts $fp "}"
}
#### Generate protobuff format netlist ####
proc gen_pb_netlist { {file_name ""} } {
set block [ord::get_db_block]
set design [$block getName]
if { $file_name != "" } {
set out_file ${file_name}
} else {
set out_file "${design}.pb.txt"
}
set fp [open $out_file w+]
print_header $fp
foreach port_ptr [$block getBTerms] {
write_node_port $port_ptr $fp
}
foreach inst_ptr [$block getInsts] {
### Macro ###
if { [${inst_ptr} isBlock] } {
write_node_macro $inst_ptr $fp
foreach macro_pin_ptr [${inst_ptr} getITerms] {
if {[${macro_pin_ptr} isInputSignal] || [${macro_pin_ptr} isOutputSignal]} {
write_node_macro_pin $macro_pin_ptr $fp
}
}
} elseif { [${inst_ptr} isCore] } {
### Standard Cells ###
write_node_stdcell $inst_ptr $fp
}
}
close $fp
exec sed -i {s@\\@@g} $out_file
puts "Output netlist: $out_file"
}
......@@ -84,7 +84,7 @@ The following screenshot shows the placed and routed Ariane133-NG45 design gener
<img height="400" src="./screenshots/CT_Routing.png">
</p>
The following table shows the different metrics, when [Flow-2](../../figures/flow-2.PNG) is used when initial macro placement is generated using CT.
The following table shows the different metrics, when [Flow-2](../../figures/flow-2.PNG) is used and the initial macro placement is generated using CT.
| Physical Design Stage | Core Area (um^2) | Standard Cell Area (um^2) | Macro Area (um^2) | Total Power (mW) | Wirelength (um) | WS (ns) | TNS (ns) | Congestion (H) | Congestion (V) |
|-----------------------|------------------|---------------------------|-------------------|------------------|-----------------|---------|----------|----------------|----------------|
| postSynth | 1814274 | 244614 | 1018356 | 761.754 | 4884882 | -0.764 | -533.519 | | |
......
set rtl_all {
./rtl/bsg_chip_block.sv2v.v
./rtl/fakeram45_32x32_dp.v
../../rtl/bsg_chip_block.sv2v.v
../../rtl/fakeram45_32x32_dp.v
}
#!/bin/tcsh
## Set to 1 to run refine_macro_place ##
setenv SYN_HANDOFF $argv[1]
setenv SEED $argv[2]
set util_dir="/home/fetzfs_projects/MacroPlacement/flow_scripts_run/MacroPlacement/Flows/util/"
if ($#argv != 3) then
echo "Required Physical synthesis handoff path and seed to run shuffle macro"
endif
module unload innovus
module load innovus/21.1
innovus -64 -overwrite -log log/macro_shuffle_innovus.log -files ${util_dir}/gen_shuffle_macro_def.tcl
## Edit the design file to make sure flow2 reads the new macro placed def instead of the default one
set def_file=`ls *_fp_shuffled_macros.def | head -n1`
sed -i "s@\S*_fp_placed_macros.def@${def_file}@" design_setup.tcl
# 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.
source lib_setup.tcl
source design_setup.tcl
set handoff_dir $::env(SYN_HANDOFF)
set netlist ${handoff_dir}/${DESIGN}.v
set sdc ${handoff_dir}/${DESIGN}.sdc
source mmmc_setup.tcl
setMultiCpuUsage -localCpu 16
set util 0.3
# default settings
set init_pwr_net VDD
set init_gnd_net VSS
# default settings
set init_verilog "$netlist"
set init_design_netlisttype "Verilog"
set init_design_settop 1
set init_top_cell "$DESIGN"
set init_lef_file "$lefs"
# MCMM setup
init_design -setup {WC_VIEW} -hold {BC_VIEW}
set_power_analysis_mode -leakage_power_view WC_VIEW -dynamic_power_view WC_VIEW
set_interactive_constraint_modes {CON}
setAnalysisMode -reset
setAnalysisMode -analysisType onChipVariation -cppr both
clearGlobalNets
globalNetConnect VDD -type pgpin -pin VDD -inst * -override
globalNetConnect VSS -type pgpin -pin VSS -inst * -override
globalNetConnect VDD -type tiehi -inst * -override
globalNetConnect VSS -type tielo -inst * -override
setOptMode -powerEffort low -leakageToDynamicRatio 0.5
setGenerateViaMode -auto true
generateVias
# basic path groups
createBasicPathGroups -expanded
## Generate the floorplan ##
defIn ${handoff_dir}/${DESIGN}.def
#### Unplace the standard cells ###
dbset [dbget top.insts.cell.subClass core -p2 ].pStatus unplaced
source ../../../../util/shuffle_macro.tcl
shuffle_macros $::env(SEED)
defOut -floorplan ./${DESIGN}_fp_shuffled_macros.def
exit
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