• Please review our updated Terms and Rules here

CP/M 2.2 Distribution + MDS-800 Emulation

PorkyPiggy

Member
Joined
Jan 11, 2024
Messages
46
Hello,

I have spent the past few days cleaning up two generic CP/M 2.2 disks from Digital Research (DRI). CP/M had generic versions released by DRI to OEMs, similar to the OEM Adaptation Kits for MS-DOS. The generic version of CP/M 2.2 consisted of two disks - the Master Control disk and the Serialization Disk.

1713790494237.png
(Not my disks, photo taken from an auction.)

Unlike MS-DOS 1.x and 2.x OAKs, the CP/M Master Control disks are actually bootable on the Intellec MDS-800, Intel's 8080 development system. I spent days searching the internet for an emulator capable of emulating the MDS-800, and eventually, I found the Z80 Emulator (ZEMU). ZEMU claims to be able to boot DRI's CP/M distributions, but I was unable to get the 2.2 disk to boot straight out of the box. Although it emulates the Intellec FDC, it is configured to use ports starting from 30H, whereas DRI's CP/M BIOS expects ports starting from 78H. Fortunately, ZEMU includes an option to remap the I/O ports, and I spent about three hours figuring out how to use the GUI to remap those ports. After this adjustment, CP/M loaded itself into memory and proceeded to crash immediately after transferring control to the BIOS. After another three hours of learning how to use the built-in debugger, I managed to identify the culprit of the problem - DRI's BIOS calls into the MDS Monitor ROM, which does not exist.

I searched the internet and found one ROM dump, but it was not compatible with the DRI BIOS. I spent the next 30 minutes hacking together a 2KB ROM with all the functionalities necessary for the generic CP/M disk to boot, and to my amazement, it actually worked!

1713791359404.png

Next, I figured I could try serializing and creating my own copy of CP/M, so I loaded up the serialization disk (from @Chuck(G)) and looked around. Immediately, I saw this inside SERIAL.ASM:

Code:
;    Modified for CompuPro by:
;        R.H. Frank
;        Sorcim Corporation
;        April 6, 1981


Ouch! I looked around further and discovered that it's half 8080 and half Z80, clearly not something DRI would have done. Fortunately, the copy of SERIAL.COM on that disk is intact and unmodified. With a bit of work in IDA, I have restored SERIAL.ASM to work with CP/M's built-in assembler and produce the exact same SERIAL.COM binary. It appears that Frank modified it to support double-density disks and hard-code the origin (OEM) number for CompuPro, and in the process, he converted half of it to Zilog mnemonics and changed half of the strings. The restored .ASM isn't original, but given that it assembles back to the original binary, it's good enough for me. I know hardcore collectors will now yell at me, but a binary-matching disassembly is about as close as you can get.

Anyway, here is how you serialize your CP/M disks:

1713792501259.png

You first enter your origin (OEM) number and then the starting serial number. After that, it will continue prompting you for disks while incrementing the serial number. Each time you serialize a disk, the disk in drive A is copied to drive B with a serial number stamped on it. Therefore, remove the Serialization Disk from drive B after you start SERIAL.COM to prevent it from getting overwritten.

Now you may wonder, what are the rest of the files for? They're mostly for building your own MOVCPM from scratch. Essentially, you provide two copies of your BIOS and run the batch file CPMGEN.SUB, which generates a copy of MOVCPM named MOVCPM1.COM. Two copies of the boot sector, BIOS, and CP/M kernel (BDOS + CCP) are needed, each assembled at a different base address (100H bytes apart). This is necessary to determine the bytes to patch when relocating CP/M, by comparing two binaries assembled at different bases.

First, it clears a region of memory, then loads BOOT0, CPSYS0, and BIOS0 into memory according to the on-disk layout. Afterward, it dumps the memory to CPM0.COM and converts it to CPM0.HEX. It performs the same process for BOOT1, CPSYS1, and BIOS1, outputting CPM1.COM and CPM1.HEX. Then, it concatenates the two .HEX files into CPM10.HEX and calls GENMOD to generate CPM10.COM, which includes the relocation information calculated by diffing the first and second halves of CPM10.HEX. After this, it loads CPMOV.HEX into memory followed by CPM10.COM and writes out the final MOVCPM1.COM binary. All of these steps are done via the SUBMIT script CPMGEN.SUB. A sample output looks like this:

