You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

691 lines
18 KiB

maclib ldropts.lib
maclib cpm3.lib
cseg
extrn phex16, phex8
extrn cin, cout
extrn crlf, crlf2
include hbios.z80
debug equ false
; 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 devini ; change baud rate of device
?drtbl: jp drvtbl ; 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 selmem ; 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 future expansion
jp 0 ; reserved for future expansion
jp 0 ; reserved for future expansion
mbrsec equ dtabuf
boot:
; The main module (cpmldr.asm) does not expect the
; boot call to use much stack. We use our own during
; this routine to avoid issues.
ld (stksav),sp
ld sp,stack
; Do the real work
call boot0
; Restore original stack and return
ld sp,(stksav)
ret
boot0:
if cmdline
boot1:
;
; The following Code is the Entry Point for the Loader when
; it is built as a COM file. Typically CPMLDR.COM or ZPMLDR.COM
;
; Get disk unit from user
ld de,msgunit ; disk unit prompt
call writestr ; display on console
call cin ; get a character
push af ; save it
call cout ; echo character
pop af ; restore it
sub '0' ; convert to binary
ld (unit),a ; save it
jr c,selerr ; loop if below 0 entered
ld bc,BC_SYSGET_DIOCNT ; HBIOS, get disk unit count
call 0FFF0h ; do it, E := disk unit count
ld a,(unit) ; get unit num back
cp e ; compare to entry
jr nc,selerr ; loop if too high
; Get disk slice from user
ld de,msgslc ; slice prompt
call writestr ; display on console
call cin ; get a character
push af ; save it
call cout ; echo it
pop af ; restore it
sub '0' ; convert to binary
ld (slice),a ; save it
jr c,selerr ; loop if below 0 entered
cp 10 ; check for over 9
jr nc,selerr ; loop if over 9
ld de,msgcrlf ; linefeed
call writestr ; ... to console
jr boot2 ; boot w/ unit & slice
selerr:
; Display invalid entry message and restart
ld de,msginv ; error message
call writestr ; display on console
jr boot1 ; loop
boot2:
; Record unit & slice w/ HBIOS
ld bc,BC_SYSSET_BOOTINFO ; HBIOS func: set boot info
ld a,(unit) ; get unit
ld d,a ; put in D
ld a,(slice) ; get slice
ld e,a ; put in E
ld l,0 ; Bank is always zero
call 0FFF0h ; do it
else
;
; The following Code is the Entry Point for the Loader when
; it is built as a SYS file, and run from the System Track
;
; Get unit & slice from HBIOS
ld bc,BC_SYSGET_BOOTINFO ; HBIOS func: get boot info
call 0FFF0h ; do it, D := boot unit, E: := slice
ld a,d ; move unit to A
ld (unit),a ; save it
ld a,e ; move slice to A
ld (slice),a ; save it
endif
; Sense media to determine media format
ld a,(unit) ; Get boot unit
ld d,a ; put in D
ld a,(slice) ; get boot slice
ld e,a ; put in E
ld b,BF_EXTSLICE ; HBIOS FUNC: SLICE
call 0FFF0H ; HBIOS call
; Check errors from the Function
cp ERR_NOUNIT ; compare to no unit error
jp z,err_nodisk ; handle no disk err
cp ERR_NOMEDIA ; no media in the device
jp z,err_nodisk ; handle the error
cp ERR_RANGE ; slice is invalid
jp z,err_noslice ; bad slice, handle err
or a ; any other error
jp nz,err_diskio ; handle as general IO error
; Initialize slice start LBA and Media ID
ld a,c
ld (medid),a ; save media id
boot8:
ld (lba),hl ; save new lba, low word
ld (lba+2),de ; save new lba, high word
boot9:
; Locate DPB corresponding to media id
ld hl,dpb$start - dpb$sz
ld de,dpb$sz
ld a,(medid) ; get media id
ld b,a ; to loop count
boot10:
add hl,de ; next dpb
djnz boot10 ; loop as needed
; Stuff DPB ptr (HL) into DPH
ld de,dph0 ; load DPH pointer
ex de,hl ; de = DPB adr, hl = DPH adr
push de ; save DPB adr
ld de,12 ; offset of DPB in DPH
add hl,de ; hl = adr of DPB field in DPH
pop de ; recover DPB adr
ld (hl),e ; update LSB
inc hl ; point to MSB
ld (hl),d ; update MSB
ret ; done
wboot:
ld a,81H
halt
const:
ld a,82H
halt
conin:
ld bc,0080h ; unit 80h (console), func 0 = CIN
call 0FFF0h ; do it
ld a,e ; put in C
ret ; done
conout:
ld e,c ; output character in E
ld bc,0180h ; unit 80h (console), func 1 = COUT
jp 0FFF0h
list:
ld a,85H
halt
auxout:
ld a,86H
halt
auxin:
ld a,87H
halt
home:
ld hl,0
ld (trk),hl
ret
seldsk:
ld hl,dph0
ret
settrk:
ld (trk),bc
ret
setsec:
ld (sect),bc
ret
setdma:
if debug
push hl
push bc
pop hl
call crlf
call phex16
pop hl
endif
ld (dma),bc
ret
read:
if debug
call crlf
ld a,(unit)
call phex8
ld a,' '
call cout
ld hl,(trk)
call phex16
ld a,' '
call cout
ld hl,(sect)
call phex16
ld a,' '
call cout
ld hl,(lba+2)
call phex16
ld hl,(lba+0)
call phex16
endif
; Check device type
ld a,(unit) ; get unit
ld c,a ; BIOS Disk Unit in C
ld b,BF_DIODEVICE ; HBIOS DEVICE function
rst 08 ; Do it, D=device type
ld a,d ; put in accum
cp 01h ; floppy?
jr nz,read2 ; if not, do LBA i/o
; Floppy I/O
ld de,(sect) ; sector -> de, head(d) becomes zero
ld hl,(trk) ; track -> hl (low bit has head)
srl h ; shift head bit out of hl
rr l ; ... and into carry
rl d ; carry bit (head) into d
jr read3 ; do the disk i/o
; LBA I/O
read2:
ld hl,(trk) ; get track
ld de,0 ; clear hiword
ld b,4 ; x16 (16 spt assumed)
call rl32 ; do it
; combine with sector
ld a,(sect) ; get sector
or l ; combine
ld l,a ; and back to L
; add in lba offset
ld bc,(lba) ; lba offset loword
add hl,bc ; add to cur loword
ex de,hl ; swap
ld bc,(lba+2) ; lba offset hiword
adc hl,bc ; add w/ carry to cur hiword
ex de,hl ; swap back
set 7,d ; set lba access bit
read3:
if debug
ld a,' '
call cout
ex de,hl
call phex16
ex de,hl
call phex16
endif
; DE:HL has sector address to read (LBA or CHS)
ld a,(unit) ; get disk unit
ld c,a ; put in C
ld b,1 ; read 1 sector
jr diskread ; read sector and return
diskread:
; Read disk sector(s)
; DE:HL is LBA, B is sector count, C is disk unit
; Seek to requested sector in DE:HL
push bc ; save unit & count
ld b,BF_DIOSEEK ; HBIOS func: seek
call 0FFF0h ; do it
pop bc ; recover unit & count
jp nz,err_diskio ; handle error
; Read sector(s) into buffer
ld e,b ; transfer count
ld b,BF_DIOREAD ; HBIOS func: disk read
ld hl,(dma) ; read into info sec buffer
ld a,(0FFE0h) ; get current bank
ld d,a ; put in D
call 0FFF0h ; do it
jp nz,err_diskio ; handle error
xor a ; signal success
ret ; and done
write:
ld a,8EH
halt
listst:
ld a,8FH
halt
sectrn:
ld h,b
ld l,c
ret
conost:
ld a,91H
halt
auxist:
ld a,92H
halt
auxost:
ld a,93H
halt
devtbl:
ld a,94H
halt
devini:
ld a,95H
halt
drvtbl:
ld a,96H
halt
multio:
ld a,97H
halt
flush:
ld a,98H
halt
move:
; On input, DE=src, HL=dest
ex de,hl ; swap HL/DE for LDIR
ldir ; Z80 block move
ex de,hl ; swap back (required!)
ret ; done
time:
ld a,9AH
halt
selmem:
ld a,9BH
halt
setbnk:
ld a,9CH
halt
xmove:
ld a,9DH
halt
;cin:
; ; Input character from console via HBIOS
; ld c,080H ; console unit to C
; ld b,BF_CIOIN ; HBIOS func: input char
; call 0FFF0H ; HBIOS reads character
; ld a,e ; To A for return
; ret ; done
;cout:
; ; Output character to console via HBIOS
; ld e,a ; output char to E
; ld c,080H ; console unit to C
; ld b,BF_CIOOUT ; HBIOS func: output char
; jp 0FFF0H ; output & return
writestr:
push af
writestr1:
ld a,(de)
cp '$' ; test for string terminator
jp z,writestr2
push de
call cout
pop de
inc de
jp writestr1
writestr2:
pop af
ret
rl32:
; Left shift DE:HL by B bits (B > 0)
or a ; clear carry
rl l ; rotate L thru carry
rl h ; rotate H thru carry
rl e ; rotate E thru carry
rl d ; rotate D thru carry
djnz rl32 ; loop B times
ret ; done
err_nodisk:
ld hl,str_err_nodisk
jr err
err_noslice:
ld hl,str_err_noslice
jr err
err_diskio:
ld hl,str_err_diskio
jr err
err_sig:
ld hl,str_err_sig
jr err
err_api:
ld hl,str_err_api
jr err
err:
push hl
ld de,str_err_prefix
call writestr
pop de
call writestr
halt
str_err_prefix db "\r\n\r\n*** ","$"
str_err_nodisk db "Disk unit not available","$"
str_err_noslice db "Slice not supported","$"
str_err_diskio db "Disk I/O failure","$"
str_err_sig db "No system image on disk","$"
str_err_api db "HBIOS API failure","$"
msgunit db 13,10,13,10,'Boot CP/M 3 from Disk Unit: $'
msgslc db ' Slice: $'
msginv db 13,10,13,10,'*** Invalid Selection ***$'
msgcrlf db 13,10,'$'
dpb$start:
dpb$rom: ; 384K ROM Drive
dw 64 ; spt: sectors per track
db 4 ; bsh: block shift factor
db 15 ; blm: block mask
db 1 ; exm: extent mask
dw 192 - 1 ; dsm: total storage in blocks - 1 = (384kb / 2k bls) - 1 = 191
dw 256 - 1 ; drm: dir entries - 1 = 256 - 1 = 255
db 11110000b ; al0: dir blk bit map, first byte
db 00000000b ; al1: dir blk bit map, second byte
dw 8000h ; cks: directory check vector size - permanent storage = 8000H
dw 0 ; off: reserved tracks = 16 trks * (16 trks * 16 heads * 16 secs * 512 bytes) = 128k
db 2 ; psh: 2 for 512 byte sectors
db 3 ; phm: (512 / 128) - 1
dpb$sz equ $ - dpb$start
dpb$ram: ; 256K RAM Drive
dw 64 ; spt: sectors per track
db 4 ; bsh: block shift factor
db 15 ; blm: block mask
db 1 ; exm: extent mask
dw 128 - 1 ; dsm: total storage in blocks - 1 = (256kb / 2k bls) - 1 = 127
dw 256 - 1 ; drm: dir entries - 1 = 256 - 1 = 255
db 11110000b ; al0: dir blk bit map, first byte
db 00000000b ; al1: dir blk bit map, second byte
dw 8000h ; cks: directory check vector size - permanent storage = 8000H
dw 0 ; off: reserved tracks = 16 trks * (16 trks * 16 heads * 16 secs * 512 bytes) = 128k
db 2 ; psh: 2 for 512 byte sectors
db 3 ; phm: (512 / 128) - 1
dpb$rf: ; 4MB RAM Floppy Drive
dw 64 ; spt: sectors per track
db 4 ; bsh: block shift factor
db 15 ; blm: block mask
db 0 ; exm: extent mask
dw 2047 ; dsm: total storage in blocks - 1 = (4mb / 2k bls) - 1 = 2047
dw 255 ; drm: dir entries - 1 = 256 - 1 = 255
db 11110000b ; al0: dir blk bit map, first byte
db 00000000b ; al1: dir blk bit map, second byte
dw 8000h ; cks: directory check vector size - permanent storage = 8000H
dw 0 ; off: reserved tracks = 0 trks
db 2 ; psh: 2 for 512 byte sectors
db 3 ; phm: (512 / 128) - 1
dpb$hd: ; 8MB Hard Disk Drive
dw 64 ; spt: sectors per track
db 5 ; bsh: block shift factor
db 31 ; blm: block mask
db 1 ; exm: extent mask
dw 2047 ; dsm: total storage in blocks - 1 = (8mb / 4k bls) - 1 = 2047
dw 512-1 ; drm: dir entries - 1 = 512 - 1 = 511
db 11110000b ; al0: dir blk bit map, first byte
db 00000000b ; al1: dir blk bit map, second byte
dw 8000h ; cks: directory check vector size - permanent storage = 8000H
dw 16 ; off: reserved tracks = 16 trks * (16 trks * 16 heads * 16 secs * 512 bytes) = 128k
db 2 ; psh: 2 for 512 byte sectors
db 3 ; phm: (512 / 128) - 1
dpb$fd720: ; 3.5" DS/DD Floppy Drive (720K)
dw 36 ; spt: sectors per track
db 4 ; bsh: block shift factor
db 15 ; blm: block mask
db 0 ; exm: extent mask
dw 350 ; dsm: total storage in blocks - 1 blk = ((720k - 18k off) / 2k bls) - 1 = 350
dw 127 ; drm: dir entries - 1 = 128 - 1 = 127
db 11000000b ; al0: dir blk bit map, first byte
db 00000000b ; al1: dir blk bit map, second byte
dw 32 ; cks: directory check vector size = 128 / 4
dw 4 ; off: reserved tracks = 4 trks * (512 b/sec * 36 sec/trk) = 18k
db 2 ; psh: 2 for 512 byte sectors
db 3 ; phm: (512 / 128) - 1
dpb_fd144: ; 3.5" DS/HD Floppy Drive (1.44M)
dw 72 ; spt: sectors per track
db 4 ; bsh: block shift factor
db 15 ; blm: block mask
db 0 ; exm: extent mask
dw 710 ; dsm: total storage in blocks - 1 blk = ((1,440k - 18k off) / 2k bls) - 1 = 710
dw 255 ; drm: dir entries - 1 = 256 - 1 = 255
db 11110000b ; al0: dir blk bit map, first byte
db 00000000b ; al1: dir blk bit map, second byte
dw 64 ; cks: directory check vector size = 256 / 4
dw 2 ; off: reserved tracks = 2 trks * (512 b/sec * 72 sec/trk) = 18k
db 2 ; psh: 2 for 512 byte sectors
db 3 ; phm: (512 / 128) - 1
dpb_fd360: ; 5.25" DS/DD Floppy Drive (360K)
dw 36 ; spt: sectors per track
db 4 ; bsh: block shift factor
db 15 ; blm: block mask
db 1 ; exm: extent mask
dw 170 ; dsm: total storage in blocks - 1 blk = ((360k - 18k off) / 2k bls) - 1 = 170
dw 127 ; drm: dir entries - 1 = 128 - 1 = 127
db 11110000b ; al0: dir blk bit map, first byte
db 00000000b ; al1: dir blk bit map, second byte
dw 32 ; cks: directory check vector size = 128 / 4
dw 4 ; off: reserved tracks = 4 trks * (512 b/sec * 36 sec/trk) = 18k
db 2 ; psh: 2 for 512 byte sectors
db 3 ; phm: (512 / 128) - 1
dpb_fd120: ; 5.25" DS/HD Floppy Drive (1.2M)
dw 60 ; spt: sectors per track
db 4 ; bsh: block shift factor
db 15 ; blm: block mask
db 0 ; exm: extent mask
dw 591 ; dsm: total storage in blocks - 1 blk = ((1,200k - 15k off) / 2k bls) - 1 = 591
dw 255 ; drm: dir entries - 1 = 256 - 1 = 255
db 11110000b ; al0: dir blk bit map, first byte
db 00000000b ; al1: dir blk bit map, second byte
dw 64 ; cks: directory check vector size = 256 / 4
dw 2 ; off: reserved tracks = 2 trks * (512 b/sec * 60 sec/trk) = 15k
db 2 ; psh: 2 for 512 byte sectors
db 3 ; phm: (512 / 128) - 1
dpb_fd111: ; 8" DS/DD Floppy Drive (1.11M)
dw 60 ; spt: sectors per track
db 4 ; bsh: block shift factor
db 15 ; blm: block mask
db 0 ; exm: extent mask
dw 569 ; dsm: total storage in blocks - 1 blk = ((1,155k - 15k off) / 2k bls) - 1 = 569
dw 255 ; drm: dir entries - 1 = 256 - 1 = 255
db 11110000b ; al0: dir blk bit map, first byte
db 00000000b ; al1: dir blk bit map, second byte
dw 64 ; cks: directory check vector size = 256 / 4
dw 2 ; off: reserved tracks = 2 trks * (512 b/sec * 60 sec/trk) = 15k
db 2 ; psh: 2 for 512 byte sectors
db 3 ; phm: (512 / 128) - 1
dpb$hdnew: ; 8MB Hard Disk Drive (new format)
dw 64 ; spt: sectors per track
db 5 ; bsh: block shift factor
db 31 ; blm: block mask
db 1 ; exm: extent mask
dw 2048 - 1 - 4 ; dsm: total storage in blocks - 1 = 2048 - 1 - resvd tracks
dw 1024 - 1 ; drm: dir entries
db 11111111b ; al0: dir blk bit map, first byte
db 00000000b ; al1: dir blk bit map, second byte
dw 8000h ; cks: directory check vector size - permanent storage = 8000H
dw 2 ; off: reserved tracks
db 2 ; psh: 2 for 512 byte sectors
db 3 ; phm: (512 / 128) - 1
dph0: dw 0 ; xlt, 0 means no translation
db 0,0,0,0,0,0,0,0,0 ; scratch (9 bytes)
db 0 ; mf: media flag
dw dpb$hd ; dpb
dw csvbuf ; csv:
dw alvbuf ; alv:
dw dirbcb ; dirbcb
dw dtabcb ; dtabcb
dw 0ffffh ; hash (disabled)
db 0 ; hbank
dtbl: dtbl dph0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
dirbcb: db 0ffh ; drv
db 0,0,0 ; rec#
db 0 ; wflg
db 0 ; scratch
dw 0 ; track
dw 0 ; sector
dw dirbuf ; buffad
dtabcb: db 0ffh ; drv
db 0,0,0 ; rec#
db 0 ; wflg
db 0 ; scratch
dw 0 ; track
dw 0 ; sector
dw dtabuf ; buffad
unit ds 1 ; HBIOS unit number
slice ds 1 ; HBIOS slice number
trk ds 2 ; current track
sect ds 2 ; current sector
dma ds 2 ; current DMA address
medid ds 1 ; media id
lba ds 4 ; current lba
ds 64
stack equ $
stksav ds 2
; CPMLDR.SYS must be a multiple of 512 bytes (one sector)
; for the RomWBW loader. Below padding as needed to force
; this.
ds 80h
csvbufs equ 256 ; length (CSV) = ((DRM+1)/4)
alvbufs equ 512 ; length (ALV) = ((DSM+1)/4)
dirbufs equ 512 ; sector buffer
dtabufs equ 512 ; sector buffer
; Trying to save space. The loader must fit underneath
; the start of BNKBDOS3 and we have a big BNKBDOS because
; of all the disk allocations. Putting these buffers
; in upper memory actually helps quite a bit.
csvbuf equ 8000h
alvbuf equ csvbuf + csvbufs
dirbuf equ alvbuf + alvbufs
dtabuf equ dirbuf + dirbufs
end