; 	[]===========================================================[]
;
;	NOTICE: THIS PROGRAM BELONGS TO AWARD SOFTWARE INTERNATIONAL(R)
;	        INC. IT IS CONSIDERED A TRADE SECRET AND IS NOT TO BE
;	        DIVULGED OR USED BY PARTIES WHO HAVE NOT RECEIVED
;	        WRITTEN AUTHORIZATION FROM THE OWNER.
;
; 	[]===========================================================[]
;
;----------------------------------------------------------------------------
;Rev  	Date	 Name	Description
;----------------------------------------------------------------------------
;R06	04/02/99 MIL	Set bit 2 WL(Weak_Locking) of Cyrix M II CPU internal
;			Region Control Register, for got better performance.
;R05	03/31/99 RCH	Update Cyrix M II CPU Prating table :
;				Frquency     PR from	to
;				---------    -------	---
;				285(95x3)	350	400
;				292(83x3.5)	366	400
;				300(75x4)	366	400
;				300(100x3)	380	433
;				315(90x3.5)	366	433
;				333(83x4)	400	466
;				333(95x3.5)	400	466
;				350(100x3.5)	433	500
;				360(90x4)	433	500
;				380(95x4)	450	533
;				400(100x4)	466	550
;
;R04	03/26/99 MIL	Record Host clock in shadow memory "P6HostClock" for
;			AMD Mode 8 & Cyrix M2 Series CPU.
;R03	03/24/99 RCH	Added 112Mhz host clock support for Pentium class
;			(socket 7) platform. Also fixing wrong CPU clock
;			display for 133Mhz host clock
;R02	03/17/99 RIC	Add "Disable_WT_ALLOC_When_Cyrix_100" for special
;			customer request.
;R01	03/17/99 RCH	Added more CPU models support for Rise. It include
;			052x, 059x for model 5 CPU & 060x,064x for model 6.
;R00	03/15/99 RAY	Initial revision in which the code is extracted from
;			the original CPUPOST.ASM. To prevent compilation error
;			Please define "CPU_586_ONLY" in your BIOS.CFG

IF	COMPILE_FOR_E0
if	STR_function	EQ	1
		extrn	CT_OPEN_SM_RAM:near
		extrn	CT_CLOSE_SM_RAM:near
		extrn	Get_SMBASE_ADD:near
endif	;STR_function	EQ	1

 ifdef	L2ECC_CMOS
		extrn	L2Ecc_Item:near
 endif;	L2ECC_CMOS

		extrn	POST_decompress:near
		extrn	F000_GetItem_Value:near
		extrn	ExtCache_Item:near

		EXTRN	ROM_AND_CMOS:NEAR
		EXTRN	ROM_OR_CMOS:NEAR
		extrn	POST_func_end:Near
		extrn	POST_VECT:Near

		extrn	Check_Cyrix_Cpu:near
		extrn	Init_Cyrix_Reg:near
		extrn	Get_Cmos:near
		extrn	Set_Cmos:near
		extrn	F000_call_proc:near
		extrn	F000_Shadow_W:Near
		extrn	F000_Shadow_R:Near

		extrn	LOCK_CYRIX:Near
		extrn	UNLOCK_CYRIX:Near
		extrn	LOCK_CYRIX:Near
		extrn	SET_CYRIX:Near
		extrn	GET_CYRIX:Near
		extrn	Check_M1_Cpu:near
		extrn	F000_Get_Cmos:near
		extrn	F000_Set_Cmos:near

ifdef	ESCD_SUPPORT
ifndef	ESCD_M2
IF BUS_TYPE NE EISA_BUS
		extrn	P5_BtB_Loc:near
endif; BUS_TYPE NE EISA_BUS
endif;	ESCD_M2
endif;	ESCD_SUPPORT

 		extrn	Check_K586_Cpu:Near
		extrn	Read_CpuID:Near
		extrn	Ct_MemHole_Status:Near
		extrn	Check_M2Cpu:near
		extrn	Check_IdtCpu:Near
		extrn	Check_RiseCpu:Near

		extrn	WinChip2A_Clock_Multiplier_In_AH:far
		extrn	fPROC_If_WinChip2A:Far
		extrn	Cpu_Cache:near

ifdef	Special_CPU_Clock_Table
		extrn	Ct_Int_Clock_Tbl:Near
endif	;Special_CPU_Clock_Table

.LIST

EGROUP		GROUP	ECODE
ECODE		SEGMENT USE16 PARA PUBLIC 'ECODE'
		ASSUME	CS:EGROUP,DS:EGROUP

;=============================================================================
;FUNC:	CYRIX_INIT
;
;DESC:	Handles the initialization of the CYRIX CPU.
;
;IN:	NONE
;OUT:	NONE
;
;SAVES:	NONE + NO STACK
;
;BY:	Richard Chen
;DATE:	18 May 1992
;=============================================================================
FLAGS_MASK	EQU	08D5H

		public	CYRIX_INIT
CYRIX_INIT	proc	near

		F000_call	Init_Cyrix_Reg

		ret

CYRIX_INIT	endp

M2Cpu_Tbl:
		db	21h,23h		;wrong stepping
		dw	CPU_M1_2	;2/1 for M1
M2CPU_LEN	EQU	($ - offset M2Cpu_Tbl)
		db	51h,59h		;2/1 for M2
		dw	CPU_M1_2
		db	52h,5Ah		;2.5/1 for M2
		dw	CPU_M1_3
		db	53h,5Bh		;3/1 for M2
		dw	CPU_M1_3
		db	54h,5Ch		;3.5/1for M2
		dw	CPU_M1_3
		db	55h,5Dh		;4/1 for M2
		dw	CPU_M1_3
		db	0

Check_M2_M1_Cpu	proc	near

;Cyrix have a cut of wrong CPU ID ( 21H & 23H ) . We implement it in boot
;block BOOTROM.ASM , but this 8K code can not be updated if INTEL boot block
;flash was used. So re-check the CPU here.

		F000_call	Check_Cyrix_Cpu
		jnz	Not_Wrong_M1

		;check if M1 already
		mov	al,CMOS_AWARD_2 NMI_OFF	; al = CMOS location
		call	F000_Get_Cmos
		and	al,CPU_TYPE_MASK
		cmp	al,TYPE_M1		;M1 CPU ?
		je	Not_Wrong_M1

		mov	al,0feh			;DIR 0
		out	22h,al
		in	al,23H			;read CPU device ID

		call	Check_M2_Cpu
		jc	Not_Wrong_M1

;set CPU type

		;clear clock mode , SMI bit and WB bit
		mov	al,OVERRIDE NMI_OFF
		call	F000_Get_Cmos
		mov	ah,al
		and	ah,NOT (CLOCK_MODE+((SMICPU+WBCPU) SHR 8))
		or	ah,bh
		mov	al,OVERRIDE NMI_OFF
		call	F000_Set_Cmos

		;set CPU type in CMOS
		mov	ah,bl
		mov	al,CMOS_AWARD_2 NMI_OFF	; al = CMOS location
		call	F000_Set_Cmos
Not_Wrong_M1:
		ret

Check_M2_M1_Cpu	endp

;Input  : AL - Device ID (DIR0) of M1(M2) CPU
;Output : Zero set - It's M2 CPU , and BX return CPU type to store in CMOS
Check_M2_Cpu	proc	near

		mov	si,offset M2Cpu_Tbl
Check_Next_M2:
		cmp	byte ptr cs:[si],0	;last table ?
		je	Not_M2

		cmp	byte ptr cs:[si],al
		je	Get_M2

		cmp	byte ptr cs:[si+1],al
		je	Get_M2

		add	si,M2CPU_LEN
		jmp	Check_Next_M2

Not_M2:
		stc
		ret
Get_M2:
		mov	bx,cs:[si+2]		;get CPU type
		clc

		ret
Check_M2_Cpu	endp

;Input : none
;Output: carry clear - it's double clock
;	 carry set   - it's not double clock
Check_Cyrix_Dclk	proc	near
Check_Cyrix_Dclk	endp

;[]========================================================================[]
;	Set the IBM CPU's Cacheable region: Bit 32-39 of register 1001h
;	according to the extended memory found!
;[]========================================================================[]
		Public	IBMCPU_Cacheable_Size
IBMCPU_Cacheable_Size	Proc	Near

		ret

IBMCPU_Cacheable_Size	Endp

;[]------------------------------------------------------------------------[]
;[]------------------------------------------------------------------------[]
		Public	Chk_Intel_S_CPU
Chk_Intel_S_CPU	Proc	Near

		push	ds
		pushad

	;replace the original int 06h with a temparary
	;one to prevent trap accurs in some CPUs

		xor	eax,eax			;input value = 1
		mov	ds,ax

		push	dword ptr ds:[4*6]	;save int 06h vector
		mov	word ptr ds:[4*6],offset Temp_Int06
		mov	word ptr ds:[4*6+2], 0e000h

		push	ds

		push	cs
		pop	ds

	;issue special OP code: CPUID(00Fh,0A2h)
	;to check if it is a S-series CPU

		db	0Fh,0A2h		;OP code: CPUID

		mov	si,offset Cpu_Vendor_Tbl
Chk_Nxt_Vendor:
		cmp	word ptr [si],-1 	;last of CPU vendor table

		je	Finish_Cpu_ID		;yes,over !

		cmp	ebx,[si+2]		;check 1st identifier string
		jne	Next_Vendor

		cmp	ecx,[si+6]		;check 2nd identifier string
		jne	Next_Vendor

		cmp	edx,[si+10]		;check 3th identifier string
		je	Good_Vendor

Next_Vendor:
		add	si,SIZE_VENDOR_TBL
		jmp	Chk_Nxt_Vendor

Good_Vendor:
		call	Set_SMI_Bit

		mov	si,[si]	 		;get vendor's CPU ID table
	;Now , we got correct identifier of CPU, next step is to get CPU ID
		mov	eax,1			;eax = 1 to read CPU ID
		db	0fh,0A2h		;CPU ID instruction
		and	al,0f0h			;mask stepping bits b3-b0

Chk_Nxt_CpuID:
		cmp	word ptr [si],-1 	;last of CPU ID table

		je	Finish_Cpu_ID
		cmp	ax,[si]			;match CPU ID ?
		je	Save_Cpu_ID		;yes

		add	si,4			;next CPU ID
		jmp	Chk_Nxt_CpuID

CpuIdNotFound:
Save_Cpu_ID:
		call	CheckNoNPentiumCPU	;skip auto-halt for non-
						;Pentium CPUs
		jc	Not_P5

		cmp	word ptr [si+2],CPU_586		;PENTIUM CPU ?
		jne	Not_P5

ifdef	ESCD_SUPPORT
ifndef	ESCD_M2
IF BUS_TYPE NE EISA_BUS
		cmp	al,10H			;skip BTB for 051x
		je	Skip_BtB
		cmp	al,20H			;skip BTB for 052x
		jne	No_Skip_BtB

Skip_BtB:
	;skip BTB control for updating ESCD
		F000_CALL F000_Shadow_W
	;change instruction from "jne" to "jmp"
		mov	ax,0f000H		;code in F-segment
		mov	es,ax
		mov	byte ptr es:[P5_BtB_Loc],0EBH
		F000_CALL F000_Shadow_R

No_Skip_BtB:

endif; BUS_TYPE NE EISA_BUS
endif;	ESCD_M2
endif;	ESCD_SUPPORT

;Disable PENTIUM parity check in TR1 register
                mov     eax,2
                mov     ecx,eax
                xor     edx,edx
                WRMSR

		;disable auto-halt mode by set bit 6 of TR12
		mov	ecx,0eh
		RDMSR
		xor	edx,edx
		mov	eax,40h
		WRMSR
Not_P5:
		mov	dx,[si+2]		;get CPU ID
		call	Set_CPU_Type_Bits
		jmp	Finish_Cpu_ID

Finish_Cpu_ID:

		pop	ds

		pop	dword ptr ds:[4*6]	;restore int 06h vector

		call	Check_M2_M1_Cpu

		call	Prepare_CPU_Info
		popad
		pop	ds
		ret

;-------------------------------------------------------
; Temporary Int 06 handler for Non-(Intel S-Series) CPU
;-------------------------------------------------------
		public	Temp_Int06

Temp_Int06	Label	Near
		push	bp
		mov	bp,sp
		add	word ptr ss:[bp+2],2
		pop	bp
		iret

Chk_Intel_S_CPU	Endp

;Function : Return Non-Pentium CPU flag
;Input    : carry clear - Pentium CPU
;Output   : carry set   - non-Pentium CPU
CheckNoNPentiumCPU	proc	near
 		pushad

 		xor	eax,eax			;get vendor ID string
 		db	0Fh,0A2h		;OP code: CPUID

	;Check if IDT/C6 CPU
 		cmp	ebx,746e6543h		;C6 vendor ID string match ?
		je	NotIntelP5	;IDT/C6 CPU

	;Check if Rise/mP6 CPU
		cmp	ebx,65736952h		;Rise CPU ?
		jne	OtherNonIntelP5	;no

	;Configuration setup of mP6 CPU family
		mov	eax, 6363452AH
		mov	ecx, 3231206CH
		mov	edx, 2A32313AH
 		db	0Fh,0A2h		;OP code: CPUID

		mov	eax, 63634523H
		mov	ecx, 32315F6CH
		mov	edx, 2333313AH
 		db	0Fh,0A2h		;OP code: CPUID

		jmp	NotIntelP5

OtherNonIntelP5:

		clc				;Intel Pentium CPU
		jmp	NoNPentiumExit
NotIntelP5:
		stc				;for Non-Intel CPUs

NoNPentiumExit:

 		popad
		ret
CheckNoNPentiumCPU	endp

Cpu_Vendor_Tbl:
		dw	offset Cpu_INTELs  	;table of INTEL CPUs
		dd	756E6547h	   	;Identifer string 1
		dd	6C65746eh	   	;Identifer string 2
		dd	49656E69h	   	;Identifer string 3
SIZE_VENDOR_TBL	EQU	$ - offset Cpu_Vendor_Tbl

		dw	offset Cpu_AMDs	   	;table of AMD CPUs
		dd	68747541h	   	;Identifer string 1
		dd	444d4163h	   	;Identifer string 2
		dd	69746e65h	   	;Identifer string 3

		dw	offset Cpu_IDTs		;table of IDT CPUs
		dd	746e6543h		;Identifer string 1
		dd	736c7561h		;Identifer string 2
		dd	48727561h		;Identifer string 3

		dw	offset Cpu_Rise		;table of Rise CPUs
		dd	65736952h		;Identifer string 1(Rise)
		dd	65736952h		;Identifer string 2(Rise)
		dd	65736952h		;Identifer string 3(Rise)

		dw	-1		   	;last of CPU venders table

;CPU table for INTEL s-series CPUs
Cpu_INTELs:

		dw	0510h,CPU_586			;PENTIUM 1/1
		dw	0520h,CPU_586			;PENTIUM 3/2
		dw	2520h,CPU_586			;PENTIUM 2/1
		dw	0540h,CPU_586			;PENTIUM 2/1
		dw	2540h,CPU_586			;PENTIUM 2/1
		dw	1520h,CPU_586			;PENTIUM 2/1 ODP
		dw	1540h,CPU_586			;PENTIUM 2/1 ODP
		dw	0570h,CPU_586			;PENTIUM 3/2
		dw	0580h,CPU_586			;PENTIUM/MMX

		dw	-1				;last of table

		ALIGN	16

;CPU table for AMD s-series CPUs
Cpu_AMDs:

		dw	0500H,CPU_AMD5K86
		dw	0510H,CPU_AMD5K86
		dw	0520H,CPU_AMD5K86
		dw	0530H,CPU_AMD5K86
		dw	0560H,CPU_AMD5K86
		dw	0570H,CPU_AMD5K86
		dw	0580H,CPU_AMD5K86
		dw	0590H,CPU_AMD5K86

		dw	-1

;CPU table for UMC s-series CPUs
Cpu_UMCs:
		dw	-1

Cpu_IDTs:	;table of IDT CPUs
		dw	0520h,CPU_586			;C6 w/o MMX
		dw	0540h,CPU_586			;C6 w/  MMX
		dw	0580h,CPU_586			;WinChip 2
		dw	0590h,CPU_586			;WinChip 2
		dw	-1

;CPU table for Rise s-series CPUs
Cpu_Rise:
		dw	0500h,CPU_586			;mP6
		dw	0510h,CPU_586			;mP6 future
		dw	0580h,CPU_586			;mp6-2 CPU
		dw	0520h,CPU_586			;Rise model 5;R01
		dw	0590h,CPU_586			;Rise model 5;R01
		dw	0600h,CPU_586			;Rise model 6;R01
		dw	0640h,CPU_586			;Rise model 6;R01
		dw	-1				;last of table

;[]==========================================================[]
;[]==========================================================[]
		Public	Chk_If_Type_P24C
Chk_If_Type_P24C:
		ret

;[]==========================================================[]
;[]==========================================================[]
		Public	Set_SMI_Bit
Set_SMI_Bit:
		mov	ah,CMOS_OVERRIDE NMI_OFF
		mov	al,ah

		call	F000_Get_Cmos
		or	al,SMICPU shr 8
		xchg	ah,al

		call	F000_Set_Cmos
		ret

;[]==========================================================[]
;[]==========================================================[]
		Public	Clear_SMI_Bit
Clear_SMI_Bit:
		mov	ah,CMOS_OVERRIDE NMI_OFF
		mov	al,ah

		call	F000_Get_Cmos
		and	al,NOT (SMICPU shr 8)
		xchg	ah,al

		call	F000_Set_Cmos
		ret

;[]==========================================================[]
;[]==========================================================[]
		Public	Chk_SMICPU_Bit
Chk_SMICPU_Bit:
		push	ax
		mov	al,CMOS_OVERRIDE NMI_OFF

		call	F000_Get_Cmos
		test	al,SMICPU shr 8
		pop	ax
		ret

