MenuetOS The Assembly Language Programmers OS!


Home | Das Wiki | Screenshots | Dokumente | Downloads | Foren | Kontakt

mit MenuetOS programmieren

1) Anwendungsprogrammierung

   1a) Struktur einer Anwendung
   1b) Assembler Beispiel
   1c) einheitliche Systemfarben benutzen
   1d) freie Fensterform
   1e) Threads
   1f) Real-Time Daten




             1) ANWENDUNGSPROGRAMMIERUNG FÜR MENUET-OS
             ========================================


                1a) Struktur einer Anwendung
                ===============================


Für Menuet zu programmieren ist so leicht, als wenn du als erstes
die Basisstruktur einer Anwendung lernst. An diesem Punkt nehme ich
an, dass du einige Erfahrungen in der Assemblersprache hast.

Die MenuetOS API (Application Programming Interface) ist ein einfach-zu-
lernender Funktionssatz mit praktisch keinem Hierarchichem Zugriff.

Das arbeiten einer Anwendung basiert auf Ereignissen.

Die Anwendung wird mit dem Ereignistyp und der entsprechenden Anwendungshandlung
beim OS registriert. Es gibt 3 Ereignistypen die eine Anwendung erwartet
Standard-Handles: Fenster neuzeichnen, Tastendruck und Buttondruck.

Flussdiagramm und Struktur einer Anwendung mit Standardereignissen:

  ;;;;;;;;;;;;;;;;;;;;;;;;;
  ;                       ;
  ;     HEADER DATEN      ;
  ;                       ;
  ;;;;;;;;;;;;;;;;;;;;;;;;;

START:

  call draw_window

  ;;;;;;;;;;;;;;;;;;;;;;;;;
  ;                       ;
  ;  WARTEN AUF EREIGNIS  ;  <--------------------------------------------------I
  ;                       ;                                                     I
  ;;;;;;;;;;;;;;;;;;;;;;;;;                                                     I
            I                                                                   I
  ;;;;;;;;;;;;;;;;;;;;;;;;;                                                     I
  ;                       ;     neuzeichnen ->  call draw_window             -> I
  ;  EREIGNISTYP AUSLESEN ; ->  Taste       ->  read keypress    -> process  -> I
  ;                       ;     Button      ->  read buttonpress -> process  -> I
  ;;;;;;;;;;;;;;;;;;;;;;;;;


draw_window:

  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;                              ;
  ;ZEICHNE STATISCHE FENSTERTEILE;
  ;                              ;
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

  ret


DATEN-BEREICH:

  ;;;;;;;;;;;;;;;;;;;;;;;;
  ;                      ;
  ;   STATISCHE DATEN    ;
  ;                      ;
  ;;;;;;;;;;;;;;;;;;;;;;;;

(Ende des Bildes)





                     1b) Assembler Beispiele
                     =======================


Eine stark kommentierte Realisierung der Assemblersprache von der oberen Struktur (1a).

Menuet Systemaufrufe werden mit dem 'int 0x40' Kommando mit der Funktions-
Nummer im Register eax und anderen Registern, wenn notwendig, ausgeführt.

Details von allen im moment Verfügbaren Systemaufrufen sind in der Sektion
(1g) Systemfunktionen.



;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                  ;
;      BEISPIELANWENDUNG                           ;
;                                                  ;
;      Compiliere mit FASM für Menuet              ;
;                                                  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Der Header

use32                                 ; Compiler um 32 Bit Instructions zu verwenden

               org    0x0             ; Die Basisadresse des Codes, immer 0x0

               db     'MENUET01'      ; 8 Byte ID für Anwendung
               dd     0x01            ; Header Version
               dd     START           ; Start der Ausführung
               dd     I_END           ; größe des Bildes
               dd     0x100000        ; zu benutzende Speichermenge
                                      ; Du hast Zugriff auf den Speicher von 0x0 bis
                                      ; zu dem hier definierten Wert. Die Verlegung
                                      ; des Codes wird mit den Selektoren erledigt
                                      ; die vom OS gesetzt werden.
               dd     0x7fff0         ; Stack-Position im Speicherbereich
               dd     0x0             ; Parameter passiert Wert
                                      ; wenn der Wert was anderes als 0 ist, werden
                                      ; die möglichen Parameter beim Start gesendet.
               dd     0x0             ; Reserviert für Icon


; Der Code-Bereich


START:                          ; Start der Ausführung

    call draw_window            ; zeichnen des Fensters


; Nachdem das Fenster gezeichnet ist, ist es praktisch eine Hauptschleife zu haben.
; Ereignisse werden von hier aus verteilt.

event_wait:


    mov  eax,10                 ; Funktion 10 : warte auf Ereignis
    int  0x40
                                ; Ereignistyp wird in eax zurückgegeben

    cmp  eax,1                  ; Ereignis Anfrage auf neuzeichnen?
    je   red                    ; Erkl.: Es gab Aktivitäten auf dem Bildschirm und
                                ; teile der Anwendung müssen neu gezeichnet werden.

    cmp  eax,2                  ; Ereignis Taste im Puffer ?
    je   key                    ; Erkl.: Benutzer hat eine Taste gedrückt während die
                                ; Anwendung im Vordergrund war.

    cmp  eax,3                  ; Ereignis Button im Puffer ?
    je   button                 ; Erkl.: Benutzer hat einen der
                                ; Anwendungs-Buttons gedrückt.

    jmp  event_wait



