Rewrite everything to be more elegant, prevent changing to non-existent drives, add the option to quit print and list while paging and modify the readme accordingly, and add info on the EttinOS-extra repository to the readme.

This commit is contained in:
CrazyEttin 2021-07-10 20:49:06 +03:00
parent a20d846f60
commit 8baa294947
12 changed files with 525 additions and 415 deletions

View File

@ -3,7 +3,9 @@ EttinOS
EttinOS is a minimalist 16-bit DOS-like hobbyist operating system for EttinOS is a minimalist 16-bit DOS-like hobbyist operating system for
the IBM Personal Computer and compatible machines. Its git repository the IBM Personal Computer and compatible machines. Its git repository
can be found at https://ahti.space/git/crazyettin/EttinOS. can be found at https://ahti.space/git/crazyettin/EttinOS and that of
EttinOS-extra, a collection of programs for the system, at
https://ahti.space/git/crazyettin/EttinOS-extra.
System requirements System requirements
------------------- -------------------
@ -38,11 +40,12 @@ overwrites the cursor location and the erase (=tab) key erases it. The
space and backspace keys move the cursor. space and backspace keys move the cursor.
EttinOS assigns the drives letters from A to D and uses the FAT12 file EttinOS assigns the drives letters from A to D and uses the FAT12 file
system. The extended BIOS parameter block, file attributes, and the file system. The hidden and total sectors entries of the BIOS parameter
access date are not supported and are ignored if present: as a result block, the entire extended BIOS parameter block, file attributes, and
disk labels and subdirectories are not supported. Drive letters and file the file access date are not supported and are ignored if present: as a
names are case-insensitive and the latter follow the 8.3 format. Text result disk labels and subdirectories are not supported. Drive letters
files use CRLF line endings. and file names are case-insensitive and the latter follow the 8.3
format. Text files use CRLF line endings.
Drives and files are specified as ([A-D]:) and ([A-D]:)FILENAME.EXT Drives and files are specified as ([A-D]:) and ([A-D]:)FILENAME.EXT
respectively. Specifying the current drive, indicated in the prompt, is respectively. Specifying the current drive, indicated in the prompt, is
@ -61,8 +64,8 @@ Commands included in EttinOS:
* PRINT: Print a text file. Syntax: PRINT FILE * PRINT: Print a text file. Syntax: PRINT FILE
Both LIST and PRINT page their output if all of it does not fit on the Both LIST and PRINT page their output if all of it does not fit on the
screen at the same time. Press any key to continue printing after each screen at the same time. Press any key other than escape to continue
screen. printing after each screen or escape to quit the program.
Programming Programming
----------- -----------

View File

