title KAYPRO CBIOS for CP/M 2.2 ;############################################################### ;## KAYPRO CBIOS for CP/M 2.2 ## ;## Copyright (C) 1982 By Non-Linear Systems, Inc. ## ;## No warranty is made, expressed or implied. ## ;############################################################### ;## Last Update: 03/28/84 [01] ## ;############################################################### ; ;History: ; Added modem off hook, auto patch of ccp, changed ; rev. level to G and reassigned vector keys to Micro-Pro standard ; Thomas N. Hayes (3/28/84) ; Added conditional equates for DriveTec ; G. Ohnysty ; Added conditional equates for II/IV systems ; Matthew Sherman (15-Dec-83) ; Add secondary xlate table for function keys ; use. 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 public p1, p2, p3, ccp .Z80 ; Z80 CPU kay10 equ 00 ; -1 for Kaypro 10, 0 for Kaypro II/IV kayII equ -1 ; -1 for Kaypro II/IV kayDT equ 00 ; -1 for Kaypro using DriveTec kay10f equ 00 ; -1 for Kaypro 10 Genflpy movcpm equ 00 if kay10 trksec equ 68 msize equ 60 endif if kayII trksec equ 40 msize equ 63 endif if kayDT trksec equ 68 msize equ 62 endif if kay10f trksec equ 40 msize equ 60 endif vers equ 22 ; CP/M version number if not movcpm bios equ 3400H+1600H+((msize-20)*1024) ccp equ bios-1600h bdos equ ccp+806h endif if movcpm ccp equ $ bdos equ $+806H ; start of BDOS (The resident portion of CP/M) bios equ $+1600H ; start of Basic I/O Subsystem (BIOS) endif cpml equ 1600h ; length of CP/M system in bytes (less BIOS) nsects equ cpml/128 ; length of CP/M system in sectors (less BIOS) 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 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: ; ; Vector keys re-defined for Micro-Pro products ; db 'E' and 1fh ; up arrow db 'X' and 1fh ; down arrow db 'S' and 1fh ; left arrow db 'D' and 1fh ; right arrow defb '0', '1', '2', '3' defb '4', '5', '6', '7' defb '8', '9', '-', ',' 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 0,0,0,0 ; - key on numeric pad defb 0,0,0,0 ; , key on numeric pad defb 0,0,0,0 ; " " defb 0,0,0,0 ; . key on numeric pad ; ; patch point to enable modem on-hook on warm start ; 0 = leave modem alone ; not 0 = take modem off hook ; modflg: db 0 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 pioinit ; take modem off hook ; call diskint xor a ; clear system disk number ld (4),a 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 kay10 nop nop nop nop nop nop 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 ' defb msize/10+'0',msize mod 10+'0','K' defb ' CP/M Version ' defb vers/10+'0', '.', vers mod 10+'0','G' 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 ; ; ccp call address patches ; ld hl,p1 ld (ccpp1),hl ld hl,p2 ld (ccpp2),hl ld hl,p3 ld (ccpp3),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: ld a,(modflg) ; see if modem is to go off hook cp 0 call nz,pioinit ; take off hook if so ; 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 xor a ld (ccp+7),a dec b jp z,goccp ; done loading inc c ; bump sector count if kayII or kay10f ld a,trksec ; next track? cp c jr nz,wb1 ld c,16 ; next sector to read push bc ld bc,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: 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 pioinit: ; ; take modem off hook ; ld a,0fh ;set all bits to output out (23h),a ld a,87h out (23h),a ;disable pio interrupts ld a,4ah out (21h),a ;put modem into inactive state ret 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 ; 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+1 ccpp2 equ ccp+00D7H+1 ccpp3 equ ccp+06E9H+1 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: dw 0 ; pointer for function key routine cnt: db 0 ; character counter for function routine curuser:db 0 ; current user fcbuser:db 0 ; user # of load file count: dw 0 ; disk time out counter savsp: dw 0 ; current spact pointer during rom call dmaadr: dw 0 ; dma address for warm boot stack equ $+64 ; a local stack end