ppcdisas.c

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

C
528
字号
    case 0xd:
        if( !CTRZero( mr ) ) return( NOT_TAKEN );
        break;
    case 0xa:
    case 0xb:
    case 0xe:
    case 0xf:
        if( dest < dd->addr.mach.offset ) {
            return( MDC_TAKEN_BACK );
        } else {
            return( MDC_TAKEN_FORWARD );
        }
    }
    if( dest < dd->addr.mach.offset ) {
        return( MDC_CONDITIONAL | MDC_TAKEN_BACK );
    } else {
        return( MDC_CONDITIONAL | MDC_TAKEN_FORWARD );
    }
}

#define TRANS_REG( mr, r ) (*(unsigned_64 *)((unsigned_8*)(mr) + RegTrans[r - DR_PPC_FIRST]))

static unsigned TrapTest( mad_disasm_data *dd, mad_registers const *mr )
{
    unsigned_64 a;
    unsigned_64 b;
    unsigned    bits;

    switch( dd->ins.type ) {
    case DI_PPC_twi:
    case DI_PPC_tdi:
       b.u._32[I64LO32] = dd->ins.op[2].value;
       if( dd->ins.op[2].value < 0 ) {
           b.u._32[I64HI32] = -1;
       } else {
           b.u._32[I64HI32] = 0;
       }
       break;
    default:
        b = TRANS_REG( mr, dd->ins.op[2].base );
        break;
    }
    a = TRANS_REG( mr, dd->ins.op[1].base );
    bits = 0;
    switch( dd->ins.type ) {
    case DI_PPC_td:
    case DI_PPC_tdi:
        if( a.u._32[I64HI32] == b.u._32[I64HI32] ) {
            if( a.u._32[I64LO32] == b.u._32[I64LO32] ) {
                bits |= 0x04;
            } else {
                if( a.u._32[I64LO32] < b.u._32[I64LO32] ) {
                    bits |= 0x02;
                    if( a.u.sign.v ) {
                        bits |= 0x08;
                    } else {
                        bits |= 0x10;
                    }
                } else {
                    bits |= 0x01;
                    if( a.u.sign.v ) {
                        bits |= 0x10;
                    } else {
                        bits |= 0x08;
                    }
                }
            }
        } else if( a.u._32[I64HI32] < b.u._32[I64HI32] ) {
            bits |= 0x02;
            if( a.u.sign.v ) {
                bits |= 0x08;
            } else {
                bits |= 0x10;
            }
        } else {
            bits |= 0x01;
            if( a.u.sign.v ) {
                bits |= 0x10;
            } else {
                bits |= 0x08;
            }
        }
        break;
    default:
        if( a.u._32[I64LO32] < b.u._32[I64LO32] ) bits |= 0x02;
        if( a.u._32[I64LO32] > b.u._32[I64LO32] ) bits |= 0x01;
        if( (signed_32)a.u._32[I64LO32] < (signed_32)b.u._32[I64LO32] ) bits |= 0x10;
        if( (signed_32)a.u._32[I64LO32] > (signed_32)b.u._32[I64LO32] ) bits |= 0x08;
        if( bits == 0 ) bits |= 0x04;
        break;
    }
    return( bits );
}

mad_disasm_control DisasmControl( mad_disasm_data *dd, mad_registers const *mr )
{
    mad_disasm_control  c;
    addr_off            v;

    switch( dd->ins.type ) {
    case DI_PPC_b:
        if( dd->ins.flags & DIF_PPC_LK ) {
            c = MDC_CALL;
        } else {
            c = MDC_JUMP;
        }
        v = dd->ins.op[0].value;
        if( dd->ins.op[0].type == DO_RELATIVE ) {
            v += dd->addr.mach.offset;
        }
        if( v < dd->addr.mach.offset ) {
            return( c | MDC_TAKEN_BACK );
        } else {
            return( c | MDC_TAKEN_FORWARD );
        }
    case DI_PPC_bc:
        if( dd->ins.flags & DIF_PPC_LK ) {
            c = MDC_CALL;
        } else {
            c = MDC_JUMP;
        }
        v = dd->ins.op[2].value;
        if( dd->ins.op[2].type == DO_RELATIVE ) {
            v += dd->addr.mach.offset;
        }
        return( c | Cond( dd, mr, v ) );
    case DI_PPC_bcctr:
        if( dd->ins.flags & DIF_PPC_LK ) {
            c = MDC_CALL;
        } else {
            c = MDC_JUMP;
        }
        return( c | Cond( dd, mr, mr->ppc.ctr.u._32[I64LO32] ) );
    case DI_PPC_bclr:
        if( dd->ins.flags & DIF_PPC_LK ) {
            c = MDC_CALL;
        } else {
            c = MDC_RET;
        }
        return( c | Cond( dd, mr, mr->ppc.lr.u._32[I64LO32] ) );
    case DI_PPC_rfi:
        return( MDC_SYSRET | MDC_TAKEN );
    case DI_PPC_sc:
        return( MDC_SYSCALL | MDC_TAKEN );
    case DI_PPC_td:
    case DI_PPC_tdi:
    case DI_PPC_tw:
    case DI_PPC_twi:
        c = MDC_SYSRET | MDC_CONDITIONAL;
        if( TrapTest( dd, mr ) & dd->ins.op[0].value ) {
            c |= MDC_TAKEN;
        }
        return( c );
    default:
        break;
    }
    return( MDC_OPER | MDC_TAKEN );
}

mad_disasm_control      DIGENTRY MIDisasmControl( mad_disasm_data *dd, mad_registers const *mr )
{
    return( DisasmControl( dd, mr ) );
}

mad_status      DIGENTRY MIDisasmInsNext( mad_disasm_data *dd, mad_registers const *mr, address *next )
{
    mad_disasm_control  dc;

    memset( next, 0, sizeof( *next ) );
    next->mach.offset = mr->ppc.iar.u._32[I64LO32] + sizeof( unsigned_32 );
    dc = DisasmControl( dd, mr );
    if( (dc & MDC_TAKEN_MASK) == MDC_TAKEN_NOT ) {
        return( MS_OK );
    }
    switch( dc & MDC_TYPE_MASK ) {
    case MDC_JUMP:
    case MDC_CALL:
    case MDC_RET:
        //NYI:
        return( MS_UNSUPPORTED );
    }
    return( MS_OK );
}

walk_result             DIGENTRY MIDisasmMemRefWalk( mad_disasm_data *dd, MI_MEMREF_WALKER *wk, mad_registers const *mr, void *d )
{
    address             a;
    unsigned            i;
    walk_result         wr;
    mad_memref_kind     mmk;

    if( dd->ins.type >= DI_PPC_lbz && dd->ins.type <= DI_PPC_lwzx ) {
        mmk = MMK_READ;
    } else if( dd->ins.type >= DI_PPC_stb && dd->ins.type <= DI_PPC_stwx ) {
        mmk = MMK_WRITE;
    } else {
        return( WR_CONTINUE );
    }
    a = dd->addr;
    for( i = 0; i < dd->ins.num_ops; ++i ) {
        if( dd->ins.op[i].type == DO_MEMORY_ABS ) {
            a.mach.offset = dd->ins.op[i].value;
            if( dd->ins.op[i].base != DR_PPC_r0 ) {
                a.mach.offset += TRANS_REG( mr, dd->ins.op[i].base ).u._32[I64LO32];
            }
            mmk &= (MMK_READ|MMK_WRITE);
            if( dd->ins.op[i].base == DR_PPC_r1 ) {
                mmk |= MMK_VOLATILE;
            }
            wr = wk( a, RefTrans[dd->ins.op[i].ref_type-DRT_PPC_FIRST], mmk, d );
            return( wr );
        } else if( dd->ins.op[i].extra & PE_XFORM ) {
            a.mach.offset = 0;
            if( dd->ins.op[i].base != DR_PPC_r0 ) {
                a.mach.offset += TRANS_REG( mr, dd->ins.op[i].base ).u._32[I64LO32];
            }
            a.mach.offset += TRANS_REG( mr, dd->ins.op[i+1].base ).u._32[I64LO32];
            mmk &= (MMK_READ|MMK_WRITE);
            if( dd->ins.op[i].base == DR_PPC_r1 || dd->ins.op[i+1].base == DR_PPC_r1 ) {
                mmk |= MMK_VOLATILE;
            }
            wr = wk( a, RefTrans[dd->ins.op[i].ref_type-DRT_PPC_FIRST], mmk, d );
            return( wr );
        }
    }
    return( WR_CONTINUE );
}

const mad_toggle_strings        *DIGENTRY MIDisasmToggleList( void )
{
    static const mad_toggle_strings list[] = {
        { MSTR_MPSEUDOINS, MSTR_PSEUDOINS, MSTR_RAWINS },
        { MSTR_MUPPER, MSTR_UPPER, MSTR_LOWER },
        { MSTR_NIL, MSTR_NIL, MSTR_NIL }
    };
    return( list );
}

unsigned                DIGENTRY MIDisasmToggle( unsigned on, unsigned off )
{
    unsigned    toggle;

    toggle = (on & off);
    MADState->disasm_state ^= toggle;
    MADState->disasm_state |= on & ~toggle;
    MADState->disasm_state &= ~off | toggle;
    return( MADState->disasm_state );
}

mad_status              DIGENTRY MIDisasmInspectAddr( char *from, unsigned len, unsigned radix, mad_registers const *mr, address *a )
{
    char        *buff = __alloca( len * 2 );
    char        *to;

    mr = mr;
    to = buff;
    while( len != 0 ) {
        if( *from == '(' ) *to++ = '+';
        *to++ = *from++;
        --len;
    }
    return( MCMemExpr( buff, to - buff, radix, a ) );
}

⌨️ 快捷键说明

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