Obsah
1. Specifika instrukční sady mikroprocesorů Intel 8086/8088
3. Programátorský model mikroprocesoru Intel 8086
5. Kolik času stojí výpočet adresy operandu?
6. Instrukční sada mikroprocesorů Intel 8088 a Intel 8086
9. Logické instrukce, bitové posuny a rotace
10. Strojové instrukce určené pro provedení skoku
12. Příznaky a podmíněné skoky
13. Vybrané instrukce pro podmíněné skoky založené na testování příznakových bitů
14. Použití instrukcí DEC a JNZ pro implementaci počítané programové smyčky
15. Odlišná realizace počítané smyčky s instrukcemi DEC, JZ a JMP
16. Počítané programové smyčky realizované instrukcí LOOP
17. Použití instrukce CMP v součinnosti s podmíněným skokem
18. Seznam již popsaných instrukcí
19. Repositář s demonstračními příklady
1. Specifika instrukční sady mikroprocesorů Intel 8086/8088
Při tvorbě profesionálních aplikací na IBM PC s mikroprocesorem Intel 8088 („ořezaná“ varianta čipu Intel 8086) se většinou používal assembler, protože jen tak bylo možné využít všech dobrých vlastností tohoto čipu (a samozřejmě i obejít ty horší vlastnosti, kterých taktéž bylo mnoho). Tehdejší překladače vyšších programovacích jazyků totiž nedokázaly pro Intel 8086 provádět dobré optimalizace, což bylo způsobeno komplikovanou instrukční sadou, relativně malým množstvím pracovních registrů, využitím jen specifických registrů pro určité operace a pochopitelně taktéž – doposud nepřekonanou – sémantickou mezerou mezi vyššími programovacími jazyky a strojovým kódem (či assemblerem). V dnešním článku a především pak v článku navazujícím se zaměříme právě na popis specifických vlastností instrukční sady Intelu 8086 (a vše platí i pro Intel 8088).
Programátorský model mikroprocesoru Intel 8086 do určité míry vychází z jeho předchůdců, tedy konkrétně 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, což umožňuje adresovat 1MB paměti + necelých 64kB nad tímto limitem. 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ě).
Mikroprocesory řady Intel 8086 jsou naprosto typickými zástupci CISC architektury, takže se nejprve zmiňme, o co se vlastně jedná. CISC znamená Complex Instruction Set Computer, tj. počítač (ale spíše mikroprocesor) s relativně složitými instrukcemi s vyšší úrovní abstrakce, než instrukce RISC (Reduced Instruction Set Computer).
2. Architektura CISC
CISC je založen na relativně starých myšlenkách. Již v roce 1962 se firma IBM rozhodla navrhnout do značné míry univerzální architekturu počítačů, která by pokrývala jak nároky jednodušších úloh (pro které stačily méně výkonné a tím pádem i levnější počítače), tak i nároky mnohem větší. Předností této architektury mělo být to, že systém „rostl“ současně s rostoucími požadavky zákazníka, a to bez nutnosti měnit programové vybavení (co nám to připomíná?). Výsledkem těchto snah firmy IBM byla platforma nazvaná System/360, resp. zkráceně S/360. Pro tuto platformu byla vytvořena poměrně rozsáhlá a složitá instrukční sada (ISA), která mimo běžné binární aritmetiky obsahovala i instrukce pro práci s textem, různé numerické formáty dat známé například z kalkulaček, ale i podporu BCD aritmetiky, která se dodnes používá například při výpočtech s měnou. V té době totiž vládlo přesvědčení, že bohatší instrukční sada ulehčí práci překladačům z vyšších programovacích jazyků, vyplní takzvanou sémantickou mezeru mezi assemblerem a vyššími programovacími jazyky atd.
Vzhledem ke složitosti instrukční sady System/360 se v praxi používaly mikroprogramy, tj. jednodušší procesory s touto architekturou kompatibilní mnoho instrukcí přímo nevykonávaly, ale vlastně emulovaly na základě takzvaného mikrokódu (mikroinstrukcí uložených v mikrořadiči) – jednalo se tedy o obdobu dnes populárních bytekódů, které také mohou být emulovány přímo v mikroprocesorech (mikroprogramem), nikoli uživatelským programem. Teprve mnohem později byly podobně koncipované instrukční sady a mikroprocesory nazvány CISC neboli Complex Instruction Set Code (v některých případech byly i mikroinstrukce pro přímé vykonání zbytečně složité, a proto byly rozkládány do takzvaných nanoinstrukcí, což vedlo ke snížení potřebné kapacity paměti v mikrořadiči i zjednodušení návrhu samotného mikroprocesoru).
Procesory s architekturou CISC se většinou vyznačují velmi obsáhlou instrukční sadou, mnohdy do značné míry ortogonální (tj. většina instrukcí může být použita se všemi adresními režimy). To ovšem vede k nutnosti použití složitého řadiče, instrukce trvají i několik desítek či stovek taktů a celková složitost mikroprocesoru obecně roste. Před cca 10–15 lety se zdálo, že celá architektura CISC bude opuštěna a nahrazena architekturou RISC. Ve skutečnosti však vznikly jakési hybridní architektury – dnes nejpopulárnější mikroprocesory jsou sice interně vytvořeny jako RISCové, ale jejich instrukční sada je CISCová. V této kombinaci se ukazují výhody obou architektur: velká rychlost a interní jednoduchost RISCů a současně kratší kód instrukcí u CISC procesorů (snižují se nároky na vyrovnávací paměti). Pro příklad nemusíme chodit daleko, protože do tohoto stavu došla i platforma x86 (a před ní VAX či Motorola 68060). I populární 32bitové RISCové procesory ARM obsahují instrukční sadu nazvanou Thumb, která umožňuje snížení velikosti programů o cca 30–40 %.
Pro ilustraci „komplexnosti“ instrukční sady následuje příklad části programu napsaného v assembleru CISCové architektury x86. Všimněte si různých adresních režimů, implicitně zadaných operandů u instrukce imul, segmentového adresování pomocí segmentového registru es, i toho, že u aritmetických instrukcí je možné používat operandy přímo načítané z operační paměti (mov es, ax, add ax,[zy1]), což je pro CISCové architektury typické a naopak netypické pro architekturu RISC:
mov ax,bp sar ax,cl imul ax ; implicitní operandy: dx:ax=ax*ax push ax mov ax,bx sar ax,cl ; při bitovém posunu se musí použít registr cl imul ax mov es:[di],ax ; uložení obsahu registru do paměti mov ax,bp sar ax,cl sar bx,5 imul bx ; implicitní operandy: dx:ax=ax*bx add ax,[zy1] ; jeden z operandů je načten z operační paměti xchg ax,bx pop ax push ax sub ax,es:[di] add ax,[zx1] mov bp, ax pop ax add ax,es:[di] dec ch jz short pokrac cmp ax,4*P jc short opak stosb ; další instrukce s implicitními operandy (porušení ortogonality)
3. Programátorský model mikroprocesoru Intel 8086
Nejprve si vysvětlíme takzvaný programátorský model mikroprocesorů řady Intel 8086, tedy i včetně čipu Intel 8088 použitého v první generaci IBM PC. Stručně řečeno popisuje programátorský model dostupné registry, adresovací režimy a skupinu použitelných instrukcí. Začněme s popisem registrů. Celkově je možné pracovat s těmito čtrnácti registry, které mají všechny šířku šestnácti bitů (u dalších modelů x86 to už tak jednoduché ani zdaleka nebude, protože některé registry jsou rozšířeny na 32bitů atd.):
# | 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 (ale logicky sem spadá i BX) |
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 specifických 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ů). Navíc se tyto registry rozdělují na „horní“ a „dolní“ osmibitové registry (tj. změna AL modifikuje spodních osm bitů registru AX a naopak):
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 pro 32bitové operace atd. |
Jména registrů SI a DI vznikla ze sousloví Source Index a Destination Index a jméno registru BP znamená Base Pointer.
4. Dostupné adresovací režimy
U procesorů Intel 8086/8088 je dostupných hned několik adresovacích režimů, které jsou dokonce pojmenovány (i když v praxi se většinou toto pojmenování nepoužívá). Podívejme se nyní, které režimy jsou podporovány:
Název režimu | Stručný popis | Ukázka instrukce |
---|---|---|
register | operandem je přímo zapsaný registr | add AX, BX |
immediate | operandem je konstanta (8bit, 16bit) | mov AL, 3; mov BX, 42 |
displacement/direct | operandem je přímá adresa | inc byte [123], inc word [123] |
register indirect | operandem je adresa uložená v SI, DI nebo BX | mov AX, [DI] |
based indexed mode | operandem je bázová adresa (BX, BP) zvýšená o offset (SI, DI) | mov AX, [BX+DI] |
indexed mode | operandem je bázová adresa (SI, DI) zvýšená o offset (konstanta) | mov AX, [SI+1000] |
based mode | dtto, ale pro bázový registr a offset | mov AX, [BP+1000] |
based indexed displacement | adresa je vypočtena z indexového registru, bázového registru a offsetu | mov AX, [SI+BP+offset] |
string | pro adresování se implicitně použije ES:DI nebo DS:SI | movs, stosb, loadsw |
Všechny možné kombinace zápisu adres (tedy ne přímo konstant či registrů v roli operandů) jsou vypsány v následující tabulce. Více kombinací už pro 8086/8088 neexistuje (vynecháno je adresování řetězců, to je totiž implicitní):
Použitý zápis v assembleru | Adresovací režim |
---|---|
přímá adresa (16bit) | displacement/direct |
[BX] | register indirect |
[SI] | register indirect |
[DI] | register indirect |
[BX+SI] | based indexed mode |
[BX+DI] | based indexed mode |
[BP+SI] | based indexed mode |
[BP+DI] | based indexed mode |
[BP+offset8_bit] | based mode |
[BX+offset8_bit] | based mode |
[SI+offset8_bit] | indexed mode |
[DI+offset8_bit] | indexed mode |
[BP+offset16_bit] | based mode |
[BX+offset16_bit] | based mode |
[SI+offset16_bit] | indexed mode |
[DI+offset16_bit] | indexed mode |
[BX+SI+offset8_bit] | based indexed displacement |
[BX+DI+offset8_bit] | based indexed displacement |
[BP+SI+offset8_bit] | based indexed displacement |
[BP+DI+offset8_bit] | based indexed displacement |
[BX+SI+offset16_bit] | based indexed displacement |
[BX+DI+offset16_bit] | based indexed displacement |
[BP+SI+offset16_bit] | based indexed displacement |
[BP+DI+offset16_bit] | based indexed displacement |
Příklad využití některých výše uvedených adresovacích režimů v naprosto umělém příkladu:
;----------------------------------------------------------------------------- BITS 16 ; 16bitovy vystup pro DOS CPU 8086 ; specifikace pouziteho instrukcniho souboru ;----------------------------------------------------------------------------- org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 256) start: add ax, bx mov ax, [bx] mov ax, [si] mov ax, [di] mov ax, [bp] mov ax, [bx+0x1f] mov ax, [si+0x1f] mov ax, [di+0x1f] mov ax, [bp+0x1f] mov ax, [bx+0xeeff] mov ax, [si+0xeeff] mov ax, [di+0xeeff] mov ax, [bp+0xeeff] mov ax, [bp+si] mov ax, [bp+di] mov ax, [bp+si+0x1f] mov ax, [bp+di+0xeeff] mov al, 42 mov ax, 42 inc byte [123] inc word [123] inc byte [10000] inc word [10000]
Překlad do strojového kódu vypadá následovně (povšimněte si délky jednotlivých instrukcí) a například rozdílu mezi [di] a [bp]:
1 ;----------------------------------------------------------------------------- 2 3 BITS 16 ; 16bitovy vystup pro DOS 4 CPU 8086 ; specifikace pouziteho instrukcniho souboru 5 6 ;----------------------------------------------------------------------------- 7 org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 256) 8 9 start: 10 00000000 01D8 add ax, bx 11 00000002 8B07 mov ax, [bx] 12 00000004 8B04 mov ax, [si] 13 00000006 8B05 mov ax, [di] 14 00000008 8B4600 mov ax, [bp] 15 16 0000000B 8B471F mov ax, [bx+0x1f] 17 0000000E 8B441F mov ax, [si+0x1f] 18 00000011 8B451F mov ax, [di+0x1f] 19 00000014 8B461F mov ax, [bp+0x1f] 20 21 00000017 8B87FFEE mov ax, [bx+0xeeff] 22 0000001B 8B84FFEE mov ax, [si+0xeeff] 23 0000001F 8B85FFEE mov ax, [di+0xeeff] 24 00000023 8B86FFEE mov ax, [bp+0xeeff] 25 26 00000027 8B02 mov ax, [bp+si] 27 00000029 8B03 mov ax, [bp+di] 28 0000002B 8B421F mov ax, [bp+si+0x1f] 29 0000002E 8B83FFEE mov ax, [bp+di+0xeeff] 30 00000032 B02A mov al, 42 31 00000034 B82A00 mov ax, 42 32 00000037 FE067B00 inc byte [123] 33 0000003B FF067B00 inc word [123] 34 0000003F FE061027 inc byte [10000] 35 00000043 FF061027 inc word [10000]
5. Kolik času stojí výpočet adresy operandu?
Mikroprocesory Intel 8086 jsou, na rozdíl od jejich následovníků, zvláštní v tom, že výpočet takzvané efektivní adresy (tj. adresy operandu) je velmi zdlouhavý a závisí na použitém adresovacím režimu. Je to mj. i z toho důvodu, že výpočet efektivní adresy využívá ALU a nikoli specializovanou sčítačku.
Podívejme se na typickou zdánlivě „krátkou“ instrukci, konkrétně na instrukci ADD. Doba jejího vykonání nezávisí na šířce operandů (8 nebo 16 bitů), ale na adresovacím režimu:
Operandy | Počet cyklů |
---|---|
reg, reg | 3 |
mem, reg | 24+EA |
reg, mem | 13+EA |
reg, imm | 4 |
mem, imm | 23+EA |
acc, imm | 4 |
Hodnota EA závisí na adresovacím režimu:
Adresování | Počet cyklů EA |
---|---|
reg+offset | 5 |
přímá adresa | 6 |
BP+DI nebo BX+SI | 7 |
BX+DI nebo BP+SI | 8 |
BP+DI+disp nebo BX+SI+disp | 11 |
BX+DI+disp nebo BP+SI+disp | 12 |
Navíc, pokud se mění (explicitně specifikuje) segmentový registr, je nutné přičíst další dva hodinové cykly.
To například znamená, že instrukce:
add CS:[BX+DI+1234], AX
bude trvat 24+12=36 cyklů (tedy evidentně se skutečně nejedná o RISC přístup).
6. Instrukční sada mikroprocesorů Intel 8088 a Intel 8086
Poměrně rozsáhlá sada instrukcí mikroprocesorů Intel 8088 a Intel 8086 je vypsána v následující tabulce. K jednotlivým instrukcím se ještě vrátíme při jejich podrobnějším popisu:
AAA | ASCII adjust AL after addition |
AAD | ASCII adjust AX before division |
AAM | ASCII adjust AX after multiplication |
AAS | ASCII adjust AL after subtraction |
ADC | Add with carry |
ADD | Add |
AND | Logical AND |
CALL | Call procedure |
CBW | Convert byte to word |
CLC | Clear carry flag |
CLD | Clear direction flag |
CLI | Clear interrupt flag |
CMC | Complement carry flag |
CMP | Compare operands |
CMPSB | Compare bytes in memory |
CMPSW | Compare words |
CWD | Convert word to doubleword |
DAA | Decimal adjust AL after addition |
DAS | Decimal adjust AL after subtraction |
DEC | Decrement by 1 |
DIV | Unsigned divide |
ESC | Used with floating-point unit |
HLT | Enter halt state |
IDIV | Signed divide |
IMUL | Signed multiply in One-operand form |
IN | Input from port |
INC | Increment by 1 |
INT | Call to interrupt |
INTO | Call to interrupt if overflow |
IRET | Return from interrupt |
Jcc | Jump if condition |
JCXZ | Jump if CX is zero |
JMP | Jump |
LAHF | Load FLAGS into AH register |
LDS | Load DS:r with far pointer |
LEA | Load Effective Address |
LES | Load ES:r with far pointer |
LOCK | Assert BUS LOCK# signal |
LODSB | Load string byte |
LODSW | Load string word |
LOOP/LOOPx | Loop control |
MOV | Move |
MOVSB | Move byte from string to string |
MOVSW | Move word from string to string |
MUL | Unsigned multiply |
NEG | Two's complement negation |
NOP | No operation |
NOT | Negate the operand, logical NOT |
OR | Logical OR |
OUT | Output to port |
POP | Pop data from stack |
POPF | Pop FLAGS register from stack |
PUSH | Push data onto stack |
PUSHF | Push FLAGS onto stack |
RCL | Rotate left (with carry) |
RCR | Rotate right (with carry) |
REPxx | Repeat MOVS/STOS/CMPS/LODS/SCAS |
RET | Return from procedure |
RETN | Return from near procedure |
RETF | Return from far procedure |
ROL | Rotate left |
ROR | Rotate right |
SAHF | Store AH into FLAGS |
SAL | Shift Arithmetically left (signed shift left) |
SAR | Shift Arithmetically right (signed shift right) |
SBB | Subtraction with borrow |
SCASB | Compare byte string |
SCASW | Compare word string |
SHL | Shift left (unsigned shift left) |
SHR | Shift right (unsigned shift right) |
STC | Set carry flag |
STD | Set direction flag |
STI | Set interrupt flag |
STOSB | Store byte in string |
STOSW | Store word in string |
SUB | Subtraction |
TEST | Logical compare (AND) |
WAIT | Wait until not busy |
XCHG | Exchange data |
XLAT | Table look-up translation |
XOR | Exclusive OR |
7. Registr s příznaky (FLAGS)
Na platformě Intel 8086 se používá, ostatně podobně jako na většině ostatních platforem (kromě MIPS), takzvaný příznakový registr nazvaný FLAGS. Stejně jako všechny ostatní registry je i FLAGS šestnáctibitový (na 386 byl rozšířen na 32 bitů, později ani tato šířka nestačila, tak vznikly další registry). Příznakový registr obsahuje skutečné příznaky výsledků operací (například nulovost), ale i bity, které řídí chování některých instrukcí (například způsob průchodu řetězcem atd.). Význam jednotlivých bitů příznakového registru je následující:
Bit | Příznak | Stručný popis příznaku |
---|---|---|
0 | CF | příznak přenosu (carry) |
1 | × | rezervováno |
2 | PF | příznak (bitové) parity |
3 | × | rezervováno |
4 | AF | příznak přenosu ze třetího do čtvrtého bitu (auxiliary carry) |
5 | × | rezervováno |
6 | ZF | příznak nulovosti (zero) |
7 | SF | příznak znaménka (sign) |
8 | TF | příznak nastavený při krokování |
9 | IF | povolení či zákaz reakce na přerušení |
10 | DF | směr změny adres při blokových (řetězcových) operacích |
11 | OF | příznak přetečení (overflow) |
12 | × | na 8086 rezervováno, použito až v 286 |
13 | × | na 8086 rezervováno, použito až v 286 |
14 | × | na 8086 rezervováno, použito až v 286 |
15 | × | na 8086 rezervováno, použito až v 286 |
8. Aritmetické instrukce
První skupinou instrukcí, se kterou se v dnešním článku seznámíme, jsou aritmetické instrukce. Na platformě Intel 8086 nalezneme všechny základní aritmetické instrukce, a to včetně násobení a dělení se znaménkem i bez znaménka. Tyto instrukce jsou však relativně pomalé. Počty cyklů nutných pro dokončení jednotlivých operací jsou naznačeny v tabulce (pro ten nejrychlejší způsob, tedy pro operace typu registr+registr):
Instrukce | Cyklů | Stručný popis instrukce |
---|---|---|
ADD | 3 | součet |
ADC | 3 | součet se započtením předchozího přenosu (carry) |
SUB | 3 | rozdíl |
SBB | 3 | rozdíl se započtením předchozí výpůjčky (borrow) |
CMP | 3 | porovnání s nastavením příznaků |
INC | 3 | zvýšení operandu o jedničku |
DEC | 3 | snížení operandu o jedničku |
MUL | 70–77 (8bit), 118–133 (16bit) | násobení bez znaménka, výsledek v AX nebo DX:AX |
DIV | 80–90 (8bit), 144–162 (16bit) | dělení a výpočet zbytku po dělení bez znaménka |
IMUL | 80–98 (8bit), 128–154 (16bit) | násobení se znaménkem |
IDIV | 101–112 (8bit), 165–184 (16bit) | dělení se znaménkem |
NEG | 3 | negace (otočení znaménka) |
Kvůli dlouhým časům násobení není divu, že se pro zpracování signálu používaly specializované DSP s velmi rychlou násobičkou.
9. Logické instrukce, bitové posuny a rotace
Mikroprocesor Intel 8086 pochopitelně obsahuje prakticky úplnou sadu logických instrukcí a instrukcí určených pro provedení bitových posunů a rotací. U instrukcí posunů a rotací je zajímavé, že operace posunu/rotace o jeden bit je velmi rychlá, ale posun o CL bitů naopak velmi pomalá, takže se (většinou) na Intel 8086 vyplatí si rozepsat například násobení osmi na tři posuny a nikoli na posun o tři bity:
Instrukce | Cyklů | Stručný popis instrukce |
---|---|---|
AND | 3 | bitová operace logického součinu |
OR | 3 | bitová operace logického součtu |
XOR | 3 | bitová operace nonekvivalence |
NOT | 3 | negace všech bitů |
TEST | 3 | provedení logického součinu bez uložení výsledku (mění se jen příznaky) |
RCL | 2 (rotace o bit) nebo 8+4n | rotace (9 nebo 17 bitů) přes příznak CF doleva |
RCR | 2 (rotace o bit) nebo 8+4n | rotace (9 nebo 17 bitů) přes příznak CF doprava |
ROL | 2 (rotace o bit) nebo 8+4n | rotace osmi či šestnácti bitů doleva |
ROR | 2 (rotace o bit) nebo 8+4n | rotace osmi či šestnácti bitů doprava |
SAL | 2 (posun o bit) nebo 8+4n | aritmetický posun doleva (stejné jako SHL) |
SHL | 2 (posun o bit) nebo 8+4n | bitový posun doleva (stejné jako SAL) |
SAR | 2 (posun o bit) nebo 8+4n | aritmetický posun doprava (zleva se nasunuje příznak SF) |
SHR | 2 (posun o bit) nebo 8+4n | bitový posun doprava (zleva se nasunuje nula) |
10. Strojové instrukce určené pro provedení skoku
Velmi důležitým typem strojových instrukcí, které v různé podobě najdeme prakticky u všech modelů mikroprocesorů (resp. přesněji řečeno u mikroprocesorů všech dnes rozšířených mikroprocesorových architektur), jsou instrukce provádějící skoky na nějakou adresu v operační paměti. Implementace skoku není, alespoň na první pohled a u jednodušších architektur bez instrukční pipeline, vlastně nijak složitá, protože se v případě použití absolutní adresy dosadí hodnota z operačního kódu instrukce do registru IP a v případě použití relativní adresy se tato hodnota (nazývaná někdy poněkud nepřesně offset) přičte k aktuální hodnotě registru PC. Relativní adresa je v tomto případě v kódu instrukce uložena se znaménkem, proto se skok může provést dozadu i dopředu (ostatně právě použití relativní adresy uvidíme v dále popisovaných demonstračních příkladech).
Skoky většinou dělíme podle jednoho kritéria (formy zápisu adresy) na absolutní a relativní a podle kritéria druhého (za jakým okolností se skok provede) na skoky podmíněné a nepodmíněné. V závislosti na použité instrukční sadě jsou možné různé kombinace, typicky však u většiny mikroprocesorů nalezneme kombinace nepodmíněný absolutní skok, nepodmíněný relativní skok a podmíněný relativní skok. Skoky nepodmíněné jsou jednodušší a svou podstatou odpovídají příkazu goto známého z některých programovacích jazyků a také z mnoha článků, ve kterých autoři mnohdy bez hlubšího zamyšlení se nad původní myšlenkou opakují, že by se goto nemělo při strukturovaném programování používat :-). V assembleru se však skoky vesele používají, neboť právě pomocí nich se vytváří základní konstrukce strukturovaného programování – podmínky a programové smyčky (navíc relativní a tudíž i lokální skok není ta nejhorší možná abstrakce).
11. Nepodmíněné skoky
U architektury mikroprocesorů Intel 8086 je základní strojovou instrukcí určenou pro provedení nepodmíněného skoku instrukce nazvaná jednoduše a přímočaře JMP (což je, jak jste zajisté zjistili, mnemotechnická zkratka slova jump). V assembleru většinou za mnemotechnickou zkratkou jména instrukce následuje návěští (label), z něhož assembler odvodí reálnou adresu. Ukažme si typický špagetový kód vznikající nadbytečným použitím této instrukce:
org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 256) start: jmp cil1 zpet: ; tisk retezce na obrazovku mov dx, message mov ah, 9 int 0x21 ; ukonceni procesu a navrat do DOSu mov ah, 0x4c int 0x21 cil2: jmp cil3 cil1: jmp cil2 ; retezec ukonceny znakem $ ; (tato data jsou soucasti vysledneho souboru typu COM) message db "Hello, world!", 0x0d, 0x0a, "$" cil3: jmp zpet
Podívejme se, jak se vlastně instrukce JMP přeloží – kolik má bajtů, zda obsahuje relativní nebo absolutní adresu atd.:
1 2 org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 256) 3 4 start: 5 00000000 EB0D jmp cil1 6 7 zpet: 8 ; tisk retezce na obrazovku 9 00000002 BA[1100] mov dx, message 10 00000005 B409 mov ah, 9 11 00000007 CD21 int 0x21 12 13 ; ukonceni procesu a navrat do DOSu 14 00000009 B44C mov ah, 0x4c 15 0000000B CD21 int 0x21 16 17 0000000D EB12 cil2: jmp cil3 18 0000000F EBFC cil1: jmp cil2 19 20 ; retezec ukonceny znakem $ 21 ; (tato data jsou soucasti vysledneho souboru typu COM) 22 00000011 48656C6C6F2C20776F- message db "Hello, world!", 0x0d, 0x0a, "$" 22 0000001A 726C64210D0A24 23 24 00000021 EBDF cil3: jmp zpet
12. Příznaky a podmíněné skoky
Alternativně je možné použít i další způsoby adresování, čímž se například implementuje tabulka skoků (jedna z možných realizací stavového automatu) atd., ovšem tyto techniky pro účely dnešního článku prozatím nepotřebujeme znát. Mnohem zajímavější jsou podmíněné skoky, které se při programování v assembleru či ve strojovém kódu používají pro implementaci programových smyček while, do-while, for a taktéž konstrukcí typu if-then-else atd. Podmíněný skok je proveden či naopak neproveden na základě nějaké podmínky. Vzhledem k tomu, že pracujeme na té nejnižší programové úrovni, tj. na úrovni strojových instrukcí, není samozřejmě možné podmínku definovat nějakým složitým a sofistikovaným způsobem – musí se jednat o operaci, kterou mikroprocesor dokáže jednoduše a především dostatečně rychle zpracovat (i přesto představují skoky úzké místo v programech).
Z tohoto prostého důvodu – podmínky musí být realizovány dostatečně jednoduchým způsobem pro snadnou implementaci na čipu – jsou na mikroprocesorových architekturách Intel 8086 podmínky založeny na testování jednoho z takzvaných příznakových bitů, negací těchto bitů či dokonce jejich kombinací. Pokud z důvodu zjednodušení výkladu celé relativně rozsáhlé problematiky budeme ignorovat některé speciálnější příznaky a především pak rozdíly mezi hodnotami bez znaménka (unsigned) a se znaménkem (signed), můžeme zpočátku použít především příznaky nazvané Carry flag, Sign flag a Zero flag, tj. příznak přenosu, příznak záporného výsledku a příznak nulovosti. Význam těchto příznakových bitů je shrnut v následující tabulce:
Příznak | Význam zkratky | Poznámka |
---|---|---|
ZF | zero flag | výsledek předchozí operace je nulový |
CF | carry flag | přenos (bezznaménková aritmetika) |
SF | sign flag | výsledek je záporný (nastaven nejvyšší bit bajtu či slova) |
V případě, že alespoň prozatím nebudeme brát v úvahu další příznakové bity, existuje šest základních variant podmíněného skoku, které jsou vypsány v tabulce v navazující kapitole. Ve chvíli, kdy podmínka není splněna (tj. testovaný příznakový bit má opačnou hodnotu než očekávanou), není skok proveden, tj. mikroprocesor instrukci skoku v podstatě ignoruje a pokračuje v načtení instrukce uvedené ihned za skokem (to, že mikroprocesor instrukci skoku ignoruje samozřejmě platí jen z pohledu logiky vytvářeného programu; samotné provedení instrukce muselo proběhnout a tudíž se program o několik strojových taktů pozdržel – i neprovedení podmíněného kroku si tedy vyžádalo svou cenu).
13. Vybrané instrukce pro podmíněné skoky založené na testování příznakových bitů
Strojové instrukce určené pro provedení podmíněných skoků jsou ve své základní variantě (existují pro ně totiž i jmenné aliasy) pojmenovány jednoduše a přímočaře – jejich jména začínají znakem J (jump), za nímž následuje volitelné písmeno N (negace) a jednoznaková zkratka příznaku. Instrukce JNC tedy znamená „proveď skok, pokud příznak Carry není nastaven“, zatímco instrukce JZ znamená „proveď skok pouze při nastavení příznaku Zero“:
Mnemotechnická zkratka instrukce | Význam instrukce podmíněného skoku |
---|---|
JC | podmíněný skok za předpokladu, že je nastaven příznak přenosu (Carry flag) |
JNC | podmíněný skok za předpokladu, že je vynulován příznak přenosu (Carry flag) |
JZ | podmíněný skok za předpokladu, že je nastaven příznak nulovosti (Zero flag) |
JNZ | podmíněný skok za předpokladu, že je vynulován příznak nulovosti (Zero flag) |
JS | podmíněný skok za předpokladu, že je nastaven příznak záporného výsledku (Sign flag) |
JNS | podmíněný skok za předpokladu, že je vynulován příznak záporného výsledku (Sign flag) |
Jmenné aliasy:
Instrukce | Alias |
---|---|
JZ | JE |
JNZ | JNE |
JC | JB, JNAE |
JNC | JNB, JAE |
JS | nemá alias |
JNS | nemá alias |
14. Použití instrukcí DEC a JNZ pro implementaci počítané programové smyčky
V předchozí kapitole jsme si řekli, že podmíněné relativní skoky jsou použity pro implementaci programových smyček a podmínek. K tomuto účelu se podmíněné skoky prakticky vždy vhodně kombinují s některou instrukcí, která modifikuje jeden příznakový bit či dokonce větší množství příznakových bitů. Například jednoduchou počítanou programovou smyčku by bylo možné implementovat s využitím kombinace strojových instrukcí DEC a JNZ. Instrukce nazvaná DEC snižuje obsah specifikovaného pracovního registru o jedničku a současně nastavuje příznak nuly, tj. Zero flag (ZF), samozřejmě ovšem pouze za předpokladu, že ten pracovní registr, jehož hodnota se snižuje, skutečně dosáhl nulové hodnoty. Instrukce JNZ znamená podmíněný skok, který je proveden pouze tehdy, pokud příznak nuly není nastaven („jump if not zero“, viz též předchozí kapitolu).
Před samotným začátkem programové smyčky je samozřejmě nutné do pracovního registru nastavit potřebný počet opakování, který by měl být ideálně odlišný od nuly. Ostatně zkuste si sami odpovědět na otázku, co by se stalo v případě, kdy by pracovní registr použitý jako počitadlo, byl před vstupem do smyčky vynulovaný. Podívejme se nyní na způsob použití 16bitového registru AX (akumulátory) ve funkci počitadla. Vzhledem k tomu, že se testuje pouze nulovost registru po snížení jeho hodnoty o jedničku, může tato smyčka být provedena 0× až 216-1× (ignoruje se znaménko):
MOV AX, počet_opakování ; počet opakování smyčky SMYCKA: příkaz 1 ; libovolné instrukce, jejichž celková příkaz 2 ; celková délka bloku musí být menší než cca 120 bytů ... ; (kvůli omezení relativního skoku, pokud se délka překročí, použije se delší instrukce) ... ... příkaz X DEC EAX ; snížení čítače smyčky o jedničku JNZ SMYCKA ; přeloží se jako relativní skok
Praktický příklad – výpis zprávy 10×, jako počitadlo je použit registr CX:
org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 256) start: mov cx, 10 ; pocatecni hodnota pocitadla opak: ; tisk retezce na obrazovku mov dx, message mov ah, 9 int 0x21 dec cx ; snizeni pocitadla o jednicku jnz opak ; skok, dokud se nedosahne nuly ; ukonceni procesu a navrat do DOSu mov ah, 0x4c int 0x21 ; retezec ukonceny znakem $ ; (tato data jsou soucasti vysledneho souboru typu COM) message db "Hello, world!", 0x0d, 0x0a, "$"
Překlad do strojového kódu ukazuje, že se opět používá short varianta relativního skoku:
1 2 org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 256) 3 4 start: 5 00000000 B90A00 mov cx, 10 ; pocatecni hodnota pocitadla 6 opak: 7 ; tisk retezce na obrazovku 8 00000003 BA[1100] mov dx, message 9 00000006 B409 mov ah, 9 10 00000008 CD21 int 0x21 11 12 0000000A 49 dec cx ; snizeni pocitadla o jednicku 13 0000000B 75F6 jnz opak ; skok, dokud se nedosahne nuly 14 15 ; ukonceni procesu a navrat do DOSu 16 0000000D B44C mov ah, 0x4c 17 0000000F CD21 int 0x21 18 19 ; retezec ukonceny znakem $ 20 ; (tato data jsou soucasti vysledneho souboru typu COM) 21 00000011 48656C6C6F2C20776F- message db "Hello, world!", 0x0d, 0x0a, "$" 21 0000001A 726C64210D0A24
15. Odlišná realizace počítané smyčky s instrukcemi DEC, JZ a JMP
Podmínku ovšem můžeme naopak přesunout i na samotný začátek smyčky. Nyní se ovšem namísto instrukce pro podmíněný skok JNZ použije instrukce JZ (tedy opačná podmínka) v kombinaci s instrukcí nepodmíněného skoku JMP:
MOV AX, počet_opakování ; počet opakování smyčky SMYCKA: DEC AX ; snížení čítače smyčky o jedničku JZ KONEC ; přeloží se jako relativní skok příkaz 1 ; libovolné instrukce, jejichž celková příkaz 2 ; celková délka bloku musí být menší než cca 120 bytů ... ; (kvůli omezení relativního skoku, pokud se délka překročí, použije se delší instrukce) ... ... příkaz X JMP SMYCKA ; nepodmíněný skok na začátek smyčky
Opět si to ukažme v praxi na realizaci výpisu zprávy několikrát na obrazovku:
org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 256) start: mov cx, 10 ; pocatecni hodnota pocitadla opak: ; tisk retezce na obrazovku mov dx, message mov ah, 9 int 0x21 dec cx ; snizeni pocitadla o jednicku jz konec ; skok, pokus se dosahne nuly jmp opak ; opakujeme smycku konec: ; ukonceni procesu a navrat do DOSu mov ah, 0x4c int 0x21 ; retezec ukonceny znakem $ ; (tato data jsou soucasti vysledneho souboru typu COM) message db "Hello, world!", 0x0d, 0x0a, "$"
Opět si pro úplnost ukažme překlad do strojového kódu:
1 2 org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 256) 3 4 start: 5 00000000 B90A00 mov cx, 10 ; pocatecni hodnota pocitadla 6 opak: 7 ; tisk retezce na obrazovku 8 00000003 BA[1300] mov dx, message 9 00000006 B409 mov ah, 9 10 00000008 CD21 int 0x21 11 12 0000000A 49 dec cx ; snizeni pocitadla o jednicku 13 0000000B 7402 jz konec ; skok, pokus se dosahne nuly 14 15 0000000D EBF4 jmp opak ; opakujeme smycku 16 konec: 17 ; ukonceni procesu a navrat do DOSu 18 0000000F B44C mov ah, 0x4c 19 00000011 CD21 int 0x21 20 21 22 ; retezec ukonceny znakem $ 23 ; (tato data jsou soucasti vysledneho souboru typu COM) 24 00000013 48656C6C6F2C20776F- message db "Hello, world!", 0x0d, 0x0a, "$" 24 0000001C 726C64210D0A24
16. Počítané programové smyčky realizované instrukcí LOOP
V předchozích dvou demonstračních příkladech jsme použili pracovní registr CX v roli počitadla programové smyčky. Zápis této smyčky vypadal zhruba následovně:
smyčka: ... ... ... dec cx ; snizeni hodnoty CL jnz smyčka ; skok pri nenulovosti vysledku
Ve skutečnosti je možné tyto dvě instrukce nahradit za jedinou instrukci LOOP, která provádí totožnou operaci, tj. snížení hodnoty CX následované skokem ve chvíli, kdy CX ještě nedosáhla nuly:
smyčka: ... ... ... loop smyčka ; snizeni hodnoty CX, skok pri nenulovosti vysledku
Jak je tato smyčka výhodná nám ukáže následující tabulka:
Operace | Bajtů | Cyklů |
---|---|---|
DEC+JNZ | 1+2 | 3+4 nebo 3+16 |
LOOP | 2 | 5 nebo 17 |
První varianta je tedy pomalejší a současně i delší, než varianta s instrukcí LOOP.
Zkusme si tedy příklad pro opakovaný výpis zprávy ještě jednou upravit, a to s využitím právě zmíněné instrukce LOOP. Výsledek bude vypadat takto:
org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 256) start: mov cx, 10 ; pocatecni hodnota pocitadla opak: ; tisk retezce na obrazovku mov dx, message mov ah, 9 int 0x21 loop opak ; snizeni pocitadla o jednicku ; a skok, dokud se nedosahne nuly ; ukonceni procesu a navrat do DOSu mov ah, 0x4c int 0x21 ; retezec ukonceny znakem $ ; (tato data jsou soucasti vysledneho souboru typu COM) message db "Hello, world!", 0x0d, 0x0a, "$"
Vygenerovaný strojový kód ukáže i kódování a délku instrukce LOOP:
1 2 org 0x100 ; zacatek kodu pro programy typu COM (vzdy se zacina na 256) 3 4 start: 5 00000000 B90A00 mov cx, 10 ; pocatecni hodnota pocitadla 6 opak: 7 ; tisk retezce na obrazovku 8 00000003 BA[1000] mov dx, message 9 00000006 B409 mov ah, 9 10 00000008 CD21 int 0x21 11 12 0000000A E2F7 loop opak ; snizeni pocitadla o jednicku 13 ; a skok, dokud se nedosahne nuly 14 15 ; ukonceni procesu a navrat do DOSu 16 0000000C B44C mov ah, 0x4c 17 0000000E CD21 int 0x21 18 19 ; retezec ukonceny znakem $ 20 ; (tato data jsou soucasti vysledneho souboru typu COM) 21 00000010 48656C6C6F2C20776F- message db "Hello, world!", 0x0d, 0x0a, "$" 21 00000019 726C64210D0A24
17. Použití instrukce CMP v součinnosti s podmíněným skokem
Společně s podmíněnými skoky se velmi často používá doposud nepopsaná instrukce nazvaná CMP (mnemotechnická zkratka od slova compare). V podstatě se jedná o běžné celočíselné odečítání, tj. o instrukci nazvanou SUB, ovšem s tím důležitým rozdílem, že výsledek, tj. samotný rozdíl, není nikam zapsán, což znamená, že se obsah běžných pracovních registrů provedením této instrukce nezmění. Na první pohled může vypadat tato instrukce nesmyslně – proč se vůbec mají odečítat dvě hodnoty, když se výsledek hned zapomene? Ovšem samotný výsledek není ve skutečnosti vše, protože při odečítání si mikroprocesor v příznakových registrech zapamatuje i to, zda byla odečítaná čísla shodná (tehdy se nastaví Zero flag na jedničku) či zda byla druhá hodnota větší než hodnota první (příznak Carry flag bude v tomto případě roven jedné). Navíc se nastaví i další příznaky používané při práci s hodnotami se znaménkem.
Instrukce CMP akceptuje různé typy operandů; může se jednat o běžné pracovní registry, ovšem použít lze i konstanty či obsah získaný ze zvolené adresy operační paměti (platí zde tedy všechny výše zmíněné adresovací režimy). V následující tabulce si ukážeme, jaké základní příznaky se nastaví při provedení různých variant funkce CMP:
První operand | Druhý operand | Zero flag | Carry flag | Význam |
---|---|---|---|---|
00 | 00 | 1 | 0 | obě hodnoty jsou shodné |
42 | 42 | 1 | 0 | obě hodnoty jsou shodné |
20 | 10 | 0 | 0 | první hodnota je větší (nedošlo k přenosu) |
10 | 20 | 0 | 1 | druhá hodnota je větší (došlo k přenosu) |
Poznámka: ve skutečnosti by v tomto případě (odečítání a porovnávání) bylo korektnější mluvit o takzvané výpůjčce (borrow) a nikoli o přenosu (carry).
Z těchto příkladů současně nepřímo vyplývá i to, jak můžeme příznakové bity použít. Jestliže je zapotřebí testovat dvě hodnoty na rovnost, postačí zjistit, zda je Zero flag nastavený na jedničku (ostatně i z tohoto důvodu má podmíněný skok JZ alias JE – jump if equal). Pokud potřebujeme otestovat, jestli je první hodnota menší než druhá, lze zjistit hodnotu příznaku Carry flag atd. Test na nulovou hodnotu lze provést odečtením nuly – výsledek bude uložen v Zero flagu (ve skutečnosti se ovšem tento test většinou neprovádí, protože i některé další instrukce dokážou nastavit tento příznak automaticky a vlastně „mimochodem“). Podobně je tomu u testování, zda je hodnota kladná či záporná. Podívejme se na několik možností použití:
; test na rovnost dvou hodnot MOV AX, hodnota 1 MOV BX, hodnota 2 CMP AX, BX JZ JE_ROVNO ; skok na kód provedený v případě rovnosti JNZ NENI_ROVNO ; skok na kód provedený v případě nerovnosti
; zjištění relace dvou čísel MOV AX, hodnota 1 MOV BX, hodnota 2 CMP AX, BX JNC AX_JE_VETSI_NEBO_ROVNO_BX JC AX_JE_MENSI_NEZ_BX
; test na nulovost MOV AX, hodnota SUB BX, BX ; vynulování registru BX (lze i XOR BX,BX) CMP AX, BX JZ AX_JE_NULOVE
; test na nulovost MOV AX, hodnota CMP AX, 0 JZ AX_JE_NULOVE
; test na kladnou či zápornou hodnou MOV AX, hodnota CMP AX, 0 JS AX_JE_ZAPORNE
18. Seznam již popsaných instrukcí
ADC | Add with carry |
ADD | Add |
AND | Logical AND |
CMP | Compare operands |
DEC | Decrement by 1 |
DIV | Unsigned divide |
IDIV | Signed divide |
IMUL | Signed multiply in One-operand form |
INC | Increment by 1 |
Jcc | Jump if condition |
JMP | Jump |
LOOP/LOOPx | Loop control |
MUL | Unsigned multiply |
NEG | Two's complement negation |
NOT | Negate the operand, logical NOT |
OR | Logical OR |
RCL | Rotate left (with carry) |
RCR | Rotate right (with carry) |
ROL | Rotate left |
ROR | Rotate right |
SAL | Shift Arithmetically left (signed shift left) |
SAR | Shift Arithmetically right (signed shift right) |
SBB | Subtraction with borrow |
SHL | Shift left (unsigned shift left) |
SHR | Shift right (unsigned shift right) |
SUB | Subtraction |
TEST | Logical compare (AND) |
XOR | Exclusive OR |
19. Repositář s demonstračními příklady
Demonstrační příklady napsané v assembleru, které jsou určené pro překlad s využitím assembleru NASM, byly uloženy do Git repositáře, který je dostupný na adrese https://github.com/tisnik/8bit-fame. Jednotlivé demonstrační příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý (dnes již poměrně rozsáhlý) repositář:
# | Příklad | Stručný popis | Adresa |
---|---|---|---|
1 | hello.asm | program typu „Hello world“ naprogramovaný v assembleru pro systém DOS | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hello.asm |
2 | hello_shorter.asm | kratší varianta výskoku z procesu zpět do DOSu | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hello_shorter.asm |
3 | hello_wait.asm | čekání na stisk klávesy | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hello_wait.asm |
4 | hello_macros.asm | realizace jednotlivých částí programu makrem | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hello_macros.asm |
5 | gfx4_putpixel.asm | vykreslení pixelu v grafickém režimu 4 | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_putpixel.asm |
6 | gfx6_putpixel.asm | vykreslení pixelu v grafickém režimu 6 | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel.asm |
7 | gfx4_line.asm | vykreslení úsečky v grafickém režimu 4 | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_line.asm |
8 | gfx6_line.asm | vykreslení úsečky v grafickém režimu 6 | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_line.asm |
9 | gfx6_fill1.asm | vyplnění obrazovky v grafickém režimu, základní varianta | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_fill1.asm |
10 | gfx6_fill2.asm | vyplnění obrazovky v grafickém režimu, varianta s instrukcí LOOP | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_fill2.asm |
11 | gfx6_fill3.asm | vyplnění obrazovky instrukcí REP STOSB | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_fill3.asm |
12 | gfx6_fill4.asm | vyplnění obrazovky, synchronizace vykreslování s paprskem | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_fill4.asm |
13 | gfx4_image1.asm | vykreslení rastrového obrázku získaného z binárních dat, základní varianta | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image1.asm |
14 | gfx4_image2.asm | varianta vykreslení rastrového obrázku s využitím instrukce REP MOVSB | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image2.asm |
15 | gfx4_image3.asm | varianta vykreslení rastrového obrázku s využitím instrukce REP MOVSW | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image3.asm |
16 | gfx4_image4.asm | korektní vykreslení všech sudých řádků bitmapy | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image4.asm |
17 | gfx4_image5.asm | korektní vykreslení všech sudých i lichých řádků bitmapy | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image5.asm |
18 | gfx4_image6.asm | nastavení barvové palety před vykreslením obrázku | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image6.asm |
19 | gfx4_image7.asm | nastavení barvové palety před vykreslením obrázku, snížená intenzita barev | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image7.asm |
20 | gfx4_image8.asm | postupná změna barvy pozadí | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx4_image8.asm |
21 | gfx6_putpixel1.asm | vykreslení pixelu, základní varianta se 16bitovým násobením | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel1.asm |
22 | gfx6_putpixel2.asm | vykreslení pixelu, varianta s osmibitovým násobením | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel2.asm |
23 | gfx6_putpixel3.asm | vykreslení pixelu, varianta bez násobení | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel3.asm |
24 | gfx6_putpixel4.asm | vykreslení pixelu přes obrázek, nekorektní chování (přepis obrázku) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel4.asm |
25 | gfx6_putpixel5.asm | vykreslení pixelu přes obrázek, korektní varianta pro bílé pixely | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/gfx6_putpixel5.asm |
26 | cga_text_mode1.asm | standardní textový režim s rozlišením 40×25 znaků | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_mode1.asm |
27 | cga_text_mode3.asm | standardní textový režim s rozlišením 80×25 znaků | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_mode3.asm |
28 | cga_text_mode_intensity.asm | změna významu nejvyššího bitu atributového bajtu: vyšší intenzita namísto blikání | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_mode_intensity.asm |
29 | cga_text_mode_cursor.asm | změna tvaru textového kurzoru | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_mode_cursor.asm |
30 | cga_text_gfx1.asm | zobrazení „rastrové mřížky“: pseudografický režim 160×25 pixelů (interně textový režim) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_gfx1.asm |
31 | cga_text_mode_char_height.asm | změna výšky znaků | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_mode_char_height.asm |
32 | cga_text_160×100.asm | grafický režim 160×100 se šestnácti barvami (interně upravený textový režim) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/cga_text_160×100.asm |
33 | hercules_text_mode1.asm | využití standardního textového režimu společně s kartou Hercules | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_text_mode1.asm |
34 | hercules_text_mode2.asm | zákaz blikání v textových režimech | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_text_mode2.asm |
35 | hercules_turn_off.asm | vypnutí generování video signálu | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_turn_off.asm |
36 | hercules_gfx_mode1.asm | přepnutí karty Hercules do grafického režimu (základní varianta) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_gfx_mode1.asm |
37 | hercules_gfx_mode2.asm | přepnutí karty Hercules do grafického režimu (vylepšená varianta) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_gfx_mode2.asm |
38 | hercules_putpixel.asm | subrutina pro vykreslení jediného pixelu na kartě Hercules | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/hercules_putpixel.asm |
39 | ega_text_mode_80×25.asm | standardní textový režim 80×25 znaků na kartě EGA | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_text_mode_80×25.asm |
40 | ega_text_mode_80×43.asm | zobrazení 43 textových řádků na kartě EGA | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_text_mode_80×43.asm |
41 | ega_gfx_mode_320×200.asm | přepnutí do grafického režimu 320×200 pixelů se šestnácti barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_gfx_mode_320×200.asm |
42 | ega_gfx_mode_640×200.asm | přepnutí do grafického režimu 640×200 pixelů se šestnácti barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_gfx_mode_640×200.asm |
43 | ega_gfx_mode_640×350.asm | přepnutí do grafického režimu 640×350 pixelů se čtyřmi nebo šestnácti barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_gfx_mode_640×350.asm |
44 | ega_gfx_mode_bitplanes1.asm | ovládání zápisu do bitových rovin v planárních grafických režimech (základní způsob) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_gfx_mode_bitplanes1.asm |
45 | ega_gfx_mode_bitplanes2.asm | ovládání zápisu do bitových rovin v planárních grafických režimech (rychlejší způsob) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_gfx_mode_bitplanes2.asm |
46 | ega_320×200_putpixel.asm | vykreslení pixelu v grafickém režimu 320×200 pixelů se šestnácti barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_320×200_putpixel.asm |
47 | ega_640×350_putpixel.asm | vykreslení pixelu v grafickém režimu 640×350 pixelů se šestnácti barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_640×350_putpixel.asm |
48 | ega_standard_font.asm | použití standardního fontu grafické karty EGA | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_standard_font.asm |
49 | ega_custom_font.asm | načtení vlastního fontu s jeho zobrazením | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_custom_font.asm |
50 | ega_palette1.asm | změna barvové palety (všech 16 barev) v grafickém režimu 320×200 se šestnácti barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_palette1.asm |
51 | ega_palette2.asm | změna barvové palety (všech 16 barev) v grafickém režimu 640×350 se šestnácti barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_palette2.asm |
52 | ega_palette3.asm | změna všech barev v barvové paletě s využitím programové smyčky | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_palette3.asm |
53 | ega_palette4.asm | změna všech barev, včetně barvy okraje, v barvové paletě voláním funkce BIOSu | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/ega_palette4.asm |
54 | vga_text_mode_80×25.asm | standardní textový režim 80×25 znaků na kartě VGA | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_text_mode_80×25.asm |
55 | vga_text_mode_80×50.asm | zobrazení 50 a taktéž 28 textových řádků na kartě VGA | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_text_mode_80×50.asm |
56 | vga_text_mode_intensity1.asm | změna chování atributového bitu pro blikání (nebezpečná varianta změny registrů) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_text_mode_intensity1.asm |
57 | vga_text_mode_intensity2.asm | změna chování atributového bitu pro blikání (bezpečnější varianta změny registrů) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_text_mode_intensity2.asm |
58 | vga_text_mode_9th_column.asm | modifikace způsobu zobrazení devátého sloupce ve znakových režimech (720 pixelů na řádku) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_text_mode_9th_column.asm |
59 | vga_text_mode_cursor_shape.asm | změna tvaru textového kurzoru na grafické kartě VGA | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_text_mode_cursor_shape.asm |
60 | vga_text_mode_custom_font.asm | načtení vlastního fontu s jeho zobrazením | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_text_mode_custom_font.asm |
61 | vga_gfx_mode_640×480.asm | přepnutí do grafického režimu 640×480 pixelů se šestnácti barvami, vykreslení vzorků | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_640×480.asm |
62 | vga_gfx_mode_320×200.asm | přepnutí do grafického režimu 320×200 pixelů s 256 barvami, vykreslení vzorků | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_320×200.asm |
63 | vga_gfx_mode_palette.asm | změna všech barev v barvové paletě grafické karty VGA | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_palette.asm |
64 | vga_gfx_mode_dac1.asm | využití DAC (neočekávané výsledky) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_dac1.asm |
65 | vga_gfx_mode_dac2.asm | využití DAC (očekávané výsledky) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_dac2.asm |
66 | vga_640×480_putpixel.asm | realizace algoritmu pro vykreslení pixelu v grafickém režimu 640×480 pixelů se šestnácti barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_640×480_putpixel.asm |
67 | vga_320×200_putpixel1.asm | realizace algoritmu pro vykreslení pixelu v grafickém režimu 320×200 s 256 barvami (základní varianta) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_putpixel1.asm |
68 | vga_320×200_putpixel2.asm | realizace algoritmu pro vykreslení pixelu v grafickém režimu 320×200 s 256 barvami (rychlejší varianta) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_putpixel2.asm |
69 | vga_gfx_mode_dac3.asm | přímé využití DAC v grafickém režimu 13h | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_dac3.asm |
70 | vga_gfx_mode_unchained_step1.asm | zobrazení barevných pruhů v režimu 13h | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_unchained_step1.asm |
71 | vga_gfx_mode_unchained_step2.asm | vypnutí zřetězení bitových rovin a změna způsobu adresování pixelů | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_unchained_step2.asm |
72 | vga_gfx_mode_unchained_step3.asm | vykreslení barevných pruhů do vybraných bitových rovin | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_unchained_step3.asm |
73 | vga_gfx_mode_320×400.asm | nestandardní grafický režim s rozlišením 320×400 pixelů a 256 barvami | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_gfx_mode_320×400.asm |
74 | vga_320×200_image.asm | zobrazení rastrového obrázku ve standardním grafickém režimu 320×200 pixelů | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_image.asm |
75 | vga_320×200_unchained_image1.asm | zobrazení rastrového obrázku v režimu s nezřetězenými rovinami (nekorektní řešení) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_unchained_image1.asm |
76 | vga_320×200_unchained_image2.asm | zobrazení rastrového obrázku v režimu s nezřetězenými rovinami (korektní řešení) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×200_unchained_image2.asm |
77 | vga_320×400_unchained_image.asm | zobrazení rastrového obrázku v nestandardním režimu 320×400 pixelů | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×400_unchained_image.asm |
78 | vga_vertical_scroll1.asm | vertikální scrolling na kartě VGA v režimu s rozlišením 320×200 pixelů | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_vertical_scroll1.asm |
79 | vga_vertical_scroll2.asm | vertikální scrolling na kartě VGA v režimu s rozlišením 320×400 pixelů | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_vertical_scroll2.asm |
80 | vga_split_screen1.asm | režim split-screen a scrolling, nefunční varianta | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_split_screen1.asm |
81 | vga_split_screen2.asm | režim split-screen a scrolling, plně funkční varianta | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_split_screen2.asm |
82 | vga_horizontal_scroll1.asm | horizontální scrolling bez rozšíření počtu pixelů na virtuálním řádku | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_horizontal_scroll1.asm |
83 | vga_horizontal_scroll2.asm | horizontální scrolling s rozšířením počtu pixelů na virtuálním řádku | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_horizontal_scroll2.asm |
84 | vga_horizontal_scroll3.asm | jemný horizontální scrolling s rozšířením počtu pixelů na virtuálním řádku | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_horizontal_scroll3.asm |
85 | vga_320×240_image.asm | nastavení grafického režimu Mode-X, načtení a vykreslení obrázku, scrolling | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×240_image.asm |
86 | io.asm | knihovna maker pro I/O operace | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/io.asm |
87 | vga_lib.asm | knihovna maker a podprogramů pro programování karty VGA | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_lib.asm |
88 | vga_320×240_lib.asm | nastavení grafického režimu Mode-X, tentokrát knihovními funkcemi | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×240_lib.asm |
89 | vga_bitblt1.asm | první (naivní) implementace operace BitBLT | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_bitblt1.asm |
90 | vga_bitblt2.asm | operace BitBLT s výběrem bitových rovin pro zápis | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_bitblt2.asm |
91 | vga_bitblt3.asm | operace BitBLT s výběrem bitových rovin pro čtení i zápis | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_bitblt3.asm |
92 | vga_bitblt4.asm | korektní BitBLT pro 16barevný režim, realizace makry | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_bitblt4.asm |
93 | vga_bitblt5.asm | korektní BitBLT pro 16barevný režim, realizace podprogramem | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_bitblt5.asm |
94 | vga_bitblt_rotate.asm | zápisový režim s rotací bajtu | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_bitblt_rotate.asm |
95 | vga_bitblt_fast.asm | rychlá korektní 32bitová operace typu BitBLT | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_bitblt_fast.asm |
96 | vga_320×400_bitblt1.asm | přenos obrázku v režimu 320×400 operací BitBLT (neúplná varianta) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×400_bitblt1.asm |
97 | vga_320×400_bitblt2.asm | přenos obrázku v režimu 320×400 operací BitBLT (úplná varianta) | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_320×400_bitblt2.asm |
98 | vga_write_modes1.asm | volitelné zápisové režimy grafické karty VGA, zápis bez úpravy latche | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_write_modes1.asm |
99 | vga_write_modes2.asm | volitelné zápisové režimy grafické karty VGA, zápis s modifikací latche | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_write_modes2.asm |
100 | vga_write_modes3.asm | volitelné zápisové režimy grafické karty VGA, cílená modifikace latche vzorkem | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/vga_write_modes3.asm |
101 | instruction_jump.asm | použití instrukce JMP | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_jump.asm |
102 | instruction_jnz.asm | použití instrukce JNZ pro realizaci programové smyčky | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_jnz.asm |
103 | instruction_jz_jmp.asm | použití instrukcí JZ a JMP pro realizaci programové smyčky | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_jz_jmp.asm |
104 | instruction_loop.asm | použití instrukce LOOP pro realizaci programové smyčky | https://github.com/tisnik/8bit-fame/blob/master/pc-dos/instruction_loop.asm |
20. Odkazy na Internetu
- The Intel 8088 Architecture and Instruction Set
https://people.ece.ubc.ca/~edc/464/lectures/lec4.pdf - x86 Opcode Structure and Instruction Overview
https://pnx.tf/files/x86_opcode_structure_and_instruction_overview.pdf - x86 instruction listings (Wikipedia)
https://en.wikipedia.org/wiki/X86_instruction_listings - x86 assembly language (Wikipedia)
https://en.wikipedia.org/wiki/X86_assembly_language - Intel Assembler (Cheat sheet)
http://www.jegerlehner.ch/intel/IntelCodeTable.pdf - 25 Microchips That Shook the World
https://spectrum.ieee.org/tech-history/silicon-revolution/25-microchips-that-shook-the-world - Chip Hall of Fame: MOS Technology 6502 Microprocessor
https://spectrum.ieee.org/tech-history/silicon-revolution/chip-hall-of-fame-mos-technology-6502-microprocessor - Chip Hall of Fame: Intel 8088 Microprocessor
https://spectrum.ieee.org/tech-history/silicon-revolution/chip-hall-of-fame-intel-8088-microprocessor - Jak se zrodil procesor?
https://www.root.cz/clanky/jak-se-zrodil-procesor/ - Apple II History Home
http://apple2history.org/ - The 8086/8088 Primer
https://www.stevemorse.org/8086/index.html - flat assembler: Assembly language resources
https://flatassembler.net/ - FASM na Wikipedii
https://en.wikipedia.org/wiki/FASM - Fresh IDE FASM inside
https://fresh.flatassembler.net/ - MS-DOS Version 4.0 Programmer's Reference
https://www.pcjs.org/documents/books/mspl13/msdos/dosref40/ - INT 21 – DOS Function Dispatcher (DOS)
https://www.stanislavs.org/helppc/int21.html - DOS API (Wikipedia)
https://en.wikipedia.org/wiki/DOS_API - Bit banging
https://en.wikipedia.org/wiki/Bit_banging - IBM Basic assembly language and successors (Wikipedia)
https://en.wikipedia.org/wiki/IBM_Basic_assembly_language_and_successors - X86 Assembly/Bootloaders
https://en.wikibooks.org/wiki/X86_Assembly/Bootloaders - Počátky grafiky na PC: grafické karty CGA a Hercules
https://www.root.cz/clanky/pocatky-grafiky-na-pc-graficke-karty-cga-a-hercules/ - Co mají společného Commodore PET/4000, BBC Micro, Amstrad CPC i grafické karty MDA, CGA a Hercules?
https://www.root.cz/clanky/co-maji-spolecneho-commodore-pet-4000-bbc-micro-amstrad-cpc-i-graficke-karty-mda-cga-a-hercules/ - Karta EGA: první použitelná barevná grafika na PC
https://www.root.cz/clanky/karta-ega-prvni-pouzitelna-barevna-grafika-na-pc/ - RGB Classic Games
https://www.classicdosgames.com/ - Turbo Assembler (Wikipedia)
https://en.wikipedia.org/wiki/Turbo_Assembler - Microsoft Macro Assembler
https://en.wikipedia.org/wiki/Microsoft_Macro_Assembler - IBM Personal Computer (Wikipedia)
https://en.wikipedia.org/wiki/IBM_Personal_Computer - Intel 8251
https://en.wikipedia.org/wiki/Intel_8251 - Intel 8253
https://en.wikipedia.org/wiki/Intel_8253 - Intel 8255
https://en.wikipedia.org/wiki/Intel_8255 - Intel 8257
https://en.wikipedia.org/wiki/Intel_8257 - Intel 8259
https://en.wikipedia.org/wiki/Intel_8259 - Support/peripheral/other chips – 6800 family
http://www.cpu-world.com/Support/6800.html - Motorola 6845
http://en.wikipedia.org/wiki/Motorola_6845 - The 6845 Cathode Ray Tube Controller (CRTC)
http://www.tinyvga.com/6845 - CRTC operation
http://www.6502.org/users/andre/hwinfo/crtc/crtc.html - 6845 – Motorola CRT Controller
https://stanislavs.org/helppc/6845.html - The 6845 Cathode Ray Tube Controller (CRTC)
http://www.tinyvga.com/6845 - Motorola 6845 and bitwise graphics
https://retrocomputing.stackexchange.com/questions/10996/motorola-6845-and-bitwise-graphics - IBM Monochrome Display Adapter
http://en.wikipedia.org/wiki/Monochrome_Display_Adapter - Color Graphics Adapter
http://en.wikipedia.org/wiki/Color_Graphics_Adapter - Color Graphics Adapter and the Brown color in IBM 5153 Color Display
https://www.aceinnova.com/en/electronics/cga-and-the-brown-color-in-ibm-5153-color-display/ - The Modern Retrocomputer: An Arduino Driven 6845 CRT Controller
https://hackaday.com/2017/05/14/the-modern-retrocomputer-an-arduino-driven-6845-crt-controller/ - flat assembler: Assembly language resources
https://flatassembler.net/ - FASM na Wikipedii
https://en.wikipedia.org/wiki/FASM - Fresh IDE FASM inside
https://fresh.flatassembler.net/ - MS-DOS Version 4.0 Programmer's Reference
https://www.pcjs.org/documents/books/mspl13/msdos/dosref40/ - INT 21 – DOS Function Dispatcher (DOS)
https://www.stanislavs.org/helppc/int21.html - DOS API (Wikipedia)
https://en.wikipedia.org/wiki/DOS_API - IBM Basic assembly language and successors (Wikipedia)
https://en.wikipedia.org/wiki/IBM_Basic_assembly_language_and_successors - X86 Assembly/Arithmetic
https://en.wikibooks.org/wiki/X86_Assembly/Arithmetic - Art of Assembly – Arithmetic Instructions
http://oopweb.com/Assembly/Documents/ArtOfAssembly/Volume/Chapter6/CH06–2.html - ASM Flags
http://www.cavestory.org/guides/csasm/guide/asm_flags.html - Status Register
https://en.wikipedia.org/wiki/Status_register - Linux assemblers: A comparison of GAS and NASM
http://www.ibm.com/developerworks/library/l-gas-nasm/index.html - Programovani v assembleru na OS Linux
http://www.cs.vsb.cz/grygarek/asm/asmlinux.html - Is it worthwhile to learn x86 assembly language today?
https://www.quora.com/Is-it-worthwhile-to-learn-x86-assembly-language-today?share=1 - Why Learn Assembly Language?
http://www.codeproject.com/Articles/89460/Why-Learn-Assembly-Language - Is Assembly still relevant?
http://programmers.stackexchange.com/questions/95836/is-assembly-still-relevant - Why Learning Assembly Language Is Still a Good Idea
http://www.onlamp.com/pub/a/onlamp/2004/05/06/writegreatcode.html - Assembly language today
http://beust.com/weblog/2004/06/23/assembly-language-today/ - Assembler: Význam assembleru dnes
http://www.builder.cz/rubriky/assembler/vyznam-assembleru-dnes-155960cz - Programming from the Ground Up Book – Summary
http://savannah.nongnu.org/projects/pgubook/ - DOSBox
https://www.dosbox.com/ - The C Programming Language
https://en.wikipedia.org/wiki/The_C_Programming_Language - Hercules Graphics Card (HCG)
https://en.wikipedia.org/wiki/Hercules_Graphics_Card - Complete 8086 instruction set
https://content.ctcd.edu/courses/cosc2325/m22/docs/emu8086ins.pdf - Complete 8086 instruction set
https://yassinebridi.github.io/asm-docs/8086_instruction_set.html - 8088 MPH by Hornet + CRTC + DESiRE (final version)
https://www.youtube.com/watch?v=hNRO7lno_DM - Area 5150 by CRTC & Hornet (Party Version) / IBM PC+CGA Demo, Hardware Capture
https://www.youtube.com/watch?v=fWDxdoRTZPc - 80×86 Integer Instruction Set Timings (8088 – Pentium)
http://aturing.umcs.maine.edu/~meadow/courses/cos335/80×86-Integer-Instruction-Set-Clocks.pdf - Colour Graphics Adapter: Notes
https://www.seasip.info/VintagePC/cga.html - Restoring A Vintage CGA Card With Homebrew HASL
https://hackaday.com/2024/06/12/restoring-a-vintage-cga-card-with-homebrew-hasl/ - Demoing An 8088
https://hackaday.com/2015/04/10/demoing-an-8088/ - Video Memory Layouts
http://www.techhelpmanual.com/89-video_memory_layouts.html - Screen Attributes
http://www.techhelpmanual.com/87-screen_attributes.html - IBM PC Family – BIOS Video Modes
https://www.minuszerodegrees.net/video/bios_video_modes.htm - EGA Functions
https://cosmodoc.org/topics/ega-functions/#the-hierarchy-of-the-ega - Why the EGA can only use 16 of its 64 colours in 200-line modes
https://www.reenigne.org/blog/why-the-ega-can-only-use-16-of-its-64-colours-in-200-line-modes/ - How 16 colors saved PC gaming – the story of EGA graphics
https://www.custompc.com/retro-tech/ega-graphics - List of 16-bit computer color palettes
https://en.wikipedia.org/wiki/List_of16-bit_computer_color_palettes - Why were those colors chosen to be the default palette for 256-color VGA?
https://retrocomputing.stackexchange.com/questions/27994/why-were-those-colors-chosen-to-be-the-default-palette-for-256-color-vga - VGA Color Palettes
https://www.fountainware.com/EXPL/vga_color_palettes.htm - Hardware Level VGA and SVGA Video Programming Information Page
http://www.osdever.net/FreeVGA/vga/vga.htm - Hardware Level VGA and SVGA Video Programming Information Page – sequencer
http://www.osdever.net/FreeVGA/vga/seqreg.htm - VGA Basics
http://www.brackeen.com/vga/basics.html - Introduction to VGA Mode ‚X‘
https://web.archive.org/web/20160414072210/http://fly.srk.fer.hr/GDM/articles/vgamodex/vgamx1.html - VGA Mode-X
https://web.archive.org/web/20070123192523/http://www.gamedev.net/reference/articles/article356.asp - Mode-X: 256-Color VGA Magic
https://downloads.gamedev.net/pdf/gpbb/gpbb47.pdf - Instruction Format in 8086 Microprocessor
https://www.includehelp.com/embedded-system/instruction-format-in-8086-microprocessor.aspx - How to use „AND,“ „OR,“ and „XOR“ modes for VGA Drawing
https://retrocomputing.stackexchange.com/questions/21936/how-to-use-and-or-and-xor-modes-for-vga-drawing - VGA Hardware
https://wiki.osdev.org/VGA_Hardware - Programmer's Guide to Yamaha YMF 262/OPL3 FM Music Synthesizer
https://moddingwiki.shikadi.net/wiki/OPL_chip - Does anybody understand how OPL2 percussion mode works?
https://forum.vcfed.org/index.php?threads/does-anybody-understand-how-opl2-percussion-mode-works.60925/ - Yamaha YMF262 OPL3 music – MoonDriver for OPL3 DEMO [Oscilloscope View]
https://www.youtube.com/watch?v=a7I-QmrkAak - Yamaha OPL vs OPL2 vs OPL3 comparison
https://www.youtube.com/watch?v=5knetge5Gs0 - OPL3 Music Crockett's Theme
https://www.youtube.com/watch?v=HXS008pkgSQ - Bad Apple (Adlib Tracker – OPL3)
https://www.youtube.com/watch?v=2lEPH6Y3Luo - FM Synthesis Chips, Codecs and DACs
https://www.dosdays.co.uk/topics/fm_synthesizers.php