Source code for skidl.package

# -*- coding: utf-8 -*-

# The MIT License (MIT) - Copyright (c) 2016-2021 Dave Vandenbout.

"""
Package a subcircuit so it can be used like a Part.
"""

from __future__ import (  # isort:skip
    absolute_import,
    division,
    print_function,
    unicode_literals,
)

from builtins import super, zip
from copy import copy

from future import standard_library

from .bus import Bus
from .circuit import subcircuit
from .interface import Interface
from .net import Net
from .part import NETLIST
from .protonet import ProtoNet

standard_library.install_aliases()


[docs]class Package(Interface): def __init__(self, **kwargs): super().__init__(**kwargs) self["circuit"] = None # Don't use update(). It doesn't seem to call __setitem__. for k, v in list(kwargs.items()): self[k] = v # Use __setitem__ so both dict item and attribute are created. def __call__(self, *args, **kwargs): """Create a copy of a package.""" # Get circuit that will contain the package subcircuitry. circuit = kwargs.pop("circuit", default_circuit) # See if this package should be instantiated into the netlist or used as a template. dest = kwargs.pop("dest", NETLIST) pckg = Package(**self.copy()) # Create a shallow copy of the package. # Set the circuit that the ProtoNets belong to. Also, make copies of any # implicit buses or nets that were specified as default I/Os in the # package definition. for k, v in pckg.items(): if isinstance(v, ProtoNet): v.circuit = circuit elif isinstance(v, (Net, Bus)): if v.is_implicit(): pckg[k] = v.__class__() # pckg[k] = v.copy() # Don't use update(). It doesn't seem to call __setitem__. for k, v in list(kwargs.items()): pckg[k] = v # Use __setitem__ so both dict item and attribute are created. pckg.subcircuit = self.subcircuit # Assign subcircuit creation function. # Remove creation function so it's not passed as a parameter. del pckg["subcircuit"] # Add package to circuit only if it's supposed to be instantiated. if dest == NETLIST: circuit += pckg return pckg
[docs] def is_movable(self): return True for obj in self.values(): try: if not obj.is_movable(): return False # Interface is not movable if any object in it is not movable. except AttributeError: pass # Objects without is_movable() are always movable. return True # Every object in the Interface that could move was movable.
[docs]def package(subcirc_func): """Decorator that creates a package for a subcircuit routine.""" pckg = Package() # Create the package. # Store the parameter names passed to the subcircuit. code = subcirc_func.__code__ num_args = code.co_argcount arg_names = code.co_varnames[:num_args] # By default, set parameters to a package to be ProtoNets. for arg_name in arg_names: pn = ProtoNet(arg_name, circuit=None) pn.intfc = pckg pn.intfc_key = arg_name pckg[arg_name] = pn # Set any default values for the parameters. if getattr(subcirc_func, "__defaults__", None): for arg_name, dflt_value in zip( reversed(arg_names), reversed(subcirc_func.__defaults__) ): pckg[arg_name] = dflt_value if getattr(subcirc_func, "__kwdefaults__", None): for arg_name, dflt_value in subcirc_func.__kwdefaults__.items(): pckg[arg_name] = dflt_value # Create the subcircuit function that will be called to insantiate this package. pckg.subcircuit = subcircuit(subcirc_func) # Remove the subcircuit key from the dict so it won't be passed to subcirc_func(). del pckg["subcircuit"] return pckg