diff options
author | blueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-05-17 19:30:10 +0000 |
---|---|---|
committer | blueswir1 <blueswir1@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-05-17 19:30:10 +0000 |
commit | 6c36d3fa860b1dfa55de1e8248be6fffcd876f69 (patch) | |
tree | bb7df0c2a61f9094c1ad1c4d55ea6ce2dd1e8085 /target-sparc/op_helper.c | |
parent | 4edebb0e8e14a5b934114b5ff74cb86437bb2532 (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.c | 131 |
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 |