Základní konstrukce v assembleru
Pokud programujete pokročilejší program, tak se bez assembleru
neobejdete. Každý jazyk používá své metody, jak psát v jazyce symbolických
adres. Je proto důležité si přečíst, jak se to či ono provádí. Turbo Pascal 7
umožňuje zapisovat assembler plným nebo Pascalovským způsobem.
Ten Pascalovský je jednodušší na pochopení. Ten standardní Vám
ale umožní obsáhnout všechny instrukce (v TP7 pouze pro 286 a nižší). Protože se
dost často setkávám s dotazy, že by ten či onen chtěl naprogramovat zvukovou
kartu či IPX síť, avšak jeho TP5 neumí bloky assembleru nebo neví, jak má použít
to či ono, rozhodl jsem se, že Vám ukážu některé základní konstrukce. Je
samozřejmě nutné, abyste o assembleru už něco věděli.
Nejčastějším způsobem je přistupování do paměti:
Když chcete např. něco uložit do video paměti v grafickém módu,
provedete to tímto způsobem:
Mem[$a000:0] := BYTE; (8 bitů)
MemW[$a000:0] := WORD; (16 bitů)
MemL[$a000:0] := DWORD; (32 bitů)
MemL[$a000:0] := (DWORD and $ffffff) or (MemL[$a000:0] and
$ff000000)
(24 bitů)
V assembleru to zapíšete následovně:
asm
push ds mov ax, $a000 mov ds, ax xor si, si mov al, BYTE
mov [si], al mov ax, WORD
mov [si], ax db 66h mov ax, DWORD
db 66h mov [si], ax
mov ax, [si]
end;
Přístup na porty je jednou z důležitých věcí, pokud např. měníte
paletu na VGA kartě nebo programujete zvukovou kartu. Pozor! Porty nejsou COM a
LPT, to jsou rozhraní. Takto se dá získat např. náhodné číslo z jednoho z
časovačů PC:
Port[$43] := 0;
BYTE := Port[$40];
V assembleru platí, že pokud chcete přistupovat k portu, jehož
číslo je menší než 256, můžete to provést přímo. K vyšším musíte použít registr
DX:
asm
mov al,0
out 43h,al
mov dx,40h in al,dx
end;
Funkce v Pascalu vrací své hodnoty v registrech. Byte se vrací v
AL (tedy stačí, když před ukončením funkce vložíte svůj výsledek do registru AL,
nebo můžete také použít @RESULT - tento symbol ale můžete použít jen ve funkci a
jen tehdy, není-li za její hlavičkou nápis ASSEMBLER;, který Vám normálně umožní
ji napsat celou podle sebe a navíc s ušetřením jednoho BEGIN a END;), Word v AX
a LongInt nebo typ Pointer ve dvojici DX:AX, kde DX je MSW nebo segment a AX je
LSW nebo offset.
Důležitou kapitolou jsou také přerušení. Vždy je nutné naplnit
nějaké ty registry a pak volat příslušné přerušení.
V TP7 se toto řeší příkazem INTR (navíc musíte použít jednotku
DOS). Musíte si definovat proměnnou, která bude zastupovat registry:
VAR R : registers;
Pak je můžete naplnit:
R.AH := 0;
R.AL := $13;
A poté volat přerušení:
INTR($10,R);
Tímto jsme změnili aktivní video mód na grafiku v režimu 320x200
a 256 barvách (textový režim 80x25 v 16 barvách, který je standardní, má číslo
režimu v AL rovno 3). Nastavit můžeme také registry AL a AH s příkazem WITH,
který Vám ušetří neustálé psaní toto R:
with R do
begin
AH := 0;
AL := $13;
end;
Ale to se hodí jen pokud těch registrů máte více. Jednodušší a
rychlejší je nastavit oba registry současně pomocí:
R.AX := $13;
Pro DOSové funkce se používá přerušení $21. Můžete jej volat
stejně jako každé jiné, nebo použít:
MSDOS(R);
Kde předáváte jen registry. Ty můžete po vykonání přerušení také
přečíst, jako každou jinou proměnnou.
Mnohem rychlejší je ale použití bloku assembleru, kde máte
jistotu, kolik instrukcí se použije a nemusíte používat další jednotku a
definovat proměnné (zápis $10 je rovnocenný zápisu 10h, mimo ASM lze ale použít
jen $, v ASM lze použít i B pro binární zápis čísla):
asm
mov ax,$13
int $10
end;
Pokud přecházíte na Free Pascal, což je stejný jazyk jako TP7
(ale již 32 bitový, rychlejší, běžící ve chráněném režimu, kde máte sice k
dispozci "neomezeně" paměti, ale zase Vám z toho plynou další omezení), můžete
používat samozřejmě assembler dál, ale bude nutné jej přizpůsobit Flat modelu.
Také je nutné si uvědomit, že ve chráněném režimu nemůžete jen tak přistupovat
na porty a také členění paměti je jiné.
Free Pascal má oproti Turbo Pascalu 7 tyto změny:
- je 32 bitový, tedy rychlejší na moderních CPU
- může využívat veškerou paměť počítače včetně virtuální (swap)
- obsahuje velké množství jednotek
- podporuje instrukce 386, 486, Pentium, MMX, SSE, 3DNow, Pentium
II, III a 4, 64 bitové CPU, SSE2 a FPU.
- je na 98% kompatibilní se syntaxí Turbo Pascalu 7
- podporuje konstrukce C, Delphi, a další
- lze vytvářet aplikace pro DOS, Windows, Linux, a další
- obsahuje rozsáhlou dokumentaci (ale jen v angličtině)
FP má jistě i další výhody, ale ty Vás budou zajímat teprve
tehdy, až se k nim dopracujete. Pokud přecházíte z TP7, je nutné si uvědomit
hlavně tyto věci:
- příkaz PORT již nelze použít bez jednotky PORTS. Lepší je ale
používat příkazy OUTPORTx a INPORTx, kde za X dosadíte šířku portu (B,W či L).
Tyto příkazy lze navíc používat pouze pod DOSem, nebo-li s využitím jednotky
GO32.
- přerušení INT 21h je funkční pouze v DOSové verzi Vašich
programů (můžete spustit DOSovou verzi pod Windows, ale pokud kompilujete přímo
pro Windows nebo Linux, pod tímto přerušením rozhodně nenajdete služby DOSu).
- příkaz MEM lze používat. Ve chráněném režimu existují dva typy
pamětí. DOSová a ta ostatní. Příkazem MEM se dostanete do prvního 1 MB paměti,
což je stejné chování, jako v TP7. K ostatní paměti se přistupuje přes proměnné,
které si definujete přes VAR nebo alokujete na haldě přes NEW či GETMEM.
- assembler v FP je výhradně 32 bitový, tedy je nutné s tím
počítat. Nastavovat registry přes AL nebo AX sice stále jde, ale je to pomalejší
než nastavení celého registru EAX. Také si např. umědomte, že instrukce LOOP
testuje registr ECX, tedy pokud ho nejprve nastavíte pomocí CX, asi Vám to
nebude fungovat správně!
- musíte se naučit rozlišovat přerušení, která jsou určena pro
reálný režim a která pro chráněný.
- Flat model nepoužívá segmentové registry (výjimka je přístup do
DOSové paměti, kterou budete potřebovat stále pro přístup do video paměti, pokud
nepoužíváte LFB, pro využití DMA, čtení BIOSu, atd.). Namísto toho každý registr
ESI, atd. už obsáhne až 4 GB paměti. To je maximální velikost jednoho prostoru,
který se alokuje přes selektor. FP standardně alokuje prostor pro haldu, kde má
umístěné všechny proměnné a ukáže na něj registry (selektory) DS a ES, které se
používá i pro přesun (instrukce MOVSx), takže s nimi nemusíte nijak manipulovat
(leda byste ručně volali nějaké funkce DOSu, které je mění - lepší je ale
používat vestavěné funkce FP). FP má DOSovou paměť také namapovanou přes
selektor FS, tedy na FS:[$a0000] najdete i videopaměť.
Free Pascal také umožňuje používat vícero syntaxe assembleru. TP7
používá standardní syntaxi Intelu, která spočívá hlavně v těchto věcech:
- segmentový registr je vždy před závorkou ES:[DI]
- cílový operand je vždy nalevo
- jméno instrukce neoznačuje šířku, a je tedy občas nutné ji
zadat pomocí ukazatele, kdy se napíše: INC BYTE PTR [$10]
- bázové adresování se zapisuje: FS:[Base+Index*Scale+Offs]
- vzdálené opuštění funkce se zapíše jako RET FAR
Příklad:
asm
mov dx,$80
in al,dx
mov eax,3
int 10h
end;
FP umí ale i AT&T, která má tyto pravidla:
- instrukce má na svém konci ještě udánu šířku operand, tj. L pro
DOWRD, W pro WORD nebo B pro BYTE
- před registry se musí uvádět znak %
- bázové adresování se zapisuje jako: FS:Offs(Base,Index,Scale)
- nalevo je zdrojový operand, cílový je napravo
- vzdálené opuštění funkce se zapíše jako LRET
- před konstantou je nutné psát znak $, který tedy neznamená
hexa!
například:
asm
movw $128,%dx
inb %dx,%al
movl $3,%eax
int $16
end;
Ale o tom si můžete přečíst v dokumentaci Free Pascalu.