<?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 © 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–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–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–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–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>