Skip to content

MiSTer Quick Reference Guide

sy2002 edited this page Jul 7, 2026 · 2 revisions

This page is the MiSTer lens for MEGA65 core porters. Before you can port a MiSTer core with MiSTer2MEGA65 (M2M), you have to be able to read that core — and its source assumes you already understand MiSTer's world: its on-screen menu, its configuration string, the emu module, the services the ARM provides, the way video and disks and ROMs flow. This guide teaches that world from the ground up, on MiSTer's own terms, for a developer who may never have owned a MiSTer.

It is a companion, not the main event. The actual porting work — every M2M file you edit, every wire you connect — lives in The Ultimate MiSTer2MEGA65 Porting Guide. Read this page first to build the mental model; then that guide turns the model into concrete steps. Wherever a MiSTer concept has a MEGA65 counterpart, this page gives you a one-line pointer to the article that owns it rather than re-explaining it here.

How to use this page

  • New to MiSTer? Read top to bottom once. You will come out able to open any core's repository and know what you are looking at.
  • Already fluent? Jump to the tables — the emu ports, the CONF_STR grammar, and the Rosetta-stone table — and move on to the porting guide.
  • Conventions: MiSTer signal and file names are in monospace. A points at the MEGA65/M2M equivalent. "The ARM" and "the HPS" both mean MiSTer's Linux co-processor.

1. What MiSTer actually is

MiSTer is an FPGA platform built on the Terasic DE10-Nano board. That board carries an Intel/Altera Cyclone V — but not a plain FPGA. It is a SoC: an FPGA fabric and, on the same chip, an ARM Cortex-A9 running Linux, called the HPS (Hard Processor System). This detail is the single most important thing to internalize, because it explains both how MiSTer is built and why M2M has to exist at all.

The division of labor is:

  • The retro machine — the C64, the Amiga, the arcade board — is FPGA logic. This is "the core".
  • Almost everything around it is done by the ARM running Linux (a program called Main_MiSTer): drawing the on-screen menu, browsing the SD card, loading ROMs, mounting disk images, reading USB gamepads, keeping the clock. On the FPGA side, a framework called sys provides the hardware endpoints for all of that (video scaling, HDMI, audio DACs, and the bridge to the ARM).
flowchart TB
    ARM["ARM + Linux (HPS) — Main_MiSTer: menu, file browser, SD, ROM load, disk mounting"]
    SYS["sys/ — the MiSTer framework (HAL): sys_top.v, hps_io.sv, video, audio"]
    EMU["emu — your glue logic (the root .sv file)"]
    RTL["rtl/ — the actual retro machine (CPU, video chip, sound chip, ...)"]
    ARM <-->|HPS_BUS| SYS
    SYS --> EMU
    EMU --> RTL
Loading

Now the punchline. The MEGA65 is a pure FPGA machine — a Xilinx Artix-7, and no ARM, no Linux. So when you move a MiSTer core to the MEGA65, the retro machine comes across almost unchanged, but every service the ARM used to provide has to be rebuilt in pure FPGA. That is exactly what M2M is: it replaces the ARM+Linux+sys stack with a small QNICE softcore CPU running the M2M Shell firmware, plus the M2M/ framework logic. QNICE is M2M's stand-in for MiSTer's ARM.

Hold that picture and the whole port becomes a translation exercise. Here is the translation table you will keep coming back to.

The Rosetta stone

