title 'Root module of relocatable BIOS for CP/M 3.0' ;ldrkrn db 08 ;version cr equ 13 lf equ 10 bell equ 7 ctlQ equ 'Q'-'@' ctlS equ 'S'-'@' ; user defined character I/O routines extrn ?co ; each take device in ; disk communication data items extrn @dtbl ; table of pointers to XDPHs public @adrv,@rdrv,@trk,@sect ; parameters for disk I/O public @dma,@dbnk,@cnt ; '' '' '' '' ; memory control public @cbnk ; current bank extrn ?xmove,?move ; select move bank, and block move extrn ?bank ; select CPU bank ; general utility routines public ?pmsg,?pdec ; print message, print number from 0 to 65535 public ?pderr ; print BIOS disk error message header ; External names for BIOS entry points public ?boot,?wboot,?const,?conin,?cono,?list,?auxo,?auxi public ?home,?sldsk,?sttrk,?stsec,?stdma,?read,?write public ?lists,?sctrn public ?conos,?auxis,?auxos,?dvtbl,?devin,?drtbl public ?mltio,?flush,?mov,?tim,?bnksl,?stbnk,?xmov ; ; routines that just return in ldrbios that aren't used ; save having to link a bunch of unneeded stuff ; public ?min, ?minst, ?mout, ?moutst, ?minit public @ermde ; BIOS Jump vector. ; All BIOS routines are invoked by calling these ; entry points. ?boot: jmp boot ; initial entry on cold start ?wboot: jmp wboot ; reentry on program exit, warm start ?const: jmp r ; return console input status ?conin: jmp r ; return console input character ?cono: jmp conout ; send console output character ?list: jmp r ; send list output character ?auxo: jmp r ; send auxilliary output character ?auxi: jmp r ; return auxilliary input character ?home: jmp home ; set disks to logical home ?sldsk: jmp seldsk ; select disk drive, return disk parameter info ?sttrk: jmp settrk ; set disk track ?stsec: jmp setsec ; set disk sector ?stdma: jmp setdma ; set disk I/O memory address ?read: jmp read ; read physical block(s) ?write: jmp write ; write physical block(s) ?lists: jmp r ; return list device status ?sctrn: jmp sectrn ;translate logical to physical sector ?conos: jmp r ; return console output status ?auxis: jmp r ; return aux input status ?auxos: jmp r ; return aux output status ?dvtbl: jmp devtbl ; return address of device def table ?devin: jmp r ; change baud rate of device ?drtbl: jmp getdrv ; return address of disk drive table ?mltio: jmp multio ; set multiple record count for disk I/O ?flush: jmp flush ; flush BIOS maintained disk caching ?mov: jmp ?move ; block move memory to memory ?tim: jmp r ; Signal Time and Date operation ?bnksl: jmp bnksel ; select bank for code execution and default DMA ?stbnk: jmp setbnk ; select different bank for disk I/O DMA operations. ?xmov: jmp ?xmove ; set source and destination banks for one operation jmp 0 ; reserved for future expansion jmp 0 ; reserved for future expansion jmp 0 ; reserved for future expansion r: ?time: ?min: ?minst: ?mout: ?moutst: ?minit: ret ; BOOT ; Initial entry point for system startup. boot: ; lxi h,ldrsignon ; call ?pmsg ret ldrsignon: db 0ah,0dh,'LDRBIOS version ' db '1.0' db ' 5/8/83',0 ; WBOOT ; Entry for system restarts. wboot: ret ; DEVTBL ; Return address of character device table devtbl: ret ; GETDRV ; Return address of drive table getdrv: lxi h,@dtbl ! ret ; CONOUT ; Console Output. Send character in ; to all selected devices conout: mvi b,0 ;select device 0 jmp ?co auxout: list: ret ; Utility Subroutines ipchl: ; vectored CALL point pchl ?pmsg: ; print message @ up to a null ; saves & push b push d pmsg$loop: mov a,m ! ora a ! jz pmsg$exit mov c,a ! push h mvi b,0 call ?co ! pop h inx h ! jmp pmsg$loop pmsg$exit: pop d pop b ret ?pdec: ; print binary number 0-65535 from lxi b,table10! lxi d,-10000 next: mvi a,'0'-1 pdecl: push h! inr a! dad d! jnc stoploop inx sp! inx sp! jmp pdecl stoploop: push d! push b mov c,a! call ?cono pop b! pop d nextdigit: pop h ldax b! mov e,a! inx b ldax b! mov d,a! inx b mov a,e! ora d! jnz next ret table10: dw -1000,-100,-10,-1,0 ?pderr: lxi h,drive$msg ! call ?pmsg ; error header lda @adrv ! adi 'A' ! mov c,a ! call ?cono ; drive code lxi h,track$msg ! call ?pmsg ; track header lhld @trk ! call ?pdec ; track number lxi h,sector$msg ! call ?pmsg ; sector header lhld @sect ! call ?pdec ; sector number ret ; BNKSEL ; Bank Select. Select CPU bank for further execution. bnksel: sta @cbnk ; remember current bank jmp ?bank ; and go exit through users ; physical bank select routine ; Disk I/O interface routines ; SELDSK ; Select Disk Drive. Drive code in . ; Invoke login procedure for drive ; if this is first select. Return ; address of disk parameter header ; in seldsk: mov a,c ! sta @adrv ; save drive select code mov l,c ! mvi h,0 ! dad h ; create index from drive code lxi b,@dtbl ! dad b ; get pointer to dispatch table mov a,m ! inx h ! mov h,m ! mov l,a ; point at disk descriptor ora h ! rz ; if no entry in table, no disk mov a,e ! ani 1 ! jnz not$first$select ; examine login bit push h ! xchg ; put pointer in stack & lxi h,-2 ! dad d ! mov a,m ! sta @RDRV ; get relative drive lxi h,-6 ! dad d ; find LOGIN addr mov a,m ! inx h ! mov h,m ! mov l,a ; get address of LOGIN routine call ipchl ; call LOGIN pop h ; recover DPH pointer not$first$select: ret ; HOME ; Home selected drive. Treated as SETTRK(0). home: lxi b,0 ; same as set track zero ; SETTRK ; Set Track. Saves track address from ; in @TRK for further operations. settrk: mov l,c ! mov h,b shld @trk ret ; SETSEC ; Set Sector. Saves sector number from ; in @sect for further operations. setsec: mov l,c ! mov h,b shld @sect ret ; SETDMA ; Set Disk Memory Address. Saves DMA address ; from in @DMA and sets @DBNK to @CBNK ; so that further disk operations take place ; in current bank. setdma: mov l,c ! mov h,b shld @dma lda @cbnk ; default DMA bank is current bank ; fall through to set DMA bank ; SETBNK ; Set Disk Memory Bank. Saves bank number ; in @DBNK for future disk data ; transfers. setbnk: sta @dbnk ret ; SECTRN ; Sector Translate. Indexes skew table in ; with sector in . Returns physical sector ; in . If no skew table (=0) then ; returns physical=logical. sectrn: mov l,c ! mov h,b mov a,d ! ora e ! rz xchg ! dad b ! mov l,m ! mvi h,0 ret ; READ ; Read physical record from currently selected drive. ; Finds address of proper read routine from ; extended disk parameter header (XDPH). read: lhld @adrv ! mvi h,0 ! dad h ; get drive code and double it lxi d,@dtbl ! dad d ; make address of table entry mov a,m ! inx h ! mov h,m ! mov l,a ; fetch table entry push h ; save address of table lxi d,-8 ! dad d ; point to read routine address jmp rw$common ; use common code ; WRITE ; Write physical sector from currently selected drive. ; Finds address of proper write routine from ; extended disk parameter header (XDPH). write: lhld @adrv ! mvi h,0 ! dad h ; get drive code and double it lxi d,@dtbl ! dad d ; make address of table entry mov a,m ! inx h ! mov h,m ! mov l,a ; fetch table entry push h ; save address of table lxi d,-10 ! dad d ; point to write routine address rw$common: mov a,m ! inx h ! mov h,m ! mov l,a ; get address of routine pop d ; recover address of table dcx d ! dcx d ; point to relative drive ldax d ! sta @rdrv ; get relative drive code and post it inx d ! inx d ; point to DPH again pchl ; leap to driver ; MULTIO ; Set multiple sector count. Saves passed count in ; @CNT multio: sta @cnt ! ret ; FLUSH ; BIOS deblocking buffer flush. Not implemented. flush: xra a ! ret ; return with no error ; error message components drive$msg db cr,lf,bell,'BIOS Error on ',0 track$msg db ': T-',0 sector$msg db ', S-',0 ; disk communication data items @adrv ds 1 ; currently selected disk drive @rdrv ds 1 ; controller relative disk drive @trk ds 2 ; current track number @sect ds 2 ; current sector number @dma ds 2 ; current DMA address @cnt db 0 ; record count for multisector transfer @dbnk db 0 ; bank for DMA operations @cbnk db 0 ; bank for processor operations @ermde db 0ffh end