Home| Sanos| RC702| Rita| Documents| Links| Contact| Search|

RC700 CP/M BIOS


 

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.

 

CP/M architecture

 

FFFFH
BIOS DA00H
BDOS INIT D480H
CC00H
CCP C400H
TPA 0100H
0000H

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.

 

History

 

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.

 

Reconstruction

 

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.

 

Reverse engineering

 

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.

 

Source code

 

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.

BIOS.MACMAIN SOURCE FILE FOR RC700 CP/M BIOS
BIOSTYPE.MACBIOS CONFIGUATION PARAMETERS
INIPARMS.MACHARDWARE INITIALIZATION PARAMETERS
DANISH.MACDANISH INPUT/OUTPUT CONVERSION TABLES
INIT.MACHARDWARE INITIALIZATION CODE
CPMBOOT.MACCP/M BIOS JUMP TABLE AND BIOS EXTENTIONS
SIO.MACZ-80 SIO DRIVER
DISPLAY.MACDISPLAY DRIVER
FLOPPY.MACFLOPPY DISK DRIVER
HARDDSK.MACWINCHESTER DISK DRIVER
DISKTAB.MACDISK DEFINITION TABLES
INTTAB.MACINTERRUPT TABLE
PIO.MACZ-80 PIO DRIVER

 

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.

 

Autoloader

 

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					*
;*									*
;************************************************************************ 

...

The ROB358 boot ROM is a newer version than the ROA375 I originally used in the RC700 emulator. I have made a build disk for the ROB358 autoloader, so it can be built from source code:

M80 ROB358.REL,ROB358.LST=ROB358.MAC
LINK ROB358.ROM=ROB358.REL[LD000
ROB358 supports booting from the hard disk, so the emulator can now boot directly from the hard disk, and this is now the default boot ROM in my RC700 emulator.

; 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