Software, die auf der CPU eines PCs ausgeführt wird, kann auf verschiedene Arten mit der restlichen Hardware kommunizieren.
Am einfachsten zu verstehen sind E / A-Ports. Die Software verwendet die OUT-Anweisung, um 8, 16 oder 32 Bits gleichzeitig in einen E / A-Port zu schreiben. In gleicher Weise verwendet die Software die IN-Anweisung, um von einem E / A-Port zu lesen. Die E / A-Anschlüsse befinden sich in einem separaten 16-Bit-Adressraum, unabhängig von dem vom Hauptspeicher verwendeten Adressraum. Jede Hardware, die E / A-Anschlüsse verwendet, verfügt über einen Bereich von E / A-Adressen. Das Schreiben und Lesen von jeder dieser Adressen hat einen anderen Effekt (und das Lesen und Schreiben an derselben Adresse hat auch unterschiedliche Auswirkungen).
Eine andere Möglichkeit sind speicherzugeordnete E / A-Vorgänge, bei denen ein Teil des Speicheradressraums einer Hardware zugeordnet ist. Anstatt in den Hauptspeicher zu gehen, gehen die Lese- und Schreibvorgänge aus und in diesen Speicherbereich zur entsprechenden Hardware. Was sie bedeuten, hängt von der Hardware und der Region ab (es ist nicht ungewöhnlich, dass sich mehr als eine E / A-Region mit Speicherzuordnung in derselben Hardware befindet). Lesen und Schreiben darauf kann einen besonderen Effekt haben (wie es bei E / A-Ports üblich ist) oder es kann einfach direkt in den Speicher der Hardware gelesen und geschrieben werden (z. B. der Bildspeicher einer Videokarte).
Auf der anderen Seite (die übrige Hardware spricht mit der auf der CPU laufenden Software) gibt es auch mehrere Möglichkeiten. Am einfachsten wäre es, auf die Abfrage der Software zu warten (entweder über einen E / A-Port oder durch Speicher zugeordnete E / A). Allein verwendet, kann dies sehr ineffizient sein.
Eine andere Möglichkeit besteht darin, dass die Hardware direkt in den Hauptspeicher schreibt. Dies ist sehr effizient für die Übertragung großer Datenmengen und kann auch in die andere Richtung (zum Lesen aus dem Hauptspeicher) verwendet werden. Die Software muss jedoch immer noch wissen, wann die Übertragung abgeschlossen ist.
Der letzte Weg ist Interrupts. Die CPU empfängt zusammen mit der Interruptnummer eine Interruptanforderung. Die CPU unterbricht (also den Namen), was sie getan hat, und wechselt zu einem anderen Teil des Codes (welcher Teil hängt von der Interrupt-Nummer ab). Normalerweise entspricht jede Hardware einer einzelnen Interruptnummer, aber Interruptnummern werden häufig von mehreren Interruptquellen gemeinsam genutzt. Es gibt auch spezielle Arten von Interrupts, die keine Nummer haben; zum Beispiel das NMI.
Als praktisches Beispiel nehmen wir eine einfache Netzwerkkarte. Diese Netzwerkkarte verfügt über eine Reihe von Registern, die entweder über E / A-Anschlüsse oder über Speicher zugeordnete E / A abgerufen werden können. Es kann auch aus dem Hauptspeicher lesen und in diesen schreiben und verfügt über einen Interrupt-Pin.
Um ein Paket an das Netzwerk zu senden, schreibt der Netzwerkkartentreiber zunächst das vollständige Paket an einer Adresse, die auf ein Vielfaches von 4 Bytes ausgerichtet ist, in den Speicher. Es schreibt dann in ein paar Register auf der Netzwerkschnittstellenkarte und teilt ihm die Speicheradresse, die Paketgröße und einige andere Informationen mit. Die Netzwerkkarte liest dann das Paket aus dem Speicher, sendet es an das Netzwerk und signalisiert den Interrupt. Der Interrupt-Controller (eine separate Hardware) sendet die Interrupt-Anforderung an die CPU und teilt ihr die Interrupt-Nummer mit. Im Interrupt-Handler liest der Treiber ein Register von der Karte, das ihm mitteilt, dass es sich bei dem Interrupt um ein gesendetes Paket handelt, liest ein anderes Register, um herauszufinden, welches Paket gesendet wurde, und weiß, dass er den Speicher, an dem er das Paket geschrieben hat, jetzt wieder verwenden kann .
Um Pakete vom Netzwerk zu empfangen, weist der Netzwerkkartentreiber einen Speicherblock zu, der als Speicher für die Pakete verwendet werden soll, und schreibt mehrere Register auf die Karte, die ihm die Speicheradresse des Speicherblocks, seine Größe und einige andere Informationen mitteilen . Wenn ein Paket vom Netzwerk empfangen wird, schreibt die Netzwerkkarte es zusammen mit der Größe des Pakets und einigen anderen Informationen in diesen Speicherblock. Es aktualisiert einige Register, die sowohl dem Fahrer als auch dem Treiber mitteilen, wie viel freier Speicherplatz in diesem Speicherblock vorhanden ist, wo der freie Speicherplatz beginnt und wo der belegte Speicherplatz beginnt (der Puffer ist kreisförmig, so dass er nach dem Ende wieder rollen kann zu Beginn). Schließlich signalisiert es seinen Interrupt. Der Treiber liest die Register und den Speicher, um die Pakete zu erhalten.
Es gibt andere Dinge, die die Karte dem Fahrer mitteilen kann, indem er seine Register schreibt und einen Interrupt signalisiert. B., dass das Netzwerkkabel nicht angeschlossen war, ein Übertragungsfehler aufgetreten ist und so weiter.