Hrátky s barvovou paletou a vykreslení jednotlivých pixelů kartou CGA

11. 7. 2024
Doba čtení: 32 minut

Sdílet

Autor: Pavel Tišnovský
Dnes se ještě jednou budeme zabývat programováním a kreslením na původním IBM PC a grafické kartě CGA. Ukážeme si práci s barvovou paletou a taktéž operace, které je nutné provádět při vykreslování jednotlivých pixelů.

Obsah

1. Krátké shrnutí předchozí části – korektní vykreslení všech sudých i lichých řádků rastrového obrázku

2. Řízení způsobu zobrazení barev kartou CGA ovládáním portu 3D9

3. Nastavení korektní barvové palety a vykreslení rastrového obrázku

4. Úplný zdrojový kód aplikace, která zobrazí rastrový obrázek i s korektní barvovou paletou

5. Změna intenzity všech barev na obrazovce

6. Úplný zdrojový kód aplikace pro změnu intenzity barev na obrazovce

7. Postupná změna barvy pozadí (16 různých možností)

8. Úplný zdrojový kód příkladu pro postupnou změnu barev pozadí

9. Programové vykreslení jediného pixelu v monochromatickém barvovém režimu

10. Výpočet adresy pro zápis pixelu

11. Výpočet masky pixelu a vlastní vykreslení

12. Úplný kód příkladu, který po svém spuštění vykreslí diagonální úsečku z jednotlivých pixelů

13. První optimalizace: realizace násobení 8×8 bitů namísto 16×16 bitů

14. Náhrada součinu za bitové posuny

15. Výsledný zdrojový kód

16. Vykreslení pixelů na neprázdném pozadí

17. Korektní vykreslení bílých pixelů vůči jakémukoli pozadí

18. Úplný zdrojový kód dnešního posledního demonstračního příkladu

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Krátké shrnutí předchozí části – korektní vykreslení všech sudých i lichých řádků rastrového obrázku

Připomeňme si, že v předchozím článku jsme si ukázali, jakým způsobem se přistupuje do video RAM grafické karty CGA, jak je tato paměť organizovaná a jak se do ní může vykreslit nějaký statický obrázek. Přitom jsme vycházeli ze screenshotu získaného ze slavné hry Golden Axe:

Obrázek 1: Statický rastrový obrázek, který budeme postupně vykreslovat.

Již jsme úspěšně vyřešili problém s uložením sudých a lichých obrazových řádků v různých částech video RAM, takže prozatím máme dostatek znalostí pro vykreslení následujícího obrázku (s nekorektní barvovou paletou):

Obrázek 2: Korektní vykreslení jak lichých, tak i sudých řádků.

Vykreslovací rutina je volána (dvakrát) následovně:

start:
        gfx_mode 4      ; nastaveni grafickeho rezimu 320x200 se ctyrmi barvami
 
        mov ax, cs
        mov ds, ax
        mov si, image   ; nyni DS:SI obsahuje adresu prvniho bajtu v obrazku
 
        mov ax, 0xb800
        mov es, ax
        mov di, 0       ; nyni ES:DI obsahuje adresu prvniho pixelu ve video RAM
 
        call move_half_image
 
        mov si, image+80; adresa prvniho pixelu na DRUHEM radku
        mov di, 8192    ; druha "stranka" video RAM
        call move_half_image
 
        wait_key
        exit
 
move_half_image:
        mov bl, 100     ; pocitadlo radku
outer_loop:
        mov cx, 80/2    ; velikost bloku ve slovech
        rep movsw       ; prenest jeden obrazovy radek
        add si, 80      ; preskocit lichy/sudy radek
        dec bl
        jnz outer_loop  ; opakovat smycku BL-krat
        ret

V dnešním článku si ukážeme ovládání barvové palety ve standardních grafických režimech. A taktéž se podíváme na to, jakým způsobem je možné vykreslit jednotlivé pixely. Jedná se sice o tu nejprimitivnější grafickou entitu, ale dále uvidíme, že samotné vykreslování pixelů je „díky“ struktuře grafické paměti relativně složitou operací.

2. Řízení způsobu zobrazení barev kartou CGA ovládáním portu 3D9

Připomeňme si, že v grafickém režimu s rozlišením 320×200 a čtyřmi barvami bylo možné zvolit barvovou paletu. Tato paleta však nemohla být libovolná (naproti tomu v textovém režimu je možné použít šestnáct barev), protože existovaly pouze dvě fixní barvové palety, přičemž při výběru barev se IBM skutečně „předvedla“, protože její nevkusná barevná schémata byla prakticky nepoužitelná :-) První paleta fixně obsahovala barvy zelenou, červenou a hnědou (red, green, brown – ovšem již víme, že hnědá byla tvořena speciálním obvodem v monitoru z tmavě žluté), druhá paleta barvy azurovou, fialovou a bílou (cyan, magenta, white). Je patrné, že obě palety se liší pouze přidáním modré barvové složky.

Pozadí, tedy čtvrtá barva, mohla být zvolena libovolně, resp. z nabídky CGA – tedy jedna z patnácti možných barev. Navíc bylo možné ovlivnit i intenzitu barev popředí – zvýšit či snížit ji o 33%.

Volba barvové palety, barvy pozadí i intenzity barev, se provádí zápisem na port dostupný na adrese 3d9. Význam jednotlivých bitů je následující:

Bit Význam v textovém režimu Význam v grafických režimech
0–3 barva okraje barva pozadí (pro pixely s nulovou hodnotou)
4 intenzita pozadí intenzita pixelů (pro rozlišení 320×200)
5 × „modrá“ varianta barvové palety
6 × ×
7 × ×

3. Nastavení korektní barvové palety a vykreslení rastrového obrázku

