calibre pex modifications to run hierarchical pex

This commit is contained in:
Bob Vanhoof 2021-03-01 09:56:25 +01:00
parent d14a68847e
commit fde8794282
6 changed files with 99 additions and 32 deletions

View File

@ -185,10 +185,10 @@ class delay(simulation):
meas.targ_name_no_port))
self.dout_volt_meas[-1].meta_str = meas.meta_str
if not OPTS.use_pex:
self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name + "{}", "FALL", "RISE", measure_scale=1e9)
else:
if OPTS.use_pex and OPTS.pex_exe[0] != 'calibre':
self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name, "FALL", "RISE", measure_scale=1e9)
else:
self.sen_meas = delay_measure("delay_sen", self.clk_frmt, self.sen_name + "{}", "FALL", "RISE", measure_scale=1e9)
self.sen_meas.meta_str = sram_op.READ_ZERO
self.sen_meas.meta_add_delay = True
@ -235,13 +235,15 @@ class delay(simulation):
storage_names = cell_inst.mod.get_storage_net_names()
debug.check(len(storage_names) == 2, ("Only inverting/non-inverting storage nodes"
"supported for characterization. Storage nets={}").format(storage_names))
if not OPTS.use_pex:
q_name = cell_name + '.' + str(storage_names[0])
qbar_name = cell_name + '.' + str(storage_names[1])
else:
#todo: bob vanhoof's modification: hierarchical pex
if OPTS.use_pex and OPTS.pex_exe[0] != 'calibre':
bank_num = self.sram.get_bank_num(self.sram.name, bit_row, bit_col)
q_name = "bitcell_Q_b{0}_r{1}_c{2}".format(bank_num, bit_row, bit_col)
qbar_name = "bitcell_Q_bar_b{0}_r{1}_c{2}".format(bank_num, bit_row, bit_col)
else:
q_name = cell_name + '.' + str(storage_names[0])
qbar_name = cell_name + '.' + str(storage_names[1])
# Bit measures, measurements times to be defined later. The measurement names must be unique
# but they is enforced externally. {} added to names to differentiate between ports allow the

View File

