Hi,
ich habe vor kurzem einen sehr einfachen 6502 Emulator in C im Quellcode
gefunden, siehe hier
http://www.zophar.net/6502/no-name-6502-emulator.html .
Der Code stammt anscheinend "irgendwo" her, keiner weiss wo und der
Autor dieses Archivs hat ihn übernommen und verbessert.
Ich habe meine Hände am Emulator selbst nicht dran gehabt, sondern ein
Programm aussenrum geschrieben, um ihn benutzen zu können.
Aufgebaut ist das ganze so:
Ich habe zwei Threads und die ganzen Emulator-Funktionen in den C-Files.
Der eine Thread stellt die CPU dar, der andere ein Monitor-Programm.
Beim Starten des Hauptprogramms lädt er den Inhalt der Datei "data.img"
ins RAM (max 64kb).
Die data.img ist ein 1:1 Abbild eines 6502 RAMs/ROMs, also nur die
opcodes/operanden/daten, kein Format wie ihex, srec o.ä.
Dann startet er die Threads, die ungefähr so aussehen (ganz
vereinfacht):
1
cpu_thread(){
2
while(1){
3
warte_auf_ok_vom_monitor_für_nächsten_schritt();
4
führe_nächsten_schritt_aus();
5
}
6
7
}
8
9
monitor_thread(){
10
while(1){
11
warte_auf_user_input();
12
entscheide_was_zu_tun_ist();
13
tu_es();
14
}
15
16
}
Das Programm läuft soweit mal, dass man was sehen kann. Die data.img,
die Dabei ist, habe ich von Hand mit dem Hexeditor und ein Liste der
Opcodes gebastelt. Wenn du ein paar Schritte weitersteppst, sieht du
gleich, dass X und Y rauf und runter gezählt werden, mehr macht das
Programm nicht, gerade mal 10bytes gross.
Mit 'h' im Monitor kommt eine kleine Hilfe.
So nun zu meinen Fragen.
Wenn ich sämtliche printfs und auf "dauerlauf" ohne durchzusteppen
umändere, komme ich auf meinem Rechner (1.6ghz) auf ca. 130-140mhz für
meine 6502 cpu. Da das viel zu viel ist (C64 = 985khz), muss ich das ja
irgendwie stoppen. Das einfachste scheint mir eigentlich, erstmal rennen
zu lassen und dann zeitlich richtig Audio/Video/IO usw zu machen.
Aber da ich früher oder später einen kompletten C64 nachbauen will, der
auch Hardware-Kompatibel sein soll würde ich das eher so machen:
In dem CPU thread beim ausführen eines Befehls die Zeit messen und
solange warten bis die Zeit für die benötigten MZ bei 985khz vergangen
ist.
Was meint ihr dazu? Oder ganz andere Ansätze?
Den Chip zum Nachbilden eines C64. Ich habe hier noch ein mini2440 mit
3,5", das würde sicher reichen um das zu machen. Doch irgendwie ist es
mir auch zu Schade dafür, kann ja für viel mehr herhalten.
Ich hatte auch noch ein etwas älteres Board, ein DNP/1486, ist ein 486er
mit 33mhz.
Auf der Seite des Emulators an sich steht ein 486er/100mhz schafft ca
3mhz auf dem 6502. Nun würde das nahezu hinhauen die Geschwindigkeit vom
C64 zu schaffen.
Allerdings habe ich bedenken, dass das noch funktioniert, wenn man die
restliche Hardware noch in Software fertigstellt.
Da das DNP/1486 weder Audio noch Video hat, würde ich einen richtigen
SID für die Audio Ausgabe und eine "Controller-Grafikkarte"
anschliessen, so viel mehr hat dann das Board mit dem Simulator auch
nicht mehr zu tun.
Wenn ich das so machen sollte, was meint ihr ist am besten geeignet für
die Videoausgabe? Können muss es im Grunde nichts super-tolles, siehe
hier
http://de.wikipedia.org/wiki/Commodore_64#Grafik
Ich denke mit 320x200px@16 Farben, jedes Pixel einzeln ansteuerbar kommt
man da gut hin, die Textmodi, Sprites usw kann man ja in Software
machen, entweder auf dem Grafik-Controller/Grafikkarte/wasauchimmer oder
im Simulator.
Ich würde da am ehesten einen Parallax Propeller nehmen oder eine 8bit
ISA VGA Karte, wobei ich aber lieber TV-Out habe.
Im Anhang ein Screenshot vom Monitor mit dem kleinen Beispielprogramm
nach ein paar Takten und ein Archiv mit meinen Quellcodes, dem
veränderten Simulator, dem originalen Simulator, der Beispieldatei
(data.img) und compiliertem Simulator für Linux.
Wer gcc drauf hat, sollte das Problemlos mit "make" compilieren können.
> In dem CPU thread beim ausführen eines Befehls die Zeit messen und> solange warten bis die Zeit für die benötigten MZ bei 985khz vergangen> ist.
Es ist sinnvoll, solche Emulationen mit korrekter Zeit ablaufen zu
lassen, weil viele Programme damals takzabhängig programmiert wurden.
Aber man will ja auch Deinge nebenbei machen, z.B. Umkopieren des
Bidlschirmspeichers auf den echten Bildschirm.
Daher eine Methode die ich mal implementiert hatte: Jeder Befehl zählt
auch, wie lange er gedauert hätte (zumindest ungefähr, also ich hab's
nicht operandenabhängig gemacht, denn so genau kommt's nun auch nicht
drauf an (ausser bei Apple ][ Disketten-Operationen aber das geht auf
dem PC eh nicht)). Erreicht der Zähler 55 Millisekunden, die Zeit des
damaligen timer ticks auf dem PC, wurde der Emulator gestoppt bis der
nächste timer tick kam.
Also der Emulator hat ein Array in dem die benötigten MZ für jeden
Befehls gespeichert sind, würde das dann wohl so machen:
1. schaue auf die uhr
2. hole opcode,operanden / führe aus
3. rechne aus wieviel zeit auf dem echten 6502 drauf gegangen wär
4. schaue uhr/warte solange bis die zeit von schritt 3 erreicht ist
das dann direkt in dem Thread der die CPU darstellt.
Meinst du dass das so sinnvoll ist? Oder sollte ich schauen dass ich
jeden Maschinen-Befehl solange dauern lasse wie im Original? Was ich
aber nicht so rasend finde, so wäre kaum Platz noch was in den CPU
thread nachträglich zu basteln. Und so hätte auch noch eine recht
einfache Möglichkeit die Geschwindigkeit der CPU zu verändern, im
laufenden Betrieb. z.B. auf die NTSC Version (geringfügig schneller)
umzuschalten oder einen "free-running-modus".
Das kopieren in den Bildschirmspeicher usw würde ich über ein Flag
gesteuert zwischen Schritt 4 und dem nächsten Schritt 1 in der Wartezeit
über einen weiteren Thread machen.
Ich weiß nicht was du vor hast, aber schau dir auch den VICE an. Ein
fast perfekter C64/128 Emulator auf dem sogar viele Spiele laufen die
mit Splitsceen oder ähnlichen Grafiktricks gearbeitet haben. Code sollte
auch offen sein und evtl. gibt auch noch aktive Entwickler die man
kontaktieren kann.
Momentan gehts darum die CPU nachzubilden, da kommt man mit einem
Datenblatt weiter als mit Quellcode zu einem Simulator, später dann
wenns darum WIE die "Hardware" simulieren+anbinden, momentan bin ich
noch nicht so weit.
@Tom.M: diesen Java-Chip-Simulator, welcher auf der Wikiseite abgebildet
ist hab ich mir sicher 3 Stunden angeschaut, das ist total genial :) Mal
anhören und vlt. Kommt ja noch ein Video.
Bin ja auch gerade dabei einen 6502 Emulator in Arm7 Assembler zu
schreiben. Mein MC läuft mit ca. 50 MHz. Dem SID habe ich (bzw. Frank
:-)) einen 1MHz Oszillator gespendet. Bei jedem Befehl zähle ich mit,
wieviel Takte verbraten werden. Dabei sollte man auch bedenken, dass es
Befehle gab, die bei "grenzüberschreitenden" Speicherzugriffen
extra-Takte benötigten. Der 1MHz Oszi hängt sowohl am SID als auch am
MC. Ich warte dann einfach die Takte ab, die die 6502 gebraucht hätte...
In der Zeit kann ich dann auch noch mein Display refreshen und Taster
abfragen.
op_a9: // LDA #$xx
r5_imm // get address for #$xx into r5
ldrb r10, [r5] // get value from #$xx into r10 (A)
affect_nz r10 // calculate affected flags
add r8, r8, #2 // program counter
add r7, r7, #2 // 2 clock cycles
b drive_cpu
Was ich an der ARM Variante super finde: 64KB SRAM / viele Register
hab mir ne Sprungtabelle gebastelt, wo die ganzen Adressen für die
Opcode-funktionen liegen. Läuft bisher super. Allerdings hab ich noch
ein paar Befehle zum Übersetzen...
Als Grundlage nehm ich erst mal:
http://www.c64-wiki.de/index.php/%C3%9Cbersicht_6502-Assemblerbefehle
Den Audio-Out Schaltplan vom Sid zum Stecker fand ich hier:
http://www.zimmers.net/anonftp/pub/cbm/ALLFILES.html?keepThis=true&TB_iframe=true
So, jetzt muss ich noch ein paar Opcodes "übersetzen".
>Dem SID habe ich (bzw. Frank :-)) einen 1MHz Oszillator gespendet. Bei >jedem
Befehl zähle ich mit, wieviel Takte verbraten werden.
Also ich bin gerade dabei es so zu machen, dass ich die simulierten
Befehle vollgas rennen lasse und in meiner cpu-schleife dann abwarte.
Ich habe ein Array in diesem Simulator, welches die Takte hält und mit
denen rechne ich mir aus, wie lange ich noch warten muss bis der nächste
op ausgeführt werden darf, ob die CPU dann nun mit 0.985 oder 1.15mhz
rennt - drauf geschissen und ein wenig dran rumschrauben kann man ja
immer noch ;)
>Dabei sollte man auch bedenken, dass es Befehle gab, die bei >grenzüberschreitenden" Speicherzugriffen extra-Takte benötigten.
So wie ich das sehe, beachtet dieser Simulator diese Takte nicht, bin
mir aber nicht ganz sicher. Auf jeden Fall, führt er schonmal 6502 Code
aus, das ist vorerst das wichtigste.
>Was ich an der ARM Variante super finde: 64KB SRAM / viele Register
Ich hab mich nun auch fürs Board so ziemlich entschieden. Ein DilNetPC
DNP/1486. 33mhz, 2mb flash, 8mb ram, ethernet, seriell, 20 IO (8 davon
5V tolerant, rest 3v3), ...
Und dieses Board hat anscheinend auch nen 16bit ISA Bus, nur hab ich das
irgendwie noch nicht gefunden, habe aber auch keine wirkliche
Dokumentation zu dem Board. Ich werd die Tage mal beim Hersteller SSV
anrufen und nachfragen ob die mir da noch was haben, denke aber mal ja.
Dann kommt da nämlich eine VGA Karte dran, ne ET4000 mit >512k Video
RAM, da hab ich dann schonmal fürs Bild gesorgt.
Hier mal ein Überblick über das Board:
http://www.dilnetpc.com/dnp0001.htm
SID soll ein echter drankommen, habe noch einen 64er mit kaputten CIA
hier, der wird dafür geschlachtet.
Ich hab die Tabelle hier zum Spicken
http://www.atarimax.com/jindroush.atari.org/aopc.html
Nils S. schrieb:> Also ich bin gerade dabei es so zu machen, dass ich die simulierten> Befehle vollgas rennen lasse und in meiner cpu-schleife dann abwarte.> Ich habe ein Array in diesem Simulator, welches die Takte hält und mit> denen rechne ich mir aus, wie lange ich noch warten muss bis der nächste> op ausgeführt werden darf, ob die CPU dann nun mit 0.985 oder 1.15mhz> rennt - drauf geschissen und ein wenig dran rumschrauben kann man ja> immer noch ;)
ja, mit Vollgas laufen die bei mir auch. Und am Ende wird entschieden,
was mit der übrigen Leistung passiert. Die C-Version des Emulators, der
schon SID-Files abspielt, arbeitet auch mit diesen Arrays (Opcodes,
Speicherzugriff und Timing). Was mir daran nicht gefällt, ist dass die
Zugriffe aufs Array auch Zeit benötigen. In Assembler arbeite ich jetzt
alles mit Makros um. Die 256KB EEPROM des ARM verkraften das :-) So wie
ich das verstanden habe, möchtest Du doch einen kompletten C64
"abbilden", oder? Ich denke, wenn Du auch was anderes als den Textmodus
betreiben möchtest, dann ist das Timing nicht egal. Aber wenn Du
wirklich auch Kompatibilität hinbekommen möchstes, dass wird´s schon
schwierig. Was mich z.B. an den aktuellen Emulatoren stört, ist dass es
noch keiner hinbekommen hat 50 Hz absolut Synchron auf dem Bildschirm
auszugeben. Ich weiß schon, dass 50Hz nicht auf jedem Monitor
darstellbar sind. Aber MAME z.B. kann das schon. Und das ist für mich
total störend, wenn Laufschriften, Sprites etc. zwischendurch "ruckeln".
Verstehe ich eigentlich nicht, dass da nicht viel passiert in diese
Richtung.
>>Dabei sollte man auch bedenken, dass es Befehle gab, die bei>>grenzüberschreitenden" Speicherzugriffen extra-Takte benötigten.> So wie ich das sehe, beachtet dieser Simulator diese Takte nicht, bin> mir aber nicht ganz sicher. Auf jeden Fall, führt er schonmal 6502 Code> aus, das ist vorerst das wichtigste.
Wie gesagt, ich denke für Grafik-Spielereien wird das Timing sehr
wichtig.
>>Was ich an der ARM Variante super finde: 64KB SRAM / viele Register> Ich hab mich nun auch fürs Board so ziemlich entschieden. Ein DilNetPC> DNP/1486. 33mhz, 2mb flash, 8mb ram, ethernet, seriell, 20 IO (8 davon> 5V tolerant, rest 3v3), ...> Und dieses Board hat anscheinend auch nen 16bit ISA Bus, nur hab ich das> irgendwie noch nicht gefunden, habe aber auch keine wirkliche> Dokumentation zu dem Board. Ich werd die Tage mal beim Hersteller SSV> anrufen und nachfragen ob die mir da noch was haben, denke aber mal ja.> Dann kommt da nämlich eine VGA Karte dran, ne ET4000 mit >512k Video> RAM, da hab ich dann schonmal fürs Bild gesorgt.> Hier mal ein Überblick über das Board:> http://www.dilnetpc.com/dnp0001.htm
Die Hardware sieht ganz nett aus. Allerdings glaube ich es nicht, dass
es möglich ist, den C64 auf einer 33MHz Plattform laufen zu lassen. Bei
meinem ARM7 dauert bis jetzt jeder Assembler Befehl einen Zyklus. Wenn
das beim 486er auch annähernd so wäre, dann hättest Du im Idealfall 33
Befehle, um alles was im C64 in einem Zyklus passiert abzubilden. Ich
denke nicht, dass das funktioniert. Bei meinem SID-Player werden auch
nicht wahnsinnig viel Recourcen übrigbleiben...
> SID soll ein echter drankommen, habe noch einen 64er mit kaputten CIA> hier, der wird dafür geschlachtet.
Ich hab 1:1 die Schaltung wie im c128 Servicemanual übernommen (weil ich
den 8580 verwende). Irgendwie haben die anderen Dinge nicht
funktioniert, die ich probiert habe. Falls Du da Probleme oder Fragen
hast, kann ich Dir gerne versuchen zu helfen...
> Ich hab die Tabelle hier zum Spicken> http://www.atarimax.com/jindroush.atari.org/aopc.html
der Link ist bei mir lila :-)
Gruß
Peter
>Die Hardware sieht ganz nett aus. Allerdings glaube ich es nicht, dass>es möglich ist, den C64 auf einer 33MHz Plattform laufen zu lassen.
Hmm der Simulator an sich packt auf einem 486/100 etwa 3mhz. 33 dann 1.
Viel Zeit bleibt da wohl nicht, aber mal gucken, mit ner ISA VGA Karte
und den SID extern und ein wenig optimieren, den Simulator evtl auf
Assembler umstricken usw. wird das ja vielleicht gehen.
>Und am Ende wird entschieden, was mit der übrigen Leistung passiert.
Noch is da bei mir gar nix, aber ich werd das so machen, dass er am Ende
in der Wartezeit ein Flag setzt und ein zweiter Thread darf den Krams
aussenrum erledigen. Im Grunde nix aufwendiges, wenn ich das mit VGA
Karte und SID machen kann.
Mal sehen ob ich nen einzelnen CPU-Simulator in x86 asm finde um zu
vergleichen.
Ich hab auch schon an irgend ein 486er PC104 mit ISA gedacht, da bekommt
man nen DX4/100 Prozessor für n paar Euro hinterhergeschmissen, mal
abgesehen von dem Haufen 20€-Ebay-Sofort-Kauf-Angeboten... grml
(Schweine, Abzocke, nix andres). Aber irgendwie reizt mich das kleine
Board, DIL64 und alles drauf was nen x86 an sich ausmacht :)
>Ich hab 1:1 die Schaltung wie im c128 Servicemanual übernommen (weil ich>den 8580 verwende). Irgendwie haben die anderen Dinge nicht>funktioniert, die ich probiert habe. Falls Du da Probleme oder Fragen>hast, kann ich Dir gerne versuchen zu helfen...
Ich hab den SID vorhin mal 1:1 von der 64er Platine aufm Steckbrett und
an einen 8051er gehängt, das tut soweit mal :), is ja auch nich schwer
:)
>für mich total störend, wenn Laufschriften, Sprites etc. zwischendurch>"ruckeln". Verstehe ich eigentlich nicht, dass da nicht viel passiert in>diese Richtung.
Oh ja, sowas geht mir auch aufn Zeiger, aber an sowas ist jetzt noch
nicht zu denken. Ich hab ja noch nichtmal den Prozessor ganz fertig bzw
es ist noch nicht mehr als ein Konzept...
>der Link ist bei mir lila :-)
Bei mir werden die nicht lila, History aus :P
...hmmm hab gerade nochmal überlegt: Es gab ja damals auch so Effekte
wie Char-Scrolling. z.B. einfach einen Punkt in einem Zeichen jeweils 1x
um ein Bit rotieren. Wenn Du dieses Zeichen dann auf dem gesammten
Bildschirm verteilt darstellst (40*25) und alleine nur dieses eine
Zeichen veränderst, musst Du das gesammte Bild neu aufbauen und das sind
bein 320x200x50Hz alleine schon 3,2 Mio Pixel / Sekunde. Dabei ist noch
nicht mal der Rahmen mit berücksichtigt. Also meine Meinung nach wie
vor. 6502 wird auf jeden Fall funktionieren. Aber wenn Du auf Grafik und
all die Eigenheiten des C64 eingehst wird das - so denke ich - nicht mal
auf nem 486DX/4 100 in x86 Assembler laufen (immer mit dem Hintergrund
50Hz PAL 100%).
Ich habe mir auch schon ein paar Gedanken gemacht, was man denn so
machen könnte. Was ich persönlich total cool fände: wenn man für jeden
speziellen IC im C64 eine kompatible MC-Variante "nachbasteln würde",
die vom Formfaktor auch noch passen würde. Wobei da sowas wie der C-One
vielleicht auch schon ne passable Alternative ist, um "keep the spirit
alive" zu spielen...
Gruß Peter
Da mir die Idee mit dem C64 auch schon länger im Kopf 'rum schwebt, kann
ich ja auch mal meinen Senf dazu geben.
Was den 6510er betrifft, habe ich auf einem ATmega eine Zyklenexakte
Emulation geschrieben die mit Faktor 20 läuft (20 AVR-Takte = 1
6510-Takt). Bei den kurzen 6510er-Opcodes(2-3 6510-Takte) lässt sich da
auch nichts mehr 'rausholen. So wie der Code aussieht, bekommt man das
auch auf einem 486 nicht mit weniger Assembler-Code hin. Das ist aber
'nur' die CPU noch kein IO geschweige denn Video.
Peter Pippinger schrieb:> Was ich persönlich total cool fände: wenn man für jeden> speziellen IC im C64 eine kompatible MC-Variante "nachbasteln würde",> die vom Formfaktor auch noch passen würde.
Ich kenne mich leider mit der Hardware-Seite noch nicht so aus bzw.
lerne noch, ich habe aber schon die Möglichkeit im Emulator
berücksichtigt, dass man ihn als vollwertigen 6510er-Ersatz verwenden
könnte. Entworfen habe ich die Hardware dafür auch schon, aber noch
nicht besorgt und gelötet.
Der Swin-SID ist zwar nicht ganz kompatibel, aber für die grobe
Sound-Wiedergabe gibt's den ja auch schon.
Um die Videoausgabe so hinzubekommen, dass mehr als der
Basic-Interpreter läuft muss man wohl jede Zeile einzeln berechnen. D.h.
144 Bytes aus RAM lesen, 8 Sprite-Zeilen verarbeiten mit Kollisionen und
parallel 320x4-bit ausgeben. Dann funktionieren auch die ganzen Tricks
bspw. mit dem Rasterinterrupt.
Würde es einen AVR mit ca. 100MHz geben würde ich sagen, dass es zwar
nicht leicht wird, aber man das hinbekommen könnte 6510+SID+VIC-II zu
emulieren. Sollte auf einem 486@100MHz somit wohl auch gehen, zumindest
in Assembler.
Mark
...hmm. hab eben mal http://cbmmuseum.kuto.de/zusatz_6569_vic2.html
überflogen. Schaut jetzt wirklich auf den ersten Blick nicht nach
Hexerei aus. Aber ich denke nach wie vor dass alles in 100 MHz äußerst
eng, eher unmöglich machbar ist. Hab gestern Nacht noch nen
interessanten Beitrag zum Thema gefunden:
http://forum.6502.org/viewtopic.php?t=1603
Mein 6502 möchte ich auf ARM7 auch bestmöglich optimieren (zumindest
sehr nahe am besten Zustand.) Ich bin von ARM irgendwie gerade recht
angetan. Hab ganz früher auch mal was auf dem 286er-486er in ASM
programmiert. War da bestimmt nicht gerade ne Leuchte, aber ich meine
sagen zu können, dass man mit dem ARM mit einem Takt mehr erreichen kann
(zumindest hier bei diesem Thema). Was ich bereits angefangen habe:
Flags direkt vom ARM übernehmen. Hab heute noch gesehen, dass man
Pointer nach dem Auslesen im gleichen Befehl automatisch erhöhen kann.
Das werde ich auch noch irgendwie reinbauen.
Naja, wie dem auch sei. Meine Zeit ist leider dermaßen knapp, dass ich
schon total stolz darauf bin, dass Sanxion-Loadertune auf meiner
"Plattform" mir nem SID zusammen läuft. Wenn das jetzt dann mal alles
soweit fertig ist, könnte ich mir gut vorstellen auch mal andere Teile
des C64 "anzusehen".
Gruß
Peter
Auch wenns schon länger her ist... Ich habe den Simulator mittlerweile
soweit, dass er auf einem mini2440 ohne Betriebssystem läuft.
Die CPU habe ich wie im Eröffnungspost von Zophar genommen (no name 6502
emulator). Stand so ca.:
SID ist ein echter angeschlossen
VIC wird später mal per Software gemacht werden
CIA in Software emuliert, Joystick 1 oder 2 über Felder auf dem
Touchscreen steuerbar
Laden von Images übers Terminal (ROMs, komplette 64k-Speicher-Abbilder,
ihex, d64 in Arbeit)
Einfaches durchsteppen von Code/Laufen lassen, komme so auf ca. 12mhz.
Momentan bastle ich an einem schönen Disassembler/Debugger für den
Emulator, der dann über ein Terminal vom Rechner aus bedient werden
kann, habe nach 2 Monaten nichts dran tun keine Lust gehabt, am
Emulator weiter zu machen, darum den Disassembler angefangen.