Pro nastavení barvové palety bude nutné změnit hodnoty bitů řídicího registru grafické karty CGA. Tyto bity jsou ovladatelné přes port dostupný (z pohledu mikroprocesoru) na adrese 3d9. Pro zápis na tento port (ale samozřejmě i na jakýkoli jiný port) se používá instrukce OUT. Ta nabízí několik adresovacích režimů:

Varianta Stručný popis
imm8, al zápis hodnoty uložené v registru AL na osmibitový port s uvedenou osmibitovou adresou
imm8, ax zápis hodnoty uložené v registru AX na šestnáctibitový port s uvedenou osmibitovou adresou
dx, al zápis hodnoty uložené v registru AL na osmibitový port, jehož adresa je uložena v registru DX
dx, ax zápis hodnoty uložené v registru AX na šestnáctibitový port, jehož adresa je uložena v registru DX

První dvě instrukce jsou sice kratší z pohledu velikosti kódu, ale trvají delší dobu. To nás ale vlastně nemusí trápit, protože porty karty CGA neleží v rozsahu 0-FF, ale výše (3d9), takže jsme stejně nuceni použít variantu s registrem DX, ve kterém je adresa portu uložena. Potřebujeme vynulovat pátý bit (tedy zakázat modrou složku v barvách), takže celá sekvence instrukcí, která změní barvovou paletu, bude vypadat následovně:

mov dx, 0x3d9   ; port s rizenim graficke palety
mov al, 0x10    ; zmena barevne palety
out dx, al      ; pres port 0x3d9
Poznámka: na porty 0-FF jsou mapovány řídicí a stavové registry základních obvodů IBM PC, tedy například časovače, řadiče DMA, nepřímo též ovládání klávesnice atd. Prozatím se jimi nebudeme zabývat, ale později budeme tyto porty používat právě pro práci s klávesnicí a taktéž pro ovládání PC Speakeru (abych vám trošku zkazil hudební sluch).

Obrázek 3: Obrázek s korektní barvovou paletou (porovnejte s originálem – obrázkem číslo 1).

4. Úplný zdrojový kód aplikace, která zobrazí rastrový obrázek i s korektní barvovou paletou

Podobně, jako tomu bylo i v předchozích dvou částech tohoto seriálu, si nyní ukážeme úplný zdrojový kód jednoduché aplikace, která po svém spuštění vykreslí rastrový obrázek v rozlišení 320×200 pixelů a čtyřmi barvami i s korektní barvovou paletou:

; Vykresleni rastroveho obrazku ziskaneho z binarnich dat.
; Korektni vykresleni vsech sudych i lichych radku obrazku.
; Nastaveni barvove palety.
;
; preklad pomoci:
;     nasm -f bin -o gfx_4.com gfx_4_image.asm
;
; nebo pouze:
;     nasm -o gfx_4.com gfx_4_image.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 4      ; nastaveni grafickeho rezimu 320x200 se ctyrmi barvami
 
        mov dx, 0x3d9   ; port s rizenim graficke palety
        mov al, 0x10    ; zmena barevne palety
        out dx, al      ; pres port 0x3d9
 
        mov ax, cs
        mov ds, ax
        mov si, image   ; nyni DS:SI obsahuje adresu prvniho bajtu v obrazku
 
        mov ax, 0xb800
        mov es, ax
        mov di, 0       ; nyni ES:DI obsahuje adresu prvniho pixelu ve video RAM
 
        call move_half_image
 
        mov si, image+80; adresa prvniho pixelu na DRUHEM radku
        mov di, 8192    ; druha "stranka" video RAM
        call move_half_image
 
        wait_key
        exit
 
move_half_image:
        mov bl, 100     ; pocitadlo radku
outer_loop:
        mov cx, 80/2    ; velikost bloku ve slovech
        rep movsw       ; prenest jeden obrazovy radek
        add si, 80      ; preskocit lichy/sudy radek
        dec bl
        jnz outer_loop  ; opakovat smycku BL-krat
        ret
 
 
image:
    incbin "image.bin"

5. Změna intenzity všech barev na obrazovce

Bitem číslo 4 na portu 3d9 se řídí intenzita všech barev na obrazovce. Jedná se většinou o zbytečnou volbu, protože nízké intenzity všech barev (v grafickém režimu) povedou k málo kontrastnímu obrazu, ovšem nic nám pochopitelně nebrání v tom si tuto volbu otestovat:

mov dx, 0x3d9   ; port s rizenim graficke palety
mov al, 0x00    ; zmena barevne palety, nizka intenzita
out dx, al      ; pres port 0x3d9

Výsledný obrázek by měl vypadat zhruba následovně:

Obrázek 4: Obrázek po přepnutí barvové palety tak, aby se používaly nízké intenzity barev.

6. Úplný zdrojový kód aplikace pro změnu intenzity barev na obrazovce

Opět si pro jistotu uvedeme úplný zdrojový kód příkladu, který po svém spuštění zobrazí (stále stejný) rastrový obrázek, nyní ovšem s nízkou intenzitou barev:

; Vykresleni rastroveho obrazku ziskaneho z binarnich dat.
; Korektni vykresleni vsech sudych i lichych radku obrazku.
; Nastaveni barvove palety.
; Nastaveni nizke intenzity.
;
; preklad pomoci:
;     nasm -f bin -o gfx_4.com gfx_4_image.asm
;
; nebo pouze:
;     nasm -o gfx_4.com gfx_4_image.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 4      ; nastaveni grafickeho rezimu 320x200 se ctyrmi barvami
 
        mov dx, 0x3d9   ; port s rizenim graficke palety
        mov al, 0x00    ; zmena barevne palety, nizka intenzita
        out dx, al      ; pres port 0x3d9
 
        mov ax, cs
        mov ds, ax
        mov si, image   ; nyni DS:SI obsahuje adresu prvniho bajtu v obrazku
 
        mov ax, 0xb800
        mov es, ax
        mov di, 0       ; nyni ES:DI obsahuje adresu prvniho pixelu ve video RAM
 
        call move_half_image
 
        mov si, image+80; adresa prvniho pixelu na DRUHEM radku
        mov di, 8192    ; druha "stranka" video RAM
        call move_half_image
 
        wait_key
        exit
 
move_half_image:
        mov bl, 100     ; pocitadlo radku
outer_loop:
        mov cx, 80/2    ; velikost bloku ve slovech
        rep movsw       ; prenest jeden obrazovy radek
        add si, 80      ; preskocit lichy/sudy radek
        dec bl
        jnz outer_loop  ; opakovat smycku BL-krat
        ret
 
 
image:
    incbin "image.bin"

7. Postupná změna barvy pozadí (16 různých možností)

Zajímavější jsou bity 0–3 portu 3d9. Těmito bity se totiž v grafických režimech určuje barva pozadí (tedy barva pixelů s nulovou hodnotou), nezávisle na ostatních třech barvách popředí (foreground). V textových režimech se pomocí těchto bitů určuje pouze barva okraje obrazovky, protože popředí i pozadí znaků je řešeno odlišnou technikou.

Vraťme se však ke grafickým režimům a barvě pozadí. Velmi jednoduchým způsobem lze implementovat programovou smyčku, která po stisku libovolné klávesy (přesněji řečeno skoro libovolné klávesy – Shift atd. se nepočítá) změní barvu pozadí a umožní nám tak projít všemi šestnácti možnostmi. Realizace této smyčky není ve skutečnosti příliš složitá, jak je to ostatně patrné i z následující sekvence osmi programových řádků:

        mov cl, 0x10    ; zmena palety, vychozi intenzita barev
        mov dx, 0x3d9   ; port s rizenim graficke palety
opak:
        mov al, cl      ; hodnota zapisovana na port 0x3d9 do registru AL
        inc cl          ; dalsi barva
        out dx, al      ; pres port 0x3d9
        wait_key        ; cekani na klavesu
        jmp opak        ; opakovat cele znovu
Poznámka: bylo by navíc možné přidat podmínku pro to, aby se po šestnáctém stisku klávesy aplikace vrátila do výchozího stavu, to však pro naše jednoduché demo není zcela nutné.

Podívejme se na několik výsledných obrázků tak, jak je aplikace postupně zobrazí:

Obrázek 5: Na pozadí je použita barva číslo 1.

Obrázek 6: Na pozadí je použita barva číslo 2.

Obrázek 7: Na pozadí je použita barva číslo 3.

Obrázek 8: Na pozadí je použita barva číslo 4.

…a tak dále…

8. Úplný zdrojový kód příkladu pro postupnou změnu barev pozadí

Opět se, nyní již bez dalšího podrobnějšího popisu, podívejme na výsledný program:

; Vykresleni rastroveho obrazku ziskaneho z binarnich dat.
; Korektni vykresleni vsech sudych i lichych radku obrazku.
; Nastaveni barvove palety.
; Nastaveni nizke intenzity.
;
; preklad pomoci:
;     nasm -f bin -o gfx_4.com gfx_4_image.asm
;
; nebo pouze:
;     nasm -o gfx_4.com gfx_4_image.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 4      ; nastaveni grafickeho rezimu 320x200 se ctyrmi barvami
 
        mov ax, cs
        mov ds, ax
        mov si, image   ; nyni DS:SI obsahuje adresu prvniho bajtu v obrazku
 
        mov ax, 0xb800
        mov es, ax
        mov di, 0       ; nyni ES:DI obsahuje adresu prvniho pixelu ve video RAM
 
        call move_half_image
 
        mov si, image+80; adresa prvniho pixelu na DRUHEM radku
        mov di, 8192    ; druha "stranka" video RAM
        call move_half_image
 
        mov cl, 0x10    ; zmena palety, vychozi intenzita barev
        mov dx, 0x3d9   ; port s rizenim graficke palety
opak:
        mov al, cl      ; hodnota zapisovana na port 0x3d9 do registru AL
        inc cl          ; dalsi barva
        out dx, al      ; pres port 0x3d9
        wait_key        ; cekani na klavesu
        jmp opak        ; opakovat cele znovu
        exit            ; (sem se rizeni nedostane)
 
move_half_image:
        mov bl, 100     ; pocitadlo radku
outer_loop:
        mov cx, 80/2    ; velikost bloku ve slovech
        rep movsw       ; prenest jeden obrazovy radek
        add si, 80      ; preskocit lichy/sudy radek
        dec bl
        jnz outer_loop  ; opakovat smycku BL-krat
        ret
 
 
image:
    incbin "image.bin"

9. Programové vykreslení jediného pixelu v monochromatickém barvovém režimu

Nyní již víme, jakým způsobem je možné vykreslit rastrový obrázek, a to nezávisle na nastaveném grafickém režimu. Prakticky stejný kód tedy bude funkční jak pro monochromatický režim s rozlišením 640×200 pixelů, tak i pro čtyřbarevný režim s rozlišením 320×200 pixelů. Ovšem nyní se zaměřme na zdánlivě jednodušší operaci – jak na obrazovku vykreslit jediný pixel. Popis začneme u monochromatického režimu, který je v tomto ohledu jednodušší.

Připravíme si kostru podprogramu, který bude v pracovním registru AX očekávat x-ovou souřadnici pixelu (0 až 639) a v registru BX y-ovou souřadnici (tedy prozatím 0 až 199). Náš podprogram se bude jmenovat putpixel:

; Vykresleni pixelu
; AX - x-ova souradnice
; BX - y-ova souradnice (staci len BL)
putpixel:
        ...
        ...
        ...
        ret

Provést musíme tři operace:

  1. Výpočet adresy, do níž se bude zapisovat (bude to jediný bajt)
  2. Výpočet masky pixelu, tedy o jaký bit v rámci bajtu se bude jednat
  3. Vlastní zápis, popř. přepis bitu/bitů na vypočtené adrese

10. Výpočet adresy pro zápis pixelu

Nejprve si vypočteme adresu bajtu v rámci video RAM, do kterého se bude zapisovat. V závislosti na y-ové souřadnici se bude jednat o bajt na stránce 0×b800 (prvních 8000 bajtů video RAM) nebo naopak o bajt na stránce o 8192 adres vyšší (druhých 8000 bajtů video RAM). Asi nejpřirozenější je zde test nejnižšího bitu y-ové souřadnice (tedy sudý:lichý) s podmíněným skokem:

        mov dx, 0xb800     ; zacatek prvni stranky Video RAM
        test bx, 1         ; test, zda se jedna o sudy nebo lichy radek na obrazovce
        jz odd_line
        add dx, 8192/16    ; přechod na druhou stránku Video RAM
odd_line:
        mov es, dx         ; nyni obsahuje ES bud prvni stranku Video RAM nebo stranku druhou

Nyní tedy máme připraven registr ES (extra segment) a další adresování bude probíhat pouze uvnitř tohoto segmentu.

Vypočteme horizontální posun (v rámci jediného obrazového řádku) založený na x-ové souřadnici. Tuto souřadnici musíme vydělit osmi (osm pixelů na bajt), což se nejrychleji provede opakováním instrukce SHR (shift arithmetic right). Každá z těchto instrukcí je vykonána za dva takty:

        shr ax, 1
        shr ax, 1
        shr ax, 1          ; x/8
        mov di, ax         ; horizontalni posun pocitany v bajtech

Poněkud složitější je vertikální posun, kdy musíme y-ovou souřadnici pixelu vydělit dvěma (spodní bit volí stránku video RAM) a následně vynásobit 80. Prozatím použijeme operaci násobení MUL, která v tomto případě vynásobí obsah registru AX registrem DX a výsledek (obecně se nevejde do šestnácti bitů) je uložen do registrového páru DX:AX. My však víme, že v našem konkrétním případě se bez problémů vejdeme do třinácti bitů, takže DX můžeme ignorovat:

        mov ax, bx         ; y-ova souradnice
        shr ax, 1          ; ignorovat nejnizsi bit s lichym/sudym radkem
        mov dx, 80         ; vynasobit delkou radku v bajtech
        mul dx             ; AX - relativni posun v y-ovem smeru

Obě adresy, tedy horizontální i vertikální posun, stačí sečíst a výsledek uložit do registru DI:

        add di, ax         ; pricist vertikalni posun k posunu horizontalnimu

11. Výpočet masky pixelu a vlastní vykreslení

Nyní ještě musíme vypočítat masku pixelu, tj. který bit se bude v rámci celého bajtu měnit. To není příliš složité, protože pokud máme v registru AX x-ovou souřadnici, použijeme nejnižší tři bity pro posun. Takže nejdříve tyto tři bity získáme vymaskováním s hodnotou 7 (1+2+4):

        mov cl, al
        and cl, 7          ; pouze spodni 3 bity x-ove souradnice

Nyní již můžeme hodnotu v registru CL použít pro posun bitové masky 0b10000000 doprava, a to právě o CL bitů:

        mov al, 0x80       ; vypocitat masku pixelu
        shr al, cl

AL je nyní maska pixelu a v registrovém páru ES:DI je adresa bajtu, ve které je pixel zakódován. Takže nám pouze stačí provést zápis:

        stosb              ; vlastni vykresleni pixelu
Poznámka: ve skutečnosti tato operace není korektní, ale k tomu se ještě dnes vrátíme.

12. Úplný kód příkladu, který po svém spuštění vykreslí diagonální úsečku z jednotlivých pixelů

Použijme nyní výše uvedenou proceduru putpixel pro vykreslení diagonální úsečky. Budeme postupně měnit souřadnice uložené v registrech AX a BX a 200× zavoláme putpixel:

        mov ax, 0
opak:
        mov bx, ax      ; y-ová souřadnice
        push ax
        call putpixel   ; vykreslení pixelu
        pop ax
        inc ax          ; pusun x+=1, y+=1
        cmp ax, 200     ; hranice obrazovky?
        jne opak        ; ne-opakujeme
Poznámka: registr AX se uvnitř putpixel modifikuje, takže si ho odložíme na zásobník.

Výsledek:

Obrázek 9: Výsledná diagonální úsečka.

A takto vypadá úplný zdrojový kód demonstračního příkladu, který úsečku vykreslí:

; Vykresleni pixelu, zakladni varianta se 16bitovym nasobenim.
;
; preklad pomoci:
;     nasm -f bin -o gfx_6.com gfx_6_putpixel_1.asm
;
; nebo pouze:
;     nasm -o gfx_6.com gfx_6_putpixel_1.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 6      ; nastaveni grafickeho rezimu 320x200 se ctyrmi barvami
 
        mov ax, 0
opak:
        mov bx, ax      ; y-ová souřadnice
        push ax
        call putpixel   ; vykreslení pixelu
        pop ax
        inc ax          ; pusun x+=1, y+=1
        cmp ax, 200     ; hranice obrazovky?
        jne opak        ; ne-opakujeme
 
        wait_key
        exit
 
; Vykresleni pixelu
; AX - x-ova souradnice
; BX - y-ova souradnice (staci len BL)
putpixel:
        mov dx, 0xb800     ; zacatek prvni stranky Video RAM
        test bx, 1         ; test, zda se jedna o sudy nebo lichy radek na obrazovce
        jz odd_line
        add dx, 8192/16
