H CPU μπορεί να έχει πρόσβαση σε δεδομένα με διαφορετικούς τρόπους. Τα δεδομένα μπορεί να βρίσκονται σε ένα καταχωρητή ή στη μνήμη ή να παρέχονται με σταθερές τιμές. Οι διάφοροι τρόποι για την πρόσβαση δεδομένων ονομάζονται μέθοδοι διευθυνσιοδότησης (addressing modes)
Single – register (immediate) addressing mode
Σ αυτή την μέθοδο διευθυνσιοδότησης ο τελεστέος είναι ένας καταχωρητής γενικού σκοπού. Ακολουθούν μερικά παραδείγματα:
NEG R18 ; negate the contents of R18
COM R19 ; complement the contents of R19
INC R20 ; increment R21
DEC R21 ; decrement R21
ROR R22 ; rotate right R22
Σε μερικές εντολές υπάρχει μια σταθερή τιμή μαζί με τον καταχωρητή, όπως
LDI R19, 0x25 ; φόρτωσε την τιμή 0x25 στον καταχωρητή R19
SUBI R19, 0x06 ; αφαίρεσε την τιμή 0x06 από τον καταχωρητή R19
ANDI R19, 0b01000000 ; λογική πράξη AND του καταχωρητή R19 με την τιμή 0x40
Αυτή η μέθοδος διευθυνσιοδότησης μπορεί να χρησιμοποιηθεί για να φορτώνουμε δεδομένα σε οποιοδήποτε από τους R16 εως R31 καταχωρητές γενικού σκοπού (π.χ. LDI). Η “immediate addressing mode” χρησιμοποιείται επίσης με τις αριθμητικές και λογικές εντολές SUBI, ANDI κ.τ.λ. Σημειώστε το γράμμα “I” στις εντολές αυτές όπως LDI, ANDI και SUBI που σημαίνει “immediate”.
Μπορούμε να χρησιμοποιήσουμε την .EQU directive για πρόσβαση σε άμεσα δεδομένα όπως στο ακόλουθο παράδειγμα:
.EQU COUNT = 0x30
. . .
LDI R16, COUNT
Two – register addressing mode
Η μέθοδος της two – register addressing mode χρησιμοποιεί δυο καταχωρητές γενικού σκοπού για να κρατήσουν τα δεδομένα που θα διαχειριστεί η εντολή. Παραδείγματα της κατάστασης διευθυνσιοδότησης δυο καταχωρητών είναι τα ακόλουθα:
ADD R20, R23 ; πρόσθεσε τα περιεχόμενα του R23 με εκείνα του R20
SUB R29, R20 ; αφαίρεσε τα περιεχόμενα του R20 από εκείνα του R29
AND R16, R17 ; λογική πράξη AND του R16 με τον R17
MOV R23, R19 ; αντέγραψε τα περιεχόμενα του καταχωρητή R19 στον R23
Direct addressing mode
Ολόκληρη η μνήμη δεδομένων (SRAM) μπορεί να προσπελαστεί χρησιμοποιώντας την άμεση μέθοδο διευθυνσιοδότησης (direct addressing mode). Στην άμεση μέθοδο διευθυνσιοδότησης, ο τελεστέος είναι μια διεύθυνση της μνήμης δεδομένων RAM η οποία είναι γνωστή και είναι μέρος της εντολής. Εξετάστε το ακόλουθο απόσπασμα κώδικα:
LDS R19, 0x560 ; φόρτωσε στον R19 τα περιεχόμενα της μνήμης δεδομένων
; με διεύθυνση 0x560
STS 0x40, R19 ; αποθήκευσε τα περιεχόμενα του R19 στη μνήμη δεδομένων στη θέση 0x40
Το εύρος διευθύνσεων της μνήμης SRAM είναι 16-bit και μπορεί να πάρει τιμές από $0000 έως $FFFF ανάλογα τον μικροελεγκτή. Θα πρέπει να σημειώσουμε ότι η μνήμη δεδομένων (data memory) δεν υποστηρίζει immediate addressing mode. Αυτό σημαίνει ότι αν θέλουμε να φορτώσουμε δεδομένα στη RAM ή στους Ι/Ο καταχωρητές, θα πρέπει πρώτα να τα φορτώσουμε πρώτα σε ένα καταχωρητή GPR (R16 –R31) και μετά να τα μετακινήσουμε από τον GPR στη μνήμη δεδομένων RAM χρησιμοποιώντας την εντολή STS. Για παράδειγμα, εάν θέλουμε να αποθηκεύσουμε την τιμή 0x25 στη θέση μνήμης 0x520 θα πρέπει να γράψουμε το ακόλουθο πρόγραμμα, μιας που δεν υπάρχει εντολή για αποθήκευση αριθμητικών τιμών άμεσα σε θέσεις μνήμης:
LDI R19, 0x95 ; φόρτωσε την τιμή 0x95 στον καταχωρητή R19
STS 0x520, R19 ; αποθήκευσε τα περιεχόμενα του R19 στη μνήμη δεδομένων
; στη διεύθυνση 0x520
Ι/Ο direct addressing mode
Για να έχουμε πρόσβαση στους Ι/Ο καταχωρητές υπάρχει μια ειδική μέθοδος διευθυνσιοδότησης γνωστή σαν Ι/Ο direct addressing mode. Με την I/O direct addressing mode μπορούμε να έχουμε πρόσβαση στους “standard I/O registers”. Οι εντολές IN και OUT χρησιμοποιούν αυτή την μέθοδο διευθυνσιοδότησης. Εξετάστε τις ακόλουθες εντολές που αντιγράφουν τα περιεχόμενα του PINB στην PORTC
IN R18, 0x03 ; R18 = περιεχόμενα της Ι/Ο θέσης $03 (PINB)
OUT 0x08, R18 ; PORTC (Ι/Ο θέση $08) = R18
Η μέθοδος Ι/Ο direct addressing mode μπορεί να χρησιμοποιηθεί με τους standard I/O registers από τις Ι/Ο διευθύνσεις $00 έως $3F (00 εως 63 στο δεκαδικό).
Οι I/O registers μπορούν να προσπελαστούν με τα ονόματα τους (που είναι πιο εύκολο) ή με τις διευθύνσεις τους. Για παράδειγμα η ΡΙΝΒ έχει διεύθυνση 0x03 και η PORTC έχει διεύθυνση $08 όπως φαίνεται στον πίνακα. Τα ακόλουθα ζευγάρια εντολών εκτελούν την ίδια εργασία:
OUT 0x08, R19 ; είναι η ίδια όπως η επόμενη εντολή
OUT PORTC, R19 ; αντιγράφει τα περιεχόμενα του R19 στον PORTC
IN R26, 0x03 ; είναι η ίδια όπως η επόμενη εντολή
IN R26, PINB ; αντιγράφει τον PINB στον καταχωρητή R26
Ο πίνακας δείχνει μερικούς AVR I/O καταχωρητές και οι διευθύνσεις τους. Θα πρέπει να επισημάνουμε τα ακόλουθα σημεία σχετικά με τις διευθύνσεις των Ι/Ο καταχωρητών:
1] Οι διευθύνσεις μεταξύ $20 και $5F της μνήμης δεδομένων έχουν καταχωρηθεί στους standard I/O registers όλων των τύπων AVR. Αυτοί οι Ι/Ο register έχουν δυο διευθύνσεις την Ι/Ο address και την data memory address (διεύθυνση στη μνήμη δεδομένων).
Η I/O address χρησιμοποιείται όταν έχουμε Ι/Ο direct addressing mode ενώ η data memory address χρησιμοποιείται όταν έχουμε direct addressing mode. Με άλλα λόγια οι standard I/O registers μπορούν να προσπελαστούν χρησιμοποιώντας και τους δυο τρόπους: direct addressing mode και την I/O addressing mode. Για παράδειγμα τα ακόλουθα ζεύγη εντολών κάνουν την ίδια εργασία, αλλά οι IN και OUT εντολές είναι πιο αποδοτικές.
OUT 0x08, R19 ; PORTC = R19 (0x08 είναι η I/O διεύθυνση του οf PORTC)
STS 0x28, R19 ; PORTC = R19 (0x28 είναι η διεύθυνση της
; μνήμης δεδομένων του PORTC)
IN R19, 0x03 ; R19 = PINB (0x03 είναι η I/O διεύθυνση του PINB)
LDS R19, 0x23 ; R19 = PINB (0x23 είναι η διεύθυνση της μνήμης δεδομένων του PINB)
2] Μερικά μέλη της οικογένειας AVR όπως ο ATmega328 έχουν περισσότερους από 64 Ι/Ο registers. Οι επιπλέον I/O registers βρίσκονται πάνω από την διεύθυνση $5F της μνήμης δεδομένων. Η μνήμη δεδομένων που δεσμεύεται για τους extra I/O registers ονομάζεται extended I/O memory. Οι εντολές ΙΝ και OUT (I/O direct addressing mode) μπορούν να χρησιμοποιηθούν μόνο με τους standard I/O registers με διευθύνσεις $00 έως $3F. Για παράδειγμα η ακόλουθη εντολή προκαλεί λάθος από το γεγονός ότι η I/O address πρέπει να είναι μεταξύ 0 και $3F
OUT 0x65, R19 ; άκυρο διότι η Ι/Ο διεύθυνση είναι πάνω από $3F
Για να προσπελάσουμε τους extended I/O registers χρησιμοποιούμε τη μέθοδο direct addressing mode. Για παράδειγμα στον ATmega128 η PORTF έχει διεύθυνση στη μνήμη δεδομένων ίση με 0x62. Έτσι με την ακόλουθη εντολή αποθηκεύουμε τα περιεχόμενα του καταχωρητή R20 στην PORTF
STS 0x62, R20 ; PORTF = R20
3] Οι Ι/Ο registers μπορούν να έχουν διαφορετικές διευθύνσεις σε διαφορετικούς AVR μικροελεγκτές. Για παράδειγμα η I/O address $4 εκχωρείται στον DDRB για τον ATmega328, ενώ η ίδια διεύθυνση εκχωρείται στον ADCL για τον ATmega128. Αυτό σημαίνει ότι στον ATmega328 η εντολή “OUT 0x4, R20” αντιγράφει τα περιεχόμενα τουR20 στο DDRB, ενώ η ίδια εντολή στον ATmega128 αντιγράφει τα περιεχόμενα του R20 στο ADCL. Με άλλα λόγια η ίδια εντολή έχει διαφορετικό αποτέλεσμα για διαφορετικούς AVR μικροελεγκτές. Αυτό μπορεί να προκαλέσει προβλήματα όταν θέλεις να τρέξεις προγράμματα γραμμένα για ένα AVR σε ένα άλλο AVR.
Για παράδειγμα εάν έχεις γράψει κώδικα για τον ATmega328 και θέλεις να τον τρέξεις σε ένα άλλο π.χ. στον ATmega128, ο καλύτερος τρόπος για να λύσεις αυτό το πρόβλημα είναι να χρησιμοποιήσεις ονόματα των Ι/Ο καταχωρητών αντί για τις διευθύνσεις τους. Για παράδειγμα η εντολή “OUT DDRB, R20” έχει το ίδιο νόημα σε όλους τους AVRs. Επομένως χρησιμοποιώντας τα ονόματα των καταχωρητών αντί για τις διευθύνσεις τους κάνουμε τον κώδικα προσβάσιμο για όλους τους AVRs.
Παράδειγμα
Γράψε ένα πρόγραμμα που να στέλνει την τιμή $55 στην Port B χρησιμοποιώντας:
α] το όνομα του καταχωρητή
β] την Ι/Ο διεύθυνση
γ] και την διεύθυνση της μνήμης δεδομένων
α]
LDI R20, 0xFF ; R20 = 0xFF
OUT DDRB, R20 ; DDRB = R20 (Port B output)
LDI R20, 0x55 ; R20 = $55
OUT PORTB, R20 ;Port B = 0x55
β]
Από τον πινάκα DDRB I/O address = $4 και PORTB I/O address = $5
LDI R20, 0xFF ; R20 = 0xFF
OUT 0x04, R20 ; DDRB = R20 (Port B output)
LDI R20, 0x55 ; R20 = $55
OUT 0x05, R20 ; PORT B = 0x55
γ]
Από τον πίνακα η διεύθυνση του DDRB στη μνήμη δεδομένων = $24 και του PORTB η διεύθυνση στη μνήμη δεδομένων = $25
LDI R20, 0xFF ; R20 = 0xFF
STS 0x24, R20 ; DDRB = R20 (Port B output)
LDI R20, 0x55 ; R20 = $55
STS 0x25, R20 ; Port B = 0x55