@ -32,37 +32,27 @@
# include "trace-tcg.h"
# include "exec/log.h"
//#define DEBUG_DISPATCH 1
/* Fake floating point. */
# define tcg_gen_mov_f64 tcg_gen_mov_i64
# define tcg_gen_qemu_ldf64 tcg_gen_qemu_ld64
# define tcg_gen_qemu_stf64 tcg_gen_qemu_st64
# define DEFO32(name, offset) static TCGv QREG_##name;
# define DEFO64(name, offset) static TCGv_i64 QREG_##name;
# define DEFF64(name, offset) static TCGv_i64 QREG_##name;
# include "qregs.def"
# undef DEFO32
# undef DEFO64
# undef DEFF64
static TCGv_i32 cpu_halted ;
static TCGv_i32 cpu_exception_index ;
static TCGv_env cpu_env ;
static char cpu_reg_names [ 3 * 8 * 3 + 5 * 4 ] ;
static char cpu_reg_names [ 2 * 8 * 3 + 5 * 4 ] ;
static TCGv cpu_dregs [ 8 ] ;
static TCGv cpu_aregs [ 8 ] ;
static TCGv_i64 cpu_fregs [ 8 ] ;
static TCGv_i64 cpu_macc [ 4 ] ;
# define REG(insn, pos) (((insn) >> (pos)) & 7)
# define DREG(insn, pos) cpu_dregs[REG(insn, pos)]
# define AREG(insn, pos) get_areg(s, REG(insn, pos))
# define FREG(insn, pos) cpu_fregs[REG(insn, pos)]
# define MACREG(acc) cpu_macc[acc]
# define QREG_SP get_areg(s, 7)
@ -87,11 +77,9 @@ void m68k_tcg_init(void)
# define DEFO64(name, offset) \
QREG_ # # name = tcg_global_mem_new_i64 ( cpu_env , \
offsetof ( CPUM68KState , offset ) , # name ) ;
# define DEFF64(name, offset) DEFO64(name, offset)
# include "qregs.def"
# undef DEFO32
# undef DEFO64
# undef DEFF64
cpu_halted = tcg_global_mem_new_i32 ( cpu_env ,
- offsetof ( M68kCPU , env ) +
@ -111,10 +99,6 @@ void m68k_tcg_init(void)
cpu_aregs [ i ] = tcg_global_mem_new ( cpu_env ,
offsetof ( CPUM68KState , aregs [ i ] ) , p ) ;
p + = 3 ;
sprintf ( p , " F%d " , i ) ;
cpu_fregs [ i ] = tcg_global_mem_new_i64 ( cpu_env ,
offsetof ( CPUM68KState , fregs [ i ] ) , p ) ;
p + = 3 ;
}
for ( i = 0 ; i < 4 ; i + + ) {
sprintf ( p , " ACC%d " , i ) ;
@ -265,6 +249,42 @@ static void update_cc_op(DisasContext *s)
}
}
/* Generate a jump to an immediate address. */
static void gen_jmp_im ( DisasContext * s , uint32_t dest )
{
update_cc_op ( s ) ;
tcg_gen_movi_i32 ( QREG_PC , dest ) ;
s - > is_jmp = DISAS_JUMP ;
}
/* Generate a jump to the address in qreg DEST. */
static void gen_jmp ( DisasContext * s , TCGv dest )
{
update_cc_op ( s ) ;
tcg_gen_mov_i32 ( QREG_PC , dest ) ;
s - > is_jmp = DISAS_JUMP ;
}
static void gen_raise_exception ( int nr )
{
TCGv_i32 tmp = tcg_const_i32 ( nr ) ;
gen_helper_raise_exception ( cpu_env , tmp ) ;
tcg_temp_free_i32 ( tmp ) ;
}
static void gen_exception ( DisasContext * s , uint32_t where , int nr )
{
update_cc_op ( s ) ;
gen_jmp_im ( s , where ) ;
gen_raise_exception ( nr ) ;
}
static inline void gen_addr_fault ( DisasContext * s )
{
gen_exception ( s , s - > insn_pc , EXCP_ADDRESS ) ;
}
/* Generate a load from the specified address. Narrow values are
sign extended to full register width . */
static inline TCGv gen_load ( DisasContext * s , int opsize , TCGv addr , int sign )
@ -286,7 +306,6 @@ static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign)
tcg_gen_qemu_ld16u ( tmp , addr , index ) ;
break ;
case OS_LONG :
case OS_SINGLE :
tcg_gen_qemu_ld32u ( tmp , addr , index ) ;
break ;
default :
@ -296,16 +315,6 @@ static inline TCGv gen_load(DisasContext * s, int opsize, TCGv addr, int sign)
return tmp ;
}
static inline TCGv_i64 gen_load64 ( DisasContext * s , TCGv addr )
{
TCGv_i64 tmp ;
int index = IS_USER ( s ) ;
tmp = tcg_temp_new_i64 ( ) ;
tcg_gen_qemu_ldf64 ( tmp , addr , index ) ;
gen_throws_exception = gen_last_qop ;
return tmp ;
}
/* Generate a store. */
static inline void gen_store ( DisasContext * s , int opsize , TCGv addr , TCGv val )
{
@ -318,7 +327,6 @@ static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val)
tcg_gen_qemu_st16 ( val , addr , index ) ;
break ;
case OS_LONG :
case OS_SINGLE :
tcg_gen_qemu_st32 ( val , addr , index ) ;
break ;
default :
@ -327,13 +335,6 @@ static inline void gen_store(DisasContext *s, int opsize, TCGv addr, TCGv val)
gen_throws_exception = gen_last_qop ;
}
static inline void gen_store64 ( DisasContext * s , TCGv addr , TCGv_i64 val )
{
int index = IS_USER ( s ) ;
tcg_gen_qemu_stf64 ( val , addr , index ) ;
gen_throws_exception = gen_last_qop ;
}
typedef enum {
EA_STORE ,
EA_LOADU ,
@ -377,6 +378,15 @@ static inline uint32_t read_im32(CPUM68KState *env, DisasContext *s)
return im ;
}
/* Read a 64-bit immediate constant. */
static inline uint64_t read_im64 ( CPUM68KState * env , DisasContext * s )
{
uint64_t im ;
im = ( uint64_t ) read_im32 ( env , s ) < < 32 ;
im | = ( uint64_t ) read_im32 ( env , s ) ;
return im ;
}
/* Calculate and address index. */
static TCGv gen_addr_index ( DisasContext * s , uint16_t ext , TCGv tmp )
{
@ -909,6 +919,304 @@ static TCGv gen_ea(CPUM68KState *env, DisasContext *s, uint16_t insn,
return gen_ea_mode ( env , s , mode , reg0 , opsize , val , addrp , what ) ;
}
static TCGv_ptr gen_fp_ptr ( int freg )
{
TCGv_ptr fp = tcg_temp_new_ptr ( ) ;
tcg_gen_addi_ptr ( fp , cpu_env , offsetof ( CPUM68KState , fregs [ freg ] ) ) ;
return fp ;
}
static TCGv_ptr gen_fp_result_ptr ( void )
{
TCGv_ptr fp = tcg_temp_new_ptr ( ) ;
tcg_gen_addi_ptr ( fp , cpu_env , offsetof ( CPUM68KState , fp_result ) ) ;
return fp ;
}
static void gen_fp_move ( TCGv_ptr dest , TCGv_ptr src )
{
TCGv t32 ;
TCGv_i64 t64 ;
t32 = tcg_temp_new ( ) ;
tcg_gen_ld16u_i32 ( t32 , src , offsetof ( FPReg , l . upper ) ) ;
tcg_gen_st16_i32 ( t32 , dest , offsetof ( FPReg , l . upper ) ) ;
tcg_temp_free ( t32 ) ;
t64 = tcg_temp_new_i64 ( ) ;
tcg_gen_ld_i64 ( t64 , src , offsetof ( FPReg , l . lower ) ) ;
tcg_gen_st_i64 ( t64 , dest , offsetof ( FPReg , l . lower ) ) ;
tcg_temp_free_i64 ( t64 ) ;
}
static void gen_load_fp ( DisasContext * s , int opsize , TCGv addr , TCGv_ptr fp )
{
TCGv tmp ;
TCGv_i64 t64 ;
int index = IS_USER ( s ) ;
t64 = tcg_temp_new_i64 ( ) ;
tmp = tcg_temp_new ( ) ;
switch ( opsize ) {
case OS_BYTE :
tcg_gen_qemu_ld8s ( tmp , addr , index ) ;
gen_helper_exts32 ( cpu_env , fp , tmp ) ;
break ;
case OS_WORD :
tcg_gen_qemu_ld16s ( tmp , addr , index ) ;
gen_helper_exts32 ( cpu_env , fp , tmp ) ;
break ;
case OS_LONG :
tcg_gen_qemu_ld32u ( tmp , addr , index ) ;
gen_helper_exts32 ( cpu_env , fp , tmp ) ;
break ;
case OS_SINGLE :
tcg_gen_qemu_ld32u ( tmp , addr , index ) ;
gen_helper_extf32 ( cpu_env , fp , tmp ) ;
break ;
case OS_DOUBLE :
tcg_gen_qemu_ld64 ( t64 , addr , index ) ;
gen_helper_extf64 ( cpu_env , fp , t64 ) ;
tcg_temp_free_i64 ( t64 ) ;
break ;
case OS_EXTENDED :
if ( m68k_feature ( s - > env , M68K_FEATURE_CF_FPU ) ) {
gen_exception ( s , s - > insn_pc , EXCP_FP_UNIMP ) ;
break ;
}
tcg_gen_qemu_ld32u ( tmp , addr , index ) ;
tcg_gen_shri_i32 ( tmp , tmp , 16 ) ;
tcg_gen_st16_i32 ( tmp , fp , offsetof ( FPReg , l . upper ) ) ;
tcg_gen_addi_i32 ( tmp , addr , 4 ) ;
tcg_gen_qemu_ld64 ( t64 , tmp , index ) ;
tcg_gen_st_i64 ( t64 , fp , offsetof ( FPReg , l . lower ) ) ;
break ;
case OS_PACKED :
/* unimplemented data type on 68040/ColdFire
* FIXME if needed for another FPU
*/
gen_exception ( s , s - > insn_pc , EXCP_FP_UNIMP ) ;
break ;
default :
g_assert_not_reached ( ) ;
}
tcg_temp_free ( tmp ) ;
tcg_temp_free_i64 ( t64 ) ;
gen_throws_exception = gen_last_qop ;
}
static void gen_store_fp ( DisasContext * s , int opsize , TCGv addr , TCGv_ptr fp )
{
TCGv tmp ;
TCGv_i64 t64 ;
int index = IS_USER ( s ) ;
t64 = tcg_temp_new_i64 ( ) ;
tmp = tcg_temp_new ( ) ;
switch ( opsize ) {
case OS_BYTE :
gen_helper_reds32 ( tmp , cpu_env , fp ) ;
tcg_gen_qemu_st8 ( tmp , addr , index ) ;
break ;
case OS_WORD :
gen_helper_reds32 ( tmp , cpu_env , fp ) ;
tcg_gen_qemu_st16 ( tmp , addr , index ) ;
break ;
case OS_LONG :
gen_helper_reds32 ( tmp , cpu_env , fp ) ;
tcg_gen_qemu_st32 ( tmp , addr , index ) ;
break ;
case OS_SINGLE :
gen_helper_redf32 ( tmp , cpu_env , fp ) ;
tcg_gen_qemu_st32 ( tmp , addr , index ) ;
break ;
case OS_DOUBLE :
gen_helper_redf64 ( t64 , cpu_env , fp ) ;
tcg_gen_qemu_st64 ( t64 , addr , index ) ;
break ;
case OS_EXTENDED :
if ( m68k_feature ( s - > env , M68K_FEATURE_CF_FPU ) ) {
gen_exception ( s , s - > insn_pc , EXCP_FP_UNIMP ) ;
break ;
}
tcg_gen_ld16u_i32 ( tmp , fp , offsetof ( FPReg , l . upper ) ) ;
tcg_gen_shli_i32 ( tmp , tmp , 16 ) ;
tcg_gen_qemu_st32 ( tmp , addr , index ) ;
tcg_gen_addi_i32 ( tmp , addr , 4 ) ;
tcg_gen_ld_i64 ( t64 , fp , offsetof ( FPReg , l . lower ) ) ;
tcg_gen_qemu_st64 ( t64 , tmp , index ) ;
break ;
case OS_PACKED :
/* unimplemented data type on 68040/ColdFire
* FIXME if needed for another FPU
*/
gen_exception ( s , s - > insn_pc , EXCP_FP_UNIMP ) ;
break ;
default :
g_assert_not_reached ( ) ;
}
tcg_temp_free ( tmp ) ;
tcg_temp_free_i64 ( t64 ) ;
gen_throws_exception = gen_last_qop ;
}
static void gen_ldst_fp ( DisasContext * s , int opsize , TCGv addr ,
TCGv_ptr fp , ea_what what )
{
if ( what = = EA_STORE ) {
gen_store_fp ( s , opsize , addr , fp ) ;
} else {
gen_load_fp ( s , opsize , addr , fp ) ;
}
}
static int gen_ea_mode_fp ( CPUM68KState * env , DisasContext * s , int mode ,
int reg0 , int opsize , TCGv_ptr fp , ea_what what )
{
TCGv reg , addr , tmp ;
TCGv_i64 t64 ;
switch ( mode ) {
case 0 : /* Data register direct. */
reg = cpu_dregs [ reg0 ] ;
if ( what = = EA_STORE ) {
switch ( opsize ) {
case OS_BYTE :
case OS_WORD :
case OS_LONG :
gen_helper_reds32 ( reg , cpu_env , fp ) ;
break ;
case OS_SINGLE :
gen_helper_redf32 ( reg , cpu_env , fp ) ;
break ;
default :
g_assert_not_reached ( ) ;
}
} else {
tmp = tcg_temp_new ( ) ;
switch ( opsize ) {
case OS_BYTE :
tcg_gen_ext8s_i32 ( tmp , reg ) ;
gen_helper_exts32 ( cpu_env , fp , tmp ) ;
break ;
case OS_WORD :
tcg_gen_ext16s_i32 ( tmp , reg ) ;
gen_helper_exts32 ( cpu_env , fp , tmp ) ;
break ;
case OS_LONG :
gen_helper_exts32 ( cpu_env , fp , reg ) ;
break ;
case OS_SINGLE :
gen_helper_extf32 ( cpu_env , fp , reg ) ;
break ;
default :
g_assert_not_reached ( ) ;
}
tcg_temp_free ( tmp ) ;
}
return 0 ;
case 1 : /* Address register direct. */
return - 1 ;
case 2 : /* Indirect register */
addr = get_areg ( s , reg0 ) ;
gen_ldst_fp ( s , opsize , addr , fp , what ) ;
return 0 ;
case 3 : /* Indirect postincrement. */
addr = cpu_aregs [ reg0 ] ;
gen_ldst_fp ( s , opsize , addr , fp , what ) ;
tcg_gen_addi_i32 ( addr , addr , opsize_bytes ( opsize ) ) ;
return 0 ;
case 4 : /* Indirect predecrememnt. */
addr = gen_lea_mode ( env , s , mode , reg0 , opsize ) ;
if ( IS_NULL_QREG ( addr ) ) {
return - 1 ;
}
gen_ldst_fp ( s , opsize , addr , fp , what ) ;
tcg_gen_mov_i32 ( cpu_aregs [ reg0 ] , addr ) ;
return 0 ;
case 5 : /* Indirect displacement. */
case 6 : /* Indirect index + displacement. */
do_indirect :
addr = gen_lea_mode ( env , s , mode , reg0 , opsize ) ;
if ( IS_NULL_QREG ( addr ) ) {
return - 1 ;
}
gen_ldst_fp ( s , opsize , addr , fp , what ) ;
return 0 ;
case 7 : /* Other */
switch ( reg0 ) {
case 0 : /* Absolute short. */
case 1 : /* Absolute long. */
case 2 : /* pc displacement */
case 3 : /* pc index+displacement. */
goto do_indirect ;
case 4 : /* Immediate. */
if ( what = = EA_STORE ) {
return - 1 ;
}
switch ( opsize ) {
case OS_BYTE :
tmp = tcg_const_i32 ( ( int8_t ) read_im8 ( env , s ) ) ;
gen_helper_exts32 ( cpu_env , fp , tmp ) ;
tcg_temp_free ( tmp ) ;
break ;
case OS_WORD :
tmp = tcg_const_i32 ( ( int16_t ) read_im16 ( env , s ) ) ;
gen_helper_exts32 ( cpu_env , fp , tmp ) ;
tcg_temp_free ( tmp ) ;
break ;
case OS_LONG :
tmp = tcg_const_i32 ( read_im32 ( env , s ) ) ;
gen_helper_exts32 ( cpu_env , fp , tmp ) ;
tcg_temp_free ( tmp ) ;
break ;
case OS_SINGLE :
tmp = tcg_const_i32 ( read_im32 ( env , s ) ) ;
gen_helper_extf32 ( cpu_env , fp , tmp ) ;
tcg_temp_free ( tmp ) ;
break ;
case OS_DOUBLE :
t64 = tcg_const_i64 ( read_im64 ( env , s ) ) ;
gen_helper_extf64 ( cpu_env , fp , t64 ) ;
tcg_temp_free_i64 ( t64 ) ;
break ;
case OS_EXTENDED :
if ( m68k_feature ( s - > env , M68K_FEATURE_CF_FPU ) ) {
gen_exception ( s , s - > insn_pc , EXCP_FP_UNIMP ) ;
break ;
}
tmp = tcg_const_i32 ( read_im32 ( env , s ) > > 16 ) ;
tcg_gen_st16_i32 ( tmp , fp , offsetof ( FPReg , l . upper ) ) ;
tcg_temp_free ( tmp ) ;
t64 = tcg_const_i64 ( read_im64 ( env , s ) ) ;
tcg_gen_st_i64 ( t64 , fp , offsetof ( FPReg , l . lower ) ) ;
tcg_temp_free_i64 ( t64 ) ;
break ;
case OS_PACKED :
/* unimplemented data type on 68040/ColdFire
* FIXME if needed for another FPU
*/
gen_exception ( s , s - > insn_pc , EXCP_FP_UNIMP ) ;
break ;
default :
g_assert_not_reached ( ) ;
}
return 0 ;
default :
return - 1 ;
}
}
return - 1 ;
}
static int gen_ea_fp ( CPUM68KState * env , DisasContext * s , uint16_t insn ,
int opsize , TCGv_ptr fp , ea_what what )
{
int mode = extract32 ( insn , 3 , 3 ) ;
int reg0 = REG ( insn , 0 ) ;
return gen_ea_mode_fp ( env , s , mode , reg0 , opsize , fp , what ) ;
}
typedef struct {
TCGCond tcond ;
bool g1 ;
@ -1124,42 +1432,6 @@ static void gen_lookup_tb(DisasContext *s)
s - > is_jmp = DISAS_UPDATE ;
}
/* Generate a jump to an immediate address. */
static void gen_jmp_im ( DisasContext * s , uint32_t dest )
{
update_cc_op ( s ) ;
tcg_gen_movi_i32 ( QREG_PC , dest ) ;
s - > is_jmp = DISAS_JUMP ;
}
/* Generate a jump to the address in qreg DEST. */
static void gen_jmp ( DisasContext * s , TCGv dest )
{
update_cc_op ( s ) ;
tcg_gen_mov_i32 ( QREG_PC , dest ) ;
s - > is_jmp = DISAS_JUMP ;
}
static void gen_raise_exception ( int nr )
{
TCGv_i32 tmp = tcg_const_i32 ( nr ) ;
gen_helper_raise_exception ( cpu_env , tmp ) ;
tcg_temp_free_i32 ( tmp ) ;
}
static void gen_exception ( DisasContext * s , uint32_t where , int nr )
{
update_cc_op ( s ) ;
gen_jmp_im ( s , where ) ;
gen_raise_exception ( nr ) ;
}
static inline void gen_addr_fault ( DisasContext * s )
{
gen_exception ( s , s - > insn_pc , EXCP_ADDRESS ) ;
}
# define SRC_EA(env, result, opsize, op_sign, addrp) do { \
result = gen_ea ( env , s , insn , opsize , NULL_QREG , addrp , \
op_sign ? EA_LOADS : EA_LOADU ) ; \
@ -4133,15 +4405,11 @@ undef:
DISAS_INSN ( fpu )
{
uint16_t ext ;
int32_t offset ;
int opmode ;
TCGv_i64 src ;
TCGv_i64 dest ;
TCGv_i64 res ;
TCGv tmp32 ;
int round ;
int set_dest ;
int opsize ;
TCGv_ptr cpu_src , cpu_dest ;
ext = read_im16 ( env , s ) ;
opmode = ext & 0x7f ;
@ -4151,59 +4419,12 @@ DISAS_INSN(fpu)
case 1 :
goto undef ;
case 3 : /* fmove out */
src = FREG ( ext , 7 ) ;
tmp32 = tcg_temp_new_i32 ( ) ;
/* fmove */
/* ??? TODO: Proper behavior on overflow. */
cpu_src = gen_fp_ptr ( REG ( ext , 7 ) ) ;
opsize = ext_opsize ( ext , 10 ) ;
switch ( opsize ) {
case OS_LONG :
gen_helper_f64_to_i32 ( tmp32 , cpu_env , src ) ;
break ;
case OS_SINGLE :
gen_helper_f64_to_f32 ( tmp32 , cpu_env , src ) ;
break ;
case OS_WORD :
gen_helper_f64_to_i32 ( tmp32 , cpu_env , src ) ;
break ;
case OS_DOUBLE :
tcg_gen_mov_i32 ( tmp32 , AREG ( insn , 0 ) ) ;
switch ( ( insn > > 3 ) & 7 ) {
case 2 :
case 3 :
break ;
case 4 :
tcg_gen_addi_i32 ( tmp32 , tmp32 , - 8 ) ;
break ;
case 5 :
offset = cpu_ldsw_code ( env , s - > pc ) ;
s - > pc + = 2 ;
tcg_gen_addi_i32 ( tmp32 , tmp32 , offset ) ;
break ;
default :
goto undef ;
}
gen_store64 ( s , tmp32 , src ) ;
switch ( ( insn > > 3 ) & 7 ) {
case 3 :
tcg_gen_addi_i32 ( tmp32 , tmp32 , 8 ) ;
tcg_gen_mov_i32 ( AREG ( insn , 0 ) , tmp32 ) ;
break ;
case 4 :
tcg_gen_mov_i32 ( AREG ( insn , 0 ) , tmp32 ) ;
break ;
}
tcg_temp_free_i32 ( tmp32 ) ;
return ;
case OS_BYTE :
gen_helper_f64_to_i32 ( tmp32 , cpu_env , src ) ;
break ;
default :
goto undef ;
if ( gen_ea_fp ( env , s , insn , opsize , cpu_src , EA_STORE ) = = - 1 ) {
gen_addr_fault ( s ) ;
}
DEST_EA ( env , insn , opsize , tmp32 , NULL ) ;
tcg_temp_free_i32 ( tmp32 ) ;
tcg_temp_free_ptr ( cpu_src ) ;
return ;
case 4 : /* fmove to control register. */
case 5 : /* fmove from control register. */
@ -4213,6 +4434,7 @@ DISAS_INSN(fpu)
case 7 :
{
TCGv addr ;
TCGv_ptr fp ;
uint16_t mask ;
int i ;
if ( ( ext & 0x1f00 ) ! = 0x1000 | | ( ext & 0xff ) = = 0 )
@ -4225,136 +4447,86 @@ DISAS_INSN(fpu)
addr = tcg_temp_new_i32 ( ) ;
tcg_gen_mov_i32 ( addr , tmp32 ) ;
mask = 0x80 ;
fp = tcg_temp_new_ptr ( ) ;
for ( i = 0 ; i < 8 ; i + + ) {
if ( ext & mask ) {
dest = FREG ( i , 0 ) ;
if ( ext & ( 1 < < 13 ) ) {
/* store */
tcg_gen_qemu_stf64 ( dest , addr , IS_USER ( s ) ) ;
} else {
/* load */
tcg_gen_qemu_ldf64 ( dest , addr , IS_USER ( s ) ) ;
}
tcg_gen_addi_ptr ( fp , cpu_env ,
offsetof ( CPUM68KState , fregs [ i ] ) ) ;
gen_ldst_fp ( s , OS_DOUBLE , addr , fp ,
( ext & ( 1 < < 13 ) ) ? EA_STORE : EA_LOADS ) ;
if ( ext & ( mask - 1 ) )
tcg_gen_addi_i32 ( addr , addr , 8 ) ;
}
mask > > = 1 ;
}
tcg_temp_free_i32 ( addr ) ;
tcg_temp_free_ptr ( fp ) ;
}
return ;
}
if ( ext & ( 1 < < 14 ) ) {
/* Source effective address. */
opsize = ext_opsize ( ext , 10 ) ;
if ( opsize = = OS_DOUBLE ) {
tmp32 = tcg_temp_new_i32 ( ) ;
tcg_gen_mov_i32 ( tmp32 , AREG ( insn , 0 ) ) ;
switch ( ( insn > > 3 ) & 7 ) {
case 2 :
case 3 :
break ;
case 4 :
tcg_gen_addi_i32 ( tmp32 , tmp32 , - 8 ) ;
break ;
case 5 :
offset = cpu_ldsw_code ( env , s - > pc ) ;
s - > pc + = 2 ;
tcg_gen_addi_i32 ( tmp32 , tmp32 , offset ) ;
break ;
case 7 :
offset = cpu_ldsw_code ( env , s - > pc ) ;
offset + = s - > pc - 2 ;
s - > pc + = 2 ;
tcg_gen_addi_i32 ( tmp32 , tmp32 , offset ) ;
break ;
default :
goto undef ;
}
src = gen_load64 ( s , tmp32 ) ;
switch ( ( insn > > 3 ) & 7 ) {
case 3 :
tcg_gen_addi_i32 ( tmp32 , tmp32 , 8 ) ;
tcg_gen_mov_i32 ( AREG ( insn , 0 ) , tmp32 ) ;
break ;
case 4 :
tcg_gen_mov_i32 ( AREG ( insn , 0 ) , tmp32 ) ;
break ;
}
tcg_temp_free_i32 ( tmp32 ) ;
} else {
SRC_EA ( env , tmp32 , opsize , 1 , NULL ) ;
src = tcg_temp_new_i64 ( ) ;
switch ( opsize ) {
case OS_LONG :
case OS_WORD :
case OS_BYTE :
gen_helper_i32_to_f64 ( src , cpu_env , tmp32 ) ;
break ;
case OS_SINGLE :
gen_helper_f32_to_f64 ( src , cpu_env , tmp32 ) ;
break ;
}
cpu_src = gen_fp_result_ptr ( ) ;
if ( gen_ea_fp ( env , s , insn , opsize , cpu_src , EA_LOADS ) = = - 1 ) {
gen_addr_fault ( s ) ;
return ;
}
} else {
/* Source register. */
src = FREG ( ext , 10 ) ;
opsize = OS_EXTENDED ;
cpu_src = gen_fp_ptr ( REG ( ext , 10 ) ) ;
}
dest = FREG ( ext , 7 ) ;
res = tcg_temp_new_i64 ( ) ;
if ( opmode ! = 0x3a )
tcg_gen_mov_f64 ( res , dest ) ;
round = 1 ;
set_dest = 1 ;
cpu_dest = gen_fp_ptr ( REG ( ext , 7 ) ) ;
switch ( opmode ) {
case 0 : case 0x40 : case 0x44 : /* fmove */
tcg_gen_mov_f64 ( res , src ) ;
gen_fp_move ( cpu_dest , cpu_src ) ;
break ;
case 1 : /* fint */
gen_helper_iround_f64 ( res , cpu_env , src ) ;
gen_helper_firound ( cpu_env , cpu_dest , cpu_src ) ;
round = 0 ;
break ;
case 3 : /* fintrz */
gen_helper_itrunc_f64 ( res , cpu_env , src ) ;
gen_helper_fitrunc ( cpu_env , cpu_dest , cpu_src ) ;
round = 0 ;
break ;
case 4 : case 0x41 : case 0x45 : /* fsqrt */
gen_helper_sqrt_f64 ( res , cpu_env , src ) ;
gen_helper_fsqrt ( cpu_env , cpu_dest , cpu_src ) ;
break ;
case 0x18 : case 0x58 : case 0x5c : /* fabs */
gen_helper_abs_f64 ( res , src ) ;
gen_helper_fabs ( cpu_env , cpu_dest , cpu_src ) ;
break ;
case 0x1a : case 0x5a : case 0x5e : /* fneg */
gen_helper_chs_f64 ( res , src ) ;
gen_helper_fchs ( cpu_env , cpu_dest , cpu_src ) ;
break ;
case 0x20 : case 0x60 : case 0x64 : /* fdiv */
gen_helper_div_f64 ( res , cpu_env , res , src ) ;
gen_helper_fdiv ( cpu_env , cpu_dest , cpu_src , cpu_dest ) ;
break ;
case 0x22 : case 0x62 : case 0x66 : /* fadd */
gen_helper_add_f64 ( res , cpu_env , res , src ) ;
gen_helper_fadd ( cpu_env , cpu_dest , cpu_src , cpu_dest ) ;
break ;
case 0x23 : case 0x63 : case 0x67 : /* fmul */
gen_helper_mul_f64 ( res , cpu_env , res , src ) ;
gen_helper_fmul ( cpu_env , cpu_dest , cpu_src , cpu_dest ) ;
break ;
case 0x28 : case 0x68 : case 0x6c : /* fsub */
gen_helper_sub_f64 ( res , cpu_env , res , src ) ;
gen_helper_fsub ( cpu_env , cpu_dest , cpu_src , cpu_dest ) ;
break ;
case 0x38 : /* fcmp */
gen_helper_sub_cmp_f64 ( res , cpu_env , res , src ) ;
set_dest = 0 ;
tcg_temp_free_ptr ( cpu_dest ) ;
cpu_dest = gen_fp_result_ptr ( ) ;
gen_helper_fsub_cmp ( cpu_env , cpu_dest , cpu_src , cpu_dest ) ;
round = 0 ;
break ;
case 0x3a : /* ftst */
tcg_gen_mov_f64 ( res , src ) ;
set_dest = 0 ;
tcg_temp_free_ptr ( cpu_dest ) ;
cpu_dest = gen_fp_result_ptr ( ) ;
gen_fp_move ( cpu_dest , cpu_src ) ;
round = 0 ;
break ;
default :
goto undef ;
}
if ( ext & ( 1 < < 14 ) ) {
tcg_temp_free_i64 ( src ) ;
}
if ( round ) {
if ( opmode & 0x40 ) {
if ( ( opmode & 0x4 ) ! = 0 )
@ -4364,16 +4536,18 @@ DISAS_INSN(fpu)
}
}
if ( round ) {
TCGv tmp = tcg_temp_new_i32 ( ) ;
gen_helper_f64_to_f32 ( tmp , cpu_env , res ) ;
gen_helper_f32_to_f64 ( res , cpu_env , tmp ) ;
tcg_temp_free_i32 ( tmp ) ;
}
tcg_gen_mov_f64 ( QREG_FP_RESULT , res ) ;
if ( set_dest ) {
tcg_gen_mov_f64 ( dest , res ) ;
TCGv tmp = tcg_temp_new ( ) ;
gen_helper_redf32 ( tmp , cpu_env , cpu_dest ) ;
gen_helper_extf32 ( cpu_env , cpu_dest , tmp ) ;
tcg_temp_free ( tmp ) ;
} else {
TCGv_i64 t64 = tcg_temp_new_i64 ( ) ;
gen_helper_redf64 ( t64 , cpu_env , cpu_dest ) ;
gen_helper_extf64 ( cpu_env , cpu_dest , t64 ) ;
tcg_temp_free_i64 ( t64 ) ;
}
tcg_temp_free_i64 ( res ) ;
tcg_temp_free_ptr ( cpu_src ) ;
tcg_temp_free_ptr ( cpu_dest ) ;
return ;
undef :
/* FIXME: Is this right for offset addressing modes? */
@ -4387,6 +4561,7 @@ DISAS_INSN(fbcc)
uint32_t addr ;
TCGv flag ;
TCGLabel * l1 ;
TCGv_ptr fp_result ;
addr = s - > pc ;
offset = cpu_ldsw_code ( env , s - > pc ) ;
@ -4398,7 +4573,9 @@ DISAS_INSN(fbcc)
l1 = gen_new_label ( ) ;
/* TODO: Raise BSUN exception. */
flag = tcg_temp_new ( ) ;
gen_helper_compare_f64 ( flag , cpu_env , QREG_FP_RESULT ) ;
fp_result = gen_fp_result_ptr ( ) ;
gen_helper_fcompare ( flag , cpu_env , fp_result ) ;
tcg_temp_free_ptr ( fp_result ) ;
/* Jump to l1 if condition is true. */
switch ( insn & 0xf ) {
case 0 : /* f */
@ -5028,11 +5205,15 @@ void register_m68k_insns (CPUM68KState *env)
INSN ( bfop_reg , eec0 , fff8 , BITFIELD ) ; /* bfset */
INSN ( bfop_mem , e8c0 , ffc0 , BITFIELD ) ; /* bftst */
INSN ( bfop_reg , e8c0 , fff8 , BITFIELD ) ; /* bftst */
INSN ( undef_fpu , f000 , f000 , CF_ISA_A ) ;
BASE ( undef_fpu , f000 , f000 ) ;
INSN ( fpu , f200 , ffc0 , CF_FPU ) ;
INSN ( fbcc , f280 , ffc0 , CF_FPU ) ;
INSN ( frestore , f340 , ffc0 , CF_FPU ) ;
INSN ( fsave , f340 , ffc0 , CF_FPU ) ;
INSN ( fsave , f300 , ffc0 , CF_FPU ) ;
INSN ( fpu , f200 , ffc0 , FPU ) ;
INSN ( fbcc , f280 , ff80 , FPU ) ;
INSN ( frestore , f340 , ffc0 , FPU ) ;
INSN ( fsave , f300 , ffc0 , FPU ) ;
INSN ( intouch , f340 , ffc0 , CF_ISA_A ) ;
INSN ( cpushl , f428 , ff38 , CF_ISA_A ) ;
INSN ( wddata , fb00 , ff00 , CF_ISA_A ) ;
@ -5158,6 +5339,18 @@ void gen_intermediate_code(CPUM68KState *env, TranslationBlock *tb)
tb - > icount = num_insns ;
}
static double floatx80_to_double ( CPUM68KState * env , uint16_t high , uint64_t low )
{
floatx80 a = { . high = high , . low = low } ;
union {
float64 f64 ;
double d ;
} u ;
u . f64 = floatx80_to_float64 ( a , & env - > fp_status ) ;
return u . d ;
}
void m68k_cpu_dump_state ( CPUState * cs , FILE * f , fprintf_function cpu_fprintf ,
int flags )
{
@ -5165,20 +5358,19 @@ void m68k_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf,
CPUM68KState * env = & cpu - > env ;
int i ;
uint16_t sr ;
CPU_DoubleU u ;
for ( i = 0 ; i < 8 ; i + + )
{
u . d = env - > fregs [ i ] ;
cpu_fprintf ( f , " D%d = %08x A%d = %08x F%d = %08x%08x (%12g) \n " ,
for ( i = 0 ; i < 8 ; i + + ) {
cpu_fprintf ( f , " D%d = %08x A%d = %08x "
" F%d = %04x %016 " PRIx64 " (%12g) \n " ,
i , env - > dregs [ i ] , i , env - > aregs [ i ] ,
i , u . l . upper , u . l . lower , * ( double * ) & u . d ) ;
}
i , env - > fregs [ i ] . l . upper , env - > fregs [ i ] . l . lower ,
floatx80_to_double ( env , env - > fregs [ i ] . l . upper ,
env - > fregs [ i ] . l . lower ) ) ;
}
cpu_fprintf ( f , " PC = %08x " , env - > pc ) ;
sr = env - > sr | cpu_m68k_get_ccr ( env ) ;
cpu_fprintf ( f , " SR = %04x %c%c%c%c%c " , sr , ( sr & CCF_X ) ? ' X ' : ' - ' ,
( sr & CCF_N ) ? ' N ' : ' - ' , ( sr & CCF_Z ) ? ' Z ' : ' - ' ,
( sr & CCF_V ) ? ' V ' : ' - ' , ( sr & CCF_C ) ? ' C ' : ' - ' ) ;
cpu_fprintf ( f , " FPRESULT = %12g \n " , * ( double * ) & env - > fp_result ) ;
}
void restore_state_to_opc ( CPUM68KState * env , TranslationBlock * tb ,