Skip to content

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.

Code: Apache 2.0. Content: CC0 1.0. No game material: bring your own copy.