;[]==========================================================[]
;Input : DL = Value for CMOS_AWARD_2  (03DH)
;        DH = Value for CMOS_OVERRIDE (03FH)
;[]==========================================================[]
Set_CPU_Type_Bits:
		mov	al,CMOS_AWARD_2 NMI_OFF
		mov	ah,dl

		call	F000_Set_Cmos

		mov	ah,CMOS_OVERRIDE NMI_OFF
		mov	al,ah

		call	F000_Get_Cmos
		and	al,NOT (CLOCK_MODE+((SMICPU+WBCPU) SHR 8))
		or	al,dh
		xchg	ah,al

		call	F000_Set_Cmos
		ret

;[]------------------------------------------------------------------------[]
;[]------------------------------------------------------------------------[]
		public	Intel_To_AMD
Intel_To_AMD	proc	near

		ret

Intel_To_AMD	endp

;[]------------------------------------------------------------------------[]
;Procedur	:	Prepare_CPU_Info
;
;Input		:	None
;
;Output		:	None
;
;Description	:	- This routine is called after the BIOS has issued
;			  the CPUID instruction & all the CPUs are identified.
;
;			- There are 2 variables in the stack area namely
;			  CPU_BRAND[bp] & CPU_SMI_TYPE[bp]
;			  This routine will place appropriate values into
;			  these 2 [BP] variables
;			  The BIOS engineers can easily reference to them
;			  for their own programming
;
;			- please refer to BSETUP.INC for the definitions
;			  of CPU_BRAND[bp] & CPU_SMI_TYPE[bp]
;
;Note		:	BIOS engineers should use instruction "test" to
;			check SMI type & "cmp" for CPU brand
;
;			e.g.
;			    cmp   CPU_BRAND[bp], CPU_BRAND_CYRIX
;			    test  CPU_SMI_TYPE[bp], SMI_TYPE_CYRIX
;
;[]------------------------------------------------------------------------[]
		Public	Prepare_CPU_Info
Prepare_CPU_Info	Proc	Near

		mov	al,CMOS_AWARD_2 NMI_OFF

		call	F000_Get_Cmos
		and	al,CPU_TYPE_MASK
		movzx	si,al

		xor	ah, ah
		shr	ax, 1
		add	si, ax

		mov	dx,word ptr cs:CPU_Info_Tbl[si]
		mov	word ptr CPU_BRAND[bp],dx

		mov	al, byte ptr cs:CPU_Info_Tbl[si+2]
		mov	byte ptr CPU_LEVEL[bp], al

		mov	al,OVERRIDE NMI_OFF

		call	F000_Get_Cmos
		test	al,((SMICPU) shr 8)		;SMI CPU?
		jnz	Set_SMI_OK		;Yes

		mov	byte ptr CPU_SMI_TYPE[bp],SMI_NONE
Set_SMI_OK:
		ret

Prepare_CPU_Info	Endp

		ALIGN	4
CPU_Info_Tbl:

	db	CPU_BRAND_INTEL	,SMI_NONE	 ,LEVEL_386	;TYPE_386DX
	db	CPU_BRAND_INTEL	,SMI_NONE 	 ,LEVEL_386	;TYPE_386SX
	db	CPU_BRAND_INTEL	,SMI_NONE 	 ,LEVEL_386	;TYPE_386SL
	db	CPU_BRAND_INTEL	,SMI_TYPE_INTEL  ,LEVEL_486	;TYPE_486DX
	db	CPU_BRAND_INTEL	,SMI_TYPE_INTEL  ,LEVEL_486	;TYPE_486SX
	db	CPU_BRAND_INTEL	,SMI_TYPE_INTEL	 ,LEVEL_486	;TYPE_486DX2
	db	CPU_BRAND_CYRIX	,SMI_NONE	 ,LEVEL_386	;TYPE_486SLC
	db	CPU_BRAND_CYRIX	,SMI_TYPE_CYRIX	 ,LEVEL_386	;TYPE_486DLC
	db	CPU_BRAND_IBM	,SMI_TYPE_IBM	 ,LEVEL_386	;TYPE_IBM386SLC
	db	CPU_BRAND_IBM	,SMI_TYPE_IBM	 ,LEVEL_386	;TYPE_IBM486SLC2
	db	CPU_BRAND_INTEL	,SMI_TYPE_INTEL	 ,LEVEL_486	;TYPE_P24T
	db	CPU_BRAND_CYRIX	,SMI_TYPE_CYRIX	 ,LEVEL_486	;TYPE_CX486S
	db	CPU_BRAND_CYRIX	,SMI_TYPE_CYRIX	 ,LEVEL_486	;TYPE_CX486S2
	db	CPU_BRAND_INTEL	,SMI_TYPE_INTEL	 ,LEVEL_586	;TYPE_586
	db	CPU_BRAND_INTEL	,SMI_TYPE_INTEL	 ,LEVEL_486	;TYPE_486DXS
	db	CPU_BRAND_INTEL	,SMI_TYPE_INTEL	 ,LEVEL_486	;TYPE_486SXS
	db	CPU_BRAND_INTEL	,SMI_TYPE_INTEL	 ,LEVEL_486	;TYPE_486DX2S
	db	CPU_BRAND_IBM	,SMI_TYPE_IBM	 ,LEVEL_386	;TYPE_IBM486DLC3
	db	CPU_BRAND_CYRIX	,SMI_TYPE_CYRIX	 ,LEVEL_486	;TYPE_M7
	db	CPU_BRAND_CYRIX	,SMI_TYPE_CYRIX	 ,LEVEL_486	;TYPE_M7_2
	db	CPU_BRAND_CYRIX	,SMI_NONE	 ,LEVEL_386	;TYPE_CX486SLC2
	db	CPU_BRAND_INTEL	,SMI_TYPE_INTEL	 ,LEVEL_486	;TYPE_P24C
	db	CPU_BRAND_TI	,SMI_TYPE_CYRIX	 ,LEVEL_486	;TYPE_TI486SXL
	db	CPU_BRAND_TI	,SMI_TYPE_CYRIX	 ,LEVEL_486	;TYPE_TI486SXL2
	db	CPU_BRAND_UMC	,SMI_TYPE_OLD_AMD,LEVEL_486	;TYPE_U5
	db	CPU_BRAND_AMD	,SMI_NONE	 ,LEVEL_486	;TYPE_AMD486
	db	CPU_BRAND_INTEL	,SMI_TYPE_INTEL	 ,LEVEL_586	;TYPE_P54C
	db	CPU_BRAND_TI	,SMI_TYPE_CYRIX	 ,LEVEL_486	;TYPE_TI486SXLC
	db	CPU_BRAND_TI	,SMI_TYPE_CYRIX	 ,LEVEL_486	;TYPE_TI486SXLC2
	db	CPU_BRAND_AMD	,SMI_NONE	 ,LEVEL_486	;TYPE_AMD486DX2
	db	CPU_BRAND_INTEL	,SMI_TYPE_INTEL	 ,LEVEL_486	;TYPE_P24D
	db	CPU_BRAND_AMD	,SMI_NONE	 ,LEVEL_486	;TYPE_AMD486DX4
	db	CPU_BRAND_CYRIX	,SMI_TYPE_CYRIX	 ,LEVEL_586	;TYPE_M1
	db	CPU_BRAND_AMD	,SMI_TYPE_INTEL	 ,LEVEL_486	;TYPE_AMD486PLUS
	db	CPU_BRAND_AMD	,SMI_TYPE_INTEL	 ,LEVEL_486	;TYPE_AMD486DX4PLUS
	db	CPU_BRAND_UMC	,SMI_TYPE_OLD_AMD,LEVEL_486	;TYPE_U486SX2
	db	CPU_BRAND_UMC	,SMI_TYPE_INTEL	 ,LEVEL_486	;TYPE_U486DX
	db	CPU_BRAND_UMC	,SMI_TYPE_INTEL	 ,LEVEL_486	;TYPE_U486DX2
ifndef	CPU_Support_Above_GXM
	db	CPU_BRAND_CYRIX	,SMI_TYPE_CYRIX	 ,LEVEL_486	;TYPE_M9
else	;CPU_Support_Above_GXM
	db	CPU_BRAND_CYRIX	,SMI_TYPE_CYRIX	 ,LEVEL_586
endif	;CPU_Support_Above_GXM
	db	CPU_BRAND_CYRIX	,SMI_TYPE_CYRIX	 ,LEVEL_486	;TYPE_CYRIX_DX4
	db	CPU_BRAND_INTEL	,SMI_TYPE_INTEL	 ,LEVEL_686	;TYPE_P6
	db	CPU_BRAND_AMD	,SMI_TYPE_INTEL	 ,LEVEL_486	;TYPE_X5
	db	CPU_BRAND_AMD	,SMI_TYPE_INTEL	 ,LEVEL_586	;TYPE_AMD5K86
	db	CPU_BRAND_CYRIX ,SMI_TYPE_CYRIX	 ,LEVEL_586	;TYPE_CYRIX_GXM

;[]==============================================================[]
;
;CpuClk_Int08:
;
;	Temporary interrupt service routine for caculating CPU clock
;
;Saves: NONE
;
;Entry: NONE
;Exit:	NONE
;
;[]==============================================================[]
		ALIGN	4
CpuClk_Int08	PROC	NEAR

		push	edx

		db	0fh,31h			;ReaD Time Stamp Counter
		cmp	dword ptr ds:[4fch],-1	;high 32 bit value
		je	First_Int

		cmp	byte ptr ds:[4f0h],0aaH	;second INT ?
		je	Finish_Int

		mov	edi,dword ptr ds:[4fch]	;high 32 bit value
		mov	esi,dword ptr ds:[4f8h]	;low 32 bit value

		sub	edx,edi			;high 32-bit value
		sub	eax,esi			;low 32-bit value
		jnc	No_Dec_High32
		dec	edx
No_Dec_High32:
		mov	dword ptr ds:[4fch],edx	;high 32 bit value
		mov	dword ptr ds:[4f8h],eax	;low 32 bit value

		mov	byte ptr ds:[4f0h],0aaH;mark for second INT
		jmp	Finish_Int

First_Int:
		mov	dword ptr ds:[4fch],edx	;high 32 bit value
		mov	dword ptr ds:[4f8h],eax	;low 32 bit value

Finish_Int:
		pop	edx

		NEWIODELAY
		mov	al,END_OF_INT		; eoi command
		out	a8259,al		; tell controller
		NEWIODELAY

		iret
CpuClk_Int08	ENDP

;-----------------------------------------------------------------
;Input	:	None
;Output :	carry set - this CPU don't have instruction RDTSC
;		carry clear - this CPU have instruction RDTSC and
;		BX : CPU clock detected (0-65535Mhz) return
;Destroy:	use 0:4f8H - 0:4ffH as temporary memory
;-----------------------------------------------------------------
;
New_CpuClk_Detection	proc	near
;use RDTSC to check CPU clock if 586 level CPU
		cli
		cmp	byte ptr CPU_LEVEL[bp], LEVEL_686
		je	Yes_Rdtsc
		cmp	byte ptr CPU_LEVEL[bp], LEVEL_586
		stc				;assume CPU no counter
		jne	No_Rdtsc

Yes_Rdtsc:
		xor	edx,edx
		xor	eax,eax			;input value = 1
		mov	ds,ax
		push	dword ptr ds:[4*6]	;save int 06h vector
		mov	word ptr ds:[4*6],offset Temp_Int06
		mov	word ptr ds:[4*6+2], cs

		db	0fh,31h			;ReaD Time Stamp Counter

		pop	dword ptr ds:[4*6]	;restore int 06h vector

		or	eax,edx			;counter changed ?
		stc				;assume CPU no counter
		jz	No_Rdtsc		;no , this CPU don't have
						;counter

		mov	ax,G_RAM		; seg_0
		mov	ds,ax
		assume	ds:G_RAM

		mov	byte ptr ds:[4f8h],0	;init flag
		mov	dword ptr ds:[4f8h],0	;init low dword value
		mov	dword ptr ds:[4fch],-1	;init high dword value

;
;	Move INT 08h vector to a temporary routine
;

		mov	dx,word ptr [int08]	; save vector
		mov	bx,word ptr [int08+2]

		mov	word ptr [int08],offset CpuClk_Int08; tmr isr entry
		mov	word ptr [int08+2],cs	; code segment

;
;	Enable just the timer interrupt
;

		mov	al,0ffh 		; mask all interrupts on controller 2
		out	B8259+1,al		; tell controller
		NEWIODELAY
		dec	al			; mask all except timer (IRQ 8)
		out	A8259+1,al		; tell controller

;
;	Set up timer 0
;

		mov	al,36h			; setup timer counter 0
		out	43h,al			; select counter 0
		NEWIODELAY

		xor	ax,ax			; INT every 1/18 seconds
		out	40h,al			; write lsb
		NEWIODELAY
		out	40h,al			; write msb

;
;	Wait for interrupts
;

		xor	ax,ax			; clear interrupt flag
		sti				; enable interrupt
Wait_Irq0:
		cmp	byte ptr ds:[4f0h],0aaH	;second INT occured ?
		jne	Wait_Irq0
		cli				; disable interrupts

;
;	Turn off all of the interrupts
;
		mov	al,0ffh 		; mask all interrupts
		out	A8259+1,al		; tell controller
		NEWIODELAY

;
;	Restore INT 08h vector
;

		mov	word ptr [int08],dx	; restore old vector
		mov	word ptr [int08+2],bx

;Now , the content of 0:[4f8h] contain counter value
		mov	bx,1
		mov	eax,dword ptr ds:[4f8h]
		mov	ecx,55100		;factor to calculate
Next_Div:
		sub	eax,ecx
		jc	Finish_Div
		inc	bx
		jmp	Next_Div
Finish_Div:
		clc
No_Rdtsc:
		ret
New_CpuClk_Detection	endp

;Table for CPU clock over 255Mhz
CPU_Over255MHz:
		db	400-256, 400-256-2,	CPU66		;66x6
		db	373-256, 373-256-2,	CPU83		;83x4.5
		db	366-256, 366-256-2,	CPU66		;66x5.5
		db	350-256, 350-256-2,	CPU100		;100x3.5
		db	333-256, 333-256-2,	CPU66		;66x5
		db	300-256, 300-256-2,	CPU66		;66x4.5

		DB	290-256, 290-256-2,	CPU83		;83X3.5
		db	266-256, 266-256-2,	CPU66		;66x4
		db	0					;end of table

;Clock table for P5-class CPUs
NewCPU_Int_Clock_Tbl:

ifdef	CLOCK_TBL_FOR_ICWORK
		db	250,	246,	CPU66		;83*3
ifndef	NO_CPU_240MHZ_SUPPORT
		db	240,	236,	CPU60		;60x4
endif;	NO_CPU_240MHZ_SUPPORT
		db	233,	228,	CPU66		;66x3.5
		db	225,	223,	CPU75		;75x3

		db	210,	205,	CPU60		;60x3.5
		db	200,	194,	CPU66		;66x3

		db	188,	185,	CPU66		;75*2.5
		db	180,	176,	CPU60		;60x3
		db	166,	163,	CPU66		;66x2.5
		db	150,	147,	CPU60		;60x2.5

		db	133,	128,	CPU66		;66x2	;here special
		db	125,	124,	CPU50		;50x2.5
		db	120,	118,	CPU60		;60x2	;here special
		db	117,	115,	CPU66		;66x1.75
		db	110,	109,	CPU50		;55x2
		db	105,	103,	CPU60		;60x1.75
		db	100,   	 98,	CPU66		;66x1.5	;here special

else;	CLOCK_TBL_FOR_ICWORK

ifdef	CLOCK_TBL_FOR_ICS
		db	250,	248,	CPU66		;83*3
ifndef	NO_CPU_240MHZ_SUPPORT
		db	240,	238,	CPU60		;60x4
endif;	NO_CPU_240MHZ_SUPPORT

ifdef	Lower_233Mhz_FOR_ICS
		db	233,	223,	CPU66		;66x3.5
else;	Lower_233Mhz_FOR_ICS
		db	233,	230,	CPU66		;66x3.5
endif;	Lower_233Mhz_FOR_ICS

ifndef	NO_CPU_225MHZ_SUPPORT_FOR_ICS
		db	225,	223,	CPU75		;75x3

endif;	NO_CPU_225MHZ_SUPPORT_FOR_ICS

ifndef	NO_CPU_210MHZ_SUPPORT_FOR_ICS
		db	210,	208,	CPU60		;60x3.5
endif;	NO_CPU_210MHZ_SUPPORT_FOR_ICS

		db	200,	186,	CPU66		;66x3
		db	193,	181,	CPU50		;55*3.5

ifndef	NO_CPU_188MHZ_SUPPORT_FOR_ICS
		db	188,	174,	CPU66		;75*2.5
endif;	NO_CPU_188MHZ_SUPPORT_FOR_ICS
		db	180,	170,	CPU60		;60x3
ifndef	NO_CPU_175MHZ_SUPPORT_FOR_ICS
		db	175,	164,	CPU50		;50x3.5
endif;	NO_CPU_175MHZ_SUPPORT_FOR_ICS
		db	166,	154,	CPU66		;66x2.5
		db	150,	138,	CPU60		;60x2.5
		db	133,	123,	CPU66		;66x2
ifndef	NO_CPU_125MHZ_SUPPORT_FOR_ICS
		db	125,	115,	CPU50		;50x2.5
endif;	NO_CPU_125MHZ_SUPPORT_FOR_ICS
		db	120,	110,	CPU60		;60x2
		db	117,	106,	CPU66		;66x1.75
		db	110,	101,	CPU50		;55x2
ifndef	NO_CPU_105MHZ_SUPPORT_FOR_ICS
		db	105,	 96,	CPU60		;60x1.75
