A Z80-based MP/M II emulator with SSH terminal access. Multiple users can connect simultaneously to run CP/M-compatible software.
MP/M II Command Reference - Complete guide to all commands and utilities
# Build with DRI binaries (default, fast)
./scripts/build_all.sh
# Or build from source (requires uplm80/um80/ul80)
./scripts/build_all.sh --tree=src
# Run with local console
./build/mpm2_emu -l -d A:disks/mpm2_system.img
# Or run with SSH access (connect from another terminal)
./build/mpm2_emu -d A:disks/mpm2_system.img
ssh -p 2222 user@localhostPre-built packages are available for Linux systems. Download the appropriate package and disk image from the Releases page.
# Download and install
wget https://github.com/avwohl/mpm2/releases/latest/download/mpm2-emu_0.3.0_amd64.deb
sudo dpkg -i mpm2-emu_0.3.0_amd64.deb
sudo apt-get install -f # Install dependencies if needed
# Download disk image
wget https://github.com/avwohl/mpm2/releases/latest/download/mpm2_system.img
# Run
mpm2_emu -l -d A:mpm2_system.img# Download and install
wget https://github.com/avwohl/mpm2/releases/latest/download/mpm2-emu-0.3.0-1.x86_64.rpm
sudo dnf install ./mpm2-emu-0.3.0-1.x86_64.rpm
# Download disk image
wget https://github.com/avwohl/mpm2/releases/latest/download/mpm2_system.img
# Run
mpm2_emu -l -d A:mpm2_system.img| Package | Contents |
|---|---|
.deb / .rpm |
mpm2_emu emulator binary |
mpm2_system.img |
Pre-built 8MB disk image with MP/M II and utilities |
The disk image is required - it contains the MP/M II operating system, boot loader, and standard utilities.
| Dependency | Purpose | Installation |
|---|---|---|
| CMake 3.16+ | Build system | brew install cmake or apt install cmake |
| C++17 compiler | Compile emulator | Xcode (macOS) or apt install g++ |
| Python 3 | Build scripts, um80/ul80 | Usually pre-installed |
| cpmemu | Z80 CPU emulator + disk tools | Clone from github.com/avwohl/cpmemu |
# Clone these as siblings to mpm2/
cd ~/src # or wherever you keep source
# Z80 CPU emulator (required)
git clone https://github.com/avwohl/cpmemu.git
# um80/ul80 - MACRO-80 compatible assembler/linker (required)
git clone https://github.com/avwohl/um80_and_friends.git
cd um80_and_friends
pip install -e . # Installs um80 and ul80 commands
cd ..
# uplm80 - PL/M-80 cross-compiler (required for --tree=src builds)
git clone https://github.com/avwohl/uplm80.git
cd uplm80
pip install -e . # Installs uplm80 command
cd ..
# MP/M II distribution files are included in the mpm2_external/ directoryFor network access via SSH (recommended for multi-user):
# macOS
brew install libssh
# Linux (Debian/Ubuntu)
sudo apt install libssh-devThe project supports two binary trees:
| Tree | Description | Requirements |
|---|---|---|
dri |
Original DRI binaries (default) | None - binaries included |
src |
Build from source code | uplm80, um80, ul80 |
cd mpm2
# Build with DRI binaries (fast, recommended)
./scripts/build_all.sh
# Build from source (compiles PL/M and assembly)
./scripts/build_all.sh --tree=srcBuild steps:
- [src only] build_src.sh - Compile source code to bin/src/
- build_hd1k.sh - Creates 8MB disk image with binaries from selected tree
- build_asm.sh - Assembles LDRBIOS and BNKXIOS, builds C++ emulator, writes boot sector
- gensys.sh - Runs GENSYS to create MPM.SYS (4 consoles, 7 memory banks)
Output: disks/mpm2_system.img - bootable disk with MP/M II
When using --tree=src, all utilities are compiled from the original Digital Research
source code using modern cross-compilers:
- uplm80 - PL/M-80 to Z80 assembly compiler
- um80 - MACRO-80 compatible assembler
- ul80 - LINK-80 compatible linker
The source build system supports local modifications in src/overrides/ that take
precedence over the original source. For example, the MPMLDR has its serial number
check disabled in src/overrides/MPMLDR/MPMLDR.PLM.
With --tree=src, the entire MP/M II operating system is built from source. Only 4
development tools are binary-only (no source available):
| Binary | Purpose | Note |
|---|---|---|
| RMAC.COM | Relocatable Macro Assembler | Replaced by um80 |
| LINK.COM | Linker | Replaced by ul80 |
| LIB.COM | Library Manager | Not needed for build |
| XREF.COM | Cross Reference | Not needed for build |
These are included on the disk for completeness but are not used in the build process.
To build just the source binaries without creating a disk:
./scripts/build_src.shThe original DRI GENSYS.COM has a bug in its relocation code (LDRLWR.ASM) that corrupts SPR/BRS files when code size doesn't align well with 128-byte sectors. The bug is most severe at exactly 1024 bytes where 100% of relocation uses garbage.
The Bug: LDRLWR.ASM loads ceil(prgsiz/128) sectors, which includes code plus
extra bytes from rounding. It uses these extra bytes as the relocation bitmap. When
more bitmap is needed, it should read from disk - but the detection check compares
the bitmap pointer against an unrelated buffer address (bitmap+128) instead of
checking if it exceeded the loaded data. Result: garbage is used instead of the
actual bitmap.
This project uses a Python replacement (tools/gensys.py) that reads the complete
bitmap directly from the SPR file and applies it correctly:
- Fixes the bitmap relocation bug for all file sizes
- Reads configuration from JSON instead of interactive prompts
- Generates identical MPM.SYS output for valid inputs
- Supports RSP modules with banked code (BRS files)
Generate host key and configure user authentication:
mkdir -p keys
# Generate host key (required for SSH)
ssh-keygen -t rsa -b 2048 -m PEM -f keys/ssh_host_rsa_key -N ''Authentication options:
| Mode | Configuration | Use Case |
|---|---|---|
| Public key | keys/authorized_keys |
Production - add user public keys |
| Open access | --no-auth flag |
Development - accept any connection |
For public key authentication, add authorized public keys:
# Add your key
cat ~/.ssh/id_rsa.pub >> keys/authorized_keys
# Or multiple users
cat user1.pub user2.pub >> keys/authorized_keysFor development/testing without authentication:
./build/mpm2_emu --no-auth -d A:disks/mpm2_system.img./build/mpm2_emu [options] -d A:diskimage
Options:
-d, --disk A:FILE Mount disk image (required)
-l, --local Local console mode (output to stdout)
-w, --http [IP:]PORT HTTP server address (default: 8000, 0 to disable)
Can be repeated for multiple listeners
--log FILE Access log file (default: mpm2.log)
-p, --port [IP:]PORT SSH listen address (default: 2222)
Can be repeated for multiple listeners
Use [IPv6]:PORT for IPv6 addresses
-k, --key FILE Host key file (default: keys/ssh_host_rsa_key)
-a, --authorized-keys FILE Authorized keys file (default: keys/authorized_keys)
-n, --no-auth Disable SSH authentication (accept any connection)
-t, --timeout SECS Timeout for debugging
-h, --help Show helpThe emulator boots from sector 0 of the disk mounted as drive A.
# Local console - see output directly
./build/mpm2_emu -l -d A:disks/mpm2_system.img
# SSH mode - connect via ssh (requires keys/authorized_keys)
./build/mpm2_emu -d A:disks/mpm2_system.img
ssh -p 2222 user@localhost
# SSH mode without authentication (development only)
./build/mpm2_emu --no-auth -d A:disks/mpm2_system.img
# Bind to specific IP address
./build/mpm2_emu -p 127.0.0.1:2222 -w 127.0.0.1:8000 -d A:disks/mpm2_system.img
# Multiple listeners (IPv4 and IPv6)
./build/mpm2_emu -p 127.0.0.1:2222 -p '[::1]:2222' -w 8000 -d A:disks/mpm2_system.imgThe emulator includes an integrated SFTP server for transferring files to and from the MP/M II disk. This allows you to use standard SFTP clients to upload, download, and manage files.
# Connect with sftp (same port as SSH terminal)
sftp -P 2222 user@localhostSFTP paths use the format /<drive>.<user>/<filename>:
| Path | Description |
|---|---|
/A.0/ |
Drive A, user 0 |
/B.3/TEST.COM |
Drive B, user 3, file TEST.COM |
/A.0/*.TXT |
Wildcard pattern for .TXT files |
| Command | Description |
|---|---|
ls /A.0/ |
List directory |
get /A.0/FILE.TXT |
Download file |
put local.txt /A.0/FILE.TXT |
Upload file |
rm /A.0/FILE.TXT |
Delete file |
rename /A.0/OLD.TXT /A.0/NEW.TXT |
Rename file |
sftp -P 2222 user@localhost
sftp> ls /A.0/
/A.0/GENHEX.COM /A.0/LIB.COM /A.0/LINK.COM
sftp> put myfile.txt /A.0/MYFILE.TXT
Uploading myfile.txt to /A.0/MYFILE.TXT
sftp> ls /A.0/MYFILE.TXT
/A.0/MYFILE.TXT
sftp> quitSFTP operations are handled by an RSP (Resident System Process) running inside MP/M II. The C++ emulator receives SFTP protocol messages and forwards them to the Z80 RSP via a bridge interface. The RSP performs actual file operations using BDOS calls, ensuring proper file locking and consistency with MP/M II processes.
Files involved:
asm/sftp_brs.plm- Z80 RSP code (PL/M-80)asm/sftp_glue.asm- Assembly glue for BDOS callssrc/sftp_bridge.cpp- C++ request/reply bridgesrc/ssh_session_libssh.cpp- SFTP protocol handling
The emulator includes a read-only HTTP server for browsing and downloading files from MP/M II disks using a web browser.
Open in any web browser:
http://localhost:8000/
| Path | Description |
|---|---|
/ |
List mounted drives |
/a/ |
Drive A, all users |
/a.0/ |
Drive A, user 0 only |
/a/file.txt |
Download file from drive A |
/a.0/file.txt |
Download file from drive A, user 0 |
- URLs are case-insensitive (
/A/FILE.TXTand/a/file.txtboth work) - Directory listings show filenames in lowercase
- Text files (.txt, .asm, .plm, etc.) are served with Unix line endings (CR stripped)
# Default: HTTP on port 8000
./build/mpm2_emu -d A:disks/mpm2_system.img
# Custom port
./build/mpm2_emu -w 8080 -d A:disks/mpm2_system.img
# Disable HTTP server
./build/mpm2_emu -w 0 -d A:disks/mpm2_system.imgHTTP file operations share the same RSP bridge as SFTP. When an HTTP request arrives, it queues a file request to the Z80 RSP, which performs the actual disk read via BDOS calls. Requests from HTTP and SFTP clients are serialized to ensure consistent access.
The emulator logs HTTP, SSH, and SFTP access to a file (default: mpm2.log):
2026-01-06 23:21:19 [HTTP] 127.0.0.1 GET /
2026-01-06 23:21:26 [SSH] 127.0.0.1 connected
2026-01-06 23:21:26 [SSH] 127.0.0.1 auth user=test method=none
2026-01-06 23:21:26 [SSH] 127.0.0.1 exec command=exit
2026-01-06 23:21:29 [SSH] 127.0.0.1 disconnected
Each log entry includes:
- ISO timestamp (YYYY-MM-DD HH:MM:SS)
- Service type (HTTP, SSH, SFTP)
- Client IP address
- Event details (request path, auth method, command, etc.)
To use a different log file:
./build/mpm2_emu --log /var/log/mpm2.log -d A:disks/mpm2_system.imgmpm2/
├── scripts/
│ ├── build_all.sh # Master build script (--tree=dri|src)
│ ├── build_src.sh # Build from source code
│ ├── build_hd1k.sh # Create disk image with MP/M II files
│ ├── build_asm.sh # Assemble Z80 code, build C++, write boot sector
│ └── gensys.sh # Generate MPM.SYS
├── bin/
│ ├── dri/ # Original DRI binaries (.COM, .PRL, .SPR)
│ └── src/ # Source-built binaries (generated)
├── src/
│ ├── overrides/ # Source code modifications
│ │ ├── MPMLDR/ # MPMLDR with disabled serial check
│ │ └── NUCLEUS/ # Kernel source overrides
│ └── cpm_runtime.mac # Runtime support for PL/M programs
├── tools/
│ ├── build.py # Source build script (Python)
│ ├── gensys.py # MP/M II system generator (replaces DRI GENSYS)
│ └── dri_patch.py # Binary patching tool
├── asm/
│ ├── coldboot.asm # Boot sector (loads MPMLDR + LDRBIOS)
│ ├── ldrbios.asm # Loader BIOS for boot phase
│ ├── bnkxios.asm # Runtime XIOS (I/O port dispatch)
│ ├── sftp_brs.plm # SFTP RSP banked code (PL/M-80)
│ ├── sftp_glue.asm # SFTP assembly glue for BDOS calls
│ └── sftp_brs_header.asm # SFTP RSP header and entry point
├── src/ # C++ emulator source
│ ├── main.cpp # Entry point and main loop
│ ├── http_server.cpp # HTTP file browser
│ ├── sftp_bridge.cpp # SFTP/HTTP to Z80 bridge
│ └── ssh_session_libssh.cpp # SSH/SFTP server
├── include/ # C++ headers
│ ├── logger.h # Access logging
├── build/ # CMake build directory (generated)
├── disks/ # Disk images (generated)
└── mpm2_external/ # MP/M II source and distribution
├── mpm2src/ # Original source code
└── mpm2dist/ # Original binaries
MP/M II is Digital Research's multi-user, multi-tasking operating system for Z80. This emulator:
- Boots from disk sector 0 (cold boot loader)
- Loads MPMLDR and LDRBIOS from reserved tracks
- MPMLDR loads MPM.SYS into high memory
- Provides 7 memory banks (48KB user + 16KB common each)
- Runs 60Hz timer interrupts for task switching
- Exposes 4 consoles via SSH connections
The XIOS uses I/O port traps - Z80 code does OUT (0xE0), A and the emulator intercepts to handle disk, console, and system functions.
Run ./scripts/gensys.sh to regenerate MPM.SYS with matching serial numbers.
Install um80/ul80: pip install -e path/to/um80_and_friends
Ensure the emulator is running and check if port 2222 is available.
Use -l flag for local console mode to see boot messages.
GPL-3.0-or-later
- MP/M II Command Reference - Quick reference for all commands
- MP/M II System Guide - Original Digital Research documentation
- RomWBW - hd1k disk format
- cpmemu - Z80 emulator with cpm_disk.py utility
- 80un - Unpacker for CP/M compression and archive formats (LBR, ARC, squeeze, crunch, CrLZH)
- cpmdroid - Z80/CP/M emulator for Android with RomWBW HBIOS compatibility and VT100 terminal
- cpmemu - CP/M 2.2 emulator with Z80/8080 CPU emulation and BDOS/BIOS translation to Unix filesystem
- ioscpm - Z80/CP/M emulator for iOS and macOS with RomWBW HBIOS compatibility
- learn-ada-z80 - Ada programming examples for the uada80 compiler targeting Z80/CP/M
- mbasic - Modern MBASIC 5.21 Interpreter & Compilers
- mbasic2025 - MBASIC 5.21 source code reconstruction - byte-for-byte match with original binary
- mbasicc - C++ implementation of MBASIC 5.21
- mbasicc_web - WebAssembly MBASIC 5.21
- romwbw_emu - Hardware-level Z80 emulator for RomWBW with 512KB ROM + 512KB RAM banking and HBIOS support
- scelbal - SCELBAL BASIC interpreter - 8008 to 8080 translation
- uada80 - Ada compiler targeting Z80 processor and CP/M 2.2 operating system
- ucow - Unix/Linux Cowgol to Z80 compiler
- um80_and_friends - Microsoft MACRO-80 compatible toolchain for Linux: assembler, linker, librarian, disassembler
- upeepz80 - Universal peephole optimizer for Z80 compilers
- uplm80 - PL/M-80 compiler targeting Intel 8080 and Zilog Z80 assembly language
- z80cpmw - Z80 CP/M emulator for Windows (RomWBW)