Merge branch 'dev' into tech_migration

This commit is contained in:
Matt Guthaus 2019-12-19 16:23:22 -08:00
commit 9e8b03d6c2
5 changed files with 72 additions and 77 deletions

View File

@ -1012,7 +1012,7 @@ class layout():
def add_power_pin(self, name, loc, vertical=False, start_layer="m1"): def add_power_pin(self, name, loc, size=[1,1], vertical=False, start_layer="m1"):
""" """
Add a single power pin from M3 down to M1 at the given center location. Add a single power pin from M3 down to M1 at the given center location.
The starting layer is specified to determine which vias are needed. The starting layer is specified to determine which vias are needed.
@ -1024,12 +1024,14 @@ class layout():
if start_layer=="m1": if start_layer=="m1":
self.add_via_center(layers=self.m1_stack, self.add_via_center(layers=self.m1_stack,
size=size,
offset=loc, offset=loc,
directions=direction) directions=direction)
if start_layer=="m1" or start_layer=="m2": if start_layer=="m1" or start_layer=="m2":
via=self.add_via_center(layers=self.m2_stack, via=self.add_via_center(layers=self.m2_stack,
size=size,
offset=loc, offset=loc,
directions=direction) directions=direction)

View File

@ -304,6 +304,7 @@ def read_config(config_file, is_unit_test=True):
except: except:
debug.error("Unable to read configuration file: {0}".format(config_file),2) debug.error("Unable to read configuration file: {0}".format(config_file),2)
OPTS.overridden = {}
for k, v in config.__dict__.items(): for k, v in config.__dict__.items():
# The command line will over-ride the config file # The command line will over-ride the config file
# except in the case of the tech name! This is because the tech name # except in the case of the tech name! This is because the tech name
@ -311,6 +312,7 @@ def read_config(config_file, is_unit_test=True):
# Note that if we re-read a config file, nothing will get read again! # Note that if we re-read a config file, nothing will get read again!
if k not in OPTS.__dict__ or k == "tech_name": if k not in OPTS.__dict__ or k == "tech_name":
OPTS.__dict__[k] = v OPTS.__dict__[k] = v
OPTS.overridden[k] = True
# Massage the output path to be an absolute one # Massage the output path to be an absolute one
if not OPTS.output_path.endswith('/'): if not OPTS.output_path.endswith('/'):

View File

@ -12,63 +12,15 @@ class ModuleType():
""" """
def __init__(self): def __init__(self):
self.names = {} self.names = {}
self.names['contact'] = 'contact'
self.names['precharge'] = 'precharge'
self.names['pinv'] = 'pinv'
self.names['dff_buf'] = 'dff_buf'
self.names['sense_amp'] = 'sense_amp'
self.names['bitcell'] = 'bitcell'
self.names['port_data'] = 'port_data'
self.names['port_address'] = 'port_address'
self.names['replica_bitcell_array'] = 'replica_bitcell_array'
self.names['bank_select'] = 'bank_select'
self.names['dff'] = 'dff'
self.names['pinvbuf'] = 'pinvbuf'
self.names['hierarchical_predecode2x4'] = 'hierarchical_predecode2x4'
self.names['hierarchical_predecode3x8'] = 'hierarchical_predecode3x8'
self.names['replica_bitcell'] = 'replica_bitcell'
self.names['dummy_bitcell'] = 'dummy_bitcell'
self.names['bitcell'] = 'bitcell'
self.names['pnor2'] = 'pnor2'
self.names['pnand2'] = 'pnand2'
self.names['precharge_array'] = 'precharge_array'
self.names['sense_amp_array'] = 'sense_amp_array'
self.names['column_mux_array'] = 'column_mux_array'
self.names['write_driver_array'] = 'write_driver_array'
self.names['write_mask_and_array'] = 'write_mask_and_array'
self.names['pand2'] = 'pand2'
self.names['write_driver'] = 'write_driver'
self.names['dff_buf_array'] = 'dff_buf_array'
self.names['pdriver'] = 'pdriver'
self.names['pand3'] = 'pand3'
self.names['delay_chain'] = 'delay_chain'
self.names['decoder'] = 'decoder'
self.names['wordline_driver'] = 'wordline_driver'
self.names['tri_gate'] = 'tri_gate'
self.names['tri_gate_array'] = 'tri_gate_array'
self.names['bitcell_array'] = 'bitcell_array'
self.names['replica_column'] = 'replica_column'
self.names['dummy_array'] = 'dummy_array'
self.names['single_level_column_mux_array'] = 'single_level_column_mux_array'
self.names['single_level_column_mux'] = 'single_level_column_mux'
self.names['sram'] = 'sram'
self.names['ptx'] = 'ptx'
self.names['hierarchical_decoder'] = 'hierarchical_decoder'
self.names['pbuf'] = 'pbuf'
self.names['control_logic'] = 'control_logic'
self.names['bank'] = 'bank'
self.names['pbitcell'] = 'pbitcell'
self.names['pnand3'] = 'pnand3'
self.names['pwrite_driver'] = 'pwrite_driver'
self.names['ptristate_inv'] = 'ptristate_inv'
self.names['ptristate_buf'] = 'ptristate_buf'
def __setitem__(self, b, c): def __setitem__(self, b, c):
self.names[b] = c self.names[b] = c
def is_overridden(self, b):
return (b in self.names.keys())
def __getitem__(self, b): def __getitem__(self, b):
if b not in self.names.keys(): if b not in self.names.keys():
raise KeyError raise KeyError
return self.names[b] return self.names[b]

View File

