Clean up binning. Fix mults to 1 for certain gates.

This commit is contained in:
mrg 2020-07-15 17:15:42 -07:00
parent bb8157b3b7
commit c7bc01c3a9
8 changed files with 70 additions and 63 deletions

View File

@ -372,66 +372,78 @@ class pgate(design.design):
self.width = width self.width = width
@staticmethod @staticmethod
def bin_width(tx_type, target_width): def best_bin(tx_type, target_width):
"""
Determine the width transistor that meets the accuracy requirement and is larger than target_width.
"""
if tx_type == "nmos": # Find all of the relavent scaled bins and multiples
bins = nmos_bins[drc("minwidth_poly")] scaled_bins = pgate.scaled_bins(tx_type, target_width)
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] for (scaled_width, multiple) in scaled_bins:
if len(bins) == 1: if abs(target_width - scaled_width) / target_width <= 1 - OPTS.accuracy_requirement:
selected_bin = bins[0]
scaling_factor = math.ceil(target_width / selected_bin)
scaled_bin = bins[0] * scaling_factor
else:
base_bins = []
scaled_bins = []
scaling_factors = []
for width in bins:
m = math.ceil(target_width / width)
base_bins.append(width)
scaling_factors.append(m)
scaled_bins.append(m * width)
select = -1
for i in reversed(range(0, len(scaled_bins))):
if abs(target_width - scaled_bins[i])/target_width <= 1-OPTS.accuracy_requirement:
select = i
break break
if select == -1: else:
debug.error("failed to bin tx size {}, try reducing accuracy requirement".format(target_width), 1) debug.error("failed to bin tx size {}, try reducing accuracy requirement".format(target_width), 1)
scaling_factor = scaling_factors[select]
scaled_bin = scaled_bins[select]
selected_bin = base_bins[select]
debug.info(2, "binning {0} tx, target: {4}, found {1} x {2} = {3}".format(tx_type, selected_bin, scaling_factor, selected_bin * scaling_factor, target_width)) debug.info(2, "binning {0} tx, target: {4}, found {1} x {2} = {3}".format(tx_type,
multiple,
scaled_width / multiple,
scaled_width,
target_width))
return(selected_bin, scaling_factor) return(scaled_width / multiple, multiple)
def permute_widths(self, tx_type, target_width):
@staticmethod
def scaled_bins(tx_type, target_width):
"""
Determine a set of widths and multiples that could be close to the right size
sorted by the fewest number of fingers.
"""
if tx_type == "nmos": if tx_type == "nmos":
bins = nmos_bins[drc("minwidth_poly")] bins = nmos_bins[drc("minwidth_poly")]
elif tx_type == "pmos": elif tx_type == "pmos":
bins = pmos_bins[drc("minwidth_poly")] bins = pmos_bins[drc("minwidth_poly")]
else: else:
debug.error("invalid tx type") debug.error("invalid tx type")
# Prune out bins that are too big, except for one bigger
bins = bins[0:bisect_left(bins, target_width) + 1] bins = bins[0:bisect_left(bins, target_width) + 1]
# Determine multiple of target width for each bin
if len(bins) == 1: if len(bins) == 1:
scaled_bins = [(bins[0], math.ceil(target_width / bins[0]))] scaled_bins = [(bins[0], math.ceil(target_width / bins[0]))]
else: else:
scaled_bins = [] scaled_bins = []
# Add the biggest size as 1x multiple
scaled_bins.append((bins[-1], 1)) scaled_bins.append((bins[-1], 1))
for width in bins[:-1]: # Compute discrete multiple of other sizes
m = math.ceil(target_width / width) for width in reversed(bins[:-1]):
scaled_bins.append((m * width, m)) multiple = math.ceil(target_width / width)
scaled_bins.append((multiple * width, multiple))
return(scaled_bins) return(scaled_bins)
def bin_accuracy(self, ideal_width, width): @staticmethod
return 1-abs((ideal_width - width)/ideal_width) def nearest_bin(tx_type, target_width):
"""
Determine the nearest width to the given target_width
while assuming a single multiple.
"""
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")
# Find the next larger bin
bin_loc = bisect_left(bins, target_width)
if bin_loc < len(bins):
return bins[bin_loc]
else:
return bins[-1]
@staticmethod
def bin_accuracy(ideal_width, width):
return 1 - abs((ideal_width - width) / ideal_width)

View File

