Kiterjesztett pontosságú műveletek

[Szerzői jogok]

A fejezet tartalma:

Az előző fejezetekben 8 és 16 bites műveletekkel foglalkoztunk. Természetesen előfordulhatnak olyan esetek, amikor ennél nagyobb bitszámú adatokkal kell műveleteket végeznünk. Minél nagyobb számokkal dolgozunk, vagy minél pontosabb számábrázolásra van szükség, annál több számjegyre, annál több bitre van szükségünk a tároláshoz. Általánosságban N biten 0-tól 2N-1-ig terjedő számokat tudunk ábrázolni, ha előjel nélküli számábrázolásról van szó.

Emlékeztetőül az alábbi táblázatban felsoroltuk azokat a változótípusokat amelyekkel ebben a jegyzetben találkozunk.  Mint látjuk, 8 bites bájtokkal, valamint 16 és 32 bites szavakkal lesz dolgunk.
Méret Bájtok Ábrázolási tartomány
(előjel nélkül)
C típus
(PIC24 fordító)
C típus (e jegyzetben)
8-bit 1 0 - 28-1 = 0 - 255 unsigned char uint8
16-bit 2 0 - 216-1 = 0 - 65 535 unsigned int uint16
32-bit 4 0 - 232-1 = 0 - 4 294 967 295 unsigned long uint32
64-bit 8 0 - 264-1 = 0 - 18446744073709551615 unsigned long long uint64
A 16 vagy 32 bites szavak legalacsonyabb helyiértékű bájtját LSB-vel jelöljük (a Least Significant Byte elnevezés alapján), a legmagasabb helyiértékű bájtjukat pedig MSB-vel (Most Significant Byte).

Hasonlóan jelöljük a 32 bites változóknál az MSW rövidítéssel a magasabb helyiértékű 16 bites adatszót (Most Significant Word) és LSW-vel az alacsonyabb helyiértékű 16 bites adatszót (Least Significant Word). A PIC24 mikrovezérlők felépítéséből következően  a több-bájtos vagy többszavas változók tárolási módja "little endian", vagyis mindig az alacsonyabb memória címen található az alacsonyabb helyiértékű bájt/szó.

32 bites adatmozgatás

A PIC24 család adatmozgató utasításai között vannak kétszavas (32 bites) adatmozgató utasítások is. Az adatmozgatás történhet regiszterpárok között, valamint egy regiszterpár és egy regiszterrel indirekten címzett forrás (vagy cél) között.
Megnevezés Az utasítás alakja Művelet
kétszavas adatmozgatás
regiszterpárból regiszterpárba
MOV.D Wns, Wnd (Ws:Ws+1) → Wnd:Wnd+1
kétszavas adatmozgatás
indirekt címzésű forráshelyről
regiszterpárba
MOV.D [Ws], Wnd
MOV.D [Ws++], Wnd
MOV.D [Ws--], Wnd
MOV.D [++Ws], Wnd
MOV.D [--Ws], Wnd
([Ws]:[Ws]+2) → Wnd:Wnd+1
([Ws]:[Ws]+2) → Wnd:Wnd+1; Ws=Ws+4;
([Ws]:[Ws]+2) → Wnd:Wnd+1; Ws=Ws-4;
Ws=Ws+4; ([Ws]+4:[Ws]+6) → Wnd:Wnd+1
Ws=Ws-4; ([Ws]-4:[Ws]-2) → Wnd:Wnd+1
kétszavas adatmozgatás
regiszterpárból indirekt címzésű
célhelyre
MOV.D Wns, [Wd]
MOV.D Wns, [Wd++]
MOV.D Wns, [Wd--]
MOV.D Wns, [++Wd]
MOV.D Wns, [--Wd]
(Wns:Wns+1) → [Wd]:[Wd]+2
(Wns:Wns+1) → [Wd]:[Wd]+2; Wd=Wd+4
(Wns:Wns+1) → [Wd]:[Wd]+2; Wd=Wd-4
Wd=Wd+4; (Wns:Wns+1) → [Wd]:[Wd]+2
Wd=Wd-4; (Wns:Wns+1) → [Wd]:[Wd]+2
 A táblázat első ránézésre ijesztően bonyolultnak tűnik, de valójában csak három alapeset van, a többi már csak a post-/pre-inkrementálásos játék: adatátvitel előtt vagy után léptethetjük az indirekt címet.

Kezdjük az első (a legegyszerűbb) esettel: a közvetlen címzésű, regiszterpárból regiszterpárba történő adatátvitellel! A MOV.D Wns,Wnd utasításban a .D módosító jelzi, hogy 32 bites (D -mint Duplaszavas) átvitelről van szó. A Wns és Wnd operandusok a forrás és a cél helyét jelentő regiszterpárok alacsonyabb helyiértékű regisztereinek sorszáma. Mivel a 32 bites adatmozgatásnál mind a forrás, mind a cél páros sorszámú regiszterben kell, hogy kezdődjön, ezért mind Wns, mind Wnd csak a W0, W2, W4, W6,..., W14 regiszterek valamelyike lehet.

A (Ws:Ws+1) → Wnd:Wnd+1 jelölés azt mutatja, hogy két, egymást követő (és a fentiek szerint páros címen kezdődő) regiszterből két összefogott szó, azaz 32 bit adat másolódik a célhelyre, ami szintén páros címen kezdődő, két, egymást követő regiszter.

Az összes többi esetben vagy a forrás, vagy a cél esetében indirekt címzést használunk. A 16 bites effektív címet bármelyik regiszterben (W1...W15) tárolhatjuk. Az összes többi variáns abból adódik, hogy az indirekt címzéshez használt regisztert az adatátvitel előtt vagy utána dekrementálhatjuk vagy inkrementálhatjuk. A .D módosító használata miatt az inkrementálás vagy dekrementálás néggyel növeli vagy csökkenti a címzéshez használt regiszter értékét.

Megjegyzés: ügyeljünk arra, hogy indirekt címzésnél a címet tároló regiszter páros memóriacímre mutasson, ellenkező esetben címzéshiba kivétel történik, és megszakad a programunk, ha páratlan címről, vagy páratlan címre akarunk 32 bites adatot mozgatni! 

Az alábbi ábrán két példát mutatunk a 32 bites adatmozgatásra.

32 bites változók inicializálása

Az alábbi programrészlet a 32 bites változók inicializálását mutatja be, C és assembly nyelven. Az inicializálás sorrendje (hogy az alacsonyabb vagy a magasabb helyiértékű szót írjuk be először) közömbös.

32 bites bitenkénti logikai műveletek

Mivel a bitenkénti logikai műveletek szigorúan csak az azonos helyiértékű bitek között történnek, s nem keletkezik átvitel, így a 32 bites változók alacsonyabb és magasabb helyiértékű szaván egyenként is elvégezhetjük a műveletet, s a sorrend is közömbös. Az alábbi példán a bitenkénti AND művelet elvégzését mutatjuk be.

32/64 bites összeadás és kivonás

Összeadásnál vagy kivonásnál először a változók alacsonyabb helyiértékű felén végezzük el a műveletet, s a keletkező átvitelt vagy áthozatot figyelembe vesszük a változók magasabb helyiértékű felén végzendő műveletnél.

A fenti műveletek assembly programozásához két új utasítást is felhasználunk:
ADDC f   hatása: f = f + WREG + C, vagyis az f változóhoz WREG és Carry bit tartalmát is hozzáadja.
SUBB f    hatása: f = f - WREG - B, vagyis az f változóból kivonja WREG és a Borrow bit tartalmát.
A Borrow bit egyébként a Carry bit negáltja: B = ~C.


A fenti programban előbb betöltjük a WREG regiszterbe a j változó alacsonyabb helyiértékű felét, majd hozzáadjuk a k változó alacsonyabb helyiértékű feléhez. A keletkezett átvitelt figyelembe kell vennünk a változók magasabb helyiértékű felének az összeadásánál, ezért ehhez nem az ADD, hanem az ADDC utasítást használjuk. Az ADD és az ADDC utasítások közötti adatmozgatás (MOV) nem változtatja meg a Carry bitet.  

A kivonásnál is hasonlóan járunk el. Előbb az alacsonyabb helyiértékű adatszavakon végezzük el a kivonást, majd a keletkezett áthozatalt a SUBB utasítással alkalmazásával vesszük figyelembe. Emlékeztetőül: a SUB p utasítás a p = p - W0  műveletnek (16 bites) felel meg.

64 bites összeadás és kivonás

Bár ennek a jegyzetnek keretében nem foglalkozunk 64 bites műveletekkel, az alábbi példában bemutatjuk, hogy a 32 bites összeadás (és hasonlóan a kivonás is) könnyen kiterjeszthető tetszőleges szószámú változókra. Itt most a legkisebb helyiértékű adatszót (LSW) word0-nak, a magasabb helyiértékűeket pedig rendre word1-nek, word2-nek,word3-nak jelöltük a magyarázatokban. A 64 bites változók esetében word3 lesz a legmagasabb helyiértékű szó (MSW).



Könnyen belátható, hogy a k = k - j 64 bites kivonás is a fentihez hasonlóan végezhető, csak az ADD utasítás helyére SUB, az ADDC utasítás helyére pedig SUBB utasítást kell írnunk.

Az áthozattal végzett összeadás/kivonás egyéb formái

Az alábbi táblázatban összefoglaljuk mindazokat az utasításokat, amelyek az áthozatal figyelembevételével végzik az összeadást vagy kivonást. Ide tartozik az összehasonlítás is, ami szintén kivonást végez, bár a kivonás eredménye nem tárolódik el.
Megnevezés Az utasítás kódja Művelet
Összeadás áthozattal
(ADD with Carry)
ADDC Wb,Ws,Wd
ADDC Wb,#lit5,Wd
ADDC #lit10,Wn
ADDC f
ADDC f,WREG
(Wb) + (Ws) + (C) → Wd
(Wb) + lit5  + (C) → Wd
(Wn) + lit10 + (C) → Wn
(f) + (WREG) + (C) → f
(f) + (WREG) + (C) → WREG
Kivonás áthozattal
(Subtract with Borrow)
SUBB Wb,Ws,Wd
SUBB Wb,#lit5,Wd
SUBB #lit10,Wn
SUBB f
SUBB f,WREG
(Wb) - (Ws) - (~C) → Wd
(Wb) - lit5  - (~C) → Wd
(Wn) - lit10 - (~C) → Wn
(f) - (WREG) - (~C) → f
(f) - (WREG) - (~C) → WREG
Fordított irányú kivonás
áthozattal
(Subtract with Borrow, Reverse)
SUBBR Wb,Ws,Wd
SUBBR Wb,#lit5,Wd
SUBBR f
SUBBR f,WREG
(Ws) - (Wb) - (~C) → Wd
lit5 - (Wb)  - (~C) → Wd
(WREG) - (f) - (~C) → f
(WREG) - (f) - (~C) → WREG
Összehasonlítás áthozattal
(Compare with Borrow)
CPB Wb,Ws
CPB Wb,#lit5
CPB f
(Wb) - (Ws) - (~C)
(Wb) - lit5  - (~C)
(f) - (WREG) - (~C)

A Zero státuszbit viselkedése 32 bites műveleteknél

Az átvitel/áthozat figyelembevételével végzett összeadás/kivonás és összehasonlítás műveletek az SR státusz regiszternek  csak a DC, N, OV és C bitjeit állítják be, a Zero jelzőbitet csak törölni tudják. Az alábbi példákból megérthetjük, hogy ez miért jó: mert pont így tudja a Z státuszbit a 32 bites művelet egészére vonatkozóan jelezni, hogy az eredmény nulla-e vagy sem. A Z bitnek ugyanis akkor és csak akkor kell 1-be állítva maradnia, ha az alacsonyabb és a magasabb helyiértéken végzett művelet is nulla eredményt adott. Ez akkor teljesül, ha az alacsonyabb helyiértéken végzett művelet Z=1-et állított be, és a magasabb helyiértéken végzett művelet sem törölte a Z bitet.

Az alábbi példákat kivonásra mutatjuk be, de összeadásnál is hasonló a helyzet.


Az a. esetben az alacsonyabb helyiértéken végzett kivonás eredménye nem nulla (Z=0). A magasabb helyiértéken hiába lett nulla az eredmény, a subb utasítás csak törölni tudja a Z bitet, beállítani nem, ezért megmarad a Z=0 állapot, ami jelzi, hogy a 32 bites kivonás eredménye nem nulla.


A b. esetben az alacsonyabb helyiértéken végzett kivonás eredménye nulla (Z=1). A magasabb helyiértéken azonban nem nulla az eredmény, a subb utasítás tehát törli a Z bitet, ezért végeredményben Z=0 lesz, ami jelzi, hogy a 32 bites kivonás eredménye nem nulla.

