Assembler v príkladoch

Zmazanie obrazovky

    Začneme týmto jednoduchým príkladom. Chceme zmazať obrazovku v textovom móde a využijeme na to priamy prístup k nej. Obrazovka začína na B800:0000h a má 80 stĺpcov a 25 riadkov (v základnom textovom móde) po dvoch bajtoch. Prvý je ASCII kód znaku, druhý je farba znaku.

[BITS 16]
[ORG 0x0100]
[SECTION .text]

MOV AX,0B800H
;hexadecimálne číslo musí začínať číslicou, aby nebolo zamýlené s názvom návestia, preto ho treba zapísať ako 0B800h a nie B800h
MOV ES,AX
;segmentový register ES možno napĺňať len cez AX
MOV CX,80*25
MOV AX,7*256+' '
;farbou 7 (biela) "vymaz" obrazovku medzerami
REP STOSW

MOV AX,4C00h
INT 21h

Výpis čísla

    Ďalší príklad vypíše pevne zvolené číslo v pevne zvolenej sústave (v rozsahu 2 - dvojková - až 16 - hexidecimálna). Na výpis využíva službu DOSu.

[BITS 16]
[ORG 0x0100]

[SECTION .text]

MOV AX,12345
;vypisované číslo v rozsahu 0 až 65535
MOV BL,16
;základ sústavy v rozsahu 2 až 16

MOV DI,16
;číslo budeme zapisovať od konca - od najnižšej čílice

dalej:
DEC DI
;ďalšia číslica
XOR DX,DX
;DX<-0
DIV BX
;do DX ďalšia číslica
MOV SI,DX
MOV DL,[SI+cislice]
;zisti znak pre dané číslo...
MOV [DI+vypis],DL
;...a vypíš ho
AND AX,AX
JNZ dalej
;znova, dokým nebude AX=0, tzn. dokým nevypíšeme všetky číslice

MOV DX,text
;do DX adresu prvého textu
MOV AH,09h
;číslo služby...
INT 21h
;...určenej na vypisovanie textu
MOV DX,vypis
ADD DX,DI
;výpis čísla začneme od prvej - najvyššej, teda naposledy zapísanej číslice
MOV AH,09h
INT 21h

MOV AX,4C00h
INT 21h

[SECTION .data]
;tak takto sa definuje oblasť premenných

cislice DB '0123456789ABCDEF'
;zoznam znakov číslic
text DB 'Cislo = $'
;vypisovaný text ukončený znakom $
vypis TIMES 16 DB 0
DB '$'
;najviac šestnásťznakové číslo, ktoré bude vypísané - cez direktívu TIMES sa definuje poľe z rovnakých údajov jednoduchšie

Výpočet odmocniny

    Tento program pracuje s číslom získaného zo vstupu (z klávesnice, v prostredí NASMIDE treba vstup zadať v menu cez položku parameters), v rozsahu slova (0 až 65535). Hľadá jeho odmocninou v podstate metódou pokus - omyl. Skúša postupne nastavovať jednotlivé bity hľadaného výsledku (od najvyššieho) a tak toto číslo umocní. Ak je mocnina väčšia, nastavovaný bit treba opäť vynulovať.

[BITS 16]
[ORG 0x0100]

[SECTION .text]

MOV DX,vstup
;zo štandardného vstupu prepíš...
MOV CX,7
;...sedem znakov, keďže dva z nich budú znamenať ukončenie riadku, teda stlačenie enteru (0Dh, 0Ah)...
MOV BX,0
;...do pamäte od miesta návestia vstup
MOV AH,3Fh
INT 21h

SUB AX,2
;v AX je počet znakov zo vstupu, no treba odstrániť znak enter
OR AX,AX
JZ koniec
;ak nie je vstup, skonči
MOV CX,AX
;do CX počet znakov
MOV DI,vstup
MOV BX,10
;ideme previesť vstup v desiatkovej sústave do registra AX
XOR AX,AX
XOR DH,DH
;vynuluj AX a DH
testuj:
MUL BX
;vynásob aktuálny výsledok desiatimi
MOV DL,[DI]
;prečítaj ďalší znak
SUB DL,'0'
;zmeň ASCII znak na číslo 0 až 9
INC DI
;presuň ukazovateľ na ďalší znak
CMP DL,0
JC koniec
;ak nie je číslo v rozsahu 0 až 9, tak skonči
CMP DL,10
JNC koniec
ADD AX,DX
;pripočítaj čílicu k aktuálnemu výsledku
LOOP testuj
;t.j. SUB CX,1 a JNZ testuj - jednoduchý cyklus
JMP pokracuj

koniec:
MOV AX,4C00h
INT 21h
;bol nevhodný vstup - skonči

pokracuj:
MOV CX,AX
;do CX odmocňované číslo
MOV BL,10000000b
;začneme najvyšším bitom
XOR BH,BH
;BH<-0
MOV DL,2

hladaj:
ADD BH,BL
;pokusne pripočítaj skúmaný bit
MOV AL,BH
MUL AL
;umocni predpokladanú odmocninu...
CMP CX,AX
;...a porovnaj ju s odmocňovaným číslom
JNC dobre
SUB BH,BL
;trochu sme to prešvihli, odpočítaj ten bit späť
dobre:
MOV AL,BL
;ak je všetko v poriadku...
XOR AH,AH
DIV DL
MOV BL,AL
;posuň BL na ďalší bit - vydeľ ho dvoma a zarotuje doprava
OR AL,AL
JNZ hladaj
;ak sme nepreskúmali všetky bity, pokračuj

MOV AL,BH
MUL AL
SUB CX,AX
;ešte raz výsledné číslo umocni a získaj zvyšok po delení
MOV AL,BH
XOR AH,AH

MOV BX,10
MOV DI,3

dalej1:
;výpis registra AX - výsledku - procedúrou ako v programe výpis čísla
DEC DI
XOR DX,DX
DIV BX
MOV SI,DX
MOV DL,[SI+cislice]
MOV [DI+vypis1],DL
AND AX,AX
JNZ dalej1

MOV DX,text1
MOV AH,09h
INT 21h
MOV DX,vypis1
ADD DX,DI
MOV AH,09h
INT 21h

MOV DI,3
MOV AX,CX

dalej2:
;výpis registra CX - zvyšku - podobne
DEC DI
XOR DX,DX
DIV BX
MOV SI,DX
MOV DL,[SI+cislice]
MOV [DI+vypis2],DL
AND AX,AX
JNZ dalej2

MOV DX,text2
MOV AH,09h
INT 21h
MOV DX,vypis2
ADD DX,DI
MOV AH,09h
INT 21h

MOV AX,4C00h
INT 21h

[SECTION .data]

vstup TIMES 7 DB 0
;miesto pre vstup z klávesnice
cislice DB '0123456789'
;znaky a texty na výpis ako v programe výpis čísla
text1 DB 'Odmocnina = $'
vypis1 TIMES 3 DB 0
DB '$'
text2 DB ', zvysok = $'
vypis2 TIMES 3 DB 0
DB '.$'

Šetrič obrazovky

    Posledný program je pokus o šetrič obrazovky. Vypisuje štyridsať znakov "usmievavej tváre" (znak 01h ASCII) a pohybuje nimi rôznymi smermi. Ak nejaké "vypadne" z obrazovky, program vygeneruje ďalší znak.

[BITS 16]
[ORG 0x0100]

[SECTION .text]

zaciatok:
MOV AX,0B800h
;zmaže obrazovku
MOV ES,AX
XOR DI,DI
MOV CX,80*25
MOV AX,7*256+' '
REP STOSW

MOV SI,39*2
;vypisujeme od 39. znaku po znak 0. - spolu 40 znakov - z dvojbajtovej tabuľky
MOV AH,01h
INT 16h
JZ cyklus
;zisti, či bol stlačený znak, a skonči, ak bol
XOR AH,AH
;ešte ho však vyber zo zásobníka
INT 16h
MOV AX,4C00h
INT 21h

cyklus:
MOV CX,[SI+poz]
;zisti, či je daný znak platný (po spustení nie je zatiaľ ani jeden)
OR CX,CX
JNZ vypis
;ak je v poriadku, vypíš ho, ináč pokračuj jeho novým vygenerovaním

CALL random
;do DX náhodné číslo, zavolá procedúru random, po návrate z nej pokračuje ďalším príkazom
MOV CX,DX
;a teraz sa z DX pokúsime "vyextrahovať" smer nového znaku (s výnimkou najvyššieho - nevyužitého bitu tri najvyššie bity horného bajtu), jeho riadok (zvyšné štyri bity horného bajtu), farbu (najvyššie dva bity dolného bajtu) a stĺpec (zvyšných šesť bitov dolného bajtu)
AND CX,0000111100111111b
;maska pre ypsilónovú a ixovú súradnicu znaku...
ADD CX,5*256+9
;...ktoré boli vygenerované v rozsahu 0 až 15 (pripočítaním 5 upravené na 5 až 20) a 0 až 63 (pripočítaním 9 upravené na 9 až 72)
MOV [SI+poz],CX
;zapíš nové súradnice do tabuľky

AND DX,0111000011000000b
;maska pre smer a farbu generovaného znaku
MOV [SI+info],DX
;zapíš nové informácie do tabuľky

vypis:
MOV DL,160
;výpis znaku, v CX ostali jeho súradnice
SUB CX,0101h
;úprava z 1..80 a 1..25 na 0..79 a 0..24
ADD CL,CL
;vynásob súradnicu x dvoma - jeden znak zaberá v pamäti obrazovky dva bajty
MOV AL,CH
MUL DL
;a vynásob súradnicu y 80*2 z rovnakého dôvodu
XOR CH,CH
ADD AX,CX
MOV DI,AX
;adresu znaku na obrazovke do DI
MOV BX,[SI+info]
;zisti smer a farbu znaku
MOV AL,BL
MOV BL,01000000b
XOR AH,AH
DIV BL
;farba je na prvých dvoch najvyšších bitoch dolného bajtu - treba ju posunúť na najnižšiu pozíciu v bajte...
ADD AL,00001100b
;...a pripočítať k farbe 12, aby bola svetlá - výsledné farby teda budú svetločervená, svetlofialová, žltá a biela
MOV AH,AL
MOV AL,1
;znak 01h - usmievavá tvár
STOSW
;a výpis

MOV BL,00100000b/2
;rovnako posuň smer, ale až na druhý najnižší bit - tabuľka je dvojbajtová
MOV AL,BH
XOR AH,AH
DIV BL
MOV DI,AX
MOV CX,[SI+poz]
;do CX aktuálnu pozíciu znaku
ADD CX,[DI+tab]
;a k nej pripočítať "rýchlosť" podľa tabuľky
OR CH,CH
;zistíme, či znak náhodou nevyšiel z obrazovky
JZ zrus
CMP CH,26
JNC zrus
OR CL,CL
JZ zrus
CMP CL,81
JC nechaj
zrus:
XOR CX,CX
;vyšiel - zruš ho
nechaj:
MOV [SI+poz],CX
;zapíš novú pozíciu znaku
SUB SI,2
;choď na ďalší znak
JNC cyklus
XOR AX,AX
;všetky znaky vypísané - teraz už len čakacia slučka, aby sa tie znaky príliš nemihali pred očami...
MOV ES,AX
;...bez nej by sa pri súčasnej rýchlosti počítačov tie znaky ledva dali rozpoznať
MOV AL,[ES:046Ch]
cakaj:
CMP AL,[ES:046Ch]
JZ cakaj
;počká na zmenu časovača, ktorý sa mení každých 55 milisekúnd, teda 18.2 krát za sekundu
JMP zaciatok
;a znova na začiatok

random:
;procedúra na generovanie náhodného čísla
MOV BX,0
;naposledy vygenerované číslo
MOV DH,BL
;neviem, ako táto procedúra funguje, je odpísaná z knihy Assembler a ZX Spectrum 2, ktorej autori jú odpísali z iného programu...
MOV DL,253
;v každom prípade generuje spoľahlivo všetky čísla v rozsahu 0 až 65535
MOV AL,BH
SUB DX,BX
SBB AL,0
SBB DX,BX
SBB AL,0
MOV BL,AL
MOV BH,0
SBB DX,BX
JNC random1
INC DX
random1:
MOV [random+1],DX
;zapíš nové náhodné číslo...
RET
;...a vráť sa z procedúry

[SECTION .data]

tab DW 0FFFFh,0FF00h,0FF01h,00001h,00101h,00100h,001FFh,000FFh
;tabuľka rýchlostí v závislosti od smerov, od smeru vľavo hore smerom podľa ručičkových hodín, horný bajt je zápis "rýchlosti" y, dolný bajt je zápis "rýchlosti" x, z možností -1 (=0FFh=255), tzn. hore/vľavo, 0 a 1, tzn. dole/vpravo
poz TIMES 40 DW 0
;pozícia znakov na začiatku - všetky sú nulové, aby boli nanovo vygenerované
info TIMES 40 DW 0
;informácie o znakoch - smer a farba