- Overview
- Thanks
- Where to find CP/M-86?
- Key tools for CP/M-86 development
- License Considerations
- Prerequisites
- Script Mapping
- Fetching the tools
- Testing
- Docker image
- Using the tools
This project regroups a simple method to create a cross development environment for CP/M‑86. It happens that all DOS based tools can also be used for building DOS programs. This project was developed for myself in a nerdy spirit and for a lot of fun. Just sharing without any guarantees.
| Language | Compilers / Interpreters |
|---|---|
| C | Aztec C 3.4 (K&R), Aztec C 4.2 (almost ANSI), DR C 1.11 (ansi2kr integrated), Microsoft C 5.1 |
| Assembler | SCP ASM, RASM‑86, ASM‑86 1.1, ASM‑86 3.2, MASM 1.1, MASM 5.10, NASM 3.02, CP/M‑80 ASM |
| Basic | DR CBASIC 2.0, DR Personal Basic 1.2, MS Basic 5.21/5.22/5.28, TDL BASIC 3.05 |
| Pascal | Pascal MT+ 3.3, Turbo Pascal 3.02, PolyPascal‑86 3.11 |
| Fortran‑77 | DR Fortran‑77 4.0 |
| COBOL | Micro Focus Level II COBOL V2.1 |
| PL/M‑86 | Intel PL/M‑86 3.30 |
| PL/I | DR PL/I‑86 1.0 |
| Lisp | XLISP 1.1 |
- dmsc (https://github.com/dmsc) for the emu2 emulator, without which this project would not be nearly as pleasant to use.
- johnsonjh (https://github.com/johnsonjh) for the emu2‑cpm86 fork, the hexcom rewrite, and portability/build fixes contributed to this project.
The source for CP/M‑86 doc, sources and binaries is http://www.cpm.z80.de.
A cleaned‑up distribution and kernel is available at https://github.com/tsupplis/cpm86-kernel. This distribution is working well in virtual environments, patched with all known patches, 'y2k' friendly (it contains the version of tod which sources are in this project) and AT friendly.
| Tool | Version | Description |
|---|---|---|
| Aztec C | 4.2/4.10d | Almost‑ANSI C89; c86.lib patched & improved, d11.lib for DOS 1.1 |
| Aztec C | 3.4/3.40a | K&R/Legacy/"C86" C; c86.lib patched, patched preprocessor, otherwise as‑is |
| DR C | 1.11 | CP/M‑86 C compiler; passes drc860–drc862, runtime clearl/clears.l86 |
| MSC | 5.1 | Microsoft C compiler for DOS; |
| DR Fortran‑77 | 4.0 | CP/M‑86; compiler f77.cmd+codegen.cmd, runtime f32s/l.obj, 8087.sim |
| Pascal MT+ | 3.3 | CP/M‑86; compiler mt+86.cmd, linker linkmt.cmd, assembler asmt86.cmd |
| Turbo Pascal | 3.02 | Last CP/M‑86 Borland release; compiler turbo.cmd, installer tinst.cmd |
| PolyPascal‑86 | 3.11 | Integrated editor+compiler; small/BCD/8087 variants (ppas, ppbs, pp87) |
| DR CBASIC | 2.0 (CP/M‑86) / 2.1 (DOS) | Compiled BASIC; compiler cb86.exe, linker link86.exe |
| M2CBASIC | 1.4 | MS BASIC → CBASIC source converter; translator + runtime libs |
| DR Personal Basic | 1.2 | Interactive CP/M‑86 BASIC interpreter |
| MS Basic | 5.22 (CP/M‑86) / 5.28 (DOS) | Interpreted; patched binaries included |
| MS Basic | 5.21 (CP/M‑80) / 4.51 "Old Basic" | Run via tnylpo |
| TDL BASIC | 3.05 | Z‑80 CP/M‑80 BASIC; run via tnylpo |
| Intel PL/M‑86 | 3.30 | Compiler plm86.exe, assembler asm86.exe, linker, librarian, locator |
| DR PL/I‑86 | 1.0 | CP/M‑86; compiler pli.cmd, runtime plilib.l86, DIO sources |
| XLISP | 1.1 | Public‑domain Lisp interpreter; built from source with Aztec C 4.2 |
| Micro Focus COBOL | Level II V2.1 | CP/M‑86; compiler cobol.cmd, runtime run.cmd |
| Tool | Version | Description |
|---|---|---|
| RASM‑86 / LINK‑86 / LIB‑86 XREF-86 | 1.4a / 2.02 / 1.3 / 1.1 | DR DOS assembler toolchain |
| ASM‑86 + GENCMD | 1.1 | DR assembler; CP/M‑80 and CP/M‑86 versions |
| XLT86 | 1.3 | DR 8080/8085 → 8086 translator; xlt86.com + overlays; run via tnylpo |
| TRANS | 2.21A | SCP/Microsoft Z80 to 8086 Translator; runs via emu2 |
| MASM / LINK / ASM / LIB / EXE2BIN / HEX2BIN | 1.1 and 5.10 / 3.65 / 2.44a / 3.10 / 2.4 / — | Microsoft DOS assembler toolchain; masm patched for emu2 (https://github.com/tsupplis/pcdos11-hacking) |
| NASM | 3.02+ | Netwide assembler (native) |
| Intel ASM‑86 | 3.2 | Part of Intel PL/M‑86 toolchain (asm86.exe) |
| Tool | Version | Description |
|---|---|---|
| emu2‑cpm86 | v2026.09‑C | DOS/CP/M‑86 emulator (fork of emu2 with CP/M‑86 support) |
| tnylpo | — | CP/M‑80 emulator; used for asm86.com, gencmd.com, XLT86, MS Basic 80 |
| upx | 5.2.1 | Executable packer |
| lzexe (and utilities) | 0.91‑ecm | Executable packer |
| pc | 1.1.2 | Programmers calculator |
| crc | — | Enhanced IBM PC‑DOS CRC.EXE‑compatible 32‑bit CRC utility |
| ARC86 / LU86 | 1.0 / 4.05 | CP/M‑86 archive and library utilities for .ARC and .LBR files |
No guarantees are made for any component. Use each at your own risk subject to the conditions below.
| Component | License / Status | Reference |
|---|---|---|
| MS‑DOS tools (DOS 1.1, ASN, TRANS, MASM, LINK, Basic 86, MSC 5.1) | MIT license | LICENSE |
| Aztec C | Freeware (conditions apply) | aztecmuseum.ca |
| DR tools (RASM‑86, ASM‑86, CBASIC, DR C, Fortran‑77, Pascal MT+, Personal Basic, PL/I‑86, XLT86) | DR/Caldera open‑source license | license · faq |
| M2CBASIC (Comeau) | Unclear |
m2cbasic.zip |
| Turbo Pascal 3.01A (Borland) | Freely usable, not open source | RC750 image |
| emu2 / emu2‑cpm86 | GPL‑2.0 | emu2 · emu2‑cpm86 |
| tnylpo | BSD‑3‑Clause | LICENSE |
| pc | MIT | LICENSE |
| crc | MIT‑0 | LICENSE |
| lzexe / unlzexe / comtoexe / infoexe | MIT | LICENSE |
| NASM | BSD‑2‑Clause | nasm.us |
| hexcom.c (Jeffrey H. Johnson) | MIT‑0 | source |
| ansi2kr (Masaki Oba) | BSD‑2‑Clause | nabeta.tk |
| ARC86 (Reimer Mellin; CP/M‑86 port by D. J. Weatherall) | Public domain source; private non-commercial use only for the CP/M‑86 modifications | 86arkive.zip (stored in src/freetools) |
| LU86 (Paul J. Homchick) | Unclear |
86arkive.zip (stored in src/freetools) |
| XLISP 1.1 (David Betz) | Public domain | cpm86‑ports |
| PL/I Object Fixer | GPL‑3.0 | ccpm objfix |
| Intel PL/M‑86 3.30 | Unclear |
PLM8086Tools.zip (stored in src/inteltools) |
| PolyPascal‑86 V3.11 (PolyData MicroCenter A/S) | Unclear |
— |
| Micro Focus Level II COBOL V2.1 | Unclear |
— |
| TDL BASIC 3.05 (Technical Design Labs) | Unclear |
— |
Install any missing prerequisites with your favorite package manager.
| Status | Prerequisites |
|---|---|
| Required | · C/C++ toolchain (C99/C++14): GCC or Clang · curl · CMake · dos2unix · git · GNU Coreutils · Gzip · GNU Make · GNU patch · Screen · tar · Wget · Info‑ZIP Unzip · ncurses · XZ Utils |
| Optional | Docker, Podman, or equivalent (for containerized builds) |
When several tools can perform the same job, use the highest tier available:
- Native
(native)— compiled for the host OS, no emulation overhead. - DOS —
.exe/.combinary run underemu2. - CP/M‑86 —
.cmdbinary run underemu2. - CP/M‑80 —
.combinary run undertnylpo— legacy fallback only.
For example, cpm86_asm86 (CP/M‑86, tier 3) is preferred over cpm_asm86
(CP/M‑80, tier 4), and cmdinfo (native, tier 1) is preferred over any DOS wrapper.
All the tools are wrapped in the bin directory for direct usage:
| Category | Tool | Program | Description |
|---|---|---|---|
| Assembler | cpm_asm86 | asm86.com | DR assembler (CP/M‑80 tool) |
| Assembler | cpm_gencmd | gencmd.com | DR H86 converter (CP/M‑80 tool) |
| Assembler | cpm_xlt86 | xlt86.com | DR 8080→8086 translator (CP/M‑80, via tnylpo) |
| Assembler | pcdev_trans | trans.com | SCP/Microsoft Z80 to 8086 Translator (DOS, via emu2) |
| Assembler | cpm86_asm86 | asm86.cmd | DR assembler (CP/M‑86, via emu2, not working yet) |
| Assembler | cpm86_gencmd | gencmd.cmd | DR H86 converter (CP/M‑86 via emu2, not working yet) |
| Assembler | nasm | (native) | Netwide assembler |
| Assembler | pcdev_asm | asm.com | Microsoft/86‑DOS assembler |
| Assembler | pcdev_masm | masm.exe | Microsoft assembler |
| Assembler | pcdev_masm11 | masm11.exe | Legacy Microsoft assembler |
| Assembler | pcdev_rasm86 | rasm86.exe | DR assembler |
| Assembler | pcdev_xref86 | xref86.exe | DR cross referencer |
| Assembler | cpm_asm80 | asm80.com | DR 8008 assembler (CP/M‑80 tool) to support xlt86 |
| Linkers / Librarians | bin2cmd | (native) | CMD converter (native) |
| Linkers / Librarians | exe2cmd | (native) | EXE to CMD converter (native) |
| Linkers / Librarians | hexcom | (native) | HEX to COM translation |
| Linkers / Librarians | pcdev_bin2cmd | ‑ | obsolete alias for bin2cmd |
| Linkers / Librarians | pcdev_exe2bin | exe2bin.exe | Microsoft EXE converter |
| Linkers / Librarians | pcdev_exe2cmd | ‑ | obsolete alias for exe2cmd |
| Linkers / Librarians | pcdev_hex2bin | hex2bin.com | Microsoft HEX converter |
| Linkers / Librarians | pcdev_lib86 | lib86.exe | DR librarian |
| Linkers / Librarians | pcdev_link | link.exe | Microsoft linker |
| Linkers / Librarians | pcdev_lib | lib.exe | Microsoft librarian |
| Linkers / Librarians | pcdev_link86 | linkcmd.exe | DR linker for CP/M‑86 (alias) |
| Linkers / Librarians | pcdev_linkcmd | linkcmd.exe | DR linker for CP/M‑86 |
| Linkers / Librarians | pcdev_linkexe | linkexe.exe | DR linker for DOS |
| Debuggers | cpm86_ddt86 | ddt86.cmd | DDT‑86 debugger for CP/M‑86 |
| Debuggers | cpm86_sid86 | sid86.cmd | SID‑86 symbolic debugger/disassembler for CP/M‑86 |
| Debuggers | pcdev_sid86 | sid86.exe | SID‑86 symbolic debugger/disassembler for DOS; support is WIP |
| Debuggers | pcdev_debug | debug.com | Microsoft DOS debugger; support is WIP |
| Debuggers | pcdev_edebug | edebug.com | Microsoft DOS debugger by ECM; support is WIP |
| Debuggers | pcdev_ldebug | edebug.com | Advanced DOS debugger by ECM |
| Basic | cpm_mbasic | mbasic.com | Microsoft Basic 5.21 (8080 CP/M‑80, via tnylpo) |
| Basic | cpm_obasic | obasic.com | Microsoft Basic 4.51 (8080 CP/M‑80, via tnylpo) |
| Basic | cpm_tdlbasic | tdlbasic.com | TDL BASIC 3.05 (Z‑80 CP/M‑80, via tnylpo) |
| Basic | cpm86_basic | basic.cmd | DR Personal Basic 1.2 (via cpm86) |
| Basic | cpm86_mbasic | mbasic86.cmd | Microsoft Basic 5.22 (CP/M‑86, via emu2) |
| Basic | drcbcpm_bc | cb86.exe | DR CBASIC compiler for CP/M‑86 |
| Basic | drcbcpm_link | link86.exe | DR CBASIC linker for CP/M‑86 |
| Basic | drcbdos_bc | cb86.exe | DR CBASIC compiler for DOS |
| Basic | drcbdos_link | linkexe.exe | DR CBASIC linker for DOS |
| Basic | m2cb_cvt | m2cbasic.cmd | M2CBASIC 1.4 MBASIC to CBASIC converter |
| Basic | pcdev_mbasic | mbasic86.com | Microsoft Basic 5.28 (DOS, via emu2) |
| C | ansi2kr | (native) | ANSI C to K&R C converter (native) |
| C | aztec34_as | as.exe | Aztec assembler (v3.4) |
| C | aztec34_cc | cc.exe | Aztec K&R C compiler (v3.4) |
| C | aztec34_hex86 | hex86.exe | Aztec C H86 generator (v3.4) |
| C | aztec34_lib | lb.exe | Aztec C lib (v3.4) |
| C | aztec34_link | ln.exe | Aztec C linker (v3.4) |
| C | aztec34_obd | obd.exe | Aztec C object dump (v3.4) |
| C | aztec34_obj | obj.exe | Aztec C object lister (v3.4) |
| C | aztec34_ord | ord.exe | Aztec C library ordering helper (v3.4) |
| C | aztec34_sqz | sqz.exe | Aztec C object optimizer (v3.4) |
| C | aztec42_as | as.exe | Aztec assembler (v4.2) |
| C | aztec42_cc | cc.exe | Aztec ANSI C compiler (v4.2) |
| C | aztec42_hex86 | hex86.exe | Aztec C H86 generator (v4.2) |
| C | aztec42_lib | lb.exe | Aztec C lib (v4.2) |
| C | aztec42_link | ln.exe | Aztec C linker (v4.2) |
| C | aztec42_obd | obd.exe | Aztec C object dump (v4.2) |
| C | aztec42_obj | obj.exe | Aztec C object lister (v4.2) |
| C | aztec42_ord | ord.exe | Aztec C library ordering helper (v4.2) |
| C | aztec42_sqz | sqz.exe | Aztec C object optimizer (v4.2) |
| C | drccpm_cc | drc860+861.cmd | DR C 1.11 compiler (two‑pass) |
| C | drccpm_link | linkcmd.exe | DR C 1.11 linker |
| C | msc5_cl | cl.exe | Microsoft C 5.1 compiler (CL 5.10) |
| C | msc5_lib | lib.exe | Microsoft C 5.1 librarian (LIB 3.10) |
| C | msc5_link | link.exe | Microsoft C 5.1 linker (LINK 5.10a, patched) |
| COBOL | mfcobol_cc | cobol.cmd | Micro Focus Level II COBOL compiler (CP/M‑86) |
| COBOL | mfcobol_run | run.cmd | Micro Focus Level II COBOL runtime (CP/M‑86) |
| Emulation | cpm86 | cpm86.exe | CP/M‑86 emulator (via emu2+dos) |
| Emulation | emu2 | (native) | x86 DOS/CP/M‑86 emulator |
| Emulation | tnylpo | (native) | CP/M‑80 emulator |
| Fortran | drfcpm_fc | f77.cmd | DR Fortran‑77 4.0 compiler |
| Fortran | drfcpm_link | linkcmd.exe | DR Fortran‑77 4.0 linker |
| Lisp | cpm86_xlisp | xlisp.cmd | XLISP 1.1 interpreter (built from source) |
| Pascal | cpm86_turbo | turbo.cmd | Turbo Pascal 3.01 (CP/M‑86) |
| Pascal | drpmtcpm_asm | asmt86.cmd | Pascal MT+ 3.3 assembler |
| Pascal | drpmtcpm_link | linkmt.cmd | Pascal MT+ 3.3 linker |
| Pascal | drpmtcpm_pc | mt+86.cmd | Pascal MT+ 3.3 compiler |
| Pascal | ppcpm_pp87 | pp87.cmd | PolyPascal‑86 V3.11 8087 FPU variant (CP/M‑86) |
| Pascal | ppcpm_ppas | ppas.cmd | PolyPascal‑86 V3.11 compiler+editor (CP/M‑86) |
| Pascal | ppcpm_ppbs | ppbs.cmd | PolyPascal‑86 V3.11 BCD business variant (CP/M‑86) |
| Pascal | ppdos_pp87 | pp87.com | PolyPascal‑86 V3.11 8087 FPU variant (DOS) |
| Pascal | ppdos_ppas | ppas.com | PolyPascal‑86 V3.11 compiler+editor (DOS) |
| Pascal | ppdos_ppbs | ppbs.com | PolyPascal‑86 V3.11 BCD business variant (DOS) |
| PL/I | drplicpm_link | linkcmd.exe | DR PL/I‑86 1.0 linker |
| PL/I | drplicpm_pc | pli.cmd | DR PL/I‑86 1.0 compiler |
| PL/I | drpli_objfix | (native) | PL/I Object Compatibility Fix for DR Linker |
| PL/M | intel_asm86 | asm86.exe | Intel ASM‑86 assembler V3.2 |
| PL/M | intel_lib86 | lib86.exe | Intel librarian |
| PL/M | intel_link | link.exe | Intel/Microsoft linker |
| PL/M | intel_link86 | link86.exe | Intel linker |
| PL/M | intel_loc86 | loc86.exe | Intel locator |
| PL/M | intel_oh86 | oh86.exe | Intel object to hex converter |
| PL/M | intel_plm86 | plm86.exe | Intel PL/M‑86 3.30 compiler |
| Misc | cmdinfo | (native) | CMD info tool (native) |
| Misc | doscat | (native) | Truncate files beyond ^Z |
| Misc | tnylpo‑convert | (native) | converts text files to and from the CP/M format |
| Misc | crc | (native) | Enhanced IBM PC‑DOS CRC.EXE‑compatible 32‑bit CRC utility |
| Misc | pcdev_cmdinfo | ‑ | obsolete alias for cmdinfo |
| Misc | cpm_arc86 | arc86.cmd | ARC86 archive utility for CP/M‑86 .ARC files |
| Misc | cpm_lu86 | lu86.cmd | LU86 library utility for CP/M‑86 .LBR files |
| Misc | upx | (native) | Executable packer for DOS and CP/M‑86 binaries |
| Misc | pcdev_exepack | exepack.exe | Microsoft EXEPACK 4.06b executable packer (patched) |
| Misc | pcdev_lzexe | lzexe.exe | LZEXE executable packer for DOS EXE files (ecm fork) |
| Misc | pcdev_unlzexe | unlzexe.exe | Unpacker for DOS LZEXE packed executables (ecm fork) |
| Misc | pcdev_comtoexe | comtoexe.exe | Converts DOS COM files to EXE format (ecm fork) |
| Misc | pcdev_infoexe | infoexe.exe | Display information about a DOS EXE file (ecm fork) |
The development environment can be assembled by using the following steps:
./fetch_tools
export PATH="$(pwd -P)"/bin| Component | Source |
|---|---|
| Aztec C 4.2 | AztecC86.zip |
| Aztec C 3.4 | az8634b.zip |
| RASM‑86, LINK‑86, LIB‑86 | tools86.zip (stored in src/drtools) |
| ASM‑86 + GENCMD (CP/M‑80) | mpm862sr.zip (stored in src/drtools) |
| XLT86 1.3 | xlt86.zip (stored in src/drpackages/xlt86) |
| ASM‑86 + GENCMD (CP/M‑86) | cpm86‑kernel (GitHub) |
| DR C 1.11 + extra headers | drc_86.zip · drc86111.zip (stored in src/drpackages/drc86cpm) |
| DR Fortran‑77 4.0 | f77‑86.zip (stored in src/drpackages/drf77cpm) |
| Turbo Pascal 3.02 (CP/M‑86) | RC750 image (stored in src/turbo) |
| PolyPascal‑86 3.11 | PolyPascal (GitHub) |
| Pascal MT+ 3.3 | mt8633cp.zip (stored in src/drpackages/drpmtcpm) |
| DR CBASIC 2.0/2.1 + libs | cbasic86.zip · cb86toys.zip (stored in src/drpackages/cb86cpm, src/drpackages/cb86dos) |
| M2CBASIC 1.4 | m2cbasic.zip |
| DR Personal Basic 1.2 | datamuseum.dk (stored in src/drtools/basic.cmd) |
| MS Basic 5.21 (CP/M‑80) | repository (local copy) |
| MASM, LINK, ASM, EXE2BIN, HEX2BIN, MS Basic 86/80 | MS‑DOS (GitHub) + repository |
| cmdtools (cmdinfo, bin2cmd, exe2cmd) | cpm86‑cmdtools (GitHub, built natively) |
| NASM | nasm.us snapshots |
| UPX | UPX releases (GitHub) |
| lzexe (and utilities) | lzexe (pushbx.org, fork of the original |
| emu2‑cpm86 | emu2‑cpm86 (GitLab, fork of emu2) |
| tnylpo | tnylpo (GitLab) |
| Intel PL/M‑86 3.30 tools | PLM8086Tools.zip (stored in src/inteltools) |
| DR PL/I‑86 1.0 | pli86.zip (stored in src/drpackages/drplicpm) |
| MSC 5.1 | MS‑DOS (GitHub, stored in src/mspackages/msc51) |
| ARC86 / LU86 | 86arkive.zip (stored in src/freetools) |
| XLISP 1.1 | cpm86‑ports (GitHub, built from source with aztec42) |
| Micro Focus Level II COBOL | LII‑COBOL‑CPM86.zip |
| TDL BASIC 3.05 (CP/M‑80) | Nutting_ICE.zip |
Clearing the directory is achieved by:
./clear_tools-
The build has been tested on IBM AIX (7.2 TL5+), GNU/Linux, NetBSD, FreeBSD, OpenBSD, OpenIndiana (illumos), and Solaris (11.4 SRU 81+). No special build steps (other than installing the appropriate prerequisites) are required most platforms.
-
See special build instructions below for IBM AIX and Solaris.
- On both Solaris 11.4 SRU 81+ and current OpenIndiana (illumos) systems, you must
have GNU
taravailable asgtarand also provide your own dos2unix in the PATH. Invokefetch_toolsas follows:Replaceenv PATH="/path/to/dos2unix:$(getconf PATH):$PATH" CC=gcc CXX=g++ ./fetch_tools/path/to/dos2unixwith the actual path where you built the software.
-
On IBM AIX you must invoke
fetch_toolsas:env CC=gcc-13 CXX=g++-13 ./fetch_tools
(If you have a version of GCC later than 13, adjust your invocations accordingly.)
-
It is known that UPX 5.2.1 initially fails to build. As a workaround:
cd archive/upx rm -rf build/release -
Edit the
src/work.cppfile and (around line 159) change:// POSIX.1-2008 times[0] = st->st_atim; times[1] = st->st_mtim;
to this:
times[0].tv_sec = st->st_atim.tv_sec; times[0].tv_nsec = st->st_atim.tv_nsec; times[1].tv_sec = st->st_mtim.tv_sec; times[1].tv_nsec = st->st_mtim.tv_nsec;
-
Edit the
src/util/xspan.hfile and (around line 33) change:#ifndef WITH_XSPAN #define WITH_XSPAN 2 #endif
to this:
#undef WITH_XSPAN #define WITH_XSPAN 1
-
Edit the
src/check/dt_xspan.cppfile and (around line 29), after the#include "../conf.h"line, delete all lines until the end of the file. -
Then rebuild UPX using the following command:
sh -xc 'export PATH="/opt/freeware/bin:$PATH" && env OBJECT_MODE=64 CC="gcc-13 -maix64 -Wl,-b64 -D_ALL_SOURCE" CXX="g++-13 -maix64 -Wl,-b64 -D_ALL_SOURCE" gmake -j $(nproc) VERBOSE=1' cd ../..
Once the steps above successfully complete, run
env CC=gcc-13 CXX=g++-13 ./fetch_toolagain the build will run to completion. -
Every file downloaded by fetch_tools (the Aztec, DR, CB86 and NASM archives,
but not the git checkouts) is cached under archive/ instead of being deleted.
This keeps the build environment reproducible even if an upstream disappears:
- If a download fails,
fetch_toolsfalls back to the cached copy inarchive/. - Set
ARCHIVE_FIRST=1to rebuild entirely fromarchive/without touching the network (e.g. offline, or to pin exact versions):env ARCHIVE_FIRST=1 ./fetch_tools
clear_toolswill not remove thearchive/, so a cleared tree can always be rebuilt from the local cache.
The cpm86 tool is a cpm86 emulator for dos pulled with Aztec C. We have reverse engineered it and patch it to fix a few bugs and add some new features. It should not be relied on fully as some bugs surely remain, but it can be experimented with and works for many programs. For build tools DOS/CP/M‑80 emulations and DOS/CP/M‑80 cross compilations are far better options and proper emulation of CP/M‑86 is the best option for testing; PCE is a very good choice (http://www.hampa.ch/pce/).
Note that the enhanced cpm86 emulator supports padding records with EOF instead of NULL which may make working with text files easier, but
because this behavior does not match real CP/M‑86, it's disabled by default and only enabled if you set CPM86_EOF=1, for example:
env CPM86_EOF=1 cpm86 program.cmdThis may be a next step:
- automating pce, cpmtools
- bootable/up‑to‑date CP/M‑86 floppy ...
A Dockerfile is provided for this environment.
To build the container, from the repository root, run:
docker build --progress=plain --rm=true -t cpm86:latest -f docker/Dockerfile .to use the created image, just ensure that the local path where the compilation happens is mounted properly:
docker run -it --rm -h cpm86 -v "$(pwd -P)":/work -w /work cpm86 pcdev_rasm86 helloa.a86
docker run -it --rm -h cpm86 -v "$(pwd -P)":/work -w /work cpm86 aztec34_cc helloc.cThe only difference on the command line happens with ;
pcdev_masm hellod \;... becomes ...
docker run -it --rm -h cpm86 -v "$(pwd -P)":/work -w /work cpm86 pcdev_masm hellod '\\;'Finally, a simple Makefile with a sample c, assembler for rasm86, assembler for asm86 is provided:
./test_crossdev| Variant | Commands |
|---|---|
| DR CBASIC (compiled, CP/M‑86) | drcbcpm_bc hellor.bas drcbcpm_link hellor.cmd=hellor.o cmdinfo hellor.cmd |
| MS BASIC → CBASIC (convert + compile) | m2cb_cvt hellomsb.bas mv hellomsb.cb hellocvt.cb drcbcpm_bc hellocvt.cb drcbcpm_link hellocvt cmdinfo hellocvt.cmd |
| MS Basic 5.22 (interpreted, CP/M‑86) | cpm86_mbasic hellomsb.bas |
| MS Basic 5.28 (interpreted, DOS) | pcdev_mbasic hellomsb.bas |
| MS Basic 5.21 (CP/M‑80, via tnylpo) | cpm_mbasic hellomsb.bas |
| MS Basic 4.51 "Old Basic" (CP/M‑80, via tnylpo) | cpm_obasic hellomsb.bas |
| TDL BASIC 3.05 (Z‑80 CP/M‑80, via tnylpo) | cpm_tdlbasic hellomsb.bas |
| DR Personal Basic 1.2 (interactive) | cpm86_basic |
aztec42 is the preferred compiler — it supports almost‑ANSI syntax and its
runtime and CP/M‑86 library are actively improved. Use aztec34 only when
strict K&R compatibility is required or for legacy builds.
drccpm_cc is the DR C 1.11 compiler for CP/M‑86. It runs two passes
internally: drc860.cmd (preprocessor) produces ctemp.tok, then
drc861.cmd (code generator) consumes it. When -r is given, a third pass
(drc862.cmd) merges the listing and disassembly into a <source>.ili
interlist file. Temp files are cleaned up via a trap regardless of success or
failure. The DR C runtime libraries
(clearl.l86, clears.l86) and link86.cmd are all staged in
share/drc86cpm/. The redundant DISK3 tools (rasm86.cmd, lib86.cmd,
xref86.cmd) are not staged.
drccpm_link and drfcpm_link are thin wrappers around link86.cmd - they
set drive A to the current working directory (so .obj files are found there)
and drive D to the tool share directory (so runtime libraries are found there).
Link options are passed explicitly by the caller using the LINK‑86 [option]
syntax. The following option(s) are recognized:
| Option | Description |
|---|---|
$LD |
Search drive D for .l86 runtime libraries |
This is not necessary with the wrappers.
| Variant | Commands |
|---|---|
| Aztec C 4.2 (preferred, almost‑ANSI) | aztec42_cc helloc.c aztec42_sqz helloc.o aztec42_link -o helloc.cmd helloc.o -lc86 cmdinfo helloc.cmd |
| Aztec C 3.4 (K&R legacy) | aztec34_cc helloc.c aztec34_sqz helloc.o aztec34_link -o helloc.cmd helloc.o -lc86 cmdinfo helloc.cmd |
| DR C 1.11 (K&R) | drccpm_cc -ohellodrc.obj hellodrc.c drccpm_link 'hellodrc.cmd=hellodrc.obj' cmdinfo hellodrc.cmd |
| DR C 1.11 (ANSI mode) | drccpm_cc -e -ohelloans.obj helloans.c drccpm_link 'helloans.cmd=helloans.obj' cmdinfo helloans.cmd |
| Microsoft C 5.1 (DOS) | msc5_cl -c hellomsc.obj hellomsc.c msc5_link hellomsc.obj \; emu2 hellomsc.exe |
aztec34_link/aztec42_link automatically prepend the matching C runtime
startup object, so the $begin ‑> Croot_ ‑> main ‑> exit entry/exit code is
always present. The startup is selected from the C library you link against:
| Library | Target / Model | Startup |
|---|---|---|
‑lc86 |
CP/M‑86 small | begin86.o |
‑lc / ‑lclc |
MS‑DOS small | sbegin.o |
‑lcl / ‑lcld |
MS‑DOS large | lbegin.o |
These startup objects are produced from the C libraries by fetch_tools
(src/fetch/cross_aztec_startups). Without this, Aztec's single‑pass ln only pulls
the startup from the library on demand, so a program that references no libc
symbol — e.g. int main(void){ return 0; } — would link with no startup and
crash on exit, and a program that references the startup indirectly (e.g.
exit()) could fail to link (Undefined symbol: _exit_) unless the library was
ordered with ord or passed twice (‑lc86 ‑lc86). Prepending the startup as a
command‑line object fixes all of these cases, so neither ord nor a doubled
library is needed. To restore the old behavior set AZTEC_NOSTARTUP=1, or force
a specific startup with AZTEC_STARTUP=<obj‑in‑lib>.
| Variant | Commands |
|---|---|
| RASM‑86 | pcdev_rasm86 helloa.a86 '$' pz sz pcdev_linkcmd helloa '[$sz]' cmdinfo helloa.cmd |
| ASM‑86 (CP/M‑86) | cpm_asm86 hellob.a86 cpm_gencmd hellob.h86 cmdinfo hellob.cmd |
| MASM | pcdev_masm hellod \; pcdev_link hellod \; pcdev_exe2bin hellod.exe bin2cmd hellod.bin hellod.cmd cmdinfo hellod.cmd |
| NASM | nasm hellon.asm -fbin -o hellon.bin bin2cmd hellon.bin hellon.cmd cmdinfo hellon.cmd |
| XLT86 (8080→8086) + ASM‑86 | Pass basename without extension. XLT86 translates CALL 5 to INT 224 (0E0h). "Number of Errors: 1" for ORG 100h is expected and harmless.cpm_xlt86 hello80 cpm86_asm86 hello80.a86 cpm86_gencmd hello80.h86 cmdinfo hello80.cmd |
| Language | Commands |
|---|---|
| PolyPascal‑86 V3.11 (CP/M‑86) |
Interactive editor+compiler. Standard (ppas), BCD (ppbs), 8087 (pp87) variants.ppcpm_ppasThe editor opens first. Use COMPILE then RUN. PPAS.HLP and PPAS.ERM found automatically on drive D.
|
| Pascal MT+ 3.3 (CP/M‑86) | drpmtcpm_pc hellomt drpmtcpm_link hellomt.cmd=hellomt,p:paslib/s cmdinfo hellomt.cmd |
| DR Fortran‑77 4.0 (CP/M‑86, small model) |
Both compiler passes (f77.cmd + codegen.cmd) run internally; .cil/.cym intermediates cleaned up automatically.drfcpm_fc hellof.f77 drfcpm_link 'hellof.cmd=hellof' cmdinfo hellof.cmd |
| Micro Focus Level II COBOL V2.1 (CP/M‑86) |
Compiles .cbl to bytecode .int; runtime executes it.mfcobol_cc hellocbl.cbl mfcobol_run hellocbl.intThe cobol overlay is staged automatically and cleaned up on exit.
|
| Intel PL/M‑86 3.30 | intel_asm86 scd.a86 intel_plm86 hellop.plm debug 'optimize(3)' pcdev_linkcmd hellop=scd,hellop '[data[ori[0]]' cmdinfo hellop.cmd |
| DR PL/I‑86 1.0 (CP/M‑86) | drplicpm_pc hellopi drplicpm_link 'hellopi.cmd=hellopi' cmdinfo hellopi.cmd |
| XLISP 1.1 (CP/M‑86) |
Interactive by default. Pass a .lsp file to load and run it; use (exit) to terminate without waiting for input.cpm86_xlisp hello.lspFor an interactive session: cpm86_xlispDrive D = tool dir (contains xlisp.cmd), drive C = CWD, so .lsp files are found automatically.
|