| HOME | NEWS | AWARDS | ABOUT ME | TEXTE | REFERATE | PROJEKTE |
|
MUSIK | CHAT | SPECIAL | LINKS |

1.Kapitel: Theoretische Grundlagen

1.1 Was ist ein TSR-Programm?

Wer unter DOS schon einmal Dateien ausgedruckt hat, wird sicherlich schon die Meldung „Residenter Teil von PRINT geladen.“ gelesen haben. Was hat es damit auf sich?

Microsoft-DOS ist ein Single-Task System, d.h. es kann immer nur ein Programm aktiv sein. Da es jedoch manchmal nützlich ist, auf bestimmte Programme bzw. Tools ständig zuzugreifen zu können, wurden TSR-Programme in die Welt gesetzt. TSR steht für „Terminate and stay resident“, was soviel heißt wie: „Programm beenden und im Speicher behalten“. Ein solches Programm kann nun jederzeit wieder aus dem Speicher aufgerufen werden, z.B. über eine bestimmte Tastenkombination.

TSR-Programme gehören zu den nützlichsten, aber auch kompliziertesten Vertretern von Hilfsprogrammen, da hier ständig darauf geachtet werden muß, daß man nicht in Konflikt mit dem gerade aktuellen Programm kommt, oder während kritischer Situationen (Diskettenzugriff) auf DOS-Funktionen zugreift. Zudem ist immer im Auge zu behalten, ob das Tool nun eingreifen soll bzw. darf.

Man unterscheidet deshalb bei TSR-Programmen solche, die ständig im Hintergrund sind, wie z.B. DOS-TOOL und solche, die nur reagieren, nachdem ein sogenannter „Hotkey“ gedrückt wurde. Um ersteres zu erreichen werden oftmals Interrupts, wie der Timer verbogen, so das eine ständige Kontrolle des Systems möglich ist.

Allgemein ist bei der Programmierung von TSR´s äußerste Vorsicht geboten, da es auch leicht zu Speicherkonflikten kommen kann.

Wenn man sich ein Speicherresidentes Programm bildlich vorstellen möchte, kann man es als eine Schale um das eigentlich auszuführende Programm sehen, was jegliche Aktion des Hauptprogramms beobachtet und gegebenenfalls darauf reagiert.

Leider ist es Umfang dieser Projektarbeit nicht möglich, näher auf die Programmierung solcher Programme einzugehen. Dennoch sollte das Listing am Ende ein wenig Aufschluß über grundlegende Programmiertechniken geben, und wer noch mehr Informationen braucht, dem können wir das Buch „Effektives Programmieren mit Turbo Pascal“ aus dem Markt&Technik Verlag empfehlen.

Zurück


1.2 Das Interrupt-Konzept

1.2.1 Einführung

Interrupts sind nicht nur zur Steuerung der Hardware unverzichtbar, sondern stellen das zentrale Medium zwischen Software und den Funktionen des BIOS und DOS dar. Inwiefern diese Aussage gerechtfertigt ist und wie das Interrupt-Konzept funktioniert, soll dieser Abschnitt unserer Projektarbeit näherbringen.

Wie der Name schon nahelegt, handelt es sich bei Interrupts um Unterbrechungen. Ausgelöst durch ein Programm oder ein Gerät wird dabei die CPU in ihrer Arbeit unterbrochen und gezwungen einen sog. Interrupt-Handler aufzurufen.

Ein simples Beispiel soll das Problem veranschaulichen: Man stelle sich vor, die CPU sei gerade mit der Ausführung eines Schreibprogramms beschäftigt. Währenddessen registriert die Netzwerk-Hardware angekommene Daten. Um Datenverluste mangels Speichermöglichkeiten seitens der Netzwerkkarte zu vermeiden, muß das Schreibprogramm unterbrochen werden. Dazu meldet die Karte über ihre Interrupt-Leitung eine Unterbrechung an, die den Prozessor zwingt die Arbeit zu unterbrechen um die angekommenen Daten dem Empfänger-Programm zuzustellen. Anschließend kann ursprüngliche Arbeit wieder aufgenommen werden.

Bei Interrupts unterscheidet man jene, die durch die Software ausgelöst werden, um eine Funktion des BIOS, DOS oder ähnlichem (Speicherverwaltung) auszuführen (Software- Interrupts), von denen, die durch externe Hardware hervorgerufen werden (Hardware-Interrupts).

Zurück

1.2.2 Der Interrupt-Controller

Wenn die CPU von externer Hardware unterbrochen wird, wird ihr das über Interrupt-Leitungen signalisiert. Um welchen Interrupt-Request (IRQ) und damit um welches Gerät es sich handelt muß der CPU natürlich mitgeteilt werden. Diese Aufgabe fällt den Interrupt-Controller zu.

Ein vereinfachtes Schema könnte so aussehen:

                    Interruptanfrage
Hardware-Komponente -----------------> Interrupt-Controller -----> CPU


Dem Interrupt-Controller kommt somit für die Steuerung externer Geräte (z.B. Tastatur, Festplatte, Schnittstellen) eine immense Bedeutung zu. Vereinfacht gesagt sorgt der Interrupt-Controller bei Hardware-Interrupt-Anfragen für Ordnung, denn als Koppelglied zwischen Hardware und CPU sorgt er für Entlastung.

Ein Beispiel: Damit die Tastatur permanent auf Eingaben des Benutzers reagieren kann, müsste sie vom Prozessor auch permanent abgefragt werden, was viel CPU-Zeit in Anspruch nehmen und eine sofortige Reaktion unmöglich machen würde. Sinnvollerweise meldet sich in der Realität das Gerät, bei relevanten Ereignissen, über den Interrupt- Controller bei der CPU, die daraufhin einen sog. Interrupt-Handler aufruft.

Jede Hardware-Komponente besitzt eine eigene Interrupt-Leitung, über die Interrupt- Anfragen an die CPU weitergegeben werden können. An den Interrupt-Controller des PC`s können bis zu 8 Geräte angeschlossen, da er 8 Interrupt-Leitungen besitzt (IRQ0 - IRQ7). Da alle Geräte gleichzeitig Interrupts anmelden können, gibt es bei den Interrupt-Leitungen Prioritäten (IRQ0 hat die höchste, IRQ7 die niedrigste), nach denen die Interrupt-Anfragen weitergeleitet werden. Beim AT können durch 2 Interrupt-Controller bis zu 16 Interrupt-Leitungen abgefragt werden.
Der Interrupt-Controller kommt nur bei Hardware-Interrupts zum Einsatz; bei Software-Interrupts legt das jeweilige Programm die Interrupt-Nummer fest.

Interrupt-Leitung

Hardware-Komponente

IRQ 0

Timer

IRQ 1

Tastatur

IRQ 2

2. Interrupt-Controller

IRQ 3

ser. Schnittstelle 2

IRQ 4

ser. Schnittstelle 1

IRQ 5

Festplatte

IRQ 6

Diskette

IRQ 7

Drucker

Tab. 1: Die Besetzung der Interrupt-Leitungen

Zurück

1.2.3 Die Interrupt-Vektor-Tabelle (IVT)

Wie schon mehrfach erwähnt wird von der CPU beim Auslösen eines Interrupts ein sog. Interrupt-Handler aufgerufen. Logisch erscheint, daß jeder Interrupt seinen eigenen Handler besitzt, denn jedem Interrupt kommt schließlich eine andere Aufgabe zu. Jeder Interrupt- Handler hat natürlich auch eine Adresse im Speicher, denn die CPU muß schließlich wissen, wo der Interrupt-Vektor geholt werden muß, um die Interrupt- Routine auszuführen, auf die der Vektor zeigt.

Für die 256 Interrupts, die der PC kennt, gibt es die sog. Interrupt-Vektor-Tabelle, die demzufolge 256 Einträge enthält. Da jeder Eintrag einen Zeiger darstellt, der Segment- und Offsetadresse des jeweiligen Interrupt-Handlers angibt, belegt er 2 aufeinanderfolgende Words. Folglich umfaßt die Interrupt-Vektor-Tabelle 1024 Byte.

Diese Tabelle stellt das Herzstück des Betriebssystems da, da jeder Interrupt-Aufruf über diese Tabelle erfolgen muß. Beim Systemstart wird sie vom BIOS an der untersten Speicheradresse ($0000:$0000) angelegt.

Unser Schema aus 1.2.2 läßt sich nun konkretisieren:

        Interruptanfrage                            IVT
Hardware------------> Interrupt-Controller --> CPU -----> Interrupt Handler
        Interruptanfrage                            |
Software --------------------------------------------

Zurück

1.2.4 Interrupts und TSR-Programme

Mit dem gegebenen Einblick in das Interrupt-Konzept des PC`s erklären wir im folgenden die Funktion von Interrupts, d.h. insbesondere ihrer Handler, bei der Erstellung von TSR-Programmen. Wie anfangs erwähnt, stellen Interrupt u.a. das zentrale Medium zwischen Software und den Funktionen des BIOS und DOS dar. Das heißt jedes Programm und dessen Funktionsweise beruht auf dem Auslösen von Interrupts um Funktionen des BIOS und DOS zu nutzen.

