HRA

Catacombe
Herní styl Platformer (Scrolling Screen)
Multiplayer Bez multiplayeru
Rok vydání 1985
Programátor Stefan Posthuma
Grafik Stefan Posthuma

INTRO

Stavový registr


V závěru minulého dílu našeho-vašeho seriálu o programování v assembleru se PCH letmo zmínil o stavovém registru počítače. Pro ty, co se rádi dostávají věcem až "pod kůži" je určen tento díl, ve kterém se pokusím rozebrat tento poměrně důležitý registr dopodrobna.

Stavový registr (Status Register) se u C64 označuje zkratkou SR. Má velikost jednoho bajtu. Jeho jednotlivé bity se nazývají příznaky (flags) a jsou označeny následovně:
bit 7 6 5 4 3 2 1 0
příznak N V - B D I Z C

Nás v tomto díle budou zajímat hlavně 4 příznaky, označené tučně písmeny N, V, Z a C. Tyto příznaky se nazývají testovatelné a to proto, že můžeme v programu pomocí určitých instrukcí testovat jejich stav a program náležitě větvit.

K čemu to potřebuju znát?

Již v minulém díle jste si mohli všimnout kontrukcí typu:
INX
BNE skok někam
Z tohoto příkladu je patrné, že mezi těmito dvěma instrukcemi musí existovat nějaká vazba, nebo» jedna instrukce přičte k registru X hodnotu 1 a teprve v následující testujeme výsledek a odskakujeme někam jinam v programu v závislosti na výsledku. A od toho je tu právě Status Registr (dále SR), který v sobě ukládá informace o tom, že nastala určitá specifická situace.

V podstatě každý příznak (bit) může nabývat hodnoty 0 nebo 1. A pro každý z našich 4 příznaků existuje dvojice instrukcí, která tento stav testuje. Podívejte se na následující tabulku:
Název Stručný popis Větvení při 1 Větvení při 0
Z Nula (Zero); rovno BEQ BNE
C Přenos (Carry); větší nebo rovno BCS BCC
N Negativní; horní bit BMI BPL
V Přetečení (oVerflow); při práci se znaménkem BVS BVC

My si nyní rozebereme jednotlivé příznaky do detailu.

Příznak Z

