From a56fa0e7878e04e2d7b17688428166783f11c5f7 Mon Sep 17 00:00:00 2001 From: Matt Guthaus Date: Mon, 29 Jan 2018 15:31:14 -0800 Subject: [PATCH] Fix wrong pin order on pnand2 LVS problem. --- compiler/hierarchical_predecode.py | 4 +-- compiler/pnand2.py | 4 +-- compiler/pnand3.py | 17 ++++++----- compiler/verify/magic.py | 46 +++++++++++------------------- 4 files changed, 31 insertions(+), 40 deletions(-) diff --git a/compiler/hierarchical_predecode.py b/compiler/hierarchical_predecode.py index 6067b79b..b3f3ddc1 100644 --- a/compiler/hierarchical_predecode.py +++ b/compiler/hierarchical_predecode.py @@ -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): diff --git a/compiler/pnand2.py b/compiler/pnand2.py index df3ceca7..dfd89680 100644 --- a/compiler/pnand2.py +++ b/compiler/pnand2.py @@ -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)) diff --git a/compiler/pnand3.py b/compiler/pnand3.py index 0c7b2072..6d0b1e79 100644 --- a/compiler/pnand3.py +++ b/compiler/pnand3.py @@ -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()) diff --git a/compiler/verify/magic.py b/compiler/verify/magic.py index aec94566..c592ed6f 100644 --- a/compiler/verify/magic.py +++ b/compiler/verify/magic.py @@ -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