ppcfmt.c

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

C
1,377
字号
/****************************************************************************
*
*                            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 formats and encodings.
*
****************************************************************************/


#include "as.h"

typedef enum {
    UNNAMED,            // unnamed reloc
    SYMBOLIC            // symbolic reloc
} asm_reloc_flag;

typedef struct asm_reloc {
    owl_reloc_type      type;
    union {
        int_32          label_num;
        sym_handle      sym;
    }                   target;
    uint_32             valid : 1;
    uint_32             is_unnamed : 1;
} asm_reloc;

typedef void (*fmt_func)( ins_table *, instruction *, uint_32 *, asm_reloc * );

typedef struct {
    fmt_func    func;
    op_type     ops[ MAX_OPERANDS ];
} ppc_format;

#define _SixBits( x )           ( (x) & 0x003f )
#define _TenBits( x )           ( (x) & 0x03ff )
#define _FiveBits( x )          ( (x) & 0x001f )
#define _EightBits( x )         ( (x) & 0x00ff )
#define _FourteenBits( x )      ( (x) & 0x3fff )
#define _TwentyFourBits( x )    ( (x) & 0x00ffffff )

// these correspond to letters on Appendix A table of Motorola refrence
#define _D( x )         ( _FiveBits(x) << 21 )
#define _S( x )         ( _FiveBits(x) << 21 )
#define _A( x )         ( _FiveBits(x) << 16 )
#define _B( x )         ( _FiveBits(x) << 11 )
#define _C( x )         ( _FiveBits(x) << 6 )
#define _LI( x )        ( _TwentyFourBits(x) << 2 )
#define _BO( x )        ( _FiveBits(x) << 21 )
#define _BI( x )        ( _FiveBits(x) << 16 )
#define _BD( x )        ( _FourteenBits(x) << 2 )
#define _SH( x )        ( _FiveBits(x) << 11 )
#define _MB( x )        ( _FiveBits(x) << 6 )
#define _ME( x )        ( _FiveBits(x) << 1 )
#define _CRM( x )       ( _EightBits(x) << 12 )
#define _TBR( x )       ( _TenBits(x) << 11 )
#define _SPR( x )       ( _TenBits(x) << 11 )
#define _FM( x )        ( _EightBits(x) << 17 )

#define _Opcode( x )    ( _SixBits(x) << 26 )
#define _Opcode2( x )   ( _TenBits(x) << 1 ) // some opcode2 includes OE

// sixteen bit signed immediate
#define _SignedImmed( x )       ( (x) & 0xffff )

#define _OE( x )        ( ( ( (x) & IF_SETS_OVERFLOW ) ? 1 : 0 ) << 10 )
#define _RC( x )        ( ( ( (x) & IF_SETS_CC ) ? 1 : 0 ) << 0 )
#define _AA( x )        ( ( ( (x) & IF_SETS_ABSOLUTE ) ? 1 : 0 ) << 1 )
#define _LK( x )        ( ( ( (x) & IF_SETS_LINK ) ? 1 : 0 ) << 0 )

#define _Longword_offset( x )   ( (x) >> 2 )

#define _IsAbsolute( x )        ( ( (x) & IF_SETS_ABSOLUTE ) ? 1 : 0 )

static owl_reloc_type reloc_translate[] = {
    OWL_RELOC_ABSOLUTE,     // Corresponds to ASM_RELOC_UNSPECIFIED
    OWL_RELOC_WORD,
    OWL_RELOC_HALF_HI,
    OWL_RELOC_HALF_HA,
    OWL_RELOC_HALF_LO,
    OWL_RELOC_JUMP_REL,
    OWL_RELOC_BRANCH_REL,
};

static int_32 SPRChkList[] = {
    0, 1, 4, 5, 6, 8, 9, 18, 19, 22, 25, 26, 27, 272, 273, 274, 275, 282, 287,
    528, 529, 530, 531, 532, 533, 534, 535, 1008, 1009, 1010, 1013, 1023
};

static bool ensureTypeCorrect( ins_operand *op, op_type type, uint_8 opIdx ) {
//****************************************************************************

    if( op->type != type ) {
        Error( IMPROPER_OPERAND, opIdx );
        return( FALSE );
    }
    return( TRUE );
}

static bool ensureOpAbsolute( ins_operand *op, uint_8 opIdx ) {
//*************************************************************

    if( ( op->flags & ( RELOC | UNNAMED_RELOC ) ) ) {
        Error( RELOC_NOT_ALLOWED, opIdx );
        return( FALSE );
    }
    return( TRUE );
}

static void doEncode2( uint_32 *buffer, ins_opcode p, uint r1, uint r2, uint imm, ins_flags flags ) {
//****************************************************************************************************************
// Use when there are 2 5-bit blocks (other than opcode blocks) and
// an immediate block (16-bit)

    *buffer = _Opcode( p ) | _D( r1 ) | _A( r2 ) | _SignedImmed( imm ) | _OE( flags ) | _RC( flags );
}

static void doEncode3( uint_32 *buffer, ins_opcode p, ins_opcode s, uint r1, uint r2, uint r3, ins_flags flags ) {
//****************************************************************************************************************
// Use when there are 3 5-bit blocks (other than opcode blocks)

    *buffer = _Opcode( p ) | _D( r1 ) | _A( r2 ) | _B( r3 ) | _OE( flags ) | _Opcode2( s ) | _RC( flags );
}

static void doEncode4( uint_32 *buffer, ins_opcode p, ins_opcode s, uint r1, uint r2, uint r3, uint r4, ins_flags flags ) {
//*************************************************************************************************************************
// Use when there are 4 5-bit blocks (other than opcode blocks)

    *buffer = _Opcode( p ) | _D( r1 ) | _A( r2 ) | _C( r3 ) | _B( r4 ) | _Opcode2( s ) | _RC( flags );
}

static void doEncode5( uint_32 *buffer, ins_opcode p, uint r1, uint r2, uint r3, uint r4, uint r5, ins_flags flags ) {
//********************************************************************************************************************
// Use when there are 5 5-bit blocks (other than opcode blocks) e.g. rlwimi

    *buffer = _Opcode( p ) | _S( r1 ) | _A( r2 ) | _SH( r3 ) | _MB( r4 ) | _ME( r5 ) | _RC( flags );
}

static void doEncodeBoBiBd( uint_32 *buffer, ins_opcode p, uint bo, uint bi, uint bd, ins_flags flags ) {
//*******************************************************************************************************

    *buffer = _Opcode( p ) | _BO( bo ) | _BI( bi ) | _BD( bd ) | _AA( flags ) | _LK( flags );
}

static void doEncodeBoBiOp2( uint_32 *buffer, ins_opcode p, ins_opcode q, uint bo, uint bi, ins_flags flags ) {
//*************************************************************************************************************

    *buffer = _Opcode( p ) | _BO( bo ) | _BI( bi ) | _Opcode2( q ) | _AA( flags ) | _LK( flags );
}

static void doEncodeSPR( uint_32 *buffer, ins_opcode p, ins_opcode q, uint regidx, uint spr, ins_flags flags ) {
//**************************************************************************************************************

    int_32      swapped_spr;

    swapped_spr = ( ( spr & 0x1f ) << 5 ) | ( ( spr & 0x3e0 ) >> 5 );
    *buffer = _Opcode( p ) | _Opcode2( q ) | _D( regidx ) |
              _SPR( swapped_spr ) | _RC( flags ) | _OE( flags );
}

static owl_reloc_type relocType( asm_reloc_type type, owl_reloc_type default_type, bool absolute ) {
//**************************************************************************************************
// The absolute flag is used for jump/branch only

    owl_reloc_type  ret;

    if( type == ASM_RELOC_UNSPECIFIED ) {
        if( default_type == OWL_RELOC_JUMP_REL && absolute ) {
            return( OWL_RELOC_JUMP_ABS );
        } else if( default_type == OWL_RELOC_BRANCH_REL && absolute ) {
            return( OWL_RELOC_BRANCH_ABS );
        }
        return( default_type );
    }
    switch( default_type ) {
    case OWL_RELOC_HALF_HI:
    case OWL_RELOC_HALF_HA:
    case OWL_RELOC_HALF_LO:
        if( ( ret = reloc_translate[type] ) != OWL_RELOC_HALF_HI &&
            ret != OWL_RELOC_HALF_HA && ret != OWL_RELOC_HALF_LO ) {
            Error( INVALID_RELOC_MODIFIER );
        }
        break;
    case OWL_RELOC_BRANCH_REL:
    case OWL_RELOC_JUMP_REL:
        if( ( ret = reloc_translate[type] ) != default_type ) {
            Error( INVALID_RELOC_MODIFIER );
            break;
        }
        if( ret == OWL_RELOC_JUMP_REL && absolute ) {
            ret = OWL_RELOC_JUMP_ABS;
        } else if( ret == OWL_RELOC_BRANCH_REL && absolute ) {
            ret = OWL_RELOC_BRANCH_ABS;
        }
        break;
    default:
        //Error( "internal - unexpected default type" );
        assert( FALSE );
        ret = OWL_RELOC_ABSOLUTE;
    }
    return( ret );
}

static void doReloc( asm_reloc *reloc, ins_operand *op, owl_reloc_type rtype, ins_flags flags ) {
//***********************************************************************************************
// If it is a jump reloc, we should pass it in as a relative no matter what
// and let relocType change it to absolute if AA bit is set.

    assert( rtype != OWL_RELOC_JUMP_ABS && rtype != OWL_RELOC_BRANCH_ABS );
    if( ( op->flags & RELOC ) == RELOC ) {
        reloc->target.sym = op->reloc.target.ptr;
        reloc->type = relocType( op->reloc.type, rtype, _IsAbsolute( flags ) );
        reloc->is_unnamed = 0;
        reloc->valid = 1;
    } else if( ( op->flags & UNNAMED_RELOC ) == UNNAMED_RELOC ) {
        reloc->target.label_num = op->reloc.target.label;
        reloc->type = relocType( op->reloc.type, rtype, _IsAbsolute( flags ) );
        reloc->is_unnamed = 1;
        reloc->valid = 1;
    }
}

static void ITBinary( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc ) {
//*********************************************************************************************
// Three operands line up in the order they will be in the encoding

    assert( ins->num_operands == 3 );
    doEncode3( buffer, table->primary, table->secondary,
        RegIndex( ins->operands[0]->reg ), RegIndex( ins->operands[1]->reg ),
        RegIndex( ins->operands[2]->reg ),
        ( ins->format->flags & table->optional ) | table->required );
}

static void ITBinary2( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc ) {
//**********************************************************************************************
// The first two operands are reversed in terms of bit positioning

    assert( ins->num_operands == 3 );
    doEncode3( buffer, table->primary, table->secondary,
        RegIndex( ins->operands[1]->reg ), RegIndex( ins->operands[0]->reg ),
        RegIndex( ins->operands[2]->reg ),
        ( ins->format->flags & table->optional ) | table->required );
}

static void ITBinaryImmed( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc ) {
//**************************************************************************************************

    ins_operand *op;

    assert( ins->num_operands == 3 );
    op = ins->operands[2];
    doEncode2( buffer, table->primary, RegIndex( ins->operands[0]->reg ),
        RegIndex( ins->operands[1]->reg ), op->constant,
        ( ins->format->flags & table->optional ) | table->required );
    doReloc( reloc, op, OWL_RELOC_HALF_LO, 0 );
}

static void ITBinaryImmed2( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc ) {
//***************************************************************************************************

    ins_operand *op;

    assert( ins->num_operands == 3 );
    op = ins->operands[2];
    doEncode2( buffer, table->primary, RegIndex( ins->operands[1]->reg ),
        RegIndex( ins->operands[0]->reg ), op->constant,
        ( ins->format->flags & table->optional ) | table->required );
    doReloc( reloc, op, OWL_RELOC_HALF_LO, 0 );
}

static void ITUnary( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc ) {
//********************************************************************************************

    assert( ins->num_operands == 2 );
    doEncode3( buffer, table->primary, table->secondary,
        RegIndex( ins->operands[0]->reg ), RegIndex( ins->operands[1]->reg ), 0,
        ( ins->format->flags & table->optional ) | table->required );
}

static void ITUnary2( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc ) {
//*********************************************************************************************

    assert( ins->num_operands == 2 );
    doEncode3( buffer, table->primary, table->secondary,
        RegIndex( ins->operands[1]->reg ), RegIndex( ins->operands[0]->reg ), 0,
        ( ins->format->flags & table->optional ) | table->required );
}

static void ITFPBin( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc ) {
//********************************************************************************************

    ITBinary( table, ins, buffer, reloc );
}


static void ITFPUnary( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc ) {
//**********************************************************************************************

    assert( ins->num_operands == 2 );
    doEncode3( buffer, table->primary, table->secondary,
        RegIndex( ins->operands[0]->reg ), 0, RegIndex( ins->operands[1]->reg ),
        ( ins->format->flags & table->optional ) | table->required );
}

static void ITFPCmp( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc ) {
//********************************************************************************************

    assert( ins->num_operands == 3 );
    doEncode3( buffer, table->primary, table->secondary,
        RegIndex( ins->operands[0]->reg ) << 2,
        RegIndex( ins->operands[1]->reg ), RegIndex( ins->operands[2]->reg ),
        ( ins->format->flags & table->optional ) | table->required );
}

static void ITFPMulAdd( ins_table *table, instruction *ins, uint_32 *buffer, asm_reloc *reloc ) {
//***********************************************************************************************

    assert( ins->num_operands == 4 );
    doEncode4( buffer, table->primary, table->secondary,
        RegIndex( ins->operands[0]->reg ), RegIndex( ins->operands[1]->reg ),
        RegIndex( ins->operands[2]->reg ), RegIndex( ins->operands[3]->reg ),
        ( ins->format->flags & table->optional ) | table->required );
}

⌨️ 快捷键说明

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