Zobrazení čísel a zpracování příznaků mikroprocesoru Zilog Z80

4. 4. 2023
Doba čtení: 35 minut

Sdílet

 Autor: Depositphotos
Nejprve si ukážeme, jak s využitím standardního podprogramu z ROM tisknout celá čísla. Tyto znalosti použijeme při zkoumání příznaků (flags) mikroprocesoru Zilog Z80, jejichž znalost je při programování v assembleru nedocenitelná.

Obsah

1. Zobrazení čísel a zpracování příznaků mikroprocesoru Zilog Z80

2. Podprogram pro tisk celočíselné hodnoty v rozsahu 0 až 9999

3. Ukázka použití podprogramu pro tisk celého čísla

4. Výsledek pokusu o vytištění záporných čísel

5. Tisk maximální podporované hodnoty a pokus o vytištění vyšší hodnoty

6. Vytištění číselné řady

7. Kombinace s dalšími subrutinami

8. Příznaky mikroprocesoru Zilog Z80

9. Seznam instrukcí, které modifikují příznakové bity

10. Zobrazení obsahu příznakového registru F po provedení vybrané operace

11. Příznakové bity po provedení celočíselné operace 1+2

12. Příznakové bity po provedení celočíselné operace 0+0

13. Příznakové bity po provedení operace 255+1

14. Příznakové bity po provedení operace 254+1

15. Příznakové bity po provedení operace 255+255

16. Příznakové bity po provedení operace 100+100

17. První shrnutí: význam příznaků C, V, S a Z

18. Příloha: upravený soubor Makefile pro překlad demonstračních příkladů

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Zobrazení čísel a zpracování příznaků mikroprocesoru Zilog Z80

V úvodní části dnešního článku si ukážeme způsob použití standardního podprogramu (subrutiny) uloženého v paměti ROM, který slouží pro výpis celých čísel na obrazovku. Tento podprogram byl sice původně určen pro specifické účely (konkrétně pro výpis čísel řádků v Sinclair BASICu), ovšem i přes jeho některá omezení bude podpora pro výpis numerických hodnot velmi užitečná v navazující části článku.

Obrázek 1: Výpis numerických hodnot na obrazovku podprogramem uloženým v ROM.

Navíc se podrobněji zmíníme o problematice příznaků (flags), které jsou nastavovány některými instrukcemi a které lze využít jak v podmíněných skocích, tak i v dalších typech strojových instrukcí (rotacích atd). Prozatím jsme totiž používali pouze dva příznaky, a to konkrétně carry (příznak přenosu) a zero (příznak nulovosti), ovšem mikroprocesor Zilog Z80 kromě toho nabízí i další příznaky, které lze využít jak ve výpočtech s hodnotami se znaménkem, tak i při realizaci některých optimalizací.

2. Podprogram pro tisk celočíselné hodnoty v rozsahu 0 až 9999

Jak jsme si již naznačili v úvodní kapitole, popíšeme si v dnešním článku nejdříve způsob použití standardního podprogramu uloženého v paměti ROM, který dokáže vypsat hodnotu celého čísla na obrazovku a přitom posunout pomyslný (neviditelný) kurzor takovým způsobem, aby tisk dalších znaků následoval až za nově zobrazeným číslem. Tento podprogram, jenž je i s dalšími podrobnostmi popsán například na stránce https://skoolkid.github.i­o/rom/asm/1A1B.html, začíná na adrese 0×1A1B a očekává na vstupu celé šestnáctibitové číslo uložené v registrovém páru BC (připomeňme si, že ROM je mapována od 0×0000 do 0×3fff). Číslo předané v registrovém páru BC je vytištěno a přitom subrutina nenávratně modifikuje obsah akumulátoru A a již zmíněného registrového páru BC (a podle očekávání i příznaků). Ostatní dva registrové páry DE a HL nejsou touto subrutinou modifikovány (jsou totiž uloženy na zásobník a před koncem subrutiny jsou obnoveny).

Obrázek 2: Tento podprogram je využíván například interpretrem Sinclair BASICu pro zobrazení čísel řádků.

Poznámka: numerická hodnota se vytiskne v decimální soustavě.

3. Ukázka použití podprogramu pro tisk celého čísla

Základní způsob použití výše zmíněného podprogramu je ve skutečnosti až triviální. Pouze nám postačuje smazat obrazovku (či alternativně otevřít kanál pro zápis na obrazovku – screen), vložit do registrového páru BC celočíselnou hodnotu, která se má vypsat a následně zavolat subrutinu pro tisk celého čísla. Vše lze realizovat čtyřmi (resp. jak uvidíme o odstavec dále, tak jen třemi) instrukcemi:

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
OUT_NUM_1     equ $1A1B
 
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
        ld   BC, 1234   ; numerická hodnota, kterou chceme vytisknout
        call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT

Způsob překladu tohoto programu do strojového kódu bude vypadat následovně:

ENTRY_POINT     EQU 8000
ROM_CLS         EQU 0DAF
OUT_NUM_1       EQU 1A1B
                ORG 8000
8000:           label start
8000:CDAF0D     CALL 0DAF
8003:01D204     LD BC, 04D2
8006:CD1B1A     CALL 1A1B
8009:C9         RET
800A:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8009
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu najdete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/61-print-number-A.asm.

Podívejme se na výsledek tak, jak ho uvidíme na obrazovce ZX Spectra:

Obrázek 3: Hodnota 1234 vytištěná na obrazovce ZX Spectra.

Poznámka na okraj – v případě, že program končí dvojicí instrukcí CALL + RET, můžeme program o jednu instrukci zkrátit. Je tomu tak z toho důvodu, že volaná subrutina (jakákoli) končí instrukcí RET (nebo její podmíněnou variantou), takže můžeme tuto instrukci „zneužít“ pro přímý návrat do BASICu. To konkrétně znamená, že následující dvojici řádků:

call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla
ret             ; návrat z programu do BASICu

je možné nahradit za jedinou instrukci:

jp OUT_NUM_1    ; zavolání rutiny pro výpis celého čísla + návrat

V dnešních demonstračních příkladech ovšem ponechávám delší variantu, aby bylo možné snadno a bez většího přemýšlení za volání OUT_NUM1 přidat další instrukce.

4. Výsledek pokusu o vytištění záporných čísel

Již v úvodním textu jsme si řekli, že standardní subrutina OUT_NUM1 byla původně určena pro tisk čísel řádků v Sinclair BASICu. S tím do značné míry souvisí i různá omezení, které tato subrutina má. Například nedokáže korektně vytisknout záporná čísla (to ovšem dává smysl, protože čísla řádků nemohou být záporná). O tomto omezení se můžeme velmi snadno přesvědčit překladem a spuštěním nepatrně upraveného demonstračního příkladu:

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
OUT_NUM_1     equ $1A1B
 
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
        ld   BC, -1234  ; numerická hodnota, kterou chceme vytisknout
        call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT

Výsledek bude vypadat následovně:

Obrázek 4: Výsledek pokusu o vytištění záporného čísla standardní subrutinou OUT_NUM1.

Poznámka: úplný zdrojový kód tohoto demonstračního příkladu najdete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/62-print-number-B.asm.

5. Tisk maximální podporované hodnoty a pokus o vytištění vyšší hodnoty

V Sinclair BASICu platí ještě další omezení na rozsah čísel řádků. Nejvyšší číslo řádku může mít hodnotu 9999 (což je zvláštní, protože další BASICy pro osmibitové mikropočítače mají méně umělé omezení na 32767 řádků nebo na 65535 řádků):

Obrázek 5: Program v BASICu s číslem řádku 9999.

Obrázek 6: Program v BASICu s číslem řádku 10000 je již nekorektní.

A rutina OUT_NUM1 toto omezení skutečně bere v úvahu, protože maximální celočíselná hodnota, kterou lze bez problémů vytisknout, je rovna právě 9999. Opět se o tom snadno přesvědčíme, a to překladem a spuštěním následujících dvou demonstračních příkladů. První příklad by měl vytisknout hodnotu 9999, druhý pak „pokaženou“ hodnotu 10000 (která již není podporována).

Obrázek 7: Vytištění maximální hodnoty podporované subrutinou OUT_NUM1.

Obrázek 8: Pokus o vytištění hodnoty 10000 subrutinou OUT_NUM1.

Zdrojový kód příkladu, jenž vytiskne hodnotu 9999:

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
OUT_NUM_1     equ $1A1B
 
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
        ld   BC, 9999   ; numerická hodnota, kterou chceme vytisknout
        call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu najdete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/63-print-number-C.asm.

Program, který se pokusí o vytištění hodnoty 10000:

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
OUT_NUM_1     equ $1A1B
 
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
        ld   BC, 10000  ; numerická hodnota, kterou chceme vytisknout
        call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu najdete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/64-print-number-D.asm.

6. Vytištění číselné řady

Vyzkoušejme si nyní tisk číselné řady, v níž jednotlivé hodnoty od sebe nebudou nijak odděleny. Nejprve vytiskneme číslici 1, potom ihned za ní číslici 2 atd. až do hodnoty 10. Výsledek zobrazený na obrazovce ZX Spectra by tedy měl vypadat následovně:

Obrázek 9: Celočíselné hodnoty 1, 2, … až 10 zobrazené za sebou, bez použití oddělovače.

Samozřejmě nám nic nebrání ve vložení volání subrutiny OUT_NUM1 do programové smyčky, která může mít následující strukturu:

        ld   BC, 1      ; numerická hodnota, kterou chceme vytisknout
next_number:
        call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla
        inc  C          ; a zvýšit o jedničku
        ld   A, C
        cp   11         ; kontrola na konec smyčky
        jr   nz, next_number

Problém ovšem spočívá v tom, že hodnota uložená v registrovém páru BC je v subrutině OUT_NUM1 poškozena a tudíž takto navržená smyčka nebude zcela funkční. Musíme tedy před voláním subrutiny obsah BC uschovat (například na zásobník nebo do druhé sady registrů) a po návratu ze subrutiny ji obnovit:

        ld   BC, 1      ; numerická hodnota, kterou chceme vytisknout
next_number:
        push BC         ; uchovat počitadlo
        call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla
        pop  BC         ; obnovit počitadlo
        inc  C          ; a zvýšit o jedničku
        ld   A, C
        cp   11         ; kontrola na konec smyčky
        jr   nz, next_number

Takto navržená programová smyčka již bude plně funkční a můžeme ji tedy použít v demonstračním příkladu, jenž bude mít tvar:

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
OUT_NUM_1     equ $1A1B
 
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
        ld   BC, 1      ; numerická hodnota, kterou chceme vytisknout
next_number:
        push BC         ; uchovat počitadlo
        call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla
        pop  BC         ; obnovit počitadlo
        inc  C          ; a zvýšit o jedničku
        ld   A, C
        cp   11         ; kontrola na konec smyčky
        jr   nz, next_number
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT

Pro úplnost se podívejme, jak je tento příklad přeložen do strojového kódu. Jeho délka je rovna sedmnácti bajtům:

ENTRY_POINT     EQU 8000
ROM_CLS         EQU 0DAF
OUT_NUM_1       EQU 1A1B
                ORG 8000
8000:           label start
8000:CDAF0D     CALL 0DAF
8003:010100     LD BC, 0001
8006:           label next_number
8006:C5         PUSH BC
8007:CD1B1A     CALL 1A1B
800A:C1         POP BC
800B:0C         INC C
800C:79         LD A, C
800D:FE0B       CP 0B
800F:20F5       JR NZ, 8006
8011:C9         RET
8012:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8011
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu najdete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/65-more-numbers-A.asm.

7. Kombinace s dalšími subrutinami

V úvodním textu jsme si řekli, že subrutina OUT_NUM1 byla navržena tak, aby ji mohl využívat přímo interpret Sinclair BASICu. Lze ji tedy zkombinovat s dalšími podprogramy určenými pro tisk textů a dalších hodnot na obrazovku ZX Spectra. Díky tomu je například možné po zobrazení celočíselné hodnoty vytisknout znak pro nový řádek subrutinou na adrese 0×10 (tu již dobře známe) a tím pádem provést odřádkování:

Obrázek 10: Hodnoty 1 až 10 vytištěné po sobě, ovšem s odřádkováním.

Aby se provedlo odřádkování, musíme programovou smyčku z předchozí kapitoly pouze rozšířit o vytištění řídicího znaku 0×0d. Podívejme se, jak úprava programu vypadá:

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
OUT_NUM_1     equ $1A1B
 
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
        ld   BC, 1      ; numerická hodnota, kterou chceme vytisknout
next_number:
        push BC         ; uchovat počitadlo
        call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla
        ld   A, 0x0d    ; kód znaku pro odřádkování
        rst  0x10       ; zavolání rutiny v ROM
        pop  BC         ; obnovit počitadlo
        inc  C          ; a zvýšit o jedničku
        ld   A, C
        cp   11         ; kontrola na konec smyčky
        jr   nz, next_number
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT
Poznámka: samozřejmě si můžete namísto znaku pro konec řádku vytisknout čárku, mezeru atd.

Způsob překladu tohoto demonstračního příkladu do strojového kódu:

ENTRY_POINT     EQU 8000
ROM_CLS         EQU 0DAF
OUT_NUM_1       EQU 1A1B
                ORG 8000
8000:           label start
8000:CDAF0D     CALL 0DAF
8003:010100     LD BC, 0001
8006:           label next_number
8006:C5         PUSH BC
8007:CD1B1A     CALL 1A1B
800A:3E0D       LD A, 0D
800C:D7         RST 10
800D:C1         POP BC
800E:0C         INC C
800F:79         LD A, C
8010:FE0B       CP 0B
8012:20F2       JR NZ, 8006
8014:C9         RET
8015:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8014
Poznámka: úplný zdrojový kód tohoto demonstračního příkladu najdete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/66-more-numbers-B.asm.

