Heute ist es soweit: Mit dem Milan und dem Hades stehen den ATARI-Anwendern inzwischen zwei Rechner zur Verfügung, die einen PCI-Bus besitzen. Schon bald soll ein Falcon-PCI-Adapter erscheinen, und eines Tages wird auch der französische Phenix mit PCI-Bus zu erhalten sein.
Alles deutet also darauf hin, dass PCI-Karten nun auch für das TOS angepaßt werden.
Erfreulicherweise ist die Entwicklung in diesem Bereich soweit vorangeschritten, dass ein gemeinsames PCI-BIOS entwickelt wurde, das ermöglicht, dass einmal angepasste Treiber auf allen o.g. Systemen laufen werden.
In unserem mehrteiligen Kurs wollen wir Sie über die Funktionsweise des PCI-Busses und anschließend die Programmierung des TOS PCI-BIOS informieren.
Der Peripheral Components Interconnect (PCI) Bus wurde ursprünglich für IBM-kompatible PCs entwickelt, da dringend die Notwendigkeit eines schnellen, prozessorunabhängigen Bussystems bestand. Seither hat sich dieser Bus auch für andere Rechnerwelten etabliert (wie z.B. die aktuellen Macintosh-Modelle auf Basis des PowerPC, diverse Workstations mit DECs Alpha-Prozessor oder aber auch die aktuelle UItraSparc von SUN).
Auch die Entwickler des Hades und des Milan haben an diese wirklich universelle Schnittstelle gedacht. Diese Entwicklung führte dahin, dass man nun tatsächlich dieselben Erweiterungskarten auf unterschiedlichen Rechnerplattformen nutzen kann - sofern jeweils Treiber für das betreffende System verfügbar sind. Daher ist es längst an der Zeit, sich einmal näher mit dem PCI-Bus zu beschäftigen. Diese erste Folge soll einen überblick über die Möglichkeiten des PCI-Bus schaffen, die zweite Folge beschreibt dann die einzelnen Register für die Initialisierung und Konfiguration von PCI-Karten, und die abschließende dritte Folge befaßt sich dann mit der Portierung und Implementierung des vom PC her bekannten PCI-BIOS für ATARI-kompatible Rechner am Beispiel von Hades und Milan.
Der PCI-Bus ist für 32 Bit breite Daten bei maximal 33 MHz spezifiziert und ist optional auf 64 Bit und/oder 66 MHz erweiterbar. Der Takt darf aber im Prinzip einen beliebigen Wert zwischen 0 und 33 MHz annehmen.
Bei 33 MHz und 32 Bit Datenbreite sind theoretische übertragungsraten von bis zu 132 MB/s möglich, und in der Praxis sind tatsächlich Werte nahe diesem theoretischen Maximum erreichbar.
Nach der elektrischen Spezifikation können an einem PCI-Bus bis zu vier Slots neben dem Hostsystem untergebracht sein. über eine PCI-Bridge lässt sich dann noch ein weiterer Bus anhängen. Falls dies wieder ein PCI-Bus ist, kann man das Spiel auch mehrfach wiederholen.
Jedes PC[-Gerät kann mehrere unabhängige Funktionen beinhalten (multifunction devices), die sich auch unabhängig über den Bus ansprechen lassen. Die meisten derzeit erhältlichen Geräte sind allerdings sogenannte 'single function devices'.
Multi function devices verhalten sich prinzipiell wie mehrere single function devices, nur dass eben die Configuration Bereiche der einzelnen Funktionen dieser Karten anders angesprochen werden.
Bei den Multifunktionskarten kann man zwei von Grund auf verschiedene Versionen unterscheiden:
Nur ein einziger Bus - die Konfigurationsbereiche solcher PCI-Karten liegen jeweils 256 Bytes auseinander (d.h. die Adressleitungen spiegeln einfach Register (Bit 0-7) und Funktionsnummer (Bit 8-15) der Karte wieder.
PCI2PCI-Bridge mit single function devices oder multi function devices vom Typ 1 am zweiten Bus - so etwas kommt z.B. bei Kombikarten wie Ethernet + SCSI vor. Da die Busnummer hier über die Adressleitungen A16-23 ausgewählt werden würde, lassen sich solche Karten beim Hades wahrscheinlich nicht oder nur eingeschränkt verwenden (weil die Konfigurationsbereiche ja auf wenige KB beschränkt sind).
Für die grundlegenden Funktionen des PCI-Bus werden insgesamt 47 Pins für Slave-Adapter sowie 49 Pins für Master-Adapter benötigt. Dazu kommen die Anschlüsse der Versorgungsspannung. Auf eine Aufzählung aller Signale möchte ich hier allerdings verzichten, da diese den Artikel sichtlich sprengen würden. Deshalb sollen nur die wichtigsten, in den Abbildungen verwendeten Signale näher erläutert werden:
AD[0..31] - Address/Data
Adressen und Daten werden gemultiplext übertragen. Die einzelnen Bytes des 32-Bit-Wortes werden über die Leitungen /C/BE[0..3] freigegeben.
/C/BE[0..3] - Command/Byte Enable
Enthält in der Adressphase das Buskommando (verschiedene Lese- und Schreibarten) und in der Datenphase das Signal Byte Enable für die Datenleitungen.
IDSEL- Initialization Device Select
Chip Select für Initialisierung und Konfiguration der PCI-Karte. Für jeden PCI-Slot ist eine eigene Leitung vorhanden.
/REQ - Request, wird nur für Busmastering verwendet.
Busanforderung, für jeden Slot ist eine Leitung vorhanden.
/GNT - Grant, wird nur für Busmastering verwendet.
Buszuteilung, für jeden Slot ist eine Leitung vorhanden.
/INTA - Interrupt Request A
Anforderung eines Interrupts bei single function devices.
/INTB, C, D - Interrupt Request B, C, D
Diese Interruptleitungen dürfen nur von Geräten mit mehreren Funktionseinheiten (multi function devices) verwendet werden.
Die restlichen Signale dienen mehr oder weniger der Steuerung während den verschiedenen Adress- und Datenphasen und deren Synchronisation. Näheres findet man in der PCI Local Bus Specification und den PCI System Design Guides, einen guten überblick kann man sich aber auch mittels der Elrad-Hefte 3/97 und 4/97 verschaffen.
Da wir hier nicht neue PCI-Karten entwickeln möchten, sondern aus dem PC-Bereich bereits vorhandene Karten auch dem Hades, Milan und anderen kompatiblen ATARI-Rechnern schmackhaft machen möchten, verzichten wir hier auf weitere Hardware-Details, die für Treiber-Anpassungen nicht relevant sind. Die korrekte Verarbeitung der Signale sollte ja ohnehin von den in den Rechnern vorhandenen PCI-Bridges übernommen werden.
Wer aber trotzdem (oder gerade deswegen) eigene Karten entwickeln möchte, sollte sich Datenblätter der PCIBridges von AMCC[4] und PLX[5] besorgen. Wer das PCI-Busprotokoll selbst implementieren möchte, benötigt dafür relativ schnelle CPLDs oder FPGAs. Hersteller wie Xilinx[6] oder Lattice[7] bieten dafür auch BeispielSourcen an.
Grundsätzlich kann jedes beliebige PCI-Gerät als Busmaster auftreten. Als Busmaster kann dieses PCI-Gerät dann selbständig Daten aus seinem eigenen Speicherbereich in den Systemspeicher des Host-Rechners übertragen. Diese Art der Hintergrundverarbeitung entlastet den Prozessor des Host-Rechners sehr stark. Deshalb sollten alle PCI-Geräte, die große Datenmengen zu transportieren haben, oder aber schnelle Transfers erfordern, als Busmaster auftreten können. Die DMA-Fähigkeit des PCI-Bus benutzen z.B. SCSI-Controller oder auch moderne Netzwerkkarten, um Daten schnell in den oder aus dem Hauptspeicher zu transportieren.
Die Vorteile bei Verwendung eines busmasterfähigen PCI-Gerätes zeigen sich ganz besonders bei 'echten' Multitasking-Betriebssystemen, da dort die gesparte Rechenzeit anderen Prozessen zur Verfügung gestellt werden kann. Unter Single-Tasking unterliegt es dem Geschick des Programmierers, aus der Busmaster-Fähigkeit eines PCI-Gerätes Vorteile zu ziehen. Ein Zugriff, der nur auf das Ende einer übertragung wartet, ist zwar einfacher zu implementieren, verschenkt durch Leerlauf des Prozessors aber wieder die gewonnene Zeit.
Das busmasterfähige PCI-Gerät fordert den Bus durch Setzen seiner /REQLeitung an. Ein Master darf /REQ allerdings nur für seinen aktuellen Zugriff
Abbildung 1: PCI-Bussystem des Hades
benutzen, nicht aber, um sich den Bus auf Dauer zu sichern. Der Bus Arbiter des Host-Rechners teilt diesem Gerät den Bus durch Setzen des entsprechenden /GNT-Signals zu. Nachdem dem PCI-Gerät der Bus zugeteilt wurde, kann dieses seinen DMA-Zugriff durchführen. Wenn das PCI-Gerät nicht innerhalb einer bestimmten Zeit den Bus wieder freigibt, kann der Host-Rechner durch das Wegnehmen der /GNT-Leitung den Bus auch wieder frei bekommen. Der Busmaster muß dann nämlich augenblicklich den Zugriff beenden.
Auf dem PCI-Bus sind insgesamt vier "pegel"-getriggerte Interrupt-Leitungen vorhanden (INTA...INTD). Alle Geräte mit nur einer Funktion dürfen nur INTA verwenden, die anderen drei Leitungen sind für den Betrieb sogenannter 'multi function devices' vorgesehen.
In der PCI-Spezifikation selbst ist die weitere Verarbeitung der Interrupts nicht definiert und wird somit dem jeweiligen Boardhersteller überlassen. Die Interruptleitungen der einzelnen Slots können daher entweder als "durchgeschleifte" Busleitung (open drain) in jeder nur erdenklichen Kombination verbunden sein oder aber sie werden von jedem Slot einzeln an den entsprechenden Interrupt Controller herangeführt. Nach einer Interruptanforderung ist dann der jeweilige Treiber dieses PCI-Gerätes dafür verantwortlich, die Ursache der Unterbrechungsanforderung zu beheben.
Abbildung 1: PCI-Bussystem des Milan
Im Gegensatz zum recht kranken Design des ISA-Busses ist es daher beim PCI-Bus möglich, dass sich mehrere Karten eine Interruptleitung teilen (shared interrupt) - Engpässe, wie man sie früher von den DOSen her kannte, werden damit vermieden. Allerdings müssen dann die eingesetzten Softwaretreiber für die PCI-Karten auch Interrupts bearbeiten können, bei denen sich mehrere Geräte eine Interruptleitung teilen. Mehr zu diesem Thema gibt es dann bei der Vorstellung des PCI-BIOS.
Im Hades wird die zur Zeit gebräuchliche Implementierung mit 32 Bit und maximal 33 MHz eingesetzt. Für die Umsetzung des PCI-Busses im Hades wurde dabei die 'PCI Local Bus Specification Revision 2.0' herangezogen. Die Anbindung an die CPU erfolgt durch einen reprogrammierbaren Xilinx-Baustein, durch den daher auch spätere Erweiterungen möglich sein sollten.
Die Interruptleitungen INTA - INTD jedes Slots sind zusammengefaßt und werden danach der TT-MFP zugeführt. Durch die Verwendung eines MFP als Interrupt-Controller (nur Flankentriggerung möglich), entspricht die Anbindung beim Hades eigentlich nicht der PCI-Spezifikation, da in dieser sämtliche Interruptleitungen als 'pegelgetriggert' definiert sind. Dieser Umstand erschwert natürlich die korrekte Implementation von InterruptHandlern, die dieses Verhalten entsprechend berücksichtigen müssen. Besser ist natürlich die Verwendung eines PCI-BIOS, das einem diese "Schwerstarbeit" abnimmt.
Im Hades gibt es für die 4 PCI-Slots insgesamt 3 DMA-Kanäle. PCI-Slot 1 belegt DMA-Kanal 1 (höchste Priorität), PCI-Slot 2 ist der DMA-Kanal 2 zugeordnet. Die /REQ- und /GNT-Leitungen der Slots 3 und 4 sind bezüglich DMA zusammengefaßt und belegen den DMA-Kanal 3 (niedrigste Priorität). Die Busarbitrierung mit Hilfe dieser Signale wird von einem weiteren Mini-Xilinx übernommen.
Abbildung 1 zeigt die an der Funktion des PCI-Bus beteiligten Komponenten im Hades.
Auch der Milan hat einen PCI-Bus mit einer Datenbreite von 32 Bit bei maximal 33 MHz. Die Anbindung an die CPU erfolgt über eine PCI-Bridge der Firma PLX.
Es sind insgesamt 4 Interruptleitungen vorhanden, die zyklisch zwischen den Slots getauscht sind - dadurch bekommt bei single function devices jede Karte einen eigenen Interrupt, und erst bei multi function devices wird es nötig, Interrupts gemeinsam zu benutzen.
Interrupts werden über die Intel PCI-ISA-Bridge und die darin vorhandenen Interrupt-Controller bearbeitet und als Autovektor-Interrupt an die CPU weitergemeldet.
Die Busarbitrierung für die DMA-Zugriffe erfolgt in einem der Glue-Chips alle Slots (sowie die Onboard-Peripherie) sind busmasterfähig. Es wird eine Arbitrierung mit rotierender Priorität verwendet, bei der die Karte, die gerade den Bus besitzt, die niedrigste Priorität hat, so dass eine Karte den Bus nicht komplett blockieren kann.
Wenn niemand den Bus anfordert, wird er bei dem Gerät, welches ihn zuletzt besaß, geparkt - das spart Zeit, wenn danach das gleiche Gerät den Bus wieder anfordert.
Abbildung 2 gibt das Blockschaltbild der im Milan verwendeten HardwareStruktur wieder.
Die PCI-Spezifikation beschreibt auch einen Mechanismus, mit dem ein PCI-Gerät einen exekutierbaren ROMCode für eine gerätespezifische Initialisierung usw. anbieten kann. Dieses ROM kann dabei mehrere verschiedene ROM-Images beinhalten, um die verschiedensten Rechner und Prozessorarchitekturen zu unterstützen.
Der OPENBOOT Standard für PCI sieht Fortran-Programme im ROM vor, so dass der ROM-Code zwar langsam (weil interpretiert), aber dafür prozessorunabhängig ist. Die andere Möglichkeit sind native ROM-Images (für die jeweilige zu unterstützende Plattform), wovon die Hersteller aber keinen Gebrauch machen (wohl weil sich dann nur noch schwer begründen ließe, warum z.B. dieselbe Grafikkarte für einen PowerMac meist 100% teurer ist als für den Intel PC). Natürlich können OPENBOOT-Images und native Images gemeinsam in einem ROM untergebracht werden.
Am ATARI werden die ROMs auf den Karten im Moment zwar noch nicht genutzt, aber dieser Umstand wird sich schon demnächst ändern.
Das Zauberwort 'Plug and Play' ist sehr eng mit dem PCI-Bus verbunden. Denn erst hier ist das leidige Thema der Ressourcenvergabe für die Hardware über ein geeignetes BIOS (PCI-BIOS) elegant lösbar.
Im Idealfall sieht die Installation einer neuen PCI-Karte also folgendermaßen aus (im Gegensatz zum PC ist bei ATARI-kompatiblen ein nochmaliges (oder gar mehrmaliges) Booten während der Installation NICHT notwendig
Der PCI-Bus ist eigentlich selbstkonfigurierend definiert. Dafür beinhaltet jedes PCI-Gerät einen Satz von Registern, die während des Boot-Vorgangs ausgelesen werden können. Enthalten sind hier neben Informationen über das Gerät selbst (Hersteller, Gerät, Typenklasse, Möglichkeiten, Waitstates, Interrupt, ...) auch die benötigten Speicherbereiche.
Damit ist es dem BIOS möglich, die Karte korrekt ins System einzubinden, ohne dass Ressourcenkonflikte auftreten oder sich der Benutzer mit D~PSchaltern, Jumpern etc. herumschlagen muß.
Am Macintosh-Sektor (NuBus) und am Amiga-Sektor (Zorro II/III-Bus) ist z.B. das Problem der Autokonfigurierung übrigens bereits seit der Existenz der jeweiligen Bussysteme (also seit über 10 Jahren) gelöst!
Der PCI-Standard sieht mittlerweile auch optional die "Hot-Plug-Fähigkeit" vor, so dass PCI-Karten sogar im Betrieb gewechselt werden können. Das darf aber in keinem Fall am Hades oder Milan gemacht werden, da dies zur Zerstörung des Mainboards oder der Karte führen kann (für dieses Feature sind spezielle Voraussetzungen erforderlich).
In der nächsten Folge möchten wir dann die einzelnen Configuration-Register der PCI-Karten näher erläutern...
Quellenverzeichnis:
[1] PCI Local Bus Specification Revision 2.0
[2] Elrad 3/97 und 4/97 (Bus Basics Technische Grundlagen des PCI-Bus)
[3] PCI Special Interest Group P.O. Box 14070 OR 97214, Portland, USA http://www.pcisig.com
[4] AMCC - http://www.amcc.com
[5] PLX Technology - http://www.plx-tech.com
[6] Xilinx - http://www.xilinx.com
[7] Lattice Semiconductor http://www.latticesemi.com
Markus Fichtenbauer, Torsten Lang, Michael Schwingen