From 1f094b03bc3f2d962ebd06138cfbade446eac82c Mon Sep 17 00:00:00 2001 From: jcirimel Date: Sat, 18 Apr 2020 05:26:39 -0700 Subject: [PATCH] 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. """