doc/de_DE.ISO8859-1/books/developers-handbook/dma/chapter.sgml
2012-09-14 17:47:48 +00:00

1478 lines
42 KiB
XML

<?xml version="1.0" encoding="iso-8859-1" standalone="no"?>
<!--
The FreeBSD Documentation Project
The FreeBSD German Documentation Project
$FreeBSD$
$FreeBSDde: de-docproj/books/developers-handbook/dma/chapter.sgml,v 1.11 2009/02/15 14:17:12 jkois Exp $
basiert auf: 1.6
-->
<chapter id="dma">
<chapterinfo>
<authorgroup>
<author>
<firstname>Daniel</firstname>
<surname>Seuffert</surname>
<contrib>Übersetzt von </contrib>
</author>
</authorgroup>
</chapterinfo>
<title>DMA</title>
<sect1 id="dma-basics">
<title>DMA: Was es ist und wie es funktioniert</title>
<para><emphasis>Copyright &copy; 1995,1997 &a.uhclem;, Alle Rechte
vorbehalten. 10. Dezember 1996. Letztes Update Oktober
1997.</emphasis></para>
<para>Direct Memory Access (DMA) ist eine Methode, die es erlaubt,
Daten von einem Ort in einem Rechner an einen anderen ohne
Eingriff des Prozessors (CPU) zu übertragen.</para>
<para>Die Art und Weise, in der die DMA-Funktion implementiert
ist, variiert zwischen den Rechnerarchitekturen. Daher
beschränken wir uns im Folgenden ausschließlich auf die
Methoden und Implementierungen auf IBM Personal Computer (PC),
dem IBM PC/AT und all seinen Nachfolgern und Nachbauten.</para>
<para>Das DMA-Subsystem basiert auf dem &intel; 8237
DMA-Controller. Der 8237 enthält vier DMA-Kanäle,
welche unabhängig voneinander programmiert werden
können, und jeder dieser Kanäle kann zu einem
beliebigen Zeitpunkt aktiv sein. Diese Kanäle sind mit 0,
1, 2 und 3 nummeriert. Beginnend mit dem PC/AT fügte IBM
einen zweiten 8237-Chip hinzu und nummerierte dessen Kanäle
mit 4, 5, 6 und 7.</para>
<para>Der originale DMA-Controller (0, 1, 2 and 3) bewegt ein Byte
bei jedem Transfer. Der zweite DMA-Controller (4, 5, 6, and 7)
bewegt 16-Bits aus zwei benachbarten Speicherplätzen bei
jedem Transfer, wobei das erste Byte immer von einer
geradzahligen Adresse stammt. Die zwei Controller sind
identische Komponenten und der Unterschied in der
Transfergröße wird durch die Art und Weise
verursacht, wie der zweite Controller im System beschaltet
ist.</para>
<para>Der 8237 hat zwei elektrische Signale für jeden
Kanal: DRQ und -DACK. Zusätzlich gibt es weitere Signale
mit den Namen HRQ (Hold Request), HLDA (Hold Acknowledge), -EOP
(End of Process) sowie die Kontrollsignale für den Bus:
-MEMR (Memory Read), -MEMW (Memory Write), -IOR (I/O Read) und
-IOW (I/O Write).</para>
<para>Der 8237 DMA-Controller ist ein sogenannter
<quote>fly-by</quote>-DMA-Controller. Das bedeutet, dass
die von einem zu einem anderen Bereich bewegten Daten weder den
DMA-Chip durchlaufen noch darin gespeichert werden. Daraus
folgt, dass der DMA-Controller nur zwischen einem I/O-Port und
einer Speicheradresse Daten bewegen kann, nicht zwischen zwei
I/O-Ports oder zwei Speicherbereichen.</para>
<note>
<para>Der 8237 erlaubt es, dass zwei Kanäle verbunden
werden, um DMA-Operationen zwischen zwei Speicherbereichen in
einem nicht-<quote>fly-by</quote>-Modus durchzuführen.
Aber niemand in der PC-Industrie benutzt diese begrenzte
Resource, da es schneller ist die Daten mittels der CPU
zwischen Speicherbereichen zu bewegen.</para> </note>
<para>In der PC-Architekur wird jeder DMA-Kanal normalerweise
nur dann aktiviert, wenn die Hardware, welche einen gegebenen
DMA-Kanal benutzt, einen Transfer durch Setzen der DRQ-Linie
verlangt.</para>
<sect2>
<title>Beispiel eines DMA-Transfers</title>
<para>Hier ist ein Beispiel für die notwendigen Schritte,
welche einen DMA-Transfer veranlassen und durchführen.
In diesem Beispiel hat der Diskettencontroller (floppy disk
controller, FDC) nur ein Byte zu lesen und verlangt vom
DMA-Controller dieses Byte im Speicher unter der Adresse
0x00123456 abzulegen. Der Prozess beginnt damit, dass der
FDC das DRQ2-Signal (die DRQ-Linie für DMA-Kanal 2)
setzt, um den DMA-Controller zu alarmieren.</para>
<para>Der DMA-Controller registriert, dass das DRQ2-Signal
gesetzt ist. Der DMA-Controller stellt sicher, dass der
DMA-Kanal 2 programmiert und unmaskiert (freigegeben) ist. Der
DMA-Controller stellt gleichzeitig sicher, dass keiner
der anderen DMA-Kanäle aktiv ist oder aktiv sein
möchte und eine höhere Prioritäti hat. Sobald
all diese Überprüfungen durchlaufen sind, fordert
der DMA-Controller die CPU auf, den Bus freizugeben, damit der
DMA-Controller ihn nutzen kann. Diese Anforderung erfolgt
durch Setzen des HRQ-Signals, welches zur CPU geht.</para>
<para>Die CPU erkennt das HRQ-Signal und führt den
aktuellen Befehl komplett aus. Sobald die CPU den Bus
freigeben kann, wird sie dies tun. Nun sind alle normalerweise
von der CPU erzeugten Signale (-MEMR, -MEMW, -IOR, -IOW und
ein paar andere) in einem Status mit einem dritten Zustand
(weder hoch noch niedrig) und die CPU teilt dem DMA-Controller
mittels des HLDA-Signals mit, dass er nun die Kontrolle
über den Bus hat.</para>
<para>Abhängig vom Prozessor kann die CPU noch einige
zusätzliche Befehle ausführen ohne die Kontrolle des
Bus, aber letztendlich muss sie warten, wenn sie Befehle
verarbeiten will, welche etwas aus dem Speicher lesen
müssen, was nicht im internen Prozessor-Cache oder der
Pipeline ist.</para>
<para>Da der DMA-Controller nun <quote>verantwortlich
ist</quote>, aktiviert er seine -MEMR, -MEMW, -IOR, -IOW
Output-Signale und der Output des DMA-Controllers wird auf
0x3456 gesetzt, damit das zu übertragende Byte zu einem
bestimmten Speicherbereich gelangt.</para>
<para>Der DMA-Controller verständigt nun das Gerät,
welches die Anforderung veranlasst hat, dass der Transfer
beginnt. Dies geschieht durch Setzen des Signals -DACK oder im
Fall des Diskettencontrollers durch -DACK2.</para>
<para>Der Floppy-Controller ist nun dafür verantwortlich
das zu übertragende Byte auf den Datenbahnen des Bus zu
platziren. Sofern der Floppy-Controller nicht mehr Zeit
braucht, um das Daten-Byte auf den Bus zu bringen (falls dies
erforderlich ist benachrichtigt das Peripheriegerät
mittels READY-Signal den DMA-Controller), dann wird der
DMA-Controller ein Zeitsignal warten und die Signale -MEMW und
-IOR widerrufen, damit der Speicher das Byte auf dem Bus
sperrt und speichert und der FDC weiß, dass das
Byte übertragen wurde.</para>
<para>Da der DMA-Zyklus nur ein einzelnes Byte auf einmal
überträgt, wird der FDC nun das Signal DRQ2
deaktivieren und der DMA-Controller weiß, dass er
nicht länger benötigt wird. Der DMA-Controller setzt
das -DACK2-Signal wieder und der FDC registriert, dass
er aufhören muss Daten an den Bus zu senden.</para>
<para>Der DMA-Controller wird nun überprüfen, ob
andere DMA-Kanäle irgendwelche Arbeiten bereithalten.
Falls keiner der Kanäle DRQ-Signale gesetzt hat,
weiß der Controller, dass er seine Arbeit beendet
hat und setzt -MEMR, -MEMW, -IOR, -IOW und die Adress-Signale
auf den dritten Zustand.</para>
<para>Abschliessend setzt der DMA-Controller wieder das
HRQ-Signal. Die CPU registriert dies und entfernt das
HOLDA-Signal wieder. Die CPU aktiviert nun ihre -MEMR, -MEMW,
-IOR, -IOW und Adress-Ausgänge und fährt mit der
Verarbeitung von Befehlen und dem Zugriff auf Hauptspeicher
und Peripherie fort.</para>
<para>Für einen typischen Sektor einer Diskette wird der
obige Prozess 512 Mal wiederholt, einmal für jedes Byte.
Nach dem Transfer eines Byte wird jeweils das Adressregister
im DMA-Controller erhöht und der Zähler vermindert,
welcher anzeigt, wieviel Bytes noch zu übertragen
sind.</para>
<para>Sobald der Zähler Null erreicht hat, setzt der
DMA-Controller das EOP-Signal, welches anzeigt, dass der
Zähler Null erreicht hat und keine weiteren Daten zu
übertragen sind, bis der DMA-Controller wieder durch die
CPU programmiert wird. Dieses Ereignis bezeichnet man als
Terminal Count (TC). Es gibt nur ein EOP-Signal und da nur
jeweils ein DMA-Kanal gleichzeitig aktiv sein kann, muss
der aktive DMA-Kanal auch derjenige sein, welcher soeben seine
Aufgabe beendet hat.</para>
<para>Falls ein Peripheriegerät einen Interrupt erzeugen
will, wenn der Transfer eines Pufferspeichers beendet ist,
dann kann es überprüfen, ob sein -DACK-Signal und
EOP-Signal gleichzeitig anliegen. Falls dies zutrifft wird der
DMA-Controller keine weiteren Informationen ohne Eingriff der
CPU für dieses Peripheriegerät übertragen. Das
Peripheriegerät kann nun eines der Interrupt-Signale
einfügen, um die Aufmerksamkeit der CPU zu erlangen. In
der PC-Architektur ist der DMA-Controller selbst nicht in der
Lage Interrupts zu erzeugen. Das Peripheriegerät und
seine beigeordnete Hardware sind für die Erzeugung jedes
Interrupts verantwortlich, welcher auftritt. In der Folge gibt
es Peripheriegeräte, welche DMA nutzen aber keine
Interrupts erzeugen.</para>
<para>Es ist wichtig zu verstehen, dass obwohl die CPU
jedesmal den Bus an den DMA-Controller freigibt, wenn dieser
ihn anfordert, dieser Vorgang sowohl für das
Betriebssystem als auch die Applikation unsichtbar ist - außer
bei kleinen Änderungen im Zeitbedarf des Prozessors beim
Ausführen von Befehlen, wenn der DMA-Controller aktiv
ist. Folglich muss der Prozessor die
Peripheriegeräte und die Register im DMA-Chip
ständig abfragen oder einen Interrupt von einem
Peripheriegerät empfangen, um sicher zu sein, dass
ein bestimmter DMA-Transfer beendet wurde.</para>
</sect2>
<sect2>
<title>DMA-Seitenregister und 16
Megabyte-Adressraumbeschränkungen</title>
<para>Sie haben vielleicht vorhin bemerkt, dass der
DMA-Controller die Adress-Linien nicht auf 0x00123456 gesetzt
hat, wie wir angaben, sondern auf 0x3456. Der Grund
hierfür erfordert ein wenig Erklärung.</para>
<para>Als der originale IBM PC entworfen wurde hat IBM
entschieden sowohl DMA als auch Interrupt-Controller
einzusetzen, welche für den 8085 entwickelt worden waren,
einen 8 Bit-Prozessor mit einem Adressraum von 16 Bit (64K).
Da der IBM PC mehr als 64K unterstützte, musste etwas
geschehen, damit der DMA-Controller Adressbereiche oberhalb
der 64K-Grenze auslesen und beschreiben konnte. IBM
führte einen zusätzlichen, externen Signalspeicher
für jeden DMA-Kanal ein, welcher die oberen Bits einer
Adresse enthält, welche ausgelesen oder beschrieben
werden soll. Immer wenn ein DMA-Controller aktiv ist, wird der
Inhalt dieses Signalspeichers cwauf denzum Adress-Bus
geschrieben und dort gehalten, bis die DMA-Operation für
diesen Kanal beendet ist. IBM nannte diese zusätzlichen
Signalspeicher <quote>Seitenregister</quote> (Page
Register).</para>
<para>Für das obige Beispiel würde der DMA-Controller also den
0x3456-Teil der Adresse auf den Bus setzen und das Seitenregister
für den DMA-Kanal 2 würde dem Bus 0x0012xxxx hinzufügen.
Zusammen bilden beide Werte die komplette Speicheradresse, auf die
zugegriffen werden soll.</para>
<para>Da das Seitenregister unabhängig vom DMA-Chip ist,
darf der zu lesende oder zu schreibende Speicherbereich die
64K-Grenze nicht überschreiten. Wenn der DMA-Controller
beispielsweise auf die Speicheradresse 0xffff zugreift, dann
wird der Controller nach dem Transfer das Adress-Register
erhöhen und auf das nächste Byte an der Adresse
0x0000, nicht 0x10000, zugreifen. Dieses Zuzulassen ist
wahrscheinlich nicht beabsichtigt.</para>
<note>
<para><quote>Physikalische</quote> 64K-Grenzen sollten nicht
mit 8086-Modus 64K-<quote>Segmenten</quote> verwechselt
werden, welche durch mathematisches Addieren eines
Segment-Registers an ein Offset-Register erzeugt werden.
Seitenregister haben keinen Adressüberhang und werden
imathematisch durch ein OR zusammengefügt.</para>
</note>
<para>Um die Angelegenheit noch komplizierter zu machen, weisen
die externen DMA-Signalspeicher auf dem PC/AT nur 8 Bytes auf,
also 8+16 = 24 Bits. Dies bedeutet, dass der
DMA-Controller nur auf Speicherbereiche zwischen 0 und 16
Megabyte zeigen kann. Für neuere Rechner, die mehr als 16
Megabyte an Speicher aufweisen, kann der Standard
PC-kompatible DMA-Controller keine Speicherbereiche oberhalb
von 16 Megabyte adressieren.</para>
<para>Um diese Beschränkung zu umgehen reservieren
Betriebssysteme einen RAM-Puffer in einem Bereich unterhalb
von 16 Megabyte, der außerdem einen physisch begrenzten
Bereich von 64K nicht überschreitet. Dann wird der
DMA-Controller so programmiert, dass er Daten vom
Peripheriegerät in diesen Puffer überträgt.
Sobald der DMA-Controller die Daten in den Puffer
übertragen hat, wird das Betriebssystem sie in den
Bereich übertragen, an dem sie wirklich gespeichert
werden sollen.</para>
<para>Beim Schreiben von Daten von Adressen oberhalb von 16
Megabyte an ein DMA-basiertes Peripheriegerät müssen
die Daten zuerst von dort, wo sie liegen, in einen Puffer
unterhalb von 16 Megabyte geschrieben werden und dann kann der
DMA-Controller die Daten vom Puffer auf die Peripherie
kopieren. In FreeBSD werden diese reservierten Puffer
<quote>Bounce Buffers</quote> genannt. In der &ms-dos;-Welt
werden sie manchmal als <quote>Smart Buffers</quote>
bezeichnet.</para>
<note>
<para>Eine neuere Ausführung des 8237, 82374 genannt,
weist 16 Bit-Seitenregister auf und erlaubt Zugriff auf den
gesamten 32 Bit Adressraum ohne Zuhilfenahme von Bounce
Buffers.</para>
</note>
</sect2>
<sect2>
<title>DMA-Operationsmodi und Einstellungen</title>
<para>Der 8237 DMA-Controller kann in verschiedenen Modi
betrieben werden. Die Wichtigsten sind:</para>
<variablelist>
<varlistentry>
<term>Single</term>
<listitem>
<para>Ein einziges Byte (oder Wort) wird übertragen.
Der DMA-Controller muss für jedes
zusätzliche Byte den Bus freigeben und neu
anfordern. Dieser Modus wird normalerweise von
Geräten benutzt, welche nicht einen gesamten Block
von Daten auf einmal übertragen können. Das
Peripheriegerät wird den DMA-Controller jedesmal
anfordern, wenn es für einen weiteren Transfer
bereit ist.</para>
<para>Der Standard PC-kompatible Floppy-Controller (NEC
765) hat nur einen Puffer mit einem Byte, daher nutzt er
diesen Modus.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Block/Demand</term>
<listitem>
<para>Sobald der DMA-Controller den Bus übernommen
hat, wird ein ganzer Block von Daten übertragen bis
zu einem Maximum von 64K. Wenn das Peripheriegerät
zusätzliche Zeit benötigt, kann es das
READY-Signal setzen, um den Transfer kurzfristig zu
unterbrechen. READY sollte nicht exzessiv benutzt werden
und für langsame Peripheriegeräte sollte
stattdessen der Single Transfer-Modus genutzt
werden.</para>
<para>Der Unterschied zwischen Block und Demand ist,
dass sobald ein Block-Transfer gestartet ist,
dieser solange läuft, bis der Transfer-Zähler
Null erreicht. DRQ muss nur gesetzt werden, bis
-DACK gesetzt wird. Der Demand-Modus überträgt
ein weiteres Byte, bis DRQ gelöscht wird. An diesem
Punkt unterbricht der DMA-Controller die
Übertragung und gibt den Bus wieder an die CPU
zurück. Wenn DRQ wieder eingesetzt wird geht der
Transfer an der Stelle weiter, an welcher er
unterbrochen wurde.</para>
<para>Ältere Festplattencontroller benutzten den
Demand-Modus bis die CPU-Geschwindigkeiten stiegen,
sodass der Transfer mittels CPU schneller war,
insbesondere wenn die benutzten Speicherbereiche
jenseits der 16 Megabyte-Marke lagen.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Cascade</term>
<listitem>
<para>Dieser Mechanismus erlaubt einem DMA-Kanal den Bus
anzufordern, wobei dann aber das zugehörige
Peripheriegerät dafür verantwortlich ist die
Adressinformationen an den Bus zu senden anstatt des
DMA-Controllers. Dies wird auch dazu genutzt, um eine
Technik zu implementieren, die man als <quote>Bus
Mastering</quote> bezeichnet.</para>
<para>Wenn ein DMA-Kanal im Cascade-Modus Kontrolle
über den Bus erlangt, dann stellt der Controller
nicht die Adressen und I/O-Kontrollsignale auf den Bus,
wie es normalerweise der Fall ist. Stattdessen setzt der
Controller nur das -DACK-Signal für den aktiven
DMA-Kanal.</para>
<para>Nun ist es Aufgabe Peripheriegerätes, welches
mit diesem DMA-Kanal verbunden ist, die Adressen und
Bus-Kontrollsignale zu liefern. Das Peripheriegerät
hat vollständige Kontrolle über den Bus und
kann Lese- oder Schreibvorgänge an jeder Adresse
unterhalb von 16 Megabyte ausführen. Wenn es fertig
ist, setzt es das DRQ-Signal und der DMA-Controller kann
die Kontrolle an die CPU oder einen anderen DMA-Kanal
übergeben.</para>
<para>Der Cascade-Modus kann verwendet werden, um mehrere
DMA-Controller in Reihe zu schalten und genau dafür
wird der DMA-Kanal 4 in der PC-Architektur genutzt. Wenn
ein Peripheriegerät den Bus auf den
DMA-Kanälen 0, 1, 2 oder 3 verlangt, dann setzt der
abhängige DMA-Controller (slave DMA) HLDREQ, aber
dieses Signal ist in Wirklichkeit verbunden mit DRQ4 auf
dem primären DMA-Controller anstatt mit der CPU.
Der primäre DMA-Controller nimmt an, er habe Arbeit
zu leisten auf Kanal 4, und fordert den Bus an von der
CPU mit dem HLDREQ-Signal. Sobald die CPU die Kontrolle
des Bus an den primären DMA-Controller
übergeben hat, wird -DACK4 gesetzt und dieser Kanal
ist in Wirklichkeit mit dem abhängigen
DMA-Controller über das HDLA-Signal verbunden. Der
abhängige Controller überträgt dann die
Daten für den DMA-Kanal, der die Anforderung
gestellt hat (0, 1, 2 oder 3) oder der Controller
übergibt den Bus an ein Peripheriegerät,
welches selbst ein eigenes Bus-Mastering
durchführen will, z.B. einen
SCSI-Controller.</para>
<para>Wegen dieser Schaltungsanordnung können auf
PC/AT-Systemen nur die DMA-Kanäle 0, 1, 2, 3, 5, 6
und 7 mit Peripheriegeräten genutzt werden.</para>
<note>
<para>Der DMA-Kanal 0 war auf frühen IBM PCs
für Auffrischungs-Operationen reserviert, aber
auf modernen Rechnern ist er allgemein für
Peripheriegeräte verfügbar.</para>
</note>
<para>Wenn ein Peripheriegerät Bus Mastering
durchführt, ist es wichtig, dass es konstant
Daten vom oder zum Speicher überträgt, solange
es die Kontrolle über den Bus hält. Falls das
Peripheriegerät dies nicht kann, muss es den
Bus häufig freigeben, damit das System
Auffrischungsoperationen am Hauptspeicher vornehmen
kann.</para>
<para>Das dynamische RAM als Hauptspeicher in allen PCs
muss regelmäßig aufgefrischt werden, damit
die gespeicherten Bits <quote>geladen</quote> gehalten
werden. Dynamisches Ram besteht aus Millionen von
Transistoren, die jedes ein Bit Daten enthalten. Die
Transistoren sind geladen, um <literal>1</literal>
darzustellen, oder entladen, um <literal>0</literal> zu
repräsentieren. Da alle Transistoren Ladung
abgeben, muss in regelmäßigen Abständen
der Ladungsinhalt aufgefrischt werden durch
Wiederbeschreibung, um den Wert <literal>1</literal> zu
erhalten. Die RAM-Chips übernehmen diese Aufgabe
selbst, aber sie müssen dazu vom Rest des Rechners
angewiesen werden, damit die
Auffrischungsaktivitäten nicht mit den normalen
Zugriffen auf das RAM kollidieren. Falls der Rechner
das RAM nicht auffrischen kann wird der Inhalt des
Speichers binnen weniger Millisekunden
beschädigt.</para>
<para>Da Lese- und Schreibzyklen als Auffrischungszyklen
<quote>zählen</quote> (ein Auffrischungszyklus
eines dynamischen RAM ist in Wirklichkeit ein
unvollständiger Lesezyklus), wird diese Aktion den
gesamten Speicher auffrischen, solange der
abhängige Controller fortfährt Daten an
aufeinander folgenden Speicherbereiche zu lesen oder
dorthin zu schreiben.</para>
<para>Bus-Mastering findet man in einigen SCSI-Controllern
und anderen hochwertigen Peripherie-Controllern.</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Autoinitialize</term>
<listitem>
<para>Dieser Modus veranlasst den DMA-Controller dazu
Byte-, Block- oder Demand-Transfers auszuführen.
Aber wenn der DMA-Übertragungszähler Null
erreicht hat, dann werden die Zähler und Adressen
wieder auf den Wert zurückgesetzt, den sie
aufwiesen, als der DMA-Kanal ursprünglich
programmiert wurde. Das bedeutet, dass
Transfers zugelassen werden, solange das
Peripheriegerät sie anfordert. Es ist Aufgabe der
CPU neue Daten rechtzeitig in den Puffer zu schicken,
damit das Peripheriegerät sie schreiben kann bzw.
die neuen Daten aus dem Puffer zu lesen, wenn der
DMA-Controller bei Eingabeoperationen Daten
schreibt.</para>
<para>Diese Technik wird häufig bei Audiogeräten
genutzt, die kleine oder gar keine
<quote>Sample</quote>-Puffer in Hardware aufweisen.
Dadurch entsteht zusätzlicher CPU-Overhead bei der
Verwaltung dieses <quote>zirkulären</quote>
Puffers, aber in manchen Fällen ist es der einzige
Weg, um die Latenz zu beseitigen, die auftritt, wenn der
DMA-Zähler Null erreicht und der DMA-Controller mit
den Transfers anhält, bis er neu programmiert
ist.</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
<sect2>
<title>Das Programmieren des DMA-Controllers</title>
<para>Der zu programmierende DMA-Kanal sollte immer
<quote>maskiert</quote> werden, bevor irgendwelche
Einstellungen geladen werden. Dies soll deswegen geschehen,
weil die Hardware unerwarteterweise DRQ für diesen Kanal
setzen könnte und der Controller könnte antworten,
obwohl noch nicht alle Parameter geladen oder aktualisiert
wurden.</para>
<para>Nach der Maskierung muss der Host die Richtung des
Transfers festlegen (Speicher-zu-I/O oder I/O-zu-Speicher),
welcher DMA-Modus für den Transfer genutzt wird (Single,
Block, Demand, Cascade, etc.) und schließlich werden die
Adresse und die Länge des Transfers geladen. Die
Länge ist um 1 kleiner als die durch den DMA-Controller
zu übertragende. Das LSB und das MSB der Adresse und der
Länge werden auf den gleichen 8 Bit I/O-Port geschrieben,
also muss zunächst ein anderer Port geschrieben
werden, um zu gewährleisten, dass der DMA-Controller
das erste Byte als LSB und das zweite Byte als MSB der
Länge und der Adresse akzeptiert.</para>
<para>Stellen Sie dann sicher, dass Sie das Seitenregister
aktualisiert haben, welches extern zum DMA-Controller ist und
durch ein anderes Set von I/O-Ports angesprochen wird.</para>
<para>Sobald alle Einstellungen fertig sind, kann der DMA-Kanal
demaskiert werden. Dieser Kanal wird nun als
<quote>geschützt</quote> betrachtet und wird antworten,
wenn die DRQ-Linie für diesen Kanal gesetzt wird.</para>
<para>Schlagen Sie im Hardware Handbuch für
ausführliche Programmierdetails zum 8237 nach. Sie werden
auch auf die I/O-Portübersicht für den PC
zurückgreifen mü, welches beschreibt, wo die
DMA-Register und Seitenregister sich befinden. Eine
vollständige Tabelle der Ports finden Sie unten.</para>
</sect2>
<sect2>
<title>DMA Port-Übersicht</title>
<para>Alle Systeme, die auf dem IBM-PC und PC/AT basieren, weisen
die gleiche DMA-Hardware an identischen I/O-Ports auf. Die
vollständige Liste ist unten aufgeführt. Dem
DMA-Controller #2 zugewiesene Ports sind auf
nicht-AT-Systemeni undefiniert.</para>
<sect3>
<title>0x00&ndash;0x1f DMA-Controller #1 (Kanäle 0, 1, 2
und 3)</title>
<para>DMA-Adressregister und -Zählregister</para>
<informaltable frame="none" pgwide="1">
<tgroup cols="3">
<tbody>
<row>
<entry>0x00</entry>
<entry>write</entry>
<entry>Kanal 0 Startadresse</entry>
</row>
<row>
<entry>0x00</entry>
<entry>read</entry>
<entry>Kanal 0 gegenwärtige Adresse</entry>
</row>
<row>
<entry>0x01</entry>
<entry>write</entry>
<entry>Kanal 0 Anfangs-Wortnummer</entry>
</row>
<row>
<entry>0x01</entry>
<entry>read</entry>
<entry>Kanal 0 verbleibende Wortzahl</entry>
</row>
<row>
<entry>0x02</entry>
<entry>write</entry>
<entry>Kanal 1 Startadresse</entry>
</row>
<row>
<entry>0x02</entry>
<entry>read</entry>
<entry>Kanal 1 gegenwärtige Adresse</entry>
</row>
<row>
<entry>0x03</entry>
<entry>write</entry>
<entry>Kanal 1 Anfangs-Wortnummer</entry>
</row>
<row>
<entry>0x03</entry>
<entry>read</entry>
<entry>Kanal 1 verbleibende Wortzahl</entry>
</row>
<row>
<entry>0x04</entry>
<entry>write</entry>
<entry>Kanal 2 Startadresse</entry>
</row>
<row>
<entry>0x04</entry>
<entry>read</entry>
<entry>Kanal 2 gegenwärtige Adresse</entry>
</row>
<row>
<entry>0x05</entry>
<entry>write</entry>
<entry>Kanal 2 Anfangs-Wortnummer</entry>
</row>
<row>
<entry>0x05</entry>
<entry>read</entry>
<entry>Kanal 2 verbleibende Wortzahl</entry>
</row>
<row>
<entry>0x06</entry>
<entry>write</entry>
<entry>Kanal 3 Startadresse</entry>
</row>
<row>
<entry>0x06</entry>
<entry>read</entry>
<entry>Kanal 3 gegenwärtige Adresse</entry>
</row>
<row>
<entry>0x07</entry>
<entry>write</entry>
<entry>Kanal 3 Anfangs-Wortnummer</entry>
</row>
<row>
<entry>0x07</entry>
<entry>read</entry>
<entry>Kanal 3 verbleibende Wortzahl</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>DMA-Befehlsregister</para>
<informaltable frame="none" pgwide="1">
<tgroup cols="3">
<tbody>
<row>
<entry>0x08</entry>
<entry>write</entry>
<entry>Befehlsregister</entry>
</row>
<row>
<entry>0x08</entry>
<entry>read</entry>
<entry>Status-Register</entry>
</row>
<row>
<entry>0x09</entry>
<entry>write</entry>
<entry>Anforderungsregister</entry>
</row>
<row>
<entry>0x09</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0x0a</entry>
<entry>write</entry>
<entry>Single Mask Register Bit</entry>
</row>
<row>
<entry>0x0a</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0x0b</entry>
<entry>write</entry>
<entry>Modusregister</entry>
</row>
<row>
<entry>0x0b</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0x0c</entry>
<entry>write</entry>
<entry>Flip-Flop zm Löschen des LSB/MSB</entry>
</row>
<row>
<entry>0x0c</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0x0d</entry>
<entry>write</entry>
<entry>Master Clear/Reset</entry>
</row>
<row>
<entry>0x0d</entry>
<entry>read</entry>
<entry>Temporäres Register (in neueren Versionen
nicht verfügbar).</entry>
</row>
<row>
<entry>0x0e</entry>
<entry>write</entry>
<entry>Läsche Mask-Register</entry>
</row>
<row>
<entry>0x0e</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0x0f</entry>
<entry>write</entry>
<entry>Schreibe alle Mask-Register-Bits</entry>
</row>
<row>
<entry>0x0f</entry>
<entry>read</entry>
<entry>Lese alle Mask-Register-Bits (nur auf &intel;
82374)</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect3>
<sect3>
<title>0xc0&ndash;0xdf DMA-Controller #2 (Kanäle 4, 5, 6 und
7)</title>
<para>DMA-Adressregister und -Zählregister</para>
<informaltable frame="none" pgwide="1">
<tgroup cols="3">
<tbody>
<row>
<entry>0xc0</entry>
<entry>write</entry>
<entry>Kanal 4 Startadresse</entry>
</row>
<row>
<entry>0xc0</entry>
<entry>read</entry>
<entry>Kanal 4 gegenwärtige Adresse</entry>
</row>
<row>
<entry>0xc2</entry>
<entry>write</entry>
<entry>Kanal 4 Anfangs-Wortnummer</entry>
</row>
<row>
<entry>0xc2</entry>
<entry>read</entry>
<entry>Kanal 4 verbleibende Wortzahl</entry>
</row>
<row>
<entry>0xc4</entry>
<entry>write</entry>
<entry>Kanal 5 Startadresse</entry>
</row>
<row>
<entry>0xc4</entry>
<entry>read</entry>
<entry>Kanal 5 gegenwärtige Adresse</entry>
</row>
<row>
<entry>0xc6</entry>
<entry>write</entry>
<entry>Kanal 5 Anfangs-Wortnummer</entry>
</row>
<row>
<entry>0xc6</entry>
<entry>read</entry>
<entry>Kanal 5 verbleibende Wortzahl</entry>
</row>
<row>
<entry>0xc8</entry>
<entry>write</entry>
<entry>Kanal 6 Startadresse</entry>
</row>
<row>
<entry>0xc8</entry>
<entry>read</entry>
<entry>Kanal 6 gegenwärtige Adresse</entry>
</row>
<row>
<entry>0xca</entry>
<entry>write</entry>
<entry>Kanal 6 Anfangs-Wortnummer</entry>
</row>
<row>
<entry>0xca</entry>
<entry>read</entry>
<entry>Kanal 6 verbleibende Wortzahl</entry>
</row>
<row>
<entry>0xcc</entry>
<entry>write</entry>
<entry>Kanal 7 Startadresse</entry>
</row>
<row>
<entry>0xcc</entry>
<entry>read</entry>
<entry>Kanal 7 gegenwärtige Adresse</entry>
</row>
<row>
<entry>0xce</entry>
<entry>write</entry>
<entry>Kanal 7 Anfangs-Wortnummer</entry>
</row>
<row>
<entry>0xce</entry>
<entry>read</entry>
<entry>Kanal 7 verbleibende Wortzahl</entry>
</row>
</tbody>
</tgroup>
</informaltable>
<para>DMA-Befehlsregister</para>
<informaltable frame="none" pgwide="1">
<tgroup cols="3">
<tbody>
<row>
<entry>0xd0</entry>
<entry>write</entry>
<entry>Befehlsregister</entry>
</row>
<row>
<entry>0xd0</entry>
<entry>read</entry>
<entry>Status-Register</entry>
</row>
<row>
<entry>0xd2</entry>
<entry>write</entry>
<entry>Anforderungsregister</entry>
</row>
<row>
<entry>0xd2</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0xd4</entry>
<entry>write</entry>
<entry>Single Mask Register Bit</entry>
</row>
<row>
<entry>0xd4</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0xd6</entry>
<entry>write</entry>
<entry>Modusregister</entry>
</row>
<row>
<entry>0xd6</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0xd8</entry>
<entry>write</entry>
<entry>Flip-Flop zum Löschen des LSB/MSB</entry>
</row>
<row>
<entry>0xd8</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0xda</entry>
<entry>write</entry>
<entry>Master Clear/Reset</entry>
</row>
<row>
<entry>0xda</entry>
<entry>read</entry>
<entry>temporäres Register (nicht verfügbar
auf &intel; 82374)</entry>
</row>
<row>
<entry>0xdc</entry>
<entry>write</entry>
<entry>Lösche Mask-Register</entry>
</row>
<row>
<entry>0xdc</entry>
<entry>read</entry>
<entry>-</entry>
</row>
<row>
<entry>0xde</entry>
<entry>write</entry>
<entry>Schreibe alle Mask-Register-Bits</entry>
</row>
<row>
<entry>0xdf</entry>
<entry>read</entry>
<entry>Lese alle Mask-Register-Bits (nur auf &intel;
82374)</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect3>
<sect3>
<title>0x80&ndash;0x9f DMA-Seitenregister</title>
<informaltable frame="none" pgwide="1">
<tgroup cols="3">
<tbody>
<row>
<entry>0x87</entry>
<entry>r/w</entry>
<entry>Kanal 0 niederes Byte (23-16)
Seitenregister</entry>
</row>
<row>
<entry>0x83</entry>
<entry>r/w</entry>
<entry>Kanal 1 niederes Byte (23-16)
Seitenregister</entry>
</row>
<row>
<entry>0x81</entry>
<entry>r/w</entry>
<entry>Kanal 2 niederes Byte (23-16)
Seitenregister</entry>
</row>
<row>
<entry>0x82</entry>
<entry>r/w</entry>
<entry>Kanal 3 niederes Byte (23-16)
Seitenregister</entry>
</row>
<row>
<entry>0x8b</entry>
<entry>r/w</entry>
<entry>Kanal 5 niederes Byte (23-16)
Seitenregister</entry>
</row>
<row>
<entry>0x89</entry>
<entry>r/w</entry>
<entry>Kanal 6 niederes Byte (23-16)
Seitenregister</entry>
</row>
<row>
<entry>0x8a</entry>
<entry>r/w</entry>
<entry>Kanal 7 niederes Byte (23-16)
Seitenregister</entry>
</row>
<row>
<entry>0x8f</entry>
<entry>r/w</entry>
<entry>niederes Byte Seitenauffrischung</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect3>
<sect3>
<title>0x400&ndash;0x4ff 82374 Erweiterte DMA-Register</title>
<para>Die &intel; 82374 EISA-System-Komponente (EISA System
Component ESC) wurde Anfang 1996 eingeführt und
beinhaltet einen DMA-Controller, der die Funktionen des 8237
und zusätzlich andere PC-kompatible
Kern-Peripheriekomponenten in einer einzigen Komponente
vereint. Dieser Chip wurde für EISA und PCI-Plattformen
entworfen und stellt moderne DMA-Funktionen wie
Scatter-Gather, Ring-Puffer und direkten Zugriff des
DMA-Controllers auf alle 32 Bit des Adressraumes zur
Verfügung.</para>
<para>Werden diese Leistungsmerkmale genutzt, dann sollte Code
hinzugefügt werden, der die gleiche Funktionalität
für Geräte aus den 16 Jahren PC-kompatibler
Geräte vor diesem Chip zur Verfügung stellt. Aus
Kompatibilitätsgründen müssen einige der
Register des 82374 programmiert werden
<emphasis>nachdem</emphasis> die traditionellen Register des
8237 für jeden Transfer programmiert wurden. Das
Schreiben in eines der traditionellen 8237-Register
führt dazu, dass einige der erweiterten Register
des 82374 aus Kompatibilitätsgründen auf Null
gesetzt werden.</para>
<informaltable frame="none" pgwide="1">
<tgroup cols="3">
<tbody>
<row>
<entry>0x401</entry>
<entry>r/w</entry>
<entry>Kanal 0 hohes Byte (Bits 23-16)
Word-Zähler</entry>
</row>
<row>
<entry>0x403</entry>
<entry>r/w</entry>
<entry>Kanal 1 hohes Byte (Bits 23-16)
Word-Zähler</entry>
</row>
<row>
<entry>0x405</entry>
<entry>r/w</entry>
<entry>Kanal 2 hohes Byte (Bits 23-16)
Word-Zähler</entry>
</row>
<row>
<entry>0x407</entry>
<entry>r/w</entry>
<entry>Kanal 3 hohes Byte (Bits 23-16)
Word-Zähler</entry>
</row>
<row>
<entry>0x4c6</entry>
<entry>r/w</entry>
<entry>Kanal 5 hohes Byte (Bits 23-16)
Word-Zähler</entry>
</row>
<row>
<entry>0x4ca</entry>
<entry>r/w</entry>
<entry>Kanal 6 hohes Byte (Bits 23-16)
Word-Zähler</entry>
</row>
<row>
<entry>0x4ce</entry>
<entry>r/w</entry>
<entry>Kanal 7 hohes Byte (Bits 23-16)
Word-Zähler</entry>
</row>
<row>
<entry>0x487</entry>
<entry>r/w</entry>
<entry>Kanal 0 hohes Byte (Bits 31-24)
Seitenregister</entry>
</row>
<row>
<entry>0x483</entry>
<entry>r/w</entry>
<entry>Kanal 1 hohes Byte (Bits 31-24)
Seitenregister</entry>
</row>
<row>
<entry>0x481</entry>
<entry>r/w</entry>
<entry>Kanal 2 hohes Byte (Bits 31-24)
Seitenregister</entry>
</row>
<row>
<entry>0x482</entry>
<entry>r/w</entry>
<entry>Kanal 3 hohes Byte (Bits 31-24)
Seitenregister</entry>
</row>
<row>
<entry>0x48b</entry>
<entry>r/w</entry>
<entry>Kanal 5 hohes Byte (Bits 31-24)
Seitenregister</entry>
</row>
<row>
<entry>0x489</entry>
<entry>r/w</entry>
<entry>Kanal 6 hohes Byte (Bits 31-24)
Seitenregister</entry>
</row>
<row>
<entry>0x48a</entry>
<entry>r/w</entry>
<entry>Kanal 6 hohes Byte (Bits 31-24)
Seitenregister</entry>
</row>
<row>
<entry>0x48f</entry>
<entry>r/w</entry>
<entry>hohes Byte Seitenauffrischung</entry>
</row>
<row>
<entry>0x4e0</entry>
<entry>r/w</entry>
<entry>Kanal 0 Halteregister (Bits 7-2)</entry>
</row>
<row>
<entry>0x4e1</entry>
<entry>r/w</entry>
<entry>Kanal 0 Halteregister (Bits 15-8)</entry>
</row>
<row>
<entry>0x4e2</entry>
<entry>r/w</entry>
<entry>Kanal 0 Halteregister (Bits 23-16)</entry>
</row>
<row>
<entry>0x4e4</entry>
<entry>r/w</entry>
<entry>Kanal 1 Halteregister (Bits 7-2)</entry>
</row>
<row>
<entry>0x4e5</entry>
<entry>r/w</entry>
<entry>Kanal 1 Halteregister (Bits 15-8)</entry>
</row>
<row>
<entry>0x4e6</entry>
<entry>r/w</entry>
<entry>Kanal 1 Halteregister (Bits 23-16)</entry>
</row>
<row>
<entry>0x4e8</entry>
<entry>r/w</entry>
<entry>Kanal 2 Halteregister (Bits 7-2)</entry>
</row>
<row>
<entry>0x4e9</entry>
<entry>r/w</entry>
<entry>Kanal 2 Halteregister (Bits 15-8)</entry>
</row>
<row>
<entry>0x4ea</entry>
<entry>r/w</entry>
<entry>Kanal 2 Halteregister (Bits 23-16)</entry>
</row>
<row>
<entry>0x4ec</entry>
<entry>r/w</entry>
<entry>Kanal 3 Halteregister (Bits 7-2)</entry>
</row>
<row>
<entry>0x4ed</entry>
<entry>r/w</entry>
<entry>Kanal 3 Halteregister (Bits 15-8)</entry>
</row>
<row>
<entry>0x4ee</entry>
<entry>r/w</entry>
<entry>Kanal 3 Halteregister (Bits 23-16)</entry>
</row>
<row>
<entry>0x4f4</entry>
<entry>r/w</entry>
<entry>Kanal 5 Halteregister (Bits 7-2)</entry>
</row>
<row>
<entry>0x4f5</entry>
<entry>r/w</entry>
<entry>Kanal 5 Halteregister (Bits 15-8)</entry>
</row>
<row>
<entry>0x4f6</entry>
<entry>r/w</entry>
<entry>Kanal 5 Halteregister (Bits 23-16)</entry>
</row>
<row>
<entry>0x4f8</entry>
<entry>r/w</entry>
<entry>Kanal 6 Halteregister (Bits 7-2)</entry>
</row>
<row>
<entry>0x4f9</entry>
<entry>r/w</entry>
<entry>Kanal 6 Halteregister (Bits 15-8)</entry>
</row>
<row>
<entry>0x4fa</entry>
<entry>r/w</entry>
<entry>Kanal 6 Halteregister (Bits 23-16)</entry>
</row>
<row>
<entry>0x4fc</entry>
<entry>r/w</entry>
<entry>Kanal 7 Halteregister (Bits 7-2)</entry>
</row>
<row>
<entry>0x4fd</entry>
<entry>r/w</entry>
<entry>Kanal 7 Halteregister (Bits 15-8)</entry>
</row>
<row>
<entry>0x4fe</entry>
<entry>r/w</entry>
<entry>Kanal 7 Halteregister (Bits 23-16)</entry>
</row>
<row>
<entry>0x40a</entry>
<entry>write</entry>
<entry>Kanal 0-3 Chaining-Modusregister</entry>
</row>
<row>
<entry>0x40a</entry>
<entry>read</entry>
<entry>Kanal Interrupt Status-Register</entry>
</row>
<row>
<entry>0x4d4</entry>
<entry>write</entry>
<entry>Kanal 4-7 Chaining-Modusregister</entry>
</row>
<row>
<entry>0x4d4</entry>
<entry>read</entry>
<entry>Chaining Mode Status</entry>
</row>
<row>
<entry>0x40c</entry>
<entry>read</entry>
<entry>Chain Buffer Expiration
Kontrollregister</entry>
</row>
<row>
<entry>0x410</entry>
<entry>write</entry>
<entry>Kanal 0 Scatter-Gather Befehlsregister</entry>
</row>
<row>
<entry>0x411</entry>
<entry>write</entry>
<entry>Kanal 1 Scatter-Gather Befehlsregister</entry>
</row>
<row>
<entry>0x412</entry>
<entry>write</entry>
<entry>Kanal 2 Scatter-Gather Befehlsregister</entry>
</row>
<row>
<entry>0x413</entry>
<entry>write</entry>
<entry>Kanal 3 Scatter-Gather Befehlsregister</entry>
</row>
<row>
<entry>0x415</entry>
<entry>write</entry>
<entry>Kanal 5 Scatter-Gather Befehlsregister</entry>
</row>
<row>
<entry>0x416</entry>
<entry>write</entry>
<entry>Kanal 6 Scatter-Gather Befehlsregister</entry>
</row>
<row>
<entry>0x417</entry>
<entry>write</entry>
<entry>Kanal 7 Scatter-Gather Befehlsregister</entry>
</row>
<row>
<entry>0x418</entry>
<entry>read</entry>
<entry>Kanal 0 Scatter-Gather Statusregister</entry>
</row>
<row>
<entry>0x419</entry>
<entry>read</entry>
<entry>Kanal 1 Scatter-Gather Statusregister</entry>
</row>
<row>
<entry>0x41a</entry>
<entry>read</entry>
<entry>Kanal 2 Scatter-Gather Statusregister</entry>
</row>
<row>
<entry>0x41b</entry>
<entry>read</entry>
<entry>Kanal 3 Scatter-Gather Statusregister</entry>
</row>
<row>
<entry>0x41d</entry>
<entry>read</entry>
<entry>Kanal 5 Scatter-Gather Statusregister</entry>
</row>
<row>
<entry>0x41e</entry>
<entry>read</entry>
<entry>Kanal 5 Scatter-Gather Statusregister</entry>
</row>
<row>
<entry>0x41f</entry>
<entry>read</entry>
<entry>Kanal 7 Scatter-Gather Statusregister</entry>
</row>
<row>
<entry>0x420-0x423</entry>
<entry>r/w</entry>
<entry>Kanal 0 Scatter-Gather Descriptor Table Pointer
Register</entry>
</row>
<row>
<entry>0x424-0x427</entry>
<entry>r/w</entry>
<entry>Kanal 1 Scatter-Gather Descriptor Table Pointer
Register</entry>
</row>
<row>
<entry>0x428-0x42b</entry>
<entry>r/w</entry>
<entry>Kanal 2 Scatter-Gather Descriptor Table Pointer
Register</entry>
</row>
<row>
<entry>0x42c-0x42f</entry>
<entry>r/w</entry>
<entry>Kanal 3 Scatter-Gather Descriptor Table Pointer
Register</entry>
</row>
<row>
<entry>0x434-0x437</entry>
<entry>r/w</entry>
<entry>Kanal 5 Scatter-Gather Descriptor Table Pointer
Register</entry>
</row>
<row>
<entry>0x438-0x43b</entry>
<entry>r/w</entry>
<entry>Kanal 6 Scatter-Gather Descriptor Table Pointer
Register</entry>
</row>
<row>
<entry>0x43c-0x43f</entry>
<entry>r/w</entry>
<entry>Kanal 7 Scatter-Gather Descriptor Table Pointer
Register</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</sect3>
</sect2>
</sect1>
</chapter>