diff --git a/configs/targets/sparc64-linux-user.mak b/configs/targets/sparc64-linux-user.mak
index 930f7e13ab..a5f8f8d51a 100644
--- a/configs/targets/sparc64-linux-user.mak
+++ b/configs/targets/sparc64-linux-user.mak
@@ -4,6 +4,6 @@ TARGET_ABI_DIR=sparc
TARGET_SYSTBL_ABI=common,64
TARGET_SYSTBL=syscall.tbl
TARGET_BIG_ENDIAN=y
-TARGET_XML_FILES=gdb-xml/sparc64-core.xml gdb-xml/sparc64-cp0.xml
+TARGET_XML_FILES=gdb-xml/sparc64-core.xml gdb-xml/sparc64-fpu.xml gdb-xml/sparc64-cp0.xml
TARGET_LONG_BITS=64
TARGET_NOT_USING_LEGACY_NATIVE_ENDIAN_API=y
diff --git a/configs/targets/sparc64-softmmu.mak b/configs/targets/sparc64-softmmu.mak
index 22e7f3c94a..c35b6b1bb8 100644
--- a/configs/targets/sparc64-softmmu.mak
+++ b/configs/targets/sparc64-softmmu.mak
@@ -1,7 +1,7 @@
TARGET_ARCH=sparc64
TARGET_BASE_ARCH=sparc
TARGET_BIG_ENDIAN=y
-TARGET_XML_FILES=gdb-xml/sparc64-core.xml gdb-xml/sparc64-cp0.xml
+TARGET_XML_FILES=gdb-xml/sparc64-core.xml gdb-xml/sparc64-fpu.xml gdb-xml/sparc64-cp0.xml
TARGET_LONG_BITS=64
TARGET_NOT_USING_LEGACY_LDST_PHYS_API=y
TARGET_NOT_USING_LEGACY_NATIVE_ENDIAN_API=y
diff --git a/gdb-xml/sparc64-core.xml b/gdb-xml/sparc64-core.xml
index 1c26d8c01c..85b0820a40 100644
--- a/gdb-xml/sparc64-core.xml
+++ b/gdb-xml/sparc64-core.xml
@@ -39,54 +39,4 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/gdb-xml/sparc64-fpu.xml b/gdb-xml/sparc64-fpu.xml
new file mode 100644
index 0000000000..d7151b34c7
--- /dev/null
+++ b/gdb-xml/sparc64-fpu.xml
@@ -0,0 +1,59 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/target/sparc/gdbstub.c b/target/sparc/gdbstub.c
index bdd759dd0a..b5b1494950 100644
--- a/target/sparc/gdbstub.c
+++ b/target/sparc/gdbstub.c
@@ -40,32 +40,40 @@ int sparc_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
/* register window */
return gdb_get_rega(mem_buf, env->regwptr[n - 8]);
}
+ return 0;
+}
+
+__attribute__((unused))
+static int sparc_fpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
+{
+ CPUSPARCState *env = cpu_env(cs);
+
#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
- if (n < 64) {
+ if (n < 32) {
/* fprs */
if (n & 1) {
- return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower);
+ return gdb_get_reg32(mem_buf, env->fpr[n / 2].l.lower);
} else {
- return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper);
+ return gdb_get_reg32(mem_buf, env->fpr[n / 2].l.upper);
}
}
#else
- if (n < 64) {
+ if (n < 32) {
/* f0-f31 */
if (n & 1) {
- return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.lower);
+ return gdb_get_reg32(mem_buf, env->fpr[n / 2].l.lower);
} else {
- return gdb_get_reg32(mem_buf, env->fpr[(n - 32) / 2].l.upper);
+ return gdb_get_reg32(mem_buf, env->fpr[n / 2].l.upper);
}
}
- if (n < 80) {
+ if (n < 48) {
/* f32-f62 (16 double width registers, even register numbers only)
- * n == 64: f32 : env->fpr[16]
- * n == 65: f34 : env->fpr[17]
+ * n == 32: f32 : env->fpr[16]
+ * n == 33: f34 : env->fpr[17]
* etc...
- * n == 79: f62 : env->fpr[31]
+ * n == 47: f62 : env->fpr[31]
*/
- return gdb_get_reg64(mem_buf, env->fpr[(n - 64) + 16].ll);
+ return gdb_get_reg64(mem_buf, env->fpr[(n - 32) + 16].ll);
}
#endif
return 0;
@@ -135,39 +143,55 @@ int sparc_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
if (n < 8) {
/* g0..g7 */
env->gregs[n] = tmp;
- } else if (n < 32) {
+ } else {
/* register window */
env->regwptr[n - 8] = tmp;
}
#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
- else if (n < 64) {
- /* fprs */
- /* f0-f31 */
- if (n & 1) {
- env->fpr[(n - 32) / 2].l.lower = tmp;
- } else {
- env->fpr[(n - 32) / 2].l.upper = tmp;
- }
- }
return 4;
#else
- else if (n < 64) {
+ return 8;
+#endif
+}
+
+__attribute__((unused))
+static int sparc_fpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
+{
+ CPUSPARCState *env = cpu_env(cs);
+
+#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
+ uint32_t tmp;
+
+ tmp = ldl_p(mem_buf);
+
+ /* fprs */
+ /* f0-f31 */
+ if (n & 1) {
+ env->fpr[n / 2].l.lower = tmp;
+ } else {
+ env->fpr[n / 2].l.upper = tmp;
+ }
+
+ return 4;
+#else
+ if (n < 32) {
/* f0-f31 */
- tmp = ldl_p(mem_buf);
+ uint32_t tmp = ldl_p(mem_buf);
if (n & 1) {
- env->fpr[(n - 32) / 2].l.lower = tmp;
+ env->fpr[n / 2].l.lower = tmp;
} else {
- env->fpr[(n - 32) / 2].l.upper = tmp;
+ env->fpr[n / 2].l.upper = tmp;
}
return 4;
- } else if (n < 80) {
+ } else {
+ uint64_t tmp = ldq_p(mem_buf);
/* f32-f62 (16 double width registers, even register numbers only)
- * n == 64: f32 : env->fpr[16]
- * n == 65: f34 : env->fpr[17]
+ * n == 32: f32 : env->fpr[16]
+ * n == 33: f34 : env->fpr[17]
* etc...
- * n == 79: f62 : env->fpr[31]
+ * n == 47: f62 : env->fpr[31]
*/
- env->fpr[(n - 64) + 16].ll = tmp;
+ env->fpr[(n - 32) + 16].ll = tmp;
}
return 8;
#endif
@@ -249,6 +273,10 @@ void sparc_cpu_register_gdb_regs(CPUState *cs)
#if defined(TARGET_ABI32) || !defined(TARGET_SPARC64)
/* Not yet supported */
#else
+ gdb_register_coprocessor(cs, sparc_fpu_gdb_read_register,
+ sparc_fpu_gdb_write_register,
+ gdb_find_static_feature("sparc64-fpu.xml"),
+ 0);
gdb_register_coprocessor(cs, sparc_cp0_gdb_read_register,
sparc_cp0_gdb_write_register,
gdb_find_static_feature("sparc64-cp0.xml"),