Writing applications for KolibriOS

From KolibriOS wiki
Revision as of 20:19, 10 January 2013 by Padomay (talk | contribs) (Fixed some typos.)
Jump to navigation Jump to search

Structure of an application

Programming for KolibriOS is easy as you first learn the basic structure of an application. At this point I assume you have some experience in assembly language. The KolibriOS API (Application Programming Interface) is an easy-to-learn set of functions with practically no hierarchial accesses.

The operating of an application is based on events. The application is notified by the OS with the event type and the application acts accordingly. There are three event types an application is expected to handle by default: window redraw, keypress and buttonpress.

Flow chart and structure of an application with default events:

<syntaxhighlight>

;
HEADER DATA  ;
;

START:

       call    draw_window
;
WAIT UNTIL EVENT  ; <-----------------------------------------------I
; I
I
I
I
; redraw -> call draw_window -> I
READ EVENT TYPE  ; -> key -> read keypress -> process -> I
; button -> read buttonpress -> process -> I

draw_window:

;
DRAW STATIC WINDOW PARTS  ;
;
       ret
;
STATIC DATA  ;
;

</syntaxhighlight>

The header

<syntaxhighlight> db 'MENUET01' </syntaxhighlight>

Since KolibriOS still is more or less API compatible with MenuetOS, it has the same header. There is also an older version of the header which uses 'MENUET00', but it should not be used anymore.

<syntaxhighlight> dd 0x01 ; header version </syntaxhighlight>

Speaks for itself.

<syntaxhighlight> dd START ; start of execution </syntaxhighlight>

START is the label in your program where kernel will jump to after loading the program. You could use another name, but it's convenient to always use the same.

<syntaxhighlight> dd I_END ; size of image </syntaxhighlight>

This is the total size of the program code in bytes, its easy to use a label which you place at the end of the code.

<syntaxhighlight> dd 0x100000 </syntaxhighlight>

This is the amount of ram that will be reserved for your app. You could use a static value as shown here, or you could use I_END + xx bytes. There, I_END would be the label to the end of code + all static declarations you made after the code. The xx bytes then are the number of bytes you want to use for the stack. Also note, this value can later be changed by using system functions.

<syntaxhighlight> dd 0x100000 ; stack position in memory area </syntaxhighlight>

Where the end of stack is (the value of esp at start of program). Logically, this would be the same as the previous value.

<syntaxhighlight> dd 0x0 ; Parameters </syntaxhighlight>

If you want to use parameters, this should be a pointer to a 1024 byte buffer, in which those parameters will be written by the kernel. If you dont want to use them, set this dword to 0.

<syntaxhighlight> dd 0x0 ; Path </syntaxhighlight>

Path value, works the same as parameter.

System calls

The System calls (API) are explained in various sources. There is the file syscalls.txt which you can find in KolibriOS itself, but also in the zip file of the distribution.< If you understand russian, you can also find system calls on this wiki.

To execute a system call, you first need to fill the registers with the correct value. Say we want to wait a couple of milliseconds, we need to use system function 5 and place the time we want to wait in ebx.

<syntaxhighlight>

       mov     eax, 5
       mov     ebx, 10

</syntaxhighlight>

Now, we need to execute the function, this can be done with int 0x40:

<syntaxhighlight>

       int     0x40

</syntaxhighlight>

But also with more modern instructions such as syscall, sysenter etc. It's convenient to use the mcall macro from macros.inc, then you can chose to use int 0x40 or another method, at compile time. This macro also accepts parameters, first is eax, second is ebx, ... Code for the above would be:

<syntaxhighlight>

       mcall   5, 10

</syntaxhighlight>

Coding Style

It's advisable to use the coding style, as described here: Style

The API

You can find the latest API documention in /kernel/docs/ in the SVN repository (WebSVN)

Assembly examples

Simple example

<syntaxhighlight>

;
EXAMPLE APPLICATION  ;
;
Compile with FASM  ;
;
The header

use32  ; Tell compiler to use 32 bit instructions

org 0x0  ; the base address of code, always 0x0

db 'MENUET01' dd 0x01 dd START dd I_END dd 0x100000 dd 0x7fff0 dd 0, 0

The code area

include 'macros.inc'

START:  ; start of execution

       call    draw_window             ; draw the window
After the window is drawn, it's practical to have the main loop.
Events are distributed from here.

event_wait:

       mov     eax, 10                 ; function 10 : wait until event
       mcall                           ; event type is returned in eax
       cmp     eax, 1                  ; Event redraw request ?
       je      red                     ; Expl.: there has been activity on screen and
                                       ; parts of the applications has to be redrawn.
       cmp     eax, 2                  ; Event key in buffer ?
       je      key                     ; Expl.: User has pressed a key while the
                                       ; app is at the top of the window stack.
       cmp     eax, 3                  ; Event button in buffer ?
       je      button                  ; Expl.: User has pressed one of the
                                       ; applications buttons.
       jmp     event_wait
The next section reads the event and processes data.

red:  ; Redraw event handler

       call    draw_window             ; We call the window_draw function and
       jmp     event_wait              ; jump back to event_wait

key:  ; Keypress event handler

       mov     eax, 2                  ; The key is returned in ah. The key must be
       mcall                           ; read and cleared from the system queue.
       jmp     event_wait              ; Just read the key, ignore it and jump to event_wait.

button:  ; Buttonpress event handler

       mov     eax,17                  ; The button number defined in window_draw
       mcall                           ; is returned to ah.
  
       cmp     ah,1                    ; button id=1 ?
       jne     noclose
       mov     eax,-1                  ; Function -1 : close this program
       mcall

noclose:

       jmp     event_wait              ; This is for ignored events, useful at development
*********************************************
****** WINDOW DEFINITIONS AND DRAW ********
*********************************************
The static window parts are drawn in this function. The window canvas can
be accessed later from any parts of this code (thread) for displaying
processes or recorded data, for example.
The static parts *must* be placed within the fn 12 , ebx = 1 and ebx = 2.

draw_window:

       mov     eax, 12                 ; function 12: tell os about windowdraw
       mov     ebx, 1                  ; 1, start of draw
       mcall
       mov     eax, 0                  ; function 0 : define and draw window
       mov     ebx, 100 * 65536 + 300  ; [x start] *65536 + [x size]
       mov     ecx, 100 * 65536 + 120  ; [y start] *65536 + [y size]
       mov     edx, 0x14ffffff         ; color of work area RRGGBB
                                       ; 0x02000000 = window type 4 (fixed size, skinned window)
       mov     esi, 0x808899ff         ; color of grab bar  RRGGBB
                                       ; 0x80000000 = color glide
       mov     edi, title
       mcall
       mov     ebx, 25 * 65536 + 35    ; draw info text with function 4
       mov     ecx, 0x224466
       mov     edx, text
       mov     esi, 40
       mov     eax, 4
 .newline:                             ; text from the DATA AREA
       mcall
       add     ebx, 10
       add     edx, 40
       cmp     byte[edx], 0
       jne     .newline
       mov     eax, 12                 ; function 12:tell os about windowdraw
       mov     ebx, 2                  ; 2, end of draw
       mcall
       ret
*********************************************
************* DATA AREA *****************
*********************************************
Data can be freely mixed with code to any parts of the image.
Only the header information is required at the beginning of the image.

text db "It look's like you have just compiled "

       db  "your first program for KolibriOS.       "
       db  "                                        "
       db  "Congratulations!                        ", 0

title db "Example application", 0

I_END:

The area after I_END is free for use as the application memory,
just avoid the stack.
Application memory structure, according to the used header, 1 Mb.
0x00000 - Start of compiled image
I_END - End of compiled image
+ Free for use in the application
0x7ff00 - Start of stack area
0x7fff0 - End of stack area - defined in the header
+ Free for use in the application
0xFFFFF - End of freely useable memory - defined in the header
All of the the areas can be modified within the application with a
direct reference.
For example, mov [0x80000],byte 1 moves a byte above the stack area.

