8080 – příznaky a zásobník

Procesor potřebuje vědět, jak dopadla ta která instrukce, a občas si potřebuje nějaká data odložit na později.

Příznaky

O registru F jsem se už zmiňoval. Je to takový lehce mystický registr, do kterého se nedá přímo zapisovat a ze kterého se nedá přímo číst. Psal jsem, že v něm jsou uložené takzvané příznaky. Co to je?

Některé instrukce, převážně ty, co něco počítají, mohou dát najevo, že výsledek je v určitém formátu. Například že je nulový, záporný, jakou má paritu, nebo že při výpočtu přetekl výsledek z rozsahu 0-255. A přesně tyto informace ukládá jako příznakové bity do registru F.

U procesoru 8080 je příznakových bitů 5 a jsou v registru uloženy takto:

Bit 7 6 5 4 3 2 1 0
Příznak S Z 0 AC 0 P 1 CY
  • S (sign) informuje o znaménku výsledku. Je-li výsledek kladný, je to 0, je-li výsledek záporný, je to 1
  • Z (zero) je roven 1 v případě, že výsledek je nula. Pokud je nenulový, je Z = 0
  • AC (auxiliary carry) je roven 1, pokud při operaci došlo k přenosu přes polovinu bajtu (mezi nižší a vyšší čtveřicí)
  • P (parity) je nastaven vždy tak, aby doplnil počet jedniček ve výsledku na lichý (tedy 0, je-li lichý, 1, je-li sudý) – viz též paritní bit.
  • CY (carry) je 1, pokud dojde k přenosu z nejvyššího bitu.

Termín „přenos“ je možná nejasný, pojďme si ho upřesnit. Co se stane, když budu sčítat čísla 0FAh a 0Ah (250 a 10) v osmibitovém registru? Výsledek je 260, hexadecimálně 104h – a to je číslo, které má devět bitů. Devátý (nejvyšší) bit se do registru nevejde, tam zůstanou jen bity 0-7 (tedy osm bitů). Pokud taková situace nastane, je příznak CY nastaven na jedničku.

Tento příznak je velmi užitečný, pokud sčítáte vícebajtová čísla. Sečtete nejprve čísla na nižších řádech, a pokud je náhodou větší než možný rozsah, přenesete si jedničku do vyššího řádu.

Tentýž příznak funguje i pro odčítání – zde zase funguje jako označení „výpůjčky“ do nejvyššího řádu v případě, že výsledek je menší než 0. Když od čísla 04h odečteme číslo 05h, bude výsledek 0FFh (nezapomeňte, že hodnoty jdou za sebou a po nule je 0FFh). Příznak CY bude nastaven („půjčili“ jsme si jedničku), příznak S bude nastaven (výsledek je záporný).

Ve skutečnosti je -1 a 255 jedno a totéž číslo a je jen na nás, jestli se na něj díváme jako na číslo se znaménkem, nebo na číslo bez znaménka. -2 je 254, -3 je 253 atd. Pokud chceme v binární soustavě převést číslo na jeho zápornou hodnotu, uděláme bitovou negaci (zaměníme 0 za 1 a opačně) a přičteme jedničku (procesor na to samosebou má vhodnou instrukci).

A k čemu jsou příznaky dobré? Jednak pomáhají s výpočty, a jednak se můžete podle výsledků rozhodovat a provádět podmíněné skoky a volání podprogramů.

Zásobník

Občas procesor potřebuje, jak jsem už psal, nějaká data „odložit“ na později. Ať už to jsou data, co si potřebuje uložit programátor, nebo třeba adresa, kam se má program vrátit z podprogramu. Používá k tomu strukturu zvanou zásobník (stack). Stack je struktura typu LIFO (Last In – First Out, tedy co se poslední uloží, to se první vrátí). Implementace zásobníku je jednoduchá: V paměti si vyhradíte oblast, a adresu jejího konce +1 uložíte do registru SP (Stack Pointer). Zásobník je připravený.

Do zásobníku se vždy ukládají dva bajty, tedy buď adresa, nebo celý registrový pár. Pokud na zásobník uložíme pár HL, stane se toto: Procesor sníží SP o 1, na tuto adresu uloží obsah registru H, pak zase sníží SP o 1 a na tuto adresu uloží obsah registru L. Teď uložíme třeba pár BC: Procesor sníží SP o 1, na tuto adresu uloží obsah registru B, pak zase sníží SP o 1 a na tuto adresu uloží obsah registru C.

