-- probe_os.lua -- private probe for the COFF loader work. -- -- Prints the OS-phase heap free list (global list only, as HEAP.md advises), -- and tests whether the CPU registers can be written from a frame hook while -- the machine is running (the debugger is attached with -debug -debugger none). -- -- VT1200_SKIP_LEVEL1=1 vt1200 ... -autoboot_script dwt/loader/probe_os.lua -- -- Env: PROBE_AT (frame to sample, default 2500), PROBE_END (exit frame, 2520) local function hex(v, w) return string.format("%0" .. (w or 8) .. "X", v) end local machine = manager.machine local cpu = machine.devices[':maincpu'] local dbg = machine.debugger local prog = cpu.spaces['program'] if not dbg then print("PROBE: no debugger") machine:exit() return end local AT = tonumber(os.getenv("PROBE_AT") or "2500") local ENDF = tonumber(os.getenv("PROBE_END") or "2520") local frames = 0 local tested = false local function u32(a) local ok, v = pcall(function() return prog:read_u32(a) end) if ok then return v end return 0xdeadbeef end local function heap() print(string.format("PROBE: free counter @1E8BA0 = %d bits (%d bytes)", u32(0x1E8BA0), math.floor(u32(0x1E8BA0) / 8))) local head = u32(0x1E8AC0) print(string.format("PROBE: global free-list head @1E8AC0 = %s", hex(head))) local b = head for i = 0, 15 do if b == 0 then break end local size = u32(b) local nextp = u32(b + 0x20) print(string.format("PROBE: block[%d] hdr=%s size=%d bits (%d B) user=%s..%s next=%s", i, hex(b), size, math.floor(size / 8), hex(b + 0x40), hex(b + size), hex(nextp))) if nextp == head then break end b = nextp end end emu.register_frame_done(function() frames = frames + 1 if frames == AT then print(string.format("PROBE: frame %d PC=%s SP=%s A8=%s A14=%s", frames, hex(cpu.state['PC'].value), hex(cpu.state['SP'].value), hex(cpu.state['A8'].value), hex(cpu.state['A14'].value))) heap() -- Scratch return stub test: write jruc self at 01880F00, return address -- at 01880F10, then set SP/PC from the frame hook. prog:write_u16(0x01880F00, 0xC0FF) -- jruc 01880F00 (short, -1 word) prog:write_u32(0x01880F10, 0x01880F00) prog:write_u32(0x01880F20, 0xDEADBEEF) print(string.format("PROBE: spin word readback=%04X ret=%s", prog:read_u16(0x01880F00), hex(prog:read_u32(0x01880F10)))) cpu.state['SP'].value = 0x01880F10 cpu.state['A8'].value = 0x01880E00 cpu.state['PC'].value = 0x01880F00 tested = true end if tested and frames == AT + 2 then print(string.format("PROBE: after 2 frames PC=%s SP=%s A8=%s", hex(cpu.state['PC'].value), hex(cpu.state['SP'].value), hex(cpu.state['A8'].value))) end if frames >= ENDF then print(string.format("PROBE: marker 01880F20=%s (should be DEADBEEF, untouched)", hex(u32(0x01880F20)))) machine:exit() end end, "vt1200-loader-probe") dbg.visible_cpu = cpu dbg.execution_state = 'run'