endif;	NO_CPU_105MHZ_SUPPORT_FOR_ICS
ifndef	Higher_100Mhz_FOR_ICS
		db	100,   	 89,	CPU66		;66x1.5
else;	Higher_100Mhz_FOR_ICS
		db	100,   	 93,	CPU66		;66x1.5
endif;	Higher_100Mhz_FOR_ICS
else;	CLOCK_TBL_FOR_ICS

		db	250,	248,	CPU66		;83*3
ifndef	NO_CPU_240MHZ_SUPPORT
ifdef	Higher_240MHz_Tbl
		db	240,	240,	CPU60		;60x4
else;	Higher_240MHz_Tbl
		db	240,	238,	CPU60		;60x4
endif;	Higher_240MHz_Tbl
endif;	NO_CPU_240MHZ_SUPPORT

		db	233,	230,	CPU66		;66x3.5
		db	225,	223,	CPU75		;75x3

		db	210,	208,	CPU60		;60x3.5
		db	200,	195,	CPU66		;66x3
ifndef	No_55MHz
		db	193,	190,	CPU50		;55*3.5
endif	;No_55MHz
		db	190,	189,	CPU95

		db	188,	185,	CPU66		;75*2.5
		db	180,	179,	CPU60		;60x3
		db	175,	174,	CPU50		;50x3.5
		db	166,	165,	CPU66		;66x2.5
		db	150,	149,	CPU60		;60x2.5

		db	133,	132,	CPU66		;66x2
		db	125,	124,	CPU50		;50x2.5
		db	120,	119,	CPU60		;60x2
		db	117,	115,	CPU66		;66x1.75
ifndef	No_55MHz
		db	110,	109,	CPU50		;55x2
endif	;No_55MHz
ifndef	No_105MHz
		db	105,	103,	CPU60		;60x1.75
endif;	No_105MHz
		db	100,   	 99,	CPU66		;66x1.5

endif;	CLOCK_TBL_FOR_ICS
endif;	CLOCK_TBL_FOR_ICWORK

		db	 90,   	 88,	CPU60		;60x1.5
		db	 90,	 86,	CPU50		;50x1.75
ifndef	No_55MHz
		db	 83,   	 82,	CPU50		;55x1.5
endif	;No_55MHz

		db	 75,   	 70,	CPU50		;50x1.5
		db	 66,   	 65,	CPU66		;66x1
		db	 60,   	 59,	CPU66		;60x1
		db	 50,   	 49,	CPU66		;50x1
		db	 0		;end of table

;Clock detection for 386,486 & 586 CPUs

		ALIGN	16
		Public	MOV_SHAD_OFF
MOV_SHAD_OFF	EQU	00000H
		Public	MOV_SHAD_SEG

MOV_SHAD_SEG	EQU	5000h

		Public	Measure_CPU_Speed
Measure_CPU_Speed	proc	near

;--------------------------------------
;Copy code into RAM for speed detection
;--------------------------------------

		push	0f000h
		pop	ds

;Use new algorithm for CPU clock detection if CPU have RDTSC instruction
;(0fh,31h)
		call	New_CpuClk_Detection	;use new method to check
		jc	Cpu_NoRdtsc		; CPU clock ?
						;carry set, use old method

		mov	al,bl			;AL = Actual CPU clock found
		mov	dh,bl			;AL = Actual CPU clock found
		mov	CPU_INT_CLOCK[bp],bx	;actual internal CPU clock

		call	Get_M2_Clock_Tbl	;M2 Present ?
		jc	CpuSpeedEnd

		call	Get_AMD_Model8_Clock_Tbl ;AMD Model 8 Present ?
		jc	CpuSpeedEnd

ifdef	Special_CPU_Clock_Table
		mov	si, offset Ct_Int_Clock_Tbl
else	;Special_CPU_Clock_Table
		mov	si,offset NewCPU_Int_Clock_Tbl	;new table for PENTIUM
endif	;Special_CPU_Clock_Table

		cmp	word ptr CPU_INT_CLOCK[bp],255	;over 255Mhz ?
		jbe	Not_Over255Mhz

		mov	si,offset CPU_Over255MHz
Not_Over255Mhz:

		jmp	R_Off_Clk
Cpu_NoRdtsc:

;--------------------------------------------------
;Set KB high speed for test & save results(push bx)
;--------------------------------------------------

ifdef	TOGGLE_8042_FOR_CPU_CLK_DETECT
		mov	al,1		;Set low speed for test
		call	F000_Out_8042_Pin
endif;	TOGGLE_8042_FOR_CPU_CLK_DETECT

		in	al,PORT61
		IODELAY
		push	ax 			;save PORT61 value

	;execute the CPU detection code in DRAM

		call	far ptr S_CPU
	;return register values after calling S_CPU are
	; BH - CPU host clock
	; DL - CPU clock mode (x1, x2 ,x3 or x4)
		mov	al,bh
		mul	dl
		mov	si,ax

		pop	ax			;restore PORT61 value
		out	PORT61,al
		IODELAY

ifdef	TOGGLE_8042_FOR_CPU_CLK_DETECT
	;Save KB high speed result

		push	dx
		push	bx

;-------------------------
;Set KB low speed for test
;-------------------------

		xor	al,al			;Set high speed for test
		call	F000_Out_8042_Pin

		in	al,PORT61		;save PORT61 value
		IODELAY
		push	ax

		call	far ptr S_CPU

		pop	ax			;restore PORT61 value
		out	PORT61,al
		IODELAY

;--------------------------------------------------------------
;compare results of KB high & KB low speed, take the higher one
;--------------------------------------------------------------

	;restore KB high speed results in ax, di

		mov	al,bh
		mul	dl
		cmp	ax,si
		pop	ax
		pop	di

		jae	AUTO_CPUS_READY

	;use KB high speed result

		mov	bx,ax
		mov	dx,di

AUTO_CPUS_READY:
endif;	TOGGLE_8042_FOR_CPU_CLK_DETECT

	;write CPU_INTERNAL_CLOCK[bp] with tested value

		mov	al,bh			;system clock(integer) in AL
		mul	dl			;Sing/doub/treb value in DL

		mov	CPU_INT_CLOCK[bp],ax	;actual internal CPU clock

		mov	dl,FIXED_DISK_STEP[bp]	;get CPU type
		and	dl,CPU_TYPE_MASK	;get CPU type

;;;;; 	;special table for P24T , because the clock mode is x2.5
;;;;; 		cmp	dl,TYPE_P24T
;;;;; 		jne	Not_P24T_2Point5
;;;;; 		test	byte ptr OVERRIDE[bp],DOUBLE_CLOCK
;;;;; 		jz	Not_P24T_2Point5
;;;;; 		mov	si,offset P24T_Int_Clock_Tbl
;;;;; 		jmp	R_Off_Clk
;;;;; Not_P24T_2Point5:


	;special table for P5 & M1 & K5
		mov	bh,byte ptr FIXED_DISK_STEP[bp]
		and	bh,CPU_TYPE_MASK
		mov	si,offset CPU_Int_Clock_Tbl	;table for PENTIUM
		cmp	bh,TYPE_586			;Pentium CPU?
		je	Round_Off_It

		cmp	bh,TYPE_AMD5K86			;K5 CPU?
		je	Round_Off_It

		mov	si,offset M1_Int_Clock_Tbl	;table for M1
		cmp	bh,TYPE_M1			;M1 CPU?
		je	Round_Off_It
		jmp	Not_Pentium

Round_Off_It:
		mov	al,dh

R_Off_Clk:

	;far call Round_Off_Clock

		FAR_CALL <offset Round_Off_Clock>,0E000h

ifndef	CPU_Support_Above_GXM
		mov	CPU_INT_CLOCK[bp],bl	;actual internal CPU clock

		push	G_RAM
		pop	es

		mov	bl,cs:[si+2]			;SI+2 = system clock
endif	;CPU_Support_Above_GXM

		call	Get_IDT_WinChip_Clock		;For IDT WinChip
							;change Ratio

		cmp	byte ptr CPU_BRAND[bp], CPU_BRAND_CYRIX
		jne	NotM1_Cpu

		call	Check_M2Cpu
		je	NotM1_Cpu

;There is two combination for 150Mhz , 75*2 and 50*3 , the default is 75*2
;, we need to check the clock mode , if 3x , change host clock to 50Mhz
		mov	al,byte ptr FIXED_DISK_STEP[bp]
		and	al,CPU_TYPE_MASK
		cmp	al,TYPE_M1			;M1 CPU?
		jne	NotM1_Cpu

		cmp	byte ptr CPU_INT_CLOCK[bp],150		;150Mhze ?
		jne	NotM1_Cpu

;Now , BIOS set 150Mhz as 60x2.5 for M2
		mov	al,0FEh			;DIR0 of M2 CPU
		out	22h,al
		in	al,23h
		and	al,0f7h			;mask bit 3
		cmp	al,52H			;x2.5 ?
		je	NotM1_Cpu		;yes

		cmp	al,51h			;x2 ?
		jne	Not_M2X2

		mov	bl,CPU75		;set host clock 75x2
Not_M2X2:

		test	byte ptr OVERRIDE[bp],THREE_CLOCK	;3x mode ?
		jz	NotM1_Cpu

	;set 50Mhz host clock if 3x mode
		mov	bl,CPU50				;set host clock

NotM1_Cpu:

ifdef	K586_68MHz_Show_133MHz
		cmp	al,TYPE_AMD5K86
		jne	Not_AMD5K86

		cmp	byte ptr CPU_INT_CLOCK[bp],120		;150Mhz ?
		jne	Not_AMD5K86

	;Set 166MHz For AMD5K86 Use 68MHz
		mov	byte ptr CPU_INT_CLOCK[bp],117		;166Mhz
		mov	bl,CPU66	;66x1.75
Not_AMD5K86:
endif;	K586_68MHz_Show_133MHz

		mov	byte ptr es:[CPU_CLOCK],bl

	Not_P54C:
	Not_Pentium:

;Show 100Mhz if 99Mhz
		cmp	byte ptr CPU_INT_CLOCK[bp],132
		je	Set_133
		cmp	byte ptr CPU_INT_CLOCK[bp],99
		jne	@F
Set_133:
		inc	byte ptr CPU_INT_CLOCK[bp]
	@@:
ifdef	TOGGLE_8042_FOR_CPU_CLK_DETECT
		mov	al,1
		call	F000_Out_8042_Pin
endif;	TOGGLE_8042_FOR_CPU_CLK_DETECT

;-------------------
;Clear temporary RAM
;-------------------

		mov	ax,G_RAM
		mov	es,ax
		assume	es:G_RAM

;----------------------------
;Special treatment for TI CPU
;----------------------------

		mov	byte ptr es:CPU_CLOCK,bl

CpuSpeedEnd:
		clc
		ret

Measure_CPU_Speed	endp

;Input : BX - real CPU clock (detected by RDTSC instruction)
;Output: carry set - It is AMD K6 model 8 CPU &
;		     CPU_INT_CLOCK[bp] & G_RAM:[CPU_CLOCK] are filled
;	 no carry  - Not K6 model 8 CPU
Get_AMD_Model8_Clock_Tbl Proc 	Near

		push	ax
		push	bx

		extrn	Check_K6_CPU:near
		call	Check_K6_CPU
		clc
		jne	Not_Model8_CPU

		call	Read_CpuID		;read CPU ID
		cmp	ax,0588h
		jb	Not_Model8_CPU	;No, skip !

		mov	ecx,0c0000087h		;read bus ratio steping
     		RDMSR

		and	ax, 00000111b		;AL = 000 -> 4.5x
						;     001 -> 5.0x
						;     010 -> 4.0x
						;     011 -> 5.5x
						;     100 -> 2.5x
						;     101 -> 3.0x
						;     110 -> 6.0x
						;     111 -> 3.5x

		mov	si,ax
		add	si,offset K6_ClkRatio
CalcHostClk	label	near
; Note : The following instruction cause Cyrix M2 hang up.
;		movzx	cx,byte ptr cs:[si] 	;get clock ratio
;		mov	ax,bx
;		shl	ax,1			;multipler by 2
;		idiv	cx			;get host clock in AL

		movzx	cx,byte ptr cs:[si] 	;get clock ratio
		shl	bx, 1			;multipler by 2
		xor	ax, ax
	DivLoop:
		sub	bx, cx
		jc	short DivideOk
		inc	ax
		jmp	short DivLoop
	DivideOk:

	;now AL contains raw host clock
	;look for formal host clock
		mov	di,offset K6_HostClk
NextHostClk:
		cmp	byte ptr cs:[di+HOSTCLK_SIZE],0	;end of host clock table ?
		je	HostClkExit	;yes

		cmp	al,cs:[di]		;match ?
		jae	HostClkExit

		add	di,HOSTCLK_SIZE		;point to next entry
		jmp	NextHostClk
HostClkExit:

	;Calculate CPU real clock by multipling host clock by clock ratio

		mov	ax,cs:[di+3]		;get factor to calculate clock
		movzx	cx,byte ptr cs:[si]	;get clock ration in /2
		mul	cx
		shr	ax,1
		add	ax,5			;for round off
		mov	cx,10
		idiv	cx

		call	ChkIf_X99Mhz		;Add 1 if x99Mhz

		push	G_RAM
		pop	es
		mov	CPU_INT_CLOCK[bp],ax	;actual internal CPU clock

		mov	cl,cs:[di+2]	 	;get formal host clock
		mov	byte ptr es:[CPU_CLOCK],cl

;R04 - starts
	;Record Host clock of P5 in shadow memory for future usage
		extrn	P6HostClock:near
		pushad
		push	ds
		F000_call F000_Shadow_W		;F-segment shadow R/W

		mov	ax, DGROUP		;DS=F000
		mov	ds, ax
		mov	si, offset DGROUP:P6HostClock
		mov	al, cs:[di+1]		;get host clock frequency
		mov	[si], al		;save clock value in shadow

		F000_call F000_Shadow_R		;F-segment shadow Readonly
		pop	ds
		popad
;R04 - ends

Get_Model8_Clock_Tbl_OK:
		stc
		pop	bx
		pop	ax
		ret

Not_Model8_CPU:
		clc
		pop	bx
		pop	ax
		ret

Get_AMD_Model8_Clock_Tbl Endp

;Input : BX - real CPU clock (detected by RDTSC instruction)
;Output: carry set - It is Cyrix M2 CPU &
;		     CPU_INT_CLOCK[bp] & G_RAM:[CPU_CLOCK] are filled
;	 no carry  - Not Cyrix M2 CPU
Get_M2_Clock_Tbl	proc	near

		push	ax
		push	bx

		cmp	byte ptr CPU_BRAND[bp], CPU_BRAND_CYRIX
		clc
		jne	Not_M2_CPU

		mov	al, 0FEh
		out	22h, al
		in 	al, 23h

		mov 	ah, al
		and	ah, 11110000b			;mask bits[7:4]
		cmp	ah, 50h				; Is M2 CPU present ?
		clc
		jne	Not_M2_CPU

		xor	ah,ah
		and	al,00000111b		;AL = 51h or 59h x2
						;     52h or 5Ah x2.5
						;     53h or 5Bh x3
						;     54h or 5Ch x3.5
						;     55h or 5DH x4
		dec	ax
		mov	si,ax
		add	si,offset M2_ClkRatio

		jmp	CalcHostClk

Not_M2_CPU:
		pop	bx
		pop	ax
     		ret

Get_M2_Clock_Tbl	ENDP

M2_ClkRatio	db	4	;x2	,000
		db	5	;x2.5	,001
		db	6	;x3	;010
		db	7	;x3.5	;011
		db	8	;x4	;100

K6_ClkRatio	db	9	;x4.5	,000
		db	10	;x5	,001
		db	8	;x4	;010
		db	11	;x5.5	;011
		db	5	;x2.5	;100
		db	6	;x3.0	;101
		db	12	;x6.0	;110
		db	7	;x3.5	;111

		;possible host clock table for P6 class CPU
K6_HostClk:

		db	148,150,CPU100	;150Mhz
		dw	1500		;for real CPU frequency calculation
HOSTCLK_SIZE	EQU	($ - offset K6_HostClk)

		db	139,140,CPU100	;140Mhz
		dw	1400		;for real CPU frequency calculation

		db	134,135,CPU100	;135Mhz
		dw	1350		;for real CPU frequency calculation

	 	db	132,133,CPU100	;133Mhz
		dw	1333	;for real CPU frequency calculation	;R03

	 	db	129,130,CPU100	;130Mhz
		dw	1300	;for real CPU frequency calculation

		db	123,125,CPU100	;125Mhz
		dw	1250		;for real CPU frequency calculation

		db	118,120,CPU100	;120Mhz
		dw	1200		;for real CPU frequency calculation

		db	113,115,CPU100	;115Mhz
		dw	1150		;for real CPU frequency calculation

;R03 - start
		db	111,112,CPU100	;112Mhz
		dw	1120		;for real CPU frequency calculation
;R03 - end

		db	108,110,CPU100	;110Mhz
		dw	1100

		db	103,105,CPU100	;105Mhz
		dw	1050

		db	96,100,CPU100	;100Mhz
		dw	1000	;for real CPU frequency calculation

		db	92,95,CPU95	;95Mhz
		dw	950

		db	88,90,CPU90	;90Mhz
		dw	900

		db	80,83,CPU83	;83Mhz
		dw	832

		db	71,75,CPU75	;75Mhz
		dw	750

ifndef	K6_NO_68MHz
		db	68,68,CPU66	;68.5Mhz
		dw	685
endif;	K6_NO_68MHz

		db	64,66,CPU66	;66Mhz
		dw	666

		db	58,60,CPU60	;60Mhz
		dw	600

		db	53,55,CPU60	;55Mhz
		dw	550

		db	48,50,CPU50	;50Mhz
		dw	500

		db	0	;end of table

