www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Finetuning 6510 Emulator / C / AT91SAM7S256


Autor: Peter Pippinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo NG,

zunächst mal kurz meiner Freude Ausdruck verleihen:   :-) :-) :-)

Jetzt funktioniert mein 6510 EMU schon fast. Hier eine kleine 
Disassemlierung eines 64er-SID-Files - geladen von SD-Karte - auf dem 
ARM disassembliert - gesendet an RS232:

------ 8< ------ 8< ------ SCHNIPP

Initialize Card...
Card Initialized!
READY.
_

B009 24 F8    BIT $F8
B00B 30 2E    BMI $B039
B00D 50 43    BVC $B050
B00F A2 1F    LDX #$1F
B011 8E 18 D4 STX $D418
B014 AE 3A B5 LDX $B53A
B017 A9 00    LDA #$00
B019 BC 0F B5 LDY $B50F,X
B01C 99 04 D4 STA $D404,Y
B01F 9D 13 B5 STA $B513,X
B022 9D 16 B5 STA $B516,X
B025 9D 19 B5 STA $B519,X
B028 9D 1F B5 STA $B51F,X
B02B 99 06 D4 STA $D406,Y
B02E A9 1B    LDA #$1B
B030 9D 25 B5 STA $B525,X
B033 CA       DEX
B034 10 E1    BPL $B015
B036 85 F8    STA $F8
B038 4C 42 B4 JMP $B442

------ 8< ------ 8< ------ SCHNAPP

...so, nun zum eigentlichen Thema: der größte Teil der Emulation läuft 
eigentlich in einer Switch / Case Anweisung ab. Es wird die passende 
Aktion zum aktuellen Opcode gesucht und ausgeführt. Das darumherum ist 
eigentlich immer gleich. Jetzt stellen sich mir 3 Fragen:

1. wie wird die Switch / Case Anweisung umgesetzt? Dauert es länger, 
wenn der letzte Case zutrifft, als wenn der erste Case zutrifft? 
Arbeitet der Compiler bei Switch / Case mit einer "Sprungtabelle"?

2. wie stelle ich fest, wieviele Takt-Zyklen der ARM für die Emulation 
eines Befehls benötigt?

3. kann ich irgendwo im C Code "echte" ARM-Assembler-NOPs einfuegen, um 
alle Befehle gleich lang laufen zu lassen?

Vielen Dank für jeden Tip!
Peter

Autor: Benedikt K. (benedikt) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Pippinger wrote:

> 1. wie wird die Switch / Case Anweisung umgesetzt? Dauert es länger,
> wenn der letzte Case zutrifft, als wenn der erste Case zutrifft?

Ja, das ist meistens der Fall.

> Arbeitet der Compiler bei Switch / Case mit einer "Sprungtabelle"?

Auch das ist möglich. Wie das bei deinem Compiler genau ist, weiß ich 
jedoch nicht. Allerdings wird die Tabelle meist wohl eher nur in 
seltenen Fällen verwendet.

> 2. wie stelle ich fest, wieviele Takt-Zyklen der ARM für die Emulation
> eines Befehls benötigt?

Garnicht. Vor allem auf einem ARM mit seinem Instruction Cache (oder wie 
auch immer die das nennen) ist das nicht ohne weiteres möglich.

> 3. kann ich irgendwo im C Code "echte" ARM-Assembler-NOPs einfuegen, um
> alle Befehle gleich lang laufen zu lassen?

Das ist Pfusch, denn mit jeder neuen Compilerversion musst du dann den 
Code wieder anpassen.
Besser wäre vielleicht einen Timer zu verwenden, und am Ende einfach zu 
warten bis ein bestimmter Timerwert erreicht ist.

Autor: Peter Pippinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>> Arbeitet der Compiler bei Switch / Case mit einer "Sprungtabelle"?

>Auch das ist möglich. Wie das bei deinem Compiler genau ist, weiß ich
>jedoch nicht. Allerdings wird die Tabelle meist wohl eher nur in
>seltenen Fällen verwendet.

...naja, möglich reicht mir nicht. Ich brauch sowas definitiv, weil ich 
nicht 256 Compare-Branch-Duos warten kann, bis mal der letzte Opcode 
Emuliert wird!

Wäre ein Konstrunkt auf diese Art und Weise OK, oder ist das totaler 
Bullshit?

BEISPIEL:
---------

int o=0;
int i=0;

void opcode00()
{
  i=1;
}

void opcode01()
{
  i=2;
}

// Sprungtabelle
void (*ptrs[])() = { opcode00, opcode01};

int main()
{
  ptrs[0](); // calls opcode00
  ptrs[1](); // calls opcode01
  i=o;

  return 0;
}

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde das erst mal straightforward implementieren und die 
Optimierung dem Compiler überlassen. WENN sich dann herausstellt dass er 
es nicht schnell genug umsetzt kannst du immer noch von Hand optimieren.

Wenn du eine sportliche Herausforderung suchst solltest du in Erwägung 
ziehen einen JIT-Compiler zu schreiben der den Code zur Laufzeit in 
ARM-Code umsetzt.

Autor: Peter Pippinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Ich würde das erst mal straightforward implementieren und die
>Optimierung dem Compiler überlassen. WENN sich dann herausstellt dass er
>es nicht schnell genug umsetzt kannst du immer noch von Hand optimieren.

naja, das kann einfach nicht angehen, dass z.B. der Opcode 0xfe (INC 
$xxxx,X) 254 * (CMP + BEQ) Vorlauf benötigen bis mal was passiert.

a) Das so zu machen macht doch den Emulator zeitlich absolut 
unberechenbar und ineffizient.

b) Soviele Takte habe ich nicht zu "verschenken". Habs jetzt so gemacht, 
wie oben beschrieben. Funktioniert auch.

>Wenn du eine sportliche Herausforderung suchst solltest du in Erwägung
>ziehen einen JIT-Compiler zu schreiben der den Code zur Laufzeit in
>ARM-Code umsetzt.

Nee, lieber nicht. Hab das mit Assembler doch neulich an den Haken 
gehängt, weil ich mit der SD-Karte nicht so recht weiterkam. Und wenn 
die Musik richtig spielt ist mit am Ende sowieso Wurst, wie das passiert 
:-)

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Pippinger wrote:
>>Ich würde das erst mal straightforward implementieren und die
>>Optimierung dem Compiler überlassen. WENN sich dann herausstellt dass er
>>es nicht schnell genug umsetzt kannst du immer noch von Hand optimieren.
>
> naja, das kann einfach nicht angehen, dass z.B. der Opcode 0xfe (INC
> $xxxx,X) 254 * (CMP + BEQ) Vorlauf benötigen bis mal was passiert.

Benötigt er die wirklich, oder vermutest du das nur?

Autor: Marius S. (lupin) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da kann man doch einfach den debugger starten, wenn du yagarto benutzt 
ist auf der rechten seite ein ASM output da siehst du was er macht.

Vielleicht kommt es auch auf den Optimierungsgrad an...

Autor: gerhard (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo peter,
die opcode umsetzung würde ich einfach über eine tabelle mit 256 
einträgen machen. und das zeitverhalten würde ich wie schon erwähnt mit 
einem hardware timer nachstellen. auch dafür ist die tabelle besten 
geeignet.
stichwort: array of structures.

gruss
gerhard

Autor: Marius S. (lupin) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich würde solch einen emulator eher in assembler schreiben. (zumindest 
die Kernfunktionen)

Vorteil ist das du dann auf jeden fall weisst was passiert.

Du könntest dann anstatt ein Array mit funktionspointern zu benutzen 
einen Bereich für die Opcode-Funktionen definieren und die funktionen in 
einem festen Offset anlegen.

Wenn ich das richtig sehe hat der 6510 8 bit opcodes. Dann reservierst 
du für jeden Opcode einfach 64 byte (je nachdem wieviel Code du pro 
OPCODE brauchst) und springst dann einfach an die Addresse: 
Basisaddresse + OPCODE * 64

Bei Basisaddresse starten dann deine OPCODE Funktionen (die dann 
wirklich nur 64 byte lang sein dürfen).

So sparst dir den speicher für die Sprungtabelle...

Dann brauchst du:
2 Cycle zum das Laden der Basisaddresse (dort wo deine OPCODE Funktionen 
starten)
1 Cycle für die Addition des OPCODES * 64 (der Shift ist geschenkt)
1 Cycle zum Funktionsaufruf

Von der Sprungtabelle laden wäre wohl genau so schnell:
2 Cycle zum Laden der Basisaddresse der Sprungtabelle
1 Cycle zum addieren des OPCODES * 4 (shift ist wieder geschenkt)
1 Cycle zum Funktionsaufruf

Kann sein, dass ich das mit den cycles nicht ganz richtig habe :-)

