Merge branch 'dev' into tech_migration

This commit is contained in:
mrg 2020-04-21 16:37:36 -07:00
commit 0bb4a7f93d
7 changed files with 154 additions and 24 deletions

View File

@ -34,6 +34,10 @@ class stimuli():
self.sf = stim_file self.sf = stim_file
(self.process, self.voltage, self.temperature) = corner (self.process, self.voltage, self.temperature) = corner
try:
self.device_libraries = tech.spice["fet_libraries"][self.process]
except:
debug.info(2, "Not using spice library")
self.device_models = tech.spice["fet_models"][self.process] self.device_models = tech.spice["fet_models"][self.process]
self.sram_name = "Xsram" self.sram_name = "Xsram"
@ -247,8 +251,17 @@ class stimuli():
def write_include(self, circuit): def write_include(self, circuit):
"""Writes include statements, inputs are lists of model files""" """Writes include statements, inputs are lists of model files"""
includes = self.device_models + [circuit] includes = self.device_models + [circuit]
self.sf.write("* {} process corner\n".format(self.process)) self.sf.write("* {} process corner\n".format(self.process))
if OPTS.tech_name == "s8":
libraries = self.device_libraries
for item in list(libraries):
if os.path.isfile(item[0]):
self.sf.write(".lib \"{0}\" {1}\n".format(item[0], item[1]))
else:
debug.error("Could not find spice library: {0}\nSet SPICE_MODEL_DIR to over-ride path.\n".format(item[0]))
for item in list(includes): for item in list(includes):
if os.path.isfile(item): if os.path.isfile(item):
self.sf.write(".include \"{0}\"\n".format(item)) self.sf.write(".include \"{0}\"\n".format(item))

View File

@ -8,10 +8,14 @@
import contact import contact
import design import design
import debug import debug
from tech import layer import math
from bisect import bisect_left
from tech import layer, drc
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
if(OPTS.tech_name == "s8"):
from tech import nmos_bins, pmos_bins, accuracy_requirement
class pgate(design.design): class pgate(design.design):
""" """
@ -282,5 +286,61 @@ class pgate(design.design):
self.width = max(self.nwell_contact.rx(), self.pwell_contact.rx()) + self.m1_space + 0.5 * contact.m1_via.width self.width = max(self.nwell_contact.rx(), self.pwell_contact.rx()) + self.m1_space + 0.5 * contact.m1_via.width
self.well_width = self.width + 2 * self.nwell_enclose_active self.well_width = self.width + 2 * self.nwell_enclose_active
# Height is an input parameter, so it is not recomputed. # Height is an input parameter, so it is not recomputed.
def bin_width(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_bin = bins[0]
scaling_factor = math.ceil(target_width / selected_bin)
scaled_bin = bins[0] * scaling_factor
else:
scaled_bins = []
scaling_factors = []
scaled_bins.append(bins[-1])
scaling_factors.append(1)
for width in bins[0:-1]:
m = math.ceil(target_width / width)
scaling_factors.append(m)
scaled_bins.append(m * width)
select = bisect_left(scaled_bins, target_width)
scaling_factor = scaling_factors[select]
scaled_bin = scaled_bins[select]
select = (select + 1) % len(scaled_bins)
selected_bin = bins[select]
debug.info(2, "binning {0} tx, target: {4}, found {1} x {2} = {3}".format(tx_type, selected_bin, scaling_factor, scaled_bin, target_width))
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:
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)
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):
""" """
@ -83,6 +87,9 @@ class pinv(pgate.pgate):
self.tx_mults = 1 self.tx_mults = 1
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 == "s8":
(self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width)
(self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width)
return return
# Do a quick sanity check and bail if unlikely feasible height # Do a quick sanity check and bail if unlikely feasible height
@ -132,30 +139,62 @@ 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 = bin[0]/bin[1]
pmos_mults = valid_pmos[0][1]
break
for bin in valid_nmos:
if bin[0]/bin[1] < nmos_height_available:
self.nmos_width = bin[0]/bin[1]
nmos_mults = valid_pmos[0][1]
break
self.tx_mults = max(pmos_mults, nmos_mults)
def add_ptx(self): def add_ptx(self):
""" Create the PMOS and NMOS transistors. """ """ Create the PMOS and NMOS transistors. """

