Source code for jitxexamples.jumpstart_kits.js4_fpga_lpddr4x.fpga

"""The JS1 VP1002 with one LPDDR4X x32 interface offered on banks 702 and 701.

The offer is the rule set in :py:mod:`.pinout`, layout
:py:data:`~.pinout.OPTIMUM_X32_FLIPPED`, built as two levels of ``provide``:

- Per byte slot, :py:class:`~.bundles.Slot0Bit` to ``Slot3Bit``: each of the
  slot's eight DQ pins, offered with ``all_of``. Taking eight of them in any
  order is rule 3, the bit swap within a byte.
- :py:class:`~.bundles.VersalLPDDR4X`, offered with ``one_of``: four options,
  one per allowed byte-to-slot order (rule 4, the byte swap within a
  channel). Each option maps the fixed pins, the slot's DQS and DMI, and the
  eight DQ ports to eight pins required from the slot.

Together they offer every byte swap and bit swap the rules allow on this
layout: :py:func:`~.pinout.assignment_count` assignments. The layout's
positions are those of channel 0 on AMD's VMK180, VCK190 and VPK120 boards,
CS1 aside on the single rank VCK190 (see :py:mod:`.pinout`, "Inferred from the boards"); the chosen assignment
is still validated in Vivado. The jitx-pin-assignment skill covers the
pattern (hierarchical provider composition).
"""

from jitx.net import DiffPair, Port, Provide

from ..js1_stackup_components.versal_fpga.circuit import XCVP1002Circuit
from .bundles import SLOT_BITS, VersalLPDDR4X
from .pinout import OPTIMUM_X32_FLIPPED, Pos


[docs] class VP1002LPDDR4X(XCVP1002Circuit): """JS1's VP1002 circuit plus the LPDDR4X offer and its system clock. ``sys_clk`` is the DDRMC's differential system clock input (PG313 rule 9), on the fixed sys_clk pins of the layout. Net it to a clock source. """ sys_clk = DiffPair() def __init__(self) -> None: super().__init__() layout = OPTIMUM_X32_FLIPPED self.SYS_CLK_P = self.sys_clk.p + self._pin(layout.fixed["SYS_CLK_P"]) self.SYS_CLK_N = self.sys_clk.n + self._pin(layout.fixed["SYS_CLK_N"]) self.slot_bits = [ Provide(bit).all_of( lambda b, slot=slot: [{b.p: self._pin(pos)} for pos in slot.dq] ) for bit, slot in zip(SLOT_BITS, layout.slots, strict=True) ] self.lpddr4x = Provide(VersalLPDDR4X).one_of(self._options) def _pin(self, pos: Pos) -> Port: """The VP1002 port at a position of triplet M0 (banks 700 to 702).""" return self.fpga.xpio_triplet_pins()[0][pos.index].port def _options(self, bus: VersalLPDDR4X) -> list[dict[Port, Port]]: layout = OPTIMUM_X32_FLIPPED def at(name: str) -> Port: return self._pin(layout.fixed[name]) fixed: dict[Port, Port] = {bus.reset_n: at("RESET_N")} for ch, c in zip(bus.ch, "AB", strict=True): fixed[ch.ck.p] = at(f"CK_T_{c}") fixed[ch.ck.n] = at(f"CK_C_{c}") fixed[ch.cke] = at(f"CKE_{c}") for rank, cs in enumerate(ch.cs): fixed[cs] = at(f"CS{rank}_{c}") for i, ca in enumerate(ch.ca): fixed[ca] = at(f"CA{i}_{c}") bits = [[b.p for b in self.require(bit, count=8)] for bit in SLOT_BITS] lanes = [lane for ch in bus.ch for lane in ch.d] # bytes 0 to 3 options: list[dict[Port, Port]] = [] for order in layout.byte_orders(): option = dict(fixed) for lane, slot_index in zip(lanes, order, strict=True): slot = layout.slots[slot_index] option[lane.dqs.p] = self._pin(slot.dqs_t) option[lane.dqs.n] = self._pin(slot.dqs_c) option[lane.dmi] = self._pin(slot.dmi) for dq, pin in zip(lane.dq, bits[slot_index], strict=True): option[dq] = pin options.append(option) return options