AExp architecture: a map of the core¶
This document is the starting point for anyone who works on the Amiga 500 core for the MEGA65. It explains how the core is put together, where each part lives in the repository, which clock domains and buses connect the parts, and which rules you have to respect when you change something. The deeper design documents are listed at the end; this one tells you which of them to open.
It assumes that you know VHDL, the Xilinx tools and the MEGA65, and ideally the MiSTer2MEGA65 (M2M) framework. It does not assume that you know the Amiga. Where Amiga knowledge is needed, the text explains it or points to the glossary in floppy-adf.md.
Contents¶
- What the core simulates
- From the board to the Amiga chips
- Repository layout
- Clock domains and crossings
- QNICE devices and the HyperRAM map
- The QNICE firmware
- Rules you have to know
- The modified M2M framework
- The Minimig submodule
- The MiSTer HPS code and its replacements
- Mouse and joystick
- Checking your work before a Vivado run
- Where to read next
1. What the core simulates¶
AExp is an Amiga 500 with the original chipset (OCS), PAL only. The CPU is fx68k, a cycle-exact 68000. The chipset comes from the MiSTer Minimig-AGA core, of which AExp uses only the A500 subset: no ECS, no AGA, no 68020, no Fast RAM, no IDE.
The machine has three memories, and all three live in the FPGA's block RAM:
| Memory | Size | CPU address | Notes |
|---|---|---|---|
| Chip RAM | 512 KB | $000000-$07FFFF |
shared by CPU and the custom chips |
| Slow RAM | 512 KB | $C00000-$C7FFFF |
the A501 trapdoor expansion; can be switched off in the menu |
| Kickstart ROM | 256 KB | $F80000-$FFFFFF |
loaded from the SD card at startup |
Nothing uses SDRAM. The R3 board has none, and the SDRAM of R4 and later is left unused so that all boards run the same design.
The Kickstart ROM is not part of the core. The QNICE firmware loads it from
/amiga/kick.rom on the SD card while the core is held in reset. It is a
mandatory file (C_CRTROMTYPE_MANDATORY in CORE/vhdl/globals.vhd): if it is
missing, the firmware shows a fatal error naming the file and the core never
starts. The file is a raw 256 KB dump, big-endian, exactly as read from the ROM
chip.
Floppy disks come in two flavours. Up to three Amiga drive units (df0:,
df1:, df2:) can each be a simulated drive that mounts an .adf disk image
from the SD card, read and write (a "Disk Image" drive in the menu); at most
one of them can instead be the MEGA65's own 3.5" drive, which then reads and
writes real Amiga disks (the "Hardware Floppy"). By default only df0:
exists, as a Disk Image drive, because some games misbehave when the Amiga
sees more than one drive.
The whole Amiga runs on one clock of 28.375 MHz, the PAL master clock (the ideal value is 28.37516 MHz; the difference is -5.6 ppm, well inside the tolerance of a real crystal). The 7.09 MHz bus timing of the original machine is made with clock enables, not with additional clocks.
2. From the board to the Amiga chips¶
The design is layered. The outer layers belong to the M2M framework, the inner layers to AExp:
M2M/vhdl/top_mega65-r<n>.vhd board top, one per MEGA65 revision
|
+-- framework.vhd (M2M) QNICE CPU running the Shell firmware,
| SD card + FAT32, on-screen menu (OSM),
| keyboard scan, joystick ports,
| HyperRAM controller, audio output,
| av_pipeline: ascal scaler (HDMI) and
| scandoubler/analog path (VGA)
|
+-- MEGA65_Core = CORE/vhdl/mega65.vhd
| clk.vhd 28.375 MHz core clock + flicker-free twin
| Chip, Slow and Kickstart BRAMs
| QNICE device decode (0x0100 .. 0x0106)
| 3 x adf_mount_wrapper one ADF mount device per drive
| avm_fifo + avm_arbit_general HyperRAM access for the floppy
| physical_fdd_top + _diag Hardware Floppy front end (50 MHz)
| amiga_cold_boot Amiga-only cold boot on topology change
| OSM decoding, drive LED, flicker-free servo
|
+-- main.vhd replaces MiSTer's Minimig.sv
| amiga_config replays the MiSTer HPS configuration
| adf_track_engine Paula floppy host service (+ avm_cache)
| keyboard MEGA65 keys -> Amiga keycodes
| audio_filters A500/LED filters, stereo mix
| video clock enables, sync polarity, master volume
|
+-- amiga_clk.v clock enables of the Amiga bus
+-- cpu_wrapper.v -> fx68k the 68000
+-- minimig_m65.v -> minimig.v
Agnus, Denise, Paula, the two CIAs,
Gary, userio, the SRAM bridge
The QNICE firmware (CORE/m2m-rom/m2m-rom.asm together with the framework's
Shell in M2M/rom/) runs on the QNICE soft CPU inside the framework. It loads
the Kickstart, runs the menu, streams disk images into the core and writes
changed disk tracks back to the SD card.
A few interfaces carry almost all of the traffic between these layers.
The Amiga memory bus. With a 68000 and no Fast RAM, every memory access of
the machine, from the CPU and from the custom chips' DMA alike, goes through
one SRAM-style port of Minimig (ram_addr[22:1] plus byte enables). Minimig's
minimig_sram_bridge.v maps the CPU address space onto banks of that port:
Chip RAM is at ram_addr[22:19] = "0000", Slow RAM at "1000" and the
Kickstart at "1111" (bit 18 is ignored, which gives the $F8/$FC mirror).
mega65.vhd decodes these banks onto the BRAMs. Every memory is split into an
upper and a lower 8-bit lane, so that the byte at an even address is data bits
15..8, which is why a raw ROM dump streamed byte by byte lands correctly
without byte swapping.
The host channel. On MiSTer, an ARM processor (the HPS) talks to Minimig
over a small SPI-like bus. Two of its "chip selects" matter here: IO_UIO
carries configuration commands into userio.v, and IO_FPGA is Paula's
floppy channel. The MEGA65 has no HPS, so two AExp blocks in main.vhd speak
that bus instead. amiga_config.vhd replays MiSTer's boot-time configuration
after every reset (OCS chipset, 68000, 512 KB + 512 KB memory, drive count,
joystick port mapping) and then releases the CPU. adf_track_engine.vhd then
owns the bus and serves Paula's floppy requests. main.vhd multiplexes the
shared strobe and data lines between the two. Both blocks are modelled on
MiSTer's HPS software; section
10 names the files.
The floppy. The Amiga floppy controller cannot read sectors; it only moves
raw MFM words, and the operating system decodes them in software. AExp
therefore needs an MFM codec in hardware. adf_track_engine.vhd is a hardware
port of MiSTer's ARM-side floppy service, minimig_fdd.cpp; a copy of the
version it was modelled on is kept in this folder as
minimig_fdd.cpp, and
floppy-adf.md
lists what AExp changed and added. The disk images live in HyperRAM, one pool
per drive; the firmware copies changed tracks back to the .adf files in the
background. For the Hardware Floppy, the engine streams words that
CORE/vhdl/physical_fdd/ reconstructs from the real flux, and Paula's floppy
logic is extended so that the real drive's status lines reach the CIAs. See
floppy-adf.md and hardware-floppy.md.
Video. Minimig produces 15 kHz PAL video in the core clock domain.
main.vhd generates a frame-locked pixel clock enable (7.09 MHz, or 14.19 MHz
for hires frames), inverts the active-low Minimig syncs and exports the
interlace field flag. The framework scales the picture for HDMI with ascal,
which also weaves interlaced fields, and either scandoubles it to 31 kHz for
VGA or passes it through raw in the two 15 kHz analog modes.
Audio. Paula's four channels pass audio_filters.vhd (the A500 low-pass
and the LED filter, ported from MiSTer's Minimig.sv, plus the stereo mix) and
the master volume in main.vhd, and then reach the framework, which feeds both
HDMI and the 3.5 mm jack. See audio.md.
Keyboard, mouse, joysticks. keyboard.vhd translates the MEGA65 key matrix
into raw Amiga keycodes and hands them to CIA-A with the real keyboard
handshake. The DB9 ports reach Minimig without debouncing, so a real Amiga
mouse moves smoothly; section 11 explains the mouse
path and why the MEGA65 cannot see the right button of a passive Amiga mouse.
3. Repository layout¶
CORE/vhdl/: the port¶
All files in this folder are AExp's own.
| File | Purpose |
|---|---|
mega65.vhd |
The MEGA65_Core entity the framework instantiates. Amiga memories (BRAM), QNICE device decode, the three ADF mount devices with their HyperRAM chain, the Hardware Floppy front end and its pins, all OSM decoding (C_MENU_* constants), drive LED, the flicker-free servo. |
main.vhd |
Wraps Minimig and fx68k in the core clock domain. Takes the role of MiSTer's Minimig.sv: CPU phase enables, video clock enable and sync polarity, reset mapping, the host bus multiplexer, the floppy engine and its read cache, keyboard, audio. |
amiga_config.vhd |
Replays MiSTer's configuration commands (0xF1..0xF9) over the IO_UIO channel after every reset, then releases the 68000. |
amiga_cold_boot.vhd |
Turns a change of the memory or drive topology into a cold boot of the simulated Amiga only: holds Minimig in reset and clears the ExecBase pointer at $000004 so that Kickstart re-probes the machine. |
adf_track_engine.vhd |
The floppy host service: polls Paula, MFM-encodes sectors from HyperRAM for reads, decodes and commits written sectors, streams the Hardware Floppy's words, and feeds the physical write path. One instance for all drives. |
adf_mount_wrapper.vhd |
One ADF mount device (three instances): byte window into that drive's HyperRAM pool, the framework's load handshake with an ADF size check, and the write-back registers (dirty-track bitmap, write enable, anti-thrashing timer). |
physical_fdd/ |
The Hardware Floppy: input conditioning, flux interval measurement, the data separator, sync alignment, a dual-clock word FIFO, the write front end and the diagnostics register bank. Runs at 50 MHz. |
keyboard.vhd |
MEGA65 keyboard to Amiga keycodes, two mapping modes, CIA handshake. |
audio_filters.vhd |
A500 and LED filters and the stereo mix. |
clk.vhd |
The core clock: a native 28.375 MHz MMCM, a 28.4375 MHz twin for the HDMI flicker-free mode and a glitch-free clock multiplexer. |
config.vhd |
The on-screen menu (items, groups, dependencies, help pages), CORE_VERSION, the settings file name and other Shell configuration. |
globals.vhd |
Clock speeds, OSM canvas size, the HyperRAM map, the ADF geometry, the QNICE device ids and the list of loadable ROMs and disk images. |
CORE/m2m-rom/: the firmware¶
m2m-rom.asm is the core-specific part of the QNICE firmware (section
6). make_rom.sh assembles it together with the
framework's Shell into m2m-rom.rom, which the bitstream embeds as the QNICE
ROM. Before assembling, it scrapes constants from the VHDL sources into
generated include files (osm_const.asm, globals.asm,
shell_fhandles.asm, shell_fh_ptrs.asm; all git-ignored). synth_pre.tcl
is the Vivado pre-synthesis hook that runs make_rom.sh, so every synthesis
rebuilds the firmware from the current sources. video_filters/ holds the
coefficient tables of the HDMI scaler filters the menu offers.
CORE/Minimig_MiSTerMEGA65/: the chipset¶
A git submodule with AExp's fork of the MiSTer Minimig core. See section 9.
Vivado projects, constraints and build scripts¶
| File | Purpose |
|---|---|
CORE/CORE-R3.xpr .. CORE-R6.xpr |
One Vivado project per board revision (R3 also covers R3A). |
CORE/CORE.xdc |
All core-specific timing constraints, including the ones that cover framework paths (section 7). |
CORE/build_all.sh |
Batch build of one or more boards, with the automatic re-roll of boards that just missed timing. |
CORE/build_bitstream.tcl |
Builds one board and checks the sign-off gates. |
CORE/reroll_bitstream.tcl |
Re-implements a board with other placer and router directives. |
How to build is in developers.md; the re-roll is explained
in timing_closure.md.
Releases¶
make_release.py in the repository root is the generic M2M packaging script:
it turns the bitstreams of all boards into .cor files, generates the
matching settings file and collects the documentation. AExp's own policy lives
in CORE/release.toml (file names, version check, settings file) and
CORE/release_hooks.py (the screen-adjustment files and tool that ship with
every release, documentation link rewriting). VERSIONS.md holds the release
notes; doc/inofficial.md lists the alpha and beta builds, and
make_release.py requires a row there for every work-in-progress build.
M2M/: the framework¶
The framework is part of this repository, not a submodule (section
8 explains what AExp changed in it). Inside it,
M2M/QNICE is a submodule with the QNICE CPU, its tool chain and its monitor
and FAT32 library, and M2M/tools/make_config.sh creates the menu settings
file.
Everything else¶
doc/ holds the end-user documentation and doc/developers/ these developer
notes; doc/make_doc.py builds both into the documentation website (see
make_doc.md). aexp_screen_cfg.py and the
aexp_screen.cfg_* presets in the repository root are the end-user tool and
data for the screen adjustment (see screen_adjust.md).
tools/ holds the host-side checkers and the tools for floppy field reports,
CORE/sim/ the simulation testbenches; Tools and testbenches
describes both.
4. Clock domains and crossings¶
| Clock | Frequency | Where it is used |
|---|---|---|
main_clk |
28.375 MHz, or 28.4375 MHz while the flicker-free servo selects the twin | All of Minimig and fx68k, main.vhd, adf_track_engine, keyboard, audio filters; also the video clock handed to the framework. |
qnice_clk |
50 MHz | QNICE CPU and Shell. QNICE device accesses are done on the falling edge. The ADF mount devices (CSR, size check, write-back registers) and the whole Hardware Floppy front end run here. |
hr_clk |
100 MHz | HyperRAM controller, the framework's HyperRAM arbiter, the memory side of ascal, the floppy's four-way arbiter. |
| video output clocks | per video mode | HDMI and analog output pipelines of the framework. |
| audio clock | 12.288 MHz | framework audio output. |
The core clock switches between two MMCM outputs through a BUFGMUX_CTRL.
The HDMI output runs at exactly 50 Hz, the native Amiga frame rate is
49.92 Hz, and so ascal's single frame buffer would drop or repeat a frame
roughly every 12 seconds. The servo dithers the core clock between the native clock and a
slightly faster twin so that the average frame rate is exactly 50 Hz. The
analysis is in hdmi_latency.md. CORE.xdc times only the
faster leg (it freezes the multiplexer select with set_case_analysis and
defines main_clk on the twin's output), and build_bitstream.tcl refuses a
build in which those constraints matched no pins.
Crossings follow three patterns:
- Quasi-static values and toggle handshakes cross with the framework's
cdc_stable, whichM2M/common.xdcalready constrains. - Avalon traffic to the HyperRAM crosses with
avm_fifo. - The Hardware Floppy's word FIFO and its control synchronizers are raw
two-flop and Gray-code crossings between
qnice_clkandmain_clk.CORE.xdcbounds them with a clock-pairset_max_delay -datapath_onlyof one QNICE period in both directions. It deliberately does not use a false path, because a clock-pair false path would also override the tighter object-scoped bounds ofcommon.xdc.
CORE.xdc also bounds the asynchronous ping-pong buffers inside ascal with
set_max_delay -datapath_only. Without that, Vivado times them against
impossible inter-clock requirements and the router's hold fixes spoil the
genuine HyperRAM paths.
5. QNICE devices and the HyperRAM map¶
The QNICE CPU reaches core memories and registers through the framework's
device bus: a 16-bit device id (core devices start at 0x0100), a 4k-word
window selector and an address inside the window. The core decodes its devices
in mega65.vhd; the ids are defined in globals.vhd.
| Id | Constant | Purpose |
|---|---|---|
0x0100 |
C_DEV_AMIGA_KICK |
Kickstart ROM. The Shell writes the ROM file into it at startup. |
0x0101, 0x0102 |
C_DEV_AMIGA_CHIP, _SLOW |
Reserved and not connected (see 7.2). |
0x0103 |
C_DEV_AMIGA_ADF0 |
ADF mount device of df0:. |
0x0104 |
C_DEV_AMIGA_FDD |
Diagnostics register bank of the Hardware Floppy. |
0x0105 |
C_DEV_AMIGA_ADF1 |
ADF mount device of df1:. |
0x0106 |
C_DEV_AMIGA_ADF2 |
ADF mount device of df2:. |
The Hardware Floppy's id sits between the ADF devices because it is older than
the second and third drive, and its register map is referred to by number in
field test instructions, so it kept the id. The three ADF devices share one
layout: windows 0x0000 upwards are a byte window into the drive's image,
window 0xFFFE holds the write-back registers and window 0xFFFF the
framework's load handshake. The register maps are in
floppy-adf.md.
The HyperRAM is 8 MB, addressed in 8 KB windows:
| Windows | Bytes | Owner |
|---|---|---|
0x000-0x1FF |
0-4 MB | Framework (C_HMAP_M2M). The ascal frame buffer uses the first 2 MB. |
0x200-0x27F |
4-5 MB | df0: slot: image pool, one guard window, spare |
0x280-0x2FF |
5-6 MB | df1: slot |
0x300-0x37F |
6-7 MB | df2: slot |
0x380-0x3FE |
7-8 MB | unused |
0x3FF |
last 8 KB | top guard, so that a burst past the last region cannot wrap to 0 |
Each image pool holds the largest accepted ADF (166 tracks) and is followed by
an empty guard window, because the shared HyperRAM infrastructure (the read
cache's prefetch, the HyperRAM errata fix) can reach a few words beyond the
address a client asked for. mega65.vhd checks the ordering of the regions at
elaboration time. Keep ascal's triple buffering off (qnice_ascal_triplebuf_o
is tied to '0'): it would grow the frame buffer to 6 MB and overwrite the
disk images, and it would also break the flicker-free mode.
6. The QNICE firmware¶
The framework's Shell (M2M/rom/) does the generic work: SD card and FAT32,
the file browser, the menu, loading ROMs and disk images, saving the menu
settings. It calls back into the core-specific firmware in
CORE/m2m-rom/m2m-rom.asm at defined points. AExp uses these callbacks for:
FILTER_FILESandPREP_LOAD_IMAGE: show only.adffiles in the browser for a drive's mount line, reject files outside the accepted size range, flush and disarm the drive before a new image is loaded, and refuse to mount the same file into two drives.PREP_START: load the screen-adjustment file before the core leaves reset.OSM_SEL_PREandOSM_SEL_POST: keep the drive configuration consistent (drive count, at most one Hardware Floppy, ejecting a drive that leaves Disk Image mode), reset the core when Slow RAM is toggled, load the HDMI filter coefficients, reload the screen configuration.HANDLE_CORE_IO, a callback AExp added to the framework (section 8): called in every iteration of the Shell's main loop and of all its wait loops. It handles the SPACE key that ejects a disk, detects Amiga screen-mode changes for the screen adjustment, runs the background write-back of changed ADF tracks to the SD card, reseeds the Amiga's real-time clock every minute and updates the live Hardware Floppy status in the menu.
The write-back is the subtle part. Read floppy-adf.md sections 8 and 9 before you change anything in it.
The menu settings are saved in /amiga/aexp-<CORE_VERSION>.cfg. The file is
OPTM_SIZE bytes long (one byte per menu line), and the firmware accepts a
settings file on its length alone.
The QNICE submodule tracks the dev-V1.61 branch of QNICE-FPGA (set in
.gitmodules), not the commit that M2M V2.0.1 pins. That branch carries two
fixes to the FAT32 library that the ADF write-back depends on: the shared
sector buffer is written back before DIR_OPEN or FILE_OPEN reuse it, and
the 32-bit sector address overflow check. If you ever sync the framework from
the M2M template, make sure the submodule pointer does not move back. Update it
with git submodule update --remote M2M/QNICE; the next synthesis reassembles
the firmware against the new monitor.
7. Rules you have to know¶
Each of these rules exists because breaking it either does not build, does not close timing, or fails in a way that is hard to trace back.
7.1 Block RAM is full¶
The core uses 364 or 365 of the 365 block RAM tiles of the XC7A200T, depending
on the build. The Amiga memories alone take 320 tiles (Chip RAM 128, Slow RAM
128, Kickstart 64), and that is an exact mapping with nothing left to save.
Any new buffer must go into HyperRAM or into distributed RAM, which is why the
disk images live in HyperRAM and why the floppy engine's sector buffers are
LUTRAM. The design asks for more block RAM than the chip has: Vivado routinely
reports Synth 8-5835 (block RAM over-utilized, counted in half tiles) and
implements the excess in LUTRAM. That is only a real failure if implementation
then cannot place the design. It also means that removing a block RAM user
does not lower the count: Vivado moves memories from LUTRAM into the freed
tiles. Re-enabling IDE would need 8 more tiles and does not fit.
7.2 No QNICE ports on spread-out block RAM¶
QNICE accesses device memory on the falling edge of its 50 MHz clock, which
leaves half a period, 10 ns, for the address to reach the RAM. Chip RAM and
Slow RAM are 256 tiles spread across the die, and the address bus cannot reach
them in time; an earlier version that tried missed timing by 0.76 ns. Only the
Kickstart ROM (64 tiles) has a QNICE port. The device ids 0x0101 and
0x0102 stay reserved so that they are not reused by accident.
7.3 The timing margin is thin¶
Builds close with a worst negative slack of roughly +0.1 to +0.3 ns. Look at
the timing summary after every build; build_all.sh prints it for you. The
sign-off gates in build_bitstream.tcl also check that the flicker-free
constraints in CORE.xdc really matched: the instance names i_clk_fast
(in clk.vhd) and hr_core_speed (in mega65.vhd) are referenced by name
there, so keep them. Now and then a board misses timing by a few picoseconds of
hold in the framework's HyperRAM read capture; that is placement luck, and
timing_closure.md explains why build_all.sh simply
re-rolls such a board and why the HyperRAM IDELAY value must not be changed.
7.4 The firmware ROM must end below 0x7000¶
M2M maps its 4k-word device window at 0x7000-0x7FFF, so only 28,672 words of
the QNICE ROM are usable. make_rom.sh checks the assembled image against
this limit and fails the build loudly if it is exceeded. WIP-V2-B2 uses
27,533 words. Vivado prints Shell ROM: N/28672 words. during synthesis.
7.5 Every growth of the menu needs a heap budget check¶
The Shell copies the menu text and four arrays of OPTM_SIZE words into a
heap of MENU_HEAP_SIZE words, and then uses the rest of that heap for one
line buffer per submenu, mount line and vdrive, plus a scratch buffer. When you
change OPTM_SIZE, OPTM_ITEMS, OPTM_DX, or the number of submenus or
mount lines, recompute the demand:
20 + (characters of OPTM_ITEMS, "\n" counts as 2) + 1 + 4 x OPTM_SIZE + 1
+ (vdrives + submenus + manual ROMs + 1) x (OPTM_DX + 2)
Round the result up to the next multiple of 32 and no further, because the
file browser's heap starts right behind the menu heap and every spare word is
taken from it. If MENU_HEAP_SIZE changes, change both HEAP_SIZE constants
in m2m-rom.asm (debug and release) by the same amount in the opposite
direction, so that the totals stay the same. Currently the 148-line menu needs
2325 words and MENU_HEAP_SIZE is 2336. A wrong budget is never silent: the
firmware stops with a fatal error at boot and on every menu open. Firmware
variables count too: they sit below the heap and push it upwards, so after
adding variables check the HEAP and VAR$STACK_START addresses in
m2m-rom.lis. The comments above MENU_HEAP_SIZE in m2m-rom.asm keep the
current calculation.
The help pages have a budget as well: they are printed into a full-screen frame
that leaves 34 rows of 43 characters. Each page uses exactly 33 rows of at most
42 characters, so a free row and column separate the text from the border and
the footer stays in place while paging; tools/check_osm_menu.py enforces it.
7.6 Menu line numbers are bit numbers¶
In config.vhd, the position of a line in the menu is the number of the bit
that carries its state to the core. mega65.vhd reads these bits through the
C_MENU_* constants, so inserting a line shifts every constant behind it, and
all of them have to be updated by hand. make_rom.sh scrapes these constants
(and the core's OPTM_G_* group ids from config.vhd, the device ids and the
ADF geometry from globals.vhd) into the firmware, so the firmware has no
hard-coded menu indexes. The scraper is a line-based awk: keep every one of
these constants on a single line.
7.7 CORE_VERSION names the settings file¶
CORE_VERSION in config.vhd is the only place the version string is
written. The welcome and help screens, the core name and the settings file name
/amiga/aexp-<CORE_VERSION>.cfg all derive from it, and make_release.py
checks that the release you package matches it. A new version therefore needs
a new settings file. Generate a fresh one (see
developers.md) instead of copying an old one
forward: a used file holds the old selections, and because the firmware only
checks the length, a file of the right length restores them silently.
7.8 Keep the four Vivado projects in sync¶
Every change to the file list or to file properties goes into all four
.xpr files in the same commit. The expected differences between them are
the board top (M2M/vhdl/top_mega65-r<n>.vhd), the board constraints
(M2M/MEGA65-R<n>.xdc), and the audio output driver: R3 uses max10.vhdl and
pcm_to_pdm.vhdl, R4 and later use audio.vhd.
When you edit an .xpr by hand, the only valid SFType attributes are
VHDL2008 and SVerilog, or none at all (the type is then inferred from the
file extension). Anything else, such as Verilog or SystemVerilog, makes
Vivado crash while opening the project.
7.9 Keep OPTM_PAUSE false¶
The framework can pause the core while the menu is open, but main.vhd does
not implement pause_i (Minimig has no clean point to stop at). OPTM_PAUSE
in config.vhd must stay false.
7.10 What the framework expects from the video¶
The framework wants active-high syncs (Minimig's are active low, so
main.vhd inverts them), blanking signals that cover the syncs, and a pixel
clock enable that is locked to the frame. The video clock is main_clk
(28.375 MHz). The enable runs at 7.09 MHz, every fourth clock, in frames with
only lowres lines, and at 14.19 MHz, every second clock, while a frame
contains hires lines. MiSTer's scandoubler doubles the lines with its Hq2x
filter, which needs at least four clocks per input pixel; at two clocks it
keeps only every second hires pixel. AExp therefore sets VGA_LINEDOUBLER in
globals.vhd, and the scandoubler uses the plain line doubler of section
8.10, which needs two clocks per pixel. Never use the
full 28 MHz as pixel clock enable: the line doubler would get only one clock
per pixel, and ascal accepts at most 1024 input pixels per line. The
scandoubler is on (qnice_scandoubler_o = '1') in the standard VGA mode,
because the core outputs 15 kHz video, and off only in the two 15 kHz analog
modes.
8. The modified M2M framework¶
AExp V2 is built on MiSTer2MEGA65 V2.0.1, but not on an unmodified copy. The
framework in M2M/ carries ten AExp changes that the core needs and that
V2.0.1 does not offer. Each change is marked in the code with a comment
M2M-UPSTREAM <name>, so this command finds all of them, together with the
two tagged bug fixes of section 8.11:
The AExp V2 release is not reconciled with M2M V2.1.0. That framework release
will contain the features that make these changes unnecessary. Moving AExp to
it, dropping what V2.1.0 supersedes and carrying over the rest, is future work.
Until then, treat M2M/ as part of AExp. Do not update it from the M2M
template, and do not make further changes there unless there is no other way.
Do not merge a newer M2M release into
M2M/. A plaingit mergeor a copy of a new framework version silently drops or breaks the changes AExp depends on, and thegrepabove does not find all of them: some changes carry no tag (sections 8.5 and 8.11). Moving to a newer framework is a port, not a merge. Go through this section change by change, decide for each one whether the new framework replaces it or whether it has to be carried over, and test the result on hardware.
Constraints for framework paths go into CORE/CORE.xdc; M2M/common.xdc
stays as the framework ships it.
If you add the M2M repository as a git remote to compare, remember that its
tags (V1.0.0, V2.0.0, V2.0.1 and so on) are framework releases, not AExp
releases. AExp's own tags are V1, V2 and the WIP-* work-in-progress
builds.
8.1 interlace¶
- What: a new framework input
video_fl_i, the interlace field flag, threaded from the core throughframework.vhd,av_pipeline.vhdanddigital_pipeline.vhdinto ascal'si_flinput, and ascal instantiated withINTER => true. - Files:
framework.vhd,av_pipeline/av_pipeline.vhd,av_pipeline/digital_pipeline.vhd, the four board tops. - Why: ascal weaves the two fields of an Amiga interlaced screen into one stable progressive picture on HDMI (the "flicker fixer").
- Other cores: the input defaults to
'0', and ascal only arms its deinterlacer wheni_fltoggles, so progressive cores behave exactly as before.
8.2 core-io-hook¶
- What:
HANDLE_CORE_IO, a new mandatory core callback, called from the Shell'sHANDLE_IO. Contract: preserve all registers, return quickly, may change the selected RAMROM device and window. - Files:
M2M/rom/shell.asm. - Why:
HANDLE_IOruns in the main loop and in every blocking wait loop (menu, file browser, help screens), so a background task hooked there keeps running while the user sits in the menu. AExp's ADF write-back cannot use the framework'svdrivessystem and needs such a time slice. - Other cores: they must provide the callback, at least as an empty subroutine, or the firmware does not assemble.
8.3 screen-center¶
- What: the plumbing of the screen adjustment. Four signed per-edge crop
offsets for ascal's input window (HDMI), four signed overscan edges for a
soft blank on the analog output, and two signed pan values that feed the new
analog_positioner.vhd, which shifts the analog sync phase against the picture. The values come from QNICE general-purpose registers; a new read-only registerM2M$SYS_CORE_FLAGStells the firmware whether ascal currently sees interlaced input. - Files:
framework.vhd,qnice_wrapper.vhd,av_pipeline/av_pipeline.vhd,av_pipeline/digital_pipeline.vhd,av_pipeline/analog_pipeline.vhd,av_pipeline/ascal.vhd, the newav_pipeline/analog_positioner.vhd,M2M/rom/sysdef.asm. - Why: Amiga software uses many different screen geometries; the core picks
per-mode offsets from
aexp_screen.cfg(seescreen_adjust.md). - Other cores: all new inputs default to 0, and a pan of 0 bypasses the positioner combinationally, so the output is unchanged.
8.4 osm-hotkey¶
- What: three core-driven inputs (
osm_key_a_i,osm_key_b_i,osm_combo_i) choose which key, or which two-key combination, opens the menu. They are threaded from the core throughframework.vhdintom2m_keyb.vhd, which builds the menu bit from the ungated keyboard scan. - Files:
m2m_keyb.vhd,framework.vhd, the four board tops. - Why: Help is a useful key on the Amiga, so the user can pick another key to open the menu.
- Other cores: the defaults select Help alone, the classic behaviour. The firmware is unchanged.
8.5 osm-scale¶
- What:
tdp_ram.vhdgets aRAM_STYLE_SELECTgeneric (default"auto") that2port2clk_ram.vhdpasses through, and ascal's small asynchronous ping-pong buffers (i_dpram) are forced into distributed RAM. The OSM renderer for the "OSM Scaling" menu option was reworked in the same change: the font ROM now stores the native 8x8 Anikki glyphs, the 100% size expands them to exactly the old 16x16 font, and smaller sizes use a sharpened bilinear filter. - Files: tagged are
tdp_ram.vhdandav_pipeline/ascal.vhd; the renderer change inav_pipeline/vga_osm.vhd,av_pipeline/video_overlay.vhd,2port2clk_ram.vhdand the font files inM2M/font/carries no tag. - Why: left to its own heuristics, Vivado put ascal's buffers into four block
RAM tiles the core does not have, and absorbed a register into the block RAM
output, which broke the endpoints of the ascal constraints in
CORE.xdc. The renderer change makes the scaled menu legible. - Other cores:
"auto"keeps every other caller as before. The ascal buffer attribute and the renderer apply to every core; at 100% the menu is pixel identical to the old renderer.
8.6 raw-joyports¶
- What: the joystick debouncer in
debouncer.vhdis reduced to plain two-flop synchronizers; the 1 ms stable-time filters are gone. Port swapping and the joystick enable gating stay. - Files:
debouncer.vhd. - Why: a real Amiga does not debounce its DB9 lines, and a quadrature mouse produces pulses faster than a 1 ms filter lets through, so the pointer freezes and jumps (section 11.1).
- Other cores: this one is not default-off. Every core using this copy gets raw joystick lines. Upstream it should become a framework option.
8.7 floppy-pins¶
- What: the four board tops route the MEGA65's internal floppy connector into
MEGA65_Core: the five inputs and the drive A outputs (motor, select, side, step direction, step, density), and the two write pinsf_wdataandf_wgate. Drive B's motor and select stay tied inactive.framework.vhdis not involved. - Files: the four board tops.
- Why: the Hardware Floppy. The pattern is the one C64MEGA65 uses for its physical 1581 drive.
- Other cores: the board tops now expect these ports on
MEGA65_Core. Note that because the write pins are connected, the internal drive is not physically read-only any more; what protects a disk is the core's write gate and the disk's write-protect tab.
8.8 osm-deps¶
- What: menu dependencies, ported from C64MEGA65. A menu line tagged with
OPTM_DEPorOPTM_DEP2inconfig.vhdis only visible while a given item of a "mother" group is selected. The validator checks the dependency rules at boot and stops with one of five new error messages. - Files: the new
M2M/rom/optm_deps.asm, plusmenu.asm,options.asm,strings.asm,sysdef.asm. - Why: each drive has two lines in the main menu, a mount line and a Hardware
Floppy status line, and the menu shows the one that matches the drive's mode.
Unlike the C64 original, this copy allows dependent ROM-loader
(
OPTM_G_LOAD_ROM) lines, through which AExp mounts its ADF images, partially visible radio groups and two-level chains, and its validator is correspondingly less strict in two of its rule classes (the reasons are in the header ofoptm_deps.asm). - Other cores: a core whose
config.vhddoes not answer the feature probe sees every line, as before.
8.9 live-text¶
- What:
OPTM_LIVE_TEXTinmenu.asmreplaces a fixed-width part of one menu line in the heap copy of the menu text and repaints just those characters if the line is visible. Ported from C64MEGA65. - Files:
M2M/rom/menu.asm. - Why: the live status of the Hardware Floppy in its menu line. Unlike the C64 original, the caller decides whether the menu currently owns the screen (M2M V2.0.1 has no flag for that).
- Other cores: purely additive; nothing else calls it.
8.10 line-doubler¶
- What: a parameter
LINEDOUBLERof MiSTer'sscandoubler.v(default 0, the original Hq2x path) and a new modulelinedoublerin the same file, which replaces Hq2x when the parameter is 1.video_mixer.svpasses the parameter on;analog_pipeline.vhdandav_pipeline.vhdcarry it as the genericG_VGA_LINEDOUBLER(defaultfalse), andframework.vhdsets that generic from the constantVGA_LINEDOUBLERin the core'sglobals.vhd, the way it takesVGA_DX. - Files:
controllers/MiSTer/scandoubler.v,controllers/MiSTer/video_mixer.sv,av_pipeline/analog_pipeline.vhd,av_pipeline/av_pipeline.vhd,framework.vhd. - Why: Hq2x spends four clock enables on every input pixel, so it needs a
video clock of at least four times the pixel rate. MiSTer's Minimig runs its
video at 113.5 MHz and always meets that. AExp runs the video at
main_clk, which is four times the lowres rate but only twice the hires rate (section 7.10); there Hq2x keeps only every second hires pixel, and hires screens on the analog Standard VGA output lose every second pixel column. The line doubler needs one clock to write an input pixel and one to read an output pixel, so two clocks per pixel are enough. - How: the line doubler writes one pixel per input pixel enable into one half of a two-line buffer while it reads the other half, the previous input line, twice, one pixel per output pixel enable. The halves swap when the output window of a line's first copy opens: normally at the start of the active part of the input line, a few clocks earlier when an input line is longer than the one before it (while the analog overscan changes), because the scandoubler times its output windows from the previous line's length. Each half holds 1024 pixels of 24 bits in distributed RAM: a whole hires line including its blanking, also when an outward analog overscan widens the active window. The latency is one input line (64 µs) instead of Hq2x's one and a half, so the scandoubler takes its vsync and vblank outputs one output line earlier, and the Standard VGA picture leaves the MEGA65 32 µs sooner. In this mode the scandoubler also measures the pixel period in the vertical blanking lines, so a pixel rate that changes at vsync is in effect from the first active pixel on, and it samples the vertical blanking a second time 16 clocks into each line: the analog soft blank of section 8.3 changes vblank one clock after its hblank falls, and without the second sample the picture would show one line too late within the window. An outward left overscan of more than 15 clocks puts the core's vblank edge beyond that second sample; there the picture still shows one line late, as it does with Hq2x. There is no Hq2x filter in this mode (AExp never switches it on), no new clock and no clock-domain crossing; HDMI and the two 15 kHz modes do not pass the scandoubler and are unchanged. The line doubler uses LUTRAM. Without Hq2x the scandoubler needs none of its 5.5 block RAM tiles; Vivado fills them with memories it would otherwise implement in LUTRAM (section 7.1), so the block RAM stays full.
- Other cores: the parameter and both generics default to the original Hq2x
path, but
framework.vhdreadsVGA_LINEDOUBLERfrom the core'sglobals.vhd, so another core that uses this copy of the framework has to add that constant (falsekeeps its behaviour).
8.11 Other differences to V2.0.1¶
Besides the ten changes of sections 8.1 to 8.10, AExp differs from M2M V2.0.1
in four more places. Three of them are in M2M/, the fourth in AExp's own
firmware.
-
HyperRAM read watchdog (tag
qnice2hyperram-watchdog, ported from C64MEGA65). QNICE waits for the answer to every HyperRAM read. If the answer is lost, for example because the reset button resets the HyperRAM side in the middle of a read, QNICE would otherwise wait until a framework reset (reset button held for 1.5 s) or a power cycle. The watchdog inqnice2hyperram.vhdsends the read again every 0.65 ms until an answer arrives.It has one known limit. If the reset only delayed the original read, because the command was still queued in the clock-crossing FIFO (
avm_fifo) between QNICE and HyperRAM, both the original and the repeated read are answered. The module drops a surplus answer that arrives while no read is waiting. If QNICE has already issued its next read, the module takes the surplus answer for that read, which then returns the data of the previous address. Only a reset during a QNICE HyperRAM read can cause this. Closing the gap needs the QNICE side ofavm_fifoto be reset together with the HyperRAM side; AExp resets each side from its own domain only. -
R7 fix in
gencfg.asm(taggencfg-r7, ported from C64MEGA65).gencfg.asmwrites the control and status register through R7, but V2.0.1 never loads R7 first, so those writes land wherever R7 happens to point and the core may never leave reset. This copy loadsM2M$CSRinto R7. -
HyperRAM placement. The board constraint files
M2M/MEGA65-R<n>.xdccontain a pblock that keeps the HyperRAM controller next to its I/O pins. This keeps its receive path close to the input registers, so that it reliably meets the 2 ns maximum-delay constraints ofcommon.xdc. -
A routine borrowed from the M2M V2.1.0 development line, kept in AExp's firmware rather than in
M2M/.m2m-rom.asmcarries a copy ofM2M$LOAD_POLYPHASEfrom that line (C64MEGA65's copy of the framework,M2M/rom/tools.asmthere), which V2.0.1 lacks; it loads the coefficients of the HDMI scaling filters. Delete this copy when AExp moves to M2M V2.1.0; the assembler then reports the duplicate label.
9. The Minimig submodule¶
CORE/Minimig_MiSTerMEGA65 is AExp's fork of the MiSTer Minimig-AGA core
(sy2002/Minimig_MiSTerMEGA65 on GitHub). It has three branches:
MiSTermirrors the upstream MiSTer core unchanged. Upstream changes enter here first.developcarries all MEGA65 changes and is the branch AExp tracks.masteris the released state: it equalsdevelopat each AExp release.
The fork keeps its changes small and traceable. Every change to an original
file has a dated provenance comment of the form
// MiSTer2MEGA65 (AExp Amiga 500 port), <month> <year>: ..., and the
original code stays next to it as a comment. The submodule's README.md
summarises the modifications. In short:
- Vivado compatibility: Altera memories replaced by inferred block RAM templates, and a sweep over constructs that Quartus accepts and Vivado does not (multiply driven registers, SystemVerilog array syntax and similar).
rtl/minimig_m65.v, a new wrapper that renamesminimig.v's underscore-prefixed ports (illegal in VHDL) and ties off the unused subsystems.- MEGA65 integration: keyboard with a real CIA handshake, mouse, real-time clock, the floppy host channel.
- The Hardware Floppy in
paula_floppy.v(threaded throughpaula.v,minimig.vandminimig_m65.v): per-unit substitution of the real drive's status lines, the index pulse into CIA-B, a synthesized ready signal, and a faithfulDSKBYTRregister ($DFF01A), which Rob Northen Copylock needs to time the disk. With the Hardware Floppy switched off, the controller behaves exactly like the upstream one. - Four upstream fixes that MiSTer made after AExp forked, backported in
WIP-V2-B1: the CIA timers'CNTinput (MiSTer PR 230,cia_timera.v,cia_timerb.v,ciaa.v,ciab.v), the blitter freeze when fill mode is switched off mid-blit (PR 236,agnus_blitter.v), the exactVHPOSRreadback (PR 234,agnus_beamcounter.v), and the field flag that is only set while interlace is on (commitd16cd84,agnus_beamcounter.v).VERSIONS.mddescribes their effect.
Changes to the submodule are committed in the submodule on develop first;
the main repository then records the new submodule commit.
10. The MiSTer HPS code and its replacements¶
On MiSTer, Minimig is only half of the machine. The other half is software on
the ARM processor (the HPS): the support/minimig/ folder of
Main_MiSTer configures the
core, uploads the Kickstart ROM and serves the floppy disk images over the
host channel, and generic parts of Main_MiSTer translate USB keyboards into
Amiga keycodes and send the real-time clock. The MEGA65 has no such processor.
The QNICE CPU runs the menu and the SD card, but it is neither fast enough nor
close enough to serve Paula's floppy channel word by word. So every HPS
function AExp needs became hardware in the core or moved into the QNICE
firmware:
Main_MiSTer support/minimig/ |
Role on MiSTer | In AExp |
|---|---|---|
minimig_fdd.cpp |
The floppy service HandleFDD: MFM-encodes sectors of the .adf file for Paula's reads, decodes Paula's writes back into the file. |
Ported to hardware as adf_track_engine.vhd. Reference copy: minimig_fdd.cpp. What AExp changed and added is listed in floppy-adf.md. |
minimig_config.cpp |
The configuration menu and its presets, ApplyConfiguration (sends the userio commands 0xF1..0xF9), the Kickstart upload into Minimig's memory. |
ApplyConfiguration is the model for amiga_config.vhd, which sends the same commands with fixed A500 values after every reset. Reference copy: minimig_config.cpp. The menu is the M2M menu in config.vhd; the Kickstart upload is replaced by the M2M Shell's ROM loader, which writes the file straight into the Kickstart BRAM (device 0x0100). |
minimig_boot.cpp |
Draws Minimig's boot screen into Chip RAM. | Not used: the core boots straight into Kickstart. |
minimig_share.cpp |
Shared folder between Linux and AmigaOS. | Not used. |
Outside support/minimig/, keyboard.vhd takes the place of MiSTer's USB
keyboard translation (AExp's mapping of the MEGA65 keyboard is its own).
MiSTer's USB mouse path has no counterpart: a real Amiga mouse in the DB9 port
is read directly (section 11). The framework hands
the MEGA65's battery-backed clock to Minimig at reset, and the firmware's
RTC_STEP reseeds it once per minute, the same cadence the HPS uses.
Both reference copies are stored verbatim from Main_MiSTer commit
c738023
("Release 20260603", 3 June 2026). That is the MiSTer release that goes with
the Minimig release AExp forked from, and neither file changed upstream while
the AExp blocks were written. The last commits that changed them before that
point are aebed6b (minimig_fdd.cpp, 2021) and 61611e0 (minimig_config.cpp,
2023). The line numbers quoted in the comments of adf_track_engine.vhd
refer to this copy. Main_MiSTer is licensed under the GPL v3, like AExp;
minimig_fdd.cpp carries its own GPL v3 (or later) header from the original
Minimig authors, and minimig_config.cpp has no header and falls under the
repository license.
Upstream has changed both files since, in September 2026: external floppy drives, SCP and IPF flux images, clock bits in the MFM encoder, a zero-drive setting, and new CD32, CDTV and Ethernet configuration. None of this is reconciled with AExp. Compare against the reference copies first when you look at upstream changes, so that you see only what changed after the port.
11. Mouse and joystick¶
The MEGA65's two DB9 ports are wired like the Amiga's, so a real Amiga mouse or joystick plugs straight in, and Minimig reads the pins the way Denise, Paula and CIA-A read them in an A500. A joystick needs nothing beyond that. A mouse needs two things that are easy to break: every edge of its movement signals has to reach Minimig, and its right and middle buttons sit on lines that the MEGA65 can only partly read.
| DB9 pin | Mouse signal | The Amiga reads it through | Framework signal |
|---|---|---|---|
| 1, 3 | vertical quadrature pair | the JOY0DAT/JOY1DAT counters |
joystick up, left |
| 2, 4 | horizontal quadrature pair | the same counters | joystick down, right |
| 6 | left button | CIA-A port A (/FIR0, /FIR1) |
joystick fire |
| 9 | right button | POTINP bit 10 (DATLY) |
pot1_x (POTX) |
| 5 | middle button | POTINP bit 8 (DATLX) |
pot1_y (POTY) |
The POTINP bits are those of port 1 (the port the Hardware Reference Manual
numbers 0: JOY0DAT and the L bits of POTINP). Pins 9 and 5 carry a naming
trap: the
Amiga reads pin 9 through the channel it calls Y, while the MEGA65 schematics
and the framework follow the C64 and call the same pin X. Both are right in
their own world; on the core side, the right button is pot1_x_i.
userio.v swaps the two ports unless its joy_swap bit is set, and
amiga_config.vhd sets it (command 0xF9, payload 0x0008). MEGA65 port 1
is therefore Amiga port 1, the mouse port, and port 2 the joystick port, as on
an A500.
11.1 Movement¶
There is no dedicated mouse decoder. Minimig's userio.v keeps the counters
of the original Minimig that are fed from the joystick pins (dmouse0dat,
dmouse1dat, called "docking" counters in its comments), which count the
transitions of the two quadrature pairs into JOYxDAT, exactly like Denise. A
counter only notices a transition that is still there at its next sample, so
the whole path from the pin to the counter has to pass every edge:
- The framework's
debouncer.vhdis reduced to plain two-flop synchronizers (section 8.6). A 1 ms stable-time filter swallows the pulse trains of a moving mouse, and the pointer freezes and then jumps. - The input synchronizer of
userio.v(_sjoy/_djoy) shifts onclk7_en, the rate at which the counters sample. Shifted at the full 28 MHz, as in the upstream code, a transition would show as a difference between_sjoyand_djoyfor a single clock only, and the counters, which look once every four clocks, would catch about one transition in four; the pointer would crawl at a quarter of its speed and jitter. MiSTer never shows this, because there these inputs come from gamepad states that the HPS latches.
A joystick takes the same path and needs nothing else: its directions and its fire button are slow levels.
11.2 The right and middle buttons¶
On a real Amiga, the right and middle buttons are passive switches from pins 9
and 5 to ground; the mouse has no pull-up. Paula provides the high level:
input.device writes $FF00 to POTGO, which drives all four POT pins high,
and then reads POTINP, where a pressed button reads 0. Minimig models this at
register level: userio.v builds the POTINP bits from its mouse_btn input
and the POTGO state, so the simulated Amiga always sees a clean register,
and the physical side ends at main.vhd.
The MEGA65 cannot drive those pins. On every board from R3 to R6, each POT pin goes through 1 kΩ to a 1.2 nF capacitor with a discharge transistor and then through an always-enabled buffer into the FPGA; this is the C64 paddle circuit. There is no pull-up, and the FPGA can neither drive the pin nor reach it with an internal pull-up. The bidirectional joystick lines of R4 and later cover only the five digital pins (AExp keeps their outputs released). A passive button that grounds pin 9 therefore looks exactly like an open pin: the right and middle buttons of a real Amiga mouse are invisible, and no FPGA design can change that.
What the MEGA65 can read is a device that drives the pin itself. The
framework's paddle sampler (mouse_input.vhdl, instantiated in
qnice_wrapper.vhd) discharges the capacitor for 256 µs and then counts, at
1 MHz and up to 255, how long the pin stays low; one cycle takes about
514 µs. The framework hands 255 minus that count to the core clock domain, so
an open or grounded pin reads 0x00 and a pin driven high reads close to
0xFF. The pot_buttons process in main.vhd takes bit 7 of pot1_x_i and
pot1_y_i with the Amiga's polarity, low means pressed, and guards it twice:
- A presence latch (
rmb_capable,mmb_capable): a button is only read once its line has been seen high. An empty port and a passive mouse both read low and would otherwise hold the button down forever. On an Amiga, Paula's drive rules this case out; here the latch has to. - A watchdog: after 30 seconds of uninterrupted "pressed"
(
C_POT_BTN_TIMEOUT), the latch clears, because that is what the floating line of an unplugged adapter looks like. A genuine hold of more than 30 seconds is released once. The latch arms again within one sampler cycle, about half a millisecond, as soon as the line is driven high again.
Both latches and watchdogs clear with the Amiga reset. The result enters
Minimig as mouse_btn <= pot_mmb & (kbd_mouse_rmb or pot_rmb) & '0', active
high in the order middle, right, left. The left button stays '0' here
because it reaches CIA-A through the fire line.
kbd_mouse_rmb is the keyboard substitute for the right button, mouse_rmb_o
of keyboard.vhd: RUN/STOP (matrix key 63) in MEGA65 keyboard mode, and the
up-arrow symbol key left of RESTORE (key 54) in Amiga mode, where RUN/STOP is
Esc. Neither key sends an Amiga keycode in the mode in which it is the
substitute, so the substitute never disturbs the key stream, and a reset
releases it. The middle button has no
substitute.
11.3 What works¶
| Device | Movement and left button | Right and middle button |
|---|---|---|
| Amiga mouse | works | invisible; use the keyboard substitute |
| Passive mouse behind a pull-up adapter (2 kΩ from pin 7 to pins 9 and 5, see Mouse and joystick in the README) | works | works |
| Adapter that drives the lines push-pull, high when released and low when pressed | works | works |
| Adapter that only grounds the lines | works | invisible; use the keyboard substitute |
| mouSTer in Amiga mouse mode, default settings | works | invisible; use the keyboard substitute |
mouSTer firmware 3.23.5313 or newer with activepotlines=true in [mouse] |
works | right button works |
| Commodore 1350 or 1351 | not supported | the 1351's changing POT value can cause phantom right clicks |
The buttons on the POT lines are read on port 1 only, because userio.v feeds
mouse_btn into the port-1 bits of POTINP; a mouse in port 2 moves and
clicks left, but nothing more. Passive Amiga mice have been tested on R3
(movement, left button, keyboard substitute, no phantom clicks) and a
push-pull USB adapter on R6 (right button). The middle button has not been
tried with a real three-button device.
12. Checking your work before a Vivado run¶
A synthesis takes long, so the project relies on a few local checks first. The tools are free: nvc for VHDL, GHDL as a second opinion, and Icarus Verilog for the Minimig sources.
- Analyse and elaborate the VHDL with
nvc --std=2008, in dependency order (the M2M packages first).clk.vhdandmega65.vhdneed small stub packages for the Xilinxunisimandxpmlibraries.CORE/sim/run_nvc_chain.shdoes both, with the stubs inCORE/sim/stubs/. - Check the Verilog with
iverilog -g2012 -t null, with stubs fordpramandfx68k. - After any menu change, run the menu checker
tools/check_osm_menu.py. It recomputesOPTM_SIZE, the submenu structure, the dependency rules, the visible menu height, the heap demand and the help page geometry fromconfig.vhd, and checks everyC_MENU_*constant against the text of the line it points to. - After any firmware change, run the firmware checker
tools/check_firmware.py. It checks the per-drive tables against the drive count, and it checks everyADDCandSUBCfor a carry that comes from the right instruction. On QNICE onlyADD,ADDC,SUB,SUBC,SHLandSHRwrite the carry flag, and an address calculation inserted between a 32-bitADDand itsADDCsilently eats the carry. - Assemble the firmware with a native build of the QNICE assembler to catch
syntax errors. Run
make_rom.shitself only where the QNICE tool chain was built for the operating system you are on.
The testbenches live in CORE/sim/, one directory per area.
CORE/sim/run_all.sh runs the two checkers, the nvc chain and every bench
that finishes in minutes, and is the gate before a synthesis.
Tools and testbenches describes each tool and bench, what it
verifies, how to run it and how long it takes. What the floppy benches
prove is described in
hardware-floppy.md.
In the Vivado log, check that the 68000's microrom.mem and nanorom.mem were
read successfully: a failure there is silent and produces a dead CPU.
13. Where to read next¶
- developers.md: building the core from source.
- floppy-adf.md: the simulated floppy drives, from the Amiga disk format to the write-back invariants.
- hardware-floppy.md: the MEGA65's internal drive as a real Amiga drive.
minimig_fdd.cppandminimig_config.cpp: MiSTer's floppy service and configuration code, the software models ofadf_track_engine.vhdandamiga_config.vhd.timing_closure.md: the HyperRAM hold miss and the build re-roll.- audio.md: the audio path and its filters.
hdmi_latency.md: HDMI latency and the flicker-free mode.- The M2M Wiki: the framework itself, and the QNICE debug console.
- The C64MEGA65 core: the reference M2M port, and the origin of several patterns used here (mount devices, physical drive, menu dependencies).