aboutsummaryrefslogtreecommitdiff
path: root/target-sparc
diff options
context:
space:
mode:
authorblueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>2007-09-30 19:38:12 +0000
committerblueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>2007-09-30 19:38:12 +0000
commit3391c81801c867bc8f4dd6ce32766e4e8345813b (patch)
tree2a33edea8cbf8c8ae4e1b0580c5e1ea8aa9ba0ba /target-sparc
parentee0b03fd85652ddd04d3499f03e6821732862308 (diff)
Fix Sparc64 ldfa, lddfa, stfa, and stdfa instructions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3298 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-sparc')
-rw-r--r--target-sparc/exec.h2
-rw-r--r--target-sparc/op.c22
-rw-r--r--target-sparc/op_helper.c73
-rw-r--r--target-sparc/translate.c42
4 files changed, 133 insertions, 6 deletions
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