NavigateOverview Example System calls Extra |
The MikeOS Assembly App Developer HandbookFor version 4.7, 9 April 2022 - (C) MikeOS DevelopersThis documentation file explains how write software for MikeOS in assembly language. It shows you the tools you need, how MikeOS programs work, and how to use the system calls included in the kernel. If you have any questions, see the MikeOS website for contact details and mailing list information. Click the links on the left to navigate around this guide. OverviewIntroductionMany MikeOS programs are written in 16-bit, real mode assembly language. (The OS also includes a BASIC interpreter.) Because MikeOS and its programs live in a single 64KiB memory segment, you do not need to concern yourself with segment registers. MikeOS programs are loaded at the 32K point (32768) in the segment, and have a maximum size of 32KiB. Consequently, your programs will need to begin with these directives: BITS 16 ORG 32768 There are many system calls available in MikeOS for controlling the screen, getting input, manipulating strings, loading/saving files, and more. All parameters to MikeOS system calls are passed in registers, and not on the stack. To use them in your programs, you need this line: %INCLUDE "mikedev.inc" This doesn't include any code, but a list of equ directives that point to system call vectors in the kernel. So, by including this file you can call, for instance, the MikeOS os_print_string routine without having to know exactly where it is in the kernel. mikedev.inc is included in the programs/ directory of the MikeOS download -- it also provides a quick reference to the system calls. If a MikeOS program is run from the command line, and one or more parameters was provided with the command, they are passed to the program via the SI register as a zero-terminated string. Tools neededTo write MikeOS programs you need:
Let's clarify this: MikeOS uses NASM for its programs and kernel source code, hence why we recommend it here. You can, of course, use any other assembler that can output plain binary files (i.e. with no header) and accept 16-bit code. NASM is available in most Linux distro repositories, or you can download the Windows version from here (get the 'win32' file). For the second point, copy programs/mikedev.inc so that it's alongside your program's source code for inclusion. For the third point, if you've written MikeOS to a real floppy disk, you can just copy your .BIN programs onto that disk (root directory only!), boot MikeOS and test them out. If you're working with the virtual mikeos.flp disk image, see the Copying files section of the User Handbook. ExampleSource codeHere is an example MikeOS program, in NASM format, which prints a string to the screen and waits for the user to press a key before finishing: BITS 16 ORG 32768 %INCLUDE 'mikedev.inc' start: mov si, mystring call os_print_string call os_wait_for_key ret mystring db 'My first MikeOS program!', 0 BuildingSave the above code as testapp.asm, and enter this command to assemble it (works on both Linux and Windows): nasm -f bin -o testapp.bin testapp.asm Using the '-f bin' option we tell NASM that we just want a plain binary file: no header or sections. The resulting executable file is testapp.bin that we can copy to our floppy disk or add to the virtual disk image as described in Copying files in the User Handbook. Then we can boot MikeOS and run the program. ExplanationThis is a very short program, but we'll explain exactly how it works for complete clarity. The first three lines will not be assembled to machine code instructions, but are just directives to tell NASM that we want to operate in 16 bit mode, our code is written to be executed from the 32KiB mark, and we want to use system calls from the MikeOS API. Next we have the 'start:' label, which is not essential but good practice to make things clear. We put the location of a zero-terminated string into the SI register, then call the MikeOS os_print_string routine which we can access via the vectors listed in mikedev.inc. After that we pause program until a the user presses a key. All MikeOS programs must end with a ret instruction, which passes control back to the OS. After that instruction we have the data for our string. And that's it! System callsIntroductionThe MikeOS kernel includes system calls for outputting to the screen, taking keyboard input, manipulating strings, producing PC speaker sounds, math operations and disk I/O. You can get a quick reference to the registers that these calls take and pass back by looking at mikedev.inc, and see practical use of the calls in the programs/ directory. Here we have a detailed API explanation with examples. You can see the full source code behind these system calls in the source/features/ directory in MikeOS. Each aspect of the API below is contained within an assembly source file, so you can enhance the system calls as per the MikeOS System Developer Handbook. Diskos_get_file_listGenerate comma-separated string of files on floppy
Example: mov ax, .filestring call os_get_file_list ; Now .filestring will contain something like ; 'HELLO.BIN,FOO.BAR,THREE.TXT', 0 .filestring times 256 db 0 os_load_fileLoad file into RAM
Example: mov ax, filename mov cx, 36960 ; 4KiB after where external program loads call os_load_file ... filename db 'README.TXT', 0 os_write_fileSave (max 64KiB) file to disk
Example: ; For this example, there's some text stored in .data mov ax, .filename mov bx, .data mov cx, 4192 call os_write_file .filename db 'HELLO.TXT', 0 .data times 4192 db 0 os_file_existsCheck for presence of file on the floppy
Example: mov ax, .filename call os_file_exists jc .not_found ... .not_found: ; Print error message here .filename db 'HELLO.TXT', 0 os_create_fileCreates a new 0-byte file on the floppy disk
Example: mov ax, .filename call os_create_file ... .filename db 'HELLO.TXT', 0 os_remove_fileDeletes the specified file from the filesystem
os_rename_fileChange the name of a file on the disk
Example: mov ax, .filename1 mov bx, .filename2 call os_rename_file jc .error ... .error: ; File couldn't be renamed (may already exist) .filename1 db 'ORIG.TXT', 0 .filename2 db 'NEW.TXT', 0 os_get_file_sizeGet file size information for specified file
Keyboardos_wait_for_keyWaits for key press and returns key
Example: .loop: call os_wait_for_key cmp al, 'y' je .yes cmp al, 'n' je .no jmp .loop os_check_for_keyScans keyboard for input, but doesn't wait
Example: see code above Mathos_bcd_to_intConverts binary coded decimal number to an integer
Example: mov al, 00010110b ; 0001 0110 = 16 (decimal) or 10h in BCD call os_bcd_to_int ; AX now contains the 16 bit-integer 00000000 00010000b os_long_int_negateMultiply value in DX:AX by -1
Example: mov dx, 01h mov ax, 45h call os_long_int_negate ; DX now contains 0xFFFF ; and AX 0xFEBB os_get_randomGet a random integer between high and low values (inclusive)
Miscos_get_api_versionReturn current version of MikeOS API
Example: call os_get_api_version ; AL now contains version number (eg 8) os_pauseDelay execution for specified 10ths of second
Example: ; Halt execution for 3 secs mov ax, 30 call os_pause os_fatal_errorDisplay error message and halt execution
Example: mov ax, .error_msg call os_fatal_error .error_msg db 'Massive error!', 0 Portsos_port_byte_outSends a byte to the specified port
os_port_byte_inRetrieves a byte from the specified port
os_serial_port_enableTurn on the first serial port
os_send_via_serialSend a byte via the serial port
Example: mov al, 'a' ; Place char to transmit in AL call os_send_via_serial cmp ah, 128 ; If bit 7 is set, there's an error jnz all_ok ; Otherwise it's all OK jmp oops_error ; Deal with the error os_get_via_serialGet a byte from the serial port
Example: call os_get_via_serial cmp ah, 128 ; If bit 7 is set, there's an error. jnz all_ok ; Otherwise it's all OK jmp oops_error ; Deal with the error all_ok: mov [rx_byte], al ; Store byte we retrieved Screenos_print_stringDisplays text
Example: mov si, .message call os_print_string ... .message db 'Hello, world', 0 os_clear_screenClears the screen to background
os_move_cursorMoves cursor in text mode
Example: ; Move to middle of screen mov dh, 12 mov dl, 40 call os_move_cursor os_get_cursor_posReturn position of text cursor
os_print_horiz_lineDraw a horizontal line on the screen
os_show_cursorTurns on cursor in text mode
os_hide_cursorTurns off cursor in text mode
os_draw_blockRender block of specified colour
Example: mov bl, 0100111b ; White on red mov dl, 20 ; Start X position mov dh, 2 ; Start Y position mov si, 40 ; Width mov di, 23 ; Finish Y position call os_draw_block os_file_selectorShow a file selection dialog
Example: call os_file_selector jc .esc_pressed ; Now AX points to the chosen filename ... .esc_pressed: ... os_list_dialogShow a dialog with a list of options
Example: mov ax, .list mov bx, .msg1 mov cx, .msg2 call os_list_dialog jc .esc_pressed ; Now AX = number (from 1) of option chosen ... .esc_pressed: ... .list db 'Open,Close,Reboot', 0 .msg1 db 'Choose an option', 0 .msg2 db 'Or press Esc to quit', 0 os_draw_backgroundClear screen with white top and bottom bars, containing text, and a coloured middle section
Example: mov ax, .title_msg mov bx, .footer_msg mov cx, 00100000b ; Colour call os_draw_background ... .title_msg db 'File manager', 0 .footer_msg db 'Choose an option...', 0 os_print_newlineReset cursor to start of next line
os_dump_registersDisplays register contents in hex on the screen
os_input_dialogGet text string from user via a dialog box
Example: mov bx, .filename_msg mov ax, .filename_input call os_input_dialog ... .filename_msg 'Please enter a filename:', 0 .filename_input times 12 db 0 os_dialog_boxPrint dialog box in middle of screen, with button(s)
Example: mov ax, .string1 mov bx, .string2 mov cx, .string3 mov dx, 1 call os_dialog_box cmp ax, 1 je .first_option_chosen ; Otherwise second was chosen ... .first_option_chosen: ... .string1 db 'Welcome to my program!', 0 .string2 db 'Please choose to destroy the world,', 0 .string3 db 'or play with fluffy kittens.', 0 os_print_spacePrint a space to the screen
os_dump_stringDump string as hex bytes and printable characters
os_print_digitDisplays contents of AX as a single digit (works up to base 37, ie digits 0-Z)
os_print_1hexDisplays low nibble of AL in hex format
os_print_2hexDisplays AL in hex format
os_print_4hexDisplays AX in hex format
os_input_stringTake string from keyboard entry
Example: mov ax, .string call os_input_string ... .string times 256 db 0 Stringos_string_lengthReturn length of a string
Example: jmp Get_Len Test_String db 'This string has 46 characters including spaces', 0 Get_Len: mov ax, Test_String call os_string_length ; AX now contains the number 46 os_find_char_in_stringGet the position of a character in a string
Example: jmp Search_Str Test_String db 'This is the test string', 0 message_1 db 'Character not found', 0 message_2 db 'Character found at position', 0 message_3 db ' ', 0 str_len dw 0 Search_Str: mov ax, Test_String ; string to search mov si, ax xor ax, ax ; clear ax mov al, 'x' ; x is the character to find call os_find_char_in_string mov [str_len], ax ; store result cmp ax, 0 jz Char_Not_Found jmp Char_Found Char_Not_Found: mov si, message_1 call os_print_string jmp Main_Pgm Char_Found: mov ax, [str_len] ; convert result into string first mov bx, message_3 call os_int_to_string mov si, message_2 call os_print_string ; print message_2 call os_print_space ; print a space mov si, message_3 call os_print_string ; print the position at which x was found os_string_reverseSwar order of characters in a string
Example: mov si, mystring call os_string_reverse ; Now mystring contains 'olleH' mystring db 'Hello', 0 os_string_charchangeChange instances of character in a string
os_string_uppercaseConvert zero-terminated string to upper case
os_string_lowercaseConvert zero-terminated string to lower case
os_string_copyCopy one string into another
Example: mov si, .old_string mov di, .new_string call os_string_copy ... .old_string db 'Hello', 0 .new_string times 16 db 0 os_string_truncateChop string down to specified number of characters
Example: mov si, .string mov ax, 3 call os_string_truncate ; .string now contains 'HEL', 0 .string db 'HELLO', 0 os_string_joinJoin two strings into a third string
Example: mov ax, .string1 mov bx, .string2 mov cx, .string3 call os_string_join ; CX now points to 'HELLOYOU', 0 .string1 db 'HELLO', 0 .string2 db 'YOU', 0 .string3 times 50 db 0 os_string_chompStrip leading and trailing spaces from a string
Example: mov ax, .string call os_string_chomp ; AX now points to 'KITTEN', 0 .string db ' KITTEN ', 0 os_string_stripRemoves specified character from a string
Example: mov si, .string mov al, 'U' call os_string_strip ; .string now contains 'MOSE', 0 .string db 'MOUSE', 0 os_string_compareSee if two strings match
Example: mov si, .string1 mov di, .string2 call os_string_compare jc .same ; Strings are different ... .same: ; Strings are the same .string1 db 'ONE', 0 .string2 db 'TWO', 0 os_string_strincmpSee if two strings match up to set number of chars
Example: like above, but with CL = number of characters to check os_string_parseTake string (eg "run foo bar baz") and return pointers to zero-terminated strings (eg AX = "run", BX = "foo" etc.)
Example: mov si, .string call os_string_parse ; Now AX points to 'This', ; BX to 'is', ; CX to 'a', ; and DX to 'test' .string db 'This is a test', 0 os_string_to_intConvert decimal string to integer value
Example: mov si, .string call os_string_to_int ; Now AX contains the number 1234 .string db '1234', 0 os_int_to_stringConvert unsigned value in AX to string
Example: mov ax, 1234 call os_int_to_string ; Now AX points to '1234', 0 os_sint_to_stringConvert signed value in AX to string
Example: mov ax, -1234 call os_int_to_string ; Now AX points to '-1234', 0 os_long_int_to_stringConvert value in DX:AX to string
os_string_to_long_intConvert a decimal string to a long integer value
os_set_time_fmtSet time reporting format (eg '10:25 AM' or '2300 hours')
os_get_time_stringGet current time in a string (eg '10:25')
os_set_date_fmtSet date reporting format (M/D/Y, D/M/Y or Y/M/D - 0, 1, 2)
os_get_date_stringGet current date in a string (eg '12/31/2007')
Soundos_speaker_toneGenerate PC speaker tone (call os_speaker_off to turn off)
Example: see code below os_speaker_offTurn off PC speaker
Example: ; Generate "middle C" 261.626 Hz (263 Hz close enough) for 2 secs ; 2 secs = 2,000,000 uS which is 1E8480h jmp Play_It music_note dw 263 Play_It: mov ax, [music_note] call os_speaker_tone mov cx, 1Eh mov dx, 8480h call os_pause call os_speaker_off BASICos_run_basicRuns kernel BASIC interpreter at the specified point
ExtraHelpIf you have any questions about MikeOS, or you're developing a similar OS and want to share code and ideas, go to the MikeOS website and join the mailing list as described. LicenseMikeOS is open source and released under a BSD-like license (see doc/LICENSE.TXT in the MikeOS .zip file). Essentially, it means you can do anything you like with the code, including basing your own project on it, providing you retain the license file and give credit to the MikeOS developers for their work. |