Intel_CPU
Package Body
package body Intel_CPU is
---------------------------
-- Detect FPU presence --
---------------------------
-- There is a FPU present if we can set values to the FPU Status
-- and Control Words.
function Has_FPU return Boolean is
Register : Unsigned_16;
-- processor register to store a word
begin
-- check if we can change the status word
Asm (
-- the assembler code
"finit" & LF & HT & -- reset status word
"movw $0x5A5A, %%ax" & LF & HT & -- set value status word
"fnstsw %0" & LF & HT & -- save status word
"movw %%ax, %0", -- store status word
-- output stored in Register
-- register must be a memory location
Outputs => Unsigned_16'Asm_output ("=m", Register),
-- tell compiler that we used eax
Clobber => "eax");
-- if the status word is zero, there is no FPU
if Register = 0 then
return False; -- no status word
end if; -- check status word value
-- check if we can get the control word
Asm (
-- the assembler code
"fnstcw %0", -- save the control word
-- output into Register
-- register must be a memory location
Outputs => Unsigned_16'Asm_output ("=m", Register));
-- check the relevant bits
if (Register and 16#103F#) /= 16#003F# then
return False; -- no control word
end if; -- check control word value
-- FPU found
return True;
end Has_FPU;
--------------------------------
-- Detect CPUID instruction --
--------------------------------
-- The processor supports the CPUID instruction if it is possible
-- to change the value of ID flag bit in the EFLAGS register.
function Has_CPUID return Boolean is
Original_Flags, Modified_Flags : Processor_Register;
-- EFLAG contents before and after changing the ID flag
begin
-- try flipping the ID flag in the EFLAGS register
Asm (
-- the assembler code
"pushfl" & LF & HT & -- push EFLAGS on stack
"pop %%eax" & LF & HT & -- pop EFLAGS into eax
"movl %%eax, %0" & LF & HT & -- save EFLAGS content
"xor $0x200000, %%eax" & LF & HT & -- flip ID flag
"push %%eax" & LF & HT & -- push EFLAGS on stack
"popfl" & LF & HT & -- load EFLAGS register
"pushfl" & LF & HT & -- push EFLAGS on stack
"pop %1", -- save EFLAGS content
-- output values, may be anything
-- Original_Flags is %0
-- Modified_Flags is %1
Outputs =>
(Processor_Register'Asm_output ("=g", Original_Flags),
Processor_Register'Asm_output ("=g", Modified_Flags)),
-- tell compiler eax is destroyed
Clobber => "eax");
-- check if CPUID is supported
if Original_Flags(ID_Flag) /= Modified_Flags(ID_Flag) then
return True; -- ID flag was modified
else
return False; -- ID flag unchanged
end if; -- check for CPUID
end Has_CPUID;
-------------------------------
-- Get CPUID support level --
-------------------------------
function CPUID_Level return Natural is
Level : Unsigned_32;
-- returned support level
begin
-- execute CPUID, storing the results in the Level register
Asm (
-- the assembler code
"cpuid", -- execute CPUID
-- zero is stored in eax
-- returning the support level in eax
Inputs => Unsigned_32'Asm_input ("a", 0),
-- eax is stored in Level
Outputs => Unsigned_32'Asm_output ("=a", Level),
-- tell compiler ebx, ecx and edx registers are destroyed
Clobber => "ebx, ecx, edx");
-- return the support level
return Natural (Level);
end CPUID_Level;
--------------------------------
-- Get CPU Vendor ID String --
--------------------------------
-- The vendor ID string is returned in the ebx, ecx and edx register
-- after executing the CPUID instruction with eax set to zero.
-- In case of a true Intel processor the string returned is
-- "GenuineIntel"
function Vendor_ID return String is
Ebx, Ecx, Edx : Unsigned_Register;
-- registers containing the vendor ID string
Vendor_ID : String (1 .. 12);
-- the vendor ID string
begin
-- execute CPUID, storing the results in the processor registers
Asm (
-- the assembler code
"cpuid", -- execute CPUID
-- zero stored in eax
-- vendor ID string returned in ebx, ecx and edx
Inputs => Unsigned_32'Asm_input ("a", 0),
-- ebx is stored in Ebx
-- ecx is stored in Ecx
-- edx is stored in Edx
Outputs => (Unsigned_Register'Asm_output ("=b", Ebx),
Unsigned_Register'Asm_output ("=c", Ecx),
Unsigned_Register'Asm_output ("=d", Edx)));
-- now build the vendor ID string
Vendor_ID( 1) := Character'Val (Ebx.L1);
Vendor_ID( 2) := Character'Val (Ebx.H1);
Vendor_ID( 3) := Character'Val (Ebx.L2);
Vendor_ID( 4) := Character'Val (Ebx.H2);
Vendor_ID( 5) := Character'Val (Edx.L1);
Vendor_ID( 6) := Character'Val (Edx.H1);
Vendor_ID( 7) := Character'Val (Edx.L2);
Vendor_ID( 8) := Character'Val (Edx.H2);
Vendor_ID( 9) := Character'Val (Ecx.L1);
Vendor_ID(10) := Character'Val (Ecx.H1);
Vendor_ID(11) := Character'Val (Ecx.L2);
Vendor_ID(12) := Character'Val (Ecx.H2);
-- return string
return Vendor_ID;
end Vendor_ID;
-------------------------------
-- Get processor signature --
-------------------------------
function Signature return Processor_Signature is
Result : Processor_Signature;
-- processor signature returned
begin
-- execute CPUID, storing the results in the Result variable
Asm (
-- the assembler code
"cpuid", -- execute CPUID
-- one is stored in eax
-- processor signature returned in eax
Inputs => Unsigned_32'Asm_input ("a", 1),
-- eax is stored in Result
Outputs => Processor_Signature'Asm_output ("=a", Result),
-- tell compiler that ebx, ecx and edx are also destroyed
Clobber => "ebx, ecx, edx");
-- return processor signature
return Result;
end Signature;
------------------------------
-- Get processor features --
------------------------------
function Features return Processor_Features is
Result : Processor_Features;
-- processor features returned
begin
-- execute CPUID, storing the results in the Result variable
Asm (
-- the assembler code
"cpuid", -- execute CPUID
-- one stored in eax
-- processor features returned in edx
Inputs => Unsigned_32'Asm_input ("a", 1),
-- edx is stored in Result
Outputs => Processor_Features'Asm_output ("=d", Result),
-- tell compiler that ebx and ecx are also destroyed
Clobber => "ebx, ecx");
-- return processor signature
return Result;
end Features;
end Intel_CPU;