@ -1,122 +1,135 @@
CPU 8086 cpu 8086
ORG 0x7c00 org 0x7c00
;Jump to the code
jmp start jmp start
;Padding
nop nop
;Disk description tables ;OEM label
db "ETTINOS "
%ifdef F1440 %ifdef F1440
;1.44 MB 3.5" floppy disk (enable with the argument -d F1440)
oemlabel db "ETTINOS " ;1.44 MB 3.5" floppy disk BPB (enable with the argument -d F1440)
sectorsize dw 0x200 ;bytes sectorsize dw 0x200 ;bytes
clustersize db 0x1 ;sectors clustersize db 0x1 ;sectors
bootsectors dw 0x1 reservedsectors dw 0x1
fats db 0x2 fats db 0x2
rootentries dw 0xe0 rootentries dw 0xe0
logicalsectors dw 0xb40 logicalsectors dw 0xb40
mediadescriptor db 0xf0 mediadescriptor db 0xf0
sectorsperfat dw 0x9 sectorsperfat dw 0x9
sectorspertrack dw 0x12 sectorspertrack dw 0x12
sides dw 0x2 heads dw 0x2
hiddensectors dd 0x0
largesectors dd 0x0
%else %else
;360 KiB 5.25" floppy disk (default)
oemlabel db "ETTINOS " ;360 KiB 5.25" floppy disk BPB (default)
sectorsize dw 0x200 ;bytes sectorsize dw 0x200 ;bytes
clustersize db 0x2 ;sectors clustersize db 0x2 ;sectors
bootsectors dw 0x1 reservedsectors dw 0x1
fats db 0x2 fats db 0x2
rootentries dw 0x70 rootentries dw 0x70
logicalsectors dw 0x2d0 logicalsectors dw 0x2d0
mediadescriptor db 0xfd mediadescriptor db 0xfd
sectorsperfat dw 0x2 sectorsperfat dw 0x2
sectorspertrack dw 0x9 sectorspertrack dw 0x9
sides dw 0x2 heads dw 0x2
hiddensectors dd 0x0
largesectors dd 0x0
%endif %endif
start:
;Setup ;Setup
;Set up the data, stack, and extra segments ;Set the segments
start:
mov ax, 0x0 mov ax, 0x0
mov ds, ax mov ds, ax
mov ss, ax mov ss, ax
mov es, ax mov es, ax
;Set up the stack ;Set the stack
cli cli
mov sp, 0x0 mov sp, 0x0
sti sti
;Store the boot drive number ;Store the boot drive number
mov [drive], dl mov [drive], dl
;Load the root ;Calculate and store variables not found in the BPB
;Set the source ;Start of the root
mov ah, 0x0 mov ah, 0x0
mov al, [fats] mov al, [fats]
mul word [sectorsperfat] mul word [sectorsperfat]
add ax, [bootsectors] add ax, [reservedsectors]
push ax mov [rootstart], ax
;Set the destination ;Size of the root in sectors
mov si, buffer
mov bx, si
;Set the size
mov ax, [rootentries] mov ax, [rootentries]
mov dx, 0x20 mov dx, 0x20
mul dx mul dx
mov dx, 0x0 mov dx, 0x0
div word [sectorsize] div word [sectorsize]
mov cx, ax mov [rootsectors], ax
pop ax ;Start of data
add ax, [rootstart]
mov [datastart], ax
;Load the root
;Set the source
mov ax, [rootstart]
;Set the destination
mov si, buffer
mov bx, si
;Set the size
mov cx, [rootsectors]
;Store the source and the loop counter in the stack
loadrootsector:
push ax push ax
push cx push cx
loadroot: ;Set the source
push cx
call calcsource call calcsource
;Set the size ;Set the size
push ax
mov al, 0x1 mov al, 0x1
;Load ;Load a sector
mov ah, 0x2 mov ah, 0x2
int 0x13 int 0x13
;Load the loop counter and the source from the stack
pop cx
pop ax pop ax
;Set the next sector ;Set the next sector
add ax, 0x1 add ax, 0x1
add bx, word [sectorsize] add bx, word [sectorsize]
pop cx ;Load the next sector
loop loadroot loop loadrootsector
;Search the root for the system entry ;Search the root for the system entry
;Set DI to the root ;Set DI to the root
mov di, buffer mov di, buffer
;Initialise the search loop ;Set the number of root entries
mov cx, word [rootentries] mov cx, word [rootentries]
;Set the entry pointer
mov ax, 0x0 mov ax, 0x0
;Store the loop counter in the stack
search: search:
;Store CX in the stack
push cx push cx
;Check for the system entry ;Check for the system entry
mov si, sysfile mov si, file
mov cx, 0xb mov cx, 0xb
rep cmpsb rep cmpsb
je loadentry je loadfat
;Set DI to the next entry ;Set DI at the next entry
add ax, 0x20 add ax, 0x20
mov di, buffer mov di, buffer
add di, ax add di, ax
;Load CX from the stack ;Load the loop counter from the stack
pop cx pop cx
;Search the next entry
loop search loop search
;Print an error message if the system is not found ;Print an error message and hang if the system is not found
mov si, errormsg ;Set SI at the file error message
printerror: mov si, filerrormsg
;Load a character ;Load a character
printstr:
lodsb lodsb
;Check for the string end ;Check for the string end
cmp al, 0x0 cmp al, 0x0
@ -124,62 +137,61 @@ je $
;Print the character ;Print the character
mov ah, 0xe mov ah, 0xe
int 0x10 int 0x10
;Repeat ;Print the next character
jmp printerror jmp printstr
;Load the system entry ;Load the FAT
loadentry:
;Load CX from the stack ;Load CX from the stack
loadfat:
pop cx pop cx
;Store the first cluster ;Store the address of the first cluster
mov ax, word [es:di+0xf] mov ax, [di + 0xf]
mov word [cluster], ax mov [cluster], ax
;Set the source ;Set the source
mov ax, 0x1 mov ax, [reservedsectors]
call calcsource call calcsource
;Set the destination ;Set the destination
mov di, buffer mov bx, buffer
mov bx, di
;Set the size ;Set the size
mov ax, [sectorsperfat] mov ax, [sectorsperfat]
;Load ;Load the FAT
mov ah, 0x2 mov ah, 0x2
int 0x13 int 0x13
;Load a cluster ;Load a cluster
loadcluster: loadcluster:
;Set the source ;Set the source
pop cx
pop bx
mov ax, word [cluster] mov ax, word [cluster]
sub ax, 0x2 sub ax, 0x2
mul byte [clustersize] mul byte [clustersize]
add ax, bx add ax, [datastart]
add ax, cx
push bx
push cx
;Set the destination ;Set the destination
mov bx, word [pointer] mov bx, word [pointer]
;Load a sector ;Set the size
mov ch, 0x0 mov ch, 0x0
mov cl, byte [clustersize] mov cl, byte [clustersize]
loadsector: ;Store the loop counter in the stack
loadclustersector:
push cx push cx
;Set the source
call calcsource call calcsource
;Set the size ;Set the size
push ax push ax
mov al, 0x1 mov al, 0x1
;Load ;Load a sector
mov ah, 0x2 mov ah, 0x2
int 0x13 int 0x13
pop ax pop ax
;Set the next sector ;Set the next sector
add ax, 0x1 add ax, 0x1
add bx, word [sectorsize] add bx, [sectorsize]
;Load the loop counter from the stack
pop cx pop cx
loop loadsector ;Load the next sector
loop loadclustersector
;Calculate the next cluster ;Calculate the next cluster
;Check if the cluster is even or odd
mov ax, [cluster] mov ax, [cluster]
mov dx, 0x0 mov dx, 0x0
mov bx, 0x3 mov bx, 0x3
@ -188,67 +200,87 @@ mov bx, 0x2
div bx div bx
mov si, buffer mov si, buffer
add si, ax add si, ax
mov ax, word [ds:si] mov ax, word [si]
or dx, dx or dx, dx
jz even jz even
odd: ;If the cluster is odd shift out the first four bits
shr ax, 1 times 0x4 shr ax, 0x1
shr ax, 1
shr ax, 1
shr ax, 1
jmp contcalc jmp contcalc
;If the cluster is even mask out the final four bits
even: even:
and ax, 0xfff and ax, 0xfff
contcalc: contcalc:
mov word [cluster], ax ;Check for the file end
cmp ax, 0xff8 cmp ax, 0xff8
jge boot jge boot
;Store the address of the next cluster
mov word [cluster], ax
;Set the destination of the next cluster
mov ax, [sectorsize] mov ax, [sectorsize]
mul word [clustersize] mul word [clustersize]
add word [pointer], ax add word [pointer], ax
;Load the next cluster
jmp loadcluster jmp loadcluster
;Clear the stack and boot the system ;Boot the system
;Pass the boot drive number to the system
boot: boot:
;Clear
pop cx
pop bx
;Pass the drive number to the system
mov dl, byte [drive] mov dl, byte [drive]
;Boot ;Boot the system
jmp 0x0:0x500 jmp 0x0:0x500
;Data ;Data
drive db 0x0 drive db 0x0
sysfile db "SYSTEM BIN" rootstart dw 0x0
errormsg db "System not found", 0xd, 0xa, 0x0 rootsectors dw 0x0
cluster dw 0x0 datastart dw 0x0
pointer dw 0x500 file db "SYSTEM BIN"
filerrormsg db "System not found", 0xd, 0xa, 0x0
cluster dw 0x0
pointer dw 0x500
;***
;Calculate the source arguments for loading data from the disk ;Calculate the source arguments for loading data from the disk
calcsource: calcsource:
;Store AX and BX in the stack
push ax push ax
push bx push bx
;Calculate the cylinder, head, and sector
;Store the logical sector in BX
mov bx, ax mov bx, ax
;Calculate the sector
mov dx, 0x0 mov dx, 0x0
div word [sectorspertrack] div word [sectorspertrack]
add dl, 0x1 add dl, 0x1
mov cl, dl mov cl, dl
;Load the logical sector from BX
mov ax, bx mov ax, bx
;Calculate the head and cylinder
mov dx, 0x0 mov dx, 0x0
div word [sectorspertrack] div word [sectorspertrack]
mov dx, 0x0 mov dx, 0x0
div word [sides] div word [heads]
mov dh, dl mov dh, dl ;Head
mov ch, al mov ch, al ;Cylinder
;Load the boot drive number
mov dl, byte [drive]
;Load BX and AX from the stack
pop bx pop bx
pop ax pop ax
mov dl, byte [drive]
;Return
ret ret
;Pad the binary to a full sector and make the disk bootable ;***
;Padding ;Padding
times 0x1fe-($-$$) db 0x0 times 0x1fe-($-$$) db 0x0
;Boot signature ;Boot signature
dw 0xaa55 dw 0xaa55

View File

@ -1,12 +1,14 @@
CPU 8086 cpu 8086
ORG 0x3000 org 0x3000
;Echo the tail
;Check for an empty tail ;Check for an empty tail
cmp byte [si], 0x0 cmp byte [si], 0x0
je done je done
;Echo
;Print the message
mov ah, 0x2 mov ah, 0x2
int 0x21 int 0x21
;Return to the system
done: done:
int 0x20 int 0x20

View File

@ -1,10 +1,12 @@
CPU 8086 cpu 8086
ORG 0x3000 org 0x3000
;Print a hello world. ;Print a hello world.
mov si, hello mov si, hello
mov ah, 0x2 mov ah, 0x2
int 0x21 int 0x21
;Return to the system
int 0x20 int 0x20
;Data ;Data

View File

@ -1,7 +1,5 @@
CPU 8086 cpu 8086
ORG 0x3000 org 0x3000
;List the files on a drive
;Store the drive number ;Store the drive number
mov [drive], dl mov [drive], dl
@ -21,45 +19,36 @@ je changedrive
;Print an error message ;Print an error message
jmp driverror jmp driverror
changedrive: changedrive:
;Get the BIOS equipment list
int 0x11
;Get the number of floppy drives
times 0x6 shr ax, 0x1
and ax, 0x3
inc ax
;Set the loop and drive letter counters and the drive letter and number
mov cx, ax
mov di, driveletters
mov al, [si]
mov dl, 0x0
;Check which drive to change to ;Check which drive to change to
cmp byte [si], "a" checkdrive:
je cha cmp al, [di]
cmp byte [si], "A" je contchdrive
je cha inc di
cmp byte [si], "b" cmp al, [di]
je chb je contchdrive
cmp byte [si], "B" inc di
je chb inc dl
cmp byte [si], "c" loop checkdrive
je chc
cmp byte [si], "C"
je chc
cmp byte [si], "d"
je chd
cmp byte [si], "D"
je chd
;Print an error message ;Print an error message
jmp driverror jmp driverror
;Change ;Change the drive
cha: contchdrive:
mov dl, 0x0 mov [drive], dl
mov byte [drive], dl
jmp loadvalues
chb:
mov dl, 0x1
mov byte [drive], dl
jmp loadvalues
chc:
mov dl, 0x2
mov byte [drive], dl
jmp loadvalues
chd:
mov dl, 0x3
mov byte [drive], dl
;Load the disk description table ;Load the disk description table
loadvalues:
;Set the source ;Set the source
loadvalues:
mov dl, [drive] mov dl, [drive]
mov ch, 0x0 mov ch, 0x0
mov dh, 0x0 mov dh, 0x0
@ -69,62 +58,68 @@ mov si, buffer
mov bx, si mov bx, si
;Set the size ;Set the size
mov al, 0x1 mov al, 0x1
;Load ;Load the disk description table
mov ah, 0x2 mov ah, 0x2
int 0x13 int 0x13
jc diskerror jc diskerror
;Store the disk values used for the rest of the call ;Store the disk values used for the rest of the call
mov ax, word [buffer + 0xb] mov ax, [buffer + 0xb]
mov word [sectorsize], ax mov [sectorsize], ax
mov ax, word [buffer + 0xe] mov ax, [buffer + 0xe]
mov word [bootsectors], ax mov [reservedsectors], ax
mov al, byte [buffer + 0x10] mov al, [buffer + 0x10]
mov byte [fats], al mov [fats], al
mov ax, word [buffer + 0x11] mov ax, [buffer + 0x11]
mov word [rootentries], ax mov [rootentries], ax
mov ax, word [buffer + 0x16] mov ax, [buffer + 0x16]
mov word [sectorsperfat], ax mov [sectorsperfat], ax
mov ax, word [buffer + 0x18] mov ax, [buffer + 0x18]
mov word [sectorspertrack], ax mov [sectorspertrack], ax
mov ax, word [buffer + 0x1a] mov ax, [buffer + 0x1a]
mov word [sides], ax mov [heads], ax
;Load the root ;Calculate and store variables not found in the BPB
;Set the source ;Start of the root
mov ah, 0x0 mov ah, 0x0
mov al, [fats] mov al, [fats]
mul word [sectorsperfat] mul word [sectorsperfat]
add ax, [bootsectors] add ax, [reservedsectors]
push ax mov [rootstart], ax
;Set the destination ;Size of the root in sectors
mov si, buffer
mov bx, si
;Set the size
mov ax, [rootentries] mov ax, [rootentries]
mov dx, 0x20 mov dx, 0x20
mul dx mul dx
mov dx, 0x0 mov dx, 0x0
div word [sectorsize] div word [sectorsize]
mov cx, ax mov [rootsectors], ax
pop ax
;Load the root
;Set the source
mov ax, [rootstart]
;Set the destination
mov si, buffer
mov bx, si
;Set the size
mov cx, [rootsectors]
;Store the source and the loop counter in the stack
loadrootsector:
push ax push ax
push cx push cx
loadroot: ;Set the source
push cx
call calcsource call calcsource
;Set the size ;Set the size
push ax
mov al, 0x1 mov al, 0x1
;Load ;Load a sector
mov ah, 0x2 mov ah, 0x2
int 0x13 int 0x13
;Load the loop counter and the source from the stack
pop cx
pop ax pop ax
;Set the next sector ;Set the next sector
add ax, 0x1 add ax, 0x1
add bx, word [sectorsize] add bx, word [sectorsize]
pop cx loop loadrootsector
loop loadroot
;List ;List
;Set SI to the root ;Set SI to the root
@ -133,8 +128,8 @@ mov si, buffer
mov cx, word [rootentries] mov cx, word [rootentries]
mov ax, 0x0 mov ax, 0x0
mov bl, 0x17 mov bl, 0x17
loop:
;Store CX in the stack ;Store CX in the stack
loop:
push cx push cx
;Check for an empty entry ;Check for an empty entry
cmp byte [si], 0xe5 cmp byte [si], 0xe5
@ -178,8 +173,8 @@ pop ax
cmp bl, 0x0 cmp bl, 0x0
jz page jz page
dec bl dec bl
skip:
;Set SI to the next entry ;Set SI to the next entry
skip:
add ax, 0x20 add ax, 0x20
mov si, buffer mov si, buffer
add si, ax add si, ax
@ -190,6 +185,8 @@ page:
push ax push ax
mov ah, 0x0 mov ah, 0x0
int 0x16 int 0x16
cmp al, 0x1b
je done
pop ax pop ax
mov bl, 0x17 mov bl, 0x17
jmp skip jmp skip
@ -212,35 +209,56 @@ jmp done
;Data ;Data
drive db 0x0 drive db 0x0
sectorsize dw 0x0 ;bytes sectorsize dw 0x0 ;bytes
bootsectors dw 0x0 reservedsectors dw 0x0
fats db 0x0 fats db 0x0
rootentries dw 0x0 rootentries dw 0x0
sectorsperfat dw 0x0 sectorsperfat dw 0x0
sectorspertrack dw 0x0 sectorspertrack dw 0x0
sides dw 0x0 heads dw 0x0
rootstart dw 0x0
rootsectors dw 0x0
driveletters db "AaBbCcDd"
driverrormsg db "Drive not found", 0x0 driverrormsg db "Drive not found", 0x0
diskerrormsg db "Unable to read disk", 0x0 diskerrormsg db "Unable to read disk", 0x0
;***
;Calculate the source arguments for loading data from the disk ;Calculate the source arguments for loading data from the disk
calcsource: calcsource:
;Store AX and BX in the stack
push ax push ax
push bx push bx
;Calculate the cylinder, head, and sector
;Store the logical sector in BX
mov bx, ax mov bx, ax
;Calculate the sector
mov dx, 0x0 mov dx, 0x0
div word [sectorspertrack] div word [sectorspertrack]
add dl, 0x1 add dl, 0x1
mov cl, dl mov cl, dl
;Load the logical sector from BX
mov ax, bx mov ax, bx
;Calculate the head and cylinder
mov dx, 0x0 mov dx, 0x0
div word [sectorspertrack] div word [sectorspertrack]
mov dx, 0x0 mov dx, 0x0
div word [sides] div word [heads]
mov dh, dl mov dh, dl ;Head
mov ch, al mov ch, al ;Cylinder
;Load the drive number
mov dl, byte [drive]
;Load BX and AX from the stack
pop bx pop bx
pop ax pop ax
mov dl, byte [drive]
;Return
ret ret
;***
;Buffer ;Buffer
buffer: buffer:

View File

@ -8,7 +8,7 @@
loadf: loadf:
;Store the initial registers in the stack ;Store BX, DX, SI, and DI in the stack
push bx push bx
push dx push dx
push si push si
@ -22,24 +22,28 @@ mov byte [.drive], dl
;Change the drive if needed ;Change the drive if needed
;Check for a drive specification ;Check for a drive specification
cmp byte [si + 0x1], ":" cmp byte [si + 0x1], ":"
jne .start jne .convert
;Get the BIOS equipment list
int 0x11
;Get the number of floppy drives
times 0x6 shr ax, 0x1
and ax, 0x3
inc ax
;Set the loop and drive letter counters and the drive letter and number
mov cx, ax
mov di, driveletters
mov al, [si]
mov dl, 0x0
;Check which drive to change to ;Check which drive to change to
cmp byte [si], "a" .checkdrive:
je .cha cmp al, [di]
cmp byte [si], "A" je .contchdrive
je .cha inc di
cmp byte [si], "b" cmp al, [di]
je .chb je .contchdrive
cmp byte [si], "B" inc di
je .chb inc dl
cmp byte [si], "c" loop .checkdrive
je .chc
cmp byte [si], "C"
je .chc
cmp byte [si], "d"
je .chd
cmp byte [si], "D"
je .chd
;Set AL to 0x1, CX to 0x0, and print an error message ;Set AL to 0x1, CX to 0x0, and print an error message
mov si, .driverrormsg mov si, .driverrormsg
mov ah, 0x2 mov ah, 0x2
@ -47,57 +51,41 @@ int 0x21
mov al, 0x1 mov al, 0x1
mov cx, 0x0 mov cx, 0x0
jmp .done jmp .done
;Change ;Change the drive
.cha: .contchdrive:
mov dl, 0x0 mov [.drive], dl
mov byte [.drive], dl ;Move to the file name
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 add si, 0x2
.start:
;Set DI at .file and initialise it with spaces ;Set DI at .file and initialise it with spaces
.convert:
mov di, .file mov di, .file
mov cx, 0xb mov cx, 0xb
mov al, 0x20 mov al, 0x20
rep stosb rep stosb
sub di, 0xb sub di, 0xb
;Convert .file into FAT formatting ;Convert the main part of the file name into FAT format
;Set the length counter
;Initialise the length counter for the main part of the file name
mov bl, 0x8 mov bl, 0x8
;Convert the main part of the file name
.nameloop:
;Load a character ;Load a character
.nameloop:
lodsb lodsb
;Check for a period ;Check for a period
cmp al, 0x2e cmp al, 0x2e
je .initext je .initext
;Check for everything else and convert to upper case ;Check for everything else and convert to upper case
call .checkconv call .checkconv
;Load the next character
jmp .nameloop jmp .nameloop
;Convert the extension ;Convert the extension into FAT format
;Set DI and the length counter for the extension
.initext: .initext:
;Set DI and initialise the length counter for the extension
mov bl, 0x3 mov bl, 0x3
mov di, .file+0x8 mov di, .file+0x8
.extloop:
;Load a character ;Load a character
.extloop:
lodsb lodsb
;Check for a period ;Check for a period
push ax push ax
@ -106,6 +94,7 @@ je .error
pop ax pop ax
;Check for everything else and convert to upper case ;Check for everything else and convert to upper case
call .checkconv call .checkconv
;Load the next character
jmp .extloop jmp .extloop
;Set AL to 0x4, CX to 0x0, and print an error message ;Set AL to 0x4, CX to 0x0, and print an error message
.error: .error:
@ -118,7 +107,6 @@ mov cx, 0x0
jmp .done jmp .done
;Find and load the file ;Find and load the file
.load: .load:
pop ax pop ax
@ -133,7 +121,7 @@ mov si, buffer
mov bx, si mov bx, si
;Set the size ;Set the size
mov al, 0x1 mov al, 0x1
;Load ;Load the disk description table
mov ah, 0x2 mov ah, 0x2
int 0x13 int 0x13
jnc .storevalues jnc .storevalues
@ -147,79 +135,91 @@ jmp .done
;Store the disk values used for the rest of the call ;Store the disk values used for the rest of the call
.storevalues: .storevalues:
mov ax, word [buffer + 0xb] mov ax, [buffer + 0xb]
mov word [.sectorsize], ax mov [.sectorsize], ax
mov al, byte [buffer + 0xd] mov al, [buffer + 0xd]
mov byte [.clustersize], al mov [.clustersize], al
mov ax, word [buffer + 0xe] mov ax, [buffer + 0xe]
mov word [.bootsectors], ax mov [.reservedsectors], ax
mov al, byte [buffer + 0x10] mov al, [buffer + 0x10]
mov byte [.fats], al mov [.fats], al
mov ax, word [buffer + 0x11] mov ax, [buffer + 0x11]
mov word [.rootentries], ax mov [.rootentries], ax
mov ax, word [buffer + 0x16] mov ax, [buffer + 0x16]
mov word [.sectorsperfat], ax mov [.sectorsperfat], ax
mov ax, word [buffer + 0x18] mov ax, [buffer + 0x18]
mov word [.sectorspertrack], ax mov [.sectorspertrack], ax
mov ax, word [buffer + 0x1a] mov ax, [buffer + 0x1a]
mov word [.sides], ax mov [.heads], ax
;Load the root ;Calculate and store variables not found in the BPB
;Set the source ;Start of the root
mov ah, 0x0 mov ah, 0x0
mov al, [.fats] mov al, [.fats]
mul word [.sectorsperfat] mul word [.sectorsperfat]
add ax, [.bootsectors] add ax, [.reservedsectors]
push ax mov [.rootstart], ax
;Set the destination ;Size of the root in sectors
mov si, buffer
mov bx, si
;Set the size
mov ax, [.rootentries] mov ax, [.rootentries]
mov dx, 0x20 mov dx, 0x20
mul dx mul dx
mov dx, 0x0 mov dx, 0x0
div word [.sectorsize] div word [.sectorsize]
mov cx, ax mov [.rootsectors], ax
pop ax ;Start of data
add ax, [.rootstart]
mov [.datastart], ax
;Load the root
;Set the source
mov ax, [.rootstart]
;Set the destination
mov si, buffer
mov bx, si
;Set the size
mov cx, [.rootsectors]
;Store the source and the loop counter in the stack
.loadrootsector:
push ax push ax
push cx push cx
.loadroot: ;Set the source
push cx
call .calcsource call .calcsource
;Set the size ;Set the size
push ax
mov al, 0x1 mov al, 0x1
;Load ;Load a sector
mov ah, 0x2 mov ah, 0x2
int 0x13 int 0x13
;Load the loop counter and the source from the stack
pop cx
pop ax pop ax
;Set the next sector ;Set the next sector
add ax, 0x1 add ax, 0x1
add bx, word [.sectorsize] add bx, word [.sectorsize]
pop cx ;Load the next sector
loop .loadroot loop .loadrootsector
;Search the root for the file entry ;Search the root for the file entry
;Set DI to the root ;Set DI to the root
mov di, buffer mov di, buffer
;Initialise the search loop ;Set the number of root entries
mov cx, word [.rootentries] mov cx, word [.rootentries]
;Set the entry pointer
mov ax, 0x0 mov ax, 0x0
;Store the loop counter in the stack
.search: .search:
;Store CX in the stack
push cx push cx
;Check for the file entry ;Check for the file entry
mov si, .file mov si, .file
mov cx, 0xb mov cx, 0xb
rep cmpsb rep cmpsb
je .checksize je .checksize
;Set DI to the next entry ;Set DI at the next entry
add ax, 0x20 add ax, 0x20
mov di, buffer mov di, buffer
add di, ax add di, ax
;Load CX from the stack ;Load the loop counter from the stack
pop cx pop cx
;Search the next entry
loop .search loop .search
;Set AL to 0x4, CX to 0x0, and print an error message ;Set AL to 0x4, CX to 0x0, and print an error message
mov si, .filerrormsg mov si, .filerrormsg
@ -227,11 +227,11 @@ mov ah, 0x2
int 0x21 int 0x21
mov al, 0x4 mov al, 0x4
mov cx, 0x0 mov cx, 0x0
jmp .clearstack jmp .done
;Check and store the file size ;Check and store the file size
.checksize:
;Load CX from the stack ;Load CX from the stack
.checksize:
pop cx pop cx
;Check for files larger than 64 KiB ;Check for files larger than 64 KiB
cmp word [di + 0x13], 0x0 cmp word [di + 0x13], 0x0
@ -259,61 +259,58 @@ mov ah, 0x2
int 0x21 int 0x21
mov al, 0x8 mov al, 0x8
mov cx, 0x0 mov cx, 0x0
jmp .clearstack jmp .done
;Load the FAT ;Load the FAT
.loadfat: .loadfat:
;Store the first cluster of the file ;Store the address of the first cluster
mov ax, word [di + 0xf] mov ax, [di + 0xf]
mov word [.cluster], ax mov [.cluster], ax
;Set the source ;Set the source
mov ax, 0x1 mov ax, [.reservedsectors]
call .calcsource call .calcsource
;Set the destination ;Set the destination
mov di, buffer mov bx, buffer
mov bx, di
;Set the size ;Set the size
mov ax, [.sectorsperfat] mov ax, [.sectorsperfat]
;Load ;Load the FAT
mov ah, 0x2 mov ah, 0x2
int 0x13 int 0x13
;Load the file
;Load a cluster ;Load a cluster
.loadcluster: .loadcluster:
;Set the source ;Set the source
pop cx
pop bx
mov ax, word [.cluster] mov ax, word [.cluster]
sub ax, 0x2 sub ax, 0x2
mul byte [.clustersize] mul byte [.clustersize]
add ax, bx add ax, [.datastart]
add ax, cx
push bx
push cx
;Set the destination ;Set the destination
mov bx, word [.pointer] mov bx, word [.pointer]
;Load a sector ;Set the size
mov ch, 0x0 mov ch, 0x0
mov cl, byte [.clustersize] mov cl, byte [.clustersize]
;Store the loop counter in the stack
.loadsector: .loadsector:
push cx push cx
;Set the source
call .calcsource call .calcsource
;Set the size ;Set the size
push ax push ax
mov al, 0x1 mov al, 0x1
;Load ;Load a sector
mov ah, 0x2 mov ah, 0x2
int 0x13 int 0x13
pop ax pop ax
;Set the next sector ;Set the next sector
add ax, 0x1 add ax, 0x1
add bx, word [.sectorsize] add bx, word [.sectorsize]
;Load the loop counter from the stack
pop cx pop cx
;Load the next sector
loop .loadsector loop .loadsector
;Calculate the next cluster ;Calculate the next cluster
;Check if the cluster is even or odd
mov ax, [.cluster] mov ax, [.cluster]
mov dx, 0x0 mov dx, 0x0
mov bx, 0x3 mov bx, 0x3
@ -322,23 +319,26 @@ mov bx, 0x2
div bx div bx
mov si, buffer mov si, buffer
add si, ax add si, ax
mov ax, word [ds:si] mov ax, word [si]
or dx, dx or dx, dx
jz .even jz .even
shr ax, 1 ;If the cluster is odd shift out the first four bits
shr ax, 1 times 0x4 shr ax, 0x1
shr ax, 1
shr ax, 1
jmp .contcalc jmp .contcalc
;If the cluster is even mask out the final four bits
.even: .even:
and ax, 0xfff and ax, 0xfff
.contcalc: .contcalc:
mov word [.cluster], ax ;Check for the file end
cmp ax, 0xff8 cmp ax, 0xff8
jge .success jge .success
;Store the address of the next cluster
mov word [.cluster], ax
;Set the destination of the next cluster
mov ax, [.sectorsize] mov ax, [.sectorsize]
mul word [.clustersize] mul word [.clustersize]
add word [.pointer], ax add word [.pointer], ax
;Load the next cluster
jmp .loadcluster jmp .loadcluster
;Set AL to 0x0 and load the file size to CX if the load was succesful ;Set AL to 0x0 and load the file size to CX if the load was succesful
@ -347,13 +347,9 @@ mov al, 0x0
mov cx, [.size] mov cx, [.size]
;Clear the stack ;Clear the stack
.clearstack:
pop bx
pop bx
.done: .done:
;Load the initial registers from the stack ;Load DI, SI, DX, and BX from the stack
pop di pop di
pop si pop si
pop dx pop dx
@ -362,18 +358,22 @@ pop bx
;Set AH to its initial value ;Set AH to its initial value
mov ah, 0x0 mov ah, 0x0
;Return
iret iret
;Data ;Data
.drive db 0x0 .drive db 0x0
.sectorsize dw 0x0 ;bytes .sectorsize dw 0x0 ;bytes
.clustersize db 0x0 ;sectors .clustersize db 0x0 ;sectors
.bootsectors dw 0x0 .reservedsectors dw 0x0
.fats db 0x0 .fats db 0x0
.rootentries dw 0x0 .rootentries dw 0x0
.sectorsperfat dw 0x0 .sectorsperfat dw 0x0
.sectorspertrack dw 0x0 .sectorspertrack dw 0x0
.sides dw 0x0 .heads dw 0x0
.rootstart dw 0x0
.rootsectors dw 0x0
.datastart dw 0x0
.file times 0xb db 0x20 .file times 0xb db 0x20
.size dw 0x0 .size dw 0x0
.cluster dw 0x0 .cluster dw 0x0
@ -383,8 +383,12 @@ iret
.filerrormsg db "File or command not found", 0x0 .filerrormsg db "File or command not found", 0x0
.sizerrormsg db "Not enough memory", 0x0 .sizerrormsg db "Not enough memory", 0x0
;***
;Check the file name and convert to upper case ;Check the file name and convert to upper case
.checkconv: .checkconv:
;Check for the string end, length limit, and invalid characters
;Check for the string end ;Check for the string end
cmp al, 0x0 cmp al, 0x0
je .load je .load
@ -416,6 +420,8 @@ jmp .error
.contcheck3: .contcheck3:
cmp al, 0x7c cmp al, 0x7c
je .error je .error
;Check for lower case and convert it to upper case
;Check for lower case ;Check for lower case
cmp al, 0x61 cmp al, 0x61
jl .storech jl .storech
@ -423,30 +429,50 @@ cmp al, 0x7a
jg .storech jg .storech
;Convert lower to upper case ;Convert lower to upper case
sub al, 0x20 sub al, 0x20
.storech:
;Store the character ;Store the character
.storech:
stosb stosb
;Decrease the counter ;Decrease the counter
dec bl dec bl
;Return
ret ret
;***
;Calculate the source arguments for loading data from the disk ;Calculate the source arguments for loading data from the disk
.calcsource: .calcsource:
;Store AX and BX in the stack
push ax push ax
push bx push bx
;Calculate the cylinder, head, and sector
;Store the logical sector in BX
mov bx, ax mov bx, ax
;Calculate the sector
mov dx, 0x0 mov dx, 0x0
div word [.sectorspertrack] div word [.sectorspertrack]
add dl, 0x1 add dl, 0x1
mov cl, dl mov cl, dl
;Load the logical sector from BX
mov ax, bx mov ax, bx
;Calculate the head and cylinder
mov dx, 0x0 mov dx, 0x0
div word [.sectorspertrack] div word [.sectorspertrack]
mov dx, 0x0 mov dx, 0x0
div word [.sides] div word [.heads]
mov dh, dl mov dh, dl ;Head
mov ch, al mov ch, al ;Cylinder
;Load the drive number
mov dl, byte [.drive]
;Load BX and AX from the stack
pop bx pop bx
pop ax pop ax
mov dl, byte [.drive]
;Return
ret ret

View File

@ -1,5 +1,5 @@
CPU 8086 cpu 8086
ORG 0x3000 org 0x3000
;Load a file and print it ;Load a file and print it
@ -11,17 +11,16 @@ sti
;Check for an empty tail ;Check for an empty tail
;Check ;Check
cmp byte [si], 0x0 cmp byte [si], 0x0
jne start jne extract
;Print an error message and abort if the tail is empty ;Print an error message and abort if the tail is empty
mov si, errormsg mov si, errormsg
mov ah, 0x2 mov ah, 0x2
int 0x21 int 0x21
je done je done
start:
;Find the end of the filename and add a null if needed ;Find the end of the filename and add a null if needed
;Set DI at the tail ;Set DI at the tail
extract:
mov di, si mov di, si
findend: findend:
;Check for the string end ;Check for the string end
@ -32,13 +31,14 @@ cmp byte [di], 0x20
je addnull je addnull
inc di inc di
jmp findend jmp findend
;Add a null
addnull: addnull:
mov al, 0x0 mov al, 0x0
stosb stosb
;Load the file ;Load the file
load:
;Load ;Load
load:
mov bx, stack + 0x100 mov bx, stack + 0x100
mov ah, 0x0 mov ah, 0x0
int 0x22 int 0x22
@ -52,8 +52,8 @@ mov bh, 0x0
mov bl, 0x18 mov bl, 0x18
mov dl, 0x50 mov dl, 0x50
mov si, stack + 0x100 mov si, stack + 0x100
print:
;Decrease the character counter ;Decrease the character counter
print:
dec dl dec dl
;Load the current character ;Load the current character
lodsb lodsb
@ -66,8 +66,8 @@ je linecount
;Check for a soft line end ;Check for a soft line end
cmp dl, 0x0 cmp dl, 0x0
je linecount je linecount
contprint:
;Check paging ;Check paging
contprint:
cmp bl, 0x0 cmp bl, 0x0
jz page jz page
;Repeat for the next character ;Repeat for the next character
@ -83,15 +83,19 @@ page:
push ax push ax
mov ah, 0x0 mov ah, 0x0
int 0x16 int 0x16
cmp al, 0x1b
je done
pop ax pop ax
mov bl, 0x18 mov bl, 0x18
mov dl, 0x50 mov dl, 0x50
loop print loop print
;Return to the system
done: done:
int 0x20 int 0x20
;Data ;Data
errormsg db "File not found", 0x0 errormsg db "File not found", 0x0
;Stack
stack: stack:

View File

@ -1,5 +1,4 @@
;Print a string ending in a null from SI followed by a CRLF. ;Print a string ending in a null from SI followed by a CRLF.
println: println:
;Print the string ;Print the string
@ -9,4 +8,5 @@ int 0x21
;Print a CRLF ;Print a CRLF
call printcrlf call printcrlf
;Return
iret iret

View File

@ -1,14 +1,13 @@
;Print a string ending in a null from SI. ;Print a string ending in a null from SI.
printstr: printstr:
;Store the initial registers in the stack ;Store AX and SI in the stack
push ax push ax
push si push si
;Print the string ;Print the string
.loop:
;Load the current character ;Load the current character
.loop:
lodsb lodsb
;Check for the string end ;Check for the string end
cmp al, 0x0 cmp al, 0x0
@ -16,13 +15,13 @@ je .done
;Print the character ;Print the character
mov ah, 0xe mov ah, 0xe
int 0x10 int 0x10
;Repeat for the next character ;Print the next character
jmp .loop jmp .loop
.done:
;Load the initial registers from the stack ;Load the initial registers from the stack
.done:
pop si pop si
pop ax pop ax
;Return
iret iret

View File

@ -1,6 +1,5 @@
;Read a string ending in a null of at most AL characters to DI until a ;Read a string ending in a null of at most AL characters to DI until a
;return and print a CRLF. ;return and print a CRLF.
readln: readln:
;Read the string ;Read the string
@ -10,4 +9,5 @@ int 0x21
;Print a CRLF ;Print a CRLF
call printcrlf call printcrlf
;Return
iret iret