</syntaxhighlight>

It should look like this (perhaps with other skin):

Error creating thumbnail: Unable to save thumbnail to destination

KolibriOS's application structure is not specifically reserved for asm programming, the header can be produced with practically any other language. However, the overall application programming design is intended for easy 32 bit asm programming. The GUI is extremely easy to handle with especially asm language.

Using uniform system colours

While previous example concentrated on creating a basic application, in this section more attention is paid on the outlook of the window.

You can use uniform desktop colors defined by a colour setup application.

New fuction in this example is get_system_colours.

<syntaxhighlight>

;
UNIFORM SYSTEM COLOURS EXAMPLE  ;
;
Compile with FASM  ;
;
The header

use32

org 0x0

db 'MENUET01' dd 1, START, I_END, 0x100000, 0x7fff0, 0, 0

The code area

window_size_X equ 300 window_size_Y equ 150

include 'macros.inc'

START:  ; start of execution

       call    draw_window     ; draw the window
After the window is drawn, it's practical to have the main loop.
Events are distributed from here.

event_wait:

       mcall   10              ; function 10 : wait until event
                               ; event type is returned in eax
How the 'dec' instruction in the following code works
example
If a window redraw is needed, eax will be 1
So if we decrement eax, eax will become 0
'dec' instruction will set Zero-Flag because eax is now zero
So now we can use jz (jump if zero flag is set) to detect this..
If eax is 2, it will take 2 time 'dec eax' before zero flag will be set..
       dec     eax             ; Event redraw request ?
       jz      red             ; Expl.: there has been activity on screen and
                               ; parts of the applications has to be redrawn.
       dec     eax             ; Event key in buffer ?
       jz      key             ; Expl.: User has pressed a key while the
                               ; app is at the top of the window stack.
       dec     eax             ; Event button in buffer ?
       jz      button          ; Expl.: User has pressed one of the
                               ; applications buttons.
       jmp     event_wait
The next section reads the event and processes data.

red:  ; Redraw event handler

       call    draw_window     ; We call the window_draw function and
       jmp     event_wait      ; jump back to event_wait

key:  ; Keypress event handler

       mcall   2               ; The key is returned in ah. The key must be read and cleared from the system queue.
       jmp     event_wait      ; Just read the key, ignore it and jump to event_wait.

button:  ; Buttonpress event handler

       mcall   17              ; The button number defined in window_draw  is returned to ah.
       cmp     ah, 1           ; button id=1 ?
       jne     event_wait      ; if not, go back and wait for other events
       mcall   -1              ; Function -1 : close this program

get_system_colours:

       pusha
       mov     eax, 48                 ; fn 48 system colours
       mov     ebx, 3                  ; subfn 3 : get
       mov     ecx, app_colours        ; pointer to return area
       mov     edx, 10 * 4             ; number of bytes to return
       mcall
       popa
       ret
            • WINDOW DEFINITIONS AND DRAW ********
The static window parts are drawn in this function. The window canvas can
be accessed later from any parts of this code (thread) for displaying
processed or recorded data, for example.
The static parts *must* be placed within the fn 12 , ebx = 1 and ebx = 2.
When using system colours, the window colours are read from the
SYSTEM COLOURS TABLE

