* ========== Copyright Header Begin ==========================================
* OpenSPARC T2 Processor File: sparcv9decode.c
* Copyright (c) 2006 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
* The above named program is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
* ========== Copyright Header End ============================================
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
#pragma ident "@(#)sparcv9decode.c 1.69 07/03/19 SMI"
#include "tsparcv9internal.h"
#include "sparcv9decode.h"
#include "hostnative_asm.h" /* autogenerated from hostnative_asm.S */
#include "hostnative.h" /* autogenerated from hostnative.c */
#include "execinstns.h" /* autogenerated core defined instructions */
#include "sparcv9instns.h" /* autogenerated sparcv9 instruction definitions */
static char * v9_illegal_reason_str
[]={
"unknown_fp_instruction",
"bpcc_illegal_cc_specifier",
"bpr_illegal_cc_specifier",
"done_retry_illegal_fcn_field",
"saved_reserved_field_non_zero",
"tcc_reserved_field_non_zero",
"movcc_reserved_field_non_zero",
"movcc_illegal_cc_field",
"illtrap_reserved_field_non_zero",
"fmovcc_reserved_field_non_zero",
"fmovcc_illegal_cc_field",
"flushw_reserved_field_non_zero",
"visop36_reserved_field_non_zero",
"sir_reserved_field_non_zero",
"cas_reserved_field_non_zero",
"misc_reserved_field_non_zero"
#ifdef FP_DECODE_DISABLED
#define FP_DECODE_FPU_ON_CHECK \
if (!((sparcv9_cpu_t*)(sp->specificp))->fpu_on) goto fp_disabled
#else /* FP_DECODE_DISABLED */
#define FP_DECODE_FPU_ON_CHECK
#endif /* FP_DECODE_DISABLED */
void sparcv9_decode_me(simcpu_t
*sp
, xicache_instn_t
* xcip
)
void (*exec_funcp
)(simcpu_t
*sp
, xicache_instn_t
* xcip
);
void (*p_exec_funcp
)(simcpu_t
*sp
, xicache_instn_t
* xcip
);
* Very first step .... check to see if breakpoint
* reached. If true, install breakpoint catcher instead
* of a decoded instruction ....
* ... if there is a match, we still decode the instruction,
* but replace the actual instruction operation with a trampoline
* the instruction operation is then encoded into the
* FIXME : for the time being because of the hassles of flushing the
* x-cache, we dont install a trampoline .. we leave the decoded func
* as decode_me and pay the penalty .... this way we can track the
* breakpoint progress for the time being.
* Also means we don't have to have the decoded instn in the breakpoint
* OK: So if we match an active breakpoint, we *must* always leave the
* decoded function as *_decode_me. Asside from this whether or
* not we execute the *real* decoded instruction depends on whether or
* not the breakpoint is being executed for the first time, or this
* is the first instruction after that breakpoint being taken !
if (sp
->bp_infop
!= NULL
) {
switch (breakpoint_check(sp
->bp_infop
, sp
->pc
, DEFAULT_BP_CONTEXT
/* FIXME */, &bp
)) {
if (bp
== NULL
/* "next" breakpoint */
|| bp
->first_strike
== false) {
/* just stop if we really want to break */
/* if not, continue the decode, but don't install the function */
bp
->first_strike
= false;
* For sparcv9, to save us time an undecoded instruction is
* saved as a bit pattern in the xicache ...
* ... saves us a second v-to-p conversion so we can read memory
* Decoder is designed for a big endian instn encoding.
* So to make life simpler on a little endian host, reverse the byte order
* and then treat as big endian.
* Now go about the legitimate instruction decoding
switch ((ty_code_t
)X_OP(instn
)) {
op0c
= (T0o3_code_t
)X_OP2(instn
);
/* Deprecated integer condition code branches */
br_offset
= X_FMT2_DISP22(instn
);
br_offset
= ((br_offset
<< 10) >> 8); /* sign extend to 32bits */
annul_bit
= X_ANNUL_BIT(instn
);
SET_OP_BROFF32(br_offset
);
switch ((bcc_type_t
)X_COND(instn
)) {
SET_OPv9(bralways_ds_annul
);
if (!annul_bit
) goto do_noop
;
SET_OPv9(brnever_ds_annul
);
#define BR_DECODE(_cc, _type) \
SET_OPv9(b##_type##_##_cc##_an); \
SET_OPv9(b##_type##_##_cc); \
br_offset
= X_FMT2_DISP19(instn
);
br_offset
= ((br_offset
<< 13) >> 11); /* sign extend */
annul_bit
= X_ANNUL_BIT(instn
);
/* v9 Predicted integer condition code branches */
switch( (cc2bit_t
)X_FMT2_CC(instn
)) {
/* defined as illegal - rather than unknown */
SET_OP_ILL_REASON(bpcc_illegal_cc_specifier
);
goto illegal_instruction
;
/* Only xcc bpcc forms here ... */
SET_OP_BROFF32(br_offset
);
switch ((bcc_type_t
)X_COND(instn
)) {
case Bcc_a
: goto bicc_ba
;
case Bcc_n
: goto bicc_bn
;
if (rd
== 0) goto do_noop
;
uimm
= (instn
& 0x3FFFFF) << 10;
if (!CHECK_RESERVED_ZERO(instn
, 29, 25)) {
SET_OP_ILL_REASON(illtrap_reserved_field_non_zero
);
goto illegal_instruction
;
SET_OP_UIMM32((instn
& 0x3FFFFF));
br_offset
= X_FMT2_DISP16(instn
);
br_offset
= ((br_offset
<< 16) >> 14); /* sign extend to 32bits & scale by 4*/
annul_bit
= X_ANNUL_BIT(instn
);
SET_OP_BREGOFF32(br_offset
);
#define BREG_DECODE(_type, _an) \
SET_OPv9(br##_type##_an); \
switch ((rcond_type_t
)X_RCOND(instn
)) {
SET_OP_ILL_REASON(bpr_illegal_cc_specifier
);
goto illegal_instruction
;
switch ((rcond_type_t
)X_RCOND(instn
)) {
SET_OP_ILL_REASON(bpr_illegal_cc_specifier
);
goto illegal_instruction
;
/* Deprecated floating condition code branches */
br_offset
= X_FMT2_DISP22(instn
);
br_offset
= ((br_offset
<< 10) >> 8); /* sign extend to 32bits */
annul_bit
= X_ANNUL_BIT(instn
);
SET_OP_BROFF32(br_offset
);
switch ((bcc_type_t
)X_COND(instn
)) {
SET_OPv9(bralways_ds_annul
);
if (!annul_bit
) goto do_noop
;
SET_OPv9(brnever_ds_annul
);
#define FBR_DECODE(_cc, _type) \
SET_OPv9(fb##_type##_##_cc##_an); \
SET_OPv9(fb##_type##_##_cc); \
br_offset
= X_FMT2_DISP19(instn
);
br_offset
= ((br_offset
<< 13) >> 11); /* sign extend */
annul_bit
= X_ANNUL_BIT(instn
);
/* v9 Predicted floating condition code branches */
SET_OP_BR_FCC(X_FMT2_CC(instn
));
switch( (fcc2bit_t
)X_FMT2_CC(instn
)) {
/* Only fcc1-3 bpcc forms here ... */
SET_OP_BROFF32(br_offset
);
switch ((bcc_type_t
)X_COND(instn
)) {
case FBcc_a
: goto fbicc_ba
;
case FBcc_n
: goto fbicc_bn
;
case Ty_1
: /* Call instruction only */
offset
= X_FMT1_DISP30(instn
) << 2; /* shift to be address relative */
op2c
= (T2o3_code_t
)X_OP3(instn
);
/* register x immediate -> register forms */
* Arithmetic instructions first
if (rd
== 0) goto do_noop
;
if (rs1
== 0) goto do_zero_reg
;
if (rs1
== 0) goto do_move_simm
;
if (rd
== 0) goto do_noop
;
SET_OPv9( add_co_imm_rd0
); /* rd==0 */
SET_OPv9( add_cico_imm_rd0
); /* rd==0 */
SET_OPv9( add_cico_imm
);
if (rd
== 0) goto do_noop
;
if (simm
== 0 && rs1
== 0) goto do_zero_reg
;
if (simm
== 0) goto do_move_reg
;
if (rs1
== 0) goto do_move_simm
;
if (rd
== 0) goto do_noop
;
SET_OPv9( sub_co_imm_rd0
); /* rd==0 */
SET_OPv9( sub_cico_imm_rd0
); /* rd==0 */
SET_OPv9( sub_cico_imm
);
simm
= ~simm
; /* fall thru*/
if (rd
== 0) goto do_noop
;
if (simm
== 0 || rs1
==0) goto do_zero_reg
;
if (simm
== -1) goto do_move_reg
;
simm
= ~simm
; /* fall thru*/
if (rd
== 0) goto do_noop
;
if (simm
== 0 && rs1
==0) goto do_zero_reg
;
if (simm
== 0) goto do_move_reg
;
if (rs1
== 0) goto do_move_simm
;
simm
= ~simm
; /* fall thru*/
if (rd
== 0) goto do_noop
;
if (simm
== 0 && rs1
== 0) goto do_zero_reg
;
if (simm
== 0) goto do_move_reg
;
if (rs1
== 0) goto do_move_simm
;
/* cond code out - forms */
simm
= ~simm
; /* fall thru*/
SET_OPv9( and_cc_imm_rd0
); /* rd==0 */
simm
= ~simm
; /* fall thru*/
SET_OPv9( or_cc_imm_rd0
); /* rd==0 */
simm
= ~simm
; /* fall thru*/
SET_OPv9( xor_cc_imm_rd0
); /* rd==0 */
if (!(X_SHIFT_SIZE_BIT(instn
) ?
CHECK_RESERVED_ZERO(instn
, 11, 6) :
CHECK_RESERVED_ZERO(instn
, 11, 5))) {
SET_OP_ILL_REASON(misc_reserved_field_non_zero
);
goto illegal_instruction
;
if (rd
== 0) goto do_noop
;
if (rs1
== 0) goto do_zero_reg
;
simm
= (X_SHIFT_SIZE_BIT(instn
)) ? X_SHIFT_IMM64(instn
) : X_SHIFT_IMM32(instn
);
if (!(X_SHIFT_SIZE_BIT(instn
) ?
CHECK_RESERVED_ZERO(instn
, 11, 6) :
CHECK_RESERVED_ZERO(instn
, 11, 5))) {
SET_OP_ILL_REASON(misc_reserved_field_non_zero
);
goto illegal_instruction
;
if (rd
== 0) goto do_noop
;
if (rs1
== 0) goto do_zero_reg
;
if (X_SHIFT_SIZE_BIT(instn
)) {
simm
= X_SHIFT_IMM64(instn
);
simm
= X_SHIFT_IMM32(instn
);
if (!(X_SHIFT_SIZE_BIT(instn
) ?
CHECK_RESERVED_ZERO(instn
, 11, 6) :
CHECK_RESERVED_ZERO(instn
, 11, 5))) {
SET_OP_ILL_REASON(misc_reserved_field_non_zero
);
goto illegal_instruction
;
if (rd
== 0) goto do_noop
;
if (rs1
== 0) goto do_zero_reg
;
if (X_SHIFT_SIZE_BIT(instn
)) {
simm
= X_SHIFT_IMM64(instn
);
simm
= X_SHIFT_IMM32(instn
);
if (!CHECK_RESERVED_ZERO(instn
, 10, 8)) {
SET_OP_ILL_REASON(tcc_reserved_field_non_zero
);
goto illegal_instruction
;
switch( (cc4bit_t
)X_FMT4_CC(instn
) ) {
case CC4bit_icc
: SET_OP_TRAP_CC(0); break;
case CC4bit_xcc
: SET_OP_TRAP_CC(1); break;
SET_OP_ILL_REASON(tcc_illegal_cc_field
);
goto illegal_instruction
;
/* truncate simm - as only an 8 bit
* immediate in tcc instructions, not the
* 13 bit field we extracted above
if (X_COND(instn
) == cond_n
) goto do_noop
;
SET_OP_TRAP_COND(X_COND(instn
));
/* We attempt to fast path ta ... */
if (X_COND(instn
) == cond_a
&& rs1
==0)
/* Niagara2 and Rock support additional functions. */
/* This instruction is handled differently wrt niagara and rock.
* Therefore it is moved to cpu_decode_me() functions in rock.c
/* This instruction is handled differently wrt niagara and rock.
* Therefore it is moved to cpu_decode_me() functions in rock.c
/* This instruction is handled differently wrt niagara and rock.
* Therefore it is moved to cpu_decode_me() functions in rock.c
/* can't check for rd = 0 because side-effect is write to Y reg */
/* can't check for rd = 0 because side-effect is write to Y reg */
/* This instruction is handled differently wrt niagara and rock.
* Therefore it is moved to cpu_decode_me() functions in rock.c
/* sir shares this opcode */
if (!CHECK_RESERVED_ZERO(instn
, 18, 14)) {
SET_OP_ILL_REASON(sir_reserved_field_non_zero
);
goto illegal_instruction
;
SET_OPv9( write_state_reg_imm
);
SET_OPv9( read_priv_reg
);
simm
= rs1
; /* duplicate the reg code into simm */
SET_OPv9( read_hyper_priv_reg
);
simm
= rs1
; /* duplicate the reg code into simm */
SET_OPv9( write_priv_reg_imm
);
SET_OPv9( write_hyper_priv_reg_imm
);
/* This instruction is handled differently wrt niagara and rock.
* Therefore it is moved to cpu_decode_me() functions in rock.c
/* cant optimise for rd=0 because */
/* need to test for /0 */
SET_OPv9(tadd_co_tv_imm
);
SET_OPv9(tsub_co_tv_imm
);
SET_OP_ILL_REASON(flushw_reserved_field_non_zero
);
goto illegal_instruction
;
/* This instruction is handled differently wrt niagara and rock.
* Therefore it is moved to cpu_decode_me() functions in rock.c
if (rd
== 0) goto do_noop
;
switch ((rcond_type_t
)X_MOVRCOND(instn
)) {
SET_OP_ILL_REASON(movr_illegal_cc_field
);
goto illegal_instruction
;
/* jumping out of _imm to _rrr forms */
/* jumping out of _imm to _rrr forms */
/* jumping out of _imm to _rrr forms */
/* This instruction is handled differently wrt niagara and rock.
* Therefore it is moved to cpu_decode_me() functions in rock.c
/* register x register -> register forms */
if (rd
== 0) goto do_noop
;
if (rs1
== 0) goto do_zero_reg
;
if (rd
== 0) goto do_noop
;
SET_OPv9( add_co_rrr_rd0
);
SET_OPv9( add_cico_rrr_rd0
);
SET_OPv9( add_cico_rrr
);
if (rs2
==0 && rs1
==0) goto do_zero_reg
;
if (rs2
==0) goto do_move_reg
;
if (rd
== 0) goto do_noop
;
SET_OPv9( sub_co_rrr_rd0
);
SET_OPv9( sub_cico_rrr_rd0
);
SET_OPv9( sub_cico_rrr
);
if (rd
== 0) goto do_noop
;
if (rs2
== 0 || rs1
==0) goto do_zero_reg
;
if (rd
== 0) goto do_noop
;
if (rs2
== 0 && rs1
==0) goto do_zero_reg
;
if (rs2
== 0) goto do_move_reg
;
if (rd
== 0) goto do_noop
;
if (rs2
== 0 && rs1
==0) goto do_zero_reg
;
if (rs2
== 0) goto do_move_reg
;
if (rs1
==0) goto do_zero_reg
;
if (rs2
==0) goto do_move_reg
;
/* more optmisiing here - FIXME */
if (rd
== 0) goto do_noop
;
/* condition code forms */
if (rd
== 0) { /* RD0DECODE */
SET_OPv9( and_cc_rrr_rd0
);
if (rd
== 0) { /* RD0DECODE */
SET_OPv9( andn_cc_rrr_rd0
);
if (rd
== 0) { /* RD0DECODE */
SET_OPv9( or_cc_rrr_rd0
);
if (rd
== 0) { /* RD0DECODE */
SET_OPv9( orn_cc_rrr_rd0
);
if (rd
== 0) { /* RD0DECODE */
SET_OPv9( xor_cc_rrr_rd0
);
if (rd
== 0) { /* RD0DECODE */
SET_OPv9( xnor_cc_rrr_rd0
);
if (!CHECK_RESERVED_ZERO(instn
, 11, 5)) {
SET_OP_ILL_REASON(misc_reserved_field_non_zero
);
goto illegal_instruction
;
if (rd
== 0) goto do_noop
;
if (X_SHIFT_SIZE_BIT(instn
)) {
if (!CHECK_RESERVED_ZERO(instn
, 11, 5)) {
SET_OP_ILL_REASON(misc_reserved_field_non_zero
);
goto illegal_instruction
;
if (rd
== 0) goto do_noop
;
if (X_SHIFT_SIZE_BIT(instn
)) {
if (!CHECK_RESERVED_ZERO(instn
, 11, 5)) {
SET_OP_ILL_REASON(misc_reserved_field_non_zero
);
goto illegal_instruction
;
if (rd
== 0) goto do_noop
;
if (X_SHIFT_SIZE_BIT(instn
)) {
if (!CHECK_RESERVED_ZERO(instn
, 12, 5)) {
SET_OP_ILL_REASON(misc_reserved_field_non_zero
);
goto illegal_instruction
;
/* can't check for rd = 0 because side-effect is write to Y reg */
/* can't check for rd = 0 because side-effect is write to Y reg */
if (rd
== 0 && rs1
==15) {
if (!CHECK_RESERVED_ZERO(instn
, 12, 0)) {
SET_OP_ILL_REASON(misc_reserved_field_non_zero
);
goto illegal_instruction
;
goto all_done
; /* no further args */
SET_OPv9( read_state_reg
);
SET_OPv9( read_priv_reg
);
simm
= rs1
; /* duplicate the reg code into simm */
SET_OPv9( read_hyper_priv_reg
);
simm
= rs1
; /* duplicate the reg code into simm */
SET_OPv9( write_priv_reg_rrr
);
SET_OPv9( write_hyper_priv_reg_rrr
);
SET_OPv9( write_state_reg_rrr
);
/* This instruction is handled differently wrt niagara and rock.
* Therefore it is moved to cpu_decode_me() functions in rock.c
/* This instruction is handled differently wrt niagara and rock.
* Therefore it is moved to cpu_decode_me() functions in rock.c
/* This instruction is handled differently wrt niagara and rock.
* Therefore it is moved to cpu_decode_me() functions in rock.c
if (!CHECK_RESERVED_ZERO(instn
, 10, 5)) {
SET_OP_ILL_REASON(tcc_reserved_field_non_zero
);
goto illegal_instruction
;
switch( (cc4bit_t
)X_FMT4_CC(instn
) ) {
case CC4bit_icc
: SET_OP_TRAP_CC(0); break;
case CC4bit_xcc
: SET_OP_TRAP_CC(1); break;
SET_OP_ILL_REASON(tcc_illegal_cc_field
);
goto illegal_instruction
;
if (X_COND(instn
) == cond_n
) goto do_noop
;
SET_OP_TRAP_COND(X_COND(instn
));
/* cant optimise for rd=0 because */
/* need to test for /0 */
SET_OPv9(tadd_co_tv_rrr
);
SET_OPv9(tsub_co_tv_rrr
);
int fcn
= X_FMT2_FCN(instn
);
if (!fcn
&& (!CHECK_RESERVED_ZERO(instn
, 18, 0))) {
SET_OP_ILL_REASON(flushw_reserved_field_non_zero
);
goto illegal_instruction
;
if (!CHECK_RESERVED_ZERO(instn
, 10, 5)) {
SET_OP_ILL_REASON(movcc_reserved_field_non_zero
);
goto illegal_instruction
;
if (!X_FMT4_CC2(instn
)) {
if (rd
== 0) goto do_noop
;
/* We attempt to fast path movfcc_a ... */
if (X_FMT4_COND(instn
) == cond_n
) goto do_noop
;
if (X_FMT4_COND(instn
) == cond_a
) {
SET_OP_MOVCC_CC(X_FMT4_CC(instn
));
SET_OP_MOVCC_COND(X_FMT4_COND(instn
));
if (rd
== 0) goto do_noop
;
switch( (cc4bit_t
)X_FMT4_CC(instn
) ) {
case CC4bit_icc
: SET_OP_MOVCC_CC(0); break;
case CC4bit_xcc
: SET_OP_MOVCC_CC(1); break;
SET_OP_ILL_REASON(movcc_illegal_cc_field
);
goto illegal_instruction
;
/* We attempt to fast path movcc_a ... */
if (X_FMT4_COND(instn
) == cond_n
) goto do_noop
;
if (X_FMT4_COND(instn
) == cond_a
) {
SET_OP_MOVCC_COND(X_FMT4_COND(instn
));
if (rd
== 0) goto do_noop
;
switch ((rcond_type_t
)X_MOVRCOND(instn
)) {
SET_OP_ILL_REASON(movr_illegal_cc_field
);
goto illegal_instruction
;
switch ((T3o3_fp34_opf_t
)X_FP_OPF(instn
)) {
case FPop34_fmovs
: SET_OPv9(fmovs
); goto do_fp_s2s_ds
;
case FPop34_fmovd
: SET_OPv9(fmovd
); goto do_fp_s2d_dd
;
case FPop34_fmovq
: goto unimplemented_fpop
;
case FPop34_fnegs
: SET_OPv9(fnegs
); goto do_fp_s2s_ds
;
case FPop34_fnegd
: SET_OPv9(fnegd
); goto do_fp_s2d_dd
;
case FPop34_fnegq
: goto unimplemented_fpop
;
case FPop34_fabss
: SET_OPv9(fabss
); goto do_fp_s2s_ds
;
case FPop34_fabsd
: SET_OPv9(fabsd
); goto do_fp_s2d_dd
;
case FPop34_fabsq
: goto unimplemented_fpop
;
* Niagara 1 doesn't have fsqrt[sd], but this
* is dealt with in the fpsim_bw support.
case FPop34_fsqrts
: SET_OPv9(fsqrts
); goto do_fp_s2s_ds
;
case FPop34_fsqrtd
: SET_OPv9(fsqrtd
); goto do_fp_s2d_dd
;
case FPop34_fsqrtq
: goto unimplemented_fpop
;
case FPop34_fadds
: SET_OPv9(fadds
); goto do_fp_s1s_s2s_ds
;
case FPop34_faddd
: SET_OPv9(faddd
); goto do_fp_s1d_s2d_dd
;
case FPop34_faddq
: goto unimplemented_fpop
;
case FPop34_fsubs
: SET_OPv9(fsubs
); goto do_fp_s1s_s2s_ds
;
case FPop34_fsubd
: SET_OPv9(fsubd
); goto do_fp_s1d_s2d_dd
;
case FPop34_fsubq
: goto unimplemented_fpop
;
case FPop34_fmuls
: SET_OPv9(fmuls
); goto do_fp_s1s_s2s_ds
;
case FPop34_fmuld
: SET_OPv9(fmuld
); goto do_fp_s1d_s2d_dd
;
case FPop34_fmulq
: goto unimplemented_fpop
;
case FPop34_fdivs
: SET_OPv9(fdivs
); goto do_fp_s1s_s2s_ds
;
case FPop34_fdivd
: SET_OPv9(fdivd
); goto do_fp_s1d_s2d_dd
;
case FPop34_fdivq
: goto unimplemented_fpop
;
case FPop34_fsmuld
: SET_OPv9(fsmuld
); goto do_fp_s1s_s2s_dd
;
case FPop34_fdmulq
: goto unimplemented_fpop
;
case FPop34_fstox
: SET_OPv9(fstox
); goto do_fp_s2s_dd
;
case FPop34_fdtox
: SET_OPv9(fdtox
); goto do_fp_s2d_dd
;
case FPop34_fqtox
: goto unimplemented_fpop
;
case FPop34_fxtos
: SET_OPv9(fxtos
); goto do_fp_s2d_ds
;
case FPop34_fxtod
: SET_OPv9(fxtod
); goto do_fp_s2d_dd
;
case FPop34_fxtoq
: goto unimplemented_fpop
;
case FPop34_fitos
: SET_OPv9(fitos
); goto do_fp_s2s_ds
;
case FPop34_fdtos
: SET_OPv9(fdtos
); goto do_fp_s2d_ds
;
case FPop34_fqtos
: goto unimplemented_fpop
;
case FPop34_fitod
: SET_OPv9(fitod
); goto do_fp_s2s_dd
;
case FPop34_fstod
: SET_OPv9(fstod
); goto do_fp_s2s_dd
;
case FPop34_fqtod
: goto unimplemented_fpop
;
case FPop34_fitoq
: goto unimplemented_fpop
;
case FPop34_fstoq
: goto unimplemented_fpop
;
case FPop34_fdtoq
: goto unimplemented_fpop
;
case FPop34_fstoi
: SET_OPv9(fstoi
); goto do_fp_s2s_ds
;
case FPop34_fdtoi
: SET_OPv9(fdtoi
); goto do_fp_s2d_ds
;
case FPop34_fqtoi
: goto unimplemented_fpop
;
switch ((T3o3_fp35_opf_t
)X_FP_OPF(instn
)) {
switch( (fcc2bit_t
)X_FCOND(instn
)) {
SET_OPv9(fcmps_fcc0
); break;
SET_OPv9(fcmps_fcc1
); break;
SET_OPv9(fcmps_fcc2
); break;
SET_OPv9(fcmps_fcc3
); break;
switch( (fcc2bit_t
)X_FCOND(instn
)) {
SET_OPv9(fcmpd_fcc0
); break;
SET_OPv9(fcmpd_fcc1
); break;
SET_OPv9(fcmpd_fcc2
); break;
SET_OPv9(fcmpd_fcc3
); break;
case FPop35_fcmpq
: goto unimplemented_fpop
;
switch( (fcc2bit_t
)X_FCOND(instn
)) {
SET_OPv9(fcmpes_fcc0
); break;
SET_OPv9(fcmpes_fcc1
); break;
SET_OPv9(fcmpes_fcc2
); break;
SET_OPv9(fcmpes_fcc3
); break;
switch( (fcc2bit_t
)X_FCOND(instn
)) {
SET_OPv9(fcmped_fcc0
); break;
SET_OPv9(fcmped_fcc1
); break;
SET_OPv9(fcmped_fcc2
); break;
SET_OPv9(fcmped_fcc3
); break;
case FPop35_fcmpeq
: goto unimplemented_fpop
;
if (!CHECK_RESERVED_ZERO(instn
, 18, 18)) {
SET_OP_ILL_REASON(fmovcc_reserved_field_non_zero
);
goto illegal_instruction
;
if (X_FMT4_COND(instn
) == cond_n
)
if (X_FMT4_COND(instn
) == cond_a
) {
if (X_FMT4_CC2a(instn
)) {
switch( (cc4bit_t
)X_FMT4_CC(instn
) ) {
case CC4bit_icc
: SET_OP_MOVCC_CC(0); break;
case CC4bit_xcc
: SET_OP_MOVCC_CC(1); break;
SET_OP_ILL_REASON(fmovcc_illegal_cc_field
);
goto illegal_instruction
;
SET_OP_MOVCC_CC(X_FMT4_CC(instn
));
SET_OP_MOVCC_COND(X_FMT4_COND(instn
));
if (!CHECK_RESERVED_ZERO(instn
, 18, 18)) {
SET_OP_ILL_REASON(fmovcc_reserved_field_non_zero
);
goto illegal_instruction
;
if (X_FMT4_COND(instn
) == cond_n
)
if (X_FMT4_COND(instn
) == cond_a
) {
if (X_FMT4_CC2a(instn
)) {
switch( (cc4bit_t
)X_FMT4_CC(instn
) ) {
case CC4bit_icc
: SET_OP_MOVCC_CC(0); break;
case CC4bit_xcc
: SET_OP_MOVCC_CC(1); break;
SET_OP_ILL_REASON(fmovcc_illegal_cc_field
);
goto illegal_instruction
;
SET_OP_MOVCC_CC(X_FMT4_CC(instn
));
SET_OP_MOVCC_COND(X_FMT4_COND(instn
));
* strange but true ... if fp disabled, VIS
* instructions fail because they can't access
* the FP registers ... except the ones that
* ... otherwise unknown VIS instructions
* fail as illegal instructions.
switch ((T3o3_fp36_opf_t
)X_FP_OPF(instn
)) {
if (!CHECK_RESERVED_ZERO3(instn
, 29, 25, 18, 14, 4, 3)) {
SET_OP_ILL_REASON(visop36_reserved_field_non_zero
);
goto illegal_instruction
;
SET_OP_SIMM16((instn
& 7));
goto unimplemented_visop
;
/* This instruction is handled differently wrt niagara and rock.
* Therefore it is moved to cpu_decode_me() functions in rock.c
* Principally load/store operation decoding
op3c
= (T3o3_code_t
)X_OP3(instn
);
/* register x immediate -> register forms */
SET_OP_ILL_REASON(odd_rd_for_ldd
);
goto illegal_instruction
;
SET_OP_ASI_OP(MA_lddu64
);
SET_OP_ILL_REASON(odd_rd_for_std
);
goto illegal_instruction
;
SET_OP_ASI_OP(MA_stdu64
);
SET_OP_ASI_OP(MA_ldstub
);
SET_OP_ASI_OP(MA_ldstub
);
SET_OP_ILL_REASON(odd_rd_for_ldd
);
goto illegal_instruction
;
SET_OP_ASI_OP(MA_lddu64
);
SET_OP_ILL_REASON(odd_rd_for_std
);
goto illegal_instruction
;
SET_OP_ASI_OP(MA_stdu64
);
if (!CHECK_RESERVED_ZERO(instn
, 12, 5)) {
SET_OP_ILL_REASON(cas_reserved_field_non_zero
);
goto illegal_instruction
;
SET_OP_RS2( X_RS2(instn
) );
SET_OP_ILL_REASON(illegal_instruction
);
goto illegal_instruction
;
SET_OP_ILL_REASON(illegal_instruction
);
goto illegal_instruction
;
SET_OP_ILL_REASON(illegal_fsr_specifier
);
goto illegal_instruction
;
SET_OP_ILL_REASON(illegal_fsr_specifier
);
goto illegal_instruction
;
SET_OP_ASI_OP(MA_ldfp32
);
SET_OP_ASI_OP(MA_stfp32
);
SET_OP_ILL_REASON(illegal_instruction
);
goto illegal_instruction
;
SET_OP_ASI_OP(MA_ldfp64
);
SET_OP_ASI_OP(MA_stfp64
);
SET_OP_ILL_REASON(odd_rd_for_ldd
);
goto illegal_instruction
;
SET_OP_ASI_OP(MA_lddu64
);
SET_OP_ILL_REASON(odd_rd_for_std
);
goto illegal_instruction
;
SET_OP_ASI_OP(MA_stdu64
);
SET_OP_ASI_OP(MA_ldstub
);
SET_OP_ASI_OP(MA_ldstub
);
SET_OP_ILL_REASON(odd_rd_for_ldd
);
goto illegal_instruction
;
SET_OP_ASI_OP(MA_lddu64
);
SET_OP_ILL_REASON(odd_rd_for_std
);
goto illegal_instruction
;
SET_OP_ASI_OP(MA_stdu64
);
SET_OP_ASI_NUM( X_ASI(instn
) );
SET_OP_ILL_REASON(illegal_instruction
);
goto illegal_instruction
;
SET_OP_ILL_REASON(illegal_instruction
);
goto illegal_instruction
;
SET_OP_ILL_REASON(illegal_fsr_specifier
);
goto illegal_instruction
;
SET_OP_ILL_REASON(illegal_fsr_specifier
);
goto illegal_instruction
;
SET_OP_ASI_OP(MA_ldfp32
);
SET_OP_ASI_OP(MA_stfp32
);
SET_OP_ILL_REASON(illegal_instruction
);
goto illegal_instruction
;
SET_OP_ASI_OP(MA_ldfp64
);
SET_OP_ASI_OP(MA_stfp64
);
goto unknown_decode
; /* FIXME */
goto unknown_decode
; /* Could be CPU specific instruction. */
unknown_decode
:; /* We can reach here if either the decoder screwed up (Even illegal */
/* instructions should have a proper decode case) or we encountered */
/* a CPU specific instruction which the SparcV9 decoder doesn't */
/* know about. We check to see which of those two cases happened in */
/* the illegal instruction handling code below. */
SET_OP_ILL_REASON(unknown_instruction
);
goto illegal_instruction
;
* Sparc allows us to not decode FP ops when there is no floating point
* unit. So in this case we deliver a fp_disabled trap ...
#ifdef FP_DECODE_DISABLED
#endif /* FP_DECODE_DISABLED */
SET_OPv9(fp_unimplemented_instruction
);
/* FP version of unknown_decode. */
SET_OP_ILL_REASON(unknown_fp_instruction
);
SET_OPv9(fp_unimplemented_instruction
);
#ifdef PROCESSOR_SUPPORTS_QUADFP
SET_OPv9(fp_invalidreg_instruction
);
SET_OP_ILL_REASON(unimplemented_visop
);
goto illegal_instruction
;
illegal_instruction
:; /* we reach here if the decoder detected an illegal instruction*/
/* for example - a bpcc instrn with cc0=0 & cc1=1 */
/* Or if we have run into a CPU specific instruction which the */
/* SparcV9 decoder doesn't know about. */
SET_OPv9(illegal_instruction
);
* Before declaring the instruction illegal or unknown, we check the CPU
* specific instruction decoder.
* Since some FP instructions want to return 'unimplemented'
* instead of 'illegal', preserve whatever has been set until
* we get a positive decode from the proc-specific decode.
p_exec_funcp
= sp
->config_procp
->proc_typep
->cpu_decode_me(sp
, xcip
, instn
);
if (p_exec_funcp
!= NULL
) {
* CPU specific instruction decoder was successful.
exec_funcp
= p_exec_funcp
;
DBGILLINST( lprintf(sp
->gid
, "decoded illegal instruction 0x%x "
"(@PC = 0x%llx) : %s\n", instn
, sp
->pc
,
v9_illegal_reason_str
[(int)xcip
->di
.ill_reason
]););
if (xcip
->di
.ill_reason
== unknown_instruction
) {
fprintf(stderr
, "Error! : unable to decode instruction "
"(PC = 0x%llx in mode %s) 0x%x\n", sp
->pc
,
sparcv9_state_name
[((sparcv9_cpu_t
*)
(sp
->specificp
))->state
], instn
);
abort(); /* shouldnt get here*/
* Setup and tests for decoded floating point instructions
#ifdef PROCESSOR_SUPPORTS_QUADFP
if (rs1
& 0x2) goto invalid_fp_register
;
if (rs2
& 0x2) goto invalid_fp_register
;
if (rd
& 0x2) goto invalid_fp_register
;
/* Quad not supported yet - FIXME */
* For FP ops with a single operand (e.g. abs) SPARC encodes into rs2
* I move it into rs1 for my pre-decoded form.
SET_OP_ASI_NUM(X_ASI(instn
));
* Setup for decoded instructions
SET_OP_ASI_NUM(X_ASI(instn
));
* FIXME: This ugly hook is so that we can instruction trace for
* debugging without penalising the main execution loop.
* Basically, if debugging is turned on we leverage the same
* behaviour as for breakpoint support and after dumping the
* pre-execution state, prevent installation of the exec_func.
* Why is this a fixme ? This will ultimately done by a trampoline
* for each instruction we wish to trace .. and will be done on a per
* simcpu basis rather than globally. Until then we are left with this.
sparcv9_trace_output(sp
, instn
);
* prevent installation of any instruction
* that matched a live instruction
xcip
->exec_funcp
= sp
->decodemep
;
/* cache for next time around */
xcip
->exec_funcp
= exec_funcp
;
/* execute the instruction on behalf of the x-cache */