On MiSTer On the MEGA65, under M2M Where the MEGA65 side is documented
ARM + Linux (HPS), running Main_MiSTer QNICE softcore + M2M Shell firmware The Ultimate MiSTer2MEGA65 Porting Guide §1.2.4
sys/ framework (sys_top.v, hps_io.sv, video, audio) M2M/ framework (framework.vhd + board top) Ultimate Guide §1.2.2
emu — the root .sv glue module your main.vhd + mega65.vhd Ultimate Guide §1.1.2, Appendix A + B
CONF_STR + the status[] menu register config.vhd (OPTM_ITEMS/OPTM_GROUPS) + OSM control bits On‐Screen‐Menu (OSM), config.vhd Switches and Settings
ioctl file/ROM download CRT/ROM loading over the QNICE device bus Devices, Ultimate Guide §1.3.2
sd/img disk-image block protocol vdrives.vhd + QNICE FAT32 Devices, Ultimate Guide §1.3.3
ps2_key / ps2_mouse 80-key matrix scan + your keyboard.vhd Ultimate Guide §1.3.4
DDR3 / SDRAM HyperRAM (Avalon-MM); SDRAM is a roadmap item Devices, Ultimate Guide §1.4.3
video_mixer / video_freak / ascal the M2M av_pipeline (same ascal scaler) Video pipeline and output, Ultimate Guide §1.3.5
audio_out filters signed 16-bit PCM into the framework's filters Ultimate Guide §1.3.6
RTC[64:0] main_rtc_i Ultimate Guide §1.3.9
Quartus pll / pll_cfg your clk.vhd MMCM Ultimate Guide §1.3.7
(QNICE Shell memory budget) Shell memory layout

Everything below is a slower walk through the left-hand column.


2. Anatomy of a MiSTer core repository

MiSTer is a disciplined project: every core's GitHub repository has the same shape, so once you can read one you can read them all. Three things matter.

  • rtl/ — the actual machine. The hardware description of the retro computer or arcade board: CPU, video chip, sound chip, glue logic, often the floppy/disk controller, the core's clock definition (rtl/pll/), and frequently the ROMs. This is the part you carry over to the MEGA65, largely unchanged. For the C64 core, rtl/ holds fpga64_sid_iec.vhd (the C64 itself), the VIC-II, the SID, the T65 CPU, iec_drive/ (the 1541/1581), and roms/.

  • sys/ — the MiSTer framework. MiSTer's hardware abstraction layer: sys_top.v, hps_io.sv (the bridge to the ARM), the video pipeline (video_mixer.sv, video_freak.sv, scandoubler.v, ascal.vhd, osd.v), audio (audio_out.v), and the framework PLLs. You never carry anything from sys/ into an M2M port — M2M provides an equivalent for all of it. You read sys/ only to understand what a service does.

  • The root <Core>.sv — the glue, and your oracle. Every core has exactly one SystemVerilog file in the repository root, named after the core (c64.sv, Minimig.sv, Gameboy.sv, …). It contains a single module, always called emu. This is where the retro machine meets the framework: emu instantiates the machine from rtl/ and wires it to everything the framework provides. It is the most important file of your whole port — keep it open at all times. When you are ever unsure "what do I connect to input X?", the answer is in <Core>.sv.

The inversion that surprises everyone. You might expect the core author to write the FPGA top-level. They do not. Quartus is pointed at the framework's sys/sys_top.v as the top, and that instantiates the author's emu. Your core is a plug-in, not the root. M2M mirrors this exactly: the board top and framework.vhd instantiate your MEGA65_Core.

You do not synthesize emu and you do not port sys_top.v. You re-create emu's glue role by hand in M2M's main.vhd, and you instantiate the machine module from rtl/ — not emu — inside it.

Two more files you will meet:

  • rtl/pll/ (a Quartus PLL). The core's clock plan (see §9). It will not synthesize in Vivado; you re-create its frequencies in your own clk.vhd.
  • .mra files (arcade only). Arcade cores don't ship a ready-made ROM; instead an XML recipe assembles it on the fly from MAME zip files (see §6). The MEGA65 has no such machinery, so arcade ROMs need special handling.

What you lift vs. what you drop: lift rtl/ (the machine) and the logic inside emu that conditions the machine's signals. Drop all of sys/, sys_top.v, the emu port shell itself, and the Quartus project files — M2M replaces each of those.


3. The emu module — the one interface that matters

emu's port list is the standardized contract between any MiSTer core and the MiSTer framework. Learn its groups and you have learned what services exist, because each group maps to exactly one row of the Rosetta table.

In today's template the ports are pulled in from sys/emu_ports.vh via an `include, so the master list lives there; many older cores (and most of the online examples) spell the same ports inline inside <Core>.sv. The content is identical either way. Here are the groups, with the load-bearing details called out.

Group Dir Key signals What it is
Clock / reset in CLK_50M, RESET The only system clock handed in is 50 MHz (a fixed CLK_AUDIO is also supplied — see the Audio row); the core derives the rest with a PLL. RESET is the async power-on / "bye-bye" reset.
HPS bus inout HPS_BUS One opaque bus carrying everything to/from the ARM. Passed straight to hps_io (see §5).
Video out CLK_VIDEO, CE_PIXEL, VGA_R/G/B (8-bit), VGA_HS/VS, VGA_DE, VGA_F1, VGA_SL, VIDEO_ARX/ARY 24-bit RGB + syncs + data-enable + pixel clock-enable. See the conventions below.
HDMI geometry mixed HDMI_WIDTH, HDMI_HEIGHT, HDMI_FREEZE Framework tells the core the current HDMI canvas; core can freeze the image.
Audio mixed CLK_AUDIO, AUDIO_L/R (16-bit), AUDIO_S, AUDIO_MIX Signed/unsigned 16-bit stereo PCM + a mono-mix level (see §7).
LEDs / buttons out LED_USER, LED_POWER, LED_DISK, BUTTONS Activity/power/disk LEDs; the core can also simulate the OSD/user button presses.
DDR3 mixed DDRAM_* High-latency, big DDR3 RAM. Used by the HDMI scaler and by cores needing lots of RAM.
SDRAM mixed SDRAM_* Lower-latency external SDRAM (needs an add-on board). The classic memory for retro cores.
Misc board I/O mixed SD_* (SPI), ADC_BUS, UART_*, USER_IN/OUT, OSD_STATUS Second SD card, ADC (tape), physical serial, user port, and a flag that is high while the OSD menu is open.

Some ports only appear when a core opts into them with a `ifdef — the MISTER_FB DDR3 framebuffer path and the MISTER_DUAL_SDRAM second SDRAM chip are the common ones. The first thing a typical emu does is tie off everything it doesn't use (e.g. zero the whole DDRAM interface, tristate the SD-SPI). Those tie-offs are a gift: they tell you at a glance which services you can ignore in your port.

Video conventions you must respect (they carry straight over to M2M):

  • CLK_VIDEO vs CE_PIXEL. The core streams pixels on CLK_VIDEO but only on the cycles where CE_PIXEL is high. CLK_VIDEO usually equals the system clock; lower pixel rates are expressed by pulsing CE_PIXEL, not by making a slower clock. If the pixel rate equals CLK_VIDEO, hold CE_PIXEL high.
  • VGA_DE = ~(VBlank | HBlank). MiSTer emits a single active-display-enable that is the inverse of blanking. (M2M instead wants the two blanking signals directly — a small but important difference; see §7.)
  • Syncs are positive polarity.
  • AUDIO_S declares whether your samples are signed. Get it wrong and audio is garbled.

The emu port list is a reference; the definitive per-group MEGA65 mapping — which M2M port each one becomes — is in the Ultimate Guide's Appendix B (mega65.vhd port groups).


4. The OSD and the config string (CONF_STR)

What the OSD is

Press F12 on a MiSTer and an On-Screen Display menu drops down: a list of options, toggles, sub-pages, and "load file" / "mount disk" entries. It is how the end user chooses PAL vs. NTSC, mounts a disk into drive 8, loads a cartridge, picks a scandoubler filter, and so on. If you have never seen one, picture the MEGA65's own Options menu — M2M's OSM is its direct descendant.

Here is the crucial part: the whole menu is generated from a single string baked into the core, called CONF_STR. The ARM reads that string and builds the menu; when the user changes something, the choice is written into a wide register called status that the core reads. Nothing about the menu lives in Linux config files — it is all in the core, in one string.

Why CONF_STR is the first thing you read

CONF_STR is, in the words of one porter, the core's requirements document: the most compact, most reliable statement of what the core needs from its environment. Every option line names a status[] bit the core consumes and tells you, by its label, what that bit means. Every F/S line declares a kind of file or disk image the core can load. A status bit you wire wrong is one of the classic "the core synthesizes but won't boot" bugs — so reading CONF_STR fluently is a core skill.

The status register

Menu choices land in status, a wide register hps_io hands to the core. Its width has grown across MiSTer generations — older cores (including the C64-era hps_io that M2M's vdrives was derived from) use status[63:0]; modern cores use a 128-bit status — so don't hard-code a single width in your head. status[0] is reserved for Soft Reset. The core reads bits straight out: wire ntsc = status[2];.

The mini-language, letter by letter

CONF_STR is one long string, each entry ending in a semicolon. Bit positions use an "extended hex" alphabet — 09 then AV — so a single character addresses one of 32 bit positions. Upper-case letters address the low 32 status bits; the lower-case twin adds 32 (so o0 is status[32], t3 is a trigger on status[35], and so on).

Token Meaning
<Name>;; (first entry) The core name (menu title).
O<n>[<m>],Label,Opt0,Opt1,… Option cycler bound to status[n] (or the range status[m:n]). Lower-case o = +32.
T<n>,Label Trigger — pulses status[n] high momentarily (e.g. reset). Lower-case t = +32.
R<n>,Label Same as T, but also closes the OSD afterwards. Lower-case r = +32.
F[<idx>],<EXTS>,Label Load a file (ROM/cartridge/BIOS). Arrives over ioctl with this index. (An FS variant also supports save files.)
FC[<idx>],<EXTS>,Label Like F, but remember the file and auto-load it at the next start.
S<slot>,<EXTS>,Label Mount a disk image on virtual-drive <slot> (0–3). Drives the sd/img protocol (§5).
P<n>,Title / P<n>… Define menu page n; prefix later entries with P<n> to file them under it.
- or -,Text A separator line (with optional static text / heading).
D<n> / d<n> (prefix) Disable (grey out) the entry when menu-mask bit n is set / not set.
H<n> / h<n> (prefix) Hide the entry when menu-mask bit n is set / not set.
J[1],Btn1,… Joystick button names (up to 12). J1 locks the keyboard into joystick-emulation mode.
jn,… / jp,… Default joystick mapping, by name / by position (relative to a SNES pad).
V,<string> Version string appended to the core name.
DIP / CHEAT / C / I,… Arcade DIP-switch menu (from the MRA) / cheat menu / OSD info lines.

Prefixes stack in a fixed order: the disable/hide prefix (d/D/h/H) comes first, then the page prefix P<n>, then the option itself — e.g. d5P1o2,Vertical Crop,… means "an option on status[34], on page 1, greyed out unless menu-mask bit 5 is set." Get the order wrong and the entry silently misbehaves. J/jn/jp/V must come last in the string.

A real line, decoded

From the C64 core (c64.sv):

"H7S0,D64G64T64D81,Mount #8;"

Reading it: S0 = a disk-image mount on virtual-drive slot 0; the extensions D64, G64, T64, D81 are the file types it accepts; H7 hides the entry when menu-mask bit 7 is set (the core raises that mask bit from runtime state). That one line is what drives the entire img_mounted / sd_lba[0] disk protocol into the C64's iec_drive.

On the MEGA65 side

M2M has no status word. Instead, each menu line is its own bit in a 256-bit register, declared as text in config.vhd. So a MiSTer multi-value field like O45,Aspect Ratio,… (four choices packed into status[5:4]) typically becomes a small submenu of single-select lines on the MEGA65, and a plain on/off O bit becomes one checkbox line. How to build that menu — groups, radio buttons, wiring a menu bit to your VHDL — is the job of On‐Screen‐Menu (OSM) and config.vhd Switches and Settings, and the mechanical CONF_STRconfig.vhd translation is the Ultimate Guide's §1.3.1. This page's job was only to teach you to read the MiSTer side.


5. hps_io — the ARM's service layer

hps_io is the module every core instantiates next to emu; it is the FPGA-side endpoint of the ARM, and it hands the core every service the Linux side provides. On the MEGA65 the QNICE softcore plus the Shell firmware play this exact role. Reading a core's hps_io instantiation is how you inventory which services the core actually uses.

A quick tour of the service groups:

  • The menu (status). Covered in §4 — status, plus status_in/status_set (the core can push a value back) and status_menumask (drives the d/H show/hide prefixes).
  • ioctl — file / ROM download. How ROMs, cartridges, BIOSes and tapes get into the core. Covered below.
  • sd/img — the disk-image block protocol. How mounted disk images are read and written, block by block. Covered below — this is the one M2M reproduces most faithfully.
  • Keyboard & mouse. ps2_key[10:0] delivers PS/2 scan codes: bits [7:0] = code, [8] = extended, [9] = pressed, [10] = a toggle that flips on every event. ps2_mouse is analogous. → M2M does not speak PS/2; it hands you a key-matrix index and you write keyboard.vhd (§9).
  • Joysticks / paddles / spinners. joystick_0..5 (up to six pads; directions in bits [3:0], buttons from bit 4), paddle_0..5, analog sticks, spinners. → the MEGA65 has two physical joystick ports, which you map onto joystick_0/joystick_1.
  • RTC[64:0] and TIMESTAMP[32:0]. Wall-clock time (MSM6242B BCD layout) and Unix time from Linux, sent once at startup; the core keeps ticking from there. → main_rtc_i, same 65-bit width, sourced from M2M's own I2C real-time clock.
  • Odds and ends. buttons, forced_scandoubler, gamma_bus, and EXT_BUS. That last one is a red flag worth memorizing: EXT_BUS (with a companion hps_ext.v) is a core-specific side-channel that bypasses the standard services. The Amiga core uses it for its keyboard, mouse and HDD (IDE) — so a core with an EXT_BUS needs extra analysis, and its inputs won't map through the normal paths.

Two hps_io generations exist in the wild. The current MiSTer template's copy is newer (128-bit status, up to 10 virtual drives, split left/right analog sticks); the copy vendored into older ports — the one M2M's disk logic was derived from — is older (64-bit status, up to 4 drives). The protocols (ioctl, sd/img, ps2_key, RTC) are the same shape in both; only widths and a few extras differ.

Loading things: the ioctl interface

When the user picks a file for an F entry, the ARM streams it into the core, byte by byte:

  • ioctl_download is high for the duration of the transfer.
  • ioctl_index says which F entry triggered it (the F1 in CONF_STR → index 1), so the core can route the bytes to the right destination.
  • ioctl_addr counts up, ioctl_dout carries each byte/word, ioctl_wr strobes it.
  • ioctl_wait lets the core apply back-pressure when it can't keep up.

A textbook consumer looks like load_prg = ioctl_index=='h01; load_rom = ioctl_index==8; — the core decodes the index into load targets. ROMs, cartridges, tapes and even custom filter files all arrive over this one channel.

→ On the MEGA65 there is no linear ioctl address stream; instead each loadable object is its own QNICE device, and the Shell streams files into it. See Devices and the Ultimate Guide's §1.3.2.

Mounting disks: the sd/img block protocol

This is the most important protocol to understand, because M2M reimplements it almost bit-for-bit in vdrives.vhd — which is the single best piece of news in the whole port. The core's own drive emulation (the C64's iec_drive, say) speaks this protocol; whoever is on the other end serves the actual file.

Mounting. When the user mounts an image via an S entry, hps_io pulses the drive's bit in img_mounted and presents img_size (in bytes) and img_readonly. The core latches those. Unmounting is the same strobe with img_size == 0 — a convention worth remembering, because M2M uses it too.

Block access. To read a sector the core puts the block address on sd_lba[drive], raises its bit in sd_rd, and waits; the server raises sd_ack and streams the bytes over sd_buff_addr / sd_buff_dout / sd_buff_wr into the core's sector buffer. Writing is the mirror image: raise sd_wr, and the core feeds bytes back on sd_buff_din. The block size is 128 << BLKSZ bytes (so the default BLKSZ=2 is 512 bytes; the C64 uses BLKSZ=1 = 256).

→ M2M's vdrives.vhd presents this identical interface to your drive; the QNICE Shell plays the role of the ARM, reading and writing the disk-image file on the SD card and caching it in RAM. See Devices and the Ultimate Guide's §1.3.3. (M2M supports up to 15 virtual drives, 8-bit data only — it does not implement hps_io's 16-bit "WIDE" mode.)

Arcade cores and MRA

Arcade cores are the exception to almost everything above. An arcade core's .rbf (compiled bitstream) is hidden from the menu; the user browses .mra files instead. An MRA is an XML recipe that names which .rbf to load and, crucially, assembles the game ROM on the fly from MAME .zip files — concatenating, interleaving and patching ROM parts, then verifying the result against an MD5. DIP switches also come from the MRA (delivered over ioctl with index 254), not from status bits.

→ The MEGA65 has no MAME-zip assembly and no .mra/.rbf browsing. An arcade core that relies on this needs its ROM pre-assembled and its DIP switches surfaced through the MEGA65's own menu — a genuine porting gap to plan for, not a service M2M provides.


6. Video, the MiSTer way

A MiSTer core outputs a native retro video signal — often a 15 kHz analog RGB signal, exactly what the original machine produced. The framework then does the modern work: a scandoubler for VGA monitors, and a polyphase scaler (ascal.vhd) that upscales to a fixed HDMI mode. A key design rule follows from this: the core does not build in its own scandoubler, because 15 kHz purists want the raw signal and the framework handles the rest.

What the core provides is RGB + separate H/V sync + VGA_DE + CE_PIXEL on CLK_VIDEO (plus VGA_F1 for interlace, below). Three things a porter must know:

  • M2M wants the blanking signals, not VGA_DE. MiSTer collapses blanking into the single VGA_DE = ~(VBlank | HBlank); M2M instead wants video_hblank_o and video_vblank_o directly (active-high). Very often the core already produces them internally and only merged them at the last step, so you can tap the earlier signals.
  • The scaler is shared heritage. M2M uses the same temlib ascal.vhd MiSTer uses, so the video contract carries over cleanly. What M2M adds around it (analog VGA + HDMI) lives in Video pipeline and output and the Ultimate Guide's §1.3.5.
  • Interlace via VGA_F1. Machines like the Amiga can switch to an interlaced (laced) mode. MiSTer signals which field is current on VGA_F1, and ascal can weave the two fields into one full-height frame. Mainline M2M does not yet expose a field signal — it is an AExp-pioneered V2.1.0 roadmap item (a video_fl_i input that defaults to '0', so progressive cores are unaffected). If your core is interlaced, know this is on the horizon, not in the released framework.

Worked example — how the C64 makes its blanking. fpga64_sid_iec outputs only raw hsync/vsync + RGB; it produces no blanking. MiSTer generates blanking with a small helper module, video_sync, which also crops the visible raster to the MiSTer-standard 384×270 window. The MEGA65 port reuses the very same video_sync module, moved into main.vhd's clock domain, to produce video_hblank_o/video_vblank_o. (A trap to note: there are two video_sync.vhd files — the core-local one must win over the framework's.) This is the typical shape of a video port: find where the core's signal is complete — RGB + HS + VS + HBlank + VBlank — and tap it there.


7. Audio

Audio is refreshingly simple. The core drives signed 16-bit stereo PCM on AUDIO_L/AUDIO_R, sets AUDIO_S = 1 to say the samples are signed, and can request a mono down-mix via AUDIO_MIX. → On the MEGA65 this becomes main_audio_left_o / main_audio_right_o, signed(15 downto 0) — the same signed 16-bit contract.

Two details save you grief:

  • The audio clock differs. MiSTer's CLK_AUDIO is documented as 24.576 MHz; M2M's audio clock is 12.288 MHz (half). Don't copy a hard-coded 24.576 MHz assumption across.
  • The optional IIR filter. MiSTer offers a gentle low-pass "audio improvement" filter whose biquad coefficients live in sys/sys_top.v. M2M runs the same filter in the framework and expects those coefficients as constants in your globals.vhd, toggled by a menu bit. The mapping is the Ultimate Guide's §1.3.6.

If a core mixes several sources (the C64 blends SID with an OPL expander, a DAC and tape noise), that mixing happens inside emu before AUDIO_L/R. You reproduce as much of it as you want in main.vhd; a first port can start with just the primary sound chip and add the rest later.


8. Memory: SDRAM and DDR3 → BRAM and HyperRAM

MiSTer is rich in RAM, and this is where the MEGA65's constraints bite hardest, so it pays to understand what a core actually needs.

On MiSTer, a core has two external memories to reach for:

  • SDRAM — lower latency, on an add-on board. The classic choice for a core's fast RAM (C64 REU, Amiga chip/fast RAM, arcade work RAM).
  • DDR3 — huge but high-latency, shared with the ARM. Used for the HDMI scaler's framebuffer, HPS file transfer, and non-time-critical bulk storage.

A core signals which it uses simply by wiring SDRAM_* and/or DDRAM_*; if emu tristates the SDRAM interface, the core needs no SDRAM board.

On the MEGA65 the picture is very different. All boards share one Artix-7 with roughly 1.6 MB of fast on-chip Block RAM (BRAM) and 8 MB of HyperRAM — and the HyperRAM is slower (a read has real latency) and shared with the video scaler, which can hold it for a long burst. So the porting questions are: how much fast RAM/ROM does the core truly need, and does it fit?

A rule of thumb that has held up well: the framework itself uses ~200 KB of BRAM, so if the core's fast RAM + ROM totals under ~1.4 MB, it maps to BRAM straightforwardly and you barely touch the original. Above that you must get clever — split the needs between BRAM (fast) and HyperRAM (slow/bulk), or choose a smaller machine configuration. The Amiga is the cautionary tale: a minimal A500 (512 KB chip + 512 KB slow + 256 KB Kickstart = 1.25 MB) fits BRAM with almost nothing to spare, so its disk image and the scaler framebuffer both live in HyperRAM, and adding an IDE hard disk simply does not fit.

→ DDR3/SDRAM both map to HyperRAM, driven as an Avalon-MM master (hr_core_*), usually through a CDC FIFO and a read cache. The details, plus the roadmap for using the newer boards' SDRAM as a second memory, are in Devices and the Ultimate Guide's §1.4.


9. Inputs, clocking, and reset

Keyboard. MiSTer hands the core PS/2 scan codes on ps2_key. M2M does not: it scans the MEGA65's own keyboard and hands you a key-matrix index (0–79) plus a pressed flag. You write a small keyboard.vhd that reshapes those 80 keys into whatever format the core's keyboard logic expects. This is one of the few pieces of glue with no MiSTer counterpart to copy — see the Ultimate Guide's §1.3.4.

Joysticks, paddles, mice. The MEGA65's two physical joystick ports map onto joystick_0/joystick_1; paddles and 1351-style mice ride the analog POT lines. Amiga-style quadrature mice come in over the same analog path. The framework debounces these for you.

Clocking. The core gets only CLK_50M as a system clock (plus a fixed CLK_AUDIO) and makes everything else with its pll. Two lessons transfer directly:

  • Hit the original frequency to the Hertz. "Close enough" clocks cause subtle, maddening compatibility damage — off-pitch audio, broken tape loaders, wrong CIA timers. Read the core's rtl/pll/ files to learn the exact target frequencies, and reproduce them in your MMCM. The value also feeds CORE_CLK_SPEED in globals.vhd, which drift-free timers rely on.
  • Dynamic reconfiguration is a decision point. Some cores retune the PLL at runtime — the C64 nudges its clock for PAL vs. NTSC, and some arcade cores overclock a percent or so (Arkanoid, about 1.4%) to bring their refresh into spec for 60 Hz displays. This is not portable as-is. M2M cores usually synthesize one fixed clock plan per video standard, or instantiate parallel MMCMs and switch between them glitch-free. When you first bring a core up, pick one standard (say PAL), ignore the rest, and add complexity later. The Ultimate Guide's §1.3.7 covers clk.vhd.

Reset. The canonical core reset is wire reset = RESET | status[0] | buttons[1]; — the framework's power-on reset, OR the soft-reset menu bit, OR a physical button. One sharp edge: if a core uses DDR3, accessing it during RESET causes a hard hang — a warning straight from MiSTer's porting docs — so DDR3 requests must be held off until after reset completes. → M2M gives you a hard reset (main_reset_m2m_i) and a soft reset (main_reset_core_i) and pauses the core while the menu is open (main_pause_core_i).


10. Reading a core in fifteen minutes

Whenever you meet a new core, run this drill before touching any MEGA65 file. It is the fastest way to build the "what does emu drive into the machine, and why" picture that the whole port depends on.

  1. Find the actual machine. Search emu's body for an instantiation whose name is not framework-ish. For the C64 it is fpga64_sid_iec; Apple-II → apple2_top; Game Boy → gb; Amiga → minimig (sometimes the machine is split across several sibling instances). This module — not emu — is what you will instantiate in main.vhd.
  2. Find the PLL, extract the clock plan. Read the pll instantiation and the rtl/pll/pll_*.v config for the exact frequencies. Note whether there is a pll_cfg doing runtime reconfiguration (a porting decision point).
  3. Read CONF_STR. For every line decide, mentally, whether the MEGA65 will replicate the option, hard-wire it to a constant, or drop it. This is your work list.
  4. Inventory the hps_io services. Which ports are actually connected? Each connected one — ioctl, sd/img, ps2_key, RTC — is a service you must re-provide.
  5. Trace video. Follow the machine's hsync/vsync/RGB until the signal is complete (RGB + HS + VS + HBlank + VBlank). That is your tap point for M2M.
  6. Trace audio, then inventory memory. Find what feeds AUDIO_L/R and whether AUDIO_S says signed; then search rtl/ for every SDRAM, DDR3 and BRAM/ROM instance and add up the fast-memory total against §8's rule of thumb.

A worked, C64-specific version of this drill is the Ultimate Guide's §1.1.5.


11. Two lenses: the C64 vs. the Amiga

The two M2M reference cores span the range of what porting throws at you. The C64 (C64MEGA65) walks the standard path; the Amiga (the AExp project, Minimig-AGA) hits almost every hard case at once. Seeing them side by side tells you what "normal" looks like and where surprises live.

Concern C64 — the standard path Amiga — the hard cases
Configuration CONF_STR status bits → config.vhd almost nothing in CONF_STR; config lives in Minimig's own userio handshake, replayed by a VHDL state machine
Disk images sd/img blocks → vdrives.vhd (writable D64) raw MFM flux over a side-channel — vdrives can't be used; needs a custom track engine + a firmware write-back hook
ROM load ioctl → CRT/ROM loader same (Kickstart is a normal auto-loaded ROM)
Keyboard PS/2 → matrix keyboard.vhd raw Amiga scancodes over a side-channel; no PS/2
Interlace never laced screens mid-demo — needs the new field-flag path into ascal
Memory 64 KB + ROMs, fits BRAM easily 1.25 MB fits BRAM only in the minimal A500; image + framebuffer go to HyperRAM
Framework changes none two features being upstreamed into M2M V2.1.0 (interlace field flag; a core-I/O firmware hook)

The lesson isn't the specifics — it's the mindset: when a framework service doesn't fit, separate its mechanism from its pattern. The Amiga floppy rejects the vdrives mechanism (block-level SD access) but keeps the vdrives pattern (a RAM-cached image, lazily flushed to SD in the background, with a dirty-LED and a prevent-unmount interlock). Recognizing when to copy the pattern rather than the wire is the heart of porting the awkward cores.


12. Where to go next

You now have the MiSTer mental model. Turn it into a port:

And for the authoritative MiSTer-side detail, MiSTer's own developer documentation is the source of record — especially Porting Cores, Core Configuration String, Overview of emu module, and sys - hps_io. We port from MiSTer, but those pages describe the world we are porting from — and this guide is your map to it.

Clone this wiki locally