Source code for jitx.virtual
"""
Virtual Connections
====================
User-declared assertions that two endpoints are electrically connected, without
JITX routing the connection itself.
.. warning::
The API in this module is still experimental and may change
significantly without notice.
"""
from __future__ import annotations
from jitx._structural import Structural
from jitx.landpattern import Pad
from jitx.net import DiffPair, Port, ConnectionEndpoint, CoupledRouteConnectionEndpoint
from jitx.si import PinModel
from jitx.via import Via
def _check_endpoint(target: object, role: str) -> None:
if isinstance(target, Port):
if isinstance(target, DiffPair):
raise TypeError(
f"VirtualConnection {role} cannot be a combined "
"differential-pair port; connect a single leg instead "
"(e.g. .p or .n)."
)
if not target.is_single_pin():
raise TypeError(
f"VirtualConnection {role} must be a single-pin Port, "
f"not a bundle port ({type(target).__name__}); connect "
"one of its leaf ports instead."
)
elif isinstance(target, ConnectionEndpoint):
if isinstance(target, CoupledRouteConnectionEndpoint):
raise TypeError(
f"{role} must not be single connection endpoints, "
f"not coupled connection endpoints ({type(target).__name__}); connect "
"p/n sides instead."
)
elif not isinstance(target, (Pad, Via)):
raise TypeError(
f"VirtualConnection {role} must be a ConnectionEndpoint, Port, Pad, or Via, "
f"not {type(target).__name__}."
)
[docs]
class VirtualConnection(Structural):
"""User-declared assertion that two endpoints are electrically
connected. JITX does not route the connection; ratsnest visualization
and unrouted-warning emission are suppressed for the affected
endpoints.
Use cases include :py:class:`~jitx.feature.OverlappableCopper` bridges,
connections made manually post-fabrication (e.g., a soldered wire), and
modeling electrically real structures invisible to the router.
Each endpoint must be a single electrical target: a single-pin
:class:`~jitx.net.Port`, a :class:`~jitx.landpattern.Pad`, or a
:class:`~jitx.via.Via`. Bundle ports — including a combined
differential pair — are rejected; name a single leg (``pair.p`` /
``pair.n``) instead.
.. warning::
Declaring an VirtualConnection does not automatically bridge nets This
allows VirtualConnections to be used for pin-assigned connections An
external connection that isn't allowed will be dropped
.. warning::
Declaring multiple external connections between the same endpoint pair
is not supported. If there are multiple pin models which one is chosen
may be arbitrary.
.. note::
VirtualConnection can be used to override default models for other
connections. e.g. If two features overlap and have an VirtualConnection
defined, the VirtualConnection's pin model will be used instead of the
generated model for touching features. This can be used to override
route models in cases where VirtualConnection and route are allowed at
the same time. Though routes will need to be forced since autorouter
will consider the endpoints already connected.
"""
source: ConnectionEndpoint | Port | Pad | Via
"""One endpoint of the external connection. Must be a single-pin
:class:`~jitx.net.Port`, :class:`~jitx.landpattern.Pad`, or
:class:`~jitx.via.Via`."""
destination: ConnectionEndpoint | Port | Pad | Via
"""The other endpoint of the external connection. Same type
constraints as :py:attr:`source`."""
source_layer: int
"""Copper layer at which the connection attaches to
:py:attr:`source`. ``0`` is the top layer; negative indices count
from the bottom (``-1`` is the bottom layer), like Python sequence
indexing. The two endpoints may be on different layers."""
destination_layer: int
"""Copper layer at which the connection attaches to
:py:attr:`destination`. Same conventions as
:py:attr:`source_layer`."""
pin_model: PinModel | None
"""Optional electrical characterization of the connection.
If omitted, the endpoints still count as connected (ratsnest and
unrouted warnings are suppressed), but the connection cannot satisfy
a constrained topology: length-matching, skew, or insertion-loss
constraints routed through a model-less external connection surface
may be reported as a missing-route error. If this connection sits inside a
constrained topology, provide a pin model.
Only the base :class:`~jitx.si.PinModel` delay/loss values are
consumed; the port bindings of :class:`~jitx.si.BridgingPinModel` /
:class:`~jitx.si.TerminatingPinModel` are ignored here, as the
connection's own endpoints determine what the model bridges.
"""
def __init__(
self,
source: ConnectionEndpoint | Port | Pad | Via,
destination: ConnectionEndpoint | Port | Pad | Via,
*,
source_layer: int,
destination_layer: int,
pin_model: PinModel | None = None,
):
_check_endpoint(source, "source")
_check_endpoint(destination, "destination")
self.source = source
self.destination = destination
self.source_layer = source_layer
self.destination_layer = destination_layer
self.pin_model = pin_model