title 'Root module of relocatable BIOS for CP/M 3.0' ; version 1.0 15 Sept 82 include config.inc include z180reg.inc ; Copyright (C), 1982 ; Digital Research, Inc ; P.O. Box 579 ; Pacific Grove, CA 93950 ; This is the invariant portion of the modular BIOS and is ; distributed as source for informational purposes only. ; All desired modifications should be performed by ; adding or changing externally defined modules. ; This allows producing "standard" I/O modules that ; can be combined to support a particular system ; configuration. ctlQ equ 'Q'-'@' ctlS equ 'S'-'@' ccp equ 0100h ; Console Command Processor gets loaded ; into the TPA cseg ; GENCPM puts CSEG stuff in common memory ; variables in system data page extrn @covec,@civec,@aovec,@aivec,@lovec ; I/O redirection vectors extrn @mxtpa ; addr of system entry point extrn @bnkbf ; 128 byte scratch buffer ; initialization extrn hwinit,?init ; general initialization and signon extrn ?ldccp,?rlccp ; load & reload CCP for BOOT & WBOOT ; user defined character I/O routines extrn ?ci,?co,?cist,?cost ; each take device in extrn ?cinit ; (re)initialize device in extrn ioctl extrn @ctbl ; physical character device table ; 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 ; '' '' '' '' public @xdph,@op ; memory control public @cbnk ; current bank extrn ?xmove,?move ; select move bank, and block move extrn ?bank ; select CPU bank ; clock support extrn ?time ; signal time operation extrn ijphl ; vectored call maclib modebaud.inc ; define mode bits ; External names for BIOS entry points public ?boot,?wboot,boot,?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 public bs$stack ; BIOS Jump vector. ; All BIOS routines are invoked by calling these ; entry points. ?boot: jp boot ; initial entry on cold start ?wboot: jp wboot ; reentry on program exit, warm start ?const: jp const ; return console input status ?conin: jp conin ; return console input character ?cono: jp conout ; send console output character ?list: jp list ; send list output character ?auxo: jp auxout ; send auxiliary output character ?auxi: jp auxin ; return auxiliary input character ?home: jp home ; set disks to logical home ?sldsk: jp seldsk ; select disk drive, return disk parameter info ?sttrk: jp settrk ; set disk track ?stsec: jp setsec ; set disk sector ?stdma: jp setdma ; set disk I/O memory address ?read: jp read ; read physical block(s) ?write: jp write ; write physical block(s) ?lists: jp listst ; return list device status ?sctrn: jp sectrn ; translate logical to physical sector ?conos: jp conost ; return console output status ?auxis: jp auxist ; return aux input status ?auxos: jp auxost ; return aux output status ?dvtbl: jp devtbl ; return address of device def table ?devin: jp ?cinit ; change baud rate of device ?drtbl: jp getdrv ; return address of disk drive table ?mltio: jp multio ; set multiple record count for disk I/O ?flush: jp flush ; flush BIOS maintained disk caching ?mov: jp ?move ; block move memory to memory ?tim: jp ?time ; Signal Time and Date operation ?bnksl: jp bnksel ; select bank for code execution and default DMA ?stbnk: jp setbnk ; select different bank for disk I/O DMA operations ?xmov: jp ?xmove ; set source and destination banks for one operation jp 0 ; reserved for system implementor jp 0 ; reserved for future expansion jp 0 ; reserved for future expansion ?ioctl jp ioctl ; ; BOOT ; Initial entry point for system startup. dseg ; this part can be banked boot: ld a,SYS$CBR out0 (cbr),a ld a,USR$CBAR out0 (cbar),a ld sp,bs$stack call hwinit ; first time hardware initialisation ld bc,16*256 + 0 ; initialize all 16 character devices c$init$loop: push bc call ?cinit pop bc inc c djnz c$init$loop call ?init ; perform any additional system initialization ; and print signon message ld bc,16*256+0 ld hl,@dtbl ; init all 16 logical disk drives d$init$loop: push bc ; save remaining count and abs drive ld e,(hl) inc hl ld d,(hl) inc hl ; grab @drv entry ld a,e or d jr z,d$init$next ; if null, no drive push hl ; save @drv pointer push de pop ix ; XDPH address in ld b,(ix-2) ld (@ADRV),bc ; save absolute and relative drive code ld l,(ix-4) ld h,(ix-3) ; get init pointer call ijphl ; call init routine pop hl ; recover @drv pointer d$init$next: pop bc ; recover counter and drive # inc c djnz d$init$loop ; and loop for each drive jp boot$1 cseg ; following in resident memory boot$1: call set$jumps call ?ldccp ; fetch CCP for first time jp ccp ; WBOOT ; Entry for system restarts. wboot: ld sp,bs$stack call set$jumps ; initialize page zero call ?rlccp ; reload CCP jp ccp ; then reset jmp vectors and exit to ccp set$jumps: if banked ld a,1 call ?bnksl endif ld a,0C3h ; jp opcode ld (0),a ld (5),a ; set up jumps in page zero ld hl,?wboot ld (1),hl ; BIOS warm start entry ld hl,(@MXTPA) ld (6),hl ; BDOS system call entry ret ds bs$stack$size bs$stack equ $ ; DEVTBL ; Return address of character device table devtbl: ld hl,@ctbl ret ; GETDRV ; Return address of drive table getdrv: ld hl,@dtbl ret ; LIST ; List Output. Send character in ; to all selected devices. list: ld hl,(@lovec) ; fetch list output bit vector jr out$scan ; AUXOUT ; Auxiliary Output. Send character in ; to all selected devices auxout: ld hl,(@aovec) ; fetch aux output bit vector jr out$scan ; CONOUT ; Console Output. Send character in ; to all selected devices conout: ld hl,(@covec) ; fetch console output bit vector out$scan: ld b,0 ; start with device 0 co$next: add hl,hl ; shift out next bit jr nc,not$out$device push hl ; save the vector push bc ; save device num and the character call ?co ; if device selected, print it pop bc ; recover count and character pop hl ; recover the rest of the vector not$out$device: inc b ; next device number ld a,h or l ; see if any devices left jr nz,co$next ; and go find them... ret ; LISTST ; List Output Status. Return true if ; all selected list output devices ; are ready. listst: ld hl,(@lovec) ; get list output bit vector jr ost$scan ; AUXOST ; Auxiliary Output Status. Return true if ; all selected auxiliary output devices ; are ready. auxost: ld hl,(@aovec) ; get aux output bit vector jr ost$scan ; CONOST ; Console Output Status. Return true if ; all selected console output devices ; are ready. conost: ld hl,(@covec) ; get console output bit vector ost$scan: ld b,0 ; start with device 0 cos$next: add hl,hl ; check next bit push hl ; save the vector push bc ; save the count ld a,0FFh ; assume device ready call c,?cost ; check status for this device pop bc ; recover count pop hl ; recover bit vector or a ; see if device ready ret z ; if any not ready, return false inc b ; drop device number ld a,h or l ; see if any more selected devices jr nz,cos$next or 0FFh ; all selected were ready, return true ret cist1: ; get input status with and saved push bc push hl call ?cist pop hl pop bc or a ret ; AUXIST ; Auxiliary Input Status. Return true if ; any selected auxiliary input device ; has an available character. auxist: ld hl,(@aivec) ; get aux input bit vector jr ist$scan ; CONST ; Console Input Status. Return true if ; any selected console input device ; has an available character. const: ld hl,(@civec) ; get console input bit vector ist$scan: ld b,0 ; start with device 0 cis$next: xor a ; assume next device not ready add hl,hl ; check next bit (lets z flag unaffected) call c,cist1 ; check status for this device ret nz ; if any ready, return true inc b ; next device number ld a,h or l ; see if any more selected devices ret z ; all selected were not ready, return false jr cis$next ; AUXIN ; Auxiliary Input. Return character from first ; ready auxiliary input device. auxin: ld hl,(@aivec) jr in$scan ; CONIN ; Console Input. Return character from first ; ready console input device. conin: ld hl,(@civec) ;check if only one device assigned push hl ; save bit vector ld b,0 insc_0: or a ; clear carry adc hl,hl ; shift out next bit jr nc,insc_1 ; jr z,ci$rdy ; single device jr ci$check ; insc_1: inc b ; else, next device ld a,h or l ; see if any more devices jr nz,insc_0 ; no, pop hl in$scan: push hl ; save bit vector ld b,0 ci$next: xor a ; assume next device not ready add hl,hl ; shift out next bit ci$check: call c,cist1 ; see if the device has a character jr nz,ci$rdy ; this device has a character inc b ; else, next device ld a,h or l ; see if any more devices jr nz,ci$next ; go look at them pop hl ; recover bit vector jr in$scan ; loop til we find a character ci$rdy: pop hl ; discard extra stack jp ?ci ;------------------------------------------------------------------------------- ; Utility Subroutines ; BNKSEL ; Bank Select. Select CPU bank for further execution. bnksel: ld (@cbnk),a ; remember current bank jp ?bank ; and go exit through users ; physical bank select routine dseg ; following resides in banked memory ; 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: ld a,c ; save drive select code ld (@adrv),a xor a ld (@op),a ld (@cnt),a ld b,a ; create index from drive code ld hl,@dtbl add hl,bc ; get pointer to dispatch table add hl,bc ld a,(hl) inc hl ld h,(hl) ld l,a ; point at disk descriptor ld (@xdph),hl ; save descriptor pointer or h ret z ; if no entry in table, no disk bit 0,e ; login bit to zero flag ex de,hl ld hl,-2 ; get relative drive add hl,de ld a,(hl) ld (@RDRV),a jr nz,notfirst ; examine login bit ld hl,-6 add hl,de ld a,(hl) inc hl ld h,(hl) ld l,a call ijphl ; call LOGIN ld hl,(@xdph) ; recover DPH pointer ret ; HOME ; Home selected drive. Treated as SETTRK(0). home: ld bc,0 ; same as set track zero ; SETTRK ; Set Track. Saves track address from ; in @TRK for further operations. settrk: ld (@trk),bc ret ; SETSEC ; Set Sector. Saves sector number from ; in @sect for further operations. setsec: ld (@sect),bc 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: ld (@dma),bc ld a,(@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: ld (@dbnk),a 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: ld l,c ld h,b ld a,d or e ret z ex de,hl add hl,bc ld l,(hl) ld h,0 ret ; READ ; Read physical record from currently selected drive. ; Finds address of proper read routine from ; extended disk parameter header (XDPH). read: ld a,1 ld (@op),a ld ix,(@xdph) ; get drive descriptor pointer ld l,(ix-8) ; get read routine entry ld h,(ix-7) jp (hl) ; WRITE ; Write physical sector from currently selected drive. ; Finds address of proper write routine from ; extended disk parameter header (XDPH). write: ld a,2 ld (@op),a ld ix,(@xdph) ; get drive descriptor pointer ld l,(ix-10) ; get write routine entry ld h,(ix- 9) jp (hl) ; MULTIO ; Set multiple sector count. Saves passed count in ; @CNT multio: ld (@cnt),a ret ; FLUSH ; BIOS deblocking buffer flush. Not implemented. flush: xor a ret ; return with no error ; disk communication data items ; do not change order. sd driver depends on this @xdph: ds 2 ; pointer to currently selected drives dph @op ds 1 ; current disk operation 0:select, 1:read, 2 write @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 @dbnk: db 0 ; bank for DMA operations @cnt: db 0 ; record count for multisector transfer cseg ; common memory @cbnk: db 0 ; bank for processor operations end