;Function : Increment by one if measured frequency is x99Mhz
;Input    : ax - CPU frequency in Mhz
;Output   : ax - modified CPU frequency
ChkIf_X99Mhz	proc	near

		push	bx
		push	ax		;save original frequency
		mov	bx,100

Sub100:
		cmp	ax,bx		;value below 100 ?
		jbe	Less100	;yes

		sub	ax,bx		;no, subtract 100 until the value
		jmp	Sub100	;below 100

Less100:
		cmp	al,99		;x99Mhz ?
		pop	ax		;restore original value
		jne	Not_X99Mhz
		inc	ax		;increment by 1 if x99Mhz
Not_X99Mhz:
		pop	bx

		ret
ChkIf_X99Mhz	endp

Get_IDT_WinChip_Clock	Proc	Near
		push	eax
		push	ecx
		call	Check_IdtCpu		;is IDT C6 CPU ?
		jne	Not_IdtC6_WinChip

		mov	eax,1			;eax = 1 to read CPU ID
		db	0fh,0A2h		;CPU ID instruction

		cmp	al, 80h
		jb	Not_IdtC6_WinChip

		call	fPROC_If_WinChip2A
		je	WinChip2A_Or_WinChip3_Clock
		cmp	al, 90h
		jb	WinChip2_Clock

WinChip2A_Or_WinChip3_Clock:

		call	WinChip2A_Clock_Multiplier_In_AH
		mov	cl, ah
		and	cl, 03h
		mov	ch, ah
		shr	ch, 2
		add	cx, 0202h
		mov	ax, CPU_INT_CLOCK[bp]	;actual internal CPU clock
		div	ch
		mul	cl
		jmp	Locate_IdtC6_Host_Freq

WinChip2_Clock:

		mov	ecx,10ah
		db	0fh,32h			;Ratio of processor
						;al = 0 => 2x
						;al = 1 => 3x
						;al = 2 => 4x
						;al = 3 => 5x

		add	al,2
		mov	cl,al

		mov	ax,word ptr CPU_INT_CLOCK[bp]	;actual internal CPU clock
		div	cl

Locate_IdtC6_Host_Freq:

		mov	si,offset IdtC6_Bus_Clock_Tbl_List

Next_IdtC6_WinChip_Clock:
		mov	bl,byte ptr cs:[si+1]
		cmp	al,byte ptr cs:[si]
		jae	Get_IdtC6_WinChip_Clock_OK

		cmp	byte ptr cs:[si+2],0
		je	Get_IdtC6_WinChip_Clock_OK

		add	si,2
		jmp	Next_IdtC6_WinChip_Clock

Get_IdtC6_WinChip_Clock_OK:
Not_IdtC6_WinChip:

		pop	ecx
		pop	eax
		ret

Get_IDT_WinChip_Clock	Endp

IdtC6_Bus_Clock_Tbl_List:
		db	98,CPU100		;100MHz
		db	81,CPU83		;100MHz
		db	73,CPU75		;100MHz
		db	64,CPU66		;100MHz
		db	58,CPU60		;100MHz
		db	48,CPU50		;100MHz
		db	0
DIVID		MACRO
		mov	ax,di
		div	bx
		endm
PORT61		EQU	61H
PORT8254	EQU	42H
DATA8254	EQU	43H
COUNT		EQU	3EH

;-----------------------------------------------------------------
;Input	:	None
;Output :	BH : System Clock in interger
;		BL : System Clock i.e. 10h = 16MHz
;				       20h = 20MHz
;				       30h = 25MHz
;				       40h = 33MHz
;				       50h = 40MHz
;				       60h = 50MHz
;				       60h = 60MHz
;				       60h = 66MHz
;		DH : Actual CPU clock index found
;		DL : Single/Double/Trible
;-----------------------------------------------------------------
		ALIGN	16
S_Cpu		proc	far

		call	far ptr XMeasureNoRDTSCCpuClck

		mov	ax,26f5h	;dividend low word
		mov	dx,005ah	;dividend high word

		mov	bh,byte ptr FIXED_DISK_STEP[bp]
		and	bh,CPU_TYPE_MASK

		cmp	bh,TYPE_AMD5K86	;K86 CPU
		jne	AmdK86_CPU
		mov	dl,4AH		;for K86
AmdK86_CPU:
		cmp	bh,TYPE_M1
		jne	Not_M1
		mov	ax,0dbb8h
		mov	dl,56h
		jmp	Not_Cyrix_Cpu
Not_M1:

	;Change frequency detection factor for Rise/mP6 CPU
		call	Check_RiseCpu		;is Rise mP6 CPU ?
		jne	NotMp6Cpu
		mov	ax,0000h		;factor high word
		mov	dl,34h			;factor low word
		jmp	Not_Cyrix_Cpu
NotMp6Cpu:
		cmp	byte ptr CPU_BRAND[bp],CPU_BRAND_CYRIX
		je	Yes_Cyrix_Cpu
		jmp	Not_Cyrix_Cpu
Yes_Cyrix_Cpu:
		mov	ax,64a8h
		mov	dl,4eh
Not_Cyrix_Cpu:

		div	cx

		xor	bl,bl
Sub_1:
		inc	bl
		sub	ax,100
		jc	Fin_0
		jz	No_Carry
		jmp	Sub_1
Fin_0:
		add	ax,100

		cmp	al,50
		jae	No_Carry
		dec	bl
No_Carry:
;------------------------------------------------------------------
;calculate system clock by checking CPU type (Single/Double/Treble)
;------------------------------------------------------------------

Xchg_CPU_Mode_OK:

		xor	bh,bh
		mov	ax,bx

		mov	bl,1

		call	Check_586_Cpu		;p5 class CPU ?
		je	Single_Freq	;yes,
Single_Freq:

		div	bl
		add	al,3	       ;tolerance
Skip_Gap:
		mov	dh,al	;DH = Actual CPU clock found
		mov	dl,bl	;DL = Single/Double/Trible

		mov	si,offset Sys_Clock_Tbl
		mov	cx,Sys_Clock_Tbl_Len

	;far call Round_Off_Clock

		FAR_CALL <offset Round_Off_Clock>,0E000h

		ret

Check_586_Cpu	proc	near

		push	bx
		mov	bh,byte ptr FIXED_DISK_STEP[bp]
		and	bh,CPU_TYPE_MASK
		cmp	bh,TYPE_AMD5K86		;K86 CPU
		je	Yes_P5_Class

		cmp	bh,TYPE_586		;Pentium CPU?
		je	Yes_P5_Class

		cmp	bh,TYPE_M1
		je	Yes_P5_Class

Yes_P5_Class:
		pop	bx
		ret

Check_586_Cpu	endp

		even

Last_S_Cpu	Label	Near
S_Cpu		endp

;[]--------------------------------------------------------------[]
;Input	:	AL = Clock to be compared
;		SI = table offset
;		     (format: reference System_Clock_Table)
;		CX = no of entries
;
;Output :	BH = reference value (see System_Clock_Table)
;		BL = round-offed value
;		SI = offset which round-offed value locates
;[]--------------------------------------------------------------[]
Round_Off_Clock Proc	Far
Next_Clk_Tbl:
		mov	bx,cs:[si]
		cmp	al,bh
		jae	@F
		cmp	byte ptr cs:[si+3],0	;last table ?
		je	@F
		add	si,3			;next table
		jmp	Next_Clk_Tbl
@@:
		retf
Round_Off_Clock Endp

;--------------------------------------------------------------------
;			round	  value 	value
;			offed	  for		to be put
;			output	  reference	into G_RAM:CPU_CLOCK
;--------------------------------------------------------------------
Sys_Clock_Tbl:
		db	CPU66,		66,	CPU66
		db	CPU60,		60,	CPU60
		db	CPU50,		50,	CPU50
		db	CPU40,		40,	CPU40
		db	CPU33,		33,	CPU33
		db	CPU25,		25,	CPU25
		db	CPU20,		20,	CPU20
		db	CPU16,		16,	CPU16
		db	0		;end of table
Sys_Clock_Tbl_Len	EQU	($ - offset Sys_Clock_Tbl)/3

;--------------------------------------------------------------------
;			round	  value 	value
;			offed	  for		to be put
;			output	  reference	into G_RAM:CPU_CLOCK
;--------------------------------------------------------------------
CPU_Int_Clock_Tbl:

		;Add P55C-150,P54CT-150,P54CT-166 and P54CT-180
ifdef	LOW_CLOCK_VALUE_FOR_P5
		db	200,	193,	CPU66		;66x3
		db	180,	174,	CPU60		;60x3
		db	166,	161,	CPU66		;66x2.5
else;	LOW_CLOCK_VALUE_FOR_P5
ifdef	Higher_200MHz_Tbl
		db	200,	197,	CPU66		;66x3
else	;Higher_200MHz_Tbl
		db	200,	195,	CPU66		;66x3
endif	;Higher_200MHz_Tbl
ifdef LUCKY_START_166_CPU_DETECT
		db	180,	180,	CPU60		;60x3
else ;LUCKY_START_166_CPU_DETECT
		db	180,	179,	CPU60		;60x3
endif ;LUCKY_START_166_CPU_DETECT
		db	166,	163,	CPU66		;66x2.5
endif;	LOW_CLOCK_VALUE_FOR_P5

		db	150,	145,	CPU60		;60x2.5

		;add P54CS CPU support for 120 & 132 MHz
ifdef	Higher_133MHz_Tbl
		db	133,	129,	CPU66		;66x2
else	;Higher_133MHz_Tbl
		db	133,	127,	CPU66		;66x2
endif	;Higher_133MHz_Tbl
		db	125,	121,	CPU50
		db	120,	118,	CPU60		;60x2

ifndef	No_55MHz
ifndef	NO_110MHZ_CLOCK
ifdef	Higher_110MHz_Tbl
		db	110,	108,	CPU50		;55x2
else	;Higher_110MHz_Tbl

ifdef	LOW_CLOCK_VALUE_FOR_P5
		db	110,	105,	CPU50		;55x2
else;	LOW_CLOCK_VALUE_FOR_P5
		db	110,	107,	CPU50		;55x2
endif;	LOW_CLOCK_VALUE_FOR_P5

endif	;Higher_110MHz_Tbl
endif;	NO_110MHZ_CLOCK
endif	;No_55MHz

ifdef	Force_100_EQU_50_Double
		db	100,   	95,	CPU50
else	;Force_100_EQU_50_Double
ifdef	Special_P54C_Clock
		db	100,   	100,	CPU66		;66x1.5
else	;Special_P54C_Clock
		db	100,   	95,	CPU66		;66x1.5
endif	;Special_P54C_Clock
endif	;Force_100_EQU_50_Double

		db	 90,   	89,	CPU60		;60x1.5

		db	 83,   	81,	CPU50		;55x1.5
		db	 75,   	70,	CPU50		;50x1.5
		db	 66,   	60,	CPU66		;66x1
		db	0		;end of table

;--------------------------------------------------------------------
;			round	  value 	value
;			offed	  for		to be put
;			output	  reference	into G_RAM:CPU_CLOCK
;--------------------------------------------------------------------
M1_Int_Clock_Tbl:

ifdef	LOW_CLOCK_VALUE_FOR_P5
		db	200,	193,	CPU66		;66x3
		db	180,	174,	CPU60		;60x3
else;	LOW_CLOCK_VALUE_FOR_P5
		db	200,	195,	CPU66		;66x3
		db	180,	179,	CPU60		;60x3
endif;	LOW_CLOCK_VALUE_FOR_P5

ifdef	Lower_150MHz_Tbl

		db	150,    143,	CPU75		;75*2
else;	Lower_150MHz_Tbl

		db	150,    145,	CPU75		;75*2
endif;	Lower_150MHz_Tbl

ifdef	Higher_133MHz_Tbl
	ifdef	Special_Cyrix_Tbl_For_VLSI59X
		db	133,	130,	CPU66		;66x2
	else	;Special_Cyrix_Tbl_For_VLSI59X
		db	133,	129,	CPU66		;66x2
	endif	;Special_Cyrix_Tbl_For_VLSI59X
else	;Higher_133MHz_Tbl
		db	133,	127,	CPU66		;66x2
endif	;Higher_133MHz_Tbl

ifndef	Higher_120MHz_Tbl
		db	120,	118,	CPU60		;60x2
else	;Higher_120MHz_Tbl
		db	120,	120,	CPU60		;60x2
endif	;Higher_120MHz_Tbl

ifndef	No_55MHz
ifndef	NO_110MHZ_CLOCK
  ifdef	Higher_110MHz_Tbl
	ifdef	Special_Cyrix_Tbl_For_VLSI59X
		db	110,	109,	CPU50		;55x2
	else	;Special_Cyrix_Tbl_For_VLSI59X
		db	110,	108,	CPU50		;55x2
	endif	;Special_Cyrix_Tbl_For_VSI59X
  else	;Higher_110MHz_Tbl

	ifdef	LOW_CLOCK_VALUE_FOR_P5
		db	110,	105,	CPU50		;55x2
	else;	LOW_CLOCK_VALUE_FOR_P5
		db	110,	107,	CPU50		;55x2
	endif;	LOW_CLOCK_VALUE_FOR_P5

  endif	;Higher_110MHz_Tbl
endif;	NO_110MHZ_CLOCK
endif	;No_55MHz

ifdef	Special_P54C_Clock
		db	100,	100,	CPU50		;50x2
else	;Special_P54C_Clock
		db	100,	95,	CPU50		;50x2
endif	;Special_P54C_Clock
		db	 80,	70,	CPU40		;40x2

		db	 66,	64,	CPU66		;66x1
		db	 60,    58,	CPU60		;60x1
		db	 50,	48,	CPU50		;50x1

		db	0	;end of table

;;;;; P24T_Int_Clock_Tbl:
;;;;; ifndef	P6_BIOS_ONLY
;;;;; 		db	125,	       110,	CPU50
;;;;; 		db	100,		95,	CPU40
;;;;; 		db	 83,		75,	CPU33
;;;;; 		db	 63,		55,	CPU25
;;;;; 		db	 50,		45,	CPU20
;;;;; 		db	0
;;;;; endif;	P6_BIOS_ONLY
;;;;;
;;;;; Cpu_Speed_Msg:	db	'CPU Clock',0

;Function : Program MTRR for CPUs like P6 or P55CT
;Input	  : AL = 0 - program MTRR for conventional memory (0-640K)
;	       = 1 - program MTRR for extended memory (1Mb to top of memory)
;	    Bit 7 = 1 - 15-16MB memory hole is disabled(P6 only)
;	    esi - extended memory size
;	    BL = 0 - L2 cache status (0-disabled, 1-enabled)

;	    BH = L2 Cacheable range 000=512Mb , 001=1Gb, 010=2Gb, 011=4Gb
;				    100=8Gb   , 101=16Gb,110=32Gb,111=64Gb
;		 only for Pentium II CPUs

;Output   : none
ifdef	Special_Align_for_M1_Clock_unstable

		ALIGN	16
endif;	Special_Align_for_M1_Clock_unstable
		Public	Set_Cpu_MtRR
Set_Cpu_MtRR	proc	near

;Program cacheable region for M1 CPU
;BIOS have to set cacheable memory size for M1 CPU according to detected
;memory.
;Table for M1 CPU cacheable region control
;	memory size	value of reg.
;	-----------	-------------
;	1Mb		03H
;	2Mb		04H
;	4Mb		05H
;	8Mb		06H
;	...		...
;	4Gb		0FH
		or	al,al			;for extended memory ?
		jz	Not_M1Cpu

		mov	al,byte ptr FIXED_DISK_STEP[bp]	;get CPU type
		and	al,CPU_TYPE_MASK
		cmp	al,TYPE_M1			;6x86 CPU ?
		jne	Not_M1Cpu

		push	esi
		shl	esi,10
		and	esi, 0fff00000h
		shr	esi,10
		mov	ebx,esi
		add	ebx,1024		;add 1Mb base address

		push	ebx			;save ext memory size

		shr	ebx,10			;convert to 1Mb unit

		mov	ah,3			;value for 1Mb
		mov	si,1 			;minmum is 1Mb
Chk_MemSize:
		cmp	bx, si			;if main memory size <= cacheable
						;memory size
		jbe	Value_Ok0		;yes
		shl	si, 1			;next memory size
		inc	ah  			;next register value
		jmp	Chk_MemSize	;recheck again
Value_Ok0:
		F000_call Unlock_Cyrix	;open cyrix register locked

	;set cacheable region for M1 CPU in ARR7

		mov	cl, 0dbh	;ARR7
		mov	al, ah		;set cacheable region
		call	F000_Set_Cyrix

		cmp	bx, si		;if main memory = cacheable memory
		pop	ebx		;restore memory size
		je	Value_Ok	;yes , finish
		push	ebx		;Save memory size

		shr	ebx, 2		;EBX b4-b23 -> A12-A31
		shl	ebx, 4

		mov	cl, 0d8h	;ARR6
		mov	al, bl		;set A15-A12 address
		call	F000_Set_Cyrix

		shr	ebx, 8		;EBX bit 15-0 => A31-A16
		mov	cl, 0d6h	;ARR6
		mov	al, bh		;set A31-A24
		call	F000_Set_Cyrix

		mov	cl, 0d7h	;ARR6
		mov	al, bl		;set A23-A16
		call	F000_Set_Cyrix

		mov	cl, 0E2h
		mov	al, 1		;ARR6 as non-cacheable
		call	F000_Set_Cyrix

		pop	ebx		;get onboard memory size
		shr	ebx, 10		;ebx=ebx/1024 convert 1M
		mov	ax, bx		;ax= onboard memory size
		mov	bx, si		;Get Cacheable size
		sub	bx, ax		;bx=must set noncacheable memory size
		mov	ch, 0		;ch=D8h value if bx=0
		jz	Value_Ok1	;go to set D8h value

		mov	ch, 0Fh		;value for 32MB
		mov	si, 01000000b	;minnum is 32MB
		xor	dx, dx		;initial surplus value
