disppc.c

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

C
1,470
字号
/****************************************************************************
*
*                            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:  Instruction decoding for PowerPC architecture.
*
****************************************************************************/


#include <string.h>
#include <ctype.h>
#include "distypes.h"
#include "dis.h"

extern long SEX( unsigned long v, unsigned bit );

extern const dis_range          PPCRangeTable[];
extern const int                PPCRangeTablePos[];
extern const unsigned char      PPCMaxInsName;
extern const unsigned short     DisRegisterTable[];

#define MK_SPR(a,b) (((a)<<5)|(b))

// Macro to sort out operand position depending on endianness (needed to
// get disassembler to correctly process relocations - in big endian object
// files, 16-bit relocs are located two bytes past instruction start)
#ifdef __BIG_ENDIAN__
    #define     OP_POS( l, b )  (h->need_bswap ? l : b)
#else
    #define     OP_POS( l, b )  (h->need_bswap ? b : l)
#endif

#ifdef __BIG_ENDIAN__

typedef union {
    struct {
        unsigned_16 rB          : 5;
        // ---
        unsigned_16 OE          : 1;
        unsigned_16 type1       : 3;
        unsigned_16 mem         : 4;
        // reference types - only valid if memory = ?101
        unsigned_16 type2       : 2;
        unsigned_16 Rc          : 1;
    } math;
    struct {
        unsigned_16 third       : 5;
        unsigned_16 second      : 5;
        unsigned_16 first       : 5;
        unsigned_16 Rc          : 1;
    } general;
    unsigned_16 immediate;
    struct {
        unsigned_16 BD          : 14;
        unsigned_16 AA          : 1;
        unsigned_16 LK          : 1;
    } branch;
    struct {
        unsigned_16 IMM         : 4;
        unsigned_16 morezero    : 1;
        unsigned_16 subcode     : 10;
        unsigned_16 zero        : 1;
    } condition;
    struct {
        unsigned_16 sh          : 5;
        unsigned_16 XO          : 9;
        unsigned_16 sh_5        : 1;
        unsigned_16 Rc          : 1;
    } xs_form;
    struct {
        unsigned_16 sh          : 5;
        unsigned_16 mb          : 6;
        unsigned_16 XO          : 3;
        unsigned_16 sh_5        : 1;
        unsigned_16 Rc          : 1;
    } md_form;
    struct {
        unsigned_16 first       : 5;
        unsigned_16 mb          : 6;
        unsigned_16 XO          : 4;
        unsigned_16 Rc          : 1;
    } mds_form;
} ppc_ins_lo;

typedef union {
    struct {
        unsigned_16 memory      : 1;
        unsigned_16 floating    : 1;
        // reference types - only valid if memory=1
        unsigned_16 type        : 3;
        unsigned_16 update      : 1;
        unsigned_16 second      : 5;
        unsigned_16 first       : 5;
        // ---
    } general;
    struct {
        unsigned_16 opcode      : 6;
        unsigned_16 morezero    : 1;
        unsigned_16 FM          : 8;
        unsigned_16 zero        : 1;
    } math;
    struct {
        unsigned_16 opcode      : 6;
        unsigned_16 crfD        : 3;
        unsigned_16 zero        : 1;
        unsigned_16 L           : 1;
        unsigned_16 rA          : 5;
    } compare;
    struct {
        unsigned_16 opcode      : 6;
        unsigned_16 crfD        : 3;
        unsigned_16 morezero    : 2;
        unsigned_16 crfS        : 3;
        unsigned_16 zero        : 2;
    } condition;
} ppc_ins_hi;

typedef union {
    unsigned_32 full;
    struct {
        ppc_ins_hi  hi;
        ppc_ins_lo  lo;
    };
    struct {
        unsigned_32 opcode              : 6;
        unsigned_32 LI                  : 24;
        unsigned_32 AA                  : 1;
        unsigned_32 LK                  : 1;
    } b;
    struct {
        unsigned_32 opcode              : 6;
        unsigned_32 rD                  : 5;
        unsigned_32 lastzero            : 1;
        unsigned_32 CRM                 : 8;
        unsigned_32 morezero            : 1;
        unsigned_32 subcode             : 10;
        unsigned_32 zero                : 1;
    } CRM;
} ppc_ins;

#else

typedef union {
    struct {
        unsigned_16 Rc          : 1;
        // reference types - only valid if memory = ?101
        unsigned_16 type2       : 2;
        unsigned_16 mem         : 4;
        unsigned_16 type1       : 3;
        // ---
        unsigned_16 OE          : 1;
        unsigned_16 rB          : 5;
    } math;
    struct {
        unsigned_16 Rc          : 1;
        unsigned_16 first       : 5;
        unsigned_16 second      : 5;
        unsigned_16 third       : 5;
    } general;
    unsigned_16 immediate;
    struct {
        unsigned_16 LK          : 1;
        unsigned_16 AA          : 1;
        unsigned_16 BD          : 14;
    } branch;
    struct {
        unsigned_16 zero        : 1;
        unsigned_16 subcode     : 10;
        unsigned_16 morezero    : 1;
        unsigned_16 IMM         : 4;
    } condition;
    struct {
        unsigned_16 Rc          : 1;
        unsigned_16 sh_5        : 1;
        unsigned_16 XO          : 9;
        unsigned_16 sh          : 5;
    } xs_form;
    struct {
        unsigned_16 Rc          : 1;
        unsigned_16 sh_5        : 1;
        unsigned_16 XO          : 3;
        unsigned_16 mb          : 6;
        unsigned_16 sh          : 5;
    } md_form;
    struct {
        unsigned_16 Rc          : 1;
        unsigned_16 XO          : 4;
        unsigned_16 mb          : 6;
        unsigned_16 first       : 5;
    } mds_form;
} ppc_ins_lo;

typedef union {
    struct {
        unsigned_16 first       : 5;
        unsigned_16 second      : 5;
        // reference types - only valid if memory=1
        unsigned_16 update      : 1;
        unsigned_16 type        : 3;
        unsigned_16 floating    : 1;
        unsigned_16 memory      : 1;
        // ---
    } general;
    struct {
        unsigned_16 zero        : 1;
        unsigned_16 FM          : 8;
        unsigned_16 morezero    : 1;
        unsigned_16 opcode      : 6;
    } math;
    struct {
        unsigned_16 rA          : 5;
        unsigned_16 L           : 1;
        unsigned_16 zero        : 1;
        unsigned_16 crfD        : 3;
        unsigned_16 opcode      : 6;
    } compare;
    struct {
        unsigned_16 zero        : 2;
        unsigned_16 crfS        : 3;
        unsigned_16 morezero    : 2;
        unsigned_16 crfD        : 3;
        unsigned_16 opcode      : 6;
    } condition;
} ppc_ins_hi;

typedef union {
    unsigned_32 full;
    struct {
        ppc_ins_lo  lo;
        ppc_ins_hi  hi;
    };
    struct {
        unsigned_32 LK                  : 1;
        unsigned_32 AA                  : 1;
        unsigned_32 LI                  : 24;
        unsigned_32 opcode              : 6;
    } b;
    struct {
        unsigned_32 zero                : 1;
        unsigned_32 subcode             : 10;
        unsigned_32 morezero            : 1;
        unsigned_32 CRM                 : 8;
        unsigned_32 lastzero            : 1;
        unsigned_32 rD                  : 5;
        unsigned_32 opcode              : 6;
    } CRM;
} ppc_ins;

#endif

dis_handler_return PPCMath( dis_handle *h, void *d, dis_dec_ins *ins )
{
    ppc_ins     code;

    code.full = ins->opcode;

    ins->num_ops = 3;
    ins->op[0].type = DO_REG;
    ins->op[0].base = code.hi.general.second + DR_PPC_r0;
    ins->op[1].type = DO_REG;
    ins->op[1].base = code.hi.general.first + DR_PPC_r0;
    ins->op[2].type = DO_REG;
    ins->op[2].base = code.lo.math.rB + DR_PPC_r0;

    if( code.lo.math.Rc ) {
        ins->flags |= DIF_PPC_RC;
    }
    if( code.lo.math.OE ) {
        ins->flags |= DIF_PPC_OE;
    }
    return( DHR_DONE );
}
dis_handler_return PPCMathb( dis_handle *h, void *d, dis_dec_ins *ins )
{
    PPCMath( h, d, ins );

    ins->num_ops = 1;
    ins->op[0] = ins->op[2];

    return( DHR_DONE );
}
dis_handler_return PPCMathd( dis_handle *h, void *d, dis_dec_ins *ins )
{
    PPCMath( h, d, ins );

    ins->num_ops = 1;

    return( DHR_DONE );
}
dis_handler_return PPCMathab( dis_handle *h, void *d, dis_dec_ins *ins )
{
    PPCMath( h, d, ins );

    ins->num_ops = 2;
    ins->op[0] = ins->op[1];
    ins->op[1] = ins->op[2];

    ins->flags &= ~DIF_PPC_OE;
    return( DHR_DONE );
}
dis_handler_return PPCMathda( dis_handle *h, void *d, dis_dec_ins *ins )
{
    PPCMath( h, d, ins );

    ins->num_ops = 2;

    if( ins->type == DI_PPC_clcs ) {
        ins->flags &= ~DIF_PPC_OE;
    }

    return( DHR_DONE );
}
dis_handler_return PPCMathdb( dis_handle *h, void *d, dis_dec_ins *ins )
{
    PPCMath( h, d, ins );

    ins->num_ops = 2;
    ins->op[1] = ins->op[2];

    ins->flags &= ~DIF_PPC_OE;
    return( DHR_DONE );
}
dis_handler_return PPCMath2( dis_handle *h, void *d, dis_dec_ins *ins )
// messy parameter ordering
{
    dis_operand temp;

    PPCMath( h, d, ins );

    temp = ins->op[0];
    ins->op[0] = ins->op[1];
    ins->op[1] = temp;
    ins->flags &= ~DIF_PPC_OE;
    return( DHR_DONE );
}
dis_handler_return PPCMathsa( dis_handle *h, void *d, dis_dec_ins *ins )
{
    PPCMath2( h, d, ins );
    ins->num_ops = 2;
    return( DHR_DONE );
}
dis_handler_return PPCImmediate( dis_handle *h, void *d, dis_dec_ins *ins )
{
    ppc_ins     code;

    code.full = ins->opcode;

    ins->num_ops = 3;
    ins->op[0].type = DO_REG;
    ins->op[0].base = code.hi.general.second + DR_PPC_r0;
    ins->op[1].type = DO_REG;
    ins->op[1].base = code.hi.general.first + DR_PPC_r0;
    ins->op[2].type = DO_IMMED;
    ins->op[2].op_position = OP_POS( 0, 2 );
    switch( ins->type ) {
    case DI_PPC_andi_dot:
    case DI_PPC_andis_dot:
    case DI_PPC_ori:
    case DI_PPC_oris:
    case DI_PPC_xori:
    case DI_PPC_xoris: // These take unsigned values.
        ins->op[2].value = code.lo.immediate;
        break;
    default:
        ins->op[2].value = SEX(code.lo.immediate, 15 );
        break;
    }
    return( DHR_DONE );
}
dis_handler_return PPCImmed2( dis_handle *h, void *d, dis_dec_ins *ins )
// messy parameter ordering
{
    dis_operand temp;

    PPCImmediate( h, d, ins );

    temp = ins->op[0];
    ins->op[0] = ins->op[1];
    ins->op[1] = temp;

    return( DHR_DONE );
}
static void PPCDoFloat( dis_dec_ins *ins, const int *order )
// extract float operands.  order is null terminated array of integers as
// follows:  (instruction format as numbered in the book)
// 0              15              31
// +-----+----+----+----+----+----++
// |     | 1  | 2  | 3  | 4  |    ||
// +-----+----+----+----+----+----++
{
    ppc_ins     code;
    int         operand;

    code.full = ins->opcode;

    for( operand=0; operand<4; operand++ ) {
        if( order[operand] == 0 ) break;
        ins->op[operand].type = DO_REG;
        switch( order[operand] ) {
        case 1:
            ins->op[operand].base = code.hi.general.second + DR_PPC_f0;
            break;
        case 2:
            ins->op[operand].base = code.hi.general.first + DR_PPC_f0;
            break;
        case 3:
            ins->op[operand].base = code.lo.general.third + DR_PPC_f0;
            break;
        case 4:
            ins->op[operand].base = code.lo.general.second + DR_PPC_f0;
            break;
        }
    }
    ins->num_ops = operand;
    if( code.lo.general.Rc ) {
        ins->flags |= DIF_PPC_RC;
    }
}
dis_handler_return PPCFloat( dis_handle *h, void *d, dis_dec_ins *ins )
{
    // note silly ordering of operands
    const int order[5] = {1, 2, 4, 3, 0};

    PPCDoFloat( ins, order );

    return( DHR_DONE );
}
dis_handler_return PPCFloatdab( dis_handle *h, void *d, dis_dec_ins *ins )
{
    const int order[4] = {1, 2, 3, 0};

    PPCDoFloat( ins, order );

    return( DHR_DONE );
}
dis_handler_return PPCFloatdac( dis_handle *h, void *d, dis_dec_ins *ins )
{
    const int order[4] = {1, 2, 4, 0};

    PPCDoFloat( ins, order );

    return( DHR_DONE );
}
dis_handler_return PPCFloatCmpab( dis_handle *h, void *d, dis_dec_ins *ins )
{
    const int order[4] = {1, 2, 3, 0};
    ppc_ins     code;

    PPCDoFloat( ins, order );

    code.full = ins->opcode;

    ins->op[0].base = code.hi.compare.crfD + DR_PPC_cr0;

    return( DHR_DONE );
}
dis_handler_return PPCFloatdb( dis_handle *h, void *d, dis_dec_ins *ins )
{
    const int order[3] = {1, 3, 0};

    PPCDoFloat( ins, order );

    return( DHR_DONE );
}
dis_handler_return PPCFloato( dis_handle *h, void *d, dis_dec_ins *ins )
// Two obscure float instructions.
{
    ppc_ins     code;

⌨️ 快捷键说明

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