Code:
A>submit cpmgen.sub


A>XSUB

A>DDT
DDT VERS 2.2
-F100,20FF,0

-IBOOT0.HEX

-S5C

005C 00 02

005D 42 .

-RD180

NEXT  PC
01D0 0000
-ICPSYS0.HEX

-S5C

005C 00 02

005D 43 .

-R200

NEXT  PC
17B3 0000
-IBIOS0.HEX

-R200

NEXT  PC
1A6E 0000
-G0


(xsub active)
A>SAVE 26 CPM0.COM
A>DDT
DDT VERS 2.2
-F100,20FF,0

-IBOOT1.HEX

-S5C

005C 00 02

005D 42 .

-RD180

NEXT  PC
01D0 0000
-ICPSYS1.HEX

-S5C

005C 00 02

005D 43 .

-R100

NEXT  PC
17B3 0100
-IBIOS1.HEX

-R100

NEXT  PC
1A6E 0000
-G0


(xsub active)
A>SAVE 26 CPM1.COM
A>GENHEX CPM0.COM

HEX FILE WRITTEN
(xsub active)
A>GENHEX CPM1.COM 100

HEX FILE WRITTEN
(xsub active)
A>PIP CPM10.HEX = CPM0.HEX,CPM1.HEX

(xsub active)
A>GENMOD CPM10.HEX CPM10.COM

REL MOD END  1A00
REL MOD SIZE 1D7F
ABS MOD END  267F
MODULE CONSTRUCTED
(xsub active)
A>SAVE 38 CPM10.COM
A>DDT CPM10.COM
DDT VERS 2.2
NEXT  PC
2700 0100
-F100,7FF,0

-ICPMOVE.HEX

-S5C

005C 00 02

005D 43 .

-R

NEXT  PC
2700 0000
-G0


(xsub active)
A>SAVE 38 MOVCPM1.COM

The biggest problem with building MOVCPM is that you need to supply your own BIOS0.HEX and BIOS1.HEX. This is rather obvious - DRI's BIOS was only targeted at the MDS-800, and if you are releasing an OEM version of CP/M, you likely won't be targeting the MDS-800. Therefore, you need to write your own BIOS. However, if you are targeting the MDS-800 for some reason, you can simply release the generic DRI binaries. Nevertheless, if you want to build MOVCPM for the MDS-800 using the DRI-supplied BIOS, you'll need to modify one line and use the macro assembler MAC. Interestingly, DRI's BIOS doesn’t use the BIAS equate, which is defined and needed for producing two Intel HEX objects at different addresses. You must change line 27 from:

Code:
    org    patch

to

Code:
    org    patch+bias

And then you can set BIAS to 0 for BIOS0.HEX and 100H for BIOS1.HEX. If you don't make the above change, the 2 objects will have the same base address and therefore not work. This is the only way of making it work, and the resulting MOVCPM1.COM matches the original MOVCPM.COM, so DRI left out the "+bias" for the BIOS on purpose.

And then you can set BIAS to 0 for BIOS0.HEX and 100H for BIOS1.HEX. If you don't make the above change, the two objects will have the same base address and will therefore not work. This is the only way to make it work, and the resulting MOVCPM1.COM matches the original MOVCPM.COM, indicating that DRI intentionally omitted the "+bias" for the BIOS.

This pretty much sums up what I have been working on in the last few days. Creating a copy of CP/M from scratch in the intended/DRI way was an interesting adventure.

Downloads

ZEMU - http://www.z80.info/zip/zemu.zip (Windows only)
ZEMU config files - (attached) zemu_mds-800_package.zip
  • Apply mds-800.reg after you install ZEMU, this configures everything for you (too many things to configure by hand).
  • Run ZEMU.
  • Go to File -> Load As ROM and select stub_mds-800_rom.bin, then click OK.
  • Go to File -> Load I/O Port ReMap and select mds-800.iom.
  • Go to Disks -> A: and Disks -> B:, to select disk images for drives A and B.
  • Click "Boot" on the main window to start the emulation.
  • You will need to do this every single time you start ZEMU.
CP/M 2.2 MDS-800 disk images - (attached) cpm_2.2_generic.zip
  • The Master Control disk originated from Don Maslin's archive within the Sydex folder, so it's actually from @Chuck(G). It came with a serial number, which I have removed, enabling the MOVCPM built from scratch to run without the classic synchronization (serial mismatch) error. Freshly built MOVCPMs do not contain serial numbers (not even in the version field of the S/N), suggesting that the original Master Control disks likely also lacked serial numbers, as evidenced by the empty serial field on disk labels.
  • The Serialization Disk was uploaded by @Chuck(G). I have cleaned it up and restored SERIAL.ASM to the best of my abilities.
MDS-800 BIOS HEX files - (attached) bios_mds_hex.zip
  • Copy these to the Serialization Disk if you don't want to modify BIOS.ASM and build them yourself.

Requests

I'm sure I've overcomplicated things while trying to emulate the MDS-800 because ZEMU claims to emulate "Intellec FDCs (single density, MDS-800; and double density Intellec Series II) to run ISIS and CPM 1.3, 1.4 and 2.2 original DRI ditributions". Even if it doesn't just work out of the box, I shouldn't need to write a ROM myself tailored for the hypothetical "real hardware" emulated by ZEMU, so I might have missed something important. If anyone knows of other emulators capable of emulating the MDS-800, or how to get it working under ZEMU with fewer steps, please let me know.

Also, as you can see, we don't have true original copies of the generic disks. The Master Control disk was stamped with a serial number, and the Serialization Disk has a modified SERIAL.ASM. I would strongly prefer original, unmodified versions. Additionally, we only have the generic disks for version 2.2, so DRI distributions of versions 1.3 through 2.0 are also welcome.

Sincerely,
Pig
 

Attachments

  • cpm_2.2_generic.zip
    86.3 KB · Views: 1
  • zemu_mds-800_package.zip
    2.6 KB · Views: 2
  • bios_mds_hex.zip
    1.7 KB · Views: 1
Believe it or not, MP/M was actually bootable (with distro disks) on the MDS-800. 2 console configuration.

That the standard CP/M distro worked on the MDS should surprise no one. How do you think we got the thing going on our own hardware?
 
Believe it or not, MP/M was actually bootable (with distro disks) on the MDS-800. 2 console configuration.

That the standard CP/M distro worked on the MDS should surprise no one. How do you think we got the thing going on our own hardware?
I knew that of course, that's why I tried to get it to boot under emulation in the first place. I wasn't surprised by the fact that it's bootable, by "to my amazement, it actually worked" I was referring to my 20-line hacked up ROM :).

Sincerely,
Piggy
 
Ah, so you're not running a real MDS-800? I remember having to bootstrap a new hardware platform with 5.25" GCR disks. It took some doing. What made things more interesting is that the ROMs in the new machine expected a different filesystem to load the boot (which was in Intel HEX format). Took a bunch of code to get the thing to work.
On the new system, everything was interrupt-driven, even the display refresh. I still have the BIOS assembly code--all 4,113 lines of it.
 
Last edited:
Ah, so you're not running a real MDS-800? I remember having to bootstrap a new hardware platform with 5.25" GCR disks. It took some doing. What made things more interesting is that the ROMs in the new machine expected a different filesystem to load the boot (which was in Intel HEX format). Took a bunch of code to get the thing to work.
On the new system, everything was interrupt-driven, even the display refresh. I still have the BIOS assembly code--all 4,113 lines of it.
What system was that for @Chuck(G)?
 
I believe the F-85 was launched in either late 1978 or early 1979. It's hard for me to remember the official launch date because we had a number of beta test sites going on That we had quad-density (100 tpi) 5.25" floppies was somewhat remarkable then, just short of a megabyte apiece. The 4 port async comms were Signetics 2651s. If you had the bisync option, that was done by a 8251A using DMA. The printer itself was another 8085 with its own RAM and ROM shared with the CRTC and a separate driver board with the TO-3 packages for the motors and hammers. The carriage motor was a Litton DC servo with encoder, much like the Diablo Hitypes. The paper adavance was a stepper that could step a half-dot for the multipasss NLQ fonts. Main boards were based on Multibus (but not exact copies of the signals), with the smaller add-ons perched on S-100 sized boards behind the floppy disks. Power supply was a switch mode unit by Boschert. It was a pretty cramped package--cooling was by an AC fan located on the right side of the card cage. The case itself is painted high-density polyurethane foam--the color looks the same today.

I recall that the printer transistor heatsink was acquired through an after-work exchange over at Walker's Wagon Wheel in Mountain View.

It was a pretty hefty package--and a challenge to lift at my now advanced age. Somewhere on the web, there's an ad photo of a young lady holding the machine. Galyn was a very healthy lass from Marketing who could helt the system for about 30 seconds at a time and still smile (or grimace, depending on your viewpoint). The bulging veins in her neck were retouched out. Somewhat later, another model was selected, with the system perched on a stand, with the stand retouched out.

I'm less proud of the Poppy. We relied too mch on external vendor development (Intel for the not-quite-ready-for-prime-time CPUs and the 286 Xenix kernel) It all worked and much of the software was ported over to other Unix/Xenix setups until the early 2000s.

At about the time Molecular collapsed, I was already back in supercomputers.
 
Last edited:
I have reconstructed the 1.4 distribution disks! Now we finally have a generic MDS-800 version of CP/M 1.4 and build tools for MOVCPM to play around with!

1714018848731.png

CP/M 1.4 did not come with XSUB, so you can't just use a script to get your customized MOVCPM built. The commands are also somewhat different, as the boot sector contains 2 smaller programs - MBOOT and LBOOT. The MDS-800 ROM loads the boot sector at address 0x3000, which is a part of the system area for the default 16K CP/M distribution, so it needs to be moved down to 0x80. LBOOT is the actual boot program, and MBOOT moves LBOOT from 0x3000 down to 0x80.

Code:
A>ddt

DDT VERS 1.4
-f100,20ff,0

-imboot.hex

-rd180

NEXT  PC
019E 0000
-ilboot0.hex

-r11e

NEXT  PC
01E3 0000
-icpsys0.hex

-r200

NEXT  PC
16C2 0000
-ibios0.hex

-r200

NEXT  PC
18E7 0000
-g0


A>save 24 cpm0.com

A>ddt

DDT VERS 1.4
-f100,20ff,0

-imboot.hex

-rd180

NEXT  PC
019E 0000
-ilboot1.hex

-r11e

NEXT  PC
01E3 0000
-icpsys1.hex

-r100

NEXT  PC
16C2 0000
-ibios1.hex

-r100

NEXT  PC
18E7 0000
-g0


A>save 24 cpm1.com

A>genhex cpm0.com


HEX FILE WRITTEN
A>genhex cpm1.com 100


HEX FILE WRITTEN
A>pip cpm10.hex = cpm0.hex,cpm1.hex


A>genmod cpm10.hex cpm10.com


REL MOD END  1800
REL MOD SIZE 1AFF
ABS MOD END  23FF
MODULE CONSTRUCTED
A>save 35 cpm10.com

A>ddt cpm10.com

DDT VERS 1.4
NEXT  PC
2400 0100
-icpmove.hex

-r

NEXT  PC
2400 0000
-g0


A>save 35 movcpm1.com

Serialization works in the same way as 2.2, except the origin (OEM number) is only a single byte. This suggests that CP/M 1.4 was licensed to < 255 OEMs.

1714019289564.png

Downloads

CP/M 1.4 distribution disks - (attached) cpm_1.4_distribution.zip
  • New set of reconstructed distribution disks.
  • Files on the Master Control disk are original, the disk image itself is reconstructed.
  • Files on the Serialization Disk are all reconstructed, based on source listings or reverse engineering, or taken directly from 2.2.
CP/M 2.2 distribution disks - (attached) cpm_2.2_distribution.zip
  • Fixed some minor issues with my SERIAL.ASM reconstruction.

Sincerely,
Pig
 

Attachments

  • cpm_1.4_distribution.zip
    138.8 KB · Views: 1
  • cpm_2.2_distribution.zip
    174.8 KB · Views: 1
Back
Top