+----------------------+
|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ň