draw_window:

       mcall   12, 1                           ; Tell OS about start of redraw
       call    get_system_colours              ; fetches system colours from os
       mov     eax, 0                          ; function 0 : define and draw window
       mov     ebx, 100 * 65536 + window_size_X ; [x start] *65536 + [x size]
       mov     ecx, 100 * 65536 + window_size_Y ; [y start] *65536 + [y size]
       mov     edx, [w_work]                   ; color of work area 0xRRGGBB
       or      edx, 0x14000000                 ; 0x14000000 = window type 4, with title
       mov     esi, [w_grab]                   ; color of grab bar 0xRRGGBB
       or      esi, 0x80000000                 ; 0x80000000 = colour glide
       mov     edi, title
       mcall
       mov     ebx, 25 * 65536 + 35            ; draw info text with function 4
       mov     ecx, [w_work_text]
       mov     edx, text                       ; text from the DATA AREA
       mov     esi, 40
       mov     eax, 4
 .newline:
       mcall
       add     ebx, 10
       add     edx, 40
       cmp     byte [edx], 0
       jne     .newline
       mcall   12, 2 ; end of redraw
       ret
*********************************************
************* DATA AREA *****************
*********************************************
Data can be freely mixed with code to any parts of the image.
Only the header information is required at the beginning of the image.

text db 'THIS PROGRAM USES UNIFORM SYSTEM COLOURS'

       db  'RETURNED TO A TABLE                     ', 0

title db 'EXAMPLE APPLICATION', 0

I_END:

app_colours:  ; SYSTEM COLOURS TABLE

 w_frames           dd ?               ; - frames
 w_grab             dd ?               ; - GRAB AREA
 w_grab_button      dd ?               ;   grab area button
 w_grab_button_text dd ?               ;   grab area button text
 w_grab_text        dd ?               ;   grab area text
 w_work             dd ?               ; - WORK AREA
 w_work_button      dd ?               ;   work area button
 w_work_button_text dd ?               ;   work area button text
 w_work_text        dd ?               ;   work area text
 w_work_graph       dd ?               ;   work area graphics

</syntaxhighlight>

Freeform window

In this example we concentrate on shaping the window from rectangle to any form desired by the programmer. New fuction in this example is shape_window.

<syntaxhighlight>

;
FREEFORM EXAMPLE APPLICATION  ;
;
Compile with FASM  ;
;
The header

use32

org 0x0

db 'MENUET01' dd 1, START, I_END, 0x100000, 0x7fff0, 0x0, 0x0

include 'macros.inc'

START:  ; start of execution

       call    shape_window    ; function for shaping
       call    draw_window     ; at first, draw the window

still:

       mcall   10              ; wait here for event
       dec     eax             ; redraw request ?
       jz      red
       dec     eax             ; key in buffer ?
       je      key
       dec     eax             ; button in buffer ?
       je      button
       jmp     still

red:  ; redraw

       call    draw_window
       jmp     still
  

key:  ; key

       mcall   2               ; just read it and ignore
       jmp     still
  

button:  ; button

       mcall   17              ; get id
  
       cmp     ah, 1           ; button id=1 ?
       jne     noclose
       mcall   -1              ; close this program

noclose:

       jmp     still

shape_window:

       pusha
give the shape reference area
       mcall   50, 0, shape_reference
give the shape scale 32 x 32 -> 128 x 128
you dont have to give this, scale is 1
1 by default
scale is set to 2^ecx
       mcall   50, 1, 2
       popa
       ret

shape_reference: ; 32 x 32, ( window_size_X + 1 ) * ( window_size_Y + 1 )

 db 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0
 db 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0
 db 0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0
 db 0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0
 db 0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
 db 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0
 db 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0
 db 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0
 db 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0
 db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0
 db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0
 db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0
 db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0
 db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0
 db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0
 db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0
 db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0
 db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0
 db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0
 db 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0
 db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0
 db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0
 db 0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0
 db 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0
 db 0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0
 db 0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0
 db 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0
 db 0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0
 db 0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0
 db 0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0
 db 0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0
 db 0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0
              • WINDOW DEFINITIONS AND DRAW ********

