Skip to content

Add Apple II language card, so ProDOS software runs - #280

Merged
highbyte merged 2 commits into
masterfrom
feature/apple2-language-card
Aug 9, 2026
Merged

Add Apple II language card, so ProDOS software runs#280
highbyte merged 2 commits into
masterfrom
feature/apple2-language-card

Conversation

@highbyte

@highbyte highbyte commented Aug 9, 2026

Copy link
Copy Markdown
Owner

ProDOS 8 needs 64 KB, and the emulated machine was a 48 KB II Plus with no bank switching at all — so a ProDOS disk booted only as far as ProDOS's own memory check and stopped with RELOCATION/ CONFIGURATION ERROR. ProDOS is the gate in front of most Apple II software from roughly 1984 onward, so the Download & Run list could only ever hold DOS 3.3-era titles.

Now it boots, and Dangerous Dave in the Deserted Pirate's Hideout plays.

The card

16 KB overlaying $D000$FFFF, switched by $C080$C08F: two independently selected 4 KB banks at $D000, one shared 8 KB block at $E000 (which is why 16 KB covers a 12 KB range).

Always fitted, invisible until used. At power-on it reads as ROM with writes protected, so software that never touches $C08x sees exactly the machine it saw before. 64 KB was the standard II Plus configuration from 1982.

The write-enable rule is modelled properly. Enabling writes takes two consecutive accesses to an odd switch address, and only a read arms the first — a hardware guard so a single stray access (an indexed read landing in $C08x) cannot silently unlock RAM under the ROM. Software depends on it: reading the switch twice is the standard idiom for filling the card while still executing from ROM. The pre-write flip-flop is captured in snapshots too — one byte, without which a snapshot taken between the two reads resumes with the second read silently failing.

Mapping costs nothing per switch. The design note for this feature worried that bank switching meant re-mapping 12 KB of handlers, with an indirection as the fallback. Neither was needed: Memory already supports multiple configurations with O(1) swaps — the same mechanism C64 banking uses. The card has exactly 8 distinct maps (read source × bank × write enable), built once at startup, so a switch access costs a pointer assignment. That matters because software toggles banks in tight loops.

ProDOS sector order

Filed as a "separate and much smaller" companion item; it turned out to be on the critical path, because the target disk is ProDOS-ordered.

Detected from the image's contents, not its file name. Archive.org's copy of Deserted Pirate's Hideout is named .dsk and is ProDOS-ordered — and the archive's own metadata confirms Archive Order: ProDOS. Nibblizing with the wrong order yields plausible garbage rather than an error, and the symptom (a drive spinning with the read counter frozen) reads as a drive bug rather than a misread image.

Snapshots

New apple2-languagecard module for the card's 16 KB and switch state. Without it a restored ProDOS session comes back with its operating system replaced by zeros. It restores after apple2-core and applies the memory configuration itself, so the address space always ends up matching the switch state it restored.

Verification

  • ProDOS boots: no RELOCATION error, ProDOS relocates into the card, the CPU is observed executing from $D0xx with the card switched in, and BASIC.SYSTEM reaches its ] prompt at frame 453 with ~10.9 KB resident.
  • The game runs: leaves text mode for hi-res, loops in its own code, redraws the screen, and executes zero opcodes this CPU lacks. Confirmed visually in the desktop app — score, level 1, three lives, 60 fps — and now covered by an opt-in integration test.
  • DOS 3.3 still boots, and independently confirms the card is real: the System Master now also loads Integer BASIC into it, which it skips on a 48 KB machine.
  • 24 unit tests for the $C08x semantics, plus snapshot round-trip coverage.

All 1,801 tests pass, none skipped; build clean across 73 projects.

Added to the Download & Run list. Keyboard joystick is left off — the game reads the keyboard directly and never touches the game port, so enabling it would only steal keys.

Test rework worth flagging

The DOS 3.3 boot test failed the moment the card was added, and the failure was correct: the boot legitimately got longer. The fix was not a bigger number — the test now waits for the drive to spin up and settle, with the frame count as a safety cap. A fixed budget was the wrong shape for a test that is not about boot duration, and would have broken again the next time the machine gained hardware.

Not included

