home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1999 January / pcwk_01_1999.iso / Tajnepp / MCLK093 / S3.CPP < prev    next >
C/C++ Source or Header  |  1997-05-05  |  34KB  |  1,141 lines

  1. /*    s3.cpp        05/04/97    0.93ß
  2.  *
  3.  *    S3 class declarations
  4.  *
  5.  *    As of current, support includes...
  6.  *    S3-801/805    ( 4 settings, untested)
  7.  *    S3-Vision864/866/868    ( 4 settings, partially tested)
  8.  *    S3-Trio32/Trio64    ( 4 settings, untested)
  9.  *
  10.  *    S3 SDAC MCLK programming ( non-chipset specific, should work any S3 )
  11.  *   TI-VP3025/3026 MCLK programming ( only for 964/968 chipsets )
  12.  *    S3 Trio (32/64/64V+) MCLK programming
  13.  *    S3 Virge and VirgeVX MCLK programming (actually same as Trio MCLK)
  14.  *
  15.  *   new in v0.83
  16.  *    +created _S3::_868, _S3::_968 objects, primarily so the ::_info
  17.  *        routine will correctly discriminate EDO/burst/1-cycle RAM
  18.  *    v0.84  +fixed _S3 init code, so extended SR registers are unlocked
  19.  *          +also added 2MCLK/3MCLK write control for S3 Trio chipsets
  20.  *    v0.86  +fixed the S3 SDAC RAMDAC detection code...
  21.  *    v0.87  +fixed the S3 SDAC detection code...REALLY!  It should no
  22.  *            longer hang non-SDAC cards.
  23.  *    v0.88  +added MCLK routine for _Virge and _VirgeVX classes
  24.  *    v0.90  cosmetic change to reported-text in _864::_fxn1()
  25.  *   v0.92  cosmetic changes (no new code)
  26.  *   v0.93  added code for TIVP3025 RAMDAC (S3 964/968 only)
  27.  *            TIVP3025 code doesn't work yet
  28.  *       93b modified _s3::_s3() and added _s3::~_s3() to clean-up
  29.  *          the modifications made to certain S3 registers
  30.  *          modified TIVP3025/26 detection code
  31.  */
  32.  
  33. #include "s3.h"
  34.  
  35. #include<dos.h>
  36. #include<string.h>
  37. #include<stdio.h>
  38. #include<stdlib.h>
  39. #include<math.h>
  40. #include<iostreams.h>
  41.  
  42.  
  43. _S3::_S3( vga_info info ) : vga( info )    // Constructor
  44. {
  45.     uchar DAC;    //    temp variable for special RAMDAC detection purposes
  46.     uchar temp;    //    scratch pad
  47.  
  48.      save_cr38 = read_CR( 0x38 );    // Preserve register value
  49.      save_cr39 = read_CR( 0x39 );    // ...
  50.      save_cr45 = read_CR( 0x45 );    // ...
  51.      save_cr55 = read_CR( 0x55 );    // ...
  52.      save_sr08 = read_SR( 0x08 );    // ...
  53.     write_CR( 0x38, 0x48 );        // Unlock S3 VGA registers
  54.     write_CR( 0x39, 0xA5 );        // Unlock S3 801/805 registers
  55.     write_SR( 0x08, 0x06 );        // Unlock ext SR registers
  56.  
  57.      sdac = FALSE;
  58.      tivpdac = FALSE;
  59.  
  60.      // v0.86 The preceding two lines were added, to correctly force the
  61.     // following loop to operate correctly.  The write-operation resets
  62.     // the SDAC's internal counter, so now we can read it exactly 4 times.
  63.  
  64.     int i=0;    // Initialize loop counter
  65.     do    {
  66.         DAC = inportb( _DACmask );
  67.         temp = inportb( _DACmask );
  68.     }    while ( temp != DAC && i++ < 255 );
  69.  
  70.     // v0.87 added the i < 255 ... non-SDAC S3's should no longer hang
  71.  
  72.     // in case DACmask was preloaded to return _DACID, we reset the
  73.     // counter (wait until consecutive read is equal to previous read)
  74.  
  75.     if ( i < 255 )    {
  76.         i = 0;
  77.         do    {
  78.             DAC = inportb( _DACmask );
  79.         }    while ( temp == DAC && i++ < 255 );
  80.     }
  81.  
  82.      if ( DAC == 0x70 || DAC == 0x73 ) {    //    S3 SDAC detected
  83.         if ( DAC == 0x70 )
  84.             strcat( id.chipset, " + SDAC (ID 0x70)" );
  85.         else
  86.             strcat( id.chipset, " + SDAC (ID 0x73)" );
  87.         sdac = TRUE;    // S3 SDAC RAMDAC is present
  88.     }
  89.  
  90.      if ( sdac == FALSE )
  91.      {    // Check for TIVP 3025 RAMDAC
  92.          // The TIVP 3025 RAMDAC's ID-byte is at indirect register 0x3F
  93.           // The indirect registers are accessed through "INDEX" and "DATA"
  94.           // RS[2:0]=110 "INDEX" , RS[2:0]=111 "DATA"
  95.  
  96.           write_bit( _CRindex, 0x33, 4, 0 );    //    Unlock DAC writes
  97.  
  98.          write_bit( _CRindex, 0x55, 0, 1 );    //    set DAC extension, RS2=1
  99.           write_bit( _CRindex, 0x55, 1, 0 );    //    clear DAC extension, RS3=0
  100.           write_bit( _CRindex, 0x45, 5, 0 );    //    set RS3/ODF to RS3
  101.           outportb( _DACmask, 0x3F );    // Write 0x3F to "INDEX" (RS[110])
  102.           DAC=inportb( _DACindexR );    // Read ID byte from "DATA" (RS[111])
  103.           outportb( _DACmask, 0xFF );    // Restore DACmask to 0xFF
  104.  
  105.           if ( DAC == 0x25 )
  106.         {
  107.               tivpdac = TRUE;
  108.                strcat( id.chipset, " + TIVP3025" );
  109.           }
  110.           else if ( DAC == 0x26 )    // added TIVP3026 detection, v0.93b
  111.           {
  112.               tivpdac = TRUE;
  113.                strcat( id.chipset, " + TIVP3026" );
  114.         }
  115.      }
  116.  
  117. }
  118.  
  119.  
  120. void
  121. _S3::mclk_help( void )    //    Display help for S3 DAC/ Trio MCLK programming
  122. {
  123.     sprintf( msg.temp, "\nFormula for S3 MCLK driver... %s%s%s",
  124.      "(3 parameters, M, N, R)\n\t( M + 2 )\n\t--------- * 14.31818MHz",
  125.      "\n\t(N+2)*2^R\n\n\tConstraint:    135MHz < 2^R * 14.31818MHz < 270MHz",
  126.      "\n\t     and...   1<=M<=127    1<=N<=31    0<=R<=3" );
  127. }
  128.  
  129.  
  130. _S3::~_S3()    // Destructor added to clean-up MCLK's register fiddling
  131. {
  132.     write_CR( 0x38, save_cr38 );    // Restore register value
  133.     write_CR( 0x39, save_cr39 );    // ... v0.93b
  134.     write_CR( 0x45, save_cr45 );
  135.      write_CR( 0x55, save_cr55 );    // ...
  136.     write_SR( 0x08, save_sr08 );
  137. }
  138.  
  139. /*    PLL
  140.  *
  141.  *    Calculates MCLK frequency from M, N, _FREF, and R values
  142.  *    returns double value MHz, works for S3 SDAC and S3Trio
  143.  */
  144. double
  145. _S3::_PLL( uchar M, uchar N, uchar R )
  146. {
  147.     double Rval;
  148.  
  149.     switch ( R )    {
  150.         case 0:    case 1:    case 2:    case 3:
  151.             Rval = pow( 2.0, R );        //    Rval = 2 ^ R;
  152.  
  153.             break;    // <- how'd I forget to put this here... //
  154.         default:
  155.             Rval=0;    // Error!
  156.     }
  157.     return ( ( M + 2.0 ) * _OSC ) / ( ( N + 2.0 ) * Rval );
  158.     /*    ( M + 2 )
  159.      *   --------- * _FREF ... _FREF = 14.31818 MHz
  160.      *   (N+2)*2^R
  161.      *
  162.      *    constraint:    135MHz < 2^R * _FREF < 270MHz
  163.      *        and...    N >= 1
  164.      */
  165. }
  166.  
  167.  
  168. message
  169. _S3::_ramtype( uchar mask )
  170. {    //    mask determines which values are valid, i.e. not "RESERVED"
  171.     uchar _CR36 = read_CR( 0x36 );
  172.     _CR36 = ( _CR36 >> 2 ) & 0x03;     // 7654 3210 -> 0000 0032, bits 3-2
  173.  
  174.     switch ( _CR36 )    {
  175.         case 0:    if ( ( mask & 0x01 ) )    //    If bit0 is SET
  176.                     sprintf( msg.text, "1-cycle EDO RAM" );
  177.                 else
  178.                 sprintf( msg.text, "RESERVED [ CR36(3:2) = 00 ]" );
  179.             break;
  180.         case 1:   if ( ( mask & 0x02 ) )    //    If bit1 is SET
  181.                     sprintf( msg.text, "Burst-mode RAM" );
  182.                 else
  183.                 sprintf( msg.text, "RESERVED [ CR36(3:2) = 01 ]" );
  184.             break;
  185.         case 2:    sprintf( msg.text, "2-cycle EDO RAM" );
  186.             break;
  187.         case 3:    if ( ( mask & 0x08 ) )    //    If bit 3 is SET
  188.                     sprintf( msg.text, "fast-page mode RAM");
  189.                 else
  190.                 sprintf( msg.text, "RESERVED [ CR36(3:2) = 04 ]" );
  191.             break;
  192.         default:    sprintf( msg.text, "UNKNOWN [ 0x%02X ]", mask );
  193.     }
  194.     status = EXIT_SUCCESS;
  195.     return msg;
  196. }
  197.  
  198.  
  199. void
  200. _S3::_mclk( int cmd )    //    MCLK programming for S3 SDAC chips
  201. {
  202.     if ( cmd == _QUERY && sdac == TRUE )    {
  203.         sprintf( msg.text,"0  S3 SDAC MCLK programming\n" );
  204.         return;    }
  205.     else if ( sdac == FALSE )    {
  206.         sprintf( msg.text,"0  MCLK function NOT available\n" );
  207.         return;
  208.     }
  209.  
  210.     uchar _CR33 = read_bit( _CRindex, 0x33, 4 ); // Remember LOCK DACW v0.84
  211.  
  212.     uchar _M, _N, _R, byte1, byte2;
  213.     write_bit( _CRindex, 0x55, 0, 1 );    //    Enable DAC extension RS2
  214.     outportb( _DACindexR, 0x0A );    //    Set to PLL CLK1 parameter
  215.  
  216.     byte1 = inportb( _DACIO );
  217.     byte2 = inportb( _DACIO );
  218.     _M = byte1 & 0x7F;
  219.     _N = byte2 & 0x1F;
  220.     _R = ( byte2 >> 5 ) & 0x03;
  221.     sprintf( msg.text,"Old MCLK = %.2fMHz ( M=%u, N=%u, R=%u ) ",
  222.         _PLL( _M, _N, _R ), _M, _N, _R );
  223.  
  224.     if ( num_param < 3 && cmd == _SET )    {
  225.         strcat( msg.text, "\n...not enough parameters, need total of 3." );
  226.         cmd = _HELP;    }    //    Not enough parameters.    }
  227.     else    {
  228.         _M = (uchar)atoi( param[ 0 ] ) & 0x7F;
  229.         _N = (uchar)atoi( param[ 1 ] ) & 0x1F ;
  230.         _R = (uchar)atoi( param[ 2 ] );
  231.         byte1 = ( byte1 & 0x80 ) | _M;
  232.         _R = ( _R << 5 ) & 0X60;
  233.         byte2 = ( byte2 & 0x80 ) | _N | _R;
  234.     }
  235.  
  236.     switch ( cmd )    {
  237.         case _SET:    write_bit( _CRindex, 0x33, 4, 0 );
  238.                     // enable RAMDAC writes
  239.             write_bit( _CRindex, 0x55, 0, 1 );    // actv RS2
  240.             outportb( _DACindexW, 0x0A ); // Set to PLL CLK1
  241.             outportb( _DACIO, byte1 );    //    Write 1st byte
  242.             outportb( _DACIO, byte2 );    //    Write 2nd byte
  243.  
  244.             write_bit( _CRindex, 0x55, 0, 1 );
  245.                 //    Enable DAC extension RS2
  246.             outportb( _DACindexR, 0x0A );    //    Set to PLL CLK1 parameter
  247.             byte1 = inportb( _DACIO );
  248.             byte2 = inportb( _DACIO );
  249.             _M = byte1 & 0x7F;
  250.             _N = byte2 & 0x1F;
  251.             _R = ( byte2 >> 5 ) & 0x03;
  252.  
  253.             sprintf(msg.temp,"\nNew MCLK = %.2fMHz ( M=%u, N=%u, R=%u ) ",
  254.                 _PLL( _M, _N, _R ), _M, _N, _R );
  255.             strcat( msg.text, msg.temp );
  256.             outportb( _DACIO, byte1 );
  257.             write_bit( _CRindex, 0x33, 4, _CR33 );    // Restore bit4
  258.             break;
  259.         case _GET:    case _HELP:
  260.             strcat( msg.text, "\nS3 SDAC MCLK programming" );
  261.             mclk_help();    //    Get mclk help, put in msg.temp
  262.             strcat( msg.text, msg.temp );
  263.             break;
  264.         default:
  265.             sprintf( msg.text, "_S3::_mclk(cmd)  UNRECOGNIZED cmd.");
  266.             status = EXIT_FAILURE;
  267.     }
  268.  
  269.  
  270. }
  271.  
  272.  
  273. void
  274. _S3::_fxn1( int cmd )    //    WST CTL, EWRT POST Write-wait state control
  275. {
  276.     if ( cmd == _QUERY )    {
  277.         sprintf( msg.text,"1  S3-801/805 WST CTL, EWRT POST\n%s",
  278.             "   (2 items : write-wait state, write-buffer controls)\n" );
  279.         return;
  280.     }
  281.  
  282.     uchar _bit2 = read_bit( _CRindex, 0x40, 2 ),
  283.         _bit3 = read_bit( _CRindex, 0x40, 3 );
  284.  
  285.     sprintf(msg.text,"Old WST-CTL wait-states = %uT, buffer = %sd",_bit2,
  286.         bitstat( _bit3 ) );
  287.  
  288.     if ( num_param < 2 && cmd == _SET )    {
  289.         strcat( msg.text, "\nError!  TWO parameters required!");
  290.         cmd = _HELP; }
  291.     else    if ( num_param >= 2 ) {
  292.         _bit2 = ( (uchar)atoi( param[ 0 ] ) ) & 0x01;
  293.         _bit3 = ( (uchar)atoi( param[ 1 ] ) ) & 0x01;
  294.     }
  295.  
  296.     switch ( cmd )    {
  297.         case _SET:
  298.             write_bit( _CRindex, 0x40, 2, _bit2 );
  299.             write_bit( _CRindex, 0x40, 3, _bit3 );
  300.             sprintf( msg.temp,"\nNew WST-CTL = %uT, buffer = %sd", _bit2,
  301.                 bitstat( _bit3 ) );
  302.             strcat ( msg.text, msg.temp );
  303.             break;
  304.         case _HELP:    case _GET:
  305.             sprintf( msg.temp, "\nWrite Wait State Control\n\t%s%s",
  306.              "0 = no wait\n\t1 = one wait-state\nEnable Fast-Write ",
  307.              "buffer\n\t0 = DISABLE\n\t1 = ENABLE");
  308.             strcat( msg.text, msg.temp );
  309.             break;
  310.         default:
  311.             sprintf( msg.text, "_S3::_fxn1(cmd)  UNRECOGNIZED cmd.");
  312.             status = EXIT_FAILURE;
  313.     }
  314. }
  315.  
  316.  
  317. void
  318. _S3::_fxn2( int cmd )    //    Decode wait control, 386/486 local bus
  319. {    //    bits 5-4 of _CR40
  320.     if ( cmd == _QUERY )    {
  321.         strcpy( msg.text, "2  S3-805 Decode wait control (local bus)\n" );
  322.         return;
  323.     }
  324.  
  325.     uchar _CR40 = ( read_CR( 0x40 ) >> 4 ) & 0x03 ;
  326.     uchar new_CR40= 0x02;    //    3 wait states, default
  327.  
  328.     if ( param[ 0 ] != NULL )
  329.         new_CR40 = (uchar)atoi( param[ 0 ] );
  330.  
  331.     sprintf( msg.text, "Old Decode = %uT wait-states (WS) ", shift (_CR40 ));
  332.  
  333.     switch ( cmd )    {
  334.         case _SET:    _CR40 = read_CR ( 0x40 ) & 0xCF;    // XX00 XXXX
  335.             write_CR( 0x40, _CR40 | ( ( new_CR40 << 4 ) & 0x30 ) );
  336.             sprintf(msg.temp,"\n...now set to %uT WS ",shift(new_CR40 ));
  337.             strcat( msg.text, msg.temp );
  338.             break;
  339.         case _HELP:    case _GET:
  340.             sprintf( msg.temp,"\nDecode wait Control (local bus only)%s",
  341.                 "\n\t0 = 0WS\n\t1 = 1WS\n\t2 = 3WS\n\t3 = 2WS");
  342.             strcat( msg.text, msg.temp );
  343.             break;
  344.         default:
  345.             sprintf( msg.text, "_S3::_fxn3(cmd)  UNRECOGNIZED cmd.");
  346.             status = EXIT_FAILURE;
  347.     }
  348. }
  349.  
  350.  
  351. void
  352. _S3::_fxn3( int cmd )    //    Read Wait control
  353. {    //    bits 7-6 of _CR40
  354.     if ( cmd == _QUERY )    {
  355.         strcpy( msg.text,
  356.             "3  S3-801/805 Read-wait state control (local bus/ISA)\n" );
  357.         return;
  358.     }
  359.  
  360.     uchar _CR40 = ( read_CR( 0x40 ) >> 6 ) & 0x03;
  361.     uchar new_CR40= 0x02;    //    3 wait states, default
  362.  
  363.     if ( param[ 0 ] != NULL )
  364.         new_CR40 = (uchar)atoi( param[ 0 ] );
  365.  
  366.     sprintf( msg.text, "Old Read Wait Control = %u waitstates (WS) ",
  367.         shift (_CR40 ) );
  368.  
  369.     switch ( cmd )    {
  370.         case _SET:    _CR40 = read_CR ( 0x40 ) & 0x3F;    // 00XX XXXX
  371.             write_CR( 0x40, _CR40 | ( ( new_CR40 << 6 ) & 0xC0 ) );
  372.             sprintf(msg.temp,"\nNow set to %uT WS ", shift ( new_CR40 ));
  373.             strcat( msg.text, msg.temp );
  374.             break;
  375.         case _HELP:    case _GET:
  376.             sprintf( msg.temp,"\nRead Wait Control\n\t%s",
  377.                 "0 = 0WS\n\t1 = 1WS\n\t2 = 3WS\n\t3 = 2WS");
  378.             strcat( msg.text, msg.temp );
  379.             break;
  380.         default:
  381.             sprintf( msg.text, "_S3::_fxn3(cmd)  UNRECOGNIZED cmd.");
  382.             status = EXIT_FAILURE;
  383.     }
  384. }
  385.  
  386.  
  387. void
  388. _S3::_fxn4( int cmd )    //    Read-ahead cache
  389. {    //    bits 5-4 of _CR40
  390.     if ( cmd == _QUERY )    {
  391.         strcpy( msg.text, "4  S3-801/805 Read ahead cache size\n" );
  392.         return;
  393.     }
  394.  
  395.     uchar _CR54 = read_CR( 0x54 ) & 0x07 ;
  396.     uchar new_CR54= 0x07;    //    Maximum allowed
  397.  
  398.     if ( param[ 0 ] != NULL )
  399.         new_CR54 = (uchar)atoi( param[ 0 ] );
  400.  
  401.     sprintf( msg.text, "Old Cache size set to %u accesses, and %sd", _CR54,
  402.         bitstat( read_bit( _CRindex, 0x58, 2 ) ) );
  403.  
  404.     switch ( cmd )    {
  405.         case _SET:    _CR54 = read_CR ( 0x54 ) & 0xF8;    // XXXX X000
  406.             write_CR( 0x54, _CR54 | ( new_CR54 & 0x07 ) );
  407.             sprintf(msg.temp,"\nCache set to %u accesses", read_CR( 0x54)
  408.                 & 0x07 ) ;
  409.             write_bit( _CRindex, 0x58, 2, 1 );    // Enable read-ahead
  410.             strcat( msg.text, msg.temp );
  411.             break;
  412.         case _HELP:    case _GET:
  413.             sprintf( msg.temp,"\nRead ahead cache (auto-enabled if %s",
  414.                 "modified)\n\tAcceptable values = 0, 1, 3, 7");
  415.             strcat( msg.text, msg.temp );
  416.             break;
  417.         default:
  418.             sprintf( msg.text, "_S3::_fxn3(cmd)  UNRECOGNIZED cmd.");
  419.             status = EXIT_FAILURE;
  420.     }
  421. }
  422.  
  423.  
  424. //--------------------S3 805i class definitions---------------------------
  425.  
  426. void
  427. _805i::_fxn5( int cmd )    //    Memory interleave control
  428. {    //    bit5 of _CR53, memory interleave control
  429.     if ( cmd == _QUERY )    {
  430.         strcpy( msg.text,"5  S3-805i memory interleave (2mb only)\n");
  431.         return;
  432.     }
  433.  
  434.     uchar new_CR53 = 0x0;    //    Disable interleaving by default
  435.  
  436.     if ( param[ 0 ] != NULL )
  437.         new_CR53 = ( (uchar)atoi( param[ 0 ] ) ) & 0x01;
  438.  
  439.     sprintf(msg.text,"Interleaving is %sd",
  440.         bitstat( read_bit( _CRindex, 0x53, 5 ) ) );
  441.  
  442.     switch ( cmd )    {
  443.         case _SET:
  444.             write_bit( _CRindex, 0x53, 5, new_CR53 );
  445.             sprintf( msg.temp, "\n...now %sd",
  446.                 bitstat ( read_bit( _CRindex, 0x53, 5 ) ) );
  447.             strcat ( msg.text, msg.temp );
  448.             break;
  449.         case _HELP:    case _GET:
  450.             sprintf( msg.temp, "\nMemory interleaving control\n\t%s",
  451.                 "0 = disabled\n\t1 = enabled (requires 2mb video RAM)");
  452.             strcat( msg.text, msg.temp );
  453.             break;
  454.         default:
  455.             sprintf( msg.text, "_805i::_fxn5(cmd)  UNRECOGNIZED cmd.");
  456.             status = EXIT_FAILURE;
  457.     }
  458. }
  459.  
  460.  
  461. //---------- S3 '64 and Trio chipsets -------------------------------------//
  462.  
  463.  
  464. message
  465. _864::_info( void )
  466. {
  467.     return _ramtype( 0x0C ) ;
  468.     //    Call _ramtype, allowing case2 & 3
  469. }
  470.  
  471. /*
  472. void
  473. _864::_fxn1( int cmd )    //    Ready Control delay (VL-BUS only )
  474. {    //    bit4 of _CR40
  475.     if ( cmd == _QUERY )    {
  476.         strcpy( msg.text,
  477.          "1  S3-864/964/Trio RDY CTL wait control (VL-bus only)\n");
  478.         return;
  479.     }
  480.  
  481.     uchar _CR40 = read_bit( _CRindex, 0x40, 4 );
  482.     uchar new_CR40= 0x01;
  483.  
  484.     if ( param[ 0 ] != NULL )
  485.         new_CR40 = ( (uchar)atoi( param[ 0 ] ) ) & 0x01;
  486.  
  487.     sprintf(msg.text,"Old RDY-CTL = %uT wait state(s) ", _CR40 );
  488.  
  489.     switch ( cmd )    {
  490.         case _SET:
  491.             write_bit( _CRindex, 0x40, 4, new_CR40 );
  492.             sprintf( msg.temp,"\nNew RDY-CTL=%uT", new_CR40 );
  493.             strcat ( msg.text, msg.temp );
  494.             break;
  495.         case _HELP:    case _GET:
  496.             sprintf( msg.temp, "\nVL-bus RDY Control delay\n\t%s",
  497.                 "0T no-wait = 0d\n\t1T One-wait= 1d");
  498.             strcat( msg.text, msg.temp );
  499.             break;
  500.         default:
  501.             sprintf( msg.text, "_864::_fxn1(cmd)  UNRECOGNIZED cmd.");
  502.             status = EXIT_FAILURE;
  503.     }
  504. }
  505. */
  506.  
  507.  
  508. void
  509. _864::_fxn1( int cmd )    //    Memory page mode control )
  510. {    //    bits3-2 of _CR36
  511.     if ( cmd == _QUERY )    {
  512.         strcpy( msg.text,
  513.          "1  S3-86x/96x/Trio memory page-mode control\n");
  514.         return;
  515.     }
  516.  
  517.     uchar _CR36 = read_CR( 0x36 ) & 0xF3;    // XXXX 00XX
  518.     uchar new_CR36 = _CR36 & 0x03;
  519.  
  520.     if ( param[ 0 ] != NULL )
  521.         new_CR36 = ( (uchar)atoi( param[ 0 ] ) ) & 0x03;
  522.  
  523.     switch ( cmd )    {
  524.         case _SET:
  525.             write_CR( 0x36, ( new_CR36 << 2 ) | _CR36 );
  526.             sprintf( msg.temp,"\nSelected RAM access-mode %u", new_CR36 );
  527.             strcat ( msg.text, msg.temp );
  528.             break;
  529.         case _HELP:    case _GET:
  530.             sprintf( msg.temp, "S3 86x/96x/Trio access-mode control%s%s%s",
  531.                 "\n\t0 = 1-cycle EDO (866/868/968)\n\t1 = burst DRAM ",
  532.                 "(866/868/968)\n\t2 = 2-cycle EDO",
  533.                 "\n\t3 = fast-page mode timing");
  534.             strcat( msg.text, msg.temp );
  535.             break;
  536.         default:
  537.             sprintf( msg.text, "_864::_fxn1(cmd)  UNRECOGNIZED cmd.");
  538.             status = EXIT_FAILURE;
  539.     }
  540. }
  541.  
  542.  
  543. void
  544. _864::_fxn2( int cmd )    //    Ready Control delay (VL-BUS only )
  545. {    //    bits 1-0 of _CR68
  546.     if ( cmd == _QUERY )    {
  547.         strcpy( msg.text,
  548.          "2  S3-864/964/Trio CAS', OE' strech time, WE' delay\n" );
  549.         return;
  550.     }
  551.  
  552.  
  553.     uchar _CR68 = read_CR( 0x68 ) & 0x03;
  554.     uchar new_CR68= 0x0;  //    maximum delay default
  555.  
  556.     if ( param[ 0 ] != NULL )
  557.         new_CR68 = ( (uchar)atoi( param[ 0 ] ) ) & 0x03;
  558.  
  559.     sprintf(msg.text,"Old stretch/delay value = %02X (see table) ", _CR68 );
  560.  
  561.     switch ( cmd )    {
  562.         case _SET:    _CR68 = read_CR( 0x68 ) & 0xFC;    //    XXXX XX00
  563.             write_CR( 0x68, _CR68 | new_CR68 );
  564.             sprintf( msg.temp,"\nNew delay value = %02X ", new_CR68 );
  565.             strcat ( msg.text, msg.temp );
  566.             break;
  567.         case _HELP:    case _GET:
  568.             sprintf( msg.temp, "\nDRAM timing delays/stretches%s",
  569.              "\n\t0 = 6.5ns\n\t1 = 5ns\n\t2 = 3.5ns\n\t3 = 0ns");
  570.             strcat( msg.text, msg.temp );
  571.             break;
  572.         default:
  573.             sprintf( msg.text, "_864::_fxn2(cmd)  UNRECOGNIZED cmd.");
  574.             status = EXIT_FAILURE;
  575.     }
  576. }
  577.  
  578.  
  579. //   Does not work for 86X/Trio chipsets!!!  Timing MUST be set to RDYIN'!
  580. /*
  581. void
  582. _864::_fxn3( int cmd )    //    Write latching delay (VL-BUS only )
  583. {    //    bit5 of _CR40,     1= SRDY', 0 = RDYIN'
  584.     if ( cmd == _QUERY )    {
  585.         strcpy( msg.text,
  586.             "3  S3-864/964 Write latching delay (VL-bus only)\n");
  587.         return;
  588.     }
  589.  
  590.     uchar _CR40 = read_bit( _CRindex, 0x40, 5 );
  591.     uchar new_CR40= 0x01;
  592.     sprintf( msg.text,"Old Write latch delay = (%ud, latch on ",_CR40 );
  593.     if ( _CR40 )
  594.         strcat( msg.text, "SRDY' )" );
  595.     else
  596.         strcat( msg.text, "RDYIN' )" );
  597.  
  598.     if ( param[ 0 ] != NULL )
  599.         new_CR40 = (uchar)atoi( param[ 0 ] );
  600.  
  601.     switch ( cmd )    {
  602.         case _SET:
  603.             write_bit( _CRindex, 0x40, 5, new_CR40 );
  604.             sprintf(msg.temp,"\nNew Write latch delay=%ud ", new_CR40 );
  605.             if ( new_CR40 )
  606.                 strcat( msg.temp, "SRDY' )" );
  607.             else
  608.                 strcat( msg.temp, "RDYIN' )" );
  609.             strcat ( msg.text, msg.temp );
  610.             break;
  611.         case _HELP:    case _GET:
  612.             sprintf( msg.temp, "\nVL-bus Write latch delay\n\t%s",
  613.                 "RDYIN' = 0d\n\tSRDY'  = 1d (faster?)");
  614.             strcat( msg.text, msg.temp );
  615.             break;
  616.         default:
  617.             sprintf( msg.text, "_864::_fxn3(cmd)  UNRECOGNIZED cmd.");
  618.             status = EXIT_FAILURE;
  619.     }
  620. }    */
  621.  
  622.  
  623. void
  624. _864::_fxn3( int cmd )    //    Bus turnaround time
  625. {    //    bits7-6 of _CR40
  626.     if ( cmd == _QUERY )    {
  627.         strcpy( msg.text,
  628.             "3  S3-864/964 Bus turnaround non-overlap (VL-bus only)\n");
  629.         return;
  630.     }
  631.  
  632.     uchar _CR40 = ( read_CR( 0x40 ) >> 6 ) & 0x03,
  633.         new_CR40;
  634.     sprintf( msg.text,"Old delay = %u unit(s) ", _CR40 + 1 );
  635.  
  636.     if ( param[ 0 ] != NULL )
  637.         new_CR40 = (uchar)atoi( param[ 0 ] ) & 0x03;
  638.  
  639.     switch ( cmd )    {
  640.         case _SET:    _CR40 = read_CR( 0x40 ) & 0x3F;
  641.             write_CR( 0x40, ( ( new_CR40 >> 6 ) & 0xC0 ) | _CR40 );
  642.             sprintf( msg.temp,"\nNew delay = %u unit(s)", new_CR40 + 1 );
  643.             strcat ( msg.text, msg.temp );
  644.             break;
  645.         case _HELP:    case _GET:
  646.             sprintf( msg.temp, "\nVL-bus gap between ABEN' & DBEN'%s%s",
  647.                 "\n\t1 unit  = 00\n\t2 units = 01\n\t3 units = 02",
  648.                 "\n\t4 units = 03");
  649.             strcat( msg.text, msg.temp );
  650.             break;
  651.         default:
  652.             sprintf( msg.text, "_864::_fxn3(cmd)  UNRECOGNIZED cmd.");
  653.             status = EXIT_FAILURE;
  654.     }
  655. }
  656.  
  657.  
  658.  
  659. void
  660. _864::_fxn4( int cmd )    //    RAS precharge timing select
  661. {    //    bits 7-6 of _CR68
  662.     if ( cmd == _QUERY )    {
  663.         strcpy( msg.text, "4  S3-864/964 RAS' precharge timing delay\n" );
  664.         return;
  665.     }
  666.  
  667.  
  668.     uchar _CR68 = ( read_CR( 0x68 ) >> 6 ) & 0x03; // 7654 3210 -> 0000 0076
  669.     uchar new_CR68= 0x01;  //    maximum delay default, 4.5 MCLKs
  670.  
  671.     if ( param[ 0 ] != NULL )
  672.         new_CR68 = ( (uchar)atoi( param[ 0 ] ) ) & 0x03;
  673.  
  674.     sprintf(msg.text,"Old RAS' precharge value = %02X (see table) ", _CR68 );
  675.  
  676.     switch ( cmd )    {
  677.         case _SET:    _CR68 = read_CR( 0x68 ) & 0x3F;    //    00XX XXXX
  678.             write_CR( 0x68, _CR68 | ( ( new_CR68 << 6 ) & 0xC0 ) );
  679.             sprintf( msg.temp,"\nNew RAS' value = %02X ", new_CR68 );
  680.             strcat ( msg.text, msg.temp );
  681.             break;
  682.         case _HELP:    case _GET:
  683.             sprintf( msg.temp, "\nDRAM RAS' precharge delays%s",
  684.              "\n\t0 = RESERVED\n\t1 = 4.5MCLKs\n\t2 = 3.5\n\t3 = 2.5");
  685.             strcat( msg.text, msg.temp );
  686.             break;
  687.         default:
  688.             sprintf( msg.text, "_864::_fxn4(cmd)  UNRECOGNIZED cmd.");
  689.             status = EXIT_FAILURE;
  690.     }
  691. }
  692.  
  693.  
  694. void
  695. _864::_fxn5( int cmd )    //    RAS precharge timing select
  696. {    //    bits 5-4 of _CR68
  697.     if ( cmd == _QUERY )    {
  698.         strcpy( msg.text, "5  S3-864/964 RAS' low timing select\n" );
  699.         return;
  700.     }
  701.  
  702.  
  703.     uchar _CR68 = ( read_CR( 0x68 ) >> 4 ) & 0x03; // 7654 3210 -> 0000 0054
  704.     uchar new_CR68= 0x00;  //    maximum delay default, 6.5 MCLKs
  705.  
  706.     if ( param[ 0 ] != NULL )
  707.         new_CR68 = ( (uchar)atoi( param[ 0 ] ) ) & 0x03;
  708.  
  709.     sprintf(msg.text,"Old RAS' low timing value = %02X (see table) ", _CR68 );
  710.  
  711.     switch ( cmd )    {
  712.         case _SET:    _CR68 = read_CR( 0x68 ) & 0xCF;    //    XX00 XXXX
  713.             write_CR( 0x68, _CR68 | ( ( new_CR68 << 4 ) & 0x30 ) );
  714.             sprintf( msg.temp,"\nNew RAS' value = %02X", new_CR68 );
  715.             strcat ( msg.text, msg.temp );
  716.             break;
  717.         case _HELP:    case _GET:
  718.             sprintf( msg.temp, "\nDRAM RAS' low timing select%s",
  719.              "\n\t0 = 6.5MCLKs\n\t1 = 5.5\n\t2 = 4.5\n\t3 = 3.5");
  720.             strcat( msg.text, msg.temp );
  721.             break;
  722.         default:
  723.             sprintf( msg.text, "_864::_fxn5(cmd)  UNRECOGNIZED cmd.");
  724.             status = EXIT_FAILURE;
  725.     }
  726. }
  727.  
  728.  
  729. message
  730. _868::_info( void )
  731. {
  732.     return _ramtype( 0x0F ) ;
  733.     //    Call _ramtype, allowing all cases 0, 1, 2 & 3
  734. }
  735.  
  736.  
  737. void        //    Read "M, N, R" values from S3 registers _SR10 & _SR11
  738. _Trio::read_PLL( uchar *M, uchar *N, uchar *R )
  739. {
  740.     uchar _SR10= read_SR( 0x10 );    //    Read _SR10, contains N & R
  741.  
  742.     *M = read_SR( 0x11 ) & 0x7F;    // _SR11 -> 0XXX XXXX = M value
  743.     *N = _SR10 & 0x1F;            //    _N = _SR11 -> 000X XXXX
  744.     *R = ( _SR10 >> 5 ) & 0x03;    //    _R  ( 7654 3210 -> 0000 0065 )
  745. }
  746.  
  747.  
  748. message
  749. _Triov::_info( void )
  750. {
  751.     return _ramtype( 0x0D ) ;
  752.     //    Call _ramtype, allowing case0, 2 & 3
  753. }
  754.  
  755.  
  756. void
  757. _Trio::_mclk( int cmd )    //    MCLK reprogramming
  758. {    //    _SR10, _SR11
  759.     if ( cmd == _QUERY )    {
  760.         strcpy( msg.text, "0  S3 Trio/Virge MCLK programming\n");
  761.         return;
  762.     }
  763.  
  764.     uchar _M, _N, _R, _SR10, _SR11;
  765.     read_PLL( &_M, &_N, &_R );    //    Load _M, _N, _R with PLL values
  766.     sprintf( msg.text,"Old MCLK = %.2fMHz ( M=%u, N=%u, R=%u ) ",
  767.         _PLL( _M, _N, _R ), _M, _N, _R );
  768.  
  769.     if ( num_param < 3 && cmd == _SET )    {
  770.         strcat( msg.text, "\n...not enough parameters, need total of 3." );
  771.         cmd = _HELP;    }    //    Not enough parameters.    }
  772.     else    {
  773.         _M = (uchar)atoi( param[ 0 ] );
  774.         _N = (uchar)atoi( param[ 1 ] );
  775.         _R = (uchar)atoi( param[ 2 ] );
  776.  
  777.         _M = ( _M & 0x7F );
  778.         _SR11 = ( read_SR( 0x11 ) & 0x80 ) | _M;
  779.         _N = ( _N & 0x1F );
  780.         _R = ( _R << 5 ) & 0X60 ;
  781.         _SR10 = ( read_SR( 0x10 ) & 0x80 ) | _N | _R;
  782.     }
  783.  
  784.     switch ( cmd )    {
  785.         case _SET:    write_bit( _SRindex, 0x15, 0, 0 );    // Prep MCLK load
  786.             write_SR( 0x11, _SR11 );
  787.             write_SR( 0x10, _SR10 );
  788.             write_bit( _SRindex, 0x15, 0, 1 );    //    Load MCLK values
  789.             delay(1000);    //    Wait for new values to take effect
  790.             write_bit( _SRindex, 0x15, 0, 0 );    //    Clear MCLK load
  791.             read_PLL( &_M, &_N, &_R);    //    Reread new values
  792.             sprintf(msg.temp,"\nNew MCLK = %.2fMHz ( M=%u, N=%u, R=%u ) ",
  793.                 _PLL( _M, _N, _R ), _M, _N, _R );
  794.             strcat ( msg.text, msg.temp );
  795.             break;
  796.         case _HELP:    case _GET:
  797.             strcat( msg.text, "\nS3 Trio/Virge MCLK programming" );
  798.             mclk_help();    //    Get Trio mclk help, put in msg.temp
  799.             strcat( msg.text, msg.temp );
  800.             break;
  801.         default:
  802.             sprintf( msg.text, "_Trio::_mclk(cmd)  UNRECOGNIZED cmd.");
  803.             status = EXIT_FAILURE;
  804.     }
  805. }
  806.  
  807. void
  808. _Trio::_fxn3( int cmd )    //    RAS' timing control
  809. {    //    bit2 = RAS' Low, bit3 = RAS' precharge _CR68
  810.     if ( cmd == _QUERY )    {
  811.         strcpy(msg.text,"3  S3Trio RAS' timing control (2 parameters)\n");
  812.         return;
  813.     }
  814.  
  815.     uchar _bit2 = read_bit( _CRindex, 0x68, 2 ),
  816.         _bit3 = read_bit( _CRindex, 0x68, 3 );
  817.  
  818.     sprintf( msg.text, "Old RAS-LOW = %.1fMCLKs, Old RAS-Pre = %.1fMCLKs",
  819.         4.5 - _bit2, 3.5 - _bit3 );
  820.  
  821.     if ( num_param < 2 && cmd == _SET )     {
  822.         strcat( msg.text, "\nError!  Need TWO parameters for input!");
  823.         cmd = _HELP;    }
  824.     else    if ( num_param >= 2 ) {
  825.         _bit2 = ( (uchar)atoi( param[ 0 ] ) ) & 0x01;
  826.         _bit3 = ( (uchar)atoi( param[ 1 ] ) ) & 0x01;
  827.     }
  828.  
  829.     switch ( cmd )    {
  830.         case _SET:    write_bit( _CRindex, 0x68, 2, _bit2 );
  831.             write_bit( _CRindex, 0x68, 3, _bit3 );
  832.             sprintf(msg.temp,"\nNew LOW = %.1fMCLKs, New PRE = %.1fMCLKs",
  833.               4.5 - _bit2, 3.5 - _bit3 );
  834.             strcat ( msg.text, msg.temp );
  835.             break;
  836.         case _HELP:    case _GET:
  837.             sprintf( msg.temp, "\nDRAM RAS delays/stretches%s%s",
  838.              "\n\tRAS'LOW  RAS'PRE   (1st-param 2nd-param )",
  839.              "\n\t0 = 4.5  0 = 3.5\n\t1 = 3.5  1 = 2.5" );
  840.             strcat( msg.text, msg.temp );
  841.             break;
  842.         default:
  843.             sprintf( msg.text, "_Trio::_fxn3(cmd)  UNRECOGNIZED cmd.");
  844.             status = EXIT_FAILURE;
  845.     }
  846. }
  847.  
  848.  
  849. void
  850. _Trio::_fxn4( int cmd )    //    Memory write timing, 2MCLK/3MCLK, SR08/SR15
  851. {
  852.     if ( cmd == _QUERY )    {
  853.         sprintf( msg.text,"4  S3Trio 2MCLK/3MCLK timing controls\n" );
  854.         return;
  855.     }
  856.  
  857.     uchar _SR0A = read_bit( _SRindex, 0x0A, 7 ),    // SR0A/b7 = CPU-write
  858.         _SR15 = read_bit( _SRindex, 0x15, 7 ); // SR15/b7 = mem-write
  859.  
  860.     sprintf(msg.text,"Old CPU-write = %uMCLKs, mem-write = %uMCLKS",
  861.         3 - _SR0A, 3 - _SR15 );
  862.  
  863.     if ( num_param < 2 && cmd == _SET )    {
  864.         strcat( msg.text, "\nError!  TWO parameters required!");
  865.         cmd = _HELP; }
  866.     else    if ( num_param >= 2 ) {
  867.         _SR0A = ( (uchar)atoi( param[ 0 ] ) ) & 0x01;
  868.         _SR15 = ( (uchar)atoi( param[ 1 ] ) ) & 0x01;
  869.     }
  870.  
  871.     switch ( cmd )    {
  872.         case _SET:
  873.             write_bit( _SRindex, 0x0A, 7, _SR0A );
  874.             write_bit( _SRindex, 0x15, 7, _SR15 );
  875.             sprintf( msg.temp,"\nNew CPU = %uMCLKs, mem = %uMCLKs",
  876.                 3 - _SR0A, 3 - _SR15 );
  877.             strcat ( msg.text, msg.temp );
  878.             break;
  879.         case _HELP:    case _GET:
  880.             sprintf( msg.temp, "\nCPU-write and MEM-write control\n%s%s%s",
  881.              "For each item, enter: \n\t0 (3MCLKs)\n\t1 (2MCLKs, faster,",
  882.              " but MCLK freq must be < 57MHz.)\n\tAdditional constraint ",
  883.              "for 2MCLK MEM-write: 55MHz < MCLK <  57MHz" );
  884.             strcat( msg.text, msg.temp );
  885.             break;
  886.         default:
  887.             sprintf( msg.text, "_Trio::_fxn4(cmd)  UNRECOGNIZED cmd.");
  888.             status = EXIT_FAILURE;
  889.     }
  890. }
  891.  
  892.  
  893. void
  894. _Triov::_fxn1( int cmd )    //    Memory page mode control )
  895. {    //    bits3-2 of _CR36
  896.     if ( cmd == _QUERY )    {
  897.         strcpy( msg.text,
  898.          "1  Trio64V+/Virge memory page-mode control\n");
  899.         return;
  900.     }
  901.  
  902.     uchar _CR36 = read_CR( 0x36 ) & 0xF3;    // XXXX 00XX
  903.     uchar new_CR36 = _CR36 & 0x03;
  904.  
  905.     if ( param[ 0 ] != NULL )
  906.         new_CR36 = ( (uchar)atoi( param[ 0 ] ) ) & 0x03;
  907.  
  908.     switch ( cmd )    {
  909.         case _SET:
  910.             write_CR( 0x36, ( new_CR36 << 2 ) | _CR36 );
  911.             sprintf( msg.temp,"\nSelected RAM access-mode %u", new_CR36 );
  912.             strcat ( msg.text, msg.temp );
  913.             break;
  914.         case _HELP:    case _GET:
  915.             sprintf( msg.temp, "S3 Trio64V+/Virge memory access-mode%s%s",
  916.                 " control\n\t0 = 1-cycle EDO\n\t2 = 2-cycle EDO \n\t",
  917.                 "3 = fast-page mode timing");
  918.             strcat( msg.text, msg.temp );
  919.             break;
  920.         default:
  921.             sprintf( msg.text, "_Triov::_fxn1(cmd)  UNRECOGNIZED cmd.");
  922.             status = EXIT_FAILURE;
  923.     }
  924. }
  925.  
  926.  
  927. message
  928. _964::_info( void )
  929. {
  930.     return ( _ramtype( 0x0C ) );
  931.     //    Call _ramtype, allowing only case2 & 3
  932. }
  933.  
  934.  
  935. /*    PLL - TIVP3025
  936.  *
  937.  *    Calculates MCLK frequency from M, N, _FREF, and P values
  938.  *    returns double value MHz, works for TIVP3025 RAMDAC
  939.  */
  940. double
  941. _964::_PLL( uchar M, uchar N, uchar P )
  942. {
  943.     double Pval;
  944.  
  945.     switch ( P )    {
  946.         case 0:    case 1:    case 2:    case 3:
  947.             Pval = pow( 2.0, P );        //    Pval = 2 ^ P;
  948.  
  949.             break;    // <- how'd I forget to put this here...
  950.         default:
  951.             Pval=0;    // Error!
  952.     }
  953.     return ( 8.0 * ( M + 2.0 ) * _OSC ) / ( ( N + 2.0 ) * Pval );
  954.     /*           ( M + 2 )
  955.      *   FVCO = --------- * 8 * _FREF ... _FREF = 14.31818 MHz
  956.      *          ( N + 2 )
  957.      *
  958.       *   FPLL (MHz) = FVCO / ( 2^P )       FPLL = final MCLK frequency
  959.       *
  960.      *    constraint:    110MHz < FVCO < 220MHz
  961.       *        and...    FREF/(N+2) > 0.5MHz
  962.      *        and...    N >= 1 , M >= 1
  963.      */
  964. }
  965.  
  966.  
  967.  
  968. void
  969. _964::_mclk( int cmd )    // MCLK programming for TI VP3025 RAMDAC
  970. {
  971.     if ( cmd == _QUERY && tivpdac == TRUE )    {
  972.         sprintf( msg.text, "0  TIVP3025/3026 RAMDAC MCLK programming\n" );
  973.         return;    }
  974.     else if ( tivpdac == FALSE )    {
  975.         sprintf( msg.text,"0  MCLK function NOT available\n" );
  976.         return;
  977.     }
  978.  
  979.     uchar _CR33 = read_bit( _CRindex, 0x33, 4 ); // Remember LOCK DACW v0.84
  980.  
  981.     uchar _M, _N, _P, byte1, byte2, byte3;
  982.  
  983.      write_bit( _CRindex, 0x55, 0, 1 );    //    Enable DAC extension RS2
  984.     write_bit( _CRindex, 0x55, 1, 0 );    //    Disable DAC extension RS3
  985.     // TIVP3025's indirect registers are accessed via "INDEX" and "DATA"
  986.      // where RS[2:0]=110 "INDEX" , RS[2:0]=111 "DATA"
  987.      // MCLK PLL Control register is at 0x2E
  988.      //
  989.  
  990.      outportb( _DACmask, 0x2E );    // set "INDEX" (RS[110]) to MCLK PLL-con
  991.      // To access first MCLK PLL register, must write 00 -> PLLcontrol[1:0]
  992.      write_bit( _DACindexR, 0, 0 );    //    0 -> bit0 of PLLcontrol
  993.     write_bit( _DACindexR, 1, 0 );    //    0 -> bit1 of PLLcontrol
  994.      // PLL control register is autoincremented
  995.  
  996.     byte1 = inportb( _DACmask ); // Read data from MCLK PLL data register
  997.     byte2 = inportb( _DACmask ); // ...
  998.      byte3 = inportb( _DACmask ); // ...
  999.     _N = byte1 & 0x7F;
  1000.     _M = byte2 & 0x7F;
  1001.     _P = byte3 & 0x03;
  1002.     sprintf( msg.text,"Old MCLK = %.2fMHz ( M=%u, N=%u, P=%u ) ",
  1003.         _PLL( _M, _N, _P ), _M, _N, _P );
  1004.  
  1005.     if ( num_param < 3 && cmd == _SET )    {
  1006.         strcat( msg.text, "\n...not enough parameters, need total of 3." );
  1007.         cmd = _HELP;    }    //    Not enough parameters.    }
  1008.     else    {
  1009.         _M = (uchar)atoi( param[ 0 ] ) & 0x7F;
  1010.         _N = (uchar)atoi( param[ 1 ] ) & 0x7F;
  1011.         _P = (uchar)atoi( param[ 2 ] ) & 0x03;
  1012.         byte1 = ( byte1 & 0x80 ) | _M;
  1013.           byte2 = ( byte2 & 0x80 ) | _N;
  1014.         byte3 = ( byte3 & 0xFC ) | _P;
  1015.     }
  1016.  
  1017.     switch ( cmd )    {
  1018.         case _SET:    write_bit( _CRindex, 0x33, 4, 0 );
  1019.                     // enable RAMDAC writes
  1020.              write_bit( _CRindex, 0x55, 0, 1 );    //    set RS2 to 1
  1021.             write_bit( _CRindex, 0x55, 1, 0 );    //    clear RS3 to 0
  1022.              outportb( _DACmask, 0x2E );    // set "INDEX" to 0x2E
  1023.              write_bit( _DACindexR, 0, 0 ); //    0 -> bit0 of PLLcontrol
  1024.             write_bit( _DACindexR, 1, 0 ); //    0 -> bit1 of PLLcontrol
  1025.  
  1026.             outportb( _DACmask, byte1 );    //    Write 1st byte
  1027.             outportb( _DACmask, byte2 );    //    Write 2nd byte
  1028.                outportb( _DACmask, byte3 );    //    Write 3rd byte
  1029.  
  1030.                // Now, read-back the new values!
  1031.  
  1032.              outportb( _DACmask, 0x2E );    // set "INDEX" to 0x2E
  1033.              write_bit( _DACindexR, 0, 0 ); //    0 -> bit0 of PLLcontrol
  1034.             write_bit( _DACindexR, 1, 0 ); //    0 -> bit1 of PLLcontrol
  1035.                byte1 = inportb( _DACmask ); // Read data from MCLK PLL
  1036.             byte2 = inportb( _DACmask ); // ...
  1037.              byte3 = inportb( _DACmask ); // ...
  1038.             _N = byte1 & 0x7F;
  1039.             _M = byte2 & 0x7F;
  1040.             _P = byte3 & 0x03;
  1041.  
  1042.             sprintf(msg.temp,"\nNew MCLK = %.2fMHz ( M=%u, N=%u, P=%u ) ",
  1043.                 _PLL( _M, _N, _P ), _M, _N, _P );
  1044.             strcat( msg.text, msg.temp );
  1045.             write_bit( _CRindex, 0x33, 4, _CR33 );    // Restore bit4
  1046.             break;
  1047.         case _GET:    case _HELP:
  1048.             strcat( msg.text, "\nTIVP3025 RAMDAC MCLK programming" );
  1049.             mclk_help();    //    Get mclk help, put in msg.temp
  1050.             strcat( msg.text, msg.temp );
  1051.             break;
  1052.         default:
  1053.             sprintf( msg.text, "_964::_mclk(cmd)  UNRECOGNIZED cmd.");
  1054.             status = EXIT_FAILURE;
  1055.     }
  1056. }
  1057.  
  1058. void
  1059. _964::mclk_help( void )    //    Display help for TIVP3025 MCLK programming
  1060. {
  1061.     sprintf( msg.temp, "\nFormula for TI VP3025 MCLK driver... %s%s%s",
  1062.      "(3 parameters, M, N, P)\n\t( M + 2 ) * 8\n\t--------- * 14.31818MHz",
  1063.      "\n\t(N+2)*2^P\n\n\tConstraint:    110MHz < MCLK * (2^P) < 220MHz",
  1064.      "\n\t     and...   1<=M<=127    1<=N<=127    0<=P<=3" );
  1065. }
  1066.  
  1067.  
  1068. void
  1069. _964::_fxn1( int cmd )    //    Ready Control delay (VL-BUS only ) & SAM
  1070. {    //    bit4 of _CR40 and bit6 of CR58
  1071.     if ( cmd == _QUERY )    {
  1072.         strcpy( msg.text,
  1073.          "1  S3-964 RDY CTL (VL-bus only), VRAM SAM control (2 items)\n");
  1074.         return;
  1075.     }
  1076.  
  1077.     uchar _CR40 = read_bit( _CRindex, 0x40, 4 ),
  1078.         _CR58 = read_bit( _CRindex, 0x58, 6 );
  1079.     uchar new_CR40=0, new_CR58=0;
  1080.  
  1081.     if ( num_param < 2 && cmd == _SET )    {
  1082.         strcat( msg.text, "\nError!  TWO parameters required!");
  1083.         cmd = _HELP; }
  1084.     else    if ( num_param >= 2 ) {
  1085.         new_CR40 = ( (uchar)atoi( param[ 0 ] ) ) & 0x01;
  1086.         new_CR58 = ( (uchar)atoi( param[ 1 ] ) ) & 0x01;
  1087.     }
  1088.  
  1089.     sprintf(msg.text,"Old RDY-CTL = %uT wait state(s), SAM = %d", _CR40,
  1090.         512 - ( 256 * _CR58 ) );
  1091.  
  1092.     switch ( cmd )    {
  1093.         case _SET:
  1094.             write_bit( _CRindex, 0x40, 4, new_CR40 );
  1095.             write_bit( _CRindex, 0x58, 6, new_CR58 );
  1096.             sprintf( msg.temp,"\nNew RDY-CTL = %uT,  SAM = %d", new_CR40,
  1097.                 512 - ( 256 * new_CR58 ) );
  1098.             strcat ( msg.text, msg.temp );
  1099.             break;
  1100.         case _HELP:    case _GET:
  1101.             sprintf( msg.temp, "\nVL-bus RDY Control delay\n\t%s%s",
  1102.                 "0 = no-wait\n\t1 = one wait-state\n\n\tSAM control",
  1103.                 "\n\t0 = 512 words ( faster )\n\t1 = 256 words");
  1104.             strcat( msg.text, msg.temp );
  1105.             break;
  1106.         default:
  1107.             sprintf( msg.text, "_964::_fxn1(cmd)  UNRECOGNIZED cmd.");
  1108.             status = EXIT_FAILURE;
  1109.     }
  1110. }
  1111.  
  1112.  
  1113. message
  1114. _968::_info( void )
  1115. {
  1116.     return _ramtype( 0x0D );
  1117.     //    Call _ramtype, allowing cases 0, 2 & 3
  1118.  
  1119. }
  1120.  
  1121.  
  1122. //----S3 Virge
  1123.  
  1124. message
  1125. _Virge::_info( void )
  1126. {
  1127.     return _ramtype( 0x05 ) ;
  1128.     //    Call _ramtype, allowing case0 & 2
  1129.     return msg;
  1130. }
  1131.  
  1132.  
  1133. void
  1134. _VirgeVX::mclk_help( void )    //    Display help for VirgeVX MCLK programming
  1135. {
  1136.     sprintf( msg.temp, "\nFormula for S3 Virge/VX MCLK driver... %s%s%s",
  1137.      "(3 parameters, M, N, R)\n\t( M + 2 )\n\t--------- * 14.31818MHz",
  1138.      "\n\t(N+2)*2^R\n\n\tConstraint:    220MHz < 2^R * 14.31818MHz < 440MHz",
  1139.      "\n\t     and...   1<=M<=127    1<=N<=31    0<=R<=3" );
  1140. }
  1141.