Obsah
1. Tisk hexadecimálních hodnot podruhé
2. Úplný zdrojový kód dnešního prvního demonstračního příkladu
3. Malá odbočka: přetečení hodnoty cifry
4. Úplný zdrojový kód dnešního druhého demonstračního příkladu
5. Využití instrukce DAA namísto podmíněného skoku
6. Podrobný popis operací prováděných při převodu hexadecimální cifry na ASCII znak
7. Úplný zdrojový kód dnešního třetího demonstračního příkladu
8. Vylepšené vytištění osmibitové hexadecimální hodnoty
9. Úplný zdrojový kód dnešního čtvrtého demonstračního příkladu
10. Reprezentace numerických hodnot ve formátu pevné a plovoucí řádové (binární) tečky
11. Vybrané způsoby reprezentace numerických hodnot v operační paměti počítače
12. Uložení numerických hodnot ve formátu pevné řádové binární tečky
13. Přednosti a zápory formátu pevné řádové tečky
14. Uložení čísel ve formátu plovoucí řádové (binární) tečky
15. Formát uložení FP hodnot na ZX Spectru
16. Zásobník FP hodnot na ZX Spectru, subrutina pro tisk FP hodnot
17. Úplný zdrojový kód dnešního pátého demonstračního příkladu
18. Příloha: upravený soubor Makefile pro překlad demonstračních příkladů
19. Repositář s demonstračními příklady
1. Tisk hexadecimálních hodnot podruhé
V dnešní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).
Zaměřme se nyní na způsob zobrazení jediné hexadecimální cifry, tj. znaku „0“, „1“,… „9“, „A“ … „F“. Úloha je to vlastně velmi snadná: na vstupu budeme mít hodnotu 0 až 15 uloženou v akumulátoru A a výsledkem má být jeden z výše zmíněných znaků vytisknutých na obrazovku ZX Spectra. Znaky pro tisk se přitom pochopitelně vybírají z ASCII tabulky resp. přesněji řečeno z její „spektrácké“ verze, která vypadá následovně:
Obrázek 1: „Spektrácká“ verze ASCII tabulky (zobrazeny jsou jen tisknutelné znaky).
Jediný problém spočívá v tom, že převod hodnoty 0 až 15 na kód znaku není zcela přímočarý, protože znaky jsou v ASCII kódu uspořádány takovým způsobem, že se mezi znakem „9“ a znakem „A“ nachází sedm jiných znaků, konkrétně znaky „:“, „;“, „<“, „=“, „>“, „?“ a „@“:
Obrázek 2: Hexadecimální cifry nejsou v ASCII umístěny za sebou.
K dispozici jsou tři rozumná řešení:
- Použití převodní tabulky (ovšem ztratíme šestnáct bajtů RAM + další bajty pro kód)
- Použití podmínky + skoku, který řeší „mezeru“
- Aritmetické triky zajišťující, že se pro hodnoty vyšší než 9 provede operace +7
Druhý způsob už jsme si ukázali minule, ale pro jistotu si ho ještě zopakujme. Princip je jednoduchý – vypočteme ASCII hodnotu znaku tak, jakoby byly všechny cifry umístěny za sebou a posléze provedeme úpravu +7 pro cifry s hodnotou vyšší než 9:
print_hex_digit_nl:
push AF ; uschovat A pro pozdější využití
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
new_line:
ld A, 0x0d ; kód znaku pro odřádkování
rst 0x10 ; zavolání rutiny v ROM
pop AF ; obnovit A
ret ; návrat ze subrutiny
2. Úplný zdrojový kód dnešního prvního demonstračního příkladu
Výše uvedený kód je použit pro tisk těchto hodnot:
Obrázek 3: Hexadecimální cifry vypočtené a zobrazené dnešním prvním demonstračním příkladem.
Úplný zdrojový kód demonstračního příkladu popsaného v úvodní kapitole je dostupný na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/79-print-hex-digit-jmp.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)
xor A ; hodnota cifry, která se má vytisknout
ld B, 16 ; počitadlo smyčky
loop: ; vytisknout hexa cifru s přechodem na nový řádek
call print_hex_digit_nl
inc A ; zvýšit hodnotu tištěné cifry
djnz loop ; opakování smyčky se snížením hodnoty počitadla
ret ; návrat z programu do BASICu
print_hex_digit_nl:
push AF ; uschovat A pro pozdější využití
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
new_line:
ld A, 0x0d ; kód znaku pro odřádkování
rst 0x10 ; zavolání rutiny v ROM
pop AF ; obnovit A
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:AF XOR A
8004:0610 LD B, 10
8006: label loop
8006:CD0D80 CALL 800D
8009:3C INC A
800A:10FA DJNZ 8006
800C:C9 RET
800D: label print_hex_digit_nl
800D:F5 PUSH AF
800E:FE0A CP 0A
8010:3802 JR C, 8014
8012:C607 ADD A, 07
8014: label print_0_to_9
8014:C630 ADD A, 30
8016:D7 RST 10
8017: label new_line
8017:3E0D LD A, 0D
8019:D7 RST 10
801A:F1 POP AF
801B:C9 RET
801C: END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 801B
3. Malá odbočka: přetečení hodnoty cifry
Zajímavé bude si vyzkoušet, co se stane ve chvíli, kdy se pokusíme o převod a vytištění dekadické hodnoty větší než 15. Velmi snadno si můžeme upravit počítanou programovou smyčku v předchozím příkladu takovým způsobem, aby se smyčka nezastavila na hodnotě 15, ale až na hodnotě 19 (více řádků se již nevytiskne, protože se ROM rutina zastaví a čeká na vstup od uživatele):
xor A ; hodnota cifry, která se má vytisknout
ld B, 20 ; počitadlo smyčky
loop: ; vytisknout hexa cifru s přechodem na nový řádek
call print_hex_digit_nl
inc A ; zvýšit hodnotu tištěné cifry
djnz loop ; opakování smyčky se snížením hodnoty počitadla
Z výsledků je patrné, že se vypisují další cifry „G“ atd. až do „Z“, což vlastně znamená, že máme k dispozici rutinu platnou pro třiceti šestkovou číselnou soustavu (10 numerických znaků + 26 znaků anglické abecedy):
Obrázek 4: Tisk „hexadecimálních“ hodnot odpovídajících dekadickým hodnotám od 0 do 19. Povšimněte si, že ve skutečnosti máme k dispozici celou 36 číselnou soustavu.
4. Úplný zdrojový kód dnešního druhého demonstračního příkladu
Úplný zdrojový kód dnešního druhého demonstračního příkladu je dostupný na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/80-print-hex-digit-overflow.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)
xor A ; hodnota cifry, která se má vytisknout
ld B, 20 ; počitadlo smyčky
loop: ; vytisknout hexa cifru s přechodem na nový řádek
call print_hex_digit_nl
inc A ; zvýšit hodnotu tištěné cifry
djnz loop ; opakování smyčky se snížením hodnoty počitadla
ret ; návrat z programu do BASICu
print_hex_digit_nl:
push AF ; uschovat A pro pozdější využití
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
new_line:
ld A, 0x0d ; kód znaku pro odřádkování
rst 0x10 ; zavolání rutiny v ROM
pop AF ; obnovit A
ret ; návrat ze subrutiny
end ENTRY_POINT
Způsob překladu do strojového kódu je prakticky totožný s příkladem prvním (a to zcela podle očekávání):
ENTRY_POINT EQU 8000
ROM_CLS EQU 0DAF
OUT_NUM_1 EQU 1A1B
ORG 8000
8000: label start
8000:CDAF0D CALL 0DAF
8003:AF XOR A
8004:0614 LD B, 14
8006: label loop
8006:CD0D80 CALL 800D
8009:3C INC A
800A:10FA DJNZ 8006
800C:C9 RET
800D: label print_hex_digit_nl
800D:F5 PUSH AF
800E:FE0A CP 0A
8010:3802 JR C, 8014
8012:C607 ADD A, 07
8014: label print_0_to_9
8014:C630 ADD A, 30
8016:D7 RST 10
8017: label new_line
8017:3E0D LD A, 0D
8019:D7 RST 10
801A:F1 POP AF
801B:C9 RET
801C: END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 801B
5. Využití instrukce DAA namísto podmíněného skoku
Víme již, že problém, který řešíme, je následující: pro hodnoty větší než 9 musíme ASCII hodnotu příslušného znaku vypočítat posunutou o sedm pozic, protože takovým způsobem je uspořádána ASCII tabulka. Řešení spočívá v „chytrém“ použití instrukce DAA, která nám umožní automaticky (bez nutnosti použití podmíněného skoku) zvýšit hodnotu o 6. Zbývá nám pouze zajistit přičtení jedničky. K tomu slouží instrukce ADC, pro přičtení konstanty a případného přenosu (carry):
print_hex_digit_nl:
push AF ; uschovat A pro pozdější využití
or $f0 ; nastavit horní čtyři bity + příznaky
; nyní je v A jedna z hodnot:
; 0xf0 0xf1 0xf2 ... 0xf9 0xfa 0xfb 0xfc 0xfd 0xfe 0xff
daa ; desítková korekce pro původní hodnoty A-F
; + 0x60 0x60 0x60 ... 0x60 0x66 0x66 0x66 0x66 0x66 0x66
; nyní je v A jedna z hodnot:
; 0x50 0x51 0x52 ... 0x59 0x60 0x61 0x62 0x63 0x64 0x65
add A, $a0 ; přičtení konstanty
; nyní je v A jedna z hodnot:
; 0xf0 0xf1 0xf2 ... 0xf9 0x00 0x01 0x02 0x03 0x04 0x05
; C 0 0 0 0 1 1 1 1 1 1
adc A, $40 ; přičtení konstanty a navíc i příznaku carry
; 0x30 0x31 0x31 ... 0x39 0x41 0x42 0x43 0x44 0x45 0x46
; > '0' '1' '2' '9' 'A' 'B' 'C' 'D' 'E' 'F'
rst 0x10 ; zavolání rutiny v ROM pro tisk jednoho znaku
6. Podrobný popis operací prováděných při převodu hexadecimální cifry na ASCII znak
Výše uvedený kód provádí jak převod cifry na ASCII znak, tak i úpravu +7, tedy přeskočení těchto znaků:
Obrázek 5: Sedmice znaků v ASCII tabulce, které je nutné přeskočit.
Pojďme si nyní podrobněji popsat jednotlivé fáze výpočtu. Nejprve se pokusíme o převod hodnoty (cifry) 0, ovšem naprosto stejný popis bude platný i pro cifry od 1 do 9 (hodnoty jsou vždy uložené v akumulátoru a znak dolaru značí hexadecimální hodnotu):
| Hodnota před instrukcí | Instrukce | Provedená operace | Hodnota po instrukci | Carry | Stručný popis |
|---|---|---|---|---|---|
| $00 | or $f0 | or $f0 | $f0 | 0 | nastavit horní čtyři bity |
| $f0 | daa | $f0+$60 | $50 | 1 | desítková korekce pro horní čtyři bity (dolní jsou stále nulové) |
| $50 | add A, $a0 | $50+$a0 | $f0 | 0 | přičtení takové hodnoty, aby se nenastavil carry |
| $f0 | adc A, $40 | $f0+$40+0 | $30 | 1 | hodnota $30 skutečně odpovídá znaku „0“ |
Naproti tomu výpočet pro cifry A až F bude naprosto odlišný. Ukažme si to na hodnotě 0×0a (resp. kvůli větší konzistenci $0a):
| Hodnota před instrukcí | Instrukce | Provedená operace | Hodnota po instrukci | Carry | Stručný popis |
|---|---|---|---|---|---|
| $0a | or $f0 | or $f0 | $fa | 0 | nastavit horní čtyři bity |
| $fa | daa | $fa+$66 | $60 | 1 | desítková korekce pro horní i dolní čtyři bity (kýžené přičtení +6) |
| $60 | add A, $a0 | $60+$a0 | $00 | 1 | přičtení takové hodnoty, aby se nastavil carry (kýžené přičtení +1) |
| $00 | adc A, $40 | $00+$40+1 | $41 | 0 | hodnota $41 skutečně odpovídá znaku „A“ |
7. Úplný zdrojový kód dnešního třetího demonstračního příkladu
Výše uvedený kód můžeme bez dalších úprav použít pro tisk hexadecimálních cifer 0 až F:
Obrázek 6: Cifry 0 až F vytištěné demonstračním příkladem.
Úplný zdrojový kód dnešního třetího demonstračního příkladu je dostupný na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/81-print-hex-digit-daa.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)
xor A ; hodnota cifry, která se má vytisknout
ld B, 16 ; počitadlo smyčky
loop: ; vytisknout hexa cifru s přechodem na nový řádek
call print_hex_digit_nl
inc A ; zvýšit hodnotu tištěné cifry
djnz loop ; opakování smyčky se snížením hodnoty počitadla
ret ; návrat z programu do BASICu
print_hex_digit_nl:
push AF ; uschovat A pro pozdější využití
or $f0 ; nastavit horní čtyři bity + příznaky
; nyní je v A jedna z hodnot:
; 0xf0 0xf1 0xf2 ... 0xf9 0xfa 0xfb 0xfc 0xfd 0xfe 0xff
daa ; desítková korekce pro původní hodnoty A-F
; + 0x60 0x60 0x60 ... 0x60 0x66 0x66 0x66 0x66 0x66 0x66
; nyní je v A jedna z hodnot:
; 0x50 0x51 0x52 ... 0x59 0x60 0x61 0x62 0x63 0x64 0x65
add A, $a0 ; přičtení konstanty
; nyní je v A jedna z hodnot:
; 0xf0 0xf1 0xf2 ... 0xf9 0x00 0x01 0x02 0x03 0x04 0x05
; C 0 0 0 0 1 1 1 1 1 1
adc A, $40 ; přičtení konstanty a navíc i příznaku carry
; 0x30 0x31 0x31 ... 0x39 0x41 0x42 0x43 0x44 0x45 0x46
; > '0' '1' '2' '9' 'A' 'B' 'C' 'D' 'E' 'F'
rst 0x10 ; zavolání rutiny v ROM pro tisk jednoho znaku
new_line:
ld A, 0x0d ; kód znaku pro odřádkování
rst 0x10 ; zavolání rutiny v ROM
pop AF ; obnovit A
ret ; návrat ze subrutiny
end ENTRY_POINT
A pro úplnost se podívejme na způsob překladu výše uvedeného zdrojového kódu 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:AF XOR A
8004:0610 LD B, 10
8006: label loop
8006:CD0D80 CALL 800D
8009:3C INC A
800A:10FA DJNZ 8006
800C:C9 RET
800D: label print_hex_digit_nl
800D:F5 PUSH AF
800E:F6F0 OR F0
8010:27 DAA
8011:C6A0 ADD A, A0
8013:CE40 ADC A, 40
8015:D7 RST 10
8016: label new_line
8016:3E0D LD A, 0D
8018:D7 RST 10
8019:F1 POP AF
801A:C9 RET
801B: END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 801A
8. Vylepšené vytištění osmibitové hexadecimální hodnoty
Nyní, když již známe způsob efektivního převodu jedné hexadecimální cifry na ASCII znak, můžeme upravit původní demonstrační příklad, který tiskne osmibitovou hexadecimální hodnotu na obrazovku (a tedy dvě cifry). Nejprve se vytiskne vyšší cifra, poté cifra nižší. Povšimněte si, že podprogram print_hex_digit se volá jen jedenkrát – a to pro vyšší cifru. Pro nižší cifru není volání implementováno, protože podprogram print_hex_digit je umístěn přímo za print_hex_number, jak správně upozornil kolega _dw:
print_hex_number:
push AF ; uschovat A pro pozdější využití
rrca ; rotace o čtyři bity doprava
rrca
rrca
rrca
call print_hex_digit; vytisknout první hexa cifru
pop AF ; obnovit A
; vytisknout druhou hexa cifru
print_hex_digit:
or $f0 ; nastavit horní čtyři bity + příznaky
daa ; desítková korekce pro původní hodnoty A-F
add A, $a0 ; přičtení konstanty
adc A, $40 ; přičtení konstanty a navíc i příznaku carry
rst 0x10 ; zavolání rutiny v ROM pro tisk jednoho znaku
ret ; návrat ze subrutiny
Výsledek bude vypadat následovně:
Obrázek 7: Několik osmibitových hexadecimálních hodnot vytištěných touto subrutinou.
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 je dostupný na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/82-print-hex-numbers-daa.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, 0x02, 0x09, 0x0a, 0x10, 0x99, 0xa0, 0xaa, 0xaf, 0xf0, 0xff, 0x00
print_hex_number:
push AF ; uschovat A pro pozdější využití
rrca ; rotace o čtyři bity doprava
rrca
rrca
rrca
call print_hex_digit; vytisknout první hexa cifru
pop AF ; obnovit A
; vytisknout druhou hexa cifru
print_hex_digit:
or $f0 ; nastavit horní čtyři bity + příznaky
daa ; desítková korekce pro původní hodnoty A-F
add A, $a0 ; přičtení konstanty
adc A, $40 ; přičtení konstanty a navíc i příznaku carry
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 pro úplnost se opět podívejme na způsob překladu výše uvedeného zdrojového kódu 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: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:CD1F80 CALL 801F
800D:CD3180 CALL 8031
8010:C30680 JP 8006
8013: label numbers
8013:0102090A DEFB of 12 bytes
8017:1099A0AA
801B:AFF0FF00
801F: label print_hex_number
801F:F5 PUSH AF
8020:0F RRCA
8021:0F RRCA
8022:0F RRCA
8023:0F RRCA
8024:CD2880 CALL 8028
8027:F1 POP AF
8028: label print_hex_digit
8028:F6F0 OR F0
802A:27 DAA
802B:C6A0 ADD A, A0
802D:CE40 ADC A, 40
802F:D7 RST 10
8030:C9 RET
8031: label new_line
8031:3E0D LD A, 0D
8033:D7 RST 10
8034:C9 RET
8035: END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8034
10. Reprezentace numerických hodnot ve formátu pevné a plovoucí řádové (binární) tečky
Ve druhé části dnešního článku si ve stručnosti popíšeme některé ze způsobů reprezentace (resp. přesněji řečeno způsobu uložení) podmnožiny racionálních numerických hodnot (zkráceně čísel) v operační paměti počítače a/nebo v registrech jeho mikroprocesoru (CPU) či matematického koprocesoru (FPU). Jedná se o uložení vybrané množiny numerických hodnot v takzvaném systému pevné řádové (typicky binární nebo desetinné) tečky popř. naopak v systému plovoucí řádové tečky.
V anglické literatuře se první zmíněná forma reprezentace číselných hodnot označuje zkratkou FX nebo FXP (tato zkratka je odvozena od fixed point), zatímco dnes častěji používaná reprezentace v systému plovoucí řádové tečky se všeobecně označuje zkratkou FP (odvozeno od floating point).
Nejprve si vysvětlíme princip obou metod použitých pro ukládání podmnožiny racionálních čísel a posléze si také řekneme, jaké výhody a nevýhody jednotlivé principy přináší v každodenní programátorské praxi a ve kterých situacích je vhodnější použít pevnou řádovou čárku. V dalším textu budeme formát pevné binární řádové tečky zkracovat na FX formát a formát používající plovoucí řádovou tečku budeme zapisovat jako FP formát.
11. Vybrané způsoby reprezentace numerických hodnot v operační paměti počítače
Při ukládání numerických hodnot do operační paměti počítače záhy narazíme na některé problémy, z nichž některé souvisí s konečným počtem bitů, které pro uložení dané hodnoty „obětujeme“ a další vycházejí ze způsobu zpracování hodnot mikroprocesorem či matematickým koprocesorem (což není případ Z80). V konečném počtu bitů je totiž možné uložit pouze konečné množství různých hodnot a je plně v rukou programátora, jak efektivně daný počet bitů využije či naopak promrhá ukládáním nepodstatných informací. Poměrně často se totiž stává, že i program využívající dvojitou či dokonce rozšířenou přesnost čísel při FP operacích (tj. datové typy double a extended/temporary) dává nesprávné výsledky dané nepochopením principu práce FP aritmetiky a přitom je možné se přesnějších výsledků dobrat i při použití pouhých 32 bitů, ale s pečlivě vyváženými aritmetickými a bitovými operacemi.
Na druhou stranu nejsou dnes používané mikroprocesory tak univerzálními zařízeními, jak by se na první pohled mohlo zdát. Mikroprocesory jsou totiž (většinou) navrženy tak, aby účinně, například v rámci jedné operace či instrukce, zpracovávaly pouze konstantní počet bitů. Příkladem mohou být dnes velmi rozšířené procesory řady x86, které jsou velmi dobré při práci s 32 bitovými hodnotami, ale při požadavku na aritmetické výpočty probíhající na (řekněme) 21 bitech se veškerá jejich efektivita ztrácí a procesor se širokými vnitřními sběrnicemi, matematickým koprocesorem atd. se potýká s prohazováním jednotlivých bitů.
Mnohem lepší situace nastane v případě, že se nějaká operace implementuje na programovatelném poli FPGA – zde je možné vytvořit obvody provádějící matematické a logické operace s libovolným počtem bitů, čímž se oproti univerzálním řešením (např. konstantní bitová šířka sběrnice a/nebo registrů) ušetří mnoho plochy těchto velmi zajímavých obvodů (FPGA mohou mimochodem znamenat i velkou šanci pro hnutí open source – pomocí nich by mohlo vznikat, a někde už vzniká open hardware, které by mohlo odstranit závislost na „uzavřených“ síťových a grafických kartách apod.).
Vraťme se však ke způsobům reprezentace číselných hodnot v operační paměti. Nejprve předpokládejme, že pro reprezentaci vlastností určitého objektu či stavu z reálného světa použijeme N binárních číslic (bitů), tj. základních jednotek informace, která může nabývat pouze jedné ze dvou povolených hodnot (ty se značí například symboly yes/no nebo true/false, ale my se budeme spíše držet označení 0 a 1). Pomocí této uspořádané N-tice je možné popsat celkem:
20×21×22 … 2N-1=2N
jednoznačných, tj. navzájem odlišných, stavů. Množina těchto stavů může reprezentovat prakticky jakýkoliv abstraktní či reálný objekt. Přitom si musíme uvědomit, že u této množiny není implicitně řečeno ani myšleno, že se jedná například o celá kladná čísla, to je pouze jedna z mnoha možných interpretací zvolené N-tice (my programátoři máme tendenci považovat celá kladná čísla za přirozenou interpretaci bitové N-tice, to však vychází pouze z našeho pohledu na svět a z našich zkušeností). Reprezentaci momentálního stavu abstraktního či reálného objektu si můžeme představit jako zobrazení z množiny binárních stavů na elementy vzorové (a obecně neuspořádané) množiny. Nejčastěji používanými zobrazeními jsou zobrazení množiny binárních stavů na interval celých kladných čísel (Unsigned Integers), popřípadě na interval celých čísel (Signed Integers).
12. Uložení numerických hodnot ve formátu pevné řádové binární tečky
Numerické hodnoty zapsané ve formátu pevné řádové binární tečky se chápou jako podmnožina racionálních čísel, což jsou taková čísla, jejichž hodnoty je možné vyjádřit vztahem:
xFX=a/b a,b leží v Z, b ≠ 0
Číselné hodnoty z uvažované podmnožiny jsou navíc omezeny podmínkou:
b=2k b leží v Z, k leží v Z+
Protože b je celočíselnou mocninou dvojky (a ne desítky či jiného základu), určuje jeho hodnota n polohu binární tečky v uloženém čísle. Další podmínkou, která má však spíše implementační charakter, je zachování stejného počtu binárních cifer v každém reprezentovaném čísle, což mimo jiné znamená, že všechna čísla mají řádovou binární tečku umístěnou na stejném místě – z této podmínky ostatně plyne i název popisovaného způsobu reprezentace vybrané podmnožiny racionálních čísel. Tak jako i v jiných reprezentacích čísel, jsou nulové číslice před první nenulovou cifrou a za poslední nenulovou cifrou nevýznamné, proto je není zapotřebí uvádět.
Prakticky může být číselná hodnota v systému pevné řádové tečky uložena na osmi bitech například následujícím způsobem (uvažujeme pouze kladné hodnoty):
| Pozice bitu | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
| Váha bitu | 24 | 23 | 22 | 21 | 20 | 2-1 | 2-2 | 2-3 |
| Desítková váha bitu | 16 | 8 | 4 | 2 | 1 | 0,5 | 0,25 | 0,125 |
13. Přednosti a zápory formátu pevné řádové tečky
Ve výše uvedeném příkladu je binární řádová tečka umístěna vždy mezi třetím a čtvrtým bitem. Vzhledem k tomu, že je tato skutečnost dopředu známá algoritmu, který provádí zpracování čísel, není zapotřebí spolu s číslem uchovávat i pozici binární tečky, což výrazně snižuje počet bitů, které je zapotřebí rezervovat pro čísla ze zadaného rozsahu. To je tedy první přednost systému pevné řádové tečky – pokud programátor dopředu zná rozsah všech zpracovávaných hodnot a požadovanou přesnost, může být výhodné tento systém použít. Programátor také díky explicitním určení polohy řádové tečky může určit, ve kterém místě programu se musí přesnost či rozsah zvýšit a kdy naopak snížit. Lépe se tak využije počet bitů, které můžeme pro uložení jednoho čísla obětovat (typicky je tento počet bitů roven délce slova mikroprocesoru, popř. jeho celočíselnému násobku či naopak podílu).
Navíc je možné základní matematické operace (sčítání, odčítání, násobení a dělení) poměrně jednoduše implementovat i při použití formátu pevné řádové tečky. V případě, že není k dispozici specializovaný (a současně velmi komplikovaný) matematický koprocesor, je mnohdy mnohem jednodušší a rychlejší implementovat matematické operace v FX formátu. To je případ mnoha jednočipových mikroprocesorů (mikrořadičů), našeho oblíbeného čipu Zilog Z80, signálových procesorů, ale i specializovaných zařízení obsahujících programovatelné obvody CPLD či FPGA. Dnes sice mají komplikovanější (a dražší) FPGA implementovanou i jednotku FPU, ale mnohdy je výhodnější použít FPGA bez této jednotky a potřebné operace si do tohoto obvodu „vypálit“ po svém.
Třetí výhodou je fakt, že u FX formátu může programátor navrhnout a posléze také dodržet požadovanou přesnost všech prováděných výpočtů. To je velký rozdíl oproti FP formátu (resp. jeho podmnožinám, které se nejčastěji používají). Není vzácností narazit na programy, které používají datové typy float či double a přitom jsou výpočty prováděné v těchto programech zatíženy velkou chybou, protože si programátoři plně neuvědomují některé limity FP formátu. Kritické jsou například výpočty s peněžními hodnotami, ale i pouhé sčítání čísel, jež se od sebe o mnoho řádů liší, vede k velkým chybám, které dokonce mohou zapříčinit vznik nekonečných smyček, populární dělení nulou atd.
FX formát má však i některé nevýhody. První nevýhoda spočívá v tom, že tento formát není příliš podporován, a to ani po programové stránce (podpora v programovacích jazycích), ani výrobci mikroprocesorů pro počítače PC. Situace je však odlišná v oblasti jednočipových mikropočítačů, signálových procesorů (DSP), řídicích systémů, nebo například u IBM RS 6000, který kromě jednotky FPU obsahuje i FXU – jednotku pro provádění výpočtů v pevné řádové binární čárce. Na platformě x86 je možné pro FX formát použít instrukce MMX nebo jejich novější varinty (AVX atd.).
Dále může být použití FX formátu nevýhodné v případě, že se mají zpracovávat numerické hodnoty, které mají velkou dynamiku, tj. poměr mezi nejvyšší a nejnižší absolutní hodnotou. V takovém případě by se mohlo stát, že by se při použití FX formátu muselo pro každé číslo alokovat velké množství bitů, které by mohlo dokonce překročit počet bitů nutných pro FP formát. Také v případě, kdy dopředu nevíme, jaké hodnoty se budou zpracovávat, může být výhodnější použití FP formátu. Zde se však nabízí otázka, ve kterých případech nevíme, jaké hodnoty můžeme na vstupu získat: většinou je již z podstaty úlohy dopředu známé, s čím je možné počítat a které hodnoty jsou naprosto nesmyslné. Je však pravdou, že takovou analýzu málokdo dělá a když při výpočtech ve floatech dochází k chybám, tak se bez přemýšlení program přepíše na doubly a problém se tak buď odstraní, nebo alespoň odsune na pozdější dobu, například do chvíle, kdy jsou programu předložena reálná data a ne „pouze“ data testovací.
14. Uložení čísel ve formátu plovoucí řádové (binární) tečky
Uložení racionálních čísel ve formátu plovoucí řádové tečky (FP formát) se od FX formátu odlišuje především v tom, že si každá numerická hodnota sama v sobě nese polohu řádové tečky. Z tohoto důvodu je kromě bitů, které jsou rezervovány pro uložení významných číslic numerické hodnoty, nutné pro každou numerickou hodnotu rezervovat i další bity, pomocí nichž je určena mocnina o nějakém základu (typicky 2, 8, 10 či 16), kterou musí být významné číslice vynásobeny resp. vyděleny. První část čísla uloženého v FP formátu se nazývá mantisa, druhá část exponent. Obecný formát uložení a způsob získání původního čísla je následující:
xFP=be×m
kde:
- xFX značí reprezentovanou numerickou hodnotu z podmnožiny reálných čísel
- b je báze, někdy také nazývaná radix
- e je hodnota exponentu (může být i záporná)
- m je mantisa, která může být i záporná
Konkrétní formát numerických hodnot reprezentovaných v systému plovoucí řádové tečky závisí především na volbě báze (radixu) a také na počtu bitů rezervovaných pro uložení mantisy a exponentu. V minulosti existovalo mnoho různých formátů plovoucí řádové tečky (vzpomíná si někdo na Turbo Pascal s jeho šestibytovým datovým typem real?), dnes se však, ustálilo použití formátů specifikovaných v normě IEEE 754. Ovšem to není případ ZX Spectra, které má svůj vlastní formát, jenž si popíšeme v dalším textu.
15. Formát uložení FP hodnot na ZX Spectru
Při volbě konkrétního formátu uložení FP hodnot mají programátoři poměrně dosti volné ruce. Musí především zvolit:
- Celkovou šířku slova s FP hodnotou
- Zda bude mantisa a exponent uložena v binárním či BCD formátu (pro Z80 se BCD naprosto nehodí, na rozdíl od 6502)
- Bitová šířka mantisy
- Zda je první bit mantisy pevně nastaven na jedničku (a tudíž se nemusí ukládat)
- Základ exponentu (typicky 2, 10 či 16)
- Bitová šířka exponentu
- Formát uložení, tj. kde bude uloženo znaménko, kde mantisa a kde exponent (FP hodnota je vlastně bitové pole)
Existuje mnoho formátů, z nichž nejzajímavější či nejpoužívanější vypadají následovně:
IBM 1130, IBM 1800 32 Bit single precision floating point 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 +-+---------------------------------------------+---------------+ |S| mantissa |exp. with bias | +-+---------------------------------------------+---------------+ GE-635 36 Bit single precision floating point 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 +-+-------------+-+-----------------------------------------------------+ |S| Two's exp. |S| Two's complement mantissa | +-+-------------+-+-----------------------------------------------------+ Intel 8008, 8080 floating point UCRL-51940 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +-+-------------+-----------------------------------------------+ |S| Two's exp. | positive mantissa | +-+-------------+-----------------------------------------------+ Altair BASIC 8080 floating point 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +---------------+-+---------------------------------------------+ |exp. with bias |S| positive mantissa, MSB = 2^-1 | +---------------+-+---------------------------------------------+ Z80 40 Bit floating point 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +-+-------------+-+-------------------------------------------------------------+ |S| Two's exp. |S| Two's complement mantissa, MSB = 2^1 | +-+-------------+-+-------------------------------------------------------------+ IEEE 754 single precision 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +-+---------------+---------------------------------------------+ |S| exp. with bias| positive mantissa, MSB = 2^-1 | +-+---------------+---------------------------------------------+
Na ZX Spectru je použit 40bitový formát, přičemž 40 bitů bylo pravděpodobně zvoleno z toho důvodu, že všech pět univerzálních pracovních registrů má dohromady přesně tuto šířku (ale to může být jen spekulace):
7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 +-+-------------+-+-------------------------------------------------------------+ |exp. with bias |S| mantissa | +-+-------------+-+-------------------------------------------------------------+
Předpokládá se, že první bit mantisy je roven jedničce (což dává smysl), proto tento první bit není uložen a na jeho místě je znaménko mantisy. Exponent je posunutý o hodnotu 128 (viz další příklady).
Navíc tento formát obsahuje výjimku pro celočíselné hodnoty v rozsahu od –65535 až +65535. Tyto hodnoty jsou uloženy takovým způsobem, že první bajt (posunutý exponent) je nulový, druhý bajt obsahuje samé nuly pro kladná čísla a samé jedničky pro čísla záporná a teprve třetí a čtvrtý bajt obsahuje 16bitovou hodnotu bez znaménka. Poslední bajt je opět nulový. Tuto výjimku si podrobněji ukážeme příště.
16. Zásobník FP hodnot na ZX Spectru, subrutina pro tisk FP hodnot
V ROM ZX Spectra je uloženo několik subrutin určených pro zpracování FP hodnot. Z těchto subrutin nás dnes budou zajímat pouze dvě:
2DE3: THE 'PRINT A FLOATING-POINT NUMBER' SUBROUTINE This subroutine prints x, the 'last value' on the calculator stack. The print format never occupies more than 14 spaces. 2AB1: THE 'STK-STORE' SUBROUTINE This subroutine passes the values held in the A, B, C, D and E A First byte (when entering at STK_STO or STK_STORE) B Fifth byte C Fourth byte D Third byte E Second byte
PRINT_FP equ $2DE3 STK_STORE equ $2AB6
Subrutina STK_STORE uloží FP hodnotu předanou ve všech pěti pracovních registrech (kromě HL) na zásobník (stack) používaný při FP výpočtech. Podrobnosti si řekneme příště, protože dnes nám postačuje vědět, jaké registry a v jakém pořadí jsou použity pro předání FP hodnoty:
; A první bajt
; B pátý byte
; C čtvrtý byte
; D třetí byte
; E druhý bajt
ld A, ...
ld E, ...
ld D, ...
ld C, ...
ld B, ...
call STK_STORE ; uložit FP hodnotu na zásobník
Subrutina PRINT_FP přečte hodnotu z výše zmíněného zásobníku a vytiskne ji na obrazovku. Přitom se správně rozpoznají všechny speciální případy, tj. nuly, celočíselné hodnoty –65535..+65535 atd.
call PRINT_FP ; vytisknout FP hodnotu uloženou na vrcholu zásobníku
new_line:
ld A, 0x0d ; kód znaku pro odřádkování
rst 0x10 ; zavolání rutiny v ROM
Můžeme si tedy otestovat, jaké FP hodnoty jsou reprezentovány následujícími sekvencemi čtyřiceti bitů. Otestování bude snadné – pětici bajtů (40 bitů) uložíme do „FP zásobníku“ subrutinou STK_STORE a následně hodnotu vytiskneme zavoláním subrutiny PRINT_FP. Této subrutině se nepředávají žádné parametry – ty jsou na „FP zásobníku“:
ld IX, fp0 ; adresa s pěticí bajtů FP hodnoty
call print_fp_number ; tisk FP hodnoty na obrazovku s odřádkováním
Tisknout budeme FP hodnoty reprezentované těmito sekvencemi bitů:
; mantisa+128 s exponent fp0: db %00000000, %00000000, %00000000, %00000000, %00000000 fp1: db %10000000, %00000000, %00000000, %00000000, %00000000 fp2: db %10000000, %10000000, %00000000, %00000000, %00000000 fp3: db %10000000, %01000000, %00000000, %00000000, %00000000 fp4: db %10000001, %01000000, %00000000, %00000000, %00000000 fp5: db %10000001, %01000000, %00000000, %00000001, %00000000 fp6: db %10000001, %00111111, %11111111, %11111111, %00000000
Výsledek by měl vypadat následovně:
Obrázek 8: Sedm FP hodnot vypsaných na obrazovce ZX Spectra.
Proč hodnoty vypadají tak, jak vypadají:
- První hodnota je 16bitovým číslem se znaménkem
- Druhá hodnota obsahuje exponent=0 a mantisa má nastaven pouze nejvyšší bit za binární tečkou (ten se, jak víme, neukládá)
- Třetí hodnota je totožná, jako hodnota druhá, ovšem je nastaven znaménkový bit
- Čtvrtá hodnota obsahuje exponent=0 a mantisa je rovna 0.11 (binárně), tedy 0,5+0,25=0,75 dekadicky
- Pátá hodnota má exponent=1 (×2) a mantisu stejnou, jako hodnota předchozí, tedy 2×0,75=1,5
- Šestá hodnota je nepatrně vyšší, než hodnota pátá (viz v pořadí devátý bit zprava)
- Sedmá hodnota je naopak nepatrně menší, než hodnota pátá
Pro tisk FP hodnoty je použita tato subrutina:
print_fp_number:
; A první bajt
; B pátý byte
; C čtvrtý byte
; D třetí byte
; E druhý bajt
ld A, (IX)
ld E, (IX+1)
ld D, (IX+2)
ld C, (IX+3)
ld B, (IX+4)
call STK_STORE ; uložit FP hodnotu na zásobník
call PRINT_FP ; vytisknout FP hodnotu uloženou na vrcholu zásobníku
new_line:
ld A, 0x0d ; kód znaku pro odřádkování
rst 0x10 ; zavolání rutiny v ROM
ret ; návrat ze subrutiny
17. Úplný zdrojový kód dnešního pátého demonstračního příkladu
Úplný zdrojový kód dnešního pátého a současně i posledního demonstračního příkladu je dostupný na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/83-print-fp-numbers.asm:
ENTRY_POINT equ $8000
ROM_CLS equ $0DAF
PRINT_FP equ $2DE3
STK_STORE equ $2AB6
org ENTRY_POINT
start:
call ROM_CLS ; smazání obrazovky a otevření kanálu číslo 2 (screen)
ld IX, fp0 ; adresa s pěticí bajtů FP hodnoty
call print_fp_number ; tisk FP hodnoty na obrazovku s odřádkováním
ld IX, fp1 ; adresa s pěticí bajtů FP hodnoty
call print_fp_number ; tisk FP hodnoty na obrazovku s odřádkováním
ld IX, fp2 ; adresa s pěticí bajtů FP hodnoty
call print_fp_number ; tisk FP hodnoty na obrazovku s odřádkováním
ld IX, fp3 ; adresa s pěticí bajtů FP hodnoty
call print_fp_number ; tisk FP hodnoty na obrazovku s odřádkováním
ld IX, fp4 ; adresa s pěticí bajtů FP hodnoty
call print_fp_number ; tisk FP hodnoty na obrazovku s odřádkováním
ld IX, fp5 ; adresa s pěticí bajtů FP hodnoty
call print_fp_number ; tisk FP hodnoty na obrazovku s odřádkováním
ld IX, fp6 ; adresa s pěticí bajtů FP hodnoty
call print_fp_number ; tisk FP hodnoty na obrazovku s odřádkováním
ret
; mantisa+128 s exponent
fp0: db %00000000, %00000000, %00000000, %00000000, %00000000
fp1: db %10000000, %00000000, %00000000, %00000000, %00000000
fp2: db %10000000, %10000000, %00000000, %00000000, %00000000
fp3: db %10000000, %01000000, %00000000, %00000000, %00000000
fp4: db %10000001, %01000000, %00000000, %00000000, %00000000
fp5: db %10000001, %01000000, %00000000, %00000001, %00000000
fp6: db %10000001, %00111111, %11111111, %11111111, %00000000
print_fp_number:
; A první bajt
; B pátý byte
; C čtvrtý byte
; D třetí byte
; E druhý bajt
ld A, (IX)
ld E, (IX+1)
ld D, (IX+2)
ld C, (IX+3)
ld B, (IX+4)
call STK_STORE ; uložit FP hodnotu na zásobník
call PRINT_FP ; vytisknout FP hodnotu uloženou na vrcholu zásobníku
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
Překlad do assembleru:
ENTRY_POINT EQU 8000
ROM_CLS EQU 0DAF
PRINT_FP EQU 2DE3
STK_STORE EQU 2AB6
ORG 8000
8000: label start
8000:CDAF0D CALL 0DAF
8003:DD213580 LD IX, 8035
8007:CD5880 CALL 8058
800A:DD213A80 LD IX, 803A
800E:CD5880 CALL 8058
8011:DD213F80 LD IX, 803F
8015:CD5880 CALL 8058
8018:DD214480 LD IX, 8044
801C:CD5880 CALL 8058
801F:DD214980 LD IX, 8049
8023:CD5880 CALL 8058
8026:DD214E80 LD IX, 804E
802A:CD5880 CALL 8058
802D:DD215380 LD IX, 8053
8031:CD5880 CALL 8058
8034:C9 RET
8035: label fp0
8035:00000000 DEFB of 5 bytes
8039:00
803A: label fp1
803A:80000000 DEFB of 5 bytes
803E:00
803F: label fp2
803F:80800000 DEFB of 5 bytes
8043:00
8044: label fp3
8044:80400000 DEFB of 5 bytes
8048:00
8049: label fp4
8049:81400000 DEFB of 5 bytes
804D:00
804E: label fp5
804E:81400001 DEFB of 5 bytes
8052:00
8053: label fp6
8053:813FFFFF DEFB of 5 bytes
8057:00
8058: label print_fp_number
8058:DD7E00 LD A, (IX+00)
805B:DD5E01 LD E, (IX+01)
805E:DD5602 LD D, (IX+02)
8061:DD4E03 LD C, (IX+03)
8064:DD4604 LD B, (IX+04)
8067:CDB62A CALL 2AB6
806A:CDE32D CALL 2DE3
806D: label new_line
806D:3E0D LD A, 0D
806F:D7 RST 10
8070:C9 RET
8071: END 8000
Emiting TAP basic loader
Emiting TAP from 8000 to 8070
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 devíti článcích [1] [2], [3], [4], [5], [6], [7], [8], [9], 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 79.tap 80.tap \
81.tap 82.tap 83.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
79.tap: 79-print-hex-digit-jmp.asm
$(ASSEMBLER) -v -d --tapbas $< $@ > 79-print-hex-digit-jmp.lst
80.tap: 80-print-hex-digit-overflow.asm
$(ASSEMBLER) -v -d --tapbas $< $@ > 80-print-hex-digit-overflow.lst
81.tap: 81-print-hex-digit-daa.asm
$(ASSEMBLER) -v -d --tapbas $< $@ > 81-print-hex-digit-daa.lst
82.tap: 82-print-hex-numbers-daa.asm
$(ASSEMBLER) -v -d --tapbas $< $@ > 82-print-hex-numbers-daa.lst
83.tap: 83-print-fp-numbers.asm
$(ASSEMBLER) -v -d --tapbas $< $@ > 83-print-fp-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 | 79-print-hex-digit-jmp.asm | tisk jedné hexadecimální cifry s využitím podmíněného skoku | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/79-print-hex-digit-jmp.asm |
| 80 | 80-print-hex-digit-overflow.asm | otestování, jaký znak je vytištěn pro hodnoty větší než 15 | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/80-print-hex-digit-overflow.asm |
| 81 | 81-print-hex-digit-daa.asm | tisk jedné hexadecimální cifry s využitím instrukce DAA | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/81-print-hex-digit-daa.asm |
| 82 | 82-print-hex-numbers-daa.asm | tisk série hexadecimálních hodnot s využitím instrukce DAA | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/82-print-hex-numbers-daa.asm |
| 83 | 83-print-fp-numbers.asm | tisk numerických hodnot reprezentovaných v systému plovoucí řádové tečky | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/83-print-fp-numbers.asm |
| 84 | 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 - Z80 heaven: Floating Point
http://z80-heaven.wikidot.com/floating-point - Z80, the 8-bit Number Cruncher
http://www.andreadrian.de/oldcpu/Z80_number_cruncher.html - Floating-point library for Z80
https://github.com/DW0RKiN/Floating-point-Library-for-Z80 - z80float
https://github.com/Zeda/z80float - ZX Spectrum BASIC Programming – 2nd Edition
https://archive.org/details/zx-spectrum-basic-programming/page/n167/mode/2up - ZX Spectrum BASIC Programming – 2nd Edition
https://archive.org/details/zx-spectrum-basic-programming/page/n169/mode/2up