mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-10-30 12:03:54 +02:00
The TFTP font path loads through 3F96B850 and parses with the metadata reader 3F97EF00, which handles only PROPERTIES/ACCELERATORS/METRICS/ ENCODINGS and silently skips BITMAPS. A font with num_chars=0x40000001 therefore passes the loader (LOADER-A-SUCCESS) without the field ever being read, and pcfReadBitmaps (3F984970, multiply 3F985050) is never entered. pcfReadBitmaps has exactly one caller, 3F98BB70, in the X11 font-request reader 3F98AC20, not the TFTP fetch path. The 'refused after 1024 bytes' of evil-real.pcf is the METRICS table: its big-endian compressed count 0x00DF is read little-endian as 57088, so fosAlloc(57088*16) fails at ~906 bytes; BITMAPS (offset 2024) is never reached. Baseline.pcf fails the same way; baseline_le.pcf puts that one 2-byte field in the order the loader reads it, parses cleanly, and still ignores the crafted BITMAPS count. No ROM patch, no check disabled, no serve.py edit. Baselines unchanged: no env samples=198, stub samples=53.
92 lines
4.9 KiB
Lua
92 lines
4.9 KiB
Lua
-- pcftrace.lua -- live trace of the firmware's PCF font parser(s).
|
|
--
|
|
-- There are TWO PCF readers in the ROM:
|
|
-- * parser A L3F97EF00 (reached from the font-file loader at 3f96bb80)
|
|
-- * parser B L3F98AC20 (reached from 3f964900) -- the only caller of the
|
|
-- pcfReadBitmaps function (L3F984970) that holds the n*4 overflow.
|
|
-- This traces both, plus the font-file dispatch, so the run says which reader
|
|
-- the TFTP font path actually uses and where it bails.
|
|
|
|
local machine = manager.machine
|
|
local dbg = machine.debugger
|
|
local cpu = machine.devices[':maincpu']
|
|
|
|
if not dbg then
|
|
print("ERROR: debugger not enabled; pass -debug")
|
|
machine:exit()
|
|
return
|
|
end
|
|
|
|
FRAME = 0
|
|
|
|
-- Font-file loader / dispatch.
|
|
dbg:command('bpset 3f96b850,,{ printf "FONTLOAD fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f96bb20,,{ printf "FONT-MAGIC fr=%d magic=%08X\\n", FRAME, a5 ; g }')
|
|
dbg:command('bpset 3f96bb80,,{ printf "PCF->parserA fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f96c930,,{ printf "LOADER-A-SUCCESS fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f96d300,,{ printf "LOAD-A-call fr=%d\\n", FRAME ; g }')
|
|
|
|
-- Parser A entry.
|
|
dbg:command('bpset 3f97ef00,,{ printf "PARSER-A-ENTRY fr=%d\\n", FRAME ; g }')
|
|
-- Parser A validations (labels 1/2/4/32).
|
|
dbg:command('bpset 3f97fa40,,{ printf "A-FAIL properties fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f9803a0,,{ printf "A-FAIL accelerators fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f980bb0,,{ printf "A-FAIL encodings fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f981050,,{ printf "A-FAIL metrics fr=%d\\n", FRAME ; g }')
|
|
-- Parser A dispatch (label in a8 right after it is loaded).
|
|
dbg:command('bpset 3f981200,,{ printf "A-TOC fr=%d i=%d label=%d\\n", FRAME, a9, a8 ; g }')
|
|
|
|
-- Parser A metrics handler internals.
|
|
dbg:command('bpset 3f980e40,,{ printf "A-METRICS fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f980f20,,{ printf "A-METRICS seekret=%08X\\n", a8 ; g }')
|
|
dbg:command('bpset 3f980ff0,,{ printf "A-METRICS callreader fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f981020,,{ printf "A-METRICS readerret=%08X\\n", a8 ; g }')
|
|
dbg:command('bpset 3f9886b0,,{ printf "A-METR-ENTRY fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f9889a0,,{ printf "A-METR fmtread ret=%08X fmt=%08X\\n", a8, d@(a13+0x20) ; g }')
|
|
dbg:command('bpset 3f988a40,,{ printf "A-METR compressed fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f988b90,,{ printf "A-METR badfmt fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f989820,,{ printf "A-METR-C-ENTRY fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f989940,,{ printf "A-METR-C countread ret=%08X count=%04X\\n", a8, d@(a13) ; g }')
|
|
dbg:command('bpset 3f989ac0,,{ printf "A-METR-C badcount fr=%d nChars=%08X count=%04X\\n", FRAME, d@(a13+0xffc0)+0, d@(a13) ; g }')
|
|
dbg:command('bpset 3f989c80,,{ printf "A-METR-C allocret=%08X\\n", a8 ; g }')
|
|
dbg:command('bpset 3f989f20,,{ printf "A-METR-C byteread-fail fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f98a120,,{ printf "A-METR-C byteread-fail2 fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f98a970,,{ printf "A-METR-C done fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f988f80,,{ printf "A-METR done fr=%d\\n", FRAME ; g }')
|
|
|
|
-- Parser B entry and its pcfReadBitmaps call.
|
|
dbg:command('bpset 3f98ac20,,{ printf "PARSER-B-ENTRY fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f98bb70,,{ printf "B-CALL-BITMAPS fr=%d\\n", FRAME ; g }')
|
|
|
|
-- pcfReadBitmaps internals.
|
|
dbg:command('bpset 3f984970,,{ printf "BITMAPS-ENTRY fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f984e70,,{ printf "BITMAPS-ARITH fr=%d nChars=%08X n=%08X\\n", FRAME, d@(a9+0x270), d@(a13+0x20) ; g }')
|
|
dbg:command('bpset 3f985060,,{ printf "MULTIPLY fr=%d n4=%08X n=%08X\\n", FRAME, a11, d@(a13+0x20) ; g }')
|
|
dbg:command('bpset 3f9850e0,,{ printf "OFFSETS-ALLOC fr=%d result=%08X\\n", FRAME, a8 ; g }')
|
|
dbg:command('bpset 3f984f80,,{ printf "VALIDATE bad count fr=%d nChars=%08X n=%08X\\n", FRAME, d@(a9+0x270), d@(a13+0x20) ; g }')
|
|
dbg:command('bpset 3f985150,,{ printf "VALIDATE alloc-offsets-fail fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f9856b0,,{ printf "VALIDATE alloc-glyphs-fail fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f985860,,{ printf "VALIDATE short-read-glyphs fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f98b8c0,,{ printf "B-FAIL PCF metrics fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f98bbe0,,{ printf "B-FAIL PCF bitmaps fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f98bed0,,{ printf "B-FAIL PCF accelerators fr=%d\\n", FRAME ; g }')
|
|
dbg:command('bpset 3f98c1b0,,{ printf "B-FAIL PCF encodings fr=%d\\n", FRAME ; g }')
|
|
|
|
-- The TFTP font fetch, for the record.
|
|
dbg:command('bpset 3f5ed230,,{ printf "TFTP-READ fr=%d\\n", FRAME ; g }')
|
|
|
|
local maxframes = tonumber(os.getenv("PCT_FRAMES") or "20000")
|
|
emu.register_frame_done(function()
|
|
FRAME = FRAME + 1
|
|
if FRAME % 2000 == 0 then
|
|
print(string.format("frame %d PC=%08X", FRAME, cpu.state['PC'].value))
|
|
end
|
|
if FRAME >= maxframes then
|
|
print("done (" .. FRAME .. " frames)")
|
|
machine:exit()
|
|
end
|
|
end, "vt1200-pct")
|
|
|
|
dbg.visible_cpu = cpu
|
|
dbg.execution_state = 'run'
|