odd_line:
        mov es, dx         ; nyni obsahuje ES bud prvni stranku Video RAM nebo stranku druhou
 
        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
        shr ax, 1          ; ignorovat nejnizsi bit s lichym/sudym radkem
        mov dx, 80         ; vynasobit delkou radku v bajtech
        mul dx             ; AX - relativni posun v y-ovem smeru
 
        add di, ax         ; pricist vertikalni posun k posunu horizontalnimu
 
        mov al, 0x80       ; vypocitat masku pixelu
        shr al, cl
        stosb              ; vlastni vykresleni pixelu
 
        ret
Poznámka: zdá se vám kód dlouhý? Ve skutečnosti má po překladu délku jen 75 bajtů.

13. První optimalizace: realizace násobení 8×8 bitů namísto 16×16 bitů

V předchozím demonstračním příkladu jsme při výpočtu vertikálního posunu využili násobení dvou šestnáctibitových hodnot, přičemž výsledkem byla hodnota 32bitová, uložená v registrovém páru DX:AX. Ovšem to není nutné, protože y-ová souřadnice nepřesáhne hodnotu 199 a násobíme konstantou 80. Obě hodnoty jsou tedy osmibitové a tudíž můžeme použít kratší variantu násobení (instrukce MUL):

        mov al, bl         ; y-ova souradnice
        shr al, 1          ; ignorovat nejnizsi bit s lichym/sudym radkem
        mov dl, 80         ; vynasobit delkou radku v bajtech
        mul dl             ; AX - relativni posun v y-ovem smeru
 
        add di, ax         ; pricist vertikalni posun k posunu horizontalnimu

Kolik času ušetříme? Čas násobení se zkrátí ze 118 až 133 taktů na 70 až 77 taktů. Mimochodem – zde je patrné, jak pomalé je vykonávání instrukcí řízených mikrokódem.

Ověřme si výsledek:

Obrázek 10: Výsledná diagonální úsečka.

A takto vypadá úplný zdrojový kód tohoto příkladu:

; Vykresleni pixelu, varianta s osmibitovym nasobenim.
;
; preklad pomoci:
;     nasm -f bin -o gfx_6.com gfx_6_putpixel_2.asm
;
; nebo pouze:
;     nasm -o gfx_6.com gfx_6_putpixel_2.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 6      ; nastaveni grafickeho rezimu 320x200 se ctyrmi barvami
 
        mov ax, 0
opak:
        mov bx, ax      ; y-ová souřadnice
        push ax
        call putpixel   ; vykreslení pixelu
        pop ax
        inc ax          ; pusun x+=1, y+=1
        cmp ax, 200     ; hranice obrazovky?
        jne opak        ; ne-opakujeme
 
        wait_key
        exit
 
; Vykresleni pixelu
; AX - x-ova souradnice
; BX - y-ova souradnice (staci len BL)
putpixel:
        mov dx, 0xb800     ; zacatek prvni stranky Video RAM
        test bx, 1         ; test, zda se jedna o sudy nebo lichy radek na obrazovce
        jz odd_line
        add dx, 8192/16
odd_line:
        mov es, dx         ; nyni obsahuje ES bud prvni stranku Video RAM nebo stranku druhou
 
        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 al, bl         ; y-ova souradnice
        shr al, 1          ; ignorovat nejnizsi bit s lichym/sudym radkem
        mov dl, 80         ; vynasobit delkou radku v bajtech
        mul dl             ; AX - relativni posun v y-ovem smeru
 
        add di, ax         ; pricist vertikalni posun k posunu horizontalnimu
 
        mov al, 0x80       ; vypocitat masku pixelu
        shr al, cl
        stosb              ; vlastni vykresleni pixelu
 
        ret

14. Náhrada součinu za bitové posuny

Ve skutečnosti je ovšem možné (a vhodné) nahradit operaci násobení za kombinaci bitových posunů a součtů, minimálně v situaci, kdy se násobí relativně „kulatou“ konstantou 80. Součin n*80 je totiž možné nahradit za n*64 + n*16 a tyto částečné součiny již můžeme zaměnit za bitové posuny, tedy za n << 6 + n << 4. V assembleru to bude vypadat následovně.

Původní operace:

        mov al, bl         ; y-ova souradnice
        shr al, 1          ; ignorovat nejnizsi bit s lichym/sudym radkem
        mov dl, 80         ; vynasobit delkou radku v bajtech
        mul dl             ; AX - relativni posun v y-ovem smeru

Nová operace:

        mov ax, bx         ; y-ova souradnice
        and al, 0xfe       ; nejnizsi bit urcuje lichy/sudy radek -> nyni ignorovat
        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
                           ; -> y*16 + y*64 = y*80

Rychlosti:

mov al, bl        2
shr al, 1         2
mov dl, 80        4
mul dl          70-77
---------------------------
                78-85 cyklů
mov ax, bx        2
and al, 0xfe      4
shl ax, 1         2
shl ax, 1         2
shl ax, 1         2
add di, ax        3
shl ax, 1         2
shl ax, 1         2
-------------------------
                19 cyklů

Zde je tedy výhoda ručních optimalizací značná!

Opět si zkontrolujme výsledek:

Obrázek 11: Pixely vykreslené bez použití operace součinu.

15. Výsledný zdrojový kód

Opět se pro úplnost podívejme na výsledný zdrojový kód:

; Vykresleni pixelu, varianta bez nasobeni.
;
; preklad pomoci:
;     nasm -f bin -o gfx_6.com gfx_6_putpixel_3.asm
;
; nebo pouze:
;     nasm -o gfx_6.com gfx_6_putpixel_3.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 6      ; nastaveni grafickeho rezimu 320x200 se ctyrmi barvami
 
        mov ax, 0
