6502 ROR auf ARM7 Emulieren / freie Bits im Statusregister?

OP #2038342
Lesenswert?

Hallo NG,

ich bin ja gerade dabe, den 6502 Emulator zu schreiben.
Nachdem ich ja nur das oberste Byte nehme, um gleich die Status-Flags 
des ARMs ausnützen zu können, gilt dem ROR-Befehl besondere 
Aufmerksamkeit:
1
opc_ROR macro 
2
  lsrs r6, r6, #1          // lsr value
3
  tst r6, #1 << 23         // check if bit is "outshifted"
4
  bicne r6, r6, #1 << 23   // clear "outshifted" bit
5
  orrnes r6, r6, #3 << 31  // also set carry
6
  strb r6, [r5]            // store value
7
  mrs r9, cpsr
8
  endm

r6 ist der 8-Bit-Wert (Bit 24-31)
r5 ist der PC des 6502
r9 ist das Statusregister

Kann man da noch was besser machen (weniger Befehle)?

Und dann wollte ich noch Fragen, ob es beim ARM7 in cpsr noch "freie 
Bits" gibt. Ich würde die gerne verwenden, um das Dezimal-Flag und das 
Interrupt-Flag vom 6502 mit rein zu nehmen.

Gute Nacht,
Peter
#2038427
Lesenswert?

Nein, es gibt keine "freien" Bits im Statusregister.

ROR hat Carry rein, dein Code nicht.

Bist du sicher, dass dein C-Status danach stimmt?
C dürfte bei dir identisch mit N sein.

Besser:
1
mov  r6, r6, rrx         // the rotate operation
2
movs temp, r6, lsr #24   // bit 23 to C
3
and  r6, r6, #0xFF << 24 // clear bits 0-23
4
tst  r6, r6              // get NZV state, C unaffected
OP #2038431
Lesenswert?

hallo AK,

>mov  r6, r6, rrx         // the rotate operation
ist rrx ein shift-befehl?

habs ausprobiert:
orrnes r6, r6, #3 << 31  // also set carry

hab extra die 3 genommen (Bit0+1). Bit1 "rutscht" automatisch ins Carry.
Bin eigentlich ziemlich begeistert von diesem nächtlichen Gedankenblitz 
:-)

Dann darf man wohl eher nicht ins Statusregister schreiben?
Werden alle Bits immer gesetzt bei den Flag-relevanten Befehlen?
Kann man einzelne Flags auch wieder löschen?

Also mit Kann meine ich mehr oder weniger immer: darf.

Gruß
Peter
OP #2038451
Lesenswert?

A. K. schrieb im Beitrag #2038439:
> Peter Pippinger schrieb:
>
>> hab extra die 3 genommen (Bit0+1). Bit1 "rutscht" automatisch ins Carry.

> Die Doku drückt sich da etwas anders aus. Derzufolge entstammt das Carry
> bei Data-Immediate und Rotatecount != 0 dem Bit 31 der fertig rotierten
> Konstanten. Ohnehin ist 3<<31 der Wert 0x1_8000_0000 und auf 32 Bits
> beschränkt identisch mit 0x8000_0000 also 1<<31.

Hmm, da hab ich mich wohl auf die Workbench verlassen. Ich habs im 
SW-Debugger getestet und da wird das Carry gesetzt. Muss ich mir nochmal 
anschauen.

>> Werden alle Bits immer gesetzt bei den Flag-relevanten Befehlen?
>
> Deine Konsequenz bei der Vermeidung jedweder zielführender Lektüre ist
> auf Dauer irgendwie beeindruckend, insbesondere wenn man bedenkt dass du
> schon seit mehreren Jahren an ARMs sitzt und Code schreibst, bei dem es
> auf jedes Detail ankommt.

Naja, der Zeitraum stimmt. Allerdings mit extremen zeitlichen Lücken 
dazwischen. So war das erste Mal, als ich mich mit der Thematik 
auseinander gesetzt habe vor einer Renovierung eines alten Häuschens. 
Danach hättest Du mich nur noch zum Thema Brecheisen etc. befragen 
können :-) Ich bin so einer, der relativ schnell Dinge vergisst, die er 
nicht ständig anwendet. Ist halt so. Und ehrlich gesagt, glaube ich, 
dass es da anderen auch nicht unbedingt besser geht. Ich denke, wenn ich 
mit dem Zeug mein Geld verdienen würde, dann würde der Code auch anders 
aussehen. Ich hab jetzt eigentlich nur noch die Brach-Befehle zu machen. 
Wenn das dann alles fertig ist, werde ich mal so einen 6502 
Emulator-Testcode laufen lassen und schauen, was passiert.

