mirror of https://github.com/VLSIDA/OpenRAM.git
Fix wrong pin order on pnand2 LVS problem.
This commit is contained in:
parent
8fcc8a1674
commit
a56fa0e787
|
|
@ -250,9 +250,9 @@ class hierarchical_predecode(design.design):
|
|||
index_lst= nand_input_line_combination[k]
|
||||
|
||||
if self.number_of_inputs == 2:
|
||||
gate_lst = ["A","B"]
|
||||
gate_lst = ["B","A"]
|
||||
else:
|
||||
gate_lst = ["A","B","C"]
|
||||
gate_lst = ["C","B","A"]
|
||||
|
||||
# this will connect pins A,B or A,B,C
|
||||
for rail_pin,gate_pin in zip(index_lst,gate_lst):
|
||||
|
|
|
|||
|
|
@ -136,13 +136,13 @@ class pnand2(pgate.pgate):
|
|||
self.nmos1_inst=self.add_inst(name="pnand2_nmos1",
|
||||
mod=self.nmos,
|
||||
offset=nmos1_pos)
|
||||
self.connect_inst(["Z", "A", "net1", "gnd"])
|
||||
self.connect_inst(["Z", "B", "net1", "gnd"])
|
||||
|
||||
self.nmos2_pos = nmos1_pos + self.overlap_offset
|
||||
self.nmos2_inst=self.add_inst(name="pnand2_nmos2",
|
||||
mod=self.nmos,
|
||||
offset=self.nmos2_pos)
|
||||
self.connect_inst(["net1", "B", "gnd", "gnd"])
|
||||
self.connect_inst(["net1", "A", "gnd", "gnd"])
|
||||
|
||||
# Output position will be in between the PMOS and NMOS
|
||||
self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))
|
||||
|
|
|
|||
|
|
@ -24,7 +24,9 @@ class pnand3(pgate.pgate):
|
|||
pgate.pgate.__init__(self, name)
|
||||
debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size))
|
||||
|
||||
self.nmos_size = 3*size
|
||||
# We have trouble pitch matching a 3x sizes to the bitcell...
|
||||
# If we relax this, we could size this better.
|
||||
self.nmos_size = 2*size
|
||||
self.pmos_size = parameter["beta"]*size
|
||||
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
|
||||
self.pmos_width = self.pmos_size*drc["minwidth_tx"]
|
||||
|
|
@ -89,11 +91,12 @@ class pnand3(pgate.pgate):
|
|||
# This will help with the wells and the input/output placement
|
||||
self.output_pos = vector(0,0.5*self.height)
|
||||
|
||||
# This is the extra space needed to ensure DRC rules to the active contacts
|
||||
nmos = ptx(tx_type="nmos")
|
||||
extra_contact_space = max(-nmos.get_pin("D").by(),0)
|
||||
# This is a poly-to-poly of a flipped cell
|
||||
# This is extra liberal for pnand3 because we know there are big transistor sizes
|
||||
# and so contacts won't interfere with the rails. Therefore, ignore metal spacing.
|
||||
# We need to do this to fit the 3 inputs in with M2M3 via accessibility.
|
||||
self.top_bottom_space = max(drc["poly_extend_active"], self.poly_space)
|
||||
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
|
||||
drc["poly_extend_active"], self.poly_space)
|
||||
|
||||
def add_supply_rails(self):
|
||||
""" Add vdd/gnd rails to the top and bottom. """
|
||||
|
|
@ -137,7 +140,7 @@ class pnand3(pgate.pgate):
|
|||
self.nmos1_inst=self.add_inst(name="pnand3_nmos1",
|
||||
mod=self.nmos,
|
||||
offset=nmos1_pos)
|
||||
self.connect_inst(["Z", "A", "net1", "gnd"])
|
||||
self.connect_inst(["Z", "C", "net1", "gnd"])
|
||||
|
||||
nmos2_pos = nmos1_pos + self.overlap_offset
|
||||
self.nmos2_inst=self.add_inst(name="pnand3_nmos2",
|
||||
|
|
@ -150,7 +153,7 @@ class pnand3(pgate.pgate):
|
|||
self.nmos3_inst=self.add_inst(name="pnand3_nmos3",
|
||||
mod=self.nmos,
|
||||
offset=self.nmos3_pos)
|
||||
self.connect_inst(["net2", "C", "gnd", "gnd"])
|
||||
self.connect_inst(["net2", "A", "gnd", "gnd"])
|
||||
|
||||
# This should be placed at the top of the NMOS well
|
||||
self.well_pos = vector(0,self.nmos1_inst.uy())
|
||||
|
|
|
|||
|
|
@ -74,8 +74,8 @@ def write_magic_script(cell_name, gds_name, extract=False):
|
|||
f.write("#!/bin/sh\n")
|
||||
f.write("{} -dnull -noconsole << EOF\n".format(OPTS.drc_exe[1]))
|
||||
f.write("tech load SCN3ME_SUBM.30\n")
|
||||
f.write("scalegrid 1 2\n")
|
||||
f.write("gds rescale no\n")
|
||||
#gf.write("scalegrid 1 8\n")
|
||||
#f.write("gds rescale no\n")
|
||||
f.write("gds polygon subcell true\n")
|
||||
f.write("gds warning default\n")
|
||||
f.write("gds read {}\n".format(gds_name))
|
||||
|
|
@ -87,6 +87,7 @@ def write_magic_script(cell_name, gds_name, extract=False):
|
|||
f.write("drc count\n")
|
||||
if extract:
|
||||
f.write("extract\n")
|
||||
f.write("ext2spice hierarchy on\n")
|
||||
f.write("ext2spice scale off\n")
|
||||
# Can choose hspice, ngspice, or spice3,
|
||||
# but they all seem compatible enough.
|
||||
|
|
@ -107,38 +108,21 @@ def write_netgen_script(cell_name, sp_name):
|
|||
f = open(run_file, "w")
|
||||
f.write("#!/bin/sh\n")
|
||||
f.write("{} -noconsole << EOF\n".format(OPTS.lvs_exe[1]))
|
||||
f.write("readnet {0}{1}.spice\n".format(OPTS.openram_temp,
|
||||
cell_name))
|
||||
f.write("readnet {}.spice\n".format(cell_name))
|
||||
f.write("readnet {}\n".format(sp_name))
|
||||
f.write("ignore class c\n")
|
||||
# default is on
|
||||
#f.write("permute transistors\n")
|
||||
f.write("equate class {{{0}{1}.spice nfet}} {{{2} n}}\n".format(OPTS.openram_temp,
|
||||
cell_name,
|
||||
sp_name))
|
||||
f.write("equate class {{{0}{1}.spice pfet}} {{{2} p}}\n".format(OPTS.openram_temp,
|
||||
cell_name,
|
||||
sp_name))
|
||||
#Do the individual commands rather than the built in script
|
||||
#f.write("lvs {0}.spice {{{1} {0}}}\n".format(cell_name, sp_name))
|
||||
f.write("log file lvs.results\n")
|
||||
f.write("property {{{0}{1}.spice nfet}} remove as ad ps pd\n".format(OPTS.openram_temp,
|
||||
cell_name))
|
||||
f.write("property {{{0}{1}.spice pfet}} remove as ad ps pd\n".format(OPTS.openram_temp,
|
||||
cell_name))
|
||||
f.write("permute transistors\n")
|
||||
f.write("equate class {{{0}.spice nfet}} {{{1} n}}\n".format(cell_name, sp_name))
|
||||
f.write("equate class {{{0}.spice pfet}} {{{1} p}}\n".format(cell_name, sp_name))
|
||||
f.write("property {{{0}.spice nfet}} remove as ad ps pd\n".format(cell_name))
|
||||
f.write("property {{{0}.spice pfet}} remove as ad ps pd\n".format(cell_name))
|
||||
# Allow some flexibility in W size because magic will snap to a lambda grid
|
||||
# This can also cause disconnects unfortunately!
|
||||
# f.write("property {{{0}{1}.spice nfet}} tolerance {{w 0.1}}\n".format(OPTS.openram_temp,
|
||||
# cell_name))
|
||||
# f.write("property {{{0}{1}.spice pfet}} tolerance {{w 0.1}}\n".format(OPTS.openram_temp,
|
||||
# cell_name))
|
||||
f.write("permute default\n")
|
||||
f.write("log start\n")
|
||||
f.write("compare hierarchical {0}{1}.spice {{{2} {1}}}\n".format(OPTS.openram_temp,
|
||||
cell_name,
|
||||
sp_name))
|
||||
f.write("run converge\n")
|
||||
f.write("log end\n")
|
||||
f.write("lvs {0}.spice {{{1} {0}}} setup.tcl lvs.results\n".format(cell_name, sp_name))
|
||||
f.write("quit\n")
|
||||
f.write("EOF\n")
|
||||
f.close()
|
||||
|
|
@ -184,7 +168,7 @@ def run_drc(cell_name, gds_name, extract=False):
|
|||
if errors > 0:
|
||||
for line in results:
|
||||
if "error tiles" in line:
|
||||
debug.info(0,line.rstrip("\n"))
|
||||
debug.info(1,line.rstrip("\n"))
|
||||
debug.error("DRC Errors {0}\t{1}".format(cell_name, errors))
|
||||
else:
|
||||
debug.info(1, "DRC Errors {0}\t{1}".format(cell_name, errors))
|
||||
|
|
@ -237,7 +221,10 @@ def run_lvs(cell_name, gds_name, sp_name):
|
|||
# Fail if they don't match. Something went wrong!
|
||||
if correct == 0:
|
||||
total_errors += 1
|
||||
|
||||
|
||||
# Require pins to match?
|
||||
# Cell pin lists for pnand2_1.spice and pnand2_1 altered to match.
|
||||
|
||||
if total_errors>0:
|
||||
# check the result for these lines in the summary:
|
||||
f = open("{}lvs.results".format(OPTS.openram_temp), "r")
|
||||
|
|
@ -245,7 +232,8 @@ def run_lvs(cell_name, gds_name, sp_name):
|
|||
f.close()
|
||||
# Just print out the whole file, it is short.
|
||||
for e in results:
|
||||
debug.error(e.strip("\n"))
|
||||
debug.info(1,e.strip("\n"))
|
||||
debug.error("LVS mismatch (results in {}lvs.results)".format(OPTS.openram_temp))
|
||||
|
||||
return total_errors
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue