Skip to main content

cpm80

CP/M-80 2.2 emulator with Python API.

Python package CI PyPI Python License: MIT

Based on the fast and flexible z80 emulator.

Running the 1982 CP/M game Ladder, loaded straight from the host directory:

Ladder running under cpm80

Installing

$ pip install cpm80

Running and terminating

$ cpm80
62k CP/M vers 2.2

A>save 1 dump.dat
A>dir
A: DUMP     DAT
A>exit

Enter exit or just hit Ctrl + C three times to quit the emulator.

Exchanging files with the host

--mount <dir> puts a host directory on the next drive, and fresh disks come with PIP, so files just copy.

$ ls
hello.txt
$ cpm80 --mount .
62k CP/M vers 2.2

A>dir b:
B: HELLO    TXT
A>pip a:=b:hello.txt
A>save 1 b:dump.dat
A>exit
$ ls
DUMP.DAT  hello.txt

--mount also takes a disk image file instead of a directory. A single Ctrl + C re-reads a mounted directory -- the usual CP/M way of telling the system the disk has changed.

Running commands automatically

From the command line:

$ cpm80 dir 'save 1 a.dat' dir

Alternatively, we can use the API's StringKeyboard class to feed arbitrary commands to the command processor, CCP, thus replacing KeyboardDevice console readers used by default:

import cpm80

COMMANDS = (
    'dir',
    'save 1 a.dat',
    'dir',
    )

console_reader = cpm80.StringKeyboard(*COMMANDS)
m = cpm80.I8080CPMMachine(console_reader=console_reader)
m.run()

string_keyboard.py

Output:

62k CP/M vers 2.2

A>dir
NO FILE
A>save 1 a.dat
A>dir
A: A        DAT
A>

Getting output as a string

Similarly, we can replace DisplayDevice console writers used by default with custom writers to do special work for the emulator's output. For example, one could use a StringDisplay writer to gather the output into a string.

d = cpm80.StringDisplay()

m = cpm80.I8080CPMMachine(
    console_reader=cpm80.StringKeyboard('dir'),
    console_writer=d)

m.run()

print(d.string)

string_display.py

Making BDOS calls

BDOS calls can be performed on the machine object directly or by using convenience wrappers.

m = cpm80.I8080CPMMachine()

STR_ADDR = 0x100
m.set_memory_block(STR_ADDR, b'Hello $')
m.bdos_call(m.C_WRITESTR, de=STR_ADDR)

m.write_str('World!\n')

bdos_call.py

Working with files

Similarly, using BDOS wrappers one can manipulate files on disks.

drive = cpm80.DiskDrive()

m = cpm80.I8080CPMMachine(drives=[drive])
m.make_file('file.txt')
m.write_file(f'bin(100) is {bin(100)}\n'.encode())
m.close_file()
del m

# Then read and print the contents of the file using another machine.
m = cpm80.I8080CPMMachine(drives=[drive])
m.open_file('file.txt')
print(m.read_file())
m.close_file()

doing_files.py

Metadata

Release files for cpm80 1.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cpm80 1.2.0
File Size Uploaded
cpm80-1.2.0.tar.gz 41.7 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cpm80 1.2.0
File Interpreter ABI Platform
cpm80-1.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 75.5 kB

Release files / cpm80-1.2.0.tar.gz

Download URL cpm80-1.2.0.tar.gz
Size 41.7 kB
Tags Source
SHA-256 checksum
How to use checksums
1dfb66fb9d04e4e257a447a75400c22d52a382ad0cc4635f93a500b962e9919f
BLAKE2b-256 checksum
How to use checksums
4daa8af7e2bfc6b1770373bed84742cd38f089a99e3d1e2585e0b9c679ca01a7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.

Transparency log

Release files / cpm80-1.2.0-py3-none-any.whl

Download URL cpm80-1.2.0-py3-none-any.whl
Size 33.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
237ee7534e881b57be66b8226b1498c0d99148ef5081229fcb32c773a1de78e7
BLAKE2b-256 checksum
How to use checksums
d4b25ede632bcb0ebab575bb50fb8ea2444ed05dc8e03d40f42bdb430d4fb619
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.

Transparency log
Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page