View File

@ -9,6 +9,7 @@ import contact
import pgate import pgate
import debug import debug
from tech import drc, parameter, spice from tech import drc, parameter, spice
from globals import OPTS
from vector import vector from vector import vector
import logical_effort import logical_effort
from sram_factory import factory from sram_factory import factory
@ -37,6 +38,10 @@ class pnand2(pgate.pgate):
debug.check(size == 1, "Size 1 pnand2 is only supported now.") debug.check(size == 1, "Size 1 pnand2 is only supported now.")
self.tx_mults = 1 self.tx_mults = 1
if OPTS.tech_name == "s8":
(self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width)
(self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width)
# Creates the netlist and layout # Creates the netlist and layout
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height)

View File

@ -14,7 +14,6 @@ import logical_effort
from sram_factory import factory from sram_factory import factory
from globals import OPTS from globals import OPTS
class pnand3(pgate.pgate): class pnand3(pgate.pgate):
""" """
This module generates gds of a parametrically sized 2-input nand. This module generates gds of a parametrically sized 2-input nand.
@ -41,6 +40,10 @@ class pnand3(pgate.pgate):
"Size 1 pnand3 is only supported now.") "Size 1 pnand3 is only supported now.")
self.tx_mults = 1 self.tx_mults = 1
if OPTS.tech_name == "s8":
(self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width)
(self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width)
# Creates the netlist and layout # Creates the netlist and layout
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height)

View File

@ -8,6 +8,7 @@
import contact import contact
import pgate import pgate
import debug import debug
from globals import OPTS
from tech import drc, parameter, spice from tech import drc, parameter, spice
from vector import vector from vector import vector
from sram_factory import factory from sram_factory import factory
@ -36,6 +37,10 @@ class pnor2(pgate.pgate):
debug.check(size==1, "Size 1 pnor2 is only supported now.") debug.check(size==1, "Size 1 pnor2 is only supported now.")
self.tx_mults = 1 self.tx_mults = 1
if OPTS.tech_name == "s8":
(self.nmos_width, self.tx_mults) = self.bin_width("nmos", self.nmos_width)
(self.pmos_width, self.tx_mults) = self.bin_width("pmos", self.pmos_width)
# Creates the netlist and layout # Creates the netlist and layout
pgate.pgate.__init__(self, name, height) pgate.pgate.__init__(self, name, height)

View File

@ -8,6 +8,7 @@
import contact import contact
import design import design
import debug import debug
from pgate import pgate
from tech import parameter from tech import parameter
from vector import vector from vector import vector
from globals import OPTS from globals import OPTS
@ -28,6 +29,7 @@ class precharge(design.design):
self.bitcell = factory.create(module_type="bitcell") self.bitcell = factory.create(module_type="bitcell")
self.beta = parameter["beta"] self.beta = parameter["beta"]
self.ptx_width = self.beta * parameter["min_tx_size"] self.ptx_width = self.beta * parameter["min_tx_size"]
self.ptx_mults = 1
self.width = self.bitcell.width self.width = self.bitcell.width
self.bitcell_bl = bitcell_bl self.bitcell_bl = bitcell_bl
self.bitcell_br = bitcell_br self.bitcell_br = bitcell_br
@ -78,8 +80,11 @@ class precharge(design.design):
""" """
Initializes the upper and lower pmos Initializes the upper and lower pmos
""" """
if(OPTS.tech_name == "s8"):
(self.ptx_width, self.ptx_mults) = pgate.bin_width(self, "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,
tx_type="pmos") tx_type="pmos")
self.add_mod(self.pmos) self.add_mod(self.pmos)