Devices: Block (disks) and Character (console), with the PDP2011 Case Study¶
Reference for how the shipped core serves storage and console: floppy/Winchester/ tape as image files on the Linux side, the console on the machine's own screen and keyboard, microcode uploaded from the HPS at core load. All links verified 2026-07-08.
What actually shipped: five OSD mount slots (floppy 0/1, Winchester 0/1, paper
tape) served over the block interface by rtl/nd_storage_hps.v; a clean-room
TDV2200 terminal on the MiSTer's own screen + keyboard (shared with the MEGA65
port); and 4 MB main memory in the DE10-Nano SDRAM add-on module. Sections 2 and
5 keep, in short, the reference material that informed those choices (trimmed
28-SEP-2026; the full case study is in git history).
1. Block devices — the hps_io protocol¶
Source of truth: sys/hps_io.sv
(https://raw.githubusercontent.com/MiSTer-devel/Template_MiSTer/master/sys/hps_io.sv)
and the official overview
(https://mister-devel.github.io/MkDocs_MiSTer/developer/hps_io/).
When the user mounts an image via an S menu slot, Linux opens the file and from
then on services sector requests from your logic. Per-drive signals (arrays sized
by the VDNUM parameter, up to 10 drives; up to 4 images mounted simultaneously per
the porting docs):
| Signal | Dir (core view) | Width | Meaning |
|---|---|---|---|
img_mounted[n] |
in | 1 | pulses when slot n (un)mounts |
img_readonly |
in | 1 | valid during img_mounted pulse |
img_size |
in | 64 | bytes; 0 = unmounted. valid during pulse |
sd_lba[n] |
out | 32 | block number to transfer |
sd_blk_cnt[n] |
out | 6 | blocks-1 per request (total <= 16 KB) |
sd_rd[n] / sd_wr[n] |
out | 1 | request read / write |
sd_ack[n] |
in | 1 | high while Linux services the request |
sd_buff_addr |
in | 13 (8-bit) / 12 (16-bit) | address into YOUR buffer RAM |
sd_buff_dout |
in | 8/16 | data from image (reads) |
sd_buff_wr |
in | 1 | write strobe for sd_buff_dout |
sd_buff_din[n] |
out | 8/16 | data to image (writes) |
Protocol: raise sd_rd[n] with sd_lba[n] valid → Linux polls, asserts
sd_ack[n], streams the sector through the buffer port (the comments say the port
is designed for a 2-port altsyncram — you supply a small dual-port BRAM as the
sector buffer) → drop your request on ack. Block size defaults to 512 bytes
(BLKSZ parameter). The disk image is a flat sequence of blocks — exactly what
a file on the SD card provides.
2. Case study: how PDP2011 does its disks (short)¶
PDP2011 (https://github.com/MiSTer-Enhanced/PDP2011_MiSTer) did not rewrite its
disk controllers for MiSTer: its RK11/RL11/RH70 controllers speak SPI-SD
natively, and the port puts the framework's sys/sd_card.sv SD-card emulator
between each controller's SPI pins and hps_io. Lesson taken for the ND-120:
drive sd_lba/sd_rd/sd_wr/sd_buff_* directly with a sector-level handshake -
the SPI layer is baggage from PDP2011's standalone-FPGA origin. Two tricks worth
copying: the mount pulse makes a controller present/absent at runtime, and an OSD
option can redirect a controller to the physical secondary SD slot.
3. File upload (ioctl) — the microcode path¶
From hps_io.sv (same source): the F menu entries and boot files arrive as a
byte/word stream:
ioctl_download— high during transfer;ioctl_index[15:0]— which menu entry (F1 → 1...;boot.romauto-loads as index 0 at core start);ioctl_wrstrobe +ioctl_addr[26:0]+ioctl_dout[7:0 or 15:0];ioctl_wait— throttle the stream if your write port is slow;ioctl_file_ext[31:0]— the actual extension picked;- upload in the other direction exists too (
ioctl_upload/ioctl_din) — could dump machine state or memory to a file for offline diffing against Verilator.
ND-120 use: replace baked-in AM27256_45132L.hex / WCS hex init with an ioctl
receiver that writes the WCS/EPROM RAMs while holding the CPU in MCL. Name the file
boot.rom in /media/fat/games/ND120/ and index-0 auto-load gives "microcode
loads at core start" with no user action. [the exact boot.rom per-core folder
lookup is standard practice via the games path
(https://mister-devel.github.io/MkDocs_MiSTer/cores/paths/) — verify the filename
convention on first use]
4. Character devices — OPCOM console and beyond¶
Three options, all real (validated):
- Framework UART (recommended first):
emuhasUART_RXD/TXD/CTS/RTS/DTR/DSR. Per the official emu docs (https://mister-devel.github.io/MkDocs_MiSTer/developer/emu/ and the wiki emu page): "Serial is passed to the linux arm side of the MiSTer. On the arm side, software decides what to do with the data. ie: send it to shell, ppp, MIDI, etc." — enabled/configured by theUART<speeds>token in the CONF_STR header (PDP2011:"PDP2011;UART19200;"). Wire the ND-120 current-loop/UART console (OPCOM) here; on the Linux side you attach a terminal to it via the OSD. - User port as raw UART:
USER_IN[6:0]/USER_OUT[6:0]on the I/O board's USB3-style user port (open-drain; set USER_OUT bit to 1 to read USER_IN) — a direct cable to a USB-serial adapter, independent of the Linux side. Good as a debug side-channel. - Built-in video terminal (later, and very much in the ND spirit): PDP2011
ships a VT100/VT105 (
rtl/vt.vhd+rtl/vga.vhd+rtl/ps2.vhd) rendered via the framework video chain, with an OSD switch choosing whether the console KL11 talks to the on-screen VT or the external UART. An ND "Tandberg terminal on HDMI + USB keyboard" would follow exactly that pattern;hps_ioprovidesps2_keyfor the keyboard. Video helpers: https://mister-devel.github.io/MkDocs_MiSTer/developer/video_mixer/
PDP2011 instantiates four KL11 serial units and muxes unit 0/1 between the VT and the external UART with one status bit — a good template for OPCOM + extra ND terminal ports.
5. Main memory (shipped: 4 MB in the SDRAM module)¶
The shipped core puts 4 MB (2M words) of main memory in the DE10-Nano SDRAM
add-on module (WCS in block RAM, cache off), on the Tang Nano 20K SDRAM bridge.
The documented fallback is the HPS DDR3 through the DDRAM_* emu ports (as
ao486 uses it): higher, variable latency, no add-on board, and the porting docs
warn it needs careful reset handling.
Device checklist¶
- Microcode loads from the HPS at core load, CPU boots to OPCOM.
- Main memory in the SDRAM module passes the memory test that runs in Verilator.
- A disc image mounts from the OSD; the controller reads sector 0 (verify by checksumming the same file over ssh).
- SINTRAN boots from a mounted Winchester image.
Addendum, 27-AUG-2026 - the built-in terminal, and why we cannot vendor PDP2011's¶
PDP2011's VT100/VT105 terminal files carry a non-commercial-use-only
header (Sytse van Slooten, 2008-2021), which is NOT the repo's GPL-2.0
LICENSE and cannot be mixed into this MIT repo.
Decision (carried out): the terminal was re-implemented clean-room, using
PDP2011 only as a feature checklist, and shared with the MEGA65 port. The
shipped console is a TDV2200 terminal on the MiSTer's own screen + keyboard
(box-drawing font and keyboard confirmed on hardware 02-SEP-2026), not a VT100.
Terminal core: ../../../Terminals/.