#ifdef WIN32
#pragma warning(disable:4786)
#endif
#include "vs1.0_inst.h"
#include <stdio.h>
#include <string>
#include <map>
#include <string.h>
#include "nvparse_errors.h"
#include "nvparse_externs.h"

std::string vs10_transstring;

#if 0
VS10Reg::VS10Reg()
{
    type = 0;
    index = 0;
	sign = 0;
    mask = 0;
}

VS10Reg::VS10Reg(const VS10Reg &r)
{
    type = r.type;
    index = r.index;
	sign = r.sign;
    mask = r.mask;
}

VS10Reg& VS10Reg::operator=(const VS10Reg &r)
{
    if ( this != &r )
    {
        type = r.type;
        index = r.index;
		sign = r.sign;
        mask = r.mask;
    }
    return *this;
}
#endif

void VS10Reg::Init()
{
    type = 0;
    index = -1;
    sign = 0;
    mask[0] = 'j';
    mask[1] = 'j';
    mask[2] = 'j';
    mask[3] = 'j';
}

int VS10Reg::ValidateIndex()
{
    switch( type )
    {
    case TYPE_TEMPORARY_REG:
        if ( index < 0 || index > 11 ) return 0;
        else return 1;
        break;
    case TYPE_VERTEX_ATTRIB_REG:
        if ( index < 0 || index > 15 ) return 0;
        else return 1;
        break;
    case TYPE_ADDRESS_REG:        
        if ( index != 0 ) return 0;
        else return 1;
        break;
    case TYPE_CONSTANT_MEM_REG:
        if ( index < 0 || index > 95 ) return 0;
        else return 1;
        break;
    case TYPE_CONSTANT_A0_REG:
    case TYPE_CONSTANT_A0_OFFSET_REG:
        return 1;
        break;
    case TYPE_POSITION_RESULT_REG:
        return 1;
        break;
    case TYPE_COLOR_RESULT_REG:
        if ( index < 0 || index > 1 ) return 0;
        else return 1;
        break;
    case TYPE_TEXTURE_RESULT_REG:
        if ( index < 0 || index > 3 ) return 0;
        else return 1;
        break;
    case TYPE_FOG_RESULT_REG:
        return 1;
        break;
    case TYPE_POINTS_RESULT_REG:
        return 1;
        break;
    default:
        errors.set( "VS10Reg::ValidateIndex() Internal Error: unknown register type\n" );
        return 1;
    }
}

void VS10Reg::Translate()
{
    char str[16];

    if ( sign == -1 )
        vs10_transstring.append( "-" );
    
    switch ( type )
    {
    case TYPE_TEMPORARY_REG:
        sprintf( str, "R%d", index );
        vs10_transstring.append( str );
        break;
    case TYPE_VERTEX_ATTRIB_REG:
        sprintf( str, "v[%d]", index );
        vs10_transstring.append( str );
        break;
    case TYPE_ADDRESS_REG:        
        sprintf( str, "A%d", index );
        vs10_transstring.append( str );
        break;
    case TYPE_CONSTANT_MEM_REG:
        sprintf( str, "c[%d]", index );
        vs10_transstring.append( str );
        break;
    case TYPE_CONSTANT_A0_REG:
        vs10_transstring.append( "c[ A0.x ]" );
        break;
    case TYPE_CONSTANT_A0_OFFSET_REG:
        sprintf( str, "c[ A0.x + %d ]", index );
        vs10_transstring.append( str );
        break;
    case TYPE_POSITION_RESULT_REG:
        vs10_transstring.append( "o[HPOS]" );
        break;
    case TYPE_COLOR_RESULT_REG:
        sprintf( str, "o[COL%d]", index );
        vs10_transstring.append( str );
        break;
    case TYPE_TEXTURE_RESULT_REG:
        sprintf( str, "o[TEX%d]", index );
        vs10_transstring.append( str );
        break;
    case TYPE_FOG_RESULT_REG:
        vs10_transstring.append( "o[FOGC]" );
        break;
    case TYPE_POINTS_RESULT_REG:
        vs10_transstring.append( "o[PSIZ]" );
        break;
    default:
        errors.set( "VS10Reg::Translate() Internal Error: unknown register type\n" );
    }

    if ( mask[0] != 0 )
    {
        str[0] = '.';
        strncpy( str+1, mask, 4 );
        str[5] = 0;
        vs10_transstring.append( str );
    }
}

VS10Inst::~VS10Inst()
{
    if (comment != NULL ) delete [] comment;
}

VS10Inst::VS10Inst()
{
    line = -1;
    instid = -1;
    dst.Init();
    src[0].Init();
    src[1].Init();
    src[2].Init();
    comment = NULL;
}

VS10Inst::VS10Inst( int currline )
{
    line = currline;
    instid = -1;
    dst.Init();
    src[0].Init();
    src[1].Init();
    src[2].Init();
    comment = NULL;
}

VS10Inst::VS10Inst( const VS10Inst &inst )
{
    line = inst.line;
    instid = inst.instid;
    dst = inst.dst;
    src[0] = inst.src[0];
    src[1] = inst.src[1];
    src[2] = inst.src[2];
    if ( inst.comment == NULL )
        comment = NULL;
    else
    {
        comment = new char[strlen(inst.comment)+1];
        strcpy( comment, inst.comment );
    }
}

VS10Inst& VS10Inst::operator=(const VS10Inst &inst)
{
    if ( this != &inst )
    {
        line = inst.line;
        instid = inst.instid;
        dst = inst.dst;
        src[0] = inst.src[0];
        src[1] = inst.src[1];
        src[2] = inst.src[2];
        if ( inst.comment == NULL )
            comment = NULL;
        else
        {
            comment = new char[strlen(inst.comment)+1];
            strcpy( comment, inst.comment );
        }
    }
    return *this;
}


VS10Inst::VS10Inst(int currline, int inst)
{
    line = currline;
    instid = inst;
    dst.Init();
    src[0].Init();
    src[1].Init();
    src[2].Init();
    comment = NULL;
}

VS10Inst::VS10Inst(int currline, int inst, char *cmt)
{
    line = currline;
    instid = inst;
    dst.Init();
    src[0].Init();
    src[1].Init();
    src[2].Init();
    comment = cmt;
}

VS10Inst::VS10Inst(int currline, int inst, VS10Reg dreg, VS10Reg src0)
{
    line = currline;
	instid = inst;
	dst = dreg;
    src[0] = src0;
    src[1].Init();
    src[2].Init();
    comment = NULL;
}

VS10Inst::VS10Inst(int currline, int inst, VS10Reg dreg, VS10Reg src0, VS10Reg src1)
{
    line = currline;
	instid = inst;
	dst = dreg;
    src[0] = src0;
    src[1] = src1;
    src[2].Init();
    comment = NULL;
}

VS10Inst::VS10Inst(int currline, int inst, VS10Reg dreg, VS10Reg src0, VS10Reg src1, VS10Reg src2)
{
    line = currline;
	instid = inst;
	dst = dreg;
    src[0] = src0;
    src[1] = src1;
    src[2] = src2;
    comment = NULL;
}

void VS10Inst::Validate( int &vsflag )
{

    // Handle comments, noops, and newlines.
    if ( instid == VS10_COMMENT || instid == VS10_NOP || instid == -1 ) return;

    // Handle the header case.
    if ( instid == VS10_HEADER )
    {
        if ( vsflag == 0 )
        {
            vsflag = 1;
            return;
        }
        else
        {
            char temp[128];
            sprintf( temp, "(%d) Error: vs.1.0 token already encountered\n", line );
            errors.set( temp );
            return;
        }
    }

    // Validate register indices are valid.
    ValidateRegIndices();

    // Verify destination masking is valid.
    ValidateDestMask();

    // Verify source swizzling is valid.
    ValidateSrcMasks();

    // Verify destination register is writable.
    ValidateDestWritable();

    // Verify source registers are readable.
    ValidateSrcReadable();

    // Verify not reading from multiple vertex attributes or constants
    ValidateReadPorts();
}

void VS10Inst::ValidateRegIndices()
{
    char temp[256];
    int result;

    // Destination register.
    result = dst.ValidateIndex();
    if ( !result )
    {
        sprintf( temp, "(%d) Error: destination register index out of range\n", line );
        errors.set( temp );
    }

    // Source register.
    result = src[0].ValidateIndex();
    if ( !result )
    {
        sprintf( temp, "(%d) Error: source register index out of range\n", line );
        errors.set( temp );
    }

    switch( instid )
    {
        // Vector operations.
        case VS10_MOV: 
        case VS10_LIT:
            break;

        // Unary operations.
        case VS10_FRC: 
            break;

        // Scalar operations.
        case VS10_EXP: 
        case VS10_EXPP:
        case VS10_LOG: 
        case VS10_LOGP:
        case VS10_RCP: 
        case VS10_RSQ:
            break;
        
        // Binary operations.
        case VS10_ADD:
        case VS10_DP3:
        case VS10_DP4: 
        case VS10_DST: 
        case VS10_SGE: 
        case VS10_SLT: 
        case VS10_SUB:
        case VS10_MAX: 
        case VS10_MIN: 
        case VS10_MUL: 
            result = src[1].ValidateIndex();
            if ( !result )
            {
                sprintf( temp, "(%d) Error: second source register index out of range\n", line );
                errors.set( temp );
            }
            break;

        case VS10_M3X2:
        case VS10_M3X3:
        case VS10_M3X4:
        case VS10_M4X3:
        case VS10_M4X4:
            {
                result = src[1].ValidateIndex();
                if ( !result )
                {
                    sprintf( temp, "(%d) Error: second source register index out of range\n", line );
                    errors.set( temp );
                }
                int orig;
                orig = src[1].index;
                switch( instid )
                {
                    case VS10_M3X2:
                        src[1].index = src[1].index + 1;
                        break;
                    case VS10_M3X3:
                    case VS10_M4X3:
                        src[1].index = src[1].index + 2;
                        break;
                    case VS10_M3X4:
                    case VS10_M4X4:
                        src[1].index = src[1].index + 3;
                        break;
                }
                result = src[1].ValidateIndex();
                src[1].index = orig;
                if ( !result )
                {
                    sprintf( temp, "(%d) Error: macro expansion produces source register index out of range\n", line );
                    errors.set( temp );
                }
            }
            break;

        // Trinary operations.
        case VS10_MAD:
            result = src[1].ValidateIndex();
            if ( !result )
            {
                sprintf( temp, "(%d) Error: second source register index out of range\n", line );
                errors.set( temp );
            }
            result = src[2].ValidateIndex();
            if ( !result )
            {
                sprintf( temp, "(%d) Error: third source register index out of range\n", line );
                errors.set( temp );
            }
            break;
        default:
            errors.set( "VS10Inst::ValidateRegIndices() Internal Error: unknown instruction type\n" );
            break;
    }
}

void VS10Inst::ValidateDestMask()
{
    char temp[256];
    typedef std::map<char, int> MyMap;
    typedef MyMap::value_type MyPair;
    static const MyPair pairs[] = 
    {
        MyPair('x',1),
        MyPair('y',2),
        MyPair('z',3),
        MyPair('w',4),
    };
    static const MyMap swizzleMap(pairs, pairs+(sizeof(pairs)/sizeof(pairs[0])));

    if ( dst.mask[0] == 0 ) return;
    int i = 1;
    while ( i < 4 && dst.mask[i] != 0 )
    {
        MyMap::const_iterator lastMaskIt = swizzleMap.find(dst.mask[i-1]);
        MyMap::const_iterator curMaskIt = swizzleMap.find(dst.mask[i]);
        if (lastMaskIt == swizzleMap.end() || curMaskIt == swizzleMap.end() ||
            lastMaskIt->second >= curMaskIt->second)
//        if ( dst.mask[i-1] >= dst.mask[i] )
        {
            char mask[5];
            strncpy( mask, dst.mask, 4 );
            mask[4] = 0;
            sprintf( temp, "(%d) Error: destination register has invalid mask: %s\n", line, mask );
            errors.set( temp );
            break;
        }
        i++;
    }
}

void VS10Inst::ValidateSrcMasks()
{
    char temp[256];
    char mask[5];
    int len;
    int i;

    switch( instid )
    {
        // Vector operations.
        case VS10_MOV: 
        case VS10_LIT:
            strncpy( mask, src[0].mask, 4 );
            mask[4] = 0;
            len = strlen( mask );
            if ( len != 1 )
            {
                for ( i = len; i < 4; i++ )
                    src[0].mask[i] = src[0].mask[len-1];
            }
            break;

        // Unary operations.
        case VS10_FRC: 
            strncpy( mask, src[0].mask, 4 );
            mask[4] = 0;
            len = strlen( mask );
            if ( len != 1 )
            {
                for ( i = len; i < 4; i++ )
                    src[0].mask[i] = src[0].mask[len-1];
            }
            break;

        // Scalar operations.
        case VS10_EXP: 
        case VS10_EXPP:
        case VS10_LOG: 
        case VS10_LOGP:
            strncpy( mask, src[0].mask, 4 );
            mask[4] = 0;
            len = strlen( mask );
            if( len != 1 )
            {
                sprintf( temp, "(%d) Error: source register has invalid mask: %s\n", line, mask );
                errors.set( temp );
            }
            break;

        case VS10_RCP: 
        case VS10_RSQ:
            strncpy( mask, src[0].mask, 4 );
            mask[4] = 0;
            len = strlen( mask );
            if( len != 0 && len != 1 )
            {
                sprintf( temp, "(%d) Error: source register has invalid mask: %s\n", line, mask );
                errors.set( temp );
            }
            if ( len == 0 )
            {
                strcpy( src[0].mask, "w" );
            }
            break;
        
        // Binary operations.
        case VS10_ADD:
        case VS10_DP3:
        case VS10_DP4: 
        case VS10_DST: 
        case VS10_SGE: 
        case VS10_SLT: 
        case VS10_SUB:
        case VS10_M3X2:
        case VS10_M3X3:
        case VS10_M3X4:
        case VS10_M4X3:
        case VS10_M4X4:
        case VS10_MAX: 
        case VS10_MIN: 
        case VS10_MUL: 
            strncpy( mask, src[0].mask, 4 );
            mask[4] = 0;
            len = strlen( mask );
            if ( len != 0 && len != 1 )
            {
                for ( i = len; i < 4; i++ )
                    src[0].mask[i] = src[0].mask[len-1];
            }
            strncpy( mask, src[1].mask, 4 );
            mask[4] = 0;
            len = strlen( mask );
            if ( len != 0 && len != 1 )
            {
                for ( i = len; i < 4; i++ )
                    src[1].mask[i] = src[1].mask[len-1];
            }
            break;

        // Trinary operations.
        case VS10_MAD:
            strncpy( mask, src[0].mask, 4 );
            mask[4] = 0;
            len = strlen( mask );
            if ( len != 0 && len != 1 )
            {
                for ( i = len; i < 4; i++ )
                    src[0].mask[i] = src[0].mask[len-1];
            }
            strncpy( mask, src[1].mask, 4 );
            mask[4] = 0;
            len = strlen( mask );
            if ( len != 0 && len != 1 )
            {
                for ( i = len; i < 4; i++ )
                    src[1].mask[i] = src[1].mask[len-1];
            }
            strncpy( mask, src[2].mask, 4 );
            mask[4] = 0;
            len = strlen( mask );
            if ( len != 0 && len != 1 )
            {
                for ( i = len; i < 4; i++ )
                    src[2].mask[i] = src[2].mask[len-1];
            }
            break;
        default:
            errors.set( "VS10Inst::ValidateSrcMasks() Internal Error: unknown instruction type\n" );
            break;
    }
}

void VS10Inst::ValidateDestWritable()
{
    char temp[256];

    switch ( dst.type )
    {
        case TYPE_TEMPORARY_REG:
        case TYPE_POSITION_RESULT_REG:
        case TYPE_COLOR_RESULT_REG:
        case TYPE_TEXTURE_RESULT_REG:
        case TYPE_FOG_RESULT_REG:
        case TYPE_POINTS_RESULT_REG:
            break;
        case TYPE_VERTEX_ATTRIB_REG:
        case TYPE_CONSTANT_MEM_REG:
        case TYPE_CONSTANT_A0_REG:
        case TYPE_CONSTANT_A0_OFFSET_REG:
            sprintf( temp, "(%d) Error: destination register is not writable\n", line );
            errors.set( temp );
            break;
        case TYPE_ADDRESS_REG:
            if ( instid != VS10_MOV )
            {
                sprintf( temp, "(%d) Error: destination register is not writable using this instruction\n", line );
                errors.set( temp );
            }
            break;
        default:
            errors.set( "VS10Inst::ValidateDestWritable() Internal Error: unknown register type\n" );
    }

    if ( instid == VS10_FRC && dst.type != TYPE_TEMPORARY_REG )
    {
        sprintf( temp, "(%d) Error: destination register must be a temporary register\n", line );
        errors.set( temp );
    }
}

void VS10Inst::ValidateSrcReadable()
{
    char temp[256];

    // Source register.
    switch( src[0].type )
    {
        case TYPE_TEMPORARY_REG:
        case TYPE_VERTEX_ATTRIB_REG:
        case TYPE_CONSTANT_MEM_REG:
        case TYPE_CONSTANT_A0_REG:
        case TYPE_CONSTANT_A0_OFFSET_REG:
            break;
        case TYPE_ADDRESS_REG:
        case TYPE_POSITION_RESULT_REG:
        case TYPE_COLOR_RESULT_REG:
        case TYPE_TEXTURE_RESULT_REG:
        case TYPE_FOG_RESULT_REG:
        case TYPE_POINTS_RESULT_REG:
            sprintf( temp, "(%d) Error: source register is not readable\n", line );
            errors.set( temp );
            break;
        default:
            errors.set( "VS10Inst::ValidateSrcReadable() Internal Error: unknown register type\n" );
    }
    
    switch( instid )
    {
        // Vector operations.
        case VS10_MOV: 
        case VS10_LIT:
            break;

        // Unary operations.
        case VS10_FRC: 
            break;

        // Scalar operations.
        case VS10_EXP: 
        case VS10_EXPP:
        case VS10_LOG: 
        case VS10_LOGP:
        case VS10_RCP: 
        case VS10_RSQ:
            break;
        
        // Binary operations.
        case VS10_ADD:
        case VS10_DP3:
        case VS10_DP4: 
        case VS10_DST: 
        case VS10_SGE: 
        case VS10_SLT: 
        case VS10_SUB:
        case VS10_M3X2:
        case VS10_M3X3:
        case VS10_M3X4:
        case VS10_M4X3:
        case VS10_M4X4:
        case VS10_MAX: 
        case VS10_MIN: 
        case VS10_MUL: 
            switch( src[1].type )
            {
                case TYPE_TEMPORARY_REG:
                case TYPE_VERTEX_ATTRIB_REG:
                case TYPE_CONSTANT_MEM_REG:
                case TYPE_CONSTANT_A0_REG:
                case TYPE_CONSTANT_A0_OFFSET_REG:
                    break;
                case TYPE_ADDRESS_REG:
                case TYPE_POSITION_RESULT_REG:
                case TYPE_COLOR_RESULT_REG:
                case TYPE_TEXTURE_RESULT_REG:
                case TYPE_FOG_RESULT_REG:
                case TYPE_POINTS_RESULT_REG:
                    sprintf( temp, "(%d) Error: second source register is not readable\n", line );
                    errors.set( temp );
                    break;
                default:
                    errors.set( "VS10Inst::ValidateSrcReadable() Internal Error: unknown register type\n" );
            }
            break;

        // Trinary operations.
        case VS10_MAD:
            switch( src[1].type )
            {
                case TYPE_TEMPORARY_REG:
                case TYPE_VERTEX_ATTRIB_REG:
                case TYPE_CONSTANT_MEM_REG:
                case TYPE_CONSTANT_A0_REG:
                case TYPE_CONSTANT_A0_OFFSET_REG:
                    break;
                case TYPE_ADDRESS_REG:
                case TYPE_POSITION_RESULT_REG:
                case TYPE_COLOR_RESULT_REG:
                case TYPE_TEXTURE_RESULT_REG:
                case TYPE_FOG_RESULT_REG:
                case TYPE_POINTS_RESULT_REG:
                    sprintf( temp, "(%d) Error: second source register is not readable\n", line );
                    errors.set( temp );
                    break;
                default:
                    errors.set( "VS10Inst::ValidateSrcReadable() Internal Error: unknown register type\n" );
            }
            switch( src[2].type )
            {
                case TYPE_TEMPORARY_REG:
                case TYPE_VERTEX_ATTRIB_REG:
                case TYPE_CONSTANT_MEM_REG:
                case TYPE_CONSTANT_A0_REG:
                case TYPE_CONSTANT_A0_OFFSET_REG:
                    break;
                case TYPE_ADDRESS_REG:
                case TYPE_POSITION_RESULT_REG:
                case TYPE_COLOR_RESULT_REG:
                case TYPE_TEXTURE_RESULT_REG:
                case TYPE_FOG_RESULT_REG:
                case TYPE_POINTS_RESULT_REG:
                    sprintf( temp, "(%d) Error: third source register is not readable\n", line );
                    errors.set( temp );
                    break;
                default:
                    errors.set( "VS10Inst::ValidateSrcReadable() Internal Error: unknown register type\n" );
            }
            break;
        default:
            errors.set( "VS10Inst::ValidateSrcReadable() Internal Error: unknown register type\n" );
            break;
    }
}

void VS10Inst::ValidateReadPorts()
{
    int constidx[3];
    int attribidx[3];
    int i;
    int acount;
    int ccount;
    char temp[256];

    switch( instid )
    {
        // Vector operations.
        case VS10_MOV: 
        case VS10_LIT:
            break;

        // Unary operations.
        case VS10_FRC: 
            break;

        // Scalar operations.
        case VS10_EXP: 
        case VS10_EXPP:
        case VS10_LOG: 
        case VS10_LOGP:
        case VS10_RCP: 
        case VS10_RSQ:
            break;
        
        // Binary operations.
        case VS10_ADD:
        case VS10_DP3:
        case VS10_DP4: 
        case VS10_DST: 
        case VS10_SGE: 
        case VS10_SLT: 
        case VS10_SUB:
        case VS10_M3X2:
        case VS10_M3X3:
        case VS10_M3X4:
        case VS10_M4X3:
        case VS10_M4X4:
        case VS10_MAX: 
        case VS10_MIN: 
        case VS10_MUL: 
            acount = 0;
            ccount = 0;
            for ( i = 0; i < 2; i++ )
            {
                switch( src[i].type )
                {
                    case TYPE_VERTEX_ATTRIB_REG:
                        attribidx[acount] = src[i].index;
                        acount++;
                        break;
                    case TYPE_CONSTANT_MEM_REG:
                        constidx[ccount] = src[i].index;
                        ccount++;
                        break;
                    case TYPE_CONSTANT_A0_REG:
                        constidx[ccount] = 100 + src[i].index;
                        ccount++;
                        break;
                    case TYPE_CONSTANT_A0_OFFSET_REG:
                        constidx[ccount] = 200 + src[i].index;
                        ccount++;
                        break;
                    case TYPE_TEMPORARY_REG:
                    case TYPE_ADDRESS_REG:
                    case TYPE_POSITION_RESULT_REG:
                    case TYPE_COLOR_RESULT_REG:
                    case TYPE_TEXTURE_RESULT_REG:
                    case TYPE_FOG_RESULT_REG:
                    case TYPE_POINTS_RESULT_REG:
                        break;
                    default:
                        errors.set( "VS10Inst::ValidateReadPorts() Internal Error: unknown register type\n" );
                }
            }
            if ( acount == 2 )
            {
                if ( attribidx[0] != attribidx[1] )
                {
                    sprintf( temp, "(%d) Error: multiple unique attribute registers accessed in this instruction\n", line );
                    errors.set( temp );
                }
            }
            else if ( ccount == 2 )
            {
                if ( constidx[0] != constidx[1] )
                {
                    sprintf( temp, "(%d) Error: multiple unique constant registers accessed in this instruction\n", line );
                    errors.set( temp );
                }
            }
            break;

        // Trinary operations.
        case VS10_MAD:
            acount = 0;
            ccount = 0;
            for ( i = 0; i < 3; i++ )
            {
                switch( src[i].type )
                {
                    case TYPE_VERTEX_ATTRIB_REG:
                        attribidx[acount] = src[i].index;
                        acount++;
                        break;
                    case TYPE_CONSTANT_MEM_REG:
                        constidx[ccount] = src[i].index;
                        ccount++;
                        break;
                    case TYPE_CONSTANT_A0_REG:
                        constidx[ccount] = 100 + src[i].index;
                        ccount++;
                        break;
                    case TYPE_CONSTANT_A0_OFFSET_REG:
                        constidx[ccount] = 200 + src[i].index;
                        ccount++;
                        break;
                    case TYPE_TEMPORARY_REG:
                    case TYPE_ADDRESS_REG:
                    case TYPE_POSITION_RESULT_REG:
                    case TYPE_COLOR_RESULT_REG:
                    case TYPE_TEXTURE_RESULT_REG:
                    case TYPE_FOG_RESULT_REG:
                    case TYPE_POINTS_RESULT_REG:
                        break;
                    default:
                        errors.set( "VS10Inst::ValidateReadPorts() Internal Error: unknown register type\n" );
                }
            }
            if ( acount == 3 )
            {
                if ( attribidx[0] != attribidx[1] || attribidx[1] != attribidx[2] )
                {
                    sprintf( temp, "(%d) Error: multiple unique attribute registers accessed in this instruction\n", line );
                    errors.set( temp );
                }
            }
            else if ( acount == 2 )
            {
                if ( attribidx[0] != attribidx[1] )
                {
                    sprintf( temp, "(%d) Error: multiple unique attribute registers accessed in this instruction\n", line );
                    errors.set( temp );
                }
            }
            else if ( ccount == 3 )
            {
                if ( constidx[0] != constidx[1] || constidx[1] != constidx[2] )
                {
                    sprintf( temp, "(%d) Error: multiple unique constant registers accessed in this instruction\n", line );
                    errors.set( temp );
                }
            }
            else if ( ccount == 2 )
            {
                if ( constidx[0] != constidx[1] )
                {
                    sprintf( temp, "(%d) Error: multiple unique constant registers accessed in this instruction\n", line );
                    errors.set( temp );
                }
            }
            break;
        default:
            errors.set( "VS10Inst::ValidateSrcReadable() Internal Error: unknown register type\n" );
            break;
    }
}

int VS10Inst::Translate()
{
    int flag;
    int ninstr;

#if DEBUGGING_PURPOSES
    char mystr[16];
    if ( instid == VS10_HEADER )
    {
        sprintf( mystr, "%d:\tvs.1.0 (skip)\n", line );
        vs10_transstring.append( mystr );
        return 0;
    }
    sprintf( mystr, "%d:\t", line );
    vs10_transstring.append( mystr );
#endif

    switch( instid )
    {
    case VS10_ADD:
        vs10_transstring.append( "ADD    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        vs10_transstring.append( ", " );
        src[1].Translate();
        ninstr = 1;
        break;
    case VS10_DP3:
        vs10_transstring.append( "DP3    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        vs10_transstring.append( ", " );
        src[1].Translate();
        ninstr = 1;
        break;
    case VS10_DP4: 
        vs10_transstring.append( "DP4    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        vs10_transstring.append( ", " );
        src[1].Translate();
        ninstr = 1;
        break;
    case VS10_DST: 
        vs10_transstring.append( "DST    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        vs10_transstring.append( ", " );
        src[1].Translate();
        ninstr = 1;
        break;
    case VS10_EXP: 
        vs10_transstring.append( "EXP    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        ninstr = 1;
        break;
    case VS10_EXPP:
        vs10_transstring.append( "EXP    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        ninstr = 1;
        break;
    case VS10_FRC:
        char temp[128];
        sprintf( temp, "(%d) Error: FRC built-in macro not yet supported.\n", line );
        errors.set( temp );
        ninstr = 0;
        break;
    case VS10_LIT: 
        vs10_transstring.append( "LIT    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        ninstr = 1;
        break;
    case VS10_LOG: 
        vs10_transstring.append( "LOG    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        ninstr = 1;
        break;
    case VS10_LOGP:
        vs10_transstring.append( "LOG    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        ninstr = 1;
        break;
    case VS10_M3X2:
    case VS10_M3X3:
    case VS10_M3X4:
        if ( dst.mask[0] != 0 )
        {
            ninstr = 0;
            int i = 0;
            while ( i < 4 && dst.mask[i] != 0 )
            {
                if ( dst.mask[i] == 'x' )
                {
                    char oldval;
                    vs10_transstring.append( "DP3    " );
                    oldval = dst.mask[0];
                    dst.mask[0] = 0;
                    dst.Translate();
                    dst.mask[0] = oldval;
                    vs10_transstring.append( ".x, " );
                    src[0].Translate();
                    vs10_transstring.append( ", " );
                    src[1].Translate();
                    vs10_transstring.append( ";\n" );
                    ninstr++;
                }
                if ( dst.mask[i] == 'y' )
                {
                    char oldval;
                    int  oldindex;
                    vs10_transstring.append( "DP3    " );
                    oldval = dst.mask[0];
                    dst.mask[0] = 0;
                    dst.Translate();
                    dst.mask[0] = oldval;
                    vs10_transstring.append( ".y, " );
                    src[0].Translate();
                    vs10_transstring.append( ", " );
                    oldindex = src[1].index;
                    src[1].index = src[1].index + 1;
                    src[1].Translate();
                    src[1].index = oldindex;
                    vs10_transstring.append( ";\n" );
                    ninstr++;
                }
                if ( dst.mask[i] == 'z' && (instid == VS10_M3X3 || instid == VS10_M3X4) )
                {
                    char oldval;
                    int  oldindex;
                    vs10_transstring.append( "DP3    " );
                    oldval = dst.mask[0];
                    dst.mask[0] = 0;
                    dst.Translate();
                    dst.mask[0] = oldval;
                    vs10_transstring.append( ".z, " );
                    src[0].Translate();
                    vs10_transstring.append( ", " );
                    oldindex = src[1].index;
                    src[1].index = src[1].index + 2;
                    src[1].Translate();
                    src[1].index = oldindex;
                    vs10_transstring.append( ";\n" );
                    ninstr++;
                }
                if ( dst.mask[i] == 'w' && instid == VS10_M3X4 )
                {
                    char oldval;
                    int  oldindex;
                    vs10_transstring.append( "DP3    " );
                    oldval = dst.mask[0];
                    dst.mask[0] = 0;
                    dst.Translate();
                    dst.mask[0] = oldval;
                    vs10_transstring.append( ".w, " );
                    src[0].Translate();
                    vs10_transstring.append( ", " );
                    oldindex = src[1].index;
                    src[1].index = src[1].index + 3;
                    src[1].Translate();
                    src[1].index = oldindex;
                    vs10_transstring.append( ";\n" );
                    ninstr++;
                }
                i++;
            }
            return ninstr;
        }
        else
        {
            ninstr = 0;

            char oldval;
            int  oldindex;

            vs10_transstring.append( "DP3    " );
            oldval = dst.mask[0];
            dst.mask[0] = 0;
            dst.Translate();
            dst.mask[0] = oldval;
            vs10_transstring.append( ".x, " );
            src[0].Translate();
            vs10_transstring.append( ", " );
            src[1].Translate();
            vs10_transstring.append( ";\n" );
            ninstr++;

            vs10_transstring.append( "DP3    " );
            oldval = dst.mask[0];
            dst.mask[0] = 0;
            dst.Translate();
            dst.mask[0] = oldval;
            vs10_transstring.append( ".y, " );
            src[0].Translate();
            vs10_transstring.append( ", " );
            oldindex = src[1].index;
            src[1].index = src[1].index + 1;
            src[1].Translate();
            src[1].index = oldindex;
            vs10_transstring.append( ";\n" );
            ninstr++;

            if ( instid == VS10_M3X3 || instid == VS10_M3X4 )
            {
                vs10_transstring.append( "DP3    " );
                oldval = dst.mask[0];
                dst.mask[0] = 0;
                dst.Translate();
                dst.mask[0] = oldval;
                vs10_transstring.append( ".z, " );
                src[0].Translate();
                vs10_transstring.append( ", " );
                oldindex = src[1].index;
                src[1].index = src[1].index + 2;
                src[1].Translate();
                src[1].index = oldindex;
                vs10_transstring.append( ";\n" );
                ninstr++;
            }

            if ( instid == VS10_M3X4 )
            {
                vs10_transstring.append( "DP3    " );
                oldval = dst.mask[0];
                dst.mask[0] = 0;
                dst.Translate();
                dst.mask[0] = oldval;
                vs10_transstring.append( ".w, " );
                src[0].Translate();
                vs10_transstring.append( ", " );
                oldindex = src[1].index;
                src[1].index = src[1].index + 3;
                src[1].Translate();
                src[1].index = oldindex;
                vs10_transstring.append( ";\n" );
                ninstr++;
            }
            return ninstr;
        }
        break;
    case VS10_M4X3:
    case VS10_M4X4:
        if ( dst.mask[0] != 0 )
        {
            ninstr = 0;
            int i = 0;
            while ( i < 4 && dst.mask[i] != 0 )
            {
                if ( dst.mask[i] == 'x' )
                {
                    char oldval;
                    vs10_transstring.append( "DP4    " );
                    oldval = dst.mask[0];
                    dst.mask[0] = 0;
                    dst.Translate();
                    dst.mask[0] = oldval;
                    vs10_transstring.append( ".x, " );
                    src[0].Translate();
                    vs10_transstring.append( ", " );
                    src[1].Translate();
                    vs10_transstring.append( ";\n" );
                    ninstr++;
                }
                if ( dst.mask[i] == 'y' )
                {
                    char oldval;
                    int  oldindex;
                    vs10_transstring.append( "DP4    " );
                    oldval = dst.mask[0];
                    dst.mask[0] = 0;
                    dst.Translate();
                    dst.mask[0] = oldval;
                    vs10_transstring.append( ".y, " );
                    src[0].Translate();
                    vs10_transstring.append( ", " );
                    oldindex = src[1].index;
                    src[1].index = src[1].index + 1;
                    src[1].Translate();
                    src[1].index = oldindex;
                    vs10_transstring.append( ";\n" );
                    ninstr++;
                }
                if ( dst.mask[i] == 'z' )
                {
                    char oldval;
                    int  oldindex;
                    vs10_transstring.append( "DP4    " );
                    oldval = dst.mask[0];
                    dst.mask[0] = 0;
                    dst.Translate();
                    dst.mask[0] = oldval;
                    vs10_transstring.append( ".z, " );
                    src[0].Translate();
                    vs10_transstring.append( ", " );
                    oldindex = src[1].index;
                    src[1].index = src[1].index + 2;
                    src[1].Translate();
                    src[1].index = oldindex;
                    vs10_transstring.append( ";\n" );
                    ninstr++;
                }
                if ( dst.mask[i] == 'w' && instid == VS10_M4X4 )
                {
                    char oldval;
                    int  oldindex;
                    vs10_transstring.append( "DP4    " );
                    oldval = dst.mask[0];
                    dst.mask[0] = 0;
                    dst.Translate();
                    dst.mask[0] = oldval;
                    vs10_transstring.append( ".w, " );
                    src[0].Translate();
                    vs10_transstring.append( ", " );
                    oldindex = src[1].index;
                    src[1].index = src[1].index + 3;
                    src[1].Translate();
                    src[1].index = oldindex;
                    vs10_transstring.append( ";\n" );
                    ninstr++;
                }
                i++;
            }
            return ninstr;
        }
        else
        {
            ninstr = 0;

            char oldval;
            int  oldindex;

            vs10_transstring.append( "DP4    " );
            oldval = dst.mask[0];
            dst.mask[0] = 0;
            dst.Translate();
            dst.mask[0] = oldval;
            vs10_transstring.append( ".x, " );
            src[0].Translate();
            vs10_transstring.append( ", " );
            src[1].Translate();
            vs10_transstring.append( ";\n" );
            ninstr++;

            vs10_transstring.append( "DP4    " );
            oldval = dst.mask[0];
            dst.mask[0] = 0;
            dst.Translate();
            dst.mask[0] = oldval;
            vs10_transstring.append( ".y, " );
            src[0].Translate();
            vs10_transstring.append( ", " );
            oldindex = src[1].index;
            src[1].index = src[1].index + 1;
            src[1].Translate();
            src[1].index = oldindex;
            vs10_transstring.append( ";\n" );
            ninstr++;

            vs10_transstring.append( "DP4    " );
            oldval = dst.mask[0];
            dst.mask[0] = 0;
            dst.Translate();
            dst.mask[0] = oldval;
            vs10_transstring.append( ".z, " );
            src[0].Translate();
            vs10_transstring.append( ", " );
            oldindex = src[1].index;
            src[1].index = src[1].index + 2;
            src[1].Translate();
            src[1].index = oldindex;
            vs10_transstring.append( ";\n" );
            ninstr++;

            if ( instid == VS10_M4X4 )
            {
                vs10_transstring.append( "DP4    " );
                oldval = dst.mask[0];
                dst.mask[0] = 0;
                dst.Translate();
                dst.mask[0] = oldval;
                vs10_transstring.append( ".w, " );
                src[0].Translate();
                vs10_transstring.append( ", " );
                oldindex = src[1].index;
                src[1].index = src[1].index + 3;
                src[1].Translate();
                src[1].index = oldindex;
                vs10_transstring.append( ";\n" );
                ninstr++;
            }
            return ninstr;
        }
        break;
    case VS10_MAD: 
        vs10_transstring.append( "MAD    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        vs10_transstring.append( ", " );
        src[1].Translate();
        vs10_transstring.append( ", " );
        src[2].Translate();
        ninstr = 1;
        break;
    case VS10_MAX: 
        vs10_transstring.append( "MAX    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        vs10_transstring.append( ", " );
        src[1].Translate();
        ninstr = 1;
        break;
    case VS10_MIN: 
        vs10_transstring.append( "MIN    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        vs10_transstring.append( ", " );
        src[1].Translate();
        ninstr = 1;
        break;
    case VS10_MOV:
        if ( dst.type == TYPE_ADDRESS_REG )
            vs10_transstring.append( "ARL    " );
        else
            vs10_transstring.append( "MOV    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        ninstr = 1;
        break;
    case VS10_MUL: 
        vs10_transstring.append( "MUL    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        vs10_transstring.append( ", " );
        src[1].Translate();
        ninstr = 1;
        break;
    case VS10_NOP: 
        return 0;
        break;
    case VS10_RCP: 
        vs10_transstring.append( "RCP    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        ninstr = 1;
        break;
    case VS10_RSQ: 
        vs10_transstring.append( "RSQ    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        ninstr = 1;
        break;
    case VS10_SGE: 
        vs10_transstring.append( "SGE    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        vs10_transstring.append( ", " );
        src[1].Translate();
        ninstr = 1;
        break;
    case VS10_SLT: 
        vs10_transstring.append( "SLT    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        vs10_transstring.append( ", " );
        src[1].Translate();
        ninstr = 1;
        break;
    case VS10_SUB:
        vs10_transstring.append( "ADD    " );
        dst.Translate();
        vs10_transstring.append( ", " );
        src[0].Translate();
        vs10_transstring.append( ", " );
        flag = src[1].sign;
        if ( flag == -1 ) src[1].sign = 1;
        else src[1].sign = -1;
        src[1].Translate();
        src[1].sign = flag;
        ninstr = 1;
        break;
    case VS10_COMMENT:
        vs10_transstring.append( comment );
        return 0;
        break;
    case VS10_HEADER:
        //vs10_transstring.append( "!!VP1.0\n" );
        return 0;
        break;
    case -1:
        vs10_transstring.append( "\n" );
        return 0;
    default:
        errors.set( "VS10Inst::Translate() Internal Error: unknown instruction type\n" );
    }

    vs10_transstring.append( ";\n" );
    return ninstr;
}