Und noch zum Thema Lernresistenz: Bin gerade dabei mir das Buch "Der 
leichte Einstieg in die Elektronik" durchzulesen. Das passiert bei mir 
immer auf dem Weg zur Arbeit. Also unterm Strich. Es ist einfach ein 
sehr weites Thema alles zusammen. Und ich habe nicht den Anspruch, alles 
auf Anhieb perfekt zu machen. Deswegen wende ich mich auch oft hier ins 
Forum. Zugegeben, dass es manchmal so aussieht wie "lass die mal 
machen". Mich interessieren halt oft auch die Meinungen von den Profis.

Viele Grüße,
Peter
#2038462
Lesenswert?

Peter Pippinger schrieb:

> > Und noch zum Thema Lernresistenz: Bin gerade dabei mir das Buch "Der
> > leichte Einstieg in die Elektronik" durchzulesen.

Das hilft dir allerdings nicht wirklich bei der Frage weiter, wann 
welcher ARM-Befehl welche Flags beeinflusst. Dafür brauchts auch keinen 
Profi (der ich übrigens nicht bin), sondern das passende Handbuch. Das 
ARM Architecture Reference Manual. Das du dafür auch nicht von vorne bis 
hinten durchblättern musst, das hat nämlich ein Inhaltsverzechnis.
OP #2038463
Lesenswert?

ahh, ok, wenn das so ist, dann habe ich da was falsch gemacht. Ich 
dachte, dass das rausgerutschte Bit ins Carry wandert, und danach gleich 
an Bit7 des eigentlichen Wertes "wandert". Das schaue ich mir mal im 
6502-Assembler an.

Ich habs frei nach
{adr}:={adr}/+C*128
aufgebaut.

Das habe ich dann wohl falsch interpretiert bzw. nicht richtig 
verstanden.

Danke für den Hinweis.

So wie es aussieht, wird der Testcode eh noch so manches ans Licht 
führen :-)
#2038467
Lesenswert?

Peter Pippinger schrieb:

> > orrnes r6, r6, #3 << 31  // also set carry

Jau, stimmt, dass Carry wird hier gesetzt. Dummerweise aber auch Bit 31,
was meiner Erinnerung nach nicht ganz zum ROR Befehl der 6502 passt, der 
ja nicht 8 sondern 9 Bits rotiert. Der LSR #1 davor passt dazu auch 
nicht, das sollte wohl eher RRX sein.

Mir scheint es wird ein Schuh draus, wenn dein ORRNES sein Ergebnis in 
die Wüste schickt. C wird gesetzt, NZ ebenfalls, und R6 ist dank RRX 
bereits vorher schon korrekt.
#2038474
Lesenswert?

Peter Pippinger schrieb:
> habs ausprobiert:
> orrnes r6, r6, #3 << 31  // also set carry
>
> hab extra die 3 genommen (Bit0+1). Bit1 "rutscht" automatisch ins Carry.

Meine ARM-Zeiten liegen schon etwas zurück, aber das kann nicht stimmen.

#3<<31 ist einfach eine Konstante, die auch so nicht (als ein Befehl) 
kodiert werden kann.
Für den "immediate"-Teil gibt es nur 12 Bit, 8 Bit für den Wert und 4 
Bit für die Shift-Position (*2) des 8-Bit-Wertes.

#3<<31 wäre binär also (als Konstante im Assembler)

1 10000000 00000000 00000000 00000000

und wenn der Assembler da keinen Fehler meldet, dann sollte er das 
rausgefallene Bit einfach abschneiden (und 1<<31 als Konstante 
verwenden).

Oder irre ich mich da?
#2038490
Lesenswert?

A. K. schrieb:

> Mir scheint es wird ein Schuh draus, wenn dein ORRNES sein Ergebnis in
> die Wüste schickt.

Nö, weil N trotzdem falsch. Es wäre eine Operation nötig, die NZ 
entsprechend R6 setzt und gleichzeitig C auf 1 setzt, ohne was an den 
Daten zu verändern.

In meine Variante oben ist der Kommentar falsch, besser:
  tst  r6, r6   // get NZ state, CV unaffected
OP #2038554
Lesenswert?

A. K. schrieb:
> Peter Pippinger schrieb:
>
>>   strb r6, [r5]            // store value
>
> Was soll das eigentlich werden?

Das wird mit allen Befehlen gemacht, die nicht implizit waren, also den 
Speicher verändern. Damit wird der Wert (r6={pc}), den meine 
entsprechende Adressierungsart an die Adresse (r5=pc) zurückgeschrieben, 
wo der Wert herkam...

