mipsfmt.c
来自「开放源码的编译器open watcom 1.6.0版的源代码」· C语言 代码 · 共 1,508 行 · 第 1/4 页
C
1,508 行
/****************************************************************************
*
* 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: MIPS instruction formats and encodings.
*
****************************************************************************/
#include "as.h"
#ifndef _STANDALONE_
#include "asinline.h"
#endif
#include "mipsenc.h"
typedef struct reloc_entry *reloc_list;
struct reloc_entry {
reloc_list next;
op_reloc_target target;
owl_reloc_type type;
unsigned loc; // offset of the reloc from &result[0].
bool is_named; // does it have a corr. named symbol
};
typedef struct asm_reloc {
reloc_list first;
reloc_list last;
} asm_reloc;
typedef void (*fmt_func)( ins_table *, instruction *, uint_32 *, asm_reloc * );
typedef struct {
fmt_func func;
op_type ops[MAX_OPERANDS];
} mips_format;
typedef enum {
DOMOV_ORIGINAL,
DOMOV_ABS,
} domov_option;
#define MAX_VARIETIES 3
typedef op_type ot_array[MAX_VARIETIES][3];
// TODO: kill off all these once the axp residue is gone
#define _EightBits( x ) ( (x) & 0x00ff )
#define _ElevenBits( x ) ( (x) & 0x07ff )
#define _FourteenBits( x ) ( (x) & 0x3fff )
#define _TwentyBits( x ) ( (x) & 0x000fffff )
#define _LIT_value( x ) ( _EightBits( x ) << 1 )
#define _LIT_bit 1
#define _LIT_unshifted( x ) ( _LIT_value( x ) | _LIT_bit )
#define _Memory_disp( x ) ( _SixteenBits( x ) << 0 )
#define _Mem_Func( x ) ( _SixteenBits( x ) << 0 )
#define _Op_Func( x ) ( _SixBits( x ) << 0 )
#define _FP_Op_Func( x ) ( _ElevenBits( x ) << 5 )
#define _LIT( x ) ( _LIT_unshifted( x ) << 12 )
// This is real MIPS stuff
#define _TenBits( x ) ( (x) & 0x03ff )
#define _Code( x ) ( _TwentyBits( x ) << 6 )
#define _TrapCode( x ) ( _TenBits( x ) << 6 )
#define _Longword_offset( x ) ( (x) >> 2 )
#define MAX_EXTENDED_INS 20 // Including the default buffer, we have
// 21 dwords for an ins that emits multiple
// instructions. (eg. ldb)
// Check if ".set noat" is in effect before using this
#define AT_REG_IDX RegIndex( AT_REG )
#define ZERO_REG MakeReg( RC_GPR, MIPS_ZERO_SINK )
#define OPCODE_NOP 0x00
#define OPCODE_ADDIU 0x09
#define OPCODE_ORI 0x0d
#define OPCODE_LUI 0x0f
#define FNCCODE_OR 0x25
#define FNCCODE_JR 0x08
#define FNCCODE_JALR 0x09
// TODO: kill off these macros
#define OPCODE_BIS 0x11
#define FUNCCODE_BIS 0x0020
#define OPCODE_LDA 0x8
#define OPCODE_LDAH 0x9
#define OP_HAS_RELOC( op ) ((op)->flags & (RELOC | UNNAMED_RELOC))
#define OP_RELOC_NAMED( op ) ((op)->flags & RELOC)
static unsigned numExtendedIns = 0; // >= 1 when we use extendedIns
static uint_32 result[MAX_EXTENDED_INS + 1];
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_BRANCH_REL, // j^ reloc
OWL_RELOC_JUMP_REL, // jump hint
};
static uint_32 cop_codes[4] = {
0x10, // COP0
0x11, // COP1
0x12, // COP2
0x13 // COP3
};
static bool ensureOpAbsolute( ins_operand *op, uint_8 opIdx )
//***********************************************************
{
if( OP_HAS_RELOC( op ) ) {
Error( RELOC_NOT_ALLOWED, opIdx );
return( FALSE );
}
return( TRUE );
}
static void addReloc( asm_reloc *reloc, op_reloc_target target, owl_reloc_type type, unsigned loc, bool is_named )
//****************************************************************************************************************
{
reloc_list new_entry;
new_entry = MemAlloc( sizeof( struct reloc_entry ) );
new_entry->next = NULL;
new_entry->target = target;
new_entry->type = type;
new_entry->loc = loc;
new_entry->target = target;
new_entry->is_named = is_named;
if( reloc->first == NULL ) {
reloc->first = new_entry;
} else {
reloc->last->next = new_entry;
}
reloc->last = new_entry;
}
static owl_reloc_type relocType( asm_reloc_type type, owl_reloc_type default_type )
//*********************************************************************************
{
owl_reloc_type ret;
if( type == ASM_RELOC_UNSPECIFIED ) {
return( default_type );
}
switch( default_type ) {
case OWL_RELOC_HALF_HI:
case OWL_RELOC_HALF_LO:
if( (ret = reloc_translate[type]) != OWL_RELOC_HALF_HI &&
ret != OWL_RELOC_HALF_LO ) {
Error( INVALID_RELOC_MODIFIER );
}
break;
case OWL_RELOC_BRANCH_REL: // j^ reloc
if( (ret = reloc_translate[type]) != default_type ) {
Error( INVALID_RELOC_MODIFIER );
}
break;
case OWL_RELOC_JUMP_REL: // jump hint
// we accept j^ to be specified for jump hint for now.
if( (ret = reloc_translate[type]) != OWL_RELOC_JUMP_REL &&
ret != OWL_RELOC_BRANCH_REL ) {
Error( INVALID_RELOC_MODIFIER );
}
ret = OWL_RELOC_JUMP_REL;
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, uint_32 *offset )
//*********************************************************************************************
{
if( op == NULL ) return;
if( !( OP_HAS_RELOC( op ) ) ) return;
addReloc( reloc, op->reloc.target, relocType( op->reloc.type, rtype ),
(unsigned)offset - (unsigned)result, ( op->flags & RELOC ) );
}
/*
IT_OPERATE:
QF_V..........+0x40
IT_FP_xxxx:
QF_S..........+0x400
QF_U..........+0x100
QF_V..........+0x100
QF_I..........+0x200
QF_C..........-0x080
QF_M..........-0x040
QF_D..........+0x040
*/
static ins_funccode getFuncCode( ins_table *table, instruction *ins )
//*******************************************************************
{
ins_funccode fc;
fc = table->funccode;
switch( table->template ) {
case IT_OPERATE:
case IT_OPERATE_IMM:
case IT_PSEUDO_NOT:
if( ins->format->flags & QF_V ) {
fc += 0x40;
} else {
assert( ins->format->flags == 0 ); // No other valid flags
}
break;
case IT_FP_OPERATE:
case IT_FP_CONVERT:
case IT_PSEUDO_NEGF:
if( ins->format->flags & QF_S ) fc += 0x400;
if( ins->format->flags & QF_U ) fc += 0x100;
if( ins->format->flags & QF_V ) fc += 0x100;
if( ins->format->flags & QF_I ) fc += 0x200;
if( ins->format->flags & QF_C ) fc -= 0x080;
if( ins->format->flags & QF_M ) fc -= 0x040;
if( ins->format->flags & QF_D ) fc += 0x040;
break;
default:
assert( FALSE ); // Others should have no need to call this.
}
return( fc );
}
static void doOpcodeJType( uint_32 *buffer, uint_8 opcode )
//*********************************************************
{
*buffer = _Opcode( opcode );
}
static void doOpcodeIType( uint_32 *buffer, uint_8 opcode, uint_8 rt, uint_8 rs, signed_16 immed )
//************************************************************************************************
{
*buffer = _Opcode( opcode ) | _Rs( rs ) | _Rt( rt ) | _Immed( immed );
}
static void doOpcodeRType( uint_32 *buffer, uint_8 opcode, uint_8 fc, uint_8 rd, uint_8 rs, uint_8 rt )
//*****************************************************************************************************
{
*buffer = _Opcode( opcode ) | _Rs( rs ) | _Rt( rt ) | _Rd( rd ) | _Function( fc );
}
static void doOpcodeCopOp( uint_32 *buffer, uint_8 opcode, uint_8 fc, uint_32 extra )
//***********************************************************************************
// This procedure doesn't fill in all the bits (missing bits 6-24).
// But we can fill it in using extra.
{
*buffer = _Opcode( opcode ) | (1 << 25) | extra | _Function( fc );
}
#if 0
static void doOpcodeIShift( uint_32 *buffer, uint_8 fc, uint_8 rd, uint_8 rt, uint_8 sa )
//***************************************************************************************
{
*buffer = _Opcode( 0 ) | _Rs( 0 ) | _Rt( rt ) | _Rd( rd ) | _Shift( sa ) | _Function( fc );
}
static void doOpcodeFloatRType( type_class_def type, uint_8 fnc, uint_8 fd, uint_8 fs, uint_8 ft )
//************************************************************************************************
{
mips_ins ins;
int fmt;
// Select operand format
if( type == FS ) {
fmt = 0x10;
} else if( type == FD || type == FL ) {
fmt = 0x11;
} else {
assert( 0 );
}
// Opcode is always COP1
ins = _Opcode( 0x11 ) | _FPFormat( fmt ) | _Ft( ft ) | _Fs( fs ) | _Fd( fd ) | _Function( fnc );
EmitIns( ins );
}
#endif
static void doOpcodeRsRt( uint_32 *buffer, ins_opcode opcode, uint_8 rs, uint_8 rt, uint_32 remain )
//**************************************************************************************************
{
*buffer = _Opcode( opcode ) | _Rs( rs ) | _Rt( rt ) | remain;
}
static void doOpcodeFcRsRt( uint_32 *buffer, ins_opcode opcode, ins_funccode fc, uint_8 ra, uint_8 rc, uint_32 extra )
//********************************************************************************************************************
// This procedure doesn't fill in all the bits (missing bits 20-12).
// But we can fill it in using extra.
{
*buffer = _Opcode( opcode ) | _Op_Func( fc ) | _Rs( ra ) | _Rt( rc ) |
extra;
}
static void doOpcodeFcRsRtImm( uint_32 *buffer, ins_opcode opcode, ins_funccode fc, uint_8 rs, uint_8 rt, uint_32 imm )
//*********************************************************************************************************************
{
*buffer = _Opcode( opcode ) | _Op_Func( fc ) | _Rs( rs ) | _Rt( rt ) |
_Immed( imm );
}
static void doOpcodeFcRdRtSa( uint_32 *buffer, ins_opcode opcode, ins_funccode fc, uint_8 rd, uint_8 rt, uint_8 sa )
//******************************************************************************************************************
{
*buffer = _Opcode( opcode ) | _Op_Func( fc ) | _Rd( rd ) | _Rt( rt ) |
_Shift( sa );
}
static void doFPInst( uint_32 *buffer, ins_opcode opcode, uint_8 ra, uint_8 rb, uint_8 rc, uint_32 remain )
//*********************************************************************************************************
{
*buffer = _Opcode( opcode ) | _Rs( ra ) | _Rt( rb ) |
_FP_Op_Func( remain ) | _Rd( rc );
}
#ifndef _STANDALONE_
static void doAutoVar( asm_reloc *reloc, op_reloc_target targ, uint_32 *buffer, ins_table *table, instruction *ins )
//******************************************************************************************************************
{
ins_operand *op;
op = ins->operands[1];
if( op->reg != ZERO_REG ) {
Error( BAD_BASE_REG_FOR_STACKVAR );
return;
}
addReloc( reloc, targ, OWL_RELOC_FP_OFFSET, (unsigned)buffer - (unsigned)&result[0], TRUE );
doOpcodeRsRt( buffer, table->opcode, MIPS_FRAME_REG,
RegIndex( ins->operands[0]->reg ), 0 );
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?