René schrieb:
> -Warum wird im obigen Beispiel einmal subi und einmal sbci verwendet?
Weil's eben die Umsetzung von 16Bit Arithmetik auf einer 8Bit Maschine
ist.
Da muss man Überträge machen (das passiert bei allen Additions- und
Subtraktionsbefehlen automatisch) und die in der höherwertigen Stelle
dann auch berücksichtigen. Das passiert allerdings nicht automatisch,
sondern nur dann, wenn man eben genau die Operation verwendet, die das
tut. Also sbci statt subi.
> -Wie würde der Code aussehen, wenn ich zwei 8 bit Register als 16 bit
> Register verwenden möchte und dort +1 rechnen möchte? "inc r16" wird
> wohl nicht gehen.
Doch, geht zur Not auch. Nur leider setzt die inc-Operation das
Übertragsflag eben gerade nicht. Bei inc noch nicht wirklich schlimm,
denn man kann hier auf's Zeroflag ausweichen, denn ein Übertrag ist
genau dann erforderlich, wenn das Ergebnis für die Stelle 0 ist. Nur
leider gibt es keine Operation, die so einen "Übertrag im Zeroflag"
mitaddieren könnte. Man muss sich also mit einer zusätzlichen
Verzweigung behelfen. Also etwa sowas bauen:
inc R16
brne PC+2
inc R17
Damit kostet die 16Bit-Operation allerdings drei Takte statt der
üblichen zwei. Der Vorteil ist allerdings: dieses Konstrukt funktioniert
mit allen Registern.
Wenn es nur mit R16..R31 funktionieren muss, dann wird man eher das
verwenden:
subi R16,Low(-1)
sbci R17,High(-1)
Das braucht nämlich nur zwei Takte. Der Trick ist hier, dass statt 1 zu
addieren -1 subtrahiert wird. Das Ergebnis ist das gleiche, allerdings
wird das Carryflag nicht so beeinflußt, wie man es von einer Addition
erwartet, sondern "umgekehrt". Das ist aber kein Problem, wenn es
entweder keine weiteren Stellen gibt oder für die weiteren Stellen
einfach nach der gleichen Methode weiter gerechnet wird. Beispiel für
inc(32Bit-Wert):
subi R16,Byte1(-1)
sbci R17,Byte2(-1)
sbci R18,Byte3(-1)
sbci R19,Byte4(-1)
Und letztlich kann man für die Registerpaare R25:R24..R31:R30 auch noch
adiw verwenden, wie im Thread schon gesagt wurde. Diese Operation hat
allerdings gegenüber der vorigen Methode nur zwei marginale Vorteile:
sie setzt das Carryflag, wie man es von einer Addition erwartet und sie
braucht zwei Bytes weniger Flash. Bezüglich der Rechengeschwindigkeit
ist sie hingegen leider nicht schneller als die subi/sbci-Methode. Und
dazu kommt noch, dass auch ihr Wertebereich stark eingeschränkt ist, das
geht nämlich nur mit Operanden im Bereich von 0..63.
All das und auch viele weitere Details findest du in der "Instruction
set reference". Sozusagen die Bibel für Assemblerprogrammierer. Lesen
und verstehen musst du sie selber.