Když teď vyzvedneme hodnotu ze zásobníku – třeba do registrů DE – procesor vezme obsah z adresy SP, uloží ho do registru E, SP zvýší o 1, vezme obsah z adresy SP, uloží ho do registru D a opět zvýší SP o 1. SP teď ukazuje na předchozí položku a v DE máme tu poslední uloženou. Což byla, shodou okolností, zrovna hodnota z registrů B a C – nikde není psáno, že se musí údaje vybrat do téhož registru, z jakého byly uloženy.

Zásobník se tedy posouvá od vyšších adres k nižším. Proto se umisťuje na konec RAM, aby měl dost prostoru kam růst. Což s sebou nese riziko, že pokud uložíte do zásobníku příliš mnoho hodnot, klesne SP až tak, že další uložená data můžou přepsat váš program (tomuto stavu se říká přetečení zásobníku, stack overflow). Pokud umístíte zásobník POD program, může se zase stát, že poklesne až třeba do oblasti, kde je ROM. Oba stavy jsou chybné, znamenají téměř stoprocentně pád programu a většinou nastávají, když se program dostane do nekonečné smyčky, ve které se odskakuje nebo ukládá.

PUSH a POP

K uložení obsahu registrů do zásobníku slouží instrukce PUSH s jedním parametrem, a tím je jméno dvojice registrů (B, D, H), nebo „PSW“ – o kterém jsem se už zmiňoval. PSW (Program Status Word) je dvojice registrů A a F. Pro vybrání hodnot ze zásobníku slouží instrukce POP (a stejné parametry). Pojďme si zaexperimentovat: nastavíme si zásobník do paměti a budeme do něj ukládat a zase vybírat data.

Všimněte si nejprve toho, jak se do paměti ukládají data, když se vykonává instrukce PUSH. Později, při načítání zpět, je načítáme v jiném pořadí, takže registry nemají původní obsah.

Na konci minulé lekce jsem zadal úkol: vymyslet způsob, jak prohodit obsah registrových párů BC a HL. Předpokládám, že jste napsali něco takového:

Což je správně, ale přijdeme tím o obsah, který je v registru A. Pokud nám to nevadí, není co řešit. Ale pokud by nám to vadilo, dáme na začátek PUSH PSW a na konec POP PSW. Samozřejmě, spoléháme na to, že zásobník je správně nastavený, ale vzhledem k tomu, jak často je používaný, tak je to jedna z prvních věcí, co slušný programátor udělá.

No a s informacemi z této lekce můžete stejné zadání vyřešit třeba takto:

SPHL

Tato instrukce naplní registr SP obsahem dvojice registrů HL. Tedy SP = HL. Ptáte se, jak se zařídí opak, tedy jak zjistíte hodnotu registru SP a uložíte ji do HL? Tipujete instrukci HLSP? Ne, žádná taková není. Musíte použít konstrukci LXI H,0 a DAD SP (o instrukci DAD si řekneme víc v další lekci).

XTHL

Další instrukce, která vyměňuje hodnoty dvojic registrů. XTHL vymění hodnotu dvojice registrů HL s „poslední uloženou hodnotou na zásobníku“. Tedy: poslední hodnota, uložená na zásobníku, se ocitne v HL, a hodnota HL bude poslední hodnota na zásobníku.

Líbil se vám článek? Podpořte autora na Patreonu
Příspěvek byl publikován v rubrice 8080. Můžete si uložit jeho odkaz mezi své oblíbené záložky.

2 komentáře u 8080 – příznaky a zásobník

  1. Roman Bórik napsal:

    >> Pokud chceme převést číslo na jeho zápornou hodnotu, uděláme bitovou negaci (zaměníme 0 za 1 a opačně) a přičteme jedničku. <<

    Alebo to číslo odpočítame od nuly. Záleží samozrejme od situácie, kedy je ktorá alternatíva výhodnejšia časovo alebo dĺžkou kódu.

    • Martin Malý napsal:

      Aha, tady jsem to špatně formuloval. Myslel jsem „mentálně“ – v duchu si udělám jeho negaci a přičtu jedničku. V procesoru samozřejmě jinak. Upravím, díky.

Napsat komentář

Vaše emailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *