Πολλές φορές θέλουμε να πάμε τη ροή της εκτέλεσης ενός προγράμματος Assembly σε άλλη εντολή. Αυτό μπορούμε να το κάνουμε με την υπό συνθήκη ή χωρίς συνθήκη διακλάδωση. Με την υπό συνθήκη διακλάδωση είναι οι εντολές: π.χ. BRNE ή BRSH ή με χωρίς συνθήκη είναι: οι JMP ή RJMP
Χρησιμοποιώντας την εντολή BRNE για την δημιουργία βρόγχων
Η εντολή BRNE (branch if not equal) χρησιμοποιεί σαν συνθήκη τη σημαία Z (zero) του καταχωρητή κατάστασης για να αποφασίσει αν η ροή θα διακλαδιστεί ή όχι: Η εντολή BRNE χρησιμοποιείται ως ακολούθως:
BACK: . . . . .
. . . . .
. . . . .
DEC Rn
BRNE BACK
Στις δυο τελευταίες εντολές ο καταχωρητής Rn (π.χ. R16 ή R17) μειώνεται κατά ένα και αν δεν πάρει την τιμή μηδέν η ροή του προγράμματος διακλαδίζεται πίσω στην διεύθυνση που αντιπροσωπεύει η ετικέτα BACK. Εάν ο Rn πάρει την τιμή μηδέν η ροή εκτέλεσης θα πάει στην από κάτω επόμενη εντολή.
Πριν την έναρξη του βρόγχου ο καταχωρητής Rn φορτώνεται με τον αριθμό επαναλήψεων του βρόγχου.
Σημειώστε ότι η εντολή BRNE αναφέρεται στη σημαία του καταχωρητή κατάστασης που διαμορφώνεται από την προηγούμενη εντολή DEC.
Παράδειγμα
Στο ακόλουθο πρόγραμμα ο καταχωρητής R16 χρησιμοποιείται σαν απαριθμητής. Αυτός ο απαριθμητής φορτώνεται στην αρχή με την τιμή 10. Σε κάθε επανάληψη η εντολή DEC μειώνει το περιεχόμενο του καταχωρητή R16 κατά ένα και θέτει τις σημαίες κατάλληλα. Εάν ο R16 δεν είναι μηδέν (Z=0) η ροή του προγράμματος πηγαίνει στην διεύθυνση που ορίζεται με την σημαία “AGAIN”. Ο βρόγχος συνεχίζεται μέχρι ο R16 γίνει μηδέν. Μετά που ο R16 πάρει την τιμή μηδεν (Ζ=1) η ροή μεταπηδά στην επόμενη εντολή έξω και ακριβώς κάτω από τον βρόγχο, που εδώ είναι η “OUT PORTB, R20”
Γράψε ένα πρόγραμμα το οποίο (α) να μηδενίζει τον R20 μετά (β) να προσθέτει τον αριθμό 3 στον R20 για δέκα φορές και (γ) να στέλνει το άθροισμα στην PORTB. Χρησιμοποίησε τη σημαία μηδενισμού και την εντολή BRNE:
; this program adds value 3 to the R20 ten times
LDI R16, 10 ; R16 = 10 (decimal) for counter
LDI R20, 0 ; R20 = 0
LDI R21, 3 ; R21 = 3
AGAIN: ADD R20, R21 ; add 03 to R20 (R20 = sum)
DEC R16 ; decrement until COUNT = 0
BRNE AGAIN ; repeat until COUNT = 0
OUT PORTB, R20 ; send sum to PORTB
Βρόγχος μέσα σε βρόγχο
Στο προηγούμενο παράδειγμα ο μέγιστος αριθμός επαναλήψεων είναι 255. Τι πρέπει να κάνουμε εάν θέλουμε να επαναλάβουμε ένα σύνολο εντολών περισσότερο από 255 φορές; Για να το κάνουμε αυτό χρησιμοποιούμε βρόγχο μέσα σε βρόγχο, όπου αυτή η διαδικασία ονομάζεται φωλιασμένος βρόγχος. Σε ένα φωλιασμένο βρόγχο χρησιμοποιούμε δυο καταχωρητές για την απαρίθμηση.
Παράδειγμα
Γράψτε ένα πρόγραμμα (α) που να φορτώνει τον καταχωρητή PORTB με την τιμή 0x55 και (β) να αναστρέφει τα bits της Port B για 700 φορές.
Λύση
Επειδή το 700 είναι μεγαλύτερο από 255 θα χρησιμοποιήσουμε δυο καταχωρητές για να κρατήσουμε την απαρίθμηση. Ο επόμενος κώδικας δείχνει πώς να χρησιμοποιήσουμε τον R20 και R21 σαν καταχωρητή απαρίθμησης.
.ORG 0
LDI R16, 0x55 ; R16 = 0x55
OUT PORTB, R16 ; PORTB = 0x55
LDI R20, 10 ; load 10 into R20 (outer loop count)
LOP_1: LDI R21, 70 ; load 70 into R21 (inner loop count)
LOP_2: COM R16 ; complement R16
OUT PORTB, R16 ; load PORT SFR with the complemented value
DEC R21 ; dec R21 (inner loop)
BRNE LOP_2 ; repeat it 70 times
DEC R20 ; dec R20 (outer loop)
BRNE LOP_1 ; repeat it 10 times
Σε αυτό το πρόγραμμα ο καταχωρητής R21 χρησιμοποιείται για να κρατήσει την απαρίθμηση του εσωτερικού βρόγχου. Στην εντολή “BRNE LO_2” όταν ο R21 γίνει 0 η ροή εκτέλεσης εξέρχεται από τον εσωτερικό βρόγχο και εκτελείτε η εντολή “DEC R20”. Η επόμενη εντολή φορτώνει τον απαριθμητή του εσωτερικού βρόγχου με την τιμή 70 και εάν R20 δεν είναι μηδέν, τότε ο εσωτερικός βρόγχος ξεκινά να εκτελείται. Αυτή η διαδικασία θα συνεχίσει να εκτελείται μέχρι ο R20 γίνει μηδέν και ο εξωτερικός βρόγχος τελειώσει.
Άλλες υπό συνθήκη διακλαδώσεις
Στη συνέχεια θα δούμε μερικές από τις υπό συνθήκη εντολές διακλάδωσης. Για παράδειγμα θα δούμε τις BREQ (διακλάδωση όταν Ζ=1) και BRLO (διακλάδωση όταν C=1), οι οποίες προκαλούν διακλάδωση στη σειρά εκτέλεσης του κώδικα κάτω από μια συνθήκη.
BREQ (branch if equal, branch if Z=1)
Σε αυτή την εντολή, η σημαία Ζ ελέγχεται. Εάν είναι Z=1, η CPU μεταπηδά στην καθορισμένη διεύθυνση που ορίζει η ετικέτα. Για παράδειγμα δες το ακόλουθο απόσπασμα κώδικα:
OVER: IN R20, PINB ; read PINB and put it in R20
TST R20 ; set the flags according to R20
BREQ OVER ; jump if R20 is zero
Σε αυτόν τον κώδικα εάν η τιμή του καταχωρητή ΡΙΝΒ είναι μηδέν, η CPU μεταπηδά στην ετικέτα OVER. Παραμένει στον βρόγχο μέχρι ο καταχωρητής ΡΙΝΒ πάρει μην μηδενική τιμή. Η εντολή TST χρησιμοποιείται για να θέσει τις σημαίες στον καταχωρητή κατάστασης σύμφωνα με τα περιεχόμενα του καθορισμένου καταχωρητή (εδώ του R20) χωρίς να εκτελέσει αριθμητική πράξη όπως μείωση ενός καταχωρητή. Όταν η εντολή TST εκτελείται, εάν ο καταχωρητής έχει την μηδενική τιμή, η σημαία Ζ τίθεται σε 1 αλλιώς τίθεται σε 0. Επίσης θέτει τη σημαία Ν σε 1 εάν το bit D7 του καταχωρητή έχει τιμή 1, αλλιώς η σημαία Ν τίθεται σε 0 (Ν=0).
Παράδειγμα:
Γράψε ένα πρόγραμμα το οποίο αν η θέση 0x200 της μνήμης RAM έχει την τιμή 0 να γράψει εκεί την τιμή 0x55.
Λύση:
.EQU MYLOC = 0x200
LDS R20, MYLOC
TST R20 ; καθορίζει τη σημαία
; (Z=1 εάν R20 έχει την μηδενική τιμή)
BRNE NEXT ; διακλάδωση εάν ο R20 δεν είναι μηδέν (Z=0)
LDI R20, 0x55 ; βάλε την τιμή 0x55 εάν ο R20 έχει την μηδενική τιμή
STS MYLOC, R20 ; και βάλε ένα αντίγραφο στη θέση μνήμης $200
ΝΕΧΤ: . . . .
BRSH (branch if same or higher, branch if C=0)
Σε αυτή την εντολή η σημαία κρατουμένου του καταχωρητή κατάστασης χρησιμοποιείται για να αποφασίσει η CPU εάν κάνει διακλάδωση. Με την εντολή “BRSH label” η CPU εξετάζει τη σημαία κρατουμένου. Εάν C=0 η CPU ξεκινά να εκτελεί τις εντολές από την διεύθυνση της ετικέτας. Εάν C=1 δεν έχουμε διακλάδωση και εκτελούνται οι εντολές μετά την BRSH. Σημειώστε ότι υπάρχει η εντολή “BRLO label” με την οποία εάν C=1 η CPU μεταπηδά στην διεύθυνση προορισμού.
Παράδειγμα
Βρες το άθροισμα των τιμών 0x81, 0xE9 και 0xF6. Βάλε το άθροισμα στους R16 (low byte) και R17 (high byte).
Λύση:
.ORG 0
LDI R17, 0 ; μηδένισε το high byte R17=0
LDI R16, 0 ; μηδένισε το low byte R16=0
LDI R20, 0x81
ADD R16, R20 ; R16 = 0 + 0x81 = 0x81, C=0
BRSH LINE_1 ; εάν C=0 πρόσθεσε τον επόμενο αριθμό
INC R17 ; C = 1
LINE_1: LDI R20, 0xE9
ADD R16, R20 ; R16 = 0x81 + 0xE9 = 0x6A και C=1
BRSH LINE_2 ; διακλάδωση εάν C = 0
INC R17 ; C = 1
LINE_2: LDI R20, 0xF6
ADD R16, R20 ; R16 = 0x6A + 0xF6 = 0x60 και C = 1
BRSH OVER ; διακλάδωση εάν C = 0
INC R17 ; C = 1
OVER: ; τώρα low byte = 0x60 και high byte = 02
Όλες οι υπό συνθήκη διακλαδώσεις είναι κοντινά άλματα
Όλες οι υπό συνθήκη διακλαδώσεις όπως οι BRSH, BREQ και BRNE πάνε την εκτέλεση σε κοντινές αποστάσεις. Η διεύθυνση προορισμού είναι σχετική της τιμής του program counter (PC). Εάν η σχετική διεύθυνση είναι θετική η διακλάδωση γίνεται προς τα μπροστά και εάν η σχετική διεύθυνση είναι αρνητική η διακλάδωση γίνεται προς τα πίσω. Η σχετική διεύθυνση μπορεί να έχει τιμή από -64 έως +63 επί του PC. Για να υπολογίσουμε τη διεύθυνση προορισμού, η σχετική διεύθυνση προστίθεται στον program counter (PC) της επόμενης εντολής.
Υπό χωρίς συνθήκη εντολές διακλάδωσης
Οι υπό χωρίς συνθήκη εντολές διακλάδωσης είναι άλματα στα οποία ο έλεγχος μεταφέρεται χωρίς συνθήκη στην διεύθυνση προορισμού. Στους μικροελεγκτές AVR υπάρχουν τρεις χωρίς συνθήκη εντολές διακλάδωσης οι: JMP (jump), RJMP (relative jump) και IJMP (indirect jump). Η εντολή που θα χρησιμοποιήσουμε εξαρτάται από την διεύθυνση προορισμού.
JMP (JMP is a long jump)
H JMP είναι μια χωρίς συνθήκη εντολή διακλάδωσης στην οποία ο έλεγχος μπορεί να μεταφερθεί σε οποιαδήποτε θέση της μνήμης προγράμματος μέσα στις 4Μ (word) θέσεις διευθύνσεων της μνήμης. Η εντολή JMP καταλαμβάνει μέγεθος 4 byte (32-bit) στην περιοχή προγράμματος και επιτρέπει άλματα μέσα σε 4Μ(words) της μνήμης από τις διευθύνσεις 000000 έως $3FFFFF και έτσι καλύπτει όλο το διάστημα διευθύνσεων.
Τα μέλη της οικογένειας AVR δεν περιέχουν τόση μεγάλη περιοχή μνήμης προγράμματος. Μερικά μέλη μικροελεγκτών AVR έχουν μόνο 4Κ – 32Κ πάνω στο τσιπ ROM σαν μνήμη προγράμματος. Για αυτό υπάρχει η RJMP (relative jump) εντολή διακλάδωσης η οποία είναι μια 2byte εντολή σε αντίθεση με την 4byte JMP εντολή. Αυτή μπορεί να μας οικονομήσει μερικά bytes μνήμης ROM σε πολλές εφαρμογές στις οποίες η μνήμη ROM δεν είναι μεγάλη σε μέγεθος.
RJMP (relative jump)
Σε αυτή την 2-byte υπό χωρίς συνθήκη εντολή διακλάδωσης, η διεύθυνση προορισμού αναφέρεται με την σχετική διεύθυνση της ετικέτας προορισμού ως προς την διεύθυνση τις τρέχων τιμής του program counter (PC). Η σχετική διεύθυνση ορίζεται από -2048 έως +2047 πάνω στην διεύθυνση του program counter και δίνει την διεύθυνση προορισμού. Εάν το άλμα είναι προς τα μπροστά η σχετική διεύθυνση είναι θετική. Εάν το άλμα είναι προς τα πίσω η σχετική διεύθυνση είναι αρνητική.
IJMP (indirect jump)
H IJMP είναι μια 2-byte εντολή. Όταν η εντολή εκτελείται, ο PC φορτώνεται με τα περιεχόμενα του καταχωρητή Ζ και έτσι η εκτέλεση πάει στην διεύθυνση που ορίζεται από τον καταχωρητή Ζ. Ο Ζ είναι ένας 2 byte καταχωρητής και έτσι το άλμα με την εντολή IJMP μπορεί να είναι μέσα στα χαμηλότερα 64Κ words της μνήμης προγράμματος.
Στις άλλες εντολές διακλάδωσης η διεύθυνση προορισμού είναι στατική, δηλαδή έχουμε άλμα σε καθορισμένη διεύθυνση. Στην εντολή διακλάδωσης IJMP έχουμε δυναμική διεύθυνση προορισμού, δηλαδή η διεύθυνση αυτή μπορεί να αλλάξει με αλλαγή των τιμών του καταχωρητή Ζ καθώς εκτελείται το πρόγραμμα.