/* Cyrix-specific information
 * $Id: cyrix.c,v 1.3 2009/04/06 05:39:31 karn Exp $
 *
 * This hasn't been updated in many years
 */

#include <stdio.h>
#include "cpuid.h"

struct featureflag Cyrix_standard_edx[] = {
  { "FPU", "Floating Point Unit"},
  { "V86", "Virtual Mode Extensions"},
  { "DBG", "Debug Extension"},
  { "",    "4MB Page Size"},
  { "",    "Time Stamp Counter"},
  { "",    "RDMSR/WRMSR (Model Specific Registers"},
  { "PAE", "PAE"},
  { "",    "Machine Check Exception"},
  { "",    "COMPXCHG8B Instruction"},
  { "APIC","On-chip Advanced Programmable Interrupt Controller present and enabled"},
  { NULL,  NULL},
  { NULL,  NULL},
  {"MTRR", "Memory Type Range Registers"},
  { "",    "Global Paging Extension"},
  {"",     "Machine Check"},
  {"CMOV", "Conditional Move Instruction"},
  { NULL,  NULL},
  { NULL,  NULL},
  { NULL,  NULL},
  { NULL,  NULL},
  { NULL,  NULL},
  { NULL,  NULL},
  { NULL,  NULL},
  { "MMX", "MMX instructions"},
  { NULL,  NULL},
  { NULL,  NULL},
  { NULL,  NULL},
  { NULL,  NULL},
  { NULL,  NULL},
  { NULL,  NULL},
  { NULL,  NULL},
  { NULL,  NULL},
};


/* Decode TLB and cache info descriptors */
void decode_cyrix_tlb(int x){
  switch(x & 0xff){
  case 0x70:
    printf("TLB: 32 entries, 4-way, 4KB pages\n");
    break;
  case 0x80:
    printf("L1 Cache: 16KB, 4-way, 16 bytes/line\n");
    break;
  }
}