@ -14,14 +14,10 @@ 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 == "sky130"):
from tech import nmos_bins, pmos_bins
class pinv(pgate.pgate): class pinv(pgate.pgate):
""" """
@ -164,8 +160,8 @@ class pinv(pgate.pgate):
else: else:
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_bins = self.permute_widths("nmos", self.nmos_width) nmos_bins = self.scaled_bins("nmos", self.nmos_width)
pmos_bins = self.permute_widths("pmos", self.pmos_width) pmos_bins = self.scaled_bins("pmos", self.pmos_width)
valid_pmos = [] valid_pmos = []
for bin in pmos_bins: for bin in pmos_bins:

View File

@ -13,6 +13,7 @@ from vector import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
class pinv_dec(pinv.pinv): class pinv_dec(pinv.pinv):
""" """
This is another version of pinv but with layout for the decoder. This is another version of pinv but with layout for the decoder.
@ -50,9 +51,8 @@ class pinv_dec(pinv.pinv):
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")
if OPTS.tech_name == "sky130": if OPTS.tech_name == "sky130":
(self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width) self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
(self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width) self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
return
# Over-ride the route input gate to call the horizontal version. # Over-ride the route input gate to call the horizontal version.
# Other top-level netlist and layout functions are not changed. # Other top-level netlist and layout functions are not changed.

View File

@ -39,8 +39,8 @@ class pnand2(pgate.pgate):
self.tx_mults = 1 self.tx_mults = 1
if OPTS.tech_name == "sky130": if OPTS.tech_name == "sky130":
(self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width) self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
(self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width) self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
# Creates the netlist and layout # Creates the netlist and layout
pgate.pgate.__init__(self, name, height, add_wells) pgate.pgate.__init__(self, name, height, add_wells)

View File

@ -42,8 +42,8 @@ class pnand3(pgate.pgate):
self.tx_mults = 1 self.tx_mults = 1
if OPTS.tech_name == "sky130": if OPTS.tech_name == "sky130":
(self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width) self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
(self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width) self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
# Creates the netlist and layout # Creates the netlist and layout
pgate.pgate.__init__(self, name, height, add_wells) pgate.pgate.__init__(self, name, height, add_wells)

View File

@ -38,8 +38,8 @@ class pnor2(pgate.pgate):
self.tx_mults = 1 self.tx_mults = 1
if OPTS.tech_name == "sky130": if OPTS.tech_name == "sky130":
(self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width) self.nmos_width = self.nearest_bin("nmos", self.nmos_width)
(self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width) self.pmos_width = self.nearest_bin("pmos", self.pmos_width)
# Creates the netlist and layout # Creates the netlist and layout
pgate.pgate.__init__(self, name, height, add_wells) pgate.pgate.__init__(self, name, height, add_wells)

View File

@ -9,11 +9,10 @@ import contact
import design import design
import debug import debug
from pgate import pgate from pgate import pgate
from tech import parameter from tech import parameter, drc
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
from sram_factory import factory from sram_factory import factory
from tech import drc, layer
class precharge(design.design): class precharge(design.design):
@ -81,7 +80,7 @@ class precharge(design.design):
Initializes the upper and lower pmos Initializes the upper and lower pmos
""" """
if(OPTS.tech_name == "sky130"): if(OPTS.tech_name == "sky130"):
(self.ptx_width, self.ptx_mults) = pgate.bin_width("pmos", self.ptx_width) self.ptx_width = pgate.nearest_bin("pmos", self.ptx_width)
self.pmos = factory.create(module_type="ptx", self.pmos = factory.create(module_type="ptx",
width=self.ptx_width, width=self.ptx_width,
mults=self.ptx_mults, mults=self.ptx_mults,

View File

@ -131,7 +131,7 @@ class ptx(design.design):
perimeter_sd = 2 * self.poly_width + 2 * self.tx_width perimeter_sd = 2 * self.poly_width + 2 * self.tx_width
if OPTS.tech_name == "sky130" and OPTS.lvs_exe and OPTS.lvs_exe[0] == "calibre": if OPTS.tech_name == "sky130" and OPTS.lvs_exe and OPTS.lvs_exe[0] == "calibre":
# sky130 simulation cannot use the mult parameter in simulation # sky130 simulation cannot use the mult parameter in simulation
(self.tx_width, self.mults) = pgate.bin_width(self.tx_type, self.tx_width) (self.tx_width, self.mults) = pgate.best_bin(self.tx_type, self.tx_width)
main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type], main_str = "M{{0}} {{1}} {0} m={1} w={2} l={3} ".format(spice[self.tx_type],
self.mults, self.mults,
self.tx_width, self.tx_width,