From a0eb9839ad55e33fdbf76d8c5fda0da528104b06 Mon Sep 17 00:00:00 2001 From: jcirimel Date: Thu, 9 Apr 2020 19:39:21 -0700 Subject: [PATCH 01/10] revert units on sp_lib, begin discrete tx simulation --- compiler/characterizer/stimuli.py | 11 +++++++ compiler/pgates/pgate.py | 49 ++++++++++++++++++++++++++++++- compiler/pgates/pinv.py | 3 ++ compiler/pgates/precharge.py | 5 ++++ compiler/pgates/ptx.py | 4 ++- 5 files changed, 70 insertions(+), 2 deletions(-) diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index 58a9e3ed..fc2a106f 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -34,6 +34,10 @@ class stimuli(): self.sf = stim_file (self.process, self.voltage, self.temperature) = corner + try: + self.device_libraries = tech.spice["fet_libraries"][self.process] + except: + debug.info(2, "Not using spice library") self.device_models = tech.spice["fet_models"][self.process] self.sram_name = "Xsram" @@ -247,8 +251,15 @@ class stimuli(): def write_include(self, circuit): """Writes include statements, inputs are lists of model files""" + libraries = self.device_libraries includes = self.device_models + [circuit] self.sf.write("* {} process corner\n".format(self.process)) + for item in list(libraries): + if os.path.isfile(item[0]): + self.sf.write(".lib \"{0}\" {1}\n".format(item[0], item[1])) + else: + debug.error("Could not find spice library: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item[0])) + for item in list(includes): if os.path.isfile(item): self.sf.write(".include \"{0}\"\n".format(item)) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index d83825ea..ba5fef75 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -8,10 +8,14 @@ import contact import design import debug -from tech import layer +import math +from bisect import bisect_left +from tech import layer, drc from vector import vector from globals import OPTS +if(OPTS.tech_name == "s8"): + from tech import nmos_bins, pmos_bins class pgate(design.design): """ @@ -282,5 +286,48 @@ class pgate(design.design): self.width = max(self.nwell_contact.rx(), self.pwell_contact.rx()) + self.m1_space + 0.5 * contact.m1_via.width self.well_width = self.width + 2 * self.nwell_enclose_active # Height is an input parameter, so it is not recomputed. + + def bin_width(self, tx_type, target_width): + + if tx_type == "nmos": + bins = nmos_bins[drc("minwidth_poly")] + elif tx_type == "pmos": + bins = pmos_bins[drc("minwidth_poly")] + else: + debug.error("invalid tx type") + + + bins = bins[0:bisect_left(bins, target_width) + 1] + if len(bins) == 1: + selected_bin = bins[0] + scaling_factor = 1 + scaled_bin = bins[0] + + else: + scaled_bins = [] + scaling_factors = [] + for width in bins[0:-1]: + m = math.ceil(target_width / width) + scaling_factors.append(m) + scaled_bins.append(m * width) + + scaled_bins.append(bins[-1]) + scaling_factors.append(1) + select = bisect_left(scaled_bins, target_width) + + selected_bin = bins[select] + scaling_factor = scaling_factors[select] + scaled_bin = scaled_bins[select] + + debug.info(2, "binning {0} tx, target: {4}, found {1} x {2} = {3}".format(tx_type, selected_bin, scaling_factor, scaled_bin, target_width)) + + return(selected_bin, scaling_factor) + + + + + + + diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index 3c2e41a2..1ccad6ca 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -81,6 +81,9 @@ class pinv(pgate.pgate): self.tx_mults = 1 self.nmos_width = self.nmos_size * drc("minwidth_tx") self.pmos_width = self.pmos_size * drc("minwidth_tx") + if OPTS.tech_name == "s8": + (self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width) + (self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width) return # Do a quick sanity check and bail if unlikely feasible height diff --git a/compiler/pgates/precharge.py b/compiler/pgates/precharge.py index afe14a05..45128421 100644 --- a/compiler/pgates/precharge.py +++ b/compiler/pgates/precharge.py @@ -8,6 +8,7 @@ import contact import design import debug +from pgate import pgate from tech import parameter from vector import vector from globals import OPTS @@ -28,6 +29,7 @@ class precharge(design.design): self.bitcell = factory.create(module_type="bitcell") self.beta = parameter["beta"] self.ptx_width = self.beta * parameter["min_tx_size"] + self.ptx_mults = 1 self.width = self.bitcell.width self.bitcell_bl = bitcell_bl self.bitcell_br = bitcell_br @@ -77,8 +79,11 @@ class precharge(design.design): """ Initializes the upper and lower pmos """ + if(OPTS.tech_name == "s8"): + (self.ptx_width, self.ptx_mults) = pgate.bin_width(self, "pmos", self.ptx_width) self.pmos = factory.create(module_type="ptx", width=self.ptx_width, + mults=self.ptx_mults, tx_type="pmos") self.add_mod(self.pmos) diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index 357e1ce4..ffd61a48 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -107,7 +107,9 @@ class ptx(design.design): # be decided in the layout later. area_sd = 2.5 * self.poly_width * self.tx_width perimeter_sd = 2 * self.poly_width + 2 * self.tx_width - if OPTS.tech_name == "s8": + + + if OPTS.tech_name == None: print("here {0}".format(self.name)) # s8 technology is in microns main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type], From afcb5174ac877ae66e6844c2a20ec08bb04acee8 Mon Sep 17 00:00:00 2001 From: jcirimel Date: Sat, 11 Apr 2020 01:19:04 -0700 Subject: [PATCH 02/10] discrete dff tests working --- compiler/characterizer/stimuli.py | 14 ++++++++------ compiler/pgates/ptx.py | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/compiler/characterizer/stimuli.py b/compiler/characterizer/stimuli.py index fc2a106f..b5a143cf 100644 --- a/compiler/characterizer/stimuli.py +++ b/compiler/characterizer/stimuli.py @@ -251,14 +251,16 @@ class stimuli(): def write_include(self, circuit): """Writes include statements, inputs are lists of model files""" - libraries = self.device_libraries + includes = self.device_models + [circuit] self.sf.write("* {} process corner\n".format(self.process)) - for item in list(libraries): - if os.path.isfile(item[0]): - self.sf.write(".lib \"{0}\" {1}\n".format(item[0], item[1])) - else: - debug.error("Could not find spice library: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item[0])) + if OPTS.tech_name == "s8": + libraries = self.device_libraries + for item in list(libraries): + if os.path.isfile(item[0]): + self.sf.write(".lib \"{0}\" {1}\n".format(item[0], item[1])) + else: + debug.error("Could not find spice library: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item[0])) for item in list(includes): if os.path.isfile(item): diff --git a/compiler/pgates/ptx.py b/compiler/pgates/ptx.py index ffd61a48..d51f42be 100644 --- a/compiler/pgates/ptx.py +++ b/compiler/pgates/ptx.py @@ -109,7 +109,7 @@ class ptx(design.design): perimeter_sd = 2 * self.poly_width + 2 * self.tx_width - if OPTS.tech_name == None: + if OPTS.tech_name == "s8": print("here {0}".format(self.name)) # s8 technology is in microns main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type], From 5f4ed47c57e9ec62e4f25c6426664d0c26f68543 Mon Sep 17 00:00:00 2001 From: jcirimel Date: Mon, 13 Apr 2020 20:48:34 -0700 Subject: [PATCH 03/10] netlist only discrete simulating --- compiler/pgates/pnand2.py | 5 +++++ compiler/pgates/pnand3.py | 6 +++++- compiler/pgates/pnor2.py | 4 ++++ 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/compiler/pgates/pnand2.py b/compiler/pgates/pnand2.py index 4a813269..22a03b6d 100644 --- a/compiler/pgates/pnand2.py +++ b/compiler/pgates/pnand2.py @@ -9,6 +9,7 @@ import contact import pgate import debug from tech import drc, parameter, spice +from globals import OPTS from vector import vector import logical_effort from sram_factory import factory @@ -37,6 +38,10 @@ class pnand2(pgate.pgate): debug.check(size == 1, "Size 1 pnand2 is only supported now.") self.tx_mults = 1 + if OPTS.tech_name == "s8": + (self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width) + (self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width) + # Creates the netlist and layout pgate.pgate.__init__(self, name, height) diff --git a/compiler/pgates/pnand3.py b/compiler/pgates/pnand3.py index cc6fd0f8..c93c867f 100644 --- a/compiler/pgates/pnand3.py +++ b/compiler/pgates/pnand3.py @@ -12,7 +12,7 @@ from tech import drc, parameter, spice from vector import vector import logical_effort from sram_factory import factory - +from globals import OPTS class pnand3(pgate.pgate): """ @@ -40,6 +40,10 @@ class pnand3(pgate.pgate): "Size 1 pnand3 is only supported now.") self.tx_mults = 1 + if OPTS.tech_name == "s8": + (self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width) + (self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width) + # Creates the netlist and layout pgate.pgate.__init__(self, name, height) diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index 75840f26..47c1cc16 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -36,6 +36,10 @@ class pnor2(pgate.pgate): debug.check(size==1, "Size 1 pnor2 is only supported now.") self.tx_mults = 1 + if OPTS.tech_name == "s8": + (self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width) + (self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width) + # Creates the netlist and layout pgate.pgate.__init__(self, name, height) From 6c1c72c520d096775ca784569329b9c269cf207c Mon Sep 17 00:00:00 2001 From: jcirimel Date: Wed, 15 Apr 2020 04:09:58 -0700 Subject: [PATCH 04/10] fix pgates binning off-by-one --- compiler/pgates/pgate.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index ba5fef75..de513cc3 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -300,24 +300,24 @@ class pgate(design.design): bins = bins[0:bisect_left(bins, target_width) + 1] if len(bins) == 1: selected_bin = bins[0] - scaling_factor = 1 - scaled_bin = bins[0] + scaling_factor = math.ceil(target_width / width) + scaled_bin = bins[0] * scaling_factor else: scaled_bins = [] scaling_factors = [] + scaled_bins.append(bins[-1]) + scaling_factors.append(1) for width in bins[0:-1]: m = math.ceil(target_width / width) scaling_factors.append(m) scaled_bins.append(m * width) - scaled_bins.append(bins[-1]) - scaling_factors.append(1) select = bisect_left(scaled_bins, target_width) - - selected_bin = bins[select] scaling_factor = scaling_factors[select] scaled_bin = scaled_bins[select] + select = (select + 1) % len(scaled_bins) + selected_bin = bins[select] debug.info(2, "binning {0} tx, target: {4}, found {1} x {2} = {3}".format(tx_type, selected_bin, scaling_factor, scaled_bin, target_width)) From a158ad1e81144c21c6b1e0b680cc38f58fdad01d Mon Sep 17 00:00:00 2001 From: jcirimel Date: Fri, 17 Apr 2020 14:24:52 -0700 Subject: [PATCH 05/10] add missing import --- compiler/pgates/pnor2.py | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/pgates/pnor2.py b/compiler/pgates/pnor2.py index 47c1cc16..b1899b4c 100644 --- a/compiler/pgates/pnor2.py +++ b/compiler/pgates/pnor2.py @@ -8,6 +8,7 @@ import contact import pgate import debug +from globals import OPTS from tech import drc, parameter, spice from vector import vector from sram_factory import factory From 486819ae0d1d11281e1f5544bc0a670c56632627 Mon Sep 17 00:00:00 2001 From: jcirimel Date: Fri, 17 Apr 2020 15:27:36 -0700 Subject: [PATCH 06/10] fix width bin typo --- compiler/pgates/pgate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index de513cc3..d3084146 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -300,7 +300,7 @@ class pgate(design.design): bins = bins[0:bisect_left(bins, target_width) + 1] if len(bins) == 1: selected_bin = bins[0] - scaling_factor = math.ceil(target_width / width) + scaling_factor = math.ceil(target_width / selected_bin) scaled_bin = bins[0] * scaling_factor else: From 1f094b03bc3f2d962ebd06138cfbade446eac82c Mon Sep 17 00:00:00 2001 From: jcirimel Date: Sat, 18 Apr 2020 05:26:39 -0700 Subject: [PATCH 07/10] use more optimal discrete pinv sizing --- compiler/pgates/pgate.py | 29 +++++++++++---- compiler/pgates/pinv.py | 77 ++++++++++++++++++++++++++++------------ 2 files changed, 78 insertions(+), 28 deletions(-) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index d3084146..a49be6a0 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -15,7 +15,7 @@ from vector import vector from globals import OPTS if(OPTS.tech_name == "s8"): - from tech import nmos_bins, pmos_bins + from tech import nmos_bins, pmos_bins, accuracy_requirement class pgate(design.design): """ @@ -323,11 +323,28 @@ class pgate(design.design): return(selected_bin, scaling_factor) + def permute_widths(self, tx_type, target_width): - - - + if tx_type == "nmos": + bins = nmos_bins[drc("minwidth_poly")] + elif tx_type == "pmos": + bins = pmos_bins[drc("minwidth_poly")] + else: + debug.error("invalid tx type") - - + bins = bins[0:bisect_left(bins, target_width) + 1] + + if len(bins) == 1: + selected_bins = (bins[0], math.ceil(target_width / bins[0])) + else: + scaled_bins = [] + scaled_bins.append((bins[-1], 1)) + for width in bins[:-1]: + m = math.ceil(target_width / width) + scaled_bins.append((m * width, m)) + + return(scaled_bins) + + def bin_accuracy(self, ideal_width, width): + return abs(1-(ideal_width - width)/ideal_width) \ No newline at end of file diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index 5e44ecff..07f724e0 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -8,15 +8,19 @@ import contact import pgate import debug +import operator from tech import drc, parameter, spice from vector import vector from math import ceil from globals import OPTS from utils import round_to_grid +from bisect import bisect_left import logical_effort from sram_factory import factory from errors import drc_error +if(OPTS.tech_name == "s8"): + from tech import nmos_bins, pmos_bins, accuracy_requirement class pinv(pgate.pgate): """ @@ -134,30 +138,59 @@ class pinv(pgate.pgate): # Determine the number of mults for each to fit width # into available space - self.nmos_width = self.nmos_size * drc("minwidth_tx") - self.pmos_width = self.pmos_size * drc("minwidth_tx") - nmos_required_mults = max(int(ceil(self.nmos_width / nmos_height_available)), 1) - pmos_required_mults = max(int(ceil(self.pmos_width / pmos_height_available)), 1) - # The mults must be the same for easy connection of poly - self.tx_mults = max(nmos_required_mults, pmos_required_mults) + if OPTS.tech_name != "s8": + self.nmos_width = self.nmos_size * drc("minwidth_tx") + self.pmos_width = self.pmos_size * drc("minwidth_tx") + nmos_required_mults = max(int(ceil(self.nmos_width / nmos_height_available)), 1) + pmos_required_mults = max(int(ceil(self.pmos_width / pmos_height_available)), 1) + # The mults must be the same for easy connection of poly + self.tx_mults = max(nmos_required_mults, pmos_required_mults) - # Recompute each mult width and check it isn't too small - # This could happen if the height is narrow and the size is small - # User should pick a bigger size to fix it... - # We also need to round the width to the grid or we will end up - # with LVS property mismatch errors when fingers are not a grid - # length and get rounded in the offset geometry. - self.nmos_width = round_to_grid(self.nmos_width / self.tx_mults) - # debug.check(self.nmos_width >= drc("minwidth_tx"), - # "Cannot finger NMOS transistors to fit cell height.") - if self.nmos_width < drc("minwidth_tx"): - raise drc_error("Cannot finger NMOS transistors to fit cell height.") + # Recompute each mult width and check it isn't too small + # This could happen if the height is narrow and the size is small + # User should pick a bigger size to fix it... + # We also need to round the width to the grid or we will end up + # with LVS property mismatch errors when fingers are not a grid + # length and get rounded in the offset geometry. + self.nmos_width = round_to_grid(self.nmos_width / self.tx_mults) + # debug.check(self.nmos_width >= drc("minwidth_tx"), + # "Cannot finger NMOS transistors to fit cell height.") + if self.nmos_width < drc("minwidth_tx"): + raise drc_error("Cannot finger NMOS transistors to fit cell height.") - self.pmos_width = round_to_grid(self.pmos_width / self.tx_mults) - #debug.check(self.pmos_width >= drc("minwidth_tx"), - # "Cannot finger PMOS transistors to fit cell height.") - if self.pmos_width < drc("minwidth_tx"): - raise drc_error("Cannot finger NMOS transistors to fit cell height.") + self.pmos_width = round_to_grid(self.pmos_width / self.tx_mults) + #debug.check(self.pmos_width >= drc("minwidth_tx"), + # "Cannot finger PMOS transistors to fit cell height.") + if self.pmos_width < drc("minwidth_tx"): + raise drc_error("Cannot finger NMOS transistors to fit cell height.") + else: + self.nmos_width = self.nmos_size * drc("minwidth_tx") + self.pmos_width = self.pmos_size * drc("minwidth_tx") + nmos_bins = self.permute_widths("nmos", self.nmos_width) + pmos_bins = self.permute_widths("pmos", self.pmos_width) + + valid_pmos = [] + for bin in pmos_bins: + if self.bin_accuracy(self.pmos_width, bin[0]) > accuracy_requirement: + valid_pmos.append(bin) + valid_pmos.sort(key = operator.itemgetter(1)) + + valid_nmos = [] + for bin in nmos_bins: + if self.bin_accuracy(self.nmos_width, bin[0]) > accuracy_requirement: + valid_nmos.append(bin) + valid_nmos.sort(key = operator.itemgetter(1)) + + for bin in valid_pmos: + if bin[0]/bin[1] < pmos_height_available: + self.pmos_width = valid_nmos[0][0] + self.tx_mults = valid_pmos[0][1] + break + + for bin in valid_nmos: + if bin[0]/bin[1] < nmos_height_available: + self.nmos_width = valid_nmos[0][0] + break def add_ptx(self): """ Create the PMOS and NMOS transistors. """ From 85bc801689a5afbdb5f79d59a6c6cda605df3159 Mon Sep 17 00:00:00 2001 From: jcirimel Date: Sat, 18 Apr 2020 05:34:55 -0700 Subject: [PATCH 08/10] fix pinv drc bug --- compiler/pgates/pinv.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/compiler/pgates/pinv.py b/compiler/pgates/pinv.py index 07f724e0..d3062cba 100644 --- a/compiler/pgates/pinv.py +++ b/compiler/pgates/pinv.py @@ -183,14 +183,17 @@ class pinv(pgate.pgate): for bin in valid_pmos: if bin[0]/bin[1] < pmos_height_available: - self.pmos_width = valid_nmos[0][0] - self.tx_mults = valid_pmos[0][1] + self.pmos_width = bin[0]/bin[1] + pmos_mults = valid_pmos[0][1] break for bin in valid_nmos: if bin[0]/bin[1] < nmos_height_available: - self.nmos_width = valid_nmos[0][0] + self.nmos_width = bin[0]/bin[1] + nmos_mults = valid_pmos[0][1] break + + self.tx_mults = max(pmos_mults, nmos_mults) def add_ptx(self): """ Create the PMOS and NMOS transistors. """ From add9ec7b2836677ba46e296d48f6bf4fe2837608 Mon Sep 17 00:00:00 2001 From: jcirimel Date: Sat, 18 Apr 2020 05:42:23 -0700 Subject: [PATCH 09/10] remove excess newlines --- compiler/pgates/pgate.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index a49be6a0..f3fc9abc 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -296,7 +296,6 @@ class pgate(design.design): else: debug.error("invalid tx type") - bins = bins[0:bisect_left(bins, target_width) + 1] if len(bins) == 1: selected_bin = bins[0] @@ -330,11 +329,8 @@ class pgate(design.design): elif tx_type == "pmos": bins = pmos_bins[drc("minwidth_poly")] else: - debug.error("invalid tx type") - - + debug.error("invalid tx type") bins = bins[0:bisect_left(bins, target_width) + 1] - if len(bins) == 1: selected_bins = (bins[0], math.ceil(target_width / bins[0])) else: From f590ecf83c2f1f318982a3152771e51cc9edef71 Mon Sep 17 00:00:00 2001 From: jcirimel Date: Sat, 18 Apr 2020 05:51:21 -0700 Subject: [PATCH 10/10] fix minimum pinv sizing --- compiler/pgates/pgate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/pgates/pgate.py b/compiler/pgates/pgate.py index f3fc9abc..a942b35f 100644 --- a/compiler/pgates/pgate.py +++ b/compiler/pgates/pgate.py @@ -332,7 +332,7 @@ class pgate(design.design): debug.error("invalid tx type") bins = bins[0:bisect_left(bins, target_width) + 1] if len(bins) == 1: - selected_bins = (bins[0], math.ceil(target_width / bins[0])) + scaled_bins = [(bins[0], math.ceil(target_width / bins[0]))] else: scaled_bins = [] scaled_bins.append((bins[-1], 1))