|| | | | | | | ||
The RC700 was basically designed as a CP/M-80 computer although it could be used with stand-alone systems like RC COMAL-80 and UCSD Pascal. The most common CP/M version for RC700 was CP/M version 2.2 and while the source code for CP/M 2.2 has been released to the public domain the BIOS for the RC700 was proprietary and has never officially been released by Regnecentralen. The BIOS was custom-made for the RC700, and contains the code for interfacing CP/M to the RC700 hardware.
I have reconstructed the original source for the RC700 CP/M BIOS based on information from DDHF's archives, and I would like to thank Dansk Datahistorisk Forening (DDHF) for their kind support. I think that preserving and restoring the software for these old computers is as important as preserving the hardware. The RC700 CP/M BIOS source code gives a unique insight into state-of-the-art systems programming for micro computers in the early 80ies.
The CP/M operating system was designed to run on a variety of different 8080-based micro computers, so an interface between the operating system and the hardware was needed. CP/M was divided into four parts, called the Basic Input/Output System (BIOS), the Basic Disk Operating System (BDOS), the Console Command Processor (CCP), and the Transient Program Area (TPA). The BIOS was a hardware-dependent module that defined the low level interface with the RC700 hardware. The BDOS interfaced to the BIOS through a jump table at the beginning of the BIOS. The CCP was used for interpreting and executing commands from the command line, and the TPA was the memory area used for running application programs.
The RC700 autoloader (see below) loads the BIOS (including the INIT code) from disk into memory and calls the entry point in the INIT code. This sets up the hardware and then loads the BDOS into memory. After initialization, the INIT portion is no longer needed, and it is overwritten by the BDOS. The BDOS then communicates with the hardware through the BIOS.
At one of my visits to DDHF, I stumbled upon a printout of the source code for the RC700 BIOS. This was not the original version, but a custom version that was patched to work with a RC700 with two extra YD-380 floppy drives. The printout belonged to Peter Heinrich who had obtained this copy from a RC technician. The patches seem to have been made by someone with the initials "TFj" in 1987. Although this version has been patched, the original source code is preserved in comments throughout the code, so the original code could be reconstructed from the patched version.
The RC700 BIOS was originally implemented in 1982 by Karsten Dindorp and Hugo K., but has been modified a number of times to fix bugs and implement support for new hardware, notably support for RC703 computers and RC763 hard disks, by people with the initials SC, VN, FK, and LO. Please let me know if you know any of these people. Then I can update this page with their real names so they can get due credit for their contributions. In the printout, "Hugo K." is truncated, so I don't know the full name of Hugo.
Binary versions of the RC700 BIOS has survived on the RC700 floppy images, and the binary machine code can be read from cylinder 0 of these images as documented in the source code.
DDHF was very kind and lent me the printout so I could make a high-resolution scan of it. I ran this through an OCR program to get the source code text, but the OCR program did not preserve the formatting of the text. Also, the OCR quality was pretty poor on source code text, so it required quite a bit of manual editing of the text to restore it to look like the original from the printout. After this process, I had a machine-readable version of the original source code for the RC700 CP/M BIOS. The printout is not of the source code itself but a listing file (.LST) output by the assembler. This shows that it was assembled using the Microsoft MACRO-80 Assembler, so I tried to assemble the reconstructed source code using M80 but this produced a lot of error messages, so it was not quite ready for making a RC700 CP/M BIOS from source code.
Since I had the binary machine code version from the floppy disk images, I knew the exact result that was expected as the output of the assembler. However, the version on the floppy disk images is for an earlier version of the BIOS (RC700 56k CP/M vers.2.2 rel.2.1), whereas the printout is based on 'RC703 56k CP/M vers. 2.2 rel 1.1', so in order to get a working version of the source code for the BIOS, I decided to reconstruct the 'RC700 56k CP/M vers.2.2 rel.2.1' version from the source code. By assembling the source code and comparing it byte-by-byte with the binary version from the floppy disk images, I could detect all the differences between the original version and the version produced from the source code.
All the patches made by TFj were clearly marked in the text and the original source code was preserved in comments, so these were easy to revert. However, there were still a number of differences between the assembled version and the original binary version, so I had to manually track these down and try to reconstruct the source code for the original version. In order to save space, absolute jumps had been replaced by relative jumps, so I reverted these. The diffs also revealed a number of OCR errors which were easy to fix. There were also some more substantial changes where I have tried to reconstruct the original source code. This is not an exact process, but I have strived to preserve the original code style and add comments in the same spirit as the rest of the source code, preserving the 80ies 'Danglish' comment style. Even though I cannot claim that this is a 100% correct reconstruction of the original source code, I believe that 97% or more of the BIOS source code is original.
I now have a version of the source code that can exactly produce the original BIOS from RC700 56k CP/M vers.2.2 rel.2.1. The source code listing contains include directives that indicate that the original source code was divided into a number of source files. I have split the source code into these files. The listing does not contain any clues to the name of the top-level assembler file, so I have just named it BIOS.MAC.
The BIOS can be built using the Microsoft MACRO-80 Assembler and the CP/M linker:
M80 BIOS.REL,BIOS.LST=BIOS.MAC LINK BIOS.BIN=BIOS.REL[LD0000
This produces a binary image, BIOS.BIN, that can be written to cylinder 0 on the boot disk.
In order to build this on a floppy-based system you need two disks: one for the source code (B:), and another for the assembler and linker (A:). You can use the emulator to build the BIOS from source code:
Please be patient when assembling the source code on the emulator. It takes a few minutes to complete. The emulator runs at roughly realtime speed, so this should be comparable to the time it would have taken on a real RC700 back in the 80ies.
A bootstrap loader is needed to boot CP/M on a RC700 computer. The RC702 has a 2KB ROM with an autoloader program for booting the computer. When the RC702 is reset, the lower 2K of the memory is mapped to the boot ROM, enabling the system to start the autoloader program. The ROM can be disabled using an OUT 0x18,A instruction, making the full 64K RAM available. The autoloader is responsible for loading the operating system from disk into memory. The autoloader initializes the hardware to a known state, and then reads the first track of the floppy disk (or hard disk) into memory at address 0x0000.
On one of the disks I got from DDHF, I found a source code listing of the autoloader for the RC700:
;************************************************************************ ;* * ;* AUTOLOAD-FILE FOR THE RC700 AND RC703 MICROCOMPUTER * ;* * ;* REGNECENTRALEN OCTOBER 1982 JOS * ;* * ;************************************************************************ ...
M80 ROB358.REL,ROB358.LST=ROB358.MAC LINK ROB358.ROM=ROB358.REL[LD000
; RC COMPUTER 23.04.83 25.06.82 15.09.82 ; 23.10.82 05.01.83 ; ; SUBJECT: RC700 CP/M BASIS SOFTWARE ; ; AUTHOR: KARSTEN DINDORP & HUGO K. ; ; HARD DISK CORRECTIONS: SC & VN JUNE 82 ; ; This program consists of: ; ; 1. Hardware initiatization routines ; ; 2. CP/M BIOS ; ; and constitutes the basis software for the CP/M operating system ; on the RC700 micro computer. ; ; The program resides on cylinder 0 of a RC700 CP/M system discette, ; and is loaded into RAM from address 0000 and forward, when the ROM ; bootstrap loader is activated by a hardware reset. ; ; UPGRADES: 1: Support of 16 bit sector number. ; 2: Support of upto 4 Winchester drives. ; 3: Support all tracks on floppy disks. ; 4: Alternative register set not used. ; 5: Alternative hard disk configuration. ; 6: Warm boot from hard disk drive C ; ; The format of TRACK 0 is as follows: ; ; SECTOR BYTE CONTENTS ; 01 000-001 Start address. Entered from ROM bootstrap loader. ; 01 002-007 0 ; 01 008-013 ' RC702' ; 01 014-127 not used. Reserved for ROM bootstrap loader. ; 02 000-127 configuration parameters. ; 03 000-127 output conversion table. ; 04-05 000-127 input conversion table. ; 06- and forward Hardware initialization routines and CPM BIOS. ; .Z80 TITLE RC702 CP/M BASIS SOFTWARE RELEASE 1.1 83.01.05 SUBTTL GLOBAL CONSTANT DEFINITION PAGE ;======================================================== ;= I/O ADDRESSES = ;======================================================== PIOAC EQU 12H ; PIO CHANNEL A CONTROL PIOAD EQU 10H ; PIO CHANNEL A DATA PIOBC EQU 13H ; PIO CHANNEL B CONTROL PIOBD EQU 11H ; PIO CHANNEL B DATA CTCCH0 EQU 0CH ; CTC CHANNEL 0 CTCCH1 EQU 0DH ; CTC CHANNEL 1 CTCCH2 EQU 0EH ; CTC CHANNEL 2 CTCCH3 EQU 0FH ; CTC CHANNEL 3 SIOAC EQU 0AH ; SIO CHANNEL A CONTROL SIOAD EQU 08H ; SIO CHANNEL A DATA SIOBC EQU 0BH ; SIO CHANNEL B CONTROL SIOBD EQU 09H ; SIO CHANNEL B DATA CTC2C0 EQU 44H ; CTC 2 CHANNEL 0 CTC2C1 EQU 45H ; CTC 2 CHANNEL 1 CTC2C2 EQU 46H ; CTC 2 CHANNEL 2 CTC2C3 EQU 47H ; CTC 2 CHANNEL 3 HDDARG EQU 60H ; WD1000 DATA REGISTER HDERRG EQU 61H ; WD1000 ERROR REGISTER (READ ONLY) HWPCMP EQU HDERRG ; WD1000 WRITE PRECOMP. REGISTER (WRITE ONLY) HSECCT EQU 62H ; WD1000 SECTOR COUNT HSECNO EQU 63H ; WD1000 SECTOR NUMBER HCYLLO EQU 64H ; WD1000 CYLINDER NO. LOW HCYLHI EQU 65H ; WD1000 CYLINDER NO. HIGH HSZDHD EQU 66H ; WD1000 SIZE/DRIVE/HEAD REGISTER HDSTRG EQU 67H ; WD1000 STATUS REGISTER (READ ONLY) HCMDRG EQU HDSTRG ; WD1000 COMMAND REGISTER (WRITE ONLY) PAGE DMAC EQU 0F8H ; DMA CONTROL DMAMOD EQU 0FBH ; DMA MODE REGISTER DMAMAS EQU 0FAH ; DMA MASK REGISTER DMAAD0 EQU 0F0H ; ADDRESS REGISTERS DMAAD1 EQU 0F2H ; DMAAD2 EQU 0F4H ; DMAAD3 EQU 0F6H ; DMACN0 EQU 0F1H ; WORD COUNT REGISTERS DMACN1 EQU 0F3H ; DMACN2 EQU 0F5H ; DMACN3 EQU 0F7H ; DMACBC EQU 0FCH ; CLEAR BYTE COUNTER DMAREQ EQU 0F9H ; DMAMSK EQU 0FFH ; DMATMP EQU 0FDH ; DSPLC EQU 001H ; DISPLAY CONTROL DSPLD EQU 000H ; DISPLAY DATA FDC EQU 004H ; FLOPPY CONTROL FDD EQU 005H ; FLOPPY DATA BELL EQU 01CH ; SW1 EQU 014H ; PAGE ;======================================================== ;= RAM LAYOUT DEFINITION = ;======================================================== MSIZE EQU 56 ; AVAILABLE MEMORY EXCL. BIOS BIAS EQU (MSIZE-20)*1024 ; CPMB EQU 3400H+BIAS ; CCP BASE CCPCLR EQU CPMB+03H ; CCP-START ADDRESS +3 CPML EQU 1600H ; LENGTH OF CCP AND BDOS BDOS EQU CPMB+806H ; BDOS BASE BIOS EQU CPMB+CPML ; BIOS BASE BUFF EQU 80H ; DMA BUFFER IOBYTE EQU 3 ; CDISK EQU 4 ; CURRENT LOGGED IN DISK NSECTS EQU CPML/128 ; LENGTH OF CCP AND BDOS IN 128 BYTES SECTORS CBOOT EQU 280H ; ROM BOOTSTRAP LOADER ENTRY POINT PATCH1 EQU CPMB+144CH ; FIRST PATCH ADDRESS TO WBOOT FROM HD PATCH2 EQU CPMB+149AH ; SECOND DO. START EQU 0D480H ; START OF CODE (INIT + BIOS) BGSTAR EQU 0F500H ; START OF BACKGROUND BITTABLE ENDPRG EQU 0EE80H ; RESERVED AREA FOR BIOS VARIABLES ISTACK EQU BGSTAR+250+38 ; STACK USED BY INTERRUPT ROUTINES STACK EQU ISTACK+96 ; STACK USED BY BIOS DRIVERS OUTCON EQU 0F680H ; OUTPUT CONVERSION TABLE INCONV EQU OUTCON+128 ; INPUT CONVERSION TABLE DSPSTR EQU 0F800H ; DISPLAY REFRESH MEMORY BASE CCTAD EQU DSPSTR+2001 ; COLUMN COUNT RCTAD EQU CCTAD+1 ; ROW COUNT CURSY EQU RCTAD+2 ; CURSUR Y POSITION LOCBUF EQU CURSY+1 ; DISPLAY BUFFER LOCATION XFLG EQU LOCBUF+2 ; XY ADDRESSING MODE FLAG LOCAD EQU XFLG+1 ; LOCATION OF CHAR USHER EQU LOCAD+2 ; OUTPUT CHARACTER POSITION BGFLG EQU USHER+1 ; BACKGROUND FLAG: ; 0 - AFTER CLEAR SCREEN ; 1 - AFTER SET FOREGROUND ; 2 - AFTER SET BACKGROUND LOCBBU EQU BGFLG+1 ; ADR0 EQU LOCBBU+2 ; FIRST BYTE OF ADDRESS IN XY ADDRESSING EXCNT0 EQU ADR0+1 ; EXIT ROUTINE 0 COUNT EXCNT1 EQU EXCNT0+2 ; EXIT ROUTINE 1 COUNT DELCNT EQU EXCNT1+2 ; DELAY COUNT EXROUT EQU DELCNT+2 ; JMP TO EXIT ROUTINE 1 FDTIMO EQU EXROUT+2 ; LOAD VALUE OF EXCNT1 RTC0 EQU 0FFFCH ; REAL TIME CLOCK RTC1 EQU 0FFFDH ; RTC2 EQU 0FFFEH ; RTC3 EQU 0FFFFH ; PAGE ;======================================================== ;= FLOPPY DRIVER VARIABLES = ;======================================================== HSTBUF EQU ENDPRG+1 ; HOST DISK DMA BUFFER DIRBF EQU HSTBUF+512 ; SCRATCH DIRECTORY AREA ALL0 EQU DIRBF+128 ; ALLOCATION VECTOR DRIVE 0 CHK0 EQU ALL0+71 ; CHECK VECTOR DRIVE 0 ALL1 EQU CHK0+32 ; ALLOCATION VECTOR DRIVE 1 CHK1 EQU ALL1+71 ; CHECK VECTOR DRIVE 1 ALVHD EQU CHK1+32 ; ALLOCATION VECTOR FOR 5 LOG.HARD DSK UNITS SEKDSK EQU ALVHD+71+(4*63) ; SEEK DISK NUMBER SEKTRK EQU SEKDSK+1 ; SEEK TRACK NUMBER SEKSEC EQU SEKTRK+2 ; SEEK SECTOR NUMBER HSTDSK EQU SEKSEC+2 ; HOST DISK NUMBER HSTTRK EQU HSTDSK+1 ; HOST TRACK NUMBER HSTSEC EQU HSTTRK+2 ; HOST SECTOR NUMBER LSTDSK EQU HSTSEC+2 ; LAST DISK SEEKED LSTTRK EQU LSTDSK+1 ; LAST TRACK SEEKED SEKHST EQU LSTTRK+2 ; SEEK SHR SECSHF HSTACT EQU SEKHST+2 ; HOST ACTIVE FLAG HSTWRT EQU HSTACT+1 ; HOST WRITTEN FLAG UNACNT EQU HSTWRT+1 ; UNALLOCATED REC COUNT UNADSK EQU UNACNT+1 ; LAST UNALLOCATED DISK UNATRK EQU UNADSK+1 ; LAST UNALLOCATED TRACK UNASEC EQU UNATRK+2 ; LAST UNALLOCATED SECTOR UNAMSK EQU UNASEC+2 ; LAST UNALLOCATED SECTOR MASKED ERFLAG EQU UNAMSK+1 ; ERROR FLAG RSFLAG EQU ERFLAG+1 ; READ SECTOR FLAG READOP EQU RSFLAG+1 ; 1 IF READ OPERATION WRTYPE EQU READOP+1 ; WRITE OPERATION TYPE DMAADR EQU WRTYPE+1 ; LAST DMA ADDRESS FORM EQU DMAADR+2 ; POINTER TO FORMAT BLOCK CFORM EQU FORM+2 ; CURRENT FORMAT EOTV EQU CFORM+1 ; LAST SECTOR ON TRACK DRNO EQU EOTV+1 ; HIGHEST DRIVE NO UNK1 EQU DRNO+1 ; ??? UNK2 EQU UNK1+1 ; ??? UNK3 EQU UNK2+1 ; ??? UNK4 EQU UNK3+1 ; ??? DSKNO EQU UNK4+1 ; CURRENT DISK DSKAD EQU DSKNO+1 ; CURRENT DMA ADDRESS ACTRA EQU DSKAD+2 ; ACTUAL (NOT CPM) TRACK NO IN READ/WRITE ACSEC EQU ACTRA+1 ; ACTUAL (NOT CPM) SECTOR NO IN READ/WRITE REPET EQU ACSEC+1 ; REPEAT COUNTER IN READ/WRITE RSTAB EQU REPET+1 ; RESULT TABLE MHDTSR EQU RSTAB+8 ; MIRROW OF WD1000 STATUS REGISTER MHDERR EQU MHDTSR+1 ; MIRROW OF WD1000 ERROR REGISTER HERRCT EQU MHDERR+1 ; WD1000 ERROR COUNTER SP_SAV EQU HERRCT+2 ; SYSTEM STACK POINTER SAVE AREA HD_FLG EQU SP_SAV+2 ; WD1000 BUSY FLAG (0=BUSY) HD_OFL EQU HD_FLG+1 ; OFFLINE/ONLINE FLAG (1=OFFLINE) FL_FLG EQU HD_OFL+1 ; FLOPPY BUSY FLAG (0=BUSY) WBFLAG EQU FL_FLG+1 ; WARMBOOT FLAG PAGE ;======================================================== ;= ACTUAL FLOPPY SYSTEM PARAMETERS = ;= INITIALIZED WHEN SELECT_DISK IS CALLED = ;======================================================== DPBLCK EQU WBFLAG+1 ; DISK PARAM BLOCK CPMRBP EQU DPBLCK+2 ; CP/M RECORDS PR. BLOCK CPMSPT EQU CPMRBP+1 ; CP/M SECTORS PR. TRACK SECMSK EQU CPMSPT+2 ; SECTOR MASK SECSHF EQU SECMSK+1 ; SECTOR SHIFT COUNT TRANTB EQU SECSHF+1 ; SECTOR TRANSLATION TABLE DTLV EQU TRANTB+2 ; DATA LENGTH DSKTYP EQU DTLV+1 ; DISK TYPE (0:=FLP, FF:=HARD) DUM EQU DSKTYP+6 ; FILLER TO OBTAIN 16 BYTE LENGTH ;============================================================================== ;= WD1000 MACRO COMMAND DEFINITIONS = ;============================================================================== RSTCMD EQU 10H ; RESTOTE COMMAND RDCMD EQU 28H ; READ SECTOR WITH DMA COMMAND WRTCMD EQU 30H ; WRITE SECTOR COMMAND FMTCMD EQU 50H ; FORMAT TRACK COMMAND SEEKCM EQU 70H ; SEEK COMMAND PAGE INCLUDE BIOSTYPE.MAC INCLUDE INIPARMS.MAC CONVTA: INCLUDE DANISH.MAC INCLUDE INIT.MAC DS (BIOS-$) ; ALIGN TO DA00H INCLUDE CPMBOOT.MAC INCLUDE SIO.MAC INCLUDE DISPLAY.MAC INCLUDE FLOPPY.MAC INCLUDE HARDDSK.MAC INCLUDE DISKTAB.MAC INCLUDE INTTAB.MAC INCLUDE PIO.MAC END