Skip to content

KDI v0.1.0 — frame format 2 (self-describing container)

Choose a tag to compare

@NickelLiang NickelLiang released this 02 Aug 21:48
· 19 commits to main since this release

Frame format 2. decode needs no descriptor: every length, lane identity, element width and cadence is on the wire.

⚠️ Not yet emitted by gateware. No shipping bitstream produces format 2, and the device leaves the clean_frame capability bit clear — so a host that requires the clean frame will correctly refuse to bind to today's hardware. The format is published ahead of the emitter, on purpose, so that it is fixed before anything binds to it. The control plane in this descriptor is hardware-verified.

The container

32 B header   magic | format=2 | flags | timestamp u48 | frame_words | layout |
              hdr_words | n_sections | run_id | contract_rev | desc_words
descriptors   n × 16 B, stride taken FROM THE WIRE so it can grow again
lane ids      Σ n_lanes × u16 · bodies element-major (1/16/32/64-bit) · CRC-32 trailer
  • magic is a resync anchor only, never a validity test. Validity is CRC + declared length + timestamp continuity. Host-side that is one call: zlib.crc32(frame) == 0x2144DF1C.
  • A new module type is a new kind, skipped by section_words — additive, no decoder change, no version bump. An unknown format is skippable too, by frame_words: magic, format and frame_words are frozen at their offsets for every future format.
  • Cadence is an exact rational (tick_num/tick_den; 30 kHz = 10000/3). Rate is never normative in this contract — the timebase is, so a hardware rate change needs no contract change.
  • One shared 48-bit timebase at 10 ns, sampled per frame, epoch per run paired with run_id. Aligning two streams is exact integer subtraction — no sync channel, no per-stream linear fit. The frame-to-frame delta jitters (3333/3334 at 30 kHz) and there is deliberately no constant-delta invariant, because at 30 kS/s one is not implementable.
  • Digital input is bit-packed: 16 lines cost one word, every bit named by its own lane id — no host-side slot→bit formula.
  • to_device is reserved (declared, unimplemented) — the container is direction-agnostic.

Testable in both directions

vectors/golden_frame.json now ships 7 negative frames alongside the good one, each with the normative reason token it must be rejected with (crc_err, reserved_bits, tick_sane, timestamp_top16, desc_words, section_words). A decoder can be proven to reject what it must, not merely accept what it should.

Known limitation, published deliberately

Digital-in levels are sampled at the end of the frame that carries them, so they trail their own timestamp by up to one frame period, and the offset varies with the enabled lane count. Derived from RTL, not bench-measured. A future emitter latches at frame start and this note tightens.

Breaking

Format 1 frames no longer decode. Safe now because nothing has bound. kdi: stays 0.1 — it is the command-set version, and no command changed.

Conformance: 12/12 pass. Source: keyvast-fpga@d567775.