Chk_MemSize1:
		shr	si, 1		;next memory size
		dec	ch  		;next register value
		cmp	bx, si		;if must set noncacheable memory size
					;=> noncacheable memory size
		jae	Value_Ok1	;then check it is on the times value
		jmp	Chk_MemSize1;next value to check
Value_Ok1:
		push	ax		;save onboard memory size
		push	dx		;save surplus value
		div	si		;onboard memory size DIV
					;noncacheable memory size
		or	dx, dx		;if on the value
		pop	dx		;restore surplus value
		pop	ax		;restore onboard memory size
		jnz	Chk_MemSize1	;go to set it

		mov	cl, 0D8h	;ARR6
		call	F000_Get_Cyrix
		and	al, 11110000b
		or	al, ch		;set REGION BLOCK size
		call	F000_Set_Cyrix

		cmp	bx, si		;if must set noncacheable memory size
					;= set noncacheable memory size
		je	Value_Ok	;then set finish

		push	bx		;save next must noncacheable address
					; MB is it unit

		xor	ebx, ebx	;clear ebx

		mov	cl, 0d6h	;ARR6 Noncacheable A31-A24
		call	F000_Get_Cyrix
		mov	bh, al

		mov	cl, 0d7h	;ARR6 Noncacheable A23-A16
		call	F000_Get_Cyrix
		mov	bl, al		;now BX is system memory size

		shl	ebx, 16		;ebx Bit 31 - 16 is A31-A16

		mov	cl, 0d8h	;ARR6 Noncacheable A15-A12
		call	F000_Get_Cyrix
		mov	bh, al		;ebx Bit 31 - 12 is A31-A12

		xor	eax, eax	;clear eax
		mov	ax, si		;get last set cacheable memory size
		shl	eax, 20		;EAX b31-b12 => A31-A12
		add	ebx, eax	;BX is next noncacheable start address
					;Bit 31-12 is A31-A12
					;now BX is next noncacheable address
		mov	al, bh		;set A15-A12
		mov	cl, 0d5h	;ARR5 A15-A12
		call	F000_Set_Cyrix

		shr	ebx, 16		;EBX bit 15-0 is A31-A16

		mov	al, bl
		mov	cl, 0d4h	;ARR5 A23-A16
		call	F000_Set_Cyrix	;set A23-A16

		mov	al, bh
		mov	cl, 0d3h	;ARR5 A31-A24
		call	F000_Set_Cyrix	;set A31-A24

		mov	cl, 0e1h
		mov	al, 1		;Set ARR5 noncacheable region
		call	F000_Set_Cyrix

		pop	bx		;get must noncacheable address
		mov	ax, si		;Get last Cacheable size
		sub	bx, ax		;if noncacheable address =
					;Cacheable size
		mov	ax, bx		;ax is must noncacheable address
		mov	ch, 0		;ch is D5 value
		jz	Value_Ok2	;go set D5 value

		mov	ch, 0fh		;value for 32MB D5 value
		mov	si, 01000000b	;maxnum is 32MB
Chk_MemSize2:
		shr	si, 1		;next memory size
		dec	ch  		;next register value
		cmp	bx, si		;if must noncacheable address
					;=> Cacheable size
		jae	Value_Ok2 ;go to check is it on the times value
		jmp	Chk_MemSize2;check next vlaue
Value_Ok2:
		push	ax		;save must noncacheable address
		push	dx		;save surplus value
		div	si		;onboard memory size DIV
					;noncacheable memory size
		or	dx, dx		;if on the value
		pop	dx		;restore surplus value
		pop	ax		;restore onboard memory size
		jnz	Chk_MemSize2	;go to set it

		mov	cl, 0D5h	;ARR5
		call	F000_Get_Cyrix
		and	al, 11110000b	;set REGION BLOCK value
		or	al, ch
		call	F000_Set_Cyrix

		cmp	bx, si		;if must set noncacheable memory size
					;= set noncacheable memory size
		je	Value_Ok	;then set finish

		push	bx		;save must noncacheable address ( MB )
		xor	ebx, ebx	;clear ebx
		mov	cl, 0d3h	;ARR5 Noncacheable A31-A24
		call	F000_Get_Cyrix
		mov	bh, al

		mov	cl, 0d4h	;ARR5 Noncacheable A23-A16
		call	F000_Get_Cyrix
		mov	bl, al		;now BX is system memory size

		shl	ebx, 16		;ebx Bit 31 - 16 is A31-A16

		mov	cl, 0d5h	;ARR5 Noncacheable A15-A12
		call	F000_Get_Cyrix
		mov	bh, al		;ebx Bit 31 - 12 is A31-A12

		xor	eax, eax	;clear EAX
		mov	ax, si		;ax is last set noncacheable size
		shl	eax, 20		;eax bit 31-12 is noncacheable size
					;A31-A12
		add	ebx, eax	;BX is next noncacheable start address
					;Bit 31-12 is A31-A12
					;now BX is next noncacheable address
		mov	al, bh
		mov	cl, 0d2h	;ARR4 A15-A12
		call	F000_Set_Cyrix

		shr	ebx, 16		;EBX bit 15-0 is A31-A16

		mov	al, bl
		mov	cl, 0d1h	;ARR4 A23-A16
		call	F000_Set_Cyrix

		mov	al, bh
		mov	cl, 0d0h	;ARR4 A31-A24
		call	F000_Set_Cyrix

		mov	cl, 0e0h
		mov	al, 1		;Set ARR4 noncacheable region
		call	F000_Set_Cyrix

		pop	bx		;get must noncacheable address ( MB )
		mov	ax, si		;Get last Cacheable size
		sub	bx, ax		;if noncacheable address =
					;Cacheable size
		mov	ax, bx		;ax is must noncacheable address
		mov	ch, 0		;ch is D2 value
		jz	Value_Ok3	;go set D2 value

		mov	ch, 0fh			;value for 32MB
		mov	si, 01000000b		;maxmum is 32MB
Chk_MemSize3:
		shr	si, 1		;next memory size
		dec	ch  		;next register value
		cmp	bx, si		;if must noncacheable address
					;=> Cacheable size
		jae	Value_Ok3	;go to check is it on the times value
		jmp	Chk_MemSize3;check next vlaue
Value_Ok3:
		push	ax		;save must noncacheable address
		push	dx		;save surplus value
		div	si		;onboard memory size DIV
					;noncacheable memory size
		or	dx, dx		;if on the value
		pop	dx		;restore surplus value
		pop	ax		;restore onboard memory size
		jnz	Chk_MemSize3	;go to set it

		mov	cl, 0D2h	;ARR4
		call	F000_Get_Cyrix
		and	al, 11110000b	;set REGION BLOCK value
		or	al, ch
		call	F000_Set_Cyrix
Value_ok:

;R06 - starts
	;----------------------------------------------
	;If DIR1 >= 08H
	;Set WL(Weak_Locking) bit of M2 CPU RCRx Reg
	;----------------------------------------------
		mov	al,0FFh		;DIR1 of M2 CPU
		out	22h,al
		in	al,23h
		cmp	al,08h		; > 08h
		jb	short	_NoSetWLBit

		mov	cl, 0E0h	;RCR4 - RCR7
	_Loop_RCRx:
		call	F000_Get_Cyrix
		or	al, 00000100b	;Set WL Bit
		call	F000_Set_Cyrix
		inc	cl
		cmp	cl, 0E4h
		jne	short	_Loop_RCRx
	_NoSetWLBit:
	;----------------------------------------------
;R06 - ends

		F000_call lock_Cyrix	;lock cyrix CPU register access

 		pop	esi
 Not_M1Cpu:
		ret

Set_Cpu_MtRR	endp

		Public	Enable_M1_FarHit
Enable_M1_FarHit	proc	near

		call	Check_M1_Cpu
		jne	Not_M1_Cpu

		F000_call	UNlock_Cyrix

ifdef	HIGH_6X86_L2_HIT_RATE
;Enable WT_ALLOC of CCR5 to improve L2 cache hit rate for CCT386.EXE
;For 256Kb cache it improve hit rate from 26% upto 62% for 6x86 CPUs

ifdef	Disable_WT_ALLOC_When_Cyrix_100		;R02 - start
		extrn	Ct_Quatify_100Mhz:Near
		call	Ct_Quatify_100Mhz	;If 100MHz Host CLK ?
		jnc	short Not_100Mhz	; Not, Jmp

		jmp	short Skip_WT_ALLOC
Not_100Mhz:
endif;	Disable_WT_ALLOC_When_Cyrix_100		;R02 - end
ifdef	Disable_WT_ALLOC_When_Cyrix_PR266
 		mov	cl,0FEh			; DIR0 of M2 CPU
		call	F000_Get_Cyrix
 						; AL = 51 : 'x 2'
 						; AL = 52 : 'x 2.5'
 						; AL = 53 : 'x 3'
		cmp	al,52h
		jnz	Not_Cyrix_PR266
 		cmp	byte ptr CPU_INT_CLOCK[bp],208	;208Mhze(PR266) ?
		jnz	Not_Cyrix_PR266
		jmp	Skip_WT_ALLOC
Not_Cyrix_PR266:
endif;	Disable_WT_ALLOC_When_Cyrix_PR266

ifdef	Disable_WT_ALLOC_When_Cyrix_83_x3
 		mov	cl,0FEh			; DIR0 of M2 CPU
		call	F000_Get_Cyrix
 						; AL = 51 : 'x 2'
 						; AL = 52 : 'x 2.5'
 						; AL = 53 : 'x 3'
		cmp	al,53h
		jnz	Not_MII_333
 		cmp	byte ptr CPU_INT_CLOCK[bp],250	;250Mhze(MII333) ?
		jnz	Not_MII_333
		jmp	Skip_WT_ALLOC
Not_MII_333:
endif;	Disable_WT_ALLOC_When_Cyrix_83_x3

		mov	cl,0E9H			;CCR5
		call	F000_Get_Cyrix
		or	al,01H			;enable WT_ALLOC
		call	F000_Set_Cyrix
Skip_WT_ALLOC:
endif;	HIGH_6X86_L2_HIT_RATE

	;set bit 6 of index 30H
		mov	cl,30H
		call	F000_Get_Cyrix
		or	al,40H
		call	F000_Set_Cyrix

	;enable far hit
		mov	ebx,28h
		db	0fh,26h,0cbh		;mov tr1,ebx
		db	0fh,24h,0d0h		;mov eax,tr2
		and	al,NOT 02H		;enable far hits
		db	0fh,26h,0d0h		;mov tr2,eax

	;clear bit 6 of index 30H
		mov	cl,30H
		call	F000_Get_Cyrix
		and	al,NOT 40H
		call	F000_Set_Cyrix

		F000_call lock_Cyrix
Not_M1_Cpu:

		ret

Enable_M1_FarHit	endp

		public	F000_Set_Cyrix
F000_Set_Cyrix	Proc	Near
		F000_Call Set_Cyrix
		ret
F000_Set_Cyrix	Endp

F000_Get_Cyrix	Proc	Near
		F000_Call Get_Cyrix
		ret
F000_Get_Cyrix	Endp

;[]========================================================================[]
;Name	  :	Prg_K5_Write_Allocate
;
;Function :	To enable the AMD K5 CPU's write allocation function
;
;Input	  :	dword ptr EXT_MEM_SIZE[bp] in terms of 1K
;
;Output	  :	None
;[]========================================================================[]
		Public	Prg_K5_Write_Allocate
Prg_K5_Write_Allocate	Proc	Near

ifndef	No_K5_Write_Allocation
		pushad

 		call	Check_K586_Cpu 			;AMD 5k86 CPU ?

 		jne	No_Write_Alloc

		call	Read_CpuID			;read CPU ID in AX
		mov	ah, al
		and	ah, 0F0h			;Model = 0x ?
		jz	No_Write_Alloc		;yes, skip
		cmp	ah, 030h			;Model = 0x, 1x, 2x ?
		ja	No_Write_Alloc		;no, skip

		and	al, 0Fh				;AL = stepping
		cmp	al, 4				;stepping >= 4
		jb	No_Write_Alloc		;no, skip

	;----------------------------------------------------------
	;MSR 85h b15-b0 : Top of memory address
	;	 b16    : Fixed Range Enable, i.e. from A0000-FFFFF
	;	 b17    : Programmable Range Enable
	;	 b18    : Top-Of-Memory Enable
	;----------------------------------------------------------

		F000_call Ct_MemHole_Status	;get hole status in AX
		mov	si, ax			;temporary save to SI

		mov	ecx, 85h
		RDMSR
		mov	ecx, EXT_MEM_SIZE[bp]
		shr	ecx, 6			;convert to 64K byte unit
		add	cx, 10h			;add 1M of base memory
		mov	ax, cx

		and	eax, not 00070000h	;always disable Fixed Range

		or	eax, 00050000h		;enable Top-Of-Mem range
						;   & Fix Range
		or	si, si			;memory hole enabled?
		jz	@F		;disabled !
		or	eax, 00020000h		;enable Programmable Range
	@@:
		mov	ecx, 85h
		WRMSR

	;program the Programmable Range for 15M-16M as Non-WA

		or	si, si			;memory hole enabled?
		jz	@F		;disabled !
		mov	ecx, 86h
		RDMSR

		mov	eax,00FF00F0h		;15M-16M as Non-cacheable
		mov	ecx, 86h
		WRMSR
	@@:

	;program bit 4 or MSR 83 to enable write allocate
	;bit 31 is for bus pipeline but undocumented.

		mov	ecx, 83h
		RDMSR

		or	eax, 80000010h		;enable write allocate
						;disable bus pipeline
		WRMSR

No_Write_Alloc:

		popad

endif	;No_K5_Write_Allocation

		ret

Prg_K5_Write_Allocate	Endp

ECODE		ENDS

XGROUP		GROUP	XCODE
XCODE		SEGMENT USE16 PARA PUBLIC 'XCODE'
		ASSUME	CS:XGROUP,ES:XGROUP

DIVID		MACRO
		mov	ax,di
		div	bx
		endm
PORT61		EQU	61H
PORT8254	EQU	42H
DATA8254	EQU	43H
COUNT		EQU	3EH

		align	16
;Function : Measure CPU clock without RDTSC instruction
;Input    : none
;Output   : CX - duration time of one CPU clock
;Note     : This routine will be executed in base memory.
;
XMeasureNoRDTSCCpuClck	proc	far

		cli
		mov	al,0fch 	;disable counter 2
		out	PORT61,al
		SIODELAY
		mov	al,0b4h 	;program counter 2
		out	DATA8254,al
		IODELAY
		xor	al,al
		out	PORT8254,al
		IODELAY
		out	PORT8254,al
		IODELAY

		mov	di,7aaah	;dividend
		mov	bx,5555h	;divisor
		xor	dx,dx
		mov	cx,COUNT	;count
		mov	al,0fdh 	;enable counter
		out	PORT61,al
		SIODELAY
		ALIGN	16
Divid_33:
		DIVID			;divide 1
		DIVID			;divide 2
		DIVID			;divide 3
		DIVID			;divide 4
		DIVID			;divide 5
		DIVID			;divide 6
		DIVID			;divide 7
		DIVID			;divide 8
		DIVID			;divide 9
		DIVID			;divide 10
		DIVID			;divide 11
		DIVID			;divide 12
		DIVID			;divide 13
		DIVID			;divide 14
		DIVID			;divide 15
		DIVID			;divide 16
		DIVID			;divide 17
		DIVID			;divide 18
		DIVID			;divide 19
		DIVID			;divide 20
		DIVID			;divide 21
		DIVID			;divide 22
		DIVID			;divide 23
		DIVID			;divide 24
		DIVID			;divide 25
		DIVID			;divide 26
		DIVID			;divide 27
		DIVID			;divide 28
		DIVID			;divide 29
		DIVID			;divide 30
		DIVID			;divide 31
		DIVID			;divide 32
		DIVID			;divide 33
		dec	cx
		jz	Finish
		jmp	Divid_33
Finish:
		mov	al,0fch 	;stop counter 2
		out	61h,al
		SIODELAY
		in	al,PORT8254	;read counter 2 low byte
		IODELAY
		mov	ah,al
		in	al,PORT8254	;read counter 2 high byte
		IODELAY
		xchg	ah,al
		mov	si,ax		;store result

		xor	dx,dx
		mov	cx,COUNT	;count
		mov	al,0fdh 	;enable counter
		out	PORT61,al
		SIODELAY
		ALIGN	16
Divid_1:
		DIVID			;divide 1
		dec	cx
		jz	short Finish1
		jmp	short Divid_1
Finish1:
		mov	al,0fch 	;stop counter 2
		out	61h,al
		SIODELAY
		in	al,PORT8254	;read counter 2 low byte
		IODELAY
		mov	ah,al
		in	al,PORT8254	;read counter 2 high byte
		IODELAY
		xchg	ah,al
		mov	cx,ax
		sub	cx,si		;result 2 - result 1

		ret
XMeasureNoRDTSCCpuClck	endp

ENDIF	;COMPILE_FOR_E0

IFE     COMPILE_FOR_E0

		extrn	F000_call_proc:near
		extrn	Ct_MemHole_Status:Near
		extrn	F000_Shadow_W:Near
		extrn	F000_Shadow_R:Near
		extrn	Skip_K6_Write_Allocate:Near

		extrn	F000_GetItem_Value:near

		extrn	F000_Display_Char:Near
		extrn	F000_Display_String:Near

		extrn	DISPLAY_CS_STRING:Near
		extrn	SYSCFG_CPU_CLOCK1:Near

		extrn	fProc_Disp_Word_Int3:far
		extrn	fProc_Disp_Byte_Int2:far
		extrn	X_Display_Char:near
		extrn	X_Display_CS_String:near

		extrn	X_GetItem_Value:near
		extrn	M2CpuID_Item:near
		extrn	UNLock_Cyrix:near
		extrn	Lock_Cyrix:near
		extrn	Get_Cyrix:near
		extrn	Set_Cyrix:near

