title KAYPRO CBIOS for CP/M 2.2 ;############################################################### ;## KAYPRO 10 CBIOS for CP/M 2.2 ## ;## Copyright (C) 1982 By Non-Linear Systems, Inc. ## ;## No warranty is made, expressed or implied. ## ;############################################################### ;## Last Update: 10/20/83 [01] ## ;############################################################### ; ;History: ; Add secondary xlate table and build in ability to have ; function keys. ; Steven R. Fabian ; Initialization of modem port on a cold boot. ; Steven R. Fabian ; Add Parallel port driver using a time delay. ; Steven R. Fabian ; true equ 0ffh false equ 0 ; ;**************************************************************** ;* * ;* This BIOS can support versions D, F and G versions of the * ;* Kaypro 10 CP/M system, if the proper equates are set. Set * ;* one and only one of the following three equates to true; * ;* be sure the other two are false. * ;* * versd equ false ; for version 2.2D * versf equ false ; for version 2.2F * versg equ true ; for version 2.2G * ;* * ;**************************************************************** ; ; ;**************************************************************** ;* * ;* Set the following equate to false if a standard CP/M BIOS * ;* is desired. Set it to true for ZCPR3 buffer initialization * ;* * zcpr3 equ true ; * ;* * ;**************************************************************** ; ; Version 3.0 ; Initial version customized for ZCPR3. ; John C. Smith July 23, 1984 ; ; Version 3.1 ; Added code to support ZCPR3 from floppy. Requires ; LDR SYS.RCP,SYS.ENV,SYS.FCP,NAMES.NDR be executed ; from the boot floppy. Path is changed to B$,B0 ; when booted from floppy to be consistent with ; hard disk path of A$,A0. Also, added code and ; conditional equates to support CP/M versions 2.2D ; and 2.2G. ; John C. Smith August 5, 1984 ; zvers equ 31 ; ZCPR version number ; ; .Z80 ; Z80 CPU hdisk equ -1 ; -1 for hard disk, 0 for floppy if zcpr3 msize equ 58 ; system memory size in k (ZCPR3) else msize equ 60 ; system memory size in k (CP/M) endif vers equ 22 ; CP/M version number bias equ (msize-20)*1024 ; bias for systems larger than 20k ccp equ 3400H+bias ; start of CCP bdos equ ccp+806H ; start of BDOS (The resident portion of CP/M) bios equ ccp+1600H ; start of Basic I/O Subsystem (BIOS) cpml equ bios-ccp ; length of CP/M system in bytes (less BIOS) nsects equ cpml/128 ; length of CP/M system in sectors (less BIOS) if hdisk trksec equ 68 ; sectors/track else trksec equ 40 endif ; ; ZCPR3 BUFFERS ; WHEEL EQU 3EH ; LOCATION OF WHEEL BYTE EXTPATH EQU 40H ; START OF EXTERNAL PATH GRAF EQU 4FH ; LOCATION OF GRAPHICS BYTE MCMD EQU 0F600H ; MUTLI-COMMAND BUFFER ; ; ; bitport equ 14H ; status/control bit maped port baudA equ 0 ; baud rate port (modem) baudB equ 8 ; baud rate port (printer) baud30 equ 05H ; 300 baud rate iobyte equ 3 ; logical to physical map rom equ 00000H ; base of rom time equ 8000H ; time out rate fox equ 0 ; set to 0 siokb0 equ 07H ; keyboard channel command/status siosp0 equ 0EH ; serial printer command/status channel siom0 equ 06H ; modem channel command/status reset equ 18H ; channel reset wr1 equ 01H ; interrupt enable and wait/ready modes tid equ 00H ; transmitter interrupt disable rid equ 00H ; recieve interrupt disable wr3 equ 03H ; receiver logic control parameters re equ 01H ; receiver enable autoe equ 20H ; auto enable (use dcd and cts to enable recv ; and xmt rbits8 equ 0C0H ; 8 bits/character wr4 equ 04H ; control bits that affect both xmt and recv sbits1 equ 04H ; 1 stop bit cr16 equ 40H ; x16 wr5 equ 05H ; control bits that affect xmt te equ 08H ; transmit enable tbits8 equ 60H ; 8 bits/character dtr equ 80H ; DTR output pfdat equ 24 ; cent out data port (8 bit latch) pstrob equ 3 ; bit in bit port ; aseg ; org bios .phase bios jp boot ; arrive here from cold start jp wboot ; arrive here for warm start jp const ; console status return in A FF=ready, 00=not jp conin ; console char in jp conout ; console char out jp list ; listing char out jp punch ; punch char out jp reader ; reader char in jp home ; move to track 0 on selected disk drive jp seldsk ; select disk drive jp settrk ; set track # jp setsec ; set sector # jp setdma ; set DMA address jp read ; read selected sector jp write ; write selected sector jp listst ; list status (Ready to print a char) jp sectran ; sector translate ioconfig: defb 10000001B ; initial value for i/o byte (may be patched) wrtsafe: defb 0 ; write safe flage 0=false vtab: defb 11, 10, 8, 12 ; vector pad xlate table ^k ^j ^h ^l defb '0', '1', '2', '3' defb '4', '5', '6', '7' defb '8', '9', 0 , 0 defb 0DH, '.' baudrt: defb baud30 ; baud rate (modem) defb baud30 ; baud rate (printer) defb (sndtab-vtab) sioint: ;i/o device initialization table ;first byte is number of bytes to send ;second byte is port to send out to ;third byte is data ;init sio channel for serial printer defb 09H defb siosp0 defb reset ;reset sio channel defb wr4 defb sbits1 or cr16 ;one stop bit 16x clock defb wr3 defb re or rbits8 or autoe ;recv enable, 8bits/char defb wr5 defb te or tbits8 or dtr ;xmt enable, 8bits/char,assert dtr defb wr1 defb tid or rid ;xmt & recv interrupts disabled ;init sio channel for modem defb 09H defb siom0 defb reset ;reset sio channel defb wr4 defb sbits1 or cr16 ;one stop bit 16x clock defb wr3 defb re or rbits8 or autoe ;recv enable, 8bits/char defb wr5 defb te or tbits8 or dtr ;xmt enable, 8bits/char,assert dtr defb wr1 defb tid or rid ;xmt & recv interrupts disabled siotbnd:defb 0 ;end of table sndtab: defb 0,0,0,0 ; up arrow key defb 0,0,0,0 ; down arrow key defb 0,0,0,0 ; left arrow key defb 0,0,0,0 ; right arrow key defb 0,0,0,0 ; 0 key on numeric pad defb 0,0,0,0 ; 1 key on numeric pad defb 0,0,0,0 ; 2 key on numeric pad defb 0,0,0,0 ; 3 key on numeric pad defb 0,0,0,0 ; 4 key on numeric pad defb 0,0,0,0 ; 5 key on numeric pad defb 0,0,0,0 ; 6 key on numeric pad defb 0,0,0,0 ; 7 key on numeric pad defb 0,0,0,0 ; 8 key on numeric pad defb 0,0,0,0 ; 9 key on numeric pad defb 'dir',0DH ; - key on numeric pad defb 'swp',0DH ; , key on numeric pad defb 0,0,0,0 ; <cr> " " defb 0,0,0,0 ; . key on numeric pad if versg mdmflg: defb 0ffh ;Internal modem flag 0=none present endif subttl Cold and Warm boot entry points defb page ; Cold boot entry point, set up system pointers and pass control to the CCP boot: call diskint xor a ; clear system disk number ld (4),a if zcpr3 LD (GRAF),A ; reset graphics byte CPL LD (WHEEL),A ; set wheel byte LD HL,PATH ; initialize path LD DE,EXTPATH LD BC,7 LDIR LD HL,CMD ; initialize multi-command line buffer LD DE,MCMD LD BC,0CH LDIR LD HL,0E600H ; initialize ZCPR3 RCP buffer by LD A,8 ; filling memory with 0 CALL ZLOOP endif if zcpr3 and not hdisk ; if boot from floppy, initialize LD HL,0F100H ; all other buffer spaces since LD a,5 ; there will be no load from the CALL ZLOOP ; "putovl" track. endif ld a,(ioconfig) ; init value for i/o byte ld (iobyte),a ld hl,sioint ; initialize i/o devices iolp: ld b,(hl) ; number of bytes to send inc hl ld c,(hl) ; port to send inc hl ; address of byte being sent otir ld a,(hl) ; get this byte or a ; clean test jr nz,iolp ; if more tables then do if versd and hdisk IN A,(BITPORT) ;2.2D PATCH OR 4 ;2.2D PATCH OUT (BITPORT),A ;2.2D PATCH endif ld a,(baudrt) ; set baud rates out (baudA),a ld a,(baudrt+1) out (baudB),a call print defb 1AH, 0DH, 0AH defb 'KAYPRO 10 ' defb msize/10+'0', msize mod 10+'0' defb 'K CP/M Version ' defb vers/10+'0', '.', vers mod 10+'0' if versd defb 'D' endif if versf defb 'F' endif if versg defb 'G' endif if zcpr3 defb ' & ZCPR Version ' defb zvers/10+'0', '.', zvers mod 10+'0' defb ' JCS' endif defb 0DH, 0AH, 00H goccp: ld hl,time ; reset disk time out ld (count),hl ld a,0C3H ; set up CP/M jumps to bdos and wboot ld hl,bios+3 ; wboot entry point ld (0),a ld (1),hl ld hl,bdos ; entry point to bdos ld (5),a ld (6),hl ld a,(4) ; last logical disk unit used ld c,a and 0FH ; valid disk? cp 3 jp c,ccp ld a,c ; no, so go to drive 0 and 0F0H ld c,a ; pass to ccp to select jp ccp ; pass control to ccp ; Warm boot entry point, re-load the CCP and BDOS wboot: if versg ld a,(mdmflg) cp 0 call nz,mdmnit endif ld c,0 ; select drive A: call seldsk call home call diskint call print defb 0DH, 0AH, 'Warm Boot', 0DH, 0AH, 00H wb0: ld sp,100H ; re-set stack ld bc,0 ; set track call settrk ld bc,ccp ; first memory location to load ld (dmaadr),bc call setdma ld bc,nsects*256+1 wb1: push bc ; save sector count and current sector call setsec ; select sector call read pop bc or a jr nz,wb0 ; oops, error on warm boot push bc ld hl,(dmaadr) ; update dma address for next sector ld de,128 ; new dma address add hl,de ld b,h ld c,l ld (dmaadr),hl call setdma pop bc if not zcpr3 xor a ld (ccp+7),a endif dec b jp z,goccp ; done loading inc c ; bump sector count if not hdisk ld a,trksec ; next track? cp c jr nz,wb1 ld c,16 ; next sector to read push bc ld c,1 call settrk ; set track number pop bc endif jr wb1 subttl logical to physical devices CON:, PUN:, RDR:, and LST: page ; logical devices are con: rdr: pun: and lst: ; physical devices are: ; crt: video and kbd ; tty: serial ; lpt: centronics ; ul1: serial with cts as busy ; pun: same as ul1 ; ;con: tty, crt ;rdr: tty ;pun: tty, pun ;lst: tty, crt, lpt, ul1 const: ld hl,(count) ; time out motors? dec hl ld (count),hl ld a,h or l call z,diskoff ld a,(cnt) ;load function counter or a ;clean test jr nz,loadup ;set to do function if not 0 ld a,(iobyte) ; get i/o byte and 03H ; strip to con bits ld l,rom+33H ; serial status jp z,callrom ld l,rom+2AH ; assume CRT jp callrom loadup: ld a,0ffh ;set for get character or a ;clean test ret conin: call const ; key press? or a jr z,conin ld a,(cnt) ;get counter value or a ;clean test jr nz,frjp ;do function if not 0 ld a,(iobyte) ; go get character and 03H ; check i/o byte ld l,rom+36H ; serial input jp z,callrom ld l,rom+2DH ; assume input from kbd call callrom ; go get char or a ret p ; msb not set and 01FH ; form table index to vtab ld hl,vtab ld c,a ld b,0 add hl,bc ld a,(hl) ; pick up xlated character or a ; clean test ret nz ; if valid character value return sectab: ld hl,sndtab ;set to new table value ld a,c ;get character position sla a ;shift left to sla a ;mult by 2, again ld c,a ;get new character position add hl,bc ;set hl to character position ld (pntr),hl ;store position in pointer ld a,4 ;set to this value ld (cnt),a ;initialize counter to 4 ;continue process of function frjp: ld hl,(pntr) ;get pointer value ld c,(hl) ;load character into c reg inc hl ;increment pointer ld (pntr),hl ;save this value off ld a,(cnt) ;retrieve current counter value dec a ;decrement this value ld (cnt),a ;save this value off ld a,c ;move character into a ret z ;return if zero ld a,(hl) ;get next byte value cp fox ;compare to 0 ld a,c ;move value in c to a ret nz ;return if not zero xor a ;clear accumulator ld (cnt),a ;clear counter value ld a,c ;move value in c to a ret diskoff:ld l,rom+27H jp callrom conout: if zcpr3 LD A,(GRAF) ; check graphics byte OR A ; is it set? JR NZ,R1 ; allow eighth bit if it is LD A,C ; otherwise, mask it out AND 7FH LD C,A R1: endif ld a,(iobyte) ; check i/o byte and 03H ld l,rom+39H ; serial output jp z,callrom ld l,rom+45H ; assume video jp callrom reader: ld l, rom+36H ; serial input jp callrom ;punch: ld a,(iobyte) ; check i/o byte ; and 30H ; ld l,rom+39H ; serial punch ; jp z,callrom ; ld l, rom+42H ; serial with cts as busy ; jp callrom punch: ld l,rom+39h ;serial punch jp callrom ; list: ld a,(iobyte) and 0C0H ; check i/o byte ld l,rom+39H ; serial jp z,callrom cp 80H ; centronics jp z,lstdev ; time delay routine for output ld l,rom+45H ; video cp 40H jp z,callrom ; ld l, rom+42H ; assume serial with cts as busy ld l, rom+39h ;ul1: default to serial jp callrom listst: ld a,(iobyte) ; check i/o byte and 0C0H ld l,rom+42H ; serial jp z,callrom ld l,rom+3CH ; centronics cp 80H jp z,callrom xor a ; 0=ready ret lstdev: call listst ; is printer busy jr nz,lstdev ; if not return ld a,c ; move character into a out (pfdat),a ; output character to printer in a,(bitport) ; strb. printer res pstrob,a out (bitport),a set pstrob,a out (bitport),a ret if versg mdmnit: ld a,0fh ; set up pio out (23h),a ld a,87h ; and interrupt vector out (23h),a ld a,4ah ; set modem on-hook out (21h),a endif subttl Disk I/O and ROM dispatch page diskint:ld l,rom+03H ; re-set disk software sub-system jr callrom home: ld l,rom+0CH ; home disk drive rom routine jr callrom seldsk: ld l,rom+0FH ; select disk drive jr callrom settrk: ld l,rom+12H ; seek track jr callrom setsec: ld l,rom+15H ; set sector number jr callrom setdma: ld l,rom+18H ; set dma address jr callrom read: ld hl,time ; reset time out ld (count),hl ld l,rom+1BH ; read a logical sector jr callrom write: ld hl,time ; reset time out ld (count),hl ld l,rom+1EH ; write a logical sector ld a,(wrtsafe) ; write safe flag or a ; true or false jr z,callrom ; normal operation ld c,1 ; directory write code (forces write op) jr callrom sectran:ld l,rom+21H ; xlate logical to physical sector jr callrom callrom:exx ; save cp/m arguments in a,(bitport) ; turn rom on set 7,a out (bitport),a ld (savsp),sp ; save current stack (may be under rom) ld sp,stack ; set a local stack ld de,biosret ; rom to "RET" here push de exx ; restore cp/m arguments and call loc ld h,0 jp (hl) ; to rom routine specified in hl biosret:ex af,af' ; save reg A ld sp,(savsp) ; restore stack in a,(bitport) ; off the rom res 7,a out (bitport),a ex af,af' ; restore reg A ret ; done with rom routine print: ex (sp),hl ; pop return address, points to text to print ld a,(hl) ; get a byte of text, stop on zero byte inc hl ex (sp),hl ; save new return address or a ; is it a zero byte? ret z ld c,a ; no, so print it call conout jr print if zcpr3 ZLOOP: LD B,0FFH ZERO: LD (HL),0 INC HL DJNZ ZERO DEC A JR NZ,ZLOOP RET endif if hdisk and zcpr3 PATH: DEFB 1,'$',1,0,0,0,0,0,0,0,0 ; search path else PATH: DEFB 2,'$',2,0,0,0,0,0,0,0,0 endif if zcpr3 CMD: DEFB 4,0F6H,0C8H,0,'STARTUP',0 ; mcl buffer pntr: defw 0 ; pointer for function key routine cnt: defb 0 ; character counter for function routine count: defs 2 ; disk time out counter savsp: defs 2 ; current spact pointer during rom call dmaadr: defs 2 ; dma address for warm boot db 'END' ; end of BIOS marker stack equ $+64 ; a local stack else ; Patch CCP to display user # and search user 0 for a COM file. openf equ 15 ; open disk function bdosent equ 5 ; entry point to bdos ccperr equ ccp+7EEH ccpfcb equ ccp+7CDH ccpco equ ccp+8CH ccpread equ ccp+0F9H ccpp1 equ ccp+0392H ccpp2 equ ccp+00D7H ccpp3 equ ccp+06E9H getusr macro x .xlist ld e,-1 ld c,32 call bdosent ld (x),a .list endm setusr macro x .xlist ld a,(x) ld e,a ld c,32 call bdosent .list endm p1: ld c,32 ; show user#, get current one ld e,-1 ; e=255 is get user code call bdosent cp 10 ; if a>10 then print first digit jr c,pmt0 sub 10 push af ; save second digit ld a,'1' call ccpco pop af pmt0: add a,'0' ; for ascii digit call ccpco ld a,'>' pmt2: jp ccpco p2: getusr curuser ld (fcbuser),a ld de,ccpfcb ld c,openf ; open a file (check user 0 if not found) call bdosent ld (ccperr),a inc a ret nz ; nz=file opened ld a,(curuser) ; get current user # or a jr z,nogd ; in user 0, file open no good xor a ld (fcbuser),a ; try user 0 setusr fcbuser ld de,ccpfcb ; try to open file ld c,openf call bdosent ld (ccperr),a ; ccp error return setusr curuser ; restore user # nogd: ld a,(ccperr) ; was open ok? inc a ret ; back to ccp p3: setusr fcbuser ; read a sector ld de,ccpfcb call ccpread push af setusr curuser pop af ret pntr: defw 0 ; pointer for function key routine cnt: defb 0 ; character counter for function routine curuser:defs 1 ; current user fcbuser:defs 1 ; user # of load file count: defs 2 ; disk time out counter savsp: defs 2 ; current spact pointer during rom call dmaadr: defs 2 ; dma address for warm boot stack equ $+64 ; a local stack endif end