Cocoacrumbs

Cocoacrumbs

All of the buildings, all of those cars
were once just a dream
in somebody's head
Mercy Street - Peter Gabriel

Cocoacrumbs

12 minutes read

Pic 1

Intro

I got in a nostalgic mood lately, thinking about the long gone days when I made a Z80 slave CPU for my BBC model B computer and ported CP/M 2.2 (and later ZCPR3) to it as well.

Me, decades ago, with a BBC model B and home build Z80 slave CPU (grey box at the front) at the CP/M user group stand of the yearly HCC gathering.

RetroComputing seems to be on the rise as well and quite some kits are offered to bring back the computer experience of those long gone days. For the Z80, perhaps the most successful kit is the RC2014 project which can be found on Tindie.

If you don’t want to jump directly into old hardware, there are plenty of software options that bring back the old days on your modern PC. The one I’m currently looking at is RunCPM that runs on a desktop PC (Linux, Windows or macOS) but also on a number of (modern) embedded development boards like the Arduino Due.

In this blog post I’ll into what it takes to get RunCPM running on a Linux PC and the Arduino Due.

Linux

To get started we need to clone the RunCPM repo [at your preferred location of your hard disk]:

git clone https://github.com/MockbaTheBorg/RunCPM.git -v

results in this output (I cloned the RunCPM repo in my Documents folder):

[koen@manjaro-3900X Documents]$ git clone https://github.com/MockbaTheBorg/RunCPM.git -v
Cloning into 'RunCPM'...
POST git-upload-pack (165 bytes)
remote: Enumerating objects: 22, done.
remote: Counting objects: 100% (22/22), done.
remote: Compressing objects: 100% (18/18), done.
remote: Total 2650 (delta 8), reused 12 (delta 4), pack-reused 2628
Receiving objects: 100% (2650/2650), 3.85 MiB | 5.16 MiB/s, done.
Resolving deltas: 100% (1832/1832), done.
[koen@manjaro-3900X Documents]$

Next we need to navigate to the folder where the make files are stored:

cd RunCPM/RunCPM

To build RunCPM for Linux, we need to issue this command:

make posix build

This will build RunCPM on your PC. If the build fails, this might be because development tools like the GCC C compiler, linker, ncurses, etc. are not installed. Installing the missing packages should solve any build problems you encounter.

After a successful build, you should find a new file in the directory you’re currently in, named RunCPM (without any extension and around 93 KByte in size).

We can already try to run RunCPM by issuing the following command:

./RunCPM

You will be greeted with this screen:

CP/M 2.2 Emulator v4.4 by Marcelo Dantas
      Build Aug 21 2020 - 16:21:11
-----------------------------------------
CCP : CCP-DR.60K   CCP Address: 0xe400

RunCPM Version 4.4 (CP/M 2.2 60K)
Unable to load CP/M CCP.
CPU halted

We see that RunCPM indeed starts up but can’t find the necessary code of the CP/M CCP (in this case it wants the CCP-DR.60K CCP).

To avoid messing up the RunCPM git repo, I prefer to move the RunCPM executable we just build to another location and add the missing pieces there. With the following 2 commands I create a RunCPM_testArea directory in the Documents directory (next to the already existing RunCPM directory) and copy the RunCPM executable to the RunCPM_testArea directory:

mkdir ~/Documents/RunCPM_testArea
cp RunCPM ~/Documents/RunCPM_testArea/

Now we need to copy the missing CCP-DR.60K code. Luckily this is part of the git repo we cloned earlier and we can copy it with this command (assuming you’re still in the directory where you build RunCPM):

cp ../CCP/CCP-DR.60K ~/Documents/RunCPM_testArea/

If we would now start RunCPM we would see that the CCP is indeed loaded but could not find any disk drive:

CP/M 2.2 Emulator v4.4 by Marcelo Dantas
      Build Aug 21 2020 - 16:21:11
-----------------------------------------
CCP : CCP-DR.60K   CCP Address: 0xe400

RunCPM Version 4.4 (CP/M 2.2 60K)

Bdos Error on A : Select

Adding a disk drive to RunCPM is very simple (and one of its strong points IMHO). We simply create a new folder with the letter of the disk drive we want to use next to the RunCPM executable. However, since RunCPM version 3.7, user areas are mandatory. In practise this means that we need to create a sub directory in each “disk drive” directory as well which we simply name it as 0:

mkdir ~/Documents/RunCPM_testArea/A
mkdir ~/Documents/RunCPM_testArea/A/0

