ADC vom MOS 6502 Prozessor verstehen

CPU

Lieutenant
Registriert
Jan. 2006
Beiträge
704
Hallo,

ich versuche gerade - wie es der Titel recht gut ausdrückt - die Instruktion "ADC - Add with carry", also Addition mit Übertrag, zu verstehen. Als Referenz habe ich diese hübsche Seite mit Erklärung zu grunde liegen. Dennoch zweifle ich, ob das richtig ist, was ich mir "gebastelt" habe. Unten mein kurzer Beispielcode (in C, nach dem Kompilieren sofort lauffähig).

Rein logisch finde ich das alles sonnenklar und auch richtig. Um jetzt selber zu prüfen, ob das richtig ist habe ich mal Ergebnisse mit der "ADC"-Funktion dieses Simulators hier verglichen. Nicht nur, dass ich den Quelltext (am Ende) wirr finde, meine Ergebnisse passen auch nicht zu denen des fremden Codes.

Z.B. für die Eingaben a=21, m=20 und p=1 errechnet meine Funktion a=42 (passt) und p=1 (passt auch, da kein Übertrag stattfindet). Die fremde Funktion sagt aber, dass p=64 ist - kein Übertrag, aber Überlauf. Und das passt doch überhaupt nicht.

Und da dachte ich, dass es doch hier im Forum bestimmt ein paar Experten gibt, die mal kurz über meinen Code schauen könnten. Wäre das möglich?

Weihnachtliche Grüße,
CPU

Mein Code:
Anhang anzeigen my.txt

Hier der fremde Code von hier:
Anhang anzeigen other.txt
 
Zuletzt bearbeitet: (Codesegmente angehangen um Platz zu sparen)
Also ADC (Add with Carry) ist beim 6502 einfach Akku + Wert + Carry, beim Überlauf der Addition sollte dann Carry wieder gesetzt sein.

Also ist auch 21 + 20 + Carry Set = 42.
Ich habe jetzt keine der beiden Funktionen Kompiliert, aber auch testADC sollte das richtige machen
(da regP nicht Bit 4 gesetzt hat (Dezimal) und dann regA = tmp (= regA + value + (regP&1)) & 0xff)?

Kanne es sein, dass die zweite funktion im BCD Modus läuft dann, wären (0x21 + 0x20) & 0xfe = 64 ??
 
Hallo,

goldmomo schrieb:
Also ADC (Add with Carry) ist beim 6502 einfach Akku + Wert + Carry, beim Überlauf der Addition sollte dann Carry wieder gesetzt sein.
das habe ich ja gemacht: "unsigned int tmp = a + M + (p & 0x01);".

goldmomo schrieb:
Also ist auch 21 + 20 + Carry Set = 42.
Das habe ich ja nie bezweifelt. Allerdings sagt die fremde Funktion, dass hier ein Überfluss statt findet und setzt im Statusregister das 7. Bit (= 64). Und das ist in meinen Augen falsch, da hier kein Übertrag stattfindet.

goldmomo schrieb:
Ich habe jetzt keine der beiden Funktionen Kompiliert, aber auch testADC sollte das richtige machen
(da regP nicht Bit 4 gesetzt hat (Dezimal) und dann regA = tmp (= regA + value + (regP&1)) & 0xff)?

Den Unterschied macht diese if-Anweisung zu Beginn der Funktion des fremden Codes aus:

Code:
  if( (regA ^ value) & 0x80 ) {
    regP &= 0xbf;
  } else {
    regP |= 0x40;
  }

Hier soll das Overflow-Bit gesetzt (0x40) oder gecleared (0xbf) werden. Dazu wird das MSB der beiden Operanden verglichen. Da in meinem Beispiel gilt:

Code:
21 = 0001'0101
20 = 0001'0100
XOR ------------
     0...

wird das Overflow-Bit gesetzt. Aber das ist doch kein hinreichendes Kriterium für einen Overflow, oder? Braucht man das nicht vielmehr für das Vorzeichen?

goldmomo schrieb:
Kanne es sein, dass die zweite funktion im BCD Modus läuft dann, wären (0x21 + 0x20) & 0xfe = 64 ??
Ich verstehe leider diesen Satz nicht :(

Gruß,
CPU
 
Habs mir nochmal angeschaut, eigentlich ist das erkennen (in der zweiten Funktion) der Overflow flags falsch.

Overflow sollte doch nur kommen wenn bei der Addition (jetzt als Signed gesehen) ein Überlauf passiert.

Also + (+) + = - oder – (+) - = +, also wenn beide MSBs (vor und nach der Addition) unterschiedlich sind.



Habs jetzt mal in einen Emulator versucht (http://skilldrick.github.io/easy6502/):

Code:
lda #20
clc
adc #21

;V = 0

lda #1
clc
adc #127

;V = 1

Also ist deine Funktion richtig und die andere falsch, oder ich verstehe es nicht :freak:
 
Zuletzt bearbeitet:
Hallo,

goldmomo schrieb:
Also ist deine Funktion richtig und die andere falsch, oder ich verstehe es nicht :freak:

genau, so fühle ich mich :freak:

Mal ernsthaft: ich glaube - ohne irgendwie eingebildet rüber kommen zu wollen -, dass die Funktion falsch ist. Denn: ich habe ein kleines Assembler-Programm mal im Visual6502 ausprobiert und bekomme meine Ergebnisse bestätigt.

Assembler-Programm:
Code:
09 00  LDA 0
48     PHA
28     PLP
38     SEC
a9 15  LDA 21
69 14  ADC 20 
ea     NOP

mit dem Ergebnis:
Code:
143	000a	ea	1	NOP	000a	2a	00	00	fa	nv‑Bdizc	NOP	T1
141	0009	ea	1	NOP	0009	15	00	00	fa	nv‑BdizC	ADC #	T1
139	0007	69	1	ADC #	0007	15	00	00	fa	nv‑BdizC	LDA #	T1
137	0005	a9	1	LDA #	0005	00	00	00	fa	nv‑BdizC	SEC	T1
135	0004	38	1	SEC	0004	00	00	00	fa	nv‑Bdizc	PLP	T1
131	0003	28	1	PLP	0003	00	00	00	f9	nv‑BdiZC	PHA	T1
130	01fa	00	0		0003	00	00	00	fa	nv‑BdiZC	PHA	T0
128	0002	48	1	PHA	0002	00	00	00	fa	nv‑BdiZC	LDA #	T1
(von unten nach oben zu lesen)

In der obersten Zeile steht das Ergebnis: 0x2a - also 42 - und die Status-Flags "nv-Bdizc" - außer Break-Flag (ist zu ignorieren) keines gesetzt. Damit ist doch eigentlich schon beweisen, dass etwas an der fremden Funktion nicht stimmt, oder?

Gruß,
CPU
 
Habe jetzt in den T65 Core (VHDL 6502 Reimplemetation) reingeschaut, da wird nach der Addition ADC_V so gesetzt.

AH = oberes nibble von Addition-Result
BusA = Akku vor Addition
BusB = Wert

Code:
ADC_V <= (AH(4) xor BusA(7)) and not (BusA(7) xor BusB(7));

Mal in mit anderen Variablennamen:

A = Wert 1 (Akku davor)
B = Wert 2 (Wert für ADD)
C = A+B+Carry

Laut Software google (the-6502-overflow-flag-explained):

Code:
V = A xor C and B xor C

Bei T65 Core:

Code:
V = C xor A and not (A xor B)

Beide Funktionen sind vom Ergebnis (DNF) her gleich!

Also ist deine Funktion auch nicht ok, da nur akku xor Result?
 
Zuletzt bearbeitet:
goldmomo schrieb:
Also ist deine Funktion auch nicht ok, da nur akku xor Result?

Upps, da habe ich vor lauter verschiedener Implementierungen wohl etwas vergessen. Es müsste natürlich in Zeile 12 (da wo die Bedingung für das Overflow-Flag steht) lauten:

Code:
if (((tmp1 ^ a) & 0x80) && !((a ^ tmp0) & 0x80)) {
 ...
} else {
 ...
}

Aber jetzt müsste doch auch alles stimmen, oder?

@goldmomo: Vielen Dank für Deinen Einsatz!

Gruß,
CPU
 
Ja, so sollte es passen.
Der 6502 war nach langer Zeit mal wieder ein interessantes Thema, besonders da ich das oVerflow Flag bis Heute auch nicht verstanden hatte (habe es auch nie auf den 6502 gebraucht).

P.s.:

Im Anhang mal von meinen System der ADD/SUB (mit Carry/Borrow in/out), jetzt auch mit Overflow :freaky:
Ist zwar 16Bit, aber man sieht schön wie Overflow generiert wird.

ADDSUB.png
 
Zuletzt bearbeitet:
Zurück
Oben