;Load a file named in SI as a string ending in a null to the offset BX and set AL to 0x0 if the load was succesful and 0x1 if there was an error. loadf: ;Store the initial registers in the stack push ax push bx push cx push dx push si push di ;Store the offset mov word [.pointer], bx ;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 the carry flag if the file name is invalid .error: pop ax stc 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 ;Abort if the load failed jc .done ;Store the disk values used for the rest of the call 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 call .calcsource ;Set the destination mov si, buffer mov bx, si ;Set the size push dx mov ax, [.rootentries] mov dx, 0x20 mul dx mov dx, 0x0 div word [.sectorsize] pop dx push ax ;Load mov ah, 0x2 int 0x13 ;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 .loadentry ;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 the carry flag if the file is not found stc jmp .clearstack ;Load the file entry .loadentry: ;Load CX from the stack pop cx ;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 .clearcarry mov ax, [.sectorsize] mul word [.clustersize] add word [.pointer], ax jmp .loadcluster ;Clear the carry flag if the load was succesful .clearcarry: clc ;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 pop ax ;Set AL to 0x1 if there was an error and to 0x0 otherwise and return jc .setal mov al, 0x0 iret .setal: mov al, 0x1 iret ;Data .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 ;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