Direct Memory Access

Aus Lowlevel
Version vom 10. Dezember 2008, 19:00 Uhr von DarkThing (Diskussion | Beiträge) (Artikel start erweitert. Übersicht und Beschreibung aller Ports hinzugefügt.)
Wechseln zu:Navigation,

Direct Memory Access (Abkürzung: DMA) ist eine Methode um einfache Kopiervorgänge, von Geräten zum Speicher oder umgekehrt, mit einem extra Chip anstelle der CPU zu vollziehen. Dadurch ist die CPU während des Kopierens nicht ausgelastet und kann anderweitig verwendet werden. Dies ist insbesondere bei Betriebssystemen wichtig, die Multitasking verwenden, da sonst der Prozesswechsel beispielsweise bei Festplattenzugriffen verzögert werden müsste.

Physikalischer Aufbau

Für DMA-Transfere wurde in früheren PCs ein Chip mit der Bezeichnung 8237A verwendet. Im Laufe der Zeit wurde ein weiterer Controller hinzugefügt und die Hardware in den Chipsatz integriert.

Die beiden Controller sind miteinander verbunden, einer von ihnen arbeitet als Master, der andere als Slave.

Programmierung der Controller

Übersicht

Die folgende Tabelle ist eine Übersicht über alle Ports, die von den beiden Controllern belegt werden. Master- und Slave-Controller verwenden dabei verschiedene Ports. Weiterhin muss beachtet werden, dass pro Controller vier sog. Channel, also Kanäle, zur Verfügung stehen; sie ermöglichen parallele und unabhängige Datenübertragung. Jeder Channel verwendet dabei wiederum eigene Ports, wodurch eine vergleichsweise hohe Zahl an Ports zusammenkommt.

Mit "Zugriff" ist der Assemblerbefehl gemeint, mit dem auf den Port zugegriffen werden kann. Diese Spalte gibt an, ob lesend oder schreibend zugegriffen wird. Die Spalte "Größe" gibt an, wieviele Bits das entsprechende Register umfasst. Auch wenn hier 16 stehen sollte, wird nur byteweise mit den DMA-Controllern kommuniziert - siehe dazu die Beschreibung des Flip-Flop-Registers.


Name des Registers Port Slave Port Master Zugriff Größe Beschreibung
Startadresse Ch 0: 0x00 Ch 0: 0xC0 out 16 Die Startadresse des Buffers für die Daten
Ch 1: 0x02 Ch 1: 0xC2 out 16
Ch 2: 0x04 Ch 2: 0xC4 out 16
Ch 3: 0x06 Ch 3: 0xC6 out 16
Zähler Ch 0: 0x01 Ch 0: 0xC1 out 16 Anzahl der Bytes, die übertragen werden sollen, minus eins
Ch 1: 0x03 Ch 1: 0xC3 out 16
Ch 2: 0x05 Ch 2: 0xC5 out 16
Ch 3: 0x07 Ch 3: 0xC7 out 16
Aktuelle Adresse Ch 0: 0x00 Ch 0: 0xC0 in 16 Die Aktuelle Adresse. Sie gibt an, wo der DMA-Controller gerade liest oder schreibt
Ch 1: 0x02 Ch 1: 0xC2 in 16
Ch 2: 0x04 Ch 2: 0xC4 in 16
Ch 3: 0x06 Ch 3: 0xC6 in 16
Aktueller Zähler Ch 0: 0x01 Ch 0: 0xC1 in 16 Der momentane Zählerstand gibt an, wie viele Bytes noch verbleiben
Ch 1: 0x03 Ch 1: 0xC3 in 16
Ch 2: 0x05 Ch 2: 0xC5 in 16
Ch 3: 0x07 Ch 3: 0xC7 in 16
Page Ch 0: 0x87 Ch 0: 0x8F out/in 8 Da sich mit Hilfe der Startadresse nur ein 16bit-Adressraum ansprechen lässt, also 64KiB, kann hierüber eine Page festegelegt werden. Die Startadresse wird also auf eine 24bit-Adresse erweiter, womit sich immerhin 1MiB ansprechen lässt. Dieses 8bit-Register nimmt dabei die Bits 16-23 dieser Adresse auf.
Ch 1: 0x83 Ch 1: 0x8B out/in 8
Ch 2: 0x81 Ch 2: 0x89 out/in 8
Ch 3: 0x82 Ch 3: 0x8A out/in 8
Status 0x08 0xD0 in 8 Liefert Statusinformationen zum DMA-Controller (siehe dazu unten)
Befehle 0x08 0xD0 out 8 Befehle, die der Controller ausführen soll, werden hierein geschrieben (für eine Liste der Befehle siehe unten)
Controller zurücksetzen 0x0D 0xDA out - Durch Schreiben in dieses Register wird ein Reset des entsprechenden Controllers durchgeführt
Flip-Flop 0x0C 0xD8 out 8 Dieses Register ist nötig, um mit 8bit-Zugriffen, die 16bit-Register zu verwenden. Vor dem Zugriff auf ein 16bit-Register sollte eine Null an dieses Register gesendet werden. Dadurch wird der Flip-Flop des Controllers zurückgesetzt und es wird beim anschließenden Zugriff auf ein 16bit-Register das Low-Byte adressiert. Der Controller wird das Flip-Flop-Register danach selbstständig auf Eins setzen, wodurch der nächste Zugriff das High-Byte adressiert. Dies ist sowohl beim Lesen als auch beim Schreiben aus bzw. in 16bit-Register nötig.
Transfermodus 0x0B 0xD6 out 8 Über dieses Register kann der Übertragungsmodus für einen Channel und einige weitere ergänzende Details zum Befehl, der an das Befehlsregister gesendet wird, festgelegt werden (Für eine genaue Beschreibung siehe unten)
Maskierung eines Channels 0x0A 0xD4 out 8 Hierüber kann ein einzelner Channel maksiert, also deaktiviert, werden. Dies sollte immer(!) getan werden, wenn der Controller auf einen Transfer vorbereitet wird, um gleichzeitige Zugriffe von mehreren Programmen zu unterbinden. Die Bits 0 und 1 enthalten dabei die Nummer des Channels, dessen Status geändert werden soll. In Bit 2 wird angegeben, ob der gewählte Channel aktiviert (0) oder deaktiviert (1) werden soll.
Maskierung mehrerer Channel 0x0F 0xDE out 8 Dieses Register hat die gleiche Funktion wie das Maskierungsregister oben, aber mit dem Unterschied, dass mit Hilfe dieses Registers der Zustand meherer Channel gleichzeitig geändert werden kann. Bit 0 bis 3 geben dabei an, ob der entsprechende Channel (0-3) aktiviert (0) oder deaktiviert (1) werden soll. Hierbei muss aufgepasst werden, dass nicht aus Versehen ein Channel irrtümlicherweise (de)aktiviert wird, dessen Status eigentlich unverändert bleiben soll.
Request 0x09 0xD2 out 8 Dieses Register ermöglicht es, einen Transfer mittels Software auszulösen. Für den Aufbau des zu sendenen Bytes siehe unten

Aufbau der zusammengesetzten Bytes

Statusregister

TODO

Befehlsregister

TODO

Transfermodusregister

TODO

Requestregister

TODO


Alles zusammensetzen: Vorbereiten einer Übertragung

TODO

Beispiel

TODO