draw_window:

       mcall   12, 1                   ; notice os about start of redraw
       mov     eax, 0                  ; function 0: define and draw window
       mov     ebx, 100 * 65536        ; [x start] * 65536 + [x size]
       mov     ecx, 100 * 65536        ; [y start] * 65536 + [y size]
       mov     bx , [x_size]
       mov     cx , [y_size]
       mov     edx, 0x00cccc00         ; color of work area RRGGBB,8->color glide
       mov     esi, 0x00cccc00         ; color of grab bar  RRGGBB,8->color glide
       mov     edi, 0x00cccc00         ; color of frames    RRGGBB
       mcall
       mov     eax, 8                  ; function 8: define and draw button
       mov     ebx, 78 * 65536 + 12    ; [x start] * 65536 + [x size]
       mov     ecx, 20 * 65536 + 12    ; [y start] * 65536 + [y size]
       mov     edx, 1                  ; button id
       mov     esi, 0x5599cc           ; button color RRGGBB
       mcall
       mcall   12, 2                   ; end of redraw
       ret
DATA

x_size dw 127 y_size dw 127

I_END: </syntaxhighlight>

Threads

KolibriOS assembly threading has some great advantages over higher level languages. If you keep all the variables in registers, you can start as meny threads as desired with the _same_ code, since no memory is affected and needs no saving. The registers are saved to Task Switch Segments by KolibriOS. All you have to do is to set a new stack.

Threads have no difference with the main process and use the same memory area as the process which starts it. They can have their own independent windows etc. In the closing of application, all threads have to be terminated with the default (eax = -1) system call.

New function in this example is create_thread.

<syntaxhighlight>

;
THREAD EXAMPLE  ;
;
Compile with FASM for Menuet  ;
;

use32

org 0x0

db 'MENUET01' ; 8 byte id for application dd 1, START, I_END, 0x100000, 0x80000, 0x0, 0x0

include 'macros.inc'

START:  ; start of execution

       call    draw_window               ; at first, draw the window
  

event_wait:

       mov     eax, 10                   ; wait here for event
       mcall
       cmp     eax, 1                    ; redraw request ?
       je      red
       cmp     eax, 2                    ; key in buffer ?
       je      key
       cmp     eax, 3                    ; button in buffer ?
       je      button
       jmp     event_wait

red:  ; redraw

       call    draw_window
       jmp     event_wait

key:  ; key

       mov     eax, 2                    ; just read it and ignore
       mcall
       jmp     event_wait

button:  ; button

       mov     eax, 17                   ; get id
       mcall
       cmp     ah, 1                     ; button id=1 ?
       jne     noclose
       mov     eax, -1                   ; close this program (thread)
       mcall

noclose:

       cmp     ah, 2                     ; call create_thread
       jne     no_thread
       call    create_thread
       jmp     event_wait

no_thread:

       jmp     event_wait
THREAD CREATION
All we have to do is to give the thread entry address in ecx and
a new stack postition in edx with function eax=51, ebx=1

create_thread:

       cmp     [thread_stack], 0xf0000
       jge     no_new_thread
  
       add     [thread_stack], 0x1000
  
       mov     eax, 51                   ; thread_create system call
       mov     ebx, 1
       mov     ecx, START
       mov     edx, [thread_stack]
       mcall

no_new_thread:

       ret

thread_stack dd 0x80000

              • WINDOW DEFINITIONS AND DRAW ********

