/*****************************************************************************
* Function: cpu_type (char *dir0, char *dir1)
*
* Purpose: Check for Cyrix CPU
* Determination of which Cyrix CPU
*
* Technique: Cyrix Identification Alogorithm:
*
* Execute 2 Tests:
* t1 = if CR2:2 is r/w then t1 = TRUE else FALSE
* t2 = if CR3:7 is r/w then t2 = TRUE else FALSE
*
* Decision Table:
* if t1 and t2 then DIR0 and DIR1 supported
* if t1 and !t2 then Cx486S_a no ID Reg
* if !t1 and t2 then Cx486SLC or DLC with DIR0,DIR1
* if !t1 and !t2 then Cx486_pr
*
* Parameters: pointer to char dir0 value location
* pointer to char dir1 value location
*
* Returns:
* unsigned short (16bit) <DIR1<15:8>,DIR0<7:0>
* DIR0 => Device Id Value in Cyrix Register 0xfe
* DIR1 => Step Id and Revision Value in Cyrix Register 0xff
*
* Calls: iscyrix() - Test for Cyrix CPU
* cx_r (reg) - Read Cyrix Configuration Register
* cx_w (reg, val) - Write Cyrix Configuration Register
* isv86() - Test if V86 mode
* isb() - Test for B step
******************************************************************************/
#define UNKNOWN 0xff
#define Cx486_pr 0xfd // ID Register not supported, software created
#define Cx486S_a 0xfe // ID Register not supported, software created
#define FALSE 0
#define TRUE 1
#define CR2_MASK 0x4 // LockNW
#define CR3_MASK 0x80 // Resereved bit 7
// Prototypes
int iscyrix();
char cx_r (char);
char cx_w (char, char);
int isv86();
int isb();
unsigned short cpu_type(char *dir0, char *dir1)
{
char temp, orgc2, newc2, orgc3, newc3;
int cr2_rw=FALSE, cr3_rw=FALSE;
unsigned short type;
*dir0 = UNKNOWN;
type = UNKNOWN;
if ( iscyrix() ) // this is a Cyrix part
{
// ********* Disable SMI *********
// ************************************
// Test Cyrix c2 register read/writable
// ************************************
orgc2 = cx_r (0xc2); // get current c2 value
newc2 = orgc2 ^ CR2_MASK; // toggle test bit
cx_w (0xc2, newc2); // write test value to c2
cx_r (0xc0); // dummy read to change bus
if (cx_r (0xc2) != orgc2) // did test bit toggle
cr2_rw = TRUE; // yes bit changed
cx_w (0xc2, orgc2); // return c2 to original value
// ************************************
// end c2 read writeable test
// ************************************
// ************************************
// Test Cyrix c3 register read/writable
// ************************************
orgc3 = cx_r (0xc3); // get current c3 value
newc3 = orgc3 ^ CR3_MASK; // toggle test bit
cx_w (0xc3, newc3); // write test value to c3
cx_r (0xc0); // dummy read to change bus
if (cx_r (0xc3) != orgc3) // did test bit change
cr3_rw = TRUE; // yes it did
cx_w (0xc3, orgc3); // return c3 to original value
// ************************************
// end c3 read writeable test
// ************************************
if ((cr2_rw && cr3_rw) || (!cr2_rw && cr3_rw)) //DEV ID register ok
{
// <<<<<<< READ DEVICE ID Reg >>>>>>>>
*dir0 = cx_r (0xfe);
*dir1 = cx_r (0xff);
type = *dir0; // lower byte gets IDIR0
type += *dir1 << 8; // upper byte gets IDIR1
}
else if (cr2_rw && !cr3_rw) // Cx486S A step
{
*dir0 = Cx486S_a;
type = *dir0; // lower byte
}
else if (!cr2_rw && !cr3_rw) // Pre ID Regs. Cx486SLC or DLC
{
*dir0 = Cx486_pr;
type = *dir0; // lower byte
if (!isv86 ()) // check v86 mode, can't do isb() in v86
{
*dir1 = isb()+1;
type += *dir1 << 12; // upper byte, A step or early B
}
}
// ********* Enable SMI *********
} // Cyrix part
return (type);
}