Skip to content

Case Study: A4091 / 53C710 SCSI driver

This is the deep end of the drivers pillar: writing a brand-new SCSI host adapter driver for Amix, for a board the OS was never meant to support, and getting Amix to boot with root, swap and filesystem entirely on it. It pulls together the device-driver model, Zorro AUTOCONFIG, the kernel build and the boot process — all the other driver pages applied at once to a real board.

The work is first-party and reproduced locally in Amiberry on the real Amix 2.1c distribution. Claims tagged ✅ below were reproduced on the running system; 🟡 claims are emulation-only and need real-hardware confirmation; 🔴 marks a belief we held and disproved. The source is the A4091-on-Amix project — src/a4091-wr.c, the src/kernel-patches/, driver.conf, and its CHANGELOG.md and docs/.

What the A4091 is

The A4091 is Commodore's Zorro III SCSI-2 host adapter, built on the NCR/Symbios 53C710 SCSI I/O processor ✅. It is the high-end successor to the Zorro II A2091 (WD33C93), intended for the A3000T/A4000T class.

Its AUTOCONFIG identity and memory window ✅ (src/a4091-wr.c, docs/a4091-53c710-reference.md §0):

Property Value Source
AutoConfig manufacturer 0x0202 (Commodore) a4091-wr.c A4091_PROD
AutoConfig product 0x54 a4091-wr.c A4091_PROD
Combined product id 0x02020054 a4091-wr.c #define A4091_PROD 0x02020054
er_Type 0x90 (Zorro III) reference §0
Physical board base 0x40000000 a4091-wr.c a4091map() fallback
Board window 0x01000000 (16 MB), sparse reference §1
53C710 register block board + 0x00800000 → 0x40800000 a4091-wr.c SIOP_OFF

Amix (Commodore's SVR4.0 port to 68030 Amigas, the "2.1c" distribution ✅) shipped with no 53C710 driver and is widely described as Zorro II only ✅ — see Zorro AUTOCONFIG for drivers and Supported hardware. The stock kernel only knows the A2090/A2091 (WD33C93) and the A3000 on-board SCSI. This project wrote a native 53C710 block driver and made the A4091 a first-class, auto-detected SCSI controller alongside them.

The Zorro III obstacle and the sptalloc() solution

The board is in Zorro III space, and that is exactly where the stock drivers' trick breaks down.

🔴 "Zorro III is unaddressable" — was thought absolute, is actually an unmapped address range with a work-around. Amix identity-maps only the low 1 GB of physical address space, 0x00000000–0x3FFFFFFF ✅. That leaves 0x40000000–0x7FFFFFFF unmapped — and the A4091 sits in it ✅. Zorro II boards are ≤ 24-bit (e.g. the A3000 SCSI at 0xDD0000), so they fall inside the identity map; that is why the stock WD33C93 drivers can simply dereference the address autocon() returns. Extending the identity map upward to cover the gap is unsafe — amiga/ml/syms.s places the page-mapped u-area at 0x40000000 ✅.

Correction (2026-08-14). This section previously attributed that identity map to the 68030's Transparent-Translation registers (tt0 = 0x003F0143 / tt1 = 0x807F0143, from amiga/ml/ttrap.s). AMIX does not use the TT registers — they read E = 0 on a running kernel, the boot path zeroes them, and the identity map is a section-0 early-termination page descriptor in the MMU root table ✅. Nothing below changes; see how the low 1 GB is really mapped.

The fix is the kernel primitive sptalloc(npages, prot, pfn, flag), which page-table-maps physical pages into kernel virtual address space ✅. The driver maps the board's AutoConfig page and the 53C710 register block (src/a4091-wr.c, a4091map()):

#define SIOP_OFF    0x00800000  /* 53C710 register block within the board window */
...
acfg = (volatile uchar *)sptalloc( 1, PG_V, phystopfn( (paddr_t)base), 0);          /* board base    */
siop = (volatile uchar *)sptalloc( 1, PG_V, phystopfn( (paddr_t)base + SIOP_OFF), 0); /* 53C710 regs */

Post-boot these return working kernel VAs (observed siop = 0x401CA000) and the 53C710 is fully addressable ✅. DMA is unaffected: the 53C710 bus-masters to Amix RAM at phys 0x07800000+, which is inside the identity-mapped low 1 GB, so DMA targets are reachable no matter where the board's registers land in kernel VA ✅. (See Zorro AUTOCONFIG for autocon() and the Zorro III detection that complements this mapping.)

sptalloc() is the 68030 build's mapping. The 68040/68060 arm of the same driver (-DA4091_KVA) cannot use it, because there sptalloc() gives a cacheable page: it maps both register pages non-cacheable with dev_kvmap() and sends every transfer through a DMA-coherence service (the project's docs/D42-CALL-SHAPE.md) ✅. "DMA is unaffected" is the 68030 line's rule only; the 030 build does no cache maintenance, which is justified in emulation (data cache off) only 🟡.

The 53C710 driver model — how it plugs into the Amix SCSI stack

✅ The Amix SCSI stack (amiga/alien/) layers like this:

block disk driver dd.c / gsioctl passthrough  ->  sd.c selector  ->  per-card queue function  ->  chip

The command unit handed down the stack is struct sdcom (sd.h): cdb[12], the data addr/nbyte, unit/card, the reading flag, status/okay, and an intr() completion callback ✅. See the device-driver model for the general switch-table mechanism this sits on top of.

The card registry in sd.c

sd.c carries a registry table scsicard[] mapping AutoConfig product ids to queue functions. The project ships no sd.c: its driver.conf lists one row per board the driver binds, and amix-kerntools' amix-build generates the sd.c additions from it (gen_sd_patch) ✅:

static struct {
    uint    pn;             /* product number */
    bool    (*f)( );            /* queuing function */
    char    *hardwarename;
} scsicard[] = {
    0x0202F003, &a3091queue, "A3000 Internal SCSI",
    0x02020001, &a2090queue, "A2090 SCSI",
    0x02020003, &a2091queue, "A2091 SCSI",
    0x02020054, &a4091queue, "A4091 SCSI",   /* <- generated from driver.conf */
    0xc0de0001, &a4091queue, "A4092 SCSI",
    0xc0de0002, &a4091queue, "A4770 SCSI",
};

At the first root open, sd.c init() calls autocon(productid, …) for each row and insert()s the cards it finds, sorted ascending by board base address ✅:

static void
init( )
{
    if (not queue->f)
        for (i=0; i<nel( scsicard); ++i) {
            int c = 0;
            while (autocon( scsicard[i].pn, c, &a, &o))
                insert( scsicard[i].f, c++, a, scsicard[i].hardwarename);
        }
}

So on a machine with both controllers, the A3000 SCSI (0xDD0000) becomes queue[0] (card 0) and the A4091 (0x40000000) becomes queue[1] (card 1) — the lower base sorts first ✅. This ordering is the entire story behind booting root from the A4091 — see the boot process: root on an A4091 and the phantom-A3000 fix in Zorro AUTOCONFIG.

