446 lines
7.5 KiB
Plaintext
446 lines
7.5 KiB
Plaintext
;Load a file named in SI as a string ending in a null to the offset BX
|
||
;and store the error codes in AL:
|
||
; * AL = 0x0: Succesful load
|
||
; * AL = 0x1: Drive not found
|
||
; * AL = 0x2: Unable to read disk
|
||
; * AL = 0x4: File or command not found
|
||
; * AL = 0x8: Not enough memory
|
||
|
||
loadf:
|
||
|
||
;Store the initial registers in the stack
|
||
push bx
|
||
push cx
|
||
push dx
|
||
push si
|
||
push di
|
||
|
||
;Store the current drive and offset
|
||
mov word [.pointer], bx
|
||
mov dl, byte [drive]
|
||
mov byte [.drive], dl
|
||
|
||
;Change the drive if needed
|
||
;Check for a drive specification
|
||
cmp byte [si + 0x1], ":"
|
||
jne .start
|
||
;Check which drive to change to
|
||
cmp byte [si], "a"
|
||
je .cha
|
||
cmp byte [si], "A"
|
||
je .cha
|
||
cmp byte [si], "b"
|
||
je .chb
|
||
cmp byte [si], "B"
|
||
je .chb
|
||
cmp byte [si], "c"
|
||
je .chc
|
||
cmp byte [si], "C"
|
||
je .chc
|
||
cmp byte [si], "d"
|
||
je .chd
|
||
cmp byte [si], "D"
|
||
je .chd
|
||
;Set AL to 0x1 and print an error message
|
||
mov si, .driverrormsg
|
||
mov ah, 0x2
|
||
int 0x21
|
||
mov al, 0x1
|
||
jmp .done
|
||
;Change
|
||
.cha:
|
||
mov dl, 0x0
|
||
mov byte [.drive], dl
|
||
jmp .drivechanged
|
||
.chb:
|
||
mov dl, 0x1
|
||
mov byte [.drive], dl
|
||
jmp .drivechanged
|
||
.chc:
|
||
mov dl, 0x2
|
||
mov byte [.drive], dl
|
||
jmp .drivechanged
|
||
.chd:
|
||
mov dl, 0x3
|
||
mov byte [.drive], dl
|
||
.drivechanged:
|
||
add si, 0x2
|
||
|
||
.start:
|
||
|
||
;Set DI at .file and initialise it with spaces
|
||
mov di, .file
|
||
mov cx, 0xb
|
||
mov al, 0x20
|
||
rep stosb
|
||
sub di, 0xb
|
||
|
||
;Convert .file into FAT formatting
|
||
|
||
;Initialise the length counter for the main part of the file name
|
||
mov bl, 0x8
|
||
|
||
;Convert the main part of the file name
|
||
.nameloop:
|
||
;Load a character
|
||
lodsb
|
||
;Check for a period
|
||
cmp al, 0x2e
|
||
je .initext
|
||
;Check for everything else and convert to upper case
|
||
call .checkconv
|
||
jmp .nameloop
|
||
|
||
;Convert the extension
|
||
.initext:
|
||
;Set DI and initialise the length counter for the extension
|
||
mov bl, 0x3
|
||
mov di, .file+0x8
|
||
.extloop:
|
||
;Load a character
|
||
lodsb
|
||
;Check for a period
|
||
push ax
|
||
cmp al, 0x2e
|
||
je .error
|
||
pop ax
|
||
;Check for everything else and convert to upper case
|
||
call .checkconv
|
||
jmp .extloop
|
||
;Set AL to 0x4 and print an error message
|
||
.error:
|
||
pop ax
|
||
mov si, .filerrormsg
|
||
mov ah, 0x2
|
||
int 0x21
|
||
mov al, 0x4
|
||
jmp .done
|
||
|
||
;Find and load the file
|
||
|
||
.load:
|
||
pop ax
|
||
|
||
;Load the disk description table
|
||
;Set the source
|
||
mov dl, [.drive]
|
||
mov ch, 0x0
|
||
mov dh, 0x0
|
||
mov cl, 0x1
|
||
;Set the destination
|
||
mov si, buffer
|
||
mov bx, si
|
||
;Set the size
|
||
mov al, 0x1
|
||
;Load
|
||
mov ah, 0x2
|
||
int 0x13
|
||
jnc .storevalues
|
||
;Set AL to 0x2 and print an error message
|
||
mov si, .diskerrormsg
|
||
mov ah, 0x2
|
||
int 0x21
|
||
mov al, 0x2
|
||
jmp .done
|
||
|
||
;Store the disk values used for the rest of the call
|
||
.storevalues:
|
||
mov ax, word [buffer + 0xb]
|
||
mov word [.sectorsize], ax
|
||
mov al, byte [buffer + 0xd]
|
||
mov byte [.clustersize], al
|
||
mov ax, word [buffer + 0xe]
|
||
mov word [.bootsectors], ax
|
||
mov al, byte [buffer + 0x10]
|
||
mov byte [.fats], al
|
||
mov ax, word [buffer + 0x11]
|
||
mov word [.rootentries], ax
|
||
mov ax, word [buffer + 0x16]
|
||
mov word [.sectorsperfat], ax
|
||
mov ax, word [buffer + 0x18]
|
||
mov word [.sectorspertrack], ax
|
||
mov ax, word [buffer + 0x1a]
|
||
mov word [.sides], ax
|
||
|
||
;Load the root
|
||
;Set the source
|
||
mov ah, 0x0
|
||
mov al, [.fats]
|
||
mul word [.sectorsperfat]
|
||
add ax, [.bootsectors]
|
||
push ax
|
||
;Set the destination
|
||
mov si, buffer
|
||
mov bx, si
|
||
;Set the size
|
||
mov ax, [.rootentries]
|
||
mov dx, 0x20
|
||
mul dx
|
||
mov dx, 0x0
|
||
div word [.sectorsize]
|
||
mov cx, ax
|
||
pop ax
|
||
push ax
|
||
push cx
|
||
.loadroot:
|
||
push cx
|
||
call .calcsource
|
||
;Set the size
|
||
push ax
|
||
mov al, 0x1
|
||
;Load
|
||
mov ah, 0x2
|
||
int 0x13
|
||
pop ax
|
||
;Set the next sector
|
||
add ax, 0x1
|
||
add bx, word [.sectorsize]
|
||
pop cx
|
||
loop .loadroot
|
||
|
||
;Search the root for the file entry
|
||
;Set DI to the root
|
||
mov di, buffer
|
||
;Initialise the search loop
|
||
mov cx, word [.rootentries]
|
||
mov ax, 0x0
|
||
.search:
|
||
;Store CX in the stack
|
||
push cx
|
||
;Check for the file entry
|
||
mov si, .file
|
||
mov cx, 0xb
|
||
rep cmpsb
|
||
je .checksize
|
||
;Set DI to the next entry
|
||
add ax, 0x20
|
||
mov di, buffer
|
||
add di, ax
|
||
;Load CX from the stack
|
||
pop cx
|
||
loop .search
|
||
;Set AL to 0x4 and print an error message
|
||
mov si, .filerrormsg
|
||
mov ah, 0x2
|
||
int 0x21
|
||
mov al, 0x4
|
||
jmp .clearstack
|
||
|
||
;Check the file size
|
||
.checksize:
|
||
;Load CX from the stack
|
||
pop cx
|
||
;Check for files larger than 64 KiB
|
||
cmp word [di + 0x13], 0x0
|
||
jne .sizerror
|
||
;Get the cluster size in bytes
|
||
mov ah, 0x0
|
||
mov al, [.clustersize]
|
||
mul word [.sectorsize]
|
||
mov bx, ax
|
||
;Check for files smaller than 64 KiB but too large to fit into memory
|
||
add ax, [di + 0x11]
|
||
jc .sizerror
|
||
dec ax
|
||
mov dx, 0x0
|
||
div bx
|
||
mul bx
|
||
add ax, [.pointer]
|
||
jnc .loadentry
|
||
;Set AL to 0x8 and print an error message
|
||
.sizerror:
|
||
mov si, .sizerrormsg
|
||
mov ah, 0x2
|
||
int 0x21
|
||
mov al, 0x8
|
||
jmp .clearstack
|
||
|
||
;Load the file entry
|
||
.loadentry:
|
||
;Store the first cluster
|
||
mov ax, word [es:di+0xf]
|
||
mov word [.cluster], ax
|
||
;Set the source
|
||
mov ax, 0x1
|
||
call .calcsource
|
||
;Set the destination
|
||
mov di, buffer
|
||
mov bx, di
|
||
;Set the size
|
||
mov ax, [.sectorsperfat]
|
||
;Load
|
||
mov ah, 0x2
|
||
int 0x13
|
||
|
||
;Load the file
|
||
|
||
;Load a cluster
|
||
.loadcluster:
|
||
;Set the source
|
||
pop cx
|
||
pop bx
|
||
mov ax, word [.cluster]
|
||
sub ax, 0x2
|
||
mul byte [.clustersize]
|
||
add ax, bx
|
||
add ax, cx
|
||
push bx
|
||
push cx
|
||
;Set the destination
|
||
mov bx, word [.pointer]
|
||
;Load a sector
|
||
mov ch, 0x0
|
||
mov cl, byte [.clustersize]
|
||
.loadsector:
|
||
push cx
|
||
call .calcsource
|
||
;Set the size
|
||
push ax
|
||
mov al, 0x1
|
||
;Load
|
||
mov ah, 0x2
|
||
int 0x13
|
||
pop ax
|
||
;Set the next sector
|
||
add ax, 0x1
|
||
add bx, word [.sectorsize]
|
||
pop cx
|
||
loop .loadsector
|
||
|
||
;Calculate the next cluster
|
||
mov ax, [.cluster]
|
||
mov dx, 0x0
|
||
mov bx, 0x3
|
||
mul bx
|
||
mov bx, 0x2
|
||
div bx
|
||
mov si, buffer
|
||
add si, ax
|
||
mov ax, word [ds:si]
|
||
or dx, dx
|
||
jz .even
|
||
shr ax, 1
|
||
shr ax, 1
|
||
shr ax, 1
|
||
shr ax, 1
|
||
jmp .contcalc
|
||
.even:
|
||
and ax, 0xfff
|
||
.contcalc:
|
||
mov word [.cluster], ax
|
||
cmp ax, 0xff8
|
||
jge .success
|
||
mov ax, [.sectorsize]
|
||
mul word [.clustersize]
|
||
add word [.pointer], ax
|
||
jmp .loadcluster
|
||
|
||
;Set AL to 0x0 if the load was succesful
|
||
.success:
|
||
mov al, 0x0
|
||
|
||
;Clear the stack
|
||
.clearstack:
|
||
pop cx
|
||
pop bx
|
||
|
||
.done:
|
||
|
||
;Load the initial registers from the stack
|
||
pop di
|
||
pop si
|
||
pop dx
|
||
pop cx
|
||
pop bx
|
||
|
||
;Set AH to its initial value
|
||
mov ah, 0x0
|
||
|
||
iret
|
||
|
||
;Data
|
||
.drive db 0x0
|
||
.sectorsize dw 0x0 ;bytes
|
||
.clustersize db 0x0 ;sectors
|
||
.bootsectors dw 0x0
|
||
.fats db 0x0
|
||
.rootentries dw 0x0
|
||
.sectorsperfat dw 0x0
|
||
.sectorspertrack dw 0x0
|
||
.sides dw 0x0
|
||
.file times 0xb db 0x20
|
||
.cluster dw 0x0
|
||
.pointer dw 0x0
|
||
.driverrormsg db "Drive not found", 0x0
|
||
.diskerrormsg db "Unable to read disk", 0x0
|
||
.filerrormsg db "File or command not found", 0x0
|
||
.sizerrormsg db "Not enough memory", 0x0
|
||
|
||
;Check the file name and convert to upper case
|
||
.checkconv:
|
||
;Check for the string end
|
||
cmp al, 0x0
|
||
je .load
|
||
;Check for the length limit
|
||
cmp bl, 0x0
|
||
je .error
|
||
;Check for invalid characters
|
||
cmp al, 0x22
|
||
je .error
|
||
cmp al, 0x2a
|
||
jl .contcheck1
|
||
cmp al, 0x2c
|
||
jg .contcheck1
|
||
jmp .error
|
||
.contcheck1:
|
||
cmp al, 0x2f
|
||
je .error
|
||
cmp al, 0x3a
|
||
jl .contcheck2
|
||
cmp al, 0x3f
|
||
jg .contcheck2
|
||
jmp .error
|
||
.contcheck2:
|
||
cmp al, 0x5b
|
||
jl .contcheck3
|
||
cmp al, 0x5d
|
||
jg .contcheck3
|
||
jmp .error
|
||
.contcheck3:
|
||
cmp al, 0x7c
|
||
je .error
|
||
;Check for lower case
|
||
cmp al, 0x61
|
||
jl .storech
|
||
cmp al, 0x7a
|
||
jg .storech
|
||
;Convert lower to upper case
|
||
sub al, 0x20
|
||
.storech:
|
||
;Store the character
|
||
stosb
|
||
;Decrease the counter
|
||
dec bl
|
||
ret
|
||
|
||
;Calculate the source arguments for loading data from the disk
|
||
.calcsource:
|
||
push ax
|
||
push bx
|
||
mov bx, ax
|
||
mov dx, 0x0
|
||
div word [.sectorspertrack]
|
||
add dl, 0x1
|
||
mov cl, dl
|
||
mov ax, bx
|
||
mov dx, 0x0
|
||
div word [.sectorspertrack]
|
||
mov dx, 0x0
|
||
div word [.sides]
|
||
mov dh, dl
|
||
mov ch, al
|
||
pop bx
|
||
pop ax
|
||
mov dl, byte [.drive]
|
||
ret
|
||
|