mirror of
https://github.com/VLSIDA/OpenRAM.git
synced 2026-08-22 14:17:35 +02:00
Fix wrong pin order on pnand2 LVS problem.
This commit is contained in:
@@ -250,9 +250,9 @@ class hierarchical_predecode(design.design):
|
|||||||
index_lst= nand_input_line_combination[k]
|
index_lst= nand_input_line_combination[k]
|
||||||
|
|
||||||
if self.number_of_inputs == 2:
|
if self.number_of_inputs == 2:
|
||||||
gate_lst = ["A","B"]
|
gate_lst = ["B","A"]
|
||||||
else:
|
else:
|
||||||
gate_lst = ["A","B","C"]
|
gate_lst = ["C","B","A"]
|
||||||
|
|
||||||
# this will connect pins A,B or A,B,C
|
# this will connect pins A,B or A,B,C
|
||||||
for rail_pin,gate_pin in zip(index_lst,gate_lst):
|
for rail_pin,gate_pin in zip(index_lst,gate_lst):
|
||||||
|
|||||||
+2
-2
@@ -136,13 +136,13 @@ class pnand2(pgate.pgate):
|
|||||||
self.nmos1_inst=self.add_inst(name="pnand2_nmos1",
|
self.nmos1_inst=self.add_inst(name="pnand2_nmos1",
|
||||||
mod=self.nmos,
|
mod=self.nmos,
|
||||||
offset=nmos1_pos)
|
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_pos = nmos1_pos + self.overlap_offset
|
||||||
self.nmos2_inst=self.add_inst(name="pnand2_nmos2",
|
self.nmos2_inst=self.add_inst(name="pnand2_nmos2",
|
||||||
mod=self.nmos,
|
mod=self.nmos,
|
||||||
offset=self.nmos2_pos)
|
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
|
# 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))
|
self.output_pos = vector(0,0.5*(pmos1_pos.y+nmos1_pos.y+self.nmos.active_height))
|
||||||
|
|||||||
+10
-7
@@ -24,7 +24,9 @@ class pnand3(pgate.pgate):
|
|||||||
pgate.pgate.__init__(self, name)
|
pgate.pgate.__init__(self, name)
|
||||||
debug.info(2, "create pnand3 structure {0} with size of {1}".format(name, size))
|
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.pmos_size = parameter["beta"]*size
|
||||||
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
|
self.nmos_width = self.nmos_size*drc["minwidth_tx"]
|
||||||
self.pmos_width = self.pmos_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
|
# This will help with the wells and the input/output placement
|
||||||
self.output_pos = vector(0,0.5*self.height)
|
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 a poly-to-poly of a flipped cell
|
||||||
# This is extra liberal for pnand3 because we know there are big transistor sizes
|
self.top_bottom_space = max(0.5*self.m1_width + self.m1_space + extra_contact_space,
|
||||||
# and so contacts won't interfere with the rails. Therefore, ignore metal spacing.
|
drc["poly_extend_active"], self.poly_space)
|
||||||
# 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)
|
|
||||||
|
|
||||||
def add_supply_rails(self):
|
def add_supply_rails(self):
|
||||||
""" Add vdd/gnd rails to the top and bottom. """
|
""" 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",
|
self.nmos1_inst=self.add_inst(name="pnand3_nmos1",
|
||||||
mod=self.nmos,
|
mod=self.nmos,
|
||||||
offset=nmos1_pos)
|
offset=nmos1_pos)
|
||||||
self.connect_inst(["Z", "A", "net1", "gnd"])
|
self.connect_inst(["Z", "C", "net1", "gnd"])
|
||||||
|
|
||||||
nmos2_pos = nmos1_pos + self.overlap_offset
|
nmos2_pos = nmos1_pos + self.overlap_offset
|
||||||
self.nmos2_inst=self.add_inst(name="pnand3_nmos2",
|
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",
|
self.nmos3_inst=self.add_inst(name="pnand3_nmos3",
|
||||||
mod=self.nmos,
|
mod=self.nmos,
|
||||||
offset=self.nmos3_pos)
|
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
|
# This should be placed at the top of the NMOS well
|
||||||
self.well_pos = vector(0,self.nmos1_inst.uy())
|
self.well_pos = vector(0,self.nmos1_inst.uy())
|
||||||
|
|||||||
+16
-28
@@ -74,8 +74,8 @@ def write_magic_script(cell_name, gds_name, extract=False):
|
|||||||
f.write("#!/bin/sh\n")
|
f.write("#!/bin/sh\n")
|
||||||
f.write("{} -dnull -noconsole << EOF\n".format(OPTS.drc_exe[1]))
|
f.write("{} -dnull -noconsole << EOF\n".format(OPTS.drc_exe[1]))
|
||||||
f.write("tech load SCN3ME_SUBM.30\n")
|
f.write("tech load SCN3ME_SUBM.30\n")
|
||||||
f.write("scalegrid 1 2\n")
|
#gf.write("scalegrid 1 8\n")
|
||||||
f.write("gds rescale no\n")
|
#f.write("gds rescale no\n")
|
||||||
f.write("gds polygon subcell true\n")
|
f.write("gds polygon subcell true\n")
|
||||||
f.write("gds warning default\n")
|
f.write("gds warning default\n")
|
||||||
f.write("gds read {}\n".format(gds_name))
|
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")
|
f.write("drc count\n")
|
||||||
if extract:
|
if extract:
|
||||||
f.write("extract\n")
|
f.write("extract\n")
|
||||||
|
f.write("ext2spice hierarchy on\n")
|
||||||
f.write("ext2spice scale off\n")
|
f.write("ext2spice scale off\n")
|
||||||
# Can choose hspice, ngspice, or spice3,
|
# Can choose hspice, ngspice, or spice3,
|
||||||
# but they all seem compatible enough.
|
# but they all seem compatible enough.
|
||||||
@@ -107,38 +108,21 @@ def write_netgen_script(cell_name, sp_name):
|
|||||||
f = open(run_file, "w")
|
f = open(run_file, "w")
|
||||||
f.write("#!/bin/sh\n")
|
f.write("#!/bin/sh\n")
|
||||||
f.write("{} -noconsole << EOF\n".format(OPTS.lvs_exe[1]))
|
f.write("{} -noconsole << EOF\n".format(OPTS.lvs_exe[1]))
|
||||||
f.write("readnet {0}{1}.spice\n".format(OPTS.openram_temp,
|
f.write("readnet {}.spice\n".format(cell_name))
|
||||||
cell_name))
|
|
||||||
f.write("readnet {}\n".format(sp_name))
|
f.write("readnet {}\n".format(sp_name))
|
||||||
f.write("ignore class c\n")
|
f.write("ignore class c\n")
|
||||||
# default is on
|
f.write("permute transistors\n")
|
||||||
#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}{1}.spice nfet}} {{{2} n}}\n".format(OPTS.openram_temp,
|
f.write("equate class {{{0}.spice pfet}} {{{1} p}}\n".format(cell_name, sp_name))
|
||||||
cell_name,
|
f.write("property {{{0}.spice nfet}} remove as ad ps pd\n".format(cell_name))
|
||||||
sp_name))
|
f.write("property {{{0}.spice pfet}} remove as ad ps pd\n".format(cell_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))
|
|
||||||
# Allow some flexibility in W size because magic will snap to a lambda grid
|
# Allow some flexibility in W size because magic will snap to a lambda grid
|
||||||
# This can also cause disconnects unfortunately!
|
# This can also cause disconnects unfortunately!
|
||||||
# f.write("property {{{0}{1}.spice nfet}} tolerance {{w 0.1}}\n".format(OPTS.openram_temp,
|
# f.write("property {{{0}{1}.spice nfet}} tolerance {{w 0.1}}\n".format(OPTS.openram_temp,
|
||||||
# cell_name))
|
# cell_name))
|
||||||
# f.write("property {{{0}{1}.spice pfet}} tolerance {{w 0.1}}\n".format(OPTS.openram_temp,
|
# f.write("property {{{0}{1}.spice pfet}} tolerance {{w 0.1}}\n".format(OPTS.openram_temp,
|
||||||
# cell_name))
|
# cell_name))
|
||||||
f.write("permute default\n")
|
f.write("lvs {0}.spice {{{1} {0}}} setup.tcl lvs.results\n".format(cell_name, sp_name))
|
||||||
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("quit\n")
|
f.write("quit\n")
|
||||||
f.write("EOF\n")
|
f.write("EOF\n")
|
||||||
f.close()
|
f.close()
|
||||||
@@ -184,7 +168,7 @@ def run_drc(cell_name, gds_name, extract=False):
|
|||||||
if errors > 0:
|
if errors > 0:
|
||||||
for line in results:
|
for line in results:
|
||||||
if "error tiles" in line:
|
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))
|
debug.error("DRC Errors {0}\t{1}".format(cell_name, errors))
|
||||||
else:
|
else:
|
||||||
debug.info(1, "DRC Errors {0}\t{1}".format(cell_name, errors))
|
debug.info(1, "DRC Errors {0}\t{1}".format(cell_name, errors))
|
||||||
@@ -238,6 +222,9 @@ def run_lvs(cell_name, gds_name, sp_name):
|
|||||||
if correct == 0:
|
if correct == 0:
|
||||||
total_errors += 1
|
total_errors += 1
|
||||||
|
|
||||||
|
# Require pins to match?
|
||||||
|
# Cell pin lists for pnand2_1.spice and pnand2_1 altered to match.
|
||||||
|
|
||||||
if total_errors>0:
|
if total_errors>0:
|
||||||
# check the result for these lines in the summary:
|
# check the result for these lines in the summary:
|
||||||
f = open("{}lvs.results".format(OPTS.openram_temp), "r")
|
f = open("{}lvs.results".format(OPTS.openram_temp), "r")
|
||||||
@@ -245,7 +232,8 @@ def run_lvs(cell_name, gds_name, sp_name):
|
|||||||
f.close()
|
f.close()
|
||||||
# Just print out the whole file, it is short.
|
# Just print out the whole file, it is short.
|
||||||
for e in results:
|
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
|
return total_errors
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user