Programowanie w języku Pascal

Jak zmusić 16-bitowy kompilator tp do 32-bitowych operacji

  • 3 komentarze
  • 477 odsłon
  • Oceń ten tekst jako pierwszy
Czyli jak zmusić 16-bitowy kompilator tp do 32-bitowych operacji.

Pozornie rzecz niemożliwa, a jednak...

Część tematu jest już zaprezentowana w artykule pt.: efektywne programowanie w turbo pascalu,
więc się będę nieco powtarzać. Ponadto zakładam, że znasz podstawy
asemblera, bo to dzięki niemu będziemy czarować w 32 bitach. (Będziemy
używać tylko asemblera wbudowanego w kompilator, więc jeśli używasz
asemblera zewnętrznego, to nie ma sensu żebyś czytał dalej ten artykuł.

Co nam daje działanie na 32 bitach? Przede wszystkim operacje takie są
szybsze w porównaniu do ich 16-bitowych odpowiedników, ponadto wyniki
naszych działań nie są ograniczone rozmiarem 16-bitowego rejestru a
rozmiarem rejestru 32-bitowego, czyli że bez nadmiernego kombinowania
możemy sobie działać na wielokrotnie większych liczbach - przy
zachowaniu tej samej, a nawet wyższej szybkości.

Same plusy :)

Ale jest i minus: jak? Jak zmusić kompilator tp do przełknięcia czegoś, do
czego nie był przewidziany? Popatrzmy na wbudowany asembler: nie zna
takich rejestrów, jak EAX,EBX itp, nie zna FS ani GS, w ogóle zero
zrozumienia dla naszych 32-bitowych aspiracji.

Ale zna on coś takiego, jak DB, DW i DD. I to nas urządza. :)

Jak się buduje 32-bitową instrukcję? Jeśli by za pośrednictwem debuggera
(np.: Turbo Debugger) pownikać w kod jakiegoś 32-bitowego programu, to
zobaczymy śmiesznie prostą prawidłowość: każda taka operacja jest
poprzedzona bajtem o wartości 66h (102d).

Tak! To jest naprawdę aż takie proste! Więc zaczynamy rzeźbienie...

Na pierwszy ogień najczęściej używana operacja - zerowanie rejestru.

asmend;


W ten sam sposób możemy sobie dzielić, mnożyć, dodawać, odejmować,
przesuwać bity, wrzucać na stos i z niego zdejmować - teoretycznie
cokolwiek!

W praktyce pojawia się kilka problemów, ale o tym za chwilę.

Może kilka przykładów:

asmend;


Teraz mnożenie word*word z wynikiem dword (tzn. longint). Strach
patrzeć w debuggerze na to, co robi TP z c := longint(a)*longint(b)...

asmend;


Powyższa instrukcja jest wykonywana o ponad 60% szybciej.

A może by tak zaryzykować 64 bity?... Mnożenie dword*dword z wynikiem
qword (2*longint)!!! Wynik zrzucany do dwóch zmiennych - poniżej
$FFFFFFFF do c, a to co wyżej - to do d.

asmend;


W analogiczny sposób można dzielić dword przez dword, otrzymując w
wyniku też dwa dwordy (tzn. c = a div b; d = a mod b):

asmend;


Jak szybko zwiększyć zmienną typu longint?

asmend;

asmend;


Nie trzeba dodawać, że inc jest dużo szybsze od add?

A dodawanie? Proszę bardzo:

asmend;



asmend; 


Jeśli porównasz któryś z powyższych kodów z jego odpowiednikiem
generowanym w wyniku zwykłego mnożenia, dzielenia itp., to zobaczysz
jak wiele zyskujesz.

Możemy też dopalić najbardziej czasochłonną procedurę w TP: move (nota
bene - ona jest 8-bitowa!!!). Napiszemy własną wersję, która będzie
prawie cztery razy szybsza.

A w ogóle jak działa ta procedura? Szybki rzut oka:

procedure move(var src;var dest;count : word); assembler;
asmend;


Spójrz na linijkę z trzema wykrzyknikami: rep movsb. movsb to operacja
przenoszenia bajtu ze stosu ds:si na stos es:di. Przenosimy po bajcie!
(Jeśli nie wierzysz, to odpal program, który używa tej procedury, pod
debuggerem i sam sprawdź.)

Przecież to jest bez sensu, bo kompilator bez żadnego rzeźbienia pozwala
na napisanie procedury, która będzie przenosić po słowie, czyli w tym
samym czasie skopiuje dwa razy więcej!

Ale po co się ograniczać do słowa? Poniższa procedura będzie zrzucać od
razu cztery bajty, osiągając graniczną prędkość działania równą prędkości
zegara pamięci...

procedure move32(var src;var dest;count : word); assembler;
asmend;


Chyba już łąpiesz, o co chodzi? Wtykasz db $66; wszędzie, gdzie się da, i
już możesz być szczęśliwy. Uważaj na jedno: operacje na pamięci -
zrzucanie i pobieranie ze stosu; pamiętaj, że operujesz naraz czterema
bajtami, a nie dwoma czy jednym. Jeśli nie jesteś pewien, czy poprawnie
zrobiłeś to, co chciałeś, a masz do dyspozycji Turbo Debuggera albo jakiś
inny debugger, to nie wahaj się i sprawdzaj.

Jeżeli masz jeszcze jakieś pytania lub chcesz coś dodać - pisz do mnie.

3 komentarze

mikmas 2007-02-26 18:28

Ta? To operuj sobie XMSem na 2MB buforze. Kopiowanie do pamięci konwencjonalnej, analiza, znowu kopiowanie.... nie wydaje się wam to.... wolne?

TKW 2004-09-05 15:51

Więcej pamięci? Jeżeli ponad 1Mb, należy zastosować (dla MS-DOS) EMS, XMS, DOS extender, lub napisać własny OS.

venifica 2004-02-08 23:11

Jeszce tylko pytanko - jak to zastosować do np. katr graficznych? czy to oznacza ze moge przypożadkować więcej np. pamięci?