Dopo aver parlato di scroll e overscan, veniamo adesso a quello che da molti viene considerato il pezzo forte dell’Amiga, che è stato capace di regalare immense gioie grazie a giochi come Shadow of the Beast e i suoi 13 livelli di parallasse: la cosiddetta modalità Dual Playfield, che consiste nella possibilità di visualizzare due schermi (chiamati playfield, per l’appunto) completamente indipendenti anche in termini di scroll, ma col limite di massimo 8 colori ciascuno (a seconda di quanti bitplane vengano utilizzati in totale: fino a un massimo 3 per singolo schermo).
Il controllore video – bitplane – Modalità Dual Playfield
Il trucco consiste nell’avere uno schermo frontale (il secondo playfield) in cui l’utilizzo del colore di indice zero consente di “bucare” la sua grafica e di visualizzare, invece, quella dello schermo che sta dietro (il primo playfield).
La grafica dei due schermi risulta distribuita fra i vari bitplane: quelli dispari (1, 3, 5) fanno capo al playfield #1, mentre quelli pari (2, 4, 6) appartengono al playfield #2. L’AGA mette a disposizione due bitplane in più (8 in totale), per cui i playfield possono avere fino a 16 colori (4 bitplane ciascuno), garantendo una qualità cromatica nettamente superiore rispetto a OCS/ECS (8 colori per schermo sono abbastanza miseri, e bisogna fare i salti mortali per ottenere una grafica appetibile).
Poiché abbiamo due schermi indipendenti, serviranno anche due registri separati per aggiornare i puntatori dei bitplane alla fine della visualizzazione di ogni riga (come precedentemente descritto): a BPL1MOD
si aggiunge BPL2MOD
, rispettivamente per i bitplane dispari e pari.
Similmente, servirà un altro registro per poter specificare il valore dello scroll (ritardo) per il secondo schermo. Poiché servono soltanto 4 bit, lo stesso registro BPLCON1
ha sufficiente spazio allo scopo. AGA aggiunge altri bit (e anche qualche altro registro) per consentire uno scroll più fine in modalità alta e super-alta risoluzione.
Con questi registri e modifiche l’Amiga è, quindi, in grado di visualizzare grafica completamente diversa in due schermi separati che si muovono (scroll verticale e orizzontale) in maniera totalmente indipendente l’un l’altro.
l controllore video – packed – Modalità Dual Playfield
Lo stesso si può fare tranquillamente anche con la grafica packed (che, anzi, risulta più versatile), contrariamente a quanto si legge in giro tante volte. Infatti l’errore che spesso viene commesso è quello di assumere che avere due schermi indipendenti e scrollabili liberamente sia possibile esclusivamente grazie (e necessariamente) ai bitplane. Nulla di più falso, ovviamente, in quanto l’uso dei bitplane per implementare questa modalità è semplicemente necessario con l’Amiga perché è il suo chipset funziona così! Ma ciò non implica che debba per forza di cose essere così anche in altri sistemi, in particolare in uno con la grafica packed.
Passiamo adesso all’implementazione della stessa, identica, modalità, ma usando appunto grafica packed. Abbiamo visto che il controllore video in questo caso ha bisogno di un solo puntatore (BPL1PT
) ai dati dello schermo, qualunque sia la profondità di colore usata (ricordo: da 1 a 6 bit con OCS/ECS e fino a 8 con AGA), con annessi buffer, byte interno (entrambi equivalenti al singolo registro BPL1DAT
con la grafica planare) e coda FIFO (di 2 byte. Possiamo assumere che siano equivalenti a un altro registro dati a 16 bit).
Niente di più semplice e naturale che duplicare questi registri per il secondo schermo. Dunque si aggiungerà il nuovo puntatore BPL2PT
(sempre diviso in due registri a 16 bit: BPL2PTH
e BPL2PTH
) che consentirà di leggere i dati del secondo schermo, mentre ci sarà un nuovo buffer e byte interno (equivalenti a BPL2DAT
) e un’altra coda FIFO coi suoi 2 byte. Oltre a ciò e come già spiegato per il caso del singolo schermo, serviranno nuovi registri interni a 4 bit per contare il numero di bit rimasti nel buffer, quelli rimasti nel byte interno, e i due che implementano i “puntatori” di testa e coda per la coda FIFO. Infine, serviranno i due barrel shifter a 8 bit con scorrimento fino a 7 posizioni per il nuovo buffer e byte interno, rispettivamente.
Tutto il resto rimane così com’è, quindi con BPL2MOD
che qui sarà usato per aggiornare il puntatore al secondo schermo alla fine della visualizzazione di ogni riga di raster, e il registro BPLCON1
per memorizzare il valore di scroll dei due registri (senza dimenticare che, però, serve adesso un registro in più a 4 bit per il secondo schermo, per conservarne la copia da usare quando si abilita lo scroll, come già visto in precedenza nel caso del singolo/unico schermo).
Il funzionamento del controllore video rimane sostanzialmente inalterato, ma in questo caso dovrà elaborare i dati provenienti dai due schermi. L’unica attenzione nonché cambiamento necessario è dovuto al quando far iniziare la lettura di tali dati, considerato che adesso abbiamo due set di buffer, byte interni, e code FIFO, in modo tale che abbia sempre i dati a disposizione quando servono. Se con un solo schermo si iniziava con lo slot $3F normalmente e $3E in presenza di scroll, giocoforza col dual playfield sarà necessario far partire il tutto dallo slot $3E normalmente e $3C se entrambi gli schermi hanno lo scroll abilitato ($3D se è abilitato soltanto per uno di essi).
Se qualcuno dovesse avere ancora dubbi potrebbe prendere la tabella che ho fornito in precedenza come esempio nonché simulazione del funzionamento del controllore video e gli basterebbe semplicemente duplicare le colonne relative a buffer, byte interno e coda FIFO, con altrettante ma per il secondo schermo e provare la simulazione (magari con altri dati / letterali per far risaltare il lavoro fatto dal controllore coi due diversi schermi) per vedere come l’elaborazione dei due pixel avvenga in parallelo e in maniera completamente indipendente.
Il controllore video – Costi di implementazione: planare vs packed
Dopo tanto parlare mi sembra anche giusto concludere l’argomento controllore video (che rimane comunque il componente più importante/critico dell’Amiga, assieme al Blitter) tirando le somme e facendo i conti (approssimativi, come già ribadito, ma a mio avviso abbastanza realistici) sui costi implementativi di entrambe le soluzioni con un parallelo (fianco a fianco) fra i due.
- Per i puntatori alla grafica servono 6 registri (
BPLxPT
) a 32 bit, che si traducono in 6 x 32 = 192 celle SRAM (implementate con 6 transistor per cella) per Amiga OCS/ECS, mentre 8 x 32 = 256 per l’AGA. Ne servono soltanto 2 (a prescindere da OCS/ECS/AGA) alla versione packed, quindi 2 x 32 = 64 celle SRAM. Il vantaggio della versione packed è netto. - Per contenere i dati letti servono 6 registri (
BPLxDAT
) da 16 bit più altri 6 registri interni sempre da 16 bit, quindi 2 x 6 x 16 = 192 celle SRAM per OCS/ECS, mentre 2 x 8 x 64 = 1024 per AGA (perché legge dati fino a 64 bit alla volta). Per la versione packed servono invece 8 bit per il buffer, altri 8 per il byte interno, altri 2 per la coda FIFO, 4 bit per il contatore del buffer, altrettanti per il contatore del byte interno e una coppia per i “puntatore” di testa e coda della coda FIFO, il tutto moltiplicato per due (per i due schermi), quindi 2 x (8 + 8 + 2 x 8+ 4 + 4 + 2 x 4) = 92 celle SRAM; un’eventuale versione AGA avrebbe soltanto la coda FIFO che utilizzerebbe 14 byte anziché 2, quindi 2 x (8 + 8 + 14 x 8 + 4 + 4 + 2 x 4) = 288 celle SRAM. Anche qui il vantaggio della versione packed è indiscutibile. - Per costruire l’indice del colore serve logica per estrarre i bit dai dati letti dai bitplane e assemblarli, eliminando quelli dei bitplane inutilizzati. La versione packed ha l’indice colore immediatamente disponibile nei bit più significativi del buffer, ma ha comunque bisogno di estrarli e forzare a zero i bit inutilizzati. Il costo dovrebbe essere simile.
- A ogni pixel visualizzato serve eseguire uno shift a 16 bit da singolo spostamento nei registri dati interni per scartarlo e passare al pixel successivo, il che si traduce in 6 x barrel shifter a 16 bit da singolo spostamento per OCS/ECS, mentre per AGA ne serviranno 8 da 64 bit. La versione packed ha bisogno, invece, di 2 barrel shifter da 8 bit fino a 7 spostamenti, il tutto duplicato per i due schermi; un’eventuale versione AGA ha bisogno soltanto di un bypass (non usa i barrel shifter) quando lo schermo usa 256 colori (i pixel usano 8 bit = 1 byte). Il costo è uguale per le versioni OCS/ECS ma nettamente in vantaggio per il packed con l’AGA.
- Per la gestione del buffer, del byte interno e della coda FIFO servono 5 sommatori a 4 bit, ognuno dei quali richiede 36 transistor per l’implementazione, equivalente a 6 celle SRAM. Dunque servirebbe l’equivalente di 5 x 6 = 30 celle SRAM per ogni schermo, per un totale di 60 celle SRAM. Qui il vantaggio dell’Amiga è netto (visto che non richiede niente del genere).
- Per l’implementazione dello scroll servono due registri interni (uno per ogni schermo) a 4 bit in cui copiare i valori dello scroll a ogni riga di raster. Servono anche due sommatori a 4 bit per ogni singolo schermo per controllare tale registro e aggiornarlo. Quindi l’equivalente di 2 x 2 x 6 = 24 celle SRAM, più 2 x 4 = 8 celle SRAM per i due registri interni, per un totale di 32 celle SRAM. In realtà il registro che contiene i due valori scroll ha 8 bit liberi (ne sono usati soltanto 8), quindi si potrebbero utilizzare questi anziché usare due registri interni, ma non importa: il costo è risibile e può essere aggiunto tranquillamente. Anche qui il vantaggio dell’Amiga è netto.
- L’Amiga usa una complessa logica per stabilire la priorità e il funzionamento di tutti i bitplane, la cui implementazione non è quantificabile in termini di costi. La versione packed ha bisogno di una logica molto più semplice (on-demand: se una delle due code FIFO ha posto per 2 due byte, fa partire la lettura dei dati), ma deve implementare la gestione delle code, ma nulla di quantificabile al momento. Si tratta di poche risorse in entrambi i casi, ma a mio avviso l’Amiga dovrebbe avere un leggero vantaggio.
- Ogni volta che si legge un dato è necessario incrementare di 2 (8 per AGA quando legge dati a 64 bit) un puntatore e lo stesso bisogna fare a fine riga (usando il registro di modulo) per puntare correttamente a quella successiva. Qui valgono le considerazioni già fatte: se è possibile riutilizzare il sommatore (a 18 o 20 bit), allora ne serve soltanto uno e i costi fra Amiga e versione packed sono identici. Se, invece, servono sommatori separati per ogni bitplane, allora quella packed ne esce nettamente in vantaggio (se ne servono soltanto 2 anziché 6 o 8).
Adesso possiamo finalmente stilare un bilancio complessivo (ma grezzo!), considerando soltanto le celle SRAM utilizzate o “equivalenti” per i sommatori (che sono gli elementi che incidono di più, perché richiedono parecchi transistor per la loro implementazione. Lo sono anche i barrel shifter, ma si equivalgono e quindi sono lasciati fuori dai calcoli / considerazioni), il quale ci dice che l’Amiga necessita di 192 + 192 = 384 celle SRAM per OCS/ECS, e infine 256 + 1024 = 1280 per AGA. La versione packed necessita, invece, di 64 + 92 + 60 + 32 = 248 celle SRAM per OCS/ECS e 64 + 288 + 60 + 32 = 444 per AGA.
Direi che i numeri si commentino da soli, pur tenendo conto della complessità richiesta dall’implementazione della versione packed. Complessità che, però, è dovuta al fatto che l’implementazione packed ha quasi completamente disaccoppiato la lettura dei dati dalla dimensione del bus dati, oltre che dalla profondità di colore (numero di bit utilizzati per rappresentare gli indici dei colori), mentre l’implementazione planare dell’Amiga ha scaricato questa complessità su future (nonché onerose) richieste di risorse e sul numero di bitplane a disposizione (e quindi duplicazione di risorse), rispettivamente.
Con ciò è tutto per quanto riguarda il controllore video. Il prossimo articolo parlerà degli sprite (sebbene sia legato al precedente, per ovvie ragioni).