Programovanie v assembleri na Atari Falcon – 1. časť – Vetvenie
Toto bude prvý článok z možno rozsiahlejšej série – uvidíme podľa ohlasov 🙂
Nebudem tu riešiť úplne základy, skôr také praktické veci čo sa ma ľudia občas pýtajú, resp. ktoré si často pri programovaní kladiem aj ja sám keďže sa k tomu dostávam len raz za uhorský rok, a následne pri tom zbytočne strácam čas.
Väčšina vecí bude platiť univerzálne pre všetky procesory Motorola 680×0, čiže to bude využiteľné aj pre ST/STE/TT ale aj pre Atari Falcon s CT60 a teda procesor 68060. Ale hlavné zameranie bude na Atari Falcon s procesorom Motorola 68030.
Vetvenie a podmienky vetvenia
Vetvenie sa štandardne realizuje inštrukciou Bcc, kde namiesto ‚cc‘ dosadíme kód podmienky (napr. NE pre Not Equal a teda ištrukcia bude BNE).
Klasická situácia nastáva ak porovnávam dve čísla a potrebujem vedieť ktorá konkrétna podmienka mi zabezpečí vetvenie a teda odskok a ktorá zabezpečí pokračovanie programu bez vetvenia. Čiže väčšinou použijem niečo ako:
cmp d0,d1
a hneď za tým chcem dať niečo ako:
bne odskok
a pod. (platí aj pre DBcc alebo Scc). A kedže stavový register (SR) a teda hlavne jeho časť označovaná CCR (Condition Code Register) nám ponúka kopec možností tak tu sú najčastejšie možnosti čo ma zaujímajú:
cmp d0,d1 | so znamienkom | bez znamienka |
d0 > d1 | BLT | BCS |
d0 >= d1 | BLE | BLS |
d0 = d1 | BEQ | BEQ |
d0 <> d1 | BNE | BNE |
d0 < d1 | BGT | BHI |
d0 <= d1 | BGE | BCC |
Alebo iný ešte praktickejší pohľad podľa hodnôt (bez znamienka) pre cmp d0,d1:
d0 | d1 | Odskočí | Neodskočí |
5 | 4 | BCS, BMI, BNE, BLT, BLS, BLE | BCC, BPL, BEQ, BGT, BHI, BGE |
5 | 5 | BCC, BPL, BEQ, BLS, BLE, BGE | BCS, BMI, BNE, BLT, BGT, BHI |
5 | 6 | BCC, BPL, BNE, BGT, BHI, BGE | BCS, BMI, BEQ, BLT, BLS, BLE |
Kompletný zoznam podmienok:
Kódovanie v inštrukcii | Kód | Podmienka | Platí ak: | Poznámka |
0000 | F | FALSE | Z = 1 | |
0001 | T | TRUE | Z = 0 | (BT alebo BRA) |
0010 | HI | High | C + Z = 0 | |
0011 | LS | Low or Same | C + Z = 1 | |
0100 | CC | Carry Clear | C = 0 | |
0101 | CS | Carry Set | C = 1 | |
0110 | NE | Not Equal | Z = 0 | |
0111 | EQ | Equal | Z = 1 | |
1000 | VC | oVerflow Clear | V = 0 | |
1001 | VS | oVerflow Set | V = 1 | |
1010 | PL | Plus | N = 0 | |
1011 | MI | Minus | N = 1 | |
1100 | GE | Greater or Equal | N (+) V = 0 | |
1101 | LT | Less Than | N (+) V = 1 | |
1110 | GT | Greater Than | Z + (N (+) V) = 0 | |
1111 | LE | Less or Equal | Z + (N (+) V) = 1 |
Testovať konkrétny register oproti nule je možné inštrukciou TST, napr:
tst d1
čo zodpovedá inštrukcii:
cmp #0, d1
Samozrejme jednotlivé príznaky (flagy) v CCR nám nastavujú aj iné inštrukcie a tak vetvenie dáva zmysel aj po vykonaní väčšiny inštrukcií a špeciálne aritmetických a logických 🙂
Optimalizácia:
Nakoľko inštrukcia Bcc obsahuje adresu kam má skočiť (po splnení podmienky) vo formáte priameho operandu ktorý tvorí ofset (posunutie) oproti aktuálnemu PC (Program Counter). Je dobré vždy zadefinovať aj veľkosť tohto operandu (ofsetu). Veľkosť môže byť Byte, Word alebo Long* (* Long iba pre 68020 a vyšší).
Rozdielna dĺžka inštrukcie v pamäti:
bne.s skok ; 2b v pamäti
bne.w skok ; 4b
bne.l skok ; 6b
Register CCR (Condition Code Register)
CCR sa skladá z najnižších ôsmich bitov SR a teda sa skladá z príznakov:
– – – X N Z V C
Jeho najvyššie tri bity (7., 6. a 5. bit) sú nevyužité a teda označené pomĺčkou ‚-‚.
X – eXtend – prenos pri viacnásobnej aritmetike – ako Carry, ale nastavený len pri viacnásobnej aritmetike (pozn. ak je nastavený eXtend, tak je určite zároveň nastavený aj Carry, naopak to vždy neplatí!)
N – Negative – znamienko výsledku – nastavený ak je výsledok záporný
Z – Zero – nulový výsledok – nastavený ak je výsledok rovný nula
V – oVerflow – pretečenie – nastavený ak došlo k pretečeniu pri znamienkovej aritmetike (napr. ak pri sčítaní dvoch kladných čísiel vzniklo v doplnkovej notácii číslo záporné)
C – Carry – prenos – obsahuje bit, ktorý bol pri operácií vytlačený z najvyššieho bitu výsledku.
Nultá časť: Devpac 3.10 – krátky komentovaný manuál
K dlzke tych skokov len dodam, ze vasm umoznuje ich dlzku generovat/optimalizovat automaticky. Takze nie je potrebne sa dopredu zamyslat, ci pojde o kratky alebo dlhy skok, proste sa pouzije ten, ktory tam pasuje.
zrovna tento tyzden mi mikro poradil pouzit jsr namiesto bsr, ked devpac pri bsr tvrdil, ze operand too large 🙂
jj, ale to bolo isto na ST/STE, lebo BSR rovnako ako Bcc podporuje na 68000 iba velkost Byte alebo Word. Long je podporovany az od 68020:
BSR
Attributes: Size = (Byte, Word, Long*)
*(MC68020, MC68030, MC68040 only)
Cize na Falcone by si s tym problem nemal 😉
jasne, bolo to ST.
K tej optimalizacii dodam, teda aspon na ST to tak plati:
– kod je rychlejsi ak podmienka nie je splnena a netreba skakat, cize optimalizovat kod vetvenia v loope tak, aby vacsina flow sla bez odskoku (ak viem ze 90% flow pojde cez jednu vetvu, pouzit na to vetvu bez skoku)
– ak sa riesia skutocne kriticke sekcie kodu (vnutro loopu a podobne), pouzivat len .s (alebo to iste .b) natvrdo a optimalizovat kod tak aby sa tam odskok zmestil a nespoliehat sa na kompiler ktory zvoli vhodnu dlzku odskoku – vzdy sa to nejako da popresuvat