Why the stock ordering cannot be trusted at all. Stock autocon() decides whether the A3000 internal SCSI exists from where the kernel was loaded (end > 0x07000000 in support.c, end being the kernel's own end address), never from the hardware ✅ — so it fabricates a card 0 where no controller exists and, on a machine where the kernel loads lower, silently drops the real one (root disk included) while every remaining card renumbers ✅. Both directions produce a machine that cannot find its disk and says nothing. Probe, don't guess — see quirks §41 and the chipset-gated WD33C93 probe that replaces the special case.

amix-build also generates the matching amiga/alien Makefile edit, which adds a4091.o to the OBJ list (gen_makefile_patch); the project does not ship it.

The driver itself: a4091-wr.c

The production driver is src/a4091-wr.c (the READ+WRITE driver) ✅. Its key pieces:

  • a4091map() — sptalloc-maps the board base and the register block (above; dev_kvmap on the 040/060 arm), and caches the mapping per card so it only happens once. The 68030 build falls back to the known base 0x40000000 if no base was recorded for the card; the 040/060 arm has no fallback and treats that as "no board" ✅.
  • a4091init() — a 53C710 soft reset followed by minimal polled-mode register init. Reset is via ISTAT bit 6 (not DCNTL — that is the older 53C700) and is not self-clearing, so it is set then explicitly cleared. The init writes SCNTL0=0xCC, SCNTL1=0x20, DCNTL=0x00, DMODE=0xE0 (burst-8 | FC2, the A4091 value), the one-hot host id SCID = 1 << 7 = 0x80, and the A4091 bus-arbitration errata bit CTEST8 |= 0x01 (SM). No SCSI/DMA interrupts are enabled ✅. On an A4092 with card CPLD 1.4.21 the SM bit is mandatory: the CPLD grants the bus only with it set, so a 53C710 driver that leaves it clear never gets a DMA cycle ✅ (real hardware and the CPLD's logic) — see below. All register writes go to reg + 0x40 (the A4091 write-shadow WRSHADOW), reads at reg + 0; accesses are 8- or 32-bit only, never 16-bit ✅.
  • a4091queue(c, cp) — drives any CDB from the caller's sdcom through a table-indirect 53C710 SCRIPTS program (inq_script[], a static ulong[] that lives in kernel .data, so its bus address equals &inq_script[0] under the low-1 GB identity mapping). CDB length is derived from the SCSI group code (top 3 bits of the opcode → 6 / 10 / 12 bytes). The DSA (struct siop_ds) binds IDENTIFY / CDB / status / message / data buffers; the DATA phase dispatches on the live bus phase, so one SCRIPTS program performs both READ(10) and WRITE(10). Data DMAs straight into cp->addr — the caller's buffer, already a physical address via dd.c's vtop() ✅.

The SCRIPTS program's data-phase dispatch (from inq_script[] in src/a4091-wr.c) is what makes one program serve reads and writes:

0x808b0000, 0x00000018,     /* JUMP dataout, WHEN DATA_OUT  (write)         */
0x818b0000, 0x00000020,     /* JUMP datain,  WHEN DATA_IN   (read)          */
0x838b0000, 0x00000020,     /* JUMP status,  WHEN STATUS    (no data)       */

The DSA table binds the caller's buffer for the data move ✅:

ds.data1len = cp->nbyte;  ds.data1buf = (uchar *)cp->addr;  /* DMA -> caller buf */

Completion: a bounded ISTAT poll

After launching SCRIPTS (a write to R_DSP), the driver spins on ISTAT until SIP or DIP is set or a bound of 8 000 000 reads runs out ✅:

WR32( R_DSP, (ulong)inq_script);
/* bounded-poll completion -- spin on ISTAT until SIP|DIP or the bound */
while (poll < limit) {
    istat = RD8(R_ISTAT);
    if (istat & (ISTAT_SIP | ISTAT_DIP)) break;
    poll = poll + 1;
}
...
if (!(istat & (ISTAT_SIP | ISTAT_DIP)))         rc = -2;    /* bound ran out */
else if (sstat0 & SSTAT0_STO)                   rc = -1;    /* selection timeout */
else if ((dstat & DSTAT_SIR) && dsps == 0xff00) rc = 0;     /* SCRIPTS "done" INT */

The bound exists because the same path runs the boot-time SCSI bus scan, which must not hang on an empty id ✅. After a short-read resume the driver re-polls the same way, and it keeps a4091_maxpoll (the high-water poll count) and the a4091_slow_poll console threshold so the cost on a physical disk can be read back ✅. This completion ran on metal in the 68040/68060 build — the A4092 results below came through it 🟡 (one machine). Interrupt-driven completion is not implemented: the driver enables no SCSI/DMA interrupts. The early prototypes (a4091-nopoll.c, a4091-blk.c) used a single ISTAT read, which works only because the emulated target answers synchronously ✅.

For the full 53C710 register map, SCRIPTS encoding, one-hot SELECT-ID encoding, the soft-reset sequence, the write-shadow at reg+0x40, and the emulator's full-window SIGSEGV hazard, see the project's docs/a4091-53c710-reference.md (the verified chip reference behind this driver).

The A4091 disk's /dev numbering

✅ With both an A3000 and an A4091 present, the A4091 (card 1) target 0 slice 0 is reached at:

/dev/dsk/c8d0s0    block, major 18, minor 8
/dev/rdsk/c8d0s0   char,  major 40, minor 8

The cN in the name is computed, not stored — see the SCSI minor-number scheme on the device list. From amiga/alien/sd.h:

sdunit(dev) = (dev>>0) & 7      /* SCSI target id 0-7        */
sdcard(dev) = (dev>>3) & 1      /* card index (queue[] slot) -- only 0 or 1; SDCARDS = 2 */
sdpart(dev) = (dev>>4) & 7      /* slice/partition           */

So cN = sdcard*8 + sdunit: c8d0s0 = card 1, target 0, slice 0 = makedevice(18, 8); the stock A3000-root device c6d0s1 = card 0, target 6, slice 1 = makedevice(18, 22) ✅. A dev_t is (major << 18) | minor ✅.

The READ/WRITE path was validated end to end ✅:

  • Raw SCSI passthrough via the gsioctl userspace path (src/gsio.c, /dev/scsi major 11) — INQUIRY, READ(10), WRITE(10) all returning correct data.
  • mkfs ufs + mount on the A4091 disk, with files written and surviving a reboot (genuine persistence to the disk behind the A4091, not a RAM artefact).

Driver variants — the evolution

Only a4091-wr.c is the production driver; the earlier variants are kept under src/ to show the incremental bring-up path ✅:

File Stage
a4091.c detection-only (proves sptalloc + register read)
a4091-nopoll.c INQUIRY only
a4091-blk.c READ-only block device
a4091-wr.c READ + WRITE — production
a4091-wr-dbg.c same as production + A4: printf diagnostics (used to trace the early-boot path)

Build & install

The driver is a standard kernel-relink job (kernel build & install), with the A4091-specific steps:

  1. Drop the driver src/a4091-wr.c into the kernel tree as /usr/sys/amiga/alien/a4091.c.
  2. Register it in the Makefile — add a4091.o to the amiga/alien OBJ list (generated from driver.conf by amix-kerntools' amix-build).
  3. Add the SCSI-stack rows — the scsicard[] rows in sd.c, also generated from driver.conf by amix-build.
  4. Apply the auto-detect patch — the chipset-gated autocon() in support.c (src/kernel-patches/support.c.patch); this is what lets one kernel boot both an A3000 and an A4000+A4091. The why is on Zorro AUTOCONFIG and the boot process.
  5. Build with the clean-gate. The Amix ld intermittently corrupts the linked kernel (the "D245 boot-breaker"); relink until the checksum recurs rather than trusting a single make. Use tools/build-clean-kernel.sh and verify with tools/relsim.py / checkunix.c — full detail on kernel build & install. Never make install an unverified kernel onto your working disk — it rewrites the boot partition and bricks it if the kernel is corrupt.
  6. Install carefully onto a throwaway / clone disk — see adding drivers to a custom boot disk and the "boot root on the A4091" install recipe on the boot process.

Tip — cross-develop on a modern host. As of 2026-06 you can build the driver object on Linux with the gcc-cross-amix cross-toolchain (m68k-cbm-sysv4-gcc) instead of editing on the box — it cross-compiles a real Amix driver .c to a relocatable m68k ELF; you then do only the final relink on Amix. See Toolchain → cross-compiling. ✅

The SCRIPTS source (reference/scripts/inq-wr.ss) is assembled with the NetBSD ncr53cxxx assembler from the open-source a4091.device project, which also provides the A4091 autoboot ROM used by the emulator (Amix on Amiberry).

Zorro III DMA into a Z3660's CPU RAM — the first metal data point (2026-10-02)

Can a Zorro III bus master reach the RAM on a Z3660 accelerator? For one setup the answer is yes ✅: on an A4000D (Buster -11) with a Z3660 in real-68LC060 mode, an autoconfigured A4092 (53C710, card CPLD 1.4.21, at 0x40000000) DMAs into the Z3660's CPU-local RAM at 0x08000000, the memory the Amix kernel runs from. The kernel was a 68060 Amix kernel with this driver and a DMA cache-coherence service; with copyback caching on, LBA 0 reads back as a valid RDB, 4 MB and 32 MB raw reads give the same checksum on every read and across power-cycled boots, and the coherence service's invariants held over about 72 MB of device-to-memory transfers ✅. The data is also right, not merely repeatable ✅: a host copy of the disk image (104 857 600 bytes, pulled without the Amiga's network, every 8 MiB piece CRC-checked against the device) has the same sum -r at 4 MiB (49574, matching the Amix reads on both boots) and at 32 MiB (09482, matching both reads on the first boot) and the same block 0. So the read direction — device to Z3660 RAM — is coherent ✅. The write direction (memory to device) and root on the A4092 followed on the same A4000D + Z3660 with the same driver arm 🟡 (one machine): on 2026-10-03 the A4092 carried the root filesystem through two full boots, and on 2026-10-11 the hardware acceptance of the 1.0 install media installed the 30-package set onto a 512 MB disk behind the A4092 (c9d0) in 1 h 45 min, with a clean final fsck and a booting system.

Why the read direction can be coherent in hardware 🟡. The Z3660's CPLD drives the 68060's SNOOP input low on every cycle of its own DMA engine and whenever the ARM holds the bus (z3660.vhd line 459 in the flashed DMA_WIP design; the firmware's CHANGES for v1.03 beta 2 note the SNOOP change) ✅ (read from the source). Per the MC68060 bus-snooping rules as commonly described, a snooped write by another master invalidates a matching data-cache line, while a snooped read is not supplied from a dirty cache line (the 68040's snoop-sourcing was dropped on the 68060) — the manual is not in this project's sources, so this half is 🟡. If that holds, DMA into Z3660 RAM is coherent without software help, and DMA out of it is not: a driver must push dirty cache lines to memory before a device reads them. Earlier cautions that Zorro DMA cannot reach a Z3660's memory concerned RAM autoconfigured into Zorro space; they do not describe this CPU-local aperture 🟡. Registering the A4092 at all needed the stock-kernel fix in quirks §65.

What the Zynq side sees ✅ (real hardware, A4000D + Z3660). The Z3660's CPU RAM is cache-coherent on the ARM side through the Zynq's ACP port: writes by the 68060 or by a Zorro master sit as dirty lines in the ARM's L2. Firmware that reads memory a bus master has written must clean and invalidate, never plain-invalidate (that discards the DMA'd data), and must clean anything it wrote before a master reads it. The card's bus arbiter ranks an external master above the ARM above the 68060, so the ARM can take the bus from a running 060 (grant in under 1 µs) and must not issue a bus cycle while the 53C710 may own it.

A second card, and root as a module (2026-10-18 to 2026-10-27) ✅

On the same A4000D + Z3660 a second A4092 card passed a 22 MB read whose CRC matched with the DMA buffer in motherboard RAM and in Z3660 RAM, plus a 4 MiB write/verify; under the 1.1 module kernel (68060 line) reads through it were byte-equal to the host copy, and it carried the root filesystem alone and beside the Z3660's own disk ✅ (first-party record). The "one machine" caveat in the table below still applies: one A4000D, now two A4092 cards.

A4092 CPLD and 53C710 behaviour ✅

Measured on real hardware with the 53C710 driven from the Z3660's ARM, and read from the CPLD logic:

  • CPLD 1.4.21 gates the bus grant on CTEST8.SM (the grant follows the chip's SC0 line, which SM drives). Every A4092 with that CPLD needs SM set by the driver. A diagnostic that never sets SM on a 53C710 — the ncr7xx tool's DMA tests 4–7 — therefore fails on every such card without a fault.
  • The CPLD version is readable from the board's AutoConfig serial number (01040015 = 1.4.21); the card's ROM header carries manufacturer 0xD0CE, a nibble swap of the 0xC0DE AutoConfig id.
  • Never read the 53C710's longword at +0x14 while it is connected to a target: the read pops the SCSI FIFO and raises a gross error.
  • The 53C710 can raise a selection timeout while connected and halt SCRIPTS even with SIEN clear; re-running the phase switch recovers. SCRIPTS should be phase-adaptive (the reference driver's switch shape); straight-line scripts halt at the end of MSG OUT.
  • Byte writes of CTEST8.SM and CTEST7.CDIS misbehave about one boot in four: write, read back, retry.
  • Rates through the A4092 to a ZuluSCSI target with an asynchronous transfer: 6.4 MB/s on the bus with no OS running, 3.85 MB/s with one; the asynchronous handshake ceiling is about 5.6 MB/s, and DMA is 35–48× faster than programmed I/O (9–12 µs per byte). Synchronous transfers were not measured.

The A4000T's onboard 53C710 ✅

The A4000T's onboard SCSI is a 53C710 with no AutoConfig ✅ (the reference AmigaOS driver's source and real hardware):

A4091 / A4092 A4000T onboard
Discovery AutoConfig none: fixed base $DD0000
Registers base + 0x800000 base + 0x40, written directly
DIP switches base + 0x8c0003 (byte) base + 0x3000 (longword)
DCNTL 0x00 0x20 (EA: connect _SLACK/_STERM)
Bus master Zorro III, through Buster a motherboard master, the class of the A3000's SDMAC
  • Its register window hangs any read until the A4000T ROM's own NCR driver has initialised the chip ✅ (real hardware: the first read at $DD0000 or $DD0040 hangs under a Kickstart without that driver, and 21 of 21 reads answer once it has run). An A4000D, which has no chip there, froze on a read at or near $DD0000 too (quirk 66). So a probe must be gated: AGA first (quirk 61), and then only when the A4000T ROM is known to have initialised the chip.
  • Amix boots with its root on the onboard 53C710 — on the 1.1 module kernel (68060 line), through Kickstart's NCR scsi.device, 3 of 3 cold boots ✅ (one A4000T).
  • Its DMA into Z3660 memory was clean (496 MiB, no miscompare, under AmigaOS) ✅; DMA into chip RAM with a Z3660 fitted hung or corrupted at random on the one A4000T tested, worse with larger transfers 🟡 (a reproduction board with open build items — possibly that board). A loader that keeps its DMA buffer in fast RAM booted cleanly there.

Not with the Z3660 in 68030 mode ✅: in its Amix 68030-emulation mode the Z3660 firmware hides the motherboard memory (so no memory a bus master can reach remains) and maps $DD0000 to its emulated A3000 SCSI, so neither the onboard 53C710 nor any other bus master can be used on that boot. The same mode makes Zorro III DMA impossible for the A4091/A4092 as well.

The first command's SCSI bus reset ✅

The driver's first command in a boot runs a SCSI bus reset that waits for 4000 changes of the beam counter. On metal (A4000D, A4092) that took about 0.25 s: the first INQUIRY to an empty id came back in under a second, with one reset and no reset timeout ✅. Under Amiberry at cpu_speed=max the first INQUIRY to the A4091 took 53 s on the 68060 kernel and 72 s on the 68030 kernel, and every later command under a second ✅. The likely reason 🟡: the wait counts changes of VHPOSR's high byte, which Amiberry at that speed shows only once or twice a frame, so any busy wait on the beam counter runs slow there. A fix that counts lines passed is pending.

Status

Claim Status
A4091/53C710 driver detects, reads and writes; root + swap + filesystem on the A4091; multi-user, networking ✅ emulation-proven (Amiberry, real Amix 2.1c)
One universal kernel boots both A3000(ECS) and A4000(AGA) + A4091 ✅ emulation-proven, one binary
Bounded ISTAT-poll completion (real disks are not instant) ✅ shipped; run on metal in the 68040/68060 build (A4092) 🟡 one machine; no interrupt-driven completion
Real-hardware validation of the 68030 line on a physical A3000 and A4000 + A4091 🟡 pending (emulation only)
An A4092 on real hardware (A4000D + Z3660, 68060 kernel): registered, raw reads match a host copy of the disk, DMA into the Z3660's RAM ✅ 2026-10-02
The same A4092: writes, root (two boots, 2026-10-03), a full install onto a disk behind it (2026-10-11) 🟡 one machine
A second A4092 card on the same machine; root on an A4092 under the 1.1 module kernel (68060 line) ✅ 2026-10-27, one machine
The A4000T onboard 53C710 as root (1.1 module kernel, 68060 line) ✅ 2026-10-28, one machine
Any bus-master DMA with the Z3660 in its 68030-emulation mode ✅ not possible (firmware hides the reachable memory)

See also

Sources

  • The first-command bus reset (first-party record, 2026-11-02) ✅/🟡 — kbootset inquiry timings under Amiberry on both kernel lines and on an A4000D with an A4092 (the driver's reset counters read with modadmin -p); the per-card bus reset in amigaux/amix kernel/drivers/a4091/CHANGELOG.md (2026-10-03). The VHPOSR explanation is the driver project's 🟡.
  • Stock sources, public ✅ — the stock SCSI layer in amigaux/amix-system (7cba961): usr/sys/amiga/alien/sd.c, usr/include/sys/sd.h, usr/sys/amiga/alien/dd.c, usr/sys/amiga/kernel/support.c.

  • The Z3660 CPLD's SNOOP drive — z3660-firmware/CPLD/DMA _WIP/z3660.vhd line 459 (nSNOOP low when DMA_BUSY or on an ARM bus grant; DMA_BUSY set whenever the CPLD's DMA state machine is not idle, line 424) and the firmware CHANGES.md, v1.03 beta 2 ✅. The 68060 snoop semantics are 🟡: the MC68060 User's Manual is not among this project's sources.

  • The first Zorro III DMA metal run into a Z3660's RAM ✅ — first-party record, 2026-10-02 (A4000D, Z3660 68LC060, an A4092 with CPLD 1.4.21 at 0x40000000; valid RDB at LBA 0, repeatable sum -r over 4 MB and 32 MB raw reads across power-cycled boots with copyback on, coherence invariants over ~72 MB), and the host-truth compare that closed the read side (the disk image pulled to the host, sha256 ec8d8d24…, every 8 MiB piece CRC-matched to the device, sum -r 49574 / 09482 and block 0 equal to the Amix reads).
  • The signed manufacturer compare in stock autocon() ✅ — amix-a4091 commit 06a7d96 (2026-10-02, support.c.patch: the unsigned shift, codegen swap/ext.l → clr.w/swap), the matching one-byte asr.l → lsr.l patch in the 68040/68060 relink tooling the same day, and the A4000D metal run that proved it (the A4092's 0xC0DE0001 handed over in bootinfo.autocon[] but unregistered without the fix, registered as card 1 with it; first-party record, 2026-10-02).
  • The 2026-09-29 stock-kernel RAM-layout measurement ✅ — on the emulated bench the same 64 MB A3000 motherboard bank boots a kernel that probes for the A3000 SCSI and stops the pinned stock kernel at s5mountroot VOP_OPEN error 6 (no card 0), symbolised against the stock autocon() load-address guess (first-party record, 2026-09-29; quirks §57).
  • The A4091-on-Amix project, https://github.com/jusii/amix-a4091 — README (incl. its Status table), CHANGELOG.md (dated entries, 2026-06 to 2026-10), docs/A4000T-ONBOARD-710.md, docs/D42-CALL-SHAPE.md (the 040/060 arm's dev_kvmap mapping and DMA-coherence service), and src//tools/; the emulation bring-up itself is first-party record, 2026-06-04/05 (reproduced locally ✅).
  • src/a4091-wr.c — the 53C710 READ+WRITE driver (A4091_PROD 0x02020054, SIOP_OFF 0x00800000, sptalloc() mapping, inq_script[], a4091queue() with its bounded ISTAT poll, a4091_maxpoll/a4091_slow_poll); SCRIPTS from the a4091-software repo's ncr53cxxx source.
  • src/kernel-patches/support.c.patch — the chipset-gated autocon() diff; driver.conf — the A4091, A4092 and A4770 identities from which amix-kerntools' amix-build (https://github.com/jusii/amix-kerntools, gen_sd_patch, gen_makefile_patch) generates the scsicard[] rows, sdcardbase() and the a4091.o OBJ entry.
  • The A4092 writes and root on metal 🟡 (one machine) — the amix-a4091 README (root filesystem through two full boots on an A4000D + Z3660, 2026-10-03) and Installer-NG docs/releases/1.0.md, Hardware acceptance (not public; the 30-package install onto c9d0 behind the A4092, 2026-10-11).
  • docs/a4091-53c710-reference.md in the project repo — the verified 53C710 register/SCRIPTS detail behind this driver.
  • The 2026-08-12/14 RAM-ceiling investigation (first-party record, 2026-08-12/14) — the identity map's real mechanism (the TT registers are disabled; a section-0 early-termination root-table descriptor maps the low 1 GB) and the two-sided failure of the stock load-address SCSI inference in support.c:305 (described then as a RAM-size test; corrected 2026-09-29), with real A3000s above 16 MB inside the affected envelope ✅.
  • a4091.device open-source project: https://github.com/A4091/a4091-software (A4091 ROM + ncr53cxxx SCRIPTS assembler).
  • The Zorro III write-path and DMA work on an A4000D + Z3660 (first-party record, 2026-10-17 to 2026-10-19) ✅: the ACP coherence rule, the CPLD arbiter priority, the A4092 CPLD 1.4.21 SM gate (with the CPLD's logic), the 53C710 behaviours, the menu-route and OS-route rates.
  • The second A4092 card and the module-kernel rows (first-party record, 2026-10-26 to 2026-10-27) ✅; amix-kerntools CHANGELOG 2026-10-27/28 (the A4000D and A4000T metal blocks).
  • amix-a4091 docs/A4000T-ONBOARD-710.md §1 (the onboard chip versus the A4091, from the reference driver's a4091.h, attach.c, siop.c, ncr7xx.c), §2 "T0 result" (the read hangs and the 21 answered reads), §10.10 (the Z3660 68030 mode) ✅.