Obsah
1. Grafická karta EGA: pouze mírný pokrok v mezích zákona (2. část)
2. Optimalizace podprogramu pro výběr bitových rovin pro zápis pixelů
4. Podprogram pro vykreslení pixelu s libovolnou barvou vybranou z barvové palety
5. Úplný zdrojový kód dnešního druhého demonstračního příkladu: úsečky v režimu 320×200
6. Úprava algoritmu pro vykreslení pixelů v režimu s 640 sloupci na obrazovém řádku
7. Úplný zdrojový kód dnešního třetího demonstračního příkladu: úsečky v režimu 640×350
8. Standardní znaková sada karty EGA
9. Získání tvarů znaků z GNU Unifontu
10. Programová modifikace znakové sady
11. Úplný zdrojový kód dnešního čtvrtého demonstračního příkladu: použití vlastní znakové sady
12. Výběr barev do barvové palety
13. Chování grafického režimu 320×200 pixelů při modifikaci barvové palety
14. Změna barvové palety a grafický režim s rozlišením 640×350 pixelů
15. Změna všech barev v paletě s využitím programové smyčky
16. Úplný zdrojový kód příkladu pro změnu všech barev v paletě
17. Změna barev v paletě jediným voláním služby BIOSu
18. Poslední demonstrační příklad: změna všech barev (včetně okraje) službou BIOSu
19. Repositář s demonstračními příklady
1. Grafická karta EGA: pouze mírný pokrok v mezích zákona (2. část)
Na předchozí článek o grafické kartě EGA dnes navážeme. Nejprve si řekneme, jak lze zjednodušit a urychlit výběr bitových rovin při vykreslování grafiky s barvami. S touto problematikou souvisí i náš oblíbený problém – jak efektivně vykreslit jednotlivé pixely, tj. základní grafické primitivum. Dále se seznámíme s tím, jakým způsobem lze využít vlastní znakovou sadu v textových režimech, což je vlastně na platformě PC novinka, protože žádná z předchozích grafických karet (MDA, CGA, Hercules) tuto možnost nenabízely, jelikož bitové mapy znaků byly uloženy v ROM (většinou v EPROM, ovšem programovatelné mimo PC)*. A nezapomeneme ani na problematiku výběru barev do barvové palety, což je oblast, v níž se opět ukazují určitá omezení karty EGA, která vycházejí ze snahy o zpětnou kompatibilitu se staršími monitory určenými pro původní kartu CGA.
Obrázek 1: Známá hra Xenon 2: The megablast v šestnáctibarevném grafickém režimu karty EGA.
2. Optimalizace podprogramu pro výběr bitových rovin pro zápis pixelů
Vraťme se na chvíli k předchozímu článku, v němž jsme si řekli, jakým způsobem je organizovaná video paměť karty EGA v nových grafických režimech. Video RAM je rozdělena do bitových rovin (bitplanes) a této technologii se z tohoto důvodu taktéž říká planární organizace nebo planární grafika. Data pixelu jsou zde konkrétně rozdělena do dvou či čtyř bitových rovin, přičemž v každé rovině je uložen jediný bit s kusem barvové informace o pixelu.
Pro výběr, do které bitové roviny nebo bitových rovin (libovolná kombinace) se má provést zápis, slouží následující podprogram, který zapíše požadovanou masku do jednoho z řídicích registrů karty EGA:
select_bitplane: mov dx, ega_controller push ax mov al, bitplane_selector out dx, al ; vyber registru sekvenceru pop ax inc dx out dx, al ; zapis masky bitovych rovin ret ; hotovo
Tento podprogram je ovšem možné zkrátit, přičemž využijeme (pro nás novou) instrukci XCHG (exchange), která dokáže prohodit obsah zdrojového a cílového registru nebo registru a paměti (bajt, nebo slovo). Výsledek se obejde bez nutnosti uchování registru AX na zásobníku a současně je ukázáno, že instrukce OUT DX, AX dokáže zapsat na dva osmibitové I/O porty, které leží za sebou. V tomto případě tedy na port s výběrem registru a datový port:
select_bitplane: mov dx, ega_controller mov ah, bitplane_selector xchg ah, al out dx, ax ; vyber registru sekvenceru ; a zapis masky bitovych rovin ret ; hotovo
Obrázek 2: Další screenshot ze hry Xenon 2: The megablast běžící v grafickém režimu karty EGA.
3. Úplný zdrojový kód dnešního prvního demonstračního příkladu: vykreslení barevných pruhů s využitím 16 barev
Opět se podívejme, jak je v tomto seriálu zvykem, na úplný zdrojový kód příkladu, který po svém překladu assemblerem NASM a spuštění v emulátoru DOSu (nebo na původním HW) vykreslí následující obrázek:
Obrázek 3: Barevné pruhy vykreslené dnešním prvním demonstračním příkladem.
Kód tohoto příkladu vypadá následovně:
; Graficky rezim karty EGA s rozlisenim 320x200 pixelu. ; Zmena barvovych rovin, do kterych se zapisuje. ; ; preklad pomoci: ; nasm -f bin -o ega.com ega_gfx_mode_bitplanes_2.asm ; ; nebo pouze: ; nasm -o ega.com ega_gfx_mode_bitplanes_2.asm ;----------------------------------------------------------------------------- ; registry karty EGA/VGA ega_controller equ 0x3c4 bitplane_selector equ 0x02 ; ukonceni procesu a navrat do DOSu %macro exit 0 mov ah, 0x4c int 0x21 %endmacro ; vyprazdneni bufferu klavesnice a cekani na klavesu %macro wait_key 0 xor ax, ax int 0x16 %endmacro ; nastaveni grafickeho rezimu %macro gfx_mode 1 mov ah, 0 mov al, %1 int 0x10 %endmacro ;----------------------------------------------------------------------------- org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 436) start: gfx_mode 0x0d ; nastaveni rezimu 320x200 se sestnacti barvami mov ax, 0xa000 ; video RAM v textovem rezimu mov es, ax xor di, di ; nyni ES:DI obsahuje adresu prvniho pixelu ve video RAM xor al, al ; maska bitovych rovin mov cl, 16 ; pocitadlo barevnych pruhu opak: call draw_block_into_bitplanes loop opak wait_key ; cekani na klavesu exit ; navrat do DOSu select_bitplane: mov dx, ega_controller mov ah, bitplane_selector xchg ah, al out dx, ax ; vyber registru sekvenceru ; a zapis masky bitovych rovin ret ; hotovo draw_block_into_bitplanes: push ax push cx call select_bitplane; maska bitovych rovin call draw_block add di, 320*3/8 ; posun o nekolik radku nize pop cx pop ax inc al ; zmena masky ret ; hotovo draw_block: mov cx, 320*9/8 ; pocet zapisovanych pixelu (ovsem pocitano v bajtech) mov al, 0xff ; kod pixelu rep stosb ret
4. Podprogram pro vykreslení pixelu s libovolnou barvou vybranou z barvové palety
V tento okamžik již máme k dispozici všechny informace potřebné k tomu, abychom dokázali v libovolném novém grafickém režimu karty EGA vykreslit jednotlivé pixely:
- Díky lineárnímu adresování v rámci jedné bitové roviny umíme spočítat adresu pixelu
- Dokážeme nastavit bitové roviny na základě požadované barvy pixelu
- Umíme spočítat masku pixelu v rámci osmice pixelů (již jsme si otestovali na CGA i Herculesu)
Podprogram určený pro vykreslení pixelu akceptuje 16bitové (což je nyní již nutnost) souřadnice pixelu předávané v pracovních registrech AX a BX a taktéž barvu pixelu 0–15 předanou v pracovním registru CL:
; Vykresleni pixelu ; AX - x-ova souradnice ; BX - y-ova souradnice (staci len BL) ; CL - barva putpixel: ... ... ... ret
Nejdříve na základě obsahu registru CL (barva pixelu) povolíme zápis do příslušných barvových rovin (se zachováním x-ové souřadnice pixelu předávané v registru AX):
push ax mov al, cl ; vyber bitove roviny nebo bitovych rovin call select_bitplane pop ax
Nastavíme segmentový registr ES na segment video RAM (již dobře známe):
mov dx, 0xa000 ; zacatek stranky video RAM mov es, dx ; nyni obsahuje ES stranku video RAM
Do CL se uloží informace použité později pro maskování:
mov cl, al and cl, 7 ; pouze spodni 3 bity x-ove souradnice
V dalším kroku, a to bez operace násobení, vypočteme adresu pixelu součtem horizontálního posunu (v rámci jednoho obrazového řádku) a posunu vertikálního (vynásobení souřadnice y konstantou 40):
shr ax, 1 shr ax, 1 shr ax, 1 ; x/8 mov di, ax ; horizontalni posun pocitany v bajtech mov ax, bx ; y-ova souradnice shl ax, 1 ; y*2 shl ax, 1 ; y*4 shl ax, 1 ; y*8 add di, ax ; pricist cast y-oveho posunu shl ax, 1 ; y*16 shl ax, 1 ; y*32 add di, ax ; pricist zbytek y-oveho posunu ; -> y*8 + y*32 = y*40
Samotný zápis je nyní poněkud paradoxně snadnější, než tomu bylo u karet CGA a Hercules, protože nemusíme brát v úvahu prokládání obrazových řádků:
mov al, 0x80 ; vypocitat masku pixelu shr al, cl or [es:di], al ; vlastni vykresleni pixelu
Pokud ve smyčce vykreslíme úsečky z pixelů, dostaneme tento výsledek:
Obrázek 4: Barevné úsečky vykreslené z jednotlivých pixelů.
5. Úplný zdrojový kód dnešního druhého demonstračního příkladu: úsečky v režimu 320×200
Dnešní druhý demonstrační příklad vypadá následovně:
; Graficky rezim karty EGA s rozlisenim 320x200 pixelu. ; Zmena barvovych rovin, do kterych se zapisuje. ; Vykresleni barevnych usecek. ; ; preklad pomoci: ; nasm -f bin -o ega.com ega_320x200_putpixel.asm ; ; nebo pouze: ; nasm -o ega.com ega_320x200_putpixel.asm ;----------------------------------------------------------------------------- ; registry karty EGA/VGA ega_controller equ 0x3c4 bitplane_selector equ 0x02 ; ukonceni procesu a navrat do DOSu %macro exit 0 mov ah, 0x4c int 0x21 %endmacro ; vyprazdneni bufferu klavesnice a cekani na klavesu %macro wait_key 0 xor ax, ax int 0x16 %endmacro ; nastaveni grafickeho rezimu %macro gfx_mode 1 mov ah, 0 mov al, %1 int 0x10 %endmacro ;----------------------------------------------------------------------------- org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 436) start: gfx_mode 0x0d ; nastaveni rezimu 320x200 se sestnacti barvami mov ax, 0xa000 ; video RAM v textovem rezimu mov es, ax xor di, di ; nyni ES:DI obsahuje adresu prvniho pixelu ve video RAM mov ax, 0 opak: mov bx, ax ; y-ová souřadnice push ax mov cl, 10 ; barva call putpixel ; vykreslení pixelu pop ax push ax mov cl, 11 ; barva add ax, 10 ; horizontalni posun usecky call putpixel ; vykreslení pixelu pop ax push ax mov cl, 12 ; barva add ax, 20 ; horizontalni posun usecky call putpixel ; vykreslení pixelu pop ax inc ax ; pusun x+=1, y+=1 cmp ax, 200 ; hranice obrazovky? jne opak ; ne-opakujeme wait_key ; cekani na klavesu exit ; navrat do DOSu select_bitplane: mov dx, ega_controller mov ah, bitplane_selector xchg ah, al out dx, ax ; vyber registru sekvenceru ; a zapis masky bitovych rovin ret ; hotovo ; Vykresleni pixelu ; AX - x-ova souradnice ; BX - y-ova souradnice (staci len BL) ; CL - barva putpixel: push ax mov al, cl ; vyber bitove roviny nebo bitovych rovin call select_bitplane pop ax mov dx, 0xa000 ; zacatek stranky video RAM mov es, dx ; nyni obsahuje ES stranku video RAM mov cl, al and cl, 7 ; pouze spodni 3 bity x-ove souradnice shr ax, 1 shr ax, 1 shr ax, 1 ; x/8 mov di, ax ; horizontalni posun pocitany v bajtech mov ax, bx ; y-ova souradnice shl ax, 1 ; y*2 shl ax, 1 ; y*4 shl ax, 1 ; y*8 add di, ax ; pricist cast y-oveho posunu shl ax, 1 ; y*16 shl ax, 1 ; y*32 add di, ax ; pricist zbytek y-oveho posunu ; -> y*8 + y*32 = y*40 mov al, 0x80 ; vypocitat masku pixelu shr al, cl or [es:di], al ; vlastni vykresleni pixelu ret
6. Úprava algoritmu pro vykreslení pixelů v režimu s 640 sloupci na obrazovém řádku
V případě, že budeme chtít upravit algoritmus pro vykreslení pixelů takovým způsobem, aby pracoval korektně i v grafických režimech s 640 sloupci (640×200 a 640×350), musíme provést jen nepatrnou úpravu – namísto násobení y-ové souřadnice konstantou 40 provedeme násobení konstantou 80, protože 640/8=80 (bajtů).
Připomeňme si, že původní kód pro násobení vypadal takto:
mov ax, bx ; y-ova souradnice shl ax, 1 ; y*2 shl ax, 1 ; y*4 shl ax, 1 ; y*8 add di, ax ; pricist cast y-oveho posunu shl ax, 1 ; y*16 shl ax, 1 ; y*32 add di, ax ; pricist zbytek y-oveho posunu ; -> y*8 + y*32 = y*40
Úprava pro režim 640×200/350 je až triviálně snadná, protože přidáme jeden bitový posun doleva:
mov ax, bx ; y-ova souradnice shl ax, 1 ; y*2 shl ax, 1 ; y*4 shl ax, 1 ; y*8 shl ax, 1 ; y*16 add di, ax ; pricist cast y-oveho posunu shl ax, 1 ; y*32 shl ax, 1 ; y*64 add di, ax ; pricist zbytek y-oveho posunu ; -> y*16 + y*64 = y*80
Výsledek:
Obrázek 5: Barevné úsečky vykreslené z jednotlivých pixelů.
7. Úplný zdrojový kód dnešního třetího demonstračního příkladu: úsečky v režimu 640×350
Výsledný zdrojový kód se až na výše zmíněnou instrukci pro bitový posun, nijak zásadně nezmění, pouze nastavíme odlišný grafický režim a taktéž zvýšíme počet pixelů vykreslených v jedné úsečce z 200 na 350:
; Graficky rezim karty EGA s rozlisenim 640x350 pixelu. ; Zmena barvovych rovin, do kterych se zapisuje. ; Vykresleni barevnych usecek. ; ; preklad pomoci: ; nasm -f bin -o ega.com ega_640x350_putpixel.asm ; ; nebo pouze: ; nasm -o ega.com ega_640x350_putpixel.asm ;----------------------------------------------------------------------------- ; registry karty EGA/VGA ega_controller equ 0x3c4 bitplane_selector equ 0x02 ; ukonceni procesu a navrat do DOSu %macro exit 0 mov ah, 0x4c int 0x21 %endmacro ; vyprazdneni bufferu klavesnice a cekani na klavesu %macro wait_key 0 xor ax, ax int 0x16 %endmacro ; nastaveni grafickeho rezimu %macro gfx_mode 1 mov ah, 0 mov al, %1 int 0x10 %endmacro ;----------------------------------------------------------------------------- org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 436) start: gfx_mode 0x10 ; nastaveni rezimu 640x350 se sestnacti barvami mov ax, 0xa000 ; video RAM v textovem rezimu mov es, ax xor di, di ; nyni ES:DI obsahuje adresu prvniho pixelu ve video RAM mov ax, 0 opak: mov bx, ax ; y-ová souřadnice push ax mov cl, 10 ; barva call putpixel ; vykreslení pixelu pop ax push ax mov cl, 11 ; barva add ax, 10 ; horizontalni posun usecky call putpixel ; vykreslení pixelu pop ax push ax mov cl, 12 ; barva add ax, 20 ; horizontalni posun usecky call putpixel ; vykreslení pixelu pop ax inc ax ; pusun x+=1, y+=1 cmp ax, 350 ; hranice obrazovky? jne opak ; ne-opakujeme wait_key ; cekani na klavesu exit ; navrat do DOSu select_bitplane: mov dx, ega_controller mov ah, bitplane_selector xchg ah, al out dx, ax ; vyber registru sekvenceru ; a zapis masky bitovych rovin ret ; hotovo ; Vykresleni pixelu ; AX - x-ova souradnice ; BX - y-ova souradnice (staci len BL) putpixel: push ax mov al, cl ; vyber bitove roviny nebo bitovych rovin call select_bitplane pop ax mov dx, 0xa000 ; zacatek stranky video RAM mov es, dx ; nyni obsahuje ES stranku video RAM mov cl, al and cl, 7 ; pouze spodni 3 bity x-ove souradnice shr ax, 1 shr ax, 1 shr ax, 1 ; x/8 mov di, ax ; horizontalni posun pocitany v bajtech mov ax, bx ; y-ova souradnice shl ax, 1 ; y*2 shl ax, 1 ; y*4 shl ax, 1 ; y*8 shl ax, 1 ; y*16 add di, ax ; pricist cast y-oveho posunu shl ax, 1 ; y*32 shl ax, 1 ; y*64 add di, ax ; pricist zbytek y-oveho posunu ; -> y*16 + y*64 = y*80 mov al, 0x80 ; vypocitat masku pixelu shr al, cl or [es:di], al ; vlastni vykresleni pixelu ret
8. Standardní znaková sada karty EGA
Již několikrát jsme si řekli, že původní karty pro PC, tedy jak MDA, tak i CGA (ale i Hercules), měly znakovou sadu používanou v textových režimech uschovánu v paměti ROM (většinou EPROM, ať již s okénkem nebo bez okénka) a tudíž nebylo zcela snadné ji měnit. A při výměně, například při potřebě použití českých nabodeníček, se pochopitelně přestaly zobrazovat původní znaky (různé rámečky atd.). Řešení přinesla právě až grafická karta EGA, která umožňovala kromě ROM sady (na originální EGA uložena od adresy 0×2230, ale na to se nedá spolehnout), uložení vlastních sad znaků přímo ve video RAM. Interně byla video RAM i v textových režimech rozdělena na bitové roviny: znaky, atributy a bitmapy fontů, to však při praktickém použití EGA můžeme do značné míry ignorovat a tvářit se, že textové režimy mají stejný formát, jako na MDA, CGA i Herculesu.
Jak vlastně vypadá standardní znaková sada EGA? Původní znaky vytvořila IBM a některé klony EGA mohou používat nepatrně odlišné znaky, ovšem základní znaky z ASCII by měly vypadat následovně:
Obrázek 6: Základní ASCII znaky zobrazené kartou EGA (resp. v tomto konkrétním případě emulátorem DOSBox).
Tento obrázek byl získán zcela jednoduchým programem:
; Textovy rezim karty EGA s rozlisenim 80x25 znaku. ; Vypis vsech standardnich ASCII znaku. ; ; preklad pomoci: ; nasm -f bin -o ega.com ega_standard_font.asm ; ; nebo pouze: ; nasm -o ega.com ega_standard_font.asm ;----------------------------------------------------------------------------- ; ukonceni procesu a navrat do DOSu %macro exit 0 mov ah, 0x4c int 0x21 %endmacro ; vyprazdneni bufferu klavesnice a cekani na klavesu %macro wait_key 0 xor ax, ax int 0x16 %endmacro ; nastaveni grafickeho rezimu %macro gfx_mode 1 mov ah, 0 mov al, %1 int 0x10 %endmacro ;----------------------------------------------------------------------------- org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 256) start: gfx_mode 3 ; nastaveni standardniho textoveho rezimu 80x25 znaku mov ax, 0xb800 ; video RAM v textovem rezimu mov es, ax mov di, 0 ; nyni ES:DI obsahuje adresu prvniho znaku ve video RAM mov cx, 95 ; pocet zapisovanych znaku mov al, 32 ; kod zapisovaneho znaku opak: stosb ; zapis znaku inc al ; dalsi znak inc di ; preskocit atribut loop opak ; opakujeme CX-krat wait_key ; cekani na klavesu exit ; navrat do DOSu
9. Získání tvarů znaků z GNU Unifontu
Zkusme si nyní načíst a zobrazit nějakou alternativní znakovou sadu. Vzhledem k tomu, že mnoho původních fontů má copyright, použijeme GNU Unifont. Ten obsahuje definice znaků v maskách 16×16 pixelů, ovšem základní ASCII znaky mají masku zmenšenou na 8×16 pixelů. A to je přesně ten formát, který potřebujeme. Postačuje si stáhnout .hex soubor s celou znakovou sadou a získat z ní 95 znaků ze standardní ASCII (teoreticky se jedná o 96 znaků, ovšem znak DEL již má odlišnou masku).
Soubor s 95 znaky ASCII vypadá takto:
0020:00000000000000000000000000000000 0021:00000000080808080808080008080000 0022:00002222222200000000000000000000 0023:000000001212127E24247E4848480000 0024:00000000083E4948380E09493E080000 0025:00000000314A4A340808162929460000 0026:000000001C2222141829454246390000 0027:00000808080800000000000000000000 0028:00000004080810101010101008080400 0029:00000020101008080808080810102000 002A:00000000000008492A1C2A4908000000 002B:0000000000000808087F080808000000 002C:00000000000000000000000018080810 002D:0000000000000000003C000000000000 002E:00000000000000000000000018180000 002F:00000000020204080810102040400000 0030:00000000182442464A52624224180000 0031:000000000818280808080808083E0000 0032:000000003C4242020C102040407E0000 0033:000000003C4242021C020242423C0000 0034:00000000040C142444447E0404040000 0035:000000007E4040407C020202423C0000 0036:000000001C2040407C424242423C0000 0037:000000007E0202040404080808080000 0038:000000003C4242423C424242423C0000 0039:000000003C4242423E02020204380000 003A:00000000000018180000001818000000 003B:00000000000018180000001808081000 003C:00000000000204081020100804020000 003D:000000000000007E0000007E00000000 003E:00000000004020100804081020400000 003F:000000003C4242020408080008080000 0040:000000001C224A565252524E201E0000 0041:0000000018242442427E424242420000 0042:000000007C4242427C424242427C0000 0043:000000003C42424040404042423C0000 0044:00000000784442424242424244780000 0045:000000007E4040407C404040407E0000 0046:000000007E4040407C40404040400000 0047:000000003C424240404E4242463A0000 0048:00000000424242427E42424242420000 0049:000000003E08080808080808083E0000 004A:000000001F0404040404044444380000 004B:00000000424448506060504844420000 004C:000000004040404040404040407E0000 004D:00000000424266665A5A424242420000 004E:0000000042626252524A4A4646420000 004F:000000003C42424242424242423C0000 0050:000000007C4242427C40404040400000 0051:000000003C4242424242425A663C0300 0052:000000007C4242427C48444442420000 0053:000000003C424240300C0242423C0000 0054:000000007F0808080808080808080000 0055:000000004242424242424242423C0000 0056:00000000414141222222141408080000 0057:00000000424242425A5A666642420000 0058:00000000424224241818242442420000 0059:00000000414122221408080808080000 005A:000000007E02020408102040407E0000 005B:0000000E080808080808080808080E00 005C:00000000404020101008080402020000 005D:00000070101010101010101010107000 005E:00001824420000000000000000000000 005F:00000000000000000000000000007F00 0060:00201008000000000000000000000000 0061:0000000000003C42023E4242463A0000 0062:0000004040405C6242424242625C0000 0063:0000000000003C4240404040423C0000 0064:0000000202023A4642424242463A0000 0065:0000000000003C42427E4040423C0000 0066:0000000C1010107C1010101010100000 0067:0000000000023A44444438203C42423C 0068:0000004040405C624242424242420000 0069:000000080800180808080808083E0000 006A:0000000404000C040404040404044830 006B:00000040404044485060504844420000 006C:000000180808080808080808083E0000 006D:00000000000076494949494949490000 006E:0000000000005C624242424242420000 006F:0000000000003C4242424242423C0000 0070:0000000000005C6242424242625C4040 0071:0000000000003A4642424242463A0202 0072:0000000000005C624240404040400000 0073:0000000000003C4240300C02423C0000 0074:000000001010107C10101010100C0000 0075:000000000000424242424242463A0000 0076:00000000000042424224242418180000 0077:00000000000041494949494949360000 0078:00000000000042422418182442420000 0079:0000000000004242424242261A02023C 007A:0000000000007E0204081020407E0000 007B:0000000C10100808102010080810100C 007C:00000808080808080808080808080808 007D:00000030080810100804081010080830 007E:00000031494600000000000000000000
Obsah tohoto souboru převedeme do binárního formátu tak, aby obsahoval skutečně pouze masky 8×16×95 (1520 bajtů). K tomu použijeme tento konvertor (který jsem napsal velmi rychle a neobsahuje žádné kontroly; není to produkční kód):
#include <stdio.h> #define INPUT_FILE "font.hex" #define OUTPUT_FILE "font.bin" #define CHARACTERS 95 #define CHAR_HEIGHT 16 int main(void) { FILE *fin; FILE *fout; int i; fin = fopen(INPUT_FILE, "r"); fout = fopen(OUTPUT_FILE, "wb"); for (i = 0; i < CHARACTERS; i++) { int c; int scanline; printf("%d\n", i); /* skip to ':' */ while ((c = fgetc(fin)) != ':') { /* read until hits ':' */ } for (scanline = 0; scanline < CHAR_HEIGHT; scanline++) { int b; fscanf(fin, "%02x", &b); fputc(b, fout); } /* skip endline */ while ((c = fgetc(fin)) != '\n') { /* read until hits '\n' */ } } fclose(fin); fclose(fout); }
Výsledný binární soubor font.bin využijeme v dalším demonstračním příkladu.
10. Programová modifikace znakové sady
Vyzkoušejme si nyní zobrazení fontu, který jsme získali právě popsanou konverzí. Binární soubor s fontem si přilinkujeme do výsledného souboru COM nám již známým způsobem:
font: incbin "font.bin"
Dále musíme v runtime získat adresu prvního bajtu tohoto binárního bloku a uložit ji do dvojice ES:BP, kde ji očekává BIOS. To je snadná operace:
mov ax, cs mov es, ax mov bp, font ; ES:BP obsabuje adresu fontu
Nyní nastavíme parametry, které služba BIOSu pro změnu fontu vyžaduje. Zejména je nutné vyplnit počet znaků, které se budou měnit (v našem případě 95 znaků, tj. vlastně celá základní ASCII), dále ASCII kód prvního měněného znaku (v našem případě mezera), index znakové sady 0..3 (můžeme přepínat mezi čtyřmi sadami, viz příští článek) a výška znaků. Tu nastavíme na 16 obrazových řádků, protože to odpovídá původnímu fontu a s konkrétním počtem řádků na obrazovce tato hodnota nemusí zcela souviset (je menší – jen 14 obrazových řádků):
mov cx, 95 ; pocet menenych znaku mov dx, 32 ; ASCII kod prvniho meneneho znaku mov bl, 0 ; index znakove sady mov bh, 16 ; vyska znaku
V posledním kroku nastavíme číslo služby a podslužby, kterou voláme a službu zavoláme:
mov ax, 0x1110 ; nacteni + nastaveni uzivatelskeho fontu int 0x10 ; provest operaci
Obrázek 7: Zobrazení modifikované znakové sady
11. Úplný zdrojový kód dnešního čtvrtého demonstračního příkladu: použití vlastní znakové sady
Opět se podívejme na to, jak by mohl vypadat příklad, který ve standardním textovém režimu použije nestandardní znakovou sadu. Od předchozího příkladu se odlišuje v tom, že volá funkci BIOSu (popsanou v desáté kapitole) pro inicializaci nestandardní znakové sady:
; Textovy rezim karty EGA s rozlisenim 80x25 znaku. ; Nastaveni vlastniho fontu. ; ; preklad pomoci: ; nasm -f bin -o ega.com ega_custom_font.asm ; ; nebo pouze: ; nasm -o ega.com ega_custom_font.asm ;----------------------------------------------------------------------------- ; ukonceni procesu a navrat do DOSu %macro exit 0 mov ah, 0x4c int 0x21 %endmacro ; vyprazdneni bufferu klavesnice a cekani na klavesu %macro wait_key 0 xor ax, ax int 0x16 %endmacro ; nastaveni grafickeho rezimu %macro gfx_mode 1 mov ah, 0 mov al, %1 int 0x10 %endmacro ;----------------------------------------------------------------------------- org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 256) start: gfx_mode 3 ; nastaveni standardniho textoveho rezimu 80x25 znaku mov ax, 0xb800 ; video RAM v textovem rezimu mov es, ax mov di, 0 ; nyni ES:DI obsahuje adresu prvniho znaku ve video RAM mov cx, 95 ; pocet zapisovanych znaku mov al, 32 ; kod zapisovaneho znaku opak: stosb ; zapis znaku inc al ; dalsi znak inc di ; preskocit atribut loop opak ; opakujeme CX-krat mov ax, cs mov es, ax mov bp, font ; ES:BP obsabuje adresu fontu mov ax, 0x1110 ; nacteni + nastaveni uzivatelskeho fontu mov cx, 95 ; pocet menenych znaku mov dx, 32 ; ASCII kod prvniho meneneho znaku mov bl, 0 ; index znakove sady mov bh, 16 ; vyska znaku int 0x10 ; provest operaci wait_key ; cekani na klavesu exit ; navrat do DOSu font: incbin "font.bin"
12. Výběr barev do barvové palety
Grafická karta EGA dokáže současně zobrazit šestnáct barev umístěných v barvové paletě (ovšem s omezeními, o kterých se zmíníme dále). Těchto šestnáct barev již není konstantních tak, jako tomu bylo u CGA, protože nabízená barvová škála obsahuje celkem 64 barvových odstínů. Jak se ale k tomuto číslu došlo? Pro každou barvovou složku RGB můžeme specifikovat její nulovou intenzitu, 1/3 intenzitu, 2/3 intenzitu nebo 100% intenzitu. To znamená, že pro každou barvovou složku existují čtyři možnosti a výsledkem kombinace barvových složek je 4×4×4=64 podporovaných barvových odstínů.
Barvový odstín se do barvové palety (se šestnácti místy) přidává službou BIOSu 0×10h (video BIOS). Konkrétní číslo služby a podslužby je 0×1000 (předáno v registru AX), index barvy 0..15 se předává v registru BL a v registru BH je barva určena bitovou maskou 0b00rgbRGB, kde malé písmeno značí 1/3 intenzitu (pokud je bit roven jedné) a velké písmeno 2/3 intenzitu (opět, pokud je roven jedné). Například tmavě šedá barva bude mít 1/3 intenzitu všech tří barvových složek a bude tedy určena hodnotou 0b00111000. Takovou barvu přidáme do barvové palety následovně:
mov ax, 0x1000 mov bl, 1 ; index barvy mov bh, 0b111000 ; tmave seda int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy
Pokusme se tedy změnit barvovou paletu tak, aby se zobrazily tyto pruhy:
Obrázek 8: Pruhy s barvami, které umístíme do barvové palety.
Barvová paleta by tedy měla obsahovat postupně tyto barvy:
0b000000 ; cerna (pozadi) 0b111000 ; tmave seda 0b000111 ; svetle seda 0b111111 ; bila 0b010000 ; tmave zelena 0b000010 ; stredne zelena 0b010010 ; svetle zelena 0b100000 ; tmave cervena 0b000100 ; stredne cervena 0b100100 ; svetle cervena 0b001000 ; tmave modra 0b000001 ; stredne modra 0b001001 ; svetle modra 0b110000 ; tmave hneda 0b000110 ; svetle hneda 0b110110 ; zluta
13. Chování grafického režimu 320×200 pixelů při modifikaci barvové palety
Pokud se ovšem pokusíme barvovou paletu nastavit na hodnoty vypsané výše, bude výsledek v některých případech dosti odlišný:
Obrázek 9: Barvová paleta v grafickém režimu 320×200 pixelů.
Co se změnilo? V režimu s 200 obrazovými řádky se předpokládá, že je připojen CGA monitor, který dokáže zobrazit osm základních barev ve dvou intenzitách, ovšem nedokáže již měnit intenzity individuálních barvových složek. To souvisí s již minule zmíněnými změnami v zapojení monitoru:
Pin | CGA | EGA |
---|---|---|
1 | GND | GND |
2 | GND | 2/3 Red |
3 | Red | 1/3 Red |
4 | Green | 1/3 Green |
5 | Blue | 1/3 Blue |
6 | Intenzita | 2/3 Green |
7 | Rezervováno | 2/3 Blue |
8 | H-sync | H-sync |
9 | V-sync | V-sync |
Navíc CGA monitor obsahuje speciální obvod pro zobrazení hnědé namísto tmavě žluté (což je ve skutečnosti stejná barva, ale odlišný odstín). I to můžeme na obrázku číslo 9 vidět. DOSBox toto chování plně emuluje. A jedná se o jeden z důvodů, proč většina her určených pro kartu CGA a rozlišení 320×200 pixelů, používá původní barvovou paletu CGA – v takovém případě bude vše bezpečné a nedojde k případnému „odpálení“ výstupu karty EGA (červená složka, která může být v CGA monitoru uzemněna).
Výše uvedený obrázek číslo 9 vznikne po překladu a spuštění následujícího příkladu (individuální nastavení barev posléze změníme, zde je pouzito proto, aby byl kód sice dlouhý, ale dobře pochopitelný):
; Graficky rezim karty EGA s rozlisenim 320x200 pixelu. ; Zmena barvovych rovin, do kterych se zapisuje. ; Konfigurace barvove palety. ; ; preklad pomoci: ; nasm -f bin -o ega.com ega_palette_1.asm ; ; nebo pouze: ; nasm -o ega.com ega_palette_1.asm ;----------------------------------------------------------------------------- ; registry karty EGA/VGA ega_controller equ 0x3c4 bitplane_selector equ 0x02 ; ukonceni procesu a navrat do DOSu %macro exit 0 mov ah, 0x4c int 0x21 %endmacro ; vyprazdneni bufferu klavesnice a cekani na klavesu %macro wait_key 0 xor ax, ax int 0x16 %endmacro ; nastaveni grafickeho rezimu %macro gfx_mode 1 mov ah, 0 mov al, %1 int 0x10 %endmacro ;----------------------------------------------------------------------------- org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 436) start: gfx_mode 0x0d ; nastaveni rezimu 320x200 se sestnacti barvami mov ax, 0xa000 ; video RAM v textovem rezimu mov es, ax xor di, di ; nyni ES:DI obsahuje adresu prvniho pixelu ve video RAM xor al, al ; maska bitovych rovin mov cl, 16 ; pocitadlo barevnych pruhu opak: call draw_block_into_bitplanes loop opak wait_key ; cekani na klavesu mov ax, 0x1000 mov bl, 1 ; index barvy mov bh, 0b111000 ; tmave seda int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 2 ; index barvy mov bh, 0b000111 ; svetle seda int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 3 ; index barvy mov bh, 0b111111 ; bila int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 4 ; index barvy mov bh, 0b010000 ; tmave zelena int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 5 ; index barvy mov bh, 0b000010 ; stredne zelena int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 6 ; index barvy mov bh, 0b010010 ; svetle zelena int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 7 ; index barvy mov bh, 0b100000 ; tmave cervena int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 8 ; index barvy mov bh, 0b000100 ; stredne cervena int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 9 ; index barvy mov bh, 0b100100 ; svetle cervena int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 10 ; index barvy mov bh, 0b001000 ; tmave modra int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 11 ; index barvy mov bh, 0b000001 ; stredne modra int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 12 ; index barvy mov bh, 0b001001 ; svetle modra int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 13 ; index barvy mov bh, 0b110000 ; tmave hneda int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 14 ; index barvy mov bh, 0b000110 ; svetle hneda int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 15 ; index barvy mov bh, 0b110110 ; zluta int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy wait_key ; cekani na klavesu exit ; navrat do DOSu select_bitplane: mov dx, ega_controller mov ah, bitplane_selector xchg ah, al out dx, ax ; vyber registru sekvenceru ; a zapis masky bitovych rovin ret ; hotovo draw_block_into_bitplanes: push ax push cx call select_bitplane; maska bitovych rovin call draw_block add di, 320*3/8 ; posun o nekolik radku nize pop cx pop ax inc al ; zmena masky ret ; hotovo draw_block: mov cx, 320*9/8 ; pocet zapisovanych pixelu (ovsem pocitano v bajtech) mov al, 0xff ; kod pixelu rep stosb ret
14. Změna barvové palety a grafický režim s rozlišením 640×350 pixelů
V případě, že naprosto stejnou barvovou paletu nastavíme v režimu 640×200, dostaneme stejný (špatný) výsledek jako u režimu 320×200, protože nezáleží na horizontálním rozlišení, ale na počtu obrazových řádků (200=kompatibilita s CGA, 350=EGA monitor). Takže se pokusme zobrazit si barvové pruhy s využitím vlastní palety v nejvyšší režimu karty EGA, tedy konkrétně v grafickém režimu s rozlišením 640×350 pixelů. Nyní bude výsledek plně odpovídat nastavené barvové paletě, protože není nutné dodržovat zpětnou kompatibilitu (CGA monitory nedokážou pracovat s 350 obrazovými řádky):
Obrázek 10: Barvová paleta v grafickém režimu 640×350 pixelů.
A pro jistotu si zopakujme, tak bude tento příklad vypadat:
; Graficky rezim karty EGA s rozlisenim 640x350 pixelu. ; Zmena barvovych rovin, do kterych se zapisuje. ; Konfigurace barvove palety. ; ; preklad pomoci: ; nasm -f bin -o ega.com ega_palette_2.asm ; ; nebo pouze: ; nasm -o ega.com ega_palette_2.asm ;----------------------------------------------------------------------------- ; registry karty EGA/VGA ega_controller equ 0x3c4 bitplane_selector equ 0x02 ; ukonceni procesu a navrat do DOSu %macro exit 0 mov ah, 0x4c int 0x21 %endmacro ; vyprazdneni bufferu klavesnice a cekani na klavesu %macro wait_key 0 xor ax, ax int 0x16 %endmacro ; nastaveni grafickeho rezimu %macro gfx_mode 1 mov ah, 0 mov al, %1 int 0x10 %endmacro ;----------------------------------------------------------------------------- org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 436) start: gfx_mode 0x10 ; nastaveni rezimu 640x200 se sestnacti barvami mov ax, 0xa000 ; video RAM v textovem rezimu mov es, ax xor di, di ; nyni ES:DI obsahuje adresu prvniho pixelu ve video RAM xor al, al ; maska bitovych rovin mov cl, 16 ; pocitadlo barevnych pruhu opak: call draw_block_into_bitplanes loop opak wait_key ; cekani na klavesu mov ax, 0x1000 ; cislo sluzby a podsluzby BIOSu mov bl, 1 ; index barvy mov bh, 0b111000 ; tmave seda int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 2 ; index barvy mov bh, 0b000111 ; svetle seda int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 3 ; index barvy mov bh, 0b111111 ; bila int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 4 ; index barvy mov bh, 0b010000 ; tmave zelena int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 5 ; index barvy mov bh, 0b000010 ; stredne zelena int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 6 ; index barvy mov bh, 0b010010 ; svetle zelena int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 7 ; index barvy mov bh, 0b100000 ; tmave cervena int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 8 ; index barvy mov bh, 0b000100 ; stredne cervena int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 9 ; index barvy mov bh, 0b100100 ; svetle cervena int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 10 ; index barvy mov bh, 0b001000 ; tmave modra int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 11 ; index barvy mov bh, 0b000001 ; stredne modra int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 12 ; index barvy mov bh, 0b001001 ; svetle modra int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 13 ; index barvy mov bh, 0b110000 ; tmave hneda int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 14 ; index barvy mov bh, 0b000110 ; svetle hneda int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy mov bl, 15 ; index barvy mov bh, 0b110110 ; zluta int 0x10 ; volani sluzby BIOSu pro zmenu jedne barvy wait_key ; cekani na klavesu exit ; navrat do DOSu select_bitplane: mov dx, ega_controller mov ah, bitplane_selector xchg ah, al out dx, ax ; vyber registru sekvenceru ; a zapis masky bitovych rovin ret ; hotovo draw_block_into_bitplanes: push ax push cx call select_bitplane; maska bitovych rovin call draw_block add di, 640*3/8 ; posun o nekolik radku nize pop cx pop ax inc al ; zmena masky ret ; hotovo draw_block: mov cx, 640*9/4 ; pocet zapisovanych pixelu (ovsem pocitano v bajtech) mov al, 0xff ; kod pixelu rep stosb ret
15. Změna všech barev v paletě s využitím programové smyčky
To, jakým způsobem jsme postupně měnili barvy v paletě, nebylo zcela ideální řešení, protože se opakovaly stále ty stejné instrukce. A v případě, že by barev bylo 256, by už bylo toto řešení zcela absurdní. Pokusme se tedy o lepší řešení. Nejdříve si kdekoli v kódovém segmentu vytvoříme tabulku šestnácti barev, tedy včetně barvy pozadí). To je v NASMu snadné:
palette: ; barvova paleta bez barvy okraje db 0b000000 ; cerna (pozadi) db 0b111000 ; tmave seda db 0b000111 ; svetle seda db 0b111111 ; bila db 0b010000 ; tmave zelena db 0b000010 ; stredne zelena db 0b010010 ; svetle zelena db 0b100000 ; tmave cervena db 0b000100 ; stredne cervena db 0b100100 ; svetle cervena db 0b001000 ; tmave modra db 0b000001 ; stredne modra db 0b001001 ; svetle modra db 0b110000 ; tmave hneda db 0b000110 ; svetle hneda db 0b110110 ; zluta
Nyní nám postačuje volat již známou službu BIOSu a při každém volání korektně naplnit registr BH hodnotou načtenou z tabulky. Jedno z řešení, které v tomto případě není založeno na instrukci lodsb (používá odlišné registry), by mohlo vypadat například takto:
mov ax, 0x1000 ; cislo sluzby a podsluzby BIOSu mov si, palette mov bl, 0 ; index barvy next_color: mov bh, [cs:si] ; hodnota barvy s indexem v BL int 0x10 ; zmena barvy inc bl ; modifikace indexu inc si ; modifikace adresy cmp bl, 16 jne next_color ; dalsi barva
Zkontrolujeme výsledek:
Obrázek 11: Výsledek běhu upraveného příkladu, tentokrát založeného na použití programové smyčky.
16. Úplný zdrojový kód příkladu pro změnu všech barev v paletě
Pro úplnost si ukažme, jak se celý program nepatrně zkrátil zavedením tabulky barev a programové smyčky:
; Graficky rezim karty EGA s rozlisenim 640x350 pixelu. ; Zmena barvovych rovin, do kterych se zapisuje. ; Konfigurace barvove palety. ; ; preklad pomoci: ; nasm -f bin -o ega.com ega_palette_3.asm ; ; nebo pouze: ; nasm -o ega.com ega_palette_3.asm ;----------------------------------------------------------------------------- ; registry karty EGA/VGA ega_controller equ 0x3c4 bitplane_selector equ 0x02 ; ukonceni procesu a navrat do DOSu %macro exit 0 mov ah, 0x4c int 0x21 %endmacro ; vyprazdneni bufferu klavesnice a cekani na klavesu %macro wait_key 0 xor ax, ax int 0x16 %endmacro ; nastaveni grafickeho rezimu %macro gfx_mode 1 mov ah, 0 mov al, %1 int 0x10 %endmacro ;----------------------------------------------------------------------------- org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 436) start: gfx_mode 0x10 ; nastaveni rezimu 640x200 se sestnacti barvami mov ax, 0xa000 ; video RAM v textovem rezimu mov es, ax xor di, di ; nyni ES:DI obsahuje adresu prvniho pixelu ve video RAM xor al, al ; maska bitovych rovin mov cl, 16 ; pocitadlo barevnych pruhu opak: call draw_block_into_bitplanes loop opak wait_key ; cekani na klavesu mov ax, 0x1000 ; cislo sluzby a podsluzby BIOSu mov si, palette mov bl, 0 ; index barvy next_color: mov bh, [cs:si] ; hodnota barvy s indexem v BL int 0x10 ; zmena barvy inc bl ; modifikace indexu inc si ; modifikace adresy cmp bl, 16 jne next_color ; dalsi barva wait_key ; cekani na klavesu exit ; navrat do DOSu palette: ; barvova paleta bez barvy okraje db 0b000000 ; cerna (pozadi) db 0b111000 ; tmave seda db 0b000111 ; svetle seda db 0b111111 ; bila db 0b010000 ; tmave zelena db 0b000010 ; stredne zelena db 0b010010 ; svetle zelena db 0b100000 ; tmave cervena db 0b000100 ; stredne cervena db 0b100100 ; svetle cervena db 0b001000 ; tmave modra db 0b000001 ; stredne modra db 0b001001 ; svetle modra db 0b110000 ; tmave hneda db 0b000110 ; svetle hneda db 0b110110 ; zluta select_bitplane: mov dx, ega_controller mov ah, bitplane_selector xchg ah, al out dx, ax ; vyber registru sekvenceru ; a zapis masky bitovych rovin ret ; hotovo draw_block_into_bitplanes: push ax push cx call select_bitplane; maska bitovych rovin call draw_block add di, 640*3/8 ; posun o nekolik radku nize pop cx pop ax inc al ; zmena masky ret ; hotovo draw_block: mov cx, 640*9/4 ; pocet zapisovanych pixelu (ovsem pocitano v bajtech) mov al, 0xff ; kod pixelu rep stosb ret
17. Změna barev v paletě jediným voláním služby BIOSu
V praxi se velmi často setkáme s nutností změny celé barvové palety, takže se nabízí otázka, jestli všichni vývojáři museli neustále opakovat programovou smyčku, kterou jsme si ukázali výše. Odpovědí je – nemuseli, protože BIOS grafické karty EGA nám nabízí k tomu určenou službu, která doplňuje službu pro změnu jediné barvy. Tato služba (+ podslužba) má číslo 0×1002 a vyžaduje, aby v registrovém páru ES:DX (pozor! skutečně DX a nikoli DI nebo BX, jak bychom logicky očekávali) byl uložen ukazatel na tabulku se sedmnácti barvami. Ona „divná“ sedmnáctá barva je barvou okraje (overscan border), které některé monitory podporují.
Namísto vlastní programové smyčky tedy postačuje napsat:
mov ax, cs mov es, ax mov dx, palette ; ES:BX obsahuje adresu barvove palety mov ax, 0x1002 ; cislo sluzby a podsluzby BIOSu int 0x10 ; volani sluzby BIOSu
18. Poslední demonstrační příklad: změna všech barev (včetně okraje) službou BIOSu
V dnešním posledním demonstračním příkladu je ukázán postup popsaný v předchozí kapitole, tj. změna všech barev v paletě, a to včetně barvy okraje na těch monitorech, které okraj zobrazují. Výsledek je kratší, než tomu bylo v předchozích třech demonstračních příkladech:
; Graficky rezim karty EGA s rozlisenim 640x350 pixelu. ; Zmena barvovych rovin, do kterych se zapisuje. ; Konfigurace barvove palety jedinym volanim prislusne sluzby. ; ; preklad pomoci: ; nasm -f bin -o ega.com ega_palette_4.asm ; ; nebo pouze: ; nasm -o ega.com ega_palette_4.asm ;----------------------------------------------------------------------------- ; registry karty EGA/VGA ega_controller equ 0x3c4 bitplane_selector equ 0x02 ; ukonceni procesu a navrat do DOSu %macro exit 0 mov ah, 0x4c int 0x21 %endmacro ; vyprazdneni bufferu klavesnice a cekani na klavesu %macro wait_key 0 xor ax, ax int 0x16 %endmacro ; nastaveni grafickeho rezimu %macro gfx_mode 1 mov ah, 0 mov al, %1 int 0x10 %endmacro ;----------------------------------------------------------------------------- org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 436) start: gfx_mode 0x10 ; nastaveni rezimu 640x200 se sestnacti barvami mov ax, 0xa000 ; video RAM v textovem rezimu mov es, ax xor di, di ; nyni ES:DI obsahuje adresu prvniho pixelu ve video RAM xor al, al ; maska bitovych rovin mov cl, 16 ; pocitadlo barevnych pruhu opak: call draw_block_into_bitplanes loop opak wait_key ; cekani na klavesu mov ax, cs mov es, ax mov dx, palette ; ES:BX obsahuje adresu barvove palety mov ax, 0x1002 ; cislo sluzby a podsluzby BIOSu int 0x10 ; volani sluzby BIOSu wait_key ; cekani na klavesu exit ; navrat do DOSu palette: ; barvova paleta i s barvou okraje db 0b000000 ; cerna (pozadi) db 0b111000 ; tmave seda db 0b000111 ; svetle seda db 0b111111 ; bila db 0b010000 ; tmave zelena db 0b000010 ; stredne zelena db 0b010010 ; svetle zelena db 0b100000 ; tmave cervena db 0b000100 ; stredne cervena db 0b100100 ; svetle cervena db 0b001000 ; tmave modra db 0b000001 ; stredne modra db 0b001001 ; svetle modra db 0b110000 ; tmave hneda db 0b000110 ; svetle hneda db 0b110110 ; zluta db 0b111111 ; okraj select_bitplane: mov dx, ega_controller mov ah, bitplane_selector xchg ah, al out dx, ax ; vyber registru sekvenceru ; a zapis masky bitovych rovin ret ; hotovo draw_block_into_bitplanes: push ax push cx call select_bitplane; maska bitovych rovin call draw_block add di, 640*3/8 ; posun o nekolik radku nize pop cx pop ax inc al ; zmena masky ret ; hotovo draw_block: mov cx, 640*9/4 ; pocet zapisovanych pixelu (ovsem pocitano v bajtech) mov al, 0xff ; kod pixelu rep stosb ret
19. Repositář s demonstračními příklady
Demonstrační příklady napsané v assembleru, které jsou určené pro překlad pomocí assembleru NASM, byly uložen do Git repositáře, který je dostupný na adrese https://github.com/tisnik/8bit-fame. Jednotlivé demonstrační příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý (dnes již poměrně rozsáhlý) repositář:
# | Příklad | Stručný popis | Adresa |
---|---|---|---|
1 | hello.asm | program typu „Hello world“ naprogramovaný v assembleru pro systém DOS | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hello.asm |
2 | hello_shorter.asm | kratší varianta výskoku z procesu zpět do DOSu | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hello_shorter.asm |
3 | hello_wait.asm | čekání na stisk klávesy | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hello_wait.asm |
4 | hello_macros.asm | realizace jednotlivých částí programu makrem | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hello_macros.asm |
5 | gfx4_putpixel.asm | vykreslení pixelu v grafickém režimu 4 | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_putpixel.asm |
6 | gfx6_putpixel.asm | vykreslení pixelu v grafickém režimu 6 | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel.asm |
7 | gfx4_line.asm | vykreslení úsečky v grafickém režimu 4 | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_line.asm |
8 | gfx6_line.asm | vykreslení úsečky v grafickém režimu 6 | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_line.asm |
9 | gfx6_fill1.asm | vyplnění obrazovky v grafickém režimu, základní varianta | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_fill1.asm |
10 | gfx6_fill2.asm | vyplnění obrazovky v grafickém režimu, varianta s instrukcí LOOP | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_fill2.asm |
11 | gfx6_fill3.asm | vyplnění obrazovky instrukcí REP STOSB | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_fill3.asm |
12 | gfx6_fill4.asm | vyplnění obrazovky, synchronizace vykreslování s paprskem | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_fill4.asm |
13 | gfx4_image1.asm | vykreslení rastrového obrázku získaného z binárních dat, základní varianta | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image1.asm |
14 | gfx4_image2.asm | varianta vykreslení rastrového obrázku s využitím instrukce REP MOVSB | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image2.asm |
15 | gfx4_image3.asm | varianta vykreslení rastrového obrázku s využitím instrukce REP MOVSW | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image3.asm |
16 | gfx4_image4.asm | korektní vykreslení všech sudých řádků bitmapy | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image4.asm |
17 | gfx4_image5.asm | korektní vykreslení všech sudých i lichých řádků bitmapy | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image5.asm |
18 | gfx4_image6.asm | nastavení barvové palety před vykreslením obrázku | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image6.asm |
19 | gfx4_image7.asm | nastavení barvové palety před vykreslením obrázku, snížená intenzita barev | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image7.asm |
20 | gfx4_image8.asm | postupná změna barvy pozadí | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image8.asm |
21 | gfx6_putpixel1.asm | vykreslení pixelu, základní varianta se 16bitovým násobením | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel1.asm |
22 | gfx6_putpixel2.asm | vykreslení pixelu, varianta s osmibitovým násobením | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel2.asm |
23 | gfx6_putpixel3.asm | vykreslení pixelu, varianta bez násobení | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel3.asm |
24 | gfx6_putpixel4.asm | vykreslení pixelu přes obrázek, nekorektní chování (přepis obrázku) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel4.asm |
25 | gfx6_putpixel5.asm | vykreslení pixelu přes obrázek, korektní varianta pro bílé pixely | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel5.asm |
26 | cga_text_mode1.asm | standardní textový režim s rozlišením 40×25 znaků | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_mode1.asm |
27 | cga_text_mode3.asm | standardní textový režim s rozlišením 80×25 znaků | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_mode3.asm |
28 | cga_text_mode_intensity.asm | změna významu nejvyššího bitu atributového bajtu: vyšší intenzita namísto blikání | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_mode_intensity.asm |
29 | cga_text_mode_cursor.asm | změna tvaru textového kurzoru | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_mode_cursor.asm |
30 | cga_text_gfx1.asm | zobrazení „rastrové mřížky“: pseudografický režim 160×25 pixelů (interně textový režim) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_gfx1.asm |
31 | cga_text_mode_char_height.asm | změna výšky znaků | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_mode_char_height.asm |
32 | cga_text_160×100.asm | grafický režim 160×100 se šestnácti barvami (interně upravený textový režim) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_160×100.asm |
33 | hercules_text_mode1.asm | využití standardního textového režimu společně s kartou Hercules | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_text_mode1.asm |
34 | hercules_text_mode2.asm | zákaz blikání v textových režimech | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_text_mode2.asm |
35 | hercules_turn_off.asm | vypnutí generování video signálu | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_turn_off.asm |
36 | hercules_gfx_mode1.asm | přepnutí karty Hercules do grafického režimu (základní varianta) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_gfx_mode1.asm |
37 | hercules_gfx_mode2.asm | přepnutí karty Hercules do grafického režimu (vylepšená varianta) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_gfx_mode2.asm |
38 | hercules_putpixel.asm | subrutina pro vykreslení jediného pixelu na kartě Hercules | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_putpixel.asm |
39 | ega_text_mode_80×25.asm | standardní textový režim 80×25 znaků na kartě EGA | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_text_mode_80×25.asm |
40 | ega_text_mode_80×43.asm | zobrazení 43 textových řádků na kartě EGA | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_text_mode_80×43.asm |
41 | ega_gfx_mode_320×200.asm | přepnutí do grafického režimu 320×200 pixelů se šestnácti barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_gfx_mode_320×200.asm |
42 | ega_gfx_mode_640×200.asm | přepnutí do grafického režimu 640×200 pixelů se šestnácti barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_gfx_mode_640×200.asm |
43 | ega_gfx_mode_640×350.asm | přepnutí do grafického režimu 640×350 pixelů se čtyřmi nebo šestnácti barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_gfx_mode_640×350.asm |
44 | ega_gfx_mode_bitplanes1.asm | ovládání zápisu do bitových rovin v planárních grafických režimech (základní způsob) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_gfx_mode_bitplanes1.asm |
45 | ega_gfx_mode_bitplanes2.asm | ovládání zápisu do bitových rovin v planárních grafických režimech (rychlejší způsob) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_gfx_mode_bitplanes2.asm |
46 | ega_320×200_putpixel.asm | vykreslení pixelu v grafickém režimu 320×200 pixelů se šestnácti barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_320×200_putpixel.asm |
47 | ega_640×350_putpixel.asm | vykreslení pixelu v grafickém režimu 640×350 pixelů se šestnácti barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_640×350_putpixel.asm |
48 | ega_standard_font.asm | použití standardního fontu grafické karty EGA | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_standard_font.asm |
49 | ega_custom_font.asm | načtení vlastního fontu s jeho zobrazením | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_custom_font.asm |
50 | ega_palette1.asm | změna barvové palety (všech 16 barev) v grafickém režimu 320×200 se šestnácti barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_palette1.asm |
51 | ega_palette2.asm | změna barvové palety (všech 16 barev) v grafickém režimu 640×350 se šestnácti barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_palette2.asm |
52 | ega_palette3.asm | změna všech barev v barvové paletě s využitím programové smyčky | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_palette3.asm |
53 | ega_palette4.asm | změna všech barev, včetně barvy okraje, v barvové paletě voláním funkce BIOSu | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_palette4.asm |
20. Odkazy na Internetu
- The Intel 8088 Architecture and Instruction Set
https://people.ece.ubc.ca/~edc/464/lectures/lec4.pdf - x86 Opcode Structure and Instruction Overview
https://pnx.tf/files/x86_opcode_structure_and_instruction_overview.pdf - x86 instruction listings (Wikipedia)
https://en.wikipedia.org/wiki/X86_instruction_listings - x86 assembly language (Wikipedia)
https://en.wikipedia.org/wiki/X86_assembly_language - Intel Assembler (Cheat sheet)
http://www.jegerlehner.ch/intel/IntelCodeTable.pdf - 25 Microchips That Shook the World
https://spectrum.ieee.org/tech-history/silicon-revolution/25-microchips-that-shook-the-world - Chip Hall of Fame: MOS Technology 6502 Microprocessor
https://spectrum.ieee.org/tech-history/silicon-revolution/chip-hall-of-fame-mos-technology-6502-microprocessor - Chip Hall of Fame: Intel 8088 Microprocessor
https://spectrum.ieee.org/tech-history/silicon-revolution/chip-hall-of-fame-intel-8088-microprocessor - Jak se zrodil procesor?
https://www.root.cz/clanky/jak-se-zrodil-procesor/ - Apple II History Home
http://apple2history.org/ - The 8086/8088 Primer
https://www.stevemorse.org/8086/index.html - flat assembler: Assembly language resources
https://flatassembler.net/ - FASM na Wikipedii
https://en.wikipedia.org/wiki/FASM - Fresh IDE FASM inside
https://fresh.flatassembler.net/ - MS-DOS Version 4.0 Programmer's Reference
https://www.pcjs.org/documents/books/mspl13/msdos/dosref40/ - INT 21 – DOS Function Dispatcher (DOS)
https://www.stanislavs.org/helppc/int21.html - DOS API (Wikipedia)
https://en.wikipedia.org/wiki/DOS_API - Bit banging
https://en.wikipedia.org/wiki/Bit_banging - IBM Basic assembly language and successors (Wikipedia)
https://en.wikipedia.org/wiki/IBM_Basic_assembly_language_and_successors - X86 Assembly/Bootloaders
https://en.wikibooks.org/wiki/X86_Assembly/Bootloaders - Počátky grafiky na PC: grafické karty CGA a Hercules
https://www.root.cz/clanky/pocatky-grafiky-na-pc-graficke-karty-cga-a-hercules/ - Co mají společného Commodore PET/4000, BBC Micro, Amstrad CPC i grafické karty MDA, CGA a Hercules?
https://www.root.cz/clanky/co-maji-spolecneho-commodore-pet-4000-bbc-micro-amstrad-cpc-i-graficke-karty-mda-cga-a-hercules/ - Karta EGA: první použitelná barevná grafika na PC
https://www.root.cz/clanky/karta-ega-prvni-pouzitelna-barevna-grafika-na-pc/ - RGB Classic Games
https://www.classicdosgames.com/ - Turbo Assembler (Wikipedia)
https://en.wikipedia.org/wiki/Turbo_Assembler - Microsoft Macro Assembler
https://en.wikipedia.org/wiki/Microsoft_Macro_Assembler - IBM Personal Computer (Wikipedia)
https://en.wikipedia.org/wiki/IBM_Personal_Computer - Intel 8251
https://en.wikipedia.org/wiki/Intel_8251 - Intel 8253
https://en.wikipedia.org/wiki/Intel_8253 - Intel 8255
https://en.wikipedia.org/wiki/Intel_8255 - Intel 8257
https://en.wikipedia.org/wiki/Intel_8257 - Intel 8259
https://en.wikipedia.org/wiki/Intel_8259 - Support/peripheral/other chips – 6800 family
http://www.cpu-world.com/Support/6800.html - Motorola 6845
http://en.wikipedia.org/wiki/Motorola_6845 - The 6845 Cathode Ray Tube Controller (CRTC)
http://www.tinyvga.com/6845 - CRTC operation
http://www.6502.org/users/andre/hwinfo/crtc/crtc.html - 6845 – Motorola CRT Controller
https://stanislavs.org/helppc/6845.html - The 6845 Cathode Ray Tube Controller (CRTC)
http://www.tinyvga.com/6845 - Motorola 6845 and bitwise graphics
https://retrocomputing.stackexchange.com/questions/10996/motorola-6845-and-bitwise-graphics - IBM Monochrome Display Adapter
http://en.wikipedia.org/wiki/Monochrome_Display_Adapter - Color Graphics Adapter
http://en.wikipedia.org/wiki/Color_Graphics_Adapter - Color Graphics Adapter and the Brown color in IBM 5153 Color Display
https://www.aceinnova.com/en/electronics/cga-and-the-brown-color-in-ibm-5153-color-display/ - The Modern Retrocomputer: An Arduino Driven 6845 CRT Controller
https://hackaday.com/2017/05/14/the-modern-retrocomputer-an-arduino-driven-6845-crt-controller/ - flat assembler: Assembly language resources
https://flatassembler.net/ - FASM na Wikipedii
https://en.wikipedia.org/wiki/FASM - Fresh IDE FASM inside
https://fresh.flatassembler.net/ - MS-DOS Version 4.0 Programmer's Reference
https://www.pcjs.org/documents/books/mspl13/msdos/dosref40/ - INT 21 – DOS Function Dispatcher (DOS)
https://www.stanislavs.org/helppc/int21.html - DOS API (Wikipedia)
https://en.wikipedia.org/wiki/DOS_API - IBM Basic assembly language and successors (Wikipedia)
https://en.wikipedia.org/wiki/IBM_Basic_assembly_language_and_successors - X86 Assembly/Arithmetic
https://en.wikibooks.org/wiki/X86_Assembly/Arithmetic - Art of Assembly – Arithmetic Instructions
http://oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter6/CH06–2.html - ASM Flags
http://www.cavestory.org/guides/csasm/guide/asm_flags.html - Status Register
https://en.wikipedia.org/wiki/Status_register - Linux assemblers: A comparison of GAS and NASM
http://www.ibm.com/developerworks/library/l-gas-nasm/index.html - Programovani v assembleru na OS Linux
http://www.cs.vsb.cz/grygarek/asm/asmlinux.html - Is it worthwhile to learn x86 assembly language today?
https://www.quora.com/Is-it-worthwhile-to-learn-x86-assembly-language-today?share=1 - Why Learn Assembly Language?
http://www.codeproject.com/Articles/89460/Why-Learn-Assembly-Language - Is Assembly still relevant?
http://programmers.stackexchange.com/questions/95836/is-assembly-still-relevant - Why Learning Assembly Language Is Still a Good Idea
http://www.onlamp.com/pub/a/onlamp/2004/05/06/writegreatcode.html - Assembly language today
http://beust.com/weblog/2004/06/23/assembly-language-today/ - Assembler: Význam assembleru dnes
http://www.builder.cz/rubriky/assembler/vyznam-assembleru-dnes-155960cz - Programming from the Ground Up Book – Summary
http://savannah.nongnu.org/projects/pgubook/ - DOSBox
https://www.dosbox.com/ - The C Programming Language
https://en.wikipedia.org/wiki/The_C_Programming_Language - Hercules Graphics Card (HCG)
https://en.wikipedia.org/wiki/Hercules_Graphics_Card - Complete 8086 instruction set
https://content.ctcd.edu/courses/cosc2325/m22/docs/emu8086ins.pdf - Complete 8086 instruction set
https://yassinebridi.github.io/asm-docs/8086_instruction_set.html - 8088 MPH by Hornet + CRTC + DESiRE (final version)
https://www.youtube.com/watch?v=hNRO7lno_DM - Area 5150 by CRTC & Hornet (Party Version) / IBM PC+CGA Demo, Hardware Capture
https://www.youtube.com/watch?v=fWDxdoRTZPc - 80×86 Integer Instruction Set Timings (8088 – Pentium)
http://aturing.umcs.maine.edu/~meadow/courses/cos335/80×86-Integer-Instruction-Set-Clocks.pdf - Colour Graphics Adapter: Notes
https://www.seasip.info/VintagePC/cga.html - Restoring A Vintage CGA Card With Homebrew HASL
https://hackaday.com/2024/06/12/restoring-a-vintage-cga-card-with-homebrew-hasl/ - Demoing An 8088
https://hackaday.com/2015/04/10/demoing-an-8088/ - Video Memory Layouts
http://www.techhelpmanual.com/89-video_memory_layouts.html - Screen Attributes
http://www.techhelpmanual.com/87-screen_attributes.html - IBM PC Family – BIOS Video Modes
https://www.minuszerodegrees.net/video/bios_video_modes.htm - EGA Functions
https://cosmodoc.org/topics/ega-functions/#the-hierarchy-of-the-ega - Why the EGA can only use 16 of its 64 colours in 200-line modes
https://www.reenigne.org/blog/why-the-ega-can-only-use-16-of-its-64-colours-in-200-line-modes/ - How 16 colors saved PC gaming – the story of EGA graphics
https://www.custompc.com/retro-tech/ega-graphics - List of 16-bit computer color palettes
https://en.wikipedia.org/wiki/List_of16-bit_computer_color_palettes