ASSEMBLY GYAKORLAT 4. Irta Kaproncai Tamas [tomcat@szif.hu] -BILLENTYUZET-,FAJLKEZELES- 18a. Ismetleskent csinaljuk meg a kovetkezo feladatot: A keprnyo kozepere rajzoljuk egy piros teglalapot kek keretben es irjuk bele feherrel, hogy "Hello!". Ehhez eloszor is gyujtsuk ki az osszes szubrutint az ASMGYAK3.TXT-bol egy kulon fajlba, aminek a neve legyen RUTINOK.INC! (A kosobbiek soran mindenki szabadon bovitgetheti maganak ezt a rutin gyujtemeny a felkeszulese soran). Aki csak az NC-t hasznalja annak tippkent mondom, hogy nevezze at a fajlt es torolje ki belole a felesleges sorokat! (NC-ben egy teljes sort CTRL+Y-nal, vagy az F3-mal kijelolt blokkot F8-cal lehet torolni). Ha kesz ez a fajl, akkor ennek segitsegevel oldjuk meg a kituzott feladatot. Ehhez, ha valaki belegondol, akkor latja, hogy 3 szubrutin hivasra lesz szukseg (2 teglalap + 1 strki). Akkor most mar csak azt kell megnezni a szubrutinok elejen, hogy hogyan kell parameterezni oket. A kovetkezo tipikus hibakat kovethetjuk el: 1. Elszall a program. - Az %INCLUDE "rutinok.inc" sornak a kilepes utan a helye! 2. Nem rajzol teglalapot. - Valoszinu, hogy rossz a szinkod (min. 10H!). 3. Karaktereket rajzol a teglalap helyett. - DI erteke paros, ezert nem az attributum bajtokat irja felul a teglalap. 4. Nem latszik a szoveg. - Az strki nem allitja a szineket, valoszinu, hogy a korabban kirajzolt teglelap pl. piros alapon piros irast allitott be. 5. Egy nem kivant tegalap is megjelenik. - Elfelejtunk kilepni a programbol, ezert elindul az elso szubrutin. 6. Szoveg helyett szinek jelennek meg. - DI erteke paratlan, igy az attributum bajtokba ir az strki. 7. Mas szoveg jelenik meg. - Elfelejtettuk az ORG 100H sort a program legelejere beirni. Akkor lassuk a "medvet": ORG 100H ; mindenek elott Megegyszer elevenitsuk fel, hogy hogyan tudjuk pont kozepre tenni a teglalapot: - eldontjuk mekkora legyen a teglalap, pl. 40x12 MOV BX,40 ; szelesseg MOV DX,12 ; magassag - akkor kiszamoljuk mennyi karakter esik a teglalap ele es utan: ------------------- | 6 | (25-12)/2 = 6.5 | ========= | | | | | | 20 | | 20 | (80-40)/2 = 20 | | | | | ========= | | 7 | - ezek utan DI = 6 db teljes sor + 20 karakter ------------------- MOV DI,6*160 + 20*2 + 1 ; a szinek miatt kell a +1 - a szinek sorszamait a THELP -> SCREEN ATTRIBUTES oldalon lehet megnezni. MOV AL,11H ; kek alapon kek, a kerethez. CALL teglalap ; a nagyobbik teglalap megrajzolasa MOV BX,38 MOV DX,10 ; minden oldalt elveszunk egy karaktert MOV DI,7*160 + 21*2 +1 ; eggyel lejebb es balra rajzulunk MOV AL,47H ; piros alapon feher szin CALL teglalap MOV SI,szoveg ; a szoveg cimkeje MOV DI,12*160 + 37*2 ; paros! mert szoveg CALL strki MOV AX,4C00H ; kilepes DOS funkcioval INT 21H %INCLUDE "rutinok.inc" ; mintha ide beirtuk volna az osszes ; szubrutint szoveg DB 'Hello!',0 ; az strki sztring lezarasa nulla! Es itt van a RUTINOK.INC tartalma is az egyertelmuseg kedveert: teglalap: ; BX: szelesseg PUSHA ; DX: magassag PUSH ES ; AL: szin ; DI: a bal-felso sarok memoriacime MOV CX,0B800H MOV ES,CX ; Azert CX-szel csinalom, mert AL foglalt! MOV CX,DX .ciklus1: ; ha egy cimke .-tal kezdodik, akkor az lokalis PUSH CX PUSH DI MOV CX,BX .ciklus2: PUSH CX MOV [ES:DI],AL ADD DI,2 POP CX LOOP .ciklus2 POP DI ADD DI,160 POP CX LOOP .ciklus1 POP ES POPA RETN strki: ; SI: a sztring memoria cime PUSHA ; DI: a szoveg kezdo pozicioja a kepen PUSH ES MOV AX,0B800H MOV ES,AX .ujra: MOV AL,[SI] ; Egy karaktert beolvas a sztrinbol, INC SI ; lep a sztrin kov. karakterere. CMP AL,0 ; Megvizsgaljuk, hogy a karakter nulla-e, JZ .vege ; ha igen akkor ugras a szubrutin vegere. MOV [ES:DI],AL ; Kiirjuk a beolvasott karaktert a kepre, ADD DI,2 ; lepes a kovetkezo karakterre a kepernyon. JMP .ujra ; Feltetel nelkul ugras az iteracio elejere. .vege: POP ES POPA RETN szamki: ; AX: a kiirando szam erteke PUSHA ; DI: a kiiras kepernyo pozicioja MOV SI,szamstr + 4 ; az utolso szamjegy helye a sztringben .ujra: MOV BX,10 ; 10-es osztassal valasztunk le egy jegyet MOV DX,0 ; DX:AX az osztando szam, BX az oszto DIV BX ; hanyados -> AX, maradek -> DX ADD DL,'0' ; a kapott szamjegy karakterre alakitasa MOV [SI],DL ; egy karakter beirsa a sztringbe DEC SI ; lepes a kovetkezo jegy mem.cimehez CMP AX,0 ; Van meg mit osztani? JNZ .ujra ; ha igen, akkor ujabb iteracio INC SI CALL strki ; sztring kiiras POPA RETN szamstr DB ' ',0 ; helyfoglalas a sztringnek (min. 5 karakter). Jegyezzuk meg, hogy igy megha nem is hasznaltuk a szamki szubrutinunk, akkor is belekerult a leforditott kodba novelve ezzel a COM fajl hosszat. 18b. Aprobb modositas: a felirat legyen vilabosabb es villogjon! THELP -> SCREEN ATTRIBUTES Az eloter szinehez hozzaadunk 8-t, akkor vilagosabb lesz 7+8=15= 0FH A hatter szinehez hozzaadunk 8-t, akkor vilogni fog 4+8=12= 0CH Igy AL erteke 0CFH lesz. 19a. Probaljuk ki a szamkiiro szubrutint is! Irjunk programot, ami adott memoriacimrol [0:46C] kiolvas egy erteket es olvashato formaban kiirja a jobb-felso sarokba. Ezt addig ismetelgeti, amig egy billentyut le nem nyomnak. Az ismetlest a billentyuzet puffer uressegenek vizsgalataval oldjuk meg: MOV AH,1 INT 16h JZ ujra ; ha ures a puffer, akkor ugras ismetelni Mi a neve a szam kiiro szubrutinnak? CALL szamki Milyen regiszterben kell megadni, hogy a jobb felso sarokba irjon? MOV DI,75*2 ; ez a szam max. 5 jegyu lesz Miben varja a szamot? MOV AX,[0:46C] ; ez igy nem jo, helyette... MOV AX,0 ; igy helyes MOV ES,AX MOV AX,[ES:46CH] Na akkor az egesz program: ORG 100H ujra: MOV AX,0 MOV ES,AX MOV AX,[ES:46CH] MOV DI,75*2 CALL szamki MOV AH,1 INT 16h JZ ujra MOV AX,4C00H INT 21H %INCLUDE "rutinok.inc" Figyeljuk meg, hogy mi lesz a kilepeshez leutott billentyuvel! 19b. Nyeljuk el a kilepeshez leutott billentyut! A mar ismert BIOS hivas kell: MOV AH,0 INT 16H 19c. Egy adott billentyure (pl. ESC) lepjen ki a program! Az elozo funkcio nem csak kiveszi a leutott billentyut a pufferbol, de meg is jegyzi melyik billentyu volt az. AX regiszterben talaljuk az adatait: AL: ASCII kod THELP -> ASCII Code Table AH: scan kod THELP -> Keyboard Scan Codes Az ESC scan kodja: 1, ASCII kodja 27=1BH, ezert: CMP AX,011BH ; (eleg lenne csak az egyiket megvizsgalni) JNE ujra ; Jump vissza, ha Nem Egyenlo 19d. Most a BACKSPACE billentyure lepjen ki a program! Ez kinezheto lenne tablazatbol is, de most inkabb "kerdezzuk meg a gepet"! Inditsuk el a DEBUG (hibakereso) programot es gepeljuk be a kovetkezot! -a MOV AH,0 INT 16 ; Itt minden szam hexa! INT 3 -g Most ussuk le a kerdesest billentyut es mar olvashatjuk is AX regiszterben a kivant ertekeket: AX=0E08 (scan kod = 14, ascii kod = 8 ) -q segitsegevel kilephetunk a hibakeresobol es javithatjuk a forras programunk. Ha esetleg egyszerre tobb billentyunek a kodjara is kivancsiak vagyunk, akkor kilepes helyett az ujabb -g parancs elott egy -r ip 100 paranccsal az utasitas szamlalot visszaallitjuk a programocskank elejere, aztan -g Tehat ennek a programnak a vege igy nez ki: MOV AH,1 INT 16h JZ ujra MOV AH,0 INT 16H CMP AX,0E08H JNE ujra MOV AX,4C00H INT 21H %INCLUDE "rutinok.inc" Fajlkezeles ----------- Ez a fajlkezeles egyfele, tipus nelkuli. A fajlmuveleteket a megfelelo DOS funkciok meghivasaval fogjuk vegrehajtani. A hat fo fajlmuvelet, amit megismerunk: Fajl megnyitasa (THELP -> DOS Functions -> 3dH Open File) Fajlbol olvasas (THELP -> DOS Functions -> 3fH Read File) Fajl lezarasa (THELP -> DOS Functions -> 3eH Close File) Fajl letrehozasa (THELP -> DOS Functions -> 3ch Create File) Fajlba iras (THELP -> DOS Functions -> 40H Write File) Fajlban pozicionalas (THELP -> DOS Functions -> 42H Seek File) 20a. Eloszor is nezzunk egy peldat, ami betolt egy fajlt. ORG 100H MOV AH,3DH ; fajl megnyitasa MOV AL,0 ; a nyitas modja: 0 => olvasasra nyitas MOV DX,FajlNev ; melyik fajl kell megnyitni INT 21H ; a DOS megprobalja megnyitni a fajlt JNC FajlOke ; ha sikerult, akkor ugras tovabb MOV AH,9 ; sztring kiiras DOS funkcioval MOV DX,Hiba1 ; a hiba uzenet cimkeje INT 21H ; megejelenik a hibauzenet MOV AX,4C01H ; kilepes 1-es hibakoddal INT 21H FajlOke: MOV BX,AX ; a fajlt azonosito fajlszam attoltese BX-be MOV AH,3FH ; a DOS betoltes funkcioja MOV DX,Puffer ; a memoriacim, ahova tolteni fogunk MOV CX,32768 ; a toltendo bajtok szama, ennel rovidebb INT 21H ; fajlok teljesen be fognak toltodni MOV AH,3EH ; fajl lezarasa INT 21H MOV AX,4C00H ; normal kilepes INT 21H FajlNev DB 'C.BAT',0 ; akar teljes fajlspecifikacio, amit 0 zar le Hiba1 DB 'Nincs ilyen fajl',10,13,'$' ; DOS sztring $ jellel zarul! Puffer RESB 32768 ; 32768 bajt lefoglalasa Ha ezt lefuttatjuk, meg nem latunk semmit, de remelhetoleg visszater a program, illetve ha nincs meg a C.BAT fajl, akkor hibauzenetet is kapunk. 20b. A puffernek lefoglalt terulet sok nullaja ne keruljon bele a COM fajlba! Be kell irni ezt a sort a Puffer ele: section .bss Ezutan olyan "szekcio" kovetkezik, aminek csak a cimkeit szamitja ki a fordito, de fizikailag a kod nem kerul bele a COM fajlba. 20c. Jelenitsuk is meg a betoltott fajlt a kepernyon! Ehhez meg kell jegyezni, hogy hany bajtot sikerult beolvasni, es ennyi darab karaktert egyenkent kiiratunk a kepernyore magint csak a DOS-szal. A fajl betoltes utan, a fajl lezarasa ele kerul: PUSH AX ; tenylegesen betoltott bajtok szamat elmentjuk A fajl lezarasa utan a kilepes ele: POP CX ; a ciklusszamlalo a bajtok szamaval indul MOV SI,Puffer ; SI mutat az aktualis karakterre ciklus: PUSH CX ; a ciklus szamlalo vermbe mentese MOV AH,2 ; a DOS karakter kiiro alfunkciojanak szama: 2 MOV DL,[SI] ; betesszuk az aktualis karaktert DL-be INC SI ; lepunk a kovetkezo karakterre INT 21H ; a karakter kiiro funkcio meghivasa POP CX ; a ciklus szamlalo visszatoltese a verembol LOOP ciklus ; leptetjuk a ciklusunk Ezzel kesz is a program, ami minden 32768 bajtnal rovidebb fajlt meg tud jeleniteni a kepernyon. Hosszabb fajlok teljes betolteset csak tobb reszletben tudjuk megtenni (tobbszor kell meghivni a 3FH alfunkciot), hala a 16 bites fajlkezelesnek. Par gyakorlo pelda, amit a THELP-ben talalhato infok alapjan lehet megoldani: 21a. Mentsuk ki a memoria egy blokkjat egy uj fajlba! (A memoria cim: [C000:0], meret: 512 bajt, a fajlnev: VGABIOS.BIN). 22a. Irjunk masolo programot, ami adott fajlt atmasol adott nevre! 22b. Barmely hosszu fajlt is tudjon masolni a program!