ppcdisas.c

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

C
528
字号
/****************************************************************************
*
*                            Open Watcom Project
*
*    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
*
*  ========================================================================
*
*    This file contains Original Code and/or Modifications of Original
*    Code as defined in and that are subject to the Sybase Open Watcom
*    Public License version 1.0 (the 'License'). You may not use this file
*    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
*    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
*    provided with the Original Code and Modifications, and is also
*    available at www.sybase.com/developer/opensource.
*
*    The Original Code and all software distributed under the License are
*    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
*    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
*    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
*    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
*    NON-INFRINGEMENT. Please see the License for the specific language
*    governing rights and limitations under the License.
*
*  ========================================================================
*
* Description:  PowerPC instruction decoding.
*
****************************************************************************/


#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include "walloca.h"
#include "ppc.h"
#include "ppctypes.h"
#include "madregs.h"

static dis_handle DH;

mad_status DisasmInit()
{
    bool        swap_bytes;

#ifdef __BIG_ENDIAN__
    swap_bytes = FALSE;
#else
    swap_bytes = TRUE;
#endif
    if( DisInit( DISCPU_ppc, &DH, swap_bytes ) != DR_OK ) {
        return( MS_ERR | MS_FAIL );
    }
    return( MS_OK );
}

void DisasmFini()
{
    DisFini( &DH );
}

dis_return DisCliGetData( void *d, unsigned off, unsigned size, void *data )
{
    mad_disasm_data     *dd = d;
    address             addr;

    addr = dd->addr;
    addr.mach.offset += off;
    if( MCReadMem( addr, size, data ) == 0 ) return( DR_FAIL );
    return( DR_OK );
}

unsigned DisCliValueString( void *d, dis_dec_ins *ins, unsigned op, char *buff )
{
    mad_disasm_data     *dd = d;
    char                *p;
    unsigned            max;
    mad_type_info       mti;
    address             val;

    p = buff;
    p[0] = '\0';
    val = dd->addr;
    switch( ins->op[op].type & DO_MASK ) {
    case DO_RELATIVE:
        val.mach.offset += ins->op[op].value;
        //NYI: 64 bit
        MCAddrToString( val, PPCT_N32_PTR, MLK_CODE, 40, p );
        break;
    case DO_IMMED:
    case DO_ABSOLUTE:
    case DO_MEMORY_ABS:
        MCTypeInfoForHost( MTK_INTEGER, -sizeof( ins->op[0].value ), &mti );
        max = 40;
        MCTypeToString( dd->radix, &mti, &ins->op[op].value, &max, p );
        break;
    }
    return( strlen( buff ) );
}

unsigned                DIGENTRY MIDisasmDataSize( void )
{
    return( sizeof( mad_disasm_data ) );
}

unsigned                DIGENTRY MIDisasmNameMax( void )
{
    return( DisInsNameMax( &DH ) );
}

mad_status DisasmOne( mad_disasm_data *dd, address *a, int adj )
{
    addr_off    new;

    dd->addr = *a;
    new = dd->addr.mach.offset + adj * (int)sizeof( unsigned_32 );
    if( (adj < 0 && new > dd->addr.mach.offset)
     || (adj > 0 && new < dd->addr.mach.offset) ) {
        return( MS_FAIL );
    }
    dd->addr.mach.offset = new;
    DisDecodeInit( &DH, &dd->ins );
    if( DisDecode( &DH, dd, &dd->ins ) != DR_OK ) {
        return( MS_ERR | MS_FAIL );
    }
    a->mach.offset = dd->addr.mach.offset + sizeof( unsigned_32 );
    return( MS_OK );
}

mad_status              DIGENTRY MIDisasm( mad_disasm_data *dd, address *a, int adj )
{
    return( DisasmOne( dd, a, adj ) );
}

unsigned                DIGENTRY MIDisasmFormat( mad_disasm_data *dd, mad_disasm_piece dp, unsigned radix, unsigned max, char *buff )
{
    char                nbuff[20];
    char                obuff[256];
    char                *np;
    char                *op;
    unsigned            nlen;
    unsigned            olen;
    unsigned            len;
    dis_format_flags    ff;

    nbuff[0] = '\0';
    obuff[0] = '\0';
    np = (dp & MDP_INSTRUCTION) ? nbuff : NULL;
    op = (dp & MDP_OPERANDS)    ? obuff : NULL;
    ff = DFF_NONE;
    if( MADState->disasm_state & DT_PSUEDO_OPS ) ff |= DFF_PSEUDO;
    if( MADState->disasm_state & DT_UPPER ) ff |= DFF_INS_UP | DFF_REG_UP;
    dd->radix = radix;
    if( DisFormat( &DH, dd, &dd->ins, ff, np, op ) != DR_OK ) {
        return( 0 );
    }
    olen = strlen( obuff );
    nlen = strlen( nbuff );
    if( dp == MDP_ALL ) nbuff[ nlen++ ] = ' ';
    len = nlen + olen;
    if( max > 0 ) {
        --max;
        if( max > len ) max = len;
        if( nlen > max ) nlen = max;
        memcpy( buff, nbuff, nlen );
        buff += nlen;
        max -= nlen;
        if( olen > max ) olen = max;
        memcpy( buff, obuff, olen );
        buff[max] = '\0';
    }
    return( len );
}

unsigned                DIGENTRY MIDisasmInsSize( mad_disasm_data *dd )
{
    return( sizeof( unsigned_32 ) );
}

mad_status              DIGENTRY MIDisasmInsUndoable( mad_disasm_data *dd )
{
#if 0 //NYI:
    switch( dd->ins.type ) {
    case DI_AXP_CALL_PAL:
    case DI_AXP_PAL19:
    case DI_AXP_PAL1B:
    case DI_AXP_PAL1D:
    case DI_AXP_PAL1E:
    case DI_AXP_PAL1F:
    case DI_AXP_LDL_L:
    case DI_AXP_LDQ_L:
    case DI_AXP_STL_C:
    case DI_AXP_STQ_C:
        return( MS_FAIL );
    }
#endif
    return( MS_OK );
}

#define SKIP_ASM_REGS
const unsigned_16 RegTrans[] = {
#undef regpick
#define regpick( e, n ) offsetof( mad_registers, ppc.e ),
#include "regppc.h"
};

#define PPCT_BRHWORD    PPCT_HWORD
#define PPCT_BRWORD     PPCT_WORD
#define PPCT_BRDWORD    PPCT_DWORD
#define PPCT_SWORD      MAD_NIL_TYPE_HANDLE
#define PPCT_MWORD      MAD_NIL_TYPE_HANDLE
#define PPCT_SFLOAT     PPCT_FLOAT
#define PPCT_DFLOAT     PPCT_DOUBLE
static const mad_type_handle RefTrans[] = {
#undef refpick
#define refpick( e, n ) PPCT_##e,
#include "refppc.h"
};

static int CTRZero( mad_registers const *mr )
{
    if( mr->ppc.ctr.u._32[I64LO32] != 1 ) return( 0 );
    if( mr->ppc.msr.u._32[I64HI32] & (1UL << MSR_H_sf) ) {
        if( mr->ppc.ctr.u._32[I64HI32] != 0 ) return( 0 );
    }
    return( 1 );
}

static int CRTest( mad_registers const *mr, mad_disasm_data *dd )
{
    if( mr->ppc.cr & (1 << (31 - dd->ins.op[1].value)) ) return( 1 );
    return( 0 );
}

static mad_disasm_control Cond( mad_disasm_data *dd, mad_registers const *mr,
                        addr_off dest )
{
    #define NOT_TAKEN   (MDC_CONDITIONAL | MDC_TAKEN_NOT)
    switch( dd->ins.op[0].value >> 1 ) {
    case 0x0:
        if( CTRZero( mr ) || CRTest( mr, dd ) ) return( NOT_TAKEN );
        break;
    case 0x1:
        if( !CTRZero( mr ) || CRTest( mr, dd ) ) return( NOT_TAKEN );
        break;
    case 0x2:
    case 0x3:
        if( CRTest( mr, dd ) ) return( NOT_TAKEN );
        break;
    case 0x4:
        if( CTRZero( mr ) || !CRTest( mr, dd ) ) return( NOT_TAKEN );
        break;
    case 0x5:
        if( !CTRZero( mr ) || !CRTest( mr, dd ) ) return( NOT_TAKEN );
        break;
    case 0x6:
    case 0x7:
        if( !CRTest( mr, dd ) ) return( NOT_TAKEN );
        break;
    case 0x8:
    case 0xc:
        if( CTRZero( mr ) ) return( NOT_TAKEN );
        break;
    case 0x9:

⌨️ 快捷键说明

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