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.1

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.1
File Size Uploaded
cpm80-1.2.1.tar.gz 41.7 kB Details

Built distribution (wheel)

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

Total release size: 75.5 kB

Release files / cpm80-1.2.1.tar.gz

Download URL cpm80-1.2.1.tar.gz
Size 41.7 kB
Tags Source
SHA-256 checksum
How to use checksums
b77726a3f7fe077a85b3a0d50bf4c228159ec1eb2c641b0f67ebb0c956e074a4
BLAKE2b-256 checksum
How to use checksums
84007f7ac24a7783d8a222dfdfb4d3fb843b19bb561358347f869b0099b947c5
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 5, 2026.

Transparency log

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

Download URL cpm80-1.2.1-py3-none-any.whl
Size 33.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7239d5ea29d0ed3a2913ff562579af2b8ee051f168489c26e1ef0df378cb9f47
BLAKE2b-256 checksum
How to use checksums
3ce3f2baa032ecc3f15c6301a9ac650fda8be502e3c15252515686eef1b55f1e
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 5, 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