mirror of https://github.com/VLSIDA/OpenRAM.git
Merge branch 'dev' into tech_migration
This commit is contained in:
commit
9e8b03d6c2
|
|
@ -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)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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('/'):
|
||||||
|
|
|
||||||
|
|
@ -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]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue