X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=target-unicore32%2Fhelper.c;h=9bf4fea5db72b9ea2831d8baea74b742687553af;hb=HEAD;hp=b5b1cb7c9bb11e29af2c5f66c62d9f88f6463fee;hpb=d06cddf517d2b33389c02971b353d10dd4edda1a;p=qemu.git diff --git a/target-unicore32/helper.c b/target-unicore32/helper.c index b5b1cb7c9..9bf4fea5d 100644 --- a/target-unicore32/helper.c +++ b/target-unicore32/helper.c @@ -1,90 +1,45 @@ /* - * Copyright (C) 2010-2011 GUAN Xue-tao + * Copyright (C) 2010-2012 Guan Xuetao * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. + * + * Contributions from 2012-04-01 on are considered under GPL version 2, + * or (at your option) any later version. */ -#include -#include -#include #include "cpu.h" -#include "gdbstub.h" +#include "exec/gdbstub.h" #include "helper.h" -#include "qemu-common.h" -#include "host-utils.h" - -static inline void set_feature(CPUState *env, int feature) -{ - env->features |= feature; -} +#include "qemu/host-utils.h" +#ifndef CONFIG_USER_ONLY +#include "ui/console.h" +#endif -struct uc32_cpu_t { - uint32_t id; - const char *name; -}; +#undef DEBUG_UC32 -static const struct uc32_cpu_t uc32_cpu_names[] = { - { UC32_CPUID_UCV2, "UniCore-II"}, - { UC32_CPUID_ANY, "any"}, - { 0, NULL} -}; +#ifdef DEBUG_UC32 +#define DPRINTF(fmt, ...) printf("%s: " fmt , __func__, ## __VA_ARGS__) +#else +#define DPRINTF(fmt, ...) do {} while (0) +#endif -/* return 0 if not found */ -static uint32_t uc32_cpu_find_by_name(const char *name) +CPUUniCore32State *uc32_cpu_init(const char *cpu_model) { - int i; - uint32_t id; + UniCore32CPU *cpu; + CPUUniCore32State *env; + ObjectClass *oc; - id = 0; - for (i = 0; uc32_cpu_names[i].name; i++) { - if (strcmp(name, uc32_cpu_names[i].name) == 0) { - id = uc32_cpu_names[i].id; - break; - } + oc = cpu_class_by_name(TYPE_UNICORE32_CPU, cpu_model); + if (oc == NULL) { + return NULL; } - return id; -} - -CPUState *uc32_cpu_init(const char *cpu_model) -{ - CPUState *env; - uint32_t id; - static int inited = 1; + cpu = UNICORE32_CPU(object_new(object_class_get_name(oc))); + env = &cpu->env; - env = g_malloc0(sizeof(CPUState)); - cpu_exec_init(env); + object_property_set_bool(OBJECT(cpu), true, "realized", NULL); - id = uc32_cpu_find_by_name(cpu_model); - switch (id) { - case UC32_CPUID_UCV2: - set_feature(env, UC32_HWCAP_CMOV); - set_feature(env, UC32_HWCAP_UCF64); - env->ucf64.xregs[UC32_UCF64_FPSCR] = 0; - env->cp0.c0_cachetype = 0x1dd20d2; - env->cp0.c1_sys = 0x00090078; - break; - case UC32_CPUID_ANY: /* For userspace emulation. */ - set_feature(env, UC32_HWCAP_CMOV); - set_feature(env, UC32_HWCAP_UCF64); - break; - default: - cpu_abort(env, "Bad CPU ID: %x\n", id); - } - - env->cpu_model_str = cpu_model; - env->cp0.c0_cpuid = id; - env->uncached_asr = ASR_MODE_USER; - env->regs[31] = 0; - - if (inited) { - inited = 0; - uc32_translate_init(); - } - - tlb_flush(env, 1); - qemu_init_vcpu(env); return env; } @@ -98,389 +53,206 @@ uint32_t HELPER(clz)(uint32_t x) return clz32(x); } -void do_interrupt(CPUState *env) -{ - env->exception_index = -1; -} - -int uc32_cpu_handle_mmu_fault(CPUState *env, target_ulong address, int rw, - int mmu_idx) -{ - env->exception_index = UC32_EXCP_TRAP; - env->cp0.c4_faultaddr = address; - return 1; -} - -/* These should probably raise undefined insn exceptions. */ -void HELPER(set_cp)(CPUState *env, uint32_t insn, uint32_t val) -{ - int op1 = (insn >> 8) & 0xf; - cpu_abort(env, "cp%i insn %08x\n", op1, insn); - return; -} - -uint32_t HELPER(get_cp)(CPUState *env, uint32_t insn) -{ - int op1 = (insn >> 8) & 0xf; - cpu_abort(env, "cp%i insn %08x\n", op1, insn); - return 0; -} - -void HELPER(set_cp0)(CPUState *env, uint32_t insn, uint32_t val) -{ - cpu_abort(env, "cp0 insn %08x\n", insn); -} - -uint32_t HELPER(get_cp0)(CPUState *env, uint32_t insn) -{ - cpu_abort(env, "cp0 insn %08x\n", insn); - return 0; -} - -void switch_mode(CPUState *env, int mode) -{ - if (mode != ASR_MODE_USER) { - cpu_abort(env, "Tried to switch out of user mode\n"); - } -} - -void HELPER(set_r29_banked)(CPUState *env, uint32_t mode, uint32_t val) -{ - cpu_abort(env, "banked r29 write\n"); -} - -uint32_t HELPER(get_r29_banked)(CPUState *env, uint32_t mode) -{ - cpu_abort(env, "banked r29 read\n"); - return 0; -} - -/* UniCore-F64 support. We follow the convention used for F64 instrunctions: - Single precition routines have a "s" suffix, double precision a - "d" suffix. */ - -/* Convert host exception flags to f64 form. */ -static inline int ucf64_exceptbits_from_host(int host_bits) -{ - int target_bits = 0; - - if (host_bits & float_flag_invalid) { - target_bits |= UCF64_FPSCR_FLAG_INVALID; - } - if (host_bits & float_flag_divbyzero) { - target_bits |= UCF64_FPSCR_FLAG_DIVZERO; - } - if (host_bits & float_flag_overflow) { - target_bits |= UCF64_FPSCR_FLAG_OVERFLOW; - } - if (host_bits & float_flag_underflow) { - target_bits |= UCF64_FPSCR_FLAG_UNDERFLOW; - } - if (host_bits & float_flag_inexact) { - target_bits |= UCF64_FPSCR_FLAG_INEXACT; - } - return target_bits; -} - -uint32_t HELPER(ucf64_get_fpscr)(CPUState *env) -{ - int i; - uint32_t fpscr; - - fpscr = (env->ucf64.xregs[UC32_UCF64_FPSCR] & UCF64_FPSCR_MASK); - i = get_float_exception_flags(&env->ucf64.fp_status); - fpscr |= ucf64_exceptbits_from_host(i); - return fpscr; -} - -/* Convert ucf64 exception flags to target form. */ -static inline int ucf64_exceptbits_to_host(int target_bits) -{ - int host_bits = 0; - - if (target_bits & UCF64_FPSCR_FLAG_INVALID) { - host_bits |= float_flag_invalid; - } - if (target_bits & UCF64_FPSCR_FLAG_DIVZERO) { - host_bits |= float_flag_divbyzero; - } - if (target_bits & UCF64_FPSCR_FLAG_OVERFLOW) { - host_bits |= float_flag_overflow; - } - if (target_bits & UCF64_FPSCR_FLAG_UNDERFLOW) { - host_bits |= float_flag_underflow; - } - if (target_bits & UCF64_FPSCR_FLAG_INEXACT) { - host_bits |= float_flag_inexact; - } - return host_bits; -} - -void HELPER(ucf64_set_fpscr)(CPUState *env, uint32_t val) -{ - int i; - uint32_t changed; - - changed = env->ucf64.xregs[UC32_UCF64_FPSCR]; - env->ucf64.xregs[UC32_UCF64_FPSCR] = (val & UCF64_FPSCR_MASK); - - changed ^= val; - if (changed & (UCF64_FPSCR_RND_MASK)) { - i = UCF64_FPSCR_RND(val); - switch (i) { - case 0: - i = float_round_nearest_even; - break; - case 1: - i = float_round_to_zero; - break; - case 2: - i = float_round_up; - break; - case 3: - i = float_round_down; - break; - default: /* 100 and 101 not implement */ - cpu_abort(env, "Unsupported UniCore-F64 round mode"); - } - set_float_rounding_mode(i, &env->ucf64.fp_status); - } - - i = ucf64_exceptbits_to_host(UCF64_FPSCR_TRAPEN(val)); - set_float_exception_flags(i, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_adds)(float32 a, float32 b, CPUState *env) -{ - return float32_add(a, b, &env->ucf64.fp_status); -} - -float64 HELPER(ucf64_addd)(float64 a, float64 b, CPUState *env) -{ - return float64_add(a, b, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_subs)(float32 a, float32 b, CPUState *env) -{ - return float32_sub(a, b, &env->ucf64.fp_status); -} - -float64 HELPER(ucf64_subd)(float64 a, float64 b, CPUState *env) -{ - return float64_sub(a, b, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_muls)(float32 a, float32 b, CPUState *env) -{ - return float32_mul(a, b, &env->ucf64.fp_status); -} - -float64 HELPER(ucf64_muld)(float64 a, float64 b, CPUState *env) -{ - return float64_mul(a, b, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_divs)(float32 a, float32 b, CPUState *env) -{ - return float32_div(a, b, &env->ucf64.fp_status); -} - -float64 HELPER(ucf64_divd)(float64 a, float64 b, CPUState *env) -{ - return float64_div(a, b, &env->ucf64.fp_status); -} - -float32 HELPER(ucf64_negs)(float32 a) -{ - return float32_chs(a); -} - -float64 HELPER(ucf64_negd)(float64 a) -{ - return float64_chs(a); -} - -float32 HELPER(ucf64_abss)(float32 a) -{ - return float32_abs(a); -} - -float64 HELPER(ucf64_absd)(float64 a) -{ - return float64_abs(a); -} - -/* XXX: check quiet/signaling case */ -void HELPER(ucf64_cmps)(float32 a, float32 b, uint32_t c, CPUState *env) -{ - int flag; - flag = float32_compare_quiet(a, b, &env->ucf64.fp_status); - env->CF = 0; - switch (c & 0x7) { - case 0: /* F */ - break; - case 1: /* UN */ - if (flag == 2) { - env->CF = 1; - } - break; - case 2: /* EQ */ - if (flag == 0) { - env->CF = 1; +#ifndef CONFIG_USER_ONLY +void helper_cp0_set(CPUUniCore32State *env, uint32_t val, uint32_t creg, + uint32_t cop) +{ + /* + * movc pp.nn, rn, #imm9 + * rn: UCOP_REG_D + * nn: UCOP_REG_N + * 1: sys control reg. + * 2: page table base reg. + * 3: data fault status reg. + * 4: insn fault status reg. + * 5: cache op. reg. + * 6: tlb op. reg. + * imm9: split UCOP_IMM10 with bit5 is 0 + */ + switch (creg) { + case 1: + if (cop != 0) { + goto unrecognized; } + env->cp0.c1_sys = val; break; - case 3: /* UEQ */ - if ((flag == 0) || (flag == 2)) { - env->CF = 1; + case 2: + if (cop != 0) { + goto unrecognized; } + env->cp0.c2_base = val; break; - case 4: /* OLT */ - if (flag == -1) { - env->CF = 1; + case 3: + if (cop != 0) { + goto unrecognized; } + env->cp0.c3_faultstatus = val; break; - case 5: /* ULT */ - if ((flag == -1) || (flag == 2)) { - env->CF = 1; + case 4: + if (cop != 0) { + goto unrecognized; } + env->cp0.c4_faultaddr = val; break; - case 6: /* OLE */ - if ((flag == -1) || (flag == 0)) { - env->CF = 1; + case 5: + switch (cop) { + case 28: + DPRINTF("Invalidate Entire I&D cache\n"); + return; + case 20: + DPRINTF("Invalidate Entire Icache\n"); + return; + case 12: + DPRINTF("Invalidate Entire Dcache\n"); + return; + case 10: + DPRINTF("Clean Entire Dcache\n"); + return; + case 14: + DPRINTF("Flush Entire Dcache\n"); + return; + case 13: + DPRINTF("Invalidate Dcache line\n"); + return; + case 11: + DPRINTF("Clean Dcache line\n"); + return; + case 15: + DPRINTF("Flush Dcache line\n"); + return; } break; - case 7: /* ULE */ - if (flag != 1) { - env->CF = 1; + case 6: + if ((cop <= 6) && (cop >= 2)) { + /* invalid all tlb */ + tlb_flush(env, 1); + return; } break; + default: + goto unrecognized; } - env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29) - | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff); -} - -void HELPER(ucf64_cmpd)(float64 a, float64 b, uint32_t c, CPUState *env) -{ - int flag; - flag = float64_compare_quiet(a, b, &env->ucf64.fp_status); - env->CF = 0; - switch (c & 0x7) { - case 0: /* F */ - break; - case 1: /* UN */ - if (flag == 2) { - env->CF = 1; - } - break; - case 2: /* EQ */ - if (flag == 0) { - env->CF = 1; - } - break; - case 3: /* UEQ */ - if ((flag == 0) || (flag == 2)) { - env->CF = 1; + return; +unrecognized: + DPRINTF("Wrong register (%d) or wrong operation (%d) in cp0_set!\n", + creg, cop); +} + +uint32_t helper_cp0_get(CPUUniCore32State *env, uint32_t creg, uint32_t cop) +{ + /* + * movc rd, pp.nn, #imm9 + * rd: UCOP_REG_D + * nn: UCOP_REG_N + * 0: cpuid and cachetype + * 1: sys control reg. + * 2: page table base reg. + * 3: data fault status reg. + * 4: insn fault status reg. + * imm9: split UCOP_IMM10 with bit5 is 0 + */ + switch (creg) { + case 0: + switch (cop) { + case 0: + return env->cp0.c0_cpuid; + case 1: + return env->cp0.c0_cachetype; } break; - case 4: /* OLT */ - if (flag == -1) { - env->CF = 1; + case 1: + if (cop == 0) { + return env->cp0.c1_sys; } break; - case 5: /* ULT */ - if ((flag == -1) || (flag == 2)) { - env->CF = 1; + case 2: + if (cop == 0) { + return env->cp0.c2_base; } break; - case 6: /* OLE */ - if ((flag == -1) || (flag == 0)) { - env->CF = 1; + case 3: + if (cop == 0) { + return env->cp0.c3_faultstatus; } break; - case 7: /* ULE */ - if (flag != 1) { - env->CF = 1; + case 4: + if (cop == 0) { + return env->cp0.c4_faultaddr; } break; } - env->ucf64.xregs[UC32_UCF64_FPSCR] = (env->CF << 29) - | (env->ucf64.xregs[UC32_UCF64_FPSCR] & 0x0fffffff); -} - -/* Helper routines to perform bitwise copies between float and int. */ -static inline float32 ucf64_itos(uint32_t i) -{ - union { - uint32_t i; - float32 s; - } v; - - v.i = i; - return v.s; -} - -static inline uint32_t ucf64_stoi(float32 s) -{ - union { - uint32_t i; - float32 s; - } v; - - v.s = s; - return v.i; + DPRINTF("Wrong register (%d) or wrong operation (%d) in cp0_set!\n", + creg, cop); + return 0; } -static inline float64 ucf64_itod(uint64_t i) +#ifdef CONFIG_CURSES +/* + * FIXME: + * 1. curses windows will be blank when switching back + * 2. backspace is not handled yet + */ +static void putc_on_screen(unsigned char ch) { - union { - uint64_t i; - float64 d; - } v; + static WINDOW *localwin; + static int init; - v.i = i; - return v.d; -} - -static inline uint64_t ucf64_dtoi(float64 d) -{ - union { - uint64_t i; - float64 d; - } v; + if (!init) { + /* Assume 80 * 30 screen to minimize the implementation */ + localwin = newwin(30, 80, 0, 0); + scrollok(localwin, TRUE); + init = TRUE; + } - v.d = d; - return v.i; -} + if (isprint(ch)) { + wprintw(localwin, "%c", ch); + } else { + switch (ch) { + case '\n': + wprintw(localwin, "%c", ch); + break; + case '\r': + /* If '\r' is put before '\n', the curses window will destroy the + * last print line. And meanwhile, '\n' implifies '\r' inside. */ + break; + default: /* Not handled, so just print it hex code */ + wprintw(localwin, "-- 0x%x --", ch); + } + } -/* Integer to float conversion. */ -float32 HELPER(ucf64_si2sf)(float32 x, CPUState *env) -{ - return int32_to_float32(ucf64_stoi(x), &env->ucf64.fp_status); + wrefresh(localwin); } +#else +#define putc_on_screen(c) do { } while (0) +#endif -float64 HELPER(ucf64_si2df)(float32 x, CPUState *env) +void helper_cp1_putc(target_ulong x) { - return int32_to_float64(ucf64_stoi(x), &env->ucf64.fp_status); + putc_on_screen((unsigned char)x); /* Output to screen */ + DPRINTF("%c", x); /* Output to stdout */ } +#endif -/* Float to integer conversion. */ -float32 HELPER(ucf64_sf2si)(float32 x, CPUState *env) +#ifdef CONFIG_USER_ONLY +void switch_mode(CPUUniCore32State *env, int mode) { - return ucf64_itos(float32_to_int32(x, &env->ucf64.fp_status)); + if (mode != ASR_MODE_USER) { + cpu_abort(env, "Tried to switch out of user mode\n"); + } } -float32 HELPER(ucf64_df2si)(float64 x, CPUState *env) +void uc32_cpu_do_interrupt(CPUState *cs) { - return ucf64_itos(float64_to_int32(x, &env->ucf64.fp_status)); -} + UniCore32CPU *cpu = UNICORE32_CPU(cs); + CPUUniCore32State *env = &cpu->env; -/* floating point conversion */ -float64 HELPER(ucf64_sf2df)(float32 x, CPUState *env) -{ - return float32_to_float64(x, &env->ucf64.fp_status); + cpu_abort(env, "NO interrupt in user mode\n"); } -float32 HELPER(ucf64_df2sf)(float64 x, CPUState *env) +int uc32_cpu_handle_mmu_fault(CPUUniCore32State *env, target_ulong address, + int access_type, int mmu_idx) { - return float64_to_float32(x, &env->ucf64.fp_status); + cpu_abort(env, "NO mmu fault in user mode\n"); + return 1; } +#endif