www.delorie.com/gnu/docs/gcc/gnat_ug_263.html   search  
 
Buy the book!


Untitled Document

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

24.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;


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

  webmaster     delorie software   privacy  
  Copyright 2003   by The Free Software Foundation     Updated Jun 2003