Now we need to add some files to our disk drive. The git repo already contains a zipped sample A drive. We can unzip and put the unzipped files in the correct place with this command:

unzip ../DISK/A.ZIP -d ~/Documents/RunCPM_testArea/A/0/

Now we navigate to the directory containing the RunCPM executable:

cd ~/Documents/RunCPM_testArea/

And start up RunCPM. With the dir command we can list the files of drive A to verify if everything works:

CP/M 2.2 Emulator v4.4 by Marcelo Dantas
      Build Aug 21 2020 - 16:21:11
-----------------------------------------
CCP : CCP-DR.60K   CCP Address: 0xe400

RunCPM Version 4.4 (CP/M 2.2 60K)

A>dir
A: 1STREAD  ME  : ASM      COM : BDOS     ASM : BDOS     LUA
A: BDOS     SUB : BDOSEQU  LIB : CAL      COM : CCP-ZCP3 BIN
A: CCP      ASM : CCP      SUB : CCPZ     SUB : CCPZ     Z80
A: CLEAN    SUB : CONSOLE7 COM : CONSOLE7 Z80 : CONSOLE8 COM
A: CONSOLE8 Z80 : DDT      COM : DISKDEF  LIB : DISPLAY  LIB
A: DUMP     ASM : DUMP     COM : ED       COM : EXIT     COM
A: EXIT     SUB : EXIT     Z80 : FORMAT   COM : FORMAT   SUB
A: FORMAT   Z80 : HELLO    LUA : INFO     COM : INFO     SUB
A: INFO     Z80 : LOAD     COM : LU       COM : LUA      COM
A: LUA      SUB : LUA      Z80 : LUAINFO  LUA : MAC      COM
A: MAKEFCB  LIB : MBASIC   COM : MLOAD    ASM : MLOAD    COM
A: MLOAD    DOC : MOVCPM   COM : OPCODES  DOC : PIP      COM
A: RSTAT    COM : RSTAT    SUB : RSTAT    Z80 : STAT     COM
A: SUBMIT   COM : SUBMITD  COM : SYSGEN   COM : TE       COM
A: UNARC    COM : UNCR     COM : USQ      COM : XMODEM   COM
A: XSUB     COM : Z2HDR    LIB : Z3BASE   LIB : Z3HDR    LIB
A: Z80ASM   COM : Z80ASM   PDF : Z80CCP   ASM : Z80CCP   SUB
A: ZCPR2    ASM : ZCPR2    SUB : ZCPR3    ASM : ZCPR3    SUB
A: ZEXALL   COM : ZEXDOC   COM : ZSID     COM : ZTRAN    COM
A>

Let’s try out Microsoft Basic which we can find on the drive as the file MBASIC.COM:

A>mbasic
BASIC-85 Rev. 5.29
[CP/M Version]
Copyright 1985-1986  $  by Microsoft
Created: 28-Jul-85
34872 Bytes free
Ok
10 for i=1 to 10
20 print "Hello World"
30 next i
list
10 FOR I=1 TO 10
20 PRINT "Hello World"
30 NEXT I
Ok
run
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Hello World
Ok
SYSTEM

RunCPM Version 4.4 (CP/M 2.2 60K)

A>

ZCPR3

ZCPR is a replacement for the CP/M CCP which offers quite some new, interesting features:

  • shells
  • aliases
  • I/O redirection
  • flow control
  • named directories
  • search paths
  • custom menus
  • passwords
  • on line help

ZCPR3.3 also includes a full complement of utilities with considerably extended capabilities.

Very convenient, the ZCPR3 CCP is also part of the git repo (as the file CCP-ZCP3.60K). However, we do need to recompile the RunCPM executable to select the ZCPR3 CCP instead of the default CCP-DR.60K (which is the CP/M 2.2 CCP).

For this we need to modify the globals.h file. When you open globals.h you will find these lines:

/* Definition of which CCP to use (must define only one) */
//#define CCP_INTERNAL	// If this is defined, an internal CCP will emulated
#define CCP_DR
//#define CCP_CCPZ
//#define CCP_ZCPR2
//#define CCP_ZCPR3
//#define CCP_Z80

To select the ZCPR3 CCP, we make the following modifications:

/* Definition of which CCP to use (must define only one) */
//#define CCP_INTERNAL	// If this is defined, an internal CCP will emulated
//#define CCP_DR
//#define CCP_CCPZ
//#define CCP_ZCPR2
#define CCP_ZCPR3
//#define CCP_Z80