View File

@ -1,9 +1,8 @@
;Read a string ending in a null of at most AL characters to DI until a ;Read a string ending in a null of at most AL characters to DI until a
;return. ;return.
readstr: readstr:
;Store the initial registers in the stack ;Store AX, BX, CX, DX, and DI in the stack
push ax push ax
push bx push bx
push cx push cx
@ -26,12 +25,11 @@ mov ah, 0xf
int 0x10 int 0x10
dec ah dec ah
mov [.lastcolumn], ah mov [.lastcolumn], ah
;Initialise the cursor pointer in BL and clear BH ;Set the cursor pointer in BL and clear BH
mov bx, 0x1 mov bx, 0x1
.loop:
;Read a keypress ;Read a keypress
.loop:
mov ah, 0x0 mov ah, 0x0
int 0x16 int 0x16
@ -87,29 +85,27 @@ jmp .loop
;Check for the input beginning ;Check for the input beginning
cmp bl, 0x1 cmp bl, 0x1
je .loop je .loop
;Move ;Move the cursor
call .prevchar call .prevchar
dec di dec di
dec bl dec bl
jmp .loop jmp .loop
;Finish reading the string
.return:
;Check for and remove trailing spaces ;Check for and remove trailing spaces
;Go to the end of the input ;Go to the end of the input
.return:
pop ax pop ax
mov bh, 0x0 mov bh, 0x0
sub ax, bx sub ax, bx
push di push di
add di, ax add di, ax
;Check for trailing spaces
.findtrailing: .findtrailing:
;Check
cmp byte [di], 0x20 cmp byte [di], 0x20
je .deltrailing je .deltrailing
jmp .end jmp .end
;Remove trailing spaces
.deltrailing: .deltrailing:
;Remove
mov al, 0x0 mov al, 0x0
stosb stosb
sub di, 0x2 sub di, 0x2
@ -128,49 +124,57 @@ inc di
inc bl inc bl
jmp .findend jmp .findend
;Load DI, DX, CX, BX, and AX from the stack
.done: .done:
;Load the initial registers from the stack
pop di pop di
pop dx pop dx
pop cx pop cx
pop bx pop bx
pop ax pop ax
;Return
iret iret
;Data ;Data
.lastcolumn db 0x0 .lastcolumn db 0x0
;Move the cursor forward within a line ;***
;Move the cursor forward
.nextchar: .nextchar:
;Get the cursor position ;Get the cursor position
mov ah, 0x3 mov ah, 0x3
int 0x10 int 0x10
;Check for the end of the line ;Check for the end of the line
cmp dl, [.lastcolumn] cmp dl, [.lastcolumn]
je .nextln je .nextln
;Move
;Move the cursor forward within a line
inc dl inc dl
mov ah, 0x2 mov ah, 0x2
int 0x10 int 0x10
;Return
ret ret
;Move the cursor to the beginning of the next line ;Move the cursor to the beginning of the next line
.nextln:
;Check if the current line is the last on screen ;Check if the current line is the last on screen
.nextln:
cmp dh, 0x18 cmp dh, 0x18
je .scroll je .scroll
;Move ;Move the cursor
mov ah, 0x2 mov ah, 0x2
inc dh inc dh
mov dl, 0x0 mov dl, 0x0
int 0x10 int 0x10
;Return
ret ret
;Scroll the screen up by one line ;Scroll the screen up by one line
.scroll: .scroll:
;Scroll
mov ah, 0x6 mov ah, 0x6
mov al, 0x1 mov al, 0x1
mov bh, 0x7 mov bh, 0x7
@ -179,25 +183,35 @@ mov cl, 0x0
mov dh, 0x18 mov dh, 0x18
mov dl, [.lastcolumn] mov dl, [.lastcolumn]
int 0x10 int 0x10
;Move to the beginning of the new line ;Move to the beginning of the new line
mov ah, 0x2 mov ah, 0x2
mov bh, 0x0 mov bh, 0x0
mov dl, 0x0 mov dl, 0x0
int 0x10 int 0x10
;Return
ret ret
;Move the cursor backward within a line ;***
;Move the cursor backward
.prevchar: .prevchar:
;Get the cursor position ;Get the cursor position
mov ah, 0x3 mov ah, 0x3
int 0x10 int 0x10
;Check for the beginning of the line ;Check for the beginning of the line
cmp dl, 0x0 cmp dl, 0x0
je .prevln je .prevln
;Move
;Move the cursor backward within a line
dec dl dec dl
mov ah, 0x2 mov ah, 0x2
int 0x10 int 0x10
;Return
ret ret
;Move the cursor to the end of the previous line ;Move the cursor to the end of the previous line
@ -206,4 +220,6 @@ mov ah, 0x2
dec dh dec dh
mov dl, [.lastcolumn] mov dl, [.lastcolumn]
int 0x10 int 0x10
;Return
ret ret

View File

@ -1,6 +1,7 @@
CPU 8086 cpu 8086
ORG 0x500 org 0x500
;Jump to the code
jmp start jmp start
;Interrupt handler ;Interrupt handler
@ -25,17 +26,16 @@ je loadf
;To do: savef ;To do: savef
iret iret
;System calls ;System call includes
%include "PRINTSTR.INC" %include "PRINTSTR.INC"
%include "READSTR.INC" %include "READSTR.INC"
%include "PRINTLN.INC" %include "PRINTLN.INC"
%include "READLN.INC" %include "READLN.INC"
%include "LOADF.INC" %include "LOADF.INC"
start:
;Set up the interrupt vectors ;Set up the interrupt vectors
;Interrupt 0x20 offset ;Interrupt 0x20 offset
start:
mov ax, int0x20 mov ax, int0x20
mov [0x80], ax mov [0x80], ax
;Interrupt 0x21 offset ;Interrupt 0x21 offset
@ -110,10 +110,10 @@ mov cx, 0xe
mov al, 0x20 mov al, 0x20
rep stosb rep stosb
sub di, 0xe sub di, 0xe
;Initialise the length counter ;Set the length counter
mov bl, 0xa mov bl, 0xa
specloop:
;Load a character ;Load a character
specloop:
lodsb lodsb
;Check for the string end ;Check for the string end
cmp al, 0x0 cmp al, 0x0
@ -128,16 +128,18 @@ je cmderror
stosb stosb
;Decrease the counter ;Decrease the counter
dec bl dec bl
;Extract the next character
jmp specloop jmp specloop
;Add extension to the name ;Store the start of the command tail in the stack
addext: addext:
push si push si
;Add extension to the specification
mov si, extension mov si, extension
mov cx, 0x5 mov cx, 0x5
rep movsb rep movsb
;Load and execute the program ;Load and execute the program
;Load ;Load the program
mov bx, 0x3000 mov bx, 0x3000
mov si, program mov si, program
mov ah, 0x0 mov ah, 0x0
@ -149,9 +151,43 @@ jne shell
mov dl, [drive] mov dl, [drive]
pop si pop si
call ignoreleading call ignoreleading
;Execute ;Execute the program
jmp 0x3000 jmp 0x3000
;Change the drive
;Get the BIOS equipment list
changedrive:
int 0x11
;Get the number of floppy drives
times 0x6 shr ax, 0x1
and ax, 0x3
inc ax
;Set the loop and drive letter counters and the drive letter and number
mov cx, ax
mov di, driveletters
mov al, [si]
mov dl, 0x0
;Check which drive to change to
checkdrive:
cmp al, [di]
je contchdrive
inc di
cmp al, [di]
je contchdrive
inc di
inc dl
loop checkdrive
;Print a drive error message and return to the shell
mov si, driverrormsg
mov ah, 0x2
int 0x21
jmp shell
;Change the drive
contchdrive:
mov [drive], dl
call setdriveletter
jmp shell
;Print a command error message and return to the shell ;Print a command error message and return to the shell
cmderror: cmderror:
mov si, cmderrormsg mov si, cmderrormsg
@ -159,56 +195,11 @@ mov ah, 0x2
int 0x21 int 0x21
jmp shell jmp shell
;Change the drive
changedrive:
;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
;Print a drive error message and return to the shell
mov si, driverrormsg
mov ah, 0x2
int 0x21
jmp shell
;Change
cha:
mov dl, 0x0
mov [drive], dl
call setdriveletter
jmp shell
chb:
mov dl, 0x1
mov [drive], dl
call setdriveletter
jmp shell
chc:
mov dl, 0x2
mov [drive], dl
call setdriveletter
jmp shell
chd:
mov dl, 0x3
mov [drive], dl
call setdriveletter
jmp shell
;Data ;Data
welcomemsg db 0xd, 0xa, "Welcome to EttinOS!", 0xd, 0xa, 0x0 welcomemsg db 0xd, 0xa, "Welcome to EttinOS!", 0xd, 0xa, 0x0
drive db 0x0 drive db 0x0
driveletter db "?:", 0x0 driveletter db "?:", 0x0
driveletters db "AaBbCcDd"
prompt db "> ", 0x0 prompt db "> ", 0x0
input times 0x4c db 0x0 input times 0x4c db 0x0
program times 0xf db 0x0 program times 0xf db 0x0
@ -216,53 +207,70 @@ extension db ".BIN", 0x0
cmderrormsg db "File or command not found", 0x0 cmderrormsg db "File or command not found", 0x0
driverrormsg db "Drive not found", 0x0 driverrormsg db "Drive not found", 0x0
;***
;Set the drive letter ;Set the drive letter
setdriveletter: setdriveletter:
;Set the drive number and letter counters
mov dh, 0x0
mov si, driveletters
;Check the drive number ;Check the drive number
cmp dl, 0x0 .checkdrive:
je .seta cmp dl, dh
cmp dl, 0x1 je .set
je .setb add si, 0x2
cmp dl, 0x2 inc dh
je .setc jmp .checkdrive
cmp dl, 0x3
je .setd ;Set the drive letter
ret .set:
;Set mov al, [si]
.seta: mov byte [driveletter], al
mov byte [driveletter], "A"
ret ;Return
.setb:
mov byte [driveletter], "B"
ret
.setc:
mov byte [driveletter], "C"
ret
.setd:
mov byte [driveletter], "D"
ret ret
;***
;Ignore leading spaces in the command and its tail ;Ignore leading spaces in the command and its tail
ignoreleading: ignoreleading:
;Check for a space
lodsb lodsb
cmp al, 0x20 cmp al, 0x20
je ignoreleading je ignoreleading
;Set SI to the first non-space character
dec si dec si
;Return
ret ret
;***
;Print a CRLF ;Print a CRLF
printcrlf: printcrlf:
;Store the initial registers in the stack
;Store SI in the stack
push si push si
;Print the CRLF ;Print the CRLF
mov si, .crlf mov si, .crlf
mov ah, 0x0 mov ah, 0x0
int 0x21 int 0x21
;Load the initial registers from the stack
;Load SI from the stack
pop si pop si
;Return
ret ret
;Data ;Data
.crlf db 0xd, 0xa, 0x0 .crlf db 0xd, 0xa, 0x0
;***
;File system buffer ;File system buffer
buffer: buffer: