Assembly Avanzato con MASM
Capitolo 11: La memoria video in modalità grafica VESA
Nel 1987, mentre la IBM studiava le possibili evoluzioni dell'adattatore
VGA, una azienda di nome NEC Home Electronics suscitò grande clamore mettendo
in commercio una potente scheda video per PC capace di supportare una risoluzione
grafica da 800x600 pixel a 256 colori; per sottolineare il notevole balzo in
avanti fatto rispetto al modo VGA, questa nuova modalità video venne denominata
Super VGA o SVGA.
La IBM cercò di replicare a questa mossa imprevista e realizzò l'adattatore
8514/A capace di supportare risoluzioni grafiche sino a 1024x768 pixel a
256 colori; forse però a causa della quasi totale assenza di adeguata documentazione
sulle specifiche hardware, questo nuovo adattatore ottenne uno scarso successo.
Stessa sorte toccò nel 1990 ad un ancora più potente adattatore denominato
eXtended Graphics Array o XGA; questo adattatore era capace di supportare
risoluzioni grafiche da 1024x768 pixel a 256 colori e da 640x480 pixel
a ben 65536 colori!
Nel frattempo, l'iniziativa della NEC era stata seguita rapidamente da diversi altri
produttori di hardware i quali misero in commercio schede video di classe SVGA con
caratteristiche sempre più evolute; la fine del dominio IBM nel settore degli
adattatori grafici era ormai iniziata in modo irreversibile!
Analizzando ciò che è diventato oggi il mondo delle schede video, possiamo affermare che la
fine del dominio IBM ha avuto enormi conseguenze positive in quanto i produttori di
hardware si sono potuti svincolare da standard spesso troppo restrittivi; in questo modo è
stato possibile dare libero sfogo alla creatività dei progettisti determinando così una
evoluzione vertiginosa del settore della grafica computerizzata.
In questa fase di evoluzione, una tappa fondamentale è stata la nascita dell'azienda
3Dfx, fondata nel 1994 da vari colossi della computer grafica come Digital
Equipment Corporation, Silicon Graphics, MIPS Computer Systems e
Pellucid; l'obiettivo era quello di portare anche nel mondo dei PC il concetto
di accelerazione grafica, sino ad allora riservato solo ad ambienti professionali.
Per raggiungere tale obiettivo la 3Dfx mise in commercio schede video dotate di una
novità rivoluzionaria rappresentata dalla GPU o Graphics Processing Unit; la
GPU determina un enorme aumento delle prestazioni generali del sistema in quanto si
fa carico di tutto il pesantissimo lavoro di elaborazione grafica che altrimenti andrebbe a
gravare sulla CPU.
L'effetto negativo legato alla fine del dominio IBM è stato sicuramente il caos che si
è venuto a creare in relazione alle specifiche hardware delle nuove schede video; in
particolare, i vari produttori hanno abbandonato ogni convenzione in relazione alla codifica
delle modalità video e degli indirizzi hardware dei registri.
Questa situazione ha avuto pesanti ripercussioni sui programmatori i quali si sono trovati
costretti a destreggiarsi tra una miriade di codici e indirizzi che differivano da una scheda
video all'altra; a titolo di esempio, la Figura 11.1 illustra i differenti codici utilizzati
dai vari produttori di schede video per indicare la modalità 1024x768 a 16 colori.
Da un lato, non avrebbe avuto senso imporre delle convenzioni univoche su aspetti legati
all'hardware in quanto così facendo si sarebbe tornati indietro ai tempi del dominio
IBM; d'altra parte, bisognava necessariamente trovare una qualche soluzione per
venire incontro alle esigenze dei programmatori, senza limitare in alcun modo la creatività
dei progettisti.
Fortunatamente, gli stessi produttori di schede video si resero conto della situazione e si
riunirono per dare vita ad un consorzio denominato Video Electronics Standards
Association o VESA; lo scopo che si prefiggeva tale consorzio era proprio quello
di mettere a disposizione degli sviluppatori una interfaccia di programmazione standard
capace di semplificare al massimo l'accesso a tutte le caratteristiche di qualsiasi scheda
video dotata di supporto VESA.
11.1 Le specifiche VESA VGA BIOS Extension
Una delle attività più importanti svolte dal comitato VESA è la definizione e
l'aggiornamento continuo delle specifiche VGA BIOS Extension o VBE; scopo di
tali specifiche è quello di estendere i servizi video forniti dal BIOS attraverso la
INT 10h in modo da supportare tutte le modalità SVGA disponibili con le
schede video aderenti allo standard VESA. Nel seguito del capitolo ci occuperemo delle
specifiche VBE versione 3.0 pubblicate nel 1998 e destinate alla modalità
reale.
Una scheda video VESA compatibile supporta quindi tutti i servizi standard imposti a
suo tempo dalla IBM e, in più, una ulteriore serie di servizi definiti dalle specifiche
VBE; il programmatore accede a tutti questi servizi attraverso la normalissima procedura
di chiamata della INT 10h.
I vecchi programmi grafici possono continuare a girare senza modifiche richiedendo i normali
servizi standard IBM e ignorando completamente le specifiche VBE; i nuovi
programmi grafici possono accedere a tutti i servizi VBE abbandonando del tutto i
servizi standard IBM.
Le specifiche VBE includono anche i due vecchi servizi 00h (Set Video Mode) e
0Fh (Read Current Video State); in ogni caso, per i nuovi programmi che vogliono
avvalersi delle specifiche VBE è raccomandato l'uso dei servizi alternativi 02h
(Set Super VGA Video Mode) e 03h (Read Current Super VGA Video State).
Per distinguere i servizi VBE da quelli ordinari, viene utilizzato il valore 4Fh
che deve essere caricato in AH; la chiamata di un servizio VBE assume quindi il
seguente aspetto generale:
Tutte le informazioni di stato (VBE Return Status) relative al servizio richiesto con
il codice precedente vengono restituite in AL e AH; il contenuto di tali registri
assume il seguente significato espresso con gli operatori booleani del linguaggio C:
- AL == 4Fh il servizio richiesto è supportato
- AL != 4Fh il servizio richiesto non è supportato
- AH == 00h il servizio richiesto è stato eseguito correttamente
- AH == 01h il servizio richiesto non è stato eseguito correttamente
- AH == 02h il servizio richiesto non è supportato nella configurazione
hardware corrente
- AH == 03h il servizio richiesto non è supportato nella modalità video
corrente
Le specifiche VBE raccomandano che un qualunque valore diverso da zero in AH venga
trattato dal programmatore come una condizione generale di errore; è anche importante testare
il valore restituito in AL in quanto determinati servizi potrebbero essere disponibili
solo con le versioni più recenti delle specifiche VBE.
Per convenzione, tutte le modalità video VESA devono essere rappresentate da un codice a
16 bit il cui bit di posto 8 deve valere 1; ne consegue che tali codici
partono dal valore minimo 0100h.
La modalità video è rappresentata quindi dai primi 9 bit del codice a 16 bit;
i restanti 7 bit vengono utilizzati per abilitare o disabilitare determinate funzionalità.
I bit nelle posizioni 9 e 10 sono riservati e devono valere 0.
Il bit in posizione 11 serve per selezionare la modalità di controllo della frequenza di
scansione verticale del monitor; se questo bit vale 0 si abilita la modalità predefinita
controllata dal BIOS, mentre se questo bit vale 1 si lascia al programmatore il
compito di effettuare le necessarie impostazioni.
I bit nelle posizioni 12 e 13 sono riservati e devono valere 0.
Il bit in posizione 14 serve per abilitare o disabilitare l'uso del frame buffer lineare
per l'accesso alla VRAM; se questo bit vale 0 viene usato un normale frame buffer
che permette di vedere la VRAM suddivisa in una serie di blocchi di dimensione
predefinita (segmentazione della modalità reale), mentre se questo bit vale 1 viene
usato un frame buffer lineare che permette di vedere la VRAM come un unico blocco
(modalità protetta).
Il bit in posizione 15 serve per abilitare o disabilitare la pulizia della VRAM
quando viene attivata una nuova modalità video VESA; se questo bit vale 0 il
vecchio contenuto della VRAM viene cancellato, mentre se questo bit vale 1 il
vecchio contenuto della VRAM viene preservato.
La Figura 11.2 illustra l'elenco delle principali modalità video grafiche ufficiali aggiornate
allo standard VESA versione 3.0; la risoluzione è espressa in pixel.
La Figura 11.3 illustra l'elenco delle principali modalità video testo ufficiali aggiornate
allo standard VESA versione 3.0; la risoluzione è espressa in celle.
11.2 Accesso alla VRAM in modalità reale attraverso i servizi VBE
In modalità reale, l'accesso alla VRAM deve avvenire necessariamente in modo segmentato;
come sappiamo, ciò è dovuto al fatto che in tale modalità la CPU vede qualunque tipo di
memoria suddivisa in tanti blocchi (segmenti) ciascuno dei quali non può superare la dimensione
di 65536 byte (in quanto i registri puntatori a 16 bit permettono di esprimere
un offset compreso tra 0 e 65535).
Per venire incontro a questa situazione, le specifiche VBE implementano l'accesso alla
VRAM in modalità reale attraverso una tecnica del tutto simile a quella illustrata nel
capitolo dedicato allo standard EMS; la Figura 11.4 illustra tutti i dettagli.
Osserviamo subito che la VRAM viene suddivisa in tanti blocchi consecutivi e contigui
denominati memory banks (banchi di memoria), indicizzati a partire da 0; la
dimensione fissa di ogni banco rappresenta la granularità della VRAM.
Il valore più usato per la granularità è pari a 64 KiB, ma non è raro trovare schede
video con granularità 8 KiB, 16 KiB o 32 KiB; nell'esempio di Figura
11.4 la granularità è pari a 16 KiB.
Per l'accesso ai vari banchi di memoria il programmatore ha a disposizione due apposite
finestre (in genere da 64 KiB ciascuna) denominate Window A e Window B,
nelle quali possiamo mappare qualunque area della VRAM; la presenza di due finestre
(anziché del singolo frame buffer dello standard EMS) permette di ottimizzare al
massimo le operazioni di I/O con la VRAM grazie al fatto che si può usare, ad
esempio, la Window A per la lettura dei dati e la Window B per la scrittura
dei dati.
Questo però è un caso ideale in quanto la maggior parte delle schede video supporta una
singola finestra da utilizzare quindi, sia per la lettura, sia per la scrittura dei dati;
ovviamente, è compito dei programmi individuare l'esatta configurazione disponibile
(granularità della VRAM, numero di finestre di I/O, dimensione delle finestre,
etc).
Come è stato già spiegato, ogni finestra di I/O può essere usata per mappare a
piacere qualunque area della VRAM; in Figura 11.4, ad esempio, vediamo che la
Window A (da 64 KiB) sta mappando la VRAM a partire dal banco 2
in modo da permettere la lettura diretta dei dati dai banchi 2, 3, 4, 5, mentre la
Window B (da 64 KiB) sta mappando la VRAM a partire dal banco 9
in modo da permettere la scrittura diretta dei dati nei banchi 9, 10, 11, 12.
11.3 Servizi VBE 3.0
Analizziamo ora i principali servizi messi a disposizione dalle specifiche VBE versione
3.0; come è stato già anticipato, prenderemo in considerazione solamente i servizi
destinati alla modalità reale.
11.3.1 Servizio n. 4F00h: Return VBE Controller Information
Questo servizio restituisce una numerosa serie di informazioni relative alla versione
VBE supportata dal Video BIOS (VBIOS) e alle caratteristiche hardware
dell'adattatore video.
Un programma che intende accedere correttamente ai servizi VBE supportati dal
BIOS della scheda video, deve prima raccogliere una serie completa di informazioni
relative alle capacità hardware dell'adattatore; a tale proposito, è disponibile proprio
il servizio 4F00h.
Questo servizio richiede che la coppia ES:DI stia puntando ad un blocco di memoria
appositamente allocato dal programmatore; tale blocco viene riempito dal servizio
4F00h con una numerosa serie di informazioni che, necessariamente, possono variare
a seconda della versione VBE supportata dal VBIOS.
Tutte le informazioni vengono restituite dal servizio 4F00h in una struttura che
prende il nome di VbeInfoBlock; tale struttura assume le caratteristiche illustrate
in Figura 11.5.
Il membro VbeSignature viene riempito dal servizio 4F00h con la stringa
"VESA"; lo stesso membro può essere usato dal programmatore per richiedere
esplicitamente informazioni avanzate disponibili solo a partire dalla versione 2.0
delle specifiche VBE.
Se questo membro non viene inizializzato dal programmatore con l'apposita stringa
"VBE2", il servizio 4F00h riempie solo i primi 256 byte della struttura
VbeInfoBlock (come previsto dalla versione 1.0 delle specifiche VBE);
se questo membro viene inizializzato dal programmatore con l'apposita stringa "VBE2",
il servizio 4F00h riempie tutti i 512 byte della struttura VbeInfoBlock
(come previsto dalla versione 2.0 o superiore delle specifiche VBE).
Il membro VbeVersion indica la versione VBE, in formato BCD,
implementata nel VBIOS; ad esempio, il valore 0102h indica la versione
1.2, dove 1 è il major number, mentre 2 è il minor number.
Il membro OemStringPtr è un puntatore FAR ad una stringa C contenente
informazioni relative all'Original Equipment Manufacturer o OEM (fabbricante
dell'hardware); questa stringa ha una lunghezza massima raccomandata di 256 byte e
può trovarsi memorizzata nella RAM o nella ROM della scheda video (a partire
dalle specifiche VBE 3.0 la stringa si trova nel membro OemData della struttura
VbeInfoBlock).
Il membro Capabilities fornisce informazioni su particolari caratteristiche grafiche
supportate dall'adattatore video; si tratta di un valore a 32 bit che assume la
struttura illustrata in Figura 11.6.
Il bit 0 indica la struttura del DAC per la rappresentazione dei colori primari
RGB; la sigla DAC sta per Digital to Analog Converter ed indica il
dispositivo hardware che converte una terna RGB (digitale) in un segnale analogico da
inviare al monitor.
Se il bit 0 vale 0, il DAC usa 6 bit per ogni colore primario;
se il bit 0 vale 1, il DAC può essere programmato per usare 8
(o più) bit per ogni colore primario.
Il bit 1 indica la compatibilità VGA dell'adattatore video; controllando tale
bit il programmatore può sapere se, anche quando si opera in modalità VBE, possono
essere utilizzate le funzionalità tipiche degli adattatori VGA (indirizzi delle porte
hardware, tavolozze dei colori, etc).
Se il bit 1 vale 0, l'adattatore è VGA compatibile; se il bit 1
vale 1, l'adattatore non è VGA compatibile (cioè, supporta solo le
funzionalità standard VBE, ma non quelle VGA).
Il bit 2 indica la modalità operativa del DAC; se si eccettua il caso delle
vecchie schede video, normalmente tale bit viene posto a 0 per indicare la modalità
operativa predefinita.
Le vecchie schede video, per evitare il fastidioso fenomeno dello sfarfallio, richiedevano
che la programmazione del DAC avvenisse in modo sincrono con il refresh verticale;
per queste vecchie schede video, il bit 2 deve essere posto a 1.
Il bit 3 indica se l'adattatore video supporta via hardware l'effetto "stereoscopico";
si tratta di una tecnica che consiste nel ricorso ad un particolare sistema di suddivisione
e visualizzazione delle immagini in modo da creare un effetto stereoscopico tridimensionale.
Se il bit 3 vale 0, l'adattatore non supporta l'effetto stereoscopico;
se il bit 3 vale 1, l'adattatore possiede l'hardware necessario per il supporto
dell'effetto stereoscopico.
Se il servizio 4F00h pone a 1 il bit 3, allora il bit 4 indica se
il segnale di sincronizzazione stereoscopica arriva attraverso un apposito connettore
denominato EVC; se il bit 4 vale 1, è presente un connettore EVC,
mentre in caso contrario è presente un generico connettore VESA.
Tornando alla struttura VbeInfoBlock di Figura 11.5, il membro VideoModePtr
contiene un puntatore FAR ad una lista di modalità video VESA supportate
dall'adattatore; tali modalità sono indicate dai valori a 16 bit di Figura 11.2 e
Figura 11.3, mentre la fine della lista è individuata dal valore FFFFh.
Il membro TotalMemory indica la quantità totale di VRAM (espressa in numero di
blocchi da 64 KiB ciascuno) fisicamente disponibile e indirizzabile attraverso il
frame buffer; si tenga presente che, a seconda della modalità video selezionata, potrebbe
risultare disponibile tutta o solo un parte della VRAM totale.
Quando si utilizza una macchina virtuale o un emulatore DOS, il membro TotalMemory
fornisce in genere una quantità totale di VRAM inferiore a quella effettivamente presente
sulla scheda video; ovviamente, ciò è dovuto al fatto che una parte consistente della VRAM
è riservata all'uso esclusivo del SO ospitante (host).
Tutti i successivi membri della struttura VbeInfoBlock sono disponibili solo in
presenza del supporto VBE 2.0 o superiore e contengono informazioni che gli OEM
utilizzano per identificare l'hardware da essi prodotto; tali informazioni sono rappresentate
da numeri in formato BCD e da stringhe C.
A partire dalle specifiche VBE 2.0, le informazioni relative all'OEM possono
trovarsi inserite, eventualmente, nei 256 byte del membro OemData.
In base alle considerazioni appena esposte, possiamo affermare quindi che il servizio
4F00h può essere usato innanzi tutto per verificare se un determinato VBIOS
supporta i servizi VBE; ciò avviene quando lo stesso servizio 4F00h restituisce
AL=4Fh e AH=00h.
Se in AL e AH si ottengono codici di errore, bisogna ovviamente terminare il
programma segnalando, attraverso un apposito messaggio, il mancato supporto VBE; se,
invece, il supporto VBE è presente, si può usare il contenuto della struttura
VbeInfoBlock per ricavare tutte le informazioni sull'adattatore video.
Si ricordi che, per ottenere le informazioni estese sul supporto VBE, bisogna chiamare
il servizio 4F00h dopo aver inizializzato il membro VbeSignature con la stringa
"VBE2"; come sappiamo, tali informazioni sono disponibili solo in presenza di un
VBIOS che supporta le specifiche VBE 2.0 o superiori (cosa che può essere
verificata attraverso il membro VbeVersion). In ogni caso, per evitare spiacevoli
sorprese conviene sempre allocare 512 byte di memoria da destinare alla struttura
VbeInfoBlock!
11.3.2 Servizio n. 4F01h: Return VBE Mode Information
Questo servizio restituisce una numerosa serie di informazioni relative ad una specifica
modalità video supportata dall'adattatore.
Per ciascuna delle modalità video restituite nella lista puntata da VideoModePtr
(Figura 11.5), è possibile richiedere una serie di ulteriori informazioni estremamente
dettagliate; tali informazioni vengono restituite dal servizio 4F01h in una struttura
denominata ModeInfoBlock.
La struttura ModeInfoBlock ha una dimensione pari a 256 byte che devono essere
allocati dal programma che richiede il servizio 4F01h; la Figura 11.7 illustra tutti
i dettagli.
Il membro ModeAttributes è un valore a 16 bit che fornisce importanti
caratteristiche hardware della modalità video selezionata; il significato dei vari bit è
illustrato dalla Figura 11.8.
Il bit 0 è molto importante in quanto ci permette di sapere se la modalità video
VESA che abbiamo specificato è effettivamente attivabile sul computer in uso; come è
stato spiegato in precedenza, può capitare che una determinata modalità video VESA, pur
essendo supportata dalla scheda video, non possa essere attivata a causa delle limitazioni del
monitor e/o della VRAM insufficiente.
Il bit 2 indica se il BIOS supporta le funzioni di emulazione del terminale; in
caso affermativo, il programmatore può chiamare eventualmente la INT 10h per usufruire
dei servizi standard 01h, 02h, 06h, 07h, 09h, 0Ah,
0Eh (vedere il documento VGABIOS.TXT disponibile nella sezione
Documentazione tecnica di supporto al corso assembly dell’
Area Downloads di questo sito.
Il bit 3 indica se la modalità video selezionata è monocromatica o a colori; analogamente,
il bit 4 indica se la modalità video selezionata è testuale o grafica.
Il bit 5 indica se la modalità video selezionata è "VGA compatibile"; in tal caso,
il programmatore può eventualmente accedere a tutte le caratteristiche hardware standard degli
adattatori VGA (porte di I/O, frame buffer, etc).
Il bit 6 (che deve essere combinato con il bit 7) indica se la modalità video
selezionata permette l'accesso alla VRAM attraverso le apposite finestre (Window
A e Window B) di I/O (accesso segmentato in modalità reale); in caso
affermativo, come è stato già spiegato, la VRAM risulta suddivisa in tanti blocchi
(generalmente da 64 KiB ciascuno) denominati memory banks (banchi di memoria).
Il bit 7 indica se la modalità video selezionata permette l'accesso alla VRAM
attraverso un frame buffer lineare (modalità protetta); il bit 7 si combina con il bit
6 per formare un codice a 2 bit per il quale sono permessi solamente i tre valori
00b (solo accesso segmentato), 10b (accesso segmentato o lineare), 11b
(solo accesso lineare).
Il bit 8 indica se la modalità video selezionata supporta il "double scan"; nelle
modalità video "double scan" (con risoluzioni standard da 320x200, 320x240,
400x300) ogni scan line viene scandita due volte durante il refresh verticale.
Il bit 9 indica se la modalità video selezionata supporta la scansione interlacciata
delle scan line; in caso affermativo, durante il vertical refresh, vengono scandite prima le
scan line di indice pari e poi quelle di indice dispari.
Il bit 10 indica se la modalità video selezionata supporta il "triple buffering"; in caso
affermativo i programmi possono usufruire di tre appositi buffer attraverso i quali si possono
velocizzare notevolmente le operazioni di rendering sullo schermo.
Il bit 11 indica se la modalità video selezionata supporta lo "stereoscopic display";
come è stato già spiegato, si tratta di una tecnica che consiste nel ricorso ad un particolare
sistema di suddivisione e visualizzazione delle immagini in modo da creare un effetto
stereoscopico tridimensionale.
Il bit 12 indica se la modalità video selezionata supporta l'indirizzamento del "dual
display"; in caso affermativo, l'effetto stereoscopico può essere creato con l'ausilio di due
monitor.
Tornando alla struttura di Figura 11.7, i membri WinAAttributes e WinBAttributes
forniscono le caratteristiche delle finestre per l'accesso segmentato alla VRAM; ciascuno
dei due valori a 8 bit assume la struttura mostrata in Figura 11.9.
Nella gran parte dei casi, risulta disponibile unicamente la Window A la quale sarà
quindi leggibile e scrivibile; se nessuna delle due finestre è supportata, il programmatore
può accedere alla VRAM solo attraverso un frame buffer lineare (modalità protetta).
Il membro WinGranularity indica la dimensione in KiB di ciascuno dei banchi di memoria
visibili in Figura 11.4; si tratta quindi dell'incremento (decremento) in KiB necessario per
posizionare la finestra di I/O sul banco di memoria successivo (precedente) a quello
in cui ci troviamo.
Il membro WinSize indica la dimensione in KiB di ciascuna delle due finestre di
I/O; il valore raccomandato dal comitato VESA è pari a 64 KiB (pari cioè
alla dimensione di un segmento di memoria della modalità reale) e quindi, i programmi possono
sempre assumere WinSize=64.
I membri WinASegment e WinBSegment hanno senso solo per la modalità reale e
contengono l'indirizzo di memoria da cui parte la relativa finestra di I/O; come al
solito, si tratta di un indirizzo allineato al paragrafo, per cui viene fornita la sola
componente Seg a 16 bit (la componente Offset vale implicitamente
0000h).
Nel caso più frequente è presente una sola finestra che parte all'indirizzo A000h:0000h
per le modalità grafiche, B800h:0000h per le modalità testo a colori e
B000h:0000h per le modalità testo in bianco e nero; se una determinata finestra non è
supportata, il relativo membro vale 0000h.
Il membro WinFuncPtr è un puntatore FAR da utilizzare per la chiamata di una
apposita funzione attraverso la quale si può posizionare una finestra di I/O nell'area
desiderata della VRAM; se tale funzione non è disponibile, il relativo membro vale
0000h:0000h (puntatore a NULL).
L'utilizzo della "window function" permette di velocizzare notevolmente le operazioni di
posizionamento delle finestre di I/O; in assenza di tale funzione, il programmatore
deve necessariamente ricorrere al meno efficiente servizio 4F05h della INT 10h
(vedere più avanti).
Il membro BytesPerScanLine indica la dimensione in byte di ogni linea di scansione dello
schermo; come abbiamo visto nel precedente capitolo, tale valore coincide con la larghezza in
pixel dello schermo solo nelle modalità grafiche che utilizzano 1 byte per identificare
il colore di ogni pixel.
I membri XResolution e YResolution indicano le dimensioni (larghezza e altezza) dello
schermo nella modalità video selezionata; per le modalità grafiche si tratta di valori in pixel,
mentre per le modalità testuali si tratta di valori in celle di carattere.
I membri XCharSize e YCharSize indicano le dimensioni in pixel di ogni cella di
carattere nella modalità video selezionata.
Il membro NumberOfPlanes indica il numero di piani di bit utilizzati dalla modalità video
che si sta usando; come abbiamo visto nel precedente capitolo, alcune particolari modalità video
rappresentano la VRAM sotto forma di piani di bit sovrapposti.
Il membro BitsPerPixel indica il numero di bit utilizzato per rappresentare il colore di
ciascun pixel nella modalità video che si sta usando; come sappiamo, spesso tale valore
rappresenta un indice relativo agli elementi di una apposita tavolozza di colori.
Il membro MemoryModel codifica l'organizzazione della VRAM nella modalità video
selezionata; si tratta di un codice a 8 bit che può assumere i valori illustrati in
Figura 11.10.
Il membro NumberOfBanks indica il numero di banchi di memoria nei quali si trovano
raggruppate le scan line relative alla modalità grafica selezionata; per le modalità video
che non utilizzano il raggruppamento in banchi delle scan line, il valore di questo membro
è 1.
Dividendo l'indice n di una scan line per il valore NumberOfBanks si ottiene un
quoziente che rappresenta l'indice b del banco che contiene la scan line n; il
resto della divisione rappresenta, invece, l'indice i della scan line n relativo
al banco b.
Il membro BankSize rappresenta la dimensione in KiB di ciascun banco utilizzato per
raggruppare le scan line nella modalità video selezionata; per le modalità video che non
utilizzano il raggruppamento in banchi delle scan line, il valore di questo membro è 0.
Il membro NumberOfImgPages rappresenta il numero totale, meno uno, di schermate complete
che la VRAM è in grado di contenere contemporaneamente; se questo valore è maggiore di
uno, è possibile gestire nella VRAM più schermate, ciascuna delle quali può essere poi
trasferita velocemente sullo schermo.
I membri RedMaskSize, GreenMaskSize, BlueMaskSize e RsvdMaskSize
rappresentano le dimensioni in bit delle tre componenti RGB (più una componente riservata)
utilizzate per codificare i colori nelle modalità video che supportano tale caratteristica
(Modello di memoria Direct Color o YUV); per le modalità video che non supportano le componenti
di colore, questi quattro membri valgono 0.
I membri RedFieldPos, GreenFieldPos, BlueFieldPos e RsvdFieldPos
rappresentano le posizioni del bit meno significativo di ciascuna delle tre componenti di
colore (più una componente riservata) all'interno di una terna RGB; ad esempio, se le
tre precedenti MaskSize sono 8:8:8, allora questi tre membri indicano le
posizioni 16:8:0.
Per le modalità video che non supportano le componenti di colore, questi quattro membri valgono
0.
Il membro DirectColModeInfo contiene importanti informazioni relative alle modalità video
che supportano le componenti di colore RGB; si tratta di un valore a 8 bit di cui
solamente i primi due bit hanno significato.
Il bit in posizione 0 indica se la tavolozza dei colori è fissa (0) o programmabile
(1); se tale bit vale 1, il programmatore può utilizzare il servizio 4F09h
per caricare una tavolozza personalizzata.
Il bit in posizione 1 indica se i membri RsvdMaskSize e RsvdFieldPos sono
usabili (1) o no (0); se tale bit vale 1, i colori RGB utilizzano
anche una quarta componente (ad esempio, alcuni SO si servono di questa quarta componente
per definire il grado di trasparenza del colore RGB di un pixel).
Tutti gli altri membri della struttura ModeInfoBlock hanno significato solo per la modalità
protetta.
11.3.3 Servizio n. 4F02h: Set VBE Mode
Questo servizio permette di abilitare una modalità video VESA supportata dall'adattatore
video.
Il servizio 4F02h permette di abilitare una delle modalità video VESA supportate
dall'hardware del computer che si sta utilizzando; il registro BX deve contenere
l'opportuno codice di Figura 11.2.
Come è stato già spiegato in precedenza, il bit in posizione 11 di tale codice serve per
selezionare la modalità di controllo della frequenza di scansione verticale del monitor; se
questo bit vale 0 vengono utilizzate le impostazioni predefinite del BIOS, mentre
se questo bit vale 1 vengono utilizzate le impostazioni personalizzate che il
programmatore deve specificare in una struttura CRTCInfoBlock puntata da ES:DI.
A meno che si sappia esattamente ciò che si sta facendo, si consiglia vivamente di lasciare
a 0 il bit in posizione 11; per maggiori dettagli sulla struttura
CRTCInfoBlock si può consultare il documento VBE3.PDF disponibile nella sezione
Documentazione tecnica di supporto al corso assembly dell’
Area Downloads di questo sito.
Un altro aspetto molto importante da ricordare è che una data modalità video, pur essendo
supportata dal proprio adattatore, potrebbe non essere attivabile a causa della scarsità di
VRAM o a causa delle limitazioni del monitor; proprio per questo motivo, prima di
abilitare la modalità video desiderata conviene sempre consultare il bit in posizione
0 del membro ModeAttributes della struttura ModeInfoBlock.
11.3.4 Servizio n. 4F03h: Return Current VBE Mode
Questo servizio permette di ottenere informazioni sulla modalità video VESA attualmente
abilitata.
Il servizio 4F03h restituisce alcune sommarie informazioni sulla modalità video VESA
corrente; tali informazioni risultano disponibili nel registro BX.
I bit nelle posizioni dalla 0 alla 13 contengono il codice della modalità video
corrente (Figura 11.2). Il bit in posizione 14 indica se il modo video corrente supporta
il frame buffer a finestre (0) o il frame buffer lineare (1); il bit in posizione
15 indica se, quando è stata attivata la modalità video corrente, la VRAM è stata
cancellata (0) oppure no (1).
Si tenga presente che il servizio 4F03h restituisce le informazioni appena descritte solo
quando la modalità video corrente è stata attivata con il servizio 4F02h; ciò può non
accadere quando la modalità video corrente è stata attivata con il servizio standard 00h
(Set Video Mode) della INT 10h.
11.3.5 Servizio n. 4F04h: Save/Restore Video State
Questo servizio permette di salvare o ripristinare lo stato hardware dell'adattatore video.
Attraverso il servizio 4F04h è possibile salvare lo stato hardware corrente o
ripristinare lo stato hardware precedente dell'adattatore video; la specifica operazione
da eseguire deve essere indicata attraverso un codice nel registro DL.
- Se DL=00h, stiamo richiedendo la dimensione del buffer da utilizzare per
contenere le informazioni da salvare o ripristinare; tale dimensione viene
restituita nel registro BX ed è espressa in blocchi da 64 byte.
- Se DL=01h stiamo richiedendo il salvataggio dello stato hardware corrente
dell'adattatore video; le informazioni vengono salvate nell'area di memoria puntata
da ES:BX (allocata dal programmatore in base al valore calcolato in
precedenza con DL=00h).
- Se DL=02h stiamo richiedendo il ripristino dello stato hardware precedente
dell'adattatore video; le informazioni vengono lette dall'area di memoria puntata
da ES:BX.
Il registro CX, attraverso i suoi 4 bit meno significativi, permette di
specificare quale stato hardware si deve salvare (DL=01h) o ripristinare
(DL=02h); il bit in posizione 0 si riferisce allo stato hardware del
controller, il bit in posizione 1 si riferisce allo stato dei dati del BIOS,
il bit in posizione 2 si riferisce allo stato hardware del DAC, il bit in
posizione 3 si riferisce allo stato dei registri.
Naturalmente, è anche possibile combinare questi 4 bit; ponendo, ad esempio,
CX=000Fh (00001111b), si indica che l'operazione di salvataggio o ripristino
coinvolge tutte le quattro voci elencate in precedenza.
11.3.6 Servizio n. 4F05h: Display Window Control
Questo servizio permette di gestire l'accesso alla VRAM attraverso il frame buffer.
Attraverso il servizio 4F05h è possibile controllare il posizionamento nella
VRAM del frame buffer a finestre; l'operazione da svolgere viene specificata attraverso
il registro BH, mentre la finestra coinvolta (A o B) viene specificata
attraverso il registro BL.
- Se BH=0, stiamo richiedendo il posizionamento della finestra in VRAM;
in tal caso, il registro DX deve specificare la posizione in unità di misura
pari alla granularità (vedere la Figura 11.4).
- Se BH=1, stiamo richiedendo la posizione attuale della finestra in VRAM;
in tal caso, l'informazione richiesta viene restituita nel registro DX ed è
espressa in unità di misura pari alla granularità.
Il registro BL indica la finestra alla quale ci stiamo riferendo; il valore 0
indica la Window A, mentre il valore 1 indica la Window B.
Molti programmi fanno un uso piuttosto pesante del bank switching (commutazione di
banco); in casi del genere, la chiamata del servizio 4F05h attraverso la INT 10h
può provocare un sensibile calo delle prestazioni.
Per ovviare a questo inconveniente, il programmatore può anche servirsi della window
function il cui indirizzo FAR, come già sappiamo, viene restituito nel membro
WinFuncPtr della struttura ModeInfoBlock; è importante ricordare che, se tale
funzione non è supportata, il membro WinFuncPtr restituisce l'indirizzo
0000h:0000h (puntatore FAR a NULL).
Se la window function è supportata, il suo utilizzo è vivamente raccomandato al posto
della INT 10h; a tale proposito, dopo aver inizializzato i registri BX e DX
richiesti dal servizio 4F05h, basta effettuare una chiamata FAR all'indirizzo
WinFuncPtr. Ad esempio, se abbiamo creato una istanza mode_info della struttura
ModeInfoBlock, possiamo scrivere:
Ovviamente, se la window function non è supportata, dobbiamo sostituire la precedente
chiamata FAR con una istruzione INT 10h (dopo aver posto AX=4F05h)!
11.3.7 Servizio n. 4F06h: Set/Get Logical Scan Line Length
Questo servizio permette di specificare la larghezza virtuale dello schermo.
Attraverso il servizio 4F06h il programmatore può impostare una larghezza "virtuale" dello
schermo maggiore di quella fisicamente visibile sul monitor; ad esempio, dopo aver attivato una
modalità video da 640x480 pixel si può impostare una larghezza virtuale pari a
3*640=1920 pixel.
Il registro BL permette di specificare l'operazione richiesta; i valori disponibili sono:
00h (imposta la larghezza in pixel della scan line), 01h (restituisce la larghezza
corrente della scan line), 02h (imposta la larghezza in byte della scan line), 03h
(restituisce la massima larghezza possibile per una scan line).
Il registro CX permette di specificare la larghezza desiderata di una scan line; se
BL=00h allora CX indica una larghezza in pixel, mentre se BL=02h allora
CX indica una larghezza in byte (il contenuto di CX viene ignorato quando
BL vale 01h o 03h).
In risposta alla chiamata del servizio 4F06h, vengono restituite una serie di
informazioni nei registri BX, CX e DX; il registro BX restituisce
la larghezza in byte della scan line, il registro CX restituisce la larghezza in pixel
della scan line, mentre il registro DX restituisce il massimo numero di scan line
disponibili.
Si presti molta attenzione al fatto che la richiesta di questo servizio può restituire un
errore; come è stato spiegato in precedenza, ciò è dovuto ad eventuali limitazioni hardware
(in questo caso, VRAM insufficiente).
11.3.8 Servizio n. 4F07h: Set/Get Display Start
Questo servizio permette di specificare quale pixel dello schermo virtuale verrà visualizzato
nell'angolo in alto a sinistra del monitor.
Attraverso il servizio 4F07h il programmatore può specificare la porzione dello schermo
"virtuale" che verrà visualizzata sul monitor (cioè, il pixel dello schermo virtuale che
comparirà nell'angolo in alto a sinistra del monitor); in tal modo è possibile creare un
effetto di scorrimento dello schermo virtuale sul monitor.
Per effettuare tutte le necessarie impostazioni bisogna porre BL=00h; in tal caso,
DX deve contenere l'indice della prima scan line da visualizzare, mentre CX deve
contenere l'indice del pixel, di quella stessa scan line, da visualizzare per primo .
Per richiedere le impostazioni correnti bisogna porre BL=01h; in tal caso in DX
viene restituito l'indice della prima scan line visualizzata, mentre in CX viene
restituito il primo pixel visualizzato nella stessa prima scan line.
Lo standard VBE 3.0 introduce diverse nuove funzionalità per il servizio 4F07h;
a tale proposito, si consiglia di consultare il documento VBE3.PDF disponibile nella
sezione Documentazione tecnica di supporto al corso assembly dell’
Area Downloads di questo sito.
11.3.9 Servizio n. 4F08h: Set/Get DAC Palette Format
Questo servizio permette di specificare il numero di bit da utilizzare per rappresentare
ciascuna delle 3 componenti RGB di un colore (Direct Color).
Attraverso il servizio 4F08h il programmatore può specificare il numero di bit da
utilizzare per rappresentare ciascuna delle 3 componenti primarie di un colore
RGB (modello di memoria Direct Color); ciò è possibile solo quando il bit meno
significativo del membro Capabilities della struttura VbeInfoBlock vale 1.
Per impostare il numero di bit per componente primaria bisogna porre BL=00h; in ogni
caso (e quindi, anche in caso di errore), il registro BH restituisce il numero effettivo
di bit assegnato ad ogni componente primaria.
Per richiedere le impostazioni correnti bisogna porre BL=01h; in tal caso in BH
viene restituito il numero corrente di bit assegnato ad ogni componente primaria.
11.3.10 Servizio n. 4F09h: Set/Get DAC Palette Data
Questo servizio permette di gestire una tavolozza di colori RGB da utilizzare nelle
modalità video con modello di memoria Direct Color.
Attraverso il servizio 4F09h il programmatore può gestire la tavolozza dei colori da
utilizzare nelle modalità video con modello di memoria Direct Color; questa funzionalità deve
essere impiegata solo con gli adattatori video che non supportano l'accesso diretto alla
tavolozza attraverso i servizi standard VGA (vedere la Figura 11.6).
Per impostare una nuova tavolozza bisogna porre BL=00h; in tal caso, il registro
CX deve specificare il numero di elementi RGB da aggiornare nella tavolozza
(max. 256), il registro DX deve specificare l'indice del primo elemento
RGB da aggiornare nella tavolozza, mentre ES:DI deve puntare alla nuova tavolozza.
Per conoscere la tavolozza corrente bisogna porre BL=01h; anche in questo caso, il
registro CX specifica il numero di elementi RGB da leggere (max. 256), il
registro DX specifica l'indice del primo elemento RGB da leggere, mentre
ES:DI deve puntare all'area di memoria dove salvare la tavolozza.
La tavolozza è un vettore di elementi RGB, ciascuno dei quali assume l'aspetto
illustrato in Figura 11.11.
Usualmente, il DAC utilizza 6 bit per ogni componente primaria di colore; per
sapere se il DAC supporta le componenti a 8 bit è necessario consultare il bit
in posizione 1 del membro Capabilities (vedere figura 11.6).
11.4 Supporto VESA per le vecchie schede video SVGA
Può capitare di imbattersi in vecchi PC dotati di schede video le quali, pur supportando
diverse modalità SVGA, risultano prive delle estensioni VBE nel VBIOS
essendo state fabbricate in un periodo precedente alla nascita dello standard VESA;
molto spesso, questo problema può essere efficacemente risolto attraverso appositi programmi
TSR (Terminate and Stay Resident) reperibili su Internet.
Una volta che il programmatore ha reperito il TSR adatto alla propria scheda video,
procede alla relativa installazione ed attivazione al boot attraverso il file
AUTOEXEC.BAT; ad esempio, nel caso di una scheda video Tseng Labs ET4000, il
TSR prende il nome di TLIVESA.COM e, supponendo che tale file si trovi in
C:\, può essere installato con la riga:
LH C:\TLIVESA.COM
(il comando LH significa Load High e permette di installare un programma nella
upper memory).
Al riavvio del PC, il TSR si installa permanentemente in memoria ed effettua un
lavoro molto importante che consiste nell'intercettare tutte le chiamate alla INT 10h;
se il TSR si accorge che AH=4Fh, provvede a fornire il servizio VBE
richiesto, mentre in caso contrario trasferisce la chiamata alla ISR predefinita per
la INT 10h.
La Figura 11.12 illustra un elenco, in ordine alfabetico, dei principali produttori di
(vecchie) schede video e dei relativi TSR reperibili su Internet; generalmente,
ogni TSR è accompagnato da un documento che illustra le modalità di utilizzo e la
versione VBE supportata.
Naturalmente, è del tutto superfluo sottolineare che il programmatore deve munirsi del
TSR adeguato per la propria scheda video SVGA; in caso contrario, si possono
ottenere risultati del tutto imprevedibili!
11.5 Il bank switching
Come è stato ampiamente spiegato in precedenza, quando si programma in modalità VESA,
uno degli aspetti fondamentali riguarda il cosiddetto bank switching (commutazione di
banco); con questo termine si indica l'operazione di posizionamento della finestra (o delle
finestre) nell'area desiderata della VRAM nella quale si intende leggere o scrivere.
Per svolgere correttamente tale lavoro, il programmatore deve prima raccogliere una serie
completa di informazioni come quelle restituite dai servizi 4F00h e 4F01h; in
particolare, le informazioni più importanti riguardano: la disponibilità del frame buffer a
finestre, la dimensione delle finestre e la granularità della VRAM.
Tutte queste informazioni sono necessarie in quanto l'operazione di bank switching
comporta lo svolgimento di una serie di calcoli; per chiarire questo aspetto, vediamo un
esempio pratico illustrato dalla Figura 11.13.
Nell'esempio di Figura 11.13 supponiamo di aver attivato una ipotetica modalità video
512x512 a 256 colori; come sappiamo, nelle modalità grafiche a 256
colori vengono utilizzati 8 bit per codificare il colore di ogni pixel.
La struttura ModeInfoBlock ci restituisce quindi le informazioni BitsPerPixel=8
e XResolution=512 (che coincide con BytesPerScanLine=512); supponiamo, inoltre,
che sia presente il supporto per la sola WindowA con WinASegment=A000h,
WinSize=64 KiB e WinGranularity=16 KiB.
La conseguenza di tutto ciò è che una schermata 512x512 pixel (che occupa quindi
262144 byte) risulterà suddivisa in 16 banchi di memoria (indicizzati in Figura
11.13 da 0 a 15) da 16 KiB ciascuno; la stessa Figura 11.13 mostra anche
i 16 banchi di memoria suddivisi in 4 gruppi da 64 KiB ciascuno (e
indicizzati da 0 a 3).
Un'altra conseguenza è che ogni banco di memoria risulterà contenere 32 scan line
complete; come vedremo in seguito, questa è una situazione ideale che non sempre si verifica
nella realtà.
Nell'esempio di Figura 11.13 risulta semplicissimo il calcolo dell'offset relativo ad un pixel
di coordinate x, y; la formula generale è, infatti:
pixel_address = (y * XResolution) + x
Nel nostro caso, con x=158 e y=300, otteniamo:
pixel_address = (300 * 512) + 158 = 153758
Osservando che 512=29, possiamo velocizzare notevolmente il precedente
calcolo eliminando la lentissima moltiplicazione e scrivendo simbolicamente:
pixel_address = (SHL y, 9) + x = 153600 + 158 = 153758
L'aspetto importantissimo da notare è che il risultato ottenuto può anche richiedere più di
16 bit per la sua rappresentazione; è fondamentale quindi utilizzare sempre ampiezze a
32 bit per questi particolari calcoli.
A questo punto dobbiamo determinare l'indice (win_bank) del banco di memoria che
contiene il pixel P; questo calcolo è semplicissimo in quanto basta dividere
pixel_address per WinGranularity.
Nel nostro caso, WinGranularity=16384 byte, per cui si ha (divisione intera):
win_bank = pixel_address / WinGranularity = 153758 / 16384 = 9
Anche in questo caso, osservando che 16384=214, possiamo eliminare la
lentissima divisione e scrivere simbolicamente:
win_bank = SHR pixel_address, 14 = SHR 153758, 14 = 9
La Figura 11.13 conferma che il risultato del calcolo è corretto.
Dopo aver posizionato la WindowA nel banco 9, dobbiamo effettuare un ultimo
calcolo che riguarda la determinazione dell'offset (a 16 bit) del pixel P
all'interno dello stesso banco 9 da 16 KiB; anche questo calcolo è molto semplice
in quanto basta sottrarre a pixel_address il valore win_bank*WinGranularity.
Considerando ancora il fatto che il valore WinGranularity è 16384=214,
si può rendere tale operazione molto più efficiente in questo modo:
pixel_offset = pixel_address - (SHL win_bank, 14) = 153758 - 147456 = 6302
Osservando che 6302=189Eh, possiamo affermare che il nostro pixel P si troverà
all'indirizzo logico A000h:189Eh della WindowA la quale, a sua volta, si trova già
posizionata nel banco 9 della VRAM.
11.6 Codifica dei colori nelle modalità video VESA/SVGA
Nel precedente capitolo, parlando delle varie modalità video grafiche standard, abbiamo visto
che in certi casi i bit della VRAM assegnati ad ogni pixel contengono un valore che non
rappresenta direttamente il colore del pixel stesso, bensì l'indice relativo ad un vettore di
colori; l'elemento associato a quell'indice codifica l'effettivo colore del pixel.
Questa stessa situazione si presenta anche quando si programmano le modalità SVGA
attraverso lo standard VESA; la differenza fondamentale è data dal fatto che, nelle
modalità SVGA, si ha a che fare con un numero di colori che può andare da 2
(modalità monocromatiche) a diversi milioni, per cui si rendono necessarie anche altre tecniche
di codifica!
Abbiamo anche visto che, quando si lavora con le modalità video grafiche standard a bassa
risoluzione (CGA, EGA, VGA e MCGA), le varie tecniche di codifica
dei colori permettono di gestire in memoria una intera schermata senza mai sconfinare dal
limite dei 64 KiB; in questo modo, il programmatore può lavorare sulla VRAM in
modo estremamente efficiente.
Nella gestione della VRAM in modalità SVGA, attraverso lo standard VESA,
si ha spesso a che fare con risoluzioni grafiche piuttosto alte che comportano la suddivisione
di una schermata in numerosi blocchi da 64 KiB; ciò significa che, quando si deve
accedere in I/O alla VRAM, si può rendere necessario un pesante lavoro di bank
switching.
Per chiarire tutti questi aspetti, analizziamo i vari sistemi di codifica dei colori nelle
modalità video grafiche VESA/SVGA.
11.6.1 Modalità video grafiche a 2 e a 4 colori
Nel precedente capitolo abbiamo visto che, nelle modalità video grafiche monocromatiche, ad
ogni pixel viene assegnato un solo bit della VRAM; infatti, con 1 bit possiamo
codificare la condizione 0 (pixel spento = colore nero) o 1 (pixel acceso).
Ogni byte della VRAM contiene le informazioni relative a 8/1=8 pixel; possiamo
affermare quindi che il valore BytesPerScanLine è pari a XResolution/8.
Nelle modalità video grafiche a 4 colori, ad ogni pixel vengono assegnati 2 bit
della VRAM; infatti, con 2 bit possiamo codificare 22=4 colori
differenti.
Ogni byte della VRAM contiene le informazioni relative a 8/2=4 pixel; possiamo
affermare quindi che il valore BytesPerScanLine è pari a XResolution/4.
La Figura 11.14 illustra quest'ultima situazione.
Le specifiche VESA non prevedono alcun supporto per le modalità video grafiche a
2 o 4 colori; il programmatore deve quindi ricorrere ai servizi standard del
BIOS illustrati nel precedente capitolo.
11.6.2 Modalità video grafiche a 16 colori
Nel precedente capitolo abbiamo visto che, nelle modalità video grafiche a 16 colori,
ad ogni pixel vengono assegnati 4 bit della VRAM; infatti, con 4 bit
possiamo codificare 24=16 colori differenti.
I 4 bit di ogni pixel risultano disposti in posizioni corrispondenti su 4
piani sovrapposti; la Figura 11.15 illustra questa situazione.
Ogni piano di bit risulta composto da XResolution*YResolution bit; possiamo affermare
quindi che il valore BytesPerScanLine è pari a XResolution/8.
Le specifiche VESA forniscono il supporto per le modalità video grafiche a 16
colori con risoluzione maggiore o uguale a 800x600; le risoluzioni inferiori (ad
esempio, 640x480) possono essere programmate con i servizi standard del BIOS
illustrati nel precedente capitolo.
A seconda della risoluzione grafica (ad esempio, 1024x768) la quantità di memoria
richiesta per gestire una schermata supera il limite dei 64 KiB (per ogni piano di bit)
per cui entra in gioco anche il bank switching; ovviamente, questo aspetto vale per
ciascuno dei 4 piani di bit.
Come sappiamo, nelle modalità video grafiche a 16 colori, i 4 bit assegnati ad
ogni pixel rappresentano l'indice relativo ai primi 16 elementi di un vettore di
256 colori; ogni elemento è formato da 3 byte (componenti RGB) di
ciascuno dei quali vengono utilizzati solo i primi 6 bit in modo da ottenere sino a
218=262144 colori.
Se il proprio adattatore video è dotato di compatibilità VGA (Figura 11.6 e Figura
11.8), tutti i registri relativi alla gestione dei piani di bit e della tavolozza dei colori
possono essere programmati attraverso le tecniche illustrate nel precedente capitolo; in caso
contrario, si veda il servizio 4F09h descritto in questo capitolo.
11.6.3 Modalità video grafiche a 256 colori
Nel precedente capitolo abbiamo visto che, nelle modalità video grafiche a 256 colori,
ad ogni pixel vengono assegnati 8 bit della VRAM; infatti, con 8 bit
possiamo codificare 28=256 colori differenti.
I vari gruppi di 8 bit risultano disposti in sequenza nella VRAM per cui la
programmazione di queste modalità grafiche risulta semplicissima; la Figura 11.16 illustra
questa situazione.
L'unico piano di bit presente risulta composto da XResolution*YResolution byte; possiamo
affermare quindi che il valore BytesPerScanLine è pari a XResolution.
Come risulta dalla Figura 11.2, le specifiche VESA 3.0 forniscono il supporto per cinque
differenti modalità video grafiche a 256 colori; le risoluzioni vanno dalla
640x400 alla 1280x1024.
A seconda della risoluzione grafica, la quantità di memoria richiesta per gestire una schermata
supera il limite dei 64 KiB per cui entra in gioco anche il bank switching; ad
esempio, una schermata da 640x480 pixel richiede 640x480=307200 byte di VRAM
suddivisi in quasi 5 blocchi da 64 KiB.
Come sappiamo, nelle modalità video grafiche a 256 colori, gli 8 bit assegnati
ad ogni pixel rappresentano l'indice relativo agli elementi di un vettore di 256 colori;
ogni elemento è formato da 3 byte (componenti RGB) di ciascuno dei quali vengono
utilizzati solo i primi 6 bit in modo da ottenere sino a 218=262144
colori.
Se il proprio adattatore video è dotato di compatibilità VGA (Figura 11.6 e Figura 11.8),
tutti i registri relativi alla gestione della tavolozza dei colori possono essere programmati
attraverso le tecniche illustrate nel precedente capitolo; in caso contrario, si veda il
servizio 4F09h descritto in questo capitolo.
11.6.4 Modalità video grafiche High Color
La continua evoluzione tecnologica degli adattatori video ha portato anche ad un notevole
aumento della quantità disponibile di VRAM e ciò ha reso possibile il supporto di
modalità video grafiche capaci di gestire decine di migliaia di colori contemporaneamente;
tali modalità video sono state definite High Color.
La codifica dei colori nelle modalità High Color si basa sempre sul concetto di terna
RGB; a tale proposito, vengono utilizzati 2 byte (1 word) per ogni pixel
secondo lo schema illustrato in Figura 11.17.
In Figura 11.17a vediamo la tecnica di codifica di tipo 5:5:5 che consiste
nell'utilizzare 5 bit per ogni componente primaria di colore; in questo modo,
complessivamente, possiamo rappresentare:
25 * 25 * 25 = 25 + 5 + 5 = 215 = 32768
colori differenti.
Osservando che, nella WORD associata ad ogni pixel, rimane 1 bit libero, si può
pensare ad una seconda tecnica di codifica di tipo 5:6:5 come descritto in Figura
11.17b; in questo modo, complessivamente, possiamo rappresentare:
25 * 26 * 25 = 25 + 6 + 5 = 216 = 65536
colori differenti.
La notevole quantità di VRAM presente negli adattatori video con supporto High
Color permette di memorizzare i colori effettivi direttamente nella stessa VRAM;
in sostanza, la memoria video nelle modalità High Color è strutturata come un vettore
di WORD, ciascuna delle quali contiene direttamente il colore del relativo pixel.
Ogni schermata High Color risulta composta da (XResolution*2)*YResolution byte;
possiamo affermare quindi che il valore BytesPerScanLine è pari a XResolution*2.
11.6.5 Modalità video grafiche True Color
L'ulteriore evoluzione tecnologica degli adattatori video ha reso possibile il supporto di
modalità video grafiche capaci di gestire milioni di colori contemporaneamente; tali modalità
video sono state definite True Color.
La codifica dei colori nelle modalità True Color si basa sempre sul concetto di terna
RGB; a tale proposito, vengono utilizzati 3 byte per ogni pixel secondo lo
schema illustrato in Figura 11.18.
La tecnica di codifica è di tipo 8:8:8 e consiste nell'utilizzare 8 bit per
ogni componente primaria di colore; in questo modo, complessivamente, possiamo rappresentare:
28 * 28 * 28 = 28 + 8 + 8 = 224 = 16777216
colori differenti.
La notevole quantità di VRAM presente negli adattatori video con supporto True
Color permette di memorizzare i colori effettivi direttamente nella stessa VRAM;
in sostanza, la memoria video nelle modalità True Color è strutturata come un vettore
di terne di BYTE, ciascuna delle quali contiene direttamente il colore del relativo
pixel.
Ogni schermata True Color risulta composta da (XResolution*3)*YResolution byte;
possiamo affermare quindi che il valore BytesPerScanLine è pari a XResolution*3.
Esistono anche modalità True Color che prevedono la rappresentazione del colore di un
pixel attraverso 4 byte di cui i primi tre contengono la solita terna RGB di
tipo 8:8:8, mentre il quarto byte è disponibile per altri usi; in questo caso, ogni
schermata risulta composta da (XResolution*4)*YResolution byte con il valore
BytesPerScanLine che è pari a XResolution*4.
11.7 Esempi pratici
Prima di analizzare alcuni esempi pratici è necessario sottolineare un aspetto importante;
una macchina virtuale (come VirtualBox) o un emulatore DOS, possono fornire
un proprio supporto VESA che potrebbe anche risultare differente da quello
effettivamente presente nel VBIOS del computer host.
Generalmente, la differenza principale riguarda la versione VBE; non è raro allora che
una macchina virtuale o un emulatore DOS dispongano di caratteristiche hardware
"virtuali" superiori a quelle effettivamente disponibili.
11.7.1 Visualizzazione di informazioni dettagliate sul supporto VBE
Per programmare una scheda video in modo corretto ed efficiente attraverso le specifiche
VESA, è necessario raccogliere innanzi tutto una serie dettagliata di informazioni
relative all'hardware supportato; il programma di Figura 11.19 si prefigge proprio di
eseguire tale compito.
Il programma inizia chiamando il servizio 4F00h per riempire la struttura
VbeInfoBlock; se la chiamata non restituisce un codice di errore, vengono
visualizzate le principali informazioni contenute nella struttura stessa.
Successivamente, il programma si serve del puntatore VideoModePtr per attivare un
loop dal quale si esce quando viene incontrato il valore FFFFh (fine lista delle
modalità video); per ogni modalità video, vengono mostrate tutte le informazioni principali
restituite nella struttura ModeInfoBlock dal servizio 4F01h.
11.7.2 Trasferimento dati in VRAM nei modi video a 256 colori
Vediamo ora un programma che utilizza REP STOSD per riempire con differenti colori i
vari blocchi da 64 KiB che compongono una schermata grafica a 256 colori
(modalità video standard con BitsPerPixel=8); la Figura 11.20 mostra il relativo
listato.
Inizialmente il programma effettua una serie di controlli per verificare che tutto sia a posto;
in particolare, viene verificata la presenza del supporto VESA, il supporto hardware del
modo video richiesto e la presenza del frame buffer a finestre.
Se tutti i controlli forniscono esito positivo, si procede con il calcolo di una serie di
parametri da utilizzare nel seguito del programma; in particolare, viene determinato il numero
di banchi che compongono una finestra, il numero di finestre in una schermata e il valore
bank_shift di cui si è parlato in precedenza.
Successivamente, viene attivata la modalità video richiesta e si avvia un loop attraverso il
quale si procede al riempimento dei vari blocchi da 64 KiB con differenti colori; si noti
che, in generale, l'ultimo blocco ha una dimensione che è sempre minore o uguale a 64 KiB.
Osservando l'output che questo programma produce con certe risoluzioni grafiche, si nota
chiaramente che ogni finestra da 64 KiB contiene un numero non intero di scan line; ciò
accade quando la XResolution non è esprimibile come potenza intera di 2.
Ad esempio, per la risoluzione 640x480, ogni scan line occupa 640 byte, per cui
il numero totale di scan line contenuto in una finestra da 64 KiB sarà:
65536 / 640 = 102.4
Un altro aspetto da notare nel listato del programma è la presenza di direttive IFDEF,
ELSE e ENDIF; grazie a tali direttive è possibile assemblare determinate porzioni
di programma al posto di altre (assemblaggio condizionale).
In particolare, lo scopo di queste direttive nel listato di Figura 11.20 è legato alla
necessità di impiegare preferibilmente la window function al posto della INT 10h
per tutte le operazioni di bank switching (evitando l'uso pesante di istruzioni per il
controllo del flusso); nel caso di hardware grafico che non supporta la window function,
basta commentare la dichiarazione della costante simbolica WIN_FUNC all'inizio del
programma per fare in modo che venga usata automaticamente la INT 10h.
11.7.3 Accesso ai pixel nelle modalità grafiche True Color
Vediamo ora un programma che ha lo scopo di evidenziare un importante aspetto relativo alle
modalità video grafiche True Color con BitsPerPixel=24; la Figura 11.21 mostra il
relativo listato.
Il compito di questo programma è apparentemente molto semplice; si tratta, infatti, di riempire
una intera schermata con XResolution*YResolution pixel.
Per ogni pixel di coordinate x,y dobbiamo calcolare innanzi tutto il valore
pixel_address; osservando che, nelle modalità True Color, ogni pixel richiede 3
byte in VRAM, la formula generale sarà:
pixel_address = (y * BytesPerScanLine) + (x * 3)
Il blocco da 64 KiB in cui si trova il pixel si ottiene dalla formula:
win_bank = pixel_address >> 16
Dopo aver calcolato nel solito modo il valore bank_shift, possiamo determinare il banco
in cui posizionare la finestra con la formula:
bank = win_bank << bank_shift
Dopo aver posizionato la finestra, calcoliamo l'offset del pixel con la formula:
pixel_offset = pixel_address AND FFFFh
A questo punto non dobbiamo fare altro che trasferire 3 byte di colore all'indirizzo
appena calcolato; se però proviamo ad usare queste formule nel programma di Figura 11.21
otteniamo un sicuro crash!
Il perché di questo crash è legato proprio al fatto che, nelle modalità True Color, il colore
di ogni pixel viene rappresentato con 3 byte, ma la dimensione di un banco di memoria
è sempre multipla intera di 2 e non di 3; ciò significa che la terna di
BYTE relativa a particolari pixel potrebbe trovarsi a cavallo tra un banco di memoria
e quello successivo!
Questo problema non si presenta nelle modalità High Color dove ogni pixel occupa 2 byte
in VRAM; questa coppia di BYTE relativa ad ogni pixel verrà quindi sempre a
trovarsi all'interno dello stesso banco di memoria.
Il programma di Figura 11.21 mostra come affrontare la situazione nelle modalità True Color;
in pratica, si distinguono i seguenti tre casi:
- l'offset del pixel è al massimo FFFDh per cui i relativi 3 byte devono
essere disposti tutti all'interno dello stesso banco di memoria
- l'offset del pixel è pari a FFFEh per cui i relativi 3 byte devono
essere disposti: i primi due in un banco di memoria e il terzo nel banco successivo
- l'offset del pixel è pari a FFFFh per cui i relativi 3 byte devono essere
disposti: il primo in un banco di memoria e gli altri due nel banco successivo
Da notare l'importantissimo ruolo svolto dalla variabile curr_bank che memorizza l'indice
del banco di memoria correntemente attivo; consultando tale variabile possiamo ridurre al minimo
indispensabile le pesanti operazioni di bank switching!
L'esempio di Figura 11.21 si riferisce alla modalità VESA standard 0112h
(risoluzione 640x480 e colori a 24 bit 8:8:8); il programma è totalmente
parametrizzato per cui può essere testato anche con le altre modalità standard True Color
(24 bit) tenendo però presente ciò che è stato spiegato per l'esempio di Figura 11.20.
Lo stesso esempio di Figura 11.21, inoltre, può essere facilmente adattato al caso
BitsPerPixel=32 (dove i primi tre BYTE rappresentano una terna RGB di
tipo 8:8:8, mentre il quarto BYTE è disponibile per altri usi); in tal caso la
situazione si semplifica notevolmente in quanto WinGranularity è anche un multiplo
intero di 4, per cui è impossibile che la quaterna di BYTE relativa ad un
qualunque pixel venga a trovarsi a cavallo tra due banchi di memoria adiacenti.
Per esercizio si può provare a realizzare proprio l'adattamento appena descritto; in tal caso,
si tenga presente che:
pixel_address = (y * BytesPerScanLine) + (x * 4)
11.8 Libreria VESALIB
Anziché riscrivere ogni volta centinaia di linee di codice da zero, conviene seguire il metodo
già illustrato nei precedenti capitoli, che consiste nel crearsi una apposita libreria di
procedure pronte per l'uso; in particolare, in relazione allo standard VBE, tali procedure
devono fornire tutto il necessario per effettuare le varie verifiche e inizializzazioni.
In una libreria grafica è anche importante disporre di una procedura capace di svolgere un
compito fondamentale, che consiste nella visualizzazione di un pixel sullo schermo; a partire
da tale procedura, si possono poi affrontare casi più complessi, come la visualizzazione di
stringhe, segmenti di retta, etc.
Nella sezione Librerie di supporto per il corso assembly dell’
Area Downloads di questo sito, è presente una libreria, denominata VESALIB, che può essere linkata ai
programmi destinati alla generazione di eseguibili in formato EXE; all'interno del
pacchetto vesalibexe.zip è presente la libreria VESALIB.ASM, l'include file
VESALIBN.INC per il NASM e l'include file VESALIBM.INC per il MASM.
Per la creazione dell'object file di VESALIB.ASM è richiesto il NASM;
l'assemblaggio consiste nel semplice comando:
nasm -f obj vesalib.asm
L'object file così ottenuto è perfettamente linkabile anche ai programmi
scritti con MASM.
Analizziamo in dettaglio le procedure fornite dalla libreria VESALIB; ulteriori
informazioni possono essere ottenute leggendo gli abbondanti commenti presenti nel file
VESALIB.ASM.
Questa procedura verifica la presenza del supporto VESA; se tale supporto è presente,
viene riempita una struttura interna info_block di tipo VbeInfoBlock.
Non è richiesto alcun parametro in ingresso.
I parametri in uscita vengono restituiti in AL, AH, EBX e ECX.
AL contiene il valore di ritorno vero e proprio; come sappiamo, AL=4Fh indica
che il supporto VESA è presente. AH contiene un codice diagnostico; abbiamo
visto che AH=00h indica che il servizio richiesto è stato eseguito correttamente. I
due registri EBX e ECX restituiscono dei puntatori FAR a delle stringhe;
tali stringhe descrivono il contenuto dei due registri AL e AH.
Questa procedura restituisce i vari campi della struttura info_block riempita dalla
procedura vesa_getcontrollerinfo; ovviamente, tali campi hanno senso solo se il
supporto VESA è presente.
Come parametro in ingresso si deve inserire in BX l'identificatore del campo richiesto;
a tale proposito, si veda l'include file della libreria VESALIB. Si può notare che gli
identificatori non sono altro che gli offset dei vari campi della struttura info_block.
Il parametro in uscita consiste nel campo richiesto, il quale viene restituito in AX/EAX,
a seconda dell'ampiezza; se in BX si passa l'identificatore VI_VBEINFOBLPTR, allora
in EAX viene restituito un puntatore FAR alla struttura info_block.
Questa procedura verifica la presenza del supporto VESA per una determinata modalità
video; se tale supporto è presente, viene riempita una struttura interna mode_info di
tipo ModeInfoBlock.
Come parametro in ingresso si deve inserire in CX l'identificatore del modo video
richiesto; a tale proposito, si vedano le Figure 11.2 e 11.3.
I parametri in uscita vengono restituiti in AL, AH, EBX e ECX; il
loro significato è identico a quello già descritto per la procedura vesa_getcontrollerinfo.
Questa procedura restituisce i vari campi della struttura mode_info riempita dalla
procedura vesa_getvbemodeinfo; ovviamente, tali campi hanno senso solo se il
supporto VESA alla modalità video richiesta è presente.
Come parametro in ingresso si deve inserire in BX l'identificatore del campo richiesto;
a tale proposito, si veda l'include file della libreria VESALIB. Anche in questo caso si
può notare che gli identificatori non sono altro che gli offset dei vari campi della struttura
mode_info; se il programmatore ne ha la necessità, può aggiungere nell'include file anche
gli identificatori mancanti, che devono rappresentare in ogni caso gli offset dei relativi campi.
Il parametro in uscita consiste nel campo richiesto, il quale viene restituito in AL/AX/EAX,
a seconda dell'ampiezza; se in BX si passa l'identificatore MI_MODEINFOBLPTR, allora
in EAX viene restituito un puntatore FAR alla struttura mode_info.
Questa procedura tenta di attivare il modo video VESA richiesto; se tale attivazione
avviene correttamente, vengono effettuate una serie di inizializzazioni che, per le modalità
grafiche, comprendono vari parametri per il bank switching, il puntatore al vettore dei
caratteri nella ROM BIOS, etc. Prima di attivare il modo video richiesto, vengono
effettuati tutti i necessari controlli; in particolare, viene anche testato il bit in posizione
0 del campo ModeAttributes (supporto hardware del modo video richiesto).
Come parametro in ingresso si deve inserire in BX l'identificatore del modo video
richiesto; a tale proposito, si vedano le Figure 11.2 e 11.3.
I parametri in uscita vengono restituiti in AL, AH, EBX e ECX; il
loro significato è identico a quello già descritto per la procedura vesa_getcontrollerinfo.
Questa procedura riporta lo schermo in modalità video testo 80x25 celle a 16
colori; ovviamente, essa deve essere usata per uscire da una modalità grafica precedentemente
attivata con vesa_setvbemode.
Non è previsto alcun parametro in ingresso.
Non è previsto alcun parametro in uscita.
Questa procedura deve essere utilizzata solo nelle modalità grafiche a 256 colori, i
cui codici sono 0101h, 0103h, 0105h e 0107h (Figura 11.2); il
suo scopo è visualizzare un pixel in una determinata posizione (x, y), con il colore
specificato. Le coordinate del pixel devono essere espresse come numeri interi con segno a
16 bit, riferiti ad un sistema di coordinate cartesiane la cui origine è nel centro dello
schermo (vedere più avanti); come sappiamo, si tratta di numeri compresi tra -32768 e
+32767.
I parametri in ingresso sono BX (ascissa del pixel), CX (ordinata del pixel) e
DL (colore del pixel); il colore è un numero compreso tra 0 e 255 che, come
sappiamo, rappresenta un indice nella tavolozza dei colori.
Non è previsto alcun parametro in uscita.
Questa procedura deve essere utilizzata solo nelle modalità grafiche a 256 colori, i
cui codici sono 0101h, 0103h, 0105h e 0107h (Figura 11.2); il
suo scopo è leggere il colore del pixel presente in una determinata posizione (x, y). Per
le coordinate del pixel valgono tutte le considerazioni esposte in precedenza per la procedura
vesa_putpixel256.
I parametri in ingresso sono BX (ascissa del pixel) e CX (ordinata del pixel).
Il parametro in uscita viene restituito in AL e rappresenta il colore del pixel (indice
nella tavolozza dei colori).
Questa procedura deve essere utilizzata solo nelle modalità grafiche a 256 colori, i
cui codici sono 0101h, 0103h, 0105h e 0107h (Figura 11.2); il
suo scopo è visualizzare un segmento orizzontale compreso tra gli estremi P1(x1, y) e
P2(x2, y), con il colore specificato. Per le coordinate valgono tutte le considerazioni
esposte in precedenza per la procedura vesa_putpixel256.
I parametri in ingresso sono AX (ascissa iniziale x1), BX (ascissa finale
x2), CX (ordinata fissa y) e DL (colore del segmento); l'ascissa
x1 può essere maggiore o minore di x2.
Non è previsto alcun parametro in uscita.
Questa procedura deve essere utilizzata solo nelle modalità grafiche a 256 colori, i
cui codici sono 0101h, 0103h, 0105h e 0107h (Figura 11.2); il
suo scopo è visualizzare un segmento verticale compreso tra gli estremi P1(x, y1) e
P2(x, y2), con il colore specificato. Per le coordinate valgono tutte le considerazioni
esposte in precedenza per la procedura vesa_putpixel256.
I parametri in ingresso sono AX (ascissa fissa x), BX (ordinata iniziale
y1), CX (ordinata finale y2) e DL (colore del segmento); l'ordinata
y1 può essere maggiore o minore di y2.
Non è previsto alcun parametro in uscita.
Questa procedura deve essere utilizzata solo nelle modalità grafiche a 256 colori, i
cui codici sono 0101h, 0103h, 0105h e 0107h (Figura 11.2); il suo
scopo è visualizzare una stringa C a partire da una determinata posizione (x, y),
con il colore specificato. Per le coordinate valgono tutte le considerazioni esposte in precedenza
per la procedura vesa_putpixel256.
I parametri in ingresso sono BX (ascissa iniziale), CX (ordinata iniziale),
DL (colore della stringa) e DS:SI (puntatore FAR alla stringa C); le
coordinate iniziali indicano il punto in alto a sinistra da cui parte la visualizzazione della
stringa.
Non è previsto alcun parametro in uscita.
Questa procedura deve essere utilizzata solo nelle modalità grafiche a 256 colori, i
cui codici sono 0101h, 0103h, 0105h e 0107h (Figura 11.2); il
suo scopo è visualizzare un sistema di assi cartesiani Oxy nel piano, la cui origine è
posizionata al centro del monitor.
Non è previsto alcun parametro in ingresso.
Non è previsto alcun parametro in uscita.
Questa procedura deve essere utilizzata solo nelle modalità grafiche a 256 colori, i
cui codici sono 0101h, 0103h, 0105h e 0107h (Figura 11.2); il
suo scopo è impostare una nuova tavolozza da 256 colori.
I parametri in ingresso sono CX (numero elementi da aggiornare), DX (indice primo
elemento), ES:DI (puntatore alla nuova tavolozza).
I parametri in uscita vengono restituiti in AL, AH, EBX e ECX; il
loro significato è identico a quello già descritto per la procedura vesa_getcontrollerinfo.
Questa procedura deve essere utilizzata solo nelle modalità grafiche a 256 colori, i
cui codici sono 0101h, 0103h, 0105h e 0107h (Figura 11.2); il
suo scopo è leggere la tavolozza corrente da 256 colori.
I parametri in ingresso sono CX (numero elementi da leggere), DX (indice primo
elemento), ES:DI (puntatore all'area di memoria che verrà riempita con la tavolozza).
I parametri in uscita vengono restituiti in AL, AH, EBX e ECX; il
loro significato è identico a quello già descritto per la procedura vesa_getcontrollerinfo.
11.8.1 Dettagli sulla libreria VESALIB
Analizziamo alcuni importanti dettagli sulle procedure grafiche della libreria VESALIB,
destinate alle modalità video a 256 colori; eventualmente, il programmatore può anche
aggiungere analoghe procedure per il supporto delle modalità video High Color e True
Color.
Come abbiamo visto in precedenza, per velocizzare il calcolo dell'offset assoluto di un pixel
(pixel_address), conviene eliminare la moltiplicazione y*XResolution, sostituendola
con degli shift a sinistra; a tale proposito, si può notare quanto segue:
- Modo 0101h (640x480): XResolution = 640 =
27 + 28 + 28
- Modo 0103h (800x600): XResolution = 800 =
25 + 28 + 29
- Modo 0105h (1024x768): XResolution = 1024 =
28 + 28 + 29
- Modo 0107h (1280x1024): XResolution = 1280 =
28 + 29 + 29
Avremo quindi, ad esempio:
y * 800 = y * (25 + 28 + 29) = (y * 25) + (y * 28) + (y * 29)
Di conseguenza:
y * 800 = (SHL y, 5) + (SHL y, 8) + (SHL y, 9)
Analogamente, la divisione pixel_address/WinGranularity, per determinare il banco di
memoria in cui leggere o scrivere, può essere convertita in uno shift verso destra di
pixel_address; non è casuale il fatto che WinGranularity sia sempre esprimibile
come potenza intera di 2.
Tutti i parametri necessari per effettuare questi calcoli, vengono inizializzati dalla
procedura vesa_setvbemode.
Le procedure grafiche della libreria VESALIB lavorano con coordinate dei pixel riferite
ad un sistema di assi cartesiani Oxy, la cui origine O si trova al centro dello
schermo; tali coordinate devono essere espresse da numeri interi con segno a 16 bit,
compresi tra -32768 e +32767.
La libreria VESALIB provvede a convertire queste coordinate "relative" in coordinate
"assolute", riferite ad un sistema di assi cartesiani O1x1y1, la cui origine O1
si trova nell'angolo in alto a sinistra dello schermo e il cui asse y1 è orientato verso
il basso; la Figura 11.22 illustra tutti i dettagli.
Il sistema di assi cartesiani O1x1y1 tiene conto del fatto che lo schermo grafico può
essere immaginato come una matrice di m colonne per n righe di pixel; dato un
pixel in posizione "assoluta" (x1,y1), si può notare che x1 è l'indice di colonna
compreso tra 0 e m-1, a partire da sinistra, mentre y1 è l'indice di riga
compreso tra 0 e n-1, a partire dall'alto.
La conversione di coordinate da Oxy a O1x1y1 per un punto P(x,y) (Figura
11.22) è semplicissima; infatti, se Ox e Oy sono le coordinate di O
rispetto a O1x1y1, si ha:
Come è stato appena spiegato, il programmatore non deve preoccuparsi di questi aspetti in
quanto tutti i calcoli vengono effettuati dalla libreria VESALIB.
La visualizzazione delle stringhe avviene con il metodo già descritto nel precedente capitolo;
a tale proposito, in fase di attivazione di una modalità video grafica, viene predisposto un
puntatore FAR ad un vettore di bitmap dei caratteri da 8x16 pixel, presente
nella ROM BIOS del computer. Si tenga presente che il vettore contiene solo le bitmap
relative ai primi 128 simboli del set di codici
ASCII; se si prova quindi a visualizzare
una stringa contenente vocali accentate o simboli speciali internazionali, si possono ottenere
risultati privi di senso.
Ogni bitmap occupa 16 byte (16 righe da 8 bit ciascuna); di conseguenza,
l'offset nel vettore di un carattere c da visualizzare sarà dato da:
ASCII(c) * 16 = ASCII(c) * 24 = SHL ASCII(c), 4
11.8.2 Test della libreria VESALIB
Per illustrare il funzionamento della libreria VESALIB, scriviamo un semplice
programma che effettua tutti i necessari controlli, mostra una serie di informazioni e
attiva una modalità grafica a 256 colori; lo stesso programma visualizza poi
il sistema di assi cartesiani Oxy, un pixel e alcune stringhe.
La Figura 11.23 mostra il listato del programma VLIBTEST.ASM.
La Figura 11.24 mostra l'output di VLIBTEST.EXE in modalità video 640x480 a
256 colori.
Il programma è interamente parametrizzato, per cui può essere eseguito con tutte le modalità
video grafiche a 256 colori, identificate dai codici 0101h, 0103h,
0105h e 0107h; a tale proposito, si deve modificare la costante simbolica
VESA_MODE in VLIBTEST.ASM.
Bibliografia
VESASP12.TXT - Super VGA BIOS Extension - Standard #VS911022 - VBE Version 1.2
(disponibile nella sezione Documentazione tecnica di supporto al corso assembly dell’
Area Downloads di questo sito - vesasp12.zip)
VBE3.PDF - VESA BIOS EXTENSION - Core Functions Standard
(disponibile nella sezione Documentazione tecnica di supporto al corso assembly dell’
Area Downloads di questo sito - vbe3.zip)