Asembler
Rejestry procesora
No to skoro przeszliśmy przez dość trudny początek i bardzo spodobał się nam (jak na razie) asembler to wgłębmy się w niego jeszcze bardziej. Będzie znowu trochę zakręconej teorii, ale dosyć ciekawej.
Wspominałem już, ile procesor się musi naliczyć, ażeby zadowolić programistę i wyświetlić coś na ekranie. Pobawmy się trochę w filozofów i postawmy pytanie: ile procesor musi się naliczyć, aby dodać dwie liczby? Człowiek zrobiłby to albo używając kalkulatora, albo pisemnie albo w pamięci. Tak się składa, że procesor komputera ani nie ma pod ręką kalkulatora, ani niczego do pisania, więc pozostaje mu tylko pamięć. Ktoś powie: tyle obliczeń i wszystko w pamięci!? Jak on to robi? Otóż, żeby w tym wszystkim się nie zgubić, jego pamięć (nie mylić z RAM'em) jest podzielona na tzw. rejestry. Oczywiście żeby było ciekawiej jest ich kilka rodzajów. Na początku zajmiemy się rejestrami ogólnego przeznaczenia. Są to:

AX - Accumulator	| akumulator
BX - Base Register	| rejestr bazowy
CX - Count Register	| licznik
DX - Data Register	| rejestr danych
SP - Stack Pointer	| wskaźnik stosu
BP - Base Pointer	| wskaźnik bazy
SI - Source Index	| indeks źródła
DI - Destination Index	| indeks przeznaczenia

Operując na nich jesteśmy w stanie dodać dwie liczby, choć jeszcze nie tak od razu. Większość operacji nie możemy wykonać po prostu na liczbach, bo od tego właśnie są rejestry (to takie kolejne ułatwienie). Najpierw więc przeniesiemy nasze liczby do rejestrów za pomocą instrukcji, której składnia wygląda tak: mov gdzie, co. Pierwszy argument określa gdzie będzie przechowywana wartość drugiego (dlaczego właśnie taka kolejność?). Przykładzik:

  asm
   mov ax,2
   mov bx,3
  end;

Teraz wystarczy zsumować za pomocą instrukcji add x, y , a wynik zostanie umieszczony w x:

  asm
   mov ax,2
   mov bx,3
   add ax,bx
  end;

Po tej operacji rejestr AX będzie miał wartość 5 (wbrew pozorom:). Chyba łatwe. Każdy rejestr ogólnego przeznaczenia jest 16-bitowy czyli można powiedzieć, że jest typu word. Na szczególną uwagę zasługują te, które w nazwie mają literkę X. Możemy je podzielić na dwie połówki: wyższą (AH-igher) oraz niższą (AL-ower).Każda z tych połówek zawiera 8 bitów (jeden bajt). Rozpatrzmy to na przykładzie akumulatora AX:

AX
AH AL
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Jeśli np. odwołamy się bezpośrednio do AH:

  ...
  mov ah, 255
  ...

...to rejestr AX będzie wyglądał tak:

AX=65280
AH=255 AL=0
1 1 1 1 1 1 1 1 0 0 0 0 0 0 0 0

Stąd można łatwo wyciągnąć wniosek, że AX można rozpisać wzorem:

AX = AH * 256 + AL.

Oczywiście to samo dotyczy innych rejestrów 'z iksem'. Pozostałe są prostsze i mają postać, przykładowo:

BP

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

Co oznacza mniejsze pole manewru niż w poprzednim przypadku.

Istnieje specjalny rejestr, o którym chciałbym Ci jeszcze powiedzieć, tzw. rejestr flagi (znaczników). Są one zupełnie inne niż te poznane do tej pory. Można je przyrównać do przełączników, które mogą być albo włączone albo wyłączone, lub dokładniej: do bitów, które albo mają wartość 0 albo 1. Flag nie możemy bezpośrednio modyfikować. Są one ustawiane automatycznie przez pewne procesy lub operacje i są zależne od ich wyników. W zależności od procesora flag może być od 9 do 11. Zawartości sześciu z nich są istotne dla sterowania operacjami logicznymi i arytmetycznymi, ponieważ informują o pewnych cechach wyniku. Pozostałe przełączają procesor w odpowiedni sposób pracy. Omówię tu tylko dwa znaczniki. (Reszta na razie Cię nie musi interesować. Jeżeli zajdzie potrzeba to omówię je później.) Są to:

PF - Parity Flag    | znacznik parzystości: informuje o wystąpieniu w
                      mniej znaczącym bajcie wyniku parzystej liczby bitów
		      o wartości 1
ZF - Zero Flag	    | znacznik zera: informuje o zerowym wyniku	

Aby móc zobrazować to przykładem potrzebne nam będą dwie nowe instrukcje: dec x, która powoduje zmniejszenie wartości x o jeden oraz jz @etykieta, która powoduje skok do etykiety jeśli ustawiona jest (ma wartość 1) ZF. I tak:

  asm
    mov ax,2		
    dec ax		{po tej operacji AX ma wartość 1}
    jz @etykieta	{czyli ten skok nie zostanie wykonany}
    dec ax		{ax=0 czyli ZF przyjmuje wartosc 1}
    jz @etykieta	{hop}
    mov ax,100	
   @etykieta:
  end;

Co dziwne, jeżeli wykonamy: mov ax,0 to mimo iż wynik tej operacji jest zerowy ZF nie będzie ustawiona. Nie mam pojęcia dlaczego. Skoro już jesteśmy przy tym warto wspomnieć jeszcze o instrukcji cmp x,y. Porównuje ona wartości x oraz y i w przypadku gdy są sobie równe ustawia ZF. Nie mam pojęcia dlaczego:).


Copyright © 2000-2001 Bartosz 'SILV' Jaworski
All rights reserved