opak:
        mov bx, ax      ; y-ová souřadnice
        push ax
        call putpixel   ; vykreslení pixelu
        pop ax
        inc ax          ; pusun x+=1, y+=1
        cmp ax, 200     ; hranice obrazovky?
        jne opak        ; ne-opakujeme
 
        wait_key
        exit
 
; Vykresleni pixelu
; AX - x-ova souradnice
; BX - y-ova souradnice (staci len BL)
putpixel:
        mov dx, 0xb800     ; zacatek prvni stranky Video RAM
        test bx, 1         ; test, zda se jedna o sudy nebo lichy radek na obrazovce
        jz odd_line
        add dx, 8192/16
odd_line:
        mov es, dx         ; nyni obsahuje ES bud prvni stranku Video RAM nebo stranku druhou
 
        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
        and al, 0xfe       ; nejnizsi bit urcuje lichy/sudy radek -> nyni ignorovat
        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
        stosb              ; vlastni vykresleni pixelu
 
        ret

16. Vykreslení pixelů na neprázdném pozadí

V předchozím textu jsem naznačil, že naše subrutina pro vykreslení jednoho pixelu není zcela korektní. Konkrétně nebude plně funkční ve chvíli, kdy se namísto prázdného pozadí kreslí na již vyplněnou bitmapu. Výsledek nebude uspokojivý – podívejte se sami, jak se v trpaslíkovi objevily černé pruhy, které jsou široké přesně osm pixelů:

Obrázek 12: Pixely se nejenom vykreslí, ale navíc se vymaže i jejich okolí (7 pixelů).

Tohoto efektu jsme dosáhli následujícím demonstračním příkladem, který v sobě spojuje vykreslení bitmapy s vykreslením jednotlivých pixelů:

; Vykresleni pixelu, varianta bez nasobeni.
; Pixely se prekresli pres obrazek.
;
; preklad pomoci:
;     nasm -f bin -o gfx_6.com gfx_6_putpixel_4.asm
;
; nebo pouze:
;     nasm -o gfx_6.com gfx_6_putpixel_4.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 6      ; nastaveni grafickeho rezimu 320x200 se ctyrmi barvami
 
        mov ax, cs
        mov ds, ax
        mov si, image   ; nyni DS:SI obsahuje adresu prvniho bajtu v obrazku
 
        mov ax, 0xb800
        mov es, ax
        mov di, 0       ; nyni ES:DI obsahuje adresu prvniho pixelu ve video RAM
 
        call move_half_image
 
        mov si, image+80; adresa prvniho pixelu na DRUHEM radku
        mov di, 8192    ; druha "stranka" video RAM
        call move_half_image
 
        mov ax, 0
opak:
        mov bx, ax      ; y-ová souřadnice
        push ax
        add ax, 30
        call putpixel   ; vykreslení pixelu
        pop ax
        inc ax          ; pusun x+=1, y+=1
        cmp ax, 200     ; hranice obrazovky?
        jne opak        ; ne-opakujeme
 
        wait_key
        exit
 
; Vykresleni pixelu
; AX - x-ova souradnice
; BX - y-ova souradnice (staci len BL)
putpixel:
        mov dx, 0xb800     ; zacatek prvni stranky Video RAM
        test bx, 1         ; test, zda se jedna o sudy nebo lichy radek na obrazovce
        jz odd_line
        add dx, 8192/16
odd_line:
        mov es, dx         ; nyni obsahuje ES bud prvni stranku Video RAM nebo stranku druhou
 
        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
        and al, 0xfe       ; nejnizsi bit urcuje lichy/sudy radek -> nyni ignorovat
        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
        stosb              ; vlastni vykresleni pixelu
 
        ret
 
 
move_half_image:
        mov bl, 100     ; pocitadlo radku
outer_loop:
        mov cx, 80/2    ; velikost bloku ve slovech
        rep movsw       ; prenest jeden obrazovy radek
        add si, 80      ; preskocit lichy/sudy radek
        dec bl
        jnz outer_loop  ; opakovat smycku BL-krat
        ret
 
 
image:
    incbin "image.bin"

17. Korektní vykreslení bílých pixelů vůči jakémukoli pozadí

Prozatím jsme pixely vykreslovali zápisem celého bajtu (což je dobře, bitový přístup do paměti možný není), ovšem tak, že se zapsal vždy jeden bílý pixel a ostatní pixely byly vybarveny černě, bez ohledu na jejich předchozí barvu:

        mov al, 0x80       ; vypocitat masku pixelu
        shr al, cl
        stosb              ; vlastni vykresleni pixelu

Ovšem aby se nepoškodilo již nakreslené pozadí, musíme namísto přepisu všech osmi bitů v bajtu provést operaci OR, kterou nastavíme jediný bit:

        mov al, 0x80       ; vypocitat masku pixelu
        shr al, cl
        or [es:di], al     ; vlastni vykresleni pixelu

Instrukce STOSB je rychlejší; nová operace je o cca 12 instrukčních cyklů delší. Ovšem to se dalo čekat, protože se provádí čtení z paměti, vlastní operace OR a následuje zpětný zápis do paměti.

Výsledek bude vypadat následovně:

Obrázek 13: Nyní je již vše v pořádku, minimálně pro bílé pixely.

Poznámka: ve skutečnosti je korektní jen zápis bílého pixelu. Pokud by se měl vykreslit černý pixel, musí maskování a prováděná operace vypadat odlišně – maska musí být invertována a namísto operace OR se provede AND. Tuto změnu si však dnes NEukážeme, to prozatím ponechám na laskavém čtenáři (a volném víkendu).

18. Úplný zdrojový kód dnešního posledního demonstračního příkladu

