; =============================================================================
;
; Litos - Initialize CPU, protected mode
;
; =============================================================================
%ifdef DEBUG
;%define DEBUG_CPU ; uncomment this to display CPU info
%endif
CODE_SECTION 32
; ------------- Macro - test if Time-Stamp Counter is supported (NZ=supported)
%define TSC_OK test byte [CPUInfo+CPU_Features],B4
; ------------- CPU information for Intel (i386) architecture
struc CPUINFO
CPU_Type: resb 1 ; 0: CPU basic type
CPU_Family: resb 1 ; 1: CPU family
CPU_Model: resb 1 ; 2: CPU model
CPU_VendorID: resb 1 ; 3: CPU vendor ID
CPU_Vendor: resb 12 ; 4: vendor name (12 characters)
CPU_Flags: resd 1 ; 10h: flags
; B0: multiprocessor
; B1: MMX supported
; B2: SSE supported
; B3: SSE2 supported
; B4: 3DNow! supported
; B5: 3DNow! Extended supported
; B6: MMX+ AMD extension supported
; B7: MMX+ Cyrix extension supported
; B8: FPU coprocessor present
; B9: FPU coprocessor is emulated
CPU_Features: resd 1 ; 14h: features (reported by CPU)
; B0: (FPU) floating point unit
; B1: (VME) virtual mode enhancement
; B2: (DE) debugging extensions
; B3: (PSE) page size extensions
; B4: (TSC) time stamp counter
; B5: (MSR) model-specific registers
; B6: (PAE) physical address extens.
; B7: (MCE) machine check exceptions
; B8: (CX8) CMPXCHG8B instruction
; B9: (APIC) APIC on chip
; B10: ...reserved
; B11: (SEP) fast system calls
; B12: (MTRR) mem.type range registers
; B13: (PGE) PTE page global bit enab.
; B14: (MCA) machine check architect.
; B15: (CMOV) condit.move/comp.instr.
; B16: (PAT) page attribute table
; B17: (PSE) 36-bit page size extens.
; B18: (PSN) processor serial number
; B19: (CLFSH) CFLUSH instruction
; B20: ...reserved
; B21: (DS) debug store
; B22: (ACPI) thermal mon.+clock ctrl.
; B23: (MMC) MMX instruction set
; B24: (FXSR) FXSAVE/FXRSTOR instruct,
; B25: (SSE) SSE extensions
; B26: (SSE2) SSE2 extensions
; B27: (SS) self snoop
; B28: (HTT) hyper-threading technol.
; B29: (TM) thermal monitor
; B30: (IA-64) IA-64(64-bit Intel CPU)
; B31: (PBE) pending break event
CPU_Extended: resd 1 ; 18h: extended features (vendor depen.)
; B10: AMD K6 model 6: Fast Syst.Calls
; B11: AMD K6 model 7 or newer:
; Fast System Calls
; B16: (fcmov) Cyrix, AMD K6 CPUs:
; Floating-point Conditional Move
; (pat) AMD K7 CPUs:
; Page Attribute Table
; B19: (mp) MP(MultiProcessor) Capable
; B22: (mmx+) AMD: MMX+ (AMD MMX Ext.)
; B24: (cxmmx) Cyrix: Extended MMX
; (fxsr) AMD K7:
; Fast float. point save/restore
; B29: (lm) AA-64 (AMD 64-bit CPU)
; B30: (3dnowext) 3DNow! extended
; B31: (3dnow) 3DNow! instructions
CPU_Frequency: resd 1 ; 1Ch: CPU frequency in Hz (min. 2 MHz)
endstruc ; size 20h = 32 bytes
; ------------- CPU flags
CPU_SMP EQU B0 ; multiprocessor
CPU_MMX EQU B1 ; MMX supported
CPU_SSE EQU B2 ; SSE supported
CPU_SSE2 EQU B3 ; SSE2 supported
CPU_3DNOW EQU B4 ; 3DNow! supported
CPU_3DNOW2 EQU B5 ; 3DNow! Extended supported
CPU_MMXAMD EQU B6 ; MMX+ AMD extension supported
CPU_MMXCYR EQU B7 ; MMX+ Cyrix extension supported
CPU_FPU EQU B8 ; FPU coprocessor present
CPU_EMU EQU B9 ; FPU coprocessor is emulated
; ------------- CPU architecture
CPU_ARCH_GENER EQU 0 ; generic CPU
CPU_ARCH_INTEL EQU 1 ; Intel (i386)
; ------------- CPU basic type - Intel architecture
CPU_8086 EQU 0 ; 8086 (unsupported)
CPU_186 EQU 1 ; 80186 (unsupported)
CPU_286 EQU 2 ; 80286 (unsupported)
CPU_386 EQU 3 ; 80386
CPU_486 EQU 4 ; 80486
CPU_PENTIUM EQU 5 ; Pentium
CPU_PENTIUM2 EQU 6 ; Pentium 2, Pentium Pro
CPU_PENTIUM3 EQU 7 ; Pentium 3
CPU_PENTIUM4 EQU 8 ; Pentium 4
; ------------- CPU vendor ID
CPU_VEND_GENER EQU 0 ; generic or unknown
CPU_VEND_INTEL EQU 1 ; Intel ("GenuineIntel")
CPU_VEND_AMD EQU 2 ; AMD ("AuthenticAMD")
CPU_VEND_CYRIX EQU 3 ; Cyrix ("CyrixInstead")
CPU_VEND_CENT EQU 4 ; Centaur ("CentaurHauls")
CPU_VEND_NEXGEN EQU 5 ; NexGen ("NexGenDriven")
CPU_VEND_TRANS EQU 6 ; Transmeta ("GenuineTMx86")
CPU_VEND_RISE EQU 7 ; Rise ("RiseRiseRise")
CPU_VEND_UMC EQU 8 ; UMC ("UMC UMC UMC ")
CPU_VEND_SIS EQU 9 ; SiS ("SiS SiS SiS ")
CPU_VEND_NSC EQU 10 ; National Semiconductor
; ("Geode by NSC")
CPU_VEND_NUM EQU 11 ; number of vendor ID codes
; ------------- CPU family and model variants:
; Family: Model: Name:
; 0 0 8086 (unsupported)
; 1 0 80186 (unsupported)
; 2 0 80286 (unsupported)
; 3 1 80386 DX
; 2 80386 SX
; -------------
; Intel:
; Family: Model: Name:
; 4 0 486 DX-25/33
; 1 486 DX-50
; 2 486 SX
; 3 486 DX/2
; 4 486 SL
; 5 486 SX/2
; 7 486 DX/2-WB
; 8 486 DX/4
; 9 486 DX/4-WB
; 5 0 Pentium 60/66 A-step
; 1 Pentium 60/66
; 2 Pentium 75 - 200
; 3 OverDrive PODP5V83
; 4 Pentium MMX
; 7 Mobile Pentium 75 - 200
; 8 Mobile Pentium MMX
; 6 0 Pentium Pro A-step
; 1 Pentium Pro
; 3 Pentium II (Klamath)
; 5 Pentium II (Deschutes), Celeron (Covington),
; Mobile Pentium II (Dixon)
; 6 Mobile Pentium II, Celeron (Mendocino)
; 7 Pentium III (Katmai)
; 8 Pentium III (Coppermine)
; 9 Mobile Pentium III
; 10 Pentium III (0.18 um) (Cascades)
; 11 Pentium III (0.13 um) (Tualatin)
; 13 Mobile Pentium III 2 MB (0.09 um)
; 14 Mobile Pentium III DC (65 nm) 2 MB
; 15 Core 2 DC (65 nm) 4 MB
; 7 .. Itanium (IA-64)
; 16 0 Pentium IV (0.18 um)
; 1 Pentium IV (0.13 um) (Willamette)
; 2 Pentium IV (0.13 um) (Northwood)
; 3 Pentium IV (0.09 um)
; 4,5 Pentium IV (Foster)
; 17 .. Itanium 2 (IA-64)
; 18 ? Itanium 2 DC (IA-64)
; -------------
; AMD:
; Family: Model: Name:
; 4 3 486 DX/2
; 7 486 DX/2-WB
; 8 486 DX/4
; 9 486 DX/4-WB
; 14 Am5x86-WT
; 15 Am5x86-WB
; 5 0 K5/SSA5
; 1..3 K5
; 6,7 K6
; 8 K6-2
; 9 K6-3
; 13 K6-2+ or K6-III+
; 6 0,1 Athlon (25 um)
; 2 Athlon (18 um)
; 3 Duron
; 4 Athlon (Thunderbird)
; 6 Athlon (Palamino)
; 7 Duron (Morgan)
; 8 Athlon (Thoroughbred)
; 10 Athlon (Barton)
; 16 4 Athlon 64
; 5 Athlon 64 FX
; Opteron
; ? K8 (130 nm)
; 17 ? K8 (90 nm Rev D)
; 18 ? K8 (90 nm Rev E)
; 20 ? K8 (90 nm Rev F)
; -------------
; Cyrix:
; Family: Model: Name:
; 4 4 MediaGX
; 5 2 6x86 / 6x86L
; 4 MediaGX MMX Enhanced
; 6 0 m II (6x86MX)
; 5 VIA Cyrix M2 core
; 6 WinChip C5A
; 7 WinChip C5B, WinChip C5C
; 8 WinChip C5N
; 9 WinChip C5XL, WinChip C5P
; -------------
; UMC:
; Family: Model: Name:
; 4 1 U5D
; 2 U5S
; -------------
; NexGen:
; Family: Model: Name:
; 5 0 Nx586
; -------------
; Rise
; Family: Model: Name:
; 5 0,1 mP6
; -------------
; SiS
; Family: Model: Name:
; 5 0 55x
; -------------
;Transmeta
; Family: Model: Name:
; 5 4 Crusoe TM3x00 and TM5x00
; 16 0 Efficeon
; -------------
; Centaur
; Family: Model: Name:
; 5 4 C6
; 8 C2
; 9 C3
; -------------
; National Semiconductor
; Family: Model: Name:
; 5 4 GX1, GXLV, GXm
; 5 5 GX2
; -----------------------------------------------------------------------------
; Detect and init CPU
; -----------------------------------------------------------------------------
; ------------- Prepare information structure
InitCPU: mov esi,CPUInfo ; ESI <- CPU info structure
mov byte [esi+CPU_Type],CPU_386 ; 80386
mov byte [esi+CPU_Family],3 ; Family 80386
inc byte [esi+CPU_Model] ; Model 80386 DX
; ------------- Check CPU if it is 486 at least (486 can change AC flag bit)
pushf ; push flags
pushf ; push flags
pop eax ; EAX <- flags
mov ecx,eax ; ECX <- store flags
xor eax,B18+B21 ; change bits AC and ID
push eax ; push EAX
popf ; set new flags
pushf ; push flags
pop eax ; EAX <- changed flags
popf ; pop old flags
xor eax,ecx ; EAX <- changed bits
test eax,B18 ; bit AC changed?
jnz InitCPU2 ; bit AC can be changed, it is 486
; ------------- Check CPU if it is 386 SX (386 SX cannot change bit 4 of CR0)
mov eax,cr0 ; EAX <- CR0
mov ecx,eax ; ECX <- push original CR0
xor al,B4 ; change bit 4 (ET)
mov cr0,eax ; set new value into CR0
mov eax,cr0 ; EAX <- new value
mov cr0,ecx ; CR0 <- return original value
xor eax,ecx ; EAX <- changed bits
test al,B4 ; can be bit 4 changed?
jnz InitCPU1 ; can be changed, it is 386 DX
inc byte [esi+CPU_Model] ; else it is 80386 SX
InitCPU1: ret
; ------------- Check CPU if it is 486 SX (486 SX has no math coprocessor)
InitCPU2: inc byte [esi+CPU_Type] ; it is 486
inc byte [esi+CPU_Family] ; Family 80386
test byte [BIOSEquip],B1 ; is math coprocessor installed?
jnz InitCPU3 ; math coprocessor is installed
inc byte [esi+CPU_Model] ; else it is 80486 SX
; ------------- Check if CPU supports CPUID information
InitCPU3: test eax,B21 ; bit ID changed?
jz InitCPU1 ; ID cannot be changed, it has not ID
inc byte [esi+CPU_Type] ; it is Pentium
inc byte [esi+CPU_Family] ; Family Pentium
mov byte [esi+CPU_Model],1 ; Model Pentium
; ------------- Get vendor name
xor eax,eax ; EAX <- 0 function code
cpuid ; get vendor name
mov [esi+CPU_Vendor],ebx ; Vendor name 0 to 3
mov [esi+CPU_Vendor+4],edx ; Vendor name 4 to 7
mov [esi+CPU_Vendor+8],ecx ; Vendor name 8 to 11
; ------------- Find vendor ID (search vendor string)
mov byte [esi+CPU_VendorID],CPU_VEND_NUM-1 ; last ID
mov edi,CPUVendString+(CPU_VEND_NUM-2)*12 ; last string
InitCPU4: cmp ebx,[edi] ; check characters 0 to 3
jne InitCPU42 ; not equal
cmp edx,[edi+4] ; check characters 4 to 7
jne InitCPU42 ; not equal
cmp ecx,[edi+8] ; check characters 8 to 11
je InitCPU5 ; found vendor
InitCPU42: sub edi,byte 12 ; shift string pointer
dec byte [esi+CPU_VendorID] ; decrease vendor ID
jnz InitCPU4 ; test next vendor string
; ------------- Get CPU information
InitCPU5: or eax,eax ; another information?
jz InitCPU1 ; no other information
mov eax,1 ; EAX <- 1 function code
cpuid ; get CPU type
; ------------- CPU features
mov [esi+CPU_Features],edx ; store CPU features
test edx,B23 ; MMX supported?
jz InitCPU52 ; MMX not supported
or byte [esi+CPU_Flags],byte CPU_MMX ; MMX supported
InitCPU52: test edx,B25 ; SSE supported?
jz InitCPU53 ; SSE not supported
or byte [esi+CPU_Flags],CPU_SSE ; SSE supported
InitCPU53: test edx,B26 ; SSE2 supported?
jz InitCPU56 ; SSE2 not supported
or byte [esi+CPU_Flags],CPU_SSE2 ; SSE2 supported
; ------------- CPU family
InitCPU56: mov ecx,eax ; ECX <- push CPU version
shr eax,8 ; EAX <- family
and al,0fh ; mask family
cmp al,15 ; use extended family?
jne InitCPU6 ; no, use base family
shr eax,20-8 ; EAX <- extended family
add al,16 ; AL <- extended family
InitCPU6: mov [esi+CPU_Family],al ; store family
; ------------- CPU model
xchg eax,ecx ; EAX <- CPU version, CL <- family
shr eax,4 ; EAX <- model
and al,0fh ; mask model
cmp cl,6 ; supports extended model?
jbe InitCPU62 ; doesn't support extended model
cmp al,15 ; use extended model?
jne InitCPU62 ; no, use base model
shr eax,16-4 ; EAX <- extended model
and al,0fh ; mask extended model
add al,16 ; AL <- extended model
InitCPU62: mov [esi+CPU_Model],al ; store model
; ------------- Detect Pentium CPU basic type
cmp cl,4 ; 486?
ja InitCPU64 ; no 486
dec byte [esi+CPU_Type] ; it is 80486
InitCPU64: cmp cl,5 ; Pentium 1?
jbe InitCPU7 ; Pentium 1
inc byte [esi+CPU_Type] ; Pentium 2
cmp cl,6 ; Pentium Pro, 2 or 3?
ja InitCPU65 ; Pentium 4
cmp al,7 ; Pentium 3?
jb InitCPU66 ; Pentium 2 or 3
InitCPU65: inc byte [esi+CPU_Type] ; Pentium 3
InitCPU66: cmp cl,7 ; Pentium 4?
jb InitCPU7 ; no
inc byte [esi+CPU_Type] ; Pentium 4
; ------------- Extended features
InitCPU7: mov eax,80000000h ; EAX <- function code
push eax ; push EAX
cpuid ; get max. function type
pop ecx ; ECX <- function code
inc ecx ; ECX <- function code+1
cmp eax,ecx ; is function 1 supported?
jb InitCPU9 ; function 1 is not supported
xchg eax,ecx ; EAX <- function code
cpuid ; get extended features
mov [esi+CPU_Extended],edx ; store extended features
; ------------- Check extended features
test edx,B31 ; 3DNow supported?
jz InitCPU72 ; 3DNow not supported
or byte [esi+CPU_Flags],CPU_3DNOW ; 3DNOW supported
InitCPU72: test edx,B30 ; 3DNow2 supported?
jz InitCPU74 ; 3DNow2 not supported
or byte [esi+CPU_Flags],CPU_3DNOW2 ; 3DNOW2 supported
InitCPU74: cmp byte [esi+CPU_VendorID],CPU_VEND_AMD ; AMD CPU?
jne InitCPU75 ; no AMD
test edx,B22 ; MMX+ AMD supported?
jz InitCPU75 ; MMX+ AMD not supported
or byte [esi+CPU_Flags],CPU_MMXAMD ; MMX+ AMD supported
InitCPU75: cmp byte [esi+CPU_VendorID],CPU_VEND_CYRIX ; Cyrix CPU?
jne InitCPU9 ; no Cyrix
test edx,B24 ; MMX+ Cyrix supported?
jz InitCPU9 ; MMX+ Cyrix not supported
or byte [esi+CPU_Flags],CPU_MMXCYR ; MMX+ Cyrix supported
InitCPU9: ret
; -----------------------------------------------------------------------------
; Init math coprocessor
; -----------------------------------------------------------------------------
; ------------- Init CR0 register
InitFPU: mov eax,cr0 ; EAX <- CR0
and eax,B31+B4+B0 ; save PG, ET and PE bits
or eax,byte B1 ; set MP bit (monitor coprocessor)
cmp byte [CPUInfo+CPU_Type],CPU_486 ; is 486 or more?
jb InitFPU2 ; is 386
or eax,B18+B16+B5 ; set AM, WP and NE flags, too
InitFPU2: mov cr0,eax ; set CR0
; ------------- Check if FPU is valid
clts ; clear task-switched flag in CR0
fninit ; initialize FPU
fstsw ax ; AX <- FPU status word
or al,al ; AL = 0?
jz InitFPU4 ; coprocessor is OK
; ------------- Set EM flag (FPU is emulated)
; FPU emulator currently not supported
; mov eax,cr0 ; EAX <- CR0
; or eax,byte B2 ; set EM flag (FPU is emulated)
; mov cr0,eax ; CR0 <- EAX
; or byte [CPUInfo+CPU_Flags+1],CPU_EMU>>8; FPU is emulated
ret
; ------------- FPU is hardware
InitFPU4: or byte [CPUInfo+CPU_Flags+1],CPU_FPU>>8; FPU is hardware
fsetpm ; init protected mode on 287
ret
; -----------------------------------------------------------------------------
; Initialize CPU frequency
; -----------------------------------------------------------------------------
; NOTES: This function must be called with interrupt disabled.
; -----------------------------------------------------------------------------
; ------------- Disable output to PC speaker and enable Timer 2 output
InitCPUFreq: in al,61h ; get keyboard controller B
and al,~B1 ; disable output to speaker
or al,B0 ; enable speaker gate
out 61h,al ; set output to speaker
; ------------- Set Timer 2 counter to 65536 (= period 54.92540 ms)
mov al,B7+B5+B4 ; select timer 2, LSB+MSB, mode 0
out 43h,al ; set Timer 2 mode
xor eax,eax ; EAX <- 0
out 42h,al ; set divisor LOW
SHORT_DELAY ; short delay
out 42h,al ; set divisor HIGH
; ------------- Check if time-stamp counter is supported
TSC_OK ; is time-stamp counter supported?
jz InitCPUFreq5 ; time-stamp counter is not supported
; ------------- Read time-stamp counter, start time
rdtsc ; read time-stamp counter (-> EDX:EAX)
xchg eax,esi ; ESI <- start time LOW
mov edi,edx ; EDI <- start time HIGH
; ------------- Wait for Timer 2 output
InitCPUFreq3: in al,61h ; read keyboard controller B
test al,B5 ; is Timer 2 output reached?
jz InitCPUFreq3 ; wait for end of Timer 2 counting
; ------------- Read time-stamp counter, get interval
rdtsc ; read time-stamp counter (-> EDX:EAX)
sub eax,esi ; EAX <- interval LOW
sbb edx,edi ; EDX <- interval HIGH
; ------------- Limit counter value
cmp edx,byte 0fh ; maximal value
jbe InitCPUFreq4 ; value is OK
mov edx,0fh ; limit maximal value HIGH
or eax,byte -1 ; limit maximal value LOW
; ------------- Calculate frequency
InitCPUFreq4: shld edx,eax,28 ; shift EDX:EAX << 28 (e.g. *2^28)
shl eax,28 ; shift EAX << 28
mov ecx,14743925 ; timer divisor (=0.054925401*(2^28))
div ecx ; calculate frequency
jmp short InitCPUFreq8
; ------------- Reset accumulator
InitCPUFreq5: xor esi,esi ; ESI <- 0, accumulator LOW
xor edi,edi ; EDI <- 0, accumulator HIGH
; ------------- Wait for Timer 2 output
InitCPUFreq6: add esi,byte 1 ; increment accumulator LOW
adc edi,byte 0 ; carry
in al,61h ; read keyboard controller B
test al,B5 ; is Timer 2 output reached?
jz InitCPUFreq6 ; wait for end of Timer 2 counting
; ------------- Limit counter value
or edi,edi ; maximal value
jz InitCPUFreq7 ; value is OK
or esi,byte -1 ; limit maximal value
; ------------- Calculate frequency
InitCPUFreq7: mov edx,esi ; EDX <- counter LOW * 2^32
xor eax,eax ; EAX <- 0
mov ecx,98300 ; timer divisor for Pentium
cmp byte [CPUInfo+CPU_Type],CPU_PENTIUM ; Pentium?
jae InitCPUFreq72 ; Pentium
mov ecx,50000 ; timer divisor for 486
cmp byte [CPUInfo+CPU_Type],CPU_486 ; 486?
jae InitCPUFreq72 ; 486
mov ecx,25000 ; timer divisor for 386 DX
cmp byte [CPUInfo+CPU_Model],1 ; 386 DX?
jbe InitCPUFreq72 ; 386 DX
mov ecx,15000 ; timer divisor for 386 SX
InitCPUFreq72: div ecx ; calculate frequency
; ------------- Round frequency
cmp eax,140000000 ; is it valid value?
jae InitCPUFreq8 ; value is above valid value
mov esi,LowCPUFreq ; ESI <- frequency table
mov edi,80000000h ; EDI <- found nearest distance
InitCPUFreq74: mov ecx,eax ; ECX <- found frequency
sub ecx,[esi] ; ECX <- distance
jns InitCPUFreq75 ; distance is not negative
neg ecx ; ECX <- absolute value of distance
InitCPUFreq75: cmp ecx,edi ; is it better frequency?
jae InitCPUFreq76 ; it is not better frequency
mov ebx,eax ; EBX <- found best frequency
mov edi,ecx ; EDI <- distance of found best freq.
InitCPUFreq76: add esi,byte 4 ; ESI <- next frequency
cmp esi,LowCPUFreq2 ; end of table?
jb InitCPUFreq74 ; next value
xchg eax,ebx ; EAX <- found best frequency
; ------------- Minimal value
InitCPUFreq8: mov ebx,2000000 ; EBX <- minimal frequency (2 MHz)
cmp eax,ebx ; is it valid value?
ja InitCPUFreq9 ; it is valid value
xchg eax,ebx ; EAX <- limit to minimal frequency
InitCPUFreq9: mov [CPUInfo+CPU_Frequency],eax ; store CPU frequency
; ------------- Debug display CPU info
%ifdef DEBUG_CPU
call DebInitCPU ; debug display CPU info
%endif
ret
; -----------------------------------------------------------------------------
; Debug display CPU info
; -----------------------------------------------------------------------------
%ifdef DEBUG_CPU
; ------------- Display CPU basic type
DebInitCPU: mov esi,CPUMsg ; ESI <- message text
call DebOutText ; display text
movzx eax,byte [CPUInfo+CPU_Type] ; EAX <- CPU basic type
mov esi,[CPUMsg1_Addr+eax*4-CPU_386*4] ; ESI <- message text
call DebOutText ; display text
; ------------- Display CPU vendor
mov esi,CPUMsg2 ; ESI <- message text
call DebOutText ; display text
movzx eax,byte [CPUInfo+CPU_VendorID] ; EAX <- CPU vendor
mov esi,[CPUMsg2_Addr+eax*4] ; ESI <- message text
call DebOutText ; display text
; ------------- Display CPU family
mov esi,CPUMsg3 ; ESI <- message text
call DebOutText ; display text
movzx eax,byte [CPUInfo+CPU_Family] ; EAX <- CPU family
call DebOutNum ; display family
; ------------- Display CPU model
mov esi,CPUMsg4 ; ESI <- message text
call DebOutText ; display text
movzx eax,byte [CPUInfo+CPU_Model] ; EAX <- CPU model
call DebOutNum ; display model
; ------------- Display CPU features
mov esi,CPUMsg5 ; ESI <- message text
call DebOutText ; display text
test byte [CPUInfo+CPU_Flags],B1 ; MMX
jz DebInitCPU21 ; no MMX
mov esi,CPUMsg5_2 ; ESI <- message text
call DebOutText ; display text MMX
DebInitCPU21: test byte [CPUInfo+CPU_Flags],B2 ; SSE
jz DebInitCPU22 ; no SSE
mov esi,CPUMsg5_3 ; ESI <- message text
call DebOutText ; display text SSE
DebInitCPU22: test byte [CPUInfo+CPU_Flags],B3 ; SSE2
jz DebInitCPU23 ; no SSE2
mov esi,CPUMsg5_4 ; ESI <- message text
call DebOutText ; display text SSE2
DebInitCPU23: test byte [CPUInfo+CPU_Flags],B4 ; 3DNow!
jz DebInitCPU24 ; no 3DNow!
mov esi,CPUMsg5_5 ; ESI <- message text
call DebOutText ; display text 3DNow!
DebInitCPU24: test byte [CPUInfo+CPU_Flags],B5 ; 3DNow! Extended
jz DebInitCPU25 ; no 3DNow! Extended
mov esi,CPUMsg5_6 ; ESI <- message text
call DebOutText ; display text 3DNow! Extended
DebInitCPU25: test byte [CPUInfo+CPU_Flags],B6 ; MMX+ AMD
jz DebInitCPU26 ; no MMX+ AMD
mov esi,CPUMsg5_7 ; ESI <- message text
call DebOutText ; display text MMX+ AMD
DebInitCPU26: test byte [CPUInfo+CPU_Flags],B7 ; MMX+ Cyrix
jz DebInitCPU27 ; no MMX+ Cyrix
mov esi,CPUMsg5_8 ; ESI <- message text
call DebOutText ; display text MMX+ Cyrix
DebInitCPU27: test byte [CPUInfo+CPU_Flags+1],B8>>8 ; FPU
jz DebInitCPU28 ; no FPU
mov esi,CPUMsg5_9 ; ESI <- message text
call DebOutText ; display text FPU
DebInitCPU28: TSC_OK ; TSC
jz DebInitCPU29 ; no TSC
mov esi,CPUMsg5_10 ; ESI <- message text
call DebOutText ; display text TSC
; ------------- Display CPU frequency
DebInitCPU29: mov esi,CPUMsg6 ; ESI <- message text
call DebOutText ; display text
mov eax,[CPUInfo+CPU_Frequency] ; EAX <- CPU frequency
add eax,500 ; round frequency
xor edx,edx ; EDX <- 0
mov ecx,1000 ; ECX <- divider
div ecx ; EAX <- frequency in kHz
call DebOutNum ; display CPU frequency
mov esi,CPUMsg7 ; ESI <- message text
call DebOutText ; display text
ret
%endif
; -----------------------------------------------------------------------------
; Data
; -----------------------------------------------------------------------------
DATA_SECTION
; ------------- Vendor strings
CPUVendString: db 'GenuineIntel' ; Intel
db 'AuthenticAMD' ; AMD
db 'CyrixInstead' ; Cyrix
db 'CentaurHauls' ; Centaur
db 'NexGenDriven' ; NexGen
db 'GenuineTMx86' ; Transmeta
db 'RiseRiseRise' ; Rise
db 'UMC UMC UMC ' ; UMC
db 'SiS SiS SiS ' ; SiS
db 'Geode by NSC' ; National Semiconductor
; ------------- Low-CPU typical frequencies
LowCPUFreq: dd 16666667 ; 16 MHz
dd 20000000 ; 20 MHz
dd 25000000 ; 25 MHz
dd 33333333 ; 33 MHz
dd 40000000 ; 40 MHz
dd 50000000 ; 50 MHz
dd 60000000 ; 60 MHz
dd 66666667 ; 66 MHz
dd 75000000 ; 75 MHz
dd 80000000 ; 80 MHz
dd 100000000 ; 100 MHz
dd 120000000 ; 120 MHz
dd 133333333 ; 133 MHz
LowCPUFreq2:
; ------------- Debug messages
%ifdef DEBUG_CPU
CPUMsg: db 10,'--- CPU:',10
db 'Basic type: ',0
CPUMsg1_386: db '386',0
CPUMsg1_486: db '486',0
CPUMsg1_P1: db 'Pentium',0
CPUMsg1_P2: db 'Pentium 2, Pentium Pro',0
CPUMsg1_P3: db 'Pentium 3',0
CPUMsg1_P4: db 'Pentium 4',0
CPUMsg1_Addr: dd CPUMsg1_386
dd CPUMsg1_486
dd CPUMsg1_P1
dd CPUMsg1_P2
dd CPUMsg1_P3
dd CPUMsg1_P4
CPUMsg2: db 10,'Vendor: ',0
CPUMsg2_0: db 'unknown',0
CPUMsg2_1: db 'Intel',0
CPUMsg2_2: db 'AMD',0
CPUMsg2_3: db 'Cyrix',0
CPUMsg2_4: db 'Centaur',0
CPUMsg2_5: db 'NexGen',0
CPUMsg2_6: db 'Transmeta',0
CPUMsg2_7: db 'Rise',0
CPUMsg2_8: db 'UMC',0
CPUMsg2_9: db 'SiS',0
CPUMsg2_10: db 'National Semiconductor',0
CPUMsg2_Addr: dd CPUMsg2_0
dd CPUMsg2_1
dd CPUMsg2_2
dd CPUMsg2_3
dd CPUMsg2_4
dd CPUMsg2_5
dd CPUMsg2_6
dd CPUMsg2_7
dd CPUMsg2_8
dd CPUMsg2_9
dd CPUMsg2_10
CPUMsg3: db 10,'Family: ',0
CPUMsg4: db 10,'Model: ',0
CPUMsg5: db 10,'Features: ',0
CPUMsg5_2: db 'MMX ',0
CPUMsg5_3: db 'SSE ',0
CPUMsg5_4: db 'SSE2 ',0
CPUMsg5_5: db '3DNow! ',0
CPUMsg5_6: db '3DNow!ext ',0
CPUMsg5_7: db 'MMX+(AMD) ',0
CPUMsg5_8: db 'MMX+(Cyrix) ',0
CPUMsg5_9: db 'FPU ',0
CPUMsg5_10: db 'TSC ',0
CPUMsg6: db 10,'Frequency: ',0
CPUMsg7: db ' kHz',10,0
%endif
; -----------------------------------------------------------------------------
; Uninitialized data
; -----------------------------------------------------------------------------
BSS_SECTION
; ------------- CPU information
align 8, resb 1
CPUInfo: resb CPUINFO_size
|