A C compiler targeting the Z80 processor and CP/M operating system. Produces assembly compatible with the um80 assembler and linker toolchain.
pip install uc80
Or from source:
pip install -e .
Requires the um80 assembler/linker toolchain:
pip install um80
# Compile, assemble, and link a C program
uc80 hello.c -o hello.mac
um80 hello.mac -o hello.rel
ul80 hello.rel src/uc80/lib/libc.lib src/uc80/lib/runtime.lib -o hello.comFor smallest binaries, compile all .c files in a single invocation.
This enables whole-program optimizations that are not possible when
compiling files separately:
# Single-file (best optimization - all optimizations enabled by default)
uc80 main.c utils.c -o program.mac
um80 program.mac -o program.rel
ul80 program.rel src/uc80/lib/libc.lib src/uc80/lib/runtime.lib -o program.comDefault optimizations (all enabled unless disabled):
- Whole-program mode: Dead function elimination across all files
- Shared storage: Non-recursive functions use static allocation instead of stack frames
- Function inlining: Small functions expanded at call sites
- Constant propagation: Interprocedural constant folding
- AST optimization: Expression simplification, strength reduction
- Assembly DCE: Dead code elimination at assembly level
- Peephole optimization: Pattern-based instruction replacement
- Printf auto-detection: Scans format strings to link only needed handlers;
rewrites
printf("...\n")toputs("...")when no format specifiers are used - Embedded runtime: Runtime functions included as source, DCE removes unused ones
The compiler auto-detects which printf format specifiers your program uses and links only the needed handlers. You can also control this explicitly:
# Command line
uc80 program.c --printf int # %d %u %x %o %s %c %p only
uc80 program.c --printf int --printf long # add %ld %lu %lx
uc80 program.c --printf float # add %f
# In source code
#pragma printf int
#pragma printf longBy default int is 16 bits (natural Z80 word width). Code that assumes
32-bit int can be compiled with a CLI override — no source changes:
uc80 program.c --int=32 -o program.mac # 32-bit int
uc80 program.c --long=64 -o program.mac # 64-bit longThe bundled headers (<limits.h>, <stdint.h>, <stddef.h>, <inttypes.h>)
derive their typedefs and limit macros from compiler-supplied __SIZEOF_*__
and __*_MAX__ macros, so the same header files work under every config.
Codegen routes arithmetic, printf/scanf format dispatch, and sizeof
through the selected widths automatically.
When compiling files separately for separate linking, use --no-whole-program:
uc80 --no-whole-program module.c -o module.macuc80 produces the smallest known binaries for Z80/CP/M among current compilers.
Tested against z88dk (SDCC backend, -SO3 --max-allocs-per-node10000)
on the Fujitsu compiler-test-suite:
| Metric | Result |
|---|---|
| uc80 smaller | 47/47 tests (100%) |
| Aggregate size ratio | 46% (uc80 is less than half the size) |
| Total uc80 | 170,496 bytes |
| Total z88dk | 369,644 bytes |
| Minimal binary | 128 bytes (vs 5,172 for z88dk) |
Sample sizes (bytes):
| Program | uc80 | z88dk | Ratio |
|---|---|---|---|
| hello world (puts) | 256 | 5,172 | 5% |
| printf %d | 4,608 | 7,696 | 60% |
| integer math | 5,248 | 7,948 | 66% |
| long arithmetic | 5,632 | 7,793 | 72% |
Tested against multiple external test suites:
| Suite | Pass Rate | Notes |
|---|---|---|
| c-testsuite | 220/220 | full pass |
c-testsuite --int=32 |
219/220 | 00200 (long-long shift) overflows 64K TPA |
c-testsuite --int=32 --long=64 |
218/220 | same as above + marginal timeout |
| Fujitsu compiler-test-suite 0003 | 371/374 | |
| Fujitsu 0010 | 58/75 | 9 int16, 1 float, 2 timeout |
| Fujitsu 0011 | 287/335 | 14 int16, 5 large struct |
| Fujitsu 0012 | 4/9 | 4 int16/long long, 1 static DCE |
| SDCC regression tests | 514/523 | 3 fail, 4 sdcc ext, 2 multi-file link |
Remaining non-passing tests are environmental, not codegen bugs:
- sdcc ext: SDCC-specific extensions (
__asm,#pragma save/restore) - multi-file: tests that require separate compilation units
- float precision: ACOSF/TANF near asymptotes (single-precision IEEE 754 limit)
- malloc OOM: SDCC test asserts
malloc(2000) == NULL; we have plenty of TPA - 00200: 67KB binary exceeds 64KB CP/M TPA
- ANSI C (C11/C23) with most standard features
- Z80 code generation with peephole optimization
- IEEE 754 single-precision float
- Configurable integer sizes (
--int=16|32,--long=32|64); default is 16-bit int, 32-bit long, 64-bit long long - Structs, unions, bitfields, enums
- Full preprocessor (#include, #define, #if, #pragma, etc.)
- Modular library with selective linking
- Whole-program optimization
- CP/M target with embedded crt0
- 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
- mpm2 - MP/M II multi-user CP/M emulator with SSH terminal access and SFTP file transfer
- 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
- uc386 - C23 compiler targeting Intel 386 (x86-32) and MS-DOS; sibling backend sharing the uc_core frontend
- uc_core - Shared C23 frontend and AST optimizer used by uc80 and uc386
- ucow - Unix/Linux Cowgol to Z80 compiler
- um80_and_friends - Microsoft MACRO-80 compatible toolchain for Linux: assembler, linker, librarian, disassembler
- upeepz80 - Z80 peephole optimizer
- uplm80 - PL/M-80 compiler targeting Intel 8080 and Zilog Z80 assembly language
- uplox - Parser/lexer-table generator that produces uc_core's C23 frontend (from
examples/c23.uplox) - z80cpmw - Z80 CP/M emulator for Windows (RomWBW)
GPL-3.0-or-later. See LICENSE.