;  Der nächste Abschnitt liest die Ereignisse und verarbeitet die Daten.


  red:                          ; Ereignishandler: neuzeichnen
    call draw_window            ; Wir rufen die window_draw Funktion auf und
    jmp  event_wait             ; springen zurück zu event_wait

  key:                          ; Ereignishandler: Tastendruck
    mov  eax,2                  ; Die Taste wird in ah zurückgegeben. Die Taste muss
    int  0x40                   ; ausgelesen und von der Systemwarteschlange gelöscht werden.
    jmp  event_wait             ; Lies die Taste aus, ignoriere es und springe zu
                                ; event_wait.

  button:                       ; Ereignishandler: Buttondruck
    mov  eax,17                 ; Die Button-Nummerdie in window_draw definiert ist
    int  0x40                   ; wird in ah zurückgegeben.

    cmp  ah,1                   ; Button ID=1 ?
    jne  noclose
    mov  eax,-1                 ; Funktion -1 : schließe dieses Programm
    int  0x40
  noclose:

    jmp  event_wait             ; Dies wird für ignorierte Ereignisse verwendet,
                                ; nützlich für Entwicklung


;  *************************************************
;  ******  FENSTER-DEFINITIONEN UND ZEICHNEN  ******
;  *************************************************
;
;  Die statischen Fensterteile werden in dieser Funktion gezeichnet. Auf die Fensterleinwand
;  kann später von jedem teil des Codes (Threads) aus zugegriffen werden um z.B. Prozesse oder
;  aufgenommene Daten anzuzeigen.
;
;  Die statischen Teile *müssen* innerhalb der Funktionsnummer 12 platziert werden,
;  ebx = 1 und ebx = 2.

draw_window:


    mov  eax,12                    ; Funktion 12: dem OS mitteilen, dass Fenster gezeichnet werden soll
    mov  ebx,1                     ; 1, zeichnen starten
    int  0x40

                                   ; ZEICHNE FENSTER
    mov  eax,0                     ; Funktion 0 : definiere und zeichne Fenster
    mov  ebx,100*65536+300         ; [x start] *65536 + [x gr��e]
    mov  ecx,100*65536+120         ; [y start] *65536 + [y gr��e]
    mov  edx,0x02ffffff            ; Farbe des Arbeitsbereichs RRGGBB
                                   ; 0x02000000 = Fenstertyp 2
    mov  esi,0x808899ff            ; Farbe der Titelleiste  RRGGBB
                                   ; 0x80000000 = Farbverlauf
    mov  edi,0x008899ff            ; Rahmenfarbe RRGGBB
    int  0x40

                                   ; FENSTERBEZEICHNUNG
    mov  eax,4                     ; Funktion 4 : schreibe Text zum Fenster
    mov  ebx,8*65536+8             ; [x start] *65536 + [y start]
    mov  ecx,0x00ddeeff            ; Textfarbe RRGGBB
    mov  edx,labelt                ; Zeiger auf Textanfang
    mov  esi,labellen-labelt       ; Textlänge
    int  0x40

                                   ; BUTTON SCHLIE�EN
    mov  eax,8                     ; Funktion 8 : definiere und zeichne Button
    mov  ebx,(300-19)*65536+12     ; [x start] *65536 + [x größe]
    mov  ecx,5*65536+12            ; [y start] *65536 + [y größe]
    mov  edx,1                     ; Button ID
    mov  esi,0x6677cc              ; Buttonfarbe RRGGBB
    int  0x40


    mov  ebx,25*65536+35           ; zeichne Info-Text mit der Funktion 4
    mov  ecx,0x224466
    mov  edx,text
    mov  esi,40
    newline:                       ; Text vom DATENBEREICH
    mov  eax,4
    int  0x40
    add  ebx,10
    add  edx,40
    cmp  [edx],byte 'x'
    jne  newline

    mov  eax,12                    ; Funktion 12: dem OS über das Fensterzeichnen informieren
    mov  ebx,2                     ; 2, Ende des zeichnens
    int  0x40

    ret



;  *********************************************
;  *************  DATENBEREICH  ****************
;  *********************************************
;
; Daten können frei mit dem Code jeden teils des Images vermischt werden.
; Nur die Header-Informationen wird am Anfang des Images benötigt.


text:       db  'DIES IST EIN BEISPIELPROGRAMM, DASS DU               '
            db  'BENUTZEN KANNST, A:\EXAMPLE.ASM CODE IST KOMMENTIERT '
            db  'UND KLAR. SYSTEMFUNKTIONEN SIND IN DER DATEI         '
            db  'SYSFUNCS.TXT UND KOMMANDOS IN CMD.TXT                '
            db  'x <- ENDMARKIERUNG, NICHT LÖSCHEN                 '

labelt:     db  'BEISPIELANWENDUNG'
labellen:


I_END:


; Der Bereich nach I_END frei als Anwendungsspeicher zu benutzen,
; vermeide den Stack.
;
; Struktur des Anwendungsspeicher, aufgrund des benutzten Headers, 1MB.
;
; 0x00000   - Beginn des compilierten Images
; I_END     - Ende des compilierten Images
;
;           + Frei zur Nutzung in der Anwendung
;
; 0x7ff00   - Beginn des Stack-Bereichs
; 0x7fff0   - Ende des Stack-Bereichs                 - definiert im Header
;
;           + Frei zur Nutzung in der Anwendung
;
; 0xFFFFF   - Ende des frei nutzbaren Speichers       - definiert im Header
;
; Die ganzen Bereiche können mit einer direkten Referenz innerhalb
; der Anwendung modifiziert werden.
; Zum Beispiel, mov [0x80000], Byte 1 bewegt ein Byte über den Stack-Bereich.

Menuet's Anwendungsstruktur ist nicht für die Assemblerprogrammierung
reserviert, der Header kann praktisch in jeder anderen Sprache erzeugt
werden. Jedenfalls ist das allgemeine Anwendungsprogrammierdesign für
32 Bit Assemblerprogrammierung vorgesehen. Die GUI ist extrem einfach
mit einer besonderen Assemblersprache zu Handlen.





               1c) einheitliche Systemfarben benutzen
               ======================================


Während die vorigen Beispiele sich auf eine Basisanwendung konzentriert haben,
wird in dieser Sektion mehr Wert auf das aussehen des Fensters gelegt.

Du kannst einheitliche Desktopfarben benutzen die von einem Farbsetup definiert wurden.

Die neue Funktion in diesem Beispiel ist get_system_colours.


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                  ;
;      BEISPIEL EINHEITLICHE SYSTEMFARBEN          ;
;                                                  ;
;      Compiliert mit FASM für Menuet              ;
;                                                  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Der Header

use32                                 ; compiler um 32 Bit Instruktionen zu nutzen

               org    0x0             ; Die Basisadresse für den Code, immer 0x0

               db     'MENUET01'      ; 8 Byte ID für Anwendung
               dd     0x01            ; Header Version
               dd     START           ; Start der Ausführung
               dd     I_END           ; größe des Images
               dd     0x100000        ; zu benutzende Speichermenge
                                      ; Du hast Zugriff auf den Speicher von 0x0 bis
                                      ; zu dem hier definierten Wert. Die Verlegung
                                      ; des Codes wird mit den Selektoren erledigt
                                      ; die vom OS gesetzt werden.
               dd     0x7fff0         ; Stack-Position im Speicherbereich
               dd     0x0             ; Parameter passiert Wert
                                      ; wenn der Wert was anderes als 0 ist, werden
                                      ; die möglichen Parameter beim Start gesendet.
               dd     0x0             ; Reserviert für Icon



; Der Code-Bereich


window_size_X  equ  300
window_size_Y  equ  150


START:                          ; Ausführungsstart

    call draw_window            ; Fenster zeichnen


; Nachdem das Fenster gezeichnet ist, ist es praktisch eine Hauptschleife zu haben.
; Ereignisse werden von hier aus verteilt.

event_wait:


    mov  eax,10                 ; Funktion 10 : auf ein Ereignis warten
    int  0x40
                                ; Ereignistyp wird in eax zurückgegeben

    cmp  eax,1                  ; Ereignis Anfrage auf neuzeichnen?
    je   red                    ; Erkl.: Es gab Aktivitäten auf dem Bildschirm und
                                ; teile der Anwendung müssen neu gezeichnet werden.

    cmp  eax,2                  ; Ereignis Taste im Puffer ?
    je   key                    ; Erkl.: Benutzer hat eine Taste gedrückt während die
                                ; Anwendung im Vordergrund war.

    cmp  eax,3                  ; Ereignis Button im Puffer ?
    je   button                 ; Erkl.: Benutzer hat einen der
                                ; Anwendungs-Buttons gedrückt.

    jmp  event_wait



;  Der nächste Abschnitt liest die Ereignisse und verarbeitet die Daten.


  red:                          ; Ereignishandler: neuzeichnen
    call draw_window            ; Wir rufen die window_draw Funktion auf und
    jmp  event_wait             ; springen zurück zu event_wait

  key:                          ; Ereignishandler: Tastendruck
    mov  eax,2                  ; Die Taste wird in ah zurückgegeben. Die Taste muss
    int  0x40                   ; ausgelesen und von der Systemwarteschlange gelöscht werden.
    jmp  event_wait             ; Lies die Taste aus, ignoriere es und springe zu
                                ; event_wait.

  button:                       ; Ereignishandler: Buttondruck
    mov  eax,17                 ; Die Button-Nummerdie in window_draw definiert ist
    int  0x40                   ; wird in ah zur�ckgegeben.

    cmp  ah,1                   ; Button ID=1 ?
    jne  noclose
    mov  eax,-1                 ; Funktion -1 : schließe dieses Programm
    int  0x40
  noclose:

    jmp  event_wait             ; Dies wird für ignorierte Ereignisse verwendet,
                                ; nützlich für Entwicklung


