...............................................................................
    PC INFORMATION FOR VIPER GC, V0.1
...............................................................................

Viper GC chip is programmed from the Parallel Port. Here is some information
to help you write a program interfacing with the Viper GC. The following code
snippets can't be compiled as it but must be included and adapted to your
program.

Note: _Always_ write 0x00 to the data bus when you are in "idle" mode (or call
      ViperGoodbye())

NOTE ABOUT "DEBUG INTERFACE" COMMANDS :
      
       User manual states that the Parallel Port connector has to be unplugged
       when you don't want to update the flash. This is to avoid any problem 
       with any Parallel Port interface for the common users. It is possible 
       anyway to leave the Parallel Port connector plugged if you need to use 
       the debugging commands (developers only!).
       If Viper GC is booting to Original BIOS / dispay baclk screen instead 
       of running the content of its flash, try the "Reset Parallel Port" 
       function of the Viper GC Flashing software, or just write 0x00 to the 
       Parallel Port Data Bus.

       The Debug interface has no clock, so you should always poll the Debug
       registers see if they changed. Because it might change while the read is
       in this progress, please read the register 3 times on the PC and GC
       proceed until the 3 values match. Typically, one bit of the debug 
       registers can be used to "emulate" a clock. Using a very safe mode 
       (reading the registers several times), it's possible to reach speeds of 
       about 2kb/s on both sides, but you can go a lot faster using unsafe mode 
       with error correction!
     

#define DEFAULT_PORT 0x378

void WriteViper(unsigned char data)
{
    unsigned char d = data&0xf;
    if (data&0x10) d|=0x20;    
    Out32(port,d);          
    while(((Inp32(port+1)>>3)&1)==0);    // Remove this for "unsafe" mode (fast)
    Out32(port,d|0x10);     
    while(((Inp32(port+1)>>3)&1)==1);    // Remove this for "unsafe" mode (fast)
}

unsigned char ReadViper ()
{
    return ((Inp32(port+1)>>3)&3);
}

// Enter Parallel Port Command Mode (after this call the GC can't read the 
// Viper GC Flash anymore).
void ViperHello()
{ 
    for (int i=0;i<20;i++)
        WriteViper(0xff);
    WriteViper(0xC);WriteViper(0x12);
}

// Leave Parallel Port Command Mode (Always call this function when you don't
// need to access the Viper GC anymore, or for some time!)
void ViperGoodbye()
{
    WriteViper(0x00); 
}

// Enter Flash Software ID mode. Never stay in that mode when turning the GC
// off!!
void ViperIDEntry()
{
    for (int i=0;i<7;i++)
        WriteViper(0x0E); 
}

// Leave Flash Sofware ID mode
void ViperIDExit()
{
    for (int i=0;i<3;i++)
        WriteViper(0x1B); 
}

void ViperWriteByte(int addr,unsigned char d)
{
    addr&=0x1FFFF;
    WriteViper(0x05); 
    WriteViper((addr>>15)|(((d>>5)&7)<<2));
    WriteViper(addr>>10);
    WriteViper(addr>>5);
    WriteViper(addr>>0);
    for (int i=0;i<4;i++)
        WriteViper(d);
}

void ViperSetAddr(int addr)
{
    WriteViper(0x11); 
    WriteViper(addr>>15);
    WriteViper(addr>>10);
    WriteViper(addr>>5);
    WriteViper(addr>>0);
}

// Address is automatically incremented after a call to ViperReadByte()
unsigned char ViperReadByte()
{
    unsigned char ReadResult = 0;
    WriteViper(0x0D); 
    for (int i=0;i<8;i++)
    {
        ReadResult = (ReadResult>>1)|((ReadViper()<<6)&0x80);
        writeViper(i);
    }
    return ReadResult;
}


int ViperVerifyID()
{
    ViperSetAddr(0);
    ViperIDEntry();    
    int ID1 = ViperReadByte();
    int ID2 = ViperReadByte();
    ViperIDExit();
    if ((ID1==0xBF) && (ID2==0xD5))
        return 1;   // OK !
    return 0;       // WRONG ID !
}

void ViperWaitEndWrite()
{
    ViperSetAddr(0);
    int Read0 = 0;
    int Read1 = ViperReadByte();
    do
    {
        Read0 = Read1;
        ViperSetAddr(0);
        Read1 = ViperReadByte();
    } while (Read0!=Read1);  // Wait toggle bit end
    ViperReadByte();
    ViperReadByte();
    
    WAIT 10ms HERE !!
}


void ViperEraseSector()
{
    for (int i=0;i<13;i++)
        WriteViper(0x15); // erasesector
    ViperWaitEndWrite();
}

void ViperEraseAll()
{
    for (int i=0;i<13;i++)
    {
        WriteViper(0x03);
    }
    ViperWaitEndWrite();

    WAIT A BIT HERE
}

// Write a byte to the GC (DEBUG INTERFACE)
void ViperWriteDebugReg(unsigned char value)
{
    WriteViper(0x9);
    WriteViper(value>>5);
    WriteViper(value>>0);
}

// Read a byte from the GC (DEBUG INTERFACE)
unsigned char ViperReadDebugReg()
{
    unsigned char Result = 0;
    WriteViper(0x0A);
    for (int i=0;i<8;i++)
    {
        Result = (Result>>1)|((ReadViper()<<6)&0x80);
        WriteViper(i);
    }
    return Result;
}



...............................................................................
Example of (safe) debug print routine:

ON PC
        ...
        ViperHello()
        ...

        while(1)
        {
            if ((Read0!=Read1) && (Read2==Read1))
            {
                printf("%c",Read1);
                Read0=Read1;
                ViperWriteDebugReg(toggle); // ACK
                toggle++;
            }
            Read1 = ViperReadDebugReg();
            Read2 = ViperReadDebugReg();
            
            if (EXIT) break;
        }
        
        ...
        ViperGoodbye();
        ...


ON GC

// With this function, the printed character must be different from the last 
// one!
void DebugPrintChar(unsigned char byte)
{
    unsigned char Read1, Read2;
    unsigned Read0 = ViperReadFromPC();
    ViperWriteToPC(byte);
    do { 
        Read1 = ViperReadFromPC()
        Read2 = ViperReadFromPC()
    } while((Read0==Read1)||(Read1!=Read2)); // WAIT FOR ACK
}

