PLAN - MiSTer storage: floppy, Winchester and paper tape from OSD-mounted files¶
Living plan, outstanding work only. Started 01-SEP-2026.
Phases 1-3 are built and recorded: the backend fpga/mister/rtl/nd_storage_hps.v
(make test-storage-hps), the device aggregator
fpga/mister/rtl/nd_storage_mister_devices.v (make test-storage-devices),
and the five OSD slots in nd120.sv (fpga/mister/docs/04-core-config-menu.md,
05-devices-block-char.md, build-defines.md section 6). Slot map: 0 floppy 0,
1 floppy 1, 2 WD0, 3 WD1, 4 tape. On the board SINTRAN III boots from an
OSD-mounted WD0 at the & prompt, with 4 MB main memory in the DE10-Nano
SDRAM (fpga/mister/README.md, 02-SEP-2026). Also measured on the board: 400$
from the tape slot loads FILSYS (the tape path and the byte order are right),
and FILSYS LIST-USERS reads FLOPPY-DISC-1 and DISC-74MB-1 (WD0) correctly.
Next¶
The Phase 4 board checks below. Every build and flash on Ronny's go.
Phase 4 - board¶
Not recorded as done anywhere; still open until someone runs them.
-
1560&: floppy boot from slot 0. Then drive 1 from slot 1. - Winchester: read known sectors with OPCOM and compare bytes against the
Verilator run (
ND120_WD_IMG, same CHS->LBA); write a sector, unmount, verify the file changed on the Linux side. - Unmount/remount while idle; a mount while a request is pending.
-
fpga/mister/nd120.sdchas no SDRAM pin constraints (neither has the Tang nor the PDP2011 port). At the present clocks the margins are wide, but if the board misbehaves that is the first thing to add.
Board facts for these checks:
- The working default mount is the MGL:
load_core /media/fat/ND120-storage-test.mglmounts floppy 0, floppy 1, WD0 and the tape. The framework automount (/media/fat/games/ND120/boot2.vhd-> slot 2) did NOT attach anything for this core (measured 02-SEP-2026 with theND120_STORAGE_PROBEconsole probe:MNT=00000), soboot2.vhdwas removed. - Typing OPCOM commands over ssh does NOT work yet: a
/dev/uinputkeyboard (mister_type.py, on the board in the games folder) is registered by the kernel but neither the console nor the F12 OSD react. Until that is solved the400$/1560&/ OPCOM steps need Ronny at the keyboard while the screenshots are pulled back. - Run Quartus in Docker from WSL, not from Git Bash: from Git Bash the container's working directory gets rewritten to a Windows path and the run dies before Quartus starts.
Phase 5 - close out¶
-
fpga/mister/README.md: a storage section on how it works, with the slot map and image sizes (floppy 315 392 B / >= 1 261 568 B, WD 8x9x1024 cylinders x 1024 B). - Move "The HPS block contract" below into
fpga/mister/docs/05-devices-block-char.md, then delete this plan.
Decided by Ronny (01-SEP-2026)¶
- Two Winchester slots (WD0, WD1), matching the card (its unit field is one
bit, control word b9,
ND_WINCHESTER.v). SMD is not built. - Paper tape: one file, one slot.
- The mount flags and the tape fault code are NOT displayed - the OSD shows
what is mounted, and the FDISK/WDISK error codes reach SINTRAN. The nets
stay in
nd120.svfor a probe.
The HPS block contract (reference)¶
Read 01-SEP-2026 from the official docs, Main_MiSTer/user_io.cpp, the
Template hps_io.sv and a survey of 11 official cores.
Decision: drive sd_rd/sd_wr DIRECTLY, one OSD slot per drive. That is what
7 of the 11 mainstream computer cores do (Atari ST and Archie floppies, Apple
II, C64, BK0011M, TRS-80, ZX Spectrum's floppy slot). The sys/sd_card.sv
virtual SPI card is used only where the GUEST software bit-bangs an SPI card
(DivMMC, MSX SD mapper, Acorn MMFS); ours never were SPI. ao486, PCXT and
Minimig use an ARM-served protocol that needs Main_MiSTer C++ changes.
- The ARM POLLS. It reads a status word (
{1, sd_blk_cnt[sdn], BLKSZ, sdn, sd_wr, sd_rd}) up to 4 times per main loop pass, picks ONE slot round-robin, reads that slot'ssd_lbain the same transaction, then runs one data transaction withsd_ack[slot]high for its whole length. So: holdsd_rd/sd_wruntilsd_ackRISES, then clear it; the FALLING edge means done;sd_lbaandsd_blk_cntstable from request until ack; several slots may request at once and are served one per poll. sd_blk_cnt = 3withBLKSZ = 2(512) = one 2048-byte transaction (one ND storage client block), one ack,sd_buff_addrrunning 0..1023 words in WIDE mode. BLKSZ is one value for ALL slots. The HPS clamps at 16384 bytes.WIDE=1gives 16-bit words. HPS words are little-endian ({byte 2w+1, byte 2w}); ND image words are big-endian. The backend swaps bytes once, in both directions.- Data arrives at the HPS SPI rate, not one word per clock;
sd_buff_wrpulses oneclk_syscycle per word, the address increments two cycles later, saturates, never wraps. For writes the core must presentsd_buff_din = buffer[sd_buff_addr]from address 0 the moment ack rises. The buffer bus is BROADCAST: qualify every buffer write with the slot's ownsd_ackbit. clk_sysintohps_iomust be >= 20 MHz (sorgelig, Main_MiSTer #683); ours is 40 MHz.sd_lbais file-relative: the HPS resolves the mounted file, so no FAT layer is needed on the MiSTer.- A read on an unmounted or short image is still acked and returns ZEROS.
"No image" is only knowable from the mount pulse:
img_mounted[n]is a few-cycle PULSE,img_size/img_readonlyare valid during it (size sent first); unmount is the same pulse withimg_size == 0. - Writes go to the file immediately (
O_SYNC, fwrite+fflush). A write past EOF is trimmed; an image cannot grow through the core. Read-only is only reported (img_readonly), never enforced on the HPS side. S{slot}is documented as 0-3 but the code accepts 0-9,hps_io.svallows VDNUM 1..10, and TRS-80_MiSTer shipsS4withVDNUM(5). (Bit 7 of the mount word is the read-only flag, so 7+ would collide.) TRS-80 also found that anFSsave-file line clobbers slot 0 - we have no such line.- The HPS is documented to automount
boot0.vhd..boot3.vhd/ND120.VHDfrom the core's folder into slots 0-3 at start (for this core it did not - see Phase 4). - Tapes in official cores (PDP-1, ZX Spectrum, C64, TRS-80) are
Fdownloads viaioctl_*, neverSmounts. Our tape adapter already reads blocks, gives rewind for free and holds one 2048-byte block, so the tape stays on anSslot. Fallback if that misbehaves: anFline withioctl_waitpacing, the PDP-1 shape. - Neither
ND_FLOPPY_DMA(itsDISK_TIMEOUTdefaults to 0 = off) norND_WINCHESTERtimes out a backend; a backend that never answers hangs the guest. The MiSTer backend answers NOTOPEN at once for an empty slot.