ZX Spectrum - adresy VRAM

Adresování pixelů ve video paměti počítačů ZX Spectrum není lineární a na první pohled se může zdát komplikované a obtížně použitelné. Ve skutečnosti záleží na situaci, např. při vykreslování znaků na textové pozice se lze o jeden pixel níž posouvat pouhou inkrementací horního bytu adresy, což je rychlejší než přičítání konstanty k registru. Ani výpočet adresy bytu (pixelu) zadaného pomocí souřadnic není tak komplikované.

Základy známé každému uživateli ZX Spectra

Obrazovka ZX Spectra je rozdělena na pixelovou část velikou 6144 bytů a barevné atributy zabírající 768 bytů. Pixelová část začíná na adrese 16384 (49152 v případě zrcadla, nebo 2. VRAM u ZX Spectra 128k), atributová část na adrese 16384 + 6144 = 22528. Dohromady celá obrazovka zabírá 6912 bytů.

Pixelová část je rozdělená na 3 třetiny. Každá třetina zabírá 2048 bytů, resp. 8 textových řádků širokých 32 znaků. Viz následující náčrtek.

třetiny video RAM

Každý uživatel ZX Spectra, který někdy načítal obrázek uložený na kazetě viděl, jak se video paměť plní daty. Přesně v tom pořadí se zaplní i následujícím programem. Nejprve pixely po třetinách z levého horního rohu, přičemž se nejprve zaplní horní byty každého znaku v celé třetině, pak nižší byty a až po zaplnění celé obrazovky pixely se lineárně vyplní i barvové atributy ke každému čtverci 8x8 pixelů.

10 FOR a=16384 TO 23295
20 POKE a,255
30 NEXT a

Adresování textových řádků ukazuje následující tabulka.

řádekřádek b.1.VRAMdvojkově2. VRAMdvojkově
0.000001638401000000 000000004915211000000 00000000
1.000011641601000000 001000004918411000000 00100000
2.000101644801000000 010000004921611000000 01000000
3.000111648001000000 011000004924811000000 01100000
4.001001651201000000 100000004928011000000 10000000
5.001011654401000000 101000004931211000000 10100000
6.001101657601000000 110000004934411000000 11000000
7.001111660801000000 111000004937611000000 11100000
8.010001843201001000 000000005120011001000 00000000
9.010011846401001000 001000005123211001000 00100000
10.010101849601001000 010000005126411001000 01000000
11.010111852801001000 011000005129611001000 01100000
12.011001856001001000 100000005132811001000 10000000
13.011011859201001000 101000005136011001000 10100000
14.011101862401001000 110000005139211001000 11000000
15.011111865601001000 111000005142411001000 11100000
16.100002048001010000 000000005324811010000 00000000
17.100012051201010000 001000005328011010000 00100000
18.100102054401010000 010000005331211010000 01000000
19.100112057601010000 011000005334411010000 01100000
20.101002060801010000 100000005337611010000 10000000
21.101012064001010000 101000005340811010000 10100000
22.101102067201010000 110000005344011010000 11000000
23.101112070401010000 111000005347211010000 11100000
atrib. - 2252801011000 000000005529611011000 00000000

Rozsáhlejší tabulka pro každý pixelový řádek je k prohlédnutí zde. Tato tabulka je velmi užitečná k pochopení funkce programů pro výpočet adresy, přepočet adresy atributu z adresy pixelů a další operace nad obrazem.

Všimněte si, jak se shodují stejnou barvou označené bity. Prostým přesunem těchto bitů lze sestavit adresu bez komplikovaného výpočtu. Proto je taky souřadnice Y počítána z levého horního rohu dolů, tj. od nejnižší adresy, stejně jako BASIC pro ZX Spectrum čísluje textové řádky. Souřadnice X je orientována tradičně zleva doprava.

Jak je potřeba přesouvat bity k získání adresy pixelu ukazuje následující náčrtek. Použil jsem v něm stejné barvy, jako v tabulce.

adresy ve video RAM

Tmavou azurovou barvou jsou vyznačené bity, které se neuplatní v adrese bytu, ale mohou být potřeba pro určení konkrétního pixelu v rámci bytu.

Všimněte si, že dolní byte adresy není pro atributy potřeba sestavovat znovu.

Ukázky programů pro výpočet adresy

Výpočet adresy bytu pixelů ze souřadnic XY

;==============================================================================
; SPRITE_XY2ADDR - výpočet adresy do VRAM od 49152
;==============================================================================
; výpočet adresy ve VRAM podle souřadnic spritu, počítá adresu do 2. VRAM od adresy 49152
;
; vstup:
;	souřadnice v HL (H = Y, L = X)
;
; výstup:
;	adresa v HL
;	počet rotací vlevo v A
;
; mění:
;	DE (ukládá do něj mezivýsledky a nakonec prohodí s HL)
;
; Časová náročnost 19*4 + 6*7 = 118T + ret (10T) a call (17T)

SPRITE_XY2ADDR	ld	a,h		; 4T - zkopíruj souřadnici Y z H do A
		rrca			; 4T - 3x rotuj vpravo (dolní 3 bity na místo horních)
		rrca			; 4T
		rrca			; 4T
		and	00011000b	; 7T - ponech jen bity Y7 a Y6 posunuté 3x vpravo
		or	11000000b	; 7T - pridej 192 (49152 = 11000000 00000000)
		xor	h		; 4T - sxoruju s Yovou souřadnicí
		and	11111000b	; 7T - ponechám horních 5 bitů
		xor	h		; 4T - takže dvojitý xor ovlivní jen dolní 3 bity
		ld	d,a		; 4T - výsledek ulož do D, horní byte je hotov
		ld	a,h		; 4T - naposledy vezmu souřadnici Y
		rlca			; 4T - 2x vlevo
		rlca			; 4T
		and	11100000b	; 7T - ponechám bity Y5, Y4, Y3
		ld	e,a		; 4T - uložím do E
		ld	a,l		; 4T - vezmu Xovou souřadnici
		rrca			; 4T - 3x vpravo
		rrca			; 4T
		rrca			; 4T
		and	00011111b	; 7T
		or	e		; 4T - přioruju dříve získané bity z Y
		ld	e,a		; 4T - výsledek uložím do E, dolní byte je hotov
		ld	a,l		; 4T - naposledy Xovou souřadnici
		and	00000111b	; 7T - ponechám dolní 3 bity, X v bytu (rotace vpravo)
		ex	hl,de		; 4T - prohodím, výsledná adresa se dostane do HL
		ret			; 10T
		
; total 4+4+4+4+7+7+4+7+4+4+4+4+4+7+4+4+4+4+4+7+4+4+4+7+4 = 118T + 10T ret & 17T call

Výpočet adresy bytu pixelů ze souřadnic XY v ZX ROM

I když použité registry nemusí vždy vyhovovat, rutina je rychlá a přítomná asi ve všech ROM včetně mnoha upravených. Často se programy v ROM vyplatí použít.

;=============================================================================
; rutina ZX ROM 8880
;=============================================================================
; vstup:
;	registr A = souřadnice Y
;	registr L = souřadnice X
;
; výstup:
;	adresa v HL
;	počet rotací vlevo v A


; výpočet adresy je součástí rutiny PIXEL-ADD, omezení pro BASIC na 172px se lze
; vyhnout voláním kódu o 3 instrukce později na desítkové adrese 8880
;
;PIXEL-ADD	la	a,0afh		; tuto část přeskočit
;		sub	b		; tuto část přeskočit
;		jp	c,024f9h	; tuto část přeskočit

