forked from opencode.energia.arti.ee/vt1200
The XIE path now runs end to end: XieCreateImage -> XieCreatePhoto ->
XiePutTile -> XieExport(photomap -> depth-1 pixmap) -> XCopyArea(pixmap ->
window), and the client's tile appears on screen at the client's own window
position, pixel-exact.
TWO FAULTS BEHIND THE LONG DEAD END
1. Device model (harness/mame/vt1200.cpp, opt-in VT1200_ACCEL=1). The
accelerator's output port 0x5600200 returns the pixel stream the firmware
pushed into the FIFO -- the firmware then stores it into the drawable itself
(file 0x125528: MOVE *B6,*B1 ; ADDK 0x10,B1). The FIFO read pointer was
never reset between transfers, so consecutive exports read stale words and
the same fill produced 759 then 516 set pixels. Reset m_fifo_in/out on the
data-register write; the export is now deterministic.
2. Measurement, not the device.
- dwt/screenshot.py without --real reads 1024x1024 at a 128-byte row stride,
but the VR319 default programs 1280x1024 at a 2048-bit (256-byte) pitch.
That is the "shifted" picture; --real is the correct read.
- The earlier "0 differing bytes over 128 KiB" VRAM comparison stepped peek
by 1024 *bit* addresses, so it scanned rows 0..63 only -- never the window
at rows 200..263. Over the real raster the white/black diff is 576 bytes
spanning exactly those rows.
- New instrument: decclient does a server-side XGetImage readback of the
pixmap and window and counts set pixels. That separated "the server never
drew it" from "the framebuffer view is wrong".
EVIDENCE (reproduced twice, the second time from a fresh machine)
no export vs 0xFF : 4096 / 4096 pixels differ
no export vs 0x00 : 0 / 4096 (the window background is black)
0xFF vs 0x00 : 4096 / 4096
0xAA vs 0x0F : 2048 / 4096 (the two stripe phases)
Tile byte 0xAA reproduces as 1-pixel vertical stripes, 0x0F as 4-pixel, with
no shear -- so the placement is right and the pixels are the client's.
Contents: xie/ holds DEC XIE 2.3 headers, 84 man pages and complete
client+server source; a libXie.a and decclient built from DEC's own code; the
XIE probes; and evidence/ with every measurement, including explicit
retractions of the earlier wrong readings (VRAM_IDENTICAL_FOR_BOTH_FILLS and
friends). xie/evidence/XIE_IMAGE_DISPLAYED.md is the report; frames are in
xie/evidence/png/.
The accelerator model stays opt-in: it answers the status poll and relays the
pixel stream, but performs no compositing, so it is a stand-in and the verified
default configuration is unchanged (a no-env run still parks in the level-0
diagnostics menu at PC=3FDCE400).
79 lines
3.6 KiB
Plaintext
79 lines
3.6 KiB
Plaintext
STRUCTURAL RESULT: a class-3 resource with a stored ID cannot be created through
|
|
slot 8 at all. The class and the registration are mutually exclusive inside the
|
|
only routine that produces either.
|
|
|
|
All offsets are FILE offsets (Ghidra addresses); the CALLA convention is
|
|
file = immediate - 0x7E40000 (verified: 0x7EA78DA -> 0x678DA).
|
|
|
|
1) slot 8 dispatches op 1 and op 2 to the SAME routine, file 0x678DA:
|
|
6696C DEC A8 ; JREQ 0x66912 op 1 ---\
|
|
66970 DEC A8 ; JREQ 0x66912 op 2 ---/ -> 0x7EA78DA
|
|
|
|
2) The only op-dependent value passed on is (op == 2) ? 1 : 0:
|
|
6799C MOVE *A9(0x20),A11,1 ; word0 = op
|
|
679A2 SUBK 0x2,A11
|
|
679A4 MOVK 0x1,A11
|
|
679A6 JREQ 0x679AA ; op==2 -> arg = 1
|
|
679A8 SUB A11,A11 ; else -> arg = 0
|
|
|
|
3) That flag alone decides the class, at 0x6CAF2 in file 0x6CA82:
|
|
6CAF2 MOVE *A13(0xfec0),A11,1 ; the flag
|
|
6CAF6 JREQ 0x6CAFC
|
|
6CAF8 MOVK 0x2,A11 ; flag != 0 -> class 2
|
|
6CAFA JR 0x6CAFE
|
|
6CAFC MOVK 0x3,A11 ; flag == 0 -> class 3
|
|
6CAFE MOVB *A11,*A9(0x20) ; obj->byte4 = class (0x20 bits = 4 bytes)
|
|
|
|
So class = 3 iff op == 1, and class = 2 iff op == 2.
|
|
|
|
4) The ID store and the table registration live ONLY in the loop body at 0x67AFC,
|
|
which is reached only when DSJ jumps:
|
|
67A20 MOVE *A9(0x20),A11,1 ; A11 = op
|
|
67A24 DSJ A11,0x00067afc ; op-1 != 0 -> jump to the registering body
|
|
67A28 ... ; op-1 == 0 -> photoflo path (see 5)
|
|
|
|
67AFC MOVE *A13(0x20),A11,1
|
|
67B00 JRNE 0x67B04
|
|
67B02 MOVE *A13,A11,1
|
|
67B04 MOVE *A9(0x40),*A11(0x0),1 ; *** ID -> obj+0 ***
|
|
67B0E MOVE @0x1ad980,A11,0
|
|
67B16 MOVI 0x3f566ed0,A7 ; the XIE handler pointer
|
|
67B1E MOVE *A13(0x20),A7,1
|
|
67B22 JRNE 0x67B26
|
|
67B24 MOVE *A13,A7,1
|
|
67B26 MOVE A7,*A14+
|
|
67B28 MOVE @0x1ad990,A7,0
|
|
67B30 MOVE *A9(0x40),*A14+ ; the id
|
|
67B34 CALLA 0x07f16ca2 ; *** register in the resource table ***
|
|
|
|
op = 1 -> DSJ decrements to 0, does not jump -> 0x67A28: the ID is NEVER
|
|
stored and the resource is NEVER registered.
|
|
op = 2 -> DSJ decrements to 1, jumps -> ID stored at obj+0 and registered.
|
|
|
|
5) What op=1 does instead is create a PHOTOflo, not a resource:
|
|
67A28 MOVK 0x14,A11 ; 20-word allocation
|
|
67A32 CALLA 0x07f63a30
|
|
67A42 MOVI 0x3f544b10,A8 ; "error allocating photoflo" string
|
|
67A88 MOVK 0x1,A7
|
|
67A8A MOVB *A7,*A11(0x20) ; that object's class = 1
|
|
67AB0 CALLA 0x07ea72a4 ; bind helper
|
|
|
|
This is why every measured create op=1 object has class 3 (from step 3) but
|
|
id@0 == 0 (step 4): they are two different objects, and the class-3 one was
|
|
never registered.
|
|
|
|
6) Measured consequence, reproduced many times this session:
|
|
create op=2 -> class 2, id@0 = ID, query OK, PUT_TILE -> BadMatch (8)
|
|
create op=1 -> class 3, id@0 = 0, query BadIDChoice, PUT_TILE -> BadIDChoice
|
|
|
|
PUT_TILE's lookup demands class 3 (slot 19 pushes MOVK 0x3 before the typed
|
|
lookup). The only class-3 producer never registers. So the import is
|
|
unreachable: not because a request shape is missing, but because the two
|
|
properties the lookup requires are mutually exclusive in the implementation.
|
|
|
|
7) Also measured, and it rules out the remaining "add levels" idea:
|
|
op=4 [newid, existing] increments a 16-bit counter on the existing resource
|
|
(obj word at byte 6): 1 -> 2 -> 3 after two calls, and RESPTR shows NO new
|
|
allocation. PUT_TILE on that resource stays BadMatch (8) at every count,
|
|
including when the counter is 3.
|