mirror of https://github.com/wwarthen/RomWBW.git
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.
1014 lines
27 KiB
1014 lines
27 KiB
;===============================================================================
|
|
; OSLdr - Load a new OS image from filesystem on running system.
|
|
; Optionally, load a new HBIOS image at the same time.
|
|
;===============================================================================
|
|
;
|
|
; Author: Wayne Warthen (wwarthen@gmail.com)
|
|
;_______________________________________________________________________________
|
|
;
|
|
; Usage:
|
|
; OSLDR /F <osimg> [<biosimg>]
|
|
; /F (force) overrides all compatibility checking
|
|
; ex. OSLDR CPM.SYS
|
|
; OSLDR CPM.SYS HBIOS.BIO
|
|
;
|
|
; <osimg> is an os image file such as cpm.sys or zsys.sys
|
|
; <biosimg> is an optional bios image such as hbios.bio
|
|
;_______________________________________________________________________________
|
|
;
|
|
; Operation:
|
|
; This application reads an OS image (and optionally HBIOS image)
|
|
; into TPA memory from the filesystem. It then copies the images to
|
|
; their appropriate locations and restarts the system.
|
|
; Note that the application itself is relocated to upper memory
|
|
; after starting so that it can manipulate the lower memory bank.
|
|
;
|
|
; The application uses the following memory layout:
|
|
;
|
|
; Loc Size Usage
|
|
; ----- ----- -----------------------------
|
|
; $0400-$3FFF $3C00 OS Image (max of 15K possible)
|
|
; $4000-$BFFF $8000 HBIOS Image (32K fixed size)
|
|
; $C000-$CFFF $1000 Application (after relocation)
|
|
;
|
|
; Notes:
|
|
; 1) Drive assignments are not retained. Drive assignments are
|
|
; reset during the OS boot.
|
|
; 2) The OS boot drive is not explicitly set by this app. If a new
|
|
; HBIOS image is not loaded, the boot drive passed to the OS will
|
|
; be the same as it was at the last boot. If a new HBIOS image
|
|
; is being loaded, the boot drive will be the default imbedded in
|
|
; the HBIOS image.
|
|
; 3) It is not possible to load a new UNA BIOS. However, when the
|
|
; app is run under UNA, it can load a new OS image and optionally
|
|
; load an HBIOS image.
|
|
;_______________________________________________________________________________
|
|
;
|
|
; Change Log:
|
|
;_______________________________________________________________________________
|
|
;
|
|
; ToDo:
|
|
;_______________________________________________________________________________
|
|
;
|
|
; Known Issues:
|
|
; 1) App will fail badly if OS image exceeds 15K
|
|
; 2) No attempt is made to match the BIOS image version against
|
|
; the running BIOS version. This is intended behavior and is
|
|
; to allow a different BIOS version to be tested. A failure
|
|
; could occur if the BIOS image does not conform to the
|
|
; expected structure (size, meta data location, entry point
|
|
; location, etc.)
|
|
;_______________________________________________________________________________
|
|
;
|
|
;===============================================================================
|
|
; Definitions
|
|
;===============================================================================
|
|
;
|
|
stksiz .equ $40 ; we are a stack pig
|
|
;
|
|
restart .equ $0000 ; CP/M restart vector
|
|
bdos .equ $0005 ; BDOS invocation vector
|
|
;
|
|
; Memory layout (see Operation description above)
|
|
;
|
|
osimg .equ $0400 ; OS image load location (max 15K)
|
|
hbimg .equ $4000 ; HBIOS image load location (32K fixed)
|
|
runloc .equ $C000 ; running location (after relocation)
|
|
;
|
|
; Below are offsets in OS image of specific data fields
|
|
; The first 1.5K of the OS image is a header
|
|
;
|
|
hdrsiz .equ $600 ; Len of OS image header (3 sectors)
|
|
ossig .equ osimg + $580 ; Signature ($A55A)
|
|
osplt .equ osimg + $582 ; Platform ID
|
|
osver .equ osimg + $5E3 ; Version (4 bytes, maj, min, up, pat)
|
|
osloc .equ osimg + $5FA ; Intended address to load OS image
|
|
osend .equ osimg + $5FC ; Ending load address of OS image
|
|
osent .equ osimg + $5FE ; Entry point for OS image
|
|
osbin .equ osimg + hdrsiz ; Start of actual OS binary (after header)
|
|
;
|
|
; HBIOS internal info (adjust if HBIOS changes)
|
|
;
|
|
bfgbnk .equ $F3 ; HBIOS Get Bank function
|
|
bfver .equ $F1 ; HBIOS Get Version function
|
|
sigptr .equ hbimg + 3 ; HBIOS signature pointer
|
|
hbmrk .equ hbimg + $100 ; HBIOS marker
|
|
hbver .equ hbimg + $102 ; HBIOS version
|
|
hbplt .equ hbimg + $104 ; HBIOS platform
|
|
bidusr .equ hbimg + $10B ; User bank id
|
|
bidbios .equ hbimg + $10C ; BIOS bank id
|
|
pxyimg .equ hbimg + $200 ; Proxy image offset within HBIOS image
|
|
pxyloc .equ $FE00 ; Proxy run location
|
|
pxysiz .equ $0200 ; Proxy size
|
|
srcbnk .equ $FFE4 ; Address of bank copy source bank id
|
|
dstbnk .equ $FFE7 ; Address of bank copy destination bank id
|
|
curbnk .equ $FFE0 ; Address of current bank id in hbios proxy
|
|
hbxbnk .equ $FFF3 ; Bank select function entry address
|
|
hbxcpy .equ $FFF6 ; Bank copy function entry address
|
|
;
|
|
;===============================================================================
|
|
; Code Section
|
|
;===============================================================================
|
|
;
|
|
.org $100 ; startup org
|
|
|
|
; relocate ourselves to upper memory
|
|
ld hl,$0000 ; from startup location
|
|
ld de,runloc ; to running location
|
|
ld bc,$0800 ; assume we are no more that 2048 bytes
|
|
ldir ; copy ourselves
|
|
jp phase2 ; jump to new location
|
|
|
|
.org $ + runloc ; adjust for phase 2 location
|
|
phase2:
|
|
; setup stack (save old value)
|
|
ld (stksav),sp ; save stack
|
|
ld sp,stack ; set new stack
|
|
|
|
; processing...
|
|
call main ; do the real work
|
|
call crlf ; formatting
|
|
|
|
; return (we only get here if an error occurs)
|
|
jp 0 ; return to CP/M via reset
|
|
;
|
|
; Main routine
|
|
;
|
|
main:
|
|
call init ; initialize
|
|
ret nz ; abort on failure
|
|
|
|
call parse ; parse command tail
|
|
ret nz ; abort on failure
|
|
|
|
; call confirm ; confirm pending action
|
|
; ret nz ; abort on failure
|
|
|
|
call crlf2 ; formatting
|
|
|
|
; Read OS image into TPA
|
|
call rdos ; do the os read
|
|
ret nz ; abort on failure
|
|
|
|
; If specified, read BIOS image
|
|
ld a,(newbio) ; get BIOS load flag
|
|
or a ; set flags
|
|
call nz,rdbio ; do the bios read
|
|
ret nz ; abort on failure
|
|
|
|
call crlf ; formatting
|
|
|
|
; If force flag set, bypass image validitity checking
|
|
ld a,(force) ; load the flag
|
|
or a ; set flags
|
|
jr nz,main1 ; if set, bypass checks
|
|
|
|
; Check BIOS Image is acceptable
|
|
ld a,(newbio) ; get BIOS load flag
|
|
or a ; set flags
|
|
call nz,chkbios ; check the bios image
|
|
ret nz ; abort on failure
|
|
|
|
; Check OS Image is acceptable for requested operation
|
|
call chkos ; check the os image
|
|
ret nz ; abort on failure
|
|
|
|
main1:
|
|
; Load OS image into upper memory OS location
|
|
call ldos ; load OS
|
|
ret nz ; abort on failure
|
|
|
|
; If specified, load BIOS image to BIOS bank
|
|
ld a,(newbio) ; get BIOS load flag
|
|
or a ; set flags
|
|
jr z,main3 ; if not set, skip BIOS load and init
|
|
call ldbio ; load BIOS
|
|
ret nz ; abort on failure
|
|
|
|
; Initialize BIOS
|
|
call initbio ; initialize BIOS
|
|
|
|
main3:
|
|
; Launch...
|
|
ld hl,(osent) ; OS entry point
|
|
jp (hl) ; jump to OS BOOT vector
|
|
;
|
|
; Initialization
|
|
;
|
|
init:
|
|
call crlf
|
|
ld de,msgban ; point to banner
|
|
call prtstr ; display it
|
|
|
|
; locate cbios function table address
|
|
ld hl,(restart+1) ; load address of CP/M restart vector
|
|
ld de,-3 ; adjustment for start of table
|
|
add hl,de ; HL now has start of table
|
|
ld (cbftbl),hl ; save it
|
|
|
|
; save current drive no
|
|
ld c,$19 ; bdos func: get current drive
|
|
call bdos ; invoke BDOS function
|
|
inc a ; 1-based index for fcb
|
|
ld (defdrv),a ; save it
|
|
|
|
; check for UNA (UBIOS)
|
|
ld de,msghb ; assume HBIOS (point to HBIOS mode string)
|
|
ld a,($fffd) ; fixed location of UNA API vector
|
|
cp $c3 ; jp instruction?
|
|
jr nz,init1 ; if not, not UNA
|
|
ld hl,($fffe) ; get jp address
|
|
ld a,(hl) ; get byte at target address
|
|
cp $fd ; first byte of UNA push ix instruction
|
|
jr nz,init1 ; if not, not UNA
|
|
inc hl ; point to next byte
|
|
ld a,(hl) ; get next byte
|
|
cp $e5 ; second byte of UNA push ix instruction
|
|
jr nz,init1 ; if not, not UNA
|
|
ld hl,unamod ; point to UNA mode flag
|
|
ld (hl),$ff ; set UNA mode
|
|
ld a,6 ; UNA platform ID
|
|
ld (bioplt),a ; save it
|
|
ld de,msgub ; point to UBIOS string
|
|
|
|
init1:
|
|
call prtstr ; print BIOS name
|
|
|
|
; if HBIOS active, get version number
|
|
ld a,(unamod) ; get UNA mode flag
|
|
or a ; set flags
|
|
jr nz,init2 ; skip if UNA BIOS active
|
|
ld b,bfver ; HBIOS func: get version
|
|
rst 08 ; do it
|
|
ld a,l ; platform to A
|
|
ld (bioplt),a ; save platform
|
|
ld h,e ; switch bytes
|
|
ld l,d ; ... to save as maj/min, up/pat
|
|
ld (biover),hl ; save version
|
|
ld b,bfgbnk ; HBIOS func: get current bank
|
|
rst 08 ; do it
|
|
ld a,c ; move to A
|
|
ld (tpabnk),a ; save it
|
|
|
|
init2:
|
|
; return success
|
|
xor a
|
|
ret
|
|
;
|
|
; Parse command tail
|
|
;
|
|
parse:
|
|
ld hl,$81 ; point to start of command tail (after length byte)
|
|
call nonblank ; locate start of parms
|
|
jp z,erruse ; no parms
|
|
call options ; process options
|
|
ret nz ; abort if error
|
|
ld de,osfcb ; point to os image fcb
|
|
call convert ; convert destination spec
|
|
jp nz,erramb ; Error, ambiguous file specification
|
|
call nonblank ; skip blanks
|
|
or a ; end of command tail (null)?
|
|
jr z,parse1 ; if end, skip bios image fcb
|
|
ld de,biofcb ; point to bios image fcb
|
|
call convert ; convert spec to fcb
|
|
jp nz,erramb ; Error, ambiguous file specification
|
|
or $FF ; flag = true
|
|
ld (newbio),a ; set newbio flag to true
|
|
;
|
|
parse1:
|
|
; return success
|
|
xor a ; signal success
|
|
ret ; done parsing
|
|
;
|
|
options:
|
|
; process options
|
|
cp '/' ; option introducer?
|
|
jr nz,options2 ; if not '/' exit with success
|
|
inc hl ; bump past option introducer
|
|
ld a,(hl) ; get the next character
|
|
cp 'F' ; compare to 'F'
|
|
jr z,optf ; handle if so
|
|
jp erruse ; bail out if unexpected option
|
|
|
|
options1:
|
|
; post-processing after option
|
|
inc hl ; move past option
|
|
call nonblank ; skip blanks
|
|
jr options ; loop
|
|
|
|
options2:
|
|
; success exit
|
|
xor a ; signal success
|
|
ret
|
|
|
|
optf:
|
|
; set force flag
|
|
or $FF ; load true
|
|
ld (force),a ; set flag
|
|
jr options1 ; done
|
|
;
|
|
; Confirm pending action with user
|
|
;
|
|
confirm:
|
|
; ; prompt
|
|
; call crlf
|
|
; ld de,sconf1
|
|
; call prtstr
|
|
; ld hl,biofcb
|
|
; call prtfcb
|
|
; ld de,sconf2
|
|
; call prtstr
|
|
; ld hl,osfcb
|
|
; call prtfcb
|
|
; ld de,sconf3
|
|
; call prtstr
|
|
;;
|
|
; ; get input
|
|
; ld c,$0A ; get console buffer
|
|
; ld de,osimg ; into buf
|
|
; ld a,1 ; max of 1 character
|
|
; ld (de),a ; set up buffer
|
|
; call bdos ; invoke BDOS
|
|
; ld a,(osimg+1) ; get num chars entered
|
|
; dec a ; check that we got exactly one char
|
|
; jr nz,confirm ; bad input, re-prompt
|
|
; ld a,(osimg+2) ; get the character
|
|
; and $DF ; force upper case
|
|
; cp 'Y' ; compare to Y
|
|
xor a ; *temp*
|
|
ret ; return with Z set appropriately
|
|
;
|
|
; Read OS image file into memory
|
|
;
|
|
rdos:
|
|
ld de,msgros ; point to "Reading OS" message
|
|
call prtstr ; display it
|
|
|
|
; open the file
|
|
ld c,$0F ; bdos open file
|
|
ld de,osfcb ; bios image fcb
|
|
ld (rwfcb),de ; save it
|
|
call bdos ; invoke bdos function
|
|
cp $FF ; $FF is error
|
|
jp z,errfil ; handle error condition
|
|
; read the header
|
|
ld a,$14 ; setup for bdos read sequential
|
|
ld (rwfun),a ; save bdos function
|
|
ld a,12 ; start with 1536 byte header (12 records)
|
|
ld (reccnt),a ; init record counter
|
|
ld hl,osimg ; start of buffer
|
|
ld (bufptr),hl ; init buffer pointer
|
|
call rwfil ; read the header
|
|
ret nz ; abort on error (no need to close file)
|
|
; check header and get image size
|
|
call chkhdr ; verifies marker, hl = image size
|
|
ret nz ; abort on error (no need to close file)
|
|
ld b,7 ; right shift 7 bits to get 128 byte record count
|
|
rdos1: srl h ; shift right msb
|
|
rr l ; shift lsb w/ carry from msb
|
|
djnz rdos1 ; loop till done
|
|
ld a,l ; record count to a
|
|
ld (reccnt),a ; set remaining records to read
|
|
add a,12 ; add the header back
|
|
ld (imgsiz),a ; and save the total image size (in records)
|
|
call rwfil ; do it
|
|
ret nz ; abort on error
|
|
; return via close file
|
|
jp closefile ; close file
|
|
;
|
|
;
|
|
;
|
|
rdbio:
|
|
ld de,msgrbio ; point to "Reading BIOS" message
|
|
call prtstr ; display it
|
|
|
|
; open the file
|
|
ld c,$0F ; bdos open file
|
|
ld de,biofcb ; bios image fcb
|
|
ld (rwfcb),de ; save it
|
|
call bdos ; invoke bdos function
|
|
cp $FF ; $FF is error
|
|
jp z,errfil ; handle error condition
|
|
; read 32K HBIOS image
|
|
ld a,$14 ; setup for bdos read sequential
|
|
ld (rwfun),a ; save bdos function
|
|
ld a,0 ; 0 means 256 records (32K)
|
|
ld (reccnt),a ; init record counter
|
|
ld hl,hbimg ; start of buffer
|
|
ld (bufptr),hl ; init buffer pointer
|
|
call rwfil ; read the header
|
|
ret nz ; abort on error (no need to close file)
|
|
; return via close file
|
|
jp closefile ; close file
|
|
;
|
|
; Examine the BIOS image loaded. Confirm existence of expected
|
|
; BIOS identification marker in first page (fail if not there).
|
|
; Display the BIOS identification information. Confirm it is HBIOS
|
|
; and fail if not. Save the HBIOS version number.
|
|
;
|
|
chkbios:
|
|
; locate ROM signature in image
|
|
ld hl,sigptr ; point to ROM signature adr
|
|
ld a,(hl) ; dereference
|
|
inc hl ; ... to point
|
|
ld h,(hl) ; ... to location
|
|
ld l,a ; ... of signature block
|
|
ld de,hbimg ; offset by start
|
|
add hl,de ; ... of BIOS image
|
|
|
|
; check signature
|
|
ld a,$76 ; first byte value
|
|
cp (hl) ; compare
|
|
jp nz,errsig ; if not equal, signature error
|
|
inc hl ; bump to next byte
|
|
ld a,$B5 ; second byte value
|
|
cp (hl) ; compare
|
|
jp nz,errsig ; if not equal, signature error
|
|
inc hl ; bump to next byte
|
|
|
|
;; display short name
|
|
;inc hl ; bump past structure version number
|
|
;inc hl ; bump past rom size
|
|
;ld e,(hl) ; load rom name
|
|
;inc hl ; ... pointer
|
|
;ld d,(hl) ; ... into DE
|
|
;ld hl,hbimg ; offset by start
|
|
;add hl,de ; ... of BIOS image
|
|
;ex de,hl ; get pointer to DE
|
|
;call crlf ; formatting
|
|
;call prtstr ; and display it
|
|
|
|
; check BIOS variant, only HBIOS supported
|
|
ld hl,hbmrk ; get the HBIOS marker
|
|
ld a,'W' ; first byte should be 'W'
|
|
cp (hl) ; compare
|
|
jp nz,errbio ; if not equal, fail
|
|
inc hl ; next byte
|
|
ld a,~'W' ; ... should be ~'W'
|
|
cp (hl) ; compare
|
|
jp nz,errbio ; if not equal, fail
|
|
|
|
; if UNA is running, skip platform/ver stuff
|
|
ld a,(unamod) ; get UNA mode flag
|
|
or a ; set flags
|
|
jr nz,chkbios1 ; skip if UNA
|
|
|
|
; get and check platform (must match)
|
|
ld hl,hbplt ; point to BIOS platform id
|
|
ld a,(bioplt) ; get current running platform id
|
|
cp (hl) ; match?
|
|
jp nz,errplt ; if not, platform error
|
|
|
|
; get HBIOS image version
|
|
ld hl,(hbver) ; get version byte from image
|
|
ld (biover),hl ; save it for later
|
|
|
|
chkbios1:
|
|
xor a
|
|
ret
|
|
;
|
|
; Examine the OS image loaded. Confirm existence of expected
|
|
; OS identification marker (fail if not there). Check the version
|
|
; number in the OS image header. Fail if OS image version does
|
|
; not match BIOS version.
|
|
;
|
|
chkos:
|
|
; check for signature
|
|
; Already verified in chkhdr
|
|
|
|
; compare platform id
|
|
ld a,(bioplt) ; get current HBIOS platform ID
|
|
ld hl,osplt ; point to OS image platform ID
|
|
cp (hl) ; compare
|
|
jp nz,errplt ; if not equal platform error
|
|
|
|
; bypass version check if UNA running
|
|
ld a,(unamod) ; get UNA mode flag
|
|
or a ; set flags
|
|
jr nz,chkos1 ; if UNA, bypass
|
|
|
|
; compare version
|
|
ld a,(osver) ; get first OS version byte (major)
|
|
rlca ; move low nibble
|
|
rlca ; ...
|
|
rlca ; ...
|
|
rlca ; ... to high nibble
|
|
ld b,a ; save in b
|
|
ld a,(osver + 1) ; get second OS version byte (minor)
|
|
or b ; combine with major nibble
|
|
ld hl,biover ; point to HBIOS version
|
|
cp (hl) ; compare
|
|
jp nz,errver ; if not equal, fail
|
|
|
|
chkos1:
|
|
xor a ; signal success
|
|
ret
|
|
;
|
|
; Load OS image into correct destination
|
|
;
|
|
ldos:
|
|
; compute the image size (does not include size of header)
|
|
ld hl,(osend) ; get CPM_END
|
|
ld de,(osloc) ; get CPM_LOC
|
|
or a ; clear CF
|
|
sbc hl,de ; image size := CPM_END - CPM_LOC
|
|
push hl ; move image size
|
|
pop bc ; ... to BC
|
|
ld hl,osbin ; copy from buf, skip header
|
|
ld de,(osloc) ; OS location
|
|
ldir ; do the copy
|
|
xor a
|
|
ret
|
|
;
|
|
; Load BIOS into correct destination
|
|
;
|
|
ldbio:
|
|
;
|
|
; copy the proxy to upper memory
|
|
ld hl,pxyimg ; location of proxy image
|
|
ld de,pxyloc ; target location of proxy
|
|
ld bc,pxysiz ; size of proxy
|
|
ldir ; copy it
|
|
ld a,(tpabnk) ; get active tpa bank id
|
|
ld (curbnk),a ; fixup the proxy
|
|
;
|
|
; copy image to bios bank
|
|
ld a,(curbnk) ; load from current bank
|
|
ld (srcbnk),a ; set source bank
|
|
ld a,(bidbios) ; copy to bios bank
|
|
ld (dstbnk),a ; set destination bank
|
|
ld hl,hbimg ; set source address
|
|
ld de,0 ; set destination address
|
|
ld bc,$8000 ; set length
|
|
ld a,(curbnk) ; return to current bank
|
|
call hbxcpy ; to the inter-bank copy
|
|
;
|
|
xor a ; signal success
|
|
ret
|
|
;
|
|
;
|
|
;
|
|
initbio:
|
|
;
|
|
; initialize HBIOS
|
|
ld a,(bidbios) ; get bios bank
|
|
call hbxbnk ; ... and activate it
|
|
call $0000 ; call bios init entry point
|
|
ld a,(tpabnk) ; get active tpa bank id
|
|
call hbxbnk ; ... and activate it
|
|
;
|
|
xor a
|
|
ret
|
|
;
|
|
; Common routine to handle read/write for file system
|
|
;
|
|
rwfil:
|
|
ld c,$1A ; BDOS set dma
|
|
ld de,(bufptr) ; current buffer pointer
|
|
push de ; save pointer
|
|
call bdos ; do it
|
|
pop de ; recover pointer
|
|
ld hl,128 ; record length
|
|
add hl,de ; increment buffer pointer
|
|
ld (bufptr),hl ; save it
|
|
ld a,(rwfun) ; get the active function
|
|
ld c,a ; set it
|
|
ld de,(rwfcb) ; active fcb
|
|
call bdos ; do it
|
|
or a ; check return code
|
|
jp nz,errdos ; BDOS err
|
|
; call prtdot ; mark progress
|
|
ld hl,reccnt ; point to record count
|
|
dec (hl) ; decrement record count
|
|
jr nz,rwfil ; loop till done
|
|
xor a ; signal success
|
|
ret ; done
|
|
;
|
|
; Close file
|
|
;
|
|
closefile:
|
|
ld c,$10 ; BDOS close file
|
|
ld de,(rwfcb) ; active fcb
|
|
call bdos ; do it
|
|
cp $FF ; $FF is error
|
|
jp z,errclo ; if error, handle it
|
|
xor a ; signal success
|
|
ret ; done
|
|
;
|
|
jphl: jp (hl) ; indirect jump
|
|
;
|
|
; Verify system image header in osimg by checking the expected signature.
|
|
; Compute and return image size (based on header values) in HL. Size
|
|
; does not include header. NZ set if signature error.
|
|
;
|
|
chkhdr:
|
|
; check signature
|
|
ld hl,(ossig) ; get signature
|
|
ld de,$A55A ; signature value
|
|
or a ; clear CF
|
|
sbc hl,de ; compare
|
|
jp nz,errsig ; invalid signature
|
|
; compute the image size (does not include size of header)
|
|
ld hl,(osend) ; get CPM_END
|
|
ld de,(osloc) ; get CPM_LOC
|
|
or a ; clear CF
|
|
sbc hl,de ; image size := CPM_END - CPM_LOC
|
|
xor a ; signal success
|
|
ret ; done
|
|
;
|
|
; Convert a filename at (HL) into an FCB at (DE).
|
|
; Includes wildcard expansion.
|
|
; On return, A=0 if unambiguous name specified, and
|
|
; (HL) points to character following filename spec
|
|
;
|
|
convert:
|
|
push de ; put fcb address on stack
|
|
ex de,hl
|
|
ld a,(de) ; get first character.
|
|
or a
|
|
jp z,convrt1
|
|
sbc a,'A'-1 ; might be a drive name, convert to binary.
|
|
ld b,a ; and save.
|
|
inc de ; check next character for a ':'.
|
|
ld a,(de)
|
|
cp ':'
|
|
jp z,convrt2
|
|
dec de ; nope, move pointer back to the start of the line.
|
|
convrt1:
|
|
ld a,(defdrv)
|
|
ld (hl),a
|
|
jp convrt3
|
|
convrt2:
|
|
ld a,b
|
|
ld (hl),b
|
|
inc de
|
|
; Convert the base file name.
|
|
convrt3:ld b,08h
|
|
convrt4:ld a,(de)
|
|
call delim
|
|
jp z,convrt8
|
|
inc hl
|
|
cp '*' ; note that an '*' will fill the remaining
|
|
jp nz,convrt5 ; field with '?'
|
|
ld (hl),'?'
|
|
jp convrt6
|
|
convrt5:ld (hl),a
|
|
inc de
|
|
convrt6:dec b
|
|
jp nz,convrt4
|
|
convrt7:ld a,(de)
|
|
call delim ; get next delimiter
|
|
jp z,getext
|
|
inc de
|
|
jp convrt7
|
|
convrt8:inc hl ; blank fill the file name
|
|
ld (hl),' '
|
|
dec b
|
|
jp nz,convrt8
|
|
getext: ld b,03h
|
|
cp '.'
|
|
jp nz,getext5
|
|
inc de
|
|
getext1:ld a,(de)
|
|
call delim
|
|
jp z,getext5
|
|
inc hl
|
|
cp '*'
|
|
jp nz,getext2
|
|
ld (hl),'?'
|
|
jp getext3
|
|
getext2:ld (hl),a
|
|
inc de
|
|
getext3:dec b
|
|
jp nz,getext1
|
|
getext4:ld a,(de)
|
|
call delim
|
|
jp z,getext6
|
|
inc de
|
|
jp getext4
|
|
getext5:inc hl
|
|
ld (hl),' '
|
|
dec b
|
|
jp nz,getext5
|
|
getext6:ld b,3
|
|
getext7:inc hl
|
|
ld (hl),0
|
|
dec b
|
|
jp nz,getext7
|
|
pop hl ; HL := start of FCB
|
|
push de ; save input line pointer
|
|
; Check to see if this is an ambiguous file name specification.
|
|
; Set the A register to non-zero if it is.
|
|
ld bc,11 ; set name length.
|
|
getext8:inc hl
|
|
ld a,(hl)
|
|
cp '?' ; any question marks?
|
|
jp nz,getext9
|
|
inc b ; count them.
|
|
getext9:dec c
|
|
jp nz,getext8
|
|
ld a,b
|
|
or a
|
|
pop hl ; return with updated input pointer
|
|
ret
|
|
;
|
|
; Print formatted FCB at (HL)
|
|
;
|
|
prtfcb:
|
|
push hl ; save HL
|
|
call chkfcb ; set flags indicating nature of FCB
|
|
pop hl ; restore HL
|
|
ret z ; nothing to print
|
|
push af ; save FCB flags
|
|
ld a,(hl) ; get first byte of FCB (drive)
|
|
inc hl ; point to next char
|
|
or a ; is drive specified (non-zero)?
|
|
jr z,prtfcb1 ; if zero, do not print drive letter
|
|
add a,'@' ; adjust drive number to alpha
|
|
call prtchr ; print it
|
|
ld a,':'
|
|
call prtchr ; print drive separator
|
|
prtfcb1:
|
|
pop af ; restore FCB flags
|
|
bit 1,a ; bit 1 set if filename specified
|
|
ret z ; return if no filename
|
|
ld b,8 ; base is 8 characters
|
|
call prtfcb2 ; print them
|
|
ld a,'.'
|
|
call prtchr ; print file extension separator
|
|
ld b,3 ; extension is 3 characters
|
|
prtfcb2:
|
|
ld a,(hl) ; load the next character
|
|
inc hl ; point to next character
|
|
cp ' ' ; check for blank
|
|
call nz,prtchr ; print char if it is not a blank
|
|
djnz prtfcb2 ; loop till done
|
|
ret ; return
|
|
;
|
|
; Check FCB to see if a drive and/or filename is specified.
|
|
; Set bit 0 for drive and bit 1 for filename in A
|
|
;
|
|
chkfcb:
|
|
ld c,0 ; use C for flags, start with none
|
|
ld a,(hl) ; get drive
|
|
or a ; anything there?
|
|
jr z,chkfcb1 ; skip if nothing there
|
|
set 0,c ; set bit zero to indicate a drive spec
|
|
chkfcb1:
|
|
ld b,11 ; set up to check 11 bytes (base & ext)
|
|
chkfcb2:
|
|
inc hl ; bump to next byte
|
|
ld a,(hl) ; get next
|
|
cp 'A' ; blank means empty byte
|
|
jr nc,chkfcb3 ; if not blank, we have a filename
|
|
djnz chkfcb2 ; loop
|
|
jr chkfcb4 ; nothing there
|
|
chkfcb3:
|
|
set 1,c ; set bit 1 to indicate a file spec
|
|
chkfcb4:
|
|
ld a,c ; put result in a
|
|
or a ; set flags
|
|
ret
|
|
;
|
|
; Print character in A without destroying any registers
|
|
;
|
|
prtchr:
|
|
push bc ; save registers
|
|
push de
|
|
push hl
|
|
ld e,a ; character to print in E
|
|
ld c,$02 ; BDOS function to output a character
|
|
call bdos ; do it
|
|
pop hl ; restore registers
|
|
pop de
|
|
pop bc
|
|
ret
|
|
;
|
|
prtdot:
|
|
push af
|
|
ld a,'.'
|
|
call prtchr
|
|
pop af
|
|
ret
|
|
;
|
|
; Print a zero terminated string at (DE) without destroying any registers
|
|
;
|
|
prtstr:
|
|
push de
|
|
;
|
|
prtstr1:
|
|
ld a,(de) ; get next char
|
|
or a
|
|
jr z,prtstr2
|
|
call prtchr
|
|
inc de
|
|
jr prtstr1
|
|
;
|
|
prtstr2:
|
|
pop de ; restore registers
|
|
ret
|
|
;
|
|
; Print the value in A in hex without destroying any registers
|
|
;
|
|
prthex:
|
|
push af ; save AF
|
|
push de ; save DE
|
|
call hexascii ; convert value in A to hex chars in DE
|
|
ld a,d ; get the high order hex char
|
|
call prtchr ; print it
|
|
ld a,e ; get the low order hex char
|
|
call prtchr ; print it
|
|
pop de ; restore DE
|
|
pop af ; restore AF
|
|
ret ; done
|
|
;
|
|
; Convert binary value in A to ascii hex characters in DE
|
|
;
|
|
hexascii:
|
|
ld d,a ; save A in D
|
|
call hexconv ; convert low nibble of A to hex
|
|
ld e,a ; save it in E
|
|
ld a,d ; get original value back
|
|
rlca ; rotate high order nibble to low bits
|
|
rlca
|
|
rlca
|
|
rlca
|
|
call hexconv ; convert nibble
|
|
ld d,a ; save it in D
|
|
ret ; done
|
|
;
|
|
; Convert low nibble of A to ascii hex
|
|
;
|
|
hexconv:
|
|
and $0F ; low nibble only
|
|
add a,$90
|
|
daa
|
|
adc a,$40
|
|
daa
|
|
ret
|
|
;
|
|
; Start a new line (or 2)
|
|
;
|
|
crlf2:
|
|
call crlf ; double new line entry
|
|
crlf:
|
|
ld a,13 ; <CR>
|
|
call prtchr ; print it
|
|
ld a,10 ; <LF>
|
|
jr prtchr ; print it
|
|
;
|
|
; Get the next non-blank character from (HL).
|
|
;
|
|
nonblank:
|
|
ld a,(hl) ; load next character
|
|
or a ; string ends with a null
|
|
ret z ; if null, return pointing to null
|
|
cp ' ' ; check for blank
|
|
ret nz ; return if not blank
|
|
inc hl ; if blank, increment character pointer
|
|
jr nonblank ; and loop
|
|
;
|
|
; Check character at (DE) for delimiter.
|
|
;
|
|
delim: or a
|
|
ret z
|
|
cp ' ' ; blank
|
|
ret z
|
|
jr c,delim1 ; handle control characters
|
|
cp '=' ; equal
|
|
ret z
|
|
cp '_' ; underscore
|
|
ret z
|
|
cp '.' ; period
|
|
ret z
|
|
cp ':' ; colon
|
|
ret z
|
|
cp $3b ; semicolon
|
|
ret z
|
|
cp '<' ; less than
|
|
ret z
|
|
cp '>' ; greater than
|
|
ret
|
|
delim1:
|
|
; treat control chars as delimiters
|
|
xor a ; set Z
|
|
ret ; return
|
|
;
|
|
; Invoke CBIOS function
|
|
; The CBIOS function offset must be stored in the byte
|
|
; following the call instruction. ex:
|
|
; call cbios
|
|
; .db $0C ; offset of CONOUT CBIOS function
|
|
;
|
|
cbios:
|
|
ex (sp),hl
|
|
ld a,(hl) ; get the function offset
|
|
inc hl ; point past value following call instruction
|
|
ex (sp),hl ; put address back at top of stack and recover HL
|
|
ld hl,(cbftbl) ; address of CBIOS function table to HL
|
|
call addhl ; determine specific function address
|
|
jp (hl) ; invoke CBIOS
|
|
;
|
|
; Add the value in A to HL (HL := HL + A)
|
|
;
|
|
addhl:
|
|
add a,l ; A := A + L
|
|
ld l,a ; Put result back in L
|
|
ret nc ; if no carry, we are done
|
|
inc h ; if carry, increment H
|
|
ret ; and return
|
|
;
|
|
; Errors
|
|
;
|
|
erruse: ; command usage error (syntax)
|
|
ld de,msguse
|
|
jr err
|
|
erramb: ; ambiguous file spec (wild cards) is not allowed
|
|
ld de,msgamb
|
|
jr err
|
|
errdlm: ; invalid delimiter in command tail
|
|
ld de,msgdlm
|
|
jr err
|
|
errfil: ; source file not found
|
|
ld de,msgfil
|
|
jr err
|
|
errclo: ; file close error
|
|
ld de,msgclo
|
|
jr err
|
|
errsig: ; invalid system image signature error
|
|
ld de,msgsig
|
|
jr err
|
|
errbio: ; invalid BIOS image, not HBIOS
|
|
ld de,msgbio
|
|
jr err
|
|
errplt: ; platform mismatch
|
|
ld de,msgplt
|
|
jr err
|
|
errver: ; version mismatch
|
|
ld de,msgver
|
|
jr err
|
|
err: ; print error string and return error signal
|
|
call crlf2 ; print newline
|
|
call prtstr ; print error string
|
|
or $FF ; signal error
|
|
ret ; done
|
|
errdos: ; handle BDOS errors
|
|
push af ; save return code
|
|
call crlf2 ; newline
|
|
ld de,msgdos ; load
|
|
call prtstr ; and print error string
|
|
pop af ; recover return code
|
|
call prthex ; print error code
|
|
or $FF ; signal error
|
|
ret ; done
|
|
;
|
|
;===============================================================================
|
|
; Storage Section
|
|
;===============================================================================
|
|
;
|
|
defdrv .db 0 ; default drive for FCB
|
|
cbftbl .dw 0 ; address of CBIOS function table
|
|
imgsiz .db 0 ; image size (count of 128 byte records)
|
|
;
|
|
osfcb .fill 36,0 ; os image FCB
|
|
biofcb .fill 36,0 ; bios image FCB
|
|
;
|
|
unamod .db 0 ; UNA move flag (non-zero if UNA running)
|
|
newbio .db 0 ; BIOS load flag (non-zero if new BIOS load)
|
|
force .db 0 ; force operation (bypass compatibility checks)
|
|
tpabnk .db 0 ; bank id of TPA when app starts
|
|
bioplt .db 0 ; Platform ID of running HBIOS
|
|
biover .dw 0 ; version of BIOS being loaded
|
|
;
|
|
stksav .dw 0 ; stack pointer saved at start
|
|
.fill stksiz,0 ; stack
|
|
stack .equ $ ; stack top
|
|
;
|
|
rwfun .db 0 ; active read/write function
|
|
rwfcb .dw 0 ; active read/write FCB
|
|
reccnt .db 0 ; active remaining records to read/write
|
|
bufptr .dw 0 ; active pointer into buffer
|
|
;
|
|
; Messages
|
|
;
|
|
msgban .db "OSLDR v1.1 for RomWBW, 16-Jan-2018",0
|
|
msghb .db " (HBIOS Mode)",0
|
|
msgub .db " (UBIOS Mode)",0
|
|
msguse .db "Usage: OSLDR [/F] <osimg> [<hbiosimg>]\r\n"
|
|
.db " /F (force) overrides all compatibility checking",0
|
|
msgamb .db "Ambiguous file specification not allowed",0
|
|
msgdlm .db "Invalid delimiter",0
|
|
msgfil .db "File not found",0
|
|
msgclo .db "File close error",0
|
|
msgsig .db "Obsolete or invalid BIOS image (BIOS signature)",0
|
|
msgbio .db "Obsolete or invalid HBIOS image (HBIOS signature)",0
|
|
msgplt .db "Platform (hardware) mismatch",0
|
|
msgver .db "Version mismatch",0
|
|
msgdos .db "DOS error, return code=0x",0
|
|
|
|
msgros .db "Reading OS... ",0
|
|
msgrbio .db "Reading BIOS... ",0
|
|
msglos .db "Loading OS... ",0
|
|
msglbio .db "Loading BIOS... ",0
|
|
;
|
|
.end
|
|
|