From de6b207798cd8ac4ff0b9674999f6ae392778910 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 18 Dec 2019 11:33:21 +0100 Subject: [PATCH 1/5] hierachy_layout: Move number of via arg to add_power_pins() this allows custom modules to state how many vias they need for power rails. Signed-off-by: Bastian Koppelmann --- compiler/base/hierarchy_layout.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/base/hierarchy_layout.py b/compiler/base/hierarchy_layout.py index 7f23e942..4751000a 100644 --- a/compiler/base/hierarchy_layout.py +++ b/compiler/base/hierarchy_layout.py @@ -1015,7 +1015,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. The starting layer is specified to determine which vias are needed. @@ -1027,12 +1027,14 @@ class layout(): if start_layer=="m1": self.add_via_center(layers=self.m1_stack, + size=size, offset=loc, directions=direction) if start_layer=="m1" or start_layer=="m2": via=self.add_via_center(layers=self.m2_stack, + size=size, offset=loc, directions=direction) From 451ef4d8965e54131add58b62ede96a75f5061f4 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 18 Dec 2019 11:58:04 +0100 Subject: [PATCH 2/5] sram_factory: Allow a prefered module name Signed-off-by: Bastian Koppelmann --- compiler/sram_factory.py | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/compiler/sram_factory.py b/compiler/sram_factory.py index 6bb3578c..f323fbdc 100644 --- a/compiler/sram_factory.py +++ b/compiler/sram_factory.py @@ -31,7 +31,7 @@ class sram_factory: """ self.__init__() - def create(self, module_type, **kwargs): + 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. @@ -72,16 +72,18 @@ class sram_factory: if obj_kwargs == kwargs: return obj_item - # Use the default name if there are default arguments - # This is especially for library cells so that the - # spice and gds files can be found. - if len(kwargs) > 0: - # Create a unique name and increment the index - 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 + # If no prefered module name is provided, we generate one. + if module_name is None: + # Use the default name if there are default arguments + # This is especially for library cells so that the + # spice and gds files can be found. + if len(kwargs) > 0: + # Create a unique name and increment the index + 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 # type_str = "type={}".format(real_module_type) # name_str = "name={}".format(module_name) From fab963701b8eb5fd1443fc8a16c18f2150314bf1 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Wed, 18 Dec 2019 12:00:02 +0100 Subject: [PATCH 3/5] sram_base: Instantiate "dff_array" and "bank" through sram_factory Signed-off-by: Bastian Koppelmann --- compiler/modules/module_type.py | 1 + compiler/sram/sram_base.py | 13 +++++-------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/compiler/modules/module_type.py b/compiler/modules/module_type.py index 90e1fdbe..ee3e8eb2 100644 --- a/compiler/modules/module_type.py +++ b/compiler/modules/module_type.py @@ -62,6 +62,7 @@ class ModuleType(): 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 diff --git a/compiler/sram/sram_base.py b/compiler/sram/sram_base.py index cfb5af71..65297889 100644 --- a/compiler/sram/sram_base.py +++ b/compiler/sram/sram_base.py @@ -271,28 +271,25 @@ class sram_base(design, verilog, lef): self.dff = factory.create(module_type="dff") # Create the address and control flops (but not the clk) - from dff_array import dff_array - self.row_addr_dff = dff_array(name="row_addr_dff", rows=self.row_addr_size, columns=1) + self.row_addr_dff = factory.create("dff_array", module_name="row_addr_dff", rows=self.row_addr_size, columns=1) self.add_mod(self.row_addr_dff) 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) else: 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) 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) # Create the bank module (up to four are instantiated) - from bank import bank - self.bank = bank(self.sram_config, - name="bank") + self.bank = factory.create("bank", sram_config=self.sram_config, module_name="bank") self.add_mod(self.bank) # Create bank decoder From 1df16eceb60f2a50f78e18b5256cc3c318c9654a Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Thu, 19 Dec 2019 15:58:00 +0100 Subject: [PATCH 4/5] sram_factory: Give proper priority to overrides modules overridden by the user are the highest priority, then modules overridden by the technology. If nothing is overriden, use the defaults from OPTS (if they exist) or use the requested module_type. This fixes that custom tech_modules could not be used, if they had a default in OPTS even if the latter was not overridden by the user. We don't need extra defaults in the tech_modules, as we now only use them, if they have been overridden by the tech_module. Signed-off-by: Bastian Koppelmann --- compiler/globals.py | 2 ++ compiler/modules/module_type.py | 57 +++------------------------------ compiler/sram_factory.py | 43 +++++++++++++++++++++---- 3 files changed, 42 insertions(+), 60 deletions(-) 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 From 11760a999317fb7a56ab3b826424890a71a64463 Mon Sep 17 00:00:00 2001 From: Bastian Koppelmann Date: Thu, 19 Dec 2019 16:31:52 +0100 Subject: [PATCH 5/5] sram_factory: Add check for duplicate module name sram_factory cannot handle duplicate module name, thus we bail out and raise an error if a user attempts that. Signed-off-by: Bastian Koppelmann --- compiler/sram_factory.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/compiler/sram_factory.py b/compiler/sram_factory.py index 2ba34b40..110dbe15 100644 --- a/compiler/sram_factory.py +++ b/compiler/sram_factory.py @@ -63,6 +63,13 @@ class sram_factory: 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. @@ -113,6 +120,10 @@ class sram_factory: self.module_indices[real_module_type] += 1 else: module_name = real_module_type + else: + 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) # name_str = "name={}".format(module_name)