Die Basisaddresse könntest dir auch in nem Register zwischenspeichern.

Hardcore optimierungen (so wie du es gerne hättest) gehen nur in ASM. 
Solche Tricks wird kein C Compiler machen.

Beim ARM ist es auch so, dass man per ASM wirklich noch Speed raus holen 
kann (was bei größeren Systemen nix mehr bringt).

Autor: Andreas Schwarz (andreas) (Admin) Benutzerseite Flattr this
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Solche Tricks wird kein C Compiler machen.

Nachdem jetzt viel über Alternativen zum switch-case philosophiert wurde 
sollte sich einfach mal jemand hinsetzen und anschauen was der Compiler 
aus switch-case macht. Vielleicht geht dann manch einem ein Licht auf 
woher der berühmte Satz "premature optimization is the root of all evil" 
kommt.

Autor: Peter Pippinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Nachdem jetzt viel über Alternativen zum switch-case philosophiert wurde
>sollte sich einfach mal jemand hinsetzen und anschauen was der Compiler
>aus switch-case macht. Vielleicht geht dann manch einem ein Licht auf
>woher der berühmte Satz "premature optimization is the root of all evil"
>kommt.

ich habe mich mal hingesetzt, und ein neues Projekt mit nur einem Switch 
im Debugger angesehen. Es waren nur 3 Cases und wenig Code in diesen. 
Das hat der Compiler tatsächlich so gemacht, wie ich es nicht wollte. 
Allerdings scheint er bei aufwendigeren Cases tatsächlich eine 
Sprungtabelle zu verwenden. Aber das ist mir jetzt auch egal, weil ich 
die Schiene mit den Pointern auf Funktionen fahre...

Trotzdem Danke an alle.

Autor: Tom Nachdenk (tom-nachdenk)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch wenn es zu spät ist, warum suchst Du bei den Opcodes nicht binär? 8 
Vergleichen für jeden Befehl ... und wenn es geeignete Bitgruppen gibt 
evtl. noch weniger

Autor: Peter Pippinger (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@andreas

>Wenn du eine sportliche Herausforderung suchst solltest du in Erwägung
>ziehen einen JIT-Compiler zu schreiben der den Code zur Laufzeit in
>ARM-Code umsetzt.

...habe mir heute auf dem Weg zur Arbeit das mal durch den Kopf gehen 
lassen. Aber ich denke, dass sowas eher etwas für interpretierte 
Sprachen geeignet ist. Stell Dir mal vor, dass ich einen Opcode an einer 
Speicherstelle per Programm ändere. Und an dieser Stelle steht nun schon 
der umgewandelte ARM-Code... Ich denke, dass das für Assembler nahezu 
unmöglich ist.

Meine neue Herausforderung wird wohl in nächster Zeit die Renovierung 
eines alten Häuschens sein. Da wird wohl leider noch weniger bis gar 
keine Zeit für den uC übrig bleiben. Vielleicht findet sich ja danach 
jemand, der das mit mir zusammen machen möchte. Ich denke, dass das 
Projekt mehr als interessant ist. Nur schaffe ich es zeitlich einfach 
nicht :-(

PS.: ich bin z.Zt. eigentlich schon wieder eher dafür, das Ganze doch in 
Assembler zu machen.

Autor: Marius S. (lupin) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Vielleicht findet sich ja danach jemand, der das mit mir zusammen machen
> möchte.

Ich bezweifle mal, dass dir hier jemand beim renovieren helfen wird ;-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.