diff --git a/compiler/globals.py b/compiler/globals.py index 8bca4b3f..70e4b54b 100644 --- a/compiler/globals.py +++ b/compiler/globals.py @@ -304,6 +304,7 @@ def read_config(config_file, is_unit_test=True): except: debug.error("Unable to read configuration file: {0}".format(config_file),2) + OPTS.overridden = {} for k, v in config.__dict__.items(): # The command line will over-ride the config file # 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! if k not in OPTS.__dict__ or k == "tech_name": OPTS.__dict__[k] = v + OPTS.overridden[k] = True # Massage the output path to be an absolute one if not OPTS.output_path.endswith('/'): diff --git a/compiler/modules/module_type.py b/compiler/modules/module_type.py index ee3e8eb2..1d8d0cba 100644 --- a/compiler/modules/module_type.py +++ b/compiler/modules/module_type.py @@ -12,64 +12,15 @@ class ModuleType(): """ def __init__(self): 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' - self.names['dff_array'] = 'dff_array' def __setitem__(self, b, c): self.names[b] = c + def is_overridden(self, b): + return (b in self.names.keys()) + def __getitem__(self, b): if b not in self.names.keys(): raise KeyError - + return self.names[b] - diff --git a/compiler/sram_factory.py b/compiler/sram_factory.py index f323fbdc..2ba34b40 100644 --- a/compiler/sram_factory.py +++ b/compiler/sram_factory.py @@ -30,15 +30,16 @@ class sram_factory: Clear the factory instances for testing. """ self.__init__() - - def create(self, module_type, module_name=None, **kwargs): + + def get_techmodule_type(self, module_type): """ - A generic function to create a module with a given module_type. - The args are passed directly to the module constructor. + Try to load the custom tech module type. """ + overridden = False try: from tech import tech_modules real_module_type = tech_modules[module_type] + overridden = tech_modules.is_overridden(module_type) except ImportError: # If they didn't define these, then don't use the option types. # Primarily for backward compatibility and simplicity of tech files. @@ -46,12 +47,40 @@ class sram_factory: except KeyError: # If it wasn't a tech module type, we can ignore that too. 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): # Retrieve the name from OPTS if it exists, # 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 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 try: # Load a cached version from previous usage