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/