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,6 +138,7 @@ 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
if OPTS.tech_name != "s8":
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")
nmos_required_mults = max(int(ceil(self.nmos_width / nmos_height_available)), 1) nmos_required_mults = max(int(ceil(self.nmos_width / nmos_height_available)), 1)
@ -158,6 +163,34 @@ class pinv(pgate.pgate):
# "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. """