summary refs log tree commit diff stats
path: root/linux-user/xtensa/cpu_loop.c
diff options
context:
space:
mode:
authorLaurent Vivier <laurent@vivier.eu>2018-04-11 20:56:51 +0200
committerLaurent Vivier <laurent@vivier.eu>2018-04-30 09:48:32 +0200
commitde6e89b81fb41870d977656c2a23226c06b68655 (patch)
treec74a3fb91d95252b26e7165109f4c84d3a0d1795 /linux-user/xtensa/cpu_loop.c
parent1d8d0b4ec7b39735e4c3e078c7772f0cd240a0f8 (diff)
downloadfocaccia-qemu-de6e89b81fb41870d977656c2a23226c06b68655.tar.gz
focaccia-qemu-de6e89b81fb41870d977656c2a23226c06b68655.zip
linux-user: move xtensa cpu loop to xtensa directory
No code change, only move code from main.c to
xtensa/cpu_loop.c.

Signed-off-by: Laurent Vivier <laurent@vivier.eu>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20180411185651.21351-20-laurent@vivier.eu>
Diffstat (limited to 'linux-user/xtensa/cpu_loop.c')
-rw-r--r--linux-user/xtensa/cpu_loop.c241
1 files changed, 241 insertions, 0 deletions
diff --git a/linux-user/xtensa/cpu_loop.c b/linux-user/xtensa/cpu_loop.c
index b7700a5561..d142988ebe 100644
--- a/linux-user/xtensa/cpu_loop.c
+++ b/linux-user/xtensa/cpu_loop.c
@@ -21,6 +21,247 @@
 #include "qemu.h"
 #include "cpu_loop-common.h"
 
+static void xtensa_rfw(CPUXtensaState *env)
+{
+    xtensa_restore_owb(env);
+    env->pc = env->sregs[EPC1];
+}
+
+static void xtensa_rfwu(CPUXtensaState *env)
+{
+    env->sregs[WINDOW_START] |= (1 << env->sregs[WINDOW_BASE]);
+    xtensa_rfw(env);
+}
+
+static void xtensa_rfwo(CPUXtensaState *env)
+{
+    env->sregs[WINDOW_START] &= ~(1 << env->sregs[WINDOW_BASE]);
+    xtensa_rfw(env);
+}
+
+static void xtensa_overflow4(CPUXtensaState *env)
+{
+    put_user_ual(env->regs[0], env->regs[5] - 16);
+    put_user_ual(env->regs[1], env->regs[5] - 12);
+    put_user_ual(env->regs[2], env->regs[5] -  8);
+    put_user_ual(env->regs[3], env->regs[5] -  4);
+    xtensa_rfwo(env);
+}
+
+static void xtensa_underflow4(CPUXtensaState *env)
+{
+    get_user_ual(env->regs[0], env->regs[5] - 16);
+    get_user_ual(env->regs[1], env->regs[5] - 12);
+    get_user_ual(env->regs[2], env->regs[5] -  8);
+    get_user_ual(env->regs[3], env->regs[5] -  4);
+    xtensa_rfwu(env);
+}
+
+static void xtensa_overflow8(CPUXtensaState *env)
+{
+    put_user_ual(env->regs[0], env->regs[9] - 16);
+    get_user_ual(env->regs[0], env->regs[1] - 12);
+    put_user_ual(env->regs[1], env->regs[9] - 12);
+    put_user_ual(env->regs[2], env->regs[9] -  8);
+    put_user_ual(env->regs[3], env->regs[9] -  4);
+    put_user_ual(env->regs[4], env->regs[0] - 32);
+    put_user_ual(env->regs[5], env->regs[0] - 28);
+    put_user_ual(env->regs[6], env->regs[0] - 24);
+    put_user_ual(env->regs[7], env->regs[0] - 20);
+    xtensa_rfwo(env);
+}
+
+static void xtensa_underflow8(CPUXtensaState *env)
+{
+    get_user_ual(env->regs[0], env->regs[9] - 16);
+    get_user_ual(env->regs[1], env->regs[9] - 12);
+    get_user_ual(env->regs[2], env->regs[9] -  8);
+    get_user_ual(env->regs[7], env->regs[1] - 12);
+    get_user_ual(env->regs[3], env->regs[9] -  4);
+    get_user_ual(env->regs[4], env->regs[7] - 32);
+    get_user_ual(env->regs[5], env->regs[7] - 28);
+    get_user_ual(env->regs[6], env->regs[7] - 24);
+    get_user_ual(env->regs[7], env->regs[7] - 20);
+    xtensa_rfwu(env);
+}
+
+static void xtensa_overflow12(CPUXtensaState *env)
+{
+    put_user_ual(env->regs[0],  env->regs[13] - 16);
+    get_user_ual(env->regs[0],  env->regs[1]  - 12);
+    put_user_ual(env->regs[1],  env->regs[13] - 12);
+    put_user_ual(env->regs[2],  env->regs[13] -  8);
+    put_user_ual(env->regs[3],  env->regs[13] -  4);
+    put_user_ual(env->regs[4],  env->regs[0]  - 48);
+    put_user_ual(env->regs[5],  env->regs[0]  - 44);
+    put_user_ual(env->regs[6],  env->regs[0]  - 40);
+    put_user_ual(env->regs[7],  env->regs[0]  - 36);
+    put_user_ual(env->regs[8],  env->regs[0]  - 32);
+    put_user_ual(env->regs[9],  env->regs[0]  - 28);
+    put_user_ual(env->regs[10], env->regs[0]  - 24);
+    put_user_ual(env->regs[11], env->regs[0]  - 20);
+    xtensa_rfwo(env);
+}
+
+static void xtensa_underflow12(CPUXtensaState *env)
+{
+    get_user_ual(env->regs[0],  env->regs[13] - 16);
+    get_user_ual(env->regs[1],  env->regs[13] - 12);
+    get_user_ual(env->regs[2],  env->regs[13] -  8);
+    get_user_ual(env->regs[11], env->regs[1]  - 12);
+    get_user_ual(env->regs[3],  env->regs[13] -  4);
+    get_user_ual(env->regs[4],  env->regs[11] - 48);
+    get_user_ual(env->regs[5],  env->regs[11] - 44);
+    get_user_ual(env->regs[6],  env->regs[11] - 40);
+    get_user_ual(env->regs[7],  env->regs[11] - 36);
+    get_user_ual(env->regs[8],  env->regs[11] - 32);
+    get_user_ual(env->regs[9],  env->regs[11] - 28);
+    get_user_ual(env->regs[10], env->regs[11] - 24);
+    get_user_ual(env->regs[11], env->regs[11] - 20);
+    xtensa_rfwu(env);
+}
+
+void cpu_loop(CPUXtensaState *env)
+{
+    CPUState *cs = CPU(xtensa_env_get_cpu(env));
+    target_siginfo_t info;
+    abi_ulong ret;
+    int trapnr;
+
+    while (1) {
+        cpu_exec_start(cs);
+        trapnr = cpu_exec(cs);
+        cpu_exec_end(cs);
+        process_queued_cpu_work(cs);
+
+        env->sregs[PS] &= ~PS_EXCM;
+        switch (trapnr) {
+        case EXCP_INTERRUPT:
+            break;
+
+        case EXC_WINDOW_OVERFLOW4:
+            xtensa_overflow4(env);
+            break;
+        case EXC_WINDOW_UNDERFLOW4:
+            xtensa_underflow4(env);
+            break;
+        case EXC_WINDOW_OVERFLOW8:
+            xtensa_overflow8(env);
+            break;
+        case EXC_WINDOW_UNDERFLOW8:
+            xtensa_underflow8(env);
+            break;
+        case EXC_WINDOW_OVERFLOW12:
+            xtensa_overflow12(env);
+            break;
+        case EXC_WINDOW_UNDERFLOW12:
+            xtensa_underflow12(env);
+            break;
+
+        case EXC_USER:
+            switch (env->sregs[EXCCAUSE]) {
+            case ILLEGAL_INSTRUCTION_CAUSE:
+            case PRIVILEGED_CAUSE:
+                info.si_signo = TARGET_SIGILL;
+                info.si_errno = 0;
+                info.si_code =
+                    env->sregs[EXCCAUSE] == ILLEGAL_INSTRUCTION_CAUSE ?
+                    TARGET_ILL_ILLOPC : TARGET_ILL_PRVOPC;
+                info._sifields._sigfault._addr = env->sregs[EPC1];
+                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+                break;
+
+            case SYSCALL_CAUSE:
+                env->pc += 3;
+                ret = do_syscall(env, env->regs[2],
+                                 env->regs[6], env->regs[3],
+                                 env->regs[4], env->regs[5],
+                                 env->regs[8], env->regs[9], 0, 0);
+                switch (ret) {
+                default:
+                    env->regs[2] = ret;
+                    break;
+
+                case -TARGET_ERESTARTSYS:
+                    env->pc -= 3;
+                    break;
+
+                case -TARGET_QEMU_ESIGRETURN:
+                    break;
+                }
+                break;
+
+            case ALLOCA_CAUSE:
+                env->sregs[PS] = deposit32(env->sregs[PS],
+                                           PS_OWB_SHIFT,
+                                           PS_OWB_LEN,
+                                           env->sregs[WINDOW_BASE]);
+
+                switch (env->regs[0] & 0xc0000000) {
+                case 0x00000000:
+                case 0x40000000:
+                    xtensa_rotate_window(env, -1);
+                    xtensa_underflow4(env);
+                    break;
+
+                case 0x80000000:
+                    xtensa_rotate_window(env, -2);
+                    xtensa_underflow8(env);
+                    break;
+
+                case 0xc0000000:
+                    xtensa_rotate_window(env, -3);
+                    xtensa_underflow12(env);
+                    break;
+                }
+                break;
+
+            case INTEGER_DIVIDE_BY_ZERO_CAUSE:
+                info.si_signo = TARGET_SIGFPE;
+                info.si_errno = 0;
+                info.si_code = TARGET_FPE_INTDIV;
+                info._sifields._sigfault._addr = env->sregs[EPC1];
+                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+                break;
+
+            case LOAD_PROHIBITED_CAUSE:
+            case STORE_PROHIBITED_CAUSE:
+                info.si_signo = TARGET_SIGSEGV;
+                info.si_errno = 0;
+                info.si_code = TARGET_SEGV_ACCERR;
+                info._sifields._sigfault._addr = env->sregs[EXCVADDR];
+                queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
+                break;
+
+            default:
+                fprintf(stderr, "exccause = %d\n", env->sregs[EXCCAUSE]);
+                g_assert_not_reached();
+            }
+            break;
+        case EXCP_DEBUG:
+            trapnr = gdb_handlesig(cs, TARGET_SIGTRAP);
+            if (trapnr) {
+                info.si_signo = trapnr;
+                info.si_errno = 0;
+                info.si_code = TARGET_TRAP_BRKPT;
+                queue_signal(env, trapnr, QEMU_SI_FAULT, &info);
+            }
+            break;
+        case EXC_DEBUG:
+        default:
+            fprintf(stderr, "trapnr = %d\n", trapnr);
+            g_assert_not_reached();
+        }
+        process_pending_signals(env);
+    }
+}
+
 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 {
+    int i;
+    for (i = 0; i < 16; ++i) {
+        env->regs[i] = regs->areg[i];
+    }
+    env->sregs[WINDOW_START] = regs->windowstart;
+    env->pc = regs->pc;
 }