Auch TSR-Programme nutzen das Auslösen von Interrupts; mit einen entscheidenden Unterschied. Da es im Hintergrund arbeitet und dem Benutzer Aufgaben abnimmt, ohne das es notwendig ist, daß gerade ausgeführte Programm zu beenden, muß es je nach Funktion natürlich Mechanismen geben, auf die das TSR-Programm mit seinen Aufgaben reagiert. Das sind vom System ausgelöste Interrupts, die vom TSR-Programm abgefangen werden, und dessen Interrupt-Handler durch einen eigenen Handler (Interrupt-Service-Routine) ersetzt bzw. erweitert werden können. Dabei enthält ein TSR-Programm, je nach Komplexität, eine, in den meisten Fällen aber mehrere Interrupt-Service-Rountinen für die verschiedenen Interrupts.

Die Interrupt-Service-Rountine ist eine normale Prozedur, die neben anderen Prozeduren in einen Programm untergebracht ist, jedoch selbstständig arbeitet und deshalb nie als Prozedur aufgerufen wird. Sie reagiert nur auf das Auslösen eines best. Interrupts (Mechanismus) und wird dann vom System anstelle des Original-Interrupt-Handlers aufgerufen und ausgeführt. Damit das passiert, sind jedoch einige Schritte notwendig, die wir anhand unseres Programms DOS-TOOL erläutern wollen:
Um die Aufgabe, die das Programm erfüllen soll zu realisieren, ist es notwendig auf 3 best. Interrupts zu reagieren. Das sind der Timer-Interrupt $08, der vom System 18,2 mal in der Sekunde ausgelöst wird, der Tastatur-Interrupt $09, der von der Tastatur mit jedem Tastendruck ausgelöst wird und der Interrupt $28, den DOS beim Warten auf Zeicheneingaben zyklisch aufruft. Auf die Funktionen der Interrupts und die Funktionsweise unserer Interrupt-Service- Rountinen wird im Kapitel 2 näher eingegangen.
Um zu gewährleisten das aber gerade unsere Interrupt-Service-Routinen, und somit unsere gewünschten Funktionen, beim Auslösen dieses Interrupts ausgeführt werden, ist es notwendig die Interrupts auf unsere ISR zu verbiegen. Dazu ist es wichtig den Zeiger in der Interrupt-Vektor-Tabelle, der auf den best. alten Interrupt-Handler zeigt, auf unsere neue Interrupt- Service-Rountine für einen best. Interrupt zeigen zu lassen. Der Interrupt wird also beim nächsten Aufruf gezwungen, unsere ISR auszuführen.

Auf unser Programm zurückgeführt bedeutet das, das wir die Zeiger für die Interrupts $08, $09 und $28 einfach auf die Adressen unserer eigenen Routinen zeigen lassen. Vorher muß man sich den Zeiger auf den Original-Handler jedoch merken. Auch zweierlei Gründen: In der eigenen Interrupt-Service-Rountine muß der alte Interrupt-Handler aufgerufen werden, denn die eigenen Interrupt-Service-Routinen können nicht die Aufgaben, die die Original-Handler wahrnehmen übernehmen (es sei denn man will einen Treiber schreiben). Außerdem muß gewährleistet werden, das unser TSR-Programm auch dann reagiert, wenn es mit anderen TSR-Programmen „zusammenspielt“, Das Problem besteht hier darin, das ein anderes TSR-Programm denselben Interrupt schon auf seine eigene ISR umgebogen haben kann, und unser Programm beim Verzicht auf den Aufruf des alten Handlers die Funktion des anderen TSR-Programms stark beeinträchtigt (oft unbrauchbar macht).
Das Sichern des Origninal-Interrupt-Vektors (und somit der Adresse seines Handlers) erfolgt über die Pascal-Funktion GETINTVEC, das Umbiegen eines Interrupts-Vektors auf den eigenen Handler (die ISR-Prozedur) läßt sich über SETINTVEC realisieren.

Bsp.: GETINTVEC($08,intvec8){sichert die Adresse des Timer-Interrupt Handlers im pointer „intvec8“}

SETINTVEC($08,@int8){setzt den Timer-Interrupt-Vektor auf die eigene ISR namens „int8“}

Zurück


1.3. Datensegment und Stack

Auch in diesem Abschnitt möchten wir lediglich auf eine kurze, für DOS-TOOL relevante Erklärung zurückgreifen.

Programme haben im Normalfall meist globale Variablen und Konstanten. Damit diese Platz im Speicher finden, reserviert man ihnen Speicherplatz - maximal 64kByte. Die hier im Datensegment gespeicherten Variablen sind in ihrer Größe fest definiert und können während der Laufzeit nicht mehr diesbezüglich verändert werden.
Biegt man zum Beispiel einen Interrupt unter Turbo-Pascal auf eine eigene Routine um, so wird mit Aufruf der Routine auch das programmeigene Datensegment aktiviert.

Im Gegensatz zum Datensegment steht der Stack. Er übernimmt die Funktionen des Datensegmentes für die lokalen Variablen, die nur zeitweise, sprich temporär, gebraucht werden. Zudem speichert er beim Aufruf einer Prozedur oder Funktion immer die Rücksprungadresse zum Hauptprogramm bzw. der aufrufenden Prozedur. Ebenso wie das Datensegment ist der Stack auf 64kByte begrenzt. Seine Adresse läßt sich mitttels der Turbo-Variablen „sseg“ und „sptr“ abfragen.
Dies ist für TSR-Programme sehr hilfreich, diese Werte zu kennen, da beim Aufrufen zwar das Datensegment, nicht aber der Stack automatisch umgeschalten wird. Dies muß manuell und in Assembler geschehen. Ohne das Umschalten kommt es bei mehr Variablen leicht zum Programmabsturz.

Der Heapbereich kommt bei DOS-TOOL nicht zum Einsatz und wird deshalb nicht noch einmal gesondert hier besprochen.

Zurück


1.4 Der Tastaturpuffer

Vielleicht haben Sie es selber schon einmal ausprobiert: Während des Abarbeitens der Konfigurationsdateien haben Sie ein paar Tasten gedrückt und haben genau diese Zeichenfolge, nachdem das Prompt erschienen ist, auf ihrem Bildschirm.
Um sich solche, während Aktivitäten von DOS, getätigten Eingaben zu merken hat DOS einen kleinen Tastaturpuffer eingerichtet, der diese Daten zwischenspeichert, bis der Computer zu deren Ausgabe bereit ist. Dieser Puffer ist jedoch auf 16 Zeichen begrenzt, was seine Funktionsmöglichkeiten bei der Programmierung stark einschränkt. Die Startadresse des Tastaturpuffers ist in der Adresse $0040:$0080 abgelegt. Anfang und Ende der Zeichenkette im Puffer sind in den Adressen $0040:$001A und $0040:$001C abgelegt. Die Zeichenkette beginnt im Speicher bei $0040:Pufferstartadresse.

In DOS-TOOL wurde diese Programmiertechnik angewandt, um Befehle in der DOS-Ebene auszuführen.

Zurück


1.5 Das BIOS

Da das BIOS in der Programmierung von DOS-TOOL nur am Rand von Bedeutung war, soll hier nur kurz und knapp darauf eingegangen werden und bei Interesse auf die zahlreiche Fachliteratur verwiesen werden.

Das BIOS (hier im speziellen das VGA-BIOS) erledigt grundlegende Ein- und Ausgabefunktionen des Computers. Das VGA-BIOS wird über den Interrupt 10h angesprochen. Nachteil von BIOS-Aufrufen ist nicht so hohe Geschwindigkeit. Der große Vorteil liegt jedoch in der immensen Kompatiblität zu allen Grafikkarten. Im Programm DOS-TOOL wurde lediglich die Cursorposition über das BIOS abgefragt und gesetzt.

Weiterführende Informationen zum VGA-BIOS sind z.B. im Buch „VGA und Super- VGA-Programmierung“, aus dem Addison-Wesley Verlag, zu finden.

Zurück


1.6 Der Bildspeicher

In diesem Abschnitt soll kurz auf den Bildspeicher im Textmodus eingegangen werden. Der Bildspeicher im Textmodus umfaßt ein 64kByte großes Datensegment, wobei jeweils 32kByte für Monochromkarten und 32 für VGA/CGA-Karten sind. DOS-TOOL funktioniert nur mit letzterem Kartentyp!

Die Startadresse für den VGA-Textmodus-Bildspeicher liegt bei $B800:$0000. Die Zeichen werden nun jeweils immer mit ihrem Attribut fortlaufend im Speicher abgelegt. Dabei ist es wichtig zu wissen, daß die Zeichencodes an den geraden Adressen und die Attribute an den ungeraden Adressen liegen. Theoretisch verfügt man im Textmodus durch die vorhandenen 32kByte über 8 Bildseiten. Die Adresse eines Zeichens ergibt sich im 80x25 Zeichenmodus wiefolgt:

$B800:Zeile*160+Zeichen*2

Das entsprechende Attribut befindet sich ein Byte weiter.

Der Zugriff auf den Bildspeicher in Turbo-Pascal kann man über „mem“ realisieren.

MEM[adresse]:=wert bzw. wert:=MEM[adresse].

Zurück

| HOME | NEWS | AWARDS | ABOUT ME | TEXTE | REFERATE | PROJEKTE |
|
MUSIK | CHAT | SPECIAL | LINKS |