A c. esetben az alacsonyabb helyiértéken végzett kivonás eredménye nulla (Z=1). A magasabb helyiértéken szintén nulla az eredmény, a subb utasítás tehát nem törli a Z bitet, ezért végeredményben Z=1 lesz, ami jelzi, hogy a 32 bites kivonás eredménye nulla.

32 bites inkrementálás és dekrementálás

A 32 bites változók inkrementálását vagy dekrementálását úgy végezhetjük el, hogy előbb megnöveljük (vagy csökkentjük) a változó alacsonyabb helyiértékű felét, s amennyiben keletkezett átvitel vagy áthozat, akkor megnöveljük/csökkentjük a változó magasabb helyiértékű felét is. Van azonban egy apró probléma: nincs olyan utasítás a PIC24 mikrovezérlők utasítás készletében, ami a Carry bitet figyelembe vételével végezné az inkrementálást/dekrementálást. Emiatt trükköznünk kell: nullát fogunk hozzáadni, vagy kivonni, a Carry bit figyelembevételével, ami lényegében a Carry bit hozzáadásának (illetve kivonásnál a Borrow bit kivonásának) felel meg.  

32 bites logikai eltolás

A 32 bites változóknál a jobbra léptetést a magasabb helyiértékű bitekkel kell kezdeni. Az eddigiekben használt, előjel nélküli változóknál az LSR utasításra lesz szükség (nem árulok el nagy titkot, ha elmondom, hogy az előjeles változóknál pedig az ASR utasítást kell használni). Amikor a változó alacsonyabb helyiértékű bitjeit léptetjük jobbra, akkor figyelembe kell vennünk az előző lépésben a Carry bitbe kiléptetett bitet. Az alacsonyabb helyiértékű bitek jobbra léptetéséhez tehát nem az LSR, hanem az RRC (Rotate Right through Carry) utasítást használjuk. A megoldás sémája és a hozzá tartozó utasítások az alábbi ábrán láthatók.

Megjegyzés: ha több helyiértékű léptetést kell végezni (mint pl. k = k >> 3), akkor azt a fenti utasítássorozat ciklikus ismétlésével oldhatjuk meg. Az egy utasításciklusban több-helyiértékkel léptető utasítást azért nem tudjuk itt használni, mert a Carry bittel csak egyetlen kiléptetett bitet tudunk felfogni.

A balra léptetést fordítva kell csinálnunk: először a változó alacsonyabb helyiértékű bitjeit léptetjük balra egy SL utasítással, majd  a magasabb helyiértékű biteket forgatjuk egy RLC utasítással, ami figyelembe veszi a Carry bitbe előzőleg kiléptetett bitet. A 32 bites balra léptetés sémája és a hozzá tartozó utasítások az alábbi ábrán láthatók. 

Kiterjesztett pontosságú feltételvizsgálatok

A 32 bites változókra vonatkozó feltételek vizsgálatánál jó hasznát vehetjük a korábbi táblázatban már bemutatott CPB utasításnak, amely a SUBB utasításhoz hasonlóan az áthozat figyelembevételével végzett kivonásnak megfelelően állítja be a státuszbiteket. A Zero bit kivétel, mert az "ragadós" (sticky) viselkedésű, azaz a CPB utasítás csak törölni tudja (akkor, ha az eredmény nem nulla), 1-be állítani nem. Viszont megőrzi a Z=1 állapotot, ha az eredmény nulla (tehát ugyanúgy viselkedik, mint a SUBB utasítás).

Nullától való különbözőség vizsgálata

A 32 bites k változó vizsgálatát a CP és CPB utasításpárral vizsgáljuk. Előtte a WREG regisztert ki kell nullázni, a CP k utasítás ugyanis a k-WREG kivonásnak megfelelően fogja beállítani a státuszbiteket. A nullától való különbözőség vizsgálata úgy történik, hogy előbb a k változó alacsonyabb helyiértékű felét vizsgáljuk egy CP k utasítással, majd a magasabb helyiértékű felét a CPB k+2 utasítással. A Z=1 állapot akkor és csak akkor marad fenn, ha az első vizsgálat eredménye is nulla volt, s a második vizsgálatnál sem törlődött (k.MSW is nulla).


Ugyanezt a feltételvizsgálatot más módon is elvégezhetjük: kihasználhatjuk azt a tulajdonságot, hogy a k változó alacsonyabb és magasabb helyiértékű fele közötti bitenkénti "megengedő VAGY" (IOR) művelet eredmény csak akkor lesz nulla, ha k 32 bitje közül mindegyik nulla.

Ez így egy picivel hatékonyabb, mint az előző példában mutatott programrészlet, három utasítás helyett kettővel elintézzük a vizsgálatot.

Megjegyzés: talán még emlékszünk rá, hogy a MOV f{,WREG} típusú adatmozgatás beállítja az N és Z státuszbiteket. Mégsem írhatjuk a fenti programot egyszerűen így: 

A MOV f típusú utasítás ugyanis nem "ragadós" üzemmódban kezeli a Z bitet, így az mindig csak az utolsó művelet eredményének megfelelő állapotot mutatja.

Egy további példa 32 bites feltételvizsgálatra

Az alábbi példában a k || !j feltétel tulajdonképpen a (k!=0) || (j==0) összetett feltételt jelenti, tehát bármelyik részfeltétel teljesül, akkor az if törzse végrehajtandó. A k és j változók nullától való különbözőségét az előző példánál már jól bevált módon, a vizsgált változó alacsonyabb és magasabb helyiértékű fele közötti IOR művelettel vizsgáljuk.

Megjegyzés: Annak, hogy a nullától való különbözőséget az IOR utasítással vizsgáljuk, semmi köze ahhoz a tényhez, hogy az if utasítás feltételében most történetesen logikai vagy kapcsolat (||) állt. Ha az if utasításban (k && !j) állna, akkor is IOR utasítással vizsgálnánk a  nullától való különbözőséget.

Egyenlőség vizsgálata

Az alábbi példában 32 bites változók egyenlőségét vizsgáljuk. Az if utasítás törzsét akkor kell végrehajtani, ha az i == j feltétel teljesül. Az assembly nyelvű programban a feltétel vizsgálatát a CP/CPB utasításokkal oldjuk meg. Előbb az alacsonyabb helyiértékű 16 bites adatszavakat hasonlítjuk össze a CP utasítással, majd az áthozatot figyelembe vevő CPB utasítással hasonlítjuk össze a magasabb helyiértékű szavakat. Az áthozat helyes kezeléséhez ezt a kötött sorrendet be kell tartanunk!

