Mam pytanie czy podane niżej zagadnienia będą działać pod windows
Opóźnianie za pomocą operacji I/O na porcie
Inną metodą opóźniania o niewielkie ilości mikrosekund są operacje I/O na portach. Czytanie/zapisywanie jakiegokolwiek bajtu z/do portu 0x80 (patrz wyżej jak to się robi) powinno dać opóźnienie prawie dokładnie 1 mikrosekundy bez względu na typ procesora i jego prędkość. Możesz tak robić wiele razy aby uzyskać opóźnienie rzędu kilku mikrosekund. Sposób ten nie powinien wywoływać żadnych szkodliwych efektów ubocznych na żadnym standardowym komputerze (nawet niektóre moduły jądra go używają). W ten sposób uzyskują opóźnienie funkcje {in|out}[bw]_p() (zobacz asm/io.h).
W zasadzie, instrukcje I/O na większości portów w obszarze 0-0x3ff zbierają prawie dokładnie 1 mikrosekundę, więc jeśli na przykład używasz bezpośrednio portu równoległego po prostu wykonaj kilka razy inb() z tego portu aby uzyskać opóźnienie.
Opóźnianie za pomocą instrukcji asemblerowych
Jeśli znasz typ procesora i prędkośc zegara w komputerze na którym będzie działał twój program, możesz na stałe uzyskać krótsze opóźnienia poprzez zastosowanie pewnych rozkazów asemblerowych (pamiętaj jednak że twój proces może się zacząć w dowolnym momencie wobec czego opóźnienia te mogą być większe od czasu do czasu) W tabeli poniżej wewnętrzna prędkość procesora określa liczbę cykli np dla procesora 50MHz (np. 486DX-50 lub 486DX2-50) jeden cykl zegara zajmuje 1/50000000 sekundy. (200 nanosekund).
Instrukcja cykle zegara na 386 cykle zegara na 486
nop 3 1
xchg %ax,%ax 3 3
or %ax,%ax 2 1
mov %ax,%ax 2 1
add %ax,0 2 1
(Przykro mi ale niewiele wiem o Pentium. Pewnie podobnie do 486. Nie mogę znaleźć żadnej instrukcji która zajmowała by tylko jeden cykl zegara na 386. Jeśli możesz, używaj instrukcji jednocyklowych, w przeciwnym razie architektura potokowa (pipelining) używana w nowoczesnych procesorach może dać jeszcze krótsze czasy)
Rozkazy nop i xchg z tabeli powyżej nie powinny powodować żadnych skutków ubocznych. Reszta może modyfikować rejestr znaczników ale nie powinno mieć to znaczenia bo gcc powinno to wykryć. Użycie nop jest dobrym wyborem.
Aby skorzystać z powyższego, trzeba w swoim programie wywołać funkcję asm("instrukcja") Składnia instrukcji jest taka sama jak w tabeli powyżej. Jeśli chcesz użyć kilku instrukcji w jednym wywołaniu funkcji asm rozdziel je średnikami. Na przykład asm("nop ; nop ; nop ; nop") wywoła cztery razy instrukcję nop opóźniając nasz program o 4 cykle na 486 lub Pentium (lub 12 cykli na 386)
Funkcja asm() jest przez gcc tłumaczona na wstawkę w asemblerze a więc nie ma zagrożenia przekroczenia limitu wywołań funkcji.
Opóźnienia krótsze niż jeden cykl zegara nie są możliwe w architekturze Intel i386.
Instrukcja rdtsc w Pentium
Jeśli masz Pentium, możesz odczytać ilość cykli zegara które upłynęły od ostatniego uruchomienia komputera. Robi się to za pomocą takiego kodu w C:
--------------------------------------------------------------------------------
extern __inline__ unsigned long long int rdtsc()
{
unsigned long long int x;
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
return x;
}
--------------------------------------------------------------------------------
Możesz odczytywać tą wartość w celu opóźniania o dowolną ilość cykli.