Dnešní poslední demonstrační příklad ve své úplné podobě (kód má již celých 129 bajtů!!!) bude vypadat následovně:

; Vykresleni pixelu, varianta bez nasobeni. Korektni maskovani.
; Pixely se prekresli pres obrazek.
;
; preklad pomoci:
;     nasm -f bin -o gfx_6.com gfx_6_putpixel_4.asm
;
; nebo pouze:
;     nasm -o gfx_6.com gfx_6_putpixel_4.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 6      ; nastaveni grafickeho rezimu 320x200 se ctyrmi barvami
 
        mov ax, cs
        mov ds, ax
        mov si, image   ; nyni DS:SI obsahuje adresu prvniho bajtu v obrazku
 
        mov ax, 0xb800
        mov es, ax
        mov di, 0       ; nyni ES:DI obsahuje adresu prvniho pixelu ve video RAM
 
        call move_half_image
 
        mov si, image+80; adresa prvniho pixelu na DRUHEM radku
        mov di, 8192    ; druha "stranka" video RAM
        call move_half_image
 
        mov ax, 0
opak:
        mov bx, ax      ; y-ová souřadnice
        push ax
        add ax, 30
        call putpixel   ; vykreslení pixelu
        pop ax
        inc ax          ; pusun x+=1, y+=1
        cmp ax, 200     ; hranice obrazovky?
        jne opak        ; ne-opakujeme
 
        wait_key
        exit
 
; Vykresleni pixelu
; AX - x-ova souradnice
; BX - y-ova souradnice (staci len BL)
putpixel:
        mov dx, 0xb800     ; zacatek prvni stranky Video RAM
        test bx, 1         ; test, zda se jedna o sudy nebo lichy radek na obrazovce
        jz odd_line
        add dx, 8192/16
odd_line:
        mov es, dx         ; nyni obsahuje ES bud prvni stranku Video RAM nebo stranku druhou
 
        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
        and al, 0xfe       ; nejnizsi bit urcuje lichy/sudy radek -> nyni ignorovat
        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
 
 
move_half_image:
        mov bl, 100     ; pocitadlo radku
outer_loop:
        mov cx, 80/2    ; velikost bloku ve slovech
        rep movsw       ; prenest jeden obrazovy radek
        add si, 80      ; preskocit lichy/sudy radek
        dec bl
        jnz outer_loop  ; opakovat smycku BL-krat
        ret
 
 
image:
    incbin "image.bin"

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

