.title "High Bios For Turbo-ROM" .sbttl "Macros and Constants" .setwid 120 .phex .xlink ;****************************************************** ; UNIVERSAL HIGH-BIOS FOR TURBO ROM ; ; Copyright 1985 (c), Plu*Perfect Systems ; P.O. Box 1494 ; Idyllwild, California 92349 ; ;****************************************************** .remark " This code is provided for the use of owners of the Advent Products Turbo ROM (Kaypro versions). It relies heavily on the presence of the Turbo ROM and will not work without it" ;********************************************** ;fill memory up to address with nulls .define PADBYT[addr]=[ .ifg (addr - .),[ nop PADBYT addr ] ] .define XENTRY[name]=[ ;;Macro to generate ROM entry points xcount = xcount+3 name = xcount ] ;Define ROM entry points xcount = 0 xstart == xcount ;Restart Computer .slist .sall XENTRY xdskrst ;(de-activate HOST buffer) XENTRY xcrtnit ;initialise video driver XENTRY xdevnit ;(initialise unit record hardware) XENTRY xhome ;(de-activate HOST buffer only if not written) XENTRY xseldsk ;Select disk for next access XENTRY xsettrk ;Set track for next disk access XENTRY xsetsec ;Set sector for next disk access XENTRY xsetdma ;Set DMA Address for next disk access XENTRY xread ;Read Sector XENTRY xwrite ;Write Sector XENTRY xsctrn ;Sector Translation (Dummy) XENTRY xdskon ;Trun on Floppy motors XENTRY xdskoff ;Turn off/deselect drives and flush deblocking XENTRY xcrtsta ;Standard Keyboard input status XENTRY xcrtin ;Standard Keyboard input XENTRY xkbdout ;Keyboard Serial output (Use with Caution) XENTRY xttysta ;TTY input status XENTRY xttyin ;get char from TTY XENTRY xttyout ;send (C) to TTY XENTRY xlptsta ;Centronics output status XENTRY xlptout ;send (C) to Centronics XENTRY xttosta ;TTY output status XENTRY xcrtout ;send (C) to video screen XENTRY xtmsec ;delay (A) ten millseconds XENTRY xul1sta ;User List input status XENTRY xul1in ;User List input XENTRY xul1out ;User List output XENTRY xul1ost ;User List output status XENTRY xldsys ;reload system XENTRY xgetscr ;return next screen char XENTRY xdefcur ;set cursor to (A) XENTRY xmsec ;delay (A) msec .rlist sioAcommand = 06H ;TTY command port sioBcommand = 07H ;Keyboard command port sioBstatus = 07H ;keyboard status port sioBdata = 05H ;Keyboard data sioCcommand = 0EH ;UL1 command port bauda = 0 ;tty baud rate baudb = 8 ;serial printer (84 only) topmem = 0 romid = topmem - 8 ;start of ROM identifing sequence vecptr = topmem - 16 ;pointer to base of interrupt vectors hrdptr = topmem - 20 ;pointer to winchester parameters beldly = 40 ;delay before sending bell to keyboard CR = 0DH LF = 0AH .sbttl "Load Parameter Sector (Config. Tables)" .page ;********************************************** ;load parameter sector (standard Kaypro) ;This sector is loaded by the Turbo Rom into the ;CP/M directory buffer where it remains through the ;cold boot. It also contains the configuration information. ;************************************************ syssiz =\ "Enter System Size (K) - (0 generates relocatable version)" .ifg syssiz,[ .pabs .loc (syssiz*2 - 3)*512 - 1600H - 200H ] ldparm: jmpr ldparm ;ID and safety .word bootcd ;start loading .word bootcd ;cold boot entry .word syssct ;number of sectors to load ;------------------------------------------ ;sign-on message, placed here so relocator can patch in ;displayable system size sign: .byte 01AH,07 ;clear screen and ring bell .ifg syssiz,[ .byte 30H + syssiz/10, 30H + syssiz@10 .ascii '.00' ] [ .ascii '00.00' ;patched by relocator ] .ascii "K CP/M" .ascii " - TURBO-BIOS$" .ascii " " ;------------------------------------------ ;offsets from start of code to other configurable parameters ;that are set by TURBO CONFIG program .word schar - bootcd ;screen dump trigger .word iflag - bootcd ;interrupt flag (& func keys) .word motcns - bootcd ;motor off time constant .word rbtdrv - bootcd ;warm boot drive .word wptr0 - bootcd ;pointer to warm boot message .word wptr1 - bootcd ;pointer " " " " ;------------------------------------------ ;Configuration Data Structure ;miscellaneous options iiobyt: .byte 81H ;initial I/O byte curs83: .byte 7FH + 80H ;83 cursor (flashing block) curs84: .byte 01100000B ! 00000000B ;84 cursor (slow flashing block) clk84: .byte 0 ;84 machine clock entry in rom ;(0 is no clock) typena: .byte 0 ;use type ahead console clkmsk: .byte 0 ;enable keyclicks ;Floppy disk time constants fflag: .byte 0 ;flag whether replacement constants valid ftime: .byte 6,50,25 ;floppy 0 (step rate,head load,head settle) .byte 6,50,25 ;floppy 1 .byte 6,50,25 ;floppy 2 .byte 6,50,25 ;floppy 3 ;Serial Ports ; Device initialization tables ; Note order of registers taken from Osborne. devtab: ;SIOB keyboard device .byte sioBcommand, 00000010B ;select WR2 .byte sioBcommand ;---------------------------------------------------------------------- ivect: .byte 0 ;patched in by init code ;----------------------------------------------------------------------- ;BAUDA .byte bauda, 5 ;default to 300 ;SIOA tty device .byte sioAcommand, 00010100B ;select WR4 & reset ext stat .byte sioAcommand, 01000100B ;x16, async 1 stop,no parity .byte sioAcommand, 00010011B ;select WR3 & reset ext stat .byte sioAcommand, 11100001B ;rx 8 bits,yes hshak,enab rx .byte sioAcommand, 00000101B ;select WR5 .byte sioAcommand, 11101000B ;tx 8 bits,DTR assert,enab tx .byte sioAcommand, 00000001B ;select WR1 .byte sioAcommand, 00000000B ;disable interrupts ilen83 = (. - devtab)/2 ;BAUDB .byte baudb, 5 ;default to 300 ;sioC ul1 serial printer device .byte sioCcommand, 00010100B ;select WR4 & reset ext stat .byte sioCcommand, 01000100B ;x16, async 1 stop,no parity .byte sioCcommand, 00010011B ;select WR3 & reset ext stat .byte sioCcommand, 11100001B ;rx 8 bits,yes hshak,enab rx .byte sioCcommand, 00000101B ;select WR5 .byte sioCcommand, 11101000B ;tx 8 bits,DTR assert,enab tx .byte sioCcommand, 00000001B ;select WR1 .byte sioCcommand, 00000000B ;disable interrupts ilen84 = (. - devtab)/2 ;warm boot message printed by BDOS string printer ;DateStamper install moves this wmsg0: .ascii [0DH][0AH]'Warm Boot$' wmsglen = . - wmsg0 prmlen = . - ldparm .ifg prmlen - 80H,[ .prntx "Parameter Sector Overflow" ] ;------------------------------------------- .sbttl "Cold Boot Initialization Code" .page ;start of actual Cold Boot Code (note that ROM is switched in .loc ldparm + 80H bootcd: ;must initially set up stack to use during boot, put just below ;start of code lxi sp,bootcd ;verify presence of Turbo Rom lxi h,romid ;start of ID sequence push h xra a mvi b,8 ..chks: add m ;checksum inx h djnz ..chks pop h jrnz xrom ;jump if wrong ROM lxi d,sig mvi b,3 ..csig: ldax d ;now check signature cmp m jrnz xrom inx h inx d djnz ..csig jmpr romok ;********************************* sig: .ascii 'PPS' ;signature in ROM ;********************************* ;message for wrong ROM detected emsg: .ascii [1AH][07H]"Requires TURBO ROM!" elen = . - emsg ;********************************* ;use direct ROM calls to video output routine xrom: lxi h,emsg mvi b,elen ..loop: mov c,m inx h push h push b call xcrtout pop b pop h djnz ..loop ..hang: di hlt ;************************************** ;find DIRBUF to get initialization tables romok: mvi c,0 ;select drive 0 to get DPH ptr mvi e,1 ;don't bother redetermining call xseldsk ;direct ROM call lxi d,8 dad d ;now have pointer to pointer mov e,m inx h mov d,m push d pop x ;index register points to buffer ;********************************* ;initialise timer interrupts in case they are later ;enabled lhld vecptr ;get pointer to interrupt vector base ;poke low order to write register 2 mov a,h ;set up CPU interrupt vector stai im2 ;make sure in Mode 2 mov (ivect - ldparm)(x),l lxi d,timer ;note that tx interrupt is base mov m,e inx h mov m,d ;put vector in place ;initialise any unit record devices ;find which machine lda 0FFFBH ;get version byte rlc ;move machine bit to cy push psw ;save machine push x pop h lxi d,devtab - ldparm dad d xchg ;table in DE pop psw push psw ;get cy mvi a,ilen83 jrnc ..do83 mvi a,ilen84 ..do83: mvi l,xdevnit ;rom device initialize call calrom ;use ROM function (switch in RAM) ;now do other config options like cursor, bell, keyboard type-ahead ;interrupt motor turn off, motor deselect time constant, screen dump ;character ;----------------- ;cursor definition pop psw ;get back machine mov a,(curs83 - ldparm)(x) jrnc ..cu83 ;for 84 must set up display clock address mov a,(clk84 - ldparm)(x) sta 0FFE6H ;entry point in high memory mov a,(curs84 - ldparm)(x) ..cu83: mvi l,xdefcur call calrom ;define the cursor ;----------------- ;keyboard type ahead and key clicks lhld hrdptr ;get pointer to hard disk area ;point to type ahead flag dcx h mov a,(typena - ldparm)(x) mov m,a dcx h ;point to ROM bell character mov a,(clkmsk - ldparm)(x) sta txchar ;set bell used by interrupt time out sta click0 ora m mov m,a ;set ROM character ;move floppy timing mov a,(fflag - ldparm)(x) ora a ;test if floppy timing data valid jrz ..nflp lhld hrdptr lxi d,16 ;offset to high memory area dad d ;point to destination xchg push d push x pop h lxi d,ftime - ldparm dad d pop d lxi b,12 ldir ;move 12 time constants ;move warm boot message into position ..nflp: push x pop h lxi d,(wmsg0 - ldparm) dad d wptr1 = . + 1 ;for patching by DateStamper Install lxi d,wmsg lxi b,wmsglen ldir ;***************************************************** ;Note ROM calls above switched RAM back on exit so we can set up ;page zero ;set up initial IOBYTE and Logged on drive lxi h,3 mov a,(iiobyt - ldparm)(x) ;get initial IOBYTE mov m,a inx h mvi m,0 ;start with A0: ;now set rest of page zero mvi a,jmp sta 0 sta bdos ;set up BIOS/BDOS jumps lxi h,cboot+3 shld 1 ;BIOS wm boot ptr lxi h,ccpentry + 0806H shld bdos+1 ;BDOS ptr ;********************************************************************** ;now print sign on message (can use BDOS as everything else is set up) push x pop h lxi d,(sign - ldparm) dad d xchg ;point to message mvi c,9 call bdos ;********************************************************************** ;set up drive to pass to CCP, if extra init code added then this ;function must be preserved xra a mov c,a ;always set up correct drive endcode: ;pad rest of sector with NOP so we fall through to CCP, additional ;init code could be patched in here .slist .sall PADBYT ldparm+512 ;fill rest of sector with NOP .rlist ;---------------------------------------------- ;start of command processor, on sector boundary ccpsct = 4 .loc ldparm + 128*ccpsct ccpentry: ;compute space remaining on previous sector spare = ccpentry - endcode ;*********************************************** ; fix BDOS reset disk function in case we are ;installing on top of Plu*Perfect Systems enhancements ;because ROM now handles new logins correctly bdoslc = ccpentry + 0800H .loc bdoslc + 0C83H lxi h,0000 ;*********************************************** .sbttl "BIOS Proper" .page .loc ccpentry + 1600H cboot: jmp boot jmp wboot jmp consta jmp conin jmp conout jmp list jmp punch jmp reader jmp home jmp seldsk jmp settrk jmp setsec jmp setdma jmp read jmp write jmp listst jmp sectrn ;********************************************* iflag: .byte 0 ;motor interrupt flag bsflag: .byte 0 ;flags used by BIOS ;bit 7 (raw/decoded function keys) ;bit 6 (foreign language Kaypros only) ;bit 5 (foreign language Kaypros only) ;bit 4 (foreign language Kaypros only) ;bit 3 unused ;bit 2 unused ;bit 1 unused ;bit 0 Write Safe flag (Old ROMs only) ;******************************************** ;standard Kaypro layout of function keys (Pre - Universal ROM) akeys: .byte 0BH,0AH,08H,0CH ;standard ADM 3A cursor keys keypad: .ascii '0123456789-,' ;numeric keypad normal definition .byte 0DH .ascii '.' ;******************************************************** ;motor delay used in count down offset preserved ;(any program can zero this if it wants control of motor) mcnter: .word 0 ;interrupt version only uses ;first byte ;******************************************** ;TRUE cold boot entry which cause system restart ;NOTE -- this is different from Kaypro Use ; boot: mvi l,xstart xcalrm: jmp calrom ;******************************************* iobyte = 3 ;page zero address cdrive = 4 ;page zero address bdos = 5 ;page zero address wboot: lxi sp,0100H ;make sure we have good stack rbtdrv = . + 1 ;location to patch for different boot mvi a,0 ;default is to reboot from A lxi d,ccpentry ;location to load at ;number of sectors and starting sector lxi b,(1600H/80H)*256 + ccpsct mvi l,57H ;ROM warm boot entry call calrom mvi a,jmp sta 0 sta bdos ;set up BIOS/BDOS jumps lxi h,cboot+3 shld 1 ;BIOS wm boot ptr lxi h,ccpentry + 0806H shld bdos+1 ;BDOS ptr wptr0 = . + 1 ;for patching by DateStamper Install lxi d,wmsg ;pointer to warm boot message mvi c,9 call bdos ;use bdos string printer lxi h,bsflag ;point at BIOS flag res 7,m ;make sure function keys not 'raw' lda cdrive mov c,a ;get logged in drive/user jmp ccpentry + 3 ;****************************************** ;console status consta: lda iflag ora a ;test if using interrupts jrnz ..ncnt ;skip if we are ;----------------------------------------- ;CONSTAT polling motor count down lxi h,mcnter + 1 ora m ;test for count down (high byte only) jrz ..ncnt dcx h dcr m ;decrement low byte jrnz ..ncnt inx h dcr m cz motoff ;------------------------------------------ ..ncnt: lda iobyte rrc ;test for CRT/TTY mvi l,xttysta jrnc xcalrm ;No buffering from TTY bufclr = . + 1 mvi a,0 ;buffer clear flag ora a rnz ;return if not mvi l,xcrtsta ;go see if anything new call calrom rz ;return if no character ;else fetch it mvi l,xcrtin call calrom ;****************************************** ;Check for Screen Dump pressed mov c,a ;save character schar = . + 1 ;location of trigger character mvi a,0 ;get screen dump flag (00 = no) ora a jrz putchr ;save character cmp c ;actual trigger character jrnz putchr ;---------------------------------------- ;Screen Dump Function (we don't have room to speed up short lines) ;first home the dump cursor mvi c,0FFH ..loop: mvi l,xgetscr ;screen dump ROM entry call calrom push psw ;save character mov a,l ;test for end of line ani 07FH ;mask column jrnz ..not0 ;jump if not column zero mvi c,CR ;start new line call list mvi c,LF call list ..not0: pop psw ;get character jrz endscr ;dump ends with zero return mvi c,' ' ;skip greek/foreign characters cmp c jrc ..grph mov c,a ;get character to print ..grph: call list ;send it to the printer jmpr ..loop endscr: xra a ;return with status false ret ;------------------------ putchr: mov a,c sta bufchr ;store character in buffer xra a dcr a sta bufclr ;set flag ret ;set non zero ;***************************************** ;console input conin: call consta jrz conin ;loop out of ROM lda iobyte rrc jnc reader ;no screen dump or ;function keys with TTY bufchr = . + 1 ;one character look-ahead where constat ;places character mvi a,0 lxi h,bufclr mvi m,0 ;clear buffer flag ;now must map any function keys mapfnc: ora a rp ;if no high bit then return lxi h,bsflag ;see if we are to map bit 7,m rnz ;return raw function if set lxi h,akeys ;point to mapping table ani 1FH ;crunch hi bits add l mov l,a ;get offset, (always in first page) mov a,m ret ;**************************************** ;console output conout: lda iobyte rrc jrnc punch ;Send to TTY ;must trap bell character if interrupt timer being used crtout: mvi l,xcrtout lda iflag ;are we using interrupts ora a jrz calrom lda mcnter ;is motor still running ora a jrz calrom mov a,c cpi 7 ;test for bell jrnz calrom lxi h,txchar set 2,m ;set bell bit ret ;***************************************** ;list device list: call listst ;loop till ready in hi memory jrz list lda iobyte ani 0C0H ;isolate list device jrz punch rlc rlc dcr a ;test for CRT jrz crtout dcr a mvi l,xlptout jrz calrom mvi l,xul1out jmpr calrom ;************************************* ;sector translation routine sectrn: mvi l,xsctrn jmpr calrom ;************************************ ;turn off floppy motor and deselect hard disk motoff: mvi l,xdskoff jmpr calrom ;jump to ROM ;**************************************** ;punch device (always TTY) punch: mvi l,xttyout ;****************************************** ;main entry to ROM calrom: push psw ;save A ;disable SIO status interrupts lda iflag ora a jrz ..skip di ;make sure we are not hit mvi a,1 ;select write reg 1 out sioBcommand xra a ;disable all interrupts out sioBcommand ei ..skip: pop psw call 0FFFCH ;fixed ROM entry point push h push psw ;check if motor counter needs reset lda iflag ora a jrz notint lxi h,mcnter ;point to current motor counter (lo byte only ;used by interrupt counter) ana m ;test for zero jrz notint ;now reinitialize SIO status interrupts di in sioBstatus ;check if buffer empty bit 2,a jrz nempty dcr m ;decrement count jrnz not0 inr m ;make sure we are non zero ;only time-out in actual interrupt routine click0 = . + 1 not0: mvi a,0 out sioBdata ;restart timer nempty: mvi a,1 out sioBcommand ;select register 1 mvi a,00000110B ;enable vectord TX empty interrupts out sioBcommand ei notint: pop psw pop h ret ;**************************************** ;reader device (always TTY) reader: mvi l,xttyin jmpr calrom ;**************************************** ;home selected disk drive home: mvi l,xhome jmpr calrom ;**************************************** ;select disk seldsk: mvi l,xseldsk jmpr calrom ;*************************************** ;set desired track settrk: mvi l,xsettrk jmpr calrom ;*************************************** ;set desired sector setsec: mvi l,xsetsec jmpr calrom ;*************************************** ;set DMA address for transfer of next sector setdma: mvi l,xsetdma jmpr calrom ;*************************************** ;read specified sector read: mvi b,xread ;common read/write entry motcns = . + 1 stime: lxi h,7FFFH ;reset motor off timer shld mcnter mov l,b ;get function set up jmpr calrom ;*************************************** ;write specified sector write: mvi b,xwrite jmpr stime ;************************************** ;list output status listst: lda iobyte ani 0C0H ;mask out list bits mvi l,xttosta jrz calrom ;TTY used rlc rlc ;moveinto low bits dcr a ;test for CRT, always ready jrz ..true dcr a mvi l,xlptsta jrz calrom ;use Centronics mvi l,xul1ost jmpr calrom ..true: dcr a ret ;always ready ;************************************ ;Interrupt driven motor/deselect timer ; ;This interrupt driven timer uses the Keyboard TX buffer empty ;which interrupts at 30 HZ rate. If IFLAG enabled then type-ahead ;keyboard must also be enabled, so that occassional framing errors ;generated by keyboard firmware bug can be corrected. Note that ;some very early SMK keyboards with 8749 (cf 8049 in later) have ;serious bug that makes operation with interrupts impossible, ;symptoms of this problem are ^@'s appearing on console when a ;key is pressed. Maximum timing delay is 8.3 seconds. ;------------------------------------------------- timer: sspd timstk ;save current stack lxi sp,timstk ;set up new local stack push psw push h lxi h,mcnter ;point to counter dcr m ;decrement cz motoff ;deselect and flush if needed txchar = .+1 ;clicks and bell mvi a,0 ;character to send to keyboard bit 2,a ;is bell bit set jrz ..nbel ;skip if no bell mvi h,beldly ;need to delay ..lp: dcr l jrnz ..lp dcr h jrnz ..lp ;delay befor bell ..nbel: out sioBdata ;send character res 2,a ;clear bell bit sta txchar pop h ;Note motoff saves additional reg. used pop psw lspd timstk ;get back old stack pointer ei reti ;*********************************************************** ;compute total length of system in sectors for bootloader syssct = (. - bootcd)/128 .ifg ((.- bootcd)@128),[ syssct = syssct + 1 ] ;**************************************************** ;check for overall system length -- we require 4 sectors spare ;possible installation of Plu*Perfect DateStamper .ifg . - cboot - 4*128,[ .prntx "BIOS too long" ] ;*********************************************************** .loc cboot + 4*128 wmsg: .blkb 12 .loc cboot + 4*128 + 64 ;interrupt stack compatible with Plu*Perfect DateStamper timstk: .blkw 2 ;word to save stack during int. .end  bit 2,a ;is bell bit set jrz ..nbel ;skip if no bell mvi h,beldly ;need to delay ..lp: dcr l jrnz ..lp dcr h jr