Core Configuration: CONF_STR, hps_io, the OSD Menu¶
Goal: understand exactly how the F12 menu is defined and how its selections reach
your logic. Punchline up front: the menu is a string constant in your Verilog.
There is no Linux-side code to write. Confirmed from both the official docs
(https://mister-devel.github.io/MkDocs_MiSTer/developer/conf_str/) and Main_MiSTer
source (user_io.cpp reads the string from the FPGA via user_io_read_confstr()
and parse_config() builds the whole menu from it —
https://github.com/MiSTer-devel/Main_MiSTer).
All links verified 2026-07-08.
1. How it plugs together¶
In your emu module (from Template.sv, verbatim shape):
localparam CONF_STR = { ... the menu ... };
hps_io #(.CONF_STR(CONF_STR)) hps_io
(
.clk_sys(clk_sys),
.HPS_BUS(HPS_BUS),
.buttons(buttons),
.status(status), // OSD selections land here
.status_menumask({...}), // dynamic show/hide of entries
.ps2_key(ps2_key),
...
);
hps_io.svlives insys/(source: https://raw.githubusercontent.com/MiSTer-devel/Template_MiSTer/master/sys/hps_io.sv). Key parameters:VDNUM(number of virtual disk drives, 1-10),WIDE(16-bit vs 8-bit file I/O),BLKSZ(block size code: 0=128 bytes ... 2=512 default ... 7=16384).- The ARM reads CONF_STR byte-by-byte over
HPS_BUSat core load; the OSD renders it. - Official hps_io overview: https://mister-devel.github.io/MkDocs_MiSTer/developer/hps_io/
2. CONF_STR syntax (validated against the official wiki + live cores)¶
References: https://mister-devel.github.io/MkDocs_MiSTer/developer/conf_str/ and https://github.com/MiSTer-devel/Wiki_MiSTer/wiki/Core-configuration-string
"<CoreName>;<options>;"— header. Extras can ride in the header, e.g. PDP2011 uses"PDP2011;UART19200;"— theUART<speed>token enables the framework UART menu/bridge (that's how we get OPCOM to a real terminal).-;— separator line.O[hi:lo],Name,opt0,opt1,...— option mapped tostatus[hi:lo]. 128 status bits exist (status[127:0]port); bit 0 is reserved for reset by convention.T[i],Name;— momentary trigger, pulsesstatus[i](e.g.T[0],Reset;).R[i],Name;— same, but closes the OSD.S<slot>,<EXT1><EXT2>...,Label;— mount a disk image into virtual-drive slot 0-3. Extensions are 3 chars each, concatenated:S0,DSKIMGVHD,Mount Drive;. Mounting drives theimg_mounted/img_size+sd_*block interface (05-devices-block-char.md).F[S]<index>,<EXT>,Label[,Address];— load a file streamed into the core via the ioctl interface;ioctl_indextells you which F-entry sent it.FS= savable.P<n>,Title;+P<n>O[...]...— submenu pages.H<n>/h<n>hide andD<n>/d<n>disable entries based onstatus_menumask[n](uppercase = when mask bit set, lowercase = when clear).J[1],.../jn,/jp,— joystick button definitions (not needed for ND-120).V,v+`BUILD_DATE— version string shown next to the core name.I,...info lines;SS<base>:<size>savestates (future exotica).
3. A real, complete example¶
PDP2011's menu (pdp2011.sv in
https://github.com/MiSTer-Enhanced/PDP2011_MiSTer) shows the usual pattern:
S-slots for disks, O-bits for machine configuration, a P1 page for terminal
cosmetics, T/R reset. Section 4 is ours, and is the one to copy from.
4. The shipped ND-120 CONF_STR¶
The menu the core actually ships with (verbatim from nd120.sv, comments
trimmed — read the source for the full rationale on each line):
localparam CONF_STR = {
"ND120;;",
"-;",
"O[122:121],Aspect ratio,Original,Full Screen,[ARC1],[ARC2];",
"-;",
"O[6],Keyboard,US,Norwegian;",
"O[7],Operator panel,On,Off;", // default On
"O[9:8],Console colour,Green,Amber,White,Cyan;",
"-;",
"S0,IMG,Floppy drive 0;", // block dev, served by rtl/nd_storage_hps.v
"S1,IMG,Floppy drive 1;",
"S2,IMG,Winchester unit 0;",
"S3,IMG,Winchester unit 1;",
"S4,BPUTAP,Paper tape;", // slot 4: TRS-80_MiSTer pattern
"-;",
"T[0],Reset;",
"R[0],Reset and close OSD;",
"v,0;",
"V,v",`BUILD_DATE
};
Wiring notes:
status[0](T/R) OR the frameworkRESETinput → MCL (Master Clear).status[6]→ keyboard layout (US / Norwegian);status[7]→ operator panel on/off (default on);status[9:8]→ console text colour (a board-only re-tint of the console-text palette index, terminal RTL untouched).- The five
Sslots are the storage mount points, served through hps_io's block interface byrtl/nd_storage_hps.v— the slot number is the hps_io index is the storage client (slot map inrtl/nd_storage_mister_devices.v). Extensions are 3-character groups, so paper tape is.BPU/.TAP, not.BPUN. - Microcode is NOT an F-entry here — it is uploaded from the HPS at core load; see 05-devices-block-char.md §3.
- The console is the machine's own TDV2200 screen + keyboard, not a
UART<speed>bridge; the CPU serial line is also on the HPS/dev/ttyS1at 115200 7E1.
5. The status word, both directions¶
status[127:0]— OSD selections → core.status_in[127:0]+status_set— core → OSD (e.g. reflect a mode the machine changed itself).status_menumask[15:0]— drives theH/h/D/dvisibility rules.
6. When WOULD Linux-side code be needed?¶
Main_MiSTer has a support/ directory of per-core helpers (x86/ao486 IDE, minimig,
CD-image formats like CHD/CUE, etc.), activated by core-name checks in
user_io.cpp. That exists only for cores needing host-side smarts — image-format
parsing or complex device config
(https://github.com/MiSTer-devel/Main_MiSTer/tree/master/support). A minicomputer
core with raw disk images does not need any of it — plain images are served by
the generic vhd path. If we ever want the Linux side to understand SINTRAN volume
formats or e.g. expose files as ND floppy images on the fly, THAT would be a
support/nd120/ contribution to Main_MiSTer — strictly optional, much later.
Menu checklist¶
- F12 shows the ND-120 menu with Reset, options, and the disc/tape mount slots.
-
statusbits reach the core (keyboard layout, panel on/off, console colour all take effect). - Mounting a Winchester image in a slot lets
&boot SINTRAN at the#prompt.