5.6 KiB
Running the DOS tools under DOSBox — headless, at maximum speed
The TI assembler, linker and compiler shipped with this SDK are DOS programs. This note records how to run them without a window and as fast as DOSBox can go, so they can be used from build scripts and batch runs.
Verified 2026-10-18 against DOSBox 0.74-3 (Debian package) on x86-64 Linux. All timings below are from that machine; the ratios matter, not the absolute numbers.
1. There is no -nogui / -headless flag
DOSBox 0.74-3 has no headless option in the binary or in man dosbox.
-help is not implemented either — it boots the emulator. Do not go looking
for one.
Windowless operation comes from SDL's dummy drivers instead. DOSBox then runs the emulation with no window and no audio device:
SDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy \
dosbox -exit \
-conf harness/sdk-scratch/dosbox.conf \
-c "mount c harness/sdk-scratch/work" \
-c "c:" \
-c "GSPA.EXE MYFILE.ASM" \
-c exit
(GSPA.EXE is the SDK driver in harness/sdk-scratch/work; substitute your
tool. Always keep -c exit last — see gotcha 2.)
What was verified:
- Exit status 0, total wall time ≈ 1 s including emulator start-up.
- A mounted host directory really receives files the DOS program writes.
-caccepts several commands; they execute in order.- Redirection works:
dir > listing.txtandecho hi > out.txtboth produce files inside the mounted drive.
Gotchas, all of which cost time during bring-up:
- The DOS console is invisible. Shell output goes to the emulated video buffer, not to stdout. Redirect to a file when you need a transcript. The host terminal shows only DOSBox's own start-up lines.
-exitalone does not quit when no program file was given on the command line. End the command list with-c exit(or wrap the run intimeout).- DOS uppercases 8.3 names.
mkdir foocreatesFOO;echo hi > out.txtcreatesOUT.TXT. Checking for the lowercase name makes a successful run look like a failure. This produced a false "the commands did not run" conclusion before the uppercase names were noticed. - Dummy video means no display access. Do not use this path for anything that needs a screenshot, video recording, or visible screen output.
2. Maximum emulation speed
The working config harness/sdk-scratch/dosbox.conf pins a fixed cycle count
(cycles=3000, core=normal), which is slow for batch work. (The stock default
is cycles=auto, which guesses; for a batch tool that is neither predictable
nor as fast as max.) Maximum speed is two settings:
[cpu]
core=dynamic
cputype=auto
cycles=max
The comments in DOSBox's default config (~/.dosbox/dosbox-0.74-3.conf)
document each one:
core: "auto will switch to dynamic if available and appropriate." The dynamic core is the recompiler.cputype: "auto is the fastest choice."cycles: "'max' will allocate as much cycles as your computer is able to handle."
Two ways to apply it.
With a config file. Pass an override after the base config; later -conf
files win (verified):
dosbox -conf harness/sdk-scratch/dosbox.conf -conf maxspeed.conf ...
Without a file. DOSBox 0.74-3 has an internal CYCLES command, so -c
works too (verified — it moves the benchmark below from the fixed-3000 time to
the max time):
dosbox -conf harness/sdk-scratch/dosbox.conf -c "cycles max" ...
Use the config file for repeatable scripted runs; -c "cycles max" is fine for
one-offs. Other useful batch settings:
[mixer]
nosound=true
[midi]
mpu401=none
mididevice=none
nosound=true alone still makes DOSBox probe ALSA for MIDI (ALSA:Can't subscribe to MIDI port ..., MIDI:Opened device:none); the two [midi] keys
stop that.
3. Measurements
Benchmark: a .COM with a nested loop (mov dx,0x100 / mov cx,0xffff /
loop $ / dec dx / jnz / int 20h), ≈16.8 M instructions. Each setting was
run twice; wall time includes ≈0.93 s of DOSBox start-up (measured with an
empty int 20h program, 0.95 s / 0.91 s).
| setting | run 1 | run 2 | loop time ≈ |
|---|---|---|---|
cycles=fixed 3000, core=normal (the scratch config) |
6.61 s | 6.49 s | 5.6 s |
cycles=max, core=normal |
2.00 s | 2.11 s | 1.1 s |
cycles=max, core=dynamic |
1.75 s | 1.72 s | 0.8 s |
cycles=max, core=dynamic, frameskip=10 |
1.69 s | 1.73 s | 0.8 s |
- Max + dynamic is about 3.8× faster end to end, and about 7× faster on the loop itself, than the fixed-3000 config.
- The fixed-3000 run retires ≈3.0 M instructions/s, which matches the config's "instructions ... each millisecond": the benchmark is behaving as expected.
frameskip=10made no measurable difference with dummy video. Rendering is not the bottleneck here; do not expect a gain from it.core=normalatcycles=maxis close on this pure-loop benchmark (2.0 s vs 1.7 s), but the dynamic core is the right choice for real code.
4. Caveats
cycles=maxconsumes all the host CPU it can. Run one instance at a time; do not parallelise batch jobs by launching severalcycles=maxDOSBoxes unless you measure that it helps.- Max speed is not cycle-accurate. Fix the cycle count when timing matters
(for example when measuring 34010 code under the simulator), and use
cycles=maxonly when throughput matters, as it does for assembly/linking. ALT-F12("Unlock speed (turbo button)") andCTRL-F11/CTRL-F12change speed interactively, perman dosbox; they are useless in a headless run, which is why the settings above are config/-cbased.