Uživatelské nástroje

Nástroje pro tento web


lnxspectrum:blitter

Blitter

Blitter je specializovaný čip který umí přesouvat bloky dat ve videoram tak, jak je zrovna potřeba. Není odkázán jen na blokové přenosy za sebou jdoucích dat, ale umí je během přenosu upravovat a rozhodovat se o cílu přenosu. Díky tomu zrychluje práci s grafikou. Blitter se objevil poprvé v počítačích Commodore Amiga, o několik let později dorazil (po vzoru Amigy) i do Atari Mega ST.

ZX Spectrum se nikdy nedočkalo ničeho takového jako je Blitter. Nejpodobnější čip který se blížil bylo DMA, nicméně to umělo jen kopírovat velké bloky dat, což pro grafiku, a to navíc v ZX Spectru není vhodné. Smysl ale měl pro práci s jiným zařízením (třeba FDD). Kde byl velmi efektivní.

LnxSpectrum je emulátor, a tak si může dovolit Blitter emulovat. Je však pouze virtuální. Fyzicky čip nikdy neexistoval, je tedy na tom podobně, jako třeba ULA+ nebo Spec256 rozšíření. Technicky dodržuje základní pravidla časování (3 takty na čtení / zápis do paměti ZX Spectra), takže rychlost přesunů dat odpovídá rychlosti zmiňovaného DMA. Bylo by ho možné vytvořit jako externí interface s pomocí FPGA, nebo Raspberry pi.

Tento projekt vznikl pro zábavu a ze zvědavosti, co by ZX Spectrum dokázalo kdyby takový čip dostal. A musím uznat že z prvních výsledků jsem byl nadšen. Vliv na výkon to má obrovský, a díky tomu jdou dělat na ZX Spectru dosud nevídané efekty. Amigu ale samozřejmě nedožene, ta je prostě napřed mnohem mnohem více.

Virtuální LnxBlitter

Při psaní Blitteru pro ZX jsem musel počítat s neobvykle seřazenou videoramkou, která se na jiných platformách nevyskytuje. A navíc, aby se dal využít i k vykreslování spritů s tím, aby do toho muselo CPU zasahovat jen minimálně, vytvořil jsem 2 režimy. Kopírování bloků dat (podobný princip jako Blitter na Amize) a druhý Sprite režim.

LnxBlitter obsahuje 2 kanály, zdrojový (SRC) a cílový (DST). Každý z nich může být v jiném režimu (Blok / Sprite). Režim Sprite automaticky počítá s tím, že čtení nebo zápis tohoto kanálu bude do ZX videoram (ta však nemusí být striktně na adrese 16384). Pozici Spritu udáváme v souřadnicích (obrazovka 32×192). Můžeme ho začít vykreslovat i mimo obazovku. Například hodnota X=255 začne vykreslovat Sprite o jeden attribut vlevo, v prostoru borderu. Tam se samozřejmně neobjeví, začne se vykreslovat až jeho druhý attribut, který již bude v prostoru videoram. Stejně tak Můžeme Sprite vykreslovat i mimo obrazovku a nemusíme se bát, že přetečení Spritu mimo videoram poškodí náš program.

Současně s vykreslováním můžeme zapnout i automatické obarvování v rámci vykreslování. Je jedno v jakém režimu vykreslujeme (Blok nebo Sprite). Možnosti obarvení máme dva. Obarvit objekt jednou barvou, nebo kopírovat barevné attributy z dat Spritu.

Další funkce se týká posuvu dat. Lze s ním snadno posouvat obrazovky nebo jeho části horizontálně, a to o libovolný počet bitů (0-7). Je také možné data Spritu vykreslovat přímo na obrazovku s tím, že již budou posunuty. Pokud je zapnuté obarvování jednou barvou, obarví se všechny attributy, do kterých Sprite zasahuje. Posouvání nežere žádné takty navíc.

L6 verze obsahuje navíc přidavnou pamět 64KB, do které má přístup jen Blitter. Lze do ní pomocí Blitteru nakopírovat libovolná data. Ty potom můžeme vykreslovat do ZX Videoram o něco rychleji, než přenos z ZX paměti. Čtení i zápis v ní trvá 1 takt. Může v ní být uložená grafika našeho projektu, ty potom nebudou zabírat pamět DRAM ZX Spectra.

Zápis do paměti může být nastaven v několika režimech:

Režim Popis Takty na 1 Bajt
CopyZkopíruje data z SRC do DST. 3-6
And Provede instrukci AND mezi SRC a DST, uloží do DST. 3-6
Or Provede instrukci OR mezi SRC a DST, uloží do DST. 3-6
Xor Provede instrukci XOR mezi SRC a DST, uloží do DST. 3-6
Fill Vyplní oblast DST zvoleným Bajtem. 1-3
Collision Detekce kolize. Data ze SRC se sloučí pomocí AND s daty z DST. Pokud výsledek kdekoliv nebude 0, je detekována kolize. V testování dalších bajtů se v takovém případě již nepokračuje. 6
Mask Speciální režim, kdy výsledek v DST je v závislosti na vzorci: DST=(DST and SRC.MASKA) or SRC.DATA. Data pro Masku musí být součástí SRC dat. 6-9
Mask2 Speciální režim, podle vzorce DST=DST or (SRC.DATA and MOFS(hodnota registru)). 3

Ve sloupci Takty je v závorce napsáno kolik může přenos 1 bajtu do Videoram ZX Spectra trvat. To souvisí totiž s další funkcí. Blitter obsahuje vlastní kopii Videoram, cache, ve své mnohem rychlejší interní paměti. Sleduje sběrnici a při každém zápisu do Videoram, zapisuje i do své interní kopie. U režimu Copy například ověřuje, zda se nebude zapisovat do Videoram bajt se stejnou hodnotou který tam již je. Pokud ano, nezapisuje blitter do Videoram nic a ušetří 3 takty. U Fill režimu se může stát, že bude zpracování trvat jen jeden takt. A proto také režim And/Or/Xor netrvá 9 taktů, ale max 6, nebo dokonce jen 3.

Ovládání

OUT Port

K ovládání jsem použil jinou, rychlejší metodu než obvyklou pomocí instrukce OUT. Nechal jsem se inspirovat počítačem Amiga. Jeden OUT port je také potřeba, ale jen pro aktivování, Reset, případně nastavení alternativní adresy Videoram či Registrů. Zvolil jsem port 231.

Port 231
bit Popis
0 LnxBlitter enable
1 Následující OUT bude adresa Registrů, nižší bajt
2 Následující OUT bude adresa Registrů, vyšší bajt
3 Následující OUT bude adresa Videoram, vyšší bajt
4-6 Reserved
7 Reset hodnot

IN Port

Při čtení portu 231 se vrátí verze LnxBlitteru. 9.4.2019 to byla verze L6, tedy in vrátí 6.

Registry

LnxBlitter se ovládá 12 registry, a 1 registrem „Flag“. Všechny registry se nacházejí v paměti, defaultně na adrese 23296. Zápis do nich se provádí klasickým zápisem, jako kamkoliv jinam do paměti. Postačí k tomu instrukce LD a jí podobné.

První číslo v tabulce je offset registru (například registry na adrese 23296, tedy 23296+13 = registr RUN).

0 CTRL (Control)
bit Jméno Popis
0 S_SPRITE Režim SRC, 0=Blok, 1=Sprite
1 D_SPRITE Režim DST, 0=Blok, 1=Sprite
2 REVERSE Zapnutí režimu pozpátku. Mění se i směr bitového posuvu.
3 REST V případě bitového posuvu se bude zapisovat poslední bajt se zbytkem z posuvu.
4 S_SubV Pokud je SRC kanál v režimu Sprite, tento bit posouvá souřadníci Y o 256 linek nahoru. Tedy: Y=SRC.Y-256
5 D_SubV Pokud je DST kanál v režimu Sprite, tento bit posouvá souřadníci Y o 256 linek nahoru. Tedy: Y=SRC.Y-256
6 S_IntRAM Každé čtení bude prováděno do interní rozšířené paměti. Vše bude trvat max. 1 takt.
7 D_IntRAM Každý zápis bude prováděn do interní rozšířené paměti. Vše bude trvat max. 1 takt.
1 FCLR (Fill Color)
Barva, kterou se bude vyplnovat při povolení FillColor.
2 BDRW (Border Width)
bit Popis
0-3 Rozšíření okraje zprava (0-15)
4-7 Rozšíření okraje zleva (0-15)
3 BDRH (Border Height)
bit Popis
0-3 Rozšíření okraje odspoda (0-15)
4-7 Rozšíření okraje odshora (0-15)
4 SMOD (Modulo SCR)
Pokud je SRC v režimu Blok, Modulo určuje kolik bajtů se přeskočí po překopírování jedné linky (WDT). (0-255)
5 DMOD (Modulo DST)
Pokud je DSTv režimu Blok, Modulo určuje kolik bajtů se přeskočí po překopírování jedné linky (WDT). (0-255)
6 WDT (Width)
Režim Blok v SRC Šířka přenášených dat (0-65535). Aby k přenosu dat o délce WDT došlo, v HGT musí být 1. Také záleží na nastavení Modulo.
Režim Sprite v DST a Blok v SRC Šířka přenášených dat (0-255) v registru 6. Pokud je aktivní CopyCLR, v registru 7 je vertikální offset pro přenos barev (počet linek, případně attributů v lince).
8 HGT (Height)
Výška přenášených dat (0-255)
9 SRC (Source)
Zdroj dat. V režimu Blok je to přímá adresa do paměti. V režimu Sprite jsou to souřadnice do Videoram, 9=X, 10=Y.
11 DST (Destination)
Cíl dat. V režimu Blok je to přímá adresa do paměti. V režimu Sprite jsou to souřadnice do Videoram, 11=X, 12=Y.
13 RUN (RUN)
Zápis spustí úlohu
bit Jméno Popis
0-2 SHIFT Udává o kolik bitů (0-7) se posunou data vpravo, nebo pokud je REVERSE 1, vlevo.
3 FillCLR Zapne vyplnování barvou. Má přednost před CopyCLR.
4 CopyCLR Zapne kopírování barev z SRC. Data barev by se měly nacházet za bitovými daty. Takže pokud sprite má velikost 32×32 pixlů, bude WDT 4 (bajty), HGT 32 (linek). 4*32=128, takže barevná data by měla začínat na adrese SRC+128. SHIFT by měl být 0, a souřadnice Y na adresách attributů (Y = Y & 248). K WDT se připočítává i Modulo.
5-7 FMODE Režim zápisu. (Copy, And, Or, Xor, Fill, Collision, Mask, Mask2)
14 MOFS (Mask Offset)
Pokud je aktivní režim MASK, MOFS určuje kde má hledat maskovací data. Číslo udává o kolik linek níže data jsou.
Pokud je aktivní režim MASK2, MOFS určuje jakým číslem má maskovat data.
15 FLAG (FLAG)
Tendo registr je určen ke čtení. Pokud provedeme režim Collision, vrací 1 pokud došlo ke kolizi. Jinak 0.