draw_window:

       mov     eax, 12                   ; function 12: tell os about windowdraw
       mov     ebx, 1                    ; 1, start of draw
       mcall
       mov     eax, 0                    ; function 0: define and draw window
       mov     ebx, 10 * 65536 + 300     ; [x start] * 65536 + [x size]
       mov     ecx, 10 * 65536 + 140     ; [y start] * 65536 + [y size]
       mov     esi, [thread_stack]
       sub     esi, 0x80000
       shr     esi, 11
       shl     esi, 16
       add     ebx, esi
       add     ecx, esi
       mov     edx, 0x02ffffff           ; color of work area RRGGBB,8->color glide
       mov     esi, 0x808899ff           ; color of grab bar  RRGGBB,8->color glide
       mov     edi, 0x008899ff           ; color of frames    RRGGBB
       mcall
       ; WINDOW LABEL
       mov     eax, 4                    ; function 4: write text to window
       mov     ebx, 8 * 65536 + 8        ; [x start] * 65536 + [y start]
       mov     ecx, 0x00ddeeff           ; color of text RRGGBB
       mov     edx, labelt               ; pointer to text beginning
       mov     esi, labellen-labelt      ; text length
       mcall
       ; CLOSE BUTTON
       mov     eax, 8                    ; function 8: define and draw button
       mov     ebx, (300 - 19) * 65536 + 12 ; [x start] * 65536 + [x size]
       mov     ecx, 5 * 65536 + 12       ; [y start] * 65536 + [y size]
       mov     edx, 1                    ; button id
       mov     esi, 0x6677cc             ; button color RRGGBB
       mcall
       ; NEW THREAD BUTTON
       mov     eax, 8
       mov     ebx, 25 * 65536 + 128
       mov     ecx, 88 * 65536 + 20
       mov     edx, 2
       mov     esi, 0x6677cc
       mcall
       mov     ebx, 25 * 65536 + 35      ; draw info text with function 4
       mov     ecx, 0x224466
       mov     edx, text
       mov     esi, 40
 .newline:
       mov     eax, 4
       mcall
       add     ebx, 10
       add     edx, 40
       cmp     byte[edx], 0
       jne     .newline
       mov     eax, 12                   ; function 12: tell os about windowdraw
       mov     ebx, 2                    ; 2, end of draw
       mcall
       ret
DATA AREA

text:

   db 'THIS EXAMPLE CREATES THREADS BY RUNNING '
   db 'THE SAME CODE MULTIPLE TIMES. ALL WE    '
   db 'NEED IS A NEW STACK FOR EACH THREAD.    '
   db 'ALL THREADS SHARE THE SAME MEMORY.      '
   db '                                        '
   db '                                        '
   db '  CREATE NEW THREAD                     ', 0

labelt:

   db   'THREAD EXAMPLE'

labellen:

I_END: </syntaxhighlight>

Real-Time data

The following example focuses on Real-Time data fetching and processing. Application informs the OS for all the ports and datatypes to read at a specific IRQ.

Steps:

  1. reserve I/O port area
  2. reserve IRQ
  3. program IRQ
  4. program EVENT list for wanted IRQ
  5. runtime processing of the data
  6. back to default events - free IRQ from EVENT list
  7. free IRQ
  8. free port area
  9. terminate program

After IRQ's are programmed, the application has a new event for the main event loop, number (IRQ+16). When the application receives this event, the OS has recorded data ready for the application to process.

The table below shows the main structure of processing real time data. All the steps on the left of (A) are processed by the OS and the steps right from (A) are processed by the application.

IRQ           OWNER      =>  REC DATA  (A) SYS_EVENT => READ DATA => PROCESS
  
 0 TIMER       SYS
 1 KEYBOARD    SYS
 2             free      ->
 3 COM MOUSE   SYS/free  ?>
 4 COM MOUSE   SYS/free  ?>
 5 SOUND BL.   SYS
 6 FLOPPY      SYS
 7             free      ->
 8             free      ->
 9             free      ->
10             free      ->
11             free      ->
12 PS2 MOUSE   SYS/free  ?>
13 MATH PR.    SYS
14 IDE         SYS
15 IDE         SYS

An example of processing Real-Time data:

<syntaxhighlight>

;
REAL-TIME DATA  ;
;
Compile with FASM for Menuet  ;
;

use32

org 0x0

db 'MENUET01' ; 8 byte id for application dd 1, START, I_END, 0x100000, 0x7fff0, 0x0, 0x0

include 'macros.inc'

START:  ; start of execution

       call    draw_window            ; at first, draw the window
       call    program_real_time_data ; program the OS to receive real time data
       call    program_com_port       ; program the com port for specific device

