In this post, I run CP/M on the RC2014
While browsing around Grant Searle’s website looking at his Z80 projects one day, I stumbled upon his CP/M project and it sounded like a great idea to reproduce this on the RC2014.
CP/M is a disk operating system that was popular from the 1970s to the 1980s. It was particularly popular on 8-bit microprocessor platforms such as the 8080 and the Z80. There were also variants for the 8086 processor. People who grew up with MSDOS, but never experienced CP/M, will probably feel that DOS resembles CP/M in many ways.
By running CP/M on our RC2014, we can get access to a wide variety of software — from programming languages (Basic, Forth, C) to games like Zork. Access to a disk allows permanent store of programs and data.
RC2014 Modifications required
To run CP/M on the RC2014, it’s going to take several modifications:
- Replace the default 68B50 serial board with a SIO board
- Replace the individual RAM and ROM boards with a banked RAM/ROM board
- Add a CompactFlash board
Why we need the Banked RAM/ROM board
The default RC2014 used a single ROM and a single RAM chip. The ROM occupied addresses 0000h to 2000h (8KB) and the RAM occupied addresses 8000h to FFFFh (32KB). This was perfect for the BASIC interpreter since we could easily fit the interpreter into 8KB of ROM, and 32KB was plenty of space for holding out BASIC program. For CP/M there are two issues:
- 32KB of RAM is more restrictive than we’d like
- CP/M wants locates operating system data at 0h and programs at 100h, which is smack in the middle of the RC2014’s default ROM.
So the approach that we’re going to use is to boot from ROM (still at 0000h), load the CP/M BIOS and runtime into high RAM at E1600h and D000h respectively, jump into high RAM to continue executing, and finally replace the low ROM with a second RAM chip. We boot off ROM, but we end up in a state where we have all 64K of address space occupied by RAM.
Design of the Banked RAM/ROM board
The basis for this came from Grant Searle’s CPM project, though I have made a few modifications. I wanted it to be easily possible to switch back to ROM under program control, and to bank switch in additional RAM chips if we wanted to. Here is my schematic:
There are a total of two RAM chips, IC1 and IC2. IC2 is always active and is addressed from 8000h to FFFFh. IC1 is only active after it has been bank switched in and is active from 0000h to 7FFFh. We could have lowered the chip count by using a single 64KB RAM chip and playing a few different tricks with the addressing, but I already had 62256 32KB RAM chips, and decided to optimize keeping my inventory simple.
IC5 is a 64KB EPROM. It’s also addressed a 0000h. There are some jumpers to the A14 and A15 pins of the EPROM that allow us to map in a 16KB chunk out of the 64KB EPROM. This allows us an easy way for us to store four different programs in the ROM and select which one by moving jumpers about. Spencer did the same thing with the RC2014’s 64 KB ROM board.
So the trick, and the purpose of the other four ICs, is to be able to selectively switch between the EPROM, IC5, and the low RAM chip, IC1. We start with a 74HCT238E 3-to-8 decoder (NOTE: a 74HCT138 might also work and simplify inventory requirements; need to try this). This sets a port that can be used to control the bank switching. The addressing is a little bit different that my other 74HCT138-based boards in that I spaced the addressing ranges 8h apart. You can put the bank-select port at 0h, 8h, 10h, 18h, 20h, 28h, 30h, or 38h. I did this to maintain compatibility with Grant Searle’s CP/M design, which places the bank switch address at 38h.
Writing to the bank select port clocks D0 and D1 into a pair of flipflops on a 74HC84N. The RC2014’s RESET pin is connected to the clear pin of the flipflops, so that a reset will always reset the flipflops back to zero. This allows us to write any of four values — 0, 1, 2, or 3 — to the flipflops and will serve as our bank select. The default is zero.
The output of these flipflops is used as the input to a 74HCT139N dual 2-to-4 decoder. When A15 is high, it will cause the 74HCT139 to assert low one of four outputs based on the value it’s currently receiving from the flipflops. Output 0 is connected to the ROM. Output 1 is connected to the RAM. Outputs 2 and 3 are connected to a header to allow additional RAM chips to be added at a later date.
The second half of the 74HCT139N is wired up to function as an inverter. I needed an inverter to invert A15 so that it could drive the IC2 from 8000h to FFFFFh. Rather than add a 7404 of inverter for this purpose, I figured out how to repurpose the unused half of the 74HC139.
To make a long story short:
- On reset, the EPROM (IC5) is selected
- If you write a 0 to the bank select port, the EPROM (IC5) is selected
- If you write a 1 to the bank select port, the LOW RAM (IC1) is selected
- If you write a 2 to the bank select port, pin 1 of JP3 is selected, to support an external RAM chip
- If you write a 3 to the bank select port, pin 2 of JP3 is selected, to support an external RAM chip
Here’s how the CP/M boot sequence works:
- The ROM loads the CP/M runtime and BIOS into RAM at D000h and E600h respectively. The entrypoint to start CP/M is at FFFEh.
- The ROM then jumps to RAM at address FFFEh
- The CPM bios writes 1 to port 38h. This causes the ROM to be deselected and the low RAM to be selected in it’s place. This selection remains in effect until the board is reset (or some program writes a different value to port 38h).
- We’re now running entirely in 64KB RAM. The ROM is completely out of the picture.
Here is a picture of the completed RAM/ROM board
Modifications to CP/M
I made a few modifications to Grant Searle’s CP/M monitor, BIOS, and other support tools.
- I put the compactlflash at port E0h instead of at port 10h. I like keeping the 00h-79h range free for peripherals like IO boards and such.
- I put the SIO/2 at port 80h instead of port 0h. This is for the same reason as above.
- I significantly increased the size of the serial receive buffer. Flow control isn’t working for me, and XMODEM transfers were overflowing the buffer at its original size.
- Optionally, I have support for my CTC board at 90h. This is a work in progress and it to allow baud rates other than 115,200.
- I modified the bootstrap procedure that loads download.com and the format tool to load from 8100h instead of 4100h.
Installing CP/M on the RC2014
I followed the instructions on Grant Searle’s page, and things went amazingly well and trouble free
- Hardware Configuration for RC2014
- SIO/2, CompactFlash, and Banked RAM/ROM board installed
- Monitor ROM installed
- Format the Flash Card
- Boot to monitor
- paste form64.hex into monitor
- type “G8100”
- (note: assumes smbaker’s changes that relocate from64 from 4100h to 8100h)
- Install CP/M
- Boot to monitor
- paste cpm22.hex
- paste cbios64.hex
- paste putsys.hex
- type “G8100”
- (note: assumes smbaker’s changes that relocate putsys from 4100h to 8100h)
- Boot into CP/M the very first time
- Boot into monitor
- Press “X” (boot to CPM)
- Press “Y” (confirm boot)
- You’re now staring at the A> prompt
- Install Download.com
- Press RC2014 reboot button while CPM is running. This will boot to the monitor.
- Paste down8100.hex
- (note: assumes smbaker’s change that relocates download.hex from 4100h to 8100h)
- Type “GFFE8”. This will cause the monitor ROM to bank switch, and automatically copy down8100.hex from 8100h to 100h
- You should be starting at the A> prompt again
- Type “SAVE 2 DOWNLOAD.COM”
- This will cause the program that is currently located at 100h to be saved to disk under the name “DOWNLOAD.COM”
At this point, you have a minimally functional CP/M system, with a single program called DOWNLOAD.COM that you can use to download other programs into the RC2014. Grant Searle’s page has links to a bundle of useful tools (LOAD, SUBMIT, DISPLAY, PIP, STAT, DDT, DUMP, ED, ASM). I recommend installing all of these, as they are pretty useful.
I also found it very handy to install XMODEM, since my terminal program has a built-in XMODEM client. I found some XMODEM source in a google thread at https://groups.google.com/forum/#!topic/comp.os.cpm/-oI2ydzFrC8. There were a few issues I had to fix in this XMODEM program to get it to work on my CP/M RC2014. These are documented in patches/xmodem.patch in my RC2014 github repo. The two primary issues I ran into were a stack overrun which forced me to relocate where xmodem was storing its stack, and a call to RXTIMR that was causing the receive routine to prematurely terminate.
Once XMODEM is installed, it’s a simple matter to upload additional software like this:
- type this: “xmodem filename.ext /r /x0”
- initiate an xmodem upload in your terminal
The /R instructs xmodem to operate in receive mode. The /X0 tells it to transfer using the CP/M console.
CP/M Software Resources
There are several sites with useful resources on the web. At RetroArchive you can find Zork 1-3, a variety of programming languages including Microsoft Basic, etc. Note that some of this appears to be commercial software (for example, Turbo Pascal) so I haven’t provided direct links here. Note that there is both -86 software and -80 software on this site. For a Z80, you’ll want the -80 software.
cpm.z80.de is another resource, and has programming languages, tools, emulators, etc. There seems to be a lot more -86 software here than -80 software though.
Bill of Materials
- pcboard, Osh-Park
- 40-pin right handle 0.100″ male header
- 2×8 pin 0.100″ male header
- (3) 1×3 pin 0.100″ male header
- (2) 62256 static RAM
- EPROM, 27C512 suggested, others may work
- (5) 0.1uF capacitor
- IC sockets as desired (probably smart to at least socket the EPROM)
RAM/ROM PCBoard Ordering
As usual there’s an Osh Park link for ordering the banked RAM/ROM board:
As with all the other boards, I don’t make any money from this. I’ve just made the boards available on Osh Park for anyone else who wants them.
To order the other boards (SIO, CompactFlash), see my other blog posts.