Jeho označení je odvozeno od anglického Zero (nula). Pro případy srovnání by bylo vhodnější označení E ze slova Equal (rovný). Tento příznak je nastaven na "1" (setnut) ve všech případech, kdy nová hodnota některého z registrů A, X, Y je rovna nule. V opačném případě je resetnut (nastaven na "0"). Je tedy patrné, že označuje stav, kdy registr po provedení instrukce obsahuje $00 a jeho stav se nastavuje vždy, když instrukce provádí nějakou změnu obsahu registru (t.j. např. i LDX #$00). Při porovnávaní pomocí instrukcí CPX, CPY a CMP je setnut (Z = "1") při rovnosti hodnoty registru s hodnotou porovnávanou.

Jeho stav poté můžeme testovat pomocí instrukcí BEQ (Branch if EQual - větvi při rovnosti) a BNE (Branch if Not Equal - větvi při nerovnosti).

Příklad:
LDX #$05  ;vloz do registru X hodnotu $05
CPX #$06  ;porovnej s hodnotou $06
BNE $3000 ;skok na adresu $3000 pri Z=0
Co myslíte, bude program pokračovat dále za instrukcí BNE nebo skočí na adresu $3000? Správně, mo(u)dří už vědí. Program skočí na adresu $3000, protože instrukce CPX #$06 nastaví registr Z na 0, nebo» 6 není rovno 5. Pokud bychom použili instrukci BEQ, vše by bylo přesně naopak. Příznak Z je nastavován a testován velmi často, protože je ovlivňován mnoha instrukcemi.

Příznak C

Název tohoto příznaku je odvozen od slova "carry" (přenos). Je ovlivňován pouze instrukcemi pro porovnávání a aritmetickými instrukcemi pro sčítání, odečítání, násobení a dělení (rotace, probereme v dalších dílech). Využití příznaku C jste si již měli možnost vyzkoušet v minulém díle při sčítání a odčítání. Takže si zopakujme, že je využíván jako přenosový bit při výpočtech. Kdykoliv sčítání nebo násobení přesáhne hodnotu $FF nebo při odečítání dojde k podtečení pod nulu, dojde k nastavení tohoto bitu na "1".

Při porovnávání (CPX, CPY, CMP) je tento příznak setnut při obsahu registru větším nebo stejném jako je hodnota operandu. (např.: LDA #$03, CMP #$02 způsobí setnutí příznaku C, protože 3 je větší nebo rovno než 2).

Testován je instrukcemi BCS (Branch Carry Set - t.j. větvi při C = "1") a BCC (Branch Carry Clear - větvi při C = "0").
Také si připomeňme, že jeho stav můžeme přímo nastavit instrukcemi SEC (Set Carry) a CLC (Clear Carry).

Abychom tu jen teoreticky nedebatovali, bude nyní vhodné udělat si čas na malý příklad využití toho, co jsme se zatím naučili. Napíšeme si prográmek, který bude číst znaky z klávesnice, pokud to budou znaky 0-9, zobrazíme je na obrazovce. Pokud stiskneme "x", program se ukončí. Všechny ostatní klávesy budeme ignorovat.
V assembleru bude program jednodušší než si možná myslíte:
	*= $1000
znak	jsr $ffe4 ;volání rutiny <chrin> kernalu, přečte znak z klávesnice
		  ;a vloží jej do registru A
	cmp #"x"  ;je to znak "x"?
	beq konec ;pokud ano (Z="1") jdi na konec
	cmp #$30  ;je znak menší než "0"?
	bcc znak  ;pokud ano (C="0") jdi přečíst další znak
	cmp #$3a  ;je znak větší než "9"?
	bcs znak  ;pokud ano (C="1") nezajímá mě, jdi přečíst další znak
	sta $0400 ;zobraz znak na obrazovce
	jmp znak  ;jdi přečíst další znak

konec	rts	  ;konec programu
Teď si některá místa programu podrobněji vysvětlíme. Hned první instrukce JSR $ffe4 volá rutinu kernalu pro čtení znaku z klávesnice. JSR je zkratka z Jump SubRoutine. Kernal je soubor mnoha podprogramů, které počítač využívá pro jeho vlastní činnost, jako je čtení klávesnice, blikání kurzoru, zobrazování znaků na obrazovce, čtení a ukládání souborů atd... Jsou uloženy v paměti ROM a my jsme jeden z těchto podprogramů využili. Tato rutina vrací v registru A znak, který jsme stiskli na klávesnici. Pokud jsme nestiskli nic, v A bude 0. Po vstupu znaku zjistíme jestli to není "x", pokud ano ukončíme program.

Další věc, kterou je potřeba vědět jsou kódy znaků 0 - 9, abychom je mohli otestovat. Zatím nám bude stačit vědět, že to jsou kódy $30 - $39. (Detailně to probereme v některém dalším díle).
Následují tedy porovnání nejprve zda je znak menší než "0", v tom případě nás nezajímá a můžeme vesele číst další znak.
Poté zjistíme zda znak není větší než "9". Všimněte si, že porovnáváme s kódem $3a a ne $39. Je to z toho důvodu, že příznak C je setnut při hodnotě větší nebo rovné(!), jak jsme si vysvětlili dříve. Tzn. kdybychom porovnávali s kódem $39, znak "9" by se nám neobrazil (zkuste si to), proto musíme porovnávat s kódem o jednu větším. No a protože jsme v hexa-kódu, po $39 následuje $3a (nikoliv $40). Na to pozor, protože v tomto občas chybují i zdatní programátoři.

No a pak už jen vytiskneme znak na obrazovku a jdeme číst další. Je to celkem snadné, ne?

Příznak N
Název je odvozen od anglického slova Negative (Negativní). Tento příznak ukazuje, zda je číslo v registru kladné nebo záporné. Při počítaní s čísly "se znaménkem" se kladná a záporná čísla odlišují tím, zda mají nejvyšší bit "0" či "1". Nula označuje čísla kladná a jednička čísla záporná. Berte to zatím jako fakt, abychom se tu nemuseli pouštět také do aritmetiky "se znaménkem". Obsah tohoto bitu se nám promítne do příznaku N.

Příznak N je užíván stejně často jako příznak Z. Ovlivňuje jej každá instrukce, která mění obsah některého z registrů A, X, Y. Ovlivňují jej i instrukce pro porovnávání, ovšem tato skutečnost je z hlediska programátora nevýznamná. Pro správné chápání příznaku N je nutné mít osvojen převod mezi hexadecimálním a binárním zobrazením. Např. co provede s příznakem N instrukce LDA #$65? Po přepisu do binárního zobrazení ($65 = %0110 0101) vidíme, že horní bit je "0", proto bude N resetnut (také "0"). Naopak při instrukci LDX #$DA ($DA = %1101 1010) je horní bit "1" a příznak N se setne. Při podrobnějším průzkumu zjistíme, že N bude "0" pro čísla z rozsahu $00 - $7F (0 až 127) a N = "1" pro rozsah $80 - $FF (128 až 255).

Testovat jej můžeme instrukcemi BMI (Branch MInus - větvení při mínus, N = "1") a BPL (Branch PLus - větvení při plus, N = "0").

Jako příklad využití tohoto příznaku si můžeme napsat prográmek, který vypíše všechny znaky kromě inverzních. Inverzní znaky mají kód $80 a více, proto můžeme skvěle využít právě příznaku N.
	*= $1000

	ldx #$00	;začněme znakem $00
zpet	txa		;zkopíruj do A znak z X
	sta $0400,x	;vypiš znak na obrazovku
	inx		;přičti k X 1 - další znak
	bpl zpet	;dokud je kladný, znovu
	rts		;konec programu

Příznak V
Z anglického oVerflow (přetečení). Tento příznak má podobný význam jako C, jedná se o přetečení, ovšem význam má jen při práci s čísly "se znaménkem". Příznak V je ovlivňován pouze instrukcemi pro sčítání a odečítání.

V typickém programu pro procesor 65xx se užívá jen zřídka a mnohé programy čísla se znaménkem nepoužívají vůbec. Pro nás bude zajímavé pouze to, že příznak odráží stav 6. bitu registru podobně jako příznak N odráží stav 7. bitu. Toto se dá v určitých situacích využít např. pro testování stavu některých I/O portů. Na některých čipech procesorů řady 65xx je pro V vyveden zvláštní pin a příznak se pak dá setnout zvnějšku pomocí hardware.

Testovat jej můžeme instrukcemi BVS (Branch oVerflow Set - větvení při setnutém V) a BVC (Branch oVerflow Clear - větvení při V = "0"). Ještě existuje instrukce CLV (Clear oVerflow), pomocí které můžeme příznak V přímo vynulovat. Instrukce pro jeho přímé nastavení však bohužel neexistuje.

Závěr
Gratuluji, právě jste se dohrabali až do úplného závěru tohoto dílu seriálu o assembleru, který jsem věnoval popisu Stavového Registru. Pokud jste výklad přežili, máte tuhý kořínek. Pokud jste vše navíc pochopili, jste fakt dobří a máte u mne bod a také bonus v podobě krátkého popisu tří zbylých příznaků registru SR. ;)


Bonus
Pokud se podíváte na úlpný začátek tohoto textu uvidíte, že SR obsahuje ještě příznaky B, D a I. Co znamenají?

B - "Break": Indikátor přerušení. Je setnut pouze, pokud dojde k přerušení programu instrukcí BRK (Break)

D - "Decimal": Indikátor decimálního módu. Jedná se o desítkovou aritmetiku, která se však prakticky nepoužívá, takže se tím nebude příliš trápit. :)

I - "Interrupt disable": Někdy je vhodné mít zakázáno přerušení. To můžeme udělat instrukcí SEI (Set Interrupt disable), instrukce CLI (Clear Interrupt disable) zase přerušení povolí. V jakém je přerušení stavu nám indikuje právě příznak I.

- Ta pomlčka u 5. bitu značí, že tento bit je nepoužíván. Obvykle má hodnotu 1

A toto je už opravdu úplný konec, přátelé. Pokud budete mít nějaký dotaz, napište mi. Rád Vám jej zodpovím.

Luděk Smetana alias Myshaak
Nový příspěvek k článku

podpis :
První znak podpisu musí být vykřičník, jinak se příspěvek neodešle (ochrana proti spamu)

Advert

Hardcode and datamining by PCH of UNREAL, Hardware guru by RAY of UNREAL, Bugs report by SILLICON of UNREAL
UNREAL 2014-2021 Czech republic