20. Odkazy na Internetu

  1. The Intel 8088 Architecture and Instruction Set
    https://people.ece.ubc.ca/~ed­c/464/lectures/lec4.pdf
  2. x86 Opcode Structure and Instruction Overview
    https://pnx.tf/files/x86_op­code_structure_and_instruc­tion_overview.pdf
  3. x86 instruction listings (Wikipedia)
    https://en.wikipedia.org/wi­ki/X86_instruction_listin­gs
  4. x86 assembly language (Wikipedia)
    https://en.wikipedia.org/wi­ki/X86_assembly_language
  5. Intel Assembler (Cheat sheet)
    http://www.jegerlehner.ch/in­tel/IntelCodeTable.pdf
  6. 25 Microchips That Shook the World
    https://spectrum.ieee.org/tech-history/silicon-revolution/25-microchips-that-shook-the-world
  7. Chip Hall of Fame: MOS Technology 6502 Microprocessor
    https://spectrum.ieee.org/tech-history/silicon-revolution/chip-hall-of-fame-mos-technology-6502-microprocessor
  8. Chip Hall of Fame: Intel 8088 Microprocessor
    https://spectrum.ieee.org/tech-history/silicon-revolution/chip-hall-of-fame-intel-8088-microprocessor
  9. Jak se zrodil procesor?
    https://www.root.cz/clanky/jak-se-zrodil-procesor/
  10. Apple II History Home
    http://apple2history.org/
  11. The 8086/8088 Primer
    https://www.stevemorse.or­g/8086/index.html
  12. flat assembler: Assembly language resources
    https://flatassembler.net/
  13. FASM na Wikipedii
    https://en.wikipedia.org/wiki/FASM
  14. Fresh IDE FASM inside
    https://fresh.flatassembler.net/
  15. MS-DOS Version 4.0 Programmer's Reference
    https://www.pcjs.org/docu­ments/books/mspl13/msdos/dos­ref40/
  16. INT 21 – DOS Function Dispatcher (DOS)
    https://www.stanislavs.or­g/helppc/int21.html
  17. DOS API (Wikipedia)
    https://en.wikipedia.org/wiki/DOS_API
  18. Bit banging
    https://en.wikipedia.org/wi­ki/Bit_banging
  19. IBM Basic assembly language and successors (Wikipedia)
    https://en.wikipedia.org/wi­ki/IBM_Basic_assembly_lan­guage_and_successors
  20. X86 Assembly/Bootloaders
    https://en.wikibooks.org/wi­ki/X86_Assembly/Bootloaders
  21. Počátky grafiky na PC: grafické karty CGA a Hercules
    https://www.root.cz/clanky/pocatky-grafiky-na-pc-graficke-karty-cga-a-hercules/
  22. 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/
  23. Karta EGA: první použitelná barevná grafika na PC
    https://www.root.cz/clanky/karta-ega-prvni-pouzitelna-barevna-grafika-na-pc/
  24. RGB Classic Games
    https://www.classicdosgames.com/
  25. Turbo Assembler (Wikipedia)
    https://en.wikipedia.org/wi­ki/Turbo_Assembler
  26. Microsoft Macro Assembler
    https://en.wikipedia.org/wi­ki/Microsoft_Macro_Assembler
  27. IBM Personal Computer (Wikipedia)
    https://en.wikipedia.org/wi­ki/IBM_Personal_Computer
  28. Intel 8251
    https://en.wikipedia.org/wi­ki/Intel_8251
  29. Intel 8253
    https://en.wikipedia.org/wi­ki/Intel_8253
  30. Intel 8255
    https://en.wikipedia.org/wi­ki/Intel_8255
  31. Intel 8257
    https://en.wikipedia.org/wi­ki/Intel_8257
  32. Intel 8259
    https://en.wikipedia.org/wi­ki/Intel_8259
  33. Support/peripheral/other chips – 6800 family
    http://www.cpu-world.com/Support/6800.html
  34. Motorola 6845
    http://en.wikipedia.org/wi­ki/Motorola_6845
  35. The 6845 Cathode Ray Tube Controller (CRTC)
    http://www.tinyvga.com/6845
  36. CRTC operation
    http://www.6502.org/users/an­dre/hwinfo/crtc/crtc.html
  37. 6845 – Motorola CRT Controller
    https://stanislavs.org/hel­ppc/6845.html
  38. The 6845 Cathode Ray Tube Controller (CRTC)
    http://www.tinyvga.com/6845
  39. Motorola 6845 and bitwise graphics
    https://retrocomputing.stac­kexchange.com/questions/10996/mo­torola-6845-and-bitwise-graphics
  40. IBM Monochrome Display Adapter
    http://en.wikipedia.org/wi­ki/Monochrome_Display_Adap­ter
  41. Color Graphics Adapter
    http://en.wikipedia.org/wi­ki/Color_Graphics_Adapter
  42. Color Graphics Adapter and the Brown color in IBM 5153 Color Display
    https://www.aceinnova.com/en/e­lectronics/cga-and-the-brown-color-in-ibm-5153-color-display/
  43. The Modern Retrocomputer: An Arduino Driven 6845 CRT Controller
    https://hackaday.com/2017/05/14/the-modern-retrocomputer-an-arduino-driven-6845-crt-controller/
  44. flat assembler: Assembly language resources
    https://flatassembler.net/
  45. FASM na Wikipedii
    https://en.wikipedia.org/wiki/FASM
  46. Fresh IDE FASM inside
    https://fresh.flatassembler.net/
  47. MS-DOS Version 4.0 Programmer's Reference
    https://www.pcjs.org/docu­ments/books/mspl13/msdos/dos­ref40/
  48. INT 21 – DOS Function Dispatcher (DOS)
    https://www.stanislavs.or­g/helppc/int21.html
  49. DOS API (Wikipedia)
    https://en.wikipedia.org/wiki/DOS_API
  50. IBM Basic assembly language and successors (Wikipedia)
    https://en.wikipedia.org/wi­ki/IBM_Basic_assembly_lan­guage_and_successors
  51. X86 Assembly/Arithmetic
    https://en.wikibooks.org/wi­ki/X86_Assembly/Arithmetic
  52. Art of Assembly – Arithmetic Instructions
    http://oopweb.com/Assembly/Do­cuments/ArtOfAssembly/Volu­me/Chapter6/CH06–2.html
  53. ASM Flags
    http://www.cavestory.org/gu­ides/csasm/guide/asm_flag­s.html
  54. Status Register
    https://en.wikipedia.org/wi­ki/Status_register
  55. Linux assemblers: A comparison of GAS and NASM
    http://www.ibm.com/develo­perworks/library/l-gas-nasm/index.html
  56. Programovani v assembleru na OS Linux
    http://www.cs.vsb.cz/gryga­rek/asm/asmlinux.html
  57. Is it worthwhile to learn x86 assembly language today?
    https://www.quora.com/Is-it-worthwhile-to-learn-x86-assembly-language-today?share=1
  58. Why Learn Assembly Language?
    http://www.codeproject.com/Ar­ticles/89460/Why-Learn-Assembly-Language
  59. Is Assembly still relevant?
    http://programmers.stackex­change.com/questions/95836/is-assembly-still-relevant
  60. Why Learning Assembly Language Is Still a Good Idea
    http://www.onlamp.com/pub/a/on­lamp/2004/05/06/writegreat­code.html
  61. Assembly language today
    http://beust.com/weblog/2004/06/23/as­sembly-language-today/
  62. Assembler: Význam assembleru dnes
    http://www.builder.cz/rubri­ky/assembler/vyznam-assembleru-dnes-155960cz
  63. Programming from the Ground Up Book – Summary
    http://savannah.nongnu.or­g/projects/pgubook/
  64. DOSBox
    https://www.dosbox.com/
  65. The C Programming Language
    https://en.wikipedia.org/wi­ki/The_C_Programming_Langu­age
  66. Hercules Graphics Card (HCG)
    https://en.wikipedia.org/wi­ki/Hercules_Graphics_Card
  67. Complete 8086 instruction set
    https://content.ctcd.edu/cou­rses/cosc2325/m22/docs/emu8086in­s.pdf
  68. Complete 8086 instruction set
    https://yassinebridi.github.io/asm-docs/8086_instruction_set.html
  69. 8088 MPH by Hornet + CRTC + DESiRE (final version)
    https://www.youtube.com/wat­ch?v=hNRO7lno_DM
  70. Area 5150 by CRTC & Hornet (Party Version) / IBM PC+CGA Demo, Hardware Capture
    https://www.youtube.com/wat­ch?v=fWDxdoRTZPc
  71. 80×86 Integer Instruction Set Timings (8088 – Pentium)
    http://aturing.umcs.maine­.edu/~meadow/courses/cos335/80×86-Integer-Instruction-Set-Clocks.pdf
Neutrální ikona do widgetu na odběr článků ze seriálů

Zajímá vás toto téma? Chcete se o něm dozvědět víc?

Objednejte si upozornění na nově vydané články do vašeho mailu. Žádný článek vám tak neuteče.


Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.