2019-04-26 21:21:50 +02:00
|
|
|
# See LICENSE for licensing information.
|
|
|
|
|
#
|
2019-06-14 17:43:41 +02:00
|
|
|
# Copyright (c) 2016-2019 Regents of the University of California and The Board
|
|
|
|
|
# of Regents for the Oklahoma Agricultural and Mechanical College
|
|
|
|
|
# (acting for and on behalf of Oklahoma State University)
|
|
|
|
|
# All rights reserved.
|
2019-04-26 21:21:50 +02:00
|
|
|
#
|
2019-01-17 02:04:28 +01:00
|
|
|
from globals import OPTS
|
2019-10-03 01:26:02 +02:00
|
|
|
|
2019-01-17 02:04:28 +01:00
|
|
|
class sram_factory:
|
|
|
|
|
"""
|
|
|
|
|
This is a factory pattern to create modules for usage in an SRAM.
|
|
|
|
|
Since GDSII has a flat namespace, it requires modules to have unique
|
|
|
|
|
names if their layout differs. This module ensures that any module
|
|
|
|
|
with different layouts will have different names. It also ensures that
|
|
|
|
|
identical layouts will share the same name to reduce file size and promote
|
|
|
|
|
hierarchical sharing.
|
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
def __init__(self):
|
2019-10-03 01:26:02 +02:00
|
|
|
# A dictionary of modules indexed by module type
|
2019-01-17 02:04:28 +01:00
|
|
|
self.modules = {}
|
|
|
|
|
# These are the indices to append to name to make unique object names
|
|
|
|
|
self.module_indices = {}
|
|
|
|
|
# A dictionary of instance lists indexed by module type
|
|
|
|
|
self.objects = {}
|
|
|
|
|
|
|
|
|
|
def reset(self):
|
|
|
|
|
"""
|
|
|
|
|
Clear the factory instances for testing.
|
|
|
|
|
"""
|
|
|
|
|
self.__init__()
|
|
|
|
|
|
|
|
|
|
def create(self, module_type, **kwargs):
|
|
|
|
|
"""
|
2019-10-03 01:26:02 +02:00
|
|
|
A generic function to create a module with a given module_type.
|
|
|
|
|
The args are passed directly to the module constructor.
|
2019-01-17 02:04:28 +01:00
|
|
|
"""
|
2019-12-16 19:21:24 +01:00
|
|
|
try:
|
|
|
|
|
from tech import tech_modules
|
|
|
|
|
real_module_type = tech_modules[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.
|
|
|
|
|
pass
|
|
|
|
|
|
2019-01-17 02:04:28 +01:00
|
|
|
if hasattr(OPTS, module_type):
|
|
|
|
|
# Retrieve the name from OPTS if it exists,
|
|
|
|
|
# otherwise just use the name
|
2019-12-16 19:11:26 +01:00
|
|
|
real_module_type = getattr(OPTS, module_type)
|
2019-05-29 01:55:09 +02:00
|
|
|
|
2019-01-17 02:04:28 +01:00
|
|
|
# Either retrieve the already loaded module or load it
|
|
|
|
|
try:
|
2019-12-16 19:21:24 +01:00
|
|
|
# Load a cached version from previous usage
|
2019-12-16 19:11:26 +01:00
|
|
|
mod = self.modules[real_module_type]
|
2019-01-17 02:04:28 +01:00
|
|
|
except KeyError:
|
2019-12-16 19:21:24 +01:00
|
|
|
# Dynamically load the module
|
2019-05-31 17:43:37 +02:00
|
|
|
import importlib
|
2019-12-16 19:11:26 +01:00
|
|
|
c = importlib.reload(__import__(real_module_type))
|
|
|
|
|
mod = getattr(c, real_module_type)
|
|
|
|
|
self.modules[real_module_type] = mod
|
|
|
|
|
self.module_indices[real_module_type] = 0
|
|
|
|
|
self.objects[real_module_type] = []
|
2019-01-17 02:04:28 +01:00
|
|
|
|
|
|
|
|
# Either retreive a previous object or create a new one
|
2019-12-16 19:11:26 +01:00
|
|
|
for obj in self.objects[real_module_type]:
|
2019-01-17 02:04:28 +01:00
|
|
|
(obj_kwargs, obj_item) = obj
|
|
|
|
|
# Must have the same dictionary exactly (conservative)
|
|
|
|
|
if obj_kwargs == kwargs:
|
|
|
|
|
return obj_item
|
|
|
|
|
|
|
|
|
|
# Use the default name if there are default arguments
|
2019-10-03 01:26:02 +02:00
|
|
|
# This is especially for library cells so that the
|
|
|
|
|
# spice and gds files can be found.
|
|
|
|
|
if len(kwargs) > 0:
|
2019-01-17 02:04:28 +01:00
|
|
|
# Create a unique name and increment the index
|
2019-12-16 19:11:26 +01:00
|
|
|
module_name = "{0}_{1}".format(real_module_type,
|
|
|
|
|
self.module_indices[real_module_type])
|
|
|
|
|
self.module_indices[real_module_type] += 1
|
2019-05-29 01:55:09 +02:00
|
|
|
else:
|
2019-12-16 19:11:26 +01:00
|
|
|
module_name = real_module_type
|
2019-10-03 01:26:02 +02:00
|
|
|
|
2019-12-16 19:11:26 +01:00
|
|
|
# type_str = "type={}".format(real_module_type)
|
2019-10-03 01:26:02 +02:00
|
|
|
# name_str = "name={}".format(module_name)
|
|
|
|
|
# kwargs_str = "kwargs={}".format(str(kwargs))
|
|
|
|
|
# import debug
|
|
|
|
|
# debug.info(0, "New module:" + type_str + name_str + kwargs_str)
|
|
|
|
|
obj = mod(name=module_name, **kwargs)
|
2019-12-16 19:11:26 +01:00
|
|
|
self.objects[real_module_type].append((kwargs, obj))
|
2019-01-17 02:04:28 +01:00
|
|
|
return obj
|
|
|
|
|
|
2019-05-27 22:08:59 +02:00
|
|
|
def get_mods(self, module_type):
|
|
|
|
|
"""Returns list of all objects of module name's type."""
|
2019-05-29 01:55:09 +02:00
|
|
|
if hasattr(OPTS, module_type):
|
|
|
|
|
# Retrieve the name from OPTS if it exists,
|
|
|
|
|
# otherwise just use the input
|
|
|
|
|
module_type = getattr(OPTS, module_type)
|
2019-05-27 22:08:59 +02:00
|
|
|
try:
|
|
|
|
|
mod_tuples = self.objects[module_type]
|
2019-10-03 01:26:02 +02:00
|
|
|
mods = [mod for kwargs, mod in mod_tuples]
|
2019-05-27 22:08:59 +02:00
|
|
|
except KeyError:
|
|
|
|
|
mods = []
|
|
|
|
|
return mods
|
2019-10-03 01:26:02 +02:00
|
|
|
|
|
|
|
|
|
2019-01-17 02:04:28 +01:00
|
|
|
# Make a factory
|
|
|
|
|
factory = sram_factory()
|