Subject: AMD cpu detection

I looked on the AMD web site and the following instructions are a stab
at detecting the AMD chips. I can't try this myself (no AMD chips, no easy
way to make a Plan 9 kernel) and there are no instruction timings available
so I'd appreciate it if anyone who has an AMD chip could try this and
report back. Once the changes are installed the aalcycles table entries
(commented with /* guesswork */) should be altered until the value printed
by printcpufreq approximates the MHz of the processor.

Thanks, Jim.

1) fns.h
   change
	int	x86cpuid(int*, int*);
   to
	void	cpuid(char*, int*, int*);

2) l.s
   a) add
	#define CPUID	BYTE $0x0F; BYTE $0xA2	/* CPUID, argument in AX */
      after
	#define NOP	XCHGL	AX,AX

   b) replace x86cpuid by
	/*
	 * Try to determine the CPU type which requires fiddling with EFLAGS.
	 * If the Id bit can be toggled then the CPUID instruciton can be used
	 * to determine CPU identity and features. First have to check if it's
	 * a 386 (Ac bit can't be set). If it's not a 386 and the Id bit can't be
	 * toggled then it's an older 486 of some kind.
	 *
	 *	cpuid(id[], &ax, &dx);
	 */
	TEXT cpuid(SB), $0
		MOVL	$0x240000, AX
		PUSHL	AX
		POPFL					/* set Id|Ac */
	
		PUSHFL
		POPL	BX				/* retrieve value */
	
		MOVL	$0, AX
		PUSHL	AX
		POPFL					/* clear Id|Ac, EFLAGS initialised */
	
		PUSHFL
		POPL	AX				/* retrieve value */
		XORL	BX, AX
		TESTL	$0x040000, AX			/* Ac */
		JZ	_cpu386				/* can't set this bit on 386 */
		TESTL	$0x200000, AX			/* Id */
		JZ	_cpu486				/* can't toggle this bit on some 486 */
	
		MOVL	$0, AX
		CPUID
		MOVL	id+0(FP), BP
		MOVL	BX, 0(BP)			/* "Genu" "Auth" "Cyri" */
		MOVL	DX, 4(BP)			/* "ineI" "enti" "xIns" */
		MOVL	CX, 8(BP)			/* "ntel" "cAMD" "tead" */
	
		MOVL	$1, AX
		CPUID
		JMP	_cpuid
	
	_cpu486:
		MOVL	$0x400, AX
		MOVL	$0, DX
		JMP	_cpuid
	
	_cpu386:
		MOVL	$0x300, AX
		MOVL	$0, DX
	
	_cpuid:
		MOVL	ax+4(FP), BP
		MOVL	AX, 0(BP)
		MOVL	dx+8(FP), BP
		MOVL	DX, 0(BP)
		RET

3) clock.c
   a) add
	static char cpuidid[16];
   after
	static int loopconst = 100;

   b) replace the x86type array with

	static X86type x86intel[] =
	{
		{ 4,	0,	22,	"486DX", },	/* known chips */
		{ 4,	1,	22,	"486DX50", },
		{ 4,	2,	22,	"486SX", },
		{ 4,	3,	22,	"486DX2", },
		{ 4,	4,	22,	"486SL", },
		{ 4,	5,	22,	"486SX2", },
		{ 4,	7,	22,	"DX2WB", },	/* P24D */
		{ 4,	8,	22,	"DX4", },	/* P24C */
		{ 4,	9,	22,	"DX4WB", },	/* P24CT */
		{ 5,	0,	23,	"P5", },
		{ 5,	1,	23,	"P5", },
		{ 5,	2,	23,	"P54C", },
		{ 5,	3,	23,	"P24T", },
		{ 5,	4,	23,	"P55C MMX", },
		{ 5,	7,	23,	"P54C VRT", },
		{ 6,	1,	16,	"PentiumPro", },/* determined by trial and error */
		{ 6,	3,	16,	"PentiumII", },	/* determined by trial and error */
		{ 6,	5,	16,	"PentiumII", },	/* determined by trial and error */
	
		{ 3,	-1,	32,	"386", },	/* family defaults */
		{ 4,	-1,	22,	"486", },
		{ 5,	-1,	23,	"Pentium", },
		{ 6,	-1,	16,	"PentiumPro", },
	
		{ -1,	-1,	23,	"unknown", },	/* total default */
	};
	
	/*
	 * The AMD processors all implement the CPUID instruction.
	 * The later ones also return the processor name via functions
	 * 0x80000002, 0x80000003 and 0x80000004 in registers AX, BX, CX
	 * and DX:
	 *	K5	"AMD-K5(tm) Processor"
	 *	K6	"AMD-K6tm w/ multimedia extensions"
	 *	K6 3D	"AMD-K6(tm) 3D processor"
	 *	K6 3D+	?
	 */
	static X86type x86amd[] =
	{
		{ 5,	0,	23,	"AMD-K5", },	/* guesswork */
		{ 5,	1,	23,	"AMD-K5", },	/* guesswork */
		{ 5,	2,	23,	"AMD-K5", },	/* guesswork */
		{ 5,	3,	23,	"AMD-K5", },	/* guesswork */
		{ 5,	6,	11,	"AMD-K6", },	/* determined by trial and error */
		{ 5,	7,	11,	"AMD-K6", },	/* determined by trial and error */
		{ 5,	8,	23,	"AMD-K6 3D", },	/* guesswork */
		{ 5,	9,	23,	"AMD-K6 3D+", },/* guesswork */
	
		{ 4,	-1,	22,	"Am486", },	/* guesswork */
		{ 5,	-1,	23,	"AMD-K5/K6", },	/* guesswork */
	
		{ -1,	-1,	23,	"unknown", },	/* total default */
	};

   c) replace the printcpufreq function with
	
	void
	printcpufreq(void)
	{
		int i;
		char buf[128];

		i = sprint(buf, "cpu%d: %dMHz ", m->machno, cpumhz);
		if(cpuidid[0])
			i += sprint(buf+i, "%s ", cpuidid);
		sprint(buf+i, "%s (cpuid: AX 0x%4.4luX DX 0x%4.4luX)\n",
			cputype->name, cpuidax, cpuiddx);
		print(buf);
	}

   d) in clockinit replace

	x86cpuid(&cpuidax, &cpuiddx);
	family = FAMILY(cpuidax);
	model = MODEL(cpuidax);
	for(t = x86type; t->name; t++)
		if((t->family == family && t->model == model)
		|| (t->family == family && t->model == -1)
		|| (t->family == -1))
			break;
      with

	cpuid(cpuidid, &cpuidax, &cpuiddx);
	if(strncmp(cpuidid, "AuthenticAMD", 12) == 0)
		t = x86amd;
	else
		t = x86intel;
	family = FAMILY(cpuidax);
	model = MODEL(cpuidax);
	while(t->name){
		if((t->family == family && t->model == model)
		|| (t->family == family && t->model == -1)
		|| (t->family == -1))
			break;
		t++;
	}
