Programujeme zvuky a hudbu na ZX Spectru

6. 6. 2023
Doba čtení: 41 minut

Sdílet

 Autor: Depositphotos
Cesta, která vedla od prvních reproduktorů 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á.

Obsah

1. Zvuky a hudba na ZX Spectru

2. Beeper 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

5. Přehrání celé stupnice

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

17. Obsah navazujícího článku

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

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

20. Odkazy na Internetu

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
Poznámka: kde se však vzala konstanta 437500? Je to přesně frekvence 3,5MHz (tedy frekvence hodinového signálu) podělená osmi.

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.).

Poznámka: jsou všechny tóny hrány po stejně dlouhou dobu? Proč tomu tak je?

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
Poznámka: povšimněte si, že na port 0×fe zapisujeme i binární hodnotu 111 uloženou v nejnižších třech bitech. Jak uvidíme dále, jedná se o barvu okraje (border) a tuto vlastnost – možnost změny pozadí a současně i stavu reproduktoru jedinou instrukcí – využijeme v dalších demonstračních příkladech.

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:

  1. Vectron Music by Tim Follin – Captured from a real 48K ZX Spectrum
    https://www.youtube.com/wat­ch?v=FySV12aWGkg
  2. [ZX Spectrum Beeper] Mister Beep – Rubber Love (Oscilloscope View)
    https://www.youtube.com/wat­ch?v=xfuWEoUehk0
  3. Tim Follin – “Chronos (ZXS 48k)” [Oscilloscope View]
    https://www.youtube.com/wat­ch?v=wV9PfEFw78I
  4. Modern ZX Spectrum 48K BEEPER music, Part 1
    https://www.youtube.com/wat­ch?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).

Poznámka: ovšem relativně snadno lze přes sběrnici připojit i OPL-2 či OPL-3. Jedná se však o nestandardní řešení, které pochopitelně nebude původními aplikacemi podporováno.

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í.

bitcoin školení listopad 24

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

Výše uvedené demonstrační příklady i příklady, které již byly popsány v předchozích č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

  1. z80 standalone assembler
    https://www.asm80.com/one­page/asmz80.html
  2. The ZX BASIC Compiler
    https://www.boriel.com/pages/the-zx-basic-compiler.html
  3. Z80 Assembly programming for the ZX Spectrum
    https://www.chibiakumas.com/z80/ZXSpec­trum.php
  4. 8-BIT SMACKDOWN! 65C02 vs. Z80: slithy VLOGS #6
    https://www.youtube.com/wat­ch?v=P1paVoFEvyc
  5. Instrukce mikroprocesoru Z80
    https://clrhome.org/table/
  6. Z80 instructions: adresní režimy atd.
    https://jnz.dk/z80/instructions.html
  7. Z80 Instruction Groups
    https://jnz.dk/z80/instgroups.html
  8. Elena, New programming language for the ZX Spectrum Next
    https://vintageisthenewold.com/elena-new-programming-language-for-the-zx-spectrum-next/
  9. Sinclair BASIC
    https://worldofspectrum.net/legacy-info/sinclair-basic/
  10. Grafika na osmibitových počítačích firmy Sinclair
    https://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair/
  11. Grafika na osmibitových počítačích firmy Sinclair II
    https://www.root.cz/clanky/grafika-na-osmibitovych-pocitacich-firmy-sinclair-ii/
  12. HiSoft BASIC
    https://worldofspectrum.net/in­foseekid.cgi?id=0008249
  13. YS MegaBasic
    https://worldofspectrum.net/in­foseekid.cgi?id=0008997
  14. Beta Basic
    https://worldofspectrum.net/in­foseekid.cgi?id=0007956
  15. BASIC+
    https://worldofspectrum.net/in­foseekid.php?id=0014277
  16. Spectrum ROM Memory Map
    https://skoolkit.ca/disas­semblies/rom/maps/all.html
  17. Goto subroutine
    https://skoolkit.ca/disas­semblies/rom/asm/7783.html
  18. Spectrum Next: The Evolution of the Speccy
    https://www.specnext.com/about/
  19. Sedmdesátiny assemblerů: lidsky čitelný strojový kód
    https://www.root.cz/clanky/sed­mdesatiny-assembleru-lidsky-citelny-strojovy-kod/
  20. Programovací jazyk BASIC na osmibitových mikropočítačích
    https://www.root.cz/clanky/pro­gramovaci-jazyk-basic-na-osmibitovych-mikropocitacich/
  21. Programovací jazyk BASIC na osmibitových mikropočítačích (2)
    https://www.root.cz/clanky/pro­gramovaci-jazyk-basic-na-osmibitovych-mikropocitacich-2/#k06
  22. Programovací jazyk BASIC na osmibitových mikropočítačích (3)
    https://www.root.cz/clanky/pro­gramovaci-jazyk-basic-na-osmibitovych-mikropocitacich-3/
  23. Sinclair BASIC (Wikipedia CZ)
    http://cs.wikipedia.org/wi­ki/Sinclair_BASIC
  24. Assembly Language: Still Relevant Today
    http://wilsonminesco.com/AssyDefense/
  25. Programovani v assembleru na OS Linux
    http://www.cs.vsb.cz/gryga­rek/asm/asmlinux.html
  26. Why Assembly Language Programming? (Why Learning Assembly Language Is Still a Good Idea)
    https://wdc65×x.com/market­s/education/why-assembly-language-programming/
  27. Low Fat Computing
    http://www.ultratechnology­.com/lowfat.htm
  28. Assembly Language
    https://www.cleverism.com/skills-and-tools/assembly-language/
  29. Why do we need assembly language?
    https://cs.stackexchange.com/qu­estions/13287/why-do-we-need-assembly-language
  30. Assembly language (Wikipedia)
    https://en.wikipedia.org/wi­ki/Assembly_language#Histo­rical_perspective
  31. Assembly languages
    https://curlie.org/Computer­s/Programming/Languages/As­sembly/
  32. vasm
    http://sun.hasenbraten.de/vasm/
  33. B-ELITE
    https://jsj.itch.io/b-elite
  34. ZX-Spectrum Child
    http://www.dotkam.com/2008/11/19/zx-spectrum-child/
  35. Speccy.cz
    http://www.speccy.cz/
  36. Planet Sinclair
    http://www.nvg.ntnu.no/sinclair/
  37. World of Spectrum
    http://www.worldofspectrum.org/
  38. The system variables
    https://worldofspectrum.or­g/ZXBasicManual/zxmanchap25­.html
  39. ZX Spectrum manual: chapter #17 Graphics
    https://worldofspectrum.or­g/ZXBasicManual/zxmanchap17­.html
  40. Why does Sinclair BASIC have two formats for storing numbers in the same structure?
    https://retrocomputing.stac­kexchange.com/questions/8834/why-does-sinclair-basic-have-two-formats-for-storing-numbers-in-the-same-structu
  41. Plovoucí řádová čárka na ZX Spectru
    https://www.root.cz/clanky/norma-ieee-754-a-pribuzni-formaty-plovouci-radove-tecky/#k05
  42. Norma IEEE 754 a příbuzní: formáty plovoucí řádové tečky
    https://www.root.cz/clanky/norma-ieee-754-a-pribuzni-formaty-plovouci-radove-tecky/#k05
  43. 1A1B: THE ‚REPORT AND LINE NUMBER PRINTING‘ SUBROUTINE
    https://skoolkid.github.i­o/rom/asm/1A1B.html
  44. 2DE3: THE ‚PRINT A FLOATING-POINT NUMBER‘ SUBROUTINE
    https://skoolkid.github.i­o/rom/asm/2DE3.html
  45. 5C63: STKBOT – Address of bottom of calculator stack
    https://skoolkid.github.i­o/rom/asm/5C63.html
  46. 5C65: STKEND – Address of start of spare space
    https://skoolkid.github.i­o/rom/asm/5C65.html
  47. Why does Sinclair BASIC have two formats for storing numbers in the same structure?
    https://retrocomputing.stac­kexchange.com/questions/8834/why-does-sinclair-basic-have-two-formats-for-storing-numbers-in-the-same-structu
  48. Chapter 24: The memory
    https://worldofspectrum.or­g/ZXBasicManual/zxmanchap24­.html
  49. Survey of Floating-Point Formats  
    https://mrob.com/pub/math/flo­atformats.html
  50. Convert an 8bit number to hex in z80 assembler
    https://stackoverflow.com/qu­estions/22838444/convert-an-8bit-number-to-hex-in-z80-assembler
  51. 80 MICROPROCESSOR Instruction Set Summary
    http://www.textfiles.com/pro­gramming/CARDS/z80
  52. Extended Binary Coded Decimal Interchange Code
    http://en.wikipedia.org/wiki/EBCDIC
  53. ASCII/EBCDIC Conversion Table
    http://docs.hp.com/en/32212–90008/apcs01.html
  54. EBCDIC
    http://www.hansenb.pdx.edu/DMKB/dic­t/tutorials/ebcdic.php
  55. EBCDIC tables
    http://home.mnet-online.de/wzwz.de/temp/eb­cdic/cc_en.htm
  56. The Mainframe Blog
    http://mainframe.typepad.com/blog/2006/11/my_per­sonal_mai.html
  57. Binary-coded decimal
    https://en.wikipedia.org/wiki/Binary-coded_decimal
  58. BCD
    https://cs.wikipedia.org/wiki/BCD
  59. Z80 heaven: Floating Point
    http://z80-heaven.wikidot.com/floating-point
  60. Z80, the 8-bit Number Cruncher
    http://www.andreadrian.de/ol­dcpu/Z80_number_cruncher.html
  61. Floating-point library for Z80
    https://github.com/DW0RKiN/Floating-point-Library-for-Z80
  62. z80float
    https://github.com/Zeda/z80float
  63. Fixed point arithmetic
    https://www.root.cz/clanky/fixed-point-arithmetic/
  64. ZX Spectrum BASIC Programming – 2nd Edition
    https://archive.org/details/zx-spectrum-basic-programming/page/n167/mode/2up
  65. ZX Spectrum BASIC Programming – 2nd Edition
    https://archive.org/details/zx-spectrum-basic-programming/page/n169/mode/2up
  66. How fast is memcpy on the Z80?
    https://retrocomputing.stac­kexchange.com/questions/4744/how-fast-is-memcpy-on-the-z80
  67. How do Z80 Block Transfer instructions work?
    https://retrocomputing.stac­kexchange.com/questions/5416/how-do-z80-block-transfer-instructions-work
  68. Retro Programming Made Simple: Keyboard
    http://www.breakintoprogram­.co.uk/hardware/computers/zx-spectrum/keyboard
  69. How ZX Spectrum avoided key ghosting
    https://retrocomputing.stac­kexchange.com/questions/16235/how-zx-spectrum-avoided-key-ghosting
  70. ZX Spectrum Keyboard Visualized
    http://www.kameli.net/marq/?p=2055
  71. Sinclair ZX Spectrum Joysticks Explained
    https://www.retroisle.com/ge­neral/spectrum_joysticks.php
  72. 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/
  73. 03B5: THE ‚BEEPER‘ SUBROUTINE
    https://skoolkid.github.i­o/rom/asm/03B5.html
  74. How To Write ZX Spectrum Games – Chapter 3
    https://chuntey.wordpress­.com/2013/02/28/how-to-write-zx-spectrum-games-chapter-3/
  75. Understanding computer sound
    https://www.youtube.com/pla­ylist?list=PL0qES-IQZC8w4vqeQhxHxKgxYYqs3CEOx
  76. Understanding Computer Sound. 5. ZX Spectrum
    https://www.youtube.com/wat­ch?v=N5ACJd2LvbY
  77. Dark Fusion (Gremlin Graphics, 1988)
    https://www.youtube.com/wat­ch?v=ADL3mdRMzoA
  78. Arkanoid Spectrum Title Music
    https://www.youtube.com/wat­ch?v=TymO0Lj7Vp8
  79. Tim Follin – „Chronos“ (ZX Spectrum) [Oscilloscope Visualization]
    https://www.youtube.com/wat­ch?v=yJy45MHrPjc
  80. [60 FPS] Wally Beben – „Sanxion Loader“ [ZX Spectrum (Beeper)] (Oscilloscope View)
    https://www.youtube.com/wat­ch?v=JwMxOfQVl7A
  81. Understanding Computer Sound
    http://forgottencomputer.com/re­tro/sound/

Autor článku

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