forked from crazyettin/EttinOS
Change the line endings of the text files from Unix to DOS style.
This commit is contained in:
parent
08f2d57bb2
commit
2bfa61b669
46
LICENSE.MD
46
LICENSE.MD
|
@ -1,23 +1,23 @@
|
|||
MIT License
|
||||
===========
|
||||
|
||||
Copyright (c) 2021 CrazyEttin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
MIT License
|
||||
===========
|
||||
|
||||
Copyright (c) 2021 CrazyEttin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
126
README.MD
126
README.MD
|
@ -1,63 +1,63 @@
|
|||
EttinOS
|
||||
=======
|
||||
|
||||
EttinOS is a minimalist 16-bit DOS-like hobbyist operating system for
|
||||
the IBM PC and compatible computers. Its git repository can be found at
|
||||
https://ahti.space/git/crazyettin/EttinOS.
|
||||
|
||||
System requirements
|
||||
-------------------
|
||||
|
||||
* An Intel 8086 or compatible CPU
|
||||
* BIOS, or UEFI in legacy mode
|
||||
* 64 KiB of RAM
|
||||
* A floppy disk drive
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
Build dependencies:
|
||||
* A Unix-like operating system
|
||||
* bash
|
||||
* coreutils
|
||||
* dosfstools
|
||||
* mtools
|
||||
* nasm
|
||||
|
||||
Running make.sh will build EttinOS and create a bootable 360 KiB 5.25"
|
||||
floppy disk image named EttinOS.img. To get a 1.44 MB 3.5" one instead
|
||||
use the argument -1440. If you want to use another floppy disk format
|
||||
you will have to adjust the bootloader disk description tables and
|
||||
install the system manually. Hard disk drives are not supported.
|
||||
|
||||
Input
|
||||
-----
|
||||
|
||||
The EttinOS input system is inspired by typewriters. Typing a character
|
||||
overwrites the cursor location and the erase (=tab) key erases it. The
|
||||
space and backspace keys move the cursor.
|
||||
|
||||
Programming
|
||||
-----------
|
||||
|
||||
EttinOS has a flat address space of 64 KiB. The data, stack, and
|
||||
extra segments are set at the beginning of the RAM and the system stack
|
||||
at the end of the address space. Programs are loaded at address 0x2000.
|
||||
The stack is reset back to the end of the address space after a program
|
||||
has finished running.
|
||||
|
||||
System calls:
|
||||
* Interrupt 0x20: Return to the shell.
|
||||
* Interrupt 0x21: Input and output:
|
||||
* AH = 0x0: Print a string ending in a null from SI.
|
||||
* AH = 0x1: Read a string ending in a null of at most AL
|
||||
characters to DI until a return.
|
||||
* AH = 0x2: Print a string ending in a null from SI followed by a
|
||||
CRLF.
|
||||
* AH = 0x3: Read a string ending in a null of at most AL
|
||||
characters to DI until a return and print a CRLF.
|
||||
* Interrupt 0x22: Disk operations:
|
||||
* AH = 0x0: 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
|
||||
succesfull and 0x1 if there was an error.
|
||||
* AH = 0x1: Save a file (under construction).
|
||||
EttinOS
|
||||
=======
|
||||
|
||||
EttinOS is a minimalist 16-bit DOS-like hobbyist operating system for
|
||||
the IBM PC and compatible computers. Its git repository can be found at
|
||||
https://ahti.space/git/crazyettin/EttinOS.
|
||||
|
||||
System requirements
|
||||
-------------------
|
||||
|
||||
* An Intel 8086 or compatible CPU
|
||||
* BIOS, or UEFI in legacy mode
|
||||
* 64 KiB of RAM
|
||||
* A floppy disk drive
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
Build dependencies:
|
||||
* A Unix-like operating system
|
||||
* bash
|
||||
* coreutils
|
||||
* dosfstools
|
||||
* mtools
|
||||
* nasm
|
||||
|
||||
Running make.sh will build EttinOS and create a bootable 360 KiB 5.25"
|
||||
floppy disk image named EttinOS.img. To get a 1.44 MB 3.5" one instead
|
||||
use the argument -1440. If you want to use another floppy disk format
|
||||
you will have to adjust the bootloader disk description tables and
|
||||
install the system manually. Hard disk drives are not supported.
|
||||
|
||||
Input
|
||||
-----
|
||||
|
||||
The EttinOS input system is inspired by typewriters. Typing a character
|
||||
overwrites the cursor location and the erase (=tab) key erases it. The
|
||||
space and backspace keys move the cursor.
|
||||
|
||||
Programming
|
||||
-----------
|
||||
|
||||
EttinOS has a flat address space of 64 KiB. The data, stack, and
|
||||
extra segments are set at the beginning of the RAM and the system stack
|
||||
at the end of the address space. Programs are loaded at address 0x2000.
|
||||
The stack is reset back to the end of the address space after a program
|
||||
has finished running.
|
||||
|
||||
System calls:
|
||||
* Interrupt 0x20: Return to the shell.
|
||||
* Interrupt 0x21: Input and output:
|
||||
* AH = 0x0: Print a string ending in a null from SI.
|
||||
* AH = 0x1: Read a string ending in a null of at most AL
|
||||
characters to DI until a return.
|
||||
* AH = 0x2: Print a string ending in a null from SI followed by a
|
||||
CRLF.
|
||||
* AH = 0x3: Read a string ending in a null of at most AL
|
||||
characters to DI until a return and print a CRLF.
|
||||
* Interrupt 0x22: Disk operations:
|
||||
* AH = 0x0: 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
|
||||
succesfull and 0x1 if there was an error.
|
||||
* AH = 0x1: Save a file (under construction).
|
||||
|
|
486
src/BOOT.ASM
486
src/BOOT.ASM
|
@ -1,243 +1,243 @@
|
|||
CPU 8086
|
||||
ORG 0x7c00
|
||||
|
||||
jmp start
|
||||
nop
|
||||
|
||||
;Disk description tables
|
||||
|
||||
%ifdef F1440
|
||||
;1.44 MB 3.5" floppy disk (enable with the argument -d F1440 when building)
|
||||
oemlabel db "ETTINOS "
|
||||
sectorsize dw 0x200 ;bytes
|
||||
clustersize db 0x1 ;sectors
|
||||
bootsectors dw 0x1
|
||||
fats db 0x2
|
||||
rootentries dw 0xe0
|
||||
logicalsectors dw 0xb40
|
||||
mediadescriptor db 0xf0
|
||||
sectorsperfat dw 0x9
|
||||
sectorspertrack dw 0x12
|
||||
sides dw 0x2
|
||||
hiddensectors dd 0x0
|
||||
largesectors dd 0x0
|
||||
driveid dw 0x0
|
||||
drivesignature db 0x29
|
||||
volumeid dd 0x0
|
||||
volumelabel db "ETTINOS "
|
||||
filesystem db "FAT12 "
|
||||
|
||||
%else
|
||||
;360 KiB 5.25" floppy disk (default)
|
||||
oemlabel db "ETTINOS "
|
||||
sectorsize dw 0x200 ;bytes
|
||||
clustersize db 0x2 ;sectors
|
||||
bootsectors dw 0x1
|
||||
fats db 0x2
|
||||
rootentries dw 0x70
|
||||
logicalsectors dw 0x2d0
|
||||
mediadescriptor db 0xfd
|
||||
sectorsperfat dw 0x2
|
||||
sectorspertrack dw 0x9
|
||||
sides dw 0x2
|
||||
hiddensectors dd 0x0
|
||||
largesectors dd 0x0
|
||||
driveid dw 0x0
|
||||
drivesignature db 0x29
|
||||
volumeid dd 0x0
|
||||
volumelabel db "ETTINOS "
|
||||
filesystem db "FAT12 "
|
||||
|
||||
%endif
|
||||
|
||||
start:
|
||||
|
||||
;Setup
|
||||
;Set up the data, stack, and extra segments
|
||||
mov ax, 0x0
|
||||
mov ds, ax
|
||||
mov ss, ax
|
||||
mov es, ax
|
||||
;Set up the stack
|
||||
cli
|
||||
mov sp, 0x0
|
||||
sti
|
||||
;Store the boot drive number
|
||||
mov [bootdrive], dl
|
||||
|
||||
;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 system 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 system entry
|
||||
mov si, sysfile
|
||||
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
|
||||
|
||||
;Print an error message if the system is not found
|
||||
mov si, errormsg
|
||||
printerror:
|
||||
;Load a character
|
||||
lodsb
|
||||
;Check for the string end
|
||||
cmp al, 0x0
|
||||
je $
|
||||
;Print the character
|
||||
mov ah, 0xe
|
||||
int 0x10
|
||||
;Repeat
|
||||
jmp printerror
|
||||
|
||||
;Load the system 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 system 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
|
||||
call calcsource
|
||||
;Set the destination
|
||||
mov bx, word [pointer]
|
||||
;Set the size
|
||||
;mov al, 0x1
|
||||
mov al, [clustersize]
|
||||
;Load
|
||||
mov ah, 0x2
|
||||
int 0x13
|
||||
|
||||
;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
|
||||
odd:
|
||||
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 boot
|
||||
mov ax, [sectorsize]
|
||||
mul word [clustersize]
|
||||
add word [pointer], ax
|
||||
jmp loadcluster
|
||||
|
||||
;Clear the stack and boot the system
|
||||
boot:
|
||||
;Clear
|
||||
pop cx
|
||||
pop bx
|
||||
;Boot
|
||||
jmp 0x0:0x500
|
||||
|
||||
;Data
|
||||
bootdrive db 0x0
|
||||
sysfile db "SYSTEM BIN"
|
||||
errormsg db "System not found", 0xd, 0xa, 0x0
|
||||
cluster dw 0x0
|
||||
pointer dw 0x500
|
||||
|
||||
;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 [bootdrive]
|
||||
ret
|
||||
|
||||
;Pad the binary to a full sector and make the disk bootable
|
||||
;Padding
|
||||
times 0x1fe-($-$$) db 0x0
|
||||
;Boot signature
|
||||
dw 0xaa55
|
||||
|
||||
;File system buffer
|
||||
buffer:
|
||||
CPU 8086
|
||||
ORG 0x7c00
|
||||
|
||||
jmp start
|
||||
nop
|
||||
|
||||
;Disk description tables
|
||||
|
||||
%ifdef F1440
|
||||
;1.44 MB 3.5" floppy disk (enable with the argument -d F1440 when building)
|
||||
oemlabel db "ETTINOS "
|
||||
sectorsize dw 0x200 ;bytes
|
||||
clustersize db 0x1 ;sectors
|
||||
bootsectors dw 0x1
|
||||
fats db 0x2
|
||||
rootentries dw 0xe0
|
||||
logicalsectors dw 0xb40
|
||||
mediadescriptor db 0xf0
|
||||
sectorsperfat dw 0x9
|
||||
sectorspertrack dw 0x12
|
||||
sides dw 0x2
|
||||
hiddensectors dd 0x0
|
||||
largesectors dd 0x0
|
||||
driveid dw 0x0
|
||||
drivesignature db 0x29
|
||||
volumeid dd 0x0
|
||||
volumelabel db "ETTINOS "
|
||||
filesystem db "FAT12 "
|
||||
|
||||
%else
|
||||
;360 KiB 5.25" floppy disk (default)
|
||||
oemlabel db "ETTINOS "
|
||||
sectorsize dw 0x200 ;bytes
|
||||
clustersize db 0x2 ;sectors
|
||||
bootsectors dw 0x1
|
||||
fats db 0x2
|
||||
rootentries dw 0x70
|
||||
logicalsectors dw 0x2d0
|
||||
mediadescriptor db 0xfd
|
||||
sectorsperfat dw 0x2
|
||||
sectorspertrack dw 0x9
|
||||
sides dw 0x2
|
||||
hiddensectors dd 0x0
|
||||
largesectors dd 0x0
|
||||
driveid dw 0x0
|
||||
drivesignature db 0x29
|
||||
volumeid dd 0x0
|
||||
volumelabel db "ETTINOS "
|
||||
filesystem db "FAT12 "
|
||||
|
||||
%endif
|
||||
|
||||
start:
|
||||
|
||||
;Setup
|
||||
;Set up the data, stack, and extra segments
|
||||
mov ax, 0x0
|
||||
mov ds, ax
|
||||
mov ss, ax
|
||||
mov es, ax
|
||||
;Set up the stack
|
||||
cli
|
||||
mov sp, 0x0
|
||||
sti
|
||||
;Store the boot drive number
|
||||
mov [bootdrive], dl
|
||||
|
||||
;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 system 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 system entry
|
||||
mov si, sysfile
|
||||
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
|
||||
|
||||
;Print an error message if the system is not found
|
||||
mov si, errormsg
|
||||
printerror:
|
||||
;Load a character
|
||||
lodsb
|
||||
;Check for the string end
|
||||
cmp al, 0x0
|
||||
je $
|
||||
;Print the character
|
||||
mov ah, 0xe
|
||||
int 0x10
|
||||
;Repeat
|
||||
jmp printerror
|
||||
|
||||
;Load the system 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 system 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
|
||||
call calcsource
|
||||
;Set the destination
|
||||
mov bx, word [pointer]
|
||||
;Set the size
|
||||
;mov al, 0x1
|
||||
mov al, [clustersize]
|
||||
;Load
|
||||
mov ah, 0x2
|
||||
int 0x13
|
||||
|
||||
;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
|
||||
odd:
|
||||
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 boot
|
||||
mov ax, [sectorsize]
|
||||
mul word [clustersize]
|
||||
add word [pointer], ax
|
||||
jmp loadcluster
|
||||
|
||||
;Clear the stack and boot the system
|
||||
boot:
|
||||
;Clear
|
||||
pop cx
|
||||
pop bx
|
||||
;Boot
|
||||
jmp 0x0:0x500
|
||||
|
||||
;Data
|
||||
bootdrive db 0x0
|
||||
sysfile db "SYSTEM BIN"
|
||||
errormsg db "System not found", 0xd, 0xa, 0x0
|
||||
cluster dw 0x0
|
||||
pointer dw 0x500
|
||||
|
||||
;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 [bootdrive]
|
||||
ret
|
||||
|
||||
;Pad the binary to a full sector and make the disk bootable
|
||||
;Padding
|
||||
times 0x1fe-($-$$) db 0x0
|
||||
;Boot signature
|
||||
dw 0xaa55
|
||||
|
||||
;File system buffer
|
||||
buffer:
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
CPU 8086
|
||||
ORG 0x2000
|
||||
|
||||
;Prints a hello world.
|
||||
mov si, .hello
|
||||
mov ah, 0x2
|
||||
int 0x21
|
||||
int 0x20
|
||||
|
||||
;Data
|
||||
.hello db "Hello world!", 0x0
|
||||
CPU 8086
|
||||
ORG 0x2000
|
||||
|
||||
;Prints a hello world.
|
||||
mov si, .hello
|
||||
mov ah, 0x2
|
||||
int 0x21
|
||||
int 0x20
|
||||
|
||||
;Data
|
||||
.hello db "Hello world!", 0x0
|
||||
|
|
608
src/LOADF.INC
608
src/LOADF.INC
|
@ -1,304 +1,304 @@
|
|||
;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 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 and print an error message if the file name is invalid
|
||||
.error:
|
||||
pop ax
|
||||
stc
|
||||
mov si, .errormsg
|
||||
mov ah, 0x2
|
||||
int 0x21
|
||||
jmp .done
|
||||
|
||||
;Find and load the file
|
||||
|
||||
.load:
|
||||
pop 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 and print an error message if the file is not found
|
||||
stc
|
||||
mov si, .errormsg
|
||||
mov ah, 0x2
|
||||
int 0x21
|
||||
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
|
||||
call .calcsource
|
||||
;Set the destination
|
||||
mov bx, word [.pointer]
|
||||
;Set the size
|
||||
;mov al, 0x1
|
||||
mov al, [.clustersize]
|
||||
;Load
|
||||
mov ah, 0x2
|
||||
int 0x13
|
||||
|
||||
;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
|
||||
.file times 0xb db 0x20
|
||||
.errormsg db "File not found", 0x0
|
||||
.cluster dw 0x0
|
||||
.pointer dw 0x0
|
||||
|
||||
;These are temporary until i write something to load them from the disk itself
|
||||
.bootdrive db 0x0
|
||||
.sectorsize dw 0x200 ;bytes
|
||||
.clustersize db 0x2 ;sectors
|
||||
.bootsectors dw 0x1
|
||||
.fats db 0x2
|
||||
.rootentries dw 0x70
|
||||
.sectorsperfat dw 0x2
|
||||
.sectorspertrack dw 0x9
|
||||
.sides dw 0x2
|
||||
|
||||
;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
|
||||
;Increase 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 [.bootdrive]
|
||||
ret
|
||||
;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 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 and print an error message if the file name is invalid
|
||||
.error:
|
||||
pop ax
|
||||
stc
|
||||
mov si, .errormsg
|
||||
mov ah, 0x2
|
||||
int 0x21
|
||||
jmp .done
|
||||
|
||||
;Find and load the file
|
||||
|
||||
.load:
|
||||
pop 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 and print an error message if the file is not found
|
||||
stc
|
||||
mov si, .errormsg
|
||||
mov ah, 0x2
|
||||
int 0x21
|
||||
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
|
||||
call .calcsource
|
||||
;Set the destination
|
||||
mov bx, word [.pointer]
|
||||
;Set the size
|
||||
;mov al, 0x1
|
||||
mov al, [.clustersize]
|
||||
;Load
|
||||
mov ah, 0x2
|
||||
int 0x13
|
||||
|
||||
;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
|
||||
.file times 0xb db 0x20
|
||||
.errormsg db "File not found", 0x0
|
||||
.cluster dw 0x0
|
||||
.pointer dw 0x0
|
||||
|
||||
;These are temporary until i write something to load them from the disk itself
|
||||
.bootdrive db 0x0
|
||||
.sectorsize dw 0x200 ;bytes
|
||||
.clustersize db 0x2 ;sectors
|
||||
.bootsectors dw 0x1
|
||||
.fats db 0x2
|
||||
.rootentries dw 0x70
|
||||
.sectorsperfat dw 0x2
|
||||
.sectorspertrack dw 0x9
|
||||
.sides dw 0x2
|
||||
|
||||
;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
|
||||
;Increase 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 [.bootdrive]
|
||||
ret
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
;Print a string ending in a null from SI followed by a CRLF.
|
||||
|
||||
println:
|
||||
|
||||
;Print the string
|
||||
mov ah, 0x0
|
||||
int 0x21
|
||||
|
||||
;Print a CRLF
|
||||
call printcrlf
|
||||
|
||||
iret
|
||||
;Print a string ending in a null from SI followed by a CRLF.
|
||||
|
||||
println:
|
||||
|
||||
;Print the string
|
||||
mov ah, 0x0
|
||||
int 0x21
|
||||
|
||||
;Print a CRLF
|
||||
call printcrlf
|
||||
|
||||
iret
|
||||
|
|
|
@ -1,28 +1,28 @@
|
|||
;Print a string ending in a null from SI.
|
||||
|
||||
printstr:
|
||||
|
||||
;Store the initial registers in the stack
|
||||
push ax
|
||||
push si
|
||||
|
||||
;Print the string
|
||||
.loop:
|
||||
;Load the current character
|
||||
lodsb
|
||||
;Check for the string end
|
||||
cmp al, 0x0
|
||||
je .done
|
||||
;Print the character
|
||||
mov ah, 0xe
|
||||
int 0x10
|
||||
;Repeat for the next character
|
||||
jmp .loop
|
||||
|
||||
.done:
|
||||
|
||||
;Load the initial registers from the stack
|
||||
pop si
|
||||
pop ax
|
||||
|
||||
iret
|
||||
;Print a string ending in a null from SI.
|
||||
|
||||
printstr:
|
||||
|
||||
;Store the initial registers in the stack
|
||||
push ax
|
||||
push si
|
||||
|
||||
;Print the string
|
||||
.loop:
|
||||
;Load the current character
|
||||
lodsb
|
||||
;Check for the string end
|
||||
cmp al, 0x0
|
||||
je .done
|
||||
;Print the character
|
||||
mov ah, 0xe
|
||||
int 0x10
|
||||
;Repeat for the next character
|
||||
jmp .loop
|
||||
|
||||
.done:
|
||||
|
||||
;Load the initial registers from the stack
|
||||
pop si
|
||||
pop ax
|
||||
|
||||
iret
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
;Read a string ending in null of at most AL characters to DI until a return and print a CRLF.
|
||||
|
||||
readln:
|
||||
|
||||
;Read the string
|
||||
mov ah, 0x1
|
||||
int 0x21
|
||||
|
||||
;Print a CRLF
|
||||
call printcrlf
|
||||
|
||||
iret
|
||||
;Read a string ending in null of at most AL characters to DI until a return and print a CRLF.
|
||||
|
||||
readln:
|
||||
|
||||
;Read the string
|
||||
mov ah, 0x1
|
||||
int 0x21
|
||||
|
||||
;Print a CRLF
|
||||
call printcrlf
|
||||
|
||||
iret
|
||||
|
|
408
src/READSTR.INC
408
src/READSTR.INC
|
@ -1,204 +1,204 @@
|
|||
;Read a string ending in a null of at most AL characters to DI until a return.
|
||||
|
||||
readstr:
|
||||
|
||||
;Store the initial registers in the stack
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
|
||||
;Setup
|
||||
;Store the input length in the stack
|
||||
mov ah, 0
|
||||
push ax
|
||||
;Initialise the destination with spaces
|
||||
mov cx, ax
|
||||
mov al, 0x20
|
||||
rep stosb
|
||||
pop ax
|
||||
push ax
|
||||
sub di, ax
|
||||
;Initialise the cursor pointer in BL and clear BH
|
||||
mov bx, 0x1
|
||||
|
||||
.loop:
|
||||
|
||||
;Read a keypress
|
||||
mov ah, 0x0
|
||||
int 0x16
|
||||
|
||||
;Check for special keys and non-printing characters
|
||||
;Check for return
|
||||
cmp al, 0xd
|
||||
je .return
|
||||
;Check for backspace
|
||||
cmp al, 0x8
|
||||
je .backspace
|
||||
;Check for input end
|
||||
pop dx
|
||||
push dx
|
||||
cmp bl, dl
|
||||
je .loop
|
||||
;Check for space
|
||||
cmp al, 0x20
|
||||
je .space
|
||||
;Check for erase
|
||||
cmp al, 0x9
|
||||
je .erase
|
||||
;Check for non-printing characters
|
||||
cmp al, 0x1f
|
||||
jle .loop
|
||||
cmp al, 0x7f
|
||||
je .loop
|
||||
|
||||
;Store and print a character
|
||||
.character:
|
||||
;Store the character
|
||||
stosb
|
||||
;Print the character
|
||||
mov ah, 0xe
|
||||
int 0x10
|
||||
;Move the cursor pointer
|
||||
inc bl
|
||||
jmp .loop
|
||||
|
||||
;Replace the cursor position with a space
|
||||
.erase:
|
||||
mov al, 0x20
|
||||
jmp .character
|
||||
|
||||
;Move the cursor forward
|
||||
.space:
|
||||
call .nextchar
|
||||
inc di
|
||||
inc bl
|
||||
jmp .loop
|
||||
|
||||
;Move the cursor backward
|
||||
.backspace:
|
||||
;Check for the input beginning
|
||||
cmp bl, 0x1
|
||||
je .loop
|
||||
;Move the cursor
|
||||
call .prevchar
|
||||
dec di
|
||||
dec bl
|
||||
jmp .loop
|
||||
|
||||
;Finish reading the string
|
||||
.return:
|
||||
|
||||
;Find and remove trailing spaces
|
||||
;Go to the end of the input
|
||||
pop ax
|
||||
mov bh, 0x0
|
||||
sub ax, bx
|
||||
push di
|
||||
add di, ax
|
||||
.findtrailing:
|
||||
;Check for a trailing space
|
||||
cmp byte [di], 0x20
|
||||
je .deltrailing
|
||||
jmp .end
|
||||
.deltrailing:
|
||||
;Delete a trailing space
|
||||
mov al, 0x0
|
||||
stosb
|
||||
sub di, 0x2
|
||||
jmp .findtrailing
|
||||
|
||||
;Move the cursor to the end of the input string
|
||||
.end:
|
||||
pop di
|
||||
.findend:
|
||||
cmp byte [di], 0x0
|
||||
jne .notend
|
||||
jmp .done
|
||||
.notend:
|
||||
call .nextchar
|
||||
inc di
|
||||
inc bl
|
||||
jmp .findend
|
||||
|
||||
.done:
|
||||
|
||||
;Load the initial registers from the stack
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
|
||||
iret
|
||||
|
||||
;Move the cursor forward
|
||||
|
||||
;Move forward within a line
|
||||
.nextchar:
|
||||
;Get the cursor position
|
||||
mov ah, 0x3
|
||||
int 0x10
|
||||
;Check for the end of the line
|
||||
cmp dl, 0x4f
|
||||
je .nextln
|
||||
;Move
|
||||
inc dl
|
||||
mov ah, 0x2
|
||||
int 0x10
|
||||
ret
|
||||
|
||||
;Move to the beginning of the next line
|
||||
.nextln:
|
||||
;Check if the current line is the last on screen
|
||||
cmp dh, 0x18
|
||||
je .scroll
|
||||
;Move
|
||||
mov ah, 0x2
|
||||
inc dh
|
||||
mov dl, 0x0
|
||||
int 0x10
|
||||
ret
|
||||
|
||||
;Scroll the screen up by one line
|
||||
.scroll:
|
||||
;Scroll
|
||||
mov ah, 0x6
|
||||
mov al, 0x1
|
||||
mov bh, 0x7
|
||||
mov ch, 0x0
|
||||
mov cl, 0x0
|
||||
mov dh, 0x18
|
||||
mov dl, 0x4f
|
||||
int 0x10
|
||||
;Move to the beginning of the new line
|
||||
mov ah, 0x2
|
||||
mov bh, 0x0
|
||||
mov dl, 0x0
|
||||
int 0x10
|
||||
ret
|
||||
|
||||
;Move the cursor backward
|
||||
|
||||
;Move backward within a line
|
||||
.prevchar:
|
||||
;Get the cursor position
|
||||
mov ah, 0x3
|
||||
int 0x10
|
||||
;Check for the beginning of the line
|
||||
cmp dl, 0x0
|
||||
je .prevln
|
||||
;Move
|
||||
dec dl
|
||||
mov ah, 0x2
|
||||
int 0x10
|
||||
ret
|
||||
|
||||
;Move to the end of the previous line
|
||||
.prevln:
|
||||
mov ah, 0x2
|
||||
dec dh
|
||||
mov dl, 0x4f
|
||||
int 0x10
|
||||
ret
|
||||
;Read a string ending in a null of at most AL characters to DI until a return.
|
||||
|
||||
readstr:
|
||||
|
||||
;Store the initial registers in the stack
|
||||
push ax
|
||||
push bx
|
||||
push cx
|
||||
push dx
|
||||
push di
|
||||
|
||||
;Setup
|
||||
;Store the input length in the stack
|
||||
mov ah, 0
|
||||
push ax
|
||||
;Initialise the destination with spaces
|
||||
mov cx, ax
|
||||
mov al, 0x20
|
||||
rep stosb
|
||||
pop ax
|
||||
push ax
|
||||
sub di, ax
|
||||
;Initialise the cursor pointer in BL and clear BH
|
||||
mov bx, 0x1
|
||||
|
||||
.loop:
|
||||
|
||||
;Read a keypress
|
||||
mov ah, 0x0
|
||||
int 0x16
|
||||
|
||||
;Check for special keys and non-printing characters
|
||||
;Check for return
|
||||
cmp al, 0xd
|
||||
je .return
|
||||
;Check for backspace
|
||||
cmp al, 0x8
|
||||
je .backspace
|
||||
;Check for input end
|
||||
pop dx
|
||||
push dx
|
||||
cmp bl, dl
|
||||
je .loop
|
||||
;Check for space
|
||||
cmp al, 0x20
|
||||
je .space
|
||||
;Check for erase
|
||||
cmp al, 0x9
|
||||
je .erase
|
||||
;Check for non-printing characters
|
||||
cmp al, 0x1f
|
||||
jle .loop
|
||||
cmp al, 0x7f
|
||||
je .loop
|
||||
|
||||
;Store and print a character
|
||||
.character:
|
||||
;Store the character
|
||||
stosb
|
||||
;Print the character
|
||||
mov ah, 0xe
|
||||
int 0x10
|
||||
;Move the cursor pointer
|
||||
inc bl
|
||||
jmp .loop
|
||||
|
||||
;Replace the cursor position with a space
|
||||
.erase:
|
||||
mov al, 0x20
|
||||
jmp .character
|
||||
|
||||
;Move the cursor forward
|
||||
.space:
|
||||
call .nextchar
|
||||
inc di
|
||||
inc bl
|
||||
jmp .loop
|
||||
|
||||
;Move the cursor backward
|
||||
.backspace:
|
||||
;Check for the input beginning
|
||||
cmp bl, 0x1
|
||||
je .loop
|
||||
;Move the cursor
|
||||
call .prevchar
|
||||
dec di
|
||||
dec bl
|
||||
jmp .loop
|
||||
|
||||
;Finish reading the string
|
||||
.return:
|
||||
|
||||
;Find and remove trailing spaces
|
||||
;Go to the end of the input
|
||||
pop ax
|
||||
mov bh, 0x0
|
||||
sub ax, bx
|
||||
push di
|
||||
add di, ax
|
||||
.findtrailing:
|
||||
;Check for a trailing space
|
||||
cmp byte [di], 0x20
|
||||
je .deltrailing
|
||||
jmp .end
|
||||
.deltrailing:
|
||||
;Delete a trailing space
|
||||
mov al, 0x0
|
||||
stosb
|
||||
sub di, 0x2
|
||||
jmp .findtrailing
|
||||
|
||||
;Move the cursor to the end of the input string
|
||||
.end:
|
||||
pop di
|
||||
.findend:
|
||||
cmp byte [di], 0x0
|
||||
jne .notend
|
||||
jmp .done
|
||||
.notend:
|
||||
call .nextchar
|
||||
inc di
|
||||
inc bl
|
||||
jmp .findend
|
||||
|
||||
.done:
|
||||
|
||||
;Load the initial registers from the stack
|
||||
pop di
|
||||
pop dx
|
||||
pop cx
|
||||
pop bx
|
||||
pop ax
|
||||
|
||||
iret
|
||||
|
||||
;Move the cursor forward
|
||||
|
||||
;Move forward within a line
|
||||
.nextchar:
|
||||
;Get the cursor position
|
||||
mov ah, 0x3
|
||||
int 0x10
|
||||
;Check for the end of the line
|
||||
cmp dl, 0x4f
|
||||
je .nextln
|
||||
;Move
|
||||
inc dl
|
||||
mov ah, 0x2
|
||||
int 0x10
|
||||
ret
|
||||
|
||||
;Move to the beginning of the next line
|
||||
.nextln:
|
||||
;Check if the current line is the last on screen
|
||||
cmp dh, 0x18
|
||||
je .scroll
|
||||
;Move
|
||||
mov ah, 0x2
|
||||
inc dh
|
||||
mov dl, 0x0
|
||||
int 0x10
|
||||
ret
|
||||
|
||||
;Scroll the screen up by one line
|
||||
.scroll:
|
||||
;Scroll
|
||||
mov ah, 0x6
|
||||
mov al, 0x1
|
||||
mov bh, 0x7
|
||||
mov ch, 0x0
|
||||
mov cl, 0x0
|
||||
mov dh, 0x18
|
||||
mov dl, 0x4f
|
||||
int 0x10
|
||||
;Move to the beginning of the new line
|
||||
mov ah, 0x2
|
||||
mov bh, 0x0
|
||||
mov dl, 0x0
|
||||
int 0x10
|
||||
ret
|
||||
|
||||
;Move the cursor backward
|
||||
|
||||
;Move backward within a line
|
||||
.prevchar:
|
||||
;Get the cursor position
|
||||
mov ah, 0x3
|
||||
int 0x10
|
||||
;Check for the beginning of the line
|
||||
cmp dl, 0x0
|
||||
je .prevln
|
||||
;Move
|
||||
dec dl
|
||||
mov ah, 0x2
|
||||
int 0x10
|
||||
ret
|
||||
|
||||
;Move to the end of the previous line
|
||||
.prevln:
|
||||
mov ah, 0x2
|
||||
dec dh
|
||||
mov dl, 0x4f
|
||||
int 0x10
|
||||
ret
|
||||
|
|
248
src/SYSTEM.ASM
248
src/SYSTEM.ASM
|
@ -1,124 +1,124 @@
|
|||
CPU 8086
|
||||
ORG 0x500
|
||||
|
||||
jmp start
|
||||
|
||||
;Interrupt handler
|
||||
;Return to the shell
|
||||
int0x20:
|
||||
jmp shell
|
||||
;Input and output
|
||||
int0x21:
|
||||
cmp ah, 0x0
|
||||
je printstr
|
||||
cmp ah, 0x1
|
||||
je readstr
|
||||
cmp ah, 0x2
|
||||
je println
|
||||
cmp ah, 0x3
|
||||
je readln
|
||||
iret
|
||||
;Disk operations
|
||||
int0x22:
|
||||
cmp ah, 0x0
|
||||
je loadf
|
||||
;To do: savef
|
||||
iret
|
||||
|
||||
;System calls
|
||||
%include "PRINTSTR.INC"
|
||||
%include "READSTR.INC"
|
||||
%include "PRINTLN.INC"
|
||||
%include "READLN.INC"
|
||||
%include "LOADF.INC"
|
||||
|
||||
start:
|
||||
|
||||
;Set up the interrupt vectors
|
||||
;Interrupt 0x20 offset
|
||||
mov ax, int0x20
|
||||
mov [0x80], ax
|
||||
;Interrupt 0x21 offset
|
||||
mov ax, int0x21
|
||||
mov [0x84], ax
|
||||
;Interrupt 0x22 offset
|
||||
mov ax, int0x22
|
||||
mov [0x88], ax
|
||||
;Segments
|
||||
mov ax, 0x0
|
||||
mov [0x82], ax
|
||||
mov [0x86], ax
|
||||
mov [0x8a], ax
|
||||
|
||||
;Print a welcome message
|
||||
mov si, welcomemsg
|
||||
mov ah, 0x2
|
||||
int 0x21
|
||||
|
||||
shell:
|
||||
|
||||
;Re-set the stack
|
||||
cli
|
||||
mov sp, 0x0
|
||||
sti
|
||||
|
||||
;Prompt for and read a command
|
||||
;Print a prompt
|
||||
mov si, prompt
|
||||
mov ah, 0x0
|
||||
int 0x21
|
||||
;Read
|
||||
mov di, input
|
||||
mov al, 0x4e
|
||||
mov ah, 0x3
|
||||
int 0x21
|
||||
|
||||
;Load an execute the program
|
||||
;Check for an empty command
|
||||
cmp byte [input], 0x0
|
||||
jz shell
|
||||
;Load
|
||||
mov bx, 0x2000
|
||||
mov si, input
|
||||
mov ah, 0x0
|
||||
int 0x22
|
||||
;Check for errors
|
||||
cmp al, 0x1
|
||||
je error
|
||||
;Execute
|
||||
jmp 0x2000
|
||||
|
||||
;Print an error message and return to the shell
|
||||
error:
|
||||
mov bh, 0x0
|
||||
mov ah, 0x3
|
||||
int 0x10
|
||||
dec dh
|
||||
mov ah, 0x2
|
||||
int 0x10
|
||||
mov si, errormsg
|
||||
mov ah, 0x2
|
||||
int 0x21
|
||||
jmp shell
|
||||
|
||||
;Data
|
||||
welcomemsg db 0xd, 0xa, "Welcome to EttinOS!", 0xd, 0xa, 0x0
|
||||
prompt db "> ", 0x0
|
||||
errormsg db "Unknown command", 0x0
|
||||
input times 0x4e db 0x0
|
||||
crlf db 0xd, 0xa, 0x0
|
||||
|
||||
;Print a CRLF
|
||||
printcrlf:
|
||||
;Store the initial registers in the stack
|
||||
push si
|
||||
;Print the CRLF
|
||||
mov si, crlf
|
||||
mov ah, 0x0
|
||||
int 0x21
|
||||
;Load the initial registers from the stack
|
||||
pop si
|
||||
ret
|
||||
|
||||
;File system buffer
|
||||
buffer:
|
||||
CPU 8086
|
||||
ORG 0x500
|
||||
|
||||
jmp start
|
||||
|
||||
;Interrupt handler
|
||||
;Return to the shell
|
||||
int0x20:
|
||||
jmp shell
|
||||
;Input and output
|
||||
int0x21:
|
||||
cmp ah, 0x0
|
||||
je printstr
|
||||
cmp ah, 0x1
|
||||
je readstr
|
||||
cmp ah, 0x2
|
||||
je println
|
||||
cmp ah, 0x3
|
||||
je readln
|
||||
iret
|
||||
;Disk operations
|
||||
int0x22:
|
||||
cmp ah, 0x0
|
||||
je loadf
|
||||
;To do: savef
|
||||
iret
|
||||
|
||||
;System calls
|
||||
%include "PRINTSTR.INC"
|
||||
%include "READSTR.INC"
|
||||
%include "PRINTLN.INC"
|
||||
%include "READLN.INC"
|
||||
%include "LOADF.INC"
|
||||
|
||||
start:
|
||||
|
||||
;Set up the interrupt vectors
|
||||
;Interrupt 0x20 offset
|
||||
mov ax, int0x20
|
||||
mov [0x80], ax
|
||||
;Interrupt 0x21 offset
|
||||
mov ax, int0x21
|
||||
mov [0x84], ax
|
||||
;Interrupt 0x22 offset
|
||||
mov ax, int0x22
|
||||
mov [0x88], ax
|
||||
;Segments
|
||||
mov ax, 0x0
|
||||
mov [0x82], ax
|
||||
mov [0x86], ax
|
||||
mov [0x8a], ax
|
||||
|
||||
;Print a welcome message
|
||||
mov si, welcomemsg
|
||||
mov ah, 0x2
|
||||
int 0x21
|
||||
|
||||
shell:
|
||||
|
||||
;Re-set the stack
|
||||
cli
|
||||
mov sp, 0x0
|
||||
sti
|
||||
|
||||
;Prompt for and read a command
|
||||
;Print a prompt
|
||||
mov si, prompt
|
||||
mov ah, 0x0
|
||||
int 0x21
|
||||
;Read
|
||||
mov di, input
|
||||
mov al, 0x4e
|
||||
mov ah, 0x3
|
||||
int 0x21
|
||||
|
||||
;Load an execute the program
|
||||
;Check for an empty command
|
||||
cmp byte [input], 0x0
|
||||
jz shell
|
||||
;Load
|
||||
mov bx, 0x2000
|
||||
mov si, input
|
||||
mov ah, 0x0
|
||||
int 0x22
|
||||
;Check for errors
|
||||
cmp al, 0x1
|
||||
je error
|
||||
;Execute
|
||||
jmp 0x2000
|
||||
|
||||
;Print an error message and return to the shell
|
||||
error:
|
||||
mov bh, 0x0
|
||||
mov ah, 0x3
|
||||
int 0x10
|
||||
dec dh
|
||||
mov ah, 0x2
|
||||
int 0x10
|
||||
mov si, errormsg
|
||||
mov ah, 0x2
|
||||
int 0x21
|
||||
jmp shell
|
||||
|
||||
;Data
|
||||
welcomemsg db 0xd, 0xa, "Welcome to EttinOS!", 0xd, 0xa, 0x0
|
||||
prompt db "> ", 0x0
|
||||
errormsg db "Unknown command", 0x0
|
||||
input times 0x4e db 0x0
|
||||
crlf db 0xd, 0xa, 0x0
|
||||
|
||||
;Print a CRLF
|
||||
printcrlf:
|
||||
;Store the initial registers in the stack
|
||||
push si
|
||||
;Print the CRLF
|
||||
mov si, crlf
|
||||
mov ah, 0x0
|
||||
int 0x21
|
||||
;Load the initial registers from the stack
|
||||
pop si
|
||||
ret
|
||||
|
||||
;File system buffer
|
||||
buffer:
|
||||
|
|
Loading…
Reference in New Issue