Hallo Besucher, der Thread wurde 3,7k mal aufgerufen und enthält 19 Antworten

letzter Beitrag von Brotscheibe am

Hilfe für Problem mit Floating Points in Emulator

  • Hallo liebe C64 Community,


    nach wochenlanger Suche habe ich mich dann doch mal entschlossen, Kontakt aufzunehmen, da ich mit meinem Problem einfach nicht weiterkomme :-)
    Ja, ich erfülle mir gerade einen langgehegten Traum, und baue den Computer meiner Kindheit, zumindest in Software nach. Auf gut Deutsch, ich schreibe meinen eigenen C64-Emulator (in C#). Primäres Ziel: Spass am Programmieren :-)
    Dank der ausgezeichneten C64 Wikis (de/en) und der wirklich guten Beschreibungen dort, bin ich auch relativ fix vorrangekommen. Aktueller Stand: Der 6510 verrichtet auch schon ganz gut seine Arbeit (VIC CIA etc fehlen noch - sind quasi Future Work) - der KERNAL wird gebootet und BASIC meldet sich auch freundlich.


    Mein aktuelles Problem: Die Fließkommarechnungen bzw Ausgabe von Fließkommazahlen ist nicht ganz das, was es sein sollte.


    PRINT 1/2
    .50390625


    allerdings
    PRINT 0.5
    .50234375


    Wochenlanges debuggen, googeln, etc hat mich leider nicht weiter gebracht. Auch das Analysieren der entsprechenden KERNAL-Routinen gab mir nicht die zündende Idee.


    Ich vermute stark, dass ein Status Flag irgendwo noch falsch gesetzt wird...?


    Ich hoffe, dass es hier Experten gibt, die sich mit den Routinen auskennen und/oder selbst mal einen Emulator geschrieben haben und/oder auf ein ähnliches Problem gestoßen sind.


    Anbei einen Screenshot des aktuellen Emulators.


    Quellcode des Emulators kann ich gerne zur Verfügung stellen.


    .50390625 --> 0.10000001 (binary)
    was mir nahe legt, dass irgendwie eine 1 "zu wenig" weggeshiftet, wird, oder ähnliches?


    Die Frage daher: Hat Jemand eine Idee/einen Tipp, wo ich noch ansetzen könnte bzw was genau falsch laufen könnte?



    Viele Grüße und vielen Dank schon mal, für etwaige Ideen :-)
    niko

  • Helfe gerne, wenn ich kann. Hab selber oft genug einen 6502-Emulator geschrieben, und da kam es auch vor, daß die Floatingpointroutinen versagt haben. In meinem Fall lag das damals daran, daß ich einen Bug in den Verschiebe-Befehlen ROR, ROL, ASL und LSR hatte, da diese intensiv gebraucht werden auch z. B. in der für Verschiebebefehle sonst eher seltenen Adressierungsart zp,x. Bei dieser Befehlsgruppe würde ich an Deiner Stelle daher als erstes nachgucken. Und natürlich werfe ich auch gerne einen Blick auf den Quellcode, wenn es DIr nichts ausmacht.

  • Mein aktuelles Problem: Die Fließkommarechnungen bzw Ausgabe von Fließkommazahlen ist nicht ganz das, was es sein sollte.

    Teste deinen Emulator doch mal mit einer der 6502-Testsuites. Die von Wolfgang Lorenz ist praktischerweise auch gleich für den C64 geschrieben und wenn die keinen Fehler in den Opcodes mehr meldet, funktioniert wahrscheinlich auch die Fliesskommaberechnung korrekt.

  • Also die Implementierungen meiner Shift-Befehle sind folgende:
    (Wobei die jeweiligen "konkreten" Befehle diese dann aufrufen - Bsp: ROL_26 ruft Rol() entsprechend auf.).

  • Testsuites habe ich ausprobiert - soweit ich es hinbekommen habe.


    Die von Klaus Dormann habe ich mittels AS65 assembler in eine binary umgewandelt.
    Soweit ich dies jetzt verstehe, arbeitet der Emulator den Code so lange ab, bis er in einer Endlosschleife hängen bleibt (=> Fehlerfall oder am Ende, alles OK)


    Zitat:
    ; Most of the code is written sequentially. if you hit a trap, check the
    ; immediately preceeding code for the instruction to be tested. Results are
    ; tested first, flags are checked second by pushing them onto the stack and
    ; pulling them to the accumulator after the result was checked. The "real"
    ; flags are no longer valid for the tested instruction at this time!


    Mein Problem hier: Ich bekomme das "Mapping" ASM Code vs Speicheradresse der Trap nicht hin, bzw finde diese nicht.
    Mein Emulator bleibt auch tatsächlich in einem Loop hängen, aber welcher der "Traps" dies ist, ergo welcher Befehl fehlerhaft ist, ist mir da leider nicht klar.


    Die Testsuite von Wolfgang Lorenz bekomme ich leider nicht ans Rennen - mir ist da unklar, wie ich die in ein ROM-File assembliere
    Die Beschreibungen da bringen mich leider nicht weiter :-)

  • Die Testsuite von Wolfgang Lorenz bekomme ich leider nicht ans Rennen - mir ist da unklar, wie ich die in ein ROM-File assembliere

    Mindestens eine Version davon sollte als Sammlung von PRG-Dateien (evtl. aufgeteilt auf mehrere D64-Files) daherkommen - die laufen einfach aus dem RAM und verwenden die normalen C64-ROM-Kernal-Aufrufe für I/O. Deinem Screenshot nach starten Kernal und BASIC ja schon. Das Nachladen kann man auch einfach nachbauen, indem man die Emulation bei PC=$ffd5 kurz unterbricht und den Ladevorgang extern simuliert (Adresse des Filenamens steht in $bb/$bc, Länge in $b7, Ladeadresse aus den ersten beiden Byte der Datei holen, Daten dahin laden, PC auf $f5ae setzen)

  • .50390625 --> .81000000 (hex)
    .50234375 --> .80999999 (hex)
    Lauter Neunen in Hexdarstellung ist ein sehr komischer Zufall - ist möglicherweise der Dezimalmodus aktiv, obwohl er es nicht sein sollte?

  • Hiho,


    Mac Bacon: Nein, ist er nicht :-) habe den Dezimalmodus auch noch nicht implementiert


    Unseen: Ich habe es nun hinbekommen die einzelnen Files der Testsuite von Wolfgang Lorenz zu laden. Vielen Dank für die Hilfe!!!!


    Mittels
    LOAD "START"
    RUN
    lädt er nun auch entsprechend die Einzeltests von Wolfgang Lorenz nach (siehe Screenshot).


    Dazu habe ich allerdings noch ein paar Fragen :-)


    1) mir ist die Ausgabe nicht ganz klar:
    Display:
    before data accu xreg yreg flags sp
    after data accu xreg yreg flags sp
    right data accu xreg yreg flags sp
    ---> Woran erkenne ich hier genau, ob es nun richtig ist oder falsch :-)


    2) Aktuell muss ich nach jeder "Testiteration" eine Taste drücken, damit es weiterläuft. Kann man das irgendwie quasi "komplett durchlaufen" lassen?

  • ---> Woran erkenne ich hier genau, ob es nun richtig ist oder falsch :-)

    Wenn es erscheint ist was falsch. Bei einem fehlerfreien Durchlauf erscheinen lediglich die Namen der geladenen Tests.


    Zitat

    2) Aktuell muss ich nach jeder "Testiteration" eine Taste drücken, damit es weiterläuft. Kann man das irgendwie quasi "komplett durchlaufen" lassen?

    Ja, Fehler beseitigen.

  • Scheint aber nur das Break-Flag unterschiedlich zu sein, oder? Das sollte m.E. keinen Einfluss auf Float-Berechnungen haben können...

  • Scheint aber nur das Break-Flag unterschiedlich zu sein, oder? Das sollte m.E. keinen Einfluss auf Float-Berechnungen haben können...

    Schon, aber die Testsuite wird es trotzdem bei jedem einzelnen Test anmeckern und das ist ja schnell gefixt.


    Ausserdem: Sollte man wirklich nur den Float-beeinflussenden Emulationsfehler beseitigen oder nicht doch lieber alle?

  • Ja, ich habe das Break flag falsch gesetzt bzw hatte es auch falsch verstanden.
    Mein Verständnis jetzt: Break ist immer gesetzt, wird aber bei BRK gesetzt auf den Stack gelegt und bei einem Hardwareinterrupt gelöscht auf den Stack gelegt... ok.
    Das ist jetzt gefixt.


    Jetzt bleibe ich wegen dem Carry-Flag hängen (siehe Screenshot) :-)
    sobald ich bei 0x80 "ankomme".


    Und ich stimme Unseen zu, natürlich möchte ich gerne, soweit möglich, alle Fehler fixen... na, dann weitersuchen :-)

  • Ja, ich habe das Break flag falsch gesetzt bzw hatte es auch falsch verstanden.
    Mein Verständnis jetzt: Break ist immer gesetzt, wird aber bei BRK gesetzt auf den Stack gelegt und bei einem Hardwareinterrupt gelöscht auf den Stack gelegt... ok.

    Das Break-Flag gibt es in der CPU überhaupt nicht =) Das wird nur spontan erzeugt, wenn die Flags auf den Stack abgelegt werden: Normalerweise wird eine 1 reingeschrieben, einzig bei einer BRK-Anweisung wird dort eine 0 erzwungen.


    Zitat

    Jetzt bleibe ich wegen dem Carry-Flag hängen (siehe Screenshot) :-)
    sobald ich bei 0x80 "ankomme".

    Das Carry-Bit wird nur von Addition/Subtraktion, Shiftbefehlen und beim expliziten überschreiben (CLC/SEC/PLP) beeinflusst, warum beeinflusst dein LDA das überhaupt?

  • Mein LDA beeinflusst das Carry-Bit gar nicht - das ist das Merkwürdige an der Sache :-/
    Es muss ein anderer Befehl sein, der, sobald der Counter 128 erhält das Carry-Bit umsetzt. Die einzigen Befehle, die ich mir vorstellen könnte, sind ROL und ASL. Die sind bei mir wie folgt implementiert:


  • Mein LDA beeinflusst das Carry-Bit gar nicht - das ist das Merkwürdige an der Sache :-/
    Es muss ein anderer Befehl sein, der, sobald der Counter 128 erhält das Carry-Bit umsetzt. Die einzigen Befehle, die ich mir vorstellen könnte, sind ROL und ASL.

    So sieht der Innenteil der Testschleife aus:

    Ich würde also zuerst LDA und PHP verdächtigen.

  • bool newCarry = (value & 0x80) != 0;

    Hat das denn so seine Richtigkeit? Oder fehlen da Klammern? Ginge das nicht mit "_newCarry = ((value & 0x80) !=0);" ?


    (Hab aber nahezu null Ahnung von C...)

  • Juhu!!!


    Ich habe meinen (wirklich dummen!!) Fehler gefunden (siehe Quellcode).
    Beim Widerherstellen von SR (durch PLP und RTI) habe ich NUR die vorher gesetzten flags hergestellt. Wenn ein flag aktuell gesetzt war und es beim Widerherstellen nicht gesetzt sein soll, habe ich es nicht auf false gesetzt ( die Else-Zweige im setter fehlten... OMG... )...


    Danke an alle für die Tipps und vor allem die Idee und Hilfe mit der Testsuite... aktuell läuft diese jetzt ohne Probleme bis ADCB (siehe Bild)... das liegt aber daran, dass ich noch keinen decimal mode implementiert habe...
    Sehr cool! Vielen Dank nochmal... jetzt kann ich von da weiter machen und die Testsuite hilft mir, direkt Bugs zu finden... btw, durch die Tests habe ich auch noch zwei weitere Befehle gefixt :-)
    Übrigens: Die floating point routinen arbeiten jetzt auch so, wie sie sollen :-)

  • Ich habe gesehen, dass Foren-Themen als "Erledigt" markiert werden können.
    Da mein Problem, dank der Hilfe mehrerer Mitglieder hier, gelöst wurde, würde ich es auch als gelöst markieren. Ich weiss nur leider, ob ich es darf und wie es geht :-)


    Die Problemlösung war übrigens, einen Bug mit dem Speichern und Widerherstellung des Statusregisters auf dem Stack - siehe oben - zu fixen.
    Außerdem war die Ausführung der Testsuite von Wolfgang Lorenz sehr hilfreich, um Fehler zu finden und zu fixen...