@ -271,28 +271,25 @@ class sram_base(design, verilog, lef):
self.dff = factory.create(module_type="dff") self.dff = factory.create(module_type="dff")
# Create the address and control flops (but not the clk) # Create the address and control flops (but not the clk)
from dff_array import dff_array self.row_addr_dff = factory.create("dff_array", module_name="row_addr_dff", rows=self.row_addr_size, columns=1)
self.row_addr_dff = dff_array(name="row_addr_dff", rows=self.row_addr_size, columns=1)
self.add_mod(self.row_addr_dff) self.add_mod(self.row_addr_dff)
if self.col_addr_size > 0: if self.col_addr_size > 0:
self.col_addr_dff = dff_array(name="col_addr_dff", rows=1, columns=self.col_addr_size) self.col_addr_dff = factory.create("dff_array", module_name="col_addr_dff", rows=1, columns=self.col_addr_size)
self.add_mod(self.col_addr_dff) self.add_mod(self.col_addr_dff)
else: else:
self.col_addr_dff = None self.col_addr_dff = None
self.data_dff = dff_array(name="data_dff", rows=1, columns=self.word_size) self.data_dff = factory.create("dff_array", module_name="data_dff", rows=1, columns=self.word_size)
self.add_mod(self.data_dff) self.add_mod(self.data_dff)
if self.write_size: if self.write_size:
self.wmask_dff = dff_array(name="wmask_dff", rows=1, columns=self.num_wmasks) self.wmask_dff = factory.create("dff_array", module_name="wmask_dff", rows=1, columns=self.num_wmasks)
self.add_mod(self.wmask_dff) self.add_mod(self.wmask_dff)
# Create the bank module (up to four are instantiated) # Create the bank module (up to four are instantiated)
from bank import bank self.bank = factory.create("bank", sram_config=self.sram_config, module_name="bank")
self.bank = bank(self.sram_config,
name="bank")
self.add_mod(self.bank) self.add_mod(self.bank)
# Create bank decoder # Create bank decoder

View File

@ -30,15 +30,16 @@ class sram_factory:
Clear the factory instances for testing. Clear the factory instances for testing.
""" """
self.__init__() self.__init__()
def create(self, module_type, **kwargs): def get_techmodule_type(self, module_type):
""" """
A generic function to create a module with a given module_type. Try to load the custom tech module type.
The args are passed directly to the module constructor.
""" """
overridden = False
try: try:
from tech import tech_modules from tech import tech_modules
real_module_type = tech_modules[module_type] real_module_type = tech_modules[module_type]
overridden = tech_modules.is_overridden(module_type)
except ImportError: except ImportError:
# If they didn't define these, then don't use the option types. # If they didn't define these, then don't use the option types.
# Primarily for backward compatibility and simplicity of tech files. # Primarily for backward compatibility and simplicity of tech files.
@ -46,12 +47,47 @@ class sram_factory:
except KeyError: except KeyError:
# If it wasn't a tech module type, we can ignore that too. # If it wasn't a tech module type, we can ignore that too.
real_module_type = module_type real_module_type = module_type
return (real_module_type, overridden)
def get_usermodule_type(self, module_type):
"""
Try to load the custom user module type. If the user hasn't specified
anything, we use the default from 'options.py'. If we cannot find anything, we
fall back to the original 'module_type'.
"""
overridden = False
if hasattr(OPTS, module_type): if hasattr(OPTS, module_type):
# Retrieve the name from OPTS if it exists, # Retrieve the name from OPTS if it exists,
# otherwise just use the name # otherwise just use the name
real_module_type = getattr(OPTS, module_type) module_type = getattr(OPTS, module_type)
overridden = module_type in OPTS.overridden.keys()
return (module_type, overridden)
def is_duplicate_name(self, name):
for mods in self.objects.values():
for insts in mods:
if insts[1].name == name:
return True
return False
def create(self, module_type, module_name=None, **kwargs):
"""
A generic function to create a module with a given module_type.
The args are passed directly to the module constructor.
"""
tech_module_type, tm_overridden = self.get_techmodule_type(module_type)
user_module_type, um_overridden = self.get_usermodule_type(module_type)
# overridden user modules have priority
if um_overridden:
real_module_type = user_module_type
# then overridden tech modules
elif tm_overridden:
real_module_type = tech_module_type
# if nothing else works use the name generated by get_usermodule_type()
else:
real_module_type = user_module_type
# Either retrieve the already loaded module or load it # Either retrieve the already loaded module or load it
try: try:
# Load a cached version from previous usage # Load a cached version from previous usage
@ -72,16 +108,22 @@ class sram_factory:
if obj_kwargs == kwargs: if obj_kwargs == kwargs:
return obj_item return obj_item
# Use the default name if there are default arguments # If no prefered module name is provided, we generate one.
# This is especially for library cells so that the if module_name is None:
# spice and gds files can be found. # Use the default name if there are default arguments
if len(kwargs) > 0: # This is especially for library cells so that the
# Create a unique name and increment the index # spice and gds files can be found.
module_name = "{0}_{1}".format(real_module_type, if len(kwargs) > 0:
self.module_indices[real_module_type]) # Create a unique name and increment the index
self.module_indices[real_module_type] += 1 module_name = "{0}_{1}".format(real_module_type,
self.module_indices[real_module_type])
self.module_indices[real_module_type] += 1
else:
module_name = real_module_type
else: else:
module_name = real_module_type if self.is_duplicate_name(module_name):
raise ValueError("Modules with duplicate name are not allowed." \
" '{}'".format(module_name))
# type_str = "type={}".format(real_module_type) # type_str = "type={}".format(real_module_type)
# name_str = "name={}".format(module_name) # name_str = "name={}".format(module_name)