event_wait:

       mov     eax, 10                ; wait here for event
       mcall
       cmp     eax, 1                 ; redraw request ?
       je      red
       cmp     eax, 2                 ; key in buffer ?
       je      key
       cmp     eax, 3                 ; button in buffer ?
       je      button
       cmp     eax, 16 + 4            ; RT: new event for wanted IRQ data (16+IRQ)
       je      read_rt
       jmp     event_wait
The next section reads the event and processes data.

read_rt:  ; RT data

       mov     eax, 42                ; Function 42 returns recorded data for IRQ 4
       mov     ebx, 4                 ;
       mcall                          ; OS returns the recorded data.
                                      ; eax  number of bytes in buffer left
                                      ; bl   data
                                      ; ecx  0 = success, other = no data in buf.
       call    process_data
       jmp     event_wait

red:  ; redraw

       call    draw_window
       jmp     event_wait

key:  ; key

       mov     eax, 2                 ; just read it and ignore
       mcall
       jmp     event_wait

button:  ; button

       mov     eax, 17                ; get id
       mcall
       cmp     ah, 1                  ; button id=1 ?
       jne     noclose
  
       call    free_real_time_data
  
       mov     eax, -1                ; close this program
       mcall

noclose:

       jmp     event_wait

program_real_time_data:

       ; Program the Real-Time data fetch
       ;
       ; 1) reserve I/O port area
       ; 2) reserve IRQ
       ; 3) program IRQ
       ; 4) program EVENT list for wanted IRQ
       pusha
       mov     eax, 46                ; reserve ports 0x3f0 - 0x3ff
       mov     ebx, 0
       mov     ecx, 0x3f0
       mov     edx, 0x3ff
       mcall
       mov     eax, 45                ; reserve irq 4
       mov     ebx, 0
       mov     ecx, 4
       mcall
       mov     eax, 44                ; set read ports for irq 4
       mov     ebx, irqtable
       mov     ecx, 4
       mcall
       mov     eax, 40                              ; get com 1 data with irq 4
       mov     ebx, 0000000000010000b shl 16 + 111b ; after this we have a new event (16+4)
       mcall
       popa
       ret

irqtable:

   dd  0x3f8+0x01000000 ; 3f8 =port to read  : 01 =read byte, 02 =read word
   dd  0x0              ; 0x0 = termintes read per IRQ event
   dd  0x0
   dd  0x0
   dd  0x0
   dd  0x0
   dd  0x0
   dd  0x0
   dd  0x0
   dd  0x0
   dd  0x0
   dd  0x0
   dd  0x0
   dd  0x0
   dd  0x0
   dd  0x0

free_real_time_data:

       ; Free the used resources
       ;
       ; 1) get default events
       ; 2) free irq with function 45,1
       ; 3) free port area with function 46,1
       pusha
       mov     eax, 40                ; default events - disable irq 4 event
       mov     ebx, 111b
       mcall
       mov     eax, 45                ; free irq
       mov     ebx, 1
       mov     ecx, 4
       mcall
       mov     eax, 46                ; free ports 0x3f0-0x3ff
       mov     ebx, 1
       mov     ecx, 0x3f0
       mov     edx, 0x3ff
       mcall
       popa
       ret
The following functions are for processing device specific data.

process_data:

       cmp     ebx, 80
       jne     .nocd
       mov     eax, 19
       mov     ebx, cdplayer
       mov     ecx, 0
       mcall
 .nocd:
       push    ebx
       mov     eax, [pos]
       add     eax, 1
       cmp     eax, 10 * 20 + 1
       jb      .noeaxz
       mov     esi, text + 10 * 4
       mov     edi, text
       mov     ecx, 10 * 21 * 4
       cld
       rep     movsb
       mov     eax, 13
       mov     ebx, 20 * 65536 + 260
       mov     ecx, 22 * 65536 + 220
       mov     edx, [wcolor]
       mcall
       mov     eax,10*19+1
 .noeaxz:
       mov     [pos],eax
       pop     ebx
       and     ebx,0xff
       call    draw_data
       ret

