forked from arti/vt1200
docs(xie): the VT1200 ROM has no DCT (JPEG) scheme -- measured
The question was whether this ROM answers "unsupported" for XieK_DCT. It does, at both layers, and it behaves exactly like an out-of-range scheme value. SetTransport (minor 20), raw wire request, a fresh bitonal photomap per scheme: PCM / G31D / G32D / G42D -> accepted DCT (4) and 5 -> BadIDChoice(14), minor_op 20 So the ROM does not even implement the reference server's IsBitonal_ rules (G42D is accepted on a 256-level photomap, where XieTransport.c would BadMatch), but it does refuse 4 and above. Export (minor 21) with the photomap's compression byte forced to each value (the server never initialises it -- it holds the heap fill 0x55, which is why harness/mame/xie_fix.lua pokes file 0x1B256): 0..3 -> pixmap 4096/4096, no X error 4 -> BadValue, nothing drawn 5 -> BadValue, nothing drawn And the ROM carries no JPEG machinery: no "JPEG"/"DCT" string, and the standard Annex K quantisation table is absent in both zigzag and natural order (no flat 8x8 either). A DCT codec carries one of those; this ROM carries none. "DDX_RENDER: unsupported compression scheme" exists in the ROM but did not fire in these runs, so it belongs to a path these probes do not reach -- recorded as an open detail rather than claimed as the explanation. Probes: xie/xiescheme.c (libXie, one scheme per connection) and xie/xie_schemes_raw.py (raw protocol, exact error codes).
This commit is contained in:
1 parent
742501be67
commit
17dfd24340
3 files changed
+317
No files matched your search
@@ -111,6 +111,69 @@ JPEG baseline/lossless (X11R6.1, two values) — but the 2.3 protocol that the
|
||||
terminal speaks has only the single Scheme-4 DCT code, with no baseline/lossless
|
||||
split and no lossless predictor field in the wire struct.
|
||||
|
||||
## What THIS ROM actually does (measured, not inferred)
|
||||
|
||||
Two probes were built for this (`xiescheme.c` via libXie, and
|
||||
`xie_schemes_raw.py` which speaks the wire protocol directly):
|
||||
|
||||
### 1. At SetTransport (minor 20), raw request, fresh bitonal photomap each time
|
||||
|
||||
```
|
||||
PCM SetTransport -> ACCEPTED
|
||||
G31D SetTransport -> ACCEPTED
|
||||
G32D SetTransport -> ACCEPTED
|
||||
G42D SetTransport -> ACCEPTED
|
||||
DCT SetTransport -> REFUSED ERROR code=14 (BadIDChoice) minor_op=20
|
||||
5 SetTransport -> REFUSED ERROR code=14 (BadIDChoice) minor_op=20
|
||||
```
|
||||
|
||||
So **DCT is answered exactly like an out-of-range scheme value.** Note this is
|
||||
also evidence that the ROM does *not* implement the reference server's
|
||||
`IsBitonal_` rules: G42D is accepted even on a 256-level photomap, where
|
||||
`XieTransport.c` would answer BadMatch.
|
||||
|
||||
### 2. At Export (minor 21), with the photomap's compression byte forced
|
||||
|
||||
The client's `XieExport` to a depth-1 pixmap, for each value of the photomap's
|
||||
`compression_scheme` byte (`harness/mame/xie_fix.lua` pokes it at file
|
||||
`0x1B256`; the server never initialises it, so it holds the heap fill `0x55`):
|
||||
|
||||
```
|
||||
scheme 0 PCM export: pixmap 4096/4096 no X error
|
||||
scheme 1 G31D export: pixmap 4096/4096 no X error
|
||||
scheme 2 G32D export: pixmap 4096/4096 no X error
|
||||
scheme 3 G42D export: pixmap 4096/4096 no X error
|
||||
scheme 4 DCT export: FAILED BadValue, minor 21
|
||||
scheme 5 (bogus) export: FAILED BadValue, minor 21
|
||||
```
|
||||
|
||||
**DCT and a bogus value are treated identically; 0..3 are accepted.** So in this
|
||||
ROM the valid set is `0..3` and scheme 4 has no implementation — it is refused,
|
||||
not silently mis-decoded.
|
||||
|
||||
### 3. The ROM has no JPEG machinery
|
||||
|
||||
Searched `vt1200_v22.bin` (md5 `b46a3e442ccb86134d2356bd70d22fd2`):
|
||||
|
||||
* no `JPEG` / `DCT` string (the only compression-related strings are
|
||||
`DDX_RENDER: unsupported compression scheme`, `error initializing scalution`
|
||||
and `5 - Scalution Test`);
|
||||
* the standard JPEG Annex K quantisation table is **absent**, in both the
|
||||
zigzag order code stores and the natural row order — and no flat 8x8 table
|
||||
either. A DCT codec carries one of these; this ROM carries none.
|
||||
|
||||
`DDX_RENDER: unsupported compression scheme` exists but did **not** fire in any
|
||||
of the runs above (0 occurrences in the MAME debug log for schemes 4 and 5), so
|
||||
it belongs to a path these probes do not reach — reported as an open detail
|
||||
rather than claimed as the explanation.
|
||||
|
||||
### 4. Cross-check: PCM is the only scheme that helps in practice
|
||||
|
||||
The working display path uses `XieK_PCM` throughout, because the transport is
|
||||
`XieK_Tile` on a bitonal image and, per the reference rules above, that admits
|
||||
PCM only. On a depth-1 server there is no non-bitonal visual, so `XieK_DCT` is
|
||||
unreachable by protocol rule as well as unimplemented.
|
||||
|
||||
## Cross-reference: the DTJ article
|
||||
|
||||
`docs/dec/DTJ-1991-v03-04-bitonal-image-accelerators.pdf` — "Hardware
|
||||
@@ -136,3 +199,8 @@ DTJ Vol. 3 No. 4, Fall 1991). Reading it against the headers above:
|
||||
So the article's "image board" is the bitonal G3/G4 decompressor, and JPEG/DCT
|
||||
is the scheme XIE defines for the continuous-tone data type that the same
|
||||
protocol carries — the two correspond exactly to `XieK_G42D` and `XieK_DCT`.
|
||||
|
||||
This is consistent with the measurement above: the ROM has the G3/G4 half
|
||||
(`0..3` accepted, scalution test present) and no DCT half (scheme 4 refused,
|
||||
no JPEG tables). The terminal is depth 1, so the continuous-tone data type the
|
||||
DCT scheme exists for has no visual to land on.
|
||||
@@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Ask the server, in raw XIE 2.3 protocol, one question:
|
||||
|
||||
for each XieK_ compression scheme, does SetTransport accept it?
|
||||
|
||||
It builds a fresh bitonal photomap per scheme (a photomap that already has a
|
||||
transport must match it on a second SetTransport, which would turn every later
|
||||
attempt into a BadMatch for the wrong reason) and then sends a real
|
||||
xieSetTransportReq (minor 20, 140 bytes) and prints whatever comes back.
|
||||
|
||||
Usage: xie_schemes_raw.py [host]
|
||||
"""
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, HERE)
|
||||
sys.path.insert(0, os.path.join(HERE, "evidence"))
|
||||
|
||||
from probe23 import Cli, describe_all # noqa: E402
|
||||
|
||||
NAMES = {0: "PCM", 1: "G31D", 2: "G32D", 3: "G42D", 4: "DCT", 5: "(5)"}
|
||||
|
||||
|
||||
def make_photomap(c, slot, levels=2):
|
||||
"""xieCreatePhotoReq: bitonal 64x64, 1 component, 2 levels.
|
||||
|
||||
A distinct resource id per call -- reusing one after the first photomap owns
|
||||
it is a BadIDChoice, which would mask the answer we are after.
|
||||
"""
|
||||
pid = c.new_id(0x0AAAA + slot * 0x100)
|
||||
w = [2, pid, 64, 64, 0, 0, levels, 0, 0, 0x00000100, 0]
|
||||
out = c.send(8, 12, b"".join(struct.pack("<I", x) for x in w))
|
||||
return pid, describe_all(out)
|
||||
|
||||
|
||||
def set_transport(c, pid, scheme, mode=1):
|
||||
"""xieSetTransportReq, 140 bytes: 3C header + 4 + 4 + 4 + 4 + 24 + 96."""
|
||||
w = [0] * 34
|
||||
w[0] = pid
|
||||
w[1] = 0 # compression_parameter
|
||||
w[2] = scheme | (mode << 8) | (1 << 16) # scheme|mode|comp_org
|
||||
w[3] = 1 # plane_mask
|
||||
w[4] = 1 # pixel_stride[0] = 1
|
||||
w[10] = 8 # scanline_stride[0] = 8
|
||||
return c.send(20, 35, b"".join(struct.pack("<I", x) for x in w))
|
||||
|
||||
|
||||
def main(argv):
|
||||
c = Cli()
|
||||
c.send(1, 2, struct.pack("<HH", 2, 3)) # init session
|
||||
|
||||
levels = int(argv[1]) if len(argv) > 1 else 2
|
||||
schemes = [int(argv[2])] if len(argv) > 2 else (0, 1, 2, 3, 4, 5)
|
||||
mode = int(argv[3]) if len(argv) > 3 else 1
|
||||
print("levels=%d mode=%d (%s)" % (levels, mode,
|
||||
"GetStream" if mode == 1 else "PutStream"))
|
||||
for scheme in schemes:
|
||||
pid, created = make_photomap(c, scheme, levels)
|
||||
if "ERROR" in created:
|
||||
print("%-5s create FAILED: %s" % (NAMES[scheme], created))
|
||||
continue
|
||||
r = set_transport(c, pid, scheme, mode)
|
||||
kind = describe_all(r)
|
||||
if "ERROR" in kind:
|
||||
verdict = "REFUSED"
|
||||
elif "NO REPLY" in kind or "NO PACKETS" in kind:
|
||||
verdict = "ACCEPTED"
|
||||
else:
|
||||
verdict = "?"
|
||||
print("%-5s SetTransport -> %-8s %s" % (NAMES[scheme], verdict, kind))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main(sys.argv)
|
||||
+173
@@ -0,0 +1,173 @@
|
||||
/*
|
||||
* What does THIS ROM answer for each XieK_ compression scheme?
|
||||
*
|
||||
* Built against DEC XIE 2.3 (libXie from DEC's own sources). For every scheme
|
||||
* value 0..5 it issues a real SetTransport (via XieSetStream) in GetStream mode
|
||||
* on a bitonal photomap, and then on a grayscale photomap if the server will
|
||||
* create one -- and reports the protocol error the server returns.
|
||||
*
|
||||
* Xlib's default handler exits on an error, so a catching handler is installed.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/extensions/XieLib.h>
|
||||
|
||||
/* the client never calls the DDX dispatch table; satisfy the linker */
|
||||
unsigned long (*xieDdxProc[1])() = { 0 };
|
||||
|
||||
static int last_error;
|
||||
static int last_req_minor;
|
||||
static char last_text[64];
|
||||
|
||||
static int catch(Display *dpy, XErrorEvent *e)
|
||||
{
|
||||
last_error = e->error_code;
|
||||
last_req_minor = e->minor_code;
|
||||
XGetErrorText(dpy, e->error_code, last_text, sizeof last_text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *scheme_name(int s)
|
||||
{
|
||||
switch (s) {
|
||||
case XieK_PCM: return "PCM ";
|
||||
case XieK_G31D: return "G31D ";
|
||||
case XieK_G32D: return "G32D ";
|
||||
case XieK_G42D: return "G42D ";
|
||||
case XieK_DCT: return "DCT ";
|
||||
default: return "5 ";
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a photomap and push pixel data into it so it is a real image. */
|
||||
static XiePhotomap make_map(Display *dpy, Window win, int bits, int ncomp,
|
||||
int cls, const char *tag)
|
||||
{
|
||||
XieImage img;
|
||||
XiePhotomap pm;
|
||||
unsigned long lvl[3];
|
||||
unsigned int fill;
|
||||
int w = 64, h = 64, nbytes;
|
||||
|
||||
lvl[0] = lvl[1] = lvl[2] = (unsigned long) bits;
|
||||
|
||||
last_error = 0;
|
||||
img = XieCreateImage((unsigned long) w, (unsigned long) h,
|
||||
XieK_PCM, (unsigned char) XieK_BandByPlane,
|
||||
(unsigned char) cls, ncomp, lvl,
|
||||
(unsigned char) XieK_PP0, (unsigned char) XieK_LP270);
|
||||
XSync(dpy, False);
|
||||
if (!img || last_error) {
|
||||
printf(" [%s] XieCreateImage FAILED err=%d (%s)\n", tag, last_error,
|
||||
last_error ? last_text : "no error, null handle");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!uBase_(img, 0)) {
|
||||
nbytes = (int) uArSize_(img, 0);
|
||||
if (nbytes <= 0) nbytes = (w + 7) / 8 * h;
|
||||
uBase_(img, 0) = (unsigned char *) calloc(1, (size_t) nbytes);
|
||||
uArSize_(img, 0) = nbytes;
|
||||
OwnData_(img) = 1;
|
||||
}
|
||||
nbytes = (int) uArSize_(img, 0);
|
||||
fill = ((bits + 7) / 8) == 1 ? 0xAA : 0x00;
|
||||
memset(uBase_(img, 0), fill, (size_t) nbytes);
|
||||
|
||||
pm = XieCreatePhoto(dpy, XieK_Photomap, (unsigned long) w, (unsigned long) h,
|
||||
(unsigned char) cls, ncomp, lvl,
|
||||
(unsigned char) XieK_ZeroDark, 1.0,
|
||||
(unsigned char) XieK_BandByPlane,
|
||||
(unsigned char) XieK_BandByPlane);
|
||||
XSync(dpy, False);
|
||||
if (!pm || last_error) {
|
||||
printf(" [%s] XieCreatePhoto FAILED err=%d\n", tag, last_error);
|
||||
return 0;
|
||||
}
|
||||
XiePutTile(pm, img, XieK_AllPlanes, 0, 0, 0, 0,
|
||||
(unsigned long) w, (unsigned long) h);
|
||||
XSync(dpy, False);
|
||||
if (last_error) {
|
||||
/* SetTransport only needs the photomap to exist, so carry on and let the
|
||||
* transport test report whatever the server says. */
|
||||
printf(" [%s] XiePutTile failed err=%d (%s) -- continuing with an empty map\n",
|
||||
tag, last_error, last_text);
|
||||
last_error = 0;
|
||||
}
|
||||
printf(" [%s] photomap ready (arSize=%d)\n", tag, nbytes);
|
||||
return pm;
|
||||
}
|
||||
|
||||
static void try_scheme(Display *dpy, XiePhoto pm, int scheme, int mode,
|
||||
const char *mode_name)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) last_text[i] = 0;
|
||||
last_error = 0;
|
||||
last_req_minor = -1;
|
||||
XieSetStream(pm, 0, (unsigned char) mode, (unsigned char) scheme,
|
||||
0L, (unsigned char) XieK_BandByPlane, 1L, 8L);
|
||||
XSync(dpy, False);
|
||||
if (last_error)
|
||||
printf(" %s in %-9s -> ERROR %d %s (minor %d)\n",
|
||||
scheme_name(scheme), mode_name, last_error, last_text,
|
||||
last_req_minor);
|
||||
else
|
||||
printf(" %s in %-9s -> ACCEPTED\n", scheme_name(scheme), mode_name);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
Display *dpy;
|
||||
Window win;
|
||||
XSetWindowAttributes swa;
|
||||
XiePhotomap bm, gm;
|
||||
const char *disp = argc > 1 ? argv[1] : "192.168.99.2:0";
|
||||
|
||||
dpy = XOpenDisplay(disp);
|
||||
if (!dpy) { fprintf(stderr, "cannot open %s\n", disp); return 1; }
|
||||
XSetErrorHandler(catch);
|
||||
printf("display %s, root depth %d\n", disp,
|
||||
DefaultDepth(dpy, DefaultScreen(dpy)));
|
||||
|
||||
swa.background_pixel = 0;
|
||||
win = XCreateWindow(dpy, DefaultRootWindow(dpy), 150, 200, 64, 64, 0,
|
||||
CopyFromParent, InputOutput, CopyFromParent,
|
||||
CWBackPixel, &swa);
|
||||
XSync(dpy, False);
|
||||
|
||||
{
|
||||
int scheme = argc > 2 ? atoi(argv[2]) : XieK_PCM;
|
||||
int bits = (argc > 3 && !strcmp(argv[3], "gray")) ? 256 : 2;
|
||||
int cls = (bits == 2) ? XieK_Bitonal : XieK_GrayScale;
|
||||
const char *tag = (bits == 2) ? "bitonal" : "gray";
|
||||
|
||||
printf("\n--- %s photomap, scheme %s ---\n", tag, scheme_name(scheme));
|
||||
bm = make_map(dpy, win, bits, 1, cls, tag);
|
||||
if (bm) {
|
||||
try_scheme(dpy, bm, scheme, XieK_GetStream, "GetStream");
|
||||
/* and, if that was accepted, actually ask for the data */
|
||||
if (!last_error) {
|
||||
unsigned char *buf = 0;
|
||||
unsigned long got = 0;
|
||||
last_error = 0;
|
||||
printf(" XieSetStream accepted; calling XieGetStream...\n");
|
||||
XieGetStream(bm, 0, &buf, 65536L, &got);
|
||||
XSync(dpy, False);
|
||||
if (last_error)
|
||||
printf(" XieGetStream -> ERROR %d %s\n", last_error, last_text);
|
||||
else
|
||||
printf(" XieGetStream -> ok, %lu bytes, first %02X %02X %02X %02X\n",
|
||||
got, buf ? buf[0] : 0, buf ? buf[1] : 0,
|
||||
buf ? buf[2] : 0, buf ? buf[3] : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
XCloseDisplay(dpy);
|
||||
return 0;
|
||||
}
|
||||
Reference in new issue
Block a user