ROM_8880	ld	b,a		; 4T	souřadnici Y z A do B
		and	a		; 4T	vynulovat CARRY flag
		rra			; 4T	souřadnici Y v A/2, do bitu 7 narotovat 0
		scf			; 4T	nastav CARRY flag
		rra			; 4T	souřadnici Y v A/2, do bitu 7 narotovat 1
		and	a		; 4T	vynulovat CARRY flag
		rra			; 4T	souřadnici Y v A/2, do bitu 7 narotovat 0
					; 	v A jsou nyní bity 0 1 0 b7 b6 b5 b4 b2
		xor	b		; 4T	XOR s původní souřadnicí Y
		and	11111000b	; 7T	vynuluj dolní 3 bity
		xor	b		; 4T	znovu XOR, zůstanou změněné jen ty dolní 3 bity
					; 	reg. A nyní obsahuje 0 1 0 b7 b6 b5 
					;	Takže H bude obsahovat 64+8*INT (b/64)+(b mod 8)
		ld	h,a		; 4T	což je vyšší bajt adresy bodu.
		ld	a,c		; 4T	A obsahuje bity: 7 6 5 4 3 2 1 0 bajtu z reg. C.
		rlca			; 4T	
		rlca			; 4T	
		rlca			; 4T	A obsahuje bity: 2 1 0 7 6 5 4 3.
		xor	b		; 4T	
		and	199		; 7T	
		xor	b		; 4T	A obsahuje bity: 2 1 5 4 3 5 4 3.
		rlca			; 4T	
		rlca			; 4T	A obsahuje bity: 5 4 3 7 6 5 4 3.
		ld	l,a		; 4T	Takže L bude 32*INT (b/(b mod 64)/8)
		ld	a,c		; 4T	A obsahuje x (mod 8)
		and	00000111b	; 7T	Ponech jen dolní 3 bity Takže bod je bit (0 až 7) uvnitř daného bajtu
		ret			; 10T

; total 4+4+4+4+4+4+4+4+7+4+4+4+4+4+4+4+7+4+4+4+4+4+7 = 101T + 10T ret & 17T call

Výpočet adresy atributu z adresy bytu pixelů

Rutina spoléhá na to, že dolní část adresy je už v registru L a není potřeba ji měnit.

Rutina spoléhá na to, že dolní tři bity horního bytu adresy jsou nulové, tzn. adresa ukazuje na horní byte z osmi ve znakové pozici.

;=============================================================================
; ATTRADR - výpočet adresy atributu z adresy pixelu
;=============================================================================
; vstup:
;	v HL adresa 1. (horního) bytu ve znakové pozici
;
; výstup:
;	v HL adresa barvového atributu

ATTRADR		ld	a,h		; 4T	010??000b nebo 110??000b
		rrca			; 4T	3x vpravo, bit 0 se kopíruje do carry
		rrca			; 4T
		rrca			; 4T	vznikne 000010??b nebo 000110??b
		xor	01010000b	; 7T	vznikne 010110??b - pro 2. VRAM xorovat hodnotou 11000000b
		ld	h,a		; 4T 	výsledek do H a adresa je hotová
		ret			; 10T
		
; total 4+4+4+4+7+4 = 34T + 10T ret & 17T call

Vyplatí se možná spíš zařadit do kódu, je-li přepočet potřeba často než volat jako podprogram.

Výpočet adresy o pixel níž

K tomu slouží všudypřítomná a pro kreslení spritů velmi důležitá rutina DOWNH od Universuma z knihy Assembler a ZX Spectrum 1. Jen je v knize komentovaná trochu jinak.

;=============================================================================
; DOWNHL - výpočet adresy o pixel níž
;=============================================================================
; vstup:
;	v HL adresa libovolného bytu v pixelové oblasti
;
; výstup:
;	v HL adresa bytu o pixel níž, nebo u horního okraje obrazovky, byl-li nejspodnější
	
DOWNHL		inc	h		; 4T	inkrementovat H dá adresu o pixel níž, nebyla-li
		ld	a,h		; 4T	nejnižší ve znakové pozici, zkopíruj výsledek do A
		and	7		; 7T	ponech v A jen dolní 3 bity z horního bytu adresy
		ret	nz		; 5/11T	jsou-li nulové, byl inkrementovaný byte nejnižší, jinak hotovo, vrať se


		ld	a,l		; 4T	vezmi dolní byte adresy z L do A
		add	a,32		; 7T	přičti šířku řádku 32, nastaví carry flag dojde-li k přetečení
		ld	l,a		; 4T	vrať výsledek zpět do L
		ld	a,h		; 4T	do A znovu vezmi horní byte adresy (inkrementovaný)
		jr	c,DOWNHL2	; 7/12T	pokud sčítáním došlo k přetečení, odskoč, došlo k přechodu mezi třetinami