draw_data:

       pusha
       xchg    eax, ebx
       mov     ecx, 10
       shl     ebx, 2
       mov     esi, 3
 .newnum:
       xor     edx, edx
       div     ecx
       add     edx, 48
       mov     [ebx + text - 1], dl
       dec     ebx
       dec     esi
       jnz     .newnum
       call    draw_text
       popa
       ret

draw_text:

       pusha
  
       mov     ebx, 25 * 65536 + 35   ; draw info text with function 4
       mov     ecx, 0xffffff
       mov     edx, text
       mov     esi, 40
       mov     edi, 20
 .newline:
       mov     eax,4
       mcall
       add     ebx,10
       add     edx,40
       dec     edi
       jne     .newline
       popa
       ret

program_com_port:

       ; the following sequence programs COM port for infrared receiver
       mov     cx, 0x3f3 + 8
       mov     bl, 0x80
       mov     eax, 43
       mcall
       mov     cx, 0x3f1 + 8
       mov     bl, 0
       mov     eax, 43
       mcall
       mov     cx, 0x3f0 + 8
       mov     bl, 0x30 / 4
       mov     eax, 43
       mcall
       mov     cx, 0x3f3 + 8
       mov     bl, 3
       mov     eax, 43
       mcall
       mov     cx, 0x3f4 + 8
       mov     bl, 0xB
       mov     eax, 43
       mcall
       mov     cx, 0x3f1 + 8
       mov     bl, 1
       mov     eax, 43
       mcall
       mov     eax, 5
       mov     ebx, 100
       mcall
   
       mov     cx, 0x3f8
       mov     bl, 'I'
       mov     eax, 43
       mcall
       mov     eax, 5
       mov     ebx, 10
       mcall
       mov     cx, 0x3f8
       mov     bl, 'R'
       mov     eax, 43
       mcall
       ret
              • WINDOW DEFINITIONS AND DRAW ********

draw_window:

       mov     eax, 12                ; function 12:tell os about windowdraw
       mov     ebx, 1                 ; 1, start of draw
       mcall
  
       ; DRAW WINDOW
       mov     eax, 0                 ; function 0 : define and draw window
       mov     ebx, 100 * 65536 + 300 ; [x start] *65536 + [x size]
       mov     ecx, 100 * 65536 + 250 ; [y start] *65536 + [y size]
       mov     edx, [wcolor]          ; color of work area RRGGBB,8->color
       mov     esi, 0x8099bbff        ; color of grab bar  RRGGBB,8->color glide
       mov     edi, 0x00ffffff        ; color of frames    RRGGBB
       mcall
  
       ; WINDOW LABEL
       mov     eax, 4                 ; function 4 : write text to window
       mov     ebx, 8 * 65536 + 8     ; [x start] *65536 + [y start]
       mov     ecx, 0x00ffffff        ; color of text RRGGBB
       mov     edx, labelt            ; pointer to text beginning
       mov     esi, labellen - labelt ; text length
       mcall
  
       ; CLOSE BUTTON
       mov     eax, 8                 ; function 8 : define and draw button
       mov     ebx, (300 - 19) * 65536 + 12 ; [x start] *65536 + [x size]
       mov     ecx, 5 * 65536 + 12    ; [y start] *65536 + [y size]
       mov     edx, 1                 ; button id
       mov     esi, 0x5599cc          ; button color RRGGBB
       mcall
  
       call    draw_text
  
       mov     eax, 12
       mov     ebx, 2
       mcall
  
       ret
DATA AREA

wcolor dd 0x0 pos dd 0x0

cdplayer db 'CDPLAY ' labelt db 'INFRARED RECEIVER FOR IRMAN IN COM 1' labellen:

text:

I_END: </syntaxhighlight>