8. Příznaky mikroprocesoru Zilog Z80

Ve druhé části dnešního článku se budeme zabývat popisem příznaků (flags) osmibitového mikroprocesoru Zilog Z80. Jedná se o sadu šesti bitů, které jsou nastavovány mnoha strojovými instrukcemi (typicky instrukcemi aritmetickými, ale i mnoha dalšími, jak uvidíme dále) a mohou být testovány v podmíněných skocích, podmíněných skocích do podprogramů či podmíněných výskoků (návratů) z podprogramů. Všech šest příznaků je uloženo v příznakovém registru nazvaném příznačně F (od slova flags). Struktura tohoto registru vypadá následovně:

Bit 7 6 5 4 3 2 1 0
Příznak S Z x H y P/V N C

Jednotlivé příznakové bity mají následující význam:

Příznak Jméno Stručný popis
C carry příznak přenosu nebo výpůjčky, taktéž první nebo poslední bit u bitových posunů
N add/subtract nulovaný instrukcí ADD, nastavovaný instrukcí SUB
P/V parity/overflow lichá či sudá parita u logických operací, přetečení do znaménkového bitu u aritmetických operací
y ×  
H half carry přetečení ze čtvrtého do pátého bitu při provádění aritmetických operací
x ×  
Z zero příznak nulovosti výsledku
S sign nejvyšší (osmý) bit výsledku, který nese informace o znaménku

Mezi aritmetické operace pro zjednodušení počítáme i instrukci CP pro porovnání. Ta skutečně provede výpočet rozdílu, ovšem výsledek se zahodí; nastaví se pouze příznakové bity.

Poznámka: podrobnější informace o jednotlivých příznacích budou postupně uvedeny v navazujících kapitolách.

9. Seznam instrukcí, které modifikují příznakové bity

Na mikroprocesoru Zilog Z80 modifikuje příznakové bity mnoho strojových instrukcí. Tyto instrukce jsou vypsány v následující tabulce, přičemž je u každého příznaku uvedeno, jak se daný příznak instrukcí modifikuje. Význam symbolů použitých v této tabulce byl převzat ze stránky 80 MICROPROCESSOR Instruction Set Summary:

Symbol Význam
příznak zůstane nezměněn
* příznak je instrukcí změněn (na základě provedené operace)
0 příznak se vynuluje
1 příznak se nastaví na jedničku
? hodnota příznaku není oficiálně specifikována

Následuje slíbená tabulka s instrukcemi, z nichž každá nějakým způsobem modifikuje příznak či několik příznaků:

Instrukce S Z H P N C
ADC A,s * * * V 0 *
ADC HL,ss * * ? V 0 *
ADD A,s * * * V 0 *
ADD HL,ss ? 0 *
ADD IX,pp ? 0 *
ADD IY,rr ? 0 *
AND s * * * P 0 0
BIT b,m ? * 1 ? 0
CCF ? 0 *
CP s * * * V 1 *
CPD * * * * 1
CPDR * * * * 1
CPI * * * * 1
CPIR * * * * 1
CPL 1 1
DAA * * * P *
DEC s * * * V 1
IN r,[C] * * * P 0
INC r * * * V 0
INC [HL] * * * V 0
INC [xx+d] * * * V 0
IND ? * ? ? 1
INDR ? 1 ? ? 1
INI ? * ? ? 1
INIR ? 1 ? ? 1
LD A,i * * 0 * 0
LDD 0 * 0
LDDR 0 0 0
LDI 0 * 0
LDIR 0 0 0
NEG * * * V 1 *
OR s * * * P 0 0
OTDR ? 1 ? ? 1
OTIR ? 1 ? ? 1
OUTD ? * ? ? 1
OUTI ? * ? ? 1
RL m * * 0 P 0 *
RLA 0 0 *
RLC m * * 0 P 0 *
RLCA 0 0 *
RLD * * 0 P 0
RR m * * 0 P 0 *
RRA 0 0 *
RRC m * * 0 P 0 *
RRCA 0 0 *
RRD * * 0 P 0
SBC A,s * * * V 1 *
SBC HL,ss * * ? V 1 *
SCF 0 0 1
SLA m * * 0 P 0 *
SRA m * * 0 P 0 *
SRL m * * 0 P 0 *
SUB s * * * V 1 *
XOR s * * * P 0 0

10. Zobrazení obsahu příznakového registru F po provedení vybrané operace

V dalších kapitolách si na několika příkladech ukážeme, jakým způsobem jsou jednotlivé příznaky ovlivněny aritmetickými a jinými operacemi. Musíme být tedy schopni nějakým způsobem vytisknout hodnoty příznaků. Pro jednoduchost – protože pro vytištění příznaků sofistikovanějším způsobem je nutné vědět, jak příznaky používat :-) – se spokojíme s tím, že vytiskneme obsah celého osmibitového registru F. Jak to však můžeme provést? Prozatím umíme vytisknout numerickou hodnotu uloženou v registrovém páru BC, takže pouze musíme vynulovat obsah B a naopak přenést obsah registru F do registru C.

To ovšem nelze provést přímo instrukcí ld C, B, takže si musíme pomoci trikem – přesunem hodnot přes zásobník:

push AF         ; uložíme pár AF na zásobník
pop  BC         ; obnovíme původní obsah AF ze zásobníku, ovšem nyní do BC
ld   B, 0       ; vymažeme B (což byl obsah A), ponecháme jen C (což byl obsah F)

Nyní již registrový pár BC obsahuje původní hodnotu registru F v rozsahu 0 až 255, kterou lze snadno vytisknout na obrazovku:

call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla

Přesně tento postup použijeme v navazujících kapitolách.

11. Příznakové bity po provedení celočíselné operace 1+2

Nyní si vyzkoušejme, jaké příznakové bity budou nastaveny (či naopak nenastaveny) po provedení celočíselné operace 1+2 realizované instrukcí add, tedy konkrétně tímto způsobem:

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
OUT_NUM_1     equ $1A1B
 
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
 
        ld   A, 1       ; první sčítanec
        add  A, 2       ; druhý sčítance + výsledek operace
 
        push AF         ; uložíme pár AF na zásobník
        pop  BC         ; obnovíme původní obsah AF ze zásobníku, ovšem nyní do BC
        ld   B, 0       ; vymažeme B (což byl obsah A), ponecháme jen C (což byl obsah F)
 
        call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla
 
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT

Po překladu a spuštění tohoto příkladu zjistíme, že jsou všechny bity příznakového registru nulové:

Obrázek 11: Všechny bity příznakového registru F jsou nulové.

To konkrétně znamená následující:

Příznak Význam Hodnota Vysvětlení
C carry 0 bez přenosu do devátého bitu
N add/subtract 0 operace ADD
V overflow 0 bez přetečení do znaménkového bitu
H half carry 0 bez přenosu ze čtvrtého do pátého bitu
Z zero 0 výsledek je nenulový
S sign 0 výsledek je kladný

Dnes již naposledy si ještě pro úplnost ukážeme, jak vypadá překlad do strojového kódu:

ENTRY_POINT     EQU 8000
ROM_CLS         EQU 0DAF
OUT_NUM_1       EQU 1A1B
                ORG 8000
8000:           label start
8000:CDAF0D     CALL 0DAF
8003:3E01       LD A, 01
8005:C602       ADD A, 02
8007:F5         PUSH AF
8008:C1         POP BC
8009:0600       LD B, 00
800B:CD1B1A     CALL 1A1B
800E:C9         RET
800F:           END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 800E

12. Příznakové bity po provedení celočíselné operace 0+0

Nyní předchozí demonstrační příklad nepatrně upravíme, a to takovým způsobem, že budeme provádět součet 0+0 (s nulovým výsledkem). Zdrojový kód příkladu se změní jen nepatrně – viz zvýrazněnou část kódu:

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
OUT_NUM_1     equ $1A1B
 
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
 
        ld   A, 0       ; první sčítanec
        add  A, 0       ; druhý sčítance + výsledek operace
 
        push AF         ; uložíme pár AF na zásobník
        pop  BC         ; obnovíme původní obsah AF ze zásobníku, ovšem nyní do BC
        ld   B, 0       ; vymažeme B (což byl obsah A), ponecháme jen C (což byl obsah F)
 
        call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla
 
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT

Výsledná hodnota uložená do příznakového bitu bude nyní odlišná:

Obrázek 12: Nastaven je pouze sedmý bit příznakového registru F.

Nastaven je tedy pouze příznak/bit zero znamenající nulový výsledek poslední aritmetické nebo logické operace. To konkrétně znamená následující:

Příznak Význam Hodnota Vysvětlení
C carry 0 bez přenosu do devátého bitu
N add/subtract 0 operace ADD
V overflow 0 bez přetečení do znaménkového bitu
H half carry 0 bez přenosu ze čtvrtého do pátého bitu
Z zero 1 výsledek je nulový
S sign 0 výsledek je kladný

13. Příznakové bity po provedení operace 255+1

Nyní sečteme hodnoty 255+1. Výsledkem tedy bude nula (osmibitová hodnota přeteče přes 255), stejně jako tomu bylo v předchozím demonstračním příkladu. Ovšem budou stejně nastaveny i příznakové bity?

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
OUT_NUM_1     equ $1A1B
 
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
 
        ld   A, 255     ; první sčítanec
        add  A, 1       ; druhý sčítance + výsledek operace
 
        push AF         ; uložíme pár AF na zásobník
        pop  BC         ; obnovíme původní obsah AF ze zásobníku, ovšem nyní do BC
        ld   B, 0       ; vymažeme B (což byl obsah A), ponecháme jen C (což byl obsah F)
 
        call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla
 
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT

Výsledná dekadická hodnota 81 odpovídá binární hodnotě 01010001:

Obrázek 13: Příznakový registr obsahuje bity s hodnotami 01010001.

Výsledek součtu je tedy nulový, ovšem příznaky nám mohou napovědět, že se k výsledné nule došlo jiným způsobem:

Příznak Význam Hodnota Vysvětlení
C carry 1 s přenosem do devátého bitu (výsledek je větší než 255)
N add/subtract 0 operace ADD
V overflow 0 bez přetečení do znaménkového bitu
H half carry 1 s přenosem ze čtvrtého do pátého bitu
Z zero 1 výsledek je nulový
S sign 0 výsledek je kladný

14. Příznakové bity po provedení operace 254+1

Zkusme nyní první sčítanec o jedničku snížit a provést aritmetickou operaci 254+1. Výsledkem bude 255, což je hodnota, která se vejde do osmibitového výsledného registru. Ovšem hodnoty příznaků budou opět odlišné:

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
OUT_NUM_1     equ $1A1B
 
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
 
        ld   A, 254     ; první sčítanec
        add  A, 1       ; druhý sčítance + výsledek operace
 
        push AF         ; uložíme pár AF na zásobník
        pop  BC         ; obnovíme původní obsah AF ze zásobníku, ovšem nyní do BC
        ld   B, 0       ; vymažeme B (což byl obsah A), ponecháme jen C (což byl obsah F)
 
        call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla
 
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT

Výsledná dekadická hodnota 168 odpovídá binární hodnotě 10101000:

Obrázek 14: Příznakový registr obsahuje bity s hodnotami 10101000.

Příznakové bity jsou opět prakticky zcela odlišné od předchozích výsledků:

Příznak Význam Hodnota Vysvětlení
C carry 0 bez přenosu do devátého bitu (výsledek je menší nebo roven 255)
N add/subtract 0 operace ADD
V overflow 0 bez přetečení do znaménkového bitu
H half carry 0 bez přenosu ze čtvrtého do pátého bitu
Z zero 0 výsledek je nenulový
S sign 1 výsledek je záporný
Poznámka: změnily se i bity x a y, ty ovšem prozatím můžeme bez problémů ignorovat.

15. Příznakové bity po provedení operace 255+255

Pokračujme dále. Zajímavé bude zjistit, jak se bude chovat operace 255+255. Na tuto operaci se můžeme dívat jako na součet dvou celých kladných čísel nebo naopak jako na součet dvou celých čísel záporných, protože hodnota 255 je binárně uložena jako 11111111, což ovšem je současně i hodnota –1 v případě, že budeme operace provádět ve dvojkovém doplňku (samotné operace budou stejné, pouze interpretace operandů a výsledku je jiná):

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
OUT_NUM_1     equ $1A1B
 
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
 
        ld   A, 255     ; první sčítanec
        add  A, 255     ; druhý sčítance + výsledek operace
 
        push AF         ; uložíme pár AF na zásobník
        pop  BC         ; obnovíme původní obsah AF ze zásobníku, ovšem nyní do BC
        ld   B, 0       ; vymažeme B (což byl obsah A), ponecháme jen C (což byl obsah F)
 
        call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla
 
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT

Příznakový registr bude obsahovat dekadickou hodnotu 185, což binárně odpovídá 10111001.

Obrázek 15: Příznakový registr obsahuje bity s hodnotami 10111001.

Příznakové bity jsou opět odlišné od předchozích výsledků:

Příznak Význam Hodnota Vysvětlení
C carry 1 s přenosem do devátého bitu (výsledek je větší než 255)
N add/subtract 0 operace ADD
V overflow 0 bez přetečení do znaménkového bitu
H half carry 1 s přenosem ze čtvrtého do pátého bitu
Z zero 0 výsledek je nenulový
S sign 1 výsledek je záporný

16. Příznakové bity po provedení operace 100+100

V dnešním posledním demonstračním příkladu se pokusíme sečíst dvě hodnoty 100. Výsledkem je pochopitelně hodnota 200. Ovšem nyní dochází k zajímavé situaci, pokud budeme oba operandy i výsledek považovat za hodnoty se znaménkem reprezentované s dvojkovým doplňkem. Oba sčítance jsou stále kladnými hodnotami, ovšem 200 je bitově 11001000, což ve dvojkovém doplňku znamená –56 (a to ani nedošlo k přenosu!):

ENTRY_POINT   equ $8000
ROM_CLS       equ $0DAF
OUT_NUM_1     equ $1A1B
 
 
        org ENTRY_POINT
 
start:
        call ROM_CLS    ; smazání obrazovky a otevření kanálu číslo 2 (screen)
 
        ld   A, 100     ; první sčítanec
        add  A, 100     ; druhý sčítance + výsledek operace
 
        push AF         ; uložíme pár AF na zásobník
        pop  BC         ; obnovíme původní obsah AF ze zásobníku, ovšem nyní do BC
        ld   B, 0       ; vymažeme B (což byl obsah A), ponecháme jen C (což byl obsah F)
 
        call OUT_NUM_1  ; zavolání rutiny pro výpis celého čísla
 
        ret             ; návrat z programu do BASICu
 
end ENTRY_POINT

Na obrazovce ZX Spectra se zobrazí hodnota 140:

Obrázek 16: Příznakový registr obsahuje bity s hodnotami 10001100.

Příznakové bity jsou opět odlišné od předchozích výsledků:

Příznak Význam Hodnota Vysvětlení
C carry 0 bez přenosu do devátého bitu (výsledek je menší nebo roven 255)
N add/subtract 0 operace ADD
V overflow 1 s přetečením do znaménkového bitu
H half carry 0 bez přenosu ze čtvrtého do pátého bitu
Z zero 0 výsledek je nenulový
S sign 1 výsledek je záporný

17. První shrnutí: význam příznaků C, V, S a Z

Nyní si již můžeme shrnout význam čtyř příznakových bitů při provádění aritmetických operací:

Příznak S Z V C Poznámka
1+2 0 0 0 0 kladný výsledek
0+0 0 1 0 0 nulový výsledek
255+1 0 1 0 1 nulový výsledek, ovšem vzniklý přenosem (0=256)
254+1 1 0 0 0 nenulový výsledek větší než 127 (a tedy záporný ve dvojkovém doplňku)
255+255 1 0 0 1 nenulový výsledek větší než 127, který ovšem vznikl přenosem
100+100 1 0 1 0 záporný výsledek vzniklý součtem dvou kladných čísel
128+128 0 1 1 1 nulový nezáporný výsledek, došlo ovšem jak k přetečení, tak i přenosu (toto je specifický případ)
Poznámka: povšimněte si, že ne všechny kombinace příznaků mohou v praxi nastat. Příkladem je výsledek typu „záporná nula“ (tedy S=1 a současně Z=1) atd. Ovšem z tabulky je současně zřejmé, že Zilog Z80 lze použít jak pro výpočty s hodnotami bez znaménka (unsigned), tak i s hodnotami se znaménkem (signed). A dokonce jsou tyto výpočty jednodušší, než například na MOS 6502 atd.

Zbývá nám popis dvou dalších příznaků N a především příznaku H. Tyto příznaky jsou použity například v instrukci DAA, což je pravděpodobně nejkomplikovanější a nejhůře (oficiálně) popsaná instrukce Z80 vůbec.

Obrázek 17: Příznakový registr po provedení operace 128+128.

ict ve školství 24

18. Příloha: upravený soubor Makefile pro překlad demonstračních příkladů

Výše uvedené demonstrační příklady i příklady, které již byly popsány v předchozích sedmi článcích [1] [2], [3], [4], [5], [6], [7], je možné přeložit s využitím souboru Makefile, jehož aktuální verze vypadá následovně (pro překlad a slinkování je použit assembler Pasmo):

ASSEMBLER := pasmo
 
all: 01.tap 02.tap 03.tap 04.tap 05.tap 06.tap 07.tap 08.tap 09.tap 10.tap \
    11.tap 12.tap 13.tap 14.tap 15.tap 16.tap 17.tap 18.tap 19.tap 20.tap \
    21.tap 22.tap 23.tap 24.tap 25.tap 26.tap 27.tap 28.tap 29.tap 30.tap \
    31.tap 32.tap 33.tap 34.tap 35.tap 36.tap 37.tap 38.tap 39.tap 40.tap \
    41.tap 42.tap 43.tap 44.tap 45.tap 46.tap 47.tap 48.tap 49.tap 50.tap \
    51.tap 52.tap 53.tap 54.tap 55.tap 56.tap 57.tap 58.tap 59.tap 60.tap \
    61.tap 62.tap 63.tap 64.tap 65.tap 66.tap 67.tap 68.tap 69.tap 70.tap \
    71.tap 72.tap
 
clean:
        rm -f *.tap
 
.PHONY: all clean
 
 
01.tap: 01-color-attribute.asm
        $(ASSEMBLER) -v -d --tap $< $@ > 01-color-attribute.lst
 
02.tap: 02-blinking-attribute.asm
        $(ASSEMBLER) -v -d --tap $< $@ > 02-blinking-attribute.lst
 
03.tap: 03-symbolic-names.asm
        $(ASSEMBLER) -v -d --tap $< $@ > 03-symbolic-names.lst
 
04.tap: 04-operators.asm
        $(ASSEMBLER) -v -d --tap $< $@ > 04-operators.lst
 
05.tap: 05-better-symbols.asm
        $(ASSEMBLER) -v -d --tap $< $@ > 05-better-symbols.lst
 
06.tap: 06-tapbas-v1.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 06-tapbas-v1.lst
 
07.tap: 07-tapbas-v2.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 07-tapbas-v2.lst
 
08.tap: 08-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 08-loop.lst
 
09.tap: 09-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 09-loop.lst
 
10.tap: 10-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 10-loop.lst
 
11.tap: 11-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 11-loop.lst
 
12.tap: 12-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 12-loop.lst
 
13.tap: 13-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 13-loop.lst
 
14.tap: 14-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 14-loop.lst
 
15.tap: 15-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 15-loop.lst
 
16.tap: 16-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 16-loop.lst
 
17.tap: 17-loop.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 17-loop.lst
 
18.tap: 18-cls.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 18-cls.lst
 
19.tap: 19-print-char-call.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 19-print-char-call.lst
 
20.tap: 20-print-char-rst.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 20-print-char-rst.lst
 
21.tap: 21-print-char.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 21-print-char.lst
 
22.tap: 22-print-all-chars.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 22-print-all-chars.lst
 
23.tap: 23-print-all-chars.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 23-print-all-chars.lst
 
24.tap: 24-change-color.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 24-change-color.lst
 
25.tap: 25-change-flash.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 25-change-flash.lst
 
26.tap: 26-print-at.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 26-print-at.lst
 
27.tap: 27-print-string.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 27-print-string.lst
 
28.tap: 28-print-string.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 28-print-string.lst
 
29.tap: 29-print-colorized-string.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 29-print-colorized-string.lst
 
30.tap: 30-print-string-ROM.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 30-print-string-ROM.lst
 
31.tap: 31-attributes.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 31-attributes.lst
 
32.tap: 32-fill-in-vram.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 32-fill-in-vram.lst
 
33.tap: 33-fill-in-vram-no-ret.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 33-fill-in-vram-no-ret.lst
 
34.tap: 34-fill-in-vram-pattern.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 34-fill-in-vram-pattern.lst
 
35.tap: 35-slow-fill-in-vram.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 35-slow-fill-in-vram.lst
 
36.tap: 36-slow-fill-in-vram-no-ret.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 36-slow-fill-in-vram-no-ret.lst
 
37.tap: 37-fill-block.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 37-fill-block.lst
 
38.tap: 38-fill-block-with-pattern.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 38-fill-block-with-pattern.lst
 
39.tap: 39-fill-block-optimized.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 39-fill-block-optimized.lst
 
40.tap: 40-draw-char.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 40-draw-char.lst
 
41.tap: 41-draw-any-char.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 41-draw-any-char.lst
 
42.tap: 42-block-anywhere.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 42-block-anywhere.lst
 
43.tap: 43-block-anywhere-rrca.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 43-block-anywhere-rrca.lst
 
44.tap: 44-better-draw-char.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 44-better-draw-char.lst
 
45.tap: 45-even-better-draw-char.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 45-even-better-draw-char.lst
 
46.tap: 46-draw-char-at.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 46-draw-char-at.lst
 
47.tap: 47-draw-char-at-unrolled.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 47-draw-char-at-unrolled.lst
 
48.tap: 48-incorrect-print-string.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 48-incorrect-print-string.lst
 
49.tap: 49-correct-print-string.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 49-correct-print-string.lst
 
50.tap: 50-ascii-table.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 50-ascii-table.lst
 
51.tap: 51-plot-block.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 51-plot-block.lst
 
52.tap: 52-plot-pixel.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 52-plot-pixel.lst
 
53.tap: 53-plot-pixel.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 53-plot-pixel.lst
 
54.tap: 54-plot-pixel-on-background.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 54-plot-pixel-on-background.lst
 
55.tap: 55-plot-pixel-on-background.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 55-plot-pixel-on-background.lst
 
56.tap: 56-inverse-ascii-table.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 56-inverse-ascii-table.lst
 
57.tap: 57-plot-pixel-on-inverse-background.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 57-plot-pixel-on-inverse-background.lst
 
58.tap: 58-plot-inverse-pixel-on-inverse-background.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 58-plot-inverse-pixel-on-inverse-background.lst
 
59.tap: 59-configurable-ascii-table.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 59-configurable-ascii-table.lst
 
60.tap: 60-plot-over.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 60-plot-over.lst
 
61.tap: 61-print-number-A.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 61-print-number-A.lst
 
62.tap: 62-print-number-B.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 62-print-number-B.lst
 
63.tap: 63-print-number-C.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 63-print-number-C.lst
 
64.tap: 64-print-number-D.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 64-print-number-D.lst
 
65.tap: 65-more-numbers-A.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 65-more-numbers-A.lst
 
66.tap: 66-more-numbers-B.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 66-more-numbers-B.lst
 
67.tap: 67-print-flags-1.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 67-print-flags-1.lst
 
68.tap: 68-print-flags-2.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 68-print-flags-2.lst
 
69.tap: 69-print-flags-3.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 69-print-flags-3.lst
 
70.tap: 70-print-flags-4.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 70-print-flags-4.lst
 
71.tap: 71-print-flags-5.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 71-print-flags-5.lst
 
72.tap: 72-print-flags-6.asm
        $(ASSEMBLER) -v -d --tapbas $< $@ > 72-print-flags-6.lst

19. Repositář s demonstračními příklady

V tabulce zobrazené pod tímto odstavcem jsou uvedeny odkazy na všechny prozatím popsané demonstrační příklady určené pro překlad a spuštění na osmibitovém domácím mikropočítači ZX Spectrum (libovolný model či jeho klon), které jsou psány v assembleru mikroprocesoru Zilog Z80. Pro překlad těchto demonstračních příkladů je možné použít například assembler Pasmo (viz též úvodní článek):

# Soubor Stručný popis Adresa
1 01-color-attribute.asm modifikace jednoho barvového atributu https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/01-color-attribute.asm
2 02-blinking-attribute.asm barvový atribut s nastavením bitů pro blikání a vyšší intenzitu https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/02-blinking-attribute.asm
3 03-symbolic-names.asm symbolická jména v assembleru https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/03-symbolic-names.asm
4 04-operators.asm operátory a operace se symbolickými hodnotami https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/04-operators.asm
5 05-better-symbols.asm tradičnější symbolická jména https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/05-better-symbols.asm
6 06-tapbas-v1.asm vygenerování BASICovského loaderu (neúplný příklad) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/06-tapbas-v1.asm
7 07-tapbas-v2.asm vygenerování BASICovského loaderu (úplný příklad) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/07-tapbas-v2.asm
8 08-loop.asm jednoduchá počítaná programová smyčka: naivní varianta https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/08-loop.asm
9 09-loop.asm programová smyčka: zkrácení kódu pro vynulování použitých pracovních registrů https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/09-loop.asm
10 10-loop.asm programová smyčka: optimalizace skoku na konci smyčky (instrukce DJNZ) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/10-loop.asm
11 11-loop.asm programová smyčka: optimalizace využití pracovních registrů https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/11-loop.asm
12 12-loop.asm programová smyčka: použití pracovního registru IX https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/12-loop.asm
13 13-loop.asm programová smyčka: použití pracovního registru IY https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/13-loop.asm
14 14-loop.asm programová smyčka se šestnáctibitovým počitadlem, základní varianta https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/14-loop.asm
15 15-loop.asm programová smyčka se šestnáctibitovým počitadlem, vylepšená varianta https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/15-loop.asm
16 16-loop.asm použití relativního skoku a nikoli skoku absolutního https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/16-loop.asm
17 17-loop.asm programová smyčka: inc l namísto inc hl https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/17-loop.asm
       
