Obsah
1. Aritmetické operace s hodnotami uloženými binárně i v BCD
2. Podprogram pro tisk hexadecimální cifry i osmibitové hexadecimální hodnoty
3. Demonstrační příklad, který vytiskne několik specifických hexadecimálních hodnot na obrazovku
4. Optimalizace předchozího demonstračního příkladu
5. Rutina pro tisk tabulky s větším množstvím hexadecimálních hodnot
6. Úplný zdrojový kód dnešního třetího demonstračního příkladu
7. Součet osmibitových hodnot uložených ve standardním binárním kódu
8. Tisk tabulky se sčítanci i součty
9. Úplný zdrojový kód dnešního čtvrtého demonstračního příkladu
10. Uložení numerických hodnot ve formátu BCD a Packed BCD
11. Podpora pro výpočty v BCD v instrukčních sadách mikroprocesorů
12. Příznak half carry a instrukce DAA
13. Vliv příznaků a hodnoty v akumulátoru na operaci DAA
14. Realizace součtu dvou numerických hodnot uložených ve formátu Packed BCD
15. Tisk tabulky se sčítanci i součty
16. Úplný zdrojový kód dnešního pátého demonstračního příkladu
17. Obsah následujícího článku
18. Příloha: upravený soubor Makefile pro překlad demonstračních příkladů
19. Repositář s demonstračními příklady
1. Aritmetické operace s hodnotami uloženými binárně i v BCD
Na předchozí článek o tvorbě aplikací pro slavný osmibitový mikropočítač ZX Spectrum v assembleru dnes navážeme. Připomeňme si, že minule jsme si nejprve ukázali, jakým způsobem lze využít rutinu pojmenovanou OUT_NUM1 a uloženou v paměti ROM pro tisk dekadických hodnot v rozsahu od 0 do 9999. Dále jsme si popsali funkce a vlastnosti pěti základních příznaků (flags) mikroprocesoru Zilog Z80 – carry, zero, add/subtract, overflow a sign.
Obrázek 1: Výpis numerických hodnot na obrazovku podprogramem uloženým v ROM. Konkrétně se jedná o minule popsanou subrutinu nazvanou OUT_NUM1.
Dnes si nejprve ukážeme, jak by mohla vypadat poměrně přímočaře naprogramovaná subrutina určená pro tisk osmibitové hexadecimální hodnoty v rozsahu od 0×00 do 0×ff. Uvidíme, že se v této subrutině použije podmíněný skok. Ovšem ve skutečnosti je možné využít určité triky a napsat tuto subrutinu i bez skoku, a to konkrétně tak, že se využije doposud nepopsaný příznak half carry a s ním související instrukce DAA. Proto si nejprve ukážeme, jak probíhá součet (nebo i rozdíl) hodnot uložených v binárním kódu i v kódu BCD (Binary-coded decimal), protože jak příznak half carry, tak i instrukce DAA původně s BCD velmi úzce souvisí (resp. přesněji řečeno souvisí s variantou, která se nazývá packed BCD).
Obrázek 2: Výsledek pokusu o vytištění záporného čísla standardní subrutinou OUT_NUM1.
2. Podprogram pro tisk hexadecimální cifry i osmibitové hexadecimální hodnoty
Ukažme si nejprve, jak by mohla vypadat prozatím dosti primitivně naprogramovaná subrutina určená pro tisk jedné šestnáctkové (hexadecimální) cifry. Tato subrutina předpokládá, že v pracovním registru A (akumulátoru) bude uložena hodnota 0×00 až 0×0f, přičemž spodní cifra 0×0 až 0×f se vytiskne k tomu určeným standardním podprogramem z ROM. V podstatě nám pouze postačuje určit, zda se má tisknout ASCII hodnota „0“ až „9“ či „A“ až „F“. Tyto hodnoty netvoří ucelenou řadu, takže musíme provést podmíněný skok:
print_hex_digit:
cp 0x0a ; test, jestli je číslice menší než 10
jr c, print_0_to_9 ; ok, hodnota je menší než 10, budeme tedy tisknout desítkovou číslici
add A, 65-10 ; ASCII kód znaku 'A', ovšem začínáme od desítky, ne od nuly
rst 0x10 ; zavolání rutiny v ROM pro tisk jednoho znaku
ret ; návrat ze subrutiny
print_0_to_9:
add A, 48 ; ASCII kód znaku '0'
rst 0x10 ; zavolání rutiny v ROM pro tisk jednoho znaku
ret ; návrat ze subrutiny
Aby se vytiskla celá osmibitová hodnota 0×00 až 0×FF, je nutné provést tisk vyšší cifry a poté cifry nižší. To lze realizovat velmi snadno s využitím bitových posunů spojených s maskováním:
print_hex_number:
push AF ; uschovat A pro pozdější využití
rrca ; rotace o čtyři bity doprava
rrca
rrca
rrca
and $0f ; zamaskovat horní čtyři bity
call print_hex_digit; vytisknout hexa číslici
pop AF ; obnovit A
and $0f ; zamaskovat horní čtyři bity
call print_hex_digit; vytisknout hexa číslici
ret ; a návrat z podprogramu
Jak je to obvyklé prakticky ve všech instrukčních sadách, je možné dvojici instrukcí CALL+RET nahradit za jedinou instrukci přímého skoku. Podprogram pro tisk hexadecimální hodnoty tedy pozměníme takto:
print_hex_number:
push AF ; uschovat A pro pozdější využití
rrca ; rotace o čtyři bity doprava
rrca
rrca
rrca
and $0f ; zamaskovat horní čtyři bity
call print_hex_digit; vytisknout hexa číslici
pop AF ; obnovit A
and $0f ; zamaskovat horní čtyři bity
jp print_hex_digit; vytisknout hexa číslici
; a návrat z podprogramu
3. Demonstrační příklad, který vytiskne několik specifických hexadecimálních hodnot na obrazovku
Výše uvedenou rutinu několikrát zavoláme a získáme na tak obrazovce několik hexadecimálních hodnot:
Obrázek 3: Několik hexadecimálních hodnot vytištěných na obrazovku ZX Spectra.
Úplný zdrojový kód dnešního prvního demonstračního příkladu vypadá následovně:
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, 0x00 ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ld A, 0x01 ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ld A, 0x09 ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ld A, 0x99 ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ld A, 0x0a ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ld A, 0xa0 ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ld A, 0xba ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ld A, 0xff ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ret ; návrat z programu do BASICu
print_hex_number:
push AF ; uschovat A pro pozdější využití
rrca ; rotace o čtyři bity doprava
rrca
rrca
rrca
and $0f ; zamaskovat horní čtyři bity
call print_hex_digit; vytisknout hexa číslici
pop AF ; obnovit A
and $0f ; zamaskovat horní čtyři bity
call print_hex_digit; vytisknout hexa číslici
ret ; a návrat z podprogramu
print_hex_digit:
cp 0x0a ; test, jestli je číslice menší než 10
jr c, print_0_to_9 ; ok, hodnota je menší než 10, budeme tedy tisknout desítkovou číslici
add A, 65-10 ; ASCII kód znaku 'A', ovšem začínáme od desítky, ne od nuly
rst 0x10 ; zavolání rutiny v ROM pro tisk jednoho znaku
ret ; návrat ze subrutiny
print_0_to_9:
add A, 48 ; ASCII kód znaku '0'
rst 0x10 ; zavolání rutiny v ROM pro tisk jednoho znaku
ret ; návrat ze subrutiny
new_line:
ld A, 0x0d ; kód znaku pro odřádkování
rst 0x10 ; zavolání rutiny v ROM
ret ; návrat ze subrutiny
end ENTRY_POINT
A podívejme se ještě na způsob překladu tohoto zdrojového kódu z assembleru 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:3E00 LD A, 00
8005:CD4480 CALL 8044
8008:CD6180 CALL 8061
800B:3E01 LD A, 01
800D:CD4480 CALL 8044
8010:CD6180 CALL 8061
8013:3E09 LD A, 09
8015:CD4480 CALL 8044
8018:CD6180 CALL 8061
801B:3E99 LD A, 99
801D:CD4480 CALL 8044
8020:CD6180 CALL 8061
8023:3E0A LD A, 0A
8025:CD4480 CALL 8044
8028:CD6180 CALL 8061
802B:3EA0 LD A, A0
802D:CD4480 CALL 8044
8030:CD6180 CALL 8061
8033:3EBA LD A, BA
8035:CD4480 CALL 8044
8038:CD6180 CALL 8061
803B:3EFF LD A, FF
803D:CD4480 CALL 8044
8040:CD6180 CALL 8061
8043:C9 RET
8044: label print_hex_number
8044:F5 PUSH AF
8045:0F RRCA
8046:0F RRCA
8047:0F RRCA
8048:0F RRCA
8049:E60F AND 0F
804B:CD5580 CALL 8055
804E:F1 POP AF
804F:E60F AND 0F
8051:CD5580 CALL 8055
8054:C9 RET
8055: label print_hex_digit
8055:FE0A CP 0A
8057:3804 JR C, 805D
8059:C637 ADD A, 37
805B:D7 RST 10
805C:C9 RET
805D: label print_0_to_9
805D:C630 ADD A, 30
805F:D7 RST 10
8060:C9 RET
8061: label new_line
8061:3E0D LD A, 0D
8063:D7 RST 10
8064:C9 RET
8065: END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8064
4. Optimalizace předchozího demonstračního příkladu
Podprogram pro tisk jedné hexadecimální číslice lze dále zjednodušit tak, že pro hodnoty „A“ až „F“ nejprve provedeme mezivýpočet a poté se budeme tvářit, že se jedná o hodnotu „0“ až „9“:
print_hex_digit:
cp 0x0a ; test, jestli je číslice menší než 10
jr c, print_0_to_9 ; ok, hodnota je menší než 10, budeme tedy tisknout desítkovou číslici
add A, 65-10-48 ; ASCII kód znaku 'A', ovšem začínáme od desítky, ne od nuly (+ update pro další ADD)
print_0_to_9:
add A, 48 ; ASCII kód znaku '0'
rst 0x10 ; zavolání rutiny v ROM pro tisk jednoho znaku
ret ; návrat ze subrutiny
Výsledkem by měla být naprosto stejná obrazovka:
Obrázek 4: Několik hexadecimálních hodnot vytištěných na obrazovku ZX Spectra (totožné s předchozím screenshotem).
Již ve druhé kapitole jsme si řekli, že kód je možné velmi snadno (i když jen nepatrně) optimalizovat tak, že se dvojice za sebou jdoucích instrukcí CALL+RET nahradí za přímý skok. Výsledkem bude tento kód:
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, 0x00 ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ld A, 0x01 ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ld A, 0x09 ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ld A, 0x99 ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ld A, 0x0a ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ld A, 0xa0 ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ld A, 0xba ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ld A, 0xff ; vytisknout hexa hodnotu s přechodem na nový řádek
call print_hex_number
call new_line
ret ; návrat z programu do BASICu
print_hex_number:
push AF ; uschovat A pro pozdější využití
rrca ; rotace o čtyři bity doprava
rrca
rrca
rrca
and $0f ; zamaskovat horní čtyři bity
call print_hex_digit; vytisknout hexa číslici
pop AF ; obnovit A
and $0f ; zamaskovat horní čtyři bity
jp print_hex_digit ; vytisknout hexa číslici a návrat z podprogramu
print_hex_digit:
cp 0x0a ; test, jestli je číslice menší než 10
jr c, print_0_to_9 ; ok, hodnota je menší než 10, budeme tedy tisknout desítkovou číslici
add A, 65-10-48 ; ASCII kód znaku 'A', ovšem začínáme od desítky, ne od nuly (+ update pro další ADD)
print_0_to_9:
add A, 48 ; ASCII kód znaku '0'
rst 0x10 ; zavolání rutiny v ROM pro tisk jednoho znaku
ret ; návrat ze subrutiny
new_line:
ld A, 0x0d ; kód znaku pro odřádkování
rst 0x10 ; zavolání rutiny v ROM
ret ; návrat ze subrutiny
end ENTRY_POINT
Ještě si pro úplnost uveďme symbolicky popsanou podobu výsledného strojového kódu, který je o tři bajty kratší než kód originální:
ENTRY_POINT EQU 8000
ROM_CLS EQU 0DAF
OUT_NUM_1 EQU 1A1B
ORG 8000
8000: label start
8000:CDAF0D CALL 0DAF
8003:3E00 LD A, 00
8005:CD4480 CALL 8044
8008:CD5E80 CALL 805E
800B:3E01 LD A, 01
800D:CD4480 CALL 8044
8010:CD5E80 CALL 805E
8013:3E09 LD A, 09
8015:CD4480 CALL 8044
8018:CD5E80 CALL 805E
801B:3E99 LD A, 99
801D:CD4480 CALL 8044
8020:CD5E80 CALL 805E
8023:3E0A LD A, 0A
8025:CD4480 CALL 8044
8028:CD5E80 CALL 805E
802B:3EA0 LD A, A0
802D:CD4480 CALL 8044
8030:CD5E80 CALL 805E
8033:3EBA LD A, BA
8035:CD4480 CALL 8044
8038:CD5E80 CALL 805E
803B:3EFF LD A, FF
803D:CD4480 CALL 8044
8040:CD5E80 CALL 805E
8043:C9 RET
8044: label print_hex_number
8044:F5 PUSH AF
8045:0F RRCA
8046:0F RRCA
8047:0F RRCA
8048:0F RRCA
8049:E60F AND 0F
804B:CD5480 CALL 8054
804E:F1 POP AF
804F:E60F AND 0F
8051:C35480 JP 8054
8054: label print_hex_digit
8054:FE0A CP 0A
8056:3802 JR C, 805A
8058:C607 ADD A, 07
805A: label print_0_to_9
805A:C630 ADD A, 30
805C:D7 RST 10
805D:C9 RET
805E: label new_line
805E:3E0D LD A, 0D
8060:D7 RST 10
8061:C9 RET
8062: END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8061
5. Rutina pro tisk tabulky s větším množstvím hexadecimálních hodnot
Předchozí kód neustále opakoval stejnou sekvenci instrukcí:
- Načtení hodnoty, která se má vypsat
- Zavolání subrutiny pro tisk této hodnoty
- Zavolání subrutiny pro odřádkování
Ve chvíli, kdy se tiskne větší množství hodnot, může být výhodnější si nejprve připravit pole se všemi hodnotami. Pole je buď nutné ukončit nějakou předem známou hodnotou (v našem případě nulou), nebo si pamatovat délku pole popř. adresu posledního prvku. My použijeme první způsob, tedy vložení „zarážky“ na konec pole:
numbers:
db 0x01, 0x09, 0x99, 0xa0, 0xa0, 0xba, 0xff, 0x00
Dále lze vytvořit programovou smyčku, která postupně načítá hodnoty z pole a tiskne je. Pokud se dojde na koncový prvek, je subrutina ukončena instrukcí RET (což je v našem případě podmíněná instrukce testující příznak zero):
ld HL, numbers ; statické pole s hodnotami, které se mají vytisknout + zarážkou
loop:
ld A, (HL) ; načíst další hodnotu ze statického pole
or A ; test na nulu
ret z ; návrat z programu do BASICU
inc HL ; adresa dalšího prvku v poli
call print_hex_number ; tisk hexadecimální hodnoty
call new_line ; s přechodem na nový řádek
jp loop ; zpracování další hodnoty
Obrázek 5: Opět si zobrazíme sloupeček s několika hexadecimálními hodnotami. Nyní nelze kvůli logice programové smyčky vytisknout nulovou hodnotu, ovšem úprava je jednoduchá a ponechám ji na váženém čtenáři.
6. Úplný zdrojový kód dnešního třetího demonstračního příkladu
Úplný zdrojový kód demonstračního příkladu popsaného v předchozí kapitole je dostupný na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/76-print-hex-numbers.asm:
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 HL, numbers ; statické pole s hodnotami, které se mají vytisknout + zarážkou
loop:
ld A, (HL) ; načíst další hodnotu ze statického pole
or A ; test na nulu
ret z ; návrat z programu do BASICU
inc HL ; adresa dalšího prvku v poli
call print_hex_number ; tisk hexadecimální hodnoty
call new_line ; s přechodem na nový řádek
jp loop ; zpracování další hodnoty
numbers:
db 0x01, 0x09, 0x99, 0xa0, 0xa0, 0xba, 0xff, 0x00
print_hex_number:
push AF ; uschovat A pro pozdější využití
rrca ; rotace o čtyři bity doprava
rrca
rrca
rrca
and $0f ; zamaskovat horní čtyři bity
call print_hex_digit; vytisknout hexa číslici
pop AF ; obnovit A
and $0f ; zamaskovat horní čtyři bity
jp print_hex_digit ; vytisknout hexa číslici a návrat z podprogramu
print_hex_digit:
cp 0x0a ; test, jestli je číslice menší než 10
jr c, print_0_to_9 ; ok, hodnota je menší než 10, budeme tedy tisknout desítkovou číslici
add A, 65-10-48 ; ASCII kód znaku 'A', ovšem začínáme od desítky, ne od nuly (+ update pro další ADD)
print_0_to_9:
add A, 48 ; ASCII kód znaku '0'
rst 0x10 ; zavolání rutiny v ROM pro tisk jednoho znaku
ret ; návrat ze subrutiny
new_line:
ld A, 0x0d ; kód znaku pro odřádkování
rst 0x10 ; zavolání rutiny v ROM
ret ; návrat ze subrutiny
end ENTRY_POINT
Samozřejmě si opět pro úplnost ukážeme, jak byl tento zdrojový text přeložen 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:211380 LD HL, 8013
8006: label loop
8006:7E LD A, (HL)
8007:B7 OR A
8008:C8 RET Z
8009:23 INC HL
800A:CD1B80 CALL 801B
800D:CD3580 CALL 8035
8010:C30680 JP 8006
8013: label numbers
8013:010999A0 DEFB of 8 bytes
8017:A0BAFF00
801B: label print_hex_number
801B:F5 PUSH AF
801C:0F RRCA
801D:0F RRCA
801E:0F RRCA
801F:0F RRCA
8020:E60F AND 0F
8022:CD2B80 CALL 802B
8025:F1 POP AF
8026:E60F AND 0F
8028:C32B80 JP 802B
802B: label print_hex_digit
802B:FE0A CP 0A
802D:3802 JR C, 8031
802F:C607 ADD A, 07
8031: label print_0_to_9
8031:C630 ADD A, 30
8033:D7 RST 10
8034:C9 RET
8035: label new_line
8035:3E0D LD A, 0D
8037:D7 RST 10
8038:C9 RET
8039: END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8038
7. Součet osmibitových hodnot uložených ve standardním binárním kódu
V dalším kroku vytvoříme program, který na obrazovku ZX Spectra vytiskne výsledky součtu vždy dvou osmibitových hodnot, které jsou uloženy ve standardním binárním formátu. Jedná se tedy o celočíselné hodnoty v rozsahu 0 až 255. Jak jednotlivé sčítance, tak i výsledek součtu jsou vypsány v hexadecimálním tvaru (proč tomu tak je, uvidíme v kapitole o BCD):
Obrázek 6: V každém sloupci jsou vždy nejprve uvedeny oba sčítance a pod nimi i výsledek součtu.
Na dalším obrázku je ukázáno, jak se mají číst zobrazené hodnoty. V červeném rámečku je vypsána operace 1+2=3 (stejné jak v decimálním tak i hexadecimálním tvaru). V modrém rámečku je vypsána operace 6+9=15, což v hexadecimálním tvaru odpovídá hodnotě 0×0f:
Obrázek 7: Základní aritmetika: 1+2=3 a 6+9=15 (0×0f).
8. Tisk tabulky se sčítanci i součty
Podívejme se nyní na způsob zobrazení „tabulek“ se součty. Nejdříve je nutné deklarovat dvojici polí. Pole array1 obsahuje první sčítance, pole array2 sčítance druhé:
array1:
db 0x00, 0x01, 0x05, 0x09, 0x09, 0x09, 0x10, 0x10, 0xa0, 0xfe, 0xff
array2:
db 0x01, 0x02, 0x05, 0x01, 0x06, 0x07, 0x09, 0x10, 0x01, 0x01, 0x01
Dále si vytvoříme podprogram, který vytiskne celou řadu hodnot. Počet těchto hodnot je uložen v pracovním registru B a adresa pole s hodnotami v registrovém páru HL. Povšimněte si, že počet hodnot je zvolen takovým způsobem, aby se za poslední hodnotou již netiskla mezera: 11×3=33 (celkem je k dispozici 32 textových sloupců):
; podprogram pro tisk sekvence numerických hodnot v hexadecimálním formátu
; vstupy:
; HL - ukazatel na pole s hodnotami
; B - počet hodnot (délka pole)
print_numbers:
next_item:
ld A, (HL) ; načíst hodnotu z pole
inc HL ; přechod na další prvek pole
call print_hex_number ; vytisknout hexa hodnotu
ld A, B
cp 1 ; za poslední hodnotou už nechceme tisknout mezeru
jr Z, skip ; přeskočení tisku mezery u poslední hodnoty
call space
skip:
djnz next_item ; zpracování dalšího prvku pole
ret
A konečně poslední sekvence instrukcí vypočítá a následně vytiskne součet hodnot, a to bez nutnosti jejich uložení do třetího pole:
ld DE, array1 ; adresa pole s první řadou sčítanců
ld HL, array2 ; adresa pole se druhou řadou sčítanců
ld B, 11
next_add:
ld A, (DE) ; načíst první sčítanec z pole
add A, (HL) ; načíst druhý sčítanec z pole
inc DE ; posun ukazatele na další sčítanec
inc HL ; dtto
call print_hex_number ; vytisknout hexa hodnotu výsledku
call space
djnz next_add ; kontrola počtu zobrazených výsledků
ret
9. Úplný zdrojový kód dnešního čtvrtého demonstračního příkladu
Úplný zdrojový kód dnešního čtvrtého demonstračního příkladu popsaného v předchozích dvou kapitolách je dostupný na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/77-add-hex-numbers.asm:
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 HL, array1 ; vytištění 11 hodnot z pole array1 v hexadecimálním formátu
ld B, 11
call print_numbers
ld HL, array2 ; vytištění 11 hodnot z pole array2 v hexadecimálním formátu
ld B, 11
call print_numbers
call new_line ; odřádkování
call new_line ; (chyba v ROM subrutině nebo užitečná vlastnost?)
ld DE, array1 ; adresa pole s první řadou sčítanců
ld HL, array2 ; adresa pole se druhou řadou sčítanců
ld B, 11
next_add:
ld A, (DE) ; načíst první sčítanec z pole
add A, (HL) ; načíst druhý sčítanec z pole
inc DE ; posun ukazatele na další sčítanec
inc HL ; dtto
call print_hex_number ; vytisknout hexa hodnotu výsledku
call space
djnz next_add ; kontrola počtu zobrazených výsledků
ret
; podprogram pro tisk sekvence numerických hodnot v hexadecimálním formátu
; vstupy:
; HL - ukazatel na pole s hodnotami
; B - počet hodnot (délka pole)
print_numbers:
next_item:
ld A, (HL) ; načíst hodnotu z pole
inc HL ; přechod na další prvek pole
call print_hex_number ; vytisknout hexa hodnotu
ld A, B
cp 1 ; za poslední hodnotou už nechceme tisknout mezeru
jr Z, skip ; přeskočení tisku mezery u poslední hodnoty
call space
skip:
djnz next_item ; zpracování dalšího prvku pole
ret
array1:
db 0x00, 0x01, 0x05, 0x09, 0x09, 0x09, 0x10, 0x10, 0xa0, 0xfe, 0xff
array2:
db 0x01, 0x02, 0x05, 0x01, 0x06, 0x07, 0x09, 0x10, 0x01, 0x01, 0x01
print_hex_number:
push AF ; uschovat A pro pozdější využití
rrca ; rotace o čtyři bity doprava
rrca
rrca
rrca
and $0f ; zamaskovat horní čtyři bity
call print_hex_digit; vytisknout hexa číslici
pop AF ; obnovit A
and $0f ; zamaskovat horní čtyři bity
jp print_hex_digit ; vytisknout hexa číslici a návrat z podprogramu
print_hex_digit:
cp 0x0a ; test, jestli je číslice menší než 10
jr c, print_0_to_9 ; ok, hodnota je menší než 10, budeme tedy tisknout desítkovou číslici
add A, 65-10-48 ; ASCII kód znaku 'A', ovšem začínáme od desítky, ne od nuly (+ update pro další ADD)
print_0_to_9:
add A, 48 ; ASCII kód znaku '0'
rst 0x10 ; zavolání rutiny v ROM pro tisk jednoho znaku
ret ; návrat ze subrutiny
new_line:
ld A, 0x0d ; kód znaku pro odřádkování
rst 0x10 ; zavolání rutiny v ROM
ret ; návrat ze subrutiny
space:
ld A, 32 ; kód mezery
rst 0x10 ; zavolání rutiny v ROM
ret ; návrat ze subrutiny
end ENTRY_POINT
Překlad do strojového kódu bude vypadat takto:
ENTRY_POINT EQU 8000
ROM_CLS EQU 0DAF
OUT_NUM_1 EQU 1A1B
ORG 8000
8000: label start
8000:CDAF0D CALL 0DAF
8003:213E80 LD HL, 803E
8006:060B LD B, 0B
8008:CD2E80 CALL 802E
800B:214980 LD HL, 8049
800E:060B LD B, 0B
8010:CD2E80 CALL 802E
8013:CD6E80 CALL 806E
8016:CD6E80 CALL 806E
8019:113E80 LD DE, 803E
801C:214980 LD HL, 8049
801F:060B LD B, 0B
8021: label next_add
8021:1A LD A, (DE)
8022:86 ADD A, (HL)
8023:13 INC DE
8024:23 INC HL
8025:CD5480 CALL 8054
8028:CD7280 CALL 8072
802B:10F4 DJNZ 8021
802D:C9 RET
802E: label print_numbers
802E: label next_item
802E:7E LD A, (HL)
802F:23 INC HL
8030:CD5480 CALL 8054
8033:78 LD A, B
8034:FE01 CP 01
8036:2803 JR Z, 803B
8038:CD7280 CALL 8072
803B: label skip
803B:10F1 DJNZ 802E
803D:C9 RET
803E: label array1
803E:00010509 DEFB of 11 bytes
8042:09091010
8046:A0FEFF
8049: label array2
8049:01020501 DEFB of 11 bytes
804D:06070910
8051:010101
8054: label print_hex_number
8054:F5 PUSH AF
8055:0F RRCA
8056:0F RRCA
8057:0F RRCA
8058:0F RRCA
8059:E60F AND 0F
805B:CD6480 CALL 8064
805E:F1 POP AF
805F:E60F AND 0F
8061:C36480 JP 8064
8064: label print_hex_digit
8064:FE0A CP 0A
8066:3802 JR C, 806A
8068:C607 ADD A, 07
806A: label print_0_to_9
806A:C6e0 ADD A, 30
806C:D7 RST 10
806D:C9 RET
806E: label new_line
806E:3E0D LD A, 0D
8070:D7 RST 10
8071:C9 RET
8072: label space
8072:3E20 LD A, 20
8074:D7 RST 10
8075:C9 RET
8076: END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8075
10. Uložení numerických hodnot ve formátu BCD a Packed BCD
Ve druhé části dnešního článku se budeme zabývat uložením numerických hodnot ve formátu BCD; konkrétně nás bude zajímat varianta nazývaná Packed BCD. Zkratkou BCD neboli Binary-coded decimal se označuje skupina kódování numerických hodnot založená na jednoduchém principu – každá desítková číslice je uložena ve čtyřech bitech. Tyto čtyři bity jsou buď uloženy v samostatném bajtu (co bajt, to jediná číslice) nebo jsou vždy „dvojice čtveřic“ bitů uloženy do jediného bajtu. Druhý zmíněný formát se nazývá Packed BCD a v naprosté většině případů se jedná o variantu big endian (a to nezávisle na procesorové architektuře).
V případě, že je nutné pracovat například s hodnotami v rozsahu 0 až 99999, je nutné pro takové BCD hodnoty alokovat pro každou číslici čtyři bity a celkem je tedy minimálně nutné použít 5×4=20 bitů. Naproti tomu v případě použití binárního kódování je zapotřebí pouze sedmnácti bitů, protože 217=131072 > 99999.
BCD se v nejjednodušším případě používá pro uložení celých čísel, a to buď bez znaménka (jednotlivé cifry, jak již bylo naznačeno výše) nebo se znaménkem (potom je znaménko typicky uloženo ve vlastním bitu, nebo se navíc používá dvojkový doplněk, to ovšem méně často). Ovšem můžeme se setkat i s takzvaným FX formátem (fixed point), v němž je desetinná tečka umístěna za předem známou cifrou a je neměnná – počet cifer před desetinnou tečkou a za ní je stále stejný. To znamená, že se v takovém případě nemusí ukládat exponent, který u FP hodnot přímo či nepřímo určoval pozici řádové čárky v uloženém číslu.
11. Podpora pro výpočty v BCD v instrukčních sadách mikroprocesorů
Výpočty s číselnými hodnotami uloženými v kódu BCD se ve výpočetní technice používají již od první generace (elektronkových) mainframů, které společnost IBM vyráběla v padesátých letech minulého století. Dnes se s BCD setkáme například při programování mikrořadičů, protože některé sedmisegmentové LCD, čipy s hodinami reálného času či malé numerické klávesnice kód BCD používají. Ostatně i z tohoto důvodu výpočty v BCD podporuje většina mikrořadičů, s výjimkou některých řad osmibitových mikrořadičů PIC. Čipy podporující výpočty v BCD můžeme rozdělit do tří kategorií:
- Registry přímo obsahují BCD (typicky dvě číslice 00–99) a ALU taktéž produkuje výsledek v BCD. Typickým příkladem je slavný osmibitový mikroprocesor MOS 6502, který lze přepnout do „dekadického režimu“ instrukcí SED (Set Decimal Mode) či se přepnout zpátky instrukcí CLD (Clear Decimal Mode).
- ALU sice provádí výpočty v binárním kódu, ale po provedení výpočtu je možné explicitně provést úpravu výsledku na BCD (na základě nastavených příznaků přenosu a polovičního přenosu). Typickým příkladem jsou čipy Intel 8048, Intel 8051, Motorola 6809, Motorola 68HC11 atd. atd. s instrukcí DAA či DA A používanou po operaci součtu a rozdílu. Podobná je instrukce A6AAC u čtyřbitových mikrořadičů TMS-1000. S tímto konceptem se blíže seznámíme v dalších kapitolách.
- ALU provádí většinu operací v binárním režimu, ovšem některé instrukce ji mohou přepnout do režimu BCD. Příkladem je Motorola 68000 s instrukcemi ABCD (Add Binary Coded Decimal), NBCD (Negate Binary Coded Decimal) a SBCD (Subtract Binary Coded Decimal).
Obrázek 8: Jedna z typických nasazení čtyřbitových mikrořadičů – nejjednodušší kalkulačky .
Některé mikroprocesory obsahují větší množství instrukcí pro úpravu výsledku a/nebo vstupních operandů. Příkladem může být čip 8086 (s instrukční sadou udržovanou dodnes), podporující jak „packed BCD“ (dvě cifry v bajtu), tak i „unpacked BCD“ (jediná cifra v bajtu). V instrukční sadě nalezneme hned šest relevantních instrukcí:
| Operace | Packed BCD | Unpacked BCD |
|---|---|---|
| součet | DAA | AAA |
| rozdíl | DAS | AAS |
| součin | × | AAM |
| podíl | × | AAD |
BCD používá i matematický koprocesor x86 (konkrétně čip 8087 a kvůli zpětné kompatibilitě i dnešní CPU+FPU), který dokáže do osmdesáti bitového slova uložit 18 BCD cifer + znaménko (necelé dva bajty se přitom nevyužijí).
Obrázek 9: Segmentem, v němž se BCD používá dodnes, jsou kalkulačky.
12. Příznak half carry a instrukce DAA
V souvislosti s formátem Packed BCD je nutné, aby mikroprocesor při provádění aritmetických operací dokázal výsledky upravit takovým způsobem, aby výsledkem byla opět hodnota s formátem Packed BCD. V praxi to v tom nejjednodušším případě znamená, že k výsledné cifře je nutné při přetečení přes 4 bity připočíst hodnotu 6. A vzhledem k tomu, že v bajtu jsou uloženy dvě BCD cifry, znamená to:
- Je nutné detekovat přetečení/přenos z bitů 0–3 do bitu 4 (dolní BCD cifra)
- Je nutné detekovat přetečení/přenos z bitu 7 (horní BCD cifra)
Výsledná hodnota se tedy bude měnit následovně:
- +0×00 pokud nedošlo k přetečení
- +0×06 pokud došlo k prvnímu typu přetečení
- +0×60 pokud došlo ke druhém typu přetečení
- +0×66 pokud došlo k obou přetečením
O výše uvedené úpravy výsledku se stará instrukce DAA (Decimal Add Adjust). V mnoha ohledech se jedná o nejsložitější instrukci mikroprocesoru Zilog Z80, neboť její chování závisí na mnoha vstupních hodnotách.
13. Vliv příznaků a hodnoty v akumulátoru na operaci DAA
V následující tabulce je ukázáno, jaká hodnota se přičte k výsledku poslední „sčítací“ operace typu ADD, ADC a INC na základě příznaků C a H a taktéž na základě hodnoty uložené v akumulátoru. Povšimněte si, že se skutečně provádí přičtení konstant 00, 6, 60 nebo 66:
| C před DAA | Horní cifra | H před DAA | Dolní cifra | Přičítaná hodnota | C po DAA |
|---|---|---|---|---|---|
| 0 | 0–9 | 0 | 0–9 | 00 | 0 |
| 0 | 0–8 | 0 | A-F | 06 | 0 |
| 0 | 0–9 | 1 | 0–3 | 06 | 0 |
| 0 | A-F | 0 | 0–9 | 60 | 1 |
| 0 | 9-F | 0 | A-F | 66 | 1 |
| 0 | A-F | 1 | 0–3 | 66 | 1 |
| 1 | 0–2 | 0 | 0–9 | 60 | 1 |
| 1 | 0–2 | 0 | A-F | 66 | 1 |
| 1 | 0–3 | 1 | 0–3 | 66 | 1 |
Druhá tabulka platí pro „odečítací“ operace typu SUB, SBC, DEC a kupodivu taktéž NEG:
| C před DAA | Horní cifra | H před DAA | Dolní cifra | Přičítaná hodnota | C po DAA |
|---|---|---|---|---|---|
| 0 | 0–9 | 0 | 0–9 | 00 | 0 |
| 0 | 0–8 | 1 | 6-F | FA | 0 |
| 1 | 7-F | 0 | 0–9 | A0 | 1 |
| 1 | 6-F | 1 | 6-F | 9A | 1 |
14. Realizace součtu dvou numerických hodnot uložených ve formátu Packed BCD
Součet dvou numerických hodnot reprezentovaných ve formátu Packed BCD je triviální – pouze musíme za instrukci součtu doplnit instrukci DAA, která výsledek součtu opraví tak, aby se opět jednalo o BCD číslice:
ld A, (DE) ; načíst první sčítanec z pole add A, (HL) ; načíst druhý sčítanec z pole daa ; provést decimální korekci
Tuto trojici instrukcí použijeme v dnešním posledním demonstračním příkladu.
15. Tisk tabulky se sčítanci i součty
Předchozí demonstrační příklad, který vytisknul tabulku s výsledky součtů binárně uložených hodnot můžeme triviálním způsobem upravit tak, aby se výpočty prováděly s BCD hodnotami, přičemž výsledkem bude pochopitelně opět BCD hodnota. Nejprve si necháme opět vytisknout hodnoty sčítanců (vždy dva sčítance použité v jedné operaci pod sebou):
start:
call ROM_CLS ; smazání obrazovky a otevření kanálu číslo 2 (screen)
ld HL, array1 ; vytištění 11 hodnot z pole array1 v hexadecimálním formátu
ld B, 11
call print_numbers
ld HL, array2 ; vytištění 11 hodnot z pole array2 v hexadecimálním formátu
ld B, 11
call print_numbers
Vložíme prázdný řádek (ovšem popravdě řečeno mi není jasné, proč se příslušná subrutina musí volat dvakrát, pokud je kurzor za koncem řádku):
call new_line ; odřádkování
call new_line ; (chyba v ROM subrutině nebo užitečná vlastnost?)
A dále vytiskneme výsledek součtu prováděného s BCD hodnotami. Povšimněte si, že po operaci ADD je vložena instrukce DAA, která výsledek opraví do korektního BCD tvaru (pokud je to ovšem možné):
ld DE, array1 ; adresa pole s první řadou sčítanců
ld HL, array2 ; adresa pole se druhou řadou sčítanců
ld B, 11
next_add:
ld A, (DE) ; načíst první sčítanec z pole
add A, (HL) ; načíst druhý sčítanec z pole
daa ; provést decimální korekci
inc DE ; posun ukazatele na další sčítanec
inc HL ; dtto
call print_hex_number ; vytisknout hexa hodnotu výsledku
call space
djnz next_add ; kontrola počtu zobrazených výsledků
ret
A takto by měla vypadat obrazovka po dokončení běhu programu:
Obrázek 10: Tabulka se součty dvojic hodnot uložených ve formátu Packed BCD.
Výsledky můžeme rozdělit do tří kategorií:
- Korektní výsledek pro korektní vstup (modrý obdélník)
- Nekorektní výsledek pro nekorektní vstup (červený obdélník)
- Přetečení výsledku pro hodnotu přesahující 99
Obrázek 11: Modře jsou vybarveny výpočty se skutečnými hodnotami Packed BCD, červeně pak výsledky, které nejsou korektní kvůli odlišnému vstupu.
16. Úplný zdrojový kód dnešního pátého demonstračního příkladu
Úplný zdrojový kód demonstračního příkladu popsaného v předchozích dvou kapitolách je dostupný na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/78-add-bcd-numbers.asm:
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 HL, array1 ; vytištění 11 hodnot z pole array1 v hexadecimálním formátu
ld B, 11
call print_numbers
ld HL, array2 ; vytištění 11 hodnot z pole array2 v hexadecimálním formátu
ld B, 11
call print_numbers
call new_line ; odřádkování
call new_line ; (chyba v ROM subrutině nebo užitečná vlastnost?)
ld DE, array1 ; adresa pole s první řadou sčítanců
ld HL, array2 ; adresa pole se druhou řadou sčítanců
ld B, 11
next_add:
ld A, (DE) ; načíst první sčítanec z pole
add A, (HL) ; načíst druhý sčítanec z pole
daa ; provést decimální korekci
inc DE ; posun ukazatele na další sčítanec
inc HL ; dtto
call print_hex_number ; vytisknout hexa hodnotu výsledku
call space
djnz next_add ; kontrola počtu zobrazených výsledků
ret
; podprogram pro tisk sekvence numerických hodnot v hexadecimálním formátu
; vstupy:
; HL - ukazatel na pole s hodnotami
; B - počet hodnot (délka pole)
print_numbers:
next_item:
ld A, (HL) ; načíst hodnotu z pole
inc HL ; přechod na další prvek pole
call print_hex_number ; vytisknout hexa hodnotu
ld A, B
cp 1 ; za poslední hodnotou už nechceme tisknout mezeru
jr Z, skip ; přeskočení tisku mezery u poslední hodnoty
call space
skip:
djnz next_item ; zpracování dalšího prvku pole
ret
array1:
db 0x00, 0x01, 0x05, 0x09, 0x09, 0x09, 0x10, 0x10, 0xa0, 0xfe, 0xff
array2:
db 0x01, 0x02, 0x05, 0x01, 0x06, 0x07, 0x09, 0x10, 0x01, 0x01, 0x01
print_hex_number:
push AF ; uschovat A pro pozdější využití
rrca ; rotace o čtyři bity doprava
rrca
rrca
rrca
and $0f ; zamaskovat horní čtyři bity
call print_hex_digit; vytisknout hexa číslici
pop AF ; obnovit A
and $0f ; zamaskovat horní čtyři bity
jp print_hex_digit ; vytisknout hexa číslici a návrat z podprogramu
print_hex_digit:
cp 0x0a ; test, jestli je číslice menší než 10
jr c, print_0_to_9 ; ok, hodnota je menší než 10, budeme tedy tisknout desítkovou číslici
add A, 65-10-48 ; ASCII kód znaku 'A', ovšem začínáme od desítky, ne od nuly (+ update pro další ADD)
print_0_to_9:
add A, 48 ; ASCII kód znaku '0'
rst 0x10 ; zavolání rutiny v ROM pro tisk jednoho znaku
ret ; návrat ze subrutiny
new_line:
ld A, 0x0d ; kód znaku pro odřádkování
rst 0x10 ; zavolání rutiny v ROM
ret ; návrat ze subrutiny
space:
ld A, 32 ; kód mezery
rst 0x10 ; zavolání rutiny v ROM
ret ; návrat ze subrutiny
end ENTRY_POINT
Pro úplnost si ukažme způsob překladu tohoto demonstračního příkladu do assembleru:
ENTRY_POINT EQU 8000
ROM_CLS EQU 0DAF
OUT_NUM_1 EQU 1A1B
ORG 8000
8000: label start
8000:CDAF0D CALL 0DAF
8003:213F80 LD HL, 803F
8006:060B LD B, 0B
8008:CD2F80 CALL 802F
800B:214A80 LD HL, 804A
800E:060B LD B, 0B
8010:CD2F80 CALL 802F
8013:CD6F80 CALL 806F
8016:CD6F80 CALL 806F
8019:113F80 LD DE, 803F
801C:214A80 LD HL, 804A
801F:060B LD B, 0B
8021: label next_add
8021:1A LD A, (DE)
8022:86 ADD A, (HL)
8023:27 DAA
8024:13 INC DE
8025:23 INC HL
8026:CD5580 CALL 8055
8029:CD7380 CALL 8073
802C:10F3 DJNZ 8021
802E:C9 RET
802F: label print_numbers
802F: label next_item
802F:7E LD A, (HL)
8030:23 INC HL
8031:CD5580 CALL 8055
8034:78 LD A, B
8035:FE01 CP 01
8037:2803 JR Z, 803C
8039:CD7380 CALL 8073
803C: label skip
803C:10F1 DJNZ 802F
803E:C9 RET
803F: label array1
803F:00010509 DEFB of 11 bytes
8043:09091010
8047:A0FEFF
804A: label array2
804A:01020501 DEFB of 11 bytes
804E:06070910
8052:010101
8055: label print_hex_number
8055:F5 PUSH AF
8056:0F RRCA
8057:0F RRCA
8058:0F RRCA
8059:0F RRCA
805A:E60F AND 0F
805C:CD6580 CALL 8065
805F:F1 POP AF
8060:E60F AND 0F
8062:C36580 JP 8065
8065: label print_hex_digit
8065:FE0A CP 0A
8067:3802 JR C, 806B
8069:C607 ADD A, 07
806B: label print_0_to_9
806B:C630 ADD A, 30
806D:D7 RST 10
806E:C9 RET
806F: label new_line
806F:3E0D LD A, 0D
8071:D7 RST 10
8072:C9 RET
8073: label space
8073:3E20 LD A, 20
8075:D7 RST 10
8076:C9 RET
8077: END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8076
17. Obsah následujícího článku
V navazujícím článku si nejprve ukážeme trik pro tisk hexadecimálních hodnot. Tento trik je založen na instrukci DAA a osmibitové aritmetice. A posléze se zaměříme na zcela odlišnou oblast – jak se dá pracovat s numerickými hodnotami reprezentovanými v systému pevné i plovoucí řádové tečky (fixed point, floating point).
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 osmi článcích [1] [2], [3], [4], [5], [6], [7], [8], 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 73.tap 74.tap 75.tap 76.tap 77.tap 78.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
73.tap: 73-print-flags-7.asm
$(ASSEMBLER) -v -d --tapbas $< $@ > 73-print-flags-7.lst
74.tap: 74-print-hex-number.asm
$(ASSEMBLER) -v -d --tapbas $< $@ > 74-print-hex-number.lst
75.tap: 75-print-hex-number.asm
$(ASSEMBLER) -v -d --tapbas $< $@ > 75-print-hex-number.lst
76.tap: 76-print-hex-numbers.asm
$(ASSEMBLER) -v -d --tapbas $< $@ > 76-print-hex-numbers.lst
77.tap: 77-add-hex-numbers.asm
$(ASSEMBLER) -v -d --tapbas $< $@ > 77-add-hex-numbers.lst
78.tap: 78-add-bcd-numbers.asm
$(ASSEMBLER) -v -d --tapbas $< $@ > 78-add-bcd-numbers.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 |
| 74 | 74-print-hex-number.asm | tisk hexadecimálního čísla v rozsahu 0×00 až 0×ff (neoptimalizovaná varianta) | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/74-print-hex-number.asm |
| 75 | 75-print-hex-number.asm | tisk hexadecimálního čísla v rozsahu 0×00 až 0×ff (optimalizovaná varianta) | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/75-print-hex-number.asm |
| 76 | 76-print-hex-numbers.asm | tisk několika hexadecimálních hodnot | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/76-print-hex-numbers.asm |
| 77 | 77-add-hex-numbers.asm | součet dvou osmibitových hexadecimálních hodnot s tiskem všech výsledků | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/77-add-hex-numbers.asm |
| 78 | 78-add-bcd-numbers.asm | součet dvou osmibitových BCD hodnot s tiskem všech výsledků | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/78-add-bcd-numbers.asm |
| 79 | 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
- z80 standalone assembler
https://www.asm80.com/onepage/asmz80.html - The ZX BASIC Compiler
https://www.boriel.com/pages/the-zx-basic-compiler.html - Z80 Assembly programming for the ZX Spectrum
https://www.chibiakumas.com/z80/ZXSpectrum.php - 8-BIT SMACKDOWN! 65C02 vs. Z80: slithy VLOGS #6
https://www.youtube.com/watch?v=P1paVoFEvyc - Instrukce mikroprocesoru Z80
https://clrhome.org/table/ - Z80 instructions: adresní režimy atd.
https://jnz.dk/z80/instructions.html - Z80 Instruction Groups
https://jnz.dk/z80/instgroups.html - Elena, New programming language for the ZX Spectrum Next
https://vintageisthenewold.com/elena-new-programming-language-for-the-zx-spectrum-next/ - Sinclair BASIC
https://worldofspectrum.net/legacy-info/sinclair-basic/ - Grafika na osmibitových počítačích firmy Sinclair
https://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair/ - Grafika na osmibitových počítačích firmy Sinclair II
https://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair-ii/ - HiSoft BASIC
https://worldofspectrum.net/infoseekid.cgi?id=0008249 - YS MegaBasic
https://worldofspectrum.net/infoseekid.cgi?id=0008997 - Beta Basic
https://worldofspectrum.net/infoseekid.cgi?id=0007956 - BASIC+
https://worldofspectrum.net/infoseekid.php?id=0014277 - Spectrum ROM Memory Map
https://skoolkit.ca/disassemblies/rom/maps/all.html - Goto subroutine
https://skoolkit.ca/disassemblies/rom/asm/7783.html - Spectrum Next: The Evolution of the Speccy
https://www.specnext.com/about/ - Sedmdesátiny assemblerů: lidsky čitelný strojový kód
https://www.root.cz/clanky/sedmdesatiny-assembleru-lidsky-citelny-strojovy-kod/ - Programovací jazyk BASIC na osmibitových mikropočítačích
https://www.root.cz/clanky/programovaci-jazyk-basic-na-osmibitovych-mikropocitacich/ - Programovací jazyk BASIC na osmibitových mikropočítačích (2)
https://www.root.cz/clanky/programovaci-jazyk-basic-na-osmibitovych-mikropocitacich-2/#k06 - Programovací jazyk BASIC na osmibitových mikropočítačích (3)
https://www.root.cz/clanky/programovaci-jazyk-basic-na-osmibitovych-mikropocitacich-3/ - Sinclair BASIC (Wikipedia CZ)
http://cs.wikipedia.org/wiki/Sinclair_BASIC - Assembly Language: Still Relevant Today
http://wilsonminesco.com/AssyDefense/ - Programovani v assembleru na OS Linux
http://www.cs.vsb.cz/grygarek/asm/asmlinux.html - Why Assembly Language Programming? (Why Learning Assembly Language Is Still a Good Idea)
https://wdc65×x.com/markets/education/why-assembly-language-programming/ - Low Fat Computing
http://www.ultratechnology.com/lowfat.htm - Assembly Language
https://www.cleverism.com/skills-and-tools/assembly-language/ - Why do we need assembly language?
https://cs.stackexchange.com/questions/13287/why-do-we-need-assembly-language - Assembly language (Wikipedia)
https://en.wikipedia.org/wiki/Assembly_language#Historical_perspective - Assembly languages
https://curlie.org/Computers/Programming/Languages/Assembly/ - vasm
http://sun.hasenbraten.de/vasm/ - B-ELITE
https://jsj.itch.io/b-elite - ZX-Spectrum Child
http://www.dotkam.com/2008/11/19/zx-spectrum-child/ - Speccy.cz
http://www.speccy.cz/ - Planet Sinclair
http://www.nvg.ntnu.no/sinclair/ - World of Spectrum
http://www.worldofspectrum.org/ - The system variables
https://worldofspectrum.org/ZXBasicManual/zxmanchap25.html - ZX Spectrum manual: chapter #17 Graphics
https://worldofspectrum.org/ZXBasicManual/zxmanchap17.html - Why does Sinclair BASIC have two formats for storing numbers in the same structure?
https://retrocomputing.stackexchange.com/questions/8834/why-does-sinclair-basic-have-two-formats-for-storing-numbers-in-the-same-structu - Plovoucí řádová čárka na ZX Spectru
https://www.root.cz/clanky/norma-ieee-754-a-pribuzni-formaty-plovouci-radove-tecky/#k05 - 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 - 1A1B: THE ‚REPORT AND LINE NUMBER PRINTING‘ SUBROUTINE
https://skoolkid.github.io/rom/asm/1A1B.html - 2DE3: THE ‚PRINT A FLOATING-POINT NUMBER‘ SUBROUTINE
https://skoolkid.github.io/rom/asm/2DE3.html - 5C63: STKBOT – Address of bottom of calculator stack
https://skoolkid.github.io/rom/asm/5C63.html - 5C65: STKEND – Address of start of spare space
https://skoolkid.github.io/rom/asm/5C65.html - Why does Sinclair BASIC have two formats for storing numbers in the same structure?
https://retrocomputing.stackexchange.com/questions/8834/why-does-sinclair-basic-have-two-formats-for-storing-numbers-in-the-same-structu - Chapter 24: The memory
https://worldofspectrum.org/ZXBasicManual/zxmanchap24.html - Survey of Floating-Point Formats
https://mrob.com/pub/math/floatformats.html - Convert an 8bit number to hex in z80 assembler
https://stackoverflow.com/questions/22838444/convert-an-8bit-number-to-hex-in-z80-assembler - 80 MICROPROCESSOR Instruction Set Summary
http://www.textfiles.com/programming/CARDS/z80 - Extended Binary Coded Decimal Interchange Code
http://en.wikipedia.org/wiki/EBCDIC - ASCII/EBCDIC Conversion Table
http://docs.hp.com/en/32212–90008/apcs01.html - EBCDIC
http://www.hansenb.pdx.edu/DMKB/dict/tutorials/ebcdic.php - EBCDIC tables
http://home.mnet-online.de/wzwz.de/temp/ebcdic/cc_en.htm - The Mainframe Blog
http://mainframe.typepad.com/blog/2006/11/my_personal_mai.html - Binary-coded decimal
https://en.wikipedia.org/wiki/Binary-coded_decimal - BCD
https://cs.wikipedia.org/wiki/BCD