Fix wrong pin order on pnand2 LVS problem.

This commit is contained in:
Matt Guthaus 2018-01-29 15:31:14 -08:00
parent 8fcc8a1674
commit a56fa0e787
4 changed files with 31 additions and 40 deletions

View File

@ -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):

View File

@ -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))

View File

@ -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())

View File

@ -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