A vizsgálat végén a Z=1 állapot jelzi, ha az i == j feltétel teljesült. Az if törzs kikerüléséhez szükséges ugrás feltétele pedig ennek ellentettje, amihez a BRA NZ utasítást használhatjuk.

Megjegyzés: A fenti programrészletben kihasználtuk azt, hogy a mov j+2,W0 utasítás nem módosítja a státuszbiteket. Emlékeztetünk azonban arra, hogy ez csak a MOV f,Wn típusú adatmozgatásra igaz (ahol Wn a W0..W15 regiszterek valamelyike). A MOV f,WREG utasítás ezzel szemben módosítja az N és Z státuszbiteket. Figyeljünk tehát arra, hogy ne keverjük össze a MOV f,W0 és a MOV f,WREG utasításokat!

A "nagyobb, mint..." feltétel vizsgálata

Az alábbi példában az i > j feltételt vizsgáljuk. Látható, hogy az előjel nélküli 32 bites változók összehasonlítása ugyanazzal az utasítás sorozattal történik, mint az előző esetben. Különbség csupán az if törzsét kikerülő elágaztató utasítás feltételében van: itt az i<=j ellentett feltételnek megfelelően a BRA LEU (Less or Equal Unsigned = kisebb, vagy egyenlő, előjel nélkül) utasítást használjuk.

Előjeles egész számok ábrázolása

Minden eddigi példában előjel nélküli számokkal, változókkal volt dolgunk. Természetesen, szeretnénk majd előjeles mennyiségekkel is dolgozni, műveletet végezni olyan számokkal, mint például -100 vagy +27. De ahhoz, hogy ezekre sor kerülhessen, előbb találnunk kell egy olyan bináris számábrázolási módszert, amellyel az előjeles számok is kezelhetők.  Az előjeles számok ábrázolására több lehetőség is kínálkozik, melyek közül a három legelterjedtebbet tekintjük át röviden. Ezeknél a számábrázolási módok két tulajdonságukban megegyeznek: az egyik tulajdonságuk az, hogy a pozitív számokat ugyanúgy ábrázolják, mint az előjel nélküli számábrázolásnál,  a másik pedig az, hogy negatív számok esetében a legmagasabb helyiértélű bit "1" állapotú.

Előjel-abszolútértékes ábrázolás

Az előjel-abszolútértékes (signed magnitude) ábrázolás onnan kapta a nevét, hogy az előjeles számokat egy előjelbittel és azt azt követő abszolútértékkel ábrázoljuk. A legmagasabb helyiértékű bitet használjuk az előjel tárolására (pozitív számoknál az előjelbit nulla, a negatív számoknál pedig 1), a maradék bitekbe pedig a szám abszolútértékét írjuk. A negatív számok ábrázolásának ez a legegyszerűbb módja, hiszen egyszerűen csak egy 1-est írunk az előjel helyére.

Például: 8 biten ábrázolva, -12 =  0x8C  = 0b1000 1100 

Ennek a számábrázolásnakaz az előnye, hogy az előjel és az abszolutérték közvetlenül rendelkezésre áll (pl. a szám negálásához csak az előjel bitet kell invertálni). Hátránya azonban, hogy kétféle ábrázolás is van a nullának, s nem használható ugyanaz a hardver az előjeles számokkal végzett műveletekhez, mint amelyik az előjel nélküli számokhoz való. Ezt a számábrázolási módot elsősorban BCD aritmetikához, illetve a lebegőpontos számábrázolásban használják.

Inverz kódú ábrázolás

Ez az ábrázolásmód is nagyon egyszerű. Az előjel helyére 1-et írunk a többi bitet pedig invertáljuk.

Egyes komplemens:   - N = ~(+N)

Az előző példára alkalmazva:  -12 = 0xF3 = 0b1111 0011

Az inverz kódú (vagy más néven egyes komplemens) ábrázolást egyes lyukszalag vezérlésű szerszámgépekben alkalmazzák, vagy némelyik hardver gyorsítós grafikus vezérlőben. Az előjel nélküli egész számokhoz való bináris összeadó áramköröket és logikát használhatjuk az inverz kódú ábrázolással kezelt előjeles számokra is, amennyiben tolerálható, hogy egyes esetekben az eredmény eggyel eltér a helyes értéktől, ami akkor fordul elő, ha két negatív, vagy egy pozitív és egy negatív számot adunk össze.




Ha megnézzük például a 8 bites számegyenes mentén elhelyezkedő számokat, akkor rájövünk, hogy miből adódik az eltérés azoknál az összeadásoknál,amelyek átlépik a nullát. Induljunk ki -1-ből, melyhez a 0xFE hexadecimális érték tartozik, s adjunk hozzá egyet! Az eredmény 0xFF, ami -0-nak felel meg. Adjunk hozzá mégegyet! Ekkor 0xFF-ből 0x00 lesz, ami +0-nak felel meg, ami eggyel kevesebb a várt eredménynél. Ha mégegyet hozzáadunk, akkor 0x01-et,azaz +1-et kapunk eredményül, ami megint eggyel kevesebb a vártnál.

Tehát azt kaptuk, hogy: -1 + 1 = -0;    -1 + 2 = +0;    -1 + 3 = +1   

Mindez azért van, mert a számegyenes kétfele szétcsúszott, -0 és +0 között van egy egységnyi hézag! Ha a negatív számok félegyenesét egy egységgel feljebb tolnánk, vagyis a negatív számokat úgy képeznénk, hogy az egyes komplemens képzése (bitenkénti invertálás) utan a számhoz egyet még hozzáadnánk, akkor kiküszöbölhetnénk a nullát átlépő összeadások problémáját. Most jön a meglepetés, pont ez lesz a beígért harmadik módszer, amelyet a mikroprocesszorok és mikrovezérlők elterjedten használnak!

Kettes komplemens kódú ábrázolás

Mind az előjel-abszolútértékes mind az inverz kódú ábrázolás nagy hibája, hogy problematikus az összeadás és a kivonás műveletének elvégzése illetve az eredmény értelmezése. További gondot jelent, hogy mindkét ábrázolásmódban pozitív és negatív számként is ábrázolhatjuk a zérust. Ez sajnos azt jelenti, hogy nincs kölcsönösen egyértelmű megfeleltetés a szimbólumsorozatok és az általuk ábrázolt szám között.