void docyrix(){
  int i;
  unsigned int maxei,regs[4];
  int stepping,model,family,reserved,ntlb;
  int maxi;

  printf("Cyrix-specific functions\n");
  regs[0] = 0;
  cpuid(regs);
  maxi = regs[0];

  /* Do standard stuff */
  if(maxi >= 1){
    regs[0] = 1;
    cpuid(regs);
    stepping = regs[0] & 0xf;
    model = (regs[0] >> 4) & 0xf;
    family = (regs[0] >> 8) & 0xf;
    reserved = regs[0] >> 12;

    printf("Family: %d Model: %d [",family,model);
    switch(family){
    case 4:
      switch(model){
      case 4:
	printf("MediaGX");
	break;
      }
      break;
    case 5:
      switch(model){
      case 2:
	printf("6x86");
	break;
      case 4:
	printf("BXm");
	break;
      }
      break;
    case 6:
      switch(model){
      case 0:
	printf("6x86/MX");
	break;
      }
      break;
    }
    printf("]\n\n");
    printf("Standard feature flags in EDX:\n");
    decode_feature_flags(Cyrix_standard_edx,regs[3]);
    putchar('\n');
  }
  if(maxi >= 2){
    /* TLB and L1 Cache info */
    ntlb = 255;
    for(i=0;i<ntlb;i++){
      regs[0] = 2;
      cpuid(regs);
      ntlb =  regs[0] & 0xff;
      decode_cyrix_tlb(regs[0] >> 8);
      decode_cyrix_tlb(regs[0] >> 16);
      decode_cyrix_tlb(regs[0] >> 24);
      
      /* regs[1] and regs[2] are reserved */

      if((regs[3] & 0x80000000) == 0){
	decode_cyrix_tlb(regs[3]);
	decode_cyrix_tlb(regs[3] >> 8);
	decode_cyrix_tlb(regs[3] >> 16);
	decode_cyrix_tlb(regs[3] >> 24);
      }
    }
  }

  regs[0] = 0x80000000;
  cpuid(regs);
  maxei = regs[0];

  /* Check for presence of extended info */
  if(maxei < 0x80000000)
    return;

  printf("\nExtended feature flags:\n");
  if(maxei >= 0x80000001){
    regs[0] = 0x80000001;
    cpuid(regs);
    stepping = regs[0] & 0xf;
    model = (regs[0] >> 4) & 0xf;
    family = (regs[0] >> 8) & 0xf;
    reserved = regs[0] >> 12;
    printf("Family: %d Model: %d [",family,model);
    switch(family){
    case 4:
      printf("MediaGX");
      break;
    case 5:
      printf("6x86/GXm");
      break;
    case 6:
      printf("6x86/MX");
    }
    printf("]\n\n");

    printf("Extended feature flags in EDX:\n");
    if(regs[3] & (1<<0))
      printf(" 0 FPU   Floating Point Unit\n");
    if(regs[3] & (1<<1))
      printf(" 1 V86   Virtual Mode Extensions\n");
    if(regs[3] & (1<<2))
      printf(" 2 Debug Extension\n");
    if(regs[3] & (1<<3))
      printf(" 3 Page Size Extensions\n");
    if(regs[3] & (1<<4))
      printf(" 4 Time Stamp Counter\n");
    if(regs[3] & (1<<5))
      printf(" 5 Cyrix MSR\n");
    if(regs[3] & (1<<6))
      printf(" 6 PAE\n");
    if(regs[3] & (1<<7))
      printf(" 7 MC Exception\n");
    if(regs[3] & (1<<8))
      printf(" 8 COMPXCHG8B\n");
    if(regs[3] & (1<<9))
      printf(" 9 APIC on chip\n");
    if(regs[3] & (1<<10))
      printf("10 SYSCALL/SYSRET\n");
    if(regs[3] & (1<<11))
      printf("11 reserved\n");
    if(regs[3] & (1<<12))
      printf("12 MTRR\n");
    if(regs[3] & (1<<13))
      printf("13 Global bit\n");
    if(regs[3] & (1<<14))
      printf("14 Machine Check\n");
    if(regs[3] & (1<<15))
      printf("15 CMOV\n");
    if(regs[3] & (1<<16))
      printf("16 FPU CMOV\n");
    if(regs[3] & (1<<17))
      printf("17  reserved\n");
    if(regs[3] & (1<<18))
      printf("18 reserved\n");
    if(regs[3] & (1<<19))
      printf("19 reserved\n");
    if(regs[3] & (1<<20))
      printf("20 reserved\n");
    if(regs[3] & (1<<21))
      printf("21 reserved\n");
    if(regs[3] & (1<<22))
      printf("22 reserved\n");
    if(regs[3] & (1<<23))
      printf("23 MMX\n");
    if(regs[3] & (1<<24))
      printf("24 Extended MMX\n");
    if(regs[3] & (1<<25))
      printf("25 reserved\n");
    if(regs[3] & (1<<26))
      printf("26 reserved\n");
    if(regs[3] & (1<<27))
      printf("27 reserved\n");
    if(regs[3] & (1<<28))
      printf("28 reserved\n");
    if(regs[3] & (1<<29))
      printf("29 reserved\n");
    if(regs[3] & (1<<30))
      printf("30 reserved\n");
    if(regs[3] & (1<<31))
      printf("31 3DNow instructions\n");
  }
  putchar('\n');
  if(maxei >= 0x80000002){
    /* Processor identification string */
    char namestring[49],*cp;
    int i,j,k;
    cp = namestring;
    for(i=0x80000002;i<=0x80000004;i++){
      regs[0] = i;
      cpuid(regs);
      
      for(j=0;j<4;j++){
	for(k=0;k<4;k++){
	  *cp++ = regs[j] >> (8*k);
	}
      }
    }
    *cp++ = '\n';
    printf("Processor name string: %s\n",namestring);
  }
  if(maxei >= 0x80000005){
    /* TLB and L1 Cache info */
    ntlb = 255;
    for(i=0;i<ntlb;i++){
      regs[0] = 0x80000005;
      cpuid(regs);
      ntlb =  regs[0] & 0xff;
      decode_cyrix_tlb(regs[1] >> 8);
      decode_cyrix_tlb(regs[1] >> 16);
      decode_cyrix_tlb(regs[1] >> 24);
      
      /* regs[0] and regs[3] are reserved */

      if((regs[2] & 0x80000000) == 0){
	decode_cyrix_tlb(regs[2]);
	decode_cyrix_tlb(regs[2] >> 8);
	decode_cyrix_tlb(regs[2] >> 16);
	decode_cyrix_tlb(regs[2] >> 24);
      }
    }
  }
}
