123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242 |
- {
- This file is part of the Free Pascal run time library.
- Copyright (c) 1999-2000 by Florian Klaempfl
- This unit contains some routines to get informations about the
- processor
- See the file COPYING.FPC, included in this distribution,
- for details about the copyright.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- **********************************************************************}
- {$mode objfpc}
- unit cpu;
- interface
- uses
- sysutils;
- { returns true, if the processor supports the cpuid instruction }
- function cpuid_support : boolean;
- { returns true, if floating point is done by an emulator }
- function floating_point_emulation : boolean;
- { returns the contents of the cr0 register }
- function cr0 : longint;
- // function InterlockedCompareExchange128Support : boolean;
- // function AESSupport : boolean;inline;
- // function AVXSupport: boolean;inline;
- // function AVX2Support: boolean;inline;
- // function FMASupport: boolean;inline;
- // var
- // is_sse3_cpu : boolean = false;
- function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec;
- implementation
- {$ASMMODE INTEL}
- {$ASMCPU 80386}
- // var
- // _AVXSupport,
- // _AVX2Support,
- // _AESSupport,
- // _FMASupport : boolean;
- function InterlockedCompareExchange128(var Target: Int128Rec; NewValue: Int128Rec; Comperand: Int128Rec): Int128Rec;
- begin
- RunError(217);
- end;
- function cpuid_support : boolean;assembler;nostackframe;
- {
- Check if the ID-flag can be changed, if changed then CpuID is supported.
- }
- asm
- xor ax, ax
- {$IFDEF FPC_MM_HUGE}
- mov bx, SEG Test8086
- mov es, bx
- cmp byte ptr es:[Test8086], 2 { 2 = 80386 or later }
- {$ELSE FPC_MM_HUGE}
- cmp byte ptr [Test8086], 2 { 2 = 80386 or later }
- {$ENDIF FPC_MM_HUGE}
- jb @@Done { Test8086<2 means 80286 or earlier }
- pushfd
- pushfd
- pop bx
- pop cx
- mov dx, cx
- xor cx, 20h
- push cx
- push bx
- popfd
- pushfd
- pop bx
- pop cx
- popfd
- and cx, 20h
- and dx, 20h
- cmp cx, dx
- je @@Done
- inc ax
- @@Done:
- end;
- function cr0 : longint;assembler;nostackframe;
- asm
- int 3
- xor ax, ax
- xor dx, dx
- {$IFDEF FPC_MM_HUGE}
- mov bx, SEG Test8086
- mov es, bx
- mov al, byte ptr es:[Test8086]
- {$ELSE FPC_MM_HUGE}
- mov al, byte ptr [Test8086]
- {$ENDIF FPC_MM_HUGE}
- test al, al { 0 = 8086/8088/80186/80188/NEC v20/v30: no cr0/msw register; simply return 0 }
- jz @@Done
- cmp al, 1 { 1 = 80286 }
- jne @@386_or_later
- { on 80286 we use SMSW (high 16 bits are 0, because dx=0) }
- smsw ax
- jmp @@Done
- @@386_or_later:
- { use smsw first, to see if we are in real mode (mov eax, cr0 isn't supported in virtual 8086 mode) }
- smsw ax
- test al, 1
- jz @@386_read_cr0 { real mode: we can read cr0 }
- { 386 in protected mode; check the virtual 8086 mode flag }
- { unfortunately, this doesn't work, because pushfd never pushes the virtual 8086 mode flag as 1 }
- //pushfd
- //pop cx
- //pop cx
- //test cl, 2
- //jnz @@Done {if in virtual 8086 mode, we can't read cr0, so just return the SMSW result }
- { so, we must assume virtual 8086 mode and just return the SMSW result }
- { TODO: this can be updated for e.g. protected mode 286 targets, where we
- can safely assume the CPU is not in virtual 8086 mode, but proper protected mode
- and still try to read cr0 }
- jmp @@Done
- @@386_read_cr0:
- pushf { save the previous state of the interrupt flag }
- cli { disable interrupts, because some buggy TSR may destroy the high
- 16 bits of eax in an interrupt handler (BP7's 32-bit mul/div
- helpers do this, when they detect a 386 or later, so e.g. a BP7
- TSR that hooks the timer interrupt could do this) }
- { store eax, so that we preserve the high 16 bits of eax }
- push eax
- mov eax, cr0
- push eax
- pop cx
- pop dx
- pop eax { restore eax }
- mov ax, cx
- popf { restore interrupts to their previous state }
- @@Done:
- end;
- function floating_point_emulation : boolean;
- begin
- {!!!! I don't know currently the position of the EM flag }
- { $4 after Ralf Brown's list }
- floating_point_emulation:=(cr0 and $4)<>0;
- end;
- {$ASMMODE ATT}
- // function XGETBV(i : dword) : int64;assembler;
- // asm
- // movl %eax,%ecx
- // // older FPCs don't know the xgetbv opcode
- // .byte 0x0f,0x01,0xd0
- // end;
- // procedure SetupSupport;
- // var
- // _ecx,_ebx : longint;
- // begin
- // is_sse3_cpu:=false;
- // if cpuid_support then
- // begin
- // asm
- // pushl %ebx
- // movl $1,%eax
- // cpuid
- // movl %ecx,_ecx
- // popl %ebx
- // end;
- // _AESSupport:=(_ecx and $2000000)<>0;
- //
- // _AVXSupport:=
- // { XGETBV suspport? }
- // ((_ecx and $08000000)<>0) and
- // { xmm and ymm state enabled? }
- // ((XGETBV(0) and %110)=%110) and
- // { avx supported? }
- // ((_ecx and $10000000)<>0);
- //
- // is_sse3_cpu:=(_ecx and $1)<>0;
- //
- // _FMASupport:=_AVXSupport and ((_ecx and $1000)<>0);
- //
- // asm
- // pushl %ebx
- // movl $7,%eax
- // movl $0,%ecx
- // cpuid
- // movl %ebx,_ebx
- // popl %ebx
- // end;
- // _AVX2Support:=_AVXSupport and ((_ebx and $20)<>0);
- // end;
- // end;
- // function InterlockedCompareExchange128Support : boolean;
- // begin
- // { 32 Bit CPUs have no 128 Bit interlocked exchange support }
- // result:=false;
- // end;
- // function AESSupport : boolean;
- // begin
- // result:=_AESSupport;
- // end;
- // function AVXSupport: boolean;inline;
- // begin
- // result:=_AVXSupport;
- // end;
- // function AVX2Support: boolean;inline;
- // begin
- // result:=_AVX2Support;
- // end;
- // function FMASupport: boolean;inline;
- // begin
- // result:=_FMASupport;
- // end;
- begin
- // SetupSupport;
- end.
|