Navigátorposledních 10 z diskuze |
Assembler 4. část - Sčítáme, odčítáme, skáčeme a kontrolujeme1. Přičítání po jedné k registrům .... a nejen to.
|
Příkaz SBC odečítá nejen hodnotu, ale i negované CARRY, což znamená, že potřebujeme-li se propracovat ke správnému výsledku rovnice kde 10 - 5 (+neg.carry) = 5 musíme mít CARRY nastavené na 1. (negovaná hodnota je 0 !!) |
Zde je ovšem nesmírně důležité zmínit jednu věc a to jsou FLAGY neboli příznaky neboli statusregistr.
Příznaky je 8 "ukazatelů" systému (statusregistr - nepleci si z registry) , které drží v paměti určité nastavení pomocí hodnot 0 a 1. (nastaveno / nenastaveno). Tyto příznaky jsou ovlivňovány nejen aritmetickýmy vypočty, ale například podmiňují instrukce pro matematické skoky , řídí přerušení ... zkrátka .. budeme si je představovat postupně, jak se s nimi budeme dostávat do "křížku".
Následující přiklad ukazuje vlastnost příznaku C dokonale. Příznak CARRY se automaticky přičítá k instrukcím přičítajícím a odečítajícím od akumulátoru !!! V příkladu to znamená toto: jestliže nastavíme carry na 1 (sec) , přičte se automaticky k našemu výpočtu ( 3 + 3) a na adrese $2000 kam ukádáme obsah akumulátoru naleznete hodnotu 7 !!!
V druhé části příkladu příznak carry vynulujeme (clc) a počítáme-li dále náš příklad v akumulátoru 3+3, na adrese $2001, kam výsledek ukádáme najdeme hodnotu 6 !!!!
Vždy je nutno (pokud není potřeba jinak) počítat s tím, že výsledek bude ovlivněn hodnotou příznaku CARRY. Vždy si musíte uvědomit, že chcete-li přesný výsledek při počítání akumulátorem, je potřeba carry nulovat instrukcí CLC.
Zde je potřeba říct a názprně ukázat, kdy se příznak CARRY automaticky nastavuje sám. Carry je ovlivněno přetečením počtů při sčítání a odčítání.
Jestliže přetáhnete součet nad hodnotu 255, carry se automaticky nastaví na 1. Při odečítání jestliže najdříve nastavíte carry na 1 a poté přetáhnete rozdíl přes 0 , to znamená, že se carry nastaví na 0 a vy dostanete výsledek přetočen o 255. A jak to vypadá v realu ?
Tento příklad je tak absolutně vševypovídající, že jestliže ho nepochopíte ... nečtěte dál !!!
Rozebereme si ho po řádku dopodrobna.
1.Začínáme tím, že nastavíme Carry na 0.
2. Jestliže sečteme čísla , která dávají výsledek větší než #$FF, příznak Carry přeteče a nastaví se na 1.
3.Výsledek sčítání je vlastně hodnota $1020 , což znamená, že carry je nastavena na 1 a v A je #$20.
4. Jestliže do dalšího počítání necháme nastavené carry z minula a nevynulejeme ji, potom výsledek počtu 1+1 nebude 2, ale přičte se i carry,tudíž výsledek bude 3. (Uloženo na adreses 2001)
5.
Druhá část příkladu je součet, který nepřeteče. To znamená, že po sečtení hodnot #$10+#$10 = $20 s tím rozdílem, že carry zůstane na hodnotě 0.
6.
Jestliže poté provedeme stejný součet jako v první části příkladu ... tzn. 1 + 1 a výsledek uložíme na adresu, zjistíme, že výsledek je opravdu 2.
To vše znamená, že s příznakem CARRY je potřeba opravdu počítat v pravém slova smyslu.
Tato obrazovka ukazuje problém negovaného Carry příznaku v odečítání hodnot. Jako ukázka k problematice sčítání i odčítání snad tyto příklady stačí.
Opravdu je potřeba pochopit a zafixovat si tyto pravidla dokonale, protože jinak se budete potkávat ve svých programech s "pro vás náhodnými výsledky" :)
samozřejmě, že matematické sčítání a odčítání můžeme provádět taktéž s adresami a hodnotami na nich uloženými.
Myslím,že není potřeba dalších komentářů. Práce s hodnotami na adresách je totožná jako operace s čísly "natvrdo" zadanými.
Syntaxy pro příkazy ADC a SBC jsou možné snad ve všech možných možnostech.
SBC #$xx
SBC $xxxx
SBC $xx
SBC ($xx,X)
SBC (xx),Y
SBC $xx,X
SBC $xxxx,X
SBC $xxxx,Y
První příklad , který si ukážeme je výpis ascii tabulky na obrazovku.
a výsledek
Příklad si rozebereme postupně.
1. Do X registru vložíme hodnotu 0
2. intrukce TAX udělá to, že obsah registru X uloží do A.
3. Akumulátor uložíme na adresu videoram $0400 a colorram $d800.
4. Přičteme instrukcí INX k X registru hodnotu 1
5. Jestliže přeteče registr X (přes #$FF) nastaví se flag Z (ZERRO) na 1. Instrukce BNE skáče až poté, co se ZERRO nastaví na 1.
Příznak Z - ZERRO se nastaví na 1 až pokud přeteče přičítání v registrech X a Y přes 255 ($ff) a nebo jestliže proběhne pravdivě instrukce pro kontrolu . (viz dále) |
Možná se Vám bude zdát, že skáči v popisu instrukcí halabala, ale není to tak. Příkazy pro podmíněné skoky jsou ruku v ruce s kontrolními instrukcemi, proto nadále budeme brát všechny zatím probrané příkazy s těmi novými dohromady.
Příkaz CMP - Compare acumulator dělá pouze to, že kontroluje, zda-li se v akumulátoru ocitla kontrolovaná hodnota.
Pokud ANO, potom se provede skok BEQ na proměnnou STOP.
Jestliže tato hodnota zatím nepřišla, instrukce BNE opakuje smyčku tak dlouho dokud ZERRO nebude 1. (díky INX).
Tento příklad zobrazí pouze 10 znaku na obrazovku. Další příklad provede to samé za pomocí kontroly X registru.
Je to ideální ukázka využití instrukce BEQ ... příkaz BEQ se dá použít i jako rozcestník podmínek, kde se hlídá více potřebných hodnot.
Tento příklad ukáže kontrolu na vyskytlý znak P ... prográmek zobrazí i informační text.
Jako obvykle si následující příklad rozebereme dopodrobna.
1. Ve smyčce je zde progámek pro výpis ASCII tabulky.
2. V těle programu je kontrola na znak P (všimněte si syntaxu na kontrolu znaku)
3. Jestliže program narazí na znak P, instrukce BEQ skočí na další program ZNAK
4. Program ZNAK začíná uložením akumulátoru do registru Y.
5. Po té následuje smyčka pro výpis dat TEXT, která kontroluje výpis 13-ti znaků
6. Po vypsání textu provedeme uložení znaku za řetězec. STY ...
Následující příklad bude kontrolovat zmáčknutí kláves přes rutinu kernalu. Budeme kontrolovat zmáčknutí dvou kláves.
Samozřejmě, že kontrolu můžeme rozšířit na kolik kláves potřebujeme.
Rutina na adrese $FFE4 vrací v akumulátoru hodnotu zmáčklé klávesnice. Kontrolujeme klávesu A a O ... jestliže tyto zmáčknete,zobrazí se informační věta o stisku. Všimněte si hlavně zápisu STY $0400+20 . Možnosti tuboassembleru jsou vynikající a tyto výpočty můžete klidně nechávat na něm ... no není to jednodušší ?? myslim, že jo :)
Také si všimněte podmíněných skoků BEQ a BNE v první části příkladu ... Myslím, že tento příklad ukazuje využití příkazů CMP, BEQ, BNE, INX, CPX takřka dokonale ... vše v jednom.
Naschvál jsem nezmínil příkazy INY, CPY ... tyto se chovají absolutně stejně jako s X registrem.
Samozřejmě, že instrukce pro porovnávání můžeme kontrolovat hodnoty na adresách .. CMP $1000 , CPX $1000 nebo CPY $1000 ... možnosti jsou obrovské.
Poslední dnes probranými skoky budou "matematické skoky" BMI a BPL. Využití je následné a myslím, že s vašimi nabitými znalostmi určitě snado zmáknutelné ..
Tento prográmek bude kontrolovat řetězec znaků se znakem G. Pokud bude znak v řetězci menší
(CMP #"g") napíše se 0. Jinak se napíše 1.
Se skoky BMI a BPL souvisí další s flagů a to N - NEGATIVE. Je li nastaven na 1, podmínka je splněna a to znamená skok BPL. Není-li splněna, funguje instrukce BMI.
Zkuste si pořadně prozkoumat tento prográmek. Myslím,že je to velmi elegantní řešení tohoto prográmku.
Možnosti těchto příkazů jsme si ukázali již výše. Seznamte se tímto pouze se suchým syntaxem.
TAX | přenese akumulátor do X registru |
TXA | přenese X registr do akumulátoru |
TAY | přenese akumulátor do Y registru |
TYA | přenese Y registr do akumulátoru |
TSX | přenese statusregistr do X registru |
TXS | přenese X registr do statusregistru |
Zde jen zaslouží pozornost instrukce TSX a TXS .. Je to ale velmi jednoduché. Statusregistr se ve vašem programu v určité fázi nachází v určitém stavu. Jestliže je potřeba tento stav zachovat, popřípadě z něj binárně číst, je možnost statusregistr uchovat do X registru. A protože jsme si říkali, že statusregistr má 8 ukazatelů, lze z něj přečítat bity velmi jednodušše. Statusregistr si ukážeme nyní.
N | V | # | B | D | I | Z | C |
* | . | * | * | . | . | . | * |
Statusregistr je ukazatelem stavu celého počítače.
C | Carry | Nastavuje se při početních operacích v případě že počet cyklů dosáhl 255 #FF |
Z | Zero | Nastavuje se při používání podmíněných skoků |
I | Interupt | Přerušení. Probíhá-li nějaké přerušení, I je nastaveno na 1 ... jinak 0 |
D | Decimal | Jestliže je D=1, pak počítač pracuje v tzv. BCD modu. Jinak v normálu. |
B | Break | Nepoužívaný příznak. Nedá se nastavit ani smazat. Slouží jako ukazatel, byl li program zastaven nebo ne. |
# | Nevyužito | Snad jasne ... :) |
V | Overflow | Protože Commodore 64 neumí počítat se zápornými čísly, pracuje počítač tímto způsobem. Je-li flag nastaven na 1, potom hodnoty $00-$7F jsou brány jako kladné. Přeteče-li hodnota přes $7F nastaví se V na 1 |
N | Negative | Jestliže se NEGATIVE nastaví na 1, pak je umožněno pracovat s OVERFLOW |
Takže pokud jste dočetli až sem a divíte se , proč je to tak blbě napsané, když to vše je přeci jasné, tak je tady několik možnosti.
1. Buď jste již měli s nějakým assemberem něco do činění
2. Jste rodillý assemblerista
3. Jste génius
4. Napsal jsem to dobře :)
JMP END
1530 | Bubble Bobble |
1486 | Great Giana Sisters , The |
1449 | Blackwyche |
1292 | Decathlon |
1284 | 3-D Labyrinth |
1258 | Entombed |
1223 | Staff of Karnath, The |
1205 | International Soccer |
1198 | Galactic Chaos |
1197 | Dinky Doo |