Addition mit und ohne Carry; Subtraktion ebenso ("Programmieren" lernen)

  • Auch wenn es trivial klingt: Es ist mit einem Rechenregister natürlich möglich auch zu rechnen.


    Wobei bisher ja zu sehen war, daß das evtl. auch gar nicht nötig wäre, immerhin kann man sowas auch "per Hand" auf einfaches "Zahlrädchen" weiter-/zurückdrehen, also auf die Elementaroperation (z.B. INX/DEX), reduzieren. Es muß nur dann oft genug wiederholt werden.


    Angenehmer ist aber eine Addition per Befehl. Die meisten CPUs können soetwas.

    Schwieriger wird es dann, wenn man das weiterdenkt, und die Addition als Elementaroperation ansieht; eine Multiplikation als Befehl fehlt durchaus gelegentlich im Befehlssatz.


    Der Befehl fürs Addieren sagt oft lediglich, was womit zusammengezählt wird. Dabei ist zu beachten, ob noch automatisch andere Werte mit dazu gezählt werden (beim 6502 etwa das Carry-Flag).


    Ansonsten gilt: dieser Befehl beeinflußt i.a. zumindest das Negativ-Flag, das Carry-Flag, das Überlauf-Flag, das Zero-Flag.

    Man kann also nach einer Addition allerlei Verzweigungen mit bedingten Sprüngen, wie nach Vergleichsbefehlen, anschließen.


    Das wohl wichtigste ist das Carry-Flag. Wenn es während der Addition gesetzt wurde, bedeutet das, daß das Register den höchsten darstellbaren Zahlenwert durchlaufen und überschritten hat. Man erhält also wie bei schriftlicher Addition einen Übertrag in die nächsthöhere Stelle der Zahl.


    Nun kann man diesen natürlich schlecht mit dem aktuellen Register notieren, aber mit einem anderen Register oder in einer Speicherstelle ginge das schon.

    Je mehr man davon aneinanderreiht, desto höher ist die "damit insgesamt" darstellbare Zahl.


    Bei einem 8 Bit Rechner kann jede solche "Stelle" $FF Werte haben (also 256 dezimal).

    Dies verhält sich so wie mit den Werten 0 bis 9 (also 10) einer dezimalen "Stelle". Im Zehnersystem reiht man dann auch einfach mehrere davon hintereinander, um große Zahlen darzustellen, etwa die 100 (3 Stellen) oder 2000 (4 Stellen) oder 1000000 (7 Stellen).


    Die Gesamtmenge an so beschreibbaren Zahlen läßt sich dann natürlich auch ausrechnen: dabei wird einfach der "Zahlengehalt" einer einzigen Stelle so oft multipliziert, wie Stellen insgesamt verfügbar sind, für eine vierstellige Dezimalzahl also 10*10*10*10 = 10^4 ; man kann also mit 4 Dezimalstellen Werte von 0 ("0000") bis 9999 ("9999") darstellen.


    Mit zwei Stellen, die jede eine 8 Bit Zahl mit $FF (256) Werten sind, kann man demzufolge 256*256 = 256^2 Zahlen "abbilden".

    Das sind die Zahlenwerte von 0 bis 65535.

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

  • =6502=


    Die Besonderheit beim 6502 ist, daß er das Carry-Flag automatisch beim Addieren zum Ergebnis mit hinzuzählt.

    Darum heißt der Befehl auch Add-With-Carry: ADC


    Das geschieht natürlich nur wenn es gesetzt ist. Damit man nun für normale Additionen ein korrektes Ergebnis erhält, löscht man darum vorher explizit das Carry-Flag mit CLear-Carry: CLC



    Hier wird nun eine Reihe von Werten immer um $10 erhöht. Und vorher CLC ausgeführt.

    (Es ist ganz gut, sich anzugewöhnen, die Kombination CLC ADC als ein Kommando wahrzunehmen.)


    Da die Werte wieder aus dem Farbspeicher stammen (ab $0800), wird wohl etwas mit Farbe geschehen. Beim C16 sind die Farbwerte in 16er Schritten nach Helligkeiten abgelegt. Die $02 steht für tiefes Dunkelrot. Die $12 für etwas helleres Rot, die $22 für noch helleres usf., bis zur $72. Diese werden von dunkel nach hell durchgezählt.


    Andere Farben sind durch Ändern der hinteren Ziffer möglich ($03,$05 usf).

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

  • =6502=


    Trockenübung ...

    Es werden zwei Werte in $D0 und $D1 geschrieben (z.B. >00D0 00 00 ).

    Dabei steht $D0 für das mit der niedrigeren Wertigkeit, also die Stelle, die am weitesten rechts ist. $D1 ist die Stelle, auf die Überträge addiert werden. Bei jedem Start mit G5000 wird auf $D0 ein fixer Wert addiert - und wenn ein Übertrag auftreten sollte, kommt der nach $D1.



    Bitte mehrmals hintereinander G5000 und M D0 D1 ausführen.

    Bei Addition von $80 auf $D0 erfolgt in jeder zweiten Runde ein Übertrag auf $D1.


    Frage: Wo kommt der her ? - wo doch eigentlich mit ADC#$00 nur eine Null auf $D1 addiert wird (Zeile 500A).


    Bitte mit anderen Startwerten und Schrittweiten (z.B. #$40 in Zeile 5005) probieren !

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

  • =6502=


    Ein kleine "echte" Anwendung folgt nun noch. Wenn man sich die Buchstaben A-Z ansieht dann kann man sie in 2 Hälften teilen und anschließend die untere Hälfte nach oben verschieben und die obere in den unteren Bereich. Oder anders gesagt, man zählt von jedem Buchstaben 13 weiter im Alphabeth, hinterm "Z" geht es wieder von vorn beim "A" los.

    Es handelt sich dabei um eine einfache Verschlüsselungstechnik für geheime Nachrichten, die den Namen ROT13 (von Rotation) bekommen hat.


    Hier wird nun also für die ersten 13 Buchstaben (A-M) eine 13 addiert.

    Für die anderen Buchstaben (N-Z) würde die Rotation ja zunächst bis zum Z erfolgen und anschließend noch die jeweils bis zur 13 fehlenden Zeichen weitergezählt. Es ergibt sich also: ( Differenz Buchstabe - Z ) zzgl. dem Rest bis zur 13, d.h. ( 13 - Differenz ) oder einfacher: aus Z wird M und aus N wird A und daher kann man einfach bei (N-Z) 13 subtrahieren.



    Subtraktion hat beim 6502 ebenfalls die Eigenschaft, daß das Carry-Flag berücksichtigt wird. Es wird nämlich gelöscht, sobald eine größere Zahl von einer kleineren abgezogen wird und so ein "inverser Überlauf", d.h. ein "Unterlauf", auftritt, mithin wenn die $00 nach unten überschritten wird. Die Zahl muß man dann quasi als negative Zahl betrachten und genau das sagt das gelöschte Carry-Flag. Damit das klappt, muß es aber VORHER gesetzt werden, mit: SEC - Set Carry.


    Der Subtraktionsbefehl selbst heißt: SBC

    Man kann damit, wie bei ADC, sowohl Absolutwerte, als auch Werte aus dem RAM mit dem Akku verrechnen, wobei eigentlich (fast) alle Adressierungsarten erlaubt sind. (die Ausnahme ist: Zeropage Y-indiziert)

    Möglich sind: SBC #$aa, SBC $aaaa, SBC $aaaa,X , SBC $aaaa,Y , SBC $aa, SBC $aa,X , SBC ($aa,X), SBC ($aa),Y

    also wie beim ADC und beim LDA Befehl - so ziemlich ALLES WAS GEHT.



    Die Routine "rotiert" alle Buchstaben des Bildschirms. Dazu wird die bereits bekannte Variante verwendet, die jedes Zeichen im Bildschirmspeicher als Akkuinhalt an eine Subroutine schickt.

    (Wer das abgespeichert hat, lade sich das und tippe nur den Teil bei $5100 ein. Wer nicht, dem reicht vielleicht auch ein Teil davon, z.B. OHNE $500B - $502E. Und wer Spaß an der Sache hat, der möge sich schonmal überlegen, wie man diesen ersten Teil ($5000) vereinfacht/verkürzt. (Tip: Zeropage-indirekt Y-indizierte Adressierung.))




    Der Teil ab $5100 macht die eigentliche ROT13 Berechnung.


    Die Buchstaben kommen direkt aus dem Bildschirmspeicher und da hat das "A" den Wert $01, das "Z" ist $1A.

    Damit es "übersichtlicher" wird, wird mit BNE als erstes der Wert $00 abgewiesen (bei $00 erfolgt ein Rücksprung mit RTS). Anschließend wird die obere Grenze getestet - bei Werten über $1A ( >= $1B) erfolgt ebenfalls der Rücksprung.

    Dann wird der Akkuwert um 1 reduziert (-1), mittels einer Variante, die für kleine Zahlen durchaus eine Option zum richtigen Subtrahieren sein kann. Dann erfolgt die Abfrage, ob der Wert in der oberen oder unteren Buchstabenhälfte liegt und dementsprechend wird 13 abgezogen oder dazugezählt.

    Da man aber, um am Ende wieder bei den Buchstabencodierungen des Bildschirmspeichers anzukommen, die zuvor abgezogene 1 auch wieder aufschlagen muß, wird dieses gleich bei den Additions- bzw. Subtraktionsbefehlen mitberücksichtigt.


    Interessant sind m.E. die beiden Arten von Subtraktion nebeneinander und auch, daß man sieht, daß eine Subroutine über verschiedene RTS verlassen werden kann sowie der eigenartige Rücksprung auf das RTS (entgegen dem Lesefluß) im zweiten Vergleich.


    Frage: Warum wird oben lang erklärt, daß man VOR dem Subtrahieren gefälligst das Carry-Flag mit SEC zu setzen hat, und hier taucht dieser Befehl dann nirgendwo auf ?

    -- 1982 gab es keinen Raspberry Pi , aber Pi und Raspberries

    Einmal editiert, zuletzt von ThoralfAsmussen ()