mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-24 17:04:19 +00:00
721 lines
15 KiB
Plaintext
721 lines
15 KiB
Plaintext
title 'Root module of relocatable BIOS for CP/M 3.0'
|
|
;
|
|
; code differs from cp/m 3 book marked with ^^^
|
|
;
|
|
; ^^^0 : book has, mvi a,jmp
|
|
; ^^^1 : book has, dcr b
|
|
; ^^^2 : book has not, mvi a,1 | sta @cnt
|
|
; ^^^3 : book has not, mov a,c
|
|
;
|
|
maclib ASMTYPE.LIB
|
|
|
|
.z80
|
|
;
|
|
; version 1.0 15 Sept 82
|
|
;
|
|
;
|
|
; 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.
|
|
;
|
|
cr equ 13
|
|
lf equ 10
|
|
bell equ 7
|
|
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 ; I/O re-direction vectors
|
|
extrn @aivec,@lovec
|
|
extrn @mxtpa ; addr of system entry point
|
|
extrn @bnkbf ; 128 byte scratch buffer
|
|
;
|
|
; initialization
|
|
extrn ?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 <B>
|
|
extrn ?cinit ; (re)initialize device in <C>
|
|
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 ; '' '' '' ''
|
|
;
|
|
; 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
|
|
;
|
|
; general utility routines
|
|
public ?pmsg,?pdec ; print message, print number from 0 to 65535
|
|
public ?pderr ; print BIOS disk error message header
|
|
;
|
|
maclib MODEBAUD.LIB ; define mode bits
|
|
;
|
|
; 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
|
|
;
|
|
;
|
|
; 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 auxilliary output character
|
|
?auxi: jp auxin ; return auxilliary 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 ; set 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
|
|
;
|
|
;
|
|
; BOOT
|
|
; Initial entry point for system startup.
|
|
;
|
|
dseg ; this part can be banked
|
|
;
|
|
boot:
|
|
ld sp,boot$stack
|
|
ld c,15 ; initialize all 16 character devices
|
|
c$init$loop:
|
|
push bc
|
|
call ?cinit
|
|
pop bc
|
|
dec c
|
|
jp p,c$init$loop
|
|
call ?init ; perform any additional system init.
|
|
; 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
|
|
jp z,d$init$next ; if null, no drive
|
|
push hl ; save @drv pointer
|
|
ex de,hl ; XDPH address in <HL>
|
|
dec hl
|
|
dec hl
|
|
ld a,(hl)
|
|
ld (@rdrv),a ; get relative drive code
|
|
ld a,c
|
|
ld (@adrv),a ; get absolute drive code
|
|
dec hl ; point to init pointer
|
|
ld d,(hl)
|
|
dec hl
|
|
ld e,(hl) ; get init pointer
|
|
ex de,hl
|
|
call ipchl ; call init routine
|
|
pop hl ; recover @drv pointer
|
|
d$init$next:
|
|
pop bc ; recover counter and drive #
|
|
inc c
|
|
dec b
|
|
jp nz,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,boot$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 ;^^^0
|
|
ld (0000h),a
|
|
ld (0005h),a ; set up jumps in page zero
|
|
ld hl,?wboot
|
|
ld (0001h),hl ; BIOS warm start entry
|
|
ld hl,(@mxtpa)
|
|
ld (0006h),hl ; BDOS system call entry
|
|
ret
|
|
;
|
|
ds 64
|
|
;
|
|
boot$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
|
|
;
|
|
; CONOUT
|
|
; Console Output. Send character in <C>
|
|
; to all selected devices
|
|
;
|
|
conout:
|
|
ld hl,(@covec) ; fetch console output bit vector
|
|
jp out$scan
|
|
;
|
|
; AUXOUT
|
|
; Auxiliary Output. Send character in <C>
|
|
; to all selected devices
|
|
;
|
|
auxout:
|
|
ld hl,(@aovec) ; fetch aux output bit vector
|
|
jp out$scan
|
|
;
|
|
; LIST
|
|
; List output. Send character in <C>
|
|
; to all selected devices.
|
|
;
|
|
list:
|
|
ld hl,(@lovec) ; fetch list output bit vector
|
|
out$scan:
|
|
ld b,0 ; start with device 0
|
|
co$next:
|
|
add hl,hl ; shift out next bit
|
|
jp nc,not$out$device
|
|
push hl ; save the vector
|
|
push bc ; save the count and character
|
|
not$out$ready:
|
|
call coster
|
|
or a
|
|
jp z,not$out$ready
|
|
pop bc
|
|
push bc ; restore and resave the character and device
|
|
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
|
|
jp nz,co$next ; and go find them...
|
|
ret
|
|
;
|
|
; CONOST
|
|
; Console Output Status. Return true if
|
|
; all selected console output devices
|
|
; are ready.
|
|
;
|
|
conost:
|
|
ld hl,(@covec) ; get console output bit vector
|
|
jp 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
|
|
jp ost$scan
|
|
;
|
|
; LISTST
|
|
; List output status. Return true if
|
|
; all selected list output devices
|
|
; are ready.
|
|
;
|
|
listst:
|
|
ld hl,(@lovec) ; get list 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,coster ; 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 ; ^^^1 next device number
|
|
ld a,h
|
|
or l ; see if any more selected devices
|
|
jp nz,cos$next
|
|
or 0ffh ; all selected were ready, return true
|
|
ret
|
|
;
|
|
coster: ; check for output device ready, including optional
|
|
; xon/xoff support
|
|
;
|
|
ld l,b
|
|
ld h,0 ; make device code 16 bits
|
|
push hl ; save it in stack
|
|
add hl,hl
|
|
add hl,hl
|
|
add hl,hl ; create offset into device characteristics tbl
|
|
ld de,@ctbl+6
|
|
add hl,de ; make address of mode byte
|
|
ld a,(hl)
|
|
and mb$xonxoff
|
|
pop hl ; recover console number in <HL>
|
|
jp z,?cost ; not a xon device, go get output status direct
|
|
ld de,xofflist
|
|
add hl,de ; make pointer to proper xon/xoff flag
|
|
call cist1 ; see if this keyboard has character
|
|
ld a,(hl)
|
|
call nz,ci1 ; get flag or read key if any
|
|
cp ctlq
|
|
jp nz,not$q ; if its a ctl-Q,
|
|
ld a,0ffh ; set the flag ready
|
|
not$q:
|
|
cp ctls
|
|
jp nz,not$s ; if its a ctl-S,
|
|
ld a,00h ; clear the flag
|
|
not$s:
|
|
ld (hl),a ; save the flag
|
|
call cost1 ; get the actual output status,
|
|
and (hl) ; and mask with ctl-q/ctl-s flag
|
|
ret ; return this as the status
|
|
;
|
|
cist1: ; get input status with <BC> and <HL> saved
|
|
push bc
|
|
push hl
|
|
call ?cist
|
|
pop hl
|
|
pop bc
|
|
or a
|
|
ret
|
|
;
|
|
cost1: ; get output status, saving <BC> & <HL>
|
|
push bc
|
|
push hl
|
|
call ?cost
|
|
pop hl
|
|
pop bc
|
|
or a
|
|
ret
|
|
;
|
|
ci1: ; get input, saving <BC> & <HL>
|
|
push bc
|
|
push hl
|
|
call ?ci
|
|
pop hl
|
|
pop bc
|
|
ret
|
|
;
|
|
; 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
|
|
jp ist$scan
|
|
;
|
|
; 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
|
|
ist$scan:
|
|
ld b,0 ; start with device 0
|
|
cis$next:
|
|
add hl,hl ; check next bit
|
|
ld a,0 ; assume device not ready
|
|
call c,cist1 ; check status for this device
|
|
or a
|
|
ret nz ; if any ready, return true
|
|
inc b ; next device number
|
|
ld a,h
|
|
or l ; see if any more selected devices
|
|
jp nz,cis$next
|
|
xor a ; all selected were not ready, return false
|
|
ret
|
|
|
|
; CONIN
|
|
; Console Input. Return character from first
|
|
; ready console input device.
|
|
;
|
|
conin:
|
|
ld hl,(@civec)
|
|
jp in$scan
|
|
;
|
|
; AUXIN
|
|
; Auxiliary Input. Return character from first
|
|
; ready auxiliary input device.
|
|
;
|
|
auxin:
|
|
ld hl,(@aivec)
|
|
in$scan:
|
|
push hl ; save bit vector
|
|
ld b,0
|
|
ci$next:
|
|
add hl,hl ; shift out next bit
|
|
ld a,0 ; insure zero a (nonexistant device not ready).
|
|
call c,cist1 ; see if the device has a character
|
|
or a
|
|
jp nz,ci$rdy ; this device has a character
|
|
inc b ; else, next device
|
|
ld a,h
|
|
or l ; see if any more devices
|
|
jp nz,ci$next ; go look at them
|
|
pop hl ; recover bit vector
|
|
jp in$scan ; loop till we find a character
|
|
ci$rdy: pop hl ; discard extra stack
|
|
jp ?ci
|
|
;
|
|
; Utility Subroutines
|
|
;
|
|
ipchl: ; vectored call point
|
|
jp (hl)
|
|
;
|
|
?pmsg: ; print message @<HL> up to a null
|
|
; saves <BC> & <DE>
|
|
;
|
|
push bc
|
|
push de
|
|
pmsg$loop:
|
|
ld a,(hl)
|
|
or a
|
|
jp z,pmsg$exit
|
|
ld c,a
|
|
push hl
|
|
call ?cono
|
|
pop hl
|
|
inc hl
|
|
jp pmsg$loop
|
|
pmsg$exit:
|
|
pop de
|
|
pop bc
|
|
ret
|
|
;
|
|
?pdec: ; print binary number 0-65535 from <HL>
|
|
;
|
|
ld bc,table10
|
|
ld de,-10000
|
|
next:
|
|
ld a,'0'-1
|
|
pdecl:
|
|
push hl
|
|
inc a
|
|
add hl,de
|
|
jp nc,stoploop
|
|
inc sp
|
|
inc sp
|
|
jp pdecl
|
|
stoploop:
|
|
push de
|
|
push bc
|
|
ld c,a
|
|
call ?cono
|
|
pop bc
|
|
pop de
|
|
nextdigit:
|
|
pop hl
|
|
ld a,(bc)
|
|
ld e,a
|
|
inc bc
|
|
ld a,(bc)
|
|
ld d,a
|
|
inc bc
|
|
ld a,e
|
|
or d
|
|
jp nz,next
|
|
ret
|
|
;
|
|
table10:
|
|
dw -1000,-100,-10,-1,0
|
|
;
|
|
?pderr:
|
|
ld hl,drive$msg
|
|
call ?pmsg ; error header
|
|
ld a,(@adrv)
|
|
add a,'A'
|
|
ld c,a
|
|
call ?cono ; drive code
|
|
ld hl,track$msg
|
|
call ?pmsg ; track header
|
|
ld hl,(@trk)
|
|
call ?pdec ; track number
|
|
ld hl,sector$msg
|
|
call ?pmsg ; sector header
|
|
ld hl,(@sect)
|
|
call ?pdec ; sector number
|
|
ret
|
|
;
|
|
; 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
|
|
;
|
|
xofflist:
|
|
db -1,-1,-1,-1,-1,-1,-1,-1 ; ctl-s clears to zero
|
|
db -1,-1,-1,-1,-1,-1,-1,-1
|
|
;
|
|
dseg ; following resides in banked memory
|
|
;
|
|
; Disk I/O interface routines
|
|
;
|
|
; SELDSK
|
|
; Select Disk Drive. Drive code in <C>.
|
|
; Invoke login procedure for drive
|
|
; if this is first select. Return
|
|
; address of disk parameter header
|
|
; in <HL>
|
|
;
|
|
seldsk: ld a,1 ;^^^2
|
|
ld (@cnt),a ;^^^2 clear multi counter
|
|
ld a,c
|
|
ld (@adrv),a ; save drive select code
|
|
ld l,c
|
|
ld h,0
|
|
add hl,hl ; create index from drive code
|
|
ld bc,@dtbl
|
|
add hl,bc ; get pointer to dispatch table
|
|
ld a,(hl)
|
|
inc hl
|
|
ld h,(hl)
|
|
ld l,a ; point at disk descriptor
|
|
or h
|
|
ret z ; if no entry in table, no disk
|
|
ld a,e
|
|
and 1
|
|
jp nz,not$first$select ; examine login bit
|
|
push hl
|
|
ex de,hl ; put pointer in stack & <DE>
|
|
ld hl,-2
|
|
add hl,de
|
|
ld a,(hl)
|
|
ld (@rdrv),a ; get relative drive
|
|
ld hl,-6
|
|
add hl,de ; find login addr
|
|
ld a,(hl)
|
|
inc hl
|
|
ld h,(hl)
|
|
ld l,a ; get address of login routine
|
|
call ipchl ; call login
|
|
pop hl ; recover dph pointer
|
|
not$first$select:
|
|
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 <BC>
|
|
; in @trk for further operations.
|
|
;
|
|
settrk:
|
|
ld l,c
|
|
ld h,b
|
|
ld (@trk),hl
|
|
ret
|
|
;
|
|
; SETSEC
|
|
; Set Sector. Saves sector number from <BC>
|
|
; in @sect for further operations.
|
|
;
|
|
setsec:
|
|
ld l,c
|
|
ld h,b
|
|
ld (@sect),hl
|
|
ret
|
|
;
|
|
; SETDMA
|
|
; Set Disk Memory Address. Saves DMA address
|
|
; from <BC> in @DMA and sets @dbnk to @cbnk
|
|
; so that further disk operations take place
|
|
; in current bank.
|
|
;
|
|
setdma:
|
|
ld l,c
|
|
ld h,b
|
|
ld (@dma),hl
|
|
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 <DE>
|
|
; with sector in <BC>. Returns physical sector
|
|
; in <HL>. If no skew table (<DE>=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 hl,(@adrv)
|
|
ld h,0
|
|
add hl,hl ; get drive code and double it
|
|
ld de,@dtbl
|
|
add hl,de ; make address of table entry
|
|
ld a,(hl)
|
|
inc hl
|
|
ld h,(hl)
|
|
ld l,a ; fetch table entry
|
|
push hl ; save address of table
|
|
ld de,-8
|
|
add hl,de ; point to read routine address
|
|
jp 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:
|
|
ld hl,(@adrv)
|
|
ld h,0
|
|
add hl,hl ; get drive code and double it
|
|
ld de,@dtbl
|
|
add hl,de ; make address of table entry
|
|
ld a,(hl)
|
|
inc hl
|
|
ld h,(hl)
|
|
ld l,a ; fetch table entry
|
|
push hl ; save address of table
|
|
ld de,-10
|
|
add hl,de ; point to write routine address
|
|
rw$common:
|
|
ld a,(hl)
|
|
inc hl
|
|
ld h,(hl)
|
|
ld l,a ; get address of routine
|
|
pop de ; recover address of table
|
|
dec de
|
|
dec de ; point to relative drive
|
|
ld a,(de)
|
|
ld (@rdrv),a ; get relative drive code and post it
|
|
inc de
|
|
inc de ; point to dph again
|
|
jp (hl) ; leap to driver
|
|
;
|
|
; MULTIO
|
|
; Set multiple sector count. Saves passed count in
|
|
; @CNT
|
|
;
|
|
multio:
|
|
ld a,c ;^^^3 passed in c
|
|
ld (@cnt),a
|
|
ret
|
|
;
|
|
; FLUSH
|
|
; BIOS deblocking buffer flush. Not implemented.
|
|
;
|
|
flush:
|
|
xor 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
|
|
;
|
|
cseg ; common memory
|
|
;
|
|
@cbnk: db 0 ; bank for processor operations
|
|
;
|
|
end
|