Source code for skidl.netpinlist
# -*- coding: utf-8 -*-
# The MIT License (MIT) - Copyright (c) 2016-2021 Dave Vandenbout.
"""
Specialized list for handling nets, pins, and buses.
"""
from __future__ import ( # isort:skip
absolute_import,
division,
print_function,
unicode_literals,
)
from builtins import range
from future import standard_library
from .alias import Alias
from .logger import active_logger
from .net import Net
from .network import Network
from .pin import Pin
from .protonet import ProtoNet
# from .skidlbaseobj import SkidlBaseObject
from .utilities import *
standard_library.install_aliases()
[docs]class NetPinList(list):
def __iadd__(self, *nets_pins_buses):
nets_pins_a = expand_buses(self)
len_a = len(nets_pins_a)
# Check the stuff you want to connect to see if it's the right kind.
nets_pins_b = expand_buses(flatten(nets_pins_buses))
allowed_types = (Pin, Net, ProtoNet)
illegal = (np for np in nets_pins_b if not isinstance(np, allowed_types))
for np in illegal:
active_logger.raise_(
ValueError,
"Can't make connections to a {} ({}).".format(
type(np), getattr(np, "__name__", "")
),
)
len_b = len(nets_pins_b)
if len_a != len_b:
if len_a > 1 and len_b > 1:
active_logger.raise_(
ValueError,
"Connection mismatch {} != {}!".format(len_a, len_b),
)
# If just a single net is to be connected, make a list out of it that's
# just as long as the list of pins to connect to. This will connect
# multiple pins to the same net.
if len_b == 1:
nets_pins_b = [nets_pins_b[0] for _ in range(len_a)]
len_b = len(nets_pins_b)
elif len_a == 1:
nets_pins_a = [nets_pins_a[0] for _ in range(len_b)]
len_a = len(nets_pins_a)
assert len_a == len_b
for npa, npb in zip(nets_pins_a, nets_pins_b):
if isinstance(npb, ProtoNet):
# npb is a ProtoNet so it will get replaced by a real Net by the += op.
# Should the new Net replace the equivalent ProtoNet in nets_pins_buses?
# It doesn't appear to be necessary since all tests pass, but be aware
# of this issue.
npb += npa
elif isinstance(npa, ProtoNet):
# npa is a ProtoNet so it will get replaced by a real Net by the += op.
# Therefore, find the equivalent ProtoNet in self and replace it with the
# new Net.
id_npa = id(npa)
npa += npb
for i in range(len(self)):
if id_npa == id(self[i]):
self[i] = npa
else:
# Just regular attachment of nets and/or pins which updates the existing
# objects within the self and nets_pins_buses lists.
npa += npb
pass
# Set the flag to indicate this result came from the += operator.
set_iadd(self, True)
return self
[docs] def create_network(self):
"""Create a network from a list of pins and nets."""
return Network(*self) # An error will occur if list has more than 2 items.
def __and__(self, obj):
"""Attach a NetPinList and another part/pin/net in serial."""
return Network(self) & obj
def __rand__(self, obj):
"""Attach a NetPinList and another part/pin/net in serial."""
return obj & Network(self)
def __or__(self, obj):
"""Attach a NetPinList and another part/pin/net in parallel."""
return Network(self) | obj
def __ror__(self, obj):
"""Attach a NetPinList and another part/pin/net in parallel."""
return obj | Network(self)
def __len__(self):
"""Return the number of individual pins/nets in this interface."""
return len(expand_buses(self))
@property
def circuit(self):
"""Get the circuit the pins/nets are members of."""
cct = set()
for pn in self:
cct.add(pn.circuit)
if len(cct) == 1:
return cct.pop()
active_logger.raise_(
ValueError,
"This NetPinList contains nets/pins in {} circuits.".format(len(cct)),
)
@property
def width(self):
"""Return width, which is the same as using the len() operator."""
return len(self)
# Setting/clearing the do_erc flag for the list sets/clears the do_erc flags of the pins/nets in the list.
@property
def do_erc(self):
raise NotImplementedError
@do_erc.setter
def do_erc(self, on_off):
for pn in self:
pn.do_erc = on_off
@do_erc.deleter
def do_erc(self):
for pn in self:
del pn.do_erc
# Setting/clearing the drive strength for the list sets/clears the drive of the pins/nets in the list.
@property
def drive(self):
raise NotImplementedError
@do_erc.setter
def drive(self, strength):
for pn in self:
pn.drive = strength
@do_erc.deleter
def drive(self):
for pn in self:
del pn.drive
# Trying to set an alias attribute on a NetPinList is an error.
# This prevents setting an alias on a list of two or more pins that
# might be returned by the filter_list() utility.
@property
def aliases(self):
return Alias([]) # No aliases, so just return an empty list.
@aliases.setter
def aliases(self, alias):
raise NotImplementedError
@aliases.deleter
def aliases(self):
raise NotImplementedError