use more optimal discrete pinv sizing

This commit is contained in:
jcirimel 2020-04-18 05:26:39 -07:00
parent 486819ae0d
commit 1f094b03bc
2 changed files with 78 additions and 28 deletions

View File

@ -15,7 +15,7 @@ from vector import vector
from globals import OPTS from globals import OPTS
if(OPTS.tech_name == "s8"): 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): class pgate(design.design):
""" """
@ -323,11 +323,28 @@ class pgate(design.design):
return(selected_bin, scaling_factor) 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)

View File

@ -8,15 +8,19 @@
import contact import contact
import pgate import pgate
import debug import debug
import operator
from tech import drc, parameter, spice from tech import drc, parameter, spice
from vector import vector from vector import vector
from math import ceil from math import ceil
from globals import OPTS from globals import OPTS
from utils import round_to_grid from utils import round_to_grid
from bisect import bisect_left
import logical_effort import logical_effort
from sram_factory import factory from sram_factory import factory
from errors import drc_error from errors import drc_error
if(OPTS.tech_name == "s8"):
from tech import nmos_bins, pmos_bins, accuracy_requirement
class pinv(pgate.pgate): class pinv(pgate.pgate):
""" """
@ -134,30 +138,59 @@ class pinv(pgate.pgate):
# Determine the number of mults for each to fit width # Determine the number of mults for each to fit width
# into available space # into available space
self.nmos_width = self.nmos_size * drc("minwidth_tx") if OPTS.tech_name != "s8":
self.pmos_width = self.pmos_size * drc("minwidth_tx") self.nmos_width = self.nmos_size * drc("minwidth_tx")
nmos_required_mults = max(int(ceil(self.nmos_width / nmos_height_available)), 1) self.pmos_width = self.pmos_size * drc("minwidth_tx")
pmos_required_mults = max(int(ceil(self.pmos_width / pmos_height_available)), 1) nmos_required_mults = max(int(ceil(self.nmos_width / nmos_height_available)), 1)
# The mults must be the same for easy connection of poly pmos_required_mults = max(int(ceil(self.pmos_width / pmos_height_available)), 1)
self.tx_mults = max(nmos_required_mults, pmos_required_mults) # 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 # Recompute each mult width and check it isn't too small
# This could happen if the height is narrow and the size is small # This could happen if the height is narrow and the size is small
# User should pick a bigger size to fix it... # User should pick a bigger size to fix it...
# We also need to round the width to the grid or we will end up # 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 # with LVS property mismatch errors when fingers are not a grid
# length and get rounded in the offset geometry. # length and get rounded in the offset geometry.
self.nmos_width = round_to_grid(self.nmos_width / self.tx_mults) self.nmos_width = round_to_grid(self.nmos_width / self.tx_mults)
# debug.check(self.nmos_width >= drc("minwidth_tx"), # debug.check(self.nmos_width >= drc("minwidth_tx"),
# "Cannot finger NMOS transistors to fit cell height.") # "Cannot finger NMOS transistors to fit cell height.")
if self.nmos_width < drc("minwidth_tx"): if self.nmos_width < drc("minwidth_tx"):
raise drc_error("Cannot finger NMOS transistors to fit cell height.") raise drc_error("Cannot finger NMOS transistors to fit cell height.")
self.pmos_width = round_to_grid(self.pmos_width / self.tx_mults) self.pmos_width = round_to_grid(self.pmos_width / self.tx_mults)
#debug.check(self.pmos_width >= drc("minwidth_tx"), #debug.check(self.pmos_width >= drc("minwidth_tx"),
# "Cannot finger PMOS transistors to fit cell height.") # "Cannot finger PMOS transistors to fit cell height.")
if self.pmos_width < drc("minwidth_tx"): if self.pmos_width < drc("minwidth_tx"):
raise drc_error("Cannot finger NMOS transistors to fit cell height.") 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): def add_ptx(self):
""" Create the PMOS and NMOS transistors. """ """ Create the PMOS and NMOS transistors. """