pin_series_array module#

Channel choice through a pass-through part, with both sides in one mapping.

Use this pattern when signals pass through a part whose channels are interchangeable, and choosing a channel fixes a pin on each side of the part. Here a 4-bit bus runs from a driver to a receiver through a 4-channel series termination array; any channel may carry any bit, but a bit enters and leaves on the same channel. Four pieces compose:

  1. A bundle over both sides. ArrayChannel has a driver-side port a and a receiver-side port b. Each offered mapping sets both, so one choice moves both ends of the channel together. Two separate offers, one per side, could pick different channels for the two ends of a bit.

  2. The provider. SeriesTermination offers ArrayChannel with @provide (all_of): one option per channel, each usable once, all usable together. The consumer takes four with require(ArrayChannel, count=4) and keeps them local.

  3. The pin model. Each channel carries a BridgingPinModel from a[i] to b[i]; without one the path stops at the array.

  4. The constraints, on fixed physical ends either side of the assigned part: Constrain(Topology(drv.d[i], rcv.d[i])) per bit, and ConstrainReferenceDifference for bus skew with bit 0 as the single-pin guide. While the assignment is unresolved, a bit reports No path for signal constraint.

The shipping design, SeriesArrayDesign, has no placement and no routes. The verification designs place the parts and close every bit with code Routes that end on the array’s physical pins:

  • SwappedChannelsProof: bits 0 and 1 swap channels (bit 0 on channel 1, bit 1 on channel 0), the same on both sides. Offered, so every bit measures.

  • SidesDisagreeIllegal: the driver side as in the swapped proof, the receiver side straight. Bits 0 and 1 enter on one channel and leave on another, which no option offers, so two of their four routes are dropped and both bits have no path; bits 2 and 3 still measure.

Every part is fictional, not a real product. The array’s 5 ps and 0.05 dB per channel, the 1 ns delay budget and the 10 ps bus skew window are illustrative values; take real ones from the part’s datasheet and the interface’s timing budget.

To check it, save this as a script in the project root and run it with the project’s runtime running:

import jitx

from jitxexamples.patterns.pin_series_array import SwappedChannelsProof


def main() -> None:
    with jitx.runtime as rt:
        report = rt.submit(SwappedChannelsProof).issues(satisfied=True, wait=30)
        if not report.complete:
            print("report incomplete: raise wait and run again")
        for group in report.groups():
            print("met" if group.satisfied else "NOT MET", group.text)
            if len(group.issues) > 1:
                for issue in group:
                    print("   ", issue.text)


if __name__ == "__main__":
    main()

The real output for each design, on jitx 4.6.0rc10 against runtime 4.6.0-rc.16 (the shipping design and the two verification designs):

SeriesArrayDesign:

NOT MET No path for signal constraint from drv.d[0] to rcv.d[0]
NOT MET No path for signal constraint from drv.d[1] to rcv.d[1]
NOT MET No path for signal constraint from drv.d[2] to rcv.d[2]
NOT MET No path for signal constraint from drv.d[3] to rcv.d[3]
met Satisfied

SwappedChannelsProof:

met Time: 74.729ps - Target: 500ps ± 500ps from dut.drv.d[0] to dut.rcv.d[0]
met Time: 97.061ps - Target: 500ps ± 500ps from dut.drv.d[1] to dut.rcv.d[1]
met Time: 73.144ps - Target: 500ps ± 500ps from dut.drv.d[2] to dut.rcv.d[2]
met Time: 73.144ps - Target: 500ps ± 500ps from dut.drv.d[3] to dut.rcv.d[3]
NOT MET Skew: 22.332ps - Target: ± 10ps (longer from dut.drv.d[1] to dut.rcv.d[1], shorter from dut.drv.d[0] to dut.rcv.d[0])
met Skew: 1.585ps - Target: ± 10ps (longer from dut.drv.d[0] to dut.rcv.d[0], shorter from dut.drv.d[2] to dut.rcv.d[2])
met Skew: 1.585ps - Target: ± 10ps (longer from dut.drv.d[0] to dut.rcv.d[0], shorter from dut.drv.d[3] to dut.rcv.d[3])
met Satisfied

SidesDisagreeIllegal:

met Time: 73.144ps - Target: 500ps ± 500ps from dut.drv.d[2] to dut.rcv.d[2]
met Time: 73.144ps - Target: 500ps ± 500ps from dut.drv.d[3] to dut.rcv.d[3]
NOT MET No path for signal constraint from dut.drv.d[0] to dut.rcv.d[0]
NOT MET No path for signal constraint from dut.drv.d[1] to dut.rcv.d[1]
NOT MET 2 issues: Code route dropped: it conflicts with other connections
    Code route dropped: it conflicts with other connections
    Code route dropped: it conflicts with other connections

Bit 1’s skew against bit 0 misses its window because the swapped routes cross on one layer and come out unequal: the constraint bound, and this routing fails it; read group.satisfied, not the text. In the illegal design bits 0 and 1 have no path, so the bus skew, guided by bit 0, has no line at all.

BITS = 4#

Bus width, and the array’s channel count.

ARRAY_DELAY = 5e-12#

5 ps through each array channel.

Type:

Illustrative

ARRAY_LOSS = 0.05#

0.05 dB through each array channel.

Type:

Illustrative

BIT_DELAY_BUDGET = 1e-09#

1 ns from driver to receiver.

Type:

Illustrative

BUS_SKEW = Toleranced(0, 1e-11, 1e-11)#

each bit within 10 ps of bit 0.

Type:

Illustrative

STRAIGHT: tuple[int, ...] = (0, 1, 2, 3)#

bit i on channel i.

Type:

Array channel for each bit, bit 0 first

SWAPPED: tuple[int, ...] = (1, 0, 2, 3)#

Bits 0 and 1 exchange channels.

class BusDriver[source]#

Bases: Component

Fictional 4-bit bus driver. Not a real part.

d = [Port(), Port(), Port(), Port()]#
gnd = Port()#
class BusReceiver[source]#

Bases: Component

Fictional 4-bit bus receiver. Not a real part.

d = [Port(), Port(), Port(), Port()]#
gnd = Port()#
class SeriesArray4[source]#

Bases: Component

Fictional 4-channel series termination array: channel i runs from a[i] to b[i], and the channels are identical. Not a real part; its pin-model values are illustrative.

a = [Port(), Port(), Port(), Port()]#
b = [Port(), Port(), Port(), Port()]#
class ArrayChannel[source]#

Bases: Port

One array channel, both sides: a faces the driver, b the receiver.

a = Port()#
b = Port()#
class SeriesTermination[source]#

Bases: Circuit

The provider: every channel of the array, each offered once.

channel = PrePostInit#
class SeriesArrayBus[source]#

Bases: Circuit

Driver to receiver through the array, every bit constrained. Unplaced and route-free, so the channel choice stays open.

class SeriesArrayDesign(*args, **kwargs)[source]#

Bases: SampleDesign

The shipping design: no placement, no routes.

circuit: Circuit = SeriesArrayBus()#
class SeriesArrayProof(drv_side, rcv_side)[source]#

Bases: Circuit

SeriesArrayBus placed, with code routes on chosen array channels: bit i enters on drv_side[i] and leaves on rcv_side[i].

Parameters:
class SwappedChannelsProof[source]#

Bases: SampleDesign

Bits 0 and 1 on each other’s channel, both sides: offered, so every bit measures.

class SidesDisagreeIllegal[source]#

Bases: SampleDesign

Driver side swapped, receiver side straight: bits 0 and 1 change channel inside the part, which is not offered, so their routes drop.