JITX Versal FPGA from the Vendor Pin File Runbook (JS1 · Part 2)#
Goal (for the agent): In a fresh JITX Python project, model the AMD Versal Premium VP1002
FPGA in the NFVI1369 package — a 1369-ball, full 37×37-grid BGA — and wrap it in a circuit
that exposes its power rails, ground domains, and six GTM transceiver quads as JITX-native
boundary ports. At this pin count you do not transcribe a ball map: you parse AMD’s
machine-readable package pinout file and generate the component, then verify the generation.
The pinout file is the only ground truth for pin names, balls, and banks; AM013 (AMD’s Versal
packaging manual) is the only ground truth for package geometry. Estimate nothing; if the data doesn’t say it, ask me.
Don’t open this kit’s reference module (jitxexamples.jumpstart_kits.js1_stackup_components.versal_fpga)
or anything in it, even where a skill offers it as an example: it is a finished answer to this task.
Follow the steps in order; nothing is done until it passes its checks and jitx design build <non-test design target>. Where a step
is marked [HUMAN], stop and wait for me — do not proceed until I confirm.
Assumptions / prerequisites
The
jitxlibrary your project resolves should sit on the same release line as the CLI — if pip lands a different line, say so rather than silently proceeding.Python 3.12+ and
gitare available; the agent can run shell commands and fetch files from AMD.pip install pymupdfavailable for extracting AM013 pages (the component-modeler skill uses it).
Starting instructions — the pattern you are building#
These are the instructions this task executes. Read them before step 0. The generic pattern lives in the component-modeler skill and the steps below delegate to it by section name — read those sections when a step names one, rather than working from the summary here.
The recipe#
Download the package pinout file and the AM013 packaging manual — the two ground truths.
Write a stdlib-only generator that parses, reconciles, and emits the component as declarative Python. The generator is committed; the AMD file is not.
Build the land pattern from AM013 with the stock JITX BGA generator.
Partition the schematic symbols by bank.
Wrap the component in a circuit that exposes rails, ground domains and GTM quads as JITX-native boundary ports.
Verify at every stage:
pyright→pytest→jitx design build <non-test design target>→ thejitx-code-reviewskill.
What this task supplies#
The component-modeler skill carries the pattern — Generating a component from a machine-readable
vendor pin file, plus references/pin-file-generation.md for the generator shape, and the
BGAs section of references/component-guide.md, and the BGA docstring in
jitxlib.landpatterns.generators.bga for the land pattern. Drive it; don’t
re-derive it. What is specific to this task:
The part: AMD Versal Premium VP1002 in NFVI1369 — 1369 balls on a full 37×37 grid, 0.92 mm pitch. Six GTM transceiver quads (banks 202–207), GTY quads on banks 103/105, XPIO south (700–702), PS/config north (500–503).
Two ground truths, and neither substitutes for the other. The pinout file is the only authority for pin names, balls and banks. AM013 is the only authority for package geometry and for which transceiver group each quad belongs to. Estimate nothing; if the data doesn’t say it, ask me.
The row alphabet: radix-20 over
ABCDEFGHJKLMNPRTUVWY(I/O/Q/S/X/Z skipped) — A=0, Y=19, AA=20, AU=36. The corners areA1andAU37, both GND.Three ground domains that never merge: main
GND,GND_SMON(sysmon analog return), andGND_SENSE(VCCINT Kelvin return). Each takes only its own dedicated ball plus its rails’Vn.The bundle shape:
GTMQuad= 4 ×LanePair+ 2 × REFCLKDiffPair, in thejitx.commonstyle. The GT bias pins stay outside it — see step 11.The symbol-box ceiling for this part is 64 pins, which puts GND in 11 chunks.
Vendor files: link the URL, never commit the file. The AMD pinout file lives in the gitignored
.context/; the generated module records its sha256 and the AMD URLs.
Verify (before anything counts as done)#
pyright # expect zero errors and zero suppressions
pytest # the skill's test shape, plus this task's additions
jitx design build <non-test design target> # both designs: component viewer + circuit wrapper
A pyright: ignore you feel you need is a finding to report, not a way to reach zero. Run the
jitx-code-review skill before the final commit — on this pattern it catches string-keyed models
and port-storage mistakes that happy-path tests miss.
Steps#
0 · Preflight.
Read this runbook’s revision out of the HTML comment at the top of the file and tell me what it is,
so the run is pinned to a known version of the kit. This task drives the component modeler, and
for step 11 the circuit builder — invoke the base jitx skill first, then the component
modeler, and confirm both are invocable before you start.
--dry is not a substitute for the build gates in steps 9 and 12.
1 · Scaffold a fresh project.
Create a new project directory and run jitx project layout init, then set up the project
environment inside it:
# macOS / Linux
python3 -m venv .venv && source .venv/bin/activate
# Windows (PowerShell)
$env:PYTHONUTF8 = "1"; py -3 -m venv .venv; .\.venv\Scripts\Activate.ps1
pip install jitx
jitx project dependencies upgrade
jitx runtime start --background
jitx design find
Build the seeded non-test target from jitx design find — ignore any target whose module path comes from
test, tests, or a test file. Take the target verbatim from jitx design find — the two halves are
derived differently, so don’t assemble it yourself: the package is the directory lowercased with
hyphens and spaces turned into underscores, while the design class is that same name in CapWords. A
directory called js1-versal-fpga builds as jitx design build js1_versal_fpga.main.Js1VersalFpga. This
smoke test must succeed before you write any code of your own. If it fails, stop and tell me. Then
prepare the project: create tests/, add pytest and pyright as dev dependencies, and git init
if you want version control. Leave the seeded .gitignore as it is.
Run pyright inside this venv, every time. The “pyright clean” gate in steps 9 and 12 means
clean here. Run it against any other interpreter and it reports every JITX import as unresolved —
that is pyright telling you it is looking at the wrong Python, not that the imports are wrong, and a
run that stops at import errors has type-checked almost nothing.
2 · Fetch the ground truth.
Download into .context/ (gitignored — link URLs in docstrings, never commit vendor files):
The xcvp1002 NFVI1369 package pinout file,
xcvp1002nfvi1369pkg.txt. The landing page is Versal Adaptive SoC Package Device Pinout Files, but it is a JS-driven page containing zero.txtlinks —curl+ grep finds nothing, which looks like a login wall and isn’t. The download table is populated from a JSON index:https://download.amd.com/json/adaptive-socs-and-fpgas/developer/resources/package-pinout-files/versal-package-device-pinout-files.json. Resolve the current file path from there. Historical links undervppackages/are dead — that directory is nowversal/.AM013, the Versal Packaging and Pinouts manual (https://docs.amd.com/r/en-US/am013-versal-pkg-pinout). You need three things, and per the skill’s “Cite by caption first, figure number second”, find each by grepping for its caption — this is a living document and the numbers move between editions:
the figure captioned “Package Dimensions for NFVI1369” (mechanical drawing);
the table captioned “BGA Package Design Rules” (PCB land rules);
the figure captioned “VP1002 Banks in NFVI1369 Package” — the bank diagram. It carries the
[L]/[RS]transceiver power-supply-group tag per quad, and the(RCAL)marker on the quad that owns each calibration pair. Nothing else states which supply group serves a given quad, and this is what makes step 13’s question answerable.
Record the caption, edition and page for each in the code that uses it. This document really does renumber: the mechanical figure was Figure 246 in one edition, and in a later one Figure 246 is a different package’s diagram.
If a URL is dead, find the current equivalent on amd.com and tell me what you used — and say whether you hit a moved document or an egress problem.
3 · [HUMAN] Confirm device, package, and MPN.
Tell me the device/package the pinout file’s header identifies and its total pin count, and
confirm: VP1002, NFVI1369, 1369 balls. AM013 documents other VP1002 packages (SBRJ1369,
SBVJ1369, VFVF1760) and AMD’s download index offers a different set again — “packages AM013
documents” and “packages AMD publishes a pinout file for” are not the same list. We are building
only NFVI1369; SBVJ1369 is the confusable name, same ball count.
Also tell me what you intend to use as the mpn, per the skill’s “When no document states an
MPN”. Neither ground-truth document contains one: the pinout header gives a device string
(xcvp1002nfvi1369), and a real orderable AMD part number additionally encodes speed grade and
temperature range, which are procurement decisions. Say what your proposed value does and does not
identify. Wait for my approval.
4 · Parse and inventory — no component code yet.
Write the generator’s parsing stage (stdlib only), following the skill’s
references/pin-file-generation.md: whitespace-split the 7-column rows, decode every ball
reference to zero-indexed (row, col) with a round-trip self-check, and reconcile: row count ==
the file’s “Total Number of Pins” footer == 1369, unique balls, full 37×37 grid. Classify names:
repeated → rail lists; unique → scalar ports.
Print an inventory table (group → ball count → kind) whose groups partition the balls — every
ball in exactly one group — summing to 1369, plus the GTM quad roster. The overlap to resolve here
is VCCO_<bank>, which is both a rail and a member of its bank: count it once. Exclude each bank’s
own VCCO rail from the bank row (so bank 500 shows 26 of its 28) and say that’s what you did.
If it doesn’t reconcile, show me the gap — don’t guess your way to 1369.
5 · [HUMAN] Approve the inventory. Show me the partitioned inventory table and the reconciliation line. I’m checking: total is 1369; GND is 689; NC is 60; 31 supply rails; six GTM quads (banks 202–207); banks {103, 105, 109, 500–503, 700–702}. Wait for my approval before any code is emitted.
6 · Emit the component.
Extend the generator to emit xcvp1002.py, per the skill’s “What the emitted module holds”:
scalar Port() per unique pin (grouped by bank with section comments), indexed lists per rail,
ball_assignments() yielding every (port, coordinate) pair with the ball reference as a trailing
comment, coordinate tables under # fmt: off, the structural gtm_quad_pins() dict,
symbol_partitions(), and a header recording the source file name, its sha256, and the AMD URLs.
Mark the 60 NC balls no_connect() — they are open per AMD, and an ordinary Port() makes that
indistinguishable from a board designer forgetting to wire them. Output must be deterministic and
ruff format-stable per the skill’s rule for emitted collections, with a --check mode that
regenerates and diffs. Read the pin file and write the module with explicit encoding="utf-8" and
newline="\n" — the platform defaults (cp1252, CRLF on Windows) are what make --check drift
between machines. Run the generator; commit the generated module.
7 · Build the land pattern — read the drawing, then the fine print.
From the figure captioned “Package Dimensions for NFVI1369” take body 35×35 mm, height
3.43/3.63/3.83, pitch 0.92, matrix 37. Now the trap: that same figure gives the physical ball
Øb = 0.50/0.64/0.70 mm, but the JITX BGA generator’s ball_diameter argument sets the copper land
diameter of the PCB pad. Open the jitxlib BGA generator source and confirm what the parameter
drives, then take the land from the table captioned “BGA Package Design Rules” (0.92 mm pitch →
0.51 mm max PCB solder land, NSMD). The same row gives a 0.61 mm solder-mask opening: decide
whether you set it per pad or let the substrate’s registration rules size the mask at build time,
and record which in the same comment — either is defensible, an unrecorded default is not. State
in a comment where each number came from, caption first. Build landpattern.py with a
VersalBGA(BGA) subclass adding the public get_pad(row, column) adapter per the skill’s BGA notes — both arguments zero-indexed, matching the coordinates
the generated module carries, so ball A1 is get_pad(0, 0) and the framework’s 1-based column
offset lives inside the adapter rather than at every call site.
8 · Partition the symbols.
1369 pins is ~34× past the ~40-pin single-box threshold, so follow the skill’s Multi-Unit
Symbols guidance for parts at this scale. This part’s partition: one box per IO bank (signals
split left/right, VCCO_<bank> down), one per GT quad (RX left, TX + REFCLK right, bias pins down),
one for the dedicated/analog singletons, rails chunked at the 64-pin ceiling (GND → 11 chunks).
build_symbols turns partitions into BoxSymbols; the design puts each on its own schematic page
via SchematicGroup.
9 · Verify the component.
Write the tests per the skill’s “Testing a generated component”, with this task’s literals: 1369
ports == assignments == pads, the per-rail counts from your step-4 inventory, ~10 hand-read spot
checks spanning A1, AU37, a double-letter row and one pin per bank type. Follow that section’s
cached-instantiation requirement rather than one build per assertion — at this pin count it is the
difference between a suite of seconds and one that times out. Then: pyright →
pytest → jitx design build <non-test symbol-viewer design target> (expect status: ok) → run the
jitx-code-review skill, fix every CRITICAL finding and each WARNING you can, and report every
result, with the reason for each WARNING you keep. Commit when green.
10 · [HUMAN] Spot-check the balls.
Show me, side by side with the pinout file: the corners A1 and AU37 (both GND); one ball
per bank type (a GTM lane, a GTY refclk, a PMC_MIO, an LPD_MIO, an XPIO pin); both sysmon pairs
(VP/VN_500, VREFP/VREFN_500); and two GNDs from opposite corners — each as
ball → (row, col) → port → pad. Also show the geometry cross-check: the A1↔AU37 pad centers
must be 36 × 0.92 = 33.12 mm apart on both axes (the drawing’s D1/E1) — and signed: read each
pad’s transform and show A1 and AU37 at opposite corners, because the unsigned distance alone
passes a mirrored grid. Put that signed check in the tests too. Wait for my approval.
11 · Wrap the circuit.
Drive the jitx-circuit-builder skill. Create bundles.py (GTMQuad: 4 ×
jitx.common.LanePair — upper-case TX/RX sub-ports with lower-case p/n inside — + 2 ×
REFCLK DiffPair) and circuit.py (XCVP1002Circuit): one Power() port per supply rail from your
step-4 inventory — no rail invented, none dropped; a rail_ties() roster method; three ground
domains (main GND takes all 689 GND + 2 RSVDGND + every main rail’s Vn; GND_SMON and
GND_SENSE take only their dedicated ball + their rail’s Vn); sysmon inputs and the six GT
bias pins as pass-through boundary ports; self.gtm: dict[int, GTMQuad] wired lane-for-lane
with plain nets (+) against the generated gtm_quad_pins().
Read the MCU / FPGA power-domain checklist in the jitx-project-builder skill and walk it here
(read it; this step does not invoke that skill). It owns the general rules. Where this part
instantiates them:
31 rails, not 27.
VCCINT_SENSE,VCCAUX_SMON,VCC_BATTandVCC_FUSEget one ball each, so they land as scalar ports rather than rail lists. Two of the four carry the returns that defineGND_SMONandGND_SENSE, so a roster built by walking the rail lists both undercounts and silently collapses the three-ground requirement.The six GT bias pins live in banks 109, 203 and 105 —
GTM_AVTTRCAL_L,GTM_RREF_L,GTM_AVTTRCAL_RN,GTM_RREF_RN,GTY_AVTTRCAL_RS,GTY_RREF_RS; 109 carries its pair and no lanes at all. They serve whole supply groups, so keep them out ofGTMQuad: model them per-quad and four of the six quads have none.The
_L/_RSgroup tags come from the bank diagram, not the pin file — including which groups have no bonded quad in this package.
Join each rail’s balls to its net through a Net. A rail is a Python list of ports, and +=
takes a port or a Net, never a bare list, so wrap the list: Net(rail_list), or
net += Net(rail_list) onto an existing net. About 940 balls pass through here, so the bare-list
form is the first thing you will reach for and the first thing that breaks.
And name the boundary rail ports distinctly from the net names (pwr_vccint, not VCCINT) — a
named net colliding with a public port name fails only in the full runtime build (“Public name
already in use”); jitx design build --dry cannot see it.
12 · Verify the circuit.
Extend the tests (rail roster + sizes, ground-domain separation, 6 quads × 20 nets and,
for at least one quad, that each net’s two endpoints are the expected bundle sub-port and component
ball — a count alone passes a lane- or polarity-swapped wiring; circuit design translates), then
pyright → pytest → jitx design build <non-test circuit design target> →
jitx-code-review, under step 9’s code-review rule. Commit when green.
13 · [HUMAN] Close the loop.
The wrapper is what a board design consumes; show me. Invite me to ask for something —
suggest I say: “give me GTM quad 205 as a 4-lane bundle and tell me which power rails and bias
pins it needs.” Wait for me to ask. Answer from the built circuit (bundle port, rail ties,
bias pass-throughs), then open the schematic viewer (jitx ui open --schematic, in the background
— it blocks while its window is open, see JS0 step 5) and tell me the bank-205 page to look at: the
CLI opens the design, not a page, so I navigate there in the viewer.
This answer goes through a gate like every other step. State which document each claim comes from; anything not derivable from the built design or the step-2 documents, say so rather than asserting it. The bundle half of that question is answerable from the design; the rails half is not — it needs the bank diagram’s supply-group tag, which is why step 2 fetches it. An answer assembled from ball proximity or from a matching name suffix can be right here and wrong on the next package, and it reaches me looking exactly like a verified one.
Done when#
A fresh project builds, with
.context/gitignored and no AMD files committed; the generated module records the pinout file’s sha256 and URLs.The generator reconciles 1369/1369 with a printed inventory whose groups partition the balls, emits deterministically, and its
--checkmode passes against the committed module.Every ball has exactly one
Port(scalar or indexed rail list), the 60 NC balls areno_connect(), and the land pattern uses the Package Dimensions for NFVI1369 body dimensions with the BGA Package Design Rules land diameter (not the physical ball) — each cited by caption, edition and page.Symbols cover all 1369 pins, one partition each, none over 64; each bank/quad has its own box.
XCVP1002Circuitexposes all 31 supply rails asPowerports — including the four single-ball ones — with three distinct ground domains, and all six GTM quads as bundles wired through the structural pin groupings; zerogetattranywhere.pyrightclean with no suppressions,pytestgreen — with the regeneration-idempotency test confirmed to have run, not skipped — and both non-test designsjitx design buildwithstatus: ok.After step 9 and again after step 12,
jitx-code-reviewleaves no CRITICAL finding (every result reported, with the reason for each WARNING kept).The component carries the skill’s filled Component completeness check block, written next to the code, with the agreed
mpnand what it identifies recorded in itsIdentityrow.A live prompted request (e.g. GTM quad 205’s bundle + rails) is answered from the built design, with a source named for every claim not in it.