Designing the interaction between HwSpec and Manifest
📅 2025-05-15 · ✍️ Bas v.d. Wiel · 🏷 design
After finishing the first implementation of HwSpec
, I started working on handling
the Manifest
configuration file. These two are what should make DOSContainer work
like magic for the end user, so they’d better be good. As it turns out, things aren’t at
that point just yet. Some musings on the design and how DOSContainer will reconcile the
facts of what you have (HwSpec
) with what you want (Manifest
) in an optimal way.
In my time as a DevOps engineer and IT architect I’ve been exposed to quite a few systems that work around what’s called `desired state’. A system, or collection of systems, is in a currently unknown state. The engineer writes a configuration file according to a formal specification to declare the desired state for the system. Once fed into the configuration management toolbox, the target system is adjusted so that its unknown state changes into the desired state. Systems like Puppet, Ansible and Terraform work in this manner and in the world of Kubernetes everyone loves ArgoCD.
Declaring what you have
In the context of a retro DOS PC, it’s very relevant to declare what you have on your desk.
This is what the HwSpec
configuration file is for. It lists the exact hardware and
operating system characteristics that you’ll be working with. Some of these settings are
hard facts not open for negotiation. You have a CGA card in your machine? Ok, so you’re not
ever going to get VGA graphics from it. Other items are more like preferences. You can run
a wide gamut of DOS versions and the application or game won’t really mind all that much.
DOSContainer needs to take both elements into account: hard constraints and preferences.
Declaring what you need
The Manifest
configuration file is something you don’t usualy create as an end-user
of DOSContainer. It’s for collection builders to set up and maintain. While both files are
in TOML format, that’s where the similarities end. As a manifest-developer you need to know
exactly what your application or game needs: minimal non-negotiable system requirements. These
map straight to the hard facts of the hardware that the user has on their desk.
In the context of a Manifest
you’ll also have preferences. A game may work on an 8088 CPU,
but may need to be configured differently than it would be on a 80386. Or you may be running on
IBM hardware that you’d like to pair with PC-DOS rather than MS-DOS, even though both would run:
that’s a preference from the end user that requires the Manifest
to cater to. PC-DOS should
be declared as a supported option, even if it’s not the preferred operating system from the
game or application developer’s standpoint.
Constraints en preferences in HwSpec
Here’s a generic IBM XT-compatible system:
ram = "512KiB"
video = "cga"
[floppy]
floppy_type = "160k"
[cpu]
family = "8088"
clock = 4
[[audio]]
device = "bleeper"
This is the HwSpec
declaring only hard facts. We have a fixed amount of memory, graphics
hardware, a CPU, a floppy drive and a specific audio device. If a Manifest
can work with
these, it will build. If it can’t, it simply won’t build.
By adding preferences at the top you can nudge DOSContainer in some directions:
dos_vendor = "IBM"
min_dos = "1.00"
max_dos = "2.00"
These items are optional. If you don’t set them, DOSContainer will look at the ```Manifest`` for the most ideal version of DOS it thinks you’ll need. In this example the system could pick one of three versions: IBM PC-DOS 1.00, 1.10 and 2.00. If the Manifest has a DOS version that intersects with this set, it will get built with the closest match. Leave them out, and the optimal version will be determined solely by the Manifest.
Now for the kicker: if you specify a 1.44MB 3.5" floppy drive, you’ll run into an issue. The ancient
DOS versions you specified don’t support this kind of floppy drive. At all. So now what? This is where
DOSContainer errs on the side of caution by refusing to build unsupported combinations, unless you force
it to do so by adding the -F
command line parameter to force its hand. In that case it will pick
a the nearest OS version from the Manifest
that does support your floppy drive and build a floppy
for you.
Another example would be graphics. Very old DOS systems often had a Hercules monochrome graphics card,
which was awesome for text and CAD because of its high resolution. It didn’t do colour graphics, however,
so games that required CGA were out of luck. Some games, however, would still run when a CGA-emulator was
added into the mix. Such an emulator is a piece of software that loads just before the game starts and
translates the CGA graphics of the game into something the monochrome Hercules card can display. As a
manifest-developer it’s your job to figure out if this trick works with the software you’re packaging, and
add it as a Layer
that gets injected when the user has Hercules graphics.