5. 10. 2021

ZX spectrum - border a assembler

Po úspechu s húsenicou som sa rozhodol pokračovať v oprašovaní ZX Spectra s logickým pokračovaním v assembleri. Pre tieto pokusy použijem emulátor ZX Spin, ktorý obsahuje editor pre assembler.

Odskúšam kód z článku v prvom čísle časopisu Elektronika z roku 1990. Konkrétne článok od Pavla Vanouška o časovanom prepínaní okrajov. Poďme spraviť trik.

ZX Spectrum prišlo prvé v sérií Sinclair počítačov s farbami, na ich ovládanie v basicu sú použité INK, PAPER pre nastavenie písma a pozadia, BORDER na nastavenie farby okraju. Kým INK a PAPER majú limit na jednu kombináciu po znakoch (8x8 pixelov), BORDER ide nastaviť iba jeden na celý okraj obrazovky.

Avšak, ako iné 8bity, aj Spectrum má voči 50Hz vykresľovaniu obrazovky dostatočne rýchly procesor pre zmeny farieb počas vykresľovania. Tak rýchly, že aj interpretovaný kód v basicu zvládne pár príkazov počas 1/50 sekundy (1 snímka).

1 REM **  Pavel Vanousek  **
2 REM ** ELEKTRONIKA 1 90 **
4 FOR x=1 TO 21: PRINT x: NEXT x
6 BORDER 1: BORDER 2: BORDER 3: BORDER 4: BORDER 5: BORDER 6: BORDER 7: BORDER 0: PAUSE 1: GO TO 6
8 PRINT AT 9,0;"22";AT 9,0;11: GO TO 8

Príkaz "PAUSE 1" čaká na prvé prerušenie synchronizované s obrazovkou. Preto sú príkazy basicu vždy rovnako posunuté a obrazovka "drží" stabilné farby.

Tento trik funguje pre rôzne počty okrajov, ako vidieť jeden príkaz pre zmenu farby trvá približne 3 textové riadky.

Rovnaké prepínanie umožňuje aj priamo assembler, samozrejme tu sme na iných rýchlostiach a tak po každej zmene farby okraju budeme čakať nejaký počet cyklov, nech sa na obrazovke vykreslí pár riadkov.

; program 1
; spustenie RANDOMIZE USR 59000
; nakresli modry pruh, tenky biely, za nim zeleny
org 59000
	ei	; povolenie prerusenia
zac:	halt	; pause 1
	ld a,1	; border 1
	out (254),a
	ld a,7	; border 7
	ld b,10	; vyckame 10 cyklov
wa:	push bc
	ld b,255
ww:	djnz ww	; vnut cyklus cakania
	pop bc
	djnz wa	; vonk cyklus
	out (254),a
	ld a,4	; border 4
	ld b,130	; kratke cakanie
we:	djnz we
	out (254),a
	ld a,(23560)	; posledny klaves
	cp 32	; break?
	jr nz,zac
	ret

V emulátore ZX Spin otvoríme cez menu TOOLS poslednú položku Z80 assembler a tam vložíme kód. ORG 59000 určí, kam sa v pamäti daný kód začne ukladať.

Stručne popíšem niektoré inštrukcie:

halt  - zastaví program až do vyvolania prerušenia (1/50 sekundy)
ld a,1 - naplní (load) do registra "a" (8bit pamäť v procesore, niečo ako premenná pre číslo 0-255)
out (254),a  - na port 254 nastaví hodnotu registra a, v tomto prípade "1", port 254 v Spectrum hardware používa na nastavenie okraja (BORDER) a vyššie bity tohto portu pre výstup na pásku (zvuk všeobecne)
push bc - odloží "bc" teda 2 registre b,c do zásobníka
pop bc - vráti registre zo zásobníka, táto kombinácia je dobrá na uchovanie pôvodných hodnôt, pretože registrov je v procesore len malý počet voči všetkým hodnotám ktoré program potrebuje
djnz ww  - špeciálna inštrukcia, "d" znamená decrement, zníženie "b" registra o 1, "jnz" znamená jump if not zero, teda skočí ak "b" ešte nieje 0 na adresu návestia "ww"
ld a,(23560) - načíta posledný stlačený kláves zo systémových premenných Spectra
ret - return, návrat či už z podprogramu (call), alebo z celého programu (do basicu)

Po zápise kódu do assembler okna ho preložíme a uložíme do pamäte cez menu FILE a položku assemble. Dole v message okne vypíše koľko bajtov výsledok zaberá a či je bez chýb. Následne z okna emulátora basicu zavoláme RANDOMIZE USR 59000.


Je vidieť, že napriek čakaniu 130 cyklov je vykreslený zmenenou farbou pásik o šírke len zhruba 1 riadku (medzi modrou a zelenou).

Keďže assembler je omnoho rýchlejší, môžeme meniť počas zobrazovania aj PAPER a INK hodnoty vrámci jedného znaku.

; program 2
; spustenie RANDOMIZE USER 59034
; vykresli jeden znak s modrym a zltym pozadim
	ei
zas:	halt	;pause 1
	call cak1
	ld hl,22528	; adresa atributu
	ld (hl),3*8	; paper 3, ink 0
	inc hl
	ld (hl),4*8	; paper 3, ink 0
	dec hl
	call cak2	; cakaj aby presla 1/3
	ld (hl),6*8+128	; paper 6, ink 0, bright
	inc hl
	ld (hl),5*8+64	; paper 5, ink 0, flash
	dec hl
	call cak2	; cakaj aby presla 1/3
	ld (hl),1*8+5	; paper 1, ink 5
	inc hl
	ld (hl),7*8	; paper 7, ink 0
	dec hl
	ld a,(23560)	; klavesa
	cp 32		; break?
	jr nz, zas
cak1:	ld b,20		; dlzka cakania
c1:	push bc
	ld b,48
c2:	djnz c2
	pop bc
	djnz c1
	ret
cak2:	ld b,50
cc2:	djnz cc2
	ret

Ak program dáme za prvý, bude začínať na adrese 59034. Pre lepší efekt najskôr niečo vypíšeme na prvé dva znaky až potom ho spustíme:

10 PRINT AT 0,0;"ZX": RANDOMIZE USR 59034

Jediná novinka voči predchádzajúcemu programu je tu adresovanie PAPER,INK atribútov prvého a druhého znaku. Nachádza sa na adrese 22528 a 22529 (používam inc hl a dec hl pre posun medzi nimi).

Na obrázku to nevidieť, ale prostredná časť písmena "Z" bliká. Tá čierno-zelená. To zabezpečuje ULA, nie tento kód. Ten len zapína blikanie v 1/3 vykresľovania a potom zas vypína.

Na záver, tým že port 254 okrem okraju zabezpečuje aj zvuk / magnetofón, dá sa jedným OUT príkazom robiť efekt ako zvukový tak grafický. Napríklad pri hrách pri streľbe alebo zásahu. Veľmi šikovné. Uvádzam jednoduchý cyklus, žiadny zvláštny zvukový efekt nevytvorí, len akýsi šum.

; program 3
; efekty s okrajom a zvukom
; randomize usr 59075
	ld de,38970	; dlzka trvania
	ld hl,0
lopk:	ld a,h
	out (254),a	; spodne 3 bity border
	inc hl		; ale 4,5 bit je zvuk
	dec de
	ld a,d
	cp 0
	jp nz,lopk
	ret

R.I.P. Sir Clive Sinclair 16.9.2021

Žiadne komentáre:

Zverejnenie komentára