Blog

Blog

Welcome to the Blog.

Deterministic DIR Output

Treating DIR formatting as an API contract for automation

2026-03-10

The story starts at 23:14 in a room with two beige towers, one half-dead fluorescent tube, and a whiteboard covered in hand-written file counts. We had one mission: rebuild a damaged release set from mixed backup disks and compare it against a known-good manifest.

On paper, that sounds easy. In practice, it meant parsing DIR output across different machines, each configured slightly differently, each with enough personality to make automation fail at the worst moment.

By 23:42 we had already hit the first trap. One machine produced DIR output that looked “normal” to a human and ambiguous to a parser. Another printed dates in a different shape. A third had enough local customization that every assumption broke after line three. We were not failing because DOS was bad. We were failing because we had not written down what “correct output” meant.

That night we stopped treating DIR as a casual command and started treating it as an API contract.

This article is that deep dive: why a deterministic profile matters, how to structure it, and how to parse it without superstitions. ... continue

Why Old Machines Teach Systems Thinking

2026-02-22

Retrocomputing is often framed as nostalgia, but its strongest value is pedagogical. Old machines are small enough that one person can still build an end-to-end mental model: boot path, memory layout, disk behavior, interrupts, drivers, application constraints. That full-stack visibility is rare in modern systems and incredibly useful.

On contemporary platforms, abstraction layers are necessary and good, but they can hide causal chains. When performance regresses or reliability collapses, teams sometimes lack shared intuition about where to look first. Retro environments train that intuition because they force explicit resource reasoning.

Take memory as an example. In DOS-era systems, “out of memory” did not mean you lacked total RAM. It often meant wrong memory class usage or bad resident driver placement. You learned to inspect memory maps, classify allocations, and optimize by understanding address space, not by guessing.

That habit translates directly to modern work:

Different scale, same reasoning discipline. ... continue

Latency Budgeting on Old Machines

When constrained hardware makes wait time a design variable

2026-02-22

One gift of old machines is that they make latency visible. You do not need an observability platform to notice when an operation takes too long; your hands tell you immediately. Keyboard echo lags. Menu redraw stutters. Disk access interrupts flow. On constrained hardware, latency is not hidden behind animation. It is a first-class design variable.

Most retro users developed latency budgets without naming them that way. They did not begin with dashboards. They began with tolerance thresholds: if opening a directory takes longer than a second, it feels broken; if screen updates exceed a certain rhythm, confidence drops; if save operations block too long, people fear data loss. This was experiential ergonomics, built from repeated friction.

A practical budget often split work into classes. Input responsiveness had the strictest target. Visual feedback came second. Heavy background operations came third, but only if they could communicate progress honestly. Even simple tools benefited from this hierarchy. A file manager that reacts instantly to keys but defers expensive sorting feels usable. One that blocks on every key feels hostile.

Because CPUs and memory were limited, achieving these budgets required architectural choices, not just micro-optimizations. You cached directory metadata. You precomputed static UI regions. You used incremental redraw instead of repainting everything. You chose algorithms with predictable worst-case behavior over theoretically elegant options with pathological spikes. The goal was not maximum benchmark score; it was consistent interaction quality.

Disk I/O dominated many workloads, so scheduling mattered. Batching writes reduced seek churn. Sequential reads were preferred whenever possible. Temporary file design became a latency decision: poor temp strategy could double user-visible wait time. Even naming conventions influenced performance because directory traversal cost was real and structure affected lookup behavior on older filesystems. ... continue

When Crystals Drift

Timing faults in vintage hardware

2026-02-22

Vintage hardware failures are often blamed on capacitors, connectors, or corrosion. Those are common and worth checking first. But some of the strangest intermittent bugs come from timing instability: oscillators drifting, marginal clock distribution, and tolerance stacking that only breaks under specific thermal or electrical conditions.

Timing faults are difficult because symptoms appear far away from cause:

These can look like software issues until you observe enough correlation.

A crystal oscillator is not magic. It is a physical resonant component with tolerance, temperature behavior, aging characteristics, and load-capacitance sensitivity. In old systems, any of these can move the effective frequency enough to expose marginal subsystems.

The diagnostic trap is pass/fail thinking. Many boards “mostly work,” so timing is assumed healthy. Better approach: characterize timing quality, not just presence. ... continue

Recapping a Vintage Mainboard

A controlled restoration process, not just a parts swap

2026-02-22

Recapping is one of those maintenance tasks that seems simple from a distance and unforgiving in practice. “Replace old capacitors” sounds straightforward until you are diagnosing intermittent instability on a thirty-year-old board with unknown service history, lifted pads, and undocumented revisions.

Done well, recapping is not a parts swap. It is a controlled restoration process with verification steps before, during, and after soldering.

Start with baseline behavior. Do not desolder anything yet. Record:

Without baseline data, you cannot measure improvement or detect regressions introduced during rework.

Next, create a capacitor map from the actual board, not just internet photos. Vintage boards often have revision differences. Mark value, voltage rating, polarity orientation, and physical clearance constraints. Photograph every zone before removal. Good photos save bad assumptions later. ... continue

IRQ Maps and the Politics of Slots

Negotiating IRQ, DMA, and I/O on DOS-era PCs

2026-02-22

Anyone who built or maintained DOS-era PCs remembers that hardware conflicts were not rare edge cases; they were normal engineering terrain. IRQ lines, DMA channels, and I/O addresses had to be negotiated manually, and each new card could destabilize a previously stable system. This was less like plug-and-play and more like coalition politics in a fragile parliament.

The core constraint was scarcity. Popular sound cards wanted IRQ 5 or 7. Network cards often preferred 10 or 11 on later boards but collided with other devices on mixed systems. Serial ports claimed fixed ranges by convention. Printer ports occupied addresses and IRQs that software still expected. These were not abstract settings. They were finite shared resources, and two devices claiming the same line could produce failures that looked random until you mapped the whole system.

That mapping step separated casual tinkering from reliable operation. Good builders kept a notebook: slot position, card model, jumper settings, base address, IRQ, DMA low/high, BIOS toggles, and driver load order. Without this, every change became archaeology. With it, you could reason about conflicts before booting and recover quickly after experiments.

Slot placement itself mattered more than many people remember. Motherboards often wired specific slots to shared interrupt paths or delivered different electrical behavior under load. Moving a card one slot over could stabilize an entire system. This felt superstitious until you understood board traces, chipset quirks, and timing sensitivities. “Try another slot” was not a meme; it was an informed diagnostic move.

Software configuration had to align with hardware reality. A sound card set to IRQ 5 physically but configured as IRQ 7 in a game setup utility produced symptoms that were confusing but consistent: missing effects, lockups during sample playback, or intermittent crackle. The fix was not mystical. It was alignment across all layers: jumper, driver, environment variable, and application profile. ... continue

Turbo Pascal Units

As architecture, not just reuse

2026-02-22

Most people first meet Turbo Pascal units as “how to avoid copy-pasting procedures.” That is true and incomplete. In real projects, units are architecture boundaries. They define what the rest of the system is allowed to know, hide what can change, and make refactoring survivable under pressure.

In constrained DOS projects, this was not academic design purity. It was the difference between shipping and debugging forever.

A good unit interface exposes minimal, stable operations. It does not leak storage details, timing internals, or helper routines with unclear ownership. You can read the interface as a capability map.

unit RenderCore;

interface
procedure BeginFrame;
procedure DrawSprite(X, Y, Id: Integer);
procedure EndFrame;

implementation
{ internal page selection, clipping, palette handling }
end.

Notice what is missing: page indices, raw VGA register details, sprite memory layout. Those remain private so callers cannot create illegal states casually.

A practical retro project often benefits from explicit layers: ... continue

Overlay Lab: Build and Debug OVR

Hands-on overlay packaging, runtime setup, and deployment in Turbo Pascal

2026-02-22

This tutorial is intentionally practical. You will build a small Turbo Pascal program with one resident path and one overlayed path, then test deployment and failure behavior.

If your install names/options differ, keep the process and adapt the exact menu or command names.

Goal: move a cold code path out of always-resident memory and verify it loads on demand from .OVR.

Expected outcomes before you start:

1
2
3
4
OVRDEMO/
  MAIN.PAS
  REPORTS.PAS
  BUILD.BAT

Step 1: write resident core and cold module

REPORTS.PAS (cold path candidate): ... continue

Turbo Pascal History

Through tooling decisions, compile speed, and workflow discipline

2026-02-22

People often tell Turbo Pascal history as a sequence of versions and release dates. That timeline matters, but it misses why the tool changed habits so deeply. The real story is tooling ergonomics under constraints: compile speed, predictable output, integrated editing, and a workflow that kept intention intact from keystroke to executable.

In other words, Turbo Pascal was not only a language product. It was a decision system.

The key loop was short and visible:

No hidden dependency graph. No plugin negotiation. No remote service in the critical path. This reduced context switching in ways modern teams still struggle to recover through process design.

The historical importance is not nostalgia. It is evidence that feedback-loop economics shape software quality more than fashionable architecture slogans. ... continue

BGI Lab: Drivers and Diagnostics

Dynamic drivers, linked drivers, and startup harnesses in Turbo Pascal

2026-02-22

This tutorial gives you a practical BGI workflow that survives deployment:

TP5 baseline reminder:

Create BGITEST.PAS:

program BgiTest;

uses
  Graph, Crt;

var
  gd, gm, gr: Integer;

begin
  gd := Detect;
  InitGraph(gd, gm, '.\BGI');
  gr := GraphResult;
  Writeln('Driver=', gd, ' Mode=', gm, ' GraphResult=', gr);
  if gr <> grOk then
    Halt(1);

  SetColor(15);
  OutTextXY(8, 8, 'BGI OK');
  Rectangle(20, 20, 200, 120);
  ReadKey;
  CloseGraph;
end.

Expected outcome:

Important TP5 behavior: GraphResult resets to zero after being called. Always store it to a variable once, then evaluate that value. ... continue