Μέθοδοι διευθυνσιοδότησης – μέρος 1ο

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