@ -426,7 +426,8 @@ class simulation():
"""
port = self.read_ports[0]
if not OPTS.use_pex:
#todo: modified by bob vanhoof to take into account calibre pex
if not OPTS.use_pex or (OPTS.use_pex and OPTS.pex_exe[0] == 'calibre'):
self.graph.get_all_paths('{}{}'.format("clk", port),
'{}{}_{}'.format(self.dout_name, port, self.probe_data))
@ -482,7 +483,8 @@ class simulation():
debug.check(len(sa_mods) == 1, "Only expected one type of Sense Amp. Cannot perform s_en checks.")
enable_name = sa_mods[0].get_enable_name()
sen_name = self.get_alias_in_path(paths, enable_name, sa_mods[0])
if OPTS.use_pex:
# todo: modified by bob vanhoof
if OPTS.use_pex and (OPTS.pex_exe[0] != 'calibre'):
sen_name = sen_name.split('.')[-1]
return sen_name
@ -540,7 +542,8 @@ class simulation():
exclude_set = self.get_bl_name_search_exclusions()
for int_net in [cell_bl, cell_br]:
bl_names.append(self.get_alias_in_path(paths, int_net, cell_mod, exclude_set))
if OPTS.use_pex:
#todo modified by bob vanhoof
if OPTS.use_pex and OPTS.pex_exe[0] != 'calibre':
for i in range(len(bl_names)):
bl_names[i] = bl_names[i].split('.')[-1]
return bl_names[0], bl_names[1]

View File

@ -52,7 +52,7 @@ class stimuli():
def inst_model(self, pins, model_name):
""" Function to instantiate a generic model with a set of pins """
if OPTS.use_pex:
if OPTS.use_pex and OPTS.pex_exe[0] != 'calibre':
self.inst_pex_model(pins, model_name)
else:
self.sf.write("X{0} ".format(model_name))

View File

@ -136,6 +136,7 @@ class sram():
if OPTS.use_pex:
start_time = datetime.datetime.now()
# Output the extracted design if requested
#todo: bob vanhoof: re-generate the layout so that it now does include the pex labels
pexname = OPTS.output_path + self.s.name + ".pex.sp"
spname = OPTS.output_path + self.s.name + ".sp"
verify.run_pex(self.s.name, gdsname, spname, output=pexname)

View File

@ -201,7 +201,9 @@ class sram_base(design, verilog, lef):
highest_coord = self.find_highest_coords()
self.width = highest_coord[0]
self.height = highest_coord[1]
if OPTS.use_pex:
#todo: bob vanhoof: this now does not automatically propagate the pex labels when the lvs tool is calibre
if OPTS.use_pex and not OPTS.lvs_exe[0] == "calibre":
debug.info(2,"adding global pex labels")
self.add_global_pex_labels()
self.add_boundary(ll=vector(0, 0),
ur=vector(self.width, self.height))

View File

@ -125,6 +125,8 @@ def write_lvs_script(cell_name, gds_name, sp_name, final_verification=False, out
run_file = output_path + "run_lvs.sh"
f = open(run_file, "w")
f.write("#!/bin/sh\n")
#PDK_DIR=os.environ.get("PDK_DIR")
#f.write("export PDK_DIR={}\n".format(PDK_DIR))
cmd = "{0} -gui -lvs lvs_runset -batch".format(OPTS.lvs_exe[1])
f.write(cmd)
@ -154,38 +156,80 @@ def write_pex_script(cell_name, extract, output, final_verification=False, outpu
from tech import drc
pex_rules = drc["xrc_rules"]
pex_runset = {
'pexRulesFile': pex_rules,
'pexRunDir': output_path,
'pexLayoutPaths': cell_name + ".gds",
'pexLayoutPrimary': cell_name,
'pexSourcePath': cell_name + ".sp",
'pexSourcePrimary': cell_name,
'pexReportFile': cell_name + ".pex.report",
'pexPexNetlistFile': output,
'pexPexReportFile': cell_name + ".pex.report",
'pexMaskDBFile': cell_name + ".maskdb",
'cmnFDIDEFLayoutPath': cell_name + ".def",
}
# write the runset file
f = open(output_path + "pex_runset", "w")
for k in sorted(iter(pex_runset.keys())):
f.write("*{0}: {1}\n".format(k, pex_runset[k]))
# write the rules file
f = open(OPTS.openram_temp + "pex_rules", "w")
f.write('// Rules file, created by OpenRAM, (c) Bob Vanhoof\n')
f.write('\n')
f.write('LAYOUT PATH "' + OPTS.openram_temp + cell_name + '.gds"\n')
f.write('LAYOUT PRIMARY ' + cell_name + '\n')
f.write('LAYOUT SYSTEM GDSII\n')
f.write('\n')
f.write('SOURCE PATH "' + OPTS.openram_temp + cell_name + '.sp"\n')
f.write('SOURCE PRIMARY ' + cell_name +'\n')
f.write('SOURCE SYSTEM SPICE\n')
f.write('SOURCE CASE YES\n')
f.write('\n')
f.write('MASK SVDB DIRECTORY "svdb" QUERY XRC\n')
f.write('\n')
f.write('LVS REPORT "' + OPTS.openram_temp + cell_name + '.pex.report"\n')
f.write('LVS REPORT OPTION NONE\n')
f.write('LVS FILTER UNUSED OPTION NONE SOURCE\n')
f.write('LVS FILTER UNUSED OPTION NONE LAYOUT\n')
f.write('LVS POWER NAME vdd\n')
f.write('LVS GROUND NAME gnd\n')
f.write('LVS RECOGNIZE GATES ALL\n')
f.write('LVS CELL SUPPLY YES\n')
f.write('LVS PUSH DEVICES SEPARATE PROPERTIES YES\n')
f.write('\n')
f.write('PEX NETLIST "' + output + '" HSPICE 1 SOURCENAMES GROUND gnd\n')
f.write('PEX REDUCE ANALOG NO\n')
f.write('PEX NETLIST UPPERCASE KEYWORDS NO\n')
f.write('PEX NETLIST VIRTUAL CONNECT YES\n')
f.write('PEX NETLIST NOXREF NET NAMES YES\n')
f.write('PEX NETLIST MUTUAL RESISTANCE YES\n')
f.write('PEX NETLIST EXPORT PORTS YES\n')
f.write('PEX PROBE FILE "probe_file"\n')
f.write('\n')
f.write('VIRTUAL CONNECT COLON NO\n')
f.write('VIRTUAL CONNECT REPORT NO\n')
f.write('VIRTUAL CONNECT NAME vdd gnd\n')
f.write('\n')
f.write('DRC ICSTATION YES\n')
f.write('\n')
f.write('INCLUDE "'+ pex_rules +'"\n')
f.close()
# write probe file
#TODO: get from cell name
f = open(OPTS.openram_temp + "probe_file", "w")
f.write('CELL cell_1rw\n')
f.write(' Q 0.100 0.510 11\n')
f.write(' Q_bar 0.520 0.510 11\n')
f.close()
# Create an auxiliary script to run calibre with the runset
run_file = output_path + "run_pex.sh"
f = open(run_file, "w")
f.write("#!/bin/sh\n")
cmd = "{0} -gui -pex pex_runset -batch".format(OPTS.pex_exe[1])
cmd = "{0} -lvs -hier -genhcells -spice svdb/{1}.sp -turbo -hyper cmp {2}".format(OPTS.pex_exe[1],
cell_name,
'pex_rules')
f.write(cmd)
f.write("\n")
cmd = "sed '/dummy/d' svdb/{0}.hcells | sed '/replica_column/d' | sed '/replica_cell/d' > hcell_file".format(cell_name)
f.write(cmd)
f.write("\n")
cmd = "{0} -xrc -pdb -turbo -xcell hcell_file -full -rc {1}".format(OPTS.pex_exe[1], 'pex_rules')
f.write(cmd)
f.write("\n")
cmd = "{0} -xrc -fmt -full {1}".format(OPTS.pex_exe[1],'pex_rules')
f.write(cmd)
f.write("\n")
f.close()
os.system("chmod u+x {}".format(run_file))
return pex_runset
return None
def run_drc(cell_name, gds_name, sp_name, extract=False, final_verification=False):
@ -194,6 +238,9 @@ def run_drc(cell_name, gds_name, sp_name, extract=False, final_verification=Fals
global num_drc_runs
num_drc_runs += 1
# Copy file to local dir if it isn't already
#if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)):
# hutil.copy(gds_name, OPTS.openram_temp)
drc_runset = write_drc_script(cell_name, gds_name, extract, final_verification, OPTS.openram_temp)
@ -237,6 +284,12 @@ def run_lvs(cell_name, gds_name, sp_name, final_verification=False):
lvs_runset = write_lvs_script(cell_name, gds_name, sp_name, final_verification, OPTS.openram_temp)
# Copy file to local dir if it isn't already
#if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)):
# shutil.copy(gds_name, OPTS.openram_temp)
#if not os.path.isfile(OPTS.openram_temp + os.path.basename(sp_name)):
# shutil.copy(sp_name, OPTS.openram_temp)
(outfile, errfile, resultsfile) = run_script(cell_name, "lvs")
# check the result for these lines in the summary:
@ -318,6 +371,12 @@ def run_pex(cell_name, gds_name, sp_name, output=None, final_verification=False)
write_pex_script(cell_name, True, output, final_verification, OPTS.openram_temp)
# Copy file to local dir if it isn't already
#if not os.path.isfile(OPTS.openram_temp + os.path.basename(gds_name)):
# shutil.copy(gds_name, OPTS.openram_temp)
#if not os.path.isfile(OPTS.openram_temp + os.path.basename(sp_name)):
# shutil.copy(sp_name, OPTS.openram_temp)
(outfile, errfile, resultsfile) = run_script(cell_name, "pex")