home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1999 January
/
pcwk_01_1999.iso
/
Tajnepp
/
MCLK093
/
TSENG.CPP
< prev
next >
Wrap
C/C++ Source or Header
|
1997-05-04
|
16KB
|
522 lines
/* tseng.cpp
*
* Tseng ET6000 class declarations
*/
// v0.93a Added Tseng Labs ET-6000 MCLK programming
// doesn't work with some brands of ET-6000 adapters
// v0.93b modified _et6000() class to set MEEN/IOEN controls
//
//
//
//
#include "tseng.h"
#include<dos.h>
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
_w32p::_w32p( vga_info info ) : vga( info )
{
outportb( 0x3BF, 0x03 ); // Unlock W32P "key"
outportb( 0x3D8, 0xA0 ); // Unlock W32P "key"
}
void
_w32p::_fxn1( int cmd ) // PCI burst mode enable
{ // bit4 of _CR34
if ( cmd == _QUERY ) {
strcpy( msg.text, "1 W32P PCI burst mode (PCI only)\n");
return;
}
uchar _CR34 = read_bit( _CRindex, 0x34, 4 );
uchar new_CR34= 0x0;
if ( param[ 0 ] != NULL )
new_CR34 = (uchar)atoi( param[ 0 ] );
sprintf( msg.text, "PCI Burst mode = %sd", bitstat( _CR34 ) );
switch ( cmd ) {
case _SET:
write_bit( _CRindex, 0x34, 4, new_CR34 );
sprintf( msg.temp,"\n...now %sd",
bitstat( read_bit( _CRindex, 0x34, 4 ) ) );
strcat( msg.text, msg.temp );
break;
case _HELP: case _GET:
sprintf( msg.temp, "\nPCI Burst mode (PCI only) \n\t%s",
"DISable = 0d\n\tENable = 1d");
strcat( msg.text, msg.temp );
break;
default:
sprintf( msg.text, "_w32p::_fxn1(cmd) UNRECOGNIZED cmd.");
status = EXIT_FAILURE;
}
}
void
_w32p::_fxn2( int cmd ) // memory interleaving
{ // bit7 of _CR32
if ( cmd == _QUERY ) {
strcpy( msg.text, "2 W32P memory interleaving (2mb only)\n");
return;
}
uchar _CR32 = read_bit( _CRindex, 0x32, 7 );
uchar new_CR32= 0x0;
if ( param[ 0 ] != NULL )
new_CR32 = (uchar)atoi( param[ 0 ] );
sprintf(msg.text,"DRAM memory interleaving = %sd", bitstat( _CR32 ) );
switch ( cmd ) {
case _SET:
write_bit( _CRindex, 0x32, 7, new_CR32 );
sprintf( msg.temp,"\n...now %sd", bitstat( new_CR32 ) );
strcat( msg.text, msg.temp );
break;
case _HELP: case _GET: sprintf( msg.temp,
"\nDRAM Memory interleaving ( requires 2mb DRAM )%s",
"\n\tDISable = 0d\n\tENable = 1d");
strcat( msg.text, msg.temp );
break;
default:
sprintf( msg.text, "_w32p::_fxn2(cmd) UNRECOGNIZED cmd.");
status = EXIT_FAILURE;
}
}
void
_w32p::_fxn3( int cmd ) // FIFO threshold control
{ // bit7,bit5 of _CR37
if ( cmd == _QUERY ) {
strcpy( msg.text, "3 W32P FIFO threshold control (2 items)\n");
return;
}
uchar low = read_bit( _CRindex, 0x37, 7 ),
high = read_bit( _CRindex, 0x37, 5 );
sprintf( msg.text, "FIFO low threshold = %u, FIFO high threshold = %u",
low, high );
if ( num_param < 2 && cmd == _SET ) {
strcat( msg.text, "\nError! TWO parameters required!");
cmd = _HELP; }
else if ( num_param >= 2 ) {
low = ( (uchar)atoi( param[ 0 ] ) ) & 0x01;
high = ( (uchar)atoi( param[ 1 ] ) ) & 0x01;
}
switch ( cmd ) {
case _SET: write_bit( _CRindex, 0x37, 7, low );
write_bit( _CRindex, 0x37, 5, high );
sprintf( msg.temp, "\n...low = %u, high = %u ", low, high );
strcat( msg.text, msg.temp );
break;
case _HELP: case _GET: sprintf( msg.temp,
"\nLow threshold ... 0=normal, 1=increased%s%s%s",
"\nHigh threshold ... higher priority for ",
"\n\t0 = W32p (accelerator uses more bandwidth)",
"\n\t1 = CPU (host accesses get higher priority)");
strcat( msg.text, msg.temp );
break;
default:
sprintf( msg.text, "_w32p::_fxn3(cmd) UNRECOGNIZED cmd.");
status = EXIT_FAILURE;
}
}
void
_w32pb::_fxn4( int cmd ) // Fast read/write control
{ // bits5-4 of TS Register6
if ( cmd == _QUERY ) {
strcpy( msg.text,
"4 W32P fast read/write control (2 items, W32p RevB +)\n");
return;
}
uchar read = read_bit( _SRindex, 0x6, 5 ),
write = read_bit( _SRindex, 0x6, 4 );
sprintf( msg.text, "Fast read control = %sd, Fast write control = %sd",
bitstat( read ), bitstat( write ) );
if ( num_param < 2 && cmd == _SET ) {
strcat( msg.text, "\nError! TWO parameters required!");
cmd = _HELP; }
else if ( num_param >= 2 ) {
read = ( (uchar)atoi( param[ 0 ] ) ) & 0x01;
write = ( (uchar)atoi( param[ 1 ] ) ) & 0x01;
}
switch ( cmd ) {
case _SET: write_bit( _SRindex, 0x6, 5, read );
write_bit( _SRindex, 0x6, 4, write );
sprintf( msg.temp, "\n...fast read = %s, fast write = %s ",
bitstat( read ), bitstat( write ) );
strcat( msg.text, msg.temp );
break;
case _HELP: case _GET: sprintf( msg.temp,
"\nRequires W32p RevB or better\n2 parameters %s",
" ... 1=ENABLE, 0=DISABLE" );
strcat( msg.text, msg.temp );
break;
default:
sprintf( msg.text, "_w32pb::_fxn4(cmd) UNRECOGNIZED cmd.");
status = EXIT_FAILURE;
}
}
void
_w32pb::_fxn5( int cmd ) // PCI burst mode enable
{ // bit6 of _SR06
if ( cmd == _QUERY ) {
strcpy( msg.text, "5 W32P 0 wait-state control (W32p RevB + )\n");
return;
}
uchar _SR06 = read_bit( _SRindex, 0x06, 6 );
sprintf( msg.text, "Zero read/write wait-state = %sd",
bitstat( !_SR06 ) );
if ( param[ 0 ] != NULL )
_SR06 = ( (uchar)atoi( param[ 0 ] ) ) & 0x01 ;
switch ( cmd ) {
case _SET:
write_bit( _SRindex, 0x06, 6, _SR06 );
sprintf( msg.temp,"\n...now %sd", bitstat( !_SR06 ) );
strcat( msg.text, msg.temp );
break;
case _HELP: case _GET:
sprintf( msg.temp, "\nZero wait-state (W32p RevB + )\n\t%s",
"DISable = 1d\n\tENable = 0d");
strcat( msg.text, msg.temp );
break;
default:
sprintf( msg.text, "_w32pb::_fxn5(cmd) UNRECOGNIZED cmd.");
status = EXIT_FAILURE;
}
}
// v0.93 Tseng Labs ET-6000 class definition
// Constructor
_et6000::_et6000( vga_info info ) : vga( info )
{
// pci_bios_type *pci_bios;
// pci_device_handle_type pci_vga;
int i;
dword creg; // Configuration test variable to test for VL-bus ET6000
pci_bios=new pci_bios_type; // Open PCI-bios routines, INT 0x1A
pci_bus = FALSE;
// Note, the absence of BIOS-support for PCI does not automatically
// mean the host-bus isn't PCI. It could mean an older system BIOS.
// Currently, MCLK requires BIOS-support for PCI-devices.
if ( pci_bios->installation_check() != NULL )
{ // Good, PCI_BIOS present
pci_vga.vendor=0x100C; // Tseng Labs, Inc.
pci_vga.device=0x3208; // ET-6000
pci_vga.index = 0; // Only look for 1st installed ET6000
// Look for PCI ET6000, if found, find_device() will store
// the host/bus# and dev/func# into our *pci_vga object
if ( pci_bios->find_device( &pci_vga ) == TRUE )
{
pci_bus = TRUE;
strcat( id.chipset, " (PCI config)" );
}
}
if ( pci_bus == FALSE ) // No ET6000 found yet, so check VL-bus
{
for (i = 0; i < 4; ++ i ) // VL-IO can be at F100, x1, x2, or x3
outportb( 0xF100 + i, 0 ); // Enable VL-IO on ET6000
// Assume ET6000 VL-BUS installed, check for vendor/device ID
creg.b.b0 = read_cbyte( 0 ); // read ET6000 config-register
creg.b.b1 = read_cbyte( 1 ); // index 0, 1, 2, & 3
creg.b.b2 = read_cbyte( 2 ); //
creg.b.b3 = read_cbyte( 3 ); //
// Test for Tseng Labs ET6000, vendor 0x100C, Device 0x3208
if ( creg.w.w0 == 0x100C && creg.w.w1 == 0x3208 ) ;
//strcat( id.chipset, " VL-bus" );
else
strcat( id.chipset, " not found, assume VL-bus config" );
// 0x3CA is Feature Control Read Register
// Bit 5 specifies host-bus config, bit5=1 VL-BUS, bit5=0 PCI
// if ( read_bit( 0x3CA, 5 ) == 1 )
// {
// }
}
// Set Memory-space enable bit and IO space enable bit
pci_cfg04= read_cbyte( 4 ); // Preserve original value
write_cbyte( 4, pci_cfg04 | 0x03 ); // Set bits 0 and 1
}
// v0.93b Destructor
_et6000::~_et6000()
{
write_cbyte( 4, pci_cfg04 ); // Restore PCI CFG04 register
}
uchar
_et6000::read_cbyte( const uchar index )
{
uchar value, status = TRUE;
if ( pci_bus == TRUE )
{
status = pci_bios->read_cbyte( pci_vga, index, &value );
return value;
} else
return inportb( 0xF100 + index );
// ET6000 in VL-bus configuration has config registers fixed at
// port-io space F100h
}
uchar
_et6000::write_cbyte( const uchar index, const uchar value )
{
uchar status= TRUE;
if ( pci_bus == TRUE )
{
if ( pci_bios->write_cbyte( pci_vga, index, value ) != 0 )
status = FALSE;
} else
outportb( 0xF100 + index, value );
// ET6000 in VL-bus configuration has config registers fixed at
// port-io space F10Fh
return status;
}
message
_et6000::_info( void )
{
INITMSG( msg.text );
dword baseio;
baseio.b.b0 = 0x01; // ET6000 Hardware default
baseio.b.b1 = read_CR( 0x21 ); // bits 15-8 of base address 1
baseio.b.b2 = read_CR( 0x22 ); // bits 23-16 of base address 1
baseio.b.b3 = read_CR( 0x23 ); // bits 31-24 of base address 1
msgout << "IO config address = 0x" ;
hexout( msgout, baseio.b.b3 ); // print reg.h.bl in "XX" format
hexout( msgout, baseio.b.b2 );
msgout << " ";
hexout( msgout, baseio.b.b1 );
msgout << "00 ";
msgout << ends ;
return msg;
}
void
_et6000::mclk_help( void ) // Display help for ET6000 MCLK programming
{
INITMSG( msg.temp ); // initialize msgout function for TEMP
msgout << "\nFormula for ET-6000 MCLK driver... " <<
"(3 parameters, M, N, R)\n\t( M + 2 )\n\t--------- * 14.31818MHz" <<
"\n\t(N+2)*2^R\n\n\tConstraint: MCLK < 135MHz (default = 90MHz)" <<
"\n\t and... 1<=M<=127 1<=N<=31 0<=R<=3" ;
msgout << ends; // Terminate msgout iostream with NULL
}
void // Read CLOCK1 ET6000 registers CFG 0x67/0x68
_et6000::read_clock1( uchar *byte1, uchar *byte0 )
{
uchar temp; // temp Data registers
// CLKDAC registers are 0x67/68, and 0x69, where 0x67/68 is "index"
// and 0x69 is "data", Clock1 is index 0xA
// Register layout for 0x67/0x68
// bit[7:0] RRRR 3210 -> "R" = reserved, "3210" = index
temp = read_cbyte( 0x67 ) & 0xF0; // Read/modify/write
write_cbyte( 0x67, temp | 0xA ); // Select CLKDAC register 0xA
temp = read_cbyte( 0x68 ) & 0xF0; // read/modify/write
write_cbyte( 0x68, temp | 0xA ); // Select CLKDAC register 0xA
*byte0 = read_cbyte( 0x69 ); // Read Clock1 register byte0
*byte1 = read_cbyte( 0x69 ); // Read Clock1 register byte1
}
void
_et6000::_mclk( int cmd ) // MCLK reprogramming for ET6000
{
INITMSG( msg.text ); // initialize msgout function
if ( cmd == _QUERY ) {
msgout << "0 ET-6000 MCLK programming\n" << ends;
return;
}
union {
struct {
uchar b0; // Byte 0
uchar b1; // Byte 1
} b;
struct {
unsigned _M : 7; // "M" = bits6:0 of first byte
unsigned reserved1 : 1;
unsigned _N : 5; // "N1" = bits4:0 of second byte
unsigned _R : 2; // "N2" = bits 5:6 of second byte
unsigned reserved2 : 1;
double freq( void ) // Returns calculated PLL frequency
{
return ( ( _M + 2.0 ) * _OSC ) /
( ( _N + 2.0 ) * pow(2.0, _R) );
/* Calculates MCLK frequency from M, N1, N2 values
* returns double value MHz, works for ET6000
* Note, I renamed N1 -> N and N2 -> R, for code readability
* ( M + 2 )
* --------- * _FREF ... _FREF = 14.31818 MHz
* (N+2)*2^R
*
* constraint: 0 < M < 127, 0 < N < 31, 0 < R < 3
* and... N >= 1
*/
};
} name; // Named registers
} clock1; // Clock1 data structure, 16-bits total (2 bytes)
uchar _M, _N, _R; // parameters of CLKDAC
uchar byte0, byte1, temp;
read_clock1( &clock1.b.b1, &clock1.b.b0 );
// Read clock1 registers into struct clock1
// Load byte1 and byte0 with raw CLKDAC register values
msgout.precision( 2 );
msgout << "Old MCLK = " << clock1.name.freq() << " MHz ( M=" << (int)
clock1.name._M << ", N=" << (int)clock1.name._N << ", R=" << (int)
clock1.name._R << " ) ";
// sprintf( msg.text,"Old MCLK = %.2fMHz ( M=%u, N=%u, R=%u ) ",
// _PLL( _M, _N, _R ), _M, _N, _R );
if ( num_param < 3 && cmd == _SET ) {
msgout << "\n...not enough parameters, need total of 3.";
cmd = _HELP; } // Not enough parameters.
else {
clock1.name._M = (uchar)atoi( param[ 0 ] ) & 0x7F;
clock1.name._N = (uchar)atoi( param[ 1 ] ) & 0x1F;
clock1.name._R = (uchar)atoi( param[ 2 ] ) & 0x03;
}
switch ( cmd ) {
case _SET:
temp = read_cbyte( 0x67 ) & 0xF0; // Read/modify/write
write_cbyte( 0x67, temp | 0xA ); // Select CLKDAC register 0xA
temp = read_cbyte( 0x68 ) & 0xF0; // read/modify/write
write_cbyte( 0x68, temp | 0xA ); // Select CLKDAC register 0xA
write_cbyte( 0x69, clock1.b.b0 ); // "M byte" goes first
write_cbyte( 0x69, clock1.b.b1 ); // then N1/N2 byte
read_clock1( &clock1.b.b1, &clock1.b.b0 );// Reread new values
msgout << "\nNew MCLK = " << clock1.name.freq() << " MHz ( M="
<< (int)clock1.name._M << ", N=" << (int)clock1.name._N <<
", R=" << (int)clock1.name._R << " ) ";
break;
case _HELP: case _GET:
msgout << "\nTseng Labs ET-6000 MCLK programming";
mclk_help(); // Get ET6000 mclk help, put in msg.temp
msgout << msg.temp;
break;
default:
msgout << "_et6000::_mclk(cmd) UNRECOGNIZED cmd.";
status = EXIT_FAILURE;
}
msgout << ends; // Terminate msgout iostream with NULL
}
void
_et6000::_fxn1( int cmd ) // RAS/CAS configuration register (PCICFG 0x44)
{
INITMSG( msg.text ); // initialize msgout function
union {
uchar byte;
struct {
unsigned csw : 2; // bits 0-1
unsigned rsp : 2; // bits 2-3
unsigned rcd : 2; // bits 4-5
unsigned unused : 2;// bits 6-7
} x;
} creg; // Configuration register structure
if ( cmd == _QUERY ) {
msgout<<"1 ET-6000 RAS/CAS configuration (3 parameters)\n"<<ends;
return;
}
creg.byte = read_cbyte( 0x44 ); // PCICFG 0x44 = RAS/CAS config
msgout << "Old RAS/CAS configuration : RCD=" << (int)( creg.x.rcd ) <<
" RSP=" << (int)( creg.x.rsp ) << " CSW=" << (int)( creg.x.csw );
if ( num_param < 3 && cmd == _SET ) {
msgout << "\nError! Need THREE parameters for input!" ;
cmd = _HELP;
} else if ( num_param >= 3 ) {
creg.byte = creg.byte & 0xC0 ; // XX00 0000 clear bits 5-0
creg.x.rcd = ( (uchar)atoi( param[ 0 ] ) ) & 0x03;
creg.x.rsp = ( (uchar)atoi( param[ 1 ] ) ) & 0x03;
creg.x.csw = ( (uchar)atoi( param[ 2 ] ) ) & 0x03;
}
switch ( cmd ) {
case _SET:
write_cbyte( 0x44, creg.byte );
creg.byte = read_cbyte( 0x44 ); // Re-read RAS/CAS config
msgout << "\nNew RAS/CAS configuration : RCD=" <<
(int)( creg.x.rcd ) << " RSP=" << (int)( creg.x.rsp ) <<
" CSW=" << (int)( creg.x.csw );
break;
case _GET: case _HELP:
msgout << "\n\nET6000 RAS/CAS configuration register\n\t" <<
"RCD = DRAM/MDRAM RAS to CAS delay memory timing\n\t" <<
"RSP = DRAM/MDRAM RAS to RAS precharge time \n\t" <<
"CAS = DRAM read cycle pulse width, or MDRAM CAS to read "
"data latency\n\n\tValid input range (RCD/RSP/CAS) is 0-3.";
break;
default: msgout << "_et6000::_fxn1(cmd) UNRECOGNIZED cmd.";
status = EXIT_FAILURE;
}
msgout << ends; // Terminate msgout iostream with NULL
}