Also z.B.:
1
...
2
ROR__zp:
3
  mov r4, #5         // at least 5 clock-cycles
4
  mem_zp
5
  opc_ROR
6
  b drive_cpu
7
...
8
mem_zp macro                    
9
  ldrb r5, [r8], #1  // get address for $xx
10
  ldrb r6, [r5]      // get value from $xx into r6
11
  endm
12
...

PS.: die Extracyclecounts bei boundary-crossed / Branchtaken sind noch 
nicht berücksichtigt, werden aber auch noch kommen...
OP #2038582
Lesenswert?

hmm, weiß nicht. Werde ich mal anschauen...

Aber nochmal wegen strb: es würde mich sehr wundern, wenn das bei meinen 
Tests nicht aufgefallen wäre, da ich die Adressierungsarten eigentlich 
auch schon getestet habe (bin mir zumindest sicher, dass ich DEC und INC 
mit allen Adressierungsarten angesehen habe). Kann es sein, dass es 
funktioniert, wenn die Bytereihenfolge (Byteorder, oder wie man das 
nennt?) entspechend richtig eingestellt ist?
OP #2038640
Lesenswert?

Ok, habs mir nochmal angesehen:
1
opc_DEC macro 
2
  mov r6, r6, lsl #24    // shift value to last 8 bits
3
  subs r6, r6, #1 << 24  // {adress} = {adress} - 1
4
  mov r6, r6, lsr #24    // shift value to first 8 bits
5
  strb r6, [r5]   
6
  mrs r9, cpsr
7
  endm

Da ist wohl wirklich noch nicht die gewünschte Konsistenz erreicht :-) 
Werd ich noch anpassen... Macht wahrscheinlich Sinn, das gleich beim 
Laden des Wertes zu machen bzw. beim Speichern (evtl. zusätzliches 
Makro)...

Aber Danke nochmal für den Hinweis!

Gruß
Peter
OP #2038738
Lesenswert?

hmm, auch hier hast Du Recht. ( Wobei ich schon zu meiner Verteidigung 
sagen muss, dass ich durchaus nach einer Vorlage arbeite: 
http://www.oxyron.de/html/opcodes02.html ). Evtl. ist der 
Produktivitätsfaktor in der Nacht nicht so hoch :-)

Würdest Du dann sagen, dass es überhaupt Sinn macht, die Status-Flags 
vom ARM zu nehmen? Hmm vielleicht ist das wirklich zu viel der 
Optimierung zu Beginn. Ich denke mal, ich werde die Flag-Geschichten 
auch über Makros abbilden, dass ich das dann zentral ändern kann...

Wie hättest Du denn den DEC-Befehl umgesetzt?
würdest Du dann den SUB(S) ohne (S) machen und entsprechend Bit7 testen 
und N-Flag setzen, und dann noch nach Zero testen und entsprechend das 
Z-Flag setzen?

Was hältst Du davon, nur die betroffenen Bits von cpsr nach r9 zu 
"kopieren". Dann könnte ich doch weiterhin mit dem SUBS arbeiten.
#2038856
Lesenswert?

Peter Pippinger schrieb:

> Würdest Du dann sagen, dass es überhaupt Sinn macht, die Status-Flags
> vom ARM zu nehmen?

Kann man durchaus so machen wie du. Aber natürlich nur bei NVZC und bei 
6502-Befehlen mit passender Arbeitsweise. Bei BIT passt das weniger gut.

> Wie hättest Du denn den DEC-Befehl umgesetzt?

Trivial: NZ lässt sich aus dem Ergebnis testen ohne CV zu stören, wie 
ich es oben in meiner Version verwendete. Gibt halt einen Befehl mehr.
Gast #2040952
Lesenswert?

A. K. schrieb:
> Kann der IAR Assembler den Registern eigene Namen geben? Wäre hier
> sicherlich nützlich.

Hallo, nachdem jetzt endlich der Jungelkönig feststeht, habe ich mal 
Zeit gefunden in der IAR-Anleitung nachzulesen (man lese und staune!). 
Da konnte ich auf Anhieb nichts finden. Google hingegen hat mir dann ein 
Ergebnis gebracht, welches ich hier der Vollständigkeit halber aufzeigen 
möchte:

// register A
#define REG_A r10
  ldr REG_A, =0x01 << 31;

Läd dann in r10 den gewünschten Wert.

@A.K. ist ein prima Tip gewesen, den ich gleich mit in den Code 
reinbauen werde.

Um nochmal auf das Threadthema zu kommen. Ich habe eben gelesen, dass 
die Bits 8-27 im CPSR "unused" wären. Kann ich die dann auch setzen?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren