Hallo,
ich würde gerne mein Projekt vorstellen:
Einen Gameboy Color "Emulator" in VHDL.
Die allermeisten Spiele(Gameboy und Gameboy Color) die ich getestet habe
funktionieren damit. Bei manchen gibt es kleinere Grafik oder
Soundfehler. Einige größere(4Mbyte Romgröße) Gameboy Color Spiele laufen
noch nicht. Das sind jedoch hauptsächlich rein japanische, weshalb meine
Motivation begrenzt ist.
Vielleicht interessiert ja den ein oder anderen wie man sowas machen
kann.
Es dürfte zwar etwas schwierig sein den mal auszuprobieren, weil es kein
komplettes Projekt mit VGA/Input/Soundausgabe ist, aber vielleicht hat
ja jemand trotzdem auch mal Lust sich was zu basteln.
Ein paar Eckdaten (Origina / Kopie)
CPU: ~8500 Transistoren / 5000 Cyclone 4 LEs (nur CPU, Gesamtsystem:
~10000)
CPU: 8,38 Mhz / 100 Mhz
Ram: 48 Kbyte / 62Kbyte im FPGA + 8 MByte außerhalb(hauptsächlich Rom +
Saveram)
Farben: 32768 / 32768
Audio: 4 Bit Stereo / 16 Bit Mono
Auflösung: 160x144 / "Pixelperfect" scaling
Eigentlich kann man viel darüber erzählen, allerdings weiß ich nicht wo
ich anfangen sollte.
Bei Interesse einfach fragen.
FPGA zum Spass schrieb im Beitrag #5917258:
> Eigentlich kann man viel darüber erzählen, allerdings weiß ich nicht wo> ich anfangen sollte.
Dann fang mal an auf welcher Platform (Board) das Ganze realisiert wurde
und warum?
War das jetzt eher ein Programmier-technisches Projekt (zB. in VHDL
Variablen und so erstellen) oder hast du auch etwas mit Hardware (zB.
auf Gatter-Ebene) zu tun gehabt ?
Danke fürs Lob und Interesse!
Ehefrau des „Ragionier Fantozzi“ schrieb:> Dann fang mal an auf welcher Platform (Board) das Ganze realisiert wurde> und warum?
Auf dem Terasic DE2-115, mit Cyclone 4.
Ist eigentlich zu groß dafür, aber das Board nutze ich halt sonst auch.
Gründe für das Board:
- vollwertiger VGA Port mit 24Bit bei 1280*1024
- Soundausgang (16 Bit DAC + Klinke)
- Speicher: Großer SDRam(128MByte) und halbwegs großer SRam(2MByte) und
Flash und SD-Slot
Geht sicher auch auf kleineren/günstigeren Boards. Sinnvoll ist
Audio/Videoausgabe, mindestens 8 Mbyte Speicher und
Massenspeichermöglichkeit(z.b. SD-Karte).
Als Controller verwende ich einen Original N64, den bekommt man mit 3
Pins ganz leicht verbunden auf 3.3V.
Vincent H. schrieb:> War das ganze ein "ich möcht FPGA basteln/lernen" oder ein> "ich möcht Emulator basteln/lernen" Projekt?FPGA Entwicklung mache ich seit einiger Zeit, sonst hätte ich mir das
auch eher weniger zugetraut.
War eher ein Projekt mal einen Emulator zu machen.
Als Vorprojekt habe ich den Emulator in C# geschrieben, weil es zum
debuggen doch enorm viel leichter ist.
Bei Interessse kann ich den auch hochladen, wobei der eher hingebastelt
ist, weil nur Mittel zum Zweck.
Bla schrieb:> Programmier-technisches Projekt ... oder ... auch etwas mit Hardware
Größtenteils war es doch recht highlevelig, was sicher auch an meiner C#
Vorlage liegt.
Z.b. mehr Statemachines mit sequentiellen Schritten als parallele
Abarbeitung.
Ganz kommt man bei so einem Projekt aber nicht von der Gatterebene weg.
Z.b. beim Versuch den Z80 auf 100 Mhz zu takten oder die Spriteengine
schnell genug ablaufen zu lassen.
----
Was mich bei dem Projekt immer wieder verwundert und aufgeregt hat: wie
sehr sich Entwickler doch auf ihre Zielhardware verlassen.
Leicht anderes Zeitverhalten im Promillebereich, z.b. ein VSync der nur
ein bischen zu früh oder zu spät(!) kommt, kann dazu führen das sich das
komplette Spiel aufhängt.
Sowas kennt man von PC Spielen halt garnicht und rechnet damit am Anfang
auch nicht.
Es hat aber auch enorme Vorteile:
Dadurch das die Hardware keinerlei Variation überhaupt hat, z.b. jeder
Speicherzugriff und jede Berechnung ist immer exakt gleich schnell, kann
man komplette Spielabläufe aufzeichnen mit Programcounter,
Registerzuständen, Grafik Hpos/Vpos, Timerständen, usw.
Meine Validierung ist genau so gelaufen:
z.b.: Teste ob der Gameboy nach 1Mio Prozessorzyklen exakt den gleichen
internen Zustand hat wie der Emulator auf dem PC. Wenn nicht: sukzessive
Approximation um den Takt zu finden, an dem der Unterschied auftaucht.
Ist das ein Labello unter dem Monitor ? Die sollen gesundheitlich
bedenklich sein ...
Sei froh dass dein FPGA-Board ein fertiges VGA-Modul hat. Es scheint
nicht so einfach zu sein da ein sauberes Signal an TFT-Monitore zu
bekommen.
Hast du wirklich einen Z80 emuliert ? Wie funktioniert die Sprite-Engine
- kannst du das kurz beschreiben ?
Bla schrieb:> Sei froh dass dein FPGA-Board ein fertiges VGA-Modul hat. Es scheint> nicht so einfach zu sein da ein sauberes Signal an TFT-Monitore zu> bekommen
Ja, da ist ein DAC verbaut, der die vollen 24 Bit leistet. Die
Ansteuerung mit Hsync/Vsync/usw muss man natürlich trotzdem selbst
machen, aber das ist ja kein Hexenwerk.
Auf dem DE1 was ich vorher genutzt habe ist nur ein Widerstandsnetzwerk,
das schafft aber auch immerhin 12Bit bei 1280x1024.
Wichtig für den TFT ist nur, dass die Pixelfrequenz dem Standard
entspricht. Vielleicht ist aber auch mein TFT sehr tolerant.
> Hast du wirklich einen Z80 emuliert ?
Genau genommen nein.
Der Gameboy Prozessor(Sharp LR35902) ist kein reiner Z80.
Der Prozessor ist direkt in VHDL implementiert, d.h. die OPCodes werden
direkt berechnet als wäre es echte Hardware, d.h. kein Interpreter oder
Recompiler wie bei einem PC Emulator.
Im Gegensatz zur echten Gameboy CPU jedoch ohne garantierte
Ausführungszeiten, Speicherzugriffszeiten und sicherlich mit
unterschiedlichen Mikrocodes.
(Die CPU Befehle sind recht komplex, weshalb sie in Schritte verteilt
werden).
Das wird aufgefangen durch einen ~12fach höheren Takt, im Vergleich zum
Gameboy Color.
> Wie funktioniert die Sprite-Engine
In Kürze:
- Der Gameboy hat maximal 40 aktive Sprites, wovon maximal 10 pro Zeile
gemalt werden können
- Die Priorität ist (beim GBC) einfach aufsteigend.
- Dazu kommt ein Backgroundlayer
- Dazu kommt ein Windowlayer(2ter Background)
- jedes Pixel hat eine von 4 Farben.
Gemalt wird jetzt nach Priorität:
- Sprite 0
oder Sprite 1, wenn Sprite 0 für dieses Pixel inaktiv oder die Farbe 0
hat
...
oder Sprite 9, wenn Sprite 8 für dieses Pixel inaktiv oder die Farbe 0
hat
Zusätzlich wird danach noch unterschieden ob das aktuell aktive Sprite
gemalt wird oder Window oder Background, abhängig von weiteren
Prioritätsbits und den Farben(Farbe 0 = "Transparent").
Das ganze unterscheidet sich dann auch noch zwischen GB und GBColor,
wobei ich gestehen muss, das ich diesen Unterschied ignoriert habe und
nur die GBColor Variante implementiert habe.
a) weil sie einfacher ist in Hardware abzubilden
b) wei die Doppelimplementierung unnötig viele Ressourcen binden würde
c) weil ich mir im PC Emulator angekuckt habe wie groß die Fehler sind
und sie für minimal halte: ab und zu flackert ein Pixel wenn sich 2
Sprites überlappen und das mit dem größeren Index sich nach rechts
bewegt und das mit der kleineren Index nach links.
Zudem vermeiden die meisten nicht-GBC Spiele Sprite Überdeckungen,
warscheinlich weil das Prioritätshandling dort so umständlich ist.
Du könntest das Projekt auf wenige Bauteile reduzieren: den FPGA,
R2R-D/A, Musik-Klinke, SD-Kartenadapter, Joystickanschluss. Alles auf
eine kompakte Platine druff.
Das könnte man allgemein gebrauchen wenn es nicht zu teuer ist.
FPGA zum Spass schrieb im Beitrag #5920307:
>> Wie funktioniert die Sprite-Engine>> In Kürze:
Auf dem CCC gab es mal einen schönen Talk über den Gameboy. Darunter
auch, wie die Sprite Engine funktioniert:
https://www.youtube.com/watch?v=HyzD8pNlpwI
Der Talk war einer meiner Beweggründe das Projekt überhaupt in die Hand
zu nehmen :)
Zum Board:
ja es gibt sowohl MIST als auch MISTer und wer alles fertig haben nimmt
warscheinlich eher das.
Billiger ist das aber auch kaum.
Für sehr niedriges Bugdet gibts auf ebay auch fertige Chinaboards mit
VGA/Ram und ausreichend großem FPGA für 40€.
Freie Pins für ein SDCard Pmod + I2S2 Pmod sind da auch noch übrig.
Damit kommt man auf ~70€.
Ich denke nicht das man mit eigener Platine da drunter kommen kann,
dafür sind die FPGAs in Einzelstückpreisen einfach zu teuer.
Ein kleines Update, weil ich ungern Fehler von mir stehen lasse und sich
irgendwann jemand ärgert der es tatsächlich benutzt.
So ging es nämlich mir, weil ich die Funktionsweise einem anderen
Emulators abgekupfert habe und deshalb einen Fehler drin hatte:
Der Timer hat falsch rum gezählt(runter statt hoch) und den Init Wert
ignoriert, weil dieser beim runterzählen nicht funktioniert hat.
Jetzt ist es mMn ~99% korrekt. Nicht 100% cyclegenau, aber die
Geschwindigkeit in Hz stimmt.
Das fixed die Soundausgabe z.b. in Oracle of Ages oder Donkey Kong die
vorher zu langsam war.
Der Code ist hier zu finden:
https://github.com/RobertPeip/VHDLBoy
Hallo FPGA zum Spass !
>Der Prozessor ist direkt in VHDL implementiert, d.h. die OPCodes werden>direkt berechnet als wäre es echte Hardware, d.h. kein Interpreter oder>Recompiler wie bei einem PC Emulator.
Man muss ja dann noch die ganzen anderen Komponenten hinzufügen. Ich
sehe in deinem Ordner viele VHDL Dateien. D.h. du hast die ganzen
Komponenten auch hardwaremäßig geschrieben. Woher wusstest du wie man
die Grafikeinheit oder den Speicher implementiert ? Hast du dich einfach
an den gegeben Emulatoralgorithmen orientiert ? Könnte man dann auch
eine Hardwarekomponente mit C# ähnlichem Z80 algoritmus einbinden, ohne
dass man gleich den Softprozessor selber einbinden muss, oder wäre das
zu uneffizient ?
>Als Vorprojekt habe ich den Emulator in C# geschrieben, weil es zum>debuggen doch enorm viel leichter ist.
Falls ich einen GameBoy emuliere, möchte ich auch erst meinen Code in
C++ schreiben :D
Dann das ganze langsam hardwaremäßig auf meinem FPGA DE0 umsetzen, falls
es nicht zu schwer ist^^
Muss man da eigentlich ein Bussystem verwenden. Und kann man den NIOS
auch zuerst verwenden ? xD
Viele Grüße,
erwin Locker
Hallo Erwin,
erwinLocker schrieb:> Woher wusstest du wie man> die Grafikeinheit oder den Speicher implementiert ?
Die Spec gibts z.b. hier:
http://problemkaputt.de/pandocs.htm
Habe vorher in C# probiert wie alles "richtig" aussieht.
Mit einem "known-good" Emulator kann man gegen checken.
Natürlich ist es eigentlich Verschwendung so einen "Wegwerf-Emulator" zu
schreiben, aber ich halte es für die beste Möglichkeit überhaupt zu
verstehen was zu tun ist.
Das ich vorher schon selbst eigene Softcores geschrieben habe und damit
positive wie negative Erfahrungen gesammelt habe hat sicherlich viel
geholfen. So hat man die spätere Umsetzung schon grob vor Augen.
erwinLocker schrieb:> Könnte man dann auch> eine Hardwarekomponente mit C# ähnlichem Z80 algoritmus einbinden, ohne> dass man gleich den Softprozessor selber einbinden muss, oder wäre das> zu uneffizient ?
Du würdest dich wundern... der Z80 ist sogar der C# Variante viel
ähnlicher als einem echten Z80. Warum?
Weil es so einfacher zu beschreiben ist als das Original und weil ich
für den Turbo Modus eine hohe Taktrate (100 Mhz) haben wollte. Die Z80
die nach Originaldesign nachbauen schaffen das allesamt nicht, deswegen
habe ich mich dagegen entschieden den so zu bauen.
erwinLocker schrieb:> Muss man da eigentlich ein Bussystem verwenden. Und kann man den NIOS> auch zuerst verwenden ? xD
Du musst das Gameboy Bussystem nachbauen, weil die CPU dort direkt
zugriff auf 256 Registeradressen(nicht alle genutzt) hat.
Den NIOS sehe ich da nicht als hilfreich. Wenn man C-Code schreiben
will, dann geht das effizient auf dem PC. Cross compiled/gedebugged sehe
ich wenig Sinn drinne.
Rein von der Leistung wird es mit dem NIOS auch sehr knapp wenn er alles
(CPU, Grafik und Sound) machen soll. Und einen Hybrid betrieb mit Teilen
der Funktionen im FPGA stelle ich mir noch schwieriger vor.