這份文件用來解釋如何用組合語言來開發MikeOS的軟體。他將說明所需要的工具,即MikeOS程式是如何運作的。和使用核心所提供的系統呼叫。假如你有任何問題,可以參考MikeOS網站中有連絡的細節與信箱列表資訊。
點擊左邊的連結來瀏覽這份文件。
概觀
介紹
許多MikeOS程式在16位元下撰寫,真實模式的組合語言。(作業系統也包含一個BASIC解譯器)因為MikeOS和他的程式被放在單一個64K記憶體區段,你不需要關注使用的區段暫存器。
MikiOS程式載入到32K 點(32768)的區段,且最大為32K。結果,你的程式將會用下面這兩行做開頭:
BITS 16
ORG 32768
在MikeOS中有許多系統呼叫用來控制螢幕,取得輸入,操作字串,載入/儲存檔案等等。所有的MikeOS系統呼叫通過對暫存器傳遞參數,而非堆疊。要在你的程式中使用它,你需要;
%INCLUDE "mikedev.inc"
這沒有包含任何碼,但會有等同的指令指向核心中的系統呼叫向量。所以,引入這個檔案你才能呼叫。MikeOS的os_print_string常式不用確實知道他在核心的哪個位置。mikedev.inc被包括在MikeOS下載中的programs/目錄─他也提供一個對系統呼叫的快速參考。
假如一個MikeOS程式在指令行下執行,一個或多個參數被提供給指令,他們會藉由SI暫存器傳遞給程式通過一個零結束的字串。
需要的工具
寫下MikeOS程式你需要:
NASM ─ 一個強大,免費且開放原始碼的組譯器
mikedev.inc ─ 系統呼叫向量描述在上面
一個方式新增程式到磁片
細節是:MikeOS使用NASM在他的程式和核心程式碼,所以我們在這裡推薦他。當然你可以使用任何組譯器來輸出二元檔案且接受16位元碼。NASM在許多Linux系統中可以取得,或你也可以從這裡下載Windows版本(取得'win32'檔案)。
第二點,複製programs/mikedev.inc
第三點,假如你要寫入MikeOS到實體硬碟,你只要複製你的.BIN程式到磁片上(僅有根目錄),啟動MikeOS並測試他。假如你在虛擬mikeos.flp磁片影像下工作,可以查看使用者手冊中的複製檔案。
例子
程式碼
這裡有一個MikeOS程式的範例,使用NASM格式,用來印出一段文字到螢幕上,且等待使用者按下一個按鍵:
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
建置
將上面的程式儲存為testapp.asm,並輸入指令來組譯他(在Windows和Linux都適用):
nasm -f bin -o testapp.bin testapp.asm
使用-f bin選項用來告訴NASM,我們想要一個二元檔案:沒有標頭或片段。結果的可執行檔是testapp.bin,我們可以複製到我們的磁片或加入到虛擬磁片影像,描述在使用者手冊中的複製檔案。然後我們可以啟動MikeOS並執行程式。
解釋
這是一個簡短的程式,但是我們將描述他是如何工作的。最初的三行不能被組譯為機器碼指令,但是這個宣告告訴NASM我們要在16位元模式下操作,我們的碼被寫入執行從32K的位置,我們將使用MikeOS API中的系統呼叫。
接下來,我們有一個'start:'標籤,他能讓我們的程式更清楚。我們放入零結束字串的位置到SI暫存器,然後呼叫MikeOS中的os_print_string常式,我們能存取藉由在mikedev.inc中的向量列表。之後我們暫停程式直到使用者按下一個鍵。
所以的MikeOS程式必須以ret指令結束,傳回控制權到作業系統中,之後我們擁有資料給我們的字串。
系統呼叫
介紹
MikeOS核心包含系統呼叫用來輸出到螢幕上,取得鍵盤輸入,操作字串,產生PC聲音,數學運算,硬碟輸入輸出。你可以參考mikedev.inc,和查看使用這些 呼叫的練習從programs/目錄。
這裡我們有一個細節API的描述。你可以查看系統呼叫的完整的程式碼從source/features目錄。每個API都包含了組譯程式碼,所以你能增強系統呼叫的功能,須參考MikeOS系統開發者手冊。
磁碟
os_get_file_list
產生磁碟的檔案字串,檔案間以逗號分隔
IN/OUT: AX = 儲存零結束檔名字串之位置
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_file
載入檔案到RAM
IN: AX=檔案位置,CX=在RAM中載入檔案的位置
OUT:BX=檔案大小(以bytes計), carry set if file not found
例子:
mov ax, filename
mov cx, 36960 ; 4K after where external program loads
call os_load_file
...
filename db 'README.TXT'
os_write_file
儲存檔案到磁碟(最大64K)
IN: AX = 檔名, BX = 資料位置, CX = 寫入多少位元組
OUT: Carry clear if OK, set if failure
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_exists
檢查檔案是否存在於磁片
IN: AX = 檔名位置
OUT: carry clear if found, set if not
Example:
mov ax, .filename
call os_file_exists
jc .not_found
...
.not_found:
; Print error message here
.filename db 'HELLO.TXT', 0
os_create_file
建立一個新的零個位元組的檔案到磁片中
IN: AX = 檔名位置
OUT: Nothing
Example:
mov ax, .filename
call os_create_file
...
.filename db 'HELLO.TXT', 0
os_remove_file
從檔案系統中刪除指定的檔案
IN: AX = 要刪除的檔名位置
OUT: Nothing
os_rename_file
在磁碟中更改檔案名稱
IN: AX = 要更改的檔案之檔名, BX = 新的檔名 (零結束字串)
OUT: carry set on error
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_size
取得指定檔案之檔案大小資訊
IN: AX = 檔名
OUT: BX = 檔案大小以位元組計 (最大 64K) or carry set if file not found
Keyboard
os_wait_for_key
Waits for keypress and returns key
IN: Nothing
OUT: AX = key pressed, other regs preserved
Example:
.loop:
call os_wait_for_key
cmp al, 'y'
je .yes
cmp al, 'n'
je .no
jmp .loop
os_check_for_key
Scans keyboard for input, but doesn't wait
IN: Nothing
OUT: AX = 0 if no key pressed, otherwise scan code
Example: see code above
Math
os_bcd_to_int
Converts binary coded decimal number to an integer
IN: AL = BCD number
OUT: AX = integer value
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_negate
Multiply value in DX:AX by -1
IN: DX:AX = long integer
OUT: DX:AX = -(initial DX:AX)
Example:
mov dx, 01h
mov ax, 45h
call os_long_int_negate
; DX now contains 0xFFFF
; and AX 0xFEBB
os_get_random
Get a random integer between high and low values (inclusive)
IN: AX = low integer, BX = high
OUT: CX = random number between AX and BX
Misc
os_get_api_version
Return current version of MikeOS API
IN: Nothing
OUT: AL = API version number
Example:
call os_get_api_version
; AL now contains version number (eg 8)
os_pause
Delay execution for specified 10ths of second
IN: AX = number of 10ths of second to wait
OUT: nothing
Example:
; Halt execution for 3 secs
mov ax, 30
call os_pause
os_fatal_error
Display error message and halt execution
IN: AX = error message string location
OUT: nothing
Example:
mov ax, .error_msg
call os_fatal_error
.error_msg db 'Massive error!', 0
Ports
os_port_byte_out
Sends a byte to the specified port
IN: DX = port address, AL = byte
OUT: Nothing
os_port_byte_in
Retrieves a byte from the specified port
IN: DX = port address
OUT: AL = byte
os_serial_port_enable
Turn on the first serial port
IN: AX = 0 for normal mode (9600 baud), or 1 for slow mode (1200 baud)
OUT: AH = bit 7 clear on success
os_send_via_serial
Send a byte via the serial port
IN: AL = byte to send via serial
OUT: AH = bit 7 clear on success
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_serial
Get a byte from the serial port
IN: nothing
OUT: AL = byte that was received; OUT: AH = bit 7 clear on success
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
Screen
os_print_string
Displays text
IN: SI = message location (zero-terminated string)
OUT: Nothing (registers preserved)
Example:
mov si, .message
call os_print_string
...
.message db 'Hello, world', 0
os_clear_screen
Clears the screen to background
IN/OUT: Nothing (registers preserved)
os_move_cursor
Moves cursor in text mode
IN: DH, DL = row, column
OUT: Nothing (registers preserved)
Example:
; Move to middle of screen
mov dh, 12
mov dl, 40
call os_move_cursor
os_get_cursor_pos
Return position of text cursor
OUT: DH, DL = row, column
os_print_horiz_line
Draw a horizontal line on the screen
IN: AX = line type (1 for double, otherwise single)
OUT: Nothing (registers preserved)
os_show_cursor
Turns on cursor in text mode
IN/OUT: Nothing
os_hide_cursor
Turns off cursor in text mode
IN/OUT: Nothing
os_draw_block
Render block of specified colour
IN: BL/DL/DH/SI/DI = colour/start X pos/start Y pos/width/finish Y pos
OUT: Nothing
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_selector
Show a file selection dialog
IN: Nothing
OUT: AX = location of filename string (or carry set if Esc pressed)
Example:
call os_file_selector
jc .esc_pressed
; Now AX points to the chosen filename
...
.esc_pressed:
...
os_list_dialog
Show a dialog with a list of options
IN: AX = comma-separated list of strings to show (zero-terminated),
BX = first help string, CX = second help string
OUT: AX = number (starts from 1) of entry selected carry set if Esc pressed
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_background
Clear screen with white top and bottom bars, containing text, and a coloured middle section
IN: AX/BX = top/bottom string locations, CX = colour
OUT: Nothing
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_newline
Reset cursor to start of next line
IN/OUT: Nothing (registers preserved)
os_dump_registers
Displays register contents in hex on the screen
IN/OUT: AX/BX/CX/DX = registers to show
os_input_dialog
Get text string from user via a dialog box
IN: AX = string location, BX = message to show
OUT: AX = string location
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_box
Print dialog box in middle of screen, with button(s)
IN: AX, BX, CX = string locations (set registers to 0 for no display),
DX = 0 for single 'OK' dialog, 1 for two-button 'OK' and 'Cancel'
OUT: If two-button mode, AX = 0 for OK and 1 for cancel
NOTE: Each string is limited to 40 characters
Example:
mov ax, .string1
mov bx, .string1
mov cx, .string1
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_space
Print a space to the screen
IN/OUT: nothing
os_dump_string
Dump string as hex bytes and printable characters
IN: SI = points to string to dump
OUT: Nothing
os_print_digit
Displays contents of AX as a single digit (works up to base 37, ie digits 0-Z)
IN: AX = "digit" to format and print
OUT: Nothing
os_print_1hex
Displays low nibble of AL in hex format
IN: AL = number to format and print
OUT: Nothing
os_print_2hex
Displays AL in hex format
IN: AL = number to format and print
OUT: Nothing
os_print_4hex
Displays AX in hex format
IN: AX = number to format and print
OUT: Nothing
os_input_string
Take string from keyboard entry
IN/OUT: AX = location of string, other regs preserved
(Location will contain up to 255 characters, zero-terminated)
Example:
mov ax, .string
call os_input_string
...
.string times 256 db 0
String
os_string_length
Return length of a string
IN: AX = string location
OUT AX = length (other regs preserved)
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_string
Get the position of a character in a string
IN: SI = string location, AL = character to find
OUT: AX = location in string, or 0 if char not present
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_reverse
Swar order of characters in a string
IN: SI = location of zero-terminated string
Example:
mov si, mystring
call os_string_reverse
; Now mystring contains 'olleH'
mystring db 'Hello', 0
os_string_charchange
Change instances of character in a string
IN: SI = string location, AL = char to find, BL = char to replace with
os_string_uppercase
Convert zero-terminated string to upper case
IN/OUT: AX = string location
os_string_lowercase
Convert zero-terminated string to lower case
IN/OUT: AX = string location
os_string_copy
Copy one string into another
IN/OUT: SI = source, DI = destination (programmer ensure sufficient room)
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_truncate
Chop string down to specified number of characters
IN: SI = string location, AX = number of characters
OUT: string modified, registers preserved
Example:
mov si, .string
mov ax, 3
call os_string_truncate
; .string now contains 'HEL', 0
.string db 'HELLO', 0
os_string_join
Join two strings into a third string
IN/OUT: AX = string one, BX = string two, CX = destination string
Example:
mov ax, .string1
mov bx, .string2
mov cx, .string3
; CX now points to 'HELLOYOU', 0
.string1 db 'HELLO', 0
.string2 db 'YOU', 0
.string3 times 50 db 0
os_string_chomp
Strip leading and trailing spaces from a string
IN: AX = string location
OUT: nothing
Example:
mov ax, .string
call os_string_chomp
; AX now points to 'KITTEN', 0
.string db ' KITTEN ', 0
os_string_strip
Removes specified character from a string
IN: SI = string location, AL = character to remove
OUT: nothing
Example:
mov si, .string
mov al, 'U'
call os_string_strip
; .string now contains 'MOSE', 0
.string db 'MOUSE', 0
os_string_compare
See if two strings match
IN: SI = string one, DI = string two
OUT: carry set if same, clear if different
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_strincmp
See if two strings match up to set number of chars
IN: SI = string one, DI = string two, CL = chars to check
OUT: carry set if same, clear if different
Example: like above, but with CL = number of characters to check
os_string_parse
Take string (eg "run foo bar baz") and return pointers to zero-terminated strings (eg AX = "run", BX = "foo" etc.)
IN: SI = string
OUT: AX, BX, CX, DX = individual strings
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_int
Convert decimal string to integer value
IN: SI = string location (max 5 chars, up to '65536')
OUT: AX = number
Example:
mov si, .string
call os_string_to_int
; Now AX contains the number 1234
.string db '1234', 0
os_int_to_string
Convert unsigned value in AX to string
IN: AX = unsigned integer
OUT: AX = location of internal string buffer with result
Example:
mov ax, 1234
call os_int_to_string
; Now AX points to '1234', 0
os_sint_to_string
Convert signed value in AX to string
IN: AX = signed integer
OUT: AX = location of internal string buffer with result
Example:
mov ax, -1234
call os_int_to_string
; Now AX points to '-1234', 0
os_long_int_to_string
Convert value in DX:AX to string
IN: DX:AX = long unsigned integer, BX = number base, DI = string location
OUT: DI = location of converted string
os_set_time_fmt
Set time reporting format (eg '10:25 AM' or '2300 hours')
IN: AL = format flag, 0 = 12-hr format
OUT: nothing
os_get_time_string
Get current time in a string (eg '10:25')
IN/OUT: BX = string location
os_set_date_fmt
Set date reporting format (M/D/Y, D/M/Y or Y/M/D - 0, 1, 2)
IN: AX = format flag, 0-2
If AX bit 7 = 1 = use name for months
If AX bit 7 = 0, high byte = separator character
OUT: nothing
os_get_date_string
Get current date in a string (eg '12/31/2007')
IN/OUT: BX = string location
聲音
os_speaker_tone
Generate PC speaker tone (call os_speaker_off to turn off)
IN: AX = note frequency
OUT: Nothing (registers preserved)
Example: see code below
os_speaker_off
Turn off PC speaker
IN/OUT: Nothing (registers preserved)
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
BASIC
os_run_basic
在指定點執行核心BASIC解譯器
IN: AX = lBASIC碼的位置, BX = 碼的大小 (以位元組計)
幫助
假如你有任何關於MikeOS的問題,或你要開發類似的系統且想要分享程式碼和想法,
可前往MikeOS網站,並加入到信箱列表。你就可以寫信到 mikeos-developer@lists.berlios.de
來發表到列表。
授權
MikeOS是個開放原始碼,在BSD-like下授權釋出(可參考在MikeOS.zip檔案中的doc/LI
CENSE.TXT)。它意指你可以為程式碼做任何事情,包括在你的專案中使用它,
你只須保留授權檔案。
2013年2月20日 星期三
MikeOS組譯程式開發者手冊
Labels:
OS
在文字的世界裡尋找心靈的共鳴,遠山藍以溫柔的筆觸分享書籍的力量與生活的智慧。無論是細膩的書評、深刻的人生感悟,還是技術與創新的新奇發現,每篇文章都是一次內心的療癒旅程。希望透過閱讀,帶領讀者在忙碌的生活中找到一片寧靜與啟發。讓我們一起,在書香中遇見更好的自己!
訂閱:
張貼留言 (Atom)
沒有留言:
張貼留言