MZPico is a modern replacement firmware and hardware platform for the Sharp MZ-800, powered by a Raspberry Pi Pico.
This repository contains the firmware that controls the system.
| Board | Status | Notes |
|---|---|---|
| Frugal Board | ✅ Supported | Minimal build with optional MicroSD slot, limited to 8-bit address bus ![]() |
| Deluxe Board | ✅ Supported | Fits MZ-800 upper slot rails, adds level shifters, I2S sound card, Pico access for optional wireless connection ![]() |
-
Flexible file storage options
Supports internal flash memory and optional MicroSD cards. -
Native program execution
Directly loads and runs:.MZF(MZ program files).DSK(Floppy images).MZQ(Quick Disk images)
-
Storage device emulation
Emulates multiple virtual devices:- Floppy disk controller
- Quick disk
- RAM disks (SRAM boot disk, paged RAM disk, PicoRD)
-
Sound emulation over I2S (Deluxe board)
Both MZ-800 sound sources are rendered to the on-board I2S sound card:- SN76489 PSG — 3 tone channels + noise, stereo panning
- 8253 beeper — monitor beeps, MZ-700 melody and S-BASIC
MUSIC, and 1-bit "beeper engine" music in games; both the I/O-mapped and the memory-mapped 8253 access paths are captured
-
User-friendly navigation interface
-
Fast system boot via SRAM emulation Allows instant startup on the MZ-800:
- Boot via port
0xF8on cold start or reset - Startup via port
0xF8or0xA8using theEBcommand at the monitor prompt
- Boot via port
-
Highly configurable
- Simple INI-style configuration file
- Separate configuration section for each device type
- Define custom base I/O ports per device
- Supports multiple instances of the same device (e.g., multiple floppy controllers on different ports)
- Any device can be enabled/disabled individually
→ Supports very flexible hardware configurations and avoids conflicts with other expansions
-
Modular firmware architecture Written in modern C++ and structured to make adding new devices and features easy.
-
Easy firmware update
- Uses Pico USB mass-storage upload (no special programmer required)
- Flash and MicroSD contents remain untouched when updating firmware
-
WiFi and cloud storage support (Requires Raspberry Pi Pico W)
- Connect to WiFi networks
- Browse and load files from cloud storage
- Access cloud files as a virtual device
cloud:/ - Simple WiFi credential configuration via INI file
-
Download the latest release from the
👉 Releases page -
Choose the correct firmware file:
| Board Type | Pico Model | Flash Size | Firmware File |
|---|---|---|---|
| Frugal Board | Pico | 2MB | mzpico_frugal_2m.uf2 |
| Frugal Board | Pico W (WiFi) | 2MB | mzpico_frugal_2m_w.uf2 |
| Frugal Board | Purple Pico clone | 16MB | mzpico_frugal_16m.uf2 |
| Deluxe Board | Pico | 2MB | mzpico_deluxe_2m.uf2 |
| Deluxe Board | Pico W (WiFi) | 2MB | mzpico_deluxe_2m_w.uf2 |
💡 Note: Use the
*_w.uf2variants when using a Raspberry Pi Pico W to enable WiFi and cloud features.
- Hold BOOTSEL on the Pico and connect to USB.
- Copy the
.uf2file to the Pico drive. - Upload your Sharp MZ-800 software to the MZPico card using USB mass storage.
- Insert the card to a Sharp MZ-800 slot, switch it on - done!
MZPico uses a simple INI-style configuration file (mzpico.ini). At boot it is looked up on the SD card first (sd:/mzpico.ini), then on internal flash (flash:/mzpico.ini). Keep a copy on the SD card — it lets the machine boot even if the flash volume ever fails to mount.
This file defines which virtual devices are enabled, their I/O base ports, and which storage images they use. Formatting the internal flash (with the mzpico_format UF2, or automatically on first USB use of a blank flash) writes a commented default mzpico.ini with every device section present and the most common options shown commented out — this README is the full option reference.
- If a section exists in the file, the device is enabled
(unless the section containsenabled=false) - Multiple instances of the same device type are allowed
Example:[fdc1],[fdc2],[qd1],[qd2], etc.
(The instance name is the device type plus trailing digits — the type itself never ends in a digit.) - Each instance must use a unique not overlapping ports using
base_port - Instead of
base_port, explicitread_ports=/write_ports=lists may be given (comma-separated, decimal or0xhex). The list lengths must match the device's port count exactly, or boot halts - Built-in images can be referenced using
@name
| Device | Default base_port |
|---|---|
sramdisk |
0xf8 |
qd (QuickDisk) |
0xf4 |
fdc (Floppy Disk Controller) |
0xd8 |
pico_rd (MZPico-type PicoRD RAM-disk) |
0x45 |
pico_mgr (MZPico management/control device) |
0x40 |
psg (SN76489 PSG) |
0xf2 |
ramdisk (paged RAM disk) |
0xe9 (reset port fixed at 0xf8) |
ctc (8253 beeper) |
fixed system ports (base_port not applicable) |
Default enabled=true for all devices.
| Device | Frugal | Deluxe |
|---|---|---|
sramdisk, qd, fdc, pico_rd, pico_mgr |
✓ | ✓ |
ramdisk, psg, ctc |
— | ✓ |
psg and ctc need the Deluxe board's I2S sound output (ctc additionally its memory-write snooping). ramdisk needs the Deluxe bus capture for its 16-bit random-access positioning — what real MZ-1R18 software uses — so it is Deluxe-only (use pico_rd for a RAM disk on Frugal).
A configured device that the board cannot support is skipped at boot: the machine boots normally and the device is simply absent (missing from the explorer's device list) — the same behavior as when a device's buffers do not fit in RAM (see RAM budget). The same mzpico.ini can therefore be shared between boards.
| Built-in image | Description |
|---|---|
@basic |
Sharp MZ-800 BASIC with QD and PicoRD support |
@menu |
MZPico boot menu |
@explorer |
MZPico file explorer |
Images can also point to:
flash:/filename.extsd:/filename.ext
Supported extensions: .MZF, .DSK, .MZQ
The [menu] section configures quick-access programs on the boot menu.
Format:
key_<letter>=<display text>|<image or file to execute>
Example:
[menu]
key_b=Basic|@basic
key_e=Explorer|@explorer
key_y=Flappy|flash:/flappy.mzf
key_p=CP/M|flash:/cpm.dskQuick disk emulation can use either a MZQ image file or a directory. MZF files inside the directory (other files are ignored) are then served as the content of the emulated Quick Disk. The order of files in the Quick Disk is the same as their order in the MZPico device filesystem.
Directory-backed Quick Disks are fully writable: saving from the MZ-800
creates a real .mzf file in the directory (the filename is taken from the
saved Sharp file name, converted to ASCII; saving an existing name
overwrites that file), and formatting the Quick Disk deletes all MZF files
in the directory. An MZQ image is written in place. Either mount type
becomes read-only when write_protected is set; an MZQ image is also
protected by its FAT read-only attribute.
Options:
image— MZQ file or directorywrite_protected—true/false(defaultfalse)
Example:
[qd]
image=sd:/qddirThe [fdc] section emulates the MZ-800 floppy disk controller with up to 4 drives. Each drive is assigned a .DSK image:
[fdc]
image_disk1=flash:/cpm.dsk
image_disk2=sd:/games.dsk
write_protected=false ; default for all drives
write_protected1=true ; per-drive override (1..4, matches image_disk1..4)Sector reads and writes, multi-sector transfers, track formatting
(WRITE TRACK) and the READ TRACK verify pass are supported; formatting
rebuilds the DSK image in place and can create a fresh disk from an
empty image file.
A write-protected drive rejects write commands and reports the WD1793
write-protect status bit to the host, like a disk with the notch covered.
write_protected sets the default for all four drives and
write_protected<N> overrides it per drive. A drive also becomes
write-protected automatically when its image file has the FAT read-only
attribute set or sits on a write-protected medium.
A drive can also point at a directory instead of a DSK image. The directory is presented to the MZ-800 as a synthesized floppy in one of two on-disk formats:
basic— a Sharp Disk BASIC (MZ-2Z046) disk, 320 KB. The.mzffiles in the directory appear as its files (up to 63).cpm— an LEC CP/M 2.2 SD data disk, 720 KB. All files in the directory appear under 8.3 names (up to 128 directory entries).
[fdc]
image_disk2=sd:/floppy/basic ; a directory mounts as a disk
fs_disk2=basic ; or cpm; omit to auto-detectfs_disk<N> selects the filesystem; without it, a directory containing
.mzf files mounts as basic, anything else as cpm. One directory can
be mounted on one drive at a time.
Directory mounts are fully writable: files saved by BASIC or copied under CP/M appear as real files in the directory moments after the guest updates the disk's directory, deletes and renames are mirrored, and formatting the disk deletes all served files (like directory-backed Quick Disks). The disk advertises only as much free space as the backing medium really has, and a write that cannot be stored physically reports a disk error to the guest instead of pretending success.
Limitations: directory-mounted disks are not bootable (boot the system
from a DSK image or another device and use the dir mount as a data disk);
BASIC BRD random-access files are not supported; CP/M file sizes round up
to 128-byte records; long or exotic filenames are shortened for CP/M.
Writable directory mounts work best on sd:/ — flash makes every save
pay the flash filesystem's sync cost.
- Any device can be disabled using
enabled=false - Configuring multiple devices is supported, as long as each has non-conflicting ports
- If a section does not exist in the
.inifile, it will be disabled - Keep a copy of
mzpico.inion the SD card: if the internal flash ever fails to mount, an SD-based config lets the MZPico boot with flash unavailable instead of halting - The MZ-800 reset button performs a fast in-place reset: the WiFi
connection survives and images mounted from the explorer are unmounted
(images configured in
mzpico.inistay). Press reset twice within a few seconds to force a full MZPico restart instead - The internal
flash:storage is best for images that change rarely. Bulk-write workloads (e.g. formatting a floppy image) are inherently several times slower onflash:than onsd:— prefer the SD card for working disks - The internal flash filesystem is protected against power loss during
writes (double-buffered metadata). Volumes created by older firmware
keep working but lack this protection; back up the files and reformat
(e.g. with the
mzpico_formatUF2) to upgrade. A damaged flash volume is never reformatted automatically — over USB it shows as "no medium"
The Programmable Sound Generator (PSG) emulates the Texas Instruments SN76489 used in Sharp MZ-800. It provides 3 tone channels and 1 noise channel, mixed to stereo with per-channel panning. Deluxe board only (needs the I2S sound output) — on Frugal the section is skipped at boot.
Config section name: [psg]
Defaults:
base_port=0xf2enabled=truetone0_pan=20tone1_pan=80tone2_pan=40noise_pan=60volume=20
Panning keys (0–100):
tone0_pan— left/right balance for tone channel 0tone1_pan— left/right balance for tone channel 1tone2_pan— left/right balance for tone channel 2noise_pan— left/right balance for noise channel
Master volume
volume- volume level, 0-100
Example:
[psg]
base_port=0xf2
enabled=true
tone0_pan=0
tone1_pan=100
tone2_pan=0
noise_pan=100
volume=60Emulates the MZ-800 built-in beeper — the 8253 counter 0 with its gate latch and the 8255 audio mask — rendered to the I2S output. Deluxe board only — on Frugal the section is skipped at boot. Both hardware access paths are captured:
- the I/O-mapped ports used in MZ-800 mode (
0xd0–0xd7) - the memory-mapped window at
0xE004–0xE008, used by MZ-700-mode software and many games (captured by snooping memory writes on the bus, with bank-switch tracking so RAM banked over the window never produces sound)
This covers monitor beeps, S-BASIC MUSIC, MZ-700 melody, chip-music engines, and 1-bit "beeper engine" sound in games (e.g. ZX Spectrum ports), reproduced with microsecond event timing.
Config section name: [ctc]
Defaults:
enabled=truevolume=20(matches the PSG default, so both sources are balanced)pan=50
Ports are fixed system addresses; base_port does not apply.
Example:
[ctc]
volume=20
pan=50💡 Note: the power-on beep right after reset plays before MZPico's audio pipeline has started; it is heard only from the machine's internal speaker.
The [ramdisk] section emulates a paged RAM disk: 64 KB pages selected via the page register, byte access with auto-increment, and full 16-bit intra-page addressing on writes. Backed by Pico RAM, or by a file for persistent content. Deluxe board only (the 16-bit positioning that real MZ-1R18 software uses needs the Deluxe bus capture) — on Frugal the section is skipped at boot; use pico_rd for a RAM disk there.
Config section name: [ramdisk]
Options:
base_port— default0xe9(the reset port stays fixed at0xf8)size— capacity in bytes, rounded up to 64 KB multiples; default65536(one page). Use131072or more to enable page switching — with a single page, page selects wrap back to page 0.image— optional backing file; omitted = volatile RAMread_only—true/false(defaultfalse)
Example:
[ramdisk]
size=131072The [sramdisk] section emulates the SRAM boot card used for instant startup (see Fast system boot). It serves an .MZF program in the SRAM card boot format.
Config section name: [sramdisk]
Options:
image—.MZFfile or built-in image; default@menuallow_boot— answer the boot probe (defaulttrue)read_only— defaulttruein_ram— copy the image to RAM for writability (defaultfalse)size— override size in bytes
Example:
[sramdisk]
image=@menuThe [pico_rd] section provides MZPico's own PicoRD-type RAM disk (default base_port=0x45).
Why it exists when there is already an MZ-1R18-style [ramdisk]: PicoRD's simple port protocol needs no 16-bit bus capture, so it is fully functional on every board — including Frugal, where the MZ-1R18 emulation is limited to sequential access. The bundled @basic ships with a PicoRD driver, so the disk is usable from BASIC out of the box on any MZPico. Backed by Pico RAM, or by an image file for persistent content — file-backed it costs almost no RAM, which is why the default configuration ships it as image=flash:/pico_rd.img.
Config section name: [pico_rd]
Options:
image— optional backing file; omitted = volatile RAMsize— capacity in bytes; default65536when RAM-backedread_only—true/false(defaultfalse)
Example:
[pico_rd]
image=flash:/pico_rd.imgThe [pico_mgr] section provides MZPico's management/control interface (default base_port=0x40). The boot menu and the file explorer communicate with the firmware through it — without this section they cannot start. It has no options of its own, but note its fixed RAM cost (see RAM budget).
MZPico supports WiFi connectivity and cloud file storage when using a Raspberry Pi Pico W board.
- Raspberry Pi Pico W (the wireless variant with built-in WiFi)
- WiFi network with internet access
- Valid WiFi credentials
Add a [cloud] section to your mzpico.ini configuration file with your WiFi credentials:
[cloud]
wifi_ssid=YourWiFiNetworkName
wifi_password=YourWiFiPassword- Configure WiFi credentials in
mzpico.inias shown above - Power on your MZ-800 with the MZPico board
- MZPico will automatically connect to WiFi on startup
- A new storage device
cloud:/becomes available - Use the file explorer or load programs directly from
cloud:/
- Browse cloud-hosted MZ-800 software collection
- Load
.MZFfiles directly from the cloud - No local storage required for cloud files
- Automatic connection on startup
Every device and every option. The file below is a working configuration
as-is; lines starting with ; are optional settings shown with their
defaults or with example values.
[menu]
key_b=Basic|@basic
key_e=Explorer|@explorer
key_y=Flappy|flash:/flappy.mzf
key_p=CP/M|sd:/cpm_boot.dsk
; SRAM boot card - serves the boot menu by default
[sramdisk]
image=@menu
;allow_boot=true ; answer the boot probe
;read_only=true
;in_ram=false ; copy the image to RAM (writable, costs its size)
;size=32768 ; size override in bytes
; PicoRD RAM disk - the bundled @basic has a PicoRD driver; works on all boards
[pico_rd]
image=flash:/pico_rd.img ; file-backed: persistent, costs almost no RAM
size=65536
;read_only=false
; Management device - required by the menu and explorer
[pico_mgr]
;base_port=0x40
; Floppy controller: 4 drives, DSK images and directory mounts mix freely
[fdc]
image_disk1=sd:/cpm_boot.dsk ; bootable extended-DSK image
image_disk2=sd:/cpm_files ; directory served as a LEC CP/M data disk
fs_disk2=cpm
image_disk3=sd:/basic_files ; directory served as a Disk BASIC disk
fs_disk3=basic ; omit fs_disk to auto-detect (.mzf inside -> basic)
;image_disk4=sd:/games.dsk
;write_protected=false ; default for all four drives
;write_protected1=true ; per-drive override (1..4)
;base_port=0xd8
; Quick Disk: a .mzq image or a directory of .mzf files
[qd]
image=sd:/qd_files
;write_protected=false
;base_port=0xf4
; ---- Sound: Deluxe board only (sections are skipped on Frugal) ----
[psg]
;volume=20
;tone0_pan=20 ; stereo position 0-100 per channel
;tone1_pan=80
;tone2_pan=40
;noise_pan=60
;base_port=0xf2
[ctc]
;volume=20
;pan=50
; (fixed machine addresses; base_port does not apply)
; ---- Optional devices (not part of the default set) ----
; MZ-1R18-style paged RAM disk (Deluxe board only - skipped on Frugal);
; a RAM-backed size must fit the RAM budget (see below)
;[ramdisk]
;image=sd:/ramdisk.img
;size=131072
;read_only=false
;base_port=0xe9 ; the reset port stays fixed at 0xf8
; WiFi + cloud:/ storage (Pico W builds only)
[cloud]
wifi_ssid=MyWiFiNetwork
wifi_password=MyPasswordAny device section additionally accepts enabled=false (keep the
section, disable the device) and explicit read_ports=/write_ports=
lists instead of base_port (advanced; the list lengths must match the
device's port count exactly).
The Pico's RAM is shared between the firmware and the buffers of the configured devices, and RAM-backed device images are the dominant consumers. The 16 MB flash build and the Pico W WiFi stack each claim a substantial extra share of RAM, leaving less room for devices.
What costs RAM: pico_mgr needs a large fixed transfer buffer (and is
always required by the menu/explorer); pico_rd without an image file
and [ramdisk] allocate their entire size in RAM (ramdisk page
switching needs at least two pages); sramdisk costs almost nothing
unless in_ram=true; the sound devices are cheap but not free (ctc
≈ 7 KB, psg ≈ 1 KB). File-backed images (image=...) cost almost no
RAM regardless of their size — this is why the default mzpico.ini
ships pico_rd file-backed (image=flash:/pico_rd.img): a RAM-backed
64 KB pico_rd plus the full default device set does not fit the Pico W
builds' heap, and the device that then fails to allocate can be
pico_mgr itself, which presents as a dead menu.
If a device's buffers do not fit, boot continues without that device
— it will simply be missing from the explorer's device list. Free RAM by
preferring file-backed images or smaller size values; large RAM-backed
configurations fit best on the 2 MB non-WiFi builds.
Make sure the following tools are installed on your system:
build-essential(or equivalent compiler tools on your platform)cmake- ARM GCC toolchain (
gcc-arm-none-eabi) z88dk(used to build the initial MZ-800 SRAM bootstrap code)
⚠️ Pin your z88dk version. The z88dk snap tracks the auto-updatinglatest/edgechannel, and library behavior (e.g. keyboard mappings) changes between versions. Hold it withsudo snap refresh z88dk --hold. Note also that the embedded menu/explorer only rebuild when their sources change — after a z88dk update, use a fresh build directory to make sure the Z80-side binaries are rebuilt.
💡 Tip: On Linux these packages are typically available via the system package manager.
On Windows, install using MSYS2, WSL, or the Arm GNU Toolchain installer.
git clone --recurse-submodules https://github.com/MZPico/MZPico-firmware.git
cd MZPico-firmwareTwo CMake options must be specified:
| Option | Values | Description |
|---|---|---|
FLASH_SIZE |
2M or 16M |
Selects correct firmware for Pico flash size |
BOARD |
FRUGAL or DELUXE |
Selects board wiring, available devices, and configuration |
mkdir build && cd build
cmake .. -DFLASH_SIZE=16M -DBOARD=FRUGAL
makemkdir build && cd build
cmake .. -DFLASH_SIZE=2M -DBOARD=DELUXE
makeAfter build completion, the generated .uf2 firmware file will appear in the build directory.
- Only extended-CPC-style
.DSKfloppy images are supported; the standard (non-extended) DSK variant is not. Copy-protected disks relying on low-level quirks (deleted data marks, index timing) are not modeled. - The explorer mounts DSK images into drive 1 only, and cannot mount directories (use
mzpico.inifor those). - Directory-mounted floppies are not bootable, and BASIC BRD random-access files are not supported on them.
- Sound emulation (PSG + 8253 beeper) requires the Deluxe board's I2S sound card.
- The power-on beep right after reset is heard only from the machine's internal speaker (it plays before MZPico's audio pipeline has started).
The firmware uses code, libraries, or ideas from these excellent projects:
- A8PicoCart https://github.com/robinhedwards/A8PicoCart
- Sharp MZ-800 Emulator by Chaky https://sourceforge.net/projects/mz800emu/
- Sharp MZ-800 Unicard https://sourceforge.net/projects/unicardmk3/
- Atari ST SidecarTridge https://github.com/sidecartridge/atarist-sidecart-raspberry-pico
- no-OS-FatFS-SD-SDIO-SPI-RPi-Pico https://github.com/carlk3/no-OS-FatFS-SD-SDIO-SPI-RPi-Pico
- Iniparser https://gitlab.com/iniparser/iniparser
- Raspberry Pico SDK https://github.com/raspberrypi/pico-sdk