65C02 support. The 1991 re-release of Dangerous Dave is a 65C02 build — it executes $9C (STZ abs), which this NMOS 6502 lacks, so the instruction stream desynchronises and the CPU lands on $B2 (JAM). Same game, different build, different CPU requirement; only the 1988 original targets a II Plus. Recorded rather than pursued.

ProDOS 8 needs 64 KB, and the emulated machine was a 48 KB II Plus with no
bank switching at all - so a ProDOS disk booted only as far as ProDOS's own
memory check and stopped with RELOCATION/ CONFIGURATION ERROR. ProDOS is the
gate in front of most Apple II software from roughly 1984 onward.

The card is 16 KB overlaying $D000-$FFFF, switched by $C080-$C08F: two
independently selected 4 KB banks at $D000 and a shared 8 KB block at $E000.
It is always fitted and invisible until used - at power-on it reads as ROM
with writes protected, so software that never touches $C08x sees the same
machine as before. 64 KB was the standard II Plus configuration from 1982.

Enabling writes takes two consecutive accesses to an odd switch address, and
only a read arms the first: a hardware guard so one stray access cannot unlock
RAM under the ROM. Software relies on it, so it is modelled with the same
pre-write flip-flop the hardware uses, including in snapshots.

Memory mapping uses Memory's existing multi-configuration support rather than
re-mapping 12 KB of handlers per switch access. The card's state has exactly 8
distinct maps, built once at startup, so a bank switch costs a pointer
assignment - which matters because software toggles banks in tight loops.

Also adds ProDOS sector order, which turned out to be on the critical path
rather than optional. The order is detected from the image's contents, not its
file name: archive.org's copy of "Dangerous Dave in the Deserted Pirate's
Hideout" is named .dsk and is ProDOS-ordered. Nibblizing with the wrong order
produces plausible garbage rather than an error, which presents as a drive
fault instead of a misread image.

Snapshots gain an apple2-languagecard module for the card's 16 KB and switch
state; without it a restored ProDOS session comes back with its operating
system replaced by zeros.

Verified: ProDOS boots to the BASIC.SYSTEM prompt at frame 453 with ~10.9 KB
resident in the card and the CPU executing from $D0xx, and Dangerous Dave in
the Deserted Pirate's Hideout boots from ProDOS and plays. Added to the
Download & Run list, with the keyboard joystick left off since the game reads
the keyboard directly and never touches the game port.

The DOS 3.3 boot test needed reworking, for a good reason: with a card fitted
the System Master also loads Integer BASIC into it, so the boot legitimately
takes longer. The test now waits for the drive to settle rather than running a
fixed number of frames, which was the wrong shape for a test that is not about
boot duration.
The card was fitted unconditionally, documented as "the standard Apple II
Plus configuration from about 1982". That overstated it: the language card
was an expansion card, normally in slot 0, and a stock II Plus motherboard
held at most 48 KB. It was a common upgrade, not what the machine shipped as.

Software can tell the difference, so this is not just a wording problem - the
DOS 3.3 System Master loads Integer BASIC into the card when it finds one, and
skips that step when it does not. A 48 KB machine is a real configuration, and
the emulator could not express it.

LanguageCardEnabled is now a setting on Apple2SystemConfig (on by default,
since without it no ProDOS-era software runs), threaded through to the machine
and exposed as a Memory section in the Apple II configuration dialog. With it
off, $C080-$C08F reads as unconnected exactly as an empty slot 0 would, and
$D000-$FFFF stays ROM. Such a machine also builds one memory configuration
instead of eight, because the other seven describe states its address space
cannot reach.

The setting travels in the portable snapshot block, since it decides the shape
of the rebuilt machine rather than being a preference. Restoring a 64 KB
capture into a machine configured without a card keeps the card's bytes but
warns that its mapping was not applied, rather than throwing on a memory
configuration that does not exist.

Wording corrected in the docs and the class comment to say what the hardware
actually was.
@sonarqubecloud

sonarqubecloud Bot commented Aug 9, 2026

Copy link
Copy Markdown

@highbyte
highbyte merged commit 25938ac into master Aug 9, 2026
10 checks passed
@highbyte
highbyte deleted the feature/apple2-language-card branch August 9, 2026 10:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant