aboutsummaryrefslogtreecommitdiff
path: root/target-sparc/op_helper.c
diff options
context:
space:
mode:
authorblueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>2007-05-17 19:30:10 +0000
committerblueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162>2007-05-17 19:30:10 +0000
commit6c36d3fa860b1dfa55de1e8248be6fffcd876f69 (patch)
treebb7df0c2a61f9094c1ad1c4d55ea6ce2dd1e8085 /target-sparc/op_helper.c
parent4edebb0e8e14a5b934114b5ff74cb86437bb2532 (diff)
Enable faults for unassigned memory accesses and unimplemented ASIs
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2824 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-sparc/op_helper.c')
-rw-r--r--target-sparc/op_helper.c131
1 files changed, 114 insertions, 17 deletions
diff --git a/target-sparc/op_helper.c b/target-sparc/op_helper.c
index 4349503ffc..bdc5b0e154 100644
--- a/target-sparc/op_helper.c
+++ b/target-sparc/op_helper.c
@@ -3,6 +3,7 @@
//#define DEBUG_PCALL
//#define DEBUG_MMU
//#define DEBUG_UNALIGNED
+//#define DEBUG_UNASSIGNED
void raise_exception(int tt)
{
@@ -151,6 +152,8 @@ void helper_ld_asi(int asi, int size, int sign)
uint32_t ret = 0;
switch (asi) {
+ case 2: /* SuperSparc MXCC registers */
+ break;
case 3: /* MMU probe */
{
int mmulev;
@@ -179,7 +182,30 @@ void helper_ld_asi(int asi, int size, int sign)
#endif
}
break;
- case 0x20 ... 0x2f: /* MMU passthrough */
+ case 9: /* Supervisor code access */
+ switch(size) {
+ case 1:
+ ret = ldub_code(T0);
+ break;
+ case 2:
+ ret = lduw_code(T0 & ~1);
+ break;
+ default:
+ case 4:
+ ret = ldl_code(T0 & ~3);
+ break;
+ case 8:
+ ret = ldl_code(T0 & ~3);
+ T0 = ldl_code((T0 + 4) & ~3);
+ break;
+ }
+ break;
+ case 0xc: /* I-cache tag */
+ case 0xd: /* I-cache data */
+ case 0xe: /* D-cache tag */
+ case 0xf: /* D-cache data */
+ break;
+ case 0x20: /* MMU passthrough */
switch(size) {
case 1:
ret = ldub_phys(T0);
@@ -197,7 +223,9 @@ void helper_ld_asi(int asi, int size, int sign)
break;
}
break;
+ case 0x21 ... 0x2f: /* MMU passthrough, unassigned */
default:
+ do_unassigned_access(T0, 0, 0, 1);
ret = 0;
break;
}
@@ -207,6 +235,8 @@ void helper_ld_asi(int asi, int size, int sign)
void helper_st_asi(int asi, int size, int sign)
{
switch(asi) {
+ case 2: /* SuperSparc MXCC registers */
+ break;
case 3: /* MMU flush */
{
int mmulev;
@@ -271,18 +301,28 @@ void helper_st_asi(int asi, int size, int sign)
#endif
return;
}
+ case 0xc: /* I-cache tag */
+ case 0xd: /* I-cache data */
+ case 0xe: /* D-cache tag */
+ case 0xf: /* D-cache data */
+ case 0x10: /* I/D-cache flush page */
+ case 0x11: /* I/D-cache flush segment */
+ case 0x12: /* I/D-cache flush region */
+ case 0x13: /* I/D-cache flush context */
+ case 0x14: /* I/D-cache flush user */
+ break;
case 0x17: /* Block copy, sta access */
{
// value (T1) = src
// address (T0) = dst
// copy 32 bytes
- uint32_t src = T1, dst = T0;
- uint8_t temp[32];
+ unsigned int i;
+ uint32_t src = T1 & ~3, dst = T0 & ~3, temp;
- tswap32s(&src);
-
- cpu_physical_memory_read(src, (void *) &temp, 32);
- cpu_physical_memory_write(dst, (void *) &temp, 32);
+ for (i = 0; i < 32; i += 4, src += 4, dst += 4) {
+ temp = ldl_kernel(src);
+ stl_kernel(dst, temp);
+ }
}
return;
case 0x1f: /* Block fill, stda access */
@@ -290,19 +330,17 @@ void helper_st_asi(int asi, int size, int sign)
// value (T1, T2)
// address (T0) = dst
// fill 32 bytes
- int i;
- uint32_t dst = T0;
- uint64_t val;
-
- val = (((uint64_t)T1) << 32) | T2;
- tswap64s(&val);
+ unsigned int i;
+ uint32_t dst = T0 & 7;
+ uint64_t val;
- for (i = 0; i < 32; i += 8, dst += 8) {
- cpu_physical_memory_write(dst, (void *) &val, 8);
- }
+ val = (((uint64_t)T1) << 32) | T2;
+
+ for (i = 0; i < 32; i += 8, dst += 8)
+ stq_kernel(dst, val);
}
return;
- case 0x20 ... 0x2f: /* MMU passthrough */
+ case 0x20: /* MMU passthrough */
{
switch(size) {
case 1:
@@ -322,7 +360,14 @@ void helper_st_asi(int asi, int size, int sign)
}
}
return;
+ case 0x31: /* Ross RT620 I-cache flush */
+ case 0x36: /* I-cache flash clear */
+ case 0x37: /* D-cache flash clear */
+ break;
+ case 9: /* Supervisor code access, XXX */
+ case 0x21 ... 0x2f: /* MMU passthrough, unassigned */
default:
+ do_unassigned_access(T0, 1, 0, 1);
return;
}
}
@@ -441,6 +486,7 @@ void helper_ld_asi(int asi, int size, int sign)
case 0x5f: // D-MMU demap, WO
case 0x77: // Interrupt vector, WO
default:
+ do_unassigned_access(T0, 0, 0, 1);
ret = 0;
break;
}
@@ -656,6 +702,7 @@ void helper_st_asi(int asi, int size, int sign)
case 0x8a: // Primary no-fault LE, RO
case 0x8b: // Secondary no-fault LE, RO
default:
+ do_unassigned_access(T0, 1, 0, 1);
return;
}
}
@@ -986,3 +1033,53 @@ void tlb_fill(target_ulong addr, int is_write, int is_user, void *retaddr)
}
#endif
+
+#ifndef TARGET_SPARC64
+void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
+ int is_asi)
+{
+ CPUState *saved_env;
+
+ /* XXX: hack to restore env in all cases, even if not called from
+ generated code */
+ saved_env = env;
+ env = cpu_single_env;
+ if (env->mmuregs[3]) /* Fault status register */
+ env->mmuregs[3] = 1; /* overflow (not read before another fault) */
+ if (is_asi)
+ env->mmuregs[3] |= 1 << 16;
+ if (env->psrs)
+ env->mmuregs[3] |= 1 << 5;
+ if (is_exec)
+ env->mmuregs[3] |= 1 << 6;
+ if (is_write)
+ env->mmuregs[3] |= 1 << 7;
+ env->mmuregs[3] |= (5 << 2) | 2;
+ env->mmuregs[4] = addr; /* Fault address register */
+ if ((env->mmuregs[0] & MMU_E) && !(env->mmuregs[0] & MMU_NF)) {
+#ifdef DEBUG_UNASSIGNED
+ printf("Unassigned mem access to " TARGET_FMT_lx " from " TARGET_FMT_lx
+ "\n", addr, env->pc);
+#endif
+ raise_exception(TT_DATA_ACCESS);
+ }
+ env = saved_env;
+}
+#else
+void do_unassigned_access(target_ulong addr, int is_write, int is_exec,
+ int is_asi)
+{
+#ifdef DEBUG_UNASSIGNED
+ CPUState *saved_env;
+
+ /* XXX: hack to restore env in all cases, even if not called from
+ generated code */
+ saved_env = env;
+ env = cpu_single_env;
+ printf("Unassigned mem access to " TARGET_FMT_lx " from " TARGET_FMT_lx "\n",
+ addr, env->pc);
+ env = saved_env;
+#endif
+ raise_exception(TT_DATA_ACCESS);
+}
+#endif