9. Πράξεις με μη προσημασμένους αριθμούς

Πρόσθεση μη προσημασμένων αριθμών

Για την πρόσθεση δυο 8-bit αριθμών, χρησιμοποιούμε την εντολή ADD, που έχει σαν όρισμα δυο γενικού σκοπού καταχωρητών GPRs, στους οποίους έχουμε από πριν φορτώσει τις τιμές που θέλουμε να προσθέσουμε

ADD Rd, Rr  ;  Rd = Rd + Rr

Η εντολή προσθέτει τα περιεχόμενα του καταχωρητή Rr σε εκείνα του καταχωρητή Rd. Αυτή η εντολή μπορεί να αλλάξει τις σημαίες Z, C, N, V, H ή S του καταχωρητή κατάστασης ανάλογα με την περίπτωση.

Στους AVR δεν υπάρχει εντολή πρόσθεσης που να προσθέτει άμεσα τιμές της μνήμης SRAM σε άλλες θέσεις μνήμης ή σε καταχωρητές. Για να προσθέσουμε την τιμή μιας θέσης μνήμης SRAM θα πρέπει πρώτα να την έχουμε φορτώσει σε ένα καταχωρητή από τους R0 έως R31 με την εντολή LDS και μετά να χρησιμοποιήσουμε την εντολή ADD σε αυτούς τους καταχωρητές.

Παράδειγμα

LDI  R21, 0xF5   ;  R21 = 0xF5
LDI  R22, 0x0B   ;  R22 = 0x0B
ADD R21, R22     ; R21 = R21 + R22 = F5 + 0B = 00 και C = 1
  
 F5                  1111 0101
+0B               +  0000 1011
------             ----------------
100                  0000 0000

Μετά την πρόσθεση ο καταχωρητής R21 περιέχει την τιμή 00 και οι σημαίες είναι οι εξής:
C = 1  διότι έχουμε κρατούμενο πέρα του ψηφίου D7.
Z = 1  διότι η τιμή του καταχωρητή προορισμού (R21) έχει την τιμή μηδέν.
Η = 1  διότι έχουμε κρατούμενο από το ψηφίο D3 στο D4

Παράδειγμα

Υποθέστε ότι στην διεύθυνση 0x300 της μνήμης δεδομένων υπάρχει η τιμή 0x45. Γράψτε ένα πρόγραμμα που να βρίσκει το άθροισμα της τιμής που περιέχει η SRAM στη θέση 0x300 και της τιμής 0x10. Λύση:

LDS R5,  0x300      ;  R5 = 0x45
LDI R16, 0x10       ;  R6 = 0x10
ADD R16, R5         ;  R16 = R16 + R5 = 0x10 + 0x45 = 0x55 , C = 0

Η εντολή ADC στην πρόσθεση 16-bit αριθμών

Όταν προσθέτουμε 16-bit τιμές πρέπει να λάβουμε υπόψη την διάδοση κρατουμένου από το χαμηλότερο byte στο υψηλότερο byte. Η εντολή ADC (ADD με κρατούμενο) χρησιμοποιείται σε αυτές τις περιπτώσεις.

Παράδειγμα

Θέλουμε να υπολογίσουμε το άθροισμα 3CE7 + 3B8D. Με το χέρι μπορούμε να το βρούμε ως εξής:

Όταν προσθέτουμε το πρώτο byte, υπάρχει κρατούμενο (E7 + 8D = 74 , C = 1). Το κρατούμενο διαδίνεται στο υψηλότερο byte με το αποτέλεσμα 3C + 3B + 1 = 78). Ο κώδικας που υλοποιεί το παράδειγμα είναι ο ακόλουθος:

LDI R1, 8D
LDI R2, 3B
LDI R3, E7
LDI R4, 3C
ADD R3, R1   ;   R3 = R3 + R1 = E7 + 80 = 74 και C = 1
ADC R4, R2   ;   R4 = R4 + R2 + C = 3C + 3B + 1 = 78

Αφαίρεση μη προσημασμένων αριθμών

Στους μικροελεγκτές AVR υπάρχουν πέντε εντολές για την πράξη της αφαίρεσης αριθμητικών τιμών. Αυτές είναι οι SUB, SBC, SUBI, SBCI και SBIW, που ορίζονται ως εξής:

SUB  Rd, Rr        ;   Rd = Rd – Rr
SBC Rd, Rr         ;   Rd = Rd – Rr – C
SUBI  Rd, K        ;   Rd = Rd – K
SBCI  Rd, K        ;   Rd = Rd –K – C
SBIW  Rd:Rd+1, K   ;   Rd+1:Rd = Rd+1:Rd – K

