Obsah
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
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
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
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
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).
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.
![](http://i.iinfo.cz/images/173/editors-3-2-13.png)
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](http://i.iinfo.cz/images/559/pc83-4.png)
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](http://i.iinfo.cz/images/559/pc83-5.png)
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.
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.
![Autor: third_party, podle licence: <a href="http://en.wikipedia.org/wiki/Rights_Managed">Rights Managed</a>](https://i.iinfo.cz/images/405/6845-8.png)
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_](http://i.iinfo.cz/images/407/p83-1.gif)
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 |
- Textový 40×25 znaků (hodně štěstí)
- Textový 80×25 znaků
- Čtyřbarevný 320×200 pixelů s výběrem jedné ze dvou palet (viz předchozí text)
- 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
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.
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ář:
20. Odkazy na Internetu
- The Intel 8088 Architecture and Instruction Set
https://people.ece.ubc.ca/~edc/464/lectures/lec4.pdf - x86 Opcode Structure and Instruction Overview
https://pnx.tf/files/x86_opcode_structure_and_instruction_overview.pdf - x86 instruction listings (Wikipedia)
https://en.wikipedia.org/wiki/X86_instruction_listings - x86 assembly language (Wikipedia)
https://en.wikipedia.org/wiki/X86_assembly_language - Intel Assembler (Cheat sheet)
http://www.jegerlehner.ch/intel/IntelCodeTable.pdf - 25 Microchips That Shook the World
https://spectrum.ieee.org/tech-history/silicon-revolution/25-microchips-that-shook-the-world - Chip Hall of Fame: MOS Technology 6502 Microprocessor
https://spectrum.ieee.org/tech-history/silicon-revolution/chip-hall-of-fame-mos-technology-6502-microprocessor - Chip Hall of Fame: Intel 8088 Microprocessor
https://spectrum.ieee.org/tech-history/silicon-revolution/chip-hall-of-fame-intel-8088-microprocessor - Jak se zrodil procesor?
https://www.root.cz/clanky/jak-se-zrodil-procesor/ - Apple II History Home
http://apple2history.org/ - The 8086/8088 Primer
https://www.stevemorse.org/8086/index.html - flat assembler: Assembly language resources
https://flatassembler.net/ - FASM na Wikipedii
https://en.wikipedia.org/wiki/FASM - Fresh IDE FASM inside
https://fresh.flatassembler.net/ - MS-DOS Version 4.0 Programmer's Reference
https://www.pcjs.org/documents/books/mspl13/msdos/dosref40/ - INT 21 – DOS Function Dispatcher (DOS)
https://www.stanislavs.org/helppc/int21.html - DOS API (Wikipedia)
https://en.wikipedia.org/wiki/DOS_API - Bit banging
https://en.wikipedia.org/wiki/Bit_banging - IBM Basic assembly language and successors (Wikipedia)
https://en.wikipedia.org/wiki/IBM_Basic_assembly_language_and_successors - X86 Assembly/Bootloaders
https://en.wikibooks.org/wiki/X86_Assembly/Bootloaders - Počátky grafiky na PC: grafické karty CGA a Hercules
https://www.root.cz/clanky/pocatky-grafiky-na-pc-graficke-karty-cga-a-hercules/ - Co mají společného Commodore PET/4000, BBC Micro, Amstrad CPC i grafické karty MDA, CGA a Hercules?
https://www.root.cz/clanky/co-maji-spolecneho-commodore-pet-4000-bbc-micro-amstrad-cpc-i-graficke-karty-mda-cga-a-hercules/ - Karta EGA: první použitelná barevná grafika na PC
https://www.root.cz/clanky/karta-ega-prvni-pouzitelna-barevna-grafika-na-pc/ - RGB Classic Games
https://www.classicdosgames.com/ - Turbo Assembler (Wikipedia)
https://en.wikipedia.org/wiki/Turbo_Assembler - Microsoft Macro Assembler
https://en.wikipedia.org/wiki/Microsoft_Macro_Assembler - IBM Personal Computer (Wikipedia)
https://en.wikipedia.org/wiki/IBM_Personal_Computer - Intel 8251
https://en.wikipedia.org/wiki/Intel_8251 - Intel 8253
https://en.wikipedia.org/wiki/Intel_8253 - Intel 8255
https://en.wikipedia.org/wiki/Intel_8255 - Intel 8257
https://en.wikipedia.org/wiki/Intel_8257 - Intel 8259
https://en.wikipedia.org/wiki/Intel_8259 - Support/peripheral/other chips – 6800 family
http://www.cpu-world.com/Support/6800.html - Motorola 6845
http://en.wikipedia.org/wiki/Motorola_6845 - The 6845 Cathode Ray Tube Controller (CRTC)
http://www.tinyvga.com/6845 - CRTC operation
http://www.6502.org/users/andre/hwinfo/crtc/crtc.html - 6845 – Motorola CRT Controller
https://stanislavs.org/helppc/6845.html - The 6845 Cathode Ray Tube Controller (CRTC)
http://www.tinyvga.com/6845 - Motorola 6845 and bitwise graphics
https://retrocomputing.stackexchange.com/questions/10996/motorola-6845-and-bitwise-graphics - IBM Monochrome Display Adapter
http://en.wikipedia.org/wiki/Monochrome_Display_Adapter - Color Graphics Adapter
http://en.wikipedia.org/wiki/Color_Graphics_Adapter - Color Graphics Adapter and the Brown color in IBM 5153 Color Display
https://www.aceinnova.com/en/electronics/cga-and-the-brown-color-in-ibm-5153-color-display/ - The Modern Retrocomputer: An Arduino Driven 6845 CRT Controller
https://hackaday.com/2017/05/14/the-modern-retrocomputer-an-arduino-driven-6845-crt-controller/ - flat assembler: Assembly language resources
https://flatassembler.net/ - FASM na Wikipedii
https://en.wikipedia.org/wiki/FASM - Fresh IDE FASM inside
https://fresh.flatassembler.net/ - MS-DOS Version 4.0 Programmer's Reference
https://www.pcjs.org/documents/books/mspl13/msdos/dosref40/ - INT 21 – DOS Function Dispatcher (DOS)
https://www.stanislavs.org/helppc/int21.html - DOS API (Wikipedia)
https://en.wikipedia.org/wiki/DOS_API - IBM Basic assembly language and successors (Wikipedia)
https://en.wikipedia.org/wiki/IBM_Basic_assembly_language_and_successors - X86 Assembly/Arithmetic
https://en.wikibooks.org/wiki/X86_Assembly/Arithmetic - Art of Assembly – Arithmetic Instructions
http://oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter6/CH06–2.html - ASM Flags
http://www.cavestory.org/guides/csasm/guide/asm_flags.html - Status Register
https://en.wikipedia.org/wiki/Status_register - Linux assemblers: A comparison of GAS and NASM
http://www.ibm.com/developerworks/library/l-gas-nasm/index.html - Programovani v assembleru na OS Linux
http://www.cs.vsb.cz/grygarek/asm/asmlinux.html - Is it worthwhile to learn x86 assembly language today?
https://www.quora.com/Is-it-worthwhile-to-learn-x86-assembly-language-today?share=1 - Why Learn Assembly Language?
http://www.codeproject.com/Articles/89460/Why-Learn-Assembly-Language - Is Assembly still relevant?
http://programmers.stackexchange.com/questions/95836/is-assembly-still-relevant - Why Learning Assembly Language Is Still a Good Idea
http://www.onlamp.com/pub/a/onlamp/2004/05/06/writegreatcode.html - Assembly language today
http://beust.com/weblog/2004/06/23/assembly-language-today/ - Assembler: Význam assembleru dnes
http://www.builder.cz/rubriky/assembler/vyznam-assembleru-dnes-155960cz - Programming from the Ground Up Book – Summary
http://savannah.nongnu.org/projects/pgubook/ - DOSBox
https://www.dosbox.com/ - The C Programming Language
https://en.wikipedia.org/wiki/The_C_Programming_Language - Hercules Graphics Card (HCG)
https://en.wikipedia.org/wiki/Hercules_Graphics_Card - Complete 8086 instruction set
https://content.ctcd.edu/courses/cosc2325/m22/docs/emu8086ins.pdf - Complete 8086 instruction set
https://yassinebridi.github.io/asm-docs/8086_instruction_set.html