Conversation
Implements the Macintosh IIfx (model=iifx) and the supporting chip models, 68030 PMMU fix, and integration hooks needed for the System ROM to boot from POST through the ADB device-table scan to the "insert disk" prompt screen.
Implements the Macintosh IIfx (model=iifx) and the supporting chip models, 68030 PMMU fix, and integration hooks needed for the System ROM to boot from POST through the ADB device-table scan to the "insert disk" prompt screen.
Replaces the previous "ack and ignore" stub for XmtMsg[2] traffic with a complete C reimplementation of the .Sony driver protocol exposed by the SWIM IOP firmware: - All 17 xmtReq* host→IOP commands (Initialize, ShutDown, Start/StopPolling, SetHFSTagAddr, DriveStatus, Eject, Format, FormatVerify, Read, Write, ReadVerify, CacheControl, TagBufferControl, GetIcon, DiskDupInfo, GetRawData). Read/Write transfer through the image_t via disk_read_data/disk_write_data and DMA into host RAM via the global memory_map. - Async rcvReq* IOP→host events (DiskInserted, DiskEjected, DiskStatusChanged) emitted from a 20 ms drive-poll scheduler tick whenever floppy_drive_image() state changes. - DriveStatus and ExtDriveStatus synthesised from floppy module state (track, write-protect, in-place, sides, format, controller kind). Adds floppy_drive_image() to expose the disk image_t* for sector I/O without leaking the floppy internals to the IOP layer. Trims two stale private-docs path references from iop.c comments. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The previous swim_read_blocks/swim_write_blocks used memory_write_uint8 / memory_read_uint8, which route through the host CPU's current MMU SoA tables. When iop_swim_on_host_kick runs mid-instruction, those tables reflect whatever supervisor/user context the host happens to be in — and on the IIfx (MMU on with explicit TT0/TT1 setup) the write fast path was silently dropping the bytes for the .Sony driver's boot-block read buffer at $00400E6C, so the host saw the boot-time RAM scrub pattern instead of "LK ...". Replace with a direct write into the memory_map's flat RAM image via ram_native_pointer, which is what the PIC's DMA controller does on real hardware (DMA bypasses the CPU MMU and targets physical RAM). Bounds-check against ram_size to guard against bogus BufferAddr from mis-formed requests. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The .Sony driver's @AddDriveLoop iterates over DriveKinds[0..N] passing
the index `d1` as the drive-number argument to _AddDrive. With our
previous DriveKinds = {04, 04, 00, 00} the first physical floppy was
registered at d1=0, giving qDrive=0 in the drive queue. The boot
drive search loop at $40801360 then walked head-first, found that
qDrive=0 entry, wrote BootDrive ($0210) := 0 via $408015E8, and read
the boot block successfully — but the boot block code itself ($00400F9C)
copied BootDrive into ioVRefNum and called _MountVol, which rejects
ioVRefNum=0 with paramErr (-50). The ROM's failure fallback at
$4080203E then ejected the disk and reset the IOP, looping forever.
Fix: advertise DriveKinds = {00, 04, 04, 00} so .Sony skips d1=0 and
adds drives starting at d1=1 (= qDrive=1). Add a thin floppy_idx ↔
.Sony-drive-number mapping (swim_floppy_to_drvnum /
swim_drvnum_to_floppy) and route all per-drive handlers
(DriveStatus / Eject / Read / Write / Format) through it so the
physical floppy module index stays 0-based while the .Sony driver
sees 1-based numbers.
With this in place, the IIfx boots from the System 7.0.1 floppy:
trace shows xmtReqRead progressing through the HFS Master Directory
Block (blk=2), volume bitmap, catalog B-tree, and many subsequent
block reads as the OS loads the System file. Final screen at
~580M instructions: System 7 parity-circuitry warning dialog
("Shut Down / Continue"), confirming we're now in user-mode OS code.
See local/gs-docs/asm/IIfx-ROM.asm §20-§23 for the instruction-level
trace that led to this fix.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The IIfx ships with a RAM Parity Unit (RPU) chip whose self-test fires a level-7 NMI on bad-parity reads. Our emulator doesn't model the chip's register surface or NMI path, so the boot's POST self-test fails and either disables parity or leaves it in an indeterminate state. System 7's ParityINIT then sees AddrMapFlags advertising RPUExists (bit 20) but finds parity "not enabled" via _Gestalt — that combination is exactly the @parityOff path which posts the "Parity has been disabled because the parity circuitry is not functioning" alert and stalls the boot at a modal dialog. Minimal fake: after POST has installed the real AddrMapFlags (signature: low three bits set = ROM/DiagROM/VIA1 exist), strip RPUExists from the long. The OS's gestaltParityAttr handler then takes the @parityExit branch and returns zero — "no parity capability" — which makes ParityINIT skip the dialog entirely. Implementation runs from the existing VBL tick; uses ram_native_pointer to write the physical-RAM image directly (bypasses MMU like the SWIM IOP DMA path does). Guarded on the post-POST AddrMapFlags signature so the patch doesn't fire while POST is still scrubbing RAM with test patterns. Boot now reaches the System 7 Finder desktop from the floppy: "Disk Tools" volume mounted, menu bar visible, Trash icon present — no parity dialog. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This reverts commit b589fa9.
The IIfx has an optional RAM Parity Unit (RPU) chip whose base lives at $50F1E000 (DecoderInfo.RPUAddr). On real hardware the chip is only present when parity SIMMs are installed; without it, the BIU30 leaves the address undecoded and every access bus-errors. POST phase $93 ($408430DC) probes $50F1E000 with 32 BSET/BCLR/MOVE.L cycles and expects every one to bus-error. A successful probe (= "no RPU") leaves AddrMapFlags bit 20 (RPUExists) clear; an installed RPU sets the bit. System 7's gestaltParityAttr handler then either takes @parityExit (returns 0 = "no parity capability") or @checkRPU / @parityOff (= "capability present but not enabled" → ParityINIT dialog). Our prototype previously had a generic R/W backing store covering the entire OSS-extension window ($50F1C000-$50F1FFFF), which absorbed POST's probe writes silently — POST falsely concluded "RPU installed" and AddrMapFlags carried bit 20 into System 7, where the gestalt check found parity disabled and posted the warning dialog. Fix: in the I/O dispatch, route $50F1E000-$50F1E01F through iifx_bus_error() on both read and write, leaving the rest of the OSS-extension window alone. POST now sees the bus errors phase $93 needs, leaves RPUExists clear, and System 7 boots straight to the Finder desktop with no parity dialog. Replaces the earlier b589fa9 software patch (reverted in b91832d) that cleared AddrMapFlags bit 20 from a VBL hook — that was a lowmem patch real hardware would never do. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Wire the existing ADB device-state machine (adb_t) into the IIfx via
the SWIM IOP's slot-3 mailbox. The IIfx ADB bus is bit-banged by the
PIC's 65C02 firmware ($F032 in iop-swim.bin), not by VIA1's shift
register; the OS posts each ADB command to XmtMsg[3] and reads the
reply from RcvMsg[3].
- adb_iop_transact(cmd, in_data, in_len, out_data, out_len_ptr):
new public API on adb.c that dispatches Talk / Listen / Reset /
Flush through the same prepare_talk_reply / apply_listen_data
helpers the VIA-shift path uses, but returns the Talk reply by
value instead of clocking it out via_input_sr().
- adb_init() now tolerates NULL via: set_adb_int / adb_autopoll
short-circuit when the machine is IOP-based. Autopoll is the
SWIM IOP firmware's job in this configuration, not adb.c's.
- iifx_init() constructs adb_t with via=NULL and exposes it via
cfg->adb, so system_mouse_update / adb_keyboard_event route to
the SWIM IOP transparently. Teardown + checkpoint plumbing
added to match.
- swim_handle_xmt_slot / swim_adb_response / swim_handle_rcv_slot
snapshot the Listen-side ADBData into SWIM_MODEL_ADB_DATA before
the host's XmtMsg buffer can be overwritten, then call
adb_iop_transact when the deferred response fires. The reply's
Flags byte clears NoReply when a device acknowledged (including
zero-data Flush / Listen acks) and sets it otherwise.
- adb_decode_command's type-00 case now distinguishes SendReset
(\$X0) from Flush (\$X1) per Inside Mac V section 6.2. Earlier
code treated every type-00 command as a broadcast reset, which
would wipe an address remap set up by Listen-R3 immediately
before.
With this in place, the IIfx boot's ADB device-discovery scan now
sees real Talk-R3 replies from the keyboard at addr 2 and the mouse
at addr 3 — same data that the SE/30 and IIcx tests get through the
VIA-shift path. Apple-menu interaction from mouse.click doesn't yet
pull the menu down: the OS's ADB Mgr enters a Flush-keyboard (\$21)
loop instead of the expected Talk-R0 autopoll cycle, so host-side
mouse-button changes aren't sampled. Filed for follow-up.
iifx-boot / iix-floppy / se30-floppy-hd / iicx-mactest all pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Updates the iifx-boot integration test from "boot to ? disk prompt"
to "boot from System 7.0.1 floppy and verify the Finder desktop"
(the IIfx analogue of se30-floppy-hd).
Replaces question-mark-640x480.png with finder.png (640x480 grey
desktop with menu bar, "Disk Tools" volume icon, Trash icon, mouse
cursor at top-left) — the same scenario se30-floppy-hd / iix-floppy
verify on their respective machines.
Adds two new asserts beyond the rebaselined screen.match:
- fDBInit clear at $5405 (carried over: confirms the ADB device-
table scan finished).
- AddrMapFlags bit 20 (RPUExists) clear: confirms POST phase $93's
bus-error probe of $50F1E000 (commit a2f2e34) saw the bus
errors it expected and didn't advertise the optional RPU
parity unit, so System 7's ParityINIT skips its dialog.
Exercises end-to-end through:
- Full IIfx ROM POST (PMOVEFD, FMC ROM-mirror invert, OSS, IOPs,
RPU bus-error probe).
- SCC + SWIM IOP firmware load and behavioural-model start.
- SWIM IOP slot-3 ADB protocol (Talk-R3 device probe + Listen-R3
address remap + Flush + autopoll via adb_iop_transact).
- SWIM IOP slot-2 .Sony driver protocol (Initialize / SetHFSTagAddr
/ StartPolling / DiskInserted async event / DriveStatus / Read).
- Boot block code at $00400EF6, ROM-side System loader at
$4080203E + region.
Note: this test verifies the boot reaches Finder; it does NOT yet
exercise the Apple-menu / About-dialog interaction. Host-side
mouse.click currently doesn't pull the menu down on IIfx because
the OS's ADB Mgr enters a Flush-keyboard ($21) retry loop instead
of the expected Talk-R0 autopoll cycle, so host-side button
changes aren't sampled. Tracked for follow-up.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The IIfx's ADB Manager (Sys 7 source: OS/IoPrimitives/ADBPrimitives.a,
IopADB branch) splits slot-3 traffic into two distinct flavours:
- Explicit (Flags has ExplicitCmd bit 7): host fills ADBCmd with a
specific Talk / Listen / Reset / Flush byte and expects the
firmware to issue it on the bus.
- Implicit autopoll (Flags has PollEnable bit 6 — set by IOPStartReq
when fDBExpActive is already 1 or when no explicit cmd is queued):
the ADBCmd field is meaningless (just whatever stale byte the
XmtMsg buffer happened to hold), and the firmware is expected to
pick the next enabled device from its DevMap and Talk-R0 it on
its own. When SetPollEnables bit 5 is also set, ADBData carries
a fresh 2-byte DevMap that should replace the current poll mask.
Previously swim_adb_response always dispatched the host's ADBCmd byte
through adb_iop_transact, which on autopoll messages produced a
nonsensical Flush of whatever device happened to share the byte's
high nibble (typically the keyboard). The OS's IOPReqDone then took
the ImplicitRequestDone branch — fDBExpActive stayed set, the cmd
queue head never advanced, ADBOpTrap returned qErr, sendFlush retried
forever, and host-side mouse clicks were never sampled because no
Talk-R0 ever ran for the mouse address.
Fix: in swim_adb_response, branch on the request's Flags:
- ExplicitCmd path: keep the existing adb_iop_transact dispatch on
ADBCmd. Echo ExplicitCmd back in the reply so IOPReqDone takes
ExplicitRequestDone and advances the cmd queue.
- Autopoll path: cycle through ADB addresses 1..15 (round-robin
pointer in SWIM_MODEL_AUTOPOLL_ADDR, biased by SWIM_MODEL_DEVMAP
if the OS has installed a poll bitmap), Talk-R0 each via
adb_iop_transact, return the first non-NoReply reply. Set the
reply ADBCmd to the actual Talk command issued so the OS's
pollCmd / pollAddr globals reflect which device responded.
- SetPollEnables: latch the 2-byte DevMap bitmap from ADBData into
SWIM_MODEL_DEVMAP and clear the SetPollEnables bit on the reply
(it's a one-shot bit per IOPStartReq's @implicit / @explicit
layout).
With this in place, the IIfx host-side mouse.click + Apple-menu
sequence now drops the menu and selects "About This Macintosh..."
— the dialog renders "Macintosh IIfx" / "System Software 7.0.1" /
"Total Memory: 16,384K" exactly as the IIfx ROM advertises itself.
iifx-boot now matches both finder.png and about.png; iix-floppy /
se30-floppy-hd / iicx-mactest still pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The existing §16 only said "host posts XmtMsg requests describing the
floppy operation" / "Talk and listen transactions are issued as XmtMsg
requests". That hand-wave is now backed by three new sections:
§17 SwimIopMsg payload layout, all 17 xmtReq codes, the 3 rcvReq
event codes, and the DriveKinds qDrive-numbering convention
(why DriveKinds[0] must be noDriveKind on the IIfx — Mac OS
rejects ioVRefNum=0 in _MountVol).
§18 ADBMsg payload layout, the Flags bit semantics (ExplicitCmd /
PollEnable / SetPollEnables / SRQ / NoReply), and the two
transport flavors (explicit vs implicit autopoll). Documents
that the reply ADBCmd must echo the actually-issued Talk
command (autopoll round-robin) so the OS's pollCmd / pollAddr
globals stay coherent.
§19 RPU bus-error probe at \$50F1E000. POST phase \$93 runs ~32
BSET/BCLR/MOVE.L cycles all expected to bus-error; success
sets AddrMapFlags bit 20 (RPUExists) and triggers
ParityINIT's "Parity has been disabled" modal at Finder time.
§16's slot table is updated to make the channel/protocol assignment
explicit (1 = IOPMgr kernel, 2 = SonyIOP, 3 = ADBMsg).
Finder paints stable by ~225M instructions on this boot path, and the post-click About-dialog handshake settles much faster than the previous "leave plenty of headroom" budgets suggested. Verified deterministic (269,238,974 instructions at the final about-match) across three fresh-boot runs. scheduler.run 700000000 → 260000000 (boot to Finder) scheduler.run 50000000 → 10000000 (after click true; menu drop) scheduler.run 40000000 → 10000000 (between Apple-menu moves) scheduler.run 200000000 → 10000000 (after click false; About paint) Wall-clock on a Codespaces sandbox drops from ~50s+ to ~20s.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
New top-level Macintosh IIfx machine target, plus the two cross-cutting subsystems it needs that no other machine in the tree had:
IOP (Apple 343S1021 PIC) framework —
iop.cshared core +iop_scc.candiop_swim.cper-IOP behavioural models. Implements the full host-visible mailbox protocol over shared RAM: PIC register window,iopRamAddr/iopRamData/iopStatCtlsemantics, alive-handshake, code-load, soft-restart viaPatchReqAddr, and Int0/Int1 dispatch into the host.xmtReqfloppy commands (Initialize / DriveStatus / Read / Write / Format / Eject / StartPolling / …), asyncrcvReqevents (DiskInserted/Ejected/StatusChanged), and the DriveKinds qDrive-numbering convention.SetPollEnables, replyADBCmdecho of the actually-issued Talk command so the OS'spollCmd/pollAddrglobals stay coherent.\$50F04020-3F+ firmware-driven mailbox mode.OSS (Operational System Switch) — IIfx-only interrupt controller. Per-source pending bitmap + per-source priority bytes, autovector arbitration, and source-6/source-7 wiring for the two IOPs'
hintlines.IIfx machine —
src/machines/iifx.cties everything together: 68030 + 16 MB RAM + SWIM IOP + SCC IOP + OSS + ADB-via-IOP + JMFB video as slot $9 NuBus card + RTC + VIA1. Boots System 7.0.1 from a 1.44 MB MFM floppy through POST + ADB scan +.Sonydriver init + boot blocks + System loader to the Finder desktop, and brings up the "About This Macintosh" dialog via Apple-menu interaction.Optional RPU bus-error model at `$50F1E000` — POST phase $93 probes the optional RAM Parity Unit with ~32 BSET/BCLR/MOVE.L cycles all expected to bus-error. Returning anything but a bus-error sets
AddrMapFlagsbit 20 (RPUExists) and trips System 7's `ParityINIT` modal at Finder time. The model bus-errors every access in\$50F1E000..\$50F1E01F, matching the real BIU30's behaviour on unequipped IIfxs.Incidental supporting changes
\$X1isFlush, not broadcastSendReset. The old fallthrough wiped the device-address remap and made the OS loop probing the same devices forever after any Flush.viatolerance in ADB:adb_init/set_adb_intshort-circuit whenvia == NULL(IOP-based machines have no direct VIA wiring for vADBInt).adb_iop_transactpublic API: lets the SWIM IOP issue a single ADB command through the existing ADB device model and read back the reply.machine->update_iplfor machines without VIA2 (IIfx).floppy_drive_image(floppy, drive)accessor.4147DD77).Documentation
docs/iifx.md(803 lines, new): full IOP reference — register window,iopStatCtlper-bit semantics, shared-RAM layout, mailbox protocol (both directions), slot-2 SonyIOP byte protocol with all 17 commands + 3 events, slot-3 ADBMsg byte protocol with all fiveFlagsbits, the RPU bus-error probe, and per-IOP specifics for SCC vs SWIM.Test plan
make -f Makefile.headlessbuilds clean (no warnings beyond the pre-existingstrncpytruncation).make -C tests/integration test-iifx-bootPASSes — boots System 7.0.1 to Finder, matchesfinder.png, brings up the Apple-menu "About This Macintosh" dialog, matchesabout.png.ed36e07) compiles standalone after the rebase onto current main.