Για την αφαίρεση οι AVR χρησιμοποιούν τα κυκλώματα της πρόσθεσης για να έχουμε μικρότερο κόστος με την μείωση πολλών τρανζίστορ που θα χρειαζόμασταν για την ανάπτυξη κυκλωμάτων αφαίρεσης. Στους AVR η πράξη της αφαίρεσης γίνεται σε επίπεδο υλικού με τον παρακάτω τρόπο:
1] Υπολογισμός του συμπληρώματος ως προς δυο του αφαιρετέου.
2] Πρόσθεση του στο μειωτέο.
3] Αντιστροφή του κρατουμένου

Παράδειγμα

Περιγράψτε από την μεριά του μικροελεγκτή την αφαίρεση 0x3F – 0x23

LDI  R20, 0x23   ;  φόρτωσε την τιμή 0x23 στον R20
LDI  R21,  0x3F  ;   φόρτωσε την τιμή 0x3F στον R21
SUB R21, R20    ;   R21 = R21 – R20

 R21 = 3F      0011 1111                0011 1111
-R20 = 23      00100011            +    1101 1101 (συμπλήρωμα ως προς 2)
      ----                         --------------------
       1C                          1    0001 1100
                         C=0, D7=N=0  (το αποτέλεσμα είναι θετικός αριθμός)

Οι σημαίες του καταχωρητή κατάστασης είναι Ν = 0, C = 0. Ο προγραμματιστής θα πρέπει να εξετάζει την σημαία Ν (ή την C) για να δει αν το αποτέλεσμα είναι θετικός ή αρνητικός αριθμός.

Αυτά τα βήματα που αναφέραμε εκτελούνται για κάθε εντολή αφαίρεσης SUB από τα εσωτερικά κυκλώματα της CPU ανεξάρτητα από τα ορίσματα της εντολής. Με αυτά τα βήματα έχουμε το αποτέλεσμα και τίθενται κατάλληλα οι σημαίες στον καταχωρητή κατάστασης.

Μετά την εκτέλεση της εντολής SUB εάν Ν=0 ή C=0 το αποτέλεσμα είναι θετικό και εάν Ν=1 (ή C=1) το αποτέλεσμα είναι αρνητικό και ο καταχωρητής προορισμού έχει το συμπλήρωμα ως προς δυο της τιμής διαφοράς. Κανονικά το αποτέλεσμα αφήνεται στο συμπλήρωμα ως προς δυο και μπορούμε να χρησιμοποιήσουμε την εντολή NEG (δίνει το συμπλήρωμα ως προς δυο) για να πάρουμε τον καθαρό αριθμό.

Οι άλλες εντολές αφαίρεσης είναι SUBI, SBCI και SBIW με τις οποίες αφαιρούμε μια σταθερή τιμή από ένα καταχωρητή GPR. Με την εντολή SBIW αφαιρούμε μια σταθερή τιμή μέσα στο διάστημα 0-63 από ένα ζεύγος καταχωρητών και αποθηκεύει το αποτέλεσμα στο ζεύγος καταχωρητών. Σημείωση: μόνο οι τελευταίοι οκτώ καταχωρητές μπορούν να χρησιμοποιηθούν με την εντολή SBIW.

Παράδειγμα

Γράψτε ένα πρόγραμμα που να αφαιρεί την τιμή 0x18 από την 0x29 και να αποθηκεύει το αποτέλεσμα στο R21, με δυο τρόπους (1) χωρίς τη χρήση της εντολής SUBI και (2) με τη χρήση της εντολής SUBI

1]   LDI R21, 0x29    ;    R21 = 0x29
     LDI R22, 0x18    ;    R22 = 0x18
     SUB R21, R22     ;   R21 = R21 – R22 = 0x29 – 0x18 = 0x11
2]   LDI  R21, 0x29   ;   R21 = 0x29
     SUBI  R21, 0x18  ;   R21 = R21 – 0x18 = 0x29 – 0x18 = 0x11

Παράδειγμα

Γράψε ένα πρόγραμμα που να αφαιρεί την τιμή 0x10 από την τιμή 0x2917 και να αποθηκεύσει το αποτέλεσμα στους R25 και R24

LDI  R25, 0x29
LDI R24, 0x17
SBIW R25:R24, 0x18

SBC (Rd ← Rd – Rr – C) αφαίρεση με δανικό

Αυτή η εντολή χρησιμοποιείται για την αφαίρεση αριθμών σε μέγεθος μεγαλύτερο από 8bit. Εάν η σημαία δανικού είναι 1 (C = 1) πριν εκτελεστεί η εντολή SBC αυτή η εντολή αφαιρεί 1 από το αποτέλεσμα.

Παράδειγμα

Γράψτε ένα πρόγραμμα που να αφαιρεί δυο 16bit αριθμούς: 0x2762 και 0x1296. Υποθέστε R26 = (62) και R27 = (27). Τοποθετήστε τη διαφορά στους R26 και R27. O R26 θα πρέπει να έχει το χαμηλότερο byte.

; R27 = (27),  R26 = (62)
; R29 = (12),  R28 = (96)
LDI R27, 27
LDI R26, 62
LDI R29, 12
LDI R28, 96
SUB R26, R28    ; R26 = R26 – R28 = 62 -96 = 0xCC
                ; C = borrow = 1,  N=1
SBC  R27, R29   ; R27 = 27 – 12 – 1 = 0x14

Μετά την εντολή SUB ο R26 έχει την διαφορά 0x62 – 0x96 = 0xCC και η σημαία κρατουμένου τίθεται σε 1 το οποίο σημαίνει ότι έχουμε κρατούμενο (σημειώστε Ν=1). Επειδή C=1 όταν η εντολή SBC εκτελείται ο R27 έχει την τιμή 0x27 – 0x12 – 1 = 0x14. Επομένως 0x2762 – 0x1296 = 0x14CC

Η σημαία C στην αφαίρεση με τους AVR

Στους AVR μετά την εκτέλεση της εντολής της αφαίρεσης, που όπως είπαμε γίνεται με την προσθήκη του συμπληρώματος ως προς 2 του αφαιρετέου στον μειωτέο, το κρατούμενο αντιστρέφεται από την CPU και εξετάζουμε τη σημαία C για να δούμε αν το αποτέλεσμα είναι θετικός ή αρνητικός αριθμός. Αυτό σημαίνει ότι μετά την πράξη της αφαίρεσης εάν C=1 το αποτέλεσμα είναι αρνητικός αριθμός και εάν C=0 το αποτέλεσμα είναι θετικός αριθμός.

Πολλαπλασιασμός μη προσημασμένων αριθμών

Στους μικροελεγκτές AVR υπάρχουν συγκεκριμένες εντολές που κάνουν πολλαπλασιασμό αριθμών. Σε αυτή την ενότητα θα εξετάσουμε την εντολή πολλαπλασιασμού MUL. Οι υπόλοιπες εντολές που κάνουμε πολλαπλασιασμό τις παρουσιάζουμε παρακάτω, οι οποίες χρησιμοποιούνται για πολλαπλασιασμό προσημασμένων αριθμών.

Η εντολή MUL είναι μια byte προς byte εντολή πολλαπλασιασμού στην οποία τα ορίσματα πρέπει να είναι καταχωρητές GPRs. Μετά την εκτέλεση του πολλαπλασιασμού το γινόμενο τοποθετείται στους καταχωρητές R1(υψηλότερο byte) και R0(χαμηλότερο byte). Σημείωση: τα προηγούμενα περιεχόμενα των καταχωρητών R1 και R0 αντικαθίστανται από το γινόμενο των τιμών του πολλαπλασιασμού.

Παράδειγμα

LDI  R23, 0x25  ;  φόρτωσε το 0x25 στον R20
LDI  R24, 0x65  ;   φόρτωσε το 0x65 στον R24
MUL R23, R24    ;  0x25 * 0x65 = 0xE99
                ;  όπου  R1 = 0x0E  και R0 = 0x99

Διαίρεση μη προσημασμένων αριθμών

Οι AVR δεν έχουν καμία εντολή για διαίρεση αριθμών. Αντί αυτού μπορούμε να γράψουμε κώδικα για την εκτέλεση της διαίρεσης με την μέθοδο της επαναλαμβανόμενης αφαίρεσης. Για την διαίρεση byte προς byte, ο αριθμός τοποθετείται σε ένα καταχωρητή και ο διαιρέτης αφαιρείται από αυτόν επαναλαμβανόμενα. Το πηλίκο είναι ο αριθμός ίσος με εκείνο του αριθμού των φορών που έγινε η αφαίρεση και το υπόλοιπο είναι ο αριθμός που υπάρχει στον καταχωρητή στο τέλος της διαδικασίας. Δείτε το ακόλουθο απόσπασμα κώδικα:

.DEF  DIERETEOS = R20
.DEF DIERETIS = R21
.DEF PILIKO = R22
LDI  DIERETEOS, 82    ;  Διαιρετέος = 82
LDI  DIERETIS, 10     ;   Διαιρέτης = 10
CLR  PILIKO           ;   Πηλίκο = 0

L1:  INC PILIKO
     SUB  DIERETEOS, DIERETIS
     BRCC L1    ;  Διακλάδωση εάν C είναι μηδέν

DEC  PILIKO
ADD  DIERETEOS, DIERETIS

HERE: JMP  HERE  ;  Μείνε εδώ συνεχώς