18 18-cls.asm smazání obrazovky a otevření kanálu číslo 2 (screen) přes funkci v ROM https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/18-cls.asm
19 19-print-char-call.asm smazání obrazovky a výpis jednoho znaku na obrazovku přes funkci v ROM (použití instrukce CALL) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/19-print-char-call.asm
20 20-print-char-rst.asm smazání obrazovky a výpis jednoho znaku na obrazovku přes funkci v ROM (použití instrukce RST) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/20-print-char-rst.asm
21 21-print-char.asm pouze výpis jednoho znaku na obrazovku bez jejího smazání https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/21-print-char.asm
22 22-print-all-chars.asm výpis znakové sady znak po znaku (nekorektní verze příkladu) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/22-print-all-chars.asm
23 23-print-all-chars.asm výpis znakové sady znak po znaku (korektní verze příkladu) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/23-print-all-chars.asm
24 24-change-color.asm změna barvových atributů (popředí a pozadí) vypisovaných znaků https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/24-change-color.asm
25 25-change-flash.asm povolení či zákaz blikání vypisovaných znaků https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/25-change-flash.asm
26 26-print-at.asm výpis znaku či znaků na určené místo na obrazovce https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/26-print-at.asm
27 27-print-string.asm výpis celého řetězce explicitně zapsanou programovou smyčkou (základní varianta) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/27-print-string.asm
28 28-print-string.asm výpis celého řetězce explicitně zapsanou programovou smyčkou (vylepšená varianta) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/28-print-string.asm
29 29-print-colorized-string.asm výpis řetězce, který obsahuje i řídicí znaky pro změnu barvy atd. https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/29-print-colorized-string.asm
30 30-print-string-ROM.asm výpis řetězce s využitím služby/subrutiny uložené v ROM ZX Spectra https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/30-print-string-ROM.asm
       
31 31-attributes.asm modifikace atributů pro tisk řetězce subrutinou uloženou v ROM https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/31-attributes.asm
32 32-fill-in-vram.asm vyplnění celé bitmapy barvou popředí, návrat do systému https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/32-fill-in-vram.asm
33 33-fill-in-vram-no-ret.asm vyplnění celé bitmapy barvou popředí, bez návratu do systému https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/33-fill-in-vram-no-ret.asm
34 34-fill-in-vram-pattern.asm vyplnění celé bitmapy zvoleným vzorkem https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/34-fill-in-vram-pattern.asm
35 35-slow-fill-in-vram.asm pomalé vyplnění celé bitmapy, vizualizace struktury bitmapy https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/35-slow-fill-in-vram.asm
36 36-slow-fill-in-vram-no-ret.asm pomalé vyplnění celé bitmapy, vizualizace struktury bitmapy, bez návratu do systému https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/36-slow-fill-in-vram-no-ret.asm
37 37-fill-block.asm vykreslení bloku 8×8 pixelů https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/37-fill-block.asm
38 38-fill-block-with-pattern.asm vykreslení bloku 8×8 pixelů zvoleným vzorkem https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/38-fill-block-with-pattern.asm
39 39-fill-block-optimized.asm optimalizace předchozího příkladu https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/39-fill-block-optimized.asm
40 40-draw-char.asm vykreslení znaku do levého horního rohu https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/40-draw-char.asm
41 41-draw-any-char.asm podprogram pro vykreslení libovolně zvoleného znaku do levého horního rohu https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/41-draw-any-char.asm
42 42-block-anywhere.asm podprogramy pro vykreslení bloku 8×8 pixelů kamkoli na obrazovku https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/42-block-anywhere.asm
       
43 43-block-anywhere-rrca.asm podprogramy pro vykreslení bloku 8×8 pixelů kamkoli na obrazovku, vylepšená varianta https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/43-block-anywhere-rrca.asm
44 44-better-draw-char.asm vykreslení znaku v masce 8×8 pixelů, vylepšená varianta https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/44-better-draw-char.asm
45 45-even-better-draw-char.asm posun offsetu pro vykreslení dalšího znaku https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/45-even-better-draw-char.asm
46 46-draw-char-at.asm vykreslení znaku v masce 8×8 pixelů kamkoli na obrazovku https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/46-draw-char-at.asm
47 47-draw-char-at-unrolled.asm vykreslení znaku v masce 8×8 pixelů kamkoli na obrazovku https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/47-draw-char-at-unrolled.asm
48 48-incorrect-print-string.asm tisk řetězce, nekorektní varianta https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/48-incorrect-print-string.asm
49 49-correct-print-string.asm tisk řetězce, korektní varianta https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/49-correct-print-string.asm
       
50 50-ascii-table.asm tisk několika bloků ASCII tabulky https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/50-ascii-table.asm
51 51-plot-block.asm vykreslení pixelu verze 1: zápis celého bajtu na pozici pixelu https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/51-plot-block.asm
52 52-plot-pixel.asm vykreslení pixelu verze 2: korektní vykreslení jednoho pixelu, ovšem překreslení celého bajtu https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/52-plot-pixel.asm
53 53-plot-pixel.asm vykreslení pixelu verze 3: vylepšená verze předchozího demonstračního příkladu https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/53-plot-pixel.asm
54 54-plot-pixel-on-background.asm vykreslení pixelu vůči pozadí (nekorektní varianta) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/54-plot-pixel-on-background.asm
55 55-plot-pixel-on-background.asm vykreslení pixelu vůči pozadí (korektní varianta) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/55-plot-pixel-on-background.asm
       
56 56-inverse-ascii-table.asm vykreslení ASCII tabulky inverzní barvou (inkoust vs. papír) https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/56-inverse-ascii-table.asm
57 57-plot-pixel-on-inverse-background.asm vykreslení pixelů barvou papíru proti inverzní ASCII tabulce https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/57-plot-pixel-on-inverse-background.asm
58 58-plot-inverse-pixel-on-inverse-background.asm vykreslení pixelů inverzní barvou proti inverzní ASCII tabulce https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm58-plot-inverse-pixel-on-inverse-background.asm/
59 59-configurable-ascii-table.asm vykreslení ASCII tabulky buď přímo inkoustem nebo inverzně https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/59-configurable-ascii-table.asm
60 60-plot-over.asm přibližná implementace příkazu PLOT OVER https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/60-plot-over.asm
       
61 61-print-number-A.asm ukázka použití podprogramu pro tisk celého čísla https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/61-print-number-A.asm
62 62-print-number-B.asm pokus o vytištění záporných čísel https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/62-print-number-B.asm
63 63-print-number-C.asm tisk maximální podporované hodnoty 9999 https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/63-print-number-C.asm
64 64-print-number-D.asm tisk vyšší než podporované hodnoty 10000 https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/64-print-number-D.asm
65 65-more-numbers-A.asm vytištění číselné řady https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/65-more-numbers-A.asm
66 66-more-numbers-B.asm kombinace tisku celočíselných hodnot s dalšími subrutinami https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/66-more-numbers-B.asm
67 67-print-flags-1.asm příznakové bity po provedení celočíselné operace 1+2 https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/67-print-flags-1.asm
68 68-print-flags-2.asm příznakové bity po provedení celočíselné operace 0+0 https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/68-print-flags-2.asm
69 69-print-flags-3.asm příznakové bity po provedení operace 255+1 https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/69-print-flags-3.asm
70 70-print-flags-4.asm příznakové bity po provedení operace 254+1 https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/70-print-flags-4.asm
71 71-print-flags-5.asm příznakové bity po provedení operace 255+255 https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/71-print-flags-5.asm
72 72-print-flags-6.asm výsledek operace 100+100, nastavení příznakových bitů https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/72-print-flags-6.asm
73 73-print-flags-7.asm výsledek operace 128+128, nastavení příznakových bitů https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/73-print-flags-7.asm
       
Makefile Makefile pro překlad a slinkování všech demonstračních příkladů do podoby obrazu magnetické pásky https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/Makefile

20. Odkazy na Internetu

  1. z80 standalone assembler
    https://www.asm80.com/one­page/asmz80.html
  2. The ZX BASIC Compiler
    https://www.boriel.com/pages/the-zx-basic-compiler.html
  3. Z80 Assembly programming for the ZX Spectrum
    https://www.chibiakumas.com/z80/ZXSpec­trum.php
  4. 8-BIT SMACKDOWN! 65C02 vs. Z80: slithy VLOGS #6
    https://www.youtube.com/wat­ch?v=P1paVoFEvyc
  5. Instrukce mikroprocesoru Z80
    https://clrhome.org/table/
  6. Z80 instructions: adresní režimy atd.
    https://jnz.dk/z80/instructions.html
  7. Z80 Instruction Groups
    https://jnz.dk/z80/instgroups.html
  8. Elena, New programming language for the ZX Spectrum Next
    https://vintageisthenewold.com/elena-new-programming-language-for-the-zx-spectrum-next/
  9. Sinclair BASIC
    https://worldofspectrum.net/legacy-info/sinclair-basic/
  10. Grafika na osmibitových počítačích firmy Sinclair
    https://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair/
  11. Grafika na osmibitových počítačích firmy Sinclair II
    https://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair-ii/
  12. HiSoft BASIC
    https://worldofspectrum.net/in­foseekid.cgi?id=0008249
  13. YS MegaBasic
    https://worldofspectrum.net/in­foseekid.cgi?id=0008997
  14. Beta Basic
    https://worldofspectrum.net/in­foseekid.cgi?id=0007956
  15. BASIC+
    https://worldofspectrum.net/in­foseekid.php?id=0014277
  16. Spectrum ROM Memory Map
    https://skoolkit.ca/disas­semblies/rom/maps/all.html
  17. Goto subroutine
    https://skoolkit.ca/disas­semblies/rom/asm/7783.html
  18. Spectrum Next: The Evolution of the Speccy
    https://www.specnext.com/about/
  19. Sedmdesátiny assemblerů: lidsky čitelný strojový kód
    https://www.root.cz/clanky/sed­mdesatiny-assembleru-lidsky-citelny-strojovy-kod/
  20. Programovací jazyk BASIC na osmibitových mikropočítačích
    https://www.root.cz/clanky/pro­gramovaci-jazyk-basic-na-osmibitovych-mikropocitacich/
  21. Programovací jazyk BASIC na osmibitových mikropočítačích (2)
    https://www.root.cz/clanky/pro­gramovaci-jazyk-basic-na-osmibitovych-mikropocitacich-2/#k06
  22. Programovací jazyk BASIC na osmibitových mikropočítačích (3)
    https://www.root.cz/clanky/pro­gramovaci-jazyk-basic-na-osmibitovych-mikropocitacich-3/
  23. Sinclair BASIC (Wikipedia CZ)
    http://cs.wikipedia.org/wi­ki/Sinclair_BASIC
  24. Assembly Language: Still Relevant Today
    http://wilsonminesco.com/AssyDefense/
  25. Programovani v assembleru na OS Linux
    http://www.cs.vsb.cz/gryga­rek/asm/asmlinux.html
  26. Why Assembly Language Programming? (Why Learning Assembly Language Is Still a Good Idea)
    https://wdc65×x.com/market­s/education/why-assembly-language-programming/
  27. Low Fat Computing
    http://www.ultratechnology­.com/lowfat.htm
  28. Assembly Language
    https://www.cleverism.com/skills-and-tools/assembly-language/
  29. Why do we need assembly language?
    https://cs.stackexchange.com/qu­estions/13287/why-do-we-need-assembly-language
  30. Assembly language (Wikipedia)
    https://en.wikipedia.org/wi­ki/Assembly_language#Histo­rical_perspective
  31. Assembly languages
    https://curlie.org/Computer­s/Programming/Languages/As­sembly/
  32. vasm
    http://sun.hasenbraten.de/vasm/
  33. B-ELITE
    https://jsj.itch.io/b-elite
  34. ZX-Spectrum Child
    http://www.dotkam.com/2008/11/19/zx-spectrum-child/
  35. Speccy.cz
    http://www.speccy.cz/
  36. Planet Sinclair
    http://www.nvg.ntnu.no/sinclair/
  37. World of Spectrum
    http://www.worldofspectrum.org/
  38. The system variables
    https://worldofspectrum.or­g/ZXBasicManual/zxmanchap25­.html
  39. ZX Spectrum manual: chapter #17 Graphics
    https://worldofspectrum.or­g/ZXBasicManual/zxmanchap17­.html
  40. Why does Sinclair BASIC have two formats for storing numbers in the same structure?
    https://retrocomputing.stac­kexchange.com/questions/8834/why-does-sinclair-basic-have-two-formats-for-storing-numbers-in-the-same-structu
  41. Plovoucí řádová čárka na ZX Spectru
    https://www.root.cz/clanky/norma-ieee-754-a-pribuzni-formaty-plovouci-radove-tecky/#k05
  42. Norma IEEE 754 a příbuzní: formáty plovoucí řádové tečky
    https://www.root.cz/clanky/norma-ieee-754-a-pribuzni-formaty-plovouci-radove-tecky/#k05
  43. 1A1B: THE ‚REPORT AND LINE NUMBER PRINTING‘ SUBROUTINE
    https://skoolkid.github.i­o/rom/asm/1A1B.html
  44. 2DE3: THE ‚PRINT A FLOATING-POINT NUMBER‘ SUBROUTINE
    https://skoolkid.github.i­o/rom/asm/2DE3.html
  45. 5C63: STKBOT – Address of bottom of calculator stack
    https://skoolkid.github.i­o/rom/asm/5C63.html
  46. 5C65: STKEND – Address of start of spare space
    https://skoolkid.github.i­o/rom/asm/5C65.html
  47. Why does Sinclair BASIC have two formats for storing numbers in the same structure?
    https://retrocomputing.stac­kexchange.com/questions/8834/why-does-sinclair-basic-have-two-formats-for-storing-numbers-in-the-same-structu
  48. Chapter 24: The memory
    https://worldofspectrum.or­g/ZXBasicManual/zxmanchap24­.html
  49. Survey of Floating-Point Formats  
    https://mrob.com/pub/math/flo­atformats.html
  50. Convert an 8bit number to hex in z80 assembler
    https://stackoverflow.com/qu­estions/22838444/convert-an-8bit-number-to-hex-in-z80-assembler
  51. 80 MICROPROCESSOR Instruction Set Summary
    http://www.textfiles.com/pro­gramming/CARDS/z80

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.