-- osprobe.lua -- observe the DUART1-IP3 gate and the OS cold-start. -- -- Reports: -- * whether the boot gate at 0x3F2042D0 takes the OS branch (0x3F2043B0) -- instead of the level-1 runner (0x3F204400), -- * whether the OS cold-start at 0x3F5788C0 is reached, -- * a per-frame PC histogram so the parked PC (the first wall) is explicit. -- -- vt1200 -rompath roms ... -debug -debugger none -debuglog \ -- -autoboot_script harness/mame/osprobe.lua -autoboot_delay 0 -- OS_FRAMES overrides the frame budget (default 3000). local machine = manager.machine local cpu = machine.devices[':maincpu'] local dbg = machine.debugger local pc = cpu.state['PC'] if not dbg then print("ERROR: debugger not enabled; pass -debug"); machine:exit(); return end -- Empirical: what memory does the driver actually give the CPU? do local shares = machine.memory.shares local tags = {} for t, _ in pairs(shares) do tags[#tags + 1] = t end table.sort(tags) for _, t in ipairs(tags) do local s = shares[t] print(string.format("SHARE %s size=%d bytes bytewidth=%d length=%d", tostring(s.tag), s.size, s.bytewidth, s.length)) end end local maxframes = tonumber(os.getenv("OS_FRAMES") or "3000") local recent = tonumber(os.getenv("OS_RECENT") or "300") local frames = 0 local hist = {} local first = {} local lastpc = 0 local rhist = {} local rfirst = {} local gate = { skip = 0, run = 0, os = 0 } local function bp(addr, body) dbg:command('bpset ' .. addr .. ',,{ ' .. body .. ' ; g }') end bp("3f2043b0", 'printf "GATE-SKIP-BRANCH\\n"') bp("3f204400", 'printf "GATE-RUN-LEVEL1\\n"') bp("3f5788c0", 'printf "OS-COLD-START pc=%08X\\n", pc') bp("3fdf72d0", 'printf "LEVEL1-RUNNER-ENTER\\n"') emu.register_frame_done(function() frames = frames + 1 if os.getenv("OS_TRACE") and frames == tonumber(os.getenv("OS_TRACE_AT") or "1") then dbg:command('trace ' .. os.getenv("OS_TRACE")) print("TRACE-ON " .. os.getenv("OS_TRACE")) end if os.getenv("OS_TRACE") and frames == (tonumber(os.getenv("OS_TRACE_AT") or "1") + tonumber(os.getenv("OS_TRACE_FRAMES") or "1")) then dbg:command('trace off') print("TRACE-OFF") end if os.getenv("OS_GLOBALS_AT") and frames == tonumber(os.getenv("OS_GLOBALS_AT")) then local p = cpu.spaces['program'] for _, g in ipairs({0x23cbf0, 0x23cc50, 0x23cc30, 0x1b3900, 0x1e9420, 0x16f0}) do local v = p:read_u32(g) print(string.format("GLOBAL @%08X = %08X", g, v)) end -- TMS34010 on-chip INTENB (0xC0000110): which external lines are enabled. print(string.format("INTENB = %04X", p:read_u16(0xc0000110))) -- DUART1 MR1A (reg0) and CSRA (reg2) are side-effect-free reads. print(string.format("DUART1 MR1A=%02X CSRA=%02X", p:read_u16(0x6400000) & 0xff, p:read_u16(0x6400020) & 0xff)) end local v = pc.value hist[v] = (hist[v] or 0) + 1 if not first[v] then first[v] = frames end lastpc = v if frames > maxframes - recent then rhist[v] = (rhist[v] or 0) + 1 if not rfirst[v] then rfirst[v] = frames end end if frames >= maxframes then local n = 0 for _ in pairs(hist) do n = n + 1 end print(string.format("--- frames=%d distinct_pcs=%d ---", frames, n)) print("--- hottest PCs (one sample per frame) ---") local list = {} for k, c in pairs(hist) do list[#list + 1] = { k, c } end table.sort(list, function(a, b) return a[2] > b[2] end) for i = 1, math.min(20, #list) do print(string.format(" PC=%08X samples=%d first_frame=%d", list[i][1], list[i][2], first[list[i][1]])) end print(string.format("--- last frame PC=%08X ; last %d frames ---", lastpc, recent)) local rlist = {} for k, c in pairs(rhist) do rlist[#rlist + 1] = { k, c } end table.sort(rlist, function(a, b) return a[2] > b[2] end) for i = 1, math.min(12, #rlist) do print(string.format(" PARK PC=%08X samples=%d first_frame=%d", rlist[i][1], rlist[i][2], rfirst[rlist[i][1]])) end machine:exit() end end, "vt1200-osprobe") dbg.visible_cpu = cpu dbg.execution_state = 'run'