Kurs programowania w asemblerze
Jak to się robi w asemblerze?
- Nieudokumentowane instrukcje PENTIUM
- Rozpoznanie typu procesora
- Operacje na plikach
- Operacje na katalogach
- Obsługa klawiatury
- Obsługa myszki
- Obsługa joysticka
- Pamięć
- Windows
- Monitor
- Liczby losowe
- Dźwięk
Dźwięk
Często podczas pisania programów zachodzi potrzeba wydobycia z komputera jakiegoś sygnału. Można to uczynić w bardzo prosty sposób używając głośnika znajdującego się w naszym PC. Do wytwarzania dźwięku trzeba odpowiednio zaprogramować licznik czasu, czyli układ INTEL 8253, który pracuje jako programowalny dzielnik częstotliwości. Wydobycie dźwięku składa się więc z dwóch głównych czynności: zaprogramowaniu odpowiednio licznika i przesłaniu sygnału do głośnika. Aby uzyskać dźwięk o danej częstotliwości f należy skorzystać z prostej zależności: K=1193181/f, gdzie nasze K, jest to współczynnik podziału. Teraz do portu 43H należy wpisać liczbę B6H. Jest to stała sterująca, ustalająca konfigurację dzielnika częstotliwości. Następnie do portu 42H ładujemy młodszy, a potem starszy bajt naszego współczynnika podziału K. Teraz trzeba wydobyć z głośnika dźwięk. Głośnik używa dwóch najmłodszych bitów portu 61H. Aby włączyć głośnik, musimy ustawić te bity na wartość 1. Nie można podczas tej operacji zmieniać wartości innych bitów. By wyłączyć dźwięk trzeba te bity wyzerować. By wydobyć więc prosty dźwięk należy napisać:
MOV BX,K ; K - współczynnik podziału MOV AL,0B6H OUT 43H,AL ; ustalenie konfiguracji dzielnika MOV AL,BL ; AL- mniej znaczący bajt K OUT 42H,AL ; wysłanie do portu 42H MOV AL,BH ; AL- bardziej znaczący bajt K OUT 42H,AL ; wysłanie do portu 42H IN AL,61H ; wczytanie zawartości portu 61H OR AL,11B ; ustawienie dwa najniższe bity na 1 OUT 61H,AL ; i wysłanie do portu 61H ... ; dowolne operacje <dźwięk teraz gra> IN AL,61H ; do AL wartość portu 61H AND AL,11111100B ; wyzerowanie dwóch najniższych bitów OUT 61H,AL ; i wysłanie do portu 61H |
Implementacja w Turbo Pascalu procedur SOUND i NoSoudn:
SOUND: MOV BX,SP MOV BX,SS:[BX+4] MOV AX,34DDH MOV DX,0012H CMP DX,BX JNC @@2 ;ustalenie wartości dzielnika DIV BX MOV BX,AX ;sprawdzenie, czy głośnik nie jest już włączony IN AL,61H TEST AL,3 JNZ @@1 ;włączenie bramki poprzez układ 8255 OR AL,3 OUT 61H,AL ;wpis do rejestru sterującego 8253 MOV AL,0B6H OUT 43H,AL ;wpisanie wartości podzielnika do rejestru 42H @@1: MOV AL,BL OUT 42H,AL MOV AL,BH OUT 42H,AL @@2: RETF 2 |
NOSOUND: IN AL,61H AND AL,0FCH OUT 61H,AL RETF |
Liczby losowe
Bardzo często zachodzi potrzeba wygenerowania jakiejś liczby losowej. Jest to bardzo proste, wystarczy posłużyć się poniższą procedurą. Zwraca ona w rejestrze AX liczbę losową z danego przedziału:
RANDOM PROC MOV BX,Seed ADD BX,9248h ROR BX,1 ROR BX,1 ROR BX,1 MOV Seed,BX MOV AX,RndHi SUB AX,RndLo MUL BX MOV AX,DX ADD AX,RndLo RET ENDP Seed DW 1111h ; zmienna pomocnicza do generatora RndHi DW ? ; górny zakres generowanych liczb RndLo DW ? ; dolny zakres generowanych liczb |
By uniknąć cykliczne powtarzanie się liczb, należy zmieniać po pewnej liczbie losowań zmienną Seed, np. według zegarka.
Obsługa klawiatury
- Odczyt pojedynczego znaku
- Sprawdzanie bufora klawiatury
- Odczyt stanu klawiszy dodatkowych
- Ustawienie parametrów klawiatury
- Wstawienie znaku do bufora klawiatury
Klawiaturę można obsługiwać na dwóch poziomach: BIOSa i DOSa. My zajmiemy się tym pierwszym. Do obsługi klawiatury BIOS daje nam przerwanie 16H. Dzięki niemu mamy pełną kontrole na tym urządzeniem.
Do odczytu pojedynczego znaku służy funkcja 10H, a w przypadku klawiatury podstawowej 0H. Zwraca nam ona w rejestrze AH kod SCAN naciśniętego klawisza. W rejestrze AL dostaniem kod ASCII również tego klawisza. Jeśli podczas wywołania przerwania w buforze klawiatury nie znajduje się żaden znak, to funkcja będzie czekać, aż takowy zostanie naciśnięty. Funkcja również nie wyświetla naciśniętego znaku.
MOV AH,10H INT 16H AH - kod SCAN AL - kod ASCII |
Bardzo często zachodzi potrzeba sprawdzenia, czy w buforze klawiatury nie znajduje się jakiś znak. Np. jeśli chcemy wykonywać pętlę aż zostanie kliknięty klawisze jest to jedynym rozwiązaniem.
Do tego celu służy funkcja 11H, a przy klawiaturze podstawowej 01H, przerwania 16H. Jeśli w buforze znajdował się klawisz, znacznik Z jest wyzerowany, a w rejestrach: AH - znajduje się kod SCAN i w AL - znajduje się kod ASCII. Jeśli podczas wywołania przerwania w buforze nie było żadnego znaku, znacznik Z jest ustawiony (równy 1).
Funkcja ta po odczycie z bufora kodu znaku nie czyści tego bufora. Znajduje się on w niej, aż zostanie odczytany za pomocą funkcji 10H.
Odczyt stanu klawiszy dodatkowych
Podczas pisania programów zachodzi czasami potrzeba sprawdzenie stanu klawiatury, tzn. sprawdzenie, czy np. CAPS LOCK jest włączony, czy nie. Do tego celu służy funkcja 02H, która w rejestrze AL zwraca kod stanu klawiatury. Poszczególne bity mają następujące znaczenie:
bit 0 - prawy Shift
bit 1 - lewy Shift
bit 2 - Ctrl
bit 3 - Alt
bit 4 - Scroll Lock
bit 5 - Num Lock
bit 6 - Caps Lock
bit 7 - Insert
Funkcja jednak nie rozróżnia klawiszy Alt i Ctrl, czy jest wciśnięty lewy, czy prawy. Znacznie lepszym rozwiązaniem jest użycie funkcji 12H. Wówczas otrzymujemy kod stanu klawiatury w rejestrze AX. Ma on następującą postać:
bit 0 - prawy Shift
bit 1 - lewy Shift
bit 2 - Ctrl
bit 3 - Alt
bit 4 - Scroll Lock
bit 5 - Num Lock
bit 6 - Caps Lock
bit 7 - Insert
bit 8 - lewy Ctrl
bit 9 - lewy Alt
bit 10 - prawy Ctrl
bit 11 - prawy Alt
bit 12 - Scroll Lock
bit 13 - Num Lock
bit 14 - Caps Lock
bit 15 - SysReq
Ustawienie parametrów klawiatury
Przerwanie 16H daje nam również możliwość ustawienia parametrów naszej klawiatury i tak:
AX=0305H
BH= opóźnienie
00H - 0.25s
01H - 0.50s
02H - 0.75s
BL= częstotliwość samo powtarzania
00H - 30
znaków/sek
01H - 27 znaków
02H - 24 znaki
03H - 22 znaki
04H - 20 znaków
itd.
Wstawienie znaku do bufora klawiatury
Dzięki funkcji 05H przerwania 16H mamy możliwość wstawienia znaku do bufora klawiatury. Wówczas w rejestrze CH podajemy kod SCAN, a w rejestrze CL kod ASCII. Po wykonaniu przerwania nie wystąpił żaden błąd znacznik C jest wyzerowany, a AH=0. Gdy wystąpił błąd znacznik C=1 i AH=1.
Obsługa joysticka
Do obsługi joysticka zaliczamy sprawdzenie położenia i stanu przycisków. W tym celu wykonujemy przerwanie 15H, funkcję 84H. Jeśli w rejestrze DX podamy wartość 1, to w odpowiedzi w AX znajdzie się pozycja X joysticka pierwszego, w BX pozycja Y joysticka pierwszego, w CX pozycja X joysticka drugiego i w DX pozycja Y joysticka drugiego. By sprawdzić stan przycisków w DX podajemy 0. W odpowiedzi dostaniemy liczbę w AL. Poszczególne jej bity oznaczają:
bit4 : stan przycisku 1 joysticka 1
bit5 : stan przycisku 2 joysticka 1
bit6 : stan przycisku 1 joysticka 2
bit7 : stan przycisku 2 joysticka 2
joystick.zip - opis programowania joysticka PC 3.67KB
Obsługa myszki
- Sprawdzenie statusu myszy
- Wyświetlenie kursora myszy
- Wyłączenie kursora myszy
- Odczyt pozycji i stanu przycisków
- Ustawienie pozycji kursora myszy
- Ustawienie granic dla kursora
- Ustalenie prędkości przesuwania kursora
Przed uruchomieniem programy, który ma obsługiwać myszkę, należy najpierw sprawdzić, czy jest ona zainstalowana. Do tego celu, jak i do innych operacji związanych z myszką, służy przerwanie 33H. Funkcja 00H sprawdza status zainstalowania i wynik zwraca w rejestrze AX. Jeśli AX=0H, to myszka nie jest zainstalowana, a jeśli AX=0FFFFH, to jest obecna w systemie i wówczas w BX mamy liczbę przycisków myszy.
Wyświetlenie kursora myszy
Kursor myszy trzeba najpierw odkryć, gdyż po uruchomieniu programu nie jest on automatycznie wyświetlany. Do tego celu służy funkcja 01H przerwania 33H. Na ekranie pokaże się, w zależności o trybu pracy, kursor graficzny lub tekstowy.
Czasami zachodzi potrzeba ukrycia kursora myszki. Wówczas stosujemy funkcję 02H przerwania 33H.
Odczyt pozycji i stanu przycisków
Dobra. Wiemy już jak pokazać kursor. Ruszamy myszką i zmienia on swoje położenie, ale jak sprawdzić w jakim aktualnie miejscu się znajduje, albo który klawisz jest wciśnięty? Trzeba posłużyć się funkcją 03H przerwania 33H. Zwraca ona w rejestrze CX wartość przesunięcia kursora względem osi X, a w DX względem osi Y. Kursor jest więc ustawiony o współrzędnych [CX,DX]. W rejestrze BX dostajemy status wciśniętych klawiszy. Bit 0 odpowiada za klawisz lewy, bit 1 za klawisz prawy, a bit 3 za klawisz środkowy.
Ustawienie pozycji kursora myszy
Przerwanie 33H i funkcja 04H dają nam możliwość ustawienia kursora myszy. Dzięki temu możemy programowo przesuwać wskaźnik w prawo i w lewo. Wówczas w rejestrze CX podajemy współrzędną X, a w DX współrzędną Y.
Czasami zachodzi konieczność ustalenia granic dla kursora, by np. nie wyjeżdżał za ekran. Należy się wtedy posłużyć funkcją:
AH=07H - ustawianie granic poziomych
CX - numer lewej kolumny
DX - numer prawej kolumny
AH=08H - ustalenie granic poziomych
CX - numer górnego wiersza
DX - numer dolnego wiersza
Ustalenie prędkości dla przesuwania kursora
Przerwanie 33H daje nam całkowitą kontrolę nad myszką. Dzięki funkcji 0FHmożemy ustalić nawet prędkość, z jaką kursor się porusza. Wówczas do rejestru CX podajemy prędkość przesuwania się po osi X, a w DX prędkość przesuwania się po osi Y.
Pamięć
Chyba każdy program posiada jakieś tablica. Zazwyczaj deklarujemy je np. tak:
tablica DB 1024 DUP(0)
Można również zarezerwować pamięć dla danej tablicy. Przydatne jest to szczególnie, gdy wykorzystujemy duże tablice. Do obsługi pamięci służy przerwanie 21H.
Podczas uruchamiania programu, procesor rezerwuje dla niego całą dostępną pamięć, dlatego jeśli chcemy sami ją zadeklarować, musimy najpierw zmniejszyć rozmiar tego bloku. Do tego celu służy funkcja 4AH. W ES podajemy segment rezerwowany, a w BX nowy rozmiar w paragrafach. Po wykonaniu przerwania otrzymamy w rejestrze BX rozmiar największego bloku i jeśli wystąpił błąd (C=1) kod błędu w rejestrze AX.
Do rezerwacji bloku służy funkcja 48H. Wówczas to do BX podajemy rozmiar bloku rezerwowanego. Jeśli wystąpi błąd (C=1) w AX będzie kod błędu, a jeśli nie, w AX dostaniemy segment bloku przydzielonej pamięci. Adres więc naszego wolnego bloku jest: AX:000.
Na koniec pracy naszego programu trzeba zwolnić przydzieloną wcześniej pamięć. Do tego celu używamy funkcji 49H przerwania 21H. Jako parametr podajemy w ES segment zarezerwowanego przy pomocy funkcji 48H bloku.
Operacje na plikach
- Tworzenie nowego pliku
- Otwieranie pliku
- Zapis do pliku
- Czytanie z pliku
- Zamknięcie pliku
- Zmiana wskaźnika w pliku
- Usuwanie pliku
- Sprawdzanie atrybutów pliku
- Nadawanie atrybutów pliku
- Zmiana nazwy pliku
Pisząc w dowolnym języku często zachodzi potrzeba stworzenia jakieś pliku, np. z danymi. W Asemblerze nie ma do tego celu żadnych instrukcji (jak i do innych operacji z tym związanych). By stworzyć plik trzeba użyć pewnych przerwań i tak do tworzenia pliku używamy przerwania 21H i funkcji 3CH. Przerwania wykonuje się w Asemblerze za pomocą instrukcji INT, a funkcja jest to wartość rejestru AH. Przed wywołaniem tego przerwania w rejestrze CX podajemy atrybuty naszego pliku (o atrybutach powiemy później), a w DS:DX nazwę, jaką ma mieć. Nazwa ma być zapisana w kodzie ASCIIZ, tzn. musi być zakończona znakiem o kodzie 0, np. jeśli chcemy stworzyć plik o nazwie "PLIK.TXT" napiszemy tak:
MOV AH,3CH MOV CX,0 MOV DX,OFFSET Nazwa INT 21H ... Nazwa DB "PLIK.TXT",0
Jeśli operacja zakończy się sukcesem, to w rejestrze AX znajdzie się numer dojścia do pliku. Jest on bardzo ważny. Identyfikuje on plik, do którego będą później zapisywane dane. Jeśli jednak operacja tworzenia pliku zakończy się niepowodzeniem to zostanie ustawiony znacznik C, a rejestr AX będzie posiadał kod powstałego błędu.
By otworzyć plik, należy użyć funkcji 3DH przerwania 21H. Jako parametry podajemy: w DS:DX adres do nazwy pliku (ASCIIZ); AL - tryb dostępu. Mamy do dyspozycji następujące tryby:
| bity | wartość | opis |
|---|---|---|
| 7 | 0 | Procesy potomne dziedziczą dojście wraz z numerem |
| 4..6 | 000 | Każdy proces może otworzyć plik wielokrotnie z prawem do pisania i/lub czytania, ale tylko w tym trybie |
| 4..6 | 001 | Pełna wyłączność. Nie mogą istnieć żadne inne dojścia do pliku. |
| 4..6 | 010 | Wyłączność pisania, pozostałe dojścia mogą mieć tylko prawo do czytania, jednak nie mogą być otwarte w trybie 000 |
| 4..6 | 011 | Wyłączność pisania, pozostałe dojścia mogą mieć prawo tylko do czytania i mogą być otwarte w trybie 000 |
| 4..6 | 100 | Mogą istnieć inne dojścia z prawem do czytania i/lub pisania, jednak nie mogą być otwarte w trybie 000 |
| 0..3 | 000 | Prawo do czytania |
| 0..3 | 001 | Prawo do pisania |
| 0..3 | 010 | Prawo do czytania i pisania |
My będziemy zazwyczaj używali trzech trybów:
AL=0 - czytanie
AL=1 - pisanie
AL=2 - czytanie i pisanie
Jeśli więc chcemy otworzyć istniejący plik o nazwie PLIK.TXT napiszemy:
MOV AH,3DH MOV AL,0 MOV DX,OFFSET Nazwa INT 21H ... Nazwa DB "PLIK.TXT",0
Podczas otwierania mogą wystąpić również błędy i wtedy znacznik C jest ustawiany, a AX posiada kod błędu. Jeśli operacja została wykonana poprawnie C=0, a AX zawiera numer dojścia.
Jeśli mamy już otwarty plik i chcemy w nim coś zapisać musimy użyć funkcji 40H przerwania 21H. W rejestrze BX podajemy numer dojścia (uzyskaliśmy go podczas otwierania pliku), w rejestrach DS:DX podajemy adres początku danych, które chcemy zapisać, a w rejestrze CX podajmy ilość bajtów do zapisania. Jeśli operacja zakończy się sukcesem znacznik C jest wyzerowany, a AX zawiera liczbę bajtów zapisanych. Jeśli podczas zapisu wystąpił błąd C=1, a AX zawiera kod błędu. Jeśli więc chcemy zapisać w naszym (otworzonym wcześniej) pliku napis "KURS ASSEMBLERA" napiszemy:
MOV AH,40H MOV BX,Numer dojścia MOV DX,OFFSET Napis MOV CX,15 INT 21H ... Napis DB "KURS ASSEMBLERA"
Do czytania z pliku służy funkcja 3FH przerwania 21H. W rejestrze BX podajemy również numer dojścia, CX ilość bajtów, które chcemy przeczytać, a w DS:DX adres bufora, gdzie mają zostać one zapamiętane. Jeśli operacja zakończy się sukcesem w rejestrze AX będziemy mieli ilość przeczytanych bajtów, a znacznik C=0. Ilość przeczytanych bajtów nie musi być równa ilość bajtów, które kazaliśmy przeczytać. Jeśli plik zawiera np. 30 bajtów danych, a my mu każemy przeczytać 50 bajtów, to AX będzie zawierało 30 bajtów.
Każdy plik, który został wcześniej otwarty trzeba na koniec zamknąć Do tego celu służy funkcja 3EH przerwania 21H. Podajemy w rejestrze BX numer dojścia do pliku , który chcemy zamknąć. Jeśli wystąpi jakiś błąd to znacznik C zostanie ustawiony, a AX zawiera kod powstałego błędu.
Do ustawiania wskaźnika w pliku służy funkcja 42H. W rejestrze BX podajemy numer dojścia, w AL sposób przesunięcia wskaźnika, a w CX:DX odległość na jaką chcemy przesunąć. Istnieją trzy rodzaje przesunięć:
AL=0 - licząc od początku pliku
AL=1 - licząc od bieżącej pozycji kursora
AL=2 - licząc od końca zbioru
Przesunięcie względem końca zbioru używa się również do obliczania wielkości zbioru, gdyż wynikiem funkcji 42H jest w DX:AX wartość aktualnego położenia (o ile nie wystąpił błąd, wtedy C=1, a AX kod błędu).
Do usuwania zbiorów z dysku służy funkcja 41H przerwania 21H. W rejestrze DS:DX podajemy nazwę zbioru w kodzie ASCIIZ. Jeśli nie wystąpi błąd znacznik C zostaje ustawiony, a AX zawiera kod powstałego błędu.
Jeśli chcemy sprawdzić jakie dany plik ma atrybuty musimy posłużyć się funkcją 43Hprzerwania 21H. Podajemy wówczas w AL wartość 0, a w DS:DX nazwę pliku w kodzie ASCIIZ. Po wykonaniu przerwania w CX będą atrybuty pliku.
Atrybuty mają następujący format:
- bit0 - tylko do odczytu
- bit1 - ukryty
- bit2 - systemowy
- bit5 - archiwalny
Do nadawania atrybutów dla pliku służy również funkcja 43H. Podajemy teraz w AL wartość 1, w DS:DX nazwę pliku, a w rejestrze CX atrybuty, które chcemy nałożyć.
Czasami zachodzi potrzeba zmiany nazwy pliku. Wtedy trzeba posłużyć się funkcją 56H. W rejestrze DS:DX podajemy pierwotną nazwę pliku, a w rejestrze ES:DI nową nazwę pliku. Jeśli operacja zakończy się niepowodzeniem zostanie ustawiony znacznik C, a rejestr AX będzie zawierał kod błędu.
Operacje na katalogach
Do tworzenia nowych katalogów służy funkcja 39H przerwania 21H. W rejestrze DS:DX podajemy nazwę katalogu (w kodzie ASCIIZ). Jeśli operacja zakończy się błędem, zostanie on przekazany w rejestrze AX i zostanie ustawiony znacznik C
Do usuwania katalogów służy funkcja 3AH. W rejestrze DS:DX podajemy wówczas adres nazwy usuwanego katalogu.
Do ustalania katalogu bieżącego służy funkcja 3BH przerwania 21H. Jako parametr podajemy w DS:DX adres nowej nazwy katalogu.
Pobranie nazwy aktualnego katalogu
Jeśli chcemy dowiedzieć się o aktualnym katalogu bieżącym posłużymy się przerwaniem 21H i funkcją 47H. Jako parametry podajemy w DL numer dysku (o który nam chodzi). Jeśli mamy na myśli dysk bieżący wpisujemy 0, oraz w DS:SI adres 64-bajtowego bufora, w którym ma zostać zapamiętana ścieżka.. Jeśli operacja zakończy się sukcesem w buforze jest ścieżka, w przeciwnym wypadku znacznik C=1, a AX -kod błędu.
Windows
Wykrywanie Windows w pamięci
Podczas programowania zachodzi czasami potrzeba sprawdzenia, czy w pamięci znajduje się Windows, czy pracujemy w środowisku DOS. Można to uczynić wykonując przerwanie 2FH i funkcję 160AH. Jeśli po wykonaniu przerwania w rejestrze AX znajduje się wartość 0, tzn. że jest uruchomiony Windows. Wówczas w rejestrze BX znajduje się jego wersja (BH-numer wersji i BL-podnumer). Jeśli w rejestrze CX znajduje się wartość 2 tzn. że jest uruchomiony tryb standardowy. Jeśli CX=3, to uruchomiony jest tryb rozszerzony 386. Przerwanie to działa jednak tylko pod Windows 3.11 i nowszych.
Blokada klawiszy
Czasami program musi wykonać jakąś operacje, które nie może zostać mu przerwana. Jednak system operacyjny Windows umożliwia przerwanie wykonywania programu kombinacją klawiszy ALT+TAB, lub wciskając CTRL+ESC. By zapobiec takim sytuacjom trzeba użyć funkcji 1681H przerwania 2FH. Powoduje ona włączenie blokady tych klawiszy. By wyłączyć blokadę trzeba wywołać to samo przerwanie, tylko funkcję 1682H.
Monitor
Nowe monitory posiadają możliwość włączenia tzw. trybu czuwania. Jest to znacznie lepsze od wygaszaczy ekranu. Za pomocą przerwania 10H i funkcji 4F10H można sterować pracą monitora. By zmienić stan monitora do rejestru BL wpisujemy 1, a do rejestru BH wstawiamy jedną z następujących wartości:
- BH=0 - ON (monitor włączony, obraz widoczny)
- BH=1 - STANDBY (monitor w stanie czuwania)
- BH=2 - SUSPEND (monitor w stanie uśpienia)
- BH=4 - OFF (monitor w stanie głębokiego uśpienia)
- BH=8 0 REDUCED ON (opcja występuje tylko przy niektórych monitorach z płaskim ekranem)
Nieudokumentowane instrukcje PENTIUM
Do czasu pojawienia się procesorów PENTIUM problemu z obliczeniem, ile procesorowi potrzeba taktów na wykonanie danej procedury, nie było żadnym problemem. Jednak kiedy się one pojawiły problem się również pojawił, gdyż posiadają one architekturę superskalarną, tzn. ilość cykli danego kodu nie równa się sumie cykli poszczególnych instrukcji. Zazwyczaj jest mniej, ale może być również więcej.
Na szczęście procesor PENTIUM posiada jedną instrukcję o nazwie RDTSC (jej kod 0FH 31H), która odczytuje wbudowany 64-bitowy licznik cyklów zegara, który startuje wraz z procesorem. Wystarczy więc odczytać jego wartość na początku procedury, później na końcu, odjąć jedno od drugiego i koniec! Oto przykład:
.DATA Cykle_L DD 0 Cykle_H DD 0 .CODE ... DB 0FH, 31H MOV Cykle_H,EDX MOV Cykle_L,EAX ... ... DB 0FH, 31H SUB EAX,Cykle_L SUB EAX,9 ; odliczenie RDTSC SBB EDX,CykleH ...
