Hlavní navigace

Vývoj her a grafických dem pro oslavovanou i nenáviděnou platformu PC (vražedná kombinace 8088 a CGA)

4. 7. 2024
Doba čtení: 28 minut

Sdílet

 Autor: Depositphotos
Vývoj grafických dem a her pro jiné platformy (Atari ST, Amiga) může být zábavný, neb vývojář většinou měl pocit, že je HW navržený „příčetně“. IBM PC kombinující Intel 8088 a CGA grafiku, je opačným případem.

Obsah

1. Vývoj her a grafických dem pro oslavovanou i nenáviděnou platformu PC (vražedná kombinace 8088 a CGA)

2. Role maker v assemblerech: makroassemblery

3. Realizace jednotlivých částí programu s využitím maker

4. Výsledná „funkce main“ i celý zdrojový kód programu

5. Programátorský model mikroprocesoru Intel 8086

6. Instrukční sada 8086

7. Grafická karta MDA – Monochrome Display Adapter

8. Standardní textový režim karty MDA

9. Grafická karta CGA – Color Graphics Adapter

10. Barvová paleta karty CGA – když „color“ v samotném názvu je spíše výsměch uživateli

11. Oficiální grafické režimy karty CGA

12. Nastavení grafického režimu přes BIOS

13. Textové a grafické režimy karty CGA podporované BIOSem

14. Vykreslení pixelu přes BIOS: řešení pro pojídače koláčů

15. Vykreslení pixelu v monochromatickém režimu 640×200

16. Vykreslení pixelu ve čtyřbarevném režimu 320×200

17. Vykreslení diagonální úsečky: realizace v režimu 640×200

18. Vícebarevná úsečka v režimu 320×200

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

20. Odkazy na Internetu

1. Vývoj her a grafických dem pro oslavovanou i nenáviděnou platformu PC (vražedná kombinace 8088 a CGA)

Při vývoji aplikací pro originální IBM PC museli programátoři překonávat různé překážky, i když se na druhou stranu jednalo o dosti minimalisticky pojatou platformu, v níž byl každý použitý čip dobře zdokumentovaný (dnes sice máme k dispozici mnohem pokročilejší nástroje, zato ani zdaleka ne takovou hlubokou znalost používaných technologií). V případě IBM PC byl první překážkou samotný mikroprocesor Intel 8088 (8086), což byl čip s instrukční sadou CISC, v níž měl každý z pracovních registrů jak univerzální funkci, tak i nějaký speciální význam. I kódování instrukcí bylo typicky CISCové, takže například operace s registrem AX/AL byly zakódovány kratší sekvencí bajtů, než stejná instrukce s registrem BX/BL. Navíc bylo nutné řešit problém segmentace paměti, k němuž se pochopitelně ještě vrátíme.

Obrázek 1: Hra Spacewar používala monochromatický grafický režim s rozlišením 640×200 pixelů.

A problematický byl (vlastně již od začátku) taktéž video subsystém IBM PC, protože k dispozici byly hned dvě vzájemně nekompatibilní video karty – MDA (pro textový výstup s rozumným rozlišením, ovšem zcela postrádající bitmapové režimy) a CGA (pro grafický výstup, ovšem s menším rozlišením a „divnou“ barvovou paletou, která je pro CGA zcela typická a nezaměnitelná). A aby toho nebylo málo, tak rok po vydání IBM PC, tedy konkrétně v roce 1982, začala být prodávána grafická karta Hercules, která nabízela grafický režim s vysokým rozlišením (na dobu vzniku), ale nebyla s CGA kompatibilní a navíc ho firma IBM v BIOSech ostentativně ignorovala. K této problematice se samozřejmě ještě vrátíme.

Obrázek 2: Jedna ze dvou nezapomenutelných barvových palet karty CGA: black, cyan, magenta, white (obrázek ke hře Super Space Invaders).

2. Role maker v assemblerech: makroassemblery

Překážkou či určitou komplikací při vývoji mohl být i samotný assembler. Zde ovšem máme k dispozici minimálně dvě techniky umožňující tvorbu rozsáhlejších aplikací. První technikou je tvorba procedur (nebo, chcete-li, funkcí), druhou technikou pak podpora maker. A právě s makry, konkrétně s makry realizovanými v assembleru NASM, se ve stručnosti seznámíme v dalším textu.

Nástroje typu „assembler“ je možné podle principu jejich práce rozdělit do několika kategorií. Do první kategorie spadají assemblery interaktivní, které uživateli nabízejí poměrně komfortní vývojové prostředí, v němž je v případě potřeby možné zapisovat jednotlivé instrukce, spouštět programy, krokovat je, vypisovat obsahy pracovních registrů mikroprocesoru, prohlížet si obsah operační paměti, zásobníku atd. Velkou výhodou byla nezávislost těchto assemblerů na rychlém externím paměťovém médiu, proto jsme se s nimi mohli setkat například na osmibitových domácích mikropočítačích či dnes na různých zařízeních typu IoT (i když zde úlohu pouhého interaktivního assembleru mnohdy přebírá interaktivní debugger).

Obrázek 3: Alley Cat v podání karty CGA.

Druhý typ assemblerů je široce používán dodnes – jedná se vlastně o běžné překladače, kterým se na vstupu předloží zdrojový kód a po překladu se výsledný nativní kód taktéž uloží na paměťové médium (odkud ho lze přímo spustit, což se dělo například v operačním systému DOS, popř. ho ještě před spuštěním slinkovat, což je případ Linuxu a dalších moderních operačních systémů).

Obrázek 4: Alley Cat na osmibitovém Atari – mnohem levnější a méně výkonný počítač s lepší grafikou :-)

Assemblery spadající do druhé kategorie jsou mnohdy vybaveny více či méně sofistikovaným systémem maker; odtud ostatně pochází i jejich často používané označení macroassembler. Makra, která se většinou aplikují na zdrojový kód v první fázi překladu, je možné použít pro různé činnosti, ať již se jedná o zjednodušení zápisu kódu či o jeho zkrácení a zpřehlednění. Existují například sady poměrně složitých maker, která do assembleru přidávají některé konstrukce známé z vyšších programovacích jazyků – rozvětvení, programové smyčky, deklaraci objektů atd. Netwide assembler, podobně jako prakticky všechny další moderní assemblery, práci s makry podporují, i když se způsob zápisu maker i jejich základní vlastnosti od sebe odlišují.

3. Realizace jednotlivých částí programu s využitím maker

Pokusme se nyní přepsat náš program typu „Hello, world!“ do podoby, v níž se využijí makra. Původní program, který na obrazovku vypsal zprávu a následně čekal na stisk klávesy, vypadal následovně:

org  0x100        ; zacatek kodu pro programy typu COM (vzdy se zacina na 256)
 
start:
        ; tisk retezce na obrazovku
        mov     dx, message
        mov     ah, 9
        int     0x21
 
        ; vyprazdneni bufferu klavesnice a cekani na klavesu
        xor     ax, ax
        int     0x16
 
        ; ukonceni procesu a navrat do DOSu
        mov     ah, 0x4c
        int     0x21
 
        ; retezec ukonceny znakem $
message db "Hello, world!", 0x0d, 0x0a, "$"

Tři části programu přepíšeme do podoby maker. Začneme druhou částí, kterou lze přepsat do makra bez parametrů:

; vyprazdneni bufferu klavesnice a cekani na klavesu
%macro wait_key 0
        xor     ax, ax
        int     0x16
%endmacro
Poznámka: hodnota 0 za jménem makra určuje počet parametrů.

Stejným způsobem vytvoříme makro pro poslední části s voláním funkcí DOSu pro ukončení procesu:

; ukonceni procesu a navrat do DOSu
%macro exit 0
        mov     ah, 0x4c
        int     0x21
%endmacro

Makro pro tisk zprávy na obrazovku je složitější, neboť vyžaduje jeden parametr – adresu zprávy, která se má vypsat. Samotný parametr je v těle makra reprezentován symbolem %1:

; tisk retezce na obrazovku
%macro print 1
        mov     dx, %1
        mov     ah, 9
        int     0x21
%endmacro

Obrázek 5: Boulder Dash na PC s CGA.

Obrázek 6: Boulder Dash na osmibitovém Atari.

4. Výsledná „funkce main“ i celý zdrojový kód programu

Celá hlavní část programu se díky použití maker zmenšila na pouhou expanzi tří maker, z nichž první makro akceptuje parametr – adresu zprávy, která se má vypsat. Další dvě makra žádné parametry nemají:

start:
        print message
        wait_key
        exit

Takto vypadá celý zdrojový kód programu typu „Hello, world“ po přepisu do podoby založené na použití maker:

; Program typu "Hello, world!" urceny pro DOS a prelozitelny assemblerem NASM
;
; preklad pomoci:
;     nasm -f bin -o hello.com hello_macros.asm
;
; nebo pouze:
;     nasm -o hello.com hello_macros.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
 
; tisk retezce na obrazovku
%macro print 1
        mov     dx, %1
        mov     ah, 9
        int     0x21
%endmacro
 
;-----------------------------------------------------------------------------
org  0x100        ; zacatek kodu pro programy typu COM (vzdy se zacina na 256)
 
start:
        print message
        wait_key
        exit
 
        ; retezec ukonceny znakem $
message db "Hello, world!", 0x0d, 0x0a, "$"

5. Programátorský model mikroprocesoru Intel 8086

Programátorský model mikroprocesoru Intel 8086 do určité míry vychází z jeho předchůdců, tedy z čipů 8080 a 8085. Došlo ovšem k rozšíření sady registrů, k určité unifikaci jejich role (což zjednodušilo instrukční sadu) a k rozšíření pracovních registrů na šířku šestnácti bitů. Navíc se rozšířily adresovací režimy a při adresování se kromě základní 16bitové adresy počítá i adresa segmentu získaná z registrů CS, DS, ES či SS. Oproti 8080 je zde tedy výrazný skok vpřed, ovšem v porovnání s dalšími mikroprocesory této éry patří 8086 spíše mezi jednodušší mikroprocesory (což ovšem nemusí být vždy špatně).

Pracovat je možné s těmito čtrnácti registry:

# Typ registrů Počet registrů Bitová šířka registru Názvy registrů
1 Univerzální registry 4 16 bitů AX, BX, CX, DX
2 Indexové registry 2 16 bitů SI, DI
3 Bázové registry 2 16 bitů BP, SP
4 Segmentové registry 4 16 bitů CS, DS, ES, SS
5 Příznakový registr 1 16 bitů FLAGS
6 Programový čítač 1 16 bitů IP

První čtyři registry jsou sice nazvány univerzální, ovšem jejich role není zcela zaměnitelná. Každý z těchto registrů má totiž kromě své základní role ještě další roli/role a vystupuje jako implicitní operand u mnoha instrukcí (instrukční sada není v žádném případě ortogonální, naopak se jedná o snad nejméně ortogonální sadu v oblasti 16bitových čipů):

Registr Rozdělení Význam
AX AH/AL akumulátor
BX BH/BL bázová adresa
CX CH/CL čítač (counter)
DX DH/DL data, rozšíření akumulátoru

6. Instrukční sada 8086

Dnešní čipy řady x86 a x86–64 obsahují stovky instrukcí, ovšem původní čip 8086 podporoval cca 120 instrukcí, které jsou vypsány v následující tabulce:

AAA      CMPSB     JA        JNC     LAHF      MUL      REP     SCASB
AAD      CMPSW     JAE       JNE     LDS       NEG      REPE    SCASW
AAM      CWD       JB        JNG     LEA       NOP      REPNE   SHL
AAS      DAA       JBE       JNGE    LES       NOT      REPNZ   SHR
ADC      DAS       JC        JNL     LODSB     OR       REPZ    STC
ADD      DEC       JCXZ      JNLE    LODSW     OUT      RET     STD
AND      DIV       JE        JNO     LOOP      POP      RETF    STI
CALL     HLT       JG        JNP     LOOPE     POPA     ROL     STOSB
CBW      IDIV      JGE       JNS     LOOPNE    POPF     ROR     STOSW
CLC      IMUL      JL        JNZ     LOOPNZ    PUSH     SAHF    SUB
CLD      IN        JLE       JO      LOOPZ     PUSHA    SAL     TEST
CLI      INC       JMP       JP      MOV       PUSHF    SAR     XCHG
CMC      INT       JNA       JPE     MOVSB     RCL      SBB     XLATB
CMP      INTO      JNAE      JPO     MOVSW     RCR              XOR
         IRET      JNB       JS
                   JNBE      JZ
Poznámka: s mnoha těmito instrukcemi se setkáme v následujícím textu, ovšem některé z nich jsou pro většinu operací příliš obskurní a tak je vynecháme (například AAA, AAM, …). A některé jiné instrukce jsou velmi pomalé, takže se vyplatí je nahradit sekvencí instrukcí jiných (MUL, DIV).

7. Grafická karta MDA – Monochrome Display Adapter

Jak jsme si již řekli v úvodním článku, nabízela společnost IBM do svých prvních osobních počítačů (IBM) PC buď grafickou kartu MDA (Monochrome Display Adapter), nebo grafickou kartu CGA (Color Graphics Adapter). Dokonce bylo možné, aby byly v jednom počítači současně nainstalovány obě zmíněné karty, protože ani adresy jejich řídicích registrů – portů, ani adresní rozsah video paměti, se nepřekrývaly – což ovšem byla v tehdejší době konfigurace z říše snů vyžadující dva odlišné monitory. Počátek výroby obou zmíněných typů karet se datuje do roku 1981, na což je důležité myslet především při snaze o porovnání s počítači, které vyšly v roce 1984 a 1985: Atari ST, Amiga a Macintosh a které tedy musely nabídnout mnohem lepší grafické možnosti (je ostatně typické, že jen IBM PC mělo skutečný textový režim).

pc83

Obrázek 7: Grafická karta MDA s čipem MC6845.

Grafická karta MDA se od prakticky všech dalších grafických adaptérů vyráběných pro počítače IBM PC odlišovala především v tom, že neumožňovala vykreslování rastrové grafiky (označení termínem „grafická karta“ je tedy poněkud nepřesné nebo minimálně zavádějící), jelikož podporovala pouze textový režim 80×25 znaků, který je používán například při startu počítače či v operačním systému MS-DOS. Teoreticky by však mělo být možné pracovat s graficko-textovou :-) kartou MDA i pod systémy Linux či Open/Free BSD, například pro řízení zobrazování na druhém monitoru u starších systémů vybavených sběrnicí ISA (v moderních PC se pro zobrazení na více monitorech využívá poněkud odlišná technologie, takže se dnes již jedná jen o teorii). V minulosti se – zejména právě v dobách kralování DOSu – pro tuto činnost nejčastěji používaly výprodejové karty typu Hercules, protože i ty byly navrženy takovým způsobem, aby jejich řídicí porty ani adresy video paměti nekolidovaly s primární grafickou kartou.

Obrázek 8: Fotografie obrazovky počítače IBM PC se spuštěným interpretrem BASICu, v němž je napsán velmi jednoduchý program.

Jednoznačnou (a kromě slušného rozlišení vlastně i jedinou) předností této grafické karty je způsob namapování do adresního prostoru procesoru. Karta totiž využívala segment začínající adresou b000:0000 (používám zde známé Intelovské šestnáctibitové adresování typu segment:offset), který nebyl na dalších grafických kartách využit. Proto bylo možné tuto kartu kombinovat s kartou jinou a vytvořit tak vícemonitorový systém, který využívaly aplikace jako AutoCAD (grafická plocha a terminál s příkazovým řádkem), Turbo Pascal (vývojové prostředí zobrazené spolu s laděnou aplikací), Turbo C++, Lotus 1–2–3 apod. V praxi bylo možné použít například kombinace grafických karet CGA+MDA, EGA+MDA a později i VGA+MDA. Vzhledem k tomu, že firma IBM tuto kartu přestala po několika letech vyrábět, převzal úlohu sekundární grafické karty její konkurent Hercules (viz navazující článek), který kromě zobrazení textového režimu podporoval i režim grafický.

Obrázek 9: Úvodní obrazovka GW-BASICu po jeho spuštění v emulátoru PC (zde se konkrétně jedná o DOSBOX).

8. Standardní textový režim karty MDA

Při zobrazování znaků v textovém režimu 80×25 znaků byl každý znak definovaný v×masce 9×14 pixelů, což znamená, že rozlišení obrazovky bylo rovno 720×350 pixelům (samozřejmě ovšem nebylo možné pixely přímo adresovat). Poměrně velké horizontální rozlišení (a tím i velmi dobře čitelný text) bylo dále použito až u grafických karet Hercules a VGA o několik let později (grafické karty CGA a EGA byly v tomto ohledu zklamáním, zejména pro uživatele pracující převážně v textovém režimu). Znaková sada byla na grafické kartě uložena v paměti ROM, což znamená, že se při požadavku na zobrazení textů v jazycích s nabodeníčky (jedná se o prakticky všechny jazyky kromě angličtiny) musela tato paměť vyměnit za EPROM (typ 2764 případně 27C64) s vypálenou národní znakovou sadou (původní znaková sada dodávaná firmou IBM odpovídá kódové stránce 437, tj. jedná se o „rozšířenou“ ASCII tabulku). Každý znak na obrazovce měl k dispozici i svůj atributový byte, ve kterém bylo specifikováno, zda se má tento znak zobrazit normálně, zvýrazněně (větší intenzita), s podtržením, inverzně či zda by měl blikat; dokonce bylo možné nastavit i některé kombinace těchto atributů. Barevné atributy znaků byly použity (i když s poněkud jiným významem) i u dalších grafických karet na PC.

