Introduction
CP/M was a very popular operating system for 8-bit microcomputers in the 70’s and into the 80’s. At first it only supported the Intel 8080 processor and then later it also supported a few other processes, most notably the Zilog Z80. Eventually there were versions for 16-bit processors as well, but these weren’t as popular as the original 8-bit implementation. I still enjoy using CP/M nowadays just for the fun of it; one of the attractions for me is that it’s possible to understand a system completely from bottom to top, which is not practical with modern systems.
I use a real CP/M system occasionally, but if I’m developing CP/M software it’s easier to first use an emulated system because that way I can take advantage of the host system; e.g. network access, easy backups, quieter and cheaper to run, etc.
This article describes setting up an emulated CP/M 3.0 system using z80pack on either Linux or macOS.
Alternatively, you can instead use YAZE-AG; I’ve written some brief notes about setting up YAZE-AG on macOS.
Approach
We’ll be installing z80pack into ~/cpmsim
and related tools into ~/local
. The emulated system will have the usual standard development tools plus some third-party tools and applications.
Installation
First, download z80pack via http://www.autometer.de/unix4fun/z80pack/index.html#download The file we want is z80pack-1.36.tgz
. Once it is downloaded, build it and install it like this (these instructions are based on those on the z80pack website):
cd tar -xf Downloads/z80pack-1.36.tgz cd z80pack-1.36/cpmsim/srcsim make -f Makefile.osx make -f Makefile.osx clean cd ../srctools
One small issue here is that the Makefile for srctools
copies the executables to ~/bin
which is not what we want. So edit Makefile
and change INSTALLDIR
to have a value of ..
Once that is done, continue:
make make install make clean cd ../disks cp library/* backups/ cd ../.. mv cpmsim ~ cd rm -rf z80pack-1.36
At this point we could now run the as-packaged CP/M 2.2 or CP/M 3.0 system, but we first want to tailor it more to suit our purposes. First, we want to add cpmtools. cpmtools is a nice collection of command-line utilities which understand CP/M file formats and allow you to copy files into or out of a CP/M image file, etc. This makes life much easier when dealing with emulated CP/M systems.
Download cpmtools from http://www.moria.de/~michael/cpmtools/ and build and install it like this:
cd tar -xzf Downloads/cpmtools-2.20.tar.gz cd cpmtools-2.20 ./configure --prefix=${HOME}/local make make install cd rm -rf cpmtools-2.20
Setting up the emulated media
At this point we populate our emulated system with 4 floppies and 3 hard disks:
cd ~/cpmsim cp disks/library/cpm3-1.dsk disks/library/zob-a.dsk cp disks/library/cpm3-2.dsk disks/library/zob-b.dsk ./mkdskimg c ./mkdskimg d mv disks/drivec.dsk disks/library/zob-c.dsk mv disks/drived.dsk disks/library/zob-d.dsk cp disks/library/hd-tools.dsk disks/library/zob-i.dsk ./mkdskimg j ./mkdskimg p mv disks/drivej.dsk disks/library/zob-j.dsk mv disks/drivep.dsk disks/library/zob-p.dsk
This gives us A: through D: which are 8” floppy disks in ibm-3740 format, I: and J: which are 4MB hard disks in z80pack-hd
format, and P: which is a 512MB hard disk in z80pack-hdb
format. A:, B:, I: are a copy of the original content but the others are all empty.
Create a script in the current directory called zob.sh like this:
#!/bin/sh mkdir -p /tmp/.z80pack mkfifo /tmp/.z80pack/auxin mkfifo /tmp/.z80pack/auxout cd ~/cpmsim rm -f disks/drive[abcdijp].cpm for i in a b c d i j p do ln -sf library/zob-$i.dsk disks/drive$i.dsk done ./cpmsim -f4
Don’t forget to make the script executable:
chmod +x zob.sh
Running zob.sh will start an emulated CP/M 3 system at 4MHz with 7 disks. You can exit the emulated environment by using the bye
command.
I recommend setting up a terminal environment to be a more realistic CP/M experience by setting up a shortcut or script to start a terminal with suitable font, font size, colours, and with dimension of 80 columns and 24 rows. If possible, configure it to have ANSI terminal emulation.
At this point, drive I: has
- 0: standard CP/M dev tools
- 1: DRI PL/I 1.3
- 2: Aztec C compiler 1.06D
- 3: DRI Pascal MT+ 5.6.1
- 8: games
Now we start to add some interesting third-party software.
Add Turbo Pascal into user 4 on I:
From http://www.autometer.de/unix4fun/z80pack/index.html, download the disk image which contains Turbo Pascal. From it, extract file tp301a.dsk and place it in the ‘library’ used above. Manually mount it as D: (by temporarily copying tp301a.dsk
into ~/cpmsim/disks/drived.dsk
) and then copy it to drive I: user 4: like so:
A>pip i:[g4]=d:*.* A>I4: 4I>tinst
Select ANSI terminal emulation and a 4MHz clock. Once finished, exit the emulated system by using the ‘bye’ command and then remove the ~/cpmsim/disks/drived.dsk
image, it will be replaced on the next run anyway.
Once that’s done, you’ll be able to run Turbo Pascal in your emulated CP/M system by doing:
A>I4: 4I>turbo
Add SLR ASM into user 0 on I:
Make sure that the cpmtools executables are in your PATH if not already done so:
export PATH=$PATH:$HOME/local/bin
Ensure that you can properly read the HDD image, like this:
cd ~/cpmsim cpmls -F -f z80pack-hd disks/library/zob-i.dsk
This test is important; if you don’t get a meaningful directory listing, you’ve probably got the disk formats wrong in cpmtools diskdefs, fix that before proceeding otherwise you’ll corrupt your virtual media.
The supplied disk images which we’re using as a basis already include Z80ASM by SLR Systems; this is the assembler that we’ll use in these examples. But we don’t yet have the corresponding disassembler so we’ll add it now into disk I: in user 0:.
Download http://www.retroarchive.org/cpm/lang/slrdis.zip
Unzip it, and then do:
cpmcp -f z80pack-hd ~/cpmsim/disks/library/zob-i.dsk z80dis.com 0: cpmcp -f z80pack-hd -t ~/cpmsim/disks/library/zob-i.dsk z80dis.doc 0:
ZDE
We also want to have a good editor for programming. Based on the recommendations at TechTinkering we’ll go with ZDE.
Download http://cpmarchives.classiccmp.org/cpm/Software/WalnutCD/cpm/editor/zde16.lbr
Decompress it with a tool that understands LBR (such as The UnArchiver on macOS, or using unar on Ubuntu via sudo apt install unar
). Then do:
cpmcp -f z80pack-hd ~/cpmsim/disks/library/zob-i.dsk ZDE16.COM ZDENST16.COM 0:
The software is now on our I: drive but we still need to configure it. Start the emulated system and do:
A>i: I>setdef i: I>zdenst16 zde16.com
Select terminal type ANSI and then save and quit, and then do:
I>ren zde.com=zde16.com I>set zde.com [sys]
It should now be usable. To do a save-and-exit, use ESC x. For more keys see TechTinkering.
Usage Example – Assembly Language
First, we want to create a simple “Hello World” in this environment.
Just to be arbitrary, we will develop assembly code on J: in user 7 and Pascal code on J: in user 8.
Start the CP/M simulator using the script shown earlier, with ANSI terminal emulation.
Edit
We use the ZDE editor to create a file called hello.z80
. Of course you can use whatever editor you prefer, bonus points if you can cope with the “ed” editor supplied with CP/M!
A>j7: 7J>zde hello.z80
Enter the following source code and save it using ESC x
org 0100h ; do the print call ld hl,msg call vprint ; exit back to the operating system ld c,0 call 5 halt ; Print a null-terminated string to CONOUT ; HL = Start address of string vprint: ld a,(hl) cp 0 ; terminator? ret z ; return if so inc hl ; bump string pointer push hl ; and save it for later ld e,a ; E = character to print ld c,2 ; C = BDOS conout call 5 pop hl jr vprint msg: db 'Hello',0
Build
We compile hello.z80
using Z80ASM by SLR System. By default, this assembler creates an executable .COM
file in one step.
7J>z80asm hello
Test
Now it is just a simple matter to run the produced binary code in hello.com
.
7J>hello
Disassemble
It can sometimes be handy to disassemble a binary file back to Z80 source. This isn’t quite so useful for your own code but can be very useful when investigating a third-party binary. But in this example we disassemble our own binary file, using Z80DIS by SLR Systems.
The usage of Z80DIS is a little unconventional; in the following example we specify .ccc
after the file name; this is not a file extension but instead is three flags specifying the drive on which the binary is found, where the resultant output should be sent, etc. (Note that we do this example on the C: drive to avoid accidentally overwriting our original source code.)
7J>pip c:=hello.com 7>c: 7C>z80dis hello.ccc
Debug
And of course this web site needs an example of a symbolic debugger! On CP/M 3 I normally use ZSID by Digital Research. This does all the basic things that one needs from a symbolic debugger. For its era, it was a good debugger.
7C>7j: 7J>zsid hello.com
Quick guide to driving ZSID:
- use ‘l’ to list, ‘ls’ to list from address ‘s’ (a hex start address)
- use ‘ds’ to display RAM from address ‘s’ (a hex start address) in both hex and ASCII
- use ‘x’ to examine CPU state including registers
- use ‘t’ to single step; this shows the CPU state and THEN does the step
- use control-c to quit ZSID
Refer to the ZSID manual for more details.
Usage Example – Turbo Pascal
A>j4: 4J>turbo
Edit the source code using keys described at TechTinkering.
To compile and run from RAM just use ‘r’. To compile to a .com
file change the compiler options first.
Future additions
Add WordStar, VisiCalc, and dBase just for the memories.