Previous: Intel_CPU Package Specification, Up: A Complete Example


D.7.3 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;