mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-10-30 12:03:54 +02:00
dwt/screenshot: --real reads the 1024x2048 interleaved framebuffer and keeps the even rows 1:1; corrects the earlier doubling
This commit is contained in:
1 parent
71588e5405
commit
6adc04ba02
3 files changed
+51
-17
No files matched your search
Binary file not shown.
|
After Width: | Height: | Size: 6.8 KiB |
@@ -107,3 +107,28 @@ This is a **display-fetch difference, not a CPU-emulation difference**. MAME's
|
||||
driver models a linear 1bpp framebuffer, so the emulator never shows the
|
||||
interleave; the real TMS34010 display controller is programmed for the doubled
|
||||
even field.
|
||||
|
||||
### Correction: the framebuffer is 1024x2048, not line-doubled
|
||||
|
||||
The earlier "the display doubles the even field" reading was wrong. A **256 KiB**
|
||||
read (2048 rows x 128 bytes) shows the 1024 image lines sitting on **even rows
|
||||
at 1:1**, with the odd rows carrying the mask. The earlier 128 KiB read held
|
||||
only the **top 512 image lines**; doubling them stretched the top half and cut
|
||||
the bottom — which is exactly the "missing left/bottom" and "line doubled"
|
||||
appearance.
|
||||
|
||||
Correct 1:1 capture:
|
||||
|
||||
```sh
|
||||
python3 dwt/screenshot.py --host 100.103.100.103 --real --out screen.png
|
||||
```
|
||||
|
||||
`--real` means `--rows 0:2048 --field even` and outputs **1024x1024 with no
|
||||
resampling**. `dwt/evidence/real-unit-1to1.png` is that capture: Icon Box,
|
||||
Terminal Manager, Memory bar, and the `Ethernet Port Error - 24` box at the
|
||||
bottom — the whole screen.
|
||||
|
||||
`--stretch 1280x1024` is only the monitor's 5:4 scaling of the 1024-wide
|
||||
framebuffer; it is **not** 1:1 and the nearest-neighbour version produces the
|
||||
uneven-pixel artefacts. Use it only for an approximate visual match, not as
|
||||
evidence.
|
||||
+26
-17
@@ -45,7 +45,8 @@ VRAM_BASE_BITS = 0x04000000
|
||||
PITCH_BITS = 1024
|
||||
ROW_BYTES = PITCH_BITS // 8 # 128
|
||||
WIDTH = 1024
|
||||
HEIGHT = 1024
|
||||
HEIGHT = 1024 # image lines
|
||||
MAX_ROWS = 2048 # real unit: image on even rows of 2048
|
||||
CHUNK = exploit.MAX_XFER # 1024 bytes = 8 rows
|
||||
ROWS_PER_CHUNK = CHUNK // ROW_BYTES # 8
|
||||
|
||||
@@ -68,9 +69,9 @@ def parse_rows(text: str) -> tuple[int, int]:
|
||||
start, end = int(a, 0), int(b, 0)
|
||||
else:
|
||||
start, end = 0, int(text, 0)
|
||||
if not (0 <= start < end <= HEIGHT):
|
||||
if not (0 <= start < end <= MAX_ROWS):
|
||||
raise argparse.ArgumentTypeError(
|
||||
f"rows must satisfy 0 <= start < end <= {HEIGHT}")
|
||||
f"rows must satisfy 0 <= start < end <= {MAX_ROWS}")
|
||||
return start, end
|
||||
|
||||
|
||||
@@ -87,19 +88,19 @@ def decode(data: bytes, width: int = WIDTH) -> bytearray:
|
||||
return out
|
||||
|
||||
|
||||
def field_double(gray: bytearray, w: int, h: int, parity: str) -> bytearray:
|
||||
"""Select one row parity and duplicate each row.
|
||||
def field_select(gray: bytearray, w: int, h: int, parity: str) -> bytearray:
|
||||
"""De-interleave: keep one row parity, at 1:1 (no doubling).
|
||||
|
||||
The real unit's framebuffer is line-interleaved: the image is on even rows
|
||||
and the odd rows carry a 0x55 mask; the display doubles the even field.
|
||||
Reading linearly shows both, which looks 'line doubled' and striped.
|
||||
The real unit's framebuffer is 1024x2048: the 1024 image lines are on even
|
||||
rows and the odd rows carry a 0x55 mask. The display scans the even rows.
|
||||
Reading all 2048 rows and keeping the even ones gives the 1024x1024 image
|
||||
exactly as the hardware shows it.
|
||||
"""
|
||||
off = 0 if parity == "even" else 1
|
||||
out = bytearray(w * h)
|
||||
for y in range(h):
|
||||
sy = (y // 2) * 2 + off
|
||||
if sy >= h:
|
||||
sy = h - 1
|
||||
oh = h // 2
|
||||
out = bytearray(w * oh)
|
||||
for y in range(oh):
|
||||
sy = y * 2 + off
|
||||
out[y * w:(y + 1) * w] = gray[sy * w:(sy + 1) * w]
|
||||
return out
|
||||
|
||||
@@ -183,7 +184,8 @@ def one(rd: exploit.RDebug, a: argparse.Namespace, tag: str) -> None:
|
||||
root, dot, ext = out.rpartition(".")
|
||||
out = f"{root}-{tag}.{ext}" if dot else f"{out}-{tag}"
|
||||
if a.field:
|
||||
gray = field_double(gray, WIDTH, rows, a.field)
|
||||
gray = field_select(gray, WIDTH, rows, a.field)
|
||||
rows = rows // 2
|
||||
if a.stretch:
|
||||
dw, dh = a.stretch
|
||||
scaled = scale_nearest(gray, WIDTH, rows, dw, dh)
|
||||
@@ -225,9 +227,13 @@ def main(argv: list[str]) -> int:
|
||||
help="nearest-neighbour scale the raw canvas to WxH "
|
||||
"(the real unit displays 1024x1024 as 1280x1024)")
|
||||
ap.add_argument("--field", choices=("even", "odd"), default=None,
|
||||
help="select one row parity and double it; the real unit "
|
||||
"carries the image on even rows and a 0x55 mask on odd "
|
||||
"rows, and the display doubles the even field")
|
||||
help="de-interleave: keep one row parity at 1:1; the real "
|
||||
"unit's 1024 image lines are on even rows of a 2048-row "
|
||||
"framebuffer, odd rows are a 0x55 mask")
|
||||
ap.add_argument("--real", action="store_true",
|
||||
help="real-unit preset: --rows 0:2048 --field even, 1:1 "
|
||||
"(add --stretch 1280x1024 only if you want the 5:4 "
|
||||
"display scaling)")
|
||||
ap.add_argument("--screen-width", type=int, default=SCREEN_W)
|
||||
ap.add_argument("--screen-height", type=int, default=SCREEN_H)
|
||||
ap.add_argument("--offset-x", type=int, default=OFFSET_X)
|
||||
@@ -240,6 +246,9 @@ def main(argv: list[str]) -> int:
|
||||
ap.add_argument("--quiet", action="store_true")
|
||||
ap.add_argument("--verbose", action="store_true")
|
||||
a = ap.parse_args(argv[1:])
|
||||
if a.real:
|
||||
a.rows = (0, MAX_ROWS)
|
||||
a.field = "even"
|
||||
|
||||
rd = exploit.RDebug(a.host, a.port, a.timeout, a.verbose)
|
||||
rd.connect()
|
||||
|
||||
Reference in new issue
Block a user