Revision c2bc0e38 target-sparc/op_helper.c
b/target-sparc/op_helper.c | ||
---|---|---|
33 | 33 |
#define DPRINTF_ASI(fmt, args...) do {} while (0) |
34 | 34 |
#endif |
35 | 35 |
|
36 |
#ifdef TARGET_ABI32 |
|
37 |
#define ABI32_MASK(addr) do { (addr) &= 0xffffffffULL; } while (0) |
|
38 |
#else |
|
39 |
#define ABI32_MASK(addr) do {} while (0) |
|
40 |
#endif |
|
41 |
|
|
36 | 42 |
void raise_exception(int tt) |
37 | 43 |
{ |
38 | 44 |
env->exception_index = tt; |
... | ... | |
55 | 61 |
|
56 | 62 |
void helper_check_align(target_ulong addr, uint32_t align) |
57 | 63 |
{ |
58 |
if (addr & align) |
|
64 |
if (addr & align) { |
|
65 |
#ifdef DEBUG_UNALIGNED |
|
66 |
printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx |
|
67 |
"\n", addr, env->pc); |
|
68 |
#endif |
|
59 | 69 |
raise_exception(TT_UNALIGNED); |
70 |
} |
|
60 | 71 |
} |
61 | 72 |
|
62 | 73 |
#define F_HELPER(name, p) void helper_f##name##p(void) |
... | ... | |
832 | 843 |
uint32_t last_addr = addr; |
833 | 844 |
#endif |
834 | 845 |
|
846 |
helper_check_align(addr, size - 1); |
|
835 | 847 |
switch (asi) { |
836 | 848 |
case 2: /* SuperSparc MXCC registers */ |
837 | 849 |
switch (addr) { |
... | ... | |
1030 | 1042 |
|
1031 | 1043 |
void helper_st_asi(target_ulong addr, uint64_t val, int asi, int size) |
1032 | 1044 |
{ |
1045 |
helper_check_align(addr, size - 1); |
|
1033 | 1046 |
switch(asi) { |
1034 | 1047 |
case 2: /* SuperSparc MXCC registers */ |
1035 | 1048 |
switch (addr) { |
... | ... | |
1335 | 1348 |
if (asi < 0x80) |
1336 | 1349 |
raise_exception(TT_PRIV_ACT); |
1337 | 1350 |
|
1351 |
helper_check_align(addr, size - 1); |
|
1352 |
ABI32_MASK(addr); |
|
1353 |
|
|
1338 | 1354 |
switch (asi) { |
1339 | 1355 |
case 0x80: // Primary |
1340 | 1356 |
case 0x82: // Primary no-fault |
... | ... | |
1421 | 1437 |
if (asi < 0x80) |
1422 | 1438 |
raise_exception(TT_PRIV_ACT); |
1423 | 1439 |
|
1440 |
helper_check_align(addr, size - 1); |
|
1441 |
ABI32_MASK(addr); |
|
1442 |
|
|
1424 | 1443 |
/* Convert to little endian */ |
1425 | 1444 |
switch (asi) { |
1426 | 1445 |
case 0x88: // Primary LE |
... | ... | |
1491 | 1510 |
|| (asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV))) |
1492 | 1511 |
raise_exception(TT_PRIV_ACT); |
1493 | 1512 |
|
1513 |
helper_check_align(addr, size - 1); |
|
1494 | 1514 |
switch (asi) { |
1495 | 1515 |
case 0x10: // As if user primary |
1496 | 1516 |
case 0x18: // As if user primary LE |
... | ... | |
1714 | 1734 |
|| (asi >= 0x30 && asi < 0x80 && !(env->hpstate & HS_PRIV))) |
1715 | 1735 |
raise_exception(TT_PRIV_ACT); |
1716 | 1736 |
|
1737 |
helper_check_align(addr, size - 1); |
|
1717 | 1738 |
/* Convert to little endian */ |
1718 | 1739 |
switch (asi) { |
1719 | 1740 |
case 0x0c: // Nucleus Little Endian (LE) |
... | ... | |
2009 | 2030 |
unsigned int i; |
2010 | 2031 |
target_ulong val; |
2011 | 2032 |
|
2033 |
helper_check_align(addr, 3); |
|
2012 | 2034 |
switch (asi) { |
2013 | 2035 |
case 0xf0: // Block load primary |
2014 | 2036 |
case 0xf1: // Block load secondary |
... | ... | |
2018 | 2040 |
raise_exception(TT_ILL_INSN); |
2019 | 2041 |
return; |
2020 | 2042 |
} |
2021 |
if (addr & 0x3f) { |
|
2022 |
raise_exception(TT_UNALIGNED); |
|
2023 |
return; |
|
2024 |
} |
|
2043 |
helper_check_align(addr, 0x3f); |
|
2025 | 2044 |
for (i = 0; i < 16; i++) { |
2026 | 2045 |
*(uint32_t *)&env->fpr[rd++] = helper_ld_asi(addr, asi & 0x8f, 4, 0); |
2027 | 2046 |
addr += 4; |
... | ... | |
2052 | 2071 |
unsigned int i; |
2053 | 2072 |
target_ulong val = 0; |
2054 | 2073 |
|
2074 |
helper_check_align(addr, 3); |
|
2055 | 2075 |
switch (asi) { |
2056 | 2076 |
case 0xf0: // Block store primary |
2057 | 2077 |
case 0xf1: // Block store secondary |
... | ... | |
2061 | 2081 |
raise_exception(TT_ILL_INSN); |
2062 | 2082 |
return; |
2063 | 2083 |
} |
2064 |
if (addr & 0x3f) { |
|
2065 |
raise_exception(TT_UNALIGNED); |
|
2066 |
return; |
|
2067 |
} |
|
2084 |
helper_check_align(addr, 0x3f); |
|
2068 | 2085 |
for (i = 0; i < 16; i++) { |
2069 | 2086 |
val = *(uint32_t *)&env->fpr[rd++]; |
2070 | 2087 |
helper_st_asi(addr, val, asi & 0x8f, 4); |
... | ... | |
2183 | 2200 |
return ((uint64_t)high << 32) | (uint64_t)(low & 0xffffffff); |
2184 | 2201 |
} |
2185 | 2202 |
|
2186 |
#ifdef TARGET_ABI32 |
|
2187 |
#define ADDR(x) ((x) & 0xffffffff) |
|
2188 |
#else |
|
2189 |
#define ADDR(x) (x) |
|
2190 |
#endif |
|
2191 |
|
|
2192 | 2203 |
void helper_stdf(target_ulong addr, int mem_idx) |
2193 | 2204 |
{ |
2205 |
helper_check_align(addr, 7); |
|
2194 | 2206 |
#if !defined(CONFIG_USER_ONLY) |
2195 | 2207 |
switch (mem_idx) { |
2196 | 2208 |
case 0: |
2197 |
stfq_user(ADDR(addr), DT0);
|
|
2209 |
stfq_user(addr, DT0);
|
|
2198 | 2210 |
break; |
2199 | 2211 |
case 1: |
2200 |
stfq_kernel(ADDR(addr), DT0);
|
|
2212 |
stfq_kernel(addr, DT0);
|
|
2201 | 2213 |
break; |
2202 | 2214 |
#ifdef TARGET_SPARC64 |
2203 | 2215 |
case 2: |
2204 |
stfq_hypv(ADDR(addr), DT0);
|
|
2216 |
stfq_hypv(addr, DT0);
|
|
2205 | 2217 |
break; |
2206 | 2218 |
#endif |
2207 | 2219 |
default: |
2208 | 2220 |
break; |
2209 | 2221 |
} |
2210 | 2222 |
#else |
2211 |
stfq_raw(ADDR(addr), DT0); |
|
2223 |
ABI32_MASK(addr); |
|
2224 |
stfq_raw(addr, DT0); |
|
2212 | 2225 |
#endif |
2213 | 2226 |
} |
2214 | 2227 |
|
2215 | 2228 |
void helper_lddf(target_ulong addr, int mem_idx) |
2216 | 2229 |
{ |
2230 |
helper_check_align(addr, 7); |
|
2217 | 2231 |
#if !defined(CONFIG_USER_ONLY) |
2218 | 2232 |
switch (mem_idx) { |
2219 | 2233 |
case 0: |
2220 |
DT0 = ldfq_user(ADDR(addr));
|
|
2234 |
DT0 = ldfq_user(addr);
|
|
2221 | 2235 |
break; |
2222 | 2236 |
case 1: |
2223 |
DT0 = ldfq_kernel(ADDR(addr));
|
|
2237 |
DT0 = ldfq_kernel(addr);
|
|
2224 | 2238 |
break; |
2225 | 2239 |
#ifdef TARGET_SPARC64 |
2226 | 2240 |
case 2: |
2227 |
DT0 = ldfq_hypv(ADDR(addr));
|
|
2241 |
DT0 = ldfq_hypv(addr);
|
|
2228 | 2242 |
break; |
2229 | 2243 |
#endif |
2230 | 2244 |
default: |
2231 | 2245 |
break; |
2232 | 2246 |
} |
2233 | 2247 |
#else |
2234 |
DT0 = ldfq_raw(ADDR(addr)); |
|
2248 |
ABI32_MASK(addr); |
|
2249 |
DT0 = ldfq_raw(addr); |
|
2235 | 2250 |
#endif |
2236 | 2251 |
} |
2237 | 2252 |
|
... | ... | |
2240 | 2255 |
// XXX add 128 bit load |
2241 | 2256 |
CPU_QuadU u; |
2242 | 2257 |
|
2258 |
helper_check_align(addr, 7); |
|
2243 | 2259 |
#if !defined(CONFIG_USER_ONLY) |
2244 | 2260 |
switch (mem_idx) { |
2245 | 2261 |
case 0: |
2246 |
u.ll.upper = ldq_user(ADDR(addr));
|
|
2247 |
u.ll.lower = ldq_user(ADDR(addr + 8));
|
|
2262 |
u.ll.upper = ldq_user(addr);
|
|
2263 |
u.ll.lower = ldq_user(addr + 8);
|
|
2248 | 2264 |
QT0 = u.q; |
2249 | 2265 |
break; |
2250 | 2266 |
case 1: |
2251 |
u.ll.upper = ldq_kernel(ADDR(addr));
|
|
2252 |
u.ll.lower = ldq_kernel(ADDR(addr + 8));
|
|
2267 |
u.ll.upper = ldq_kernel(addr);
|
|
2268 |
u.ll.lower = ldq_kernel(addr + 8);
|
|
2253 | 2269 |
QT0 = u.q; |
2254 | 2270 |
break; |
2255 | 2271 |
#ifdef TARGET_SPARC64 |
2256 | 2272 |
case 2: |
2257 |
u.ll.upper = ldq_hypv(ADDR(addr));
|
|
2258 |
u.ll.lower = ldq_hypv(ADDR(addr + 8));
|
|
2273 |
u.ll.upper = ldq_hypv(addr);
|
|
2274 |
u.ll.lower = ldq_hypv(addr + 8);
|
|
2259 | 2275 |
QT0 = u.q; |
2260 | 2276 |
break; |
2261 | 2277 |
#endif |
... | ... | |
2263 | 2279 |
break; |
2264 | 2280 |
} |
2265 | 2281 |
#else |
2266 |
u.ll.upper = ldq_raw(ADDR(addr)); |
|
2267 |
u.ll.lower = ldq_raw(ADDR(addr + 8)); |
|
2282 |
ABI32_MASK(addr); |
|
2283 |
u.ll.upper = ldq_raw(addr); |
|
2284 |
u.ll.lower = ldq_raw((addr + 8) & 0xffffffffULL); |
|
2268 | 2285 |
QT0 = u.q; |
2269 | 2286 |
#endif |
2270 | 2287 |
} |
... | ... | |
2274 | 2291 |
// XXX add 128 bit store |
2275 | 2292 |
CPU_QuadU u; |
2276 | 2293 |
|
2294 |
helper_check_align(addr, 7); |
|
2277 | 2295 |
#if !defined(CONFIG_USER_ONLY) |
2278 | 2296 |
switch (mem_idx) { |
2279 | 2297 |
case 0: |
2280 | 2298 |
u.q = QT0; |
2281 |
stq_user(ADDR(addr), u.ll.upper);
|
|
2282 |
stq_user(ADDR(addr + 8), u.ll.lower);
|
|
2299 |
stq_user(addr, u.ll.upper);
|
|
2300 |
stq_user(addr + 8, u.ll.lower);
|
|
2283 | 2301 |
break; |
2284 | 2302 |
case 1: |
2285 | 2303 |
u.q = QT0; |
2286 |
stq_kernel(ADDR(addr), u.ll.upper);
|
|
2287 |
stq_kernel(ADDR(addr + 8), u.ll.lower);
|
|
2304 |
stq_kernel(addr, u.ll.upper);
|
|
2305 |
stq_kernel(addr + 8, u.ll.lower);
|
|
2288 | 2306 |
break; |
2289 | 2307 |
#ifdef TARGET_SPARC64 |
2290 | 2308 |
case 2: |
2291 | 2309 |
u.q = QT0; |
2292 |
stq_hypv(ADDR(addr), u.ll.upper);
|
|
2293 |
stq_hypv(ADDR(addr + 8), u.ll.lower);
|
|
2310 |
stq_hypv(addr, u.ll.upper);
|
|
2311 |
stq_hypv(addr + 8, u.ll.lower);
|
|
2294 | 2312 |
break; |
2295 | 2313 |
#endif |
2296 | 2314 |
default: |
... | ... | |
2298 | 2316 |
} |
2299 | 2317 |
#else |
2300 | 2318 |
u.q = QT0; |
2301 |
stq_raw(ADDR(addr), u.ll.upper); |
|
2302 |
stq_raw(ADDR(addr + 8), u.ll.lower); |
|
2319 |
ABI32_MASK(addr); |
|
2320 |
stq_raw(addr, u.ll.upper); |
|
2321 |
stq_raw((addr + 8) & 0xffffffffULL, u.ll.lower); |
|
2303 | 2322 |
#endif |
2304 | 2323 |
} |
2305 | 2324 |
|
2306 |
#undef ADDR |
|
2307 |
|
|
2308 | 2325 |
void helper_ldfsr(void) |
2309 | 2326 |
{ |
2310 | 2327 |
int rnd_mode; |
... | ... | |
2833 | 2850 |
#define SHIFT 3 |
2834 | 2851 |
#include "softmmu_template.h" |
2835 | 2852 |
|
2853 |
/* XXX: make it generic ? */ |
|
2854 |
static void cpu_restore_state2(void *retaddr) |
|
2855 |
{ |
|
2856 |
TranslationBlock *tb; |
|
2857 |
unsigned long pc; |
|
2858 |
|
|
2859 |
if (retaddr) { |
|
2860 |
/* now we have a real cpu fault */ |
|
2861 |
pc = (unsigned long)retaddr; |
|
2862 |
tb = tb_find_pc(pc); |
|
2863 |
if (tb) { |
|
2864 |
/* the PC is inside the translated code. It means that we have |
|
2865 |
a virtual CPU fault */ |
|
2866 |
cpu_restore_state(tb, env, pc, (void *)(long)env->cond); |
|
2867 |
} |
|
2868 |
} |
|
2869 |
} |
|
2870 |
|
|
2836 | 2871 |
static void do_unaligned_access(target_ulong addr, int is_write, int is_user, |
2837 | 2872 |
void *retaddr) |
2838 | 2873 |
{ |
2839 | 2874 |
#ifdef DEBUG_UNALIGNED |
2840 |
printf("Unaligned access to 0x%x from 0x%x\n", addr, env->pc); |
|
2875 |
printf("Unaligned access to 0x" TARGET_FMT_lx " from 0x" TARGET_FMT_lx |
|
2876 |
"\n", addr, env->pc); |
|
2841 | 2877 |
#endif |
2878 |
cpu_restore_state2(retaddr); |
|
2842 | 2879 |
raise_exception(TT_UNALIGNED); |
2843 | 2880 |
} |
2844 | 2881 |
|
... | ... | |
2848 | 2885 |
/* XXX: fix it to restore all registers */ |
2849 | 2886 |
void tlb_fill(target_ulong addr, int is_write, int mmu_idx, void *retaddr) |
2850 | 2887 |
{ |
2851 |
TranslationBlock *tb; |
|
2852 | 2888 |
int ret; |
2853 |
unsigned long pc; |
|
2854 | 2889 |
CPUState *saved_env; |
2855 | 2890 |
|
2856 | 2891 |
/* XXX: hack to restore env in all cases, even if not called from |
... | ... | |
2860 | 2895 |
|
2861 | 2896 |
ret = cpu_sparc_handle_mmu_fault(env, addr, is_write, mmu_idx, 1); |
2862 | 2897 |
if (ret) { |
2863 |
if (retaddr) { |
|
2864 |
/* now we have a real cpu fault */ |
|
2865 |
pc = (unsigned long)retaddr; |
|
2866 |
tb = tb_find_pc(pc); |
|
2867 |
if (tb) { |
|
2868 |
/* the PC is inside the translated code. It means that we have |
|
2869 |
a virtual CPU fault */ |
|
2870 |
cpu_restore_state(tb, env, pc, (void *)env->cond); |
|
2871 |
} |
|
2872 |
} |
|
2898 |
cpu_restore_state2(retaddr); |
|
2873 | 2899 |
cpu_loop_exit(); |
2874 | 2900 |
} |
2875 | 2901 |
env = saved_env; |
Also available in: Unified diff