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 + -
显示快捷键?