Obrázek 10: Tabulkový procesor VisiCalc spuštěný v DOSu (resp. přesněji řečeno v jeho emulátoru). Jednalo se o jednu z takzvaných „killer application“ pro PC, která plně podporovala i kartu MDA.

Kapacita video paměti (tedy vlastně „textové“ paměti) na této kartě byla rovna čtyřem kilobajtům, přičemž přesně 2000 bytů bylo zapotřebí pro uložení všech 80×25 znaků a dalších 2000 bytů pro uložení jejich atributů (z pohledu programátora se ukládala vždy dvojice znak-atribut, tj. jednalo se o souvislou oblast paměti, i když fyzicky byly použity dva oddělené paměťové čipy), zbylých 96 bytů bylo nevyužito. Zajímavé jsou signálové poměry, kterými se musely řídit připojené monitory. Snímková frekvence byla rovna 50 Hz, řádková frekvence 18,432 kHz (tj. tato frekvence byla poněkud vyšší než u dále popisované grafické karty CGA). Při prvním pohledu na údaj o snímkovém kmitočtu to může vypadat tak, že 50 Hz je pro práci na počítači naprosto nedostatečné, musíme si však uvědomit, že se ponejvíce používalo tmavé pozadí, na kterém není poblikávání obrazu tak patrné, jako na pozadí světlém či dokonce bílém.

Obrázek 11: Textový editor SpeedScript pro IBM PC (DOS).

9. Grafická karta CGA – Color Graphics Adapter

První dostupnou grafickou kartou s oficiální podporou zobrazování rastrové grafiky na osobních počítačích typu IBM PC byla grafická karta CGA, což je označení, které vzniklo z celého názvu Color Graphics Adapter. Tato karta, jež byla jako druhý standard uvedena (spolu s výše popsanou kartou MDA) v roce 1981, oficiálně podporuje celkem dva grafické režimy a dva režimy textové. Kromě toho je však pro televizní výstup použit třetí grafický režim a vhodnou manipulací s řídicími registry lze vytvořit i další textové, grafické či smíšené režimy (v nichž je modifikovaný textový režim použitý pro zobrazení rastrového obrazu, pochopitelně se sníženým horizontálním i vertikálním rozlišením.

pc83

Obrázek 12: Grafický režim 320×200 se čtyřmi barvami (známá hra King's Quest). Jak je z tohoto obrázku patrné, je malý počet barev kompenzován ditheringem, který ovšem při relativně malém rozlišení situaci snad ještě více zhoršuje. Poněkud paradoxní je, že většina rozšířených osmibitových počítačů dokáže – a to dokonce s poloviční velikostí obrazové paměti – tento obrázek zobrazit mnohem lépe.

Vzhledem k omezení tohoto grafického adaptéru, který byl způsobem velmi nízkou řádkovou frekvencí (pouhých 15,75 kHz), bylo možné zobrazit pouze 200 obrazových řádků, a to i v textových režimech. Z tohoto důvodu jsou jednotlivé masky znaků definovány v rastru pouhých 8×8 pixelů, tedy podobně jako u mnohých osmibitových počítačů (Atari, C64 atd.). První znakový režim dokázal zobrazit 40 znaků na textovém řádku, počet textových řádků byl roven 25. Ve druhém textovém režimu bylo možné zobrazit 80 znaků na řádku. Každý znak mohl mít přiřazenou jednu ze šestnácti předdefinovaných barev, pozadí znaku bylo možné zvolit také ze šestnácti barev, nebo pouze z osmi barev v případě, že se jeden bit atributu rezervoval pro blikání (to bylo řešeno mimo 6845). Jak barva popředí, tak i barva pozadí byly zapsány do takzvaného atributu, který měl velikost jeden byte.

pc83

Obrázek 13: Pro porovnání – tentýž obrázek, ovšem zobrazený v grafickém režimu 320×200 s barvami šestnácti na modernější grafické kartě (EGA, VGA).

10. Barvová paleta karty CGA – když „color“ v samotném názvu je spíše výsměch uživateli

Zajímavá je barvová paleta karty CGA. Ta obsahuje šestnáct barev, přičemž ze základních osmi barev jsou odvozeny barvy s 2/3 intenzitou složek (tedy tmavší barvy). To však znamenalo, že existovaly dvě černé barvy (2/3 z černé je stále černá) a tmavě žlutá barva, která vypadala škaredě. Z tohoto důvodu byla provedena úprava v zapojení monitoru tak, že namísto druhé černé barvy je světle šedá a namísto tmavé žluté hnědá barva. Tato úprava se (nyní již přímo na grafických kartách) dochovala dodnes.

Poznámka: podobné patche, které provází celou historii IBM PC, mě fascinují.

Ovšem mnohem důležitější jsou výběry barev pro čtyřbarevný grafický režim. Nebylo možné vybrat jakékoli barvy, ale jen barvy vybrané IBM (a jedná se o „divné“ kombinace, což uvidíme na screenshotech a zmíníme se o nich hned v další kapitole):

Paleta číslo 0 = green, red, brown
Paleta číslo 1 = cyan, magenta, white

11. Oficiální grafické režimy karty CGA

Mnohem zajímavější a flexibilnější než textové režimy jsou (alespoň zdánlivě) režimy grafické, která grafická karta CGA také podporovala. Oficiálně jsou podle dokumentace IBM podporovány pouze dva grafické režimy. V prvním grafickém režimu bylo možné zobrazit obraz v rastru 320×200 pixelů ve čtyřech barvách, druhý režim měl rozlišení 640×200 pixelů dvoubarevně.

V grafickém režimu o rozlišení 320×200 pixelů mohl každý pixel nabývat jedné ze čtyř barev, které byly vybrány z barvové palety. Tato paleta však nemohla být libovolná (z předchozího textu víme, že v textovém režimu je možné použít šestnáct barev), protože existovaly pouze dvě fixní barevné 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.

Obrázek 14: Slavná hra Lemmings v režimu 320×200 se čtyřmi barvami.

Čtvrtá barva byla při práci s BIOSem (přesněji řečeno při používání služeb BIOSu, například přechodu do grafického režimu) vždy nastavena na černou; ve skutečnosti se však přes řídicí registry grafické karty dala tato barva (jako jediná) nastavit na jednu ze šestnácti předdefinovaných barev. Tuto poměrně zajímavou možnost však, vzhledem k nedostupnosti technických informací, mnoho aplikací nevyužívalo. Kapacita obrazové paměti v tomto režimu byla rovna 320×200/8×2=16000 bytům, což znamenalo, že adresovací schopnosti čipu Motorola MC6845 byly využity jen částečně – ve skutečnosti se v grafických režimech používalo pouze třináct bitů adresy textových řádků (viz předchozí kapitoly s popisem tohoto čipu), přičemž výška textových řádků musela být nastavena na dva obrazové řádky.

Ve druhém grafickém režimu o rozlišení 640×200 pixelů mohl každý pixel nabývat pouze jedné ze dvou barev, které jsou při inicializaci tohoto režimu pomocí BIOSu nastaveny na černou a bílou. S využitím služeb BIOSu tyto barvy nastavit nelze, ale pomocí změny konfiguračních registrů je to možné – lze tak generovat například zeleno-červený obraz či libovolnou jinou kombinaci šestnácti základních barev (což opět nebylo využíváno). Kapacita obrazové paměti byla při použití tohoto režimu rovna 640×200/8=16000 bytům, tj. naprosto stejně, jako v předchozím grafickém režimu. Kapacita obrazové paměti byla z tohoto důvodu 16kB, přičemž posledních 384 bajtů nebylo grafickým systémem využíváno.

p83_

Obrázek 15: Známá hra Arcade Voleyball pro dva hráče taktéž využívá čtyřbarevný grafický režim karty CGA.

12. Nastavení grafického režimu přes BIOS

Grafické režimy je možné nastavit dvěma způsoby. První způsob spočívá ve změně řídicích registrů karty CGA, což je téma, ke kterému se ještě vrátíme. Tento způsob vyžaduje hlubší znalosti čipu Motorola 6845 i dalších čipů, z nichž se karta CGA skládá. A pouze některé možnosti jsou v mezích možností monitorů (s fixními frekvencemi).

Druhý způsob je mnohem jednodušší – grafický režim se změní službou BIOSu, konkrétně službou číslo 0 ze skupiny služeb pro obsluhu obrazovky. Služby z této skupiny jsou vyvolány programovým přerušením číslo 0×10, přičemž identifikace služby je předána v registru AH. Číslo grafického režimu je předáno v registru AL. To tedy znamená, že pro nastavení grafického režimu provedeme tyto tři instrukce:

  • AH=0 (číslo služby)
  • AL=číslo textového či grafického režimu
  • INT 0×10 (INT 16)

Připravme si pro tyto instrukce potřebné makro s jediným parametrem, kterým je číslo textového či grafického režimu:

; nastaveni grafickeho rezimu
%macro gfx_mode 1
        mov     ah, 0
        mov     al, %1
        int     0x10
%endmacro

13. Textové a grafické režimy karty CGA podporované BIOSem

Standardní BIOS podporoval (a dodnes podporuje!) následující textové a grafické režimy kompatibilní s grafickou kartou CGA:

Číslo (AL) Typ Rozlišení Segment
00 text, mono 40×25 0×b800
01 text, barvy 40×25 0×b800
02 text, mono 80×25 0×b800
03 text, barvy 80×25 0×b800
04 grafika, 4 barvy 320×200 0×b800
05 grafika, 4 mono 320×200 0×b800
06 grafika, B/W 640×200 0×b800
Poznámka: rozlišení monochromatického či barevného režimu je většinou zbytečné, záleží na konkrétním monitoru. To znamená, že máme k dispozici vlastně jen čtyři režimy:
  1. Textový 40×25 znaků (hodně štěstí)
  2. Textový 80×25 znaků
  3. Čtyřbarevný 320×200 pixelů s výběrem jedné ze dvou palet (viz předchozí text)
  4. Monochromaticky 640×200 pixelů s možností výběru barvy (viz předchozí text)

Ve všech případech se pracuje s obrazovou pamětí o kapacitě 16384 bajtů, přičemž v grafice je využito přesně 16000 bajtů, nezávisle na zvoleném režimu.

14. Vykreslení pixelu přes BIOS: řešení pro pojídače koláčů

Nyní již dokážeme nastavit grafický režim, takže si ukažme, jak se vykreslí jednotlivé pixely. Nejprve zvolíme ten nejjednodušší a současně i nejpomalejší způsob – vykreslení pixelu přes službu BIOSu. Tento způsob je skutečně velmi pomalý a nenajdeme ho v prakticky žádné hře, na druhou stranu nám však umožní alespoň si otestovat základní možnosti CGA.

Pro vykreslení jednotlivých pixelů je určena služba číslo 0×c patřící do stejné skupiny, jako služba pro nastavení grafického režimu (tedy 0×10). Nyní je ovšem nutné nastavit více registrů: barvu pixelu v AL, sloupec v registru CX a řádek v registru DX. Opět si pro tento účel připravíme jednoduché makro, které bude mít tři parametry:

; vykresleni pixelu pres BIOS
%macro put_pixel 3
        mov     ah, 0xc   ; cislo sluzby
        xor     bx, bx    ; cislo stranky
        mov     cx, %1    ; sloupec (X)
        mov     dx, %2    ; radek (Y)
        mov     al, %3    ; barva pixelu
        int     0x10      ; zavolani BIOSu
%endmacro

15. Vykreslení pixelu v monochromatickém režimu 640×200

Nyní si již můžeme připravit program, který poblíž středu obrazovky, konkrétně na souřadnice [320, 100] vykreslí pixel v monochromatickém režimu s rozlišením 640×200 pixelů. Jedná se o pomalé, ale zato velmi triviální řešení:

; Vykresleni pixelu tou nejpomalejsi cestou - pres funkci BIOSu
;
; preklad pomoci:
;     nasm -f bin -o gfx_6.com gfx_6_putpixel.asm
;
; nebo pouze:
;     nasm -o gfx_6.com gfx_6_putpixel.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
 
; vykresleni pixelu pres BIOS
%macro put_pixel 3
        mov     ah, 0xc
        xor     bx, bx    ; cislo stranky
        mov     cx, %1    ; sloupec (X)
        mov     dx, %2    ; radek (Y)
        mov     al, %3    ; barva pixelu
        int     0x10
%endmacro
 
;-----------------------------------------------------------------------------
org  0x100        ; zacatek kodu pro programy typu COM (vzdy se zacina na 256)
 
start:
        gfx_mode 6
        put_pixel 320, 100, 1
        wait_key
        exit
Poznámka: korektnější by bylo použít souřadnice [319, 99], to však vypadá nehezky :-)

Obrázek 16: Výsledná obrazovka po vykreslení pixelu.

16. Vykreslení pixelu ve čtyřbarevném režimu 320×200

Ve čtyřbarevném režimu karty CGA budeme používat naprosto stejný postup, jako v režimu monochromatickém. Jediným rozdílem je, že při vykreslení pixelu lze v registru AL předávat hodnoty 0 až 3 a nikoli pouze 0 až 1. A samozřejmě je sníženo horizontální rozlišení na 320 pixelů z původních 640 pixelů:

; Vykresleni pixelu tou nejpomalejsi cestou - pres funkci BIOSu
;
; preklad pomoci:
;     nasm -f bin -o gfx_4.com gfx_4_putpixel.asm
;
; nebo pouze:
;     nasm -o gfx_4.com gfx_4_putpixel.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
 
; vykresleni pixelu pres BIOS
%macro put_pixel 3
        mov     ah, 0xc
        xor     bx, bx    ; cislo stranky
        mov     cx, %1    ; sloupec (X)
        mov     dx, %2    ; radek (Y)
        mov     al, %3    ; barva pixelu
        int     0x10
%endmacro
 
;-----------------------------------------------------------------------------
org  0x100        ; zacatek kodu pro programy typu COM (vzdy se zacina na 256)
 
start:
        gfx_mode 4
        put_pixel 160, 100, 1
        wait_key
        exit

Obrázek 17: Výsledná obrazovka po vykreslení pixelu.

17. Vykreslení diagonální úsečky: realizace v režimu 640×200

Pro vykreslení úseček již ve standardním BIOSu žádná služba neexistuje, ovšem relativně snadno je možné vykreslit horizontální, vertikální či diagonální úsečky. Vyzkoušejme si tedy vykreslení diagonální úsečky v monochromatickém režimu 640×200 pixelů. Z výsledného obrázku bude zřejmé, jaký je tvar pixelu (není pochopitelně čtvercový, ale má přibližné relativní rozměry 1×2). Pro vykreslení úsečky budeme opakovaně volat službu BIOSu pro vykreslení pixelu, což je pochopitelně velmi pomalé řešení. Povšimněte si, že počítanou smyčku můžeme realizovat s využitím jakéhokoli pracovního registru jako počitadla, i když ideální je použít registr CL či CX, k čemuž se ještě vrátíme:

Obrázek 18: Výsledná obrazovka po vykreslení úsečky (v žádném případě tato úsečka nemá směrnici 45°.

; Vykresleni usecky tou nejpomalejsi cestou - pres funkci BIOSu
;
; preklad pomoci:
;     nasm -f bin -o gfx_6.com gfx_6_putpixel.asm
;
; nebo pouze:
;     nasm -o gfx_6.com gfx_6_putpixel.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
 
        mov     ah, 0xc
        mov     al, 1     ; barva pixelu
        xor     bx, bx    ; cislo stranky
        mov     cx, 0     ; sloupec
        mov     dx, 0     ; radek
opak:
        int     0x10
        inc     cx        ; x+=1
        inc     dx        ; y+=1 (lze i pouhý přesun cx->dx)
        cmp     cx, 200   ; kontrola, zda jsme dosahli posledni souradnice
        jne     opak      ; pokud ne, dalsi iterace
 
        wait_key
        exit

18. Vícebarevná úsečka v režimu 320×200

Dnešní poslední demonstrační příklad vykreslí vícebarevnou úsečku ve čtyřbarevném režimu karty CGA s rozlišením 320×200 pixelů:

Obrázek 19: Výsledná obrazovka po vykreslení úsečky.

CS24_early

Zdrojový kód tohoto příkladu je prakticky totožný s příkladem předchozím, ovšem odlišuje se nastavení grafického režimu a taktéž průběžná změna hodnoty registru AL:

; Vykresleni usecky tou nejpomalejsi cestou - pres funkci BIOSu
;
; preklad pomoci:
;     nasm -f bin -o gfx_4.com gfx_4_putpixel.asm
;
; nebo pouze:
;     nasm -o gfx_4.com gfx_4_putpixel.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 5
 
        mov     ah, 0xc
        mov     al, 1     ; barva pixelu
        xor     bx, bx    ; cislo stranky
        mov     cx, 0     ; sloupec
        mov     dx, 0     ; radek
opak:
        int     0x10
        inc     al        ; změna barvy pixelu
        inc     cx        ; x+=1
        inc     dx        ; y+=1
        cmp     cx, 200   ; kontrola, zda jsme dosahli posledni souradnice
        jne     opak      ; pokud ne, dalsi iterace
 
        wait_key
        exit

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

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

Byl pro vás článek přínosný?

Autor článku

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