; ; ################################################# ; # KAYPRO II (pre 84) CBIOS source # ; # Supports RAM DISK as drive C: # ; # # ; # Written by # ; # Mike Liddle 1st March 1984 - June 1986 # ; # # ; # For Digital Research CP/M Version 2.2 # ; ################################################# ; ;*************************************************************************** ; ; CR EQU 0DH LF EQU 0AH ; ; MSIZE EQU 63 ;63 kilobyte system memory size ;Ram support routines use an extra K BIAS EQU (MSIZE-20)*1024 CCP EQU 03400H + BIAS ;Base of CCP in CP/M BDOS EQU CCP + 806H ;Base of BDOS BIOS EQU CCP + 1600H ;Base of BIOS BIOSTK EQU 0FC00H ;Top of temporary stack used by BIOS INDMA EQU 0FC14H ;Used to pass DMA address to ROM CDISK EQU 00004H ;Address of last logged disk IOBYTE EQU 00003H ;CP/M control of I/O vectors ; ; NUDISKS EQU 2 ;Number of disks in system NSECTS EQU (BIOS-CCP)/128 ;Warm start sector count ; ; DNAME EQU 'C' ;DRive name of RAMDRIVE. DNUMB EQU DNAME - 'A' ;RAMDRIVE drive number ; ; TPA EQU 07H ; Extended addr. of main ram PIODATA EQU 01EH ; SYSPIO port B data PIOCTRL EQU 01FH ; SYSPIO port B control MODE3 EQU 0CFH ; Mode3 = Control IOMASK EQU 0F8H ; Bits 0,1,2 as output. Rest as input. ; ;************************************************************************** ; ; Jump vector for individual routines ; ORG BIOS JP BOOT ;Cold start WBOOTE JP WBOOT ;Warm start JP CONST ;Console status JP CONIN ;Console character in JP CONOUT ;Console character out JP LIST ;List character out JP PUNCH ;Punch character out JP READER ;Reader character out JP HOME ;Move head to home position JP SELDSK ;Select disk JP SETTRK ;Set track number JP SETSEC ;Set sector number JP SETDMA ;Set DMA address JP READ ;Read disk JP WRITE ;Write disk JP LISTST ;Return list status JP SECTRAN ;Sector translate ; ;************************************************************************** ; DEFIO DB 081H ;Default I/O vectors for IOBYTE WSAFE DB 000H ;Write safe flag #00 = No #FF = Yes ;Cursor key - FUNC DB 00BH ; Up ctrl-K DB 00AH ; Down ctrl-J DB 008H ; Left ctrl-H DB 00CH ; Right ctrl-L ;Blue numeric keys - DB 030H ; 0 DB 031H ; 1 DB 032H ; 2 DB 033H ; 3 DB 034H ; 4 DB 035H ; 5 DB 036H ; 6 DB 037H ; 7 DB 038H ; 8 DB 039H ; 9 DB 02DH ; - DB 02CH ; , DB 00DH ; DB 02EH ; . DBAUD DB 005H ;Default baud rates for serial ports = 300 ; ;*************************************************************************** ; ; This table defines how much of the extra 191K (256-64) of ram ; is used as a RAM disk. Each bank has an entry showing how many ; 'tracks' are available and the address of the bank. ; BLEN DB 32/TRAKLN,00H ; RAM DISK in banks 0 through 5 DB 32/TRAKLN,01H ; Lower 32K of TPA is bank 7 DB 32/TRAKLN,02H ; Upper 32K of TPA is bank 6 DB 32/TRAKLN,03H ; Upper 32K cannot be switched out DB 32/TRAKLN,04H DB 32/TRAKLN,05H DB 0 ; end of table ; ;*************************************************************************** ; ; BOOT - cold start ; BOOT CALL Init XOR A ;Put a zero to make LD (CDISK),A ;A: the default drive at startup LD A,(DEFIO) ;Default vectors for LD (IOBYTE),A ;input and output. LD A,(DBAUD) ;Default rate for OUT (0),A ;Baud clock (=300). CALL string ;Output to screen hello message hello DB 01AH ;Clear screen DB 'Kaypro 83 series CBIOSR',CR,LF DB ' * 191K Ram Drive C: * ',CR,LF DB '(c)Michael Liddle 1986.',CR,LF,00H setresv LD A,0C3H ;Initialise Jump to LD HL,WBOOTE ;warm boot vector LD (0),A ;Jump goes LD (1),HL ;into address 0-2 LD HL,BDOS LD (5),A ;Addresses 4-6 contains LD (6),HL ;Jump to BDOS LD A,(4) ;Get default drive LD C,A JP CCP ;Control jumps to CP/M CCP ; ; WARM BOOT ; WBOOT CALL init CALL string ;Tell user that we are warm booting wbmess DB CR,LF,'Warm Boot',CR,LF,00H getcpm LD SP,00100H ;Stack goes below TPA = disk buffer LD C,0 CALL seldsk ;Boot from drive A LD BC,0 CALL settrk ;Start with track 0 LD HL,CCP ;Read CCP and BDOS LD (INDMA),HL ;Address where CP/M is to go LD BC, NSECTS*256 + 1 ;B counts sectors to read C is next sector ;Start on sector 1 as sector 0 contains ;cold start loader (or info for it anyway) rdtrk PUSH BC ;save BC CALL setsec ;Position head and tell it what to do CALL read ;Read sector POP BC ;Get back BC OR A ;Zero? = success JR NZ,getcpm ;If no then try again otherwise LD HL,(INDMA) ;Having read sector get dma address LD DE,080H ;and move dma address up by 128 bytes ADD HL,DE ;ready to read next sector LD (INDMA),HL ; XOR A ;zero LD (CCP + 7),A ;Clear CCP command line, length set = 0 DEC B ;?Total of 44 sectors read? (tracks 0 & 1) JP Z,setresv ;If yes get us out of wboot by way ;of end of cold boot INC C ;otherwise add 1 to sector to read LD A,028H ;40 sectors read? CP C ;have we done it? JP NZ,rdtrk ;jump if still sectors to read on track 0 LD C,010H ;On track 1 start read at sector 010 = 16 ;as sectors 0 to 15 are directory info PUSH BC ;Save BC LD C,1 ;Track 1 CALL settrk ;position head over new track POP BC ;get BC back JR rdtrk ; ; CONST - console status ; CONST LD HL,MTRST INC (HL) CALL Z,mtroff ;don't wear out discs waiting for user LD A,(3) ;Get IOBYTE AND 3 LD L,033H ;romio 00033 - RS232C JP Z,romio LD L,02AH ;romio 0002A - Keyboard JP romio ; ; CONIN - console character in (result in Reg A) ; CONIN CALL mtroff ;don't wear out discs waiting for user LD A,(3) ;Get iobyte AND 3 ; LD L,036H ;Romio 00036 - Keyboard JP Z,romio ; LD L,02DH ;Romio 0002D - RS232C input CALL romio ; OR A RET P AND 01FH LD HL,FUNC LD C,A LD B,0 ADD HL,BC LD A,(HL) RET ; ; CONOUT - Display byte in A on monitor/punch ; CONOUT LD A,(IOBYTE) ;Get IOBYTE AND 3 ; LD L,039H ;romio 00039 - RS232C JP Z,romio ; LD L,045H ;romio 00045 - Video JP romio ; ; ; READER - paper tape reader in (result to reg A) ; READER LD L,036H ;romio 00036 JP romio ; ; PUNCH - punch out (char in reg c) ; PUNCH LD L,039H ;romio 00039 - punch JP romio ; ; LIST - list out (char in reg c) ; LIST LD A,(3) AND 0C0H LD L,039H ;romio 00039 - list JP Z,romio ; LD L,03FH ;romio 0003F - punch CP 080H JP Z,romio ; LD L,045H ;romio 00045 - video CP 040H JP Z,romio ; LD L,039H ;romio 00039 - punch JP romio ; ; ; LISTST - list status ; LISTST LD A,(3) ;Get IOBYTE AND 0C0H ; LD L,042H ;romio 00042 - RS232C JP Z,romio ; LD L,03CH ;romio 0003C - List CP 080H JP Z,romio ; XOR A ;Zero returned RET ; ; HOME - move to track 00 ; HOME LD A,(DISK) ;CHECK DISK NUMBER. CP DNUMB ;IS IT THE RAMDRIVE? JP NZ,home1 ;IF NOT, LET BIOS HANDLE IT. LD A,0 ;SET "TRACK" TO 0 LD (XTRAK),A RET home1 LD L,00CH ;romio 0000C JP romio ; ; SELDSK - select disk given by reg c ; SELDSK LD A,C ;CHECK REQUESTED DISK, LD (DISK),A CP DNUMB JP NZ,Seldsk1 LD HL,DPH ;RETURN DISK PAR. HEADER. RET seldsk1 LD L,00FH ;romio 0000F JP romio ; ; SETTRK - set track address for subsequent r/w ; SETTRK LD A,(DISK) CP DNUMB JP NZ,Settrk1 LD A,C ;TRACK NO. LD (XTRAK),A RET settrk1 LD L,012H ;romio 00012 JP romio ; ; SETSEC - set sector address ; SETSEC LD A,(DISK) CP DNUMB JP NZ,SetSec1 LD (SECTOR),BC RET setsec1 LD L,015H ;romio 0000F JP romio ; ; SETDMA - set subsequent dma address (initially 80H) ; SETDMA LD (DMAADR),BC ;SAVE DMA ADDR. BOTH HERE LD L,018H ;and in BIOS romio 00018 JP romio ; ; READ - read track/sector to present dma address ; READ LD A,(DISK) CP DNUMB JP NZ,read1 LD BC,(SECTOR) ; but we asssume sector fits in one byte LD A,(XTRAK) ;SET EXTENDED ADDRESS. LD B,A CALL MAP ; to compute bank and offset CALL SWAP EX DE,HL LD DE,RAMBUF ;TEMPORARY BUFFER. LD BC,128 ;SECTOR=128 BYTES. LDIR LD A,TPA ;RESET ADDR. CALL SWAP LD HL,RAMBUF ;MOVE FROM BUFFER LD DE,(DMAADR) ; back to main ram LD BC,128 LDIR XOR A ; show no errors RET read1 LD L,01BH ;romio 00018 JR romio ; ; WRITE - write track/sector from present dma address ; WRITE LD A,(DISK) CP DNUMB JP NZ,Write1 LD HL,(DMAADR) ;DMA --> BUFFER LD DE,RAMBUF LD BC,128 LDIR ; LD BC,(SECTOR) ; but we assume sector < 256 LD A,(XTRAK) LD B,A CALL MAP CALL SWAP LD HL,RAMBUF ;BUFFER --> RAMDRIVE. LD BC,128 LDIR ; LD A,TPA CALL SWAP XOR A ; show no error RET write1 LD L,01EH ;romio 0001E LD A,(WSAFE) OR A JR Z,romio LD C,1 JR romio ; ; SECTRAN - translate sector BC using table at DE ; SECTRAN LD A,(DISK) CP DNUMB JP NZ,Sectr1 LD H,B LD L,C RET sectr1 LD L,021H ;romio 00021 JR romio ; ; I/O routines done by ROM. ; ROMIO EXX ;Sloppy way of saving registers IN A,(01CH) SET 7,A ;Bank 1 of memory OUT (01CH),A ;Selected LD (SAVESP),SP ;Save stack pointer LD SP,BIOSTK ;Top of scratchpad stack LD DE,romret ;Put return address on stack for ROM PUSH DE EXX ;Registers back (alternate set corrupted) LD H,0 ;HL select ROM routine e.g. sectran 00021 JP (HL) ;Transfer control to ROM Romret EX AF,AF' ;Sloppy save of AF pair LD SP,(SAVESP) ;Reset old stack pointer IN A,(01CH) RES 7,A ;Back to memory bank 0 OUT (01CH),A EX AF,AF' ;Get back AF pair RET ;exit via address left on stack ;by calling routine ; ; INITIALISE disks ; Init LD L,003H ;romio 00003 - warm reset JP romio ; ; MTROFF - don't wear out discs waiting for user ; MTROFF IN A,(01CH) ;Find what is already set SET 6,A ;Set motor control bit - turns off motor OUT (01CH),A ;and send to system port RET ; ; STRING - display text on screen ; string EX (SP),HL ;Get start of string LD A,(HL) ;get a character INC HL ;point to next character/instruction EX (SP),HL ;put address onto stack OR A ;zero indicates end of string RET Z ;and (SP) contains return address LD C,A ;communicate in reg C CALL conout ;send it to conout screen JR string ;process next byte ; ;************************************************************************** ; ; Subroutine to calculate RAM address and bank ; ; called with B = track number (starts from 0) ; C = sector number (starts from 0) ; ; returns with A = extended address byte ; DE = offset into bank for start of sector ; MAP XOR A ; clear A LD A,B ; track number to A LD DE,2 ; increment for BLEN table LD HL,BLEN ; map1 SUB (HL) ; subtract bank length in K's JR C,MAP2 ; jump if track in this bank ADD HL,DE ; point to next BLEN entry JR MAP1 ; repeat till done ; map2 ADD A,(HL) ; A = relative track number in bank RLCA ; multiply by 4K RLCA RLCA RLCA LD E,D ; clear E LD D,C ; multiply sector number by 128 RR D RR E ADD A,D ; add to track starting address LD D,A ; DE = sector start in bank INC HL LD A,(HL) ; A = extended (bank) address RET ; ; This is where banks are switched. Register A contains the ; bank to be selected. ; SWAP LD C,A ; Save bank LD A,Mode3 ; Set up PIO for bank select OUT (PIOCtrl),A ; Mode 3 LD A,IOMask OUT (PIOCtrl),A ; Bits 0,1,2 are output LD A,C ; Bank 7 selected for TPA OUT (PIOData),A RET ; ;************************************************************************** ; ; DATA STORAGE AREA ; MTRST DB 00H ;0CFH SAVESP DW 0000H ;0EF3BH ; ; DISK DB 0 XTRAK DB 0 DMAADR DW 80H SECTOR DW 0 ; ;************************************************************************** ; ; DISK PARAMETER HEADER FOR RAMDRIVE ; DPH DW 0 ;NO SECTOR TRANSLATION DW 0,0,0 ;SCRATCH DW DIRBUF ;LOC. OF SCRATCHPAD AREA. DW DPB ;DISK PARAMETER BLOCK DW CSV ;DIR. CHECK AREA DW ALV ;ALLOC. VECTOR. ; ; DISK PARAMETER BLOCK ; TRAKLN EQU 4 ;Kilobytes per track DIRECT EQU 32 ;No. of directory entries. ; DPB DW (1024*TRAKLN)/128 ;SECTORS PER TRACK DB 3 ;BSH DB 7 ;BLM DB 0 ;EXM DSM DW 191 ;MAX BLOCK NO. DW DIRECT-1 ;HIGHEST DIRECT. NO. ; AL0 EQU LOW (0FFH SHL (8-DIRECT/32)) AL1 EQU 0 ; DB AL0,AL1 ; Directory blocks. ; CKS EQU 0 ; Check directory entries. ; DW CKS DW 0 ; No skipped tracks. ; CSV DS DIRECT/4 ; This could be zero since the ram is ; 'fixed'. ALV DS 32 ; This is allocation vector space which ; must have 1 bit available per block. ; this value corresponds to 256 1K ; blocks - more than needed! ; ; Instead of reserving space here it is perfectly reasonable to use the ; same buffers that are used by drives A: and B:. To do this determine ; where these are in your system and replace the following lines with ; appropriate equates. This frees 256 bytes for other use. ; DIRBUF DS 128 ; directory buffer RAMBUF DS 128 ; bank communication buffer ; END