Now we recompile the RunCPM executable again in the same way as we did earlier and copy the new executable to our test directory. Executing RunCPM now shows this greeting:

CP/M 2.2 Emulator v4.4 by Marcelo Dantas
      Build Aug 21 2020 - 17:16:53
-----------------------------------------
CCP : CCP-ZCP3.60K   CCP Address: 0xdc00

RunCPM Version 4.4 (CP/M 2.2 60K)

A0>dir
1STREAD .ME   |  ASM     .COM  |  BDOS    .ASM  |  BDOS    .LUA
BDOS    .SUB  |  BDOSEQU .LIB  |  CAL     .COM  |  CCP-ZCP3.BIN
CCP     .ASM  |  CCP     .SUB  |  CCPZ    .SUB  |  CCPZ    .Z80
CLEAN   .SUB  |  CONSOLE7.COM  |  CONSOLE7.Z80  |  CONSOLE8.COM
CONSOLE8.Z80  |  DDT     .COM  |  DISKDEF .LIB  |  DISPLAY .LIB
DUMP    .ASM  |  DUMP    .COM  |  ED      .COM  |  EXIT    .COM
EXIT    .SUB  |  EXIT    .Z80  |  FORMAT  .COM  |  FORMAT  .SUB
FORMAT  .Z80  |  HELLO   .LUA  |  INFO    .COM  |  INFO    .SUB
INFO    .Z80  |  LOAD    .COM  |  LU      .COM  |  LUA     .COM
LUA     .SUB  |  LUA     .Z80  |  LUAINFO .LUA  |  MAC     .COM
MAKEFCB .LIB  |  MBASIC  .COM  |  MLOAD   .ASM  |  MLOAD   .COM
MLOAD   .DOC  |  MOVCPM  .COM  |  OPCODES .DOC  |  PIP     .COM
RSTAT   .COM  |  RSTAT   .SUB  |  RSTAT   .Z80  |  STAT    .COM
SUBMIT  .COM  |  SUBMITD .COM  |  SYSGEN  .COM  |  TE      .COM
UNARC   .COM  |  UNCR    .COM  |  USQ     .COM  |  XMODEM  .COM
XSUB    .COM  |  Z2HDR   .LIB  |  Z3BASE  .LIB  |  Z3HDR   .LIB
Z80ASM  .COM  |  Z80ASM  .PDF  |  Z80CCP  .ASM  |  Z80CCP  .SUB
ZCPR2   .ASM  |  ZCPR2   .SUB  |  ZCPR3   .ASM  |  ZCPR3   .SUB
ZEXALL  .COM  |  ZEXDOC  .COM  |  ZSID    .COM  |  ZTRAN   .COM
A0>

RunCPM on an Arduino Due

Interestingly, RunCPM has been ported to run on a few embedded development platforms as well like the Arduino Due I discuss here. This gives you a more realistic experience on how it was to use a CP/M system back in the days. E.g. slower terminals, small disks, primitive editing, no copy/paste, etc.

If you start from a virgin Arduino IDE, you might need to install the Arduino Due Board package first (use the Board manager... menu option for this).

Compiling RunCPM for the Arduino Due is rather easy and can be done with the free Arduino Due IDE. Simply open the RunCPM.ino file in the Arduino IDE:

Arduino IDE with the RunCPM.ino file opened.

We do need to make a small modification in the RunCPM.ino file. By default, the esp32 platform is included while we need the Arduino Due platform. Simply modify line 13 from

#include "hardware/esp32.h"

to

#include "hardware/due.h"

as shown here as well:

Include the 'due.h' file instead of 'esp32.h'.

Needed libraries

Since SD cards are used to emulate the disk drives, we need the SdFat library to be present in the Arduino IDE.

Install the SdFat library'.

Compile error…

Now we can compile the code but I encountered this error:

/tmp/arduino_build_320087/sketch/hardware/due.h:4:1: error: 'SdFatEX' does not name a type
 SdFatEX SD;
 ^

This was easily fixed in the hardware/due.h file as follows. Change this line:

SdFatEX SD;

to

SdFat SD;

And now we get a successful compile which can be uploaded to the Arduino Due.

Preparing the SD card

The next step is connecting the SD Card reader to your Arduino Due. The easiest for me is to refer to the “Arduino Due CP/M Personal Computer” article explaining how to wire the SD Card shield to the Arduino Due

