/*
* $Id: identify.c,v 1.54 2004/06/11 12:35:05 davej Exp $
* This file is part of x86info.
* (C) 2001 Dave Jones.
*
* Licensed under the terms of the GNU GPL License version 2.
*
* AMD-specific information
*
* http://www.pbase.com/image/17079307/original
*/
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include "../x86info.h"
#include "AMD.h"
static char *amd_nameptr;
#define add_to_cpuname(x) amd_nameptr += snprintf(amd_nameptr, sizeof(x), "%s", x);
static void do_assoc(unsigned long assoc)
{
if ((assoc & 0xff) == 255)
printf("Fully");
else
printf("%lu-way", assoc);
printf(" associative. ");
}
static void decode_AMD_cacheinfo(struct cpudata *cpu)
{
unsigned long eax, ebx, ecx, edx;
if (cpu->maxei >= 0x80000005) {
/* TLB and cache info */
cpuid(cpu->number, 0x80000005, &eax, &ebx, &ecx, &edx);
printf("Instruction TLB: ");
do_assoc((ebx >> 8) & 0xff);
printf("%lu entries.\n", ebx & 0xff);
printf("Data TLB: ");
do_assoc(ebx >> 24);
printf("%lu entries.\n", (ebx >> 16) & 0xff);
printf("L1 Data cache:\n\t");
printf("Size: %luKb\t", ecx >> 24);
do_assoc((ecx >> 16) & 0xff);
printf("\n\t");
printf("lines per tag=%lu\t", (ecx >> 8) & 0xff);
printf("line size=%lu bytes.\n", ecx & 0xff);
printf("L1 Instruction cache:\n\t");
printf("Size: %luKb\t", edx >> 24);
do_assoc((edx >> 16) & 0xff);
printf("\n\t");
printf("lines per tag=%lu\t", (edx >> 8) & 0xff);
printf("line size=%lu bytes.\n", edx & 0xff);
}
/* check K6-III (and later) on-chip L2 cache size */
if (cpu->maxei >= 0x80000006) {
cpuid(cpu->number, 0x80000006, &eax, &ebx, &ecx, &edx);
printf("L2 (on CPU) cache:\n\t");
printf("Size: %luKb\t", ecx >> 16);
do_assoc((ecx >> 12) & 0x0f);
printf("\n\t");
printf("lines per tag=%lu\t", (ecx >> 8) & 0x0f);
printf("line size=%lu bytes.\n", ecx & 0xff);
}
printf("\n");
}
/*
* Returns size of L2 cache for Duron/Athlon descrimination
* Assumes 0x80000006 is valid.
*/
static int getL2size(int cpunum)
{
unsigned long eax, ebx, ecx, edx;
cpuid(cpunum, 0x80000006, &eax, &ebx, &ecx, &edx);
return (ecx >> 16);
}
static int is_mobile(struct cpudata *cpu)
{
unsigned long eax, ebx, ecx, edx;
if (cpu->maxei >= 0x80000007) {
cpuid(cpu->number, 0x80000007, &eax, &ebx, &ecx, &edx);
if ((edx & (1<<1|1<<2)) == 0)
return 0;
else
return 1;
} else {
return 0;
}
}
static void determine_xp_mp(struct cpudata *cpu)
{
unsigned long eax, ebx, ecx, edx;
/* There are no mobile MPs. */
if (is_mobile(cpu)) {
add_to_cpuname("XP");
return;
}
cpuid(cpu->number, 0x80000001, &eax, &ebx, &ecx, &edx);
if ((edx & (1 << 19)) == 0) {
add_to_cpuname("XP");
} else {
add_to_cpuname("MP");
}
}
void Identify_AMD(struct cpudata *cpu)
{
unsigned long eax, ebx, ecx, edx;
amd_nameptr = cpu->name;
cpu->vendor = VENDOR_AMD;
if (cpu->maxi < 1)
return;
cpuid(cpu->number, 0x00000001, &eax, &ebx, &ecx, &edx);
cpu->stepping = eax & 0xf;
cpu->model = (eax >> 4) & 0xf;
cpu->family = (eax >> 8) & 0xf;
cpu->emodel = (eax >> 16) & 0xff;
cpu->efamily= (eax >> 20) & 0xf;
switch (cpu->family) {
case 4:
cpu->connector = CONN_SOCKET_3;
break;
}
switch (tuple(cpu) & 0xff0) {
case 0x430:
add_to_cpuname("Am486DX2-WT");
break;
case 0x470:
add_to_cpuname("Am486DX2-WB");
break;
case 0x480:
add_to_cpuname("Am486DX4-WT / Am5x86-WT");
break;
case 0x490:
add_to_cpuname("Am486DX4-WB / Am5x86-WB");
break;
case 0x4a0:
add_to_cpuname("Elan SC400");
break;
case 0x4e0:
add_to_cpuname("Am5x86-WT");
break;
case 0x4f0:
add_to_cpuname("Am5x86-WB");
break;
case 0x500:
add_to_cpuname("SSA5 (PR75/PR90/PR100)");
cpu->connector = CONN_SOCKET_5_7;
break;
case 0x510:
add_to_cpuname("K5 (PR120/PR133)");
cpu->connector = CONN_SOCKET_5_7;
break;
case 0x520:
add_to_cpuname("K5 (PR166)");
cpu->connector = CONN_SOCKET_5_7;
break;
case 0x530:
add_to_cpuname("K5 (PR200)");
cpu->connector = CONN_SOCKET_5_7;
break;
case 0x560:
add_to_cpuname("K6 (0.30 um)");
cpu->connector = CONN_SOCKET_7;
break;
case 0x570:
add_to_cpuname("K6 (0.25 um)");
cpu->connector = CONN_SOCKET_7;
break;
case 0x580:
add_to_cpuname("K6-2");
cpu->connector = CONN_SUPER_SOCKET_7;
if (cpu->stepping >= 8)
add_to_cpuname(" (CXT core)");
break;
case 0x590:
add_to_cpuname("K6-III");
cpu->connector = CONN_SUPER_SOCKET_7;
break;
case 0x5c0:
add_to_cpuname("K6-2+ (0.18um)");
cpu->connector = CONN_SUPER_SOCKET_7;
break;
case 0x5d0:
add_to_cpuname("K6-3+ (0.18um)");
cpu->connector = CONN_SUPER_SOCKET_7;
break;
case 0x600:
cpu->connector = CONN_SLOT_A;
add_to_cpuname("K7 ES");
break;
case 0x610:
cpu->connector = CONN_SLOT_A;
add_to_cpuname("Athlon (0.25um)");
switch (cpu->stepping) {
case 1:
add_to_cpuname(" [C1]");
break;
case 2:
add_to_cpuname(" [C2]");
break;
}
break;
case 0x620:
cpu->connector = CONN_SLOT_A;
add_to_cpuname("Athlon (0.18um)");
switch (cpu->stepping) {
case 1:
add_to_cpuname(" [A1]");
break;
case 2:
add_to_cpuname(" [A2]");
break;
}
break;
case 0x630:
cpu->connector = CONN_SOCKET_A;
add_to_cpuname("Duron (spitfire)");
switch (cpu->stepping) {
case 0:
add_to_cpuname(" [A0]");
break;
case 1:
add_to_cpuname(" [A2]");
break;
}
break;
case 0x640:
cpu->connector = CONN_SOCKET_A;
add_to_cpuname("Athlon (Thunderbird)");
switch (cpu->stepping) {
case 0:
add_to_cpuname(" [A1]");
break;
case 1:
add_to_cpuname(" [A2]");
break;
case 2:
add_to_cpuname(" [A4-A8]");
break;
case 3:
add_to_cpuname(" [A9]");
break;
}
break;
case 0x660:
cpu->connector = CONN_SOCKET_A;
if (is_mobile(cpu)) {
add_to_cpuname("Mobile Athlon 4");
goto out_660;
}
if (getL2size(cpu->number) < 256) {
add_to_cpuname("Duron (Morgan)");
} else {
add_to_cpuname("Athlon ");
determine_xp_mp(cpu);
/* Palomino
* 0.18u L2=256KB
* 266MHz FSB
* 12%-20% faster than Athlon Thunderbird at same GHz
* Power requirement reduced by 20%
* Athlon XP 1500+ (Oct 2001)
* Athlon XP 1600+ (Oct 2001)
* Athlon XP 1700+ (Oct 2001)
* Athlon XP 1800+ (Oct 2001)
* Athlon XP 1900+ (Nov 2001)
* Athlon XP 2000+ (Jan 2002)
* Athlon XP 2100+ (Mar 2002)
*/
add_to_cpuname(" (Palomino)");
}
out_660:
switch (cpu->stepping) {
case 0:
add_to_cpuname(" [A0-A1]");
break;
case 1:
add_to_cpuname(" [A2]");
break;
}
break;
case 0x670:
cpu->connector = CONN_SOCKET_A;
if (is_mobile(cpu))
add_to_cpuname("Mobile ");
add_to_cpuname("Duron (Morgan core)");
switch (cpu->stepping) {
case 0:
add_to_cpuname(" [A0]");
break;
case 1:
add_to_cpuname(" [A1]");
break;
}
break;
case 0x680:
cpu->connector = CONN_SOCKET_A;
if (is_mobile(cpu))
add_to_cpuname("Mobile ");
if (getL2size(cpu->number) < 256) {
add_to_cpuname("Duron ");
} else {
add_to_cpuname("Athlon ");
determine_xp_mp(cpu);
}
/*
* Thoroughbred
* 0.13u L2=256KB
* Thoroughbred 'A' = 266FSB
* Thoroughbred 'B' = 266FSB
* Thoroughbred 'B' = 333FSB
* Throughbred B has an extra layer of copper interconnects
* to reduce interference.
* Athlon XP1600+ (A:June 2002 B:Mar 2003)
* Athlon XP1700+ (A:June 2002 B:Dec 2002)
* Athlon XP1800+ (A:June 2002 B:Dec 2002)
* Athlon XP1900+ (A:June 2002 B:Dec 2002)
* Athlon XP2000+ (A:June 2002 B:Aug 2002)
* Athlon XP2100+ (A:June 2002 B:Dec 2002)
* Athlon XP2200+ (A:June 2002 B:Aug 2002)
* Athlon XP2400+ ( B:Aug 2002)
* Athlon XP2600+ ( B:Aug 2002 B2: Nov 2002)
* Athlon XP2700+ ( B2: Oct 2002)
* Athlon XP2800+ ( B2: Oct 2002)
*/
add_to_cpuname(" (Thoroughbred)");
if (cpu->stepping == 0)
add_to_cpuname("[A0]");
if (cpu->stepping == 1)
add_to_cpuname("[B0]");
//fab_process = ".13 micron";
//transistors = 37600000;
//die_size = "84 sq.mm";
break;
case 0x6a0:
cpu->connector = CONN_SOCKET_A;
if (is_mobile(cpu))
add_to_cpuname("Mobile ");
add_to_cpuname("Athlon ");
determine_xp_mp(cpu);
add_to_cpuname(" (Barton)");
//fab_process = ".13 micron copper";
//transistors = 54300000;
//die_size = "101 sq. mm";
/* Barton
* L2=512
* 333 FSB & 400 FSB
* 10%-15% faster than Athlon XP (old) with same GHz
* CPU core size 20% bigger than T-bred.
* 333 FSB:
* Athlon XP 2500+ (Feb 2003)
* Athlon XP 2600+ (June 2003)
* Athlon XP 2800+ (Feb 2003)
* Athlon XP 3000+ (Feb 2003)
* 400 FSB:
* Athlon XP 3000+ (Apr 2003)
* Athlon XP 3200+ (May 2003)
* Athlon XP 3400+ (Q4 2003)
* Athlon XP 3600+ (Q1 2004)
* Athlon XP 3800+ (Q2 2004)
*/
break;
/*
* Applebred
* 0.13u L2=64KB
* 266FSB
* Barton grade processor modules with 64KB cache
*
* Duron 1.4 (Aug 2003)
* Duron 1.6 (Aug 2003)
* Duron 1.8 (Q4 2003)
*/
/*
* Socket 940
* Sledgehammer
* 0.13u
* L2=1mb
* 400FSB
* SOI (silicon on insulator)
* Registered DIMM required
* 25% faster than Athlon XP with same GHz
* Athlon 64 FX51 (Sep 2003)
* Athlon 64 FX53 (Nov 2003)
* Athlon 64 FX55 (Q4 2003)
*/
/*
* Socket 754
* Clawhammer
* 0.13
* L2=1mb
* 400FSB
* No dual channel memory access
* Registered DIMM not required
* Athlon 64 3000+ (Oct 2003)
* Athlon 64 3200+ (Sep 2003)
* Athlon 64 3400+ (Oct 2003)
* Athlon 64 3700+ (Q4 2003)
*/
/*
* Socket 939
* San Diego
* 90nm l2=1mb
* 400FSB
* Dual channel memory access
* Registered DIMM not required
* Athlon64 FX-57 (Q1 2004)
*/
/*
* Socket 754
* Victoria
* 90nm L2=1MB
* 400FSB
* No dual channel memory access
* Registered DIMM not required
* Athlon64 3x00+ (Q3 2004)
*/
case 0xF00:
cpu->connector = CONN_SOCKET_754;
add_to_cpuname("Athlon 64 ");
switch (cpu->stepping) {
case 0:
add_to_cpuname("[SH7-A0]");
break;
case 1:
add_to_cpuname("[SH7-A2]");
break;
}
break;
case 0xF10:
add_to_cpuname("Opteron ES ");
cpu->connector = CONN_SOCKET_940;
switch (cpu->stepping) {
case 0:
add_to_cpuname("[SH7-A0]");
break;
case 1:
add_to_cpuname("[SH7-A2]");
break;
}
break;
case 0xF40:
cpu->connector = CONN_SOCKET_754;
add_to_cpuname("Athlon 64 ");
switch (cpu->stepping) {
case 0:
if (cpu->emodel==0) {
add_to_cpuname("[SH7-B0]");
} else {
add_to_cpuname("[SH8-D0]");
}
break;
case 8:
// need to check for longmode bit. could be athlon xp 3000+.
// (These are 32bit only amd64's)
//might be mobile
add_to_cpuname("[SH7-C0]");
break;
case 0xa:
//might be mobile
add_to_cpuname("[SH7-CG]");
break;
}
break;
// Gar, these could also be athlon 64fx
case 0xF50:
cpu->connector = CONN_SOCKET_940;
add_to_cpuname("Opteron");
switch (cpu->stepping) {
case 0:
if (cpu->emodel==0) {
add_to_cpuname("[SH7-B0]");
} else {
add_to_cpuname("[SH8-D0]");
}
break;
case 1:
add_to_cpuname("[SH7-B3]");
break;
case 8:
add_to_cpuname("[SH7-C0]");
break;
case 0xA:
add_to_cpuname("[SH7-CG]");
break;
default:
break;
}
break;
case 0xF70:
add_to_cpuname("Athlon 64 ");
cpu->connector = CONN_SOCKET_939;
switch (cpu->stepping) {
case 0x0:
add_to_cpuname("[SH8-D0]");
break;
case 0xa:
add_to_cpuname("[SH7-CG]");
break;
}
break;
case 0xF80:
cpu->connector = CONN_SOCKET_754;
add_to_cpuname("Athlon 64 ");
switch (cpu->stepping) {
case 2:
//might be mobile
add_to_cpuname("CH7-CG");
break;
}
break;
case 0xFB0:
cpu->connector = CONN_SOCKET_939;
add_to_cpuname("Athlon 64 ");
switch (cpu->stepping) {
case 2:
add_to_cpuname("CH7-CG");
break;
}
break;
case 0xFC0:
cpu->connector = CONN_SOCKET_754;
add_to_cpuname("Athlon 64 ");
switch (cpu->stepping) {
case 0:
//might be mobile
add_to_cpuname("DH7-CG");
break;
}
break;
case 0xFE0:
//might be mobile
cpu->connector = CONN_SOCKET_754;
add_to_cpuname("Athlon 64 ");
switch (cpu->stepping) {
case 0:
add_to_cpuname("DH7-CG");
break;
}
break;
case 0xFF0:
cpu->connector = CONN_SOCKET_939;
add_to_cpuname("Athlon 64 ");
switch (cpu->stepping) {
case 0:
add_to_cpuname("DH7-CG");
break;
}
break;
default:
add_to_cpuname("Unknown CPU");
break;
}
}
void display_AMD_info(struct cpudata *cpu)
{
printf("Family: %u Model: %u Stepping: %u\n",
cpu->family, cpu->model, cpu->stepping);
printf ("CPU Model : %s\n", cpu->name);
get_model_name(cpu);
decode_feature_flags(cpu);
if (show_msr) {
if (cpu->family == 5)
dump_k6_MSR(cpu);
if (cpu->family == 6)
dump_athlon_MSR(cpu);
}
if (show_bluesmoke)
decode_athlon_bluesmoke(cpu->number);
if (show_cacheinfo)
decode_AMD_cacheinfo(cpu);
if (show_pm)
decode_powernow(cpu);
if (show_bugs)
show_amd_bugs(cpu);
/* AMD Multicore characterisation */
if (cpu->maxei >= 0x80000008) {
int nr_cores;
unsigned long ecx;
cpuid (cpu->number, 0x80000008, NULL, NULL, &ecx, NULL);
nr_cores = 1 + (ecx & 0xff);
if (nr_cores > 1)
printf ("The physical package has %d cores\n", nr_cores);
}
}
syntax highlighted by Code2HTML, v. 0.9.1