Ezeket a problémákat küszöböli ki a kettes komplemens kódú ábrázolás. Egy bináris szám kettes komplemensét úgy képezhetjük, hogy a szám inverzéhez hozzáadunk 1-et.

Kettes komplemens:   -N = ~(+N) + 1
A korábbi példára alkalmazva:  -12 = 0xF4 = 0b1111 0100


Előjeles decimális szám kettes komplemense

Ha van egy előjeles decimális (tízes számrendszerben felírt) N számunk, akkor hogyan képezzük annak a kettes komplenesét?  Például a  -N = ~(+N) + 1 képlet használatával az alábbi lépeseket hajtsuk végre:
Ha N pozitív konvertáljuk N-et hexadecimálisra! +60 = 0x3C
Ha N negatív 1. az előjelet elhagyva konvertáljuk N-et hexadecimálisra!

2. A hexadecimális számot írjuk át binárisra!

3. A bináris számot bitenként invertáljuk!

4. Az invertált számot írjuk vissza hexadecimális alakra, és adjunk hozzá egyet!

Az így kapott szám N kettes komplemense, ez lesz a -N szám  ábrázolása.

Hexadecimális számok konvertálása előjeles decimális számmá

Ha adott egy hexadecimális szám, a gyanútlan olvasóban felmerülhet a kérdés: honnan tudjuk, hogy az adott szám egyes vagy kettes komplemens ábrázolású előjeles szám, vagy pedig előjel nélküli szám? A válasz az, hogy magából a hexadecimális számból ez nem derül ki, hiszen pl. a legnagyobb helyiértékű bitre sincs ráírva, hogy ez most helyiérték vagy előjelbit. Ahhoz tehát, hogy egy adott számot helyesen értelmezzünk, többlet-tudásra, kiegészítő információra van szükségünk. Tudnunk kell, hogy milyen módszerrel kódolt, milyen konvenciók alapján kezelt adatról van szó, hogy mi is aszerint értelmezzük azt.

Nézzünk erre egy egyszerű példát! Ha egy regiszterből például 0xFE értéket olvasunk ki, akkor azt hogy értelmezzük?

0xFE ha előjel nélküli 8 bites egésznek vesszük = 254
0xFE ha kettes komplemens ábrázolású 8 bites előjeles egész = -2

Ha tudjuk, hogy az adott hexadecimális szám kettes komplemens ábrázolású előjeles egész, akkor az alábbi lépésekben konvertálhatjuk tízes számrendszerbe:

Első módszer:

  1. Megállapítjuk a szám előjelét. Ha a legmagasabb helyiértékű bit = 1 (a legmagasabb helyiértékű hexadecimális számjegy > 7), akkor negatív számról van szó (s folytassuk a 2. pontnál!),  ellenkező esetben pedig pozitív számról (akkor folytassuk az 5. pontnál!).
  2. A hexadecimális számot írjuk át binárisra!
  3. A bináris számot bitenként invertáljuk!
  4. Az invertált számot írjuk vissza hexadecimális alakra, és adjunk hozzá egyet!
  5. A kapott számot konvertáljuk 10-es számrendszerbe, és hozzáírjuk az előjelet!
Példa: értelmezzük az 0xF0 számot 8 bites, kettes komplemens ábrázolású számként!
1. Az első számjegy vizsgálata  F > 7,   0xF0 negatív szám
2. Binárissá alakítjuk 0xF0 = 0b1111 0000
3. Bitenként invertáljuk 0x0F = 0b0000 1111 
4. Visszaírjuk hexadecimális alakba, ésmegnöveljük 0x0F + 1 = 0x10
5. Tízes számrendszerbe konvertáljuk, s eléírjuk az előjelet 0x10 = 16 →  -16
Tehát a 0xF0 szám -16-ot jelent!

Második módszer:

Talán soknak tűnik ez a sok számrendszerváltás, de a bitenkénti invertálás bináris számrendszerben a legegyszerűbb, s a binárisból hexába vagy a hexából binárisba váltás roppant egyszerű, hiszen a hexadecimális rendszer számjegyei egy-egy négyjegyű számcsoportot alkotnak binárisba átírva. De ha a kivonás kényelmesebb, akkor a fenti leírás 2., 3. és 4. lépése helyett az átalakítandó N számot egyszerűen vonjuk ki 0-ból (nem törődve az átvitellel), kihasználva a 0 - (-N) = N azonosságot.

A fenti példa szerinti 0xF0-át értelmezve:  

az előjel = -   (mert F>7),
az abszolútérték = 0 - 0xF0 = 0x10 = 16

Tehát a szám -16!     

Túlcsordulás a kettes komplemens ábrázolású aritmetikában

Tekintsük például a 8 bites kettes komplemens ábrázolást, melynek felhasználásával -128 és +127 közötti számokat tudunk ábrázolni. Ha a  (+1) + (+127) = (+128) összeadással próbálkozunk, akkor mi történik, hiszen a +128 kívül esik az ábrázolható számtartományon.

  +127  =  0x7F
+   +1  =  0x01
-------------
   128  != 0x80 (ez valójában -128-nak felel meg a kettes komplemensű számábrázolásban)

Miből derül ki, hogy a fenti 8 bites összeadásban túlcsordulás történt? Abból, hogy két pozitív számot összeadtunk, és negatív lett az eredmény.

A fenti esethez hasonlóan túlcsordulás történhet akkor is, ha két negatív számot adunk össze, melyek összege -128-nál kisebb számot eredményezne (pl.  (-128) + (-1) = -129 ). Ilyen esetben - a túlcsordulás miatt - az eredmény pozitív lesz.

Az előjel nélküli számok összeadásánál a Carry bit jelezte a túlcsordulást. Megmutatjuk, hogy a kettes komplemens ábrázolású számok összeadásánál a Carry bit hasznavehetetlen, nem alkalmas a túlcsordulás jelzésére. Vegyük például a (+1) + (-1) = 0 összeadást, ami a 8 bites kettes komplemens ábrázolásban 0x01 + 0xFF alakba írható. Ez az összeg 0x00-t ad, tehát az eredmény helyes, ugyanakkor a legmagasabb helyiértéken keletkezett átvitel, tehát C=1. Tehát a Carry bit nem azt mutatja, hogy helyes-e az összeadásunk eredménye.

Az előjeles számokkal végzett műveletek esetén az SR regiszter OV státuszbitje jelzi, hogy történt-e túlcsordulás, ezt kell használnunk. Az OV státuszbitet a hardver a

V = CMSB ^ C MSB-1

képlet alapján állítja elő, ahol CMSB a legmagasabb helyiértéken keletkezett átvitel (vagyis ugyanaz, mint a Carry bit), CMSB-1 az eggyel kisebb helyiértékű biten keletkezett átvitel, a '^' jel pedig a kizáró vagy (XOR) logikai művelet jele.

Az alábbi egyszerű példákban bemutatjuk mind a négy lehetséges esetet a C és OV státuszbitek beállására.
Összeadó Előjel nélkül Előjelesen Összeadó Előjel nélkül Előjelesen
  0x01
+0xFF
  0x00

  
     1
+255
     0
     1
+  -1
     0
  0x80
+0xFF
  0x7F

  
  128
+255
  127
  -128
+    -1
  +127
C=1,  Z=1, OV=0,  N=0 C=1,  Z=0,  OV=1,  N=0
Összeadó Előjel nélkül Előjelesen Összeadó Előjel nélkül Előjelesen
  0x01
+0x7F
  0x80

  
      1
 +127
   128
      1
 +127
 -128
  0x80
+0x20
  0xA0

  
  128
+  32
  160
  -128
+  +32
    -96
C=0,  Z=0, OV=1,  N=1 C=0,  Z=0,  OV=0,  N=1
Figyeljük meg, hogy a Carry bit akkor nulla, amikor az előjel nélküli számokkal végzett összeadás eredménye helyes. Az OV (Overflow) bit pedig akkor nulla, amikor az előjeles (kettes komplemens ábrázolású) számok összeadás helyes.

Műveletek előjeles változókkal

A kettes komplemens ábrázolás egyik fő előnye, hogy az összeadás és kivonás az előjeles számokkal is ugyanúgy végezhető, mint az előjel nélküli számokkal (csak a túlcsordulást jelző bit lett más). Vannak azonban olyan műveletek, amelyeket az előjeles változókon más utasítással kell végrehajtani. Ezek áttekintését az alábbi összefogaló táblázat segíti.
Műveletek előjeles és előjel nélküli számokhoz Ugyanaz?
&, |, ^, ~ (bitenkénti logikai műveletek) igen
+, – igen
= =, !=
igen
<< (balra léptetés)
igen
>, >=, <, <=
nem
>> (jobbra léptetés)
nem
*, /  nem
Mint láthatjuk, a műveletek közül az összehasonlítás, a jobbra léptetés és a szorzás/osztás igényel "különleges elbánást" az előjeles számok esetében. Mivel a műveleteket a mikrovezérlőkben logikai kapukból kialakított áramkörök végzik, a másképp végzendő művelet azt jelenti, hogy másik áramkör lép működésbe, amihez természetesen más utasításkód, más assembly utasításnév (vagy módosító) tartozik, amelyekkel meg kell ismerkednünk, ha előjeles számokkal,változókkal akarunkdolgozni. Ezen utasítások közül ebben a fejezetben a jobbra léptetéssel és az előjeles feltételvizsgálatokkal foglalkozunk, a szorzást és az osztást majd egy későbbi fejezetben tárgyaljuk.


Az előző fejezetben már foglalkoztunk az aritmetikai jobbra léptetéssel, melynél a legmagasabb helyiértékű bit visszamásolódik a megürülő helyre (ezáltal megkettőződik). Ez biztosítja, hogy a kettes komplemens ábrázolásnál a jobbraléptetés megőrizze a szám előjelét. Az utasításnak van 8 és 16 bites változata is (használható hozzá a .B módosító). A kiléptetett legalacsonyabb helyiértékű bit pedig az SR státuszregiszter Carry bitjébe (C) másolódik.  A PIC24 utasításai közül az ASR utasítás végzi az aritmetikai jobbra léptetést, melynek operandusai, és címzésmódjai megegyeznek az LSR utasításéval.

Példa:  0x80 = -128 aritmetikai jobbra léptetése
           0x80 = 0b1000 0000    →  0b1100  0000 = 0xC0 = -64

Jobbra léptetés és kettővel történő osztás a C nyelvben

Az előjel nélküli számoknál volt róla szó, hogy a jobbra léptetés a kettővel történő osztásnak felel meg. Előjeles számoknál azonban más a helyzet. Az egyik probléma az, hogy jobbra léptetésnél implementációfüggő, hogy a fordító milyen utasításokra fordítja le a jobbra léptetést, vagyis hogy megőrzi-e az előjelet, vagy nullát léptet be a legmagasabb helyiértéken. A másik probléma pedig az, hogy negatív számok esetén az előjel megőrzése sem jelent garanciát arra, hogy a jobbra léptetés és a kettővel való osztás eredménye megegyezik - az eltérő kerekítés (pontosabb kifejezéssel élve: csonkítás) miatt. 
                       
A GNU C (ennek leszármazottja a PIC24 C fordító is) és a Visual Studio például osztásnál mindig a kisebb abszolútérték (vagyis a nulla, a számegyenes közepe) irányába csonkít, ha nem egész a hányados. Így tehát:
int8 k;
k = -5;   //ez 0xFB
k = k/2;  // –2 az eredmény, ami 0xFE

Jobbra léptetésnél viszont mindig "balra" (a -végtelen irányába) történik a "kerekítés". Így tehát:
k = -5; //this is 0xFB
k = k >> 1; // 0xFD-t ad vissza, ami –3!
Ha néhány számra felírjuk a kétféle művelet eredményét, akkor a tendenciából kiolvashatjuk a fent említett összefüggéseket. Az alábbi táblázatban -1 és -8 közötti számokra, 8 bites kettes komplemensű ábrázolásban  írtuk fel a kettővel való osztás és az aritmetikai jobbra léptetés eredményét.
k = k / 2; k = k >> 1;
-1 = 0b1111 1111 /2 = 0b0000 0000 =   0
-2 = 0b1111 1110 /2 = 0b1111 1111 =  -1
-3 = 0b1111 1101 /2 = 0b1111 1111 =  -1
-4 = 0b1111 1100 /2 = 0b1111 1110 =  -2
-5 = 0b1111 1011 /2 = 0b1111 1110 =  -2
-6 = 0b1111 1010 /2 = 0b1111 1101 =  -3
-7 = 0b1111 1001 /2 = 0b1111 1101 =  -3
-8 = 0b1111 1000 /2 = 0b1111 1100 =  -4
-1 = 0b1111 1111 >> 0b1111 1111 =  -1
-2 = 0b1111 1110 >> 0b1111 1111 =  -1
-3 = 0b1111 1101 >> 0b1111 1110 =  -2
-4 = 0b1111 1100 >> 0b1111 1110 =  -2
-5 = 0b1111 1011 >> 0b1111 1101 =  -3
-6 = 0b1111 1010 >> 0b1111 1101 =  -3
-7 = 0b1111 1001 >> 0b1111 1100 =  -4
-8 = 0b1111 1000 >> 0b1111 1100 =  -4
A fenti táblázatot az alábbi kis programmal is előállíthatjuk. Ne feledkezzünk meg a stdio.h becsatolásáról!
#include <p24hxxxx.h>
#include <stdio.h>
int i,j,k;

int main() {
  printf(" --- k = j / 2; ---\n");
  for(j=-1; j>-9; j--) {
    k = j/2;
    printf("%3d = %4X /2 = %04X = %3d\n",j,j,k,k);
  }

  printf("\n --- k = j >> 1; ---\n");
  for(j=-1; j>-9; j--) {
    k = j >> 1;
    printf("%3d = %4X >> 1 = %04X = %3d\n",j,j,k,k);
  }

return 0;
}
A program sikeres lefordításához a Project menü Build options/Project menüpontban az MPLAB LINK30 opciói között meg kell adni a Heap méretét (itt pl. 100 megfelelő érték lesz). A program kimenetének megjelenítéséhez pedig a Debugger/Settings menüpontban engedélyezni kell az Uart1 I/O-t (Enable elé pipa kell) és a kimenetet a képernyőablakba kell irányítani (Output = Window kiválasztása). A program kimenete ez lesz:
 --- k = j / 2; ---
 -1 = FFFF /2 = 0000 =   0
 -2 = FFFE /2 = FFFF =  -1
 -3 = FFFD /2 = FFFF =  -1
 -4 = FFFC /2 = FFFE =  -2
 -5 = FFFB /2 = FFFE =  -2
 -6 = FFFA /2 = FFFD =  -3
 -7 = FFF9 /2 = FFFD =  -3
 -8 = FFF8 /2 = FFFC =  -4

 --- k = j >> 1; ---
 -1 = FFFF >> 1 = FFFF =  -1
 -2 = FFFE >> 1 = FFFF =  -1
 -3 = FFFD >> 1 = FFFE =  -2
 -4 = FFFC >> 1 = FFFE =  -2
 -5 = FFFB >> 1 = FFFD =  -3
 -6 = FFFA >> 1 = FFFD =  -3
 -7 = FFF9 >> 1 = FFFC =  -4
 -8 = FFF8 >> 1 = FFFC =  -4

Láthatjuk tehát, hogy a kétfajta művelettel kapott kétféle eredmény nem a számábrázolás "hibája", hanem a kétféle "kerekítési" módszer eltéréséből adódik. Adott esetben el kell tehát döntenünk, hogy melyik műveletre van szükségünk, s ha jobbra léptetés kell, akkor használjuk azt, ha pedig osztás kell, akkor használjuk az osztási műveletet!

Előjeles feltételvizsgálat

A PIC24 mikrovezérlők két olyan állapotjelző bittel rendelkeznek, amelyek hasznosak az előjeles számokon végezett feltételvizsgálatoknál:

OV a kettes komplemens ábrázolású számokkal végzett műveleteknél a túlcsordulást jelzi
N a negatív eredményt jelzi (N = 1 lesz, ha az MSB = 1).

Fentieken kívül használható még a Z státuszbit is, ami ugyanúgy, mint az előjel nélküli számokkal végzett műveleteknél, itt is azt jelzi, hogy nulla volt-e az eredmény.

Az alábbi bonyolult ábrán bemutajuk, hogy az előjeles számok között végzett k-j kivonás hatására az SR státuszregiszter bitjei hogyan állnak be. Az ábráról leolvashatjuk a kisebb, nagyobb, kisebb vagy egyenlő, nagyobb vagy egyenlő feltételek teljesülését jelző státuszbit-állapotokat is. 

Az ábráról leolvashatjuk, hogy például a k>=j feltétel teljesüléséhez a k-j kivonás elvégzése után:
  1. Ha OV=0, vagyis nincs túlcsordulás, akkor N=0  (az eredmény nemnegatív) esetén teljesül a feltétel.
  2. Ha OV=1 , vagyis ha túlcsordulás történt, akkor pedig N=1 esetén teljesül a k>=j feltétel.

Szerencsére a PIC24 mikrovezérlők rendelkeznek előjeles feltételvizsgáló és elágaztató utasításokkal, amelyek egyetlen lépésben elvégzik a státuszbitek kiértékelését.
Megnevezés Az utasítás alakja Ugrás történik, ha...
Előjeles elágazás, > BRA GT, címke (~Z & N & OV) | (~Z & ~N & ~OV)
Előjeles elágazás, >= BRA GE, címke ( N & OV) | (~N & ~OV)
Előjeles elágazás, < BRA LT, címke ( N & ~OV) | (~N & OV)
Előjeles elágazás, <= BRA LE, címke ( N & ~OV) | (~N & OV ) | Z
A feltételes elágaztató utasítások előtt a szokásos módon vagy egy kivonást (SUB/SUBB) kell végeznünk, vagy az összehasonlító (CP/CPB) utasítást kell végrehajtani - ami szintán kivonást végez, csak az eredményt nem tároljuk el.
 
Az alábbi egyszerű példában 32 bites előjeles változókat hasonlítunk össze, a k > j feltétel teljesülését vizsgálva. A 32 bites összehasonlítás úgyanúgy történik, mint az előjel nélküli változóknál: az alacsony helyiértékű adatszavakat CP, a magas helyiértékű adatszavakat pedig az átvitelt is figyelembevevő CPB utasítással. A felteteles elágazásnál van csupán egy apró különbség: bra LEU,címke utasítás helyett most a bra LE,címke utasítást kell használnunk.     
 

Megjegyzés: az assembly programnál figyeljünk arra, hogy a 32 bites összehasonlításnál a státuszbiteket változalanul hagyó mov j+2,W0 helyett nehogy a mov j+2,WREG utasítást használjuk, mert az felülírja az előtte levő cp k utasítás által beállított státuszbiteket!

Előjel kiterjesztése

Még az olyan műveleteknél is, mint az összeadás és a kivonás, amelyek egyformán használhatók előjeles és előjel nélküli számokra, óvatosságra és körültekintésre van szükség, ha különböző bitszámú operandusokkal dolgozunk.  Az előző fejezet végén láttunk példát a típuskonverzióra előjel nélküli 8 és 16 bites változók összeadásánál. A kisebb bitszámú változót ki kellett egészíteni a másik változóval egyező méretre, mielőtt az összeadást elvégeztük volna. Az előjel nélküli változóknál egyszerűen nullával kell feltölteni a hiányzó magasabb helyiértékű biteket. Az előjeles változóknál mása helyzet, ezeknél a kisebb bitszámú változó előjelbitjével kell feltölteni a hiányzó magas helyiértékű biteket.

Az alábbi két ábrán 8 és 16, illetve 16 és 32 bites előjeles számok összeadására mutatunk egy-egy példát.
A 8 bites változót a mov.b utasítással töltjük be W0 alacsony helyiértékű felébe. W0 magas helyiértékű bájtjat a SE W0,W0 utasítással töltjük fel. Az utasítás mnemonikus kódjában a Sign Extend (előjel kiterjesztés) elnevezést ismerhetjük fel. Ez annyiban különbözik az előjel nélküli változók típuskonverziójánál használt ZE (zero extend) utasítástól, hogy az első operandus 7. bitjétől függően 0xFF vagy 0x00 tartalommal tölti fel a második operandus magasabb helyiértékű (8-15. bitek) bájtját. Ez a előjeles 8 bites szám előjelhelyes kiterjesztésének felel meg (8-bit → 16-bit típuskonverzió).


A 16-bit → 32-bit típuskonverzióhoz nincs külön utasítása a PIC24 mikrovezérlőknek, így a "magad uram, ha szolgád nincsen" elv alapján nekünk kell megoldani az előjel kiterjesztését (lásd az ábrán a bekeretezett szakaszt). Először betöltjük a 16 bites változó tartalmát a W0 regiszterbe, majd ennek legmagasabb helyiértékű bitjének (W0.#15)  értékétől függően 0xffff vagy 0x0000 tartalommal töltjük fel a W1 regisztert. Ez úgy csináljuk, hogy először feltöltjük 0-val (CLR = Clear, azaz Törlés), majd vizsgáljuk W0 15. bitjét (BTSC = Bit test and skip if clear, azaz bitvizsgálat, és átlépés, ha a bit nulla). A SETM W1 utasítás (ami minden bitet 1-be állít) csak akkor kerül végrehajtásra, ha W0 15. bitje 1-be volt állítva (negatív szám).

A BRA és a GOTO utasítás összehasonlítása

Elékeztetünk arra, hogy a GOTO utasítás két utasításszót foglal el, s benne egy 23 bites cím helyezhető el, amelyet közvetlenül betölt a PC utasításszámlálóba, így a programmemória bármelyik helyére átadható vele a vezérlés.

A BRA (branch = elágazás) utasítás ezzel szemben egy utasításszót foglal le, s egy négybites feltételkódot és egy 16 bites előjeles relatív címet tartalmaz, tehát adott feltételtől függően, a PC pillanatnyi tartalmához képest legfelejebb 32 767 utasításszónyi távolságra tud ugrani, előre vagy hátrafelé.

A BRA utasítás kódja: 
B23 ... B16 B15 ... B8 B7 ... B0
0011 bbbb nnnn nnnn nnnn nnnn
Ahol:
  bbbb      - az elágazási feltétel kódja
  nn ... nn - a relatív ugrási cím (#slit16, azaz 16 bites előjeles szám)

A BRA utasítás alakja:  BRA <feltétel>,<cél címe>

A nn..nn = #slit16 16 bites relatív címet a fordító számítja ki az alábbi képlet szerint:

#slit16 = [<cél címe> - (PCold +2)]/2, ahol PCold a BRA utasítás helyének címe.

Miért PCold+2 szerepel a fenti képletben? Azért, mert az utasítás végrehajtásakor PC már a következő utasításra mutat. A 2-vel történő osztás pedig azért van, mert az utasítások úgyis csak páros címen kezdődhetnek, ezért a relatív cím legalsó bitje mindig nulla, azt nem is tároljuk.  

Az alábbi táblázatban összefoglaltuk a feltételes ugró utasításokat, a hozzájuk tartozó bbbb feltételkódot, és az utasítás rövid funkcionális leírását.
bbbb Utasítás Funkció
0000 BRA OV Ugrás, ha OV=1 (túlcsordulás történt, előjeles)
0001 BRA C/GEU Ugrás, ha C=1 (nagyobb, vagy egyenlő, előjel nélkül)
0010 BRA Z Ugrás, ha Z=1 (nulla)
0011 BRA N Ugrás, ha N=1 (negatív)
0100 BRA LE Ugrás, ha kisebb vagy egyenlő mint... (előjeles)
0101 BRA LT Ugrás, ha kisebb mint... (előjeles)
0110 BRA LEU Ugrás, ha kisebb vagy egyenlő mint... (előjel nélkül)
0111 BRA  Ugrás feltétel nélkül
1000 BRA NOV Ugrás, ha OV=0 (nincs túlcsordulás, előjeles)
1001 BRA NC/LTU Ugrás, ha C=0 (kisebb mint, előjel nélkül)
1010 BRA NZ Ugrás, ha Z=0 (nem nulla)
1011 BRA NN Ugrás, ha N=0 (nemnegatív, előjeles)
1100 BRA GT Ugrás, ha nagyobb mint ... (előjeles)
1101 BRA GE Ugrás, ha nagyobb vagy egyenlő mint... (előjeles)
1110 BRA GTU Ugrás, ha nagyobb mint ... (előjel nélkül)

A BRA és a GOTO utasítás előnyei/hátrányai

A BRA utastás 16 bites relatív címet tartalmaz. Ez azt jelenti, hogy a cél helye az ugró utasítás helyétől számított  -32768 ... +32767 utasításszónyi tartományba kell, hogy essen.  A BRA utasítás hátránya tehát az, hogy csak korlátozott távolságon belül használható. Ez nem nagy probléma, a legtöbb elágazás vagy programciklus csak közeli címekre történő ugrást igényel. Előnye, hogy az ugrás feltételekhez köthető, s hogy csak egy utasításszónyi helyet foglal a memóriában.

A GOTO utasítás legfőbb előnye, az, hogy bárhová el lehet ugratni vele a programmemóriában. Hátránya, hogy két utasításszót foglal le.