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.
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.VRAM | dvojkově | 2. VRAM | dvojkově |
---|---|---|---|---|---|
0. | 00000 | 16384 | 01000000 00000000 | 49152 | 11000000 00000000 |
1. | 00001 | 16416 | 01000000 00100000 | 49184 | 11000000 00100000 |
2. | 00010 | 16448 | 01000000 01000000 | 49216 | 11000000 01000000 |
3. | 00011 | 16480 | 01000000 01100000 | 49248 | 11000000 01100000 |
4. | 00100 | 16512 | 01000000 10000000 | 49280 | 11000000 10000000 |
5. | 00101 | 16544 | 01000000 10100000 | 49312 | 11000000 10100000 |
6. | 00110 | 16576 | 01000000 11000000 | 49344 | 11000000 11000000 |
7. | 00111 | 16608 | 01000000 11100000 | 49376 | 11000000 11100000 |
8. | 01000 | 18432 | 01001000 00000000 | 51200 | 11001000 00000000 |
9. | 01001 | 18464 | 01001000 00100000 | 51232 | 11001000 00100000 |
10. | 01010 | 18496 | 01001000 01000000 | 51264 | 11001000 01000000 |
11. | 01011 | 18528 | 01001000 01100000 | 51296 | 11001000 01100000 |
12. | 01100 | 18560 | 01001000 10000000 | 51328 | 11001000 10000000 |
13. | 01101 | 18592 | 01001000 10100000 | 51360 | 11001000 10100000 |
14. | 01110 | 18624 | 01001000 11000000 | 51392 | 11001000 11000000 |
15. | 01111 | 18656 | 01001000 11100000 | 51424 | 11001000 11100000 |
16. | 10000 | 20480 | 01010000 00000000 | 53248 | 11010000 00000000 |
17. | 10001 | 20512 | 01010000 00100000 | 53280 | 11010000 00100000 |
18. | 10010 | 20544 | 01010000 01000000 | 53312 | 11010000 01000000 |
19. | 10011 | 20576 | 01010000 01100000 | 53344 | 11010000 01100000 |
20. | 10100 | 20608 | 01010000 10000000 | 53376 | 11010000 10000000 |
21. | 10101 | 20640 | 01010000 10100000 | 53408 | 11010000 10100000 |
22. | 10110 | 20672 | 01010000 11000000 | 53440 | 11010000 11000000 |
23. | 10111 | 20704 | 01010000 11100000 | 53472 | 11010000 11100000 |
atrib. | - | 22528 | 01011000 00000000 | 55296 | 11011000 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.
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 DOWNHL 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
- ZXS_video_RAM_address.ods - podrobná tabulka adres pro OpenOffice.org 2.x, upravená pro tisk na 4x A4 - ODF 28kB
- Assembler a ZX Spectrum 1 - skvělá kniha od Proximy převedená do PDF
- Assembler a ZX Spectrum 2 - skvělá kniha od Proximy převedená do PDF
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...