Skip to content

VINO: IndyCam capture end-to-end on IRIX 6.5#28

Merged
techomancer merged 6 commits into
techomancer:mainfrom
hanshuebner:pr/vino-indycam-6.5
May 31, 2026
Merged

VINO: IndyCam capture end-to-end on IRIX 6.5#28
techomancer merged 6 commits into
techomancer:mainfrom
hanshuebner:pr/vino-indycam-6.5

Conversation

@hanshuebner
Copy link
Copy Markdown
Contributor

Makes vidtomem / Media Recorder capture a clean, correctly-coloured 640×480 frame from the IndyCam (or the test-pattern source) on IRIX 6.5.22 — previously the VL client never received a frame on 6.5.

Changes (src/):

  • physical.rs — map the uncached 0x4000_0000 alias of low RAM, so the 6.5 driver's descriptor-ring polling resolves instead of flooding MC bus errors. Capture now engages and DESC/EOF fire.
  • vino.rs — deliver + unscramble: defer the first interlaced field's STOP/DESC (EOF only) and complete on the second so the kernel's field-pairing wakes vinoGetFrame; report CH_DESC_TABLE_PTR at the kernel's field-boundary descriptor on the 2nd field so the buffer-completion check doesn't abort; 16-byte-align the jump-bug JUMP target so all 300 data pages land in order.
  • camera.rs — read the nokhwa YUYV chroma straight (standard Cb/Cr order); the prior U/V swap had been masking the RGBA byte-order bug and caused red↔blue once that was fixed.

Plus tools/vino/ (guest-side debug helpers: vinograb, chaindump, chainwalk, mempeek, vinodump) and the full investigation writeup in rules/irix/.

Verified live on 6.5.22: test-pattern shows correct SMPTE bars; live camera shows correct colour. No 5.3 regression in the unit tests; the interlace/STOP changes are gated to the 6.5 path.

🤖 Generated with Claude Code

hanshuebner and others added 5 commits May 31, 2026 14:58
… alias

The IRIX 6.5 vino driver polls the VINO DMA descriptor ring through the
uncached 0x4000_0000 alias of RAM. The bus dispatch never mapped that
alias, so those reads/writes missed — flooding "MC: CPU Error at 48621cf0"
and capture never engaged. Map it (addr & 0xC000_0000 == 0x4000_0000 ->
addr & !0x4000_0000) at the head of every BusDevice dispatch method. With
this, 6.5 capture engages and the VINO DMA + DESC interrupt path runs.

Pure bus-alias fix; 5.3 is unaffected (it never uses the alias). End-to-end
frame delivery to videod is not yet complete; the remaining gate is in the
kernel buffer-completion / poll path, mapped in detail in
rules/irix/vino-capture-on-6.5-progress.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ndoff

