Title
-Intro
-File Table
-Function Table
-Basic $AX Program
-Correct $AX Program
-boot_start
-start
-print_string
-read_file
-write_file
-disk_manage
-get_key_press
-get_string_and_print
-string_compare
-error
-find_file
-write_allocation_table
-print_char
-remove_file
-Bugs
|
Programmer Guide
Intro
File Table
The file table consists of 12 sectors and points to 1440 positions on the disk, each corresponding to a seperate file or program or 512 bytes. It is not advised but if greater amounts of space are required multiple files can be stringed together with the same filename. (This does make the task of deleteing such files much more difficult). Each filename is 4 characters long. A filename with just zeros indicate a free space. Filenames shouldn't contain spaces at the begginning but may contain spaces elsewhere in the filename. Spaces don not appear different from zeros in the ls program and may cause confusion when trying to run or load any programs or files.
Function Table
Below is the function table that all the code example below will refer to with ... Function table here. If you want to make sure you have all of the functions available from the kernel, make sure that you check the newest released kernel for the most up-to-date list. The syntax functon_name equ 0123h basically means that you don't have to call or jump to 0123h. It makes a meaningful name equal to that number making your program code more meaningful also. Please note that this table takes up no space and only increases readability in your code.
; ------------------------------
; ## FUNCTION CALLS ##
boot_start equ 0000h ; Generally not used, completely restarts the OS
start equ 0003h ; Generally not used, allows user to start a program one layer down
print_string equ 0006h ; Prints a zero terminated string to the screen
read_file equ 0009h ; Allows user to load a program from disk to RAM using a filename
write_file equ 000Ch ; Allows user to load a program from RAM to disk using a filename
disk_manage equ 000Fh ; Allows for custom use of the disk - USE WITH CARE!
get_key_press equ 0012h ; Waits for the user to press a key and returns it
get_string_and_print equ 0015h ; Gets a string of maximum length from the user and returns it
string_compare equ 0018h ; Compares two strings and tells the user if they are equal
error equ 001Bh ; Prints an OS error to the screen. If jumped to this will also exit the user from the program
find_file equ 001Eh ; Searches for a file in the file table and returns whether it was found or not
write_allocation_table equ 0021h ; Places a filename in a position that corresponds to a given sector
print_char equ 0024h ; Prints a single character to the screen
remove_file equ 0027h ; Allows for a given filename to deleted from the file allocation table. Note the contents remain until over-written
|
Basic $AX Program
Below is an example of one of the most basic $AX programs. This program will run but breaks the current $AX program format.
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
main_program:
ret ; Return to OS
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
|
Breakdown of Code
BITS 16 ; Program MUST be set to 16 bits
|
This tells the compiler that we want 16 bit binary output. As the $AX OS is currently 16 bit, 32 bit code will not work without major modification.
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
|
This tells the compiler that we want all of our code to be compiled relative to this RAM offset. If this is removed, the offset is automativally set to zero. This can make for some interesting but unwanted results.
Please refer to 'Function table' for information on how this works.
This is a label. In this case it isn't needed, but is useful for a point of refference so others looking at your code can jump straight to where the interesting stuff is happening. Usually, the main 'loop' of your program will be here. This will call (or jump) to other parts of your code and always return here as a general rule of thumb.
This is the end of the executed program. When your program has finished, a simple return will return back to the OS.
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
|
This pads the rest of your code with zeros so that it is a sector.
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
|
The signature is usually used for a bootsector, and indicates that it is executable. In this case, it also indicates to the kernel that a file loaded into program space is executable or not.
Correct $AX Program
Below is a better example of a $AX program.
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
; ------------------------------
; ## PARAM CODE ##
main:
add si, length_of_name + 1 ; Gives the program the position to start searching for parameters
.param:
cmp byte [si], '-' ; Check for a dash as an indication there may be parameters
jne main_program ; If no dash, run program normally
inc si ; Check next position for parameter letter
.test:
cmp byte [si], 'h' ; Check for 'h' - meaning help
je print_help ; If 'h' found print help
cmp byte [si], 'v' ; Check for 'v' - meaning version
je print_version ; If 'v' found print the version
jmp error ; If no correct parameter was found jump to error and exit program
; ------------------------------
; ## MAIN CODE ##
main_program: ; If the parameters have been sorted out, start running our program
ret ; We are finnished, return to the OS
; ------------------------------
; ## PARAM CALLS ##
print_help:
mov si, help
call print_string ; Print help
ret ; We are finnished, return to the OS
print_version:
mov si, version
call print_string ; Print the version
ret ; We are finnished, return to the OS
; ------------------------------
; ## VARIABLES ##
version db 10, 13, 'ver 0', 0 ; It's important to keep your version up to date for everybody else!
help db 10, 13, 'Very small desciption of how to use your program.'
help2 db 10, 13, 'eg. edit [file]'
help3 db 10, 13, '-h Help'
help4 db 10, 13, '-v Version', 0 ; Note how it's only zero terminated at the end
length_of_name equ 4 ; The length of the Filename
; ## SIGNATURE ##
times 510-($-$$)db 0 ; Pad remainder of boot sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
file: ; If we were to load another file as part of the program, this is where we would load it
|
Breakdown of Code
The most noteable difference is the use of parameters. This allows for information to be passed from the OS prompt to the program itself.
BITS 16 ; Program MUST be set to 16 bits
|
This tells the compiler that we want 16 bit binary output. As the $AX OS is currently 16 bit, 32 bit code will not work without major modification.
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
|
This tells the compiler that we want all of our code to be compiled relative to this RAM offset. If this is removed, the offset is automativally set to zero. This can make for some interesting but unwanted results.
Please refer to 'Function table' for information on how this works.
; ------------------------------
; ## PARAM CODE ##
main:
add si, length_of_name + 1 ; Gives the program the position to start searching for parameters
.param:
cmp byte [si], '-' ; Check for a dash as an indication there may be parameters
jne main_program ; If no dash, run program normally
inc si ; Check next position for parameter letter
.test:
cmp byte [si], 'h' ; Check for 'h' - meaning help
je print_help ; If 'h' found print help
cmp byte [si], 'v' ; Check for 'v' - meaning version
je print_version ; If 'v' found print the version
jmp error ; If no correct parameter was found jump to error and exit program
|
Basically, all this does is checks if the user added additional parameters when running the program. If they did, print the information they requested. If not, continue to the main_program.
; ------------------------------
; ## MAIN CODE ##
main_program:
|
This is a label. In this case it isn't needed, but is useful for a point of refference so others looking at your code can jump straight to where the interesting stuff is happening. Usually, the main 'loop' of your program will be here. This will call (or jump) to other parts of your code and always return here as a general rule of thumb. The only real difference between this and one program above is the use of comments to make it stand out more.
This is the end of the executed program. When your program has finished, a simple return will return back to the OS.
; ------------------------------
; ## PARAM CALLS ##
print_help:
mov si, help
call print_string ; Print help
ret ; We are finnished, return to the OS
print_version:
mov si, version
call print_string ; Print the version
ret ; We are finnished, return to the OS
|
This code just ensures that the requested information is printed.
; ------------------------------
; ## VARIABLES ##
version db 10, 13, 'ver 0', 0 ; It's important to keep your version up to date for everybody else!
help db 10, 13, 'Very small desciption of how to use your program.'
help2 db 10, 13, 'eg. edit [file]'
help3 db 10, 13, '-h Help'
help4 db 10, 13, '-v Version', 0 ; Note how it's only zero terminated at the end
length_of_name equ 4 ; The length of the Filename
|
This is where the variables are generally kept. Please not that it is your responsibility to keep the version up to date and Make sure that the help actually provides basic direction on how to use your program.
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
|
This pads the rest of your code with zeros so that it is a sector.
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
|
The signature is usually used for a bootsector, and indicates that it is executable. In this case, it also indicates to the kernel that a file loaded into program space is executable or not.
boot_start
Summary
Generally not used, completely restarts the OS.
In
-
Out
-
Used
All
Detailed Explanation
This function exists simply for the fact that it is needed in order to skip over the other jumps available and start the OS. It is not advised to use this function as a reboot does everything this function does and clears the program space RAM.
Example of Use
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
main_program:
call boot_start
ret ; Return to OS
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
|
|
start
Summary
Generally not used, allows user to start a program one layer down.
In
-
Out
-
Used
All
Detailed Explanation
This function is slightly more useful than boot_start as it offers the opportunity for the text mode to be reset, the OS's prompt to be displayed and the file table to be reloaded. Be careful about running this from a program as programs are called, meaning the position is stored on the stack. Using this in a program could potentially lead to a stack overflow. A much better way of achieving similar results is to simply use ret, where the OS deals with everything for you.
Example of Use
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
main_program:
call start
ret ; Return to OS
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
|
|
print_string
Summary
Prints a zero terminated string to the screen.
In
SI : Position of the string
Out
-
Used
SI
Detailed Explanation
The print_string function is one of the most effective ways to display output to the user in the $AX OS. Being very simple to use and not effecting any registers other than SI this function proves to be a useful debugging tool. As long as a string is ended with a zero it will be printed. Something to note is the fact that the function prints the zero it's terminated with. In most cases this isn't visible but it's something to keep in mind when designing your program.
Example of Use
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
main_program:
mov si, message ; Move the location of our message into SI
call print_string
ret ; Return to OS
message db 10, 13, 'Hello World!', 0 ; The 10 and 13 makes a new line
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
|
|
read_file
Summary
Allows user to load a program from disk to RAM using a filename.
In
BX : Position of the string containg the filename to read
SI : Position to load the file
Out
-
Used
All
Detailed Explanation
This function reads a file selected by a given name into a given space. Most programs will be loaded into program space at 1C00h (7168), with files other than the loaded program likely being higher than this number as not to overwrite any system space in RAM. If a file is not found, the function outputs a double explanation mark to the side of the screen (!!). There currently isn't any offical way of knowing if a file was correctly loaded. A method that can be used is placing something where it's going to be loaded and checking whether the data placed is still there once loaded. In most programs it will be obvious that the file wasn't correctly loaded.
Example of Use
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
main_program:
mov bx, filename ; Load the filename
mov si, file ; Point to space after program
call read_file
ret ; Return to OS
filename db 'test'
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
file:
|
|
write_file
Summary
Allows user to load a program from RAM to disk using a filename.
In
BX : Position of the string containg the filename to read
SI : Position of file to write
Out
-
Used
All
Detailed Explanation
This function writes a file from RAM (determined by SI) to a given filename (determined by BX). Please note the fact that if the a file exists, it will be overwritten and if it does not then it will be created. If your program requires the knowledge of whether it exists prior to writing it then use find_file. If there is a need to know whether the file was written, your program could load the file in a different position and perform a comparison. The only known point at which this function can fail is if there is no space on the disk or there is no disk. If there is no disk there will be no warning. If there is no space an error to the left hand side of the screen will be printed (!!).
Example of Use
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
main_program:
mov bx, filename ; Load the filename
mov si, file ; Point to space after program
call write_file
ret ; Return to OS
filename db 'test'
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
file:
|
|
disk_manage
Summary
Allows for custom use of the disk - USE WITH CARE!
In
AL : Number of sectors to edit [1 to 18]
AH : Mode to perform disk Operation [Write=03h Read=02h]
CX : Sector to perform disk operation [0 to 1439]
SI : Position to read to or write from [0 to 1439]
Out
-
Used
All
Detailed Explanation
This function allows for a custom number of sectors to be read or written at any place on the disk. The file table is not updated. This function can be extremely dangerous. If you are able to use another function then please do. The reason disk_manage has been left open for programs to use if for potential file recovery programs or efficent disk wiping. The kernel uses this function to load the 12 sector file table from the disk at kernel first load.
Example of Use
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
main_program:
mov al, 12 ; Load 12 sectors
mov ah, 02h ; Read sectors from disk
mov cx, 2 ; Where to read the sectors from
mov si, file ; Where to read the sectors from
call disk_manage
ret ; Return to OS
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
file:
|
|
get_key_press
Summary
Waits for the user to press a key and returns it.
In
-
Out
AX : Details about key press [AL=Character AH=Attribute]
Used
AX
Detailed Explanation
get_key_press allows for the program to wait until a user presses a key. This is extremely useful for programs that require a 'Press any key to continue' scenario or to get a 'y/n' from the user. It also allows for normally unsupported keys to be seen. If you wish to get a number of characters greater than one it is recommended you use get_string_and_print for both efficiency and ease of use. A bug seen a few times on a small number of Virtual Machines is the keyboard buffer not being cleared correctly meaning that the next key press is the residue of the previous key press. If it is a large problem for your program simply making sure the keyboard buffer is empty after each key press solves the issue. On real hardware this problem has not been seen.
Example of Use
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
main_program:
call get_key_press ; Get a key stroke from the user
cmp al, 'y' ; Has y been pressed?
je .done ; If so exit
jmp main_program ; If not, ask the user for input again
.done:
ret ; Return to OS
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
file:
|
|
get_string_and_print
Summary
Gets a string of maximum length from the user and returns it.
In
BL : Maximum size of string to collect [0 to 255]
Out
BH : Size of string user returned [0 to 255]
SI : Position of generated user response which is zero terminated
Used
AX
Detailed Explanation
Example of Use
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
main_program:
mov si, message1 ; Message to ask user for name
call print_string
mov bl, 32 ; Restrict name to be 32 characters long
call get_string_and_print
push si ; Move the position of the name to the stack
mov si, message2 ; Print a message to nicely display their name
call print_string
pop si ; Get the position of their name back from the stack
call print_string ; Print their name
ret ; Return to OS
message1 db 10, 13, 'What is your name?', 0
message2 db 10, 13, 'Your name is', 0
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
file:
|
|
string_compare
Summary
Compares two strings and tells the user if they are equal.
In
AX : Location of Variable 1
BX : Location of Variable 2
CH : Amount of string to compare [0 to 255]
DH : Exit charcater (stops checking if this character found)
Out
BX : Result [0=Not Equal Other=Equal]
Used
AX
BX
CH
DX
Detailed Explanation
This function is very useful for quickly comparing two strings. It comes with some useful features also, such as the ability to limit the amount of the strings to compare and an exit character to save time. When the comparison finds two characters that do not match it returns. This is because if one part of the string doesn't match then there is no point on searching any further. The result is returned in BX, where anything greater than zero means they are equal and if BX equals zero then they are not equal. Other than whether BX tells you if the two strings are equal, the number output is not very useful and any correlation between input and output is not offically supported.
Example of Use
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
main_program:
mov si, message1 ; Print a prompt for password
call print_string
mov bl, 32 ; Get a response from the user
call get_string_and_print
mov ax, si ; Put user's response into AX
mov bx, password ; Put string to compare with into BX
mov ch, 8 ; Maximum number of characters to check
mov dh, 0 ; Exit character
call string_compare
cmp bx, 0 ; Are they equal?
jne .done ; If they are equal done
mov si, message3 ; If not print it was incorrect
call print_string
jmp main_program ; Ask for password again
.done:
mov si, message2 ; Print the fact it was correct
call print_string
ret ; Return to OS
password db 'password'
message1 db 10, 13, 'Password:', 0
message2 db 10, 13, 'Correct', 0
message3 db 10, 13, 'Incorrect!', 0
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
file:
|
|
error
Summary
Prints an OS error to the screen. If jumped to this will also exit the user from the program.
In
-
Out
-
Used
-
Detailed Explanation
error is $AX's standard method of telling the user there is an error. It's part of an attempt to standardise error messages. Although this doesn't tell the user much, it's a very subtle way of letting the user know something bad happened without causing disruption to the screen as it is always printed to the left. Most of the disk functions will print this error to the screen if you use them wrong. Jumping to this function from a program instead of calling it will not only print the error message but will also exit the program. This can be useful if the error in question is a major error that shouldn't have occured and the program can no longer progress. It also saves on code space, as 512 bytes is a rather tight squeeze for most programs.
Example of Use
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
main_program:
mov al, 0
cmp al, 0 ; Compare AL with zero
je error ; If AL is zero there is an error
ret ; Return to OS
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
file:
|
|
find_file
Summary
Searches for a file in the file table and returns whether it was found or not.
In
BX : File to be searched for
Out
BX : Result [0=Not Equal Other=Equal]
CX : Sector file exists [0 to 1439]
Used
AX
BX
CX
Detailed Explanation
The find_file function mostly used with internal disk functions. The reason that it has been allowed to be used at program level is the fact that it is non-harmful and could be useful for a 'Are you sure you want to overwrite the file? (y/n)' feature of a program. The ability to know whether a file exists prior to trying to do disk operation with it could potentially stop your program from crashing. Please bare in mind that if a filename is repeated in the file table (dangerous) then it will return the first instance of the filename it comes accross.
Example of Use
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
main_program:
mov bx, filename ; Load the filename
call find_file
cmp bx, 0 ; Was the file found?
je error ; If it wasn't then error
ret ; Return to OS
filename db 'test'
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
file:
|
|
write_allocation_table
Summary
Places a filename in a position that corresponds to a given sector.
In
CX : Sector to write filename for [0 to 1439]
DX : Filename to be written into the file table
Out
-
Used
All
Detailed Explanation
This is yet another function that should be used with extreme care. Writing a filename for the wrong sector position could potentially wipe important OS data from the disk. This could lead to files being lost. Potentially you are able to carelessly wipe up to 312 files from your disk with slim chances of recovery. Without doubt, you should use find_file prior to using this function. If possible, please use write_file, as it's much safer and gives less opportunity to dangerous disk acts.
Example of Use
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
main_program:
mov bx, filename ; Load the filename
call find_file
cmp bx, 0 ; Was the file found?
je error ; If it wasn't then error
mov dx, bx
call write_file_allocation_table
ret ; Return to OS
filename db 'test'
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
file:
|
|
print_char
Summary
Prints a single character to the screen.
In
AL : Character to print
Out
-
Used
AX
Detailed Explanation
This function prints a single character to the screen from the register AL using teletype. This means that the next character's position is updated if there is a requirement to print multiple characters. This function also serves as part of the print_string function. If you only wish to print one character to the current position it is highly reccomended that you use this function over print_string which requires a zero terminator. Also this function doesn't change SI which may make it more attractive as a solution to a given problem.
Example of Use
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
main_program:
mov al, ' ' ; Print space
call print_char
mov al, ':' ; Print eyes
call print_char
mov al, ')' ; Print mouth
call print_char
ret ; Return to OS
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
file:
|
|
remove_file
Summary
Allows for a given filename to deleted from the file allocation table. Note the contents remain until over-written.
In
BX : File to be removed
Out
BX : Result [0=Not Equal Other=Equal]
Used
All
Detailed Explanation
This function simply removes the filename (and therefore the refference to the file) from the file table. It is worth noting that the sector on the disk that contains the data is not wiped until written over, leaving for possibility for recovery if no other actions are taken after the deletion. To make sure that all the data is removed, simply write zeros to the data section of the file using write_file and then use remove_file to remove the filename from the file allocation table. In most cases using just this function is effective enough to achieve a file deletion. Once a file is removed from the file allocation table it's space is then freed for another file or program to overwrite it.
Example of Use
BITS 16 ; Program MUST be set to 16 bits
ORG 7168 ; Where the program is loaded, highly recommended not to be changed
... Function table here
main_program:
mov bx, filename ; Load the filename
call remove_file
cmp bx, 0 ; Was the file removed?
je error ; If it wasn't then error
ret ; Return to OS
filename db 'test'
times 510-($-$$)db 0 ; Pad remainder of program sector with zeros
dw 0AA55h ; Boot signature (DO NOT CHANGE!)
file:
|
|
Bugs
If you are using the OS on either real hardware or a virtual machine and encounter a bug, please feel free to submit a bug in the issues section, along with what the bug is and how we can repeat it. If you think the bug may be specific to your system please also give us the details of your hardware.
Bugs and suggestions can be submitted at http://www.heluxresearch.info.
|