dissparc.c

来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 420 行

C
420
字号
/****************************************************************************
*
*                            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 Sun SPARC architecture.
*
****************************************************************************/


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

#include "bool.h"
#include "sparcenc.h"

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

extern const dis_range          SPARCRangeTable[];
extern const int                SPARCRangeTablePos[];
extern const unsigned char      SPARCMaxInsName;

#define _SparcReg( x )          ( (x) + DR_SPARC_r0 )
#define _SparcFReg( x )         ( (x) + DR_SPARC_f0 )
#define _SparcCReg( x )         ( (x) + DR_SPARC_c0 )
#define _SparcIns( x )          (x)

dis_handler_return SPARCSetHi( dis_handle*h, void *d, dis_dec_ins *ins )
{
    sparc_ins   code;

    code.full = _SparcIns( ins->opcode );
    ins->op[0].type = DO_IMMED;
    ins->op[0].value = SEX( code.sethi.imm22, 21 );
    ins->op[1].type = DO_REG;
    ins->op[1].base = _SparcReg( code.sethi.rd );
    ins->num_ops = 2;
    return( DHR_DONE );
}

dis_handler_return SPARCBranch( dis_handle *h, void *d, dis_dec_ins *ins )
{
    sparc_ins   code;

    code.full = _SparcIns( ins->opcode );
    ins->op[0].type = DO_RELATIVE;
    ins->op[0].value = ( SEX( code.branch.disp22, 21 ) ) * sizeof( ins->opcode );
    if( code.branch.anul != 0 ) {
        ins->flags |= DIF_SPARC_ANUL;
    }
    ins->num_ops = 1;
    return( DHR_DONE );
}

dis_handler_return SPARCCall( dis_handle *h, void *d, dis_dec_ins *ins )
{
    sparc_ins   code;

    code.full = _SparcIns( ins->opcode );
    ins->op[0].type  = DO_RELATIVE;
    // BartoszP 16.10.2005
    // SPARC Architecture Manual says:
    // CALL saves self address not next instruction into the %o7 register
    //ins->op[0].value = ( SEX( code.call.disp, 29 ) + 1) * sizeof( ins->opcode );
    ins->op[0].value = ( SEX( code.call.disp, 29 ) ) * sizeof( ins->opcode );
    ins->num_ops     = 1;
    return( DHR_DONE );
}

dis_handler_return SPARCOp3( dis_handle *h, void *d, dis_dec_ins *ins )
{
    sparc_ins   code;

    code.full = _SparcIns( ins->opcode );
    ins->op[ 0 ].type = DO_REG;
    ins->op[ 0 ].base = _SparcReg( code.op3.rs1 );
    ins->op[ 2 ].type = DO_REG;
    ins->op[ 2 ].base = _SparcReg( code.op3.rd );
    if( code.op3.imm != 0 ) {
        ins->op[ 1 ].type = DO_IMMED;
        ins->op[ 1 ].base = DR_NONE;
        ins->op[ 1 ].value = SEX( code.op3imm.simm13, 12 );
    } else {
        ins->op[ 1 ].type = DO_REG;
        ins->op[ 1 ].base = _SparcReg( code.op3.rs2 );
        ins->op[ 1 ].value = 0;
    }
    ins->num_ops = 3;
    return( DHR_DONE );
}

static void getOpIndices( sparc_ins code, int *mem, int *reg )
// figure out which operand of an instruction should be
// the memory reference and which the register
{
    // 3rd bit in an opcode for format(3) instructions seems
    // to differentiate between loads/stores
    if( code.op3.opcode_3 & 0x04 ) {
        *mem = 1;
        *reg = 0;
    } else {
        *mem = 0;
        *reg = 1;
    }
}

static void doSparcMem( dis_handle *h, void *d, dis_operand *op, sparc_ins code )
{
    op->type = DO_MEMORY_ABS;
    op->base = _SparcReg( code.op3.rs1 );
    op->index = DR_NONE;
    op->value = 0;
    if( code.op3.imm != 0 ) {
        op->value = SEX( code.op3imm.simm13, 12 );
    } else {
        // NYI: should check for asi and stuff it into op
        op->index = _SparcReg( code.op3.rs2 );
    }
}

static const dis_ref_type integerRefTypes[] = {
    DRT_SPARC_WORD,
    DRT_SPARC_BYTE,
    DRT_SPARC_HALF,
    DRT_SPARC_DWORD
};

dis_handler_return SPARCMem( dis_handle *h, void *d, dis_dec_ins *ins )
{
    sparc_ins   code;
    int         mem_op;
    int         reg_op;

    code.full = _SparcIns( ins->opcode );
    getOpIndices( code, &mem_op, &reg_op );
    ins->op[ reg_op ].type = DO_REG;
    ins->op[ reg_op ].base = _SparcReg( code.op3.rd );
    ins->op[ mem_op ].ref_type = integerRefTypes[ code.op3.opcode_3 & 0x03 ];
    doSparcMem( h, d, &ins->op[ mem_op ], code );
    ins->num_ops = 2;
    return( DHR_DONE );
}

static const dis_ref_type floatRefTypes[] = {
    DRT_SPARC_SFLOAT,
    DRT_SPARC_WORD,
    DRT_SPARC_DFLOAT,
    DRT_SPARC_DFLOAT,
};

dis_handler_return SPARCFPop2( dis_handle *h, void *d, dis_dec_ins *ins )
{
    sparc_ins   code;

    code.full = _SparcIns( ins->opcode );
    if( code.op3opf.opcode_3 == 0x35 ) {
        // fcmp 
        ins->op[ 0 ].type = DO_REG;
        ins->op[ 0 ].base = _SparcFReg( code.op3opf.rs1 );
        ins->op[ 1 ].type = DO_REG;
        ins->op[ 1 ].base = _SparcFReg( code.op3opf.rs2 );
    } else {
        ins->op[ 0 ].type = DO_REG;
        ins->op[ 0 ].base = _SparcFReg( code.op3opf.rs2 );
        ins->op[ 1 ].type = DO_REG;
        ins->op[ 1 ].base = _SparcFReg( code.op3opf.rd );
    }
    ins->num_ops = 2;
    return( DHR_DONE );
}

dis_handler_return SPARCFPop3( dis_handle *h, void *d, dis_dec_ins *ins )
{
    sparc_ins   code;

    code.full = _SparcIns( ins->opcode );
    ins->op[ 0 ].type = DO_REG;
    ins->op[ 0 ].base = _SparcFReg( code.op3opf.rs1 );
    ins->op[ 1 ].type = DO_REG;
    ins->op[ 1 ].base = _SparcFReg( code.op3opf.rs2 );
    ins->op[ 2 ].type = DO_REG;
    ins->op[ 2 ].base = _SparcFReg( code.op3opf.rd );
    ins->num_ops = 3;
    return( DHR_DONE );
}


dis_handler_return SPARCMemF( dis_handle *h, void *d, dis_dec_ins *ins )
{
    sparc_ins   code;
    int         mem_op;
    int         reg_op;

    code.full = _SparcIns( ins->opcode );
    getOpIndices( code, &mem_op, &reg_op );
    ins->op[ reg_op ].type = DO_REG;
    ins->op[ reg_op ].base = _SparcFReg( code.op3.rd );
    ins->op[ mem_op ].ref_type = floatRefTypes[ code.op3.opcode_3 & 0x03 ];
    doSparcMem( h, d, &ins->op[ mem_op ], code );
    if( code.op3.opcode_3 == 0x21 || code.op3.opcode_3 == 0x25 ) {
        // special case for ldfsr/stfsr instructions
        ins->op[ reg_op ].base = DR_SPARC_fsr;
    }
    if( code.op3.opcode_3 == 0x26 ) {
        // another special case - stdfq instruction
        ins->op[ reg_op ].base = DR_SPARC_fq;
    }
    ins->num_ops = 2;
    return( DHR_DONE );
}

static const dis_ref_type coproRefTypes[] = {
    DRT_SPARC_WORD,
    DRT_SPARC_WORD,
    DRT_SPARC_DWORD,
    DRT_SPARC_DWORD,
};

dis_handler_return SPARCMemC( dis_handle *h, void *d, dis_dec_ins *ins )
{
    sparc_ins   code;
    int         mem_op;
    int         reg_op;

    code.full = _SparcIns( ins->opcode );
    getOpIndices( code, &mem_op, &reg_op );
    ins->op[ reg_op ].type = DO_REG;
    ins->op[ reg_op ].base = _SparcCReg( code.op3.rd );
    ins->op[ mem_op ].ref_type = coproRefTypes[ code.op3.opcode_3 & 0x03 ];
    doSparcMem( h, d, &ins->op[ mem_op ], code );
    if( code.op3.opcode_3 == 0x31 || code.op3.opcode_3 == 0x35 ) {
        // special case for ldcsr/stcsr instructions
        ins->op[ reg_op ].base = DR_SPARC_csr;
    }
    if( code.op3.opcode_3 == 0x36 ) {
        // another special case - stdcq instruction
        ins->op[ reg_op ].base = DR_SPARC_cq;
    }
    ins->num_ops = 2;
    return( DHR_DONE );
}

static unsigned SPARCInsHook( dis_handle *h, void *d, dis_dec_ins *ins,
        dis_format_flags flags, char *name )
{
    const char  *new_op_name;

    if( !(flags & DFF_PSEUDO) ) return( 0 );
    new_op_name = NULL;
    switch( ins->type ) {
    case DI_SPARC_sethi:
        if( ins->op[ 1 ].base == DR_SPARC_r0 &&
            ins->op[ 0 ].value == 0 ) {
            new_op_name = "nop";
            ins->num_ops = 0;
        }
        break;
    case DI_SPARC_jmpl:
        if( ins->op[ 0 ].base == DR_SPARC_r31 &&
            ins->op[ 0 ].value == 8 &&
            ins->op[ 1 ].base == DR_SPARC_r0 ) {
            // jmpl %i7+8, %g0 -> ret
            new_op_name = "ret";
            ins->num_ops = 0;
        } else if( ins->op[ 0 ].base == DR_SPARC_r15 &&
            ins->op[ 0 ].value == 8 &&
            ins->op[ 1 ].base == DR_SPARC_r0 ) {
            // jmpl %o7+8, %g0 -> retl
            new_op_name = "retl";
            ins->num_ops = 0;
        }
        break;
    case DI_SPARC_subcc:
        if( ins->op[ 2 ].base == DR_SPARC_r0 ) {
            new_op_name = "cmp";
            ins->num_ops = 2;
        }
        break;
    case DI_SPARC_or:
        if( ins->op[ 0 ].base == DR_SPARC_r0 ) {
            new_op_name = "mov";
            ins->num_ops = 2;
            ins->op[ 0 ] = ins->op[ 1 ];
            ins->op[ 1 ] = ins->op[ 2 ];
            if( ins->op[ 0 ].base == DR_SPARC_r0
                 || ( ins->op[ 0 ].type == DO_IMMED
                     && ins->op[ 0 ].value == 0 )  ) {
                new_op_name = "clr";
                ins->num_ops = 1;
                ins->op[ 0 ] = ins->op[ 1 ];
            }
        } else {
            if( ins->op[ 1 ].base == DR_SPARC_r0
                 || ( ins->op[ 1 ].type == DO_IMMED
                     && ins->op[ 1 ].value == 0 )  ) {
                new_op_name = "mov";
                ins->num_ops = 2;
                ins->op[ 1 ] = ins->op[ 2 ];
            }
        }
        break;
    case DI_SPARC_orcc:
        if( ins->op[ 0 ].base == DR_SPARC_r0 &&
            ins->op[ 2 ].base == DR_SPARC_r0 ) {
            new_op_name = "tst";
            ins->num_ops = 1;
            ins->op[ 0 ] = ins->op[ 1 ];
        }
        break;
    case DI_SPARC_restore:
    case DI_SPARC_save:
        if( ins->op[ 0 ].base == DR_SPARC_r0 &&
            ins->op[ 1 ].base == DR_SPARC_r0 &&
            ins->op[ 2 ].base == DR_SPARC_r0 ) {
            ins->num_ops = 0;
        }
        break;
    default:
        break;
    }
    if( name != NULL && new_op_name != NULL ) {
        strcpy( name, new_op_name );
        return( strlen( name ) );
    }
    return( 0 );
}

static unsigned SPARCFlagHook( dis_handle *h, void *d, dis_dec_ins *ins,
        dis_format_flags flags, char *name )
{
    return( 0 );
}

static dis_register sparcTranslate( dis_register reg ) {

    if( reg >= DR_SPARC_r0 && reg <= DR_SPARC_r31 ) {
        reg += DR_SPARC_g0 - DR_SPARC_r0;
        switch( reg ) {
        case DR_SPARC_i6:
            reg = DR_SPARC_fp;
            break;
        case DR_SPARC_o6:
            reg = DR_SPARC_sp;
            break;
        default:
            break;
        }
    }
    return( reg );
}

static unsigned SPARCOpHook( dis_handle *h, void *d, dis_dec_ins *ins,
        dis_format_flags flags, unsigned op_num, char *op_buff )
{
    dis_operand *op;

    ins->op[op_num].ref_type = DRT_SPARC_WORD;
    if( flags & DFF_SYMBOLIC_REG ) {
        op = &ins->op[op_num];
        if( op->base >= DR_SPARC_r0 && op->base <= DR_SPARC_r31 ) {
            op->base = sparcTranslate( op->base );
        }
        if( op->index >= DR_SPARC_r0 && op->index <= DR_SPARC_r31 ) {
            op->index = sparcTranslate( op->index );
        }
    }
    return( 0 );
}

static dis_handler_return SPARCDecodeTableCheck( 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 SPARCPreprocHook( dis_handle *h, void *d, dis_dec_ins *ins )
{
    ByteSwap( h, d, ins );
}

static unsigned SPARCPostOpHook( 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 SPARCData = {
    SPARCRangeTable, SPARCRangeTablePos, SPARCPreprocHook, SPARCDecodeTableCheck, SPARCInsHook, SPARCFlagHook, SPARCOpHook, SPARCPostOpHook, &SPARCMaxInsName, 4
};

⌨️ 快捷键说明

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