.LIST
EGROUP		GROUP	ECODE
ECODE		SEGMENT USE16 PARA PUBLIC 'ECODE'
		ASSUME	CS:EGROUP,DS:G_RAM,ES:EGROUP

;Function : return cache size in AL for display
;Input    : DL - CPU register value to indicate cache size
;		 40H - No L2 cache
;		 41H - 128K
;		 42H - 256K
;		 43H - 512K
;		 44H - 1Mb
;		 45H - 2Mb
;Output   : AL - cache size for BIOS to display
;           AL -  0 = 0K, 1=16K , 2=32K , 3=64K , 4=128K , 5=256K
;	          6 =512K, 7=1024K ,etc...
		Public	Convert_P6L2_Cache
Convert_P6L2_Cache	proc	near
		ret
Convert_P6L2_Cache	endp

;=============================================================================
;FUNC:	CPU_DISPLAY
;
;DESC:	Returns the length and description string for the CPU.
;
;IN:	NONE
;OUT:	CS:SI	String pointer
;
;SAVES:	DX
;=============================================================================
		PUBLIC	CPU_DISPLAY
CPU_DISPLAY	PROC	Near

		mov	al,FIXED_DISK_STEP[bp]
		and	al,CPU_TYPE_MASK

		cmp	al,NUM_OF_CPU_TYPE
		mov	si,offset Unknown_Str
		ja	@F
		movzx	si,al
		mov	si,word ptr cs:CPU_TYPE_STRS[si]
	@@:

 ifndef	K7_CPU_SUPPORT

		cmp	si,offset Cpu_P6_Str	;is P6 CPU ?
		jne	Not_P6Cpu

Not_P6Cpu:

 endif;	K7_CPU_SUPPORT

Cpu_Str_Ok:

	;display IDT/C6 string instead of Pentium if it is C6
		cmp	si,offset Cpu_586_Str	;assume Pentium CPU
		jne	Not_IdtC6

		call	Check_RiseCpu		;is Rise mP6 CPU ?
		jne	NotRiseCpu
;R01		mov	si,offset RiseMp6_Str	;display mP6 instead of Pentium

		call	Read_CpuID		;read CPUID
		and	al, 0F0H		;get model
;R01 - start
	;"Family 6" for 06xx CPUID
		cmp	ah, 06H			;Rise family 6 CPU(06xx) ?
		jne	short NotFamily6	;no

		mov	si, offset RiseFM6_Str	;display family 6 CPU name
		jmp	short GoCpuDisaplay

	NotFamily6:
	;"mP6(tm)" for 050x & 051x CPU
		mov	si,offset RiseMp6_Str	;display mP6 instead of Pentium
		cmp	al, 00H			;050x ?
		je	short GoCpuDisaplay
		cmp	al, 10H			;051x ?
		je	short GoCpuDisaplay

	;"mP6(tm) II" for 0580x
		mov	si,offset RiseMp6_2_Str	;display "mP6 II"
		cmp	al, 080H		;MP6-II(058x)	?
		je	short GoCpuDisaplay

	;"Family 5" for others CPUID
		mov	si, offset RiseFM5_Str	;display family 5 CPU name
		jmp	short GoCpuDisaplay

;R01 - end
;R01		cmp	al, 080H		;MP6-II	?
;R01		jne	short NotRiseCpu	;Not mP6-II
;R01		mov	si,offset RiseMp6_2_Str	;display "mP6 II"

NotRiseCpu:

		call	Check_IdtCpu		;is IDT C6 CPU ?
		jne	Not_IdtC6
		mov	si,offset IdtC6_Str	;display C6 instead of Pentium
		jmp	GoCpuDisaplay
Not_IdtC6:
		call	Check_Tillamook
		jne	Not_Tillamook
		mov	si,offset Tillamook_Str
		jmp	GoCpuDisaplay
Not_Tillamook:

	;if CPU type is AMD K6, then return with K6 string

		call	Check_K6_CPU		;K6 ?
		jne	Is_Not_K6		;no !

		call	TreatK6String

		jmp	GoCpuDisaplay

	Is_Not_K6:

		call	Check_M1_Cpu 		;check if 6x86 CPU
		jne	Not_Cy6x86Cpu

		mov	al,0feH			;DIR0 register
		out	22h,al
		in	al,23h			;read DIR0 value

		cmp	al,50h
		jb	Not_Cy6x86Cpu
		cmp	al,5fH
		ja	Not_Cy6x86Cpu

		call	M2CpuIDCntl	;CPUID instruction control

		mov	si,offset Cpu_M2_Str
   		call	Check_MII_Cpu
		jc	Not_Cy6x86Cpu
		mov	si,offset Cpu_MII_Str

Not_Cy6x86Cpu:

GoCpuDisaplay:
		ret

CPU_DISPLAY	ENDP

;Function : Disable CPUID instruction of M2 CPU if user select it in
;	    CMOS setup. Disable CPUID of M2 cause some game softwares
;	    can not use MMX instruction, but CPUID enabled cause
;	    Netware 5.0 installation failure.
;Input    : none
;Output   : none
M2CpuIDCntl	proc	near
		pushad
		mov	si, offset DGROUP:M2CpuID_Item
		call	F000_GetItem_Value	;get CMOS value
		mov	bl, 80H			;CPUID enabled
		or	al, al
		jz	short M2CpuIDEnabled
		xor	bl, bl			;disable CPUID
	M2CpuIDEnabled:

	;Enable/Disable CPUID of M2 CPU
		F000_CALL UNLock_Cyrix 		;unlock Cyrix register
		mov	cl, 0E8H
		F000_CALL  Get_Cyrix
		and	al, NOT 80H		;disable CPUID for M2
		or	al, bl
		F000_CALL Set_Cyrix
		F000_CALL Lock_Cyrix 		;lock Cyrix register
		popad

		ret
M2CpuIDCntl	endp

Check_Tillamook	Proc	Near

		cmp	byte ptr CPU_BRAND[bp], CPU_BRAND_INTEL
		jne	@F

		pushad
		mov	eax,1
		db	0Fh,0A2h
		and	al,0f0h
		cmp	al,80h
		popad
	@@:
		ret

Check_Tillamook	Endp

;Function: Check if IDT/C6 CPU plugged
;Input   : none
;Output  : zero set - it's IDT-C6 CPU
;	  non-zero - not C6 CPU
		public	fPROC_Check_IdtCpu
fPROC_Check_IdtCpu	PROC	FAR
		call	Check_IdtCpu
		ret
fPROC_Check_IdtCpu	ENDP
		public	Check_IdtCpu
Check_IdtCpu	proc	near

		cmp	byte ptr CPU_BRAND[bp], CPU_BRAND_INTEL
		jne	@F

		pushad
		xor	eax,eax			;get vendor ID string
		db	0Fh,0A2h		;OP code: CPUID
		cmp	ebx,746e6543h		;C6 vendor ID string match ?
		popad
	@@:
		ret
Check_IdtCpu	endp

;Function: Check if Rise/mP6 CPU plugged
;Input   : none
;Output  : zero set - it's Rise/mP6 CPU
;	  non-zero - not Rise/mP6
		public	fPROC_Check_RiseCpu
fPROC_Check_RiseCpu	PROC	FAR
		call	Check_RiseCpu
		ret
fPROC_Check_RiseCpu	ENDP
		public	Check_RiseCpu
Check_RiseCpu	proc	near

		cmp	byte ptr CPU_BRAND[bp], CPU_BRAND_INTEL
		jne	@F

		pushad
		xor	eax,eax			;get vendor ID string
		db	0Fh,0A2h		;OP code: CPUID
		cmp	ebx,65736952h		;mP6 vendor ID string match ?
		popad
	@@:
		ret
Check_RiseCpu	endp

CPU_TYPE_STRS:
		dw	offset cpu_386dx_str
		dw	offset cpu_386sx_str
		dw	offset cpu_386sl_str
		dw	offset cpu_486dx_str
		dw	offset cpu_486sx_str
		dw	offset cpu_486sx2_str
		dw	offset cpu_Cx486slc_str
		dw	offset cpu_Cx486dlc_str
		dw	offset cpu_ibm386slc_str
		dw	offset cpu_ibm486slc2_str
		dw	offset Cpu_P24t_str
		dw	offset Cpu_486s_Str
		dw	offset Cpu_486s2_Str
		dw	offset Cpu_586_Str
		dw	offset Cpu_486dxS_Str
		dw	offset Cpu_486sxS_Str
		dw	offset Cpu_486dx2S_Str
		dw	offset cpu_ibm486dlc3_str
		dw	offset Cpu_M7_Str
		dw	offset Cpu_M7_2_Str
		dw	offset Cpu_Cx486slc2_Str
		dw	offset Cpu_P24c_Str
		dw	offset Cpu_TI486SXL_Str
		dw	offset Cpu_TI486SXL2_Str
		dw	offset Cpu_U5_Str
		dw	offset Cpu_AMD486_Str
		dw	offset Cpu_P54c_Str
		dw	offset Cpu_TI486SXLC_Str
		dw	offset Cpu_TI486SXLC2_Str
		dw	offset Cpu_AMD486DX2_Str
		dw	offset Cpu_P24D_Str
		dw	offset Cpu_AMD486DX4_Str
		dw	offset Cpu_M1_Str
		dw	offset Cpu_AMD486Plus_Str
		dw	offset Cpu_AMD486DX4Plus_Str
		dw	offset Cpu_U486sx2_Str
		dw	offset Cpu_U486DX_Str
		dw	offset Cpu_U486DX2_Str
		dw	offset Cpu_M9_Str
		dw	offset Cpu_Cyrix_Dx4_Str
		dw	offset Cpu_P6_Str
		dw	offset Cpu_AmdDX5_Str
		dw	offset Cpu_AmdD5K86_Str
		dw	offset Cpu_CyrixGXm_Str
NUM_OF_CPU_TYPE	EQU	($ - offset CPU_TYPE_STRS)

;-------------------------- 386 CPU Strings --------------------------

	cpu_386dx_str:
	cpu_386sx_str:
	cpu_386sl_str:
	Cpu_Cx486slc2_Str:
	cpu_Cx486slc_str:
	cpu_Cx486dlc_str:	db	0

;-------------------------- 486 CPU Strings --------------------------

	Cpu_AmdDX5_Str:
	cpu_486dx_str:
	cpu_486sx_str:
	cpu_487sx_str:
	cpu_486sx2_str:
	cpu_486dx2_str:
	Cpu_P24t_str:
	Cpu_P24c_Str:
	Cpu_P24D_Str:
	Cpu_AMD486Plus_Str:
	Cpu_AMD486DX4Plus_Str:
	Cpu_U486sx2_Str:
	Cpu_U486DX_Str:
	Cpu_U486DX2_Str:
	Cpu_M9_Str:
	TI_486dx2_str:
	Cpu_Cyrix_Dx4_Str:
	Cpu_486s_Str:
	Cpu_486s2_Str:
	Cpu_M7_Str:
	Cpu_M7_2_Str:
	Cpu_AMD486_Str:
	Cpu_U5_Str:
	Cpu_AMD486DX2_Str:
	Cpu_AMD486DX4_Str:	db	0

;-------------------------- 586 CPU Strings --------------------------

	Cpu_586_Str:		db	"PENTIUM",0
	Cpu_P54c_Str:

		Public	Cpu_AmdK6_3D_Str
ifndef	CPU_Support_MXi
	Cpu_M1_Str:		db	"6x86",0
else	;CPU_Support_MXi
	Cpu_M1_Str:		db	"Cyrix MXi",0
endif	;CPU_Support_MXi
	Cpu_AmdD5K86_Str:	db	"AMD-K5",0
	Cpu_AmdK6_Str:		db	"AMD-K6(tm)",0

	Cpu_AmdK6_3D_Str:	db	"AMD-K6(tm)-2",0

	Cpu_AmdK6_3_Str:	db	"AMD-K6(tm)-III",0

	IdtC6_Str:		db	"IDT WinChip ",0
	Tillamook_Str		db	"Tillamook",0
	RiseMP6_Str:		db	"Rise mP6(tm)",0
	RiseMP6_2_Str:		db	"Rise mP6(tm) II",0
	RiseFM5_Str:		db	"Rise Family 5",0	;R01
	RiseFM6_Str:		db	"Rise Family 6",0	;R01

	Cpu_M2_Str:		db	"6x86MX",0

ifdef	Show_IBM_Only
	Cpu_MII_Str		db	"IBM 6x86MX",0
else	;Show_IBM_Only
	Cpu_MII_Str		db	"Cyrix M II/IBM 6x86MX",0
endif	;Show_IBM_Only

	Cpu_CyrixGXm_Str	db	"Cyrix MediaGX With MMX",0

;-------------------------- 686 CPU Strings --------------------------

	Cpu_P6_Str:		db	0

;-------------------------- IBM CPU Strings --------------------------

	cpu_ibm386slc_str:
	cpu_ibm486slc2_str:
	cpu_ibm486dlc3_str:	db	0

;-------------------------- TI CPU Strings --------------------------

	Cpu_TI486SXL_Str:
	Cpu_TI486SXL2_Str:
	Cpu_TI486SXLC_Str:
	Cpu_TI486SXLC2_Str:	db	0

;---------------------- Dummy/Unknown CPU Strings -------------------

	unknown_str:		db	"Unknown"
	Cpu_486dxS_Str:
	Cpu_486sxS_Str:
	Cpu_486dx2S_Str:
				db	0

;[]=================================================================[]
;Procedure   :	Disp_Extra_CPU_Info
;Input	     :	None
;Ouput	     :	None
;Description :	If CPU Type:
;
;		. PENTIUM PRO & PENTIUM
;
;		   IF   ODP CPU show 'ODP-S' on screen
;		   IF   MMX CPU show 'MMX' on screen
;		   IF   ODP-MMX CPU show 'ODP-MMX' on screen
;		   ELSE show '-S' on screen to indicate SMI
;
;		. Cyrix 6x86L CPU
;
;		  Append a 'L' to '6x86'
;
;		. Other CPUs
;
;		  show '-S' on screen to indicate SMI
;
;[]=================================================================[]
		public	Disp_Extra_CPU_Info
Disp_Extra_CPU_Info	Proc	Near

		call	Check_IdtCpu		;is IDT CPU ?
		jne	NotIdtWinChip		;no !

		mov	eax,1			;eax = 1 to read CPU ID
		db	0fh,0A2h		;CPU ID instruction
		and	al,0f0h			;mask stepping bits b3-b0

		mov	si, offset _3_Str	;"IDT WinChip 3" for stepping
		cmp	al, 90h
		je	@F			;yes show it

		mov	si, offset _2_Str	;"IDT WinChip 2" for stepping
		cmp	al, 80h			;0580h
		je	@F			;yes show it
		mov	si, offset _C6_Str	;Else "IDT WinChip C6"
	@@:
		call	Display_CS_String

NotIdtWinChip:

;---------------------------------------------------------------
; Display CPU type as "6x86L" if the revision number is 20h-2fh,
; regular 6x86 is 00h-1fh
;---------------------------------------------------------------

		call	Check_M1_Cpu 		;check if 6x86 CPU
		jne	Not_6x86Cpu

		mov	al,0ffH			;DIR1 register
		out	22h,al
		in	al,23h			;read DIR1 value

		cmp	al,20H			;6x86L ?

		jb	Not_6x86CpuL

		mov	al,"L"
		call	F000_Display_Char

Not_6x86CpuL:

Not_6x86Cpu:

;---------------------------------------------------------------
; Show -MMX & -ODP for all 586 or above CPU
;---------------------------------------------------------------

		cmp	byte ptr CPU_BRAND[bp], CPU_BRAND_INTEL
		jne	No_ODP_MMX

		call	Check_IdtCpu		;is IDT C6 CPU ?
		je	Disp_S_CPU_Exit	;yes,no MMX display

		call	Check_RiseCpu		;is Rise/mP6 CPU ?
		je	Disp_S_CPU_Exit	;yes,no MMX display

		call	Read_CpuID		;read CPU ID
		and	ah,0f0H			;get CPU type
		cmp	ah,010H			;override drive processor
		jne	Not_Odp

		mov	si,offset Odp_String	;ODP string
		call	Display_CS_String

	Not_Odp:
		cmp	al,06ah
		je	No_ODP_MMX

		shr	edx,16
		test	dl,80H			;With MMX ? (bit23 = 1 ?)
		jz	No_ODP_MMX	;no MMX

		mov	si, offset Dash_MMX_String	;'-MMX' string
		call	Display_CS_String

		jmp	Disp_S_CPU_Exit	;skip "-S" display

No_ODP_MMX:
;-------------------------------------------------------
;Try to skip '-S' for all AMD & Cyrix 586 level CPU
;-------------------------------------------------------

		call	Check_K586_Cpu 		;check if AMD 5k86 CPU
		je	Disp_S_CPU_Exit	;skip "-S" display
		call	Check_M1_Cpu 		;check if 6x86 CPU
		je	Disp_S_CPU_Exit	;skip "-S" display

;-------------------------------------------------------
; This is for special customer
; If the CPU is Cyrix then don't show S-serial
;-------------------------------------------------------

;-------------------------------------------------------
; Display '-S' on screen
;-------------------------------------------------------
ifdef	PM_SUPPORT
		test	byte ptr OVERRIDE[BP],(SMICPU shr 8)
		jz	No_S
		mov	al,"-"
		call	F000_Display_Char
		mov	al,"S"
		call	F000_Display_Char
No_S:
endif	;PM_SUPPORT

Disp_S_CPU_Exit:

		ret

Disp_Extra_CPU_Info	Endp

_2_Str		db	'2', 0
_3_Str		db	'3', 0
_C6_Str		db	'C6', 0

;Function : Read CPU ID
;Input    : none
;Output   : EAX - CPU ID information
;	    EDX - CPU features
		Public	fPROC_Read_CpuID
fPROC_Read_CpuID	PROC	FAR
		call	Read_CpuID
		ret
fPROC_Read_CpuID	ENDP
		Public	Read_CpuID
Read_CpuID	proc	near
		push	ebx
		mov	eax,1			;read cache isze
		db	0Fh,0A2h		;OP code: CPUID
		pop	ebx
		ret
Read_CpuID	endp

Odp_String		db	' ODP',0
Dash_MMX_String		db	'-MMX',0
MMX_String		db	' MMX',0

;[]--------------------------------[]
;Input	:	None
;Ouput	:	ZF - Cyrix M2
;		NZ - not Cyrix M2
;[]--------------------------------[]
		public	fPROC_Check_M2Cpu
fPROC_Check_M2Cpu	PROC	FAR
		call	Check_M2Cpu
		ret
fPROC_Check_M2Cpu	ENDP
		public	Check_M2Cpu
Check_M2Cpu	proc	near
		push	ax
		mov	al,0feH			;DIR1 register
		out	22h,al
		in	al,23h			;read DIR1 value
		cmp	al,51h
		jb	Not_M2Cpu
		cmp	al,5fh
		ja	Not_M2Cpu
		xor	al,al			;return zero flag
Not_M2Cpu:
		pop	ax
		ret
Check_M2Cpu	endp

;--------------------------------------------------------------------
;Output : CF = 0  - Cyrix MII CPU
;	  CF = 1  - Not Cyrix MII CPU
;--------------------------------------------------------------------
		Public	fPROC_Check_MII_CPU
fPROC_Check_MII_CPU	PROC	FAR
		call	Check_MII_CPU
		ret
fPROC_Check_MII_CPU	ENDP
		Public	Check_MII_CPU
Check_MII_CPU	proc	near

		call	Check_M2Cpu
		jne	Not_Cyrix_MII

		mov	al, 0FFh		;DIR1 register
		out	22h, al
		in	al, 23h			;read DIR1 value
		cmp	al,08h			; 08h or greater is MII
		jb	Not_Cyrix_MII	; No

		clc
		ret
Not_Cyrix_MII:

		stc
		ret

Check_MII_CPU	endp

;[]--------------------------------[]
;Input	:	None
;Ouput	:	ZF - Cyrix 6x86
;		NZ - not Cyrix 6x86
;[]--------------------------------[]

		public	fPROC_Check_M1_Cpu
fPROC_Check_M1_Cpu	PROC	FAR
		call	Check_M1_Cpu
		ret
fPROC_Check_M1_Cpu	ENDP
		public	Check_M1_Cpu
Check_M1_Cpu	proc	near
		push	bx
		mov	bh,byte ptr FIXED_DISK_STEP[bp]
		and	bh,CPU_TYPE_MASK
		cmp	bh,TYPE_M1
		pop	bx
		ret
Check_M1_Cpu	endp

;[]--------------------------------[]
;Input	:	None
;Ouput	:	ZF - K5 or K6
;		NZ - not K5, not K6
;[]--------------------------------[]

		public	fPROC_Check_K586_Cpu
fPROC_Check_K586_Cpu	PROC	FAR
		call	Check_K586_Cpu
		ret
fPROC_Check_K586_Cpu	ENDP
		Public	Check_K586_Cpu
Check_K586_Cpu	proc	near
		push	bx
		mov	bh,byte ptr FIXED_DISK_STEP[bp]
		and	bh,CPU_TYPE_MASK
		cmp	bh,TYPE_AMD5K86
		pop	bx
		ret
Check_K586_Cpu	endp

;[]-------------------------[]
;Input	:	None
;Ouput	:	ZF - K6
;		NZ - not K6
;[]-------------------------[]
		public	fPROC_Check_K6_Cpu
fPROC_Check_K6_Cpu	PROC	FAR
		call	Check_K6_Cpu
		ret
fPROC_Check_K6_Cpu	ENDP
		Public	Check_K6_CPU
Check_K6_CPU	Proc	Near
		cmp	byte ptr CPU_LEVEL[bp], LEVEL_586
		jne	@F
		cmp	byte ptr CPU_BRAND[bp], CPU_BRAND_AMD
		jne	@F

		pushad
		call	Read_CpuID		;read CPU ID
		and	al, 0F0h
		cmp	ax, 0590h		;new K6
		je	Yes_NewK6
		cmp	ax, 0580h		;new K6
		je	Yes_NewK6
		cmp	ax, 0570h		;new K6
		je	Yes_NewK6
		cmp	ax, 0560h		;K6 ?
Yes_NewK6:
		popad
	@@:
		ret
Check_K6_CPU	Endp

;[]------------------------------------------------------[]
;Function: Return proper CPU string for K6 series CPU
;Input	 : None
;Output  : SI - offset of CPU string to display
;Note    : "AMD-K6(tm)/xxx"   for 056x & 057x
;	   "AMD-K6(tm)-2/xxx" for 058x
;	   "AMD-K6(tm)-3/xxx" for 059x
;[]------------------------------------------------------[]
TreatK6String	proc	near

		push	eax

		call	Read_CpuID			;read CPU ID
		and	al, 0F0h

		mov	si, offset Cpu_AmdK6_3_Str	;"AMD-K6-3" for 059x
		cmp	al, 090H			;model 9 ?
		je	K6Str_Ok

		mov	si, offset Cpu_AmdK6_3D_Str	;"AMD-K6-2" for 058x
		cmp	al, 080H			;model 8 ?
		je	K6Str_Ok

		mov	si, offset Cpu_AmdK6_Str	;"AMD-K6" for 056x
							;and 057x
K6Str_Ok:
		pop	eax

		ret
TreatK6String	endp

Check_3D_feature	Proc	Near
		mov	eax,80000001h		;extended function
		db	0Fh,0A2h		;read CPUID
		and	edx,80000000h		;bit31=1 for 3D feature
		cmp	edx,80000000h
		ret
Check_3D_feature	Endp

;[]=================================================================[]
;Input	:	DI = 1 --> show P-Rating with '-'
;		DI = 0 --> show P-Rating without '-'
;
;Output	:	NC - Show P-Rating successfully
;		CF - Show P-Rating not successful
;[]=================================================================[]
		Public	Try_Show_PRating
Try_Show_PRating	Proc	Near

		stc		;defaut no show P-Rating

ifndef	NO_PRATING_DISPLAY
		call	fPROC_Try_Show_PRating
endif	;NO_PRATING_DISPLAY

		ret
Try_Show_PRating	Endp

;[]========================================================================[]
;Name	  :	Prg_K6_Write_Allocate
;
;Function :	To enable the AMD K6 CPU's write allocation function
;
;Input	  :	dword ptr EXT_MEM_SIZE[bp] in terms of 1K
;
;Output	  :	None
;[]========================================================================[]
		Public	Prg_K6_Write_Allocate
Prg_K6_Write_Allocate	Proc	Near

		pushad

		call	Prg_C6_Write_Combine

ifndef	Disable_K6_Write_Allocate
		call	Check_K6_CPU			;K6 ?
		jne	No_K6_Write_Alloc		;no !

	;-------------------------------------------------------------------
	; This write allocation must be disabled in early stage of warm boot
	; replaced the "jmp short Not_K6" instruction will with 2 NOPs
	;
	;Skip_K6_Write_Allocate	Label	Near
	;
	;	jmp	Not_K6
	;	mov	ecx, 0c0000082h
	;	RDMSR
	;	and	ax, not 1FFh
	;	WRMSR
	;
	;Not_K6:
	;-------------------------------------------------------------------

		push	ds
		F000_call F000_Shadow_W
		mov	ax, DGROUP
		mov	ds, ax
		mov	si, offset DGROUP:Skip_K6_Write_Allocate
		mov	ds:[si], 9090h
		F000_call F000_Shadow_R
		pop	ds

	;----------------------------------------------------------
	;MSR 85h b15-b0 : Top of memory address
	;	 b16    : Fixed Range Enable, i.e. from A0000-FFFFF
	;	 b17    : Programmable Range Enable
	;	 b18    : Top-Of-Memory Enable
	;----------------------------------------------------------

		F000_call Ct_MemHole_Status	;get hole status in AX
		mov	si, ax			;temporary save to SI

		mov	ecx, EXT_MEM_SIZE[bp]
		add	ecx, 1024		;add 1M of base memory
		shr	ecx, 11			;convert to 4M byte unit
		mov	al, cl

		and	al, not 01h		;15-16 disabled
		cmp	al, 08h			;memory >= 16M ?
		jb	@F		;< 16M !
		or	si, si			;memory hole enabled ?
		jnz	@F		;enabled !
		or	al, 01h			;15-16 enabled
	@@:

ifdef	Disable_K6_WCDE
		and	ah, NOT 01h   		;disable write cacheability
endif	;Disable_K6_WCDE			;detection

;----------------------------------------------------
;
; To check if K6-2 model 8 or later. If yes, translate
; the Write Allocate information to the format of
; K6-2 model 8(& later)
;
; Model 8 & later
; ---------------
; B31-22: Write Allocate Limit(maximum 4G in terms of 4M)
; B16   : Write Allocate enable/disable for 15M-16M
;
; Model 7 & before
; ----------------
; B7-1  : Write Allocate Limit(maximum 512M in terms of 4M)
; B0    : Write Allocate enable/disable for 15M-16M
;
;----------------------------------------------------
		push	eax			;save the Write Alloc. Info
		call	Read_CpuID		;read CPU ID
		cmp	ax, 0588h		;K6-2 model 8 or later?
		pop	eax			;restore the Write Alloc. Info
		jb	EndK62Model8		;No, skip !

		mov	cl, al			;save the 15M-16M status
		shl	eax, 21			;B31-22: Write Allocate Limit
						;	 for model 8 & later
						;B7-1  : Write Allocate Limit
						;	 for model 7 & before
		and	eax, 0FFC00000h
		test	cl, 01h			;15M-16M Write Alloc. enabled?
		jz	EndK62Model8		;no !

		or	eax, 00010000h		;enable 15-16M Write Allocate

	EndK62Model8:

		mov	ecx, 0C0000082h
		WRMSR

No_K6_Write_Alloc:
endif	;Disable_K6_Write_Allocate

		popad

		ret

Prg_K6_Write_Allocate	Endp

McrbaseNo	equ	110h
MCRcontrol      equ     120h
Mcrvalue	equ	01F0000FH
BcrNo		equ	145H
TLOCKBit	equ	3

;0-512k
BaseAddr0	equ	0

Mask_512K	equ	0fff80000h

;512-640k
Base_512K	equ	000080000h

Mask_640K	equ	0fffe0000h

;1M - 2M
Base_1		equ	000100000h

Mask_2		equ	0fff00000h

;2M - 4M
Base_2		equ	000200000h

Mask_4		equ	0ffe00000h

;4M-8M
Base_4		equ	000400000h

Mask_8		equ	0ffc00000h

;8M - 16M
Base_8		equ	000800000h

Mask_16		equ	0ff800000h
Mask_12		equ	0ffc00000h

;16M - 32M
Base_16		equ	001000000h

Mask_32		equ	0ff000000h

;32M - 64M
Base_32		equ	002000000h

Mask_64		equ	0fe000000h

;64M - 128M
Base_64		equ	004000000h

Mask_128	equ	0fc000000h

;128M - 256M
Base_128	equ	008000000h

Mask_256	equ	0f8000000h

;256M - 512M
Base_256	equ	010000000h

Mask_512	equ	0f0000000h

;512M - 1024M
Base_512	equ	020000000h

Mask_1024	equ	0e0000000h

;1G- 2G
Base_1024	equ	040000000h

Mask_2048	equ	0c0000000h

;2G- 4G
Base_2048	equ	080000000h

Mask_4096	equ	080000000h

;Programming table for memory range registers
IDt_McrTable	label	dword
		dd	Base_2048
		dd	Mask_4096

		dd	Base_1024
		dd	Mask_2048

		dd	Base_512
		dd	Mask_1024

		dd	Base_256
		dd	Mask_512

		dd	Base_128
		dd	Mask_256

		dd	Base_64
		dd	Mask_128

		dd	Base_32
		dd	Mask_64

		dd	Base_16
		dd	Mask_32

		dd	Base_8
		dd	Mask_16

		dd	Base_4
		dd	Mask_8

		dd	Base_2
		dd	Mask_4

		dd	Base_1
		dd	Mask_2

		dd	Base_512K
		dd	Mask_640K

		dd	-1		;end of table

;[]========================================================================[]
;Name	  :	Prg_C6_Write_Combine
;
;Function :	To enable the IDT C6 CPU's write combing function
;
;Input	  :	dword ptr EXT_MEM_SIZE[bp] in terms of 1K
;
;Output	  :	None
;[]========================================================================[]
		Public	Prg_C6_Write_Combine
Prg_C6_Write_Combine	Proc	Near

		pushad

		call	Check_IdtCpu		;is IDT C6 CPU ?
		jne	NoC6WCombine

; NAS    check to see if WC C6 or WC 2
; Assume WinChip C6
                mov     ebx, 11100000000b

      		mov	eax,0c0000000h		;special IDT function
		db	0fh,0a2h		;CPUID

      		cmp	eax,0c0000000h		;special IDT function

                je	checkhole

; here if WinChip 2
; For WC2, traits include weak read ordering, byte combining
                mov     ebx, 1000100000001b
checkhole:

		mov	edi, EXT_MEM_SIZE[bp]	;get extended mem. in 1Kb unit
		shr	edi, 10			;convert to 1Mb unit
		inc	edi

                F000_call Ct_MemHole_Status
                movzx   ebp, al

	;always set up 0-512Kb region
		mov	ecx,MCRbaseNo
		mov	edx,BaseAddr0
		mov	eax,Mask_512K
                or      al, bh                  ; put in local traits
		WRMSR

		mov	si,offset Idt_McrTable
		mov	ecx,4096
RangeComp:
		cmp	edi,ecx
		jae	Prog_Mcrs
		add	si,8
		shr	ecx,1
		jnz	RangeComp
		jmp	NoC6WCombine
Prog_Mcrs:
		mov	ecx,McrbaseNo+1
Prog_One_Mcr:
		mov	edx,cs:dword ptr [si]
		cmp	edx,-1			;last table ?
		je	Mcr_Done

		mov	eax,cs:dword ptr [si+4]
		cmp	edx,Base_8
		jne	Around_hole_chk

		or	bp,bp
		jz	Around_hole_chk
		mov	eax,Mask_12

Around_hole_chk:
                or	al, bh
		WRMSR
		add	si,8
		inc	ecx
		cmp	ecx,McrbaseNo+8
		jb	Prog_One_Mcr

Mcr_Done:
	;set up MCR_CTRL

                mov	edx, 0			; no trait mode control for c2c
                mov	ecx, MCRcontrol
                test	bl, bl			; check for c3x
                jz	c2cwc		; if c2c

        ; if WinChip 2, need to get trait mode control bits
                RDMSR				; bits 19:17 trait mode control
                and	eax, 111b shl 17	; isolate these bits
                shr	eax, 11			; move them to 8:6
                mov	edx, eax		; save the isolated bits

c2cwc:

		mov	eax,McrValue
                or	eax,edx
		xor	edx,edx
		WRMSR

		mov	ecx,BCRNo
		RDMSR
		or	al,1 SHL TLOCKbit
		WRMSR

NoC6WCombine:

		popad

		ret

Prg_C6_Write_Combine	endp

;Function : Program USWC for P6-class CPU according user's CMOS select
;Input    : none
;Output   : none
		public	Prg_P6_USWC
Prg_P6_USWC	proc	near
		ret
Prg_P6_USWC	endp

ECODE		ENDS

XGROUP		GROUP	XCODE
XCODE		SEGMENT USE16 PARA PUBLIC 'XCODE'
		ASSUME	CS:XGROUP, ES:XGROUP

ifndef	NO_PRATING_DISPLAY
Get_Host_Freq_In_AL_High_Nibble	PROC	NEAR

		push	ds
		push	si

		push	SEG G_RAM
		pop	ds
		mov	si, offset CPU_CLOCK
		mov 	al, ds:[si]
		and	al, 11110000b

		pop	si
		pop	ds
		ret

Get_Host_Freq_In_AL_High_Nibble	ENDP

Show_PRating_Using_AX	PROC	NEAR

		push	word ptr CPU_INT_CLOCK[bp]
		mov	CPU_INT_CLOCK[bp], ax
		call	Show_PRating
		pop	word ptr CPU_INT_CLOCK[bp]
		ret

Show_PRating_Using_AX	ENDP

;[]=========================================================[]
;Input	:	None
;Output	:	CY = PR Rating not successfully shown
;		NC = PR Rating successfully shown
;[]=========================================================[]
fPROC_Try_Show_PRating	PROC	FAR

		call	Show_IDT_PRating
		jnc	END_Try_Show_PRating	;IDT already shown

		call	Show_Cyrix_PRating
		jz	END_Try_Show_PRating	;Cyrix already shown

		call	Show_K6_PRating
		jnc	END_Try_Show_PRating	;K6 already shown

		call	Show_K5_PRating
		jz	END_Try_Show_PRating	;K5 already shown

		call	Show_Rise_PRating
		jz	END_Try_Show_PRating	;Rise already shown

		stc

	END_Try_Show_PRating:

		ret

fPROC_Try_Show_PRating	ENDP

