Download as pdf or txt
Download as pdf or txt
You are on page 1of 26

AVR-mikrokontrollerien

osoitusmuodot
A. Karttunen,
Metropolia,
Mikroprosessoritekniikka,
6. marraskuuta 2011
AVR-mikrokontrollerien
Data-avaruus

ATmega328P RAM = 2Kbytes.


RAMEND = $08FF.

AVR:n 32 8-bittistä rekisteriä R0-R31 näkyvät myös data-avaruuden 32:tena


ensimmäisenä muistipaikkana (0x0000 – 0x001f) (Ei Xmega-sarjassa!), ja sen
suoraan osoitettavat I/O-rekisterit näkyvät niitä seuraavina 64:nä muistipaikkana
(0x0020 – 0x005F).
AVR-mikrokontrollerien
osoitusmuodot (1)
• Jotkut käskyt eivät tarvitse mitään lisämääreitä, esimerkiksi NOP
(”No Operation”) .
• Useimmat AVR-käskyt haluavat kuitenkin yhden tai kaksi
operandia (eli tietoa siitä, mitä tai missä argumentit ovat).
• AVR:stä löytyy noin neljätoista erilaista osoitusmuotoa:
– Immediate (välitön vakioarvo, koodattu käskykoodiin mukaan, kaksi eri
varianttia)
– Register Direct (suora viittaus rekistereihin R0-R31 tai R16-R31)
– I/O direct addressing (suora viittaus I/O-rekisteriin)
– Data Direct (suora viittaus datamuistiavaruuteen)
– neljä erilaista Data Indirect-muotoa (epäsuoraa viittausta datamuistiin)
– kaksi tapaa hakea vakioarvoja ohjelmamuistista Z-rekisterin avulla
– neljä tapaa määritellä hyppyosoite koodissa, yksi absoluuttinen, yksi
epäsuora, sekä kaksi relatiivista.
AVR:n osoitusmuodot (2),
suora rekisteriviittaus
Esimerkki:
COM Rd
vaihda rekisterin Rd:n sisältö
komplementikseen:
Rd ← (Rd XOR $FF)

Esimerkki:
MOV Rd,Rr
KOPIOI (ei ”siirrä”!) rekisterin Rr
sisältö rekisteriin Rd:
Rd ← Rr

Lähde: http://www.atmel.com/dyn/resources/prod_documents/doc0856.pdf
Huom! Käskyjen esitystapa yllä yksinkertaistettu, Rd ja Rr oikeasti ”sikinsokin”.
AVR:n osoitusmuodot (3),
rekistereiden esitys
konekielikäskyissä
15-12 11-8 7-3 3-0
Yksioperandisia ASR Rd 1001 010d dddd 0101
(esimerkkejä):
COM Rd 1001 010d dddd 0000
SWAP Rd 1001 010d dddd 0010

Kaksioperandisia: ADD Rd,Rr 0000 11rd dddd rrrr


EOR Rd,Rr 0010 01rd dddd rrrr
MOV Rd,Rr 0010 11rd dddd rrrr

Yksi vai kaksi? CLR Rd 0010 01dd dddd dddd


AVR:n osoitusmuodot (4),
Välitön (immediate) operandi
• Vakiona pysyvä source-operandi (mikä tahansa 8-bittinen arvo
eli tavu) on upotettu käskyyn itseensä. Se on siis käskyn mukana
koodisektiossa (mikä oikeassa AVR:ssä kirjoitetaan Flashille), eikä
sitä sen vuoksi mielletä varsinaisesti ”dataksi”.
• Käytetään ainoastaan seuraavissa, I-loppuisissa käskyissä: ANDI,
CPI, LDI, ORI, SBCI, SUBI.
• Huom: Ylläolevissa käskyissä dst-operandin pitää olla rekisteri
väliltä R16-R31.
• Erikoistapauksina vielä rekisteripareilla operoivat käskyt ADIW ja
SBIW, jotka sallivat immediate-operandikseen vain vakio-arvot
väliltä 0-63 (siis 6 bittiä).
• Huom: Atmelin omassa DOC0856.PDF dokumentissa
”immediate-moodia” ei ole listattu varsinaisena osoitusmuotona
ollenkaan.
AVR:n osoitusmuodot (5),
”immediate”, koodaus

Huom: dddd itse koodissa on oikeasti välillä 0 (0000) ja 15 (1111), mutta


lisättäessä se lukuun 16, voidaan viitata (vain) rekistereihin R16 – R31.
Lähde: Mazidi, Naimi & Naimi: ”The avr microcontroller and embedded
system using assembly and c”, Prentice Hall, 2011, sivu 87.
AVR:n osoitusmuodot (6),
suora viittaus I/O-rekisteriin

Käytetään esimerkiksi I/O-käskyissä IN, OUT, CBI ja SBI:


IN Rd,A ;; missä 0 ≤ d ≤ 31, 0 ≤ A ≤ 63. Toiminta: Rd ← I/O(A)
OUT A,Rr ;; missä 0 ≤ r ≤ 31, 0 ≤ A ≤ 63. Toiminta: I/O(A) ← Rr
SBI A,b ;; missä (HUOM!): 0 ≤ A ≤ 31, 0 ≤ b ≤ 7. I/O(A,b) ← 1 eli asettaa bitin b päälle
I/O-osoitteessa A. Käsky CBI vastaavasti nollaa (eli ”clearaa”) yksittäisen bitin.
AVR:n osoitusmuodot (7),
suora viittaus Data-muistiin

Huom! Tuo  
on harhaanjohtavaa.
Oikea käskyn ja
osoitteen koodaustapa
on tässä: ↓ ↓ ↓
LDS, 32-bit
opcode:

STS, 32-bit
opcode:

Käytettävissä vain kahdessa käskyssä (koska AVR perustuu Load/Store-arkkitehtuuriin):


LDS Rd,k ;; missä 0 ≤ d ≤ 31, 0 ≤ k ≤ 65535. Lataa rekisteriin Rd tavun
data-avaruudesta (yleensä SRAM-muistista, joskus I/O-avaruudestakin),
absoluuttisesta 16-bittisestä osoitteesta k. (“LoaD direct from data Space”.)
STS k,Rr ;; missä 0 ≤ r ≤ 31, 0 ≤ k ≤ 65535. Kirjoittaa rekisterin Rr sisällön
absoluuttiseen osoitteeseen k. (STS = “STore direct to data Space”.)
AVR:n osoitusmuodot (8),
epäsuorat viittaustavat
• AVR:n datamuistiin voidaan viitata neljällä epäsuoralla viittaustavalla, joiden
englanninkieliset nimet ovat ”Data Indirect”, ”Data Indirect with Predecrement”,
”Data Indirect with Post-Increment” sekä ”Data Indirect with Displacement”.
Ne ovat käytettävissä vain Load ja Store-tyyppisissä käskyissä (koska AVR perustuu
Load/Store-arkkitehtuuriin).

• Näissä osoitusmuodoissa käytetään apuna AVR:stä löytyviä kolmea 16-bittistä


”indeksirekisteriä” (”Indirect Address Register”), nimiltään X, Y ja Z. Tosin oikeasti
ne ovat vain aliaksia tavallisten 8-bittisten rekisterien kolmelle viimeiselle parille: Eli
X = R27:R26, Y = R29:R28 ja Z = R31:R30.
Ideana on se, että indeksirekisterin sisältö kertoo datamuistista haettavan tai sinne
talletettavan tavun osoitteen.

• Kaikkien X:n, Y:n ja Z:n ala- ja ylätavuun voidaan lisäksi viitata tyyliin XL ja XH, joten
seuraavat yhtäläisyydet pätevät: XL=R26, XH=R27, YL=R28, YH=R29,
ZL=R30, ZH=R31. Alatavu kertoo 16-bittisen data-osoitteen alemmat kahdeksan
bittiä (bitit 0-7), ja ylätavu ylemmät kahdeksan bittiä (bitit 8-15). (AVR:ssä käytetään
ns. “little-endian” tavujärjestystä.)
AVR:n osoitusmuodot (9),
epäsuora viittaus dataan

Esimerkkejä:
LD R0,Y ;; Lataa indeksirekisterin Y kertomasta osoitteesta (= 256*R29 + R28)
yhden tavun, ja laittaa sen rekisteriin R0.
ST Z,R0 ;; Sijoittaa R0-rekisterin sisällön indeksirekisterin Z kertomaan osoitteeseen
(joka on 256*R31 + R30).
Ylläolevat käskyt vastaavat C-kielen (char *)-pointterin ”deferencing-operaatiota”, eli
”fetchausta”: r0 = *y; ja ”indirect assignmenttia”: *z = r0;
AVR:n osoitusmuodot (10),
epäsuora data, pre-decrement

LD R0,-X ;; Lataa indeksirekisterin X kertomasta osoitteesta yhden tavun, sen jälkeen


kun sitä on ensin vähennetty yhdellä (johon arvoon X myös jää), ja
laittaa sen rekisteriin R0.
ST -Z,R0 ;; Sijoittaa R0-rekisterin sisällön indeksirekisterin Z kertomaan osoitteeseen
sen jälkeen kun sitä on ensin vähennetty yhdellä (johon arvoon Z
myös jää). (Melkein sama kuin SBIW ZH:ZL,1 ja ST Z,R0 peräkkäin.)
Ylläolevat käskyt vastaavat suunnilleen C-kielen käskyjä: r0 = *--x; ja *--z = r0;
AVR:n osoitusmuodot (11),
epäsuora data, post-increment

LD R0,X+ ;; Lataa indeksirekisterin X kertomasta osoitteesta yhden tavun, joka laitetaan


rekisteriin R0, jonka jälkeen X:ää lisätään yhdellä
ST Z+,R0 ;; Sijoittaa R0-rekisterin sisällön indeksirekisterin Z kertomaan osoitteeseen.
Sen jälkeen Z-rekisteriä lisätään yhdellä .
(Melkein sama kuin käskyt ST Z,R0 ja ADIW ZH:ZL,1 peräkkäin.)
Ylläolevat käskyt vastaavat suunnilleen C-kielen käskyjä: r0 = *x++; ja *z++ = r0;
Pre-decrement and post-increment käskyillä on helppo luoda esimerkiksi omia pinoja.
AVR:n osoitusmuodot (12),
epäsuora viittaus siirteellä

Käskyyn on koodattu mukaan kuuden bitin ”siirre” (engl. ”displacement”), joka lisättynä
Y tai Z-rekisterin sisältöön, antaa sen tavun osoitteen mikä ladataan tai mihin tavu
talletetaan. Voidaan käyttää vain käskyissä LDD ja STD!
Esimerkiksi jos Z-rekisterissä on pointteri merkkijonon alkuun, niin käsky LDD R0,Z+3
vastaa C-kielen käskyä r0 = *(z+3); eli käskyä r0 = z[3]; missä z on määritelty
esim näin: register char *z;
Voidaan käyttää myös C-kielen struct-keywordilla luotuja tietueita käsiteltäessä,
ensimmäisen kentän jäljessä tulevien kenttien lukuun ja kirjoitukseen.
AVR:n osoitusmuodot (13),
ADIW ja SBIW-käskyt
epäsuorilla viittauksilla
• Edellistä osoitusmuotoa käytettäessä saattaa tulla tilanne, jossa indeksirekisteriä
pitäisi lisätä (tai vähentää) enemmän kuin yhden askeleen (tavun) verran.
Esimerkiksi mikäli data-muistissa on useampia tietueita peräkkäin, niin kyseisen
tietueen koon (C-kielellä ilmaistuna: sizeof(struct tietue)) verran
eteenpäin. Tähän sopivat seuraavat kaksi käskyä:

ADIW Rd+1:Rd,K ;; Lisää rekisteripariin Rd ja Rd+1 vakio K.


SBIW Rd+1:Rd,K ;; Vähennä rek.parista Rd ja Rd+1 vakio K.
Huom: ainoastaan rekisteripareja R25:R24 (ei erityistä aliasta), R27:R26 (= X),
R29:R28 (= Y) ja R31:R30 (= Z) voi käyttää kyseisissä käskyissä.
Vakio K voi maksimissaan saada arvon 63, mikä on myös siirteen suurin sallittu arvo
”Data Indirect with Displacement” osoitusmuotoa käytettäessä. (Kts. edellinen kalvo.)
AVR:n osoitusmuodot (14),
Koodi- ja data-avaruuksien ero

Koska AVR perustuu Harvard-arkkitehtuuriin, siinä tarvitaan erilliset käskyt datan


hakemiseen ohjelmamuistista. Huomaa että ohjelmamuisti on organisoitu sanoittain,
eli CPU lukee sitä yksi 16-bitin sana kerrallaan, ei tavu kerrallaan kuten data-avaruutta!
AVR:n osoitusmuodot (15),
vakiotavun haku z:n avulla
ohjelmamuistista

Tätä osoitusmuotoa voisi kutsua myös ”Epäsuoraksi viittaukseksi koodimuistiin” (sieltä


datantapaista tietoa haettaessa). Käytetään vain Load Program Memory –käskyssä:

LPM Rd,Z ;; Lataa ohjelmamuistin Z:nnen tavun rekisteriin Rd. CPU osaa tehdä tämän
automaattisesti , vaikka ohjelmamuisti onkin organisoitu 16-bittisesti.
AVR:n osoitusmuodot (16),
vakiotavun haku z:n avulla
ohjelmamuistista, post-incr.

Tätä osoitusmuotoa voisi kutsua myös ”Epäsuoraksi viittaukseksi koodimuistiin, post-


incrementin kera”. (Analoginen ”data indirect post-incrementille”). Käytetään vain Load
Program Memory –käskyssä:

LPM Rd,Z+ ;; Lataa ohjelmamuistin Z:nnen tavun rekisteriin Rd, ja lisää sen jälkeen Z:aa
yhdellä. Kätevä haettaessa suurempia määriä dataa koodimuistista.
AVR:n osoitusmuodot (17),
Z-rekisterin alustus LPM-
käskyä käytettäessä
• LPM-käskyä varten ohjelmamuistin osoite pitää
muuntaa tavuosoitteeksi, kertomalla se kahdella.
• Assembler osaa tehdä muunnoksen käännösaikana
ekspressiolla << (eli C-kielestä tuttu ”shift left”).
Lisäksi Z-rekisteri pitää alustaa kahdessa palassa:

LDI ZH, high(MJONO << 1) ; Tavuosoitteen ylätavu


LDI ZL, low(MJONO << 1) ; Tavuosoitteen alatavu

.cseg ;; Kertoo että seuraavat datat halutaan kirjoittaa ohjelmamuistiin:


MJONO: ;; Seuraavaksi annettavan merkkijonon sanaosoite
.db ”Testimerkkijono”, 0 ;; Muista lopetusnolla!
AVR:n osoitusmuodot (18),
Suora (abs.) hyppy koodiin

Käytetään vain JMP ja CALL-käskyissä. Molemmat asettavat ohjelmalaskurin (PC:n) uudeksi


arvoksi ohjelmamuistissa käskyn ensimmäistä sanaa seuraavan 16-bittisen
sanan, sekä lisäksi vielä käskykoodiin itseensä upotetut 6 bittiä.
Tästä näemme että Atmel on varautunut maksimissaan 16+6 = 22 bittiseen koodiavaruuteen,
toisin sanoen 2^22 sanan eli kahdeksan megatavun (!) koodimuisteihin mahdollisissa
tulevissa AVR-malleissaan.
AVR:n osoitusmuodot (19),
Epäsuora hyppy koodiin
z-rekisterin avulla

Käytetään vain IJMP ja ICALL-käskyissä. Molemmat asettavat ohjelmalaskurin (PC:n)


uudeksi arvoksi Z-rekisterin sisällön. Tätä voi käyttää hyppytaulukoiden (ns. ”jump tables”)
toteuttamiseen.
AVR:n osoitusmuodot (20),
Relatiivinen hyppy koodiin

Siirre k on upotettu käskyn kahteentoista alimpaan bittiin (bitit 0-11, eli kolme
oikeanpuoleisinta ”nybbleä” tai heksadigittiä), ja vasemmanpuoleisin nybble
kertoo opcoden: RJMP = 1100 = C ja RCALL = 1101 = D.
Siirre k tulkitaan ”signed integerinä”, eli sen avulla voi maksimissaan viitata 2^11 sanaa
taaksepäin PC+1:stä (eli minimiosoite PC-2047) ja korkeintaan 2^11 – 1 sanaa eteenpäin
PC+1:stä (eli maks.osoite on PC+2048), missä PC tässä tarkoittaa RJMP tai RCALL-käskyn
osoitetta. Esimerkiksi itseensä hyppäävä relatiivinen hyppy koodautuu aina samaksi sanaksi:
I_LOOP: RJMP I_LOOP ; Assembloituu koodiksi 0xCFFF koska k = -1.
AVR:n osoitusmuodot (21),
Lyhyt relatiivinen hyppy
ehdollisille haaraumille

BRANCH-käskyille, eli ”ehdollisille haaraumille”, voidaan määrittää seitsemällä bitillä


(käskykoodin bitit 3-9) relatiivinen siirre (eli ”displacement”) välillä (PC-63 - PC+64),
missä PC tässä viittaa kyseisen branch-käskyn paikkaan.
Huomaa että tätä ei Atmelin dokumentissa DOC0856.pdf ole listattu osoitusmuotona
laisinkaan. Branch-käskyjen käytöstä on/tulee erillinen kalvosarja.
Absoluuttiset osoitteet
• Absoluuttisella osoituksella tarkoitetaan sellaista
osoitusmuotoa, jossa varsinainen osoite (eli ns. ”effective
address”) ei muutu, vaikka sen sisältävä käskykoodi
siirrettäisiinkin toiseen paikkaan.

• Esimerkiksi käskyssä LDS, joka lataa tavun aina käskykoodin


jäljessä annetusta 16-bittisestä dataosoitteesta, riippumatta
siitä, missä kohtaa koodimuistia käsky tai tuo dataosoite itse
on.

• Samoin käskyissä JMP ja CALL, joiden mukana ja jäljessä


seuraa sellaisenaan PC:n uusi 22-bittinen arvo, mikä ei
mitenkään riipu sen vanhasta arvosta, eli siitä missä kohdin
JMP tai CALL-käsky sijaitsee koodimuistissa.
Relatiiviset osoitteet
• Relatiivisella osoitteella tarkoitetaan sellaista
osoitusmuotoa, jossa varsinainen osoite (eli ns.
”effective address”) riippuu siitä, missä kohdin
(koodi)muistia kyseinen käsky itse on.
• Esimerkiksi AVR:ssä hyppykäskyissä RJMP ja
RCALL sekä kaikissa branch-käskyissä.
• AVR-mikrokontrollereissa ei ole relatiivisesti
osoittavia datankäsittelykäskyjä, koska se on puhdas
Harvard-arkkitehtuuri, joten sen koodi- ja data-
avaruudet ovat tyystin erillään toisistaan, eikä niiden
välillä voi siksi harrastaa ”pointteriaritmetiikkaa”.
• Perinteisemmissä yhden muistiavaruuden
prosessoreissa asialla on kuitenkin merkitystä.
Paikasta riippumaton koodi,
eli ”PIC”
• Perinteisissä (Von Neumann) prosessoreissa, joissa koodi- ja data haetaan
samasta osoiteavaruudesta, ja ne on vain osittain erotettu toisistaan, on usein
mahdollista määritellä myös kaikki muistiviittaukset dataan relatiivisesti, eli
suhteessa viittauksen sisältävän käskyn paikkaan koodissa. Tällaista koodia
kutsutaan lyhenteellä PIC, eli ”Position Independent Code”.

• Tämä helpottaa asioita esimerkiksi silloin, jos halutaan tuottaa koodia ns.
”jaetuksi kirjastoksi” (eli Unixeissa ”shared libraries”, lib*.so). Mikäli aihe
kiinnostaa enemmän, katso:
http://en.wikipedia.org/wiki/Position-independent_code

• AVR:n kaltaisissa mikrokontrollereissa käännetyn koodin automaattisella


siirtyvyydellä ei kuitenkaan ole mitään väliä, koska koodi tallennetaan
vakiokohtaan Flash-muistia (yleensä osoitteesta 0x0000 eteenpäin), eikä
koodi siirtyile Flashissa ajon aikana mihinkään suuntaan.

You might also like