aboutsummaryrefslogtreecommitdiff
path: root/target-ppc/op_helper.c
diff options
context:
space:
mode:
authoraurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162>2008-11-30 16:24:21 +0000
committeraurel32 <aurel32@c046a42c-6fe2-441c-8c8c-71466251a162>2008-11-30 16:24:21 +0000
commitdfbc799d8e94d26ab2e6ad4a65dc97fd8fb6ece6 (patch)
tree05cca5d527831931b1c89bf320ba610d8080cc16 /target-ppc/op_helper.c
parent37d269dfc6ccbfc3871d458c426e089e0c4403b6 (diff)
target-ppc: convert load/store string instructions to TCG
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net> git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@5828 c046a42c-6fe2-441c-8c8c-71466251a162
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 98c428990a..75fbefbb96 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));