mirror of https://github.com/VLSIDA/OpenRAM.git
Clean up binning. Fix mults to 1 for certain gates.
This commit is contained in:
parent
bb8157b3b7
commit
c7bc01c3a9
|
|
@ -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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Find all of the relavent scaled bins and multiples
|
||||||
|
scaled_bins = pgate.scaled_bins(tx_type, target_width)
|
||||||
|
|
||||||
|
for (scaled_width, multiple) in scaled_bins:
|
||||||
|
if abs(target_width - scaled_width) / target_width <= 1 - OPTS.accuracy_requirement:
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
debug.error("failed to bin tx size {}, try reducing accuracy requirement".format(target_width), 1)
|
||||||
|
|
||||||
|
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(scaled_width / multiple, multiple)
|
||||||
|
|
||||||
|
@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:
|
||||||
selected_bin = bins[0]
|
scaled_bins = [(bins[0], math.ceil(target_width / bins[0]))]
|
||||||
scaling_factor = math.ceil(target_width / selected_bin)
|
|
||||||
scaled_bin = bins[0] * scaling_factor
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
base_bins = []
|
|
||||||
scaled_bins = []
|
scaled_bins = []
|
||||||
scaling_factors = []
|
# Add the biggest size as 1x multiple
|
||||||
|
scaled_bins.append((bins[-1], 1))
|
||||||
|
# Compute discrete multiple of other sizes
|
||||||
|
for width in reversed(bins[:-1]):
|
||||||
|
multiple = math.ceil(target_width / width)
|
||||||
|
scaled_bins.append((multiple * width, multiple))
|
||||||
|
|
||||||
for width in bins:
|
return(scaled_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
|
|
||||||
if select == -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))
|
|
||||||
|
|
||||||
return(selected_bin, scaling_factor)
|
|
||||||
|
|
||||||
def permute_widths(self, tx_type, target_width):
|
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
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":
|
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")
|
||||||
bins = bins[0:bisect_left(bins, target_width) + 1]
|
|
||||||
if len(bins) == 1:
|
|
||||||
scaled_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)
|
# Find the next larger bin
|
||||||
|
bin_loc = bisect_left(bins, target_width)
|
||||||
def bin_accuracy(self, ideal_width, width):
|
if bin_loc < len(bins):
|
||||||
return 1-abs((ideal_width - width)/ideal_width)
|
return bins[bin_loc]
|
||||||
|
else:
|
||||||
|
return bins[-1]
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def bin_accuracy(ideal_width, width):
|
||||||
|
return 1 - abs((ideal_width - width) / ideal_width)
|
||||||
|
|
|
||||||
|
|
@ -14,15 +14,11 @@ 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):
|
||||||
"""
|
"""
|
||||||
Pinv generates gds of a parametrically sized inverter. The
|
Pinv generates gds of a parametrically sized inverter. The
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue