ETI-Großprojekt 5

Werbung
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
Herunterladen