aboutsummaryrefslogtreecommitdiff
path: root/target-ppc/op_helper.c
diff options
context:
space:
mode:
Diffstat (limited to 'target-ppc/op_helper.c')
-rw-r--r--target-ppc/op_helper.c93
1 files changed, 93 insertions, 0 deletions
diff --git a/target-ppc/op_helper.c b/target-ppc/op_helper.c
index 98c4289..75fbefb 100644
--- a/target-ppc/op_helper.c
+++ b/target-ppc/op_helper.c
@@ -170,6 +170,99 @@ void helper_stmw (target_ulong addr, uint32_t reg)
}
}
+void helper_lsw(target_ulong addr, uint32_t nb, uint32_t reg)
+{
+ int sh;
+#ifdef CONFIG_USER_ONLY
+#define ldfunl ldl_raw
+#define ldfunb ldub_raw
+#else
+ int (*ldfunl)(target_ulong);
+ int (*ldfunb)(target_ulong);
+
+ switch (env->mmu_idx) {
+ default:
+ case 0:
+ ldfunl = ldl_user;
+ ldfunb = ldub_user;
+ break;
+ case 1:
+ ldfunl = ldl_kernel;
+ ldfunb = ldub_kernel;
+ break;
+ case 2:
+ ldfunl = ldl_hypv;
+ ldfunb = ldub_hypv;
+ break;
+ }
+#endif
+ for (; nb > 3; nb -= 4, addr += 4) {
+ env->gpr[reg] = ldfunl(get_addr(addr));
+ reg = (reg + 1) % 32;
+ }
+ if (unlikely(nb > 0)) {
+ env->gpr[reg] = 0;
+ for (sh = 24; nb > 0; nb--, addr++, sh -= 8) {
+ env->gpr[reg] |= ldfunb(get_addr(addr)) << sh;
+ }
+ }
+}
+/* PPC32 specification says we must generate an exception if
+ * rA is in the range of registers to be loaded.
+ * In an other hand, IBM says this is valid, but rA won't be loaded.
+ * For now, I'll follow the spec...
+ */
+void helper_lswx(target_ulong addr, uint32_t reg, uint32_t ra, uint32_t rb)
+{
+ if (likely(xer_bc != 0)) {
+ if (unlikely((ra != 0 && reg < ra && (reg + xer_bc) > ra) ||
+ (reg < rb && (reg + xer_bc) > rb))) {
+ raise_exception_err(env, POWERPC_EXCP_PROGRAM,
+ POWERPC_EXCP_INVAL |
+ POWERPC_EXCP_INVAL_LSWX);
+ } else {
+ helper_lsw(addr, xer_bc, reg);
+ }
+ }
+}
+
+void helper_stsw(target_ulong addr, uint32_t nb, uint32_t reg)
+{
+ int sh;
+#ifdef CONFIG_USER_ONLY
+#define stfunl stl_raw
+#define stfunb stb_raw
+#else
+ void (*stfunl)(target_ulong, int);
+ void (*stfunb)(target_ulong, int);
+
+ switch (env->mmu_idx) {
+ default:
+ case 0:
+ stfunl = stl_user;
+ stfunb = stb_user;
+ break;
+ case 1:
+ stfunl = stl_kernel;
+ stfunb = stb_kernel;
+ break;
+ case 2:
+ stfunl = stl_hypv;
+ stfunb = stb_hypv;
+ break;
+ }
+#endif
+
+ for (; nb > 3; nb -= 4, addr += 4) {
+ stfunl(get_addr(addr), env->gpr[reg]);
+ reg = (reg + 1) % 32;
+ }
+ if (unlikely(nb > 0)) {
+ for (sh = 24; nb > 0; nb--, addr++, sh -= 8)
+ stfunb(get_addr(addr), (env->gpr[reg] >> sh) & 0xFF);
+ }
+}
+
static void do_dcbz(target_ulong addr, int dcache_line_size)
{
target_long mask = get_addr(~(dcache_line_size - 1));