get_system_colours:

    pusha

    mov  eax,48                       ; Funktionsnummer 48: Systemfarben
    mov  ebx,3                        ; Unter-Funktionsnummer 3: ermitteln
    mov  ecx,app_colours              ; Zeiger auf Rückkehrbereich
    mov  edx,10*4                     ; Anzahl der zurückzugebenden Bytes
    int  0x40

    popa

    ret


app_colours:                          ; SYSTEMFARB-TABELLE

w_frames             dd 0x0           ; - Rahmen
w_grab               dd 0x0           ; - GRAB-Bereich
w_grab_button        dd 0x0           ;   Grab-Bereich Button
w_grab_button_text   dd 0x0           ;   Grab-Bereich Buttontext
w_grab_text          dd 0x0           ;   Grab-Bereich Text
w_work               dd 0x0           ; - Arbeitsbereich
w_work_button        dd 0x0           ;   Arbeitsbereich Button
w_work_button_text   dd 0x0           ;   Arbeitsbereich Buttontext
w_work_text          dd 0x0           ;   Arbeitsbereich Text
w_work_graph         dd 0x0           ;   Arbeitsbereich Grafiken



;  *************************************************
;  ******  FENSTER-DEFINITIONEN UND ZEICHNEN  ******
;  *************************************************
;
;  Die statischen Fensterteile werden in dieser Funktion gezeichnet. Auf die Fensterleinwand
;  kann später von jedem teil des Codes (Threads) aus zugegriffen werden um z.B. Prozesse oder
;  aufgenommene Daten anzuzeigen.
;
;  Die statischen Teile *müssen* innerhalb der Funktionsnummer 12 platziert werden,
;  ebx = 1 und ebx = 2.

draw_window:


    mov  eax,12                    ; Funktion 12: dem OS mitteilen, dass Fenster gezeichnet werden soll
    mov  ebx,1                     ; 1, zeichnen starten
    int  0x40

                                   ; ZEICHNE FENSTER
    mov  eax,0                     ; Funktion 0 : definiere und zeichne Fenster
    mov  ebx,100*65536+300         ; [x start] *65536 + [x größe]
    mov  ecx,100*65536+120         ; [y start] *65536 + [y größe]
    mov  edx,0x02ffffff            ; Farbe des Arbeitsbereichs RRGGBB
                                   ; 0x02000000 = Fenstertyp 2
    mov  esi,0x808899ff            ; Farbe der Titelleiste  RRGGBB
                                   ; 0x80000000 = Farbverlauf
    mov  edi,0x008899ff            ; Rahmenfarbe RRGGBB
    int  0x40

                                   ; FENSTERBEZEICHNUNG
    mov  eax,4                     ; Funktion 4 : schreibe Text zum Fenster
    mov  ebx,8*65536+8             ; [x start] *65536 + [y start]
    mov  ecx,0x00ddeeff            ; Textfarbe RRGGBB
    mov  edx,labelt                ; Zeiger auf Textanfang
    mov  esi,labellen-labelt       ; Textlänge
    int  0x40

                                   ; BUTTON SCHLIEßEN
    mov  eax,8                     ; Funktion 8 : definiere und zeichne Button
    mov  ebx,(300-19)*65536+12     ; [x start] *65536 + [x größe]
    mov  ecx,5*65536+12            ; [y start] *65536 + [y größe]
    mov  edx,1                     ; Button ID
    mov  esi,0x6677cc              ; Buttonfarbe RRGGBB
    int  0x40


    mov  ebx,25*65536+35           ; zeichne Info-Text mit der Funktion 4
    mov  ecx,0x224466
    mov  edx,text
    mov  esi,40
    newline:                       ; Text vom DATENBEREICH
    mov  eax,4
    int  0x40
    add  ebx,10
    add  edx,40
    cmp  [edx],byte 'x'
    jne  newline

    mov  eax,12                    ; Funktion 12: dem OS über das Fensterzeichnen informieren
    mov  ebx,2                     ; 2, Ende des zeichnens
    int  0x40

    ret


;  *********************************************
;  *************  DATENBEREICH  ****************
;  *********************************************
;
; Daten können frei mit dem Code jeden teils des Images vermischt werden.
; Nur die Header-Informationen wird am Anfang des Images benötigt.


text:       db  'DIES IST EIN BEISPIELPROGRAMM, DASS DU               '
            db  'BENUTZEN KANNST, A:\EXAMPLE.ASM CODE IST KOMMENTIERT '
            db  'UND KLAR. SYSTEMFUNKTIONEN SIND IN DER DATEI         '
            db  'SYSFUNCS.TXT UND KOMMANDOS IN CMD.TXT                '
            db  'x <- ENDMARKIERUNG, NICHT LÖSCHEN                 '

labelt:     db  'BEISPIELANWENDUNG'
labellen:

I_END:





                1d) Freiform Fenster
                ====================


In diesem Beispiel konzentrieren wir uns auf die Gestaltung der Fenster vom Rechteck
über jede Form die der Programmierer wünscht. Die neue Funktion in diesem Beispiel
ist shape_window.


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                  ;
;      FREIFORM BEISPIELANWENDUNG                  ;
;                                                  ;
;      Compiliert mit FASM für Menuet              ;
;                                                  ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

; Der Header

use32                                 ; compiler um 32 Bit Instruktionen zu nutzen

               org    0x0             ; Die Basisadresse für den Code, immer 0x0

               db     'MENUET01'      ; 8 Byte ID für Anwendung
               dd     0x01            ; Header Version
               dd     START           ; Start der Ausführung
               dd     I_END           ; größe des Images
               dd     0x100000        ; zu benutzende Speichermenge
                                      ; Du hast Zugriff auf den Speicher von 0x0 bis
                                      ; zu dem hier definierten Wert. Die Verlegung
                                      ; des Codes wird mit den Selektoren erledigt
                                      ; die vom OS gesetzt werden.
               dd     0x7fff0         ; Stack-Position im Speicherbereich
               dd     0x0             ; Parameter passiert Wert
                                      ; wenn der Wert was anderes als 0 ist, werden
                                      ; die möglichen Parameter beim Start gesendet.
               dd     0x0             ; Reserviert für Icon



START:                          ; Ausführungsstart

    call shape_window           ; Funktion für die Gestaltung

    call draw_window            ; zuerst, zeichne das Fenster

still:

    mov  eax,10                 ; hier auf Ereignisse warten
    int  0x40

    cmp  eax,1                  ; neuzeichnen Anfrage ?
    je   red
    cmp  eax,2                  ; Taste im Puffer ?
    je   key
    cmp  eax,3                  ; Button im Puffer ?
    je   button

    jmp  still

  red:                          ; neuzeichnen
    call draw_window
    jmp  still

  key:                          ; Taste
    mov  eax,2                  ; nur auslesen und ignorieren
    int  0x40
    jmp  still

  button:                       ; Button
    mov  eax,17                 ; ID ermitteln
    int  0x40

    cmp  ah,1                   ; Button-ID=1 ?
    jne  noclose
    mov  eax,-1                 ; schließe dieses Programm
    int  0x40
  noclose:

    jmp  still


shape_window:

    pusha

    mov  eax,50       ; den Referenzbereich angeben
    mov  ebx,0
    mov  ecx,shape_reference
    int  0x40

    mov  eax,50       ; die Skalierung angeben  32 x 32  ->  128 x 128
    mov  ebx,1        ; Dies musst du nicht angeben, Skalierung ist Standardmäßig 1:1
    mov  ecx,2        ; Sklalierung ist auf 2^ecx gesetzt
    int  0x40

    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


;   **********************************************
;   ****** FENSTERDEFINITIONEN UND ZEICHNEN ******
;   **********************************************


draw_window:

    mov  eax,12                    ; Funktion 12: dem OS über Fensterzeichnen informieren
    mov  ebx,1                     ; 1, zeichnen starten
    int  0x40

                                   ; FENSTER ZEICHNEN
    mov  eax,0                     ; Funktion 0: definiere und zeichne Fenster
    mov  ebx,100*65536             ; [x start] *65536 + [x größe]
    mov  ecx,100*65536             ; [y start] *65536 + [y größe]
    mov  bx,word [x_gr��e]
    mov  cx,word [y_gr��e]
    mov  edx,0x00cccc00            ; Farbe des Arbeitsbereichs RRGGBB,8->Farbverlauf
    mov  esi,0x00cccc00            ; Farbe der Titelleiste     RRGGBB,8->Farbverlauf
    mov  edi,0x00cccc00            ; Rahmenfarbe               RRGGBB
    int  0x40


                                   ; SCHLIEßEN-BUTTON
    mov  eax,8                     ; Funktion 8: definiere und zeichne Button
    mov  ebx,78*65536+12           ; [x start] *65536 + [x größe]
    mov  ecx,20*65536+12           ; [y start] *65536 + [y größe]
    mov  edx,1                     ; Button-ID
    mov  esi,0x5599cc              ; Buttonfarbe RRGGBB
    int  0x40


    mov  eax,12                    ; Funktion 12: dem OS über Fensterzeichnen informieren
    mov  ebx,2                     ; 2, Ende des zeichnens
    int  0x40

    ret

; DATEN

x_size  dd  127
y_size  dd  127

I_END:




                         1e) Threads
                         ===========


MenuetOS Assembler-Threading hat einige großartige vorteile gegenüber
Hochsprachen. Wenn du alle Variablen in Registern lässt, kannst du
soviele Threads im selben Code starten wie du möchtest, solange kein
Speicher berührt wird und nicht gespeichert werden muss. Die Register
werden in den Task-Switch Segmenten von MenuetOS gespeichert. Alles
was du tun musst, ist einen neuen Stack anzulegen.

Threads haben keinen unterschied mit dem Hauptprozess und benutzen
denselben Speicherbereich wie der Prozess der ihn gestartet hat. Sie
können ihre eigenen unabhängigen Fenster usw. haben. Beim beenden
der Anwendung, müssen alle Threads mit dem Standard-Systemaufruf
(eax = -1) beendet werden.

Die neue Funktion in diesem Beispiel ist create_thread.


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                      ;
;   THREAD BEISPIEL                                    ;
;                                                      ;
;   Compiliert mit FASM für Menuet                     ;
;                                                      ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

use32

               org    0x0

               db     'MENUET01'              ; 8 Byte ID
               dd     0x01                    ; Header Version
               dd     START                   ; Beginn des Codes
               dd     I_END                   ; größe des Images
               dd     0x100000                ; Speicher für die Anwendung
               dd     0x80000                 ; esp
               dd     0x0 , 0x0               ; I_Param , I_Icon




START:                          ; Beginn der Ausführung

    call draw_window            ; zuerst, zeichne das Fenster

event_wait:

    mov  eax,10                 ; hier auf Ereignis warten
    int  0x40

    cmp  eax,1                  ; neuzeichnen Anfrage ?
    je   red
    cmp  eax,2                  ; Taste im Puffer ?
    je   key
    cmp  eax,3                  ; Button im Puffer ?
    je   button

    jmp  event_wait

  red:                          ; neuzeichnen
    call draw_window
    jmp  event_wait

  key:                          ; Taste
    mov  eax,2                  ; auslesen und ignorieren
    int  0x40
    jmp  event_wait

  button:                       ; Button
    mov  eax,17                 ; ID ermitteln
    int  0x40

    cmp  ah,1                   ; Button-ID=1 ?
    jne  noclose
    mov  eax,-1                 ; schließe dieses Programm (Thread)
    int  0x40
  noclose:

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

    jmp  event_wait


; THREAD ERZEUGEN
;
; Alles was wir tun müssen, ist, die Thread-Einstiegsadresse mit der
; Funktion eax=51, ebx=1 in ecx und eine neue Stack-Position in edx
; anzugeben

create_thread:

    cmp  [thread_stack],0xf0000
    jge  no_new_thread

    add  [thread_stack],0x1000

    mov  eax,51                   ; thread_create Systemaufruf
    mov  ebx,1
    mov  ecx,START
    mov  edx,[thread_stack]
    int  0x40

  no_new_thread:

    ret

thread_stack dd 0x80000


;   **********************************************
;   ****** FENSTERDEFINITIONEN UND ZEICHNEN ******
;   **********************************************


draw_window:

    mov  eax,12                    ; Funktion 12: Das OS über das Fensterzeichnen informieren
    mov  ebx,1                     ; 1, zeichnen starten
    int  0x40

                                   ; FENSTER ZEICHNEN
    mov  eax,0                     ; Funktion 0: definiere und zeichne Fenster
    mov  ebx,10*65536+300          ; [x start] *65536 + [x gr��e]
    mov  ecx,10*65536+140          ; [y start] *65536 + [y gr��e]
    mov  esi,[thread_stack]
    sub  esi,0x80000
    shr  esi,11
    shl  esi,16
    add  ebx,esi
    add  ecx,esi
    mov  edx,0x02ffffff            ; Farbe des Arbeitsbereichs RRGGBB,8->Farbverlauf
    mov  esi,0x808899ff            ; Farbe der Titelleiste     RRGGBB,8->Farbverlauf
    mov  edi,0x008899ff            ; Farbe des Rahmens         RRGGBB
    int  0x40

                                   ; FENSTERBEZEICHNUNG
    mov  eax,4                     ; Funktion 4: schreibe Text zum Fenster
    mov  ebx,8*65536+8             ; [x start] *65536 + [y start]
    mov  ecx,0x00ddeeff            ; Textfarbe RRGGBB
    mov  edx,labelt                ; Zeiger auf Textanfang
    mov  esi,labellen-labelt       ; Textlänge
    int  0x40

                                   ; SCHLIEßEN-BUTTON
    mov  eax,8                     ; Funktion 8: definiere und zeichne Button
    mov  ebx,(300-19)*65536+12     ; [x start] *65536 + [x größe]
    mov  ecx,5*65536+12            ; [y start] *65536 + [y größe]
    mov  edx,1                     ; Button-ID
    mov  esi,0x6677cc              ; Buttonfarbe RRGGBB
    int  0x40

    mov  eax,8                     ; NEUER THREAD-BUTTON
    mov  ebx,25*65536+128
    mov  ecx,88*65536+20
    mov  edx,2
    mov  esi,0x6677cc
    int  0x40

    mov  ebx,25*65536+35           ; zeichne Infotext mit der Funktion 4
    mov  ecx,0x224466
    mov  edx,text
    mov  esi,40
  newline:
    mov  eax,4
    int  0x40
    add  ebx,10
    add  edx,40
    cmp  [edx],byte 'x'
    jne  newline

    mov  eax,12                    ; Funktion 12: OS über Fensterzeichnen informieren
    mov  ebx,2                     ; 2, Ende des zeichnens
    int  0x40

    ret


; DATEN-BEREICH


text:
    db 'DIESES BEISPIEL ERZEUGT THREADS INDEM ES          '
    db 'DENSELBEN CODE MEHRMALS AUSFÜHRT. ALLES WAS       '
    db 'WIR BRAUCHEN IST EIN NEUER STACK FÜR JEDEN THREAD.'
    db 'ALLE THREADS TEILEN SICH DENSELBEN SPEICHER.      '
    db '                                                  '
    db '                                                  '
    db '  NEUEN THREAD ERZEUGEN                           '

    db 'x <- ENDMARKIERUNG, NICHT LÖSCHEN              '


labelt:
     db   'THREADBEISPIEL'
labellen:

I_END:





                      1f) Echtzeit-Daten
                      ==================


Das folgende Beispiel konzentriert sich auf das Echtzeit Daten-holen und -verarbeiten.
Die Anwendung informiert das OS über alle Ports und Datentypen die an einem
bestimmten IRQ gelesen werden.

Schritte:

1) reserviere I/O Port-Bereich
2) reserviere IRQ
3) Programm-IRQ
4) Programm-EREIGNIS-Liste für den gewünschten IRQ

5) Laufzeit Verarbeitung der Daten

6) zurück zu den Standardereignissen - freier IRQ von der EREIGNIS-Liste
7) freier IRQ
8) freier Port-Bereich
9) beende Programm

Nachdem die IRQ's programmiert sind, hat die Anwendung ein neues Ereignis
für die Hauptereignisschleife, Nummer (IRQ+16).

Wenn die Anwendung dieses Ereignis empfängt, hat das OS die Daten für die
Anwendung aufgenommen um sie zu verarbeiten.

Die untere Tabelle zeigt die Hauptstruktur der zu verarbeitenden Echtzeit-Daten.

Die ganzen Schritte links vom (A) werden vom OS verarbeitet und die
Schritte rechts vom (A) sind von der Anwendung verarbeitet.


 IRQ           BESITZER   =>  REC DATEN (A) SYS_EVENT => DATEN LESEN => PROZESS

 0 TIMER       SYS
 1 TASTATUR    SYS
 2             frei      ->
 3 COM MAUS    SYS/frei  ?>
 4 COM MAUS    SYS/frei  ?>
 5 SOUND BL.   SYS
 6 DISKETTE    SYS
 7             frei      ->
 8             frei      ->
 9             frei      ->
10             frei      ->
11             frei      ->
12 PS2 MAUS    SYS/frei  ?>
13 MATH PR.    SYS
14 IDE         SYS
15 IDE         SYS


Ein Beispiel wie man Echtzeit-Daten verarbeitet:


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;                                                ;
;    ECHTZEIT-DATEN                              ;
;                                                ;
;    Compiliert mit FASM für Menuet              ;
;                                                ;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;


use32

                org     0x0

                db      'MENUET00'              ; 8 Byte ID
                dd      56                      ; benötigt OS
                dd      START                   ; Programm Start
                dd      I_END                   ; Programm Image größe
                dd      0x100000                ; benötigte Speichermenge
                                                ; esp = 0x7FFF0
                dd      0x00000000              ; reserviert=kein erweiterter Header



START:                          ; Beginn der Ausführung

    call draw_window            ; zuerst, zeichne das Fenster

    call program_real_time_data ; Programmiere das OS um Echtzeit-Daten zu empfangen

    call program_com_port       ; Programmiere den COM-Port für ein spezifisches Gerät

event_wait:

    mov  eax,10                 ; hier auf ein Ereignis warten
    int  0x40

    cmp  eax,1                  ; neuzeichnen Anfrage ?
    je   red
    cmp  eax,2                  ; Taste im Puffer ?
    je   key
    cmp  eax,3                  ; Button im Puffer ?
    je   button

    cmp  eax,16+4               ; RT: Neues Ereignis für die gewünschten IRQ-Daten (16+IRQ)
    je   read_rt

    jmp  event_wait


;  Die nächste Sektion liest die Ereignisse und verarbeitet die Daten.


  read_rt:                      ; RT Daten
    mov  eax,42                 ; Funktion 42 gibt die Daten für IRQ 4 zur�ck
    mov  ebx,4                  ;
    int  0x40                   ; OS gibt die aufgenommenen Daten zurück.
                                ; eax  restliche Anzahl an Bytes im Puffer
                                ; bl   Daten
                                ; ecx  0 = erfolg, andere = keine Daten im Puffer

    call process_data
    jmp  event_wait

  red:                          ; neuzeichnen
    call draw_window
    jmp  event_wait

  key:                          ; Taste
    mov  eax,2                  ; lesen und ignorieren
    int  0x40
    jmp  event_wait

  button:                       ; Button
    mov  eax,17                 ; ID ermitteln
    int  0x40


    cmp  ah,1                   ; Button-ID=1 ?
    jne  noclose

    call free_real_time_data

    mov  eax,-1                 ; schließe dieses Programm
    int  0x40
  noclose:

    jmp  event_wait



program_real_time_data:


    ;   holen der Echtzeit-Daten programmieren
    ;
    ;   1) reserviere I/O Port-Bereich
    ;   2) reserviere IRQ
    ;   3) Programmiere IRQ
    ;   4) Programmiere EREIGNIS-Liste für den gewünschten IRQ
    ;


    pusha

    mov  eax,46           ; reserviere Ports 0x3f0 - 0x3ff
    mov  ebx,0
    mov  ecx,0x3f0
    mov  edx,0x3ff
    int  0x40

    mov  eax,45           ; reserviere IRQ 4
    mov  ebx,0
    mov  ecx,4
    int  0x40

    mov  eax,44           ; setze lese-Ports für IRQ 4
    mov  ebx,irqtable
    mov  ecx,4
    int  0x40

    mov  eax,40                                 ; ermittle COM1 Daten mit IRQ 4
    mov  ebx,0000000000010000b shl 16 + 111b    ; nachdem wir das neue Ereignis
                                                ; haben (16+4)
    int  0x40

    popa

    ret



irqtable:

    dd  0x3f8+0x01000000 ; 3f8 = Port zum lesen  : 01 =Byte lesen, 02 =Wort lesen

    dd  0x0              ; 0x0 = beendet lesen über IRQ Ereignis
    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:

    ;  genutzte Resourcen freigeben
    ;
    ;  1) Standardereignisse ermitteln
    ;  2) IRQ mit Funktion 45,1 freimachen
    ;  3) Port-Bereich mit Funktion 46,1 freimachen
    ;


    pusha

    mov  eax,40                 ; Standardereignisse - IRQ 4 Ereignisse deaktivieren
    mov  ebx,111b
    int  0x40

    mov  eax,45                 ; IRQ freigeben
    mov  ebx,1
    mov  ecx,4
    int  0x40

    mov  eax,46                 ; Ports 0x3f0-0x3ff freigeben
    mov  ebx,1
    mov  ecx,0x3f0
    mov  edx,0x3ff
    int  0x40

    popa

    ret



; Die folgenden Funktionen sind zur Verarbeitung von Gerätespezifischen Daten.


process_data:

    cmp  ebx,80
    jne  nocd

    mov  eax,19
    mov  ebx,cdplayer
    mov  ecx,0
    int  0x40


  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]
    int  0x40
    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           ; zeichne den Info-Text mit Funktion 4
    mov  ecx,0xffffff
    mov  edx,text
    mov  esi,40
    mov  edi,20
  newline:
    mov  eax,4
    int  0x40
    add  ebx,10
    add  edx,40
    dec  edi
    jne  newline

    popa

    ret



program_com_port:

    ; Die folgende Sequenz programmiert den COM-Port für einen Infrarot-Empfänger

    mov  cx,0x3f3+8
    mov  bl,0x80
    mov  eax,43
    int  0x40

    mov  cx,0x3f1+8
    mov  bl,0
    mov  eax,43
    int  0x40

    mov  cx,0x3f0+8
    mov  bl,0x30 / 4
    mov  eax,43
    int  0x40

    mov  cx,0x3f3+8
    mov  bl,3
    mov  eax,43
    int  0x40

    mov  cx,0x3f4+8
    mov  bl,0xB
    mov  eax,43
    int  0x40

    mov  cx,0x3f1+8
    mov  bl,1
    mov  eax,43
    int  0x40

    mov  eax,5
    mov  ebx,100
    int  0x40

    mov  cx,0x3f8
    mov  bl,'I'
    mov  eax,43
    int  0x40

    mov  eax,5
    mov  ebx,10
    int  0x40

    mov  cx,0x3f8
    mov  bl,'R'
    mov  eax,43
    int  0x40

    ret





;   **********************************************
;   ****** FENSTERDEFINITIONEN UND ZEICHNEN ******
;   **********************************************


draw_window:

    mov  eax,12                    ; Funktion 12: OS über das Fensterzeichnen informieren
    mov  ebx,1                     ; 1, zeichnen beginnen
    int  0x40

                                   ; FENSTER ZEICHNEN
    mov  eax,0                     ; Funktion 0: definiere und zeichne Fenster
    mov  ebx,100*65536+300         ; [x start] *65536 + [x größe]
    mov  ecx,100*65536+250         ; [y start] *65536 + [y größe]
    mov  edx,[wcolor]              ; Farbe des Arbeitsbereichs RRGGBB,8->Farbverlauf
    mov  esi,0x8099bbff            ; Farbe der Titelleiste     RRGGBB,8->Farbverlauf
    mov  edi,0x00ffffff            ; Farbe des Rahmens         RRGGBB
    int  0x40

                                   ; FENSTERBEZEICHNUNG
    mov  eax,4                     ; Funktion 4: schreibe Text zum Fenster
    mov  ebx,8*65536+8             ; [x start] *65536 + [y start]
    mov  ecx,0x00ffffff            ; Textfarbe RRGGBB
    mov  edx,labelt                ; Zeiger auf den Textanfang
    mov  esi,labellen-labelt       ; Textlänge
    int  0x40

                                   ; SCHLIEßEN-BUTTON
    mov  eax,8                     ; Funktion 8: definiere und zeichne Button
    mov  ebx,(300-19)*65536+12     ; [x start] *65536 + [x größe]
    mov  ecx,5*65536+12            ; [y start] *65536 + [y größe]
    mov  edx,1                     ; Button-ID
    mov  esi,0x5599cc              ; Button-Farbe RRGGBB
    int  0x40

    call draw_text

    mov  eax,12
    mov  ebx,2
    int  0x40

    ret




; DATEN-BEREICH

wcolor   dd  0x0
pos      dd  0x0

cdplayer db  'CDPLAY     '
labelt   db  'INFRAROT-EMPFÄNGER FÜR IRMAN AN COM1'
labellen:

text:

I_END:



eof