;[]=========================================================[]
;Input	:	None
;Output	:	CY = Not IDT WinChip 2A nor WinChip 3
;		NC = PR Rating successfully shown
;[]=========================================================[]
Show_IDT_PRating	PROC	NEAR

	;--------------------------------------------------------
	;Display P-rating if IDT WhiChip 2A or WinChip 3 plugged
	;--------------------------------------------------------

		call	fPROC_Check_IdtCpu	;is IDT C6 CPU ?
		jne	Not_WinChip_PRating

		mov	eax, 1			;eax = 1 to read CPU ID
		db	0fh, 0A2h		;CPU ID instruction
		cmp	al, 87h
		jb	Not_WinChip_PRating
		mov	si, offset WinChip2A_PRat_Tbl
		call	fPROC_If_WinChip2A
		je	@F
		mov	si, offset WinChip3_PRat_Tbl
	@@:
		call	WinChip2A_Clock_Multiplier_In_AH
		call	Get_Host_Freq_In_AL_High_Nibble
		xor	bl, bl			;Do not show string "PR"
		call	Show_PRating_Using_AX
		jnc	@F
		mov	si, 0FFFFh		;use CPU_INT_CLOCK[bp]
		call	Show_PRating		;show P-rating
	@@:
		clc
		ret

	Not_WinChip_PRating:

		stc
		ret

Show_IDT_PRating	ENDP

WinChip2A_PRat_Tbl:
		;------------------------------------------
		;      Ratio + Clock	, P-Rating
		;------------------------------------------
		dw     (WINCHIP_3_00X shl 8)+CPU66 , 200	;3.0x66
 		dw     (WINCHIP_2_00X shl 8)+CPU100, 233	;2.0x100
		dw     (WINCHIP_2_00X shl 8)+CPU100, 233	;2.0x100
		dw     (WINCHIP_2_50X shl 8)+CPU83 , 233	;2.5x83
		dw     (WINCHIP_3_50X shl 8)+CPU66 , 233	;3.5x66
		dw     (WINCHIP_2_33X shl 8)+CPU100, 266	;2.33x100
		dw     (WINCHIP_3_00X shl 8)+CPU83 , 266	;3x83
		dw     (WINCHIP_2_50X shl 8)+CPU100, 300	;2.5x100
		dw     (WINCHIP_4_00X shl 8)+CPU66 , 266	;4x66
		dw     (WINCHIP_2_66X shl 8)+CPU100, 300	;2.66x100
		dw	0

WinChip3_PRat_Tbl:

		;------------------------------------------
		;      Ratio + Clock	, P-Rating
		;------------------------------------------

		dw     (WINCHIP_3_00X shl 8)+CPU66 , 233	;3.00x66
		dw     (WINCHIP_3_50X shl 8)+CPU66 , 266	;3.50x66
		dw     (WINCHIP_2_33X shl 8)+CPU100, 300	;2.33x100
		dw     (WINCHIP_4_00X shl 8)+CPU66 , 300	;4.00x66
		dw     (WINCHIP_2_66X shl 8)+CPU100, 333	;2.66x100
		dw     (WINCHIP_3_00X shl 8)+CPU95 , 350	;3.00x95
		dw     (WINCHIP_4_50X shl 8)+CPU66 , 333	;4.50x66
		dw     (WINCHIP_3_00X shl 8)+CPU100, 366	;3.00x100
		dw     (WINCHIP_3_33X shl 8)+CPU95 , 380	;3.33x95
		dw     (WINCHIP_5_00X shl 8)+CPU66 , 366	;5.00x66
		dw     (WINCHIP_3_33X shl 8)+CPU100, 400	;3.33x100

		dw	0

;[]=========================================================[]
;Input	:	None
;Output	:	NZ = Not Cyrix 6x86(M1) nor 6x86MX(M2)
;		ZF = It is Cyrix 6x86(M1) or 6x86MX(M2)
;		     CF : PR-Rating Not Shown
;		     NC	: PR-Rating Shown
;[]=========================================================[]
Show_Cyrix_PRating	PROC	NEAR

	;------------------------------------------
	;Display P-rating if CYRIX 6x86 CPU plugged
	;------------------------------------------

		call	fPROC_Check_M1_Cpu 	;check if 6x86 CPU
		jne	Not_M1_P_Rate

		xor	bl, bl			;Do not show string "PR"
		mov	si, offset M1_PRat_Tbl	;table of P-rating
		call	fPROC_Check_M2Cpu
		jne	Its_M1

		mov	al, 0FEh		;DIR0 register
		out	22h, al
		in	al, 23h			;read DIR0 value
		and	al, 00000111b
		mov	ah, al
		call	Get_Host_Freq_In_AL_High_Nibble
		mov	si, offset M2_PRat_Tbl
		call	Show_PRating_Using_AX
		jmp	Finish_Cyrix_PRating

	Its_M1:
		call	Show_PRating

	Finish_Cyrix_PRating:

		jc	End_Show_Cyrix_PRating

		call	fPROC_Check_M2Cpu
		je	Its_M2

		mov	al, "+"
		call	X_Display_Char
	Its_M2:
		clc				;indicate show p-rating successfully

	End_Show_Cyrix_PRating:

		mov	al, 1			;set ZF, do not destroy CF
		dec	al			;set ZF, do not destroy CF
		ret

	Not_M1_P_Rate:

		or	sp, sp			;clear ZF
		ret

Show_Cyrix_PRating	ENDP

M2_PRat_Tbl:
		;------------------------------------------
		;      Ratio + Clock	, P-Rating
		;------------------------------------------
		; '*' means this PRating value is decided by award

		dw     (01 shl 8)+CPU100, 233	;100x2 (200 Mhz)
		dw     (01 shl 8)+CPU83	, 233	;83x2 (166 Mhz)
		dw     (01 shl 8)+CPU75	, 200	;75x2 (150 Mhz)
		dw     (01 shl 8)+CPU66	, 166	;66x2 (133 Mhz)
		dw     (01 shl 8)+CPU60	, 150	;60x2 (120 Mhz)
		dw     (01 shl 8)+CPU50	, 133	;50x2 (100 Mhz)

		dw     (02 shl 8)+CPU100, 366	;100x2.5 (250 Mhz)
		dw     (02 shl 8)+CPU95 , 300	;95x2.5 (237 Mhz)
		dw     (02 shl 8)+CPU90 , 300	;90x2.5 (225 Mhz)
		dw     (02 shl 8)+CPU83	, 266	;83x2.5	(208 Mhz) *
		dw     (02 shl 8)+CPU75	, 233	;75x2.5	(188 Mhz)
		dw     (02 shl 8)+CPU66	, 200	;66x2.5	(166 Mhz)
		dw     (02 shl 8)+CPU60	, 166	;60x2.5	(150 Mhz)
		dw     (02 shl 8)+CPU50	, 150	;50x2.5	(125 Mhz) *

		dw     (03 shl 8)+CPU100, 433	;100x3 (300 Mhz) ;R05
		dw     (03 shl 8)+CPU95 , 400	;95x3 (285 Mhz)	 ;R05
		dw     (03 shl 8)+CPU90 , 350	;90x3 (270 Mhz)
		dw     (03 shl 8)+CPU83	, 333	;83x3 (250 Mhz)
		dw     (03 shl 8)+CPU75	, 300	;75x3 (225 Mhz)
		dw     (03 shl 8)+CPU66	, 266	;66x3 (200 Mhz)
		dw     (03 shl 8)+CPU60	, 200	;60x3 (180 Mhz)
		dw     (03 shl 8)+CPU50	, 166	;50x3 (150 Mhz)	*

		dw     (04 shl 8)+CPU100, 500	;100x3.5 (350 Mhz);R05
		dw     (04 shl 8)+CPU95 , 466	;95x3.5 (333 Mhz) ;R05
		dw     (04 shl 8)+CPU90 , 433	;90x3.5 (315 Mhz) ;R05
		dw     (04 shl 8)+CPU83	, 400	;83x3.5	(292 Mhz) ;R05
		dw     (04 shl 8)+CPU75	, 333	;75x3.5	(263 Mhz) *
		dw     (04 shl 8)+CPU66	, 300	;66x3.5	(233 Mhz)
		dw     (04 shl 8)+CPU60	, 233	;60x3.5	(210 Mhz) *
		dw     (04 shl 8)+CPU50	, 200	;50x3.5	(175 Mhz)

		dw     (05 shl 8)+CPU100, 550	;100x4 (400 Mhz);R05
		dw     (05 shl 8)+CPU95	, 533	;95x4 (380 Mhz)	;R05
		dw     (05 shl 8)+CPU90	, 500	;90x4 (360 Mhz) ;R05
		dw     (05 shl 8)+CPU83	, 466	;83x4 (333 Mhz) ;R05
		dw     (05 shl 8)+CPU75	, 400	;75x4 (300 Mhz) ;R05
		dw     (05 shl 8)+CPU66	, 333	;66x4 (266 Mhz)
		dw     (05 shl 8)+CPU60	, 300	;60x4 (240 Mhz)
		dw     (05 shl 8)+CPU50	, 200	;50x4 (200 Mhz)

		dw	0

;----------------------------------
; P-rating table of cyrix 6x86 CPU
;----------------------------------
M1_PRat_Tbl:
		;------------------------------
		;      MHZ	,    P-Rating
		;------------------------------
		dw	80	, 	90
PRAT_TBL_LEN	EQU	($ - offset M1_PRat_Tbl)
		dw	66	, 	90
		dw	60	, 	90
		dw	100	, 	120
		dw	110	, 	133
		dw	120	, 	150
		dw	133	, 	166
		dw	150	, 	200
		dw	0				;end of table

;[]=========================================================[]
;Output	:	CY = Not K6
;		NC = PR Rating successfully shown
;[]=========================================================[]
Show_K6_PRating	PROC	NEAR

	;------------------------------------------
	;Display P-rating if AMD K6 CPU plugged
	;------------------------------------------

		call	fPROC_Check_K6_CPU	;K6 ?
		stc
		jne	No_K6_P_Rate		;no !

		mov	si, 0FFFFh		;use CPU_INT_CLOCK[bp]
		xor	bl, bl			;Do not show string "PR"
		call	Show_PRating		;show P-rating

	No_K6_P_Rate:

		ret

Show_K6_PRating	ENDP

;[]=========================================================[]
;Input	:	None
;Output	:	NZ = Not AMD K5
;		ZF = It is AMD K5
;		     CF : PR-Rating Not Shown
;		     NC	: PR-Rating Shown
;[]=========================================================[]
Show_K5_PRating	PROC	NEAR

	;------------------------------------------
	;Display P-rating if AMD K5 CPU plugged
	;------------------------------------------

		call	fPROC_Check_K586_Cpu 	;check if AMD 5k86 CPU
		jne	Not_K586		;no, it is not AMD K5

		push	di
		call	fPROC_Read_CpuID
		pop	di
		mov	si, offset K586_051x_PRat_Tbl	;table of P-rating
		and	al, 0f0H
		cmp	al, 10H			;CPUID=051X
		jae	Go_Show_PRating

		mov	si, offset K586_PRat_Tbl	;table of P-rating

	Go_Show_PRating:

		mov	bl, 1			;show string "PR"
		call	Show_PRating
		mov	al, 1			;set ZF, do not destroy CF
		dec	al			;set ZF, do not destroy CF
		ret

	Not_K586:

		or	sp, sp			;Clear ZF
		ret

Show_K5_PRating	ENDP

;--------------------------------------
; P-rating table of AMD K5 CPU for 050XH
;--------------------------------------
K586_PRat_Tbl:
		;------------------------------
		;      MHZ	,    P-Rating
		;------------------------------
		dw	66	, 	75
		dw	75	, 	75
		dw	83	, 	90
		dw	90	, 	90
		dw	100	, 	100
		dw	120	, 	120
		dw	133	, 	133
		dw	0			;end of table

;--------------------------------------
; P-rating table of AMD K5 CPU for 051XH
;--------------------------------------
K586_051X_PRat_Tbl:
		;------------------------------
		;      MHZ	,    P-Rating
		;------------------------------
		dw	75 	, 	100
		dw	83 	, 	100
		dw	90 	, 	120
 ifdef	SHOW_K5_PR150_INSTEAD_PR133
		dw	100	, 	150
 else;	SHOW_K5_PR150_INSTEAD_PR133
		dw	100	, 	133
 endif;	SHOW_K5_PR150_INSTEAD_PR133
		dw	120	, 	150

		dw	133	, 	200	;for 053x only
		dw	105	, 	150 	;for 052X only
		dw	117	, 	166 	;for 052X only
		dw	0			;end of table

;[]=========================================================[]
;Output	:	CY = Not Rise CPU
;		NC = PR Rating successfully shown
;[]=========================================================[]
Show_Rise_PRating	PROC	NEAR

		call	fPROC_Check_RiseCpu	;is Rise mP6 CPU ?
		jne	@F

		mov	si, offset Rise_PRat_Tbl
		mov	bl, 1			;show string "PR"
		call	Show_PRating
		mov	al, 1			;set ZF, do not destroy CF
		dec	al			;set ZF, do not destroy CF
		ret
	@@:
		or	sp, sp			;Clear ZF
		ret

Show_Rise_PRating	ENDP

;--------------------------------------
; P-rating table of Rise CPU
;--------------------------------------
Rise_PRat_Tbl:
		;------------------------------
		;      MHZ	,    P-Rating
		;------------------------------
		dw	75 	, 	75	;50x1.5
		dw	83 	, 	83	;55x1.5
		dw	90 	, 	90	;60x1.5
		dw	100	, 	100	;50x2
		dw	120	, 	120	;60x2
		dw	133	, 	133	;66x2
		dw	150	, 	150	;75x2
		dw	166	, 	166	;83x2
		dw	190	, 	233	;95x2
		dw	200	, 	266	;100x2
		dw	0			;end of table

;[]======================================================================[]
;Input	:	SI - offset of Prating table to compare
;		     if SI=0FFFFh, use CPU_INT_CLOCK[bp] as PR rating
;		word ptr CPU_INT_CLOCK[bp] storing the CPU internal clock
;		DI = 1 --> show P-Rating with '-'
;		DI = 0 --> show P-Rating without '-'
;		BL = 1 --> Show string "PR"
;		BL = 0 --> Do not show string "PR"
;Output	:	NC - Show P-Rating successfully
;		CF - Show P-Rating not successful
;Function:	Display P-rating on screen
;[]======================================================================[]
Show_PRating	proc	near

		push	bx

		cmp	si, 0FFFFh		;should we reference table ?
		je	No_Ref_Tbl		;no !

	;--------------------------------------------------
	;search the P-Rating by comparing CPU_INT_CLOCK[bp]
	;with a table with pre-defined values and SI will
	;point to a word address storing the P-Rating value
	;--------------------------------------------------

		mov	ax, CPU_INT_CLOCK[bp]	;CPU real clock
Next_Mhz_Tbl:
		cmp	word ptr cs:[si], 0	;last table ?
		je	No_Prat_Found

		cmp	ax, cs:[si]		;Mhz match ?
		je	Prat_Found		;yes

	   	add	si, PRAT_TBL_LEN	  	;no, next MHz
		jmp	Next_Mhz_Tbl
Prat_Found:
		inc	si			;offset of P-Rating
		inc	si
No_Ref_Tbl:

	;------------------------------------------
	;show '-' according to the input DI
	;------------------------------------------

		cmp	di, 1
		jne	No_Dash

	;----------------------------------
	;show '/' instead of '-' for AMD K6
	;----------------------------------

		push	bx
 		mov	al, "/"			;assume show '/'
		call	fPROC_Check_K6_CPU	;K6 CPU ?
		je	@F			;yes, go show it !
 		mov	al, "-"			;show '-' on screen
	@@:
 		call	X_Display_Char
		pop	bx

	No_Dash:

	;------------------------------------------
	;If Cyrix show 'PXX'
	;If AMD show 'PRXX'
	;------------------------------------------

		or	bl, bl
		jz	Just_Show_Rating

		push	si
		mov	si, offset PR_String
		call	X_Display_CS_String
		pop	si

	;------------------------------------------
	;display P-rating value stored in CS:[SI]
	;------------------------------------------

Just_Show_Rating:

		mov	ax, CPU_INT_CLOCK[bp]	;assume CPU_INT_CLOCK[bp]
		cmp	si, 0FFFFh		;should we use this value?
		je	Go_Show_P_Rate		;yes !
		mov	ax, cs:[si]

	Go_Show_P_Rate:

		cmp	ax, 99
		ja	@F
		call	fPROC_Disp_Byte_Int2
		jmp	End_Show_P_Rate
	@@:
		call	fPROC_Disp_Word_Int3

	End_Show_P_Rate:

		pop	bx
		clc	;indicate show p-rating successfully
		ret
No_Prat_Found:
		pop	bx
		stc	;indicate show p-rating not successful
		ret

Show_PRating	ENDP

PR_String	db	'PR', 0

endif	;NO_PRATING_DISPLAY

;--------------------------------------------------------
;--------------------------------------------------------
		Public	fPROC_If_WinChip2A
fPROC_If_WinChip2A	PROC	FAR

		cmp	al, 90h
		jae	Not_2A
		cmp	al, 87h
		jb	Not_2A
		cmp	al, 8Ah
		je	Not_2A
	Its_2A:
		push	ax
		xor	al, al		;Set ZF=1
		pop	ax
		ret
	Not_2A:
		or	sp, sp		;Clear ZF
		ret

fPROC_If_WinChip2A	ENDP

		Public	WinChip2A_Clock_Multiplier_In_AH
WinChip2A_Clock_Multiplier_In_AH	PROC	FAR

		push	bx
		push	ecx

		mov	ecx, 10ah
		RDMSR
		and	al, 00000011b

		push	ax
		mov	ecx, 147h
		RDMSR
		shr	eax, 23-8-2		;shift b26-23 to AH(B3-0)
		and	ah, 00111100b
		pop	bx

		or	ah, bl

		pop	ecx
		pop	bx
		ret

WinChip2A_Clock_Multiplier_In_AH	ENDP

XCODE		ENDS

ENDIF	;COMPILE_FOR_E0