The SD Card needs to be formatted as FAT32 (obviously since we needed to use the SdFat library). If you already tried out RunCPM on Linux (like above) then you already have one or more folders prepared as disk drives. You can simply copy those over to the FAT32 formatted SD card.

Don’t forget to copy the CCP of your choice (e.g. CCP-DR.60K, CCP-ZCP3.60K, …) at the root of the SD Card as well.

Trying it out.

Now we’re ready to try everything out. Make sure you have installed everything that is needed on your SD Card. I.e. at the root, your preferred CCP like CCP-ZCP3.60K and the A and 0 sub directories filled with the files you want.

Upload the binary created by the Arduino IDE to the Arduino Due.

Start up a terminal emulator, e.g. Minicom. On Linux, you would use this command (assuming /dev/ttyACM0 is the USB port that is in use for the serial monitor):

minicom -b 9600 -o -D /dev/ttyACM0

And you get greeted by:

CP/M 2.2 Emulator v4.4 by Marcelo Dantas
Arduino read/write support by Krzysztof Klis
      Build Aug 21 2020 - 18:50:20
--------------------------------------------
CCP: CCP-ZCP3.60K    CCP Address: 0xdc00
BOARD: ARDUINO DUE
Initializing SD card.

RunCPM Version 4.4 (CP/M 2.2 60K)

A0>dir
1STREAD .ME   |  ASM     .COM  |  BDOS    .ASM  |  BDOS    .LUA
BDOS    .SUB  |  BDOSEQU .LIB  |  CAL     .COM  |  CCP-ZCP3.BIN
CCP     .ASM  |  CCP     .SUB  |  CCPZ    .SUB  |  CCPZ    .Z80
CLEAN   .SUB  |  CONSOLE7.COM  |  CONSOLE7.Z80  |  CONSOLE8.COM
CONSOLE8.Z80  |  DDT     .COM  |  DISKDEF .LIB  |  DISPLAY .LIB
DUMP    .ASM  |  DUMP    .COM  |  ED      .COM  |  EXIT    .COM
EXIT    .SUB  |  EXIT    .Z80  |  FORMAT  .COM  |  FORMAT  .SUB
FORMAT  .Z80  |  HELLO   .LUA  |  INFO    .COM  |  INFO    .SUB
INFO    .Z80  |  LOAD    .COM  |  LU      .COM  |  LUA     .COM
LUA     .SUB  |  LUA     .Z80  |  LUAINFO .LUA  |  MAC     .COM
MAKEFCB .LIB  |  MBASIC  .COM  |  MLOAD   .ASM  |  MLOAD   .COM
MLOAD   .DOC  |  MOVCPM  .COM  |  OPCODES .DOC  |  PIP     .COM                                                                                
RSTAT   .COM  |  RSTAT   .SUB  |  RSTAT   .Z80  |  STAT    .COM                                                                                
SUBMIT  .COM  |  SUBMITD .COM  |  SYSGEN  .COM  |  TE      .COM                                                                                
UNARC   .COM  |  UNCR    .COM  |  USQ     .COM  |  XMODEM  .COM                                                                                
XSUB    .COM  |  Z2HDR   .LIB  |  Z3BASE  .LIB  |  Z3HDR   .LIB                                                                                
Z80ASM  .COM  |  Z80ASM  .PDF  |  Z80CCP  .ASM  |  Z80CCP  .SUB                                                                                
ZCPR2   .ASM  |  ZCPR2   .SUB  |  ZCPR3   .ASM  |  ZCPR3   .SUB                                                                                
ZEXALL  .COM  |  ZEXDOC  .COM  |  ZSID    .COM  |  ZTRAN   .COM                                                                                
A0>

As you can see, I’m using ZCPR3 here and instead of the A> we see here a A0> indicating we’re on the A drive, user area 0.

Faster terminal output.

By default, the terminal is set to 9600 baud. You might find this too slow (although this was a fairly typical baud rate at that time, for years I had to use a mere 300 baud…). You can increase this to e.g. 115200 baud by again modifying the RunCPM.ino file on line 22 like this:

// Serial port speed
#define SERIALSPD 9600

to:

// Serial port speed
#define SERIALSPD 115200

recompile and upload to the Arduino Due and use this command line for minicom:

minicom -b 115200 -o -D /dev/ttyACM0

Have fun exploring the CP/M world of yesteryear!

Recent posts

See more

Categories

About

Cocoacrumbs