| Zeile 45: | Zeile 45: | ||
Unsere erste Routine - 0x01 von Interrupt 0x21 - wird ein Ersatz für die putstr-Funktion sein. Unsere Routine wird also den String nehmen, auf den SI zeigt und ihn über BIOS Teletype auf den Bildschirm schreiben (String muss Null-terminiert sein!). | Unsere erste Routine - 0x01 von Interrupt 0x21 - wird ein Ersatz für die putstr-Funktion sein. Unsere Routine wird also den String nehmen, auf den SI zeigt und ihn über BIOS Teletype auf den Bildschirm schreiben (String muss Null-terminiert sein!). | ||
| − | + | <asm> _int0x21: | |
_int0x21_ser0x01: ; funktion 0x01 | _int0x21_ser0x01: ; funktion 0x01 | ||
cmp al, 0x01 ; funktion 0x01 angefragt? | cmp al, 0x01 ; funktion 0x01 angefragt? | ||
| Zeile 63: | Zeile 63: | ||
_int0x21_end: | _int0x21_end: | ||
| − | iret | + | iret</asm> |
Jetzt gehen wir den Code Stück für Stück durch. Jede Funktion hat ein Label in der Form "_int0x21_ser0x01". Der erste Teil ist die Interrupt-Nummer, der Zweite die Funkionsnummer. Zu beginn jeder Funktion wird geprüft, ob in AL die Nummer der Funktion drinsteht. Wenn ja, geht der Code normal weiter und die Routine wird ausgeführt. Wenn nicht, wird zur nächsten Funktion gesprungen. In diesem Beispiel haben wir nur eine Routine, deshalb wäre dann die ISR gleich zu Ende. | Jetzt gehen wir den Code Stück für Stück durch. Jede Funktion hat ein Label in der Form "_int0x21_ser0x01". Der erste Teil ist die Interrupt-Nummer, der Zweite die Funkionsnummer. Zu beginn jeder Funktion wird geprüft, ob in AL die Nummer der Funktion drinsteht. Wenn ja, geht der Code normal weiter und die Routine wird ausgeführt. Wenn nicht, wird zur nächsten Funktion gesprungen. In diesem Beispiel haben wir nur eine Routine, deshalb wäre dann die ISR gleich zu Ende. | ||
| Zeile 69: | Zeile 69: | ||
Nun haben wir also unseren Interrupt Handler. Dieser ist aber noch nicht in der Interrupt Vector Table registriert. Bevor wir den Interrupt aufrufen, müssen wir also ein paar Pointer umbiegen, damit der PC auch unseren Interrupt Handler benutzt. | Nun haben wir also unseren Interrupt Handler. Dieser ist aber noch nicht in der Interrupt Vector Table registriert. Bevor wir den Interrupt aufrufen, müssen wir also ein paar Pointer umbiegen, damit der PC auch unseren Interrupt Handler benutzt. | ||
| − | + | <asm> push dx | |
push es | push es | ||
xor ax, ax | xor ax, ax | ||
| Zeile 78: | Zeile 78: | ||
sti | sti | ||
pop es | pop es | ||
| − | pop dx | + | pop dx</asm> |
Als erstes speichern wir DX und ES. Danach leeren wir das AX-Register und schreiben den Wert von AX in ES rein (keine Panik, das ist die schnellste Möglichkeit!). Als nächstes schalten wir Interrupts aus, da wir ja selbst mit Interrupts arbeiten. | Als erstes speichern wir DX und ES. Danach leeren wir das AX-Register und schreiben den Wert von AX in ES rein (keine Panik, das ist die schnellste Möglichkeit!). Als nächstes schalten wir Interrupts aus, da wir ja selbst mit Interrupts arbeiten. | ||
| Zeile 88: | Zeile 88: | ||
Wie benutzen wir also unsere schöne neue Funktion zur Textausgabe? | Wie benutzen wir also unsere schöne neue Funktion zur Textausgabe? | ||
| − | + | <asm> mov si, Message ; der String | |
mov al, 0x01 ; wir brauchen Funktion 0x01 | mov al, 0x01 ; wir brauchen Funktion 0x01 | ||
| − | int 0x21 ; unser Interrupt!!! | + | int 0x21 ; unser Interrupt!!!</asm> |
So, das wars auch schon. Jeder kann jetzt mit wenig Aufwand neue Funktionen hinzufügen und so seine API Stück für Stück erweitern. War doch einfach, oder? | So, das wars auch schon. Jeder kann jetzt mit wenig Aufwand neue Funktionen hinzufügen und so seine API Stück für Stück erweitern. War doch einfach, oder? | ||
| Zeile 105: | Zeile 105: | ||
Nun wird auch ersichtlicher was im folgenden Code passiert: | Nun wird auch ersichtlicher was im folgenden Code passiert: | ||
| − | + | <asm> push dx | |
push es | push es | ||
xor ax, ax | xor ax, ax | ||
| Zeile 114: | Zeile 114: | ||
sti | sti | ||
pop es | pop es | ||
| − | pop dx | + | pop dx</asm> |
Entscheiden sind hier die Zeilen zwischen "cli" und "sti". | Entscheiden sind hier die Zeilen zwischen "cli" und "sti". | ||
| Zeile 196: | Zeile 196: | ||
=== APM Powerdown === | === APM Powerdown === | ||
| − | + | <asm> ; SYSTEM POWERDOWN | |
; WARNING - DO NOT RUN UNDER WIN! (IT WORKS!) | ; WARNING - DO NOT RUN UNDER WIN! (IT WORKS!) | ||
; (C) 1999 BY VINNY | ; (C) 1999 BY VINNY | ||
| Zeile 212: | Zeile 212: | ||
MOV BX,1 | MOV BX,1 | ||
MOV CX,3 | MOV CX,3 | ||
| − | INT 0x15 ; powerdown system | + | INT 0x15 ; powerdown system</asm> |
== OS Projekte: SkyOS == | == OS Projekte: SkyOS == | ||
| Zeile 269: | Zeile 269: | ||
Für Leute, die hauptsächlich mit Hochsprachen (C / C++) arbeiten, wird Assembler ein wenig gewöhnungsbedürftig sein. Nehmen wir zum Beispiel unseren Interrupt, den wir in dieser Ausgabe geschrieben haben. Um einen String auszugeben, schreiben wir: | Für Leute, die hauptsächlich mit Hochsprachen (C / C++) arbeiten, wird Assembler ein wenig gewöhnungsbedürftig sein. Nehmen wir zum Beispiel unseren Interrupt, den wir in dieser Ausgabe geschrieben haben. Um einen String auszugeben, schreiben wir: | ||
| − | + | <asm> mov al, 0x01 | |
mov si, Meldung | mov si, Meldung | ||
| − | int 0x21 | + | int 0x21</asm> |
Umständlich, oder? Mit einem Makro können wir uns sehr viel Arbeit ersparen! | Umständlich, oder? Mit einem Makro können wir uns sehr viel Arbeit ersparen! | ||
| − | + | <asm> %macro PrintText 1 | |
mov al, 0x01 | mov al, 0x01 | ||
mov si, %1 | mov si, %1 | ||
int 0x21 | int 0x21 | ||
| − | %endmacro | + | %endmacro</asm> |
Jetzt reicht es, wenn wir im Code schreiben: | Jetzt reicht es, wenn wir im Code schreiben: | ||
| − | + | <asm> PrintText Meldung</asm> | |
Das ist die einzige Zeile, die man sich einfach merken muss. | Das ist die einzige Zeile, die man sich einfach merken muss. | ||