Records the complete reverse-engineering of why videod doesn't deliver a frame
on 6.5 despite the DMA+interrupt path working: the gate reduces to a single
capture-mode config bit, *(conn+0x118)&1, which iris yields as set (0x27) so the
driver's only viable delivery route in vino.o 0x60b4 is closed. Adds a START-HERE
handoff block with the precise next step (trace vinoSetupGetFrame's s1/+0x3a) and
the definitively-excluded dead ends (field_counter, parity, EOF/DESC, buffer ring).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
videod/vidtomem now receives a clean, correctly-coloured 640x480 frame on
IRIX 6.5 (verified live with the test-pattern source). Four fixes in the VINO
DMA/interrupt path, building on the committed 0x4000_0000 uncached-alias fix
(8426efd):

- dma_emit_dword: on an interlaced capture, defer the first field's STOP/DESC
  (raise EOF only) and complete on the second field (EOF+DESC, disable DMA).
  This makes the kernel driver's field-parity counter reach odd and clears its
  per-capture "first field" flag (conn+0xb8), the precondition for delivery.

- read_channel_reg: report CH_DESC_TABLE_PTR = start_desc_ptr + field-boundary
  span on the second field, matching the value the kernel records at
  *(bufentry+0x10). The buffer-completion check (vino.o 0x77c0) then returns 1
  instead of aborting at 0x7640/0x7710, so the EOF handler 0x60b4 reaches its
  delivery tail, clears conn+0xc and wakes vinoGetFrame.

- shift_descriptors: 16-byte-align the jump-bug JUMP target (& 0x3FFF_FFF0).
  The jump-bug chain encodes a +4 offset in the target; following it unaligned
  dropped the first data page of every 4-descriptor group (~181 of 300 pages)
  and scrambled the frame. Aligning lands all 300 pages in order.

- render_and_pump: emit 32-bit RGB as A,B,G,R (was A,R,G,B), fixing a red/blue
  channel swap (yellow<->cyan, red<->blue) in the captured image.

Full investigation in rules/irix/vino-capture-on-6.5-progress.md (cont. 12-16).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
downscale_yuyv_to_uyvy was swapping U/V (reading Cr at byte 1, Cb at byte 3),
which had been compensating for VINO's RGBA output emitting A,R,G,B. Now that
the output order is fixed to A,B,G,R (correct, verified on the test pattern),
this swap is no longer cancelled and the live camera comes out red<->blue
(a red shirt renders blue). nokhwa's macOS backend delivers standard YUYV
(Cb at byte 1, Cr at byte 3), so read the chroma straight. The test pattern is
unaffected — it hand-builds canonical UYVY and never goes through this path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The C helpers used to drive and inspect IndyCam capture from inside IRIX
(compiled on the guest with MIPSpro cc): vinograb (VL one-frame grab),
chaindump/chainwalk (descriptor-chain dump/walk via /dev/mem), mempeek
(/dev/mem reader), vinodump (DMA-page reconstruction). Referenced from
rules/irix/vino-capture-on-6.5-progress.md.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@techomancer
Copy link
Copy Markdown
Owner

wait, i noticed the errors in 0x4000_0000 range, but why. there is no alias of low ram there. we must be misunderstanding how the hw works somewhere. are these memory accesses coming from vino or vdma?

…0 alias

PR review: there is no 0x40000000 alias of low RAM on the Indy. The errors in
that range were VINO DMA, not CPU accesses: descriptor_fetch and the DMA buffer
writes go through the Physical bus, and any unmapped address VINO drives is
routed to CpuBusErrorDevice — hence the misleading "MC: CPU Error at 48621cf0".

Root cause: the descriptor address field is only bits [29:4]; bit 31 is STOP and
bit 30 is JUMP. The 6.5 driver encodes pointers as JUMP_BIT | kvtophys(addr)
(vinoBuildJumpBugDAPS), so 0x4861e000 carries the JUMP control bit, not a real
address. desc::PTR_MASK was 0xFFFF_FFF0, wrongly keeping bits 31/30, so the
CH_NEXT_4_DESC / CH_DESC_TABLE_PTR register writes left bit 30 in
next_desc_ptr/start_desc_ptr and VINO fetched at 0x4861e000 — off into unmapped
space. (The JUMP target already masked 0x3FFF_FFF0 and was fine.)

Fix at the source: narrow desc::PTR_MASK to 0x3FFF_FFF0 so the pointer-register
writes and the data-buffer write address strip the control bits and resolve to
the real lomem address (0x0861e000, in RAM at 0x08000000). This removes the need
for the physical.rs alias_phys() hack, which had aliased the entire
0x40000000-0x7FFFFFFF window for every device on the bus.

- src/vino.rs: PTR_MASK 0xFFFF_FFF0 -> 0x3FFF_FFF0; JUMP target uses PTR_MASK;
  add desc_pointer_registers_strip_bit30_control_flag regression test.
- src/physical.rs: revert alias_phys() and its call sites.
- rules: rewrite Fix techomancer#1 to reflect the corrected (vdma, not CPU) understanding.

Indy RAM is 0x08000000..0x18000000, so a legitimate address never sets bits
31/30; 5.3 descriptors carry no control bits, so its path is unchanged. All 12
vino unit tests pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@hanshuebner
Copy link
Copy Markdown
Contributor Author

You were right on both counts — there's no 0x40000000 RAM alias, and the accesses are vdma, not the CPU.

Source of the accesses: VINO's descriptor_fetch and DMA buffer writes go through the Physical bus (Vino::set_phys). When VINO drives an unmapped address, Physical routes it to CpuBusErrorDevice, which is what prints MC: CPU Error at 48621cf0 — the "CPU" label is just because every unmapped access funnels through that one sink. So it was VINO DMA the whole time.

Why bit 30 was set: the descriptor address field is only bits [29:4]; bit 31 is STOP, bit 30 is JUMP. The 6.5 driver encodes its pointers as JUMP_BIT | kvtophys(addr) (vinoBuildJumpBugDAPS), so 0x4861e000 is really JUMP_BIT | 0x0861e000. The actual bug: desc::PTR_MASK was 0xFFFF_FFF0, keeping bits 31/30, so the CH_NEXT_4_DESC / CH_DESC_TABLE_PTR register writes left bit 30 in next_desc_ptr/start_desc_ptr and VINO fetched at 0x4861e000. (The JUMP target path already masked 0x3FFF_FFF0 and was correct.)

Fix (pushed): narrowed desc::PTR_MASK to 0x3FFF_FFF0 so the pointer-register writes and the data-buffer write address strip the control bits and resolve to the real lomem address (0x0861e000, in RAM at 0x08000000). Reverted alias_phys() from physical.rs entirely — no bus alias needed. Indy RAM is 0x08000000..0x18000000 so a legitimate address never sets bits 31/30, and 5.3 descriptors carry no control bits so its path is unchanged. Added a regression test (desc_pointer_registers_strip_bit30_control_flag); all 12 vino tests pass.

@techomancer techomancer merged commit 751a566 into techomancer:main May 31, 2026
1 check passed
@techomancer
Copy link
Copy Markdown
Owner

woohoo!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants