+----------------------+ |Assembler pro blbé č.1| +----------------------+ Nedávno jsem narazil na perfektní text o assembleru a grafice. Prokousal jsem se tím a naučil se to. Myslím, že to bude zajímat více lidí, takže z toho vyrobím seriál na pokračování. Rád bych upozornil, že jsem taky začátečník. Prosím tedy staré zkušené Assemblerovské psy aby neváhali a radili a kritizovali. Často použiju dvě instrukce místo jedné, a o spoustě fint nemám určitě ani tušení. Očekávám taky, že mi vážení čtenáři budou psát maily s požadavky co nepochopili tak docela úplně. Rád svou rychlost přizpůsobím vašemu chápání. Takže mě klidně brzděte. Popohánění asi budete mít marné, protože jsem docela blbej a nemůžu vám to vysvětlovat rychleji, než se to stačím učit. Takže do toho skočíme rovnýma nohama: +--------+ |Registry| +--------+ Registry jsou něco jako proměnné ve vyšších programovacích jazycích. Průser je ovšem v tom, že je jich dost málo. Registry jsou většinou 16 bitové. Některé se dají rozdělit na dva 8mi bitové. Třeba 16ti bitový registr AX můžete používat jako dva 8mi bitové jménem AL a AH. Když vrazím do registru AX třeba hodnotu 0ABCDh (zvykněte si psát před hexa číslici nulu, pokud to je písmeno), bude AL obsahovat 0CDh a AH bude obsahovat 0ABh, jasan? Jestli ne, tak pište, pište. Takto můžete rozpůlit každý registr, který končí iksem. Dostenete potom dva kousky, jeden H a jeden L Podíváme se, co tu máme: AX - Takový jeden nejpoužívanější registr. BX - Další podobný CX - Umí to co ti nad ním, ale navíc se používá jako čítač ve smyčce. DX - Poslední z této čtveřice DS, ES, CS, SS - Segmentové registry. Viz dále SI, DI - Indexové registry, používají se pro práci s řetězci a poli. A pak je tu ještě pár dalších, ty si necháme až napak (až je pochopím) +-----------------+ |Segment & Offset:| +-----------------+ Když kdysi dávno (když na zemi vládli dinosauři) páni navrháři vynalézali procesor Intel 8086, rozhodli se, že ho vynaleznou tak, aby měl 16ti bitové registry a aby šířka jeho adresové sběrnice byla 20 bitů. Chvíli jen tak seděli a byli ze své geniality úplně paf a pak se jeden z nich poškrábal na hlavě a povídá: "Tož chlapi, šak to je ňáké divné né?" "Esli máme 20bitovů adresu, tož to možeme měť přístup k jednému megabajtovi, fíííha tož to ja." "Ale chlapi esli máme v jedném registru eném 16 bitů, tak sa k temu nemóžeme nijak dostať. Šak 16bitů to stačí eném na 64 kilobajtů." Tak zase chvilku seděli, nervózně krčili počítačové sjetiny, až jeden na to kápnul: "Já to mám, na přístup k paměti použijeme registry dva!" Jak řekli, tak udělali, ale udělali složitě. Představte si paměť jako řadu paměťových buněk. Tyto buňky jsou očíslovány od 0 po 0FFFFFh, je to celkem megabajt. Pokud chcete zjistit hodnotu, která je uložena na některé adrese, můžete říct třeba, že chcete hodnotu z adresy 1ABCh. To můžete říct vy, ale ne procesor. Ten má celou paměť rozdělenou na kusy o velikosti šestnácti bajtů. Když přistupujete na nějakou adresu udáte nejdříve číslo oné šestnáctice. To je tzv Segment, jako druhý údaj dodáte offset, což je posunutí od začátku vámi zadaného segmentu. Síla co? Takže třeba adresa 0000:0000 (Segment a Offset se od sebe oddělují dvojtečkou) je vlastně adresa 0. Adresa 0000:0100h, je totéž jako "přímá adresa" 0100h. Ovšem tuto adresu můžete zapsat také jako 0001:00F0h a nebo 000A:0060h, všechny tyto adresy ukazují na stejné místo, tedy na 0100h buňku paměti. Skutečnou adresu získáte takto: 16*Segment+Offset Naučte se tyto adresy nepřepočítávat, naučte se myslet v segmentech a offsetech. Toto je ta nejtěžší část strojového programování. +-----------------------------+ |Takže prvních pár instrukcí: | +-----------------------------+ MOV AX, 0FFFFh Do registru AX uloží hodnotu 0FFFFh MOV AX, BX Hodnotu, která je v registru BX, zkopíruje do AX (AX = BX) MOV AX, [0000:1234] Hodnota, která je uložena v paměti na adrese 0000:1234 se zkopíruje do AX (AX=Mem[0000:1234]) MOV AX, [1234] Je to totéž jako výše, ale není zde zadán segment. V takovém případě se segmentová část adresy vezme z registru DS (Data Segment) (AX=Mem[DS:1234]) MOV AX, [CS:1234] Opět stejné, ale tentokrát jsem přímo uvedl, že segmentovou část chci vzít z registru CS (Code Segment) MOV AX, [DS:SI] Jasné že? Segmentová část je v DS a offset je v SI. Všimněte si, že AX je 16bitový registr. Obsahem paměťového místa je ovšem bajt, tedy 8 bitů, takže takovéto přirazení načte bajt ze zadané adresy ten uloží do AL a načte bajt z adresy+1 a uloží jej do AH. Teď si předvedeme hrátky s registrem CX. Tento registr se kromě jiného používá jako čítač. Existuje instrukce LOOP, která zmenší CX o jedničku a pokud není nulový, skočí na zadané návěští, takže třeba: mov cx, 100 ;Smycku budu opakovat stokrat. SMYCKA: ;Navesti, sem se budu vrhat ble, ble, ble ;Tady neco pocitam, atd... ble ble ble, ble a furt pryc loop SMYCKA ;A znova dokola, stokrat. A co třeba indexové registry: Budu chtít znulovat oblast paměti velkou 100 bajtů od adresy 100:200h mov ax, 100h ;Do DS nemuzu priradit hodnotu primo mov ds, ax ;musim pres druhy registr mov di, 200h ;ted mi DS:DI ukazuje na prvni bajt ;nulovane oblasti mov ax, 0 ;Nuluju, tak je to nula mov cx, 100 ;Nuluju 100 bajtu Nuluj: mov [ds:di], ax ;Vrazim nulu na adresu DS:DI inc di ;A posunu se na dalsi adresu loop Nuluj ;To cele stokrat Jasan? Indexový registr je vlastně ukazatel v rámci jednoho segmentu. Díky tomu, že je to registr a jeho hodnota se tedy může měnit, můžu stejným programem adresovat různá místa. Časem poznáte i výkonější instrukce, které dělají hromadu věcí na jeden příkaz. Mým dnešním záměrem je ukázat, že je stroják rychlejší než cokoliv, takže zkusme vyrobit strašně rychlé přesouvání paměti. +-----------------------------------------------------------------+ |.MODEL SMALL | |.CODE | |.386 | | Obrazovka dw 0B800h ;adresa bloku v pameti | | Kusanec dw 1000 ;Kolik 4bajtu budu presouvat | | Kus2 dw 2000 ;Kolikrat budu sunout | | | |START: ;Tady zacina program | | mov cx, [cs:Kus2] | | mov ds, [cs:Obrazovka] | | mov es, [cs:Obrazovka] | |Smycka: | | push cx | | mov si, 2 ;DS:SI odkud presouvam | | mov di, 0 ;ES:DI kam presouvam | | mov cx, [cs:Kusanec] ;Kolik presouvam | | rep movsd ;CXkrat presunu [ES:DI] = [DS:SI] | | pop cx | | loop Smycka | | mov ax, 4c00h ;Konec programu, navrat do DOSu | | int 21h | |END START | +-----------------------------------------------------------------+ Část v rámečku vykopírujte do samostatného fajlu. Dejte mu příponu ASM a předhoďte jej assemblerovi. TASM.EXE nazev TLINK.EXE nazev.OBJ A je z toho EXE. Udělejte si baťák, který tento program spustí alespoň desetkrát. Teď si napište ve vašem oblíbeném vyšším programovacím jazyku program, který přesune 2000krát 4000bajtů z adresy 0B800:0002 na adresu 0B800:0000. To je to, co dělá prográmek nahoře. Vyrobte baťák na 100 opakování a měřte. Pokud se se mnou budete chtít spojit máte dvě možnosti FIDO a internet. Moje fidonetí adresa je 2:421/59. A internetí je: SysOp@pizi.fido.cz Čaute příště PIŽI výheň