Verze

Vývoj ještě neskončil, jistě tam odhalím spousta chyb, nebo funkce přidám. Další a další se nabízí. Při vývoji jsem vytvářel postupně několik verzí. Vše samozřejmě jen jako virtualní hardware.

L1Základní kopírování dat
L2Border omezení okrajů
L3Podpora barev
L4Maskování objektů
L5Interní Cache videoram. Urychluje čtení dat z Videoram. Z důvodu kompatibility přenos trvá nejméně 1 takt. Takže pokud nedojde k jinému delšímu čtení / zápisu, je min. 1 takt.
L6Přidaná interní pamět přístupná pouze pro Blitter. Rozšiřuje pamět speciálně pro grafické data. Velikost je 64KB, a je rychlá. Běžné operace trvají 1 takt.

Interní Cache a rozšířená pamět (L6)

Díky Cache obrazovky ZX Spectra dokáže Blitter z ní číst mnohem rychleji, než kdyby četl z DRAM ZX Spectra. Tato cache se obnovuje pokaždé, kdy se Z80 pokusí o zápis do videoram. Navíc pokud Blitter přenáší data do DRAM v ZX Spectru, nejprve si ověří v cache, že nebude přenášet bajt s hodnotou, která ve videoram již je. V takovém případě ušetří 3 takty.

Blitter ještě k tomu obsahuje přídavnou pamět 64 kB, ta je adresovatelná pouze Blitterem. Z80 do ní nemůže nijak zasahovat. Blitter naopak má mnohem rychlejší pamět pro svoje přesuny. Navíc díky tomu může být software pro ZX mnohem větší, pamět mu nebudou zabírat grafická data. Ty totiž můžou být v paměti Blitteru.

V takovém režimu by Z80 jen diktoval blitteru, co, jak a kam vykreslovat. Nejvíce taktů by zabralo kopírování dat do ZX Spectrum Videoram, a to by trvalo max. 20736 taktů. A to ještě jen v případě kopírování celé obrazovky i s barvama. Díky interní kopii obrazovky však této hodnoty dosáhneme jedině v případě, že každy bajt bude unikátní hodnoty. Je tedy zcela jisté, že obrazovka v ZX DRAM bude obnovena datově mnohem dříve, než paprsek TV dostihne adresu kopírování, a to včetně barevné složky. Interní paměť se dá bez problémů využít jako videobuffer. Navíc pokud by se kopírovala jen část, sníží se o další takty. Není problém během jednoho snímku smazat celou obrazovku, vykreslit sprity, a následně aktualizovat videoram v ZX DRAM.

Stále ale platí, že by se dalo vytvořit jako externí interface, bez jakéhokoliv zásahu do ZX Spectra. Grafický výkon by byl na ZX Spectrum neskutečný :) Možná dokonce by byl ve skutečném FPGA ještě rychlejší, než jak jsem ho naemuloval já. Nevím totiž kolik by za jeden Z80 takt bylo FPGA schopno zpracovat bajtů ve své interní videoram. Berme tedy, že moje virtuální verze je ta nejpomalejší, a i to nejrychlejší zpracování jednoho bajtu do Videoram sebere alespoň 1 takt. Pravděpodobně by jich zvládl udělat i 100 za 1 takt, ale to už je u ZX Spectra moc moc velký výkon :)

Příklad použití v ASM

Malý příklad použití v ASM je ke stažení zde. Použít lze jen v emulátoru LnxSpectrum, jinde fungovat nemůže. Přenáší se v něm pomocí LnxBlitteru logo o velikosti 200×56 px na obrazovku.

lnxspectrum/blitter.txt · Poslední úprava: 2019/12/08 12:40 autor: lanex

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki