unit Interval;
{$IFDEF VER2}{$DEFINE NEWFPC}{$ENDIF}
{$IFDEF VER3}{$DEFINE NEWFPC}{$ENDIF}
{$IFDEF NEWFPC}{$CALLING OLDFPCCALL}{$ENDIF}

interface

Function BiosTick:dword;
Function BiosTickFrom(last,d:dword):boolean;
Function RDTSC_Tick:int64;
Procedure WaitNS;

var
Je_RDTSC:boolean;

implementation


Function BiosTick:dword;assembler;{$IFDEF NEWFPC}nostackframe;{$ENDIF}
asm
mov eax,fs:[$400+$6c]
end;


Function BiosTickFrom(last,d:dword):boolean;assembler;
{Similar like "if FromTimer>last+d then true" but solves problem with}
{Timer wrapping on MaxDword value}
{DESTROYS: NONE (only return value into EAX)}
asm
push ecx
push ebx

call BiosTick      {BiosTick je ted v EAX}
mov ecx,eax        {a ted v ECX}

xor eax,eax

mov ebx,last       {Minula hodnota timeru je ted v EBX}


cmp ecx,ebx
jb @interval_uplynul  {osetri wrapping - nedodrzi vsak interval}

add ebx,d          {EBX:=Last+D}
cmp ecx,ebx
jb @je_mensi

@interval_uplynul:
inc eax

@je_mensi:

pop ebx
pop ecx
end;


Function Detekuj_instrukci_RDTSC:boolean;assembler;{$IFDEF NEWFPC}nostackframe;{$ENDIF}
asm
PushfD             {je vubec instrukce CPUID podporovana?}
Pop eax            {A mame instalovane alespon pentium?}
Bt eax,21
Setc dl
Btc eax,21
Push eax
PopfD

PushfD
Pop eax
Bt eax,21
Setc cl
Cmp dl,cl
mov eax,0  {nuluju EAX a nemenim priznaky (pak budu volar EAX=0/CPUID)}
Je @Konec          {Nejsme ani na Pentiu, tudiz nemame CPUID ani RDTSC}

{Ted alespon vime, ze jsme nejmene na pentiu a ze mame CPUID}
CPUID
cmp eax,1          {Lze volat CPUID s volacim parametrem 1?}
Jb @Konec          {Ne? konec}

mov eax,1          {Test na zakladni prehled schopnosti procesoru}
CPUID
xor eax,eax
Bt edx,4           {4.bit EDX udava pritomnost RDTSC}
adc eax,0

@Konec:
end;


Function RDTSC_Tick:int64;assembler;{$IFDEF NEWFPC}nostackframe;{$ENDIF}
asm
rdtsc  {vysledek vraci v EDX:EAX a take v Last_RDTSC}
end;


Procedure WaitNS;assembler;{$IFDEF NEWFPC}nostackframe;{$ENDIF}
{Pocka nekolik nanosekund. Nemeni registry}
asm
out 0EBh,al
end;


begin
Je_RDTSC:=Detekuj_instrukci_RDTSC;
end.
