disppc.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,470 行 · 第 1/3 页

C
1,470
字号
        break;
    default:
        break;
    }

    return( DHR_DONE );
}
dis_handler_return PPCNull( dis_handle *h, void *d, dis_dec_ins *ins )
{
    ins->num_ops = 0;
    return( DHR_DONE );
}

static unsigned PPCInsHook( dis_handle *h, void *d, dis_dec_ins *ins,
        dis_format_flags flags, char *name )
{
    const char *new;
    const char *more;

    if( !(flags & DFF_PSEUDO) ) return( 0 );
    new = NULL;
    more = NULL;
    switch( ins->type ) {
    // Comparison statements.
    case DI_PPC_cmpi:
        if( ins->op[1].value == 0 ) {
            ins->num_ops = 3;
            ins->op[1] = ins->op[2];
            ins->op[2] = ins->op[3];
            new = "cmpwi";
        }
        break;
    case DI_PPC_cmp:
        if( ins->op[1].value == 0 ) {
            ins->num_ops = 3;
            ins->op[1] = ins->op[2];
            ins->op[2] = ins->op[3];
            new = "cmpw";
        }
        break;
    case DI_PPC_cmpli:
        if( ins->op[1].value == 0 ) {
            ins->num_ops = 3;
            ins->op[1] = ins->op[2];
            ins->op[2] = ins->op[3];
            new = "cmplwi";
        }
        break;
    case DI_PPC_cmpl:
        if( ins->op[1].value == 0 ) {
            ins->num_ops = 3;
            ins->op[1] = ins->op[2];
            ins->op[2] = ins->op[3];
            new = "cmplw";
        }
        break;
    // Trap statements.
    //NYI: handle trap double extended stuff
    case DI_PPC_twi:
        ins->num_ops = 2;
        switch( ins->op[0].value ) {
        case 1:  new = "twlgti"; break;
        case 2:  new = "twllti"; break;
        case 4:  new = "tweqi";  break;
        case 5:  new = "twlgei"; break;
        case 6:  new = "twllei"; break;
        case 8:  new = "twgti";  break;
        case 12: new = "twgei";  break;
        case 16: new = "twlti";  break;
        case 20: new = "twlei";  break;
        case 24: new = "twnei";  break;
        default:
            ins->num_ops = 3;
        }
        if( ins->num_ops == 2 ) {
            ins->op[0] = ins->op[1];
            ins->op[1] = ins->op[2];
        }
        break;
    case DI_PPC_tw:
        ins->num_ops = 2;
        switch( ins->op[0].value ) {
        case 1:  new = "twlgt"; break;
        case 2:  new = "twllt"; break;
        case 4:  new = "tweq";  break;
        case 5:  new = "twlge";  break;
        case 6:  new = "twlle"; break;
        case 8:  new = "twgt";  break;
        case 12: new = "twge";  break;
        case 16: new = "twlt";  break;
        case 20: new = "twle";  break;
        case 24: new = "twne";  break;
        case 31: new = "trap";
            ins->num_ops = 0;
            break;
        default:
            ins->num_ops = 3;
        }
        if( ins->num_ops == 2 ) {
            ins->op[0] = ins->op[1];
            ins->op[1] = ins->op[2];
        }
        break;
    case DI_PPC_addi:
    // load 16-bit immediate value.
        if( ins->op[1].base == DR_PPC_r0 ) {
            new = "li";
            ins->num_ops = 2;
            ins->op[1] = ins->op[2];
            break;
        }
    // adding negative value.
        if( ins->op[2].value < 0 ) {
            new = "subi";
            ins->op[2].value = -ins->op[2].value;
        }
        break;
    // load 16-bit shifted immediate value.
    case DI_PPC_addis:
        if( ins->op[1].base == DR_PPC_r0 ) {
            new = "lis";
            ins->num_ops = 2;
            ins->op[1] = ins->op[2];
            break;
        }
        break;
    // Move register and compliment.
    case DI_PPC_or:
        if( ins->op[1].base == ins->op[2].base ) {
            new = "mr";
            ins->num_ops = 2;
        }
        break;
    case DI_PPC_nor:
        if( ins->op[1].base == ins->op[2].base ) {
            new = "not";
            ins->num_ops = 2;
        }
        break;
    // nop.
    case DI_PPC_ori:
        if( ins->opcode == 0x60000000) { /* ori r0, r0, 0 */
            new = "nop"; /* not no-op! */
            ins->num_ops = 0;
        }
        break;
    // SPR statements
    case DI_PPC_mtspr:
        ins->num_ops = 1;
    case DI_PPC_mfspr:
        ins->num_ops--; // ins->num_ops = 0 for mtspr, 1 for mfspr.
        switch( ins->op[ins->num_ops].value ) {
        case 1:
            more = "xer";
            break;
        case 8:
            more = "lr";
            break;
        case 9:
            more = "ctr";
            break;
        case 18:
            more = "dsisr";
            break;
        case 19:
            more = "dar";
            break;
        case 22:
            more = "dec";
            break;
        case 25:
            more = "sdr1";
            break;
        case 26:
            more = "srr0";
            break;
        case 27:
            more = "srr1";
            break;
        case 272:
        case 273:
        case 274:
        case 275:
            more = "sprg";
            ins->op[ins->num_ops].value -= 272;
            ins->num_ops += 3; // To be fixed below
            break;
        case 282:
            more = "ear";
            break;
        case 287:
            if( ins->type == DI_PPC_mfspr ) {
                more = "pvr";
            } else {
                ins->num_ops = 2;
            }
            break;
        case 528:
        case 530:
        case 532:
        case 534:
            more = "ibatu";
            ins->op[ins->num_ops].value = (ins->op[ins->num_ops].value - 528)/2;
            ins->num_ops += 3;
            break;
        case 529:
        case 531:
        case 533:
        case 535:
            more = "ibatl";
            ins->op[ins->num_ops].value = (ins->op[ins->num_ops].value - 529)/2;
            ins->num_ops += 3;
            break;
        default:
            ins->num_ops = 2;
        }
        switch( ins->num_ops ) {
        case 0:
            ins->op[0] = ins->op[1];
            ins->num_ops = 1;
            new = "mt";
            break;
        case 3:
            new = "mt";
            ins->num_ops = 2;
            break;
        case 4:
            ins->num_ops = 2;
        case 1:
            new = "mf";
            break;
        }
        break;
    // Branch statements
    case DI_PPC_bc:
        if( (ins->op[0].value & 0x14) == 0x14 ) {
            new = "b";
            ins->op[0] = ins->op[2];
            ins->num_ops = 1;
            break;
        }
    case DI_PPC_bclr:
        if( (ins->op[0].value & 0x14) == 0x14 ) {
            new = "blr";
            ins->num_ops = 0;
            break;
        }
        ins->num_ops = 2;
        switch( ins->op[0].value >> 1 ) {
        case 0:
            new = "bdnzf";
            break;
        case 1:
            new = "bdzf";
            break;
        case 4:
            new = "bdnzt";
            break;
        case 5:
            new = "bdzt";
            break;
        case 8:
            new = "bdnz";
            ins->num_ops = 1;
            ins->op[0] = ins->op[2];
            break;
        case 9:
            new = "bdz";
            ins->num_ops = 1;
            ins->op[0] = ins->op[2];
            break;
        default:
            ins->num_ops = 3;
        }
        if( ins->num_ops == 2 ) {
            ins->op[0] = ins->op[1];
            ins->op[1] = ins->op[2];
            ins->op[0].base = (ins->op[0].value / 4) + DR_PPC_cr0;
            ins->op[0].value %= 4;
        }
        if( ins->num_ops <= 2 ) {
            if( ins->type == DI_PPC_bclr ) {
                ins->num_ops--;
                more = "lr";
            }
            break;
        }
        // else, fall through
    case DI_PPC_bcctr:
        if( (ins->op[0].value & 0x14) == 0x14 ) {
            new = "bctr";
            ins->num_ops = 0;
            break;
        }
        if( (ins->op[0].value & 12) == 12 ) {
            ins->num_ops = 2;
            switch( ins->op[1].value % 4 ) {
            case 0:
                new = "blt";
                break;
            case 1:
                new = "bgt";
                break;
            case 2:
                new = "beq";
                break;
            case 3:
                new = "bso";
                break;
            }
        } else if( (ins->op[0].value & 4) == 4 ) {
            ins->num_ops = 2;
            switch( ins->op[1].value % 4 ) {
            case 0:
                new = "bge";
                break;
            case 1:
                new = "ble";
                break;
            case 2:
                new = "bne";
                break;
            case 3:
                new = "bns";
                break;
            }
        }
        if( ins->num_ops == 2 ) {
            ins->op[0] = ins->op[1];
            ins->op[1] = ins->op[2];
            ins->op[0].type = DO_REG;
            ins->op[0].base = (ins->op[0].value / 4) + DR_PPC_cr0;
            ins->op[0].value = 0;
            if( ins->op[0].base == DR_PPC_cr0 ) {
                ins->num_ops = 1;
                ins->op[0] = ins->op[1];
            }
            switch( ins->type ) {
            case DI_PPC_bclr:
                ins->num_ops--;
                more = "lr";
                break;
            case DI_PPC_bcctr:
                ins->num_ops--;
                more = "ctr";
                break;
            default:
                break;
            }
        }
        break;
    default:
        break;
    }
    if( name != NULL && new != NULL ) {
        strcpy( name, new );
        if( more != NULL ) {
            strcat( name, more );
        }
        return( strlen( name ) );
    }
    return 0;
}

static unsigned PPCFlagHook( dis_handle *h, void *d, dis_dec_ins *ins,
        dis_format_flags flags, char *name )
{
    char *p;

    p = name;
    if( ins->flags & DIF_PPC_OE ) *p++ = 'o';
    if( ins->flags & DIF_PPC_RC ) *p++ = '.';
    if( ins->flags & DIF_PPC_LK ) *p++ = 'l';
    if( ins->flags & DIF_PPC_AA ) *p++ = 'a';
    *p='\0';
    return( p-name );
}

static const char ConditionField[4][3] = {
    "lt", "gt", "eq", "so"
};

static unsigned PPCOpHook( dis_handle *h, void *d, dis_dec_ins *ins,
        dis_format_flags flags, unsigned op_num, char *op_buff )
{
    char        *p;
    int         val;
    char        ch;
    const char  *src;
    dis_operand *op;

    p = op_buff;
    switch( ins->op[op_num].type ) {
    // somewhat pointless to print out much more than this for
    // these cases.
    case DO_IMMED:
        switch( ins->type ) {
        case DI_PPC_cmp:
        case DI_PPC_cmpl:
        case DI_PPC_cmpi:
        case DI_PPC_cmpli:
            if( op_num == 1 ) {
                // The 1-bit L parameter.
                *p++ = ins->op[op_num].value + '0';
                *p='\0';
            }
            break;
        case DI_PPC_bc:
        case DI_PPC_bcctr:
        case DI_PPC_bclr:
            if( (flags & DFF_PSEUDO) && op_num == 0 ) {
                // pretty-printed BI parameter
                if( ins->op[op_num].base != DR_PPC_cr0 ) {
                    p = DisAddReg( ins->op[op_num].base, p, flags );
                    *p++ = '+';
                }
                src = ConditionField[ins->op[op_num].value % 4];
                for( ;; ) {
                    ch = *src;
                    *p = ch;
                    if( ch == '\0' ) break;
                    ++src;
                    ++p;
                }
                break;
            }
            // else, fall through
            // The 5-bit BO and BI parameters.
            //NYI: have to use client to get numeric prefix right
            *p++ = '0';
            *p++ = 'x';
            val = ins->op[op_num].value;
            *p++ = (val >> 4) + '0';
            if( (val & 0xf) > 9 ) {
                *p++ = (val & 0xf) + 'a' - 0xa;
            } else {
                *p++ = (val & 0xf) + '0';
            }
            *p='\0';
            break;
        default:
        break;
        }
    default:
        break;
    }
    if( flags & DFF_SYMBOLIC_REG ) {
        op = &ins->op[op_num];
        switch( op->base ) {
        case DR_PPC_r1:
            op->base = DR_PPC_sp;
            break;
        case DR_PPC_r2:
            op->base = DR_PPC_rtoc;
            break;
        default:
            break;
        }
    }
    return( p-op_buff );
}

static dis_handler_return PPCDecodeTableCheck( int page, dis_dec_ins *ins )
{
    return( DHR_DONE );
}

static void ByteSwap( dis_handle *h, void *d, dis_dec_ins *ins )
{
    if( h->need_bswap ) {
        SWAP_32( ins->opcode );
    }
}

static void PPCPreprocHook( dis_handle *h, void *d, dis_dec_ins *ins )
{
    ByteSwap( h, d, ins );
}

static unsigned PPCPostOpHook( dis_handle *h, void *d, dis_dec_ins *ins,
        dis_format_flags flags, unsigned op_num, char *op_buff )
{
    // Nothing to do
    return( 0 );
}

const dis_cpu_data PPCData = {
    PPCRangeTable, PPCRangeTablePos, PPCPreprocHook, PPCDecodeTableCheck, PPCInsHook, PPCFlagHook, PPCOpHook, PPCPostOpHook, &PPCMaxInsName, 4
};

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?