Obsah
1. Zvuky a hudba na ZX Spectru
3. Využití subrutiny v ROM s implementací příkazu BEEP
4. Úplný zdrojový kód dnešního prvního demonstračního příkladu
6. Úplný zdrojový kód dnešního druhého demonstračního příkladu
7. Přímé programové ovládání beeperu
8. Úplný zdrojový kód dnešního třetího demonstračního příkladu
9. Vliv přerušení na přesnost přehrávaného tónu
10. Zakázání přerušení při přehrávání
11. Úplný zdrojový kód dnešního čtvrtého demonstračního příkladu
12. Vizualizace frekvence přehrávání změnou okraje v reálném čase
13. Pruhy na okraji obrazovky při povolení či zákazu přerušení
14. Zdrojové kódy pátého a šestého příkladu
15. Skutečné možnosti beeperu – PWM, vícehlasá hudba
16. Rozšíření ZX Spectra o další zvukové subsystémy
18. Příloha: upravený soubor Makefile pro překlad demonstračních příkladů
19. Repositář s demonstračními příklady
1. Zvuky a hudba na ZX Spectru
Prakticky každý osobní počítač je v současnosti vybaven zvukovým výstupem. Elektronický obvod, který se stará o vytváření zvuků a hudby je dnes buď přímo součástí čipové sady základní desky nebo je v počítači nainstalována zvuková karta určená pro interní či (méně často) externí sběrnici. Cesta, která vedla od prvních programem či jednoduchým multivibrátorem řízených reproduktorů (ZX Spectrum, IBM PC XT) k dnešním výkonným zvukovým čipům umožňujícím tvorbu prostorových několikakanálových zvuků a hudby založené na wavetable syntéze, byla poměrně dlouhá a především zajímavá.
Obrázek 1: První úspěšnou herní konzolí bylo Atari 2600 vybavené grafickým a současně i zvukovým čipem TIA. Interně se zvuk generoval sérií posuvných registrů se zpětnou vazbou.
Tak jako v případě grafických subsystémů počítačů, i pro tvorbu zvuků a hudby zkoušeli návrháři čipů používat různé postupy a mnohdy tak vznikly zcela unikátní obvody, které se později staly legendami. Mezi tyto čipy patří například SID (Sound Interface Device) firmy Commodore, AY-3–8910/8912/8913 firmy General Instruments (později jej vyráběla i firma Yamaha pod označením YM2149) ke kterému se ještě vrátíme, POKEY firmy Atari, PAULA firmy Commodore či čipy OPL2 (YM 3812) a OPL3 (YMF 262) vyráběné firmou Yamaha. Každý z těchto čipů je založen na odlišném způsobu vytváření hudby a jimi vytvářený zvuk je (snad s výjimkou čipu PAULA) velmi charakteristický a originální.
Obrázek 2: Zvukový čip AY-3–8910 ve čtyřicetipinovém pouzdře DIL (originál od firmy General Instrument)
Některé osmibitové domácí počítače, například slavné ZX Spectrum, byly vybaveny pouze velmi jednoduchým zvukovým rozhraním – reproduktorem zapojeným přes zesilovač na logický (dvoustavový) výstup z mikroprocesoru či jiného podpůrného obvodu (například multivibrátoru, v ZX Spectru se jedná o čip ULA). Na reproduktor byl posílán obdélníkový signál u nějž bylo možné programově měnit jeho střídu (poměr mezi logickým stavem jedna a nula), ovšem nikoli amplitudu, což samozřejmě znamenalo, že výsledné zvuky získaly charakteristické a snadno rozpoznatelné zabarvení.
Obrázek 3: Složitější varianta COVOXu (osmibitový D/A převodník), která zachovává průchozí paralelní port.
Někteří zkušení autoři byli kupodivu schopni i za těchto velmi skromných podmínek vyprodukovat poměrně zajímavou hudbu, dokonce bylo možné rychlou změnou přehrávaných frekvencí simulovat polyfonii či přehrávat samplované zvuky (ve své podstatě simulovaly jednobitový digitálně-analogový převodník). Kromě tvůrců her se například jednalo o autory Buzzcocks či Freshies, kteří použili hudbu generovanou ZX Spectrem při tvorbě svých alb. Podobný princip tvorby zvuků byl později použit i u osobního počítače IBM PC pod názvem PC-Speaker (též známého jako squeezer, beeper atd.).
Obrázek 4: Zvuková karta Adlib určená do osmibitové varianty sběrnice ISA (PC BUS).
2. Beeper na ZX Spectru
„Who needs a SID when you have a Z80?“
Zvukový výstup na původním ZX Spectru 48k je realizován tím nejsnadnějším a taktéž nejlevnějším možným způsobem – binární výstup z pinu číslo 28 zákaznického obvodu ULA je přes zesilovač připojen k internímu reproduktoru ZX Spectra a současně je přes oddělovací kondenzátor přiveden i na konektor EAR, který je možné připojit k vnějšímu zesilovači a dále zpracovat. Schéma zapojení je naznačeno na pátém obrázku:
Obrázek 5: Jednobitový zvukový výstup je realizován přes pin 28 zákaznického obvodu ULA.
A jak je ovládána logická úroveň výše zmíněného pinu 28? Je to snadné – jedná se o hodnotu pátého bitu (v případě, že bity počítáme od jedničky) osmibitové hodnoty zapsané na port 0×fe, který již dobře známe, protože čtením tohoto portu se zjišťuje stav stisku kláves. ZX Spectrum je interně skutečně velmi jednoduché, protože prakticky všechny vstupně/výstupní operace provádíme přes tento jediný port. Programátor má naprostou svobodu v tom, kdy a jakou logickou hodnotu na „zvukový“ pin pošle, takže je možné realizovat i velmi sofistikované přehrávací rutiny (které se paradoxně špatně programují pro „skutečné“ zvukové čipy). Na druhou stranu je však nutné vše pečlivě načasovat, přičemž každé přerušení může přehrávání zvuku narušit, což ostatně uvidíme v dalším textu. Ostatně právě proto je poměrně složité realizovat hudbu společně s vykreslovacími subrutinami u her.
3. Využití subrutiny v ROM s implementací příkazu BEEP
BASIC u ZX Spectra obsahuje i příkaz BEEP, který slouží pro přehrání zvuku o zvolené výšce trvající určitou dobu. Tento příkaz akceptuje dvě hodnoty – konstantu se zakódovanou délkou trvání a výškou. Interně se přitom volá subrutina nazvaná BEEPER, která je v ROM uložena od adresy 0×03B5 (viz též popis této subrutiny):
BEEPER equ $03B5
Tato subrutina očekává, že parametry jí budou předány v registrových párech DE a HL, přičemž v DE je uložena doba trvání tónu (frekvence tónu×čas v sekundách) a v registrovém páru HL hodnota získaná výpočtem 437500 / frekvence tónu – 30.125:
beep MACRO pitch, duration ld hl, pitch ld de, duration call BEEPER ENDM
Například frekvence komorního A je stanovena na 440 Hz, takže do HL by se měla dosadit hodnota 437500/440–30 = 964:
start: beep 964, 1000 ; přehrání noty ret ; návrat do BASICu
Výsledný tón si můžeme nechat analyzovat a zobrazit spektrálním (sic) analyzátorem. Získáme následující výsledek:
Obrázek 6: Výsledek spektrální analýzy zvuku produkovaného ZX Spectrem.
Povšimněte si, že obě osy jsou nelineární (jak je v tomto oboru zvykem, což je nutné při pochopení rozdílů v amplitudách jednotlivých „peaků“). Základní frekvence tónu byla změřena poměrně přesně: 439 Hz. Kromě toho ovšem můžeme vidět i další dva „peaky“, a to na frekvencích přibližně 1320 Hz a 2200 Hz. Ovšem to by nemělo být příliš překvapující, neboť se jedná o vyšší harmonické obdélníkového signálu (resp. signálu, jehož tvar se alespoň částečně blíží obdélníku). Konkrétně se jedná o frekvence 3×f a 5×f, což plně odpovídá teorii – obdélníkový signál totiž obsahuje (teoreticky všechny) liché harmonické.
4. Úplný zdrojový kód dnešního prvního demonstračního příkladu
Úplný zdrojový kód dnešního prvního demonstračního příkladu najdete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/103-beep.asm:
ENTRY_POINT equ $8000 BEEPER equ $03B5 org ENTRY_POINT beep MACRO pitch, duration ld hl, pitch ld de, duration call BEEPER ENDM start: beep 964, 1000 ; přehrání noty ret ; návrat do BASICu end ENTRY_POINT
Překlad tohoto velmi jednoduchého demonstračního příkladu do strojového kódu je zcela přímočarý, což je ostatně patrné i z následujícího výpisu:
ENTRY_POINT EQU 8000 BEEPER EQU 03B5 ORG 8000 Defining MACRO beep Params: pitch, duration 8000: label start Expanding MACRO beep pitch= 03E2 duration= 03E8 LD HL , pitch 8000:21C403 LD HL, 03C4 LD DE , duration 8003:11E803 LD DE, 03E8 CALL BEEPER 8006:CDB503 CALL 03B5 ENDM ENDM End of MACRO beep 8009:C9 RET 800A: END 8000 Emiting TAP basic loader Emiting TAP from 8000 to 8009
5. Přehrání celé stupnice
Poměrně přímočarým způsobem si můžeme přehrát celou stupnici (základní tóny v jedné oktávě). Pouze si musíme připravit tabulku s hodnotami posílanými do rutiny BEEPER přes registrový pár HL:
notes: ; nota frekvence 437500 / frekvence – 30.125 ; C 261.63 1642 ; D 293.66 1459 ; E 329.63 1297 ; F 349.23 1222 ; G 392.00 1086 ; A 440.00 964 ; H 493.88 855 ; C 523.26 806 dw 1642, 1459, 1297, 1222, 1086, 964, 855, 806, 0
Nyní již postačuje načítat hodnoty z této tabulky a volat makro BEEP, které jsme si vytvořili v rámci předchozího příkladu. Mezi jednotlivé tóny je vložena pauza:
start: ld BC, notes ; adresa 16bitových konstant next_note: ld A, (BC) ; načíst spodní bajt 16bitové konstanty ld L, A ; uložit do L inc BC ; a zvýšit adresu v poli ld A, (BC) ; načíst horní bajt 16bitové konstanty ld H, A ; uložit do H inc BC ; a zvýšit adresu v poli add A, L ; test na 16bitovou nulu ret z ; návrat do BASICu pokud je načtená hodnota nulová ld DE, DURATION ; parametry pro BEEP jsou v HL a DE push BC call BEEPER ; zavolat subrutinu z ROM call delay ; doba bez tónu pop BC jr next_note ; zahrát další notu
Načítání not je možné upravit takovým způsobem, aby se použil odlišný způsob adresování, protože adresování přes registrový pár BC vyžaduje použití akumulátoru (využít se například může EX DE, HL a adresování přímo přes HL atd.).
6. Ú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 najdete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/104-music-scale.asm:
ENTRY_POINT equ $8000 BEEPER equ $03B5 DURATION equ 200 org ENTRY_POINT start: ld BC, notes ; adresa 16bitových konstant next_note: ld A, (BC) ; načíst spodní bajt 16bitové konstanty ld L, A ; uložit do L inc BC ; a zvýšit adresu v poli ld A, (BC) ; načíst horní bajt 16bitové konstanty ld H, A ; uložit do H inc BC ; a zvýšit adresu v poli add A, L ; test na 16bitovou nulu ret z ; návrat do BASICu pokud je načtená hodnota nulová ld DE, DURATION ; parametry pro BEEP jsou v HL a DE push BC call BEEPER ; zavolat subrutinu z ROM call delay ; doba bez tónu pop BC jr next_note ; zahrát další notu notes: ; nota frekvence 437500 / frekvence – 30.125 ; C 261.63 1642 ; D 293.66 1459 ; E 329.63 1297 ; F 349.23 1222 ; G 392.00 1086 ; A 440.00 964 ; H 493.88 855 ; C 523.26 806 dw 1642, 1459, 1297, 1222, 1086, 964, 855, 806, 0 delay: ; zpožďovací rutina ; mění BC (což nám nevadí) ld b, 200 ; počitadlo vnější zpožďovací smyčky outer_loop: ld c, 0 ; počitadlo vnitřní zpožďovací smyčky inner_loop: dec c ; snížení hodnoty počitadla (v první iteraci 256->255) jr NZ, inner_loop ; opakovat, dokud není dosaženo nuly djnz outer_loop ; opakovat vnější smyčku, nyní s počitadlem v B ret ; návrat z podprogramu end ENTRY_POINT
A opět si pochopitelně ukážeme i způsob překladu tohoto demonstračního příkladu do strojového kódu:
ENTRY_POINT EQU 8000 BEEPER EQU 03B5 DURATION EQU 00C8 ORG 8000 8000: label start 8000:011880 LD BC, 8018 8003: label next_note 8003:0A LD A, (BC) 8004:6F LD L, A 8005:03 INC BC 8006:0A LD A, (BC) 8007:67 LD H, A 8008:03 INC BC 8009:85 ADD A, L 800A:C8 RET Z 800B:11C800 LD DE, 00C8 800E:C5 PUSH BC 800F:CDB503 CALL 03B5 8012:CD2A80 CALL 802A 8015:C1 POP BC 8016:18EB JR 8003 8018: label notes 8018:6A06B305 DEFW of 9 words 801C:1105C604 8020:3E04C403 8024:57032603 8028:0000 802A: label delay 802A:06C8 LD B, C8 802C: label outer_loop 802C:0E00 LD C, 00 802E: label inner_loop 802E:0D DEC C 802F:20FD JR NZ, 802E 8031:10F9 DJNZ 802C 8033:C9 RET 8034: END 8000 Emiting TAP basic loader Emiting TAP from 8000 to 8033
7. Přímé programové ovládání beeperu
Rutina BEEPER uložená v paměti ROM, kterou jsme až doposud používali, interně pochopitelně mění logickou úroveň na pinu 28 čipu ULA tak, aby se generoval zvolený tón. Stejnou operaci pochopitelně můžeme provést i my. Budeme v programové smyčce negovat pátý bit na portu 0×fe a tím pádem i měnit logickou úroveň na pinu 28. V případě, že tato změna bude probíhat s nějakým (vhodně zvoleným) zpožděním, měli bychom získat čistý tón. Realizace takové smyčky je ve skutečnosti triviální (prozatím nepočítáme přesné zpoždění, které je nutné použít):
ld A, %00000111 ; původní hodnota zapisovaná na port loop: xor %00010000 ; negace pátého bitu out (BEEPER_PORT), A ; zápis na port call short_delay ; počkat jr loop ; a opakovat celé znovu
8. Úplný zdrojový kód dnešního třetího demonstračního příkladu
Úplný zdrojový kód dnešního třetího demonstračního příkladu najdete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/105-direct-speaker.asm:
ENTRY_POINT equ $8000 BEEPER_PORT equ $fe org ENTRY_POINT start: ld A, %00000111 ; původní hodnota zapisovaná na port loop: xor %00010000 ; negace pátého bitu out (BEEPER_PORT), A ; zápis na port call short_delay ; počkat jr loop ; a opakovat celé znovu short_delay: ; zpožďovací rutina ; mění B (což nám nevadí) ld b, 100 ; počitadlo zpožďovací smyčky delay_loop: djnz delay_loop ; opakovat smyčku s počitadlem v B ret ; návrat z podprogramu end ENTRY_POINT
A takto vypadá překlad tohoto demonstračního příkladu do strojového kódu:
ENTRY_POINT EQU 8000 BEEPER_PORT EQU 00FE ORG 8000 8000: label start 8000:3E07 LD A, 07 8002: label loop 8002:EE10 XOR 10 8004:D3FE OUT (FE), A 8006:CD0B80 CALL 800B 8009:18F7 JR 8002 800B: label short_delay 800B:0664 LD B, 64 800D: label delay_loop 800D:10FE DJNZ 800D 800F:C9 RET 8010: END 8000 Emiting TAP basic loader Emiting TAP from 8000 to 800F
9. Vliv přerušení na přesnost přehrávaného tónu
Pokud jste si předchozí příklad přeložili a spustili, pravděpodobně jste uslyšeli tón, který není čistý – nejedná se tedy o pravidelný obdélníkový signál. Jak je to možné? Naše programová smyčka a zpožďovací rutina mohou být (a jsou) pozastaveny, a to ve chvíli, kdy dojde k přerušení, které na ZX Spectru nastává 50× za sekundu. O významu přerušení a jeho využití se zmíníme v samostatném článku, ovšem již nyní je zřejmé, že při tvorbě zvukových efektů (a taktéž některých efektů grafických) vede obsluha přerušovací rutiny k tomu, že výsledný tón či obraz není „čistý“. Z tohoto důvodu přerušení (prozatím) zakážeme, což má sice vliv na činnost ZX Spectra (obsluha klávesnice atd.), ale tento problém nás alespoň prozatím nemusí příliš trápit.
10. Zakázání přerušení při přehrávání
Mikroprocesor Zilog Z80 obsahuje dva piny, na které se přivádí signál s informacemi o přerušení (oba signály mají inverzní logiku, jak je to v této oblasti zvykem). Jedná se o NMI (nemaskovatelné přerušení), který se však po RESETu už nepoužívá (viz schéma zapojení ZX Spectra) a INT, jenž je připojen k ULA. A signál přivedený na pin INT lze maskovat instrukcí DI neboli disable interrupt. Opakem je instrukce EI neboli enable interrupt. V případě, že naši přehrávací rutinu nepatrně upravíme, nebude již zpomalována přerušovací rutinou a vytvářený zvuk tak bude zcela čistý:
ld A, %00000111 ; původní hodnota zapisovaná na port di ; zakázat přerušení loop: xor %00010000 ; negace pátého bitu out (BEEPER_PORT), A ; zápis na port call short_delay ; počkat jr loop ; a opakovat celé znovu
11. Ú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 najdete na adrese https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/106-direct-speaker-di.asm:
ENTRY_POINT equ $8000 BEEPER_PORT equ $fe org ENTRY_POINT start: ld A, %00000111 ; původní hodnota zapisovaná na port di ; zakázat přerušení loop: xor %00010000 ; negace pátého bitu out (BEEPER_PORT), A ; zápis na port call short_delay ; počkat jr loop ; a opakovat celé znovu short_delay: ; zpožďovací rutina ; mění B (což nám nevadí) ld b, 100 ; počitadlo zpožďovací smyčky delay_loop: djnz delay_loop ; opakovat smyčku s počitadlem v B ret ; návrat z podprogramu end ENTRY_POINT
A takto se čtvrtý příklad přeloží do strojového kódu:
ENTRY_POINT EQU 8000 BEEPER_PORT EQU 00FE ORG 8000 8000: label start 8000:3E07 LD A, 07 8002:F3 DI 8003: label loop 8003:EE10 XOR 10 8005:D3FE OUT (FE), A 8007:CD0C80 CALL 800C 800A:18F7 JR 8003 800C: label short_delay 800C:0664 LD B, 64 800E: label delay_loop 800E:10FE DJNZ 800E 8010:C9 RET 8011: END 8000 Emiting TAP basic loader Emiting TAP from 8000 to 8010
12. Vizualizace frekvence přehrávání změnou okraje v reálném čase
Na ZX Spectru se při nahrávání dat (například her) z kazety zobrazují na okraji obrazovky pruhy (viz například toto video), z nichž je možné při troše tréninku zjistit například kolísání rychlosti otáčení motorku kazetového magnetofonu, přesnost nastavení hlavy magnetofonu na čtenou stopu atd. Jak se však takové pruhy vůbec zobrazují a proč se vůbec jedná o viditelné pruhy? Ve skutečnosti je to velmi jednoduché, protože nejnižší tři bity zapisované na port 0×fe (tedy na stejný port, kterým se ovládá reproduktor) obsahují index barvy pozadí; tedy hodnotu 0 až 7. A rychlým přepisem tohoto indexu lze dosáhnout zobrazení oněch pruhů. Při nahrávání z kazety se mohou zobrazovat skutečně načítaná data, tento trik je možné použít pro vizualizaci časování nějaké rutiny atd. atd.
My se pokusíme o změnu barvy okraje při každé změně polohy membrány reproduktoru. To znamená, že pro tón o frekvenci 1000 Hz by se barva okraje měla změnit 1000× za sekundu, což při 50 snímcích za sekundu znamená přibližně 1000/50=20 pruhů v každém snímku (ovšem skutečně jen přibližně, protože jsme nezapočítali vertical blank atd.).
13. Pruhy na okraji obrazovky při povolení či zákazu přerušení
Upravme si tedy nyní program pro přehrání tónu tak, aby současně měnil i barvu okraje obrazovky. Je to triviální; pouze musíme kromě změny pátého bitu měnit i jeden či více bitů 1–3. Změnou prvního bitu přepínáme mezi bílou a žlutou barvou (a další bitové kombinace si vyzkoušejte):
ld A, %00000111 ; původní hodnota zapisovaná na port loop: xor %00010001 ; negace prvního a pátého bitu out (BEEPER_PORT), A ; zápis na port call short_delay ; počkat jr loop ; a opakovat celé znovu
Vliv přerušení nyní nebude pouze slyšitelný, ale i viditelný:
Obrázek 7: Zobrazení pruhů při povoleném přerušení. Na jednom snímku to není patrné, ale pruhy po obrazovce scrollují, a to ne zcela plynule.
Obrázek 8: Při zakázaném přerušení jsou pruhy zcela pravidelné. Pruhy jsou prakticky zastaveny a scrolling je plynulý.
14. Zdrojové kódy pátého a šestého příkladu
Pro úplnost si uveďme zdrojové kódy dnešního pátého i šestého demonstračního příkladu. Tyto příklady byly popsány v předchozích kapitolách:
ENTRY_POINT equ $8000 BEEPER_PORT equ $fe org ENTRY_POINT start: ld A, %00000111 ; původní hodnota zapisovaná na port loop: xor %00010001 ; negace prvního a pátého bitu out (BEEPER_PORT), A ; zápis na port call short_delay ; počkat jr loop ; a opakovat celé znovu short_delay: ; zpožďovací rutina ; mění B (což nám nevadí) ld b, 98 ; počitadlo zpožďovací smyčky delay_loop: djnz delay_loop ; opakovat smyčku s počitadlem v B ret ; návrat z podprogramu end ENTRY_POINT
Překlad pátého příkladu do strojového kódu:
ENTRY_POINT EQU 8000 BEEPER_PORT EQU 00FE ORG 8000 8000: label start 8000:3E07 LD A, 07 8002: label loop 8002:EE11 XOR 11 8004:D3FE OUT (FE), A 8006:CD0B80 CALL 800B 8009:18F7 JR 8002 800B: label short_delay 800B:0662 LD B, 62 800D: label delay_loop 800D:10FE DJNZ 800D 800F:C9 RET 8010: END 8000 Emiting TAP basic loader Emiting TAP from 8000 to 800F
ENTRY_POINT equ $8000 BEEPER_PORT equ $fe org ENTRY_POINT start: ld A, %00000111 ; původní hodnota zapisovaná na port di ; zakázat přerušení loop: xor %00010001 ; negace prvního a pátého bitu out (BEEPER_PORT), A ; zápis na port call short_delay ; počkat jr loop ; a opakovat celé znovu short_delay: ; zpožďovací rutina ; mění B (což nám nevadí) ld b, 98 ; počitadlo zpožďovací smyčky delay_loop: djnz delay_loop ; opakovat smyčku s počitadlem v B ret ; návrat z podprogramu end ENTRY_POINT
Překlad šestého příkladu do strojového kódu:
ENTRY_POINT EQU 8000 BEEPER_PORT EQU 00FE ORG 8000 8000: label start 8000:3E07 LD A, 07 8002:F3 DI 8003: label loop 8003:EE11 XOR 11 8005:D3FE OUT (FE), A 8007:CD0C80 CALL 800C 800A:18F7 JR 8003 800C: label short_delay 800C:0663 LD B, 63 800E: label delay_loop 800E:10FE DJNZ 800E 8010:C9 RET 8011: END 8000 Emiting TAP basic loader Emiting TAP from 8000 to 8010
15. Skutečné možnosti beeperu – PWM, vícehlasá hudba
Na první pohled by se mohlo zdát, že jednobitový výstup na reproduktor je primitivní technologie, která neumožňuje polyfonii ani například napodobení reálných hudebních nástrojů. Ve skutečnosti tomu tak není, protože existuje poměrně velké množství triků, které původní „jednobitový zvuk“ dokážou značně vylepšit. Jedním z těchto triků je rychlé přepínání mezi dvěma (či třemi) notami. Tento trik je použit například ve známé hře Knight Lore. Dalšími triky (SW mixováním) lze využít i větší množství kanálů, použití samplů atd. Viz například následující videa:
- Vectron Music by Tim Follin – Captured from a real 48K ZX Spectrum
https://www.youtube.com/watch?v=FySV12aWGkg - [ZX Spectrum Beeper] Mister Beep – Rubber Love (Oscilloscope View)
https://www.youtube.com/watch?v=xfuWEoUehk0 - Tim Follin – “Chronos (ZXS 48k)” [Oscilloscope View]
https://www.youtube.com/watch?v=wV9PfEFw78I - Modern ZX Spectrum 48K BEEPER music, Part 1
https://www.youtube.com/watch?v=QZnOd_f9YjQ
Na úvodních obrazovkách her (kde není zapotřebí pohybovat grafickými objekty) lze využít i PWM (pulsní šířkovou modulaci) popř. její různé modifikace. Jedna z modifikací na ZX Spectru vypadá tak, že se přehrává tón o vysoké frekvenci, například 20 kHz (prakticky pro nás starší neslyšitelné :-). Ve skutečnosti se díky tomu, že celý zvukový řetězec obsahuje integrační členy (elektrické a mechanické) dosáhne toho, že se membrána reproduktoru pohybuje v polovině své dráhy. Změnou střídy tohoto signálu (tedy poměru délky trvání logické jedničky k délce trvání logické nuly) lze měnit amplitudu zvuku (s frekvencí nižší než oněch 20 kHz) a přehrávat tak například různé samply atd.
Obrázek 7: Pulsní šířková modulace sinusové vlny (červená barva), která je porovnávána s referenčním trojúhelníkovým signálem (modrá barva). Výsledný binární signál je zobrazen žlutou barvou.
Obrázek 8: Pulsní šířková modulace – frekvence referenčního trojúhelníkového signálu je dvojnásobná oproti signálu zobrazeném na čtvrtém obrázku, výstup by však stále nebyl (při přehrání na reproduktoru) dostatečně kvalitní.
Obrázek 9: Pulsní šířková modulace – frekvence referenčního trojúhelníkového signálu je dvojnásobná oproti signálu zobrazeném na pátém obrázku.
Obrázek 10: Na tomto grafu je frekvence referenční trojúhelníkové vlny cca 10× vyšší, než frekvence převáděného signálu, což je již pro mnoho aplikací dostatečné.
Obrázek 11: Další zdvojnásobení frekvence referenční trojúhelníkové vlny. Výsledný graf je již částečně zkreslen vlivem převodu původních analogových průběhů do rastrového obrázku (již se přibližujeme k hranici, při níž vzniká obrazový alias).
16. Rozšíření ZX Spectra o další zvukové subsystémy
I přesto, že se s využitím různých triků dá dosáhnout i s původním jednobitovým beeperem poměrně dobrých výsledků je například tvorba hudby pro hry velmi složitá, neboť je nutné všechny akce pečlivě načasovat. Lepší by bylo, aby se zvuky a hudba tvořily nezávisle na hlavním CPU, podobně jako grafika. Toho lze dosáhnout zařazením PSG – Programmable sound generator. Jedná se o specializované čipy určené přesně pro tyto činnosti. Pro ZX Spectrum byl zvolen čip AY-3–8912 (neboli slavné „ayčko“), které bylo zařazeno do ZX Spectra 128K+ z roku 1986 (tedy čtyři roky po zahájení prodeje původního ZX Spectra 48k). Ovšem AY-3–8912 se dal připojit i jako externí zařízení. Příkladem je modul Melodik vyráběný v družstvu Didaktik Skalica (tam taktéž vznikly československé mikropočítače řady Didaktik).
17. Obsah navazujícího článku
V navazující části seriálu o tvorbě programů pro slavné ZX Spectrum se opět budeme zabývat tvorbou zvuků a hudby. Tentokrát se ovšem zaměříme především na použití čipu AY-3–8912 popř. na kombinaci „ayčka“ s původním beeperem. Mnohé původní 48k totiž prošly úpravami a nyní „ayčko“ taktéž obsahují.
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 čtrnácti článcích [1] [2], [3], [4], [5], [6], [7], [8], [9], [10], [11], [12], [13], [14], 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 84.tap 85.tap 86.tap 87.tap 88.tap 80.tap 90.tap \ 91.tap 92.tap 93.tap 94.tap 95.tap 96.tap 97.tap 98.tap 99.tap 100.tap \ 101.tap 102.tap 103.tap 104.tap 105.tap 106.tap 107.tap 108.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 84.tap: 84-print-ascii-table.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 84-print-ascii-table.lst 85.tap: 85-copy-ascii-table.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 85-copy-ascii-table.lst 86.tap: 86-copy-ascii-table-B.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 86-copy-ascii-table-B.lst 87.tap: 87-copy-ascii-table-C.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 87-copy-ascii-table-C.lst 88.tap: 88-copy-ascii-table-D.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 88-copy-ascii-table-D.lst 89.tap: 89-copy-ascii-table-E.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 89-copy-ascii-table-E.lst 90.tap: 90-copy-ascii-table-F.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 90-copy-ascii-table-F.lst 91.tap: 91-copy-ascii-table-G.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 91-copy-ascii-table-G.lst 92.tap: 92-copy-ascii-table-H.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 92-copy-ascii-table-H.lst 93.tap: 93-copy-ascii-table-I.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 93-copy-ascii-table-I.lst 94.tap: 94-color-attribute.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 94-color-attribute.lst 95.tap: 95-keypress.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 95-keypress.lst 96.tap: 96-keypress-row.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 96-keypress-row.lst 97.tap: 97-keypress-all-rows.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 97-keypress-all-rows.lst 98.tap: 98-game-character.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 98-game-character.lst 99.tap: 99-game-character-2.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 99-game-character-2.lst 100.tap: 100-cursor-joystick.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 100-cursor-joystick.lst 101.tap: 101-sinclair-joystick.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 101-sinclair-joystick.lst 102.tap: 102-kempston-joystick.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 102-kempston-joystick.lst 103.tap: 103-beep.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 103-beep.lst 104.tap: 104-music-scale.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 104-music-scale.lst 105.tap: 105-direct-speaker.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 105-direct-speaker.lst 106.tap: 106-direct-speaker-di.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 106-direct-speaker-di.lst 107.tap: 107-direct-speaker-border.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 107-direct-speaker-border.lst 108.tap: 108-direct-speaker-border-di.asm $(ASSEMBLER) -v -d --tapbas $< $@ > 108-direct-speaker-border-di.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 | 84-print-ascii-table.asm | tisk jednoho bloku s ASCII tabulkou | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/84-print-ascii-table.asm |
85 | 85-copy-ascii-table.asm | kopie bloku bajt po bajtu založená na naivní programové smyčce | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/85-copy-ascii-table.asm |
86 | 86-copy-ascii-table-B.asm | kopie bloku s využitím instrukce LDIR | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/86-copy-ascii-table-B.asm |
87 | 87-copy-ascii-table-C.asm | kopie bloku bajt po bajtu založená na programové smyčce a instrukci LDI | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/87-copy-ascii-table-C.asm |
88 | 88-copy-ascii-table-D.asm | rozbalení programové smyčky s instrukcí LDI | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/88-copy-ascii-table-D.asm |
89 | 89-copy-ascii-table-E.asm | korektní smyčka pro všechny možné velikosti bloků | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/89-copy-ascii-table-E.asm |
90 | 90-copy-ascii-table-F.asm | kostra programu, který pro kopii bloků (16 bajtů) využívá zásobník | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/90-copy-ascii-table-F.asm |
91 | 91-copy-ascii-table-G.asm | definice makra a několikeré použití (aplikace) tohoto makra | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/91-copy-ascii-table-G.asm |
92 | 92-copy-ascii-table-H.asm | opakování makra založené na REPT | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/92-copy-ascii-table-H.asm |
93 | 93-copy-ascii-table-I.asm | vícenásobná kopie části obrazovky | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/93-copy-ascii-table-I.asm |
94 | 94-color-attribute.asm | modifikace jednoho barvového atributu na obrazovce ZX Spectra | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/94-color-attribute.asm |
95 | 95-keypress.asm | detekce stisku jedné klávesy s vizualizací stisku | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/95-keypress.asm |
96 | 96-keypress-row.asm | detekce stisku kláves v jednom fyzickém řádku | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/96-keypress-row.asm |
97 | 97-keypress-all-rows.asm | detekce stisku všech kláves klávesnice ZX Spectra 48k | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/97-keypress-all-rows.asm |
98 | 98-game-character.asm | zajištění pohybu hráče v herní scéně s využitím klávesnice | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/98-game-character.asm |
99 | 99-game-character-2.asm | vylepšení předchozího demonstračního příkladu | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/99-game-character-2.asm |
100 | 100-cursor-joystick.asm | zajištění pohybu hráče v herní scéně kurzorovým joystickem | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/100-cursor-joystick.asm |
101 | 101-sinclair-joystick.asm | zajištění pohybu hráče v herní scéně joystickem připojeným přes Interface 2 | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/101-sinclair-joystick.asm |
102 | 102-kempston-joystick.asm | zajištění pohybu hráče v herní scéně joystickem připojeným přes rozhraní Kempston | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/102-kempston-joystick.asm |
103 | 103-beep.asm | využití subrutiny v ROM s implementací příkazu BEEP | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/103-beep.asm |
104 | 104-music-scale.asm | přehrání celé stupnice | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/104-music-scale.asm |
105 | 105-direct-speaker.asm | přímé programové ovládání beeperu | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/105-direct-speaker.asm |
106 | 106-direct-speaker-di.asm | zakázání přerušení při přehrávání | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/106-direct-speaker-di.asm |
107 | 107-direct-speaker-border.asm | vizualizace frekvence přehrávání změnou okraje v reálném čase | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/107-direct-speaker-border.asm |
108 | 108-direct-speaker-border-di.asm | vizualizace frekvence přehrávání změnou okraje v reálném čase | https://github.com/tisnik/8bit-fame/blob/master/Speccy-asm/108-direct-speaker-border-di.asm |
103 | 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 - Fixed point arithmetic
https://www.root.cz/clanky/fixed-point-arithmetic/ - 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 - How fast is memcpy on the Z80?
https://retrocomputing.stackexchange.com/questions/4744/how-fast-is-memcpy-on-the-z80 - How do Z80 Block Transfer instructions work?
https://retrocomputing.stackexchange.com/questions/5416/how-do-z80-block-transfer-instructions-work - Retro Programming Made Simple: Keyboard
http://www.breakintoprogram.co.uk/hardware/computers/zx-spectrum/keyboard - How ZX Spectrum avoided key ghosting
https://retrocomputing.stackexchange.com/questions/16235/how-zx-spectrum-avoided-key-ghosting - ZX Spectrum Keyboard Visualized
http://www.kameli.net/marq/?p=2055 - Sinclair ZX Spectrum Joysticks Explained
https://www.retroisle.com/general/spectrum_joysticks.php - When A Single Bit Was Enough, Into The Sound Of The ZX Spectrum
https://hackaday.com/2022/01/20/when-a-single-bit-was-enough-into-the-sound-of-the-zx-spectrum/ - 03B5: THE ‚BEEPER‘ SUBROUTINE
https://skoolkid.github.io/rom/asm/03B5.html - How To Write ZX Spectrum Games – Chapter 3
https://chuntey.wordpress.com/2013/02/28/how-to-write-zx-spectrum-games-chapter-3/ - Understanding computer sound
https://www.youtube.com/playlist?list=PL0qES-IQZC8w4vqeQhxHxKgxYYqs3CEOx - Understanding Computer Sound. 5. ZX Spectrum
https://www.youtube.com/watch?v=N5ACJd2LvbY - Dark Fusion (Gremlin Graphics, 1988)
https://www.youtube.com/watch?v=ADL3mdRMzoA - Arkanoid Spectrum Title Music
https://www.youtube.com/watch?v=TymO0Lj7Vp8 - Tim Follin – „Chronos“ (ZX Spectrum) [Oscilloscope Visualization]
https://www.youtube.com/watch?v=yJy45MHrPjc - [60 FPS] Wally Beben – „Sanxion Loader“ [ZX Spectrum (Beeper)] (Oscilloscope View)
https://www.youtube.com/watch?v=JwMxOfQVl7A - Understanding Computer Sound
http://forgottencomputer.com/retro/sound/