fragments
Tool
tools/emu/fragments.py(program, Emulators). Capture fragments of a DOS program's main loop, before and after, from one headless run.
Run it with ./gameframe run fragments ARGS or python3 tools/emu/fragments.py. Source on GitHub.
Its own help
This is the help text in the tool itself, as ./gameframe tool fragments prints it.
text
Capture fragments of a DOS program's main loop, before and after, from one headless run.
Usage: fragments.py PROGRAM OUT FRAMES SPEC [SPEC...] --frame-top SEG:OFF [options]
Runs PROGRAM (an NE or MZ executable) headless under dos_emu + dos_env, from its entry, for
FRAMES frames: a frame starts each time execution reaches --frame-top (an address in the main
loop). Each time execution reaches a fragment's START it saves the program's state, runs to the
fragment's END and saves it again. A port of the fragment loads `before`, runs, and must give
`after` (re-verify: "Capturing fragments of a main loop").
SPEC is NAME=START-END[,changed=OFFSET][,every=N][,max=K][,heap=1]. START and END are seg:off.
END may be several addresses joined by | (a fragment that can finish in more than one place):
draw=1000:014f-1000:0183|1000:0185,heap=1 event=1000:0186-1000:0192,changed=a8
changed=OFFSET keep a run only if the fragment changed that data-segment word (hex), so
only frames where something happened (an event fired)
every=N keep one run in N
max=K stop saving that fragment after K runs
heap=1 also save the heap blocks named by the --heap words (see .heap below)
Fragments are taken in the order the frame reaches them; one a frame does not reach is skipped
for that frame. A fragment's END may be the next fragment's START or the frame top; two
fragments cannot share a START.
Options:
--frame-top SEG:OFF the top of the main loop (required); counts frames
--ds SEL the data segment's selector (default: DS at the program's start, the NE
auto data segment)
--screen OFF DS offset of the word holding the selector of the screen being drawn
--display OFF DS offset of the word holding the selector of the VGA display (A000h)
--heap OFF,OFF,... DS offsets of words holding selectors of heap blocks (for heap=1)
--root DIR the game folder DOS sees (default: PROGRAM's folder); never written:
files the program writes go to OUT/overlay
--start SEG:OFF where to start instead of the entry (a routine that runs the loop)
--program PATH the program's DOS path, for its PSP (default C:\GAME\<name>)
--date Y-M-D, --clock H:M:S the fixed DOS date and time (default 1999-08-31 12:00:00)
--max-steps N instruction budget for the whole run (default 4 000 000 000)
Offsets and selectors are hex.
Outputs, for each kept run K of fragment NAME: OUT/NAME/KKKKK.before.EXT and .after.EXT, with
.ds the data segment (64 KB) .ss the stack segment (64 KB)
.bp BP (2 bytes, little endian: the main loop's frame in .ss)
.scr the screen segment (--screen) .vga the display segment (--display)
.files the open DOS files, one `handle<TAB>position<TAB>name` line each
.heap (heap=1) for each block, its selector word then 64 KB. `after` keeps only the blocks
that changed
It prints `NAME: K of N runs saved in DIR` per fragment, and says so if the program exits
first. Evidence: measured.
It does not: compare anything (that is the port's test), save registers other than BP, follow
far pointers inside the saved segments, or run what dos_env does not emulate (the run stops
with the missing interrupt or import named). It captures one run; run it again with another
--clock or input to cover other paths.Named by
Skills: re-emulate, re-verify.