ETI-Großprojekt 5 Realisierung einer Spielekonsole mit Hilfe eines Mikrocontrollers und eines Field-programmable gate arrays Alexander Kogan, Alexander Friedl, Michael Stather, Sebastian Klotz, Marin Zec Tobias Lieber, Alexander Sahm, Martin Schuster, Christian Schmaler, Matthias Wieczorek 16. November 2006 1 Inhaltsverzeichnis ETI-Großsprojekt 5: Entwicklung einer Spielekonsole Inhaltsverzeichnis 1 Motivation 1.1 Projektrahmen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Projektziel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 3 3 2 Projektorganisation 2.1 Einteilung der Projektteams . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Projektkoordination und -kommunikation . . . . . . . . . . . . . . . . . . 3 3 4 3 Geplantes Spielkonzept 3.1 Spielidee . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 4 4 Architekturkonzept 4.1 Überblick Architektur . . . . . . . . 4.2 AVR . . . . . . . . . . . . . . . . . . 4.3 Protokoll . . . . . . . . . . . . . . . 4.3.1 Datenmodus (Initialisierung) 4.3.2 Framemodus (im Spiel) . . . 4.4 FPGA . . . . . . . . . . . . . . . . . . . . . . . 5 5 6 7 8 8 9 . . . . . . . . . . . . . . . 11 11 12 12 12 12 13 13 14 14 15 15 16 17 17 18 5 Umsetzung in Hardware 5.1 AVR . . . . . . . . . . . . . . . . . . 5.2 FPGA . . . . . . . . . . . . . . . . . 5.3 SPI . . . . . . . . . . . . . . . . . . . 5.3.1 SPI-Reader . . . . . . . . . . 5.3.2 SPI-Manager . . . . . . . . . 5.4 VGA . . . . . . . . . . . . . . . . . . 5.4.1 Technischer Hintergrund . . . 5.4.2 Umsetzung . . . . . . . . . . 5.4.3 Das Farbverlaufproblem . . . 5.5 Speichercontroller . . . . . . . . . . . 5.5.1 Objectbuffer . . . . . . . . . 5.5.2 Sprite-Index-Adress-Mapping 5.5.3 Sprite-Speicher . . . . . . . . 5.5.4 Manager . . . . . . . . . . . . 5.5.5 Rowbuffer . . . . . . . . . . . 6 Fazit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 2 1 Motivation ETI-Großsprojekt 5: Entwicklung einer Spielekonsole 1 Motivation 1.1 Projektrahmen Im Rahmen des ETI-Großpraktikums im Sommersemester 2006 am Lehrstuhl für Rechnertechnik und Rechnerorganisation / Parallelrechnerarchitektur an der Technischen Universität München haben wir selbstständig ein Konzept für ein Videospiel erarbeitet und anschließend unter Verwendung eines Mikrocontrollers und eines FPGA mit VGA-Ausgabe umgesetzt. 1.2 Projektziel Der Lehrstuhl für Rechnertechnik und Rechnerorganisation / Parallelrechnerarchitektur an der Technischen Universität München bietet Studierenden der Informatik, welche die Veranstaltung Einführung in die Technische Informatik besucht haben, die Möglichkeit, in Gruppenarbeit ein Projekt mit den Schwerpunkten maschinennaher Programmierung und VHDL durchzuführen. Die Projektteilnehmer bekommen hierfür vom Lehrstuhl einen Betreuer zur Seite gestellt. Jede Projektgruppe hat die Möglichkeit, ein vorgegebenes Projekt durchzuführen oder aber einen eigenen Projektvorschlag einzubringen. Für das Großprojekt der Gruppe 5 wurde die Realisierung einer kleinen Videospielkonsole unter Verwendung günstig konfigurierbarer bzw. programmierbarer elektronischer Bauteile vorgeschlagen. Im Einzelnen handelt es sich dabei um einen Mikrocontroller des Typs ATMega32 aus der AVR-Familie des Herstellers Atmel und ein FPGA der Baureihe XC3S200 der Firma Xilinx. Ansonsten sollen nur Standardbauteile verwendet werden. 2 Projektorganisation 2.1 Einteilung der Projektteams In einer gemeinsamen Besprechung mit dem Projektbetreuer wurde der Projektvorschlag akzeptiert. Die Aufgabenstellung legte die Bildung von zwei Teams nahe, von denen sich ein Team schwerpunktmäßig mit dem Mikrocontroller, dessen Peripherie und dem Videospiel befasst. Die zweite Gruppe konzentriert sich auf die Programmierung des FPGAs in VHDL. Die Teams setzen sich wie folgt zusammen: • AVR-Team: Alexander Kogan, Alexander Friedl, Michael Stather, Sebastian Klotz, Marin Zec • FPGA-Team: Tobias Lieber, Alexander Sahm, Martin Schuster, Christian Schmaler, Matthias Wieczorek 3 3 Geplantes Spielkonzept ETI-Großsprojekt 5: Entwicklung einer Spielekonsole 2.2 Projektkoordination und -kommunikation Die Projektkommunikation und -koordination erfolgte über eine Mailingliste und ein Forum. Außerdem wurden regelmäßige Teambesprechungen durchgeführt. Zur Versionskontrolle für entwickelte Dokumente und Quelltexte wurde ein SubversionServer aufgesetzt. 3 Geplantes Spielkonzept 3.1 Spielidee Um die Anforderungen besser abschätzen zu können, wurde zunächst eine konkrete Spielidee skizziert. Das AVR-Team hat sich in Rücksprache mit dem FPGA-Team auf folgende Eckdaten geeinigt: Technische Aspekte: • Grafik: Die Grafikdarstellung beschränkt sich auf 2D-Grafiken in Form von Sprites. Sprites sind in diesem Zusammenhang als Datenstruktur zu sehen, die Informationen über die Größe eines Grafikobjekts und die Farbe der einzelnen Pixel vereint. Die Ausgabe soll über einen VGA-Port erfolgen. • Steuerung: Hierfür sind handelsübliche Gamepads/Joysticks vorgesehen, welche die serielle Schnittstelle nutzen und mindestens zwei Feuerknöpfe sowie eine Möglichkeit für die Richtungsänderung unterstützen. Es sollen bis zu zwei Spieler unterstützt werden. • Externer Speicher: Da der Mikrocontroller nur beschränkte Speicherkapazität bietet, wird ein MMC-Reader als Peripherie angeschlossen, damit statische Daten wie etwa Grafiken auf externe Speichermedien ausgelagert werden können. Aspekte des Spieldesigns: • Spieleranzahl: 2 • Szenario: Zwei Spieler steuern in einer Weltraum-Adaption der Atari-Klassiker Breakout und Pong jeweils einen Schläger mit dem sie umherfliegende Bälle reflektieren können und Weltraumschrott zerstören müssen. Wenn ein Spieler Weltraumschrott zerstört oder aber der Gegenspieler einen Ball nicht reflektiert, werden Punkte zugeschrieben. 4 4 Architekturkonzept ETI-Großsprojekt 5: Entwicklung einer Spielekonsole 4 Architekturkonzept 4.1 Überblick Architektur 5 4 Architekturkonzept ETI-Großsprojekt 5: Entwicklung einer Spielekonsole 4.2 AVR Anschlussgrafik: • Der AVR ist wie im Datenblatt beschrieben an GND und VCC angeschlossen. • Der Anbindung an den FPGA erfolgt über eine serielle Schnittstelle und ist durch 4 Leitungen verwirklicht: – MoSi: Über diese Leitung werden alle Daten, also sowohl die Sprites als auch die Frames übertragen. – Clk: Der AVR gibt die Taktrate für die Übertragung vor, die über diese Leitung zum FPGA übertragen wird. – DM: Diese Leitung gibt an, ob sich der AVR im Datenmodus (Übertragung von Sprites) oder im Framemodus (Übertragung der Frames oder der Hintergrundfarbe, ebenfalls Löschen des Spritespeichers) befindet. – Eine vierte Leitung wird zur Kennzeichnung der Bytegrenzen verwendet. Diese Leitung ändert ihren Zustand vor der Übetragung eines neuen Bytes. • Als externen Speicher und zur einfachen Übertragung der Sprites wurde eine MMCKarte an den AVR angeschlossen. Die Kommunikation erfolgt über eine serielle Schnittstelle, die mit 3 Pins auskommt: 6 4 Architekturkonzept ETI-Großsprojekt 5: Entwicklung einer Spielekonsole – MoSi: Über diese Leitung sendet der AVR die Initialisierungssequenz und die Befehle an die Speicherkarte. – MiSo: Über diese Leitung empfängt der AVR die von der MMC-Karte angeforderten Daten. – Clk: Mit dieser Leitung gibt der AVR die Taktrate für die Übertragung vor. • Da die MMC-Karte mit einer Spannung von nur 2,7 V arbeitet, der AVR hingegen mit 5 V, werden 3 Spannungsteiler verwendet. Durch Widerstände werden die Spannungen von MoSi und Clk auf den benötigten Pegel abgesenkt. Die Spannungsversorgung(VCC) der MMC-Karte wird über 2 Dioden, an denen jeweils etwa 0,7 V abfällt, geregelt. Der Pegel von MiSo muss nicht angehoben werden, da diese Spannung für den AVR als High-Pegel ausreichend ist. • Der Anschluss der Controller erwies sich als problematisch, da der einzig auffindbare Schaltplan fehlerhaft war. Nach Ergänzung mit einigen Kondensatoren und Pull-Up-Widerständen konnten die Controller jedoch ohne Probleme verwendet werden. • Um den AVR zu programmieren, ist dieser nach folgendem Schema an die parallelen Schnittstelle eines Computers angeschlossen: – AVR ———— Pin – Parallel Port – Sck ———— 1 – Strobe – MoSi ———— 2 – Data 0 – MiSo ———— 11 – Busy – Reset ———— 16 – Init • Zu Debugzwecken ist der AVR über die UART-Schnittstelle mit der seriellen Schnittstelle des Computers verbunden. Diese verwendet lediglich 2 Leitungen: TXD und RXD. Um die Pegel von 0/5V auf 12/-12V anzupassen wird ein MAX232 verwendet. 4.3 Protokoll Das hier beschriebene Protokoll regelt die Datenübertragung zwischen den zwei Chips. Es gibt zwei verschiedene Übertragungsmodi, die über eine extra Leitung vom AVR ausgewählt werden: 7 4 Architekturkonzept ETI-Großsprojekt 5: Entwicklung einer Spielekonsole 4.3.1 Datenmodus (Initialisierung) Der Datenmodus wird beim Spielstart sowie beim Laden eines neuen Levels dazu benutzt, neue Spritedaten in den Speicher des FPGAs zu schreiben. Dazu werden von jedem Sprite Breite, Höhe, Typ, die interne Color-Lookup-Table sowie die eigentlichen Spritedaten folgendermaßen übertragen: color 1 bis color n bezeichnet die spriteinterne Color-Lookup-Table (CLT), die bei Sprites des Typs 0 aus 4, bei Typ 1 aus 16 Einträgen besteht. Jeder Eintrag stellt eine Farbe in der FPGA-Color-Lookup-Table dar, die mit 8 Bit angesprochen wird und dies auf die 9 Bit der VGA-Ausgabe umsetzt. 255 (0xFF) ist dabei für Transparenz belegt. Bei Typ 0 setzen sich die Spritedaten (data) aus 2 Bit pro Pixel, bei Typ 1 aus 4 Bit pro Pixel zusammen, wobei die Pixeldaten jeweils eine Farbe aus der spriteinternen CLT kodieren. Der FPGA vergibt intern, mit 1 beginnend, Indizes an die Sprites, über die diese dann im Framemodus angesprochen werden können. 4.3.2 Framemodus (im Spiel) Im Framemodus werden während des laufenden Spiels die Objekte übertragen, die im nächsten Frame zu zeichnen sind. Ein Objekt ist entweder ein zu zeichnendes Sprite (dessen Index sowie Position) oder ein Rechteck (Position der Punkte links oben (x1, y1) und rechts unten (x2, y2), Farbe). Bei den Koordinaten ergeben jeweils die niederwertigsten 3 Bit des high-Bytes sowie die 8 Bit des low-Bytes die 11-Bit-Koordinate. Außerdem gibt es noch einige Spezialbefehle: 8 4 Architekturkonzept ETI-Großsprojekt 5: Entwicklung einer Spielekonsole • Hintergrundfarbe setzen: x high: 31 (1F), x low: Farbe, Rest: don’t care • Framewechsel: y high: 255 (FF), Rest: don’t care • Löschen des Spritespeichers: x high: 255 (FF), Rest: don’t care 4.4 FPGA Die Architektur des FPGA besteht aus 3 Komponenten: die SPI-Komponente, eine Komponente zur Speicherverwaltung, die auch den Großteil der Logik beinhaltet und die VGA-Ausgabe. In dieser Reihenfolge verläuft auch der Datenfluss durch den FPGA. 9 4 Architekturkonzept ETI-Großsprojekt 5: Entwicklung einer Spielekonsole Die VGA-Komponente beeinhalten im Gegensatz zu den anderen beiden Komponenten keine weiteren Module. Die SPI-Komponente beinhaltet ein Modul zum Zusammenfassen der Bits zu Bytes, die dann an ein Modul zur Verteilung der Daten an andere Module weitergegeben werden. Der Speichercontroller ist das Herzstück der Grafikkarte und enthält die meisten Module. 10 5 Umsetzung in Hardware ETI-Großsprojekt 5: Entwicklung einer Spielekonsole 5 Umsetzung in Hardware 5.1 AVR 11 5 Umsetzung in Hardware ETI-Großsprojekt 5: Entwicklung einer Spielekonsole Der AVR muss folgende Hardware ansprechen: • Die Controller: Die verschiedenen Richtungs- und die Feuertaste des Controllers werden jeweils durch eine Leitung am AVR repräsentiert. Daher muss zum Abfragen der einzelnen Tasten jeweis nur geprüft werden, ob der Pegel des entsprechenden Pins am AVR high oder low ist. • Die MMC-Karte: Die MMC-Karte wird durch eine softwareseitig implementierte (da die hardwareseitige Schnittstelle durch den FPGA belegt ist) SPI-Schnittstelle angesprochen. Für die Kommunikation wird die Bibliothek von Ulrich Radig (www.ulrichradig.de) verwendet, mit der jeweils 512 Byte-Blöcke Daten einer Datei in den Speicher auf den AVR geladen werden. Dort können die Daten dann weiterverarbeitet werden. • Den FPGA: Die Kommunikation mit dem FPGA ist über die auf dem AVR hardwareseitig implementierte SPI-Schnittstelle realisiert. Dabei werden, wie im SPI-Protokoll festgelegt, die Spritedaten oder die Daten für das jeweils nächste zu zeichnende Bild übertragen. 5.2 FPGA 5.3 SPI Alle zur Kommunikation zwischen AVR und FPGA benötigten Daten werden über die im AVR hardwareseitig integrierte SPI-Schnittstelle ausgetauscht, wobei der AVR den Master und der FPGA den Slave darstellt. Es handelt sich in diesem Fall jedoch um eine unidirektional Verbindung, da im Protokoll für den Datentransfer zwischen AVR und FPGA keine Rückleitung vorgesehen wurde. Der MiSo-Anschluss (Master-in-Slave-out) am AVR bleibt also ungenutzt. Die SPI-Komponente des FPGA besteht aus einem Einlesemodul, das hier im weiteren Verlauf SPI-Reader genannt wird, und dem SPI-Manager. 5.3.1 SPI-Reader Der Reader liest bitweise vom MoSi-Eingang (Master-out-Slave-in) und gibt die Daten byteweise an den SPI-Manager weiter. Als Master gibt der AVR den Takt für die Übertragung vor. Dieser liegt beim FPGA am Sck-Eingang an. Sobald ein ganzes Byte eingelesen wurde liegt dieses am Ausgangs-Port des Reader-Moduls an und new-byte wird auf high gesetzt. In der Praxis hat sich dieser Ansatz alleine allerdings als nicht besonders sicher erwiesen. Werden durch Übertragungsfehler Bits verschluckt oder zusätzliche Bits erkannt, 12 5 Umsetzung in Hardware ETI-Großsprojekt 5: Entwicklung einer Spielekonsole so verschieben sich alle nachfolgenden Bits und werden falsch wieder zu Bytes zusammengefasst. Ein einmaliger Fehler hat also zur Folge, dass die gesamte nachfolgende Übertragung fehlerhaft ist. Es wird daher eine zusätzliche Leitung zwischen AVR und FPGA benutzt, um die Grenzen der übertragenen Bytes zu kennzeichnen. Diese Leitung wird vor der Übertragung eines neuen Bytes vom AVR auf high gesetzt. 5.3.2 SPI-Manager Der SPI-Manager erhält die übertragenen Daten byteweise vom SPI-Reader. Er zerlegt diesen Datenstrom nach dem, unter “Protokoll” beschriebenen, Übertragungsprotokoll und verteilt die dabei entstehenden Datenblöcke auf die anderen Module des FPGAs. Im Daten-Modus sind dies hauptsächlich SIAM und Sprite-Speicher, im Frame-Modus der Objectbuffer. Im wesentlichen besteht der SPI-Manager aus zwei State-Machines, eine für den Datenund eine für den Frame-Modus, welche die jeweiligen Teile des Protokolls implementieren. 5.4 VGA 5.4.1 Technischer Hintergrund Zur Ansteuerung des Monitors werden neben den 3 Farbleitungen für Rot, Grün und Blau 2 Steuersignale benötigt, welche den Elektronenstrahl auf dem Schirm steuern. Zum einen benötigt man den H-SYNC. Durch ihn wird beschrieben, wann eine Zeile fertig gezeichnet wurde und in die nächste zu springen ist. Zum anderen gibt es den V-SYNC, welcher angibt wann alle Zeilen des Bildes gezeichnet wurden und somit ein neuer Frame zu beginnen hat. Der Strahl des Bildschirms wird dann wieder nach oben-links gesetzt und beginnt das neu Bild wiederum Zeile für Zeile zu zeichnen. Dabei müssen genaue Zeitvorgaben beachtet werden, damit der Bildschirm das Bild richtig zeichnen kann. In folgenden Grafiken werden diese beschrieben. Das “H-Sync“ Signal: R ed, Green, Blue P i xe l Da ta 1.8 9 µs 2 5. 1 7 µ s Horizontal Sync 3.77µs 3 1 . 7 7 µs Horizontal Sync Signal 13Timing. 0.94 µs 5 Umsetzung in Hardware ETI-Großsprojekt 5: Entwicklung einer Spielekonsole Das “V-Sync“ Signal: 480 Horizontal Refresh Cycles Red, Green, Blue Pixel Data 1.0 2 m s 15.24 ms 0. 35 m s Vertical Sync 6 4 µs 1 6 .6 m s Bei einem mit 25 Mhz oder einem vielfachen getaktetem VHDL-Prozess können die entsprechenden Stellen in den Sync-Signalen durch einfaches Abzählen der Taktzyklen erkannt werden. Signal Timing. im nicht sichtbarem Bereich befinWährend der Zeit in der Vertical sich der Sync Strahl des Monitors det, müssen die Farbkanäle auf 0 gesetzt werden, da der Bildschirm sich in dieser Phase auf das gesendete Schwarz kalibriert. 5.4.2 Umsetzung Ein in zwei Teile unterteilter Prozess sorgt mit internen Signalen für die Abzählung der einzelnen Takte und somit für die Generierung der beiden Steuersignale H- und V-Sync. Wenn der Wert des H-Sync Zählers einen der oben genannten Grenzwerte erreicht, wird der Ausgang H-Sync entsprechend der Spezifikation auf High bzw. Low gesetzt. Selbiges gilt für die Erzeugung des V-Sync Signals. Zusätzlich wird die Position des momentan zu zeichnenden Pixels an den Rowbuffer und vielen anderen Einheiten des FPGAs weitergegeben. Bei Erreichen des Endes einer Zeile, bzw. bei Ende des Frames, wird ein entsprechendes Signal an die anderen Module des FPGA gesendet, damit diese auf den bevorstehenden Wechsel reagieren können. So wird beispielsweise bei jeder neuen Zeile im sichtbaren Bereich zwischen den beiden Rowbuffern gewechselt. 5.4.3 Das Farbverlaufproblem Das Farbverlaufproblem beschreibt ein Problem, welches wir während der Entwicklung der grundlegenden Architektur lange hatten. Bei großen farbigen Flächen ist stets ein Farbverlauf vom beispielsweise Hell- ins Dunkelgrüne aufgetreten. Vor allem bei farbigen Hintergründen hat sich dieses Phänomen sehr stark bemerkbar gemacht, da sich dadurch nach einem gezeichnetem Sprite stets ein Schweif bildete. 14 5 Umsetzung in Hardware ETI-Großsprojekt 5: Entwicklung einer Spielekonsole Wir gehen davon aus, dass durch die Levelshifter, die an den meisten Ausgängen des Evalboards vorhanden sind, das Ausgangssignal bei einem Farbwechsel zu Beginn kurzzeitig auf ein relativ hohes Niveau gehoben wird, um dann nach kurzer Zeit langsam auf ein niedrigeres Level abzusinken. Um das Problem zu umgehen, haben wir einen kleinen Trick angewandt. Indem vor jedem zu zeichnendem Pixel die Farbwerte an den Ausgängen für einen Takt lang auf 0 und erst danach auf den gewünschten Farbwert gesetzt werden, ist die Zeitspanne in der ein Wert anliegt stets so gering, dass der angesprochene Effekt nicht auftritt. 5.5 Speichercontroller 5.5.1 Objectbuffer An den Objekbuffer ist ein Block-RAM über 2 Lese/Schreib-Kanäle angebunden auf dem pro Speicheradresse 16 Bit angesprochen werden. Somit kann gleichzeitig ein Objekt in den Block-RAM geschrieben werden und eines gelesen werden. Zuerst zum Schreiben von Objekten in den RAM: Erhält der Objektbuffern eine steigende Flanke auf dem Signal write next object“ (vom ” SPI-Manager), werden die Werte die an den Signalen fuer X/Y-Position und Index anliegen in folgender Reihenfolge in den Block-RAM geschrieben: Somit werden pro geschriebenem Objekt 2 Speicherplätze belegt. Ist der Schreibvorgang beendet wird die Speicheradresse, an die das nächste Objekt geschrieben werden soll um 2 erhöht, damit das nächste Objekt an die korrekte Position geschrieben werden kann. Das Auslesen von Objekten: Wenn der Objektbuffer eine steigende Flanke auf dem Signal next elem“ empfängt, liest ” er das nächste Objekt aus. Die Daten, Index und X/Y-Position werden an den Manager zurückgegeben. Außerdem wird der Index noch an den SIAM weitergeleitet. Nachdem die Daten auf den Leitungen anliegen, wird das Signal new data“ für einen Takt lang ” auf high gesetzt. Nachdem Auslesen wird ein Zähler für die Position des nächsten Objekts erhöht. Ist kein Objekt mehr im Speicher, so gibt der Objektbuffer kein high auf new data“ aus und der Manager wartet vergebens auf ein eintreffen der neuen Daten. ” 15 5 Umsetzung in Hardware ETI-Großsprojekt 5: Entwicklung einer Spielekonsole Das bisher beschriebene Vorgehen des Objektbuffers erlaubt nur die Ausgabe einer Zeile. Deshalb wird beim new line“-Signal des VGA-Moduls der Zähler für die nächste Lese” position wieder zurückgesetzt. So kann aber immer nur der gleiche Frame ausgegeben werden. Deshalb besteht der Objektbuffer eigentlich auch aus 3 Objektbuffern. Sie werden durch verschiedene Speicheroffsets im Block-RAM von einander getrennt. Sobald nun ein new frame“-Signal ” vom VGA-Modul eintrifft wird der Offset für das Lesen auf dem Speicherabschnitt gesetzt, der im Moment nicht beschrieben wird und zugleich nicht der zuletzt gelesene ist. Genauso gibt es ein ähnliches Signal für das setzen eines Speicheroffsets für das Schreiben von Objekten. Dieses Signal kommt vom SPI-Manager. Wenn es eintrifft wird der Schreiboffset auf den Objekbuffer gesetzt, von dem nicht gerade gelesen wird und auf den nicht gerade geschrieben wurde. 5.5.2 Sprite-Index-Adress-Mapping Das Sprite-Index-Adress-Mapping (SIAM) hat die Aufgabe, die Indizes, die der AVR für die Adressierung der Sprites benutzt, in Speicheradressen für das Sprite-Modul zu übersetzen. Dazu speichert das SIAM noch die Größe der Sprites, also Höhe und Breite. An das SIAM ist wie an den Objektbuffer auch ein 16 Bit Block-RAM über 2 Lese/Schreibkanäle angebunden. Der Schreibmodus: Der Schreibmodus ist hier ähnlich implementiert wie im Objektbuffer: Auf eine steigende Flanke auf dem Signal write next sprite“, welches vom SPI-Manager kommt, werden ” die Werte für Spritetyp, Speicheradresse, Breite und Höhe in der folgenden Reihenfolge in das Block-RAM geschrieben. Auch hier wird ein interner Zähler geführt in dem immer die Position steht, an die der nächste Eintrag in diese Tabelle geschrieben werden muss. Das SIAM verfügt über ein weiteres Signal vom SPI-Manager. Hiermit kann das Adressmapping gelöscht werden indem der Zähler für die nächste Schreibposition auf 0 zurückgesetzt wird. Die Lesemodi: Es existieren zwei verschiedene Lesemodi. Der Erste ist immer aktiv wenn nicht gera- 16 5 Umsetzung in Hardware ETI-Großsprojekt 5: Entwicklung einer Spielekonsole de geschrieben wird und liest zu einem Index, den das SIAM vom Objektbuffer erhält, immer die dazugehörige Höhe und Breite und gibt diese Werte an den Manager weiter. Der andere Lesemodus ist wesentlich komplexer. Er erhält vom Manager folgende Werte: Ein einfaches Signal, auf dessen steigende Flanke dieser Lesemodus startet, die Reihe des Sprites, die gezeichnet werden soll, und die Nummer des ersten und des letzten Pixels welches in einer Reihe gezeichnet werden soll. Daraus werden in vier Schritten Werte für das Sprite-Modul errechnet. Zuerst wird die Anzahl der Pixel berechnet die vom Sprite-Modul ausgegeben werden müssen. Spritetyp und die Speicherposition des Sprites werden aus dem Block-RAM ausgelesen. Jetzt wird die Position des ersten Pixels ausgerechnet, welches ausgegeben werden muss. Dieser Wert wird dann in eine Speicheradresse und einen Offset in der Speicheradresse unterteilt. All diese Werte werden an das Sprite-Modul geschickt, mit einer steigenden Flanke für das Sprite Modul. 5.5.3 Sprite-Speicher An das Sprite-Modul sind 9 16 Bit Block-RAMs über 2 Lese-/Schreibkanäle angebunden. Auch hier gibt es wieder einen Schreib- und einen Lesemodus. Der Schreibmodus ist nur dann aktiv, wenn auch der Datenmodus vom SPI aktiv ist. In dieser Zeit werden alle Daten die vom SPI-Manager ankommen einfach nacheinander in den Block-RAM geschrieben. Dabei wird bei jedem Schreibvorgang ein interner Speicherstellenzähler hochgezählt. Dieser kann nur von dem flush ram“-Signal wieder zurückgesetzt werden. ” Im Lesemodus wird prinzipiell zwischen den beiden Spritetypen unterschieden. Das Vorgehen ist aber bis auf unterschiedliche Variablengrößen fast gleich. Zuerst wird die ColorLookup-Tabelle (CLT) für das Sprite eingelesen, die je nach Spritetyp 4 oder 16 Einträge besitzt. Jetzt werden die tatsächlichen Pixeldaten ausgelesen und über die CLT an den Manager ausgegeben. Dazu wird an den Manager noch ein Signal geschickt, damit dieser weis, dass Pixeldaten ankommen. 5.5.4 Manager Das Manager-Modul fügt den Objektbuffer, das SIAM, das Sprite-Modul und den Rowbuffer zusammen und koordiniert, welches Modul was zu tun hat. Der Manager beginnt damit ein Objekt aus dem Objektbuffer anzufordern. Sind Index, X-/Y-Position vom Objektbuffer und Breite und Höhe vom SIAM eingetroffen wird überprüft, ob das Objekt in der aktuellen Zeile gezeichnet werden muss. Wenn dies nicht so ist wird das nächste Objekt vom Objektbuffer angefordert. Wenn das Objekt gezeichnet werden muss, wird ausgerechnet, welche Zeile des Sprites gezeichnet werden muss und welches das erste und das letzte Pixel in der zu zeichnenden Zeile ist. Diese Daten werden an das SIAM gegeben. Jetzt wird auf ein Signal vom Sprite-Modul gewartet, dass Pixeldaten anliegen. Diese 17 5 Umsetzung in Hardware ETI-Großsprojekt 5: Entwicklung einer Spielekonsole Pixeldaten werden zusammen mit der Pixelnummer und einem Signal, dass Pixel zu zeichnen sind, an den Rowbuffer gegeben. Dabei wird so lange Pixeldaten vom SpriteModul kommen jeden Takt die Pixelnummer erhöht. Sobald keine Pixeldaten mehr vom Sprite-Modul kommen wird das nächste Objekt angefordert. Bei den Objekten ist noch ein Spezialfall zu betrachten. Soll eine Rechteckige Fläche gezeichnet werden, so werden keine Daten für das SIAM ausgerechnet, sondern der Manager geht in einen besonderen Zustand, in dem er zunächst das nächste Objekt vom Objektbuffer holt und dann Pixel in der angegebenen Farbe in dem angegebenen Bereich erzeugt. Sind alle Objekte im Objektbuffer gezeichnet, wartet der Manager vergeblich auf ein neues Objekt und hängt sich damit quasi auf. Soll also eine neue Zeile gezeichnet werden muss vom Objektbuffer, dessen Zähler dann auch zurückgesetzt wird, ein neues Objekt angefordert werden. Veranlasst wird dies durch eine steigende Flanke auf dem new line“-Signal von dem VGA-Modul. Das gleiche passiert bei einer steigenden Flan” ke auf dem new frame“-Signal. Nur wird hier im Objektbuffer nicht nur der Zähler ” zurückgesetzt, sondern es werden die Buffer geswapt. Dadurch wird der nächste Frame gezeichnet. Die Nummer der aktuellen Zeile wird hierbei vom VGA-Modul bezogen. 5.5.5 Rowbuffer Der Rowbuffer speichert die Pixel, welche in der aktuellen Bildschirmzeile angezeigt werden. Von ihm aus werden die Pixel direkt an die VGA-Ausgabe weitergereicht. Der Rowbuffer besteht eigentlich aus zwei Puffern, zwischen denen bei jeder neuen Zeile gewechselt wird. Einer der beiden enthält die Pixel, die gerade gezeichnet werden, dient also als Lesepuffer. Der andere hingegen, dient als Schreibpuffer und wird mit den Pixeldaten für die nächste Zeile beschrieben. Die angesprochenen Pixeldaten, werden als 8-Bit Wert gespeichert und repräsentieren den entsprechenden Farbwert in der Color-Lookup-Table(CLT). Die Adressierung im verwendeten 8-Bit Block-RAM erfolgt hierbei durch einen Anfangspointer und einen Offset. Der Offset beschreibt die Position des Pixels, somit hat er einen Wertebereich von 0 bis 639. Der Pointer zeigt auf die erste Adresse im Block-RAM, an der sich die Daten für den jeweiligen Puffer befinden. Somit reicht bei eintretendem Zeilenwechsel ein umbiegen der Pointer aus, um den Wechsel zwischen den Puffern zu realisieren. Das Beschreiben des aktuellen Schreibpuffers läuft immer ab, wenn das “write next pixel“ Flag vom Manager auf 1 gesetzt ist. Die ebenfalls vom Manager kommende Position des Pixels in der Zeile wird zu der Adresse verrechnet an welche die Farbinformation im RAM gespeichert wird. Nur beim Farbwert “0xFF“ wird eine Ausnahme gemacht und das “write enable“ des Block-RAMs auf 0 gesetzt, um den vorherigen Farbwert an der entsprechenden Stelle zu bewahren. Somit erscheint die Farbe “0xFF“ transparent. Beim Lesen der Daten aus dem Lesepuffer müssen die Pixeldaten synchron zu der Aus- 18 6 Ergebnis ETI-Großsprojekt 5: Entwicklung einer Spielekonsole gabe des VGA Moduls ausgelesen und weitergegeben werden. Wegen der Verzögerungen durch den Speicher, muss stets der Farbwert für den nächsten am Bildschirm zu zeichnenden Pixel ausgelesen werden. Vor allem am Beginn der Zeile ist dies zu beachten und führt zu einer entsprechenden Fallunterscheidung. Damit der Lesepuffer in der nächsten Zeile als Schreibpuffer verwendet werden kann, müssen alle Datenwerte wieder auf die Hintergrundfarbe zurückgesetzt werden. Hierzu wird die Schreibfunktion des Block-RAMs genutzt. Mit der Option “Read First“ bietet sie die Möglichkeit neue Daten an eine bestimmte Adresse zu schreiben und gleichzeitig den vorher gespeicherten Wert auszulesen. 6 Ergebnis Die vorliegende Projektdokumentation zeigt eine Möglichkeit auf, wie unter Verwendung kostengünstiger elektronischer Bauteile sowohl Mikrocontrollersoftware visualisiert werden kann als auch Mikrocontroller von der hohen Flexibilität eines FPGA profitieren können. 19