diff --git a/target-sparc/exec.h b/target-sparc/exec.h index 35f4b5fd19..063e2ee644 100644 --- a/target-sparc/exec.h +++ b/target-sparc/exec.h @@ -51,6 +51,8 @@ void cpu_loop_exit(void); void helper_flush(target_ulong addr); void helper_ld_asi(int asi, int size, int sign); void helper_st_asi(int asi, int size); +void helper_ldf_asi(int asi, int size, int rd); +void helper_stf_asi(int asi, int size, int rd); void helper_rett(void); void helper_ldfsr(void); void set_cwp(int new_cwp); diff --git a/target-sparc/op.c b/target-sparc/op.c index bb084ee0db..613bcb09ab 100644 --- a/target-sparc/op.c +++ b/target-sparc/op.c @@ -1865,6 +1865,28 @@ void OPPROTO op_st_asi_reg() helper_st_asi(env->asi, PARAM2); } +void OPPROTO op_ldf_asi_reg() +{ + T0 += PARAM1; + helper_ldf_asi(env->asi, PARAM2, PARAM3); +} + +void OPPROTO op_stf_asi_reg() +{ + T0 += PARAM1; + helper_stf_asi(env->asi, PARAM2, PARAM3); +} + +void OPPROTO op_ldf_asi() +{ + helper_ldf_asi(PARAM1, PARAM2, PARAM3); +} + +void OPPROTO op_stf_asi() +{ + helper_stf_asi(PARAM1, PARAM2, PARAM3); +} + void OPPROTO op_ldstub_asi_reg() /* XXX: should be atomically */ { target_ulong tmp; diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c index eea4a63771..fa51cdee9b 100644 --- a/target-sparc/op_helper.c +++ b/target-sparc/op_helper.c @@ -1126,6 +1126,79 @@ void helper_st_asi(int asi, int size) } } #endif /* CONFIG_USER_ONLY */ + +void helper_ldf_asi(int asi, int size, int rd) +{ + target_ulong tmp_T0 = T0, tmp_T1 = T1; + unsigned int i; + + switch (asi) { + case 0xf0: // Block load primary + case 0xf1: // Block load secondary + case 0xf8: // Block load primary LE + case 0xf9: // Block load secondary LE + for (i = 0; i < 8; i++) { + helper_ld_asi(asi & 0x8f, 8, 0); + *((int64_t *)&DT0) = T1; + T0 += 8; + } + T0 = tmp_T0; + T1 = tmp_T1; + + return; + default: + break; + } + + helper_ld_asi(asi, size, 0); + switch(size) { + default: + case 4: + *((uint32_t *)&FT0) = T1; + break; + case 8: + *((int64_t *)&DT0) = T1; + break; + } + T1 = tmp_T1; +} + +void helper_stf_asi(int asi, int size, int rd) +{ + target_ulong tmp_T0 = T0, tmp_T1 = T1; + unsigned int i; + + switch (asi) { + case 0xf0: // Block store primary + case 0xf1: // Block store secondary + case 0xf8: // Block store primary LE + case 0xf9: // Block store secondary LE + for (i = 0; i < 8; i++) { + T1 = *((int64_t *)&DT0); + helper_st_asi(asi & 0x8f, 8); + T0 += 8; + } + T0 = tmp_T0; + T1 = tmp_T1; + + return; + default: + break; + } + + switch(size) { + default: + case 4: + T1 = *((uint32_t *)&FT0); + break; + case 8: + T1 = *((int64_t *)&DT0); + break; + } + helper_st_asi(asi, size); + T1 = tmp_T1; +} + #endif /* TARGET_SPARC64 */ #ifndef TARGET_SPARC64 diff --git a/target-sparc/translate.c b/target-sparc/translate.c index 0cffa9e52e..94503bee8a 100644 --- a/target-sparc/translate.c +++ b/target-sparc/translate.c @@ -427,6 +427,34 @@ static inline void gen_st_asi(int insn, int size) } } +static inline void gen_ldf_asi(int insn, int size) +{ + int asi, offset, rd; + + rd = GET_FIELD(insn, 2, 6); + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_ldf_asi_reg(offset, size, rd); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_ldf_asi(asi, size, rd); + } +} + +static inline void gen_stf_asi(int insn, int size) +{ + int asi, offset, rd; + + rd = GET_FIELD(insn, 2, 6); + if (IS_IMM) { + offset = GET_FIELD(insn, 25, 31); + gen_op_stf_asi_reg(offset, size, rd); + } else { + asi = GET_FIELD(insn, 19, 26); + gen_op_stf_asi(asi, size, rd); + } +} + static inline void gen_swap_asi(int insn) { int asi, offset; @@ -3069,11 +3097,11 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_ld_asi(insn, 8, 0); // XXX + gen_ldf_asi(insn, 4); goto skip_move; case 0x33: /* V9 lddfa */ - gen_op_check_align_T0_7(); - gen_ld_asi(insn, 8, 0); // XXX + gen_op_check_align_T0_3(); + gen_ldf_asi(insn, 8); goto skip_move; case 0x3d: /* V9 prefetcha, no effect */ goto skip_move; @@ -3245,11 +3273,13 @@ static void disas_sparc_insn(DisasContext * dc) #ifdef CONFIG_USER_ONLY gen_op_check_align_T0_3(); #endif - gen_st_asi(insn, 0); // XXX + gen_op_load_fpr_FT0(rd); + gen_stf_asi(insn, 4); break; case 0x37: /* V9 stdfa */ - gen_op_check_align_T0_7(); - gen_st_asi(insn, 0); // XXX + gen_op_check_align_T0_3(); + gen_op_load_fpr_DT0(DFPREG(rd)); + gen_stf_asi(insn, 8); break; case 0x3c: /* V9 casa */ #ifdef CONFIG_USER_ONLY