; po přechodu na další znakovou pozici, máme v H 010??111b + 1, nutno korigovat

		sub	8		; 7T	od horního bytu adresy odečti 8, byla už 8x inkrementována
		ld	h,a		; 4T	výsledek vrať do H, adresa je sestavena

; nyní je třeba zkontrolovat, jestli nedošlo k opuštění obrazovky, protože adresa ukazovala na byte u dolního okraje
; horní byte adresy nejnižšího bytu je v rozsahu 64 až 87

DOWNHL2		cp	88		; 7T	porovnej s hodnotou mimo obrazovku
		ret	c		; 5/11T	pokud byl horní byte menší, obrazovka nebyla opuštěna, vrať se
		ld	h,64		; 7T	přesuň adresu na horní okraj obrazovky (funguje pro 1. VRAM)
		ret			; 10T	vrať se

; total 4+4+7+11 = 26T				v rámci znakové pozice (7x každý znakový řádek)
; total 4+4+7+5+4+7+4+4+7+7+4+7+11 = 75T	s přechodem mezi znakovými řádky bez přechodu mezi třetinami
; total 4+4+7+5+4+7+4+4+12+7+11 = 69T		s přechodem mezi třetinami, bez korekce na dolním okraji obrazovky
; total 4+4+7+5+4+7+4+4+12+7+5+7+10 = 80T	s přechodem mezi třetinami a korekcí na dolním okraji obrazovky

K pochopení je opět užitečná obarvená tabulka adres. Např. pro přechod mezi třetinami, který nastává ze 7. řádku na 8. a z 15. na 16.

Pokud byste chtěli, aby sprite překračující dolní okraj obrazovky nepokračoval od horního okraje, lze místo 64 do H na předposledním řádku vložit 0 a zapisovat do ROM (nepatrné riziko, že někdo bude mít místo ROM zapisovatelnou RAM). Případně na tom místě zajistit, aby se v kreslení nepokračovalo vůbec, nebo hlídat velikost spritů a jejich polohu dřív, než se kreslení spustí.

Analogicky fungující rutinu DOWNDE si v knize najděte sami.

Výpočet adresy jeden byte vpravo

Toto je užitečné pro každé kreslení spritů, které zabírají na obrazovce víc než jediný byte.

;=============================================================================
; RIGHTL - výpočet adresy jeden byte vpravo
;=============================================================================
; vstup:
;	adresa bytu v pixelové části obrazovky
;
; výstup:
;	adresa sousedící vpravo s původním bytem s ohledem na pravý okraj, třetiny a dolní okraj

RIGHTL		ld	a,l		; 4T	nižší byte z adresy do L
		inc	l		; 4T	zvyš dolní byte adresy
		xor	l		; 4T	XORuj s původní hodnotou
		bit	5,a		; 8T	v rozsahu 0 až 31 se mění jen dolních 5 bitů
		ret	z		; 11/5T Z = pravý okraj nepřekročen, bit 5 se nezměnil
		ld	h,0		; 7T	přesměruj zápis do ROM (pozor na zapisovatelné ROM!)
		ret			; 10T	vrať se
		
; total 4+4+4+8+11 = 31T	když sprite zůstává v rámci řádku
; total 4+4+4+8+5+7+10 = 42T	když sprite překročí pravý okraj obrazovky

Download

Historie změn článku

  • 2006-xx-xx - napsáno, zveřejněno
  • 2021-05-22 - revidováno, přepsáno, doplněno o HTML tabulku, rutinu z ROM, náčrtek atd...

[ Zpět na hlavní stránku ]

Tento web je převážně o ZX Spectru, kompatibilních počítačích a jiném zajímavém hardwaru. Naleznete-li chybu, nebo byste rádi cokoliv co s tímto souvisí, můžete mi napsat email. Stručně o mém webu zde.