1
2;	for new GOGO-no-coda (1999/09)
3;	Copyright (C) 1999 shigeo
4;	modified by Keiichi SAKAI, URURI, Hash
5
6;	99/07/29
7;	99/09/06	�ե饰�ɲ�
8;	99/09/07	SSE�ν������̤ˤ���
9;	99/09/29	Cx586�к�
10;	99/11/10	Cxrix�к�
11
12;	int haveUNIT(void);
13
14;	486̤����CPU�ޤ���FPU����ܤ��Ƥ��ʤ����0
15;	����ʳ��ϼ����ͤ�������
16;	PIII�Ǥϴݤ����ͼθ����⡼�ɤˤ���(�餷��)
17
18;	haveunit.h�Ȥ����������
19
20%include "nasm.h"
21
22tFPU	equ	(1<<0)
23tMMX	equ	(1<<1)
24t3DN	equ	(1<<2)
25tSSE	equ	(1<<3)
26tCMOV	equ	(1<<4)
27tE3DN	equ	(1<<5)	;/* Athlon�� (extend 3D Now!)*/
28tEMMX   equ	(1<<6)  ;/* EMMX=E3DNow!_INT=SSE_INT */
29
30tSPC1	equ	(1<<16)	;/* ���̤ʥ����å� */
31tSPC2	equ	(1<<17)	;/* ���ӤϷ�ޤäƤʤ� */
32
33tINTEL	equ	(1<<8)
34tAMD	equ	(1<<9)
35tCYRIX	equ	(1<<10)
36tIDT	equ	(1<<11)
37tUNKNOWN	equ	(1<<15)	;�٥������ʬ����ʤ�
38
39tFAMILY4	equ	(1<<20)	;/* 486 ���λ��٥����Ƚ������Ƥˤʤ�ʤ� */
40tFAMILY5	equ	(1<<21)	;/* 586 (P5, P5-MMX, K6, K6-2, K6-III) */
41tFAMILY6	equ	(1<<22)	;/* 686�ʹ� P-Pro, P-II, P-III, Athlon */
42
43		globaldef	haveUNIT
44		globaldef	setPIII_round
45		globaldef	maskFPU_exception
46
47	segment_data
48	segment_code
49
50ACflag equ (1<<18)
51IDflag equ (1<<21)
52
53		align	16
54haveUNIT:
55		push	ebx
56		push	esi
57		xor		esi,esi
58		call	near haveFPU
59		jnz		near .Lexit
60		or		esi,tFPU
61		pushfd						;flag��¸
62		pushfd
63		pop		eax					;eax=flag
64		or		eax,ACflag			;eax=flag|ACflag
65		push	eax
66		popfd						;flag=eax
67		pushfd
68		pop		eax					;eax=flag
69		popfd						;flag����
70		test	eax,ACflag			;ACflag���Ѳ���������
71		jz		near .Lexit
72;486�ʹ�
73		pushfd						;flag��¸
74		pushfd
75		pop		eax					;eax=flag
76		or		eax,IDflag			;eax=flag|IDflag
77		push	eax
78		popfd						;flag=eax
79		pushfd
80		pop		eax					;eax=flag
81		popfd						;flag����
82		test	eax,IDflag
83;		jz		short .Lexit
84		jnz		.L586
85
86%if 1
87	;Cyrix 486CPU check Cyrix �� HP �ˤ��ä���� by Hash
88
89        xor   ax, ax         ; clear ax
90        sahf                 ; clear flags, bit 1 is always 1 in flags
91        mov   ax, 5
92        mov   bx, 2
93        div   bl             ; do an operation that does not change flags
94        lahf                 ; get flags
95        cmp   ah, 2          ; check for change in flags
96        jne   .L486intel     ; flags changed not Cyrix
97        or    esi,tCYRIX     ; TRUE Cyrix CPU
98        jmp   .L486
99
100.L486intel:
101		or		esi,tINTEL
102.L486:
103		or		esi,tFAMILY4
104		jmp		.Lexit
105
106%else
107	; check for Cyrix 486DLC -- based on check routine
108	; documented in "Cx486SLC/e SMM Programmer's Guide"
109		xor		dx,dx
110		cmp		dx,dx
111		pushf
112		pop		cx
113		mov		ax,0FFFFh
114		mov		bx,4
115		div		bx
116		pushf
117		pop		ax
118		and		ax,8D5h
119		and		cx,8D5h
120		cmp		ax,cx
121		jnz		.L486intel
122		or		esi,tCYRIX
123		jmp		.L486
124.L486intel:
125		or		esi,tINTEL
126.L486:
127		or		esi,tFAMILY4
128		jmp		.Lexit
129%endif
130
131
132.L586:
133
134;cpuid �� eax,ebx,ecx,edx���˲�����Τ���ա�����
135
136		xor		eax,eax
137		cpuid
138;		cmp		ecx,"letn"
139		cmp		ecx,"ntel"	;�����NASM��ȿ�Ф����֤�����
140		jne		.F00
141		or		esi,tINTEL
142		jmp		.F09
143.F00:
144;		cmp		ecx,"DMAc"
145		cmp		ecx,"cAMD"
146		jne		.F01
147		or		esi,tAMD
148		jmp		.F09
149.F01:
150;		cmp		ecx,"daet"
151		cmp		ecx,"tead"
152		jne		.F02
153		or		esi,tCYRIX
154		jmp		.F09
155.F02:
156;		cmp		ecx,"slua"
157		cmp		ecx,"auls"
158		jne		.F03
159		or		esi,tIDT
160		jmp		.F09
161.F03:
162		or		esi,tUNKNOWN
163		jmp		.F09
164.F09:
165		mov		eax,1
166		cpuid
167		cmp		ah,4
168		jne		.F10
169		or		esi,tFAMILY4
170		jmp		.Lexit
171.F10:
172		cmp		ah,5
173		jne		.F11
174		or		esi,tFAMILY5
175		jmp		.F19
176.F11:
177		cmp		ah,6
178		jne		.F12
179		or		esi,tFAMILY6
180		jmp		.F19
181.F12:
182		or		esi,tFAMILY6	; 7�ʾ��6�ȸ��ʤ�
183.F19:
184
185		;for AMD, IDT
186		mov		eax,80000001h
187		cpuid
188		test	edx,(1 << 31)
189		jz		.F20
190		or		esi,t3DN
191.F20:
192		test	edx,(1 << 15)	;CMOVcc
193		jz		.F21
194;		test	edx,(1 << 16)	;FCMOVcc ;K7�����ѹ� by URURI
195;		jz		.F21
196		or		esi,tCMOV
197.F21:
198		test	edx,(1 << 30)	;��ĥ 3D Now!
199		jz		.F22
200%ifdef USE_E3DN
201		or		esi,tE3DN
202%endif
203.F22:
204		test	edx,(1 << 22)	;AMD MMX Ext
205		jz		.F23
206		or		esi,tEMMX
207.F23:
208	;Intel��
209		mov		eax,1
210		cpuid
211		test	edx,(1 << 23)
212		jz		.F30
213		or		esi,tMMX
214.F30:
215		test	edx,(1 << 15)		;CMOVcc and FCMOV if FPU=1
216		jz		.F31
217		or		esi,tCMOV
218.F31:
219		test	edx,(1 << 25)
220		jz		short .Lexit
221		or		esi,tEMMX
222%ifndef UNAVAILABLE_SSE
223		or		esi,tSSE
224%endif
225.Lexit:
226		mov		eax,esi
227		pop		esi
228		pop		ebx
229		ret
230
231;	  in:none
232;	 out:ZF FPU����=1, �ʤ�=0
233;	dest:eax
234
235		align	16
236haveFPU:
237		mov		al,1
238		fninit
239		fnstsw	ax
240		cmp		al,0
241		jne		short .LhF_exit
242		sub		esp,4
243		fnstcw	word [esp]
244		mov		ax,[esp]
245		add		esp,4
246		and		ax,103Fh
247		cmp		ax,3Fh
248.LhF_exit:
249		ret
250
251setPIII_round:
252		;P-III��SSE��μ¤˻ͼθ����⡼�ɤ�
253;		mov		eax,0x1f80	; default mode
254		mov		eax,0x9f80	; flush to ZERO mode
255		push	eax
256		ldmxcsr	[esp]			; setup MXCSR
257		pop		eax
258		ret
259
260;	for Win32 Delphi
261maskFPU_exception:
262		push		eax
263		fnstcw	word [esp]
264		and	word [esp],0xFFF2
265		fldcw	word [esp]
266		pop		eax
267		ret
268
269		end
270