diff options
Diffstat (limited to 'qemu/target-alpha')
-rw-r--r-- | qemu/target-alpha/cpu.c | 17 | ||||
-rw-r--r-- | qemu/target-alpha/cpu.h | 9 | ||||
-rw-r--r-- | qemu/target-alpha/fpu_helper.c | 3 | ||||
-rw-r--r-- | qemu/target-alpha/gdbstub.c | 6 | ||||
-rw-r--r-- | qemu/target-alpha/helper.c | 67 | ||||
-rw-r--r-- | qemu/target-alpha/helper.h | 4 | ||||
-rw-r--r-- | qemu/target-alpha/int_helper.c | 52 | ||||
-rw-r--r-- | qemu/target-alpha/machine.c | 5 | ||||
-rw-r--r-- | qemu/target-alpha/mem_helper.c | 3 | ||||
-rw-r--r-- | qemu/target-alpha/sys_helper.c | 25 | ||||
-rw-r--r-- | qemu/target-alpha/translate.c | 297 | ||||
-rw-r--r-- | qemu/target-alpha/vax_helper.c | 1 |
12 files changed, 271 insertions, 218 deletions
diff --git a/qemu/target-alpha/cpu.c b/qemu/target-alpha/cpu.c index 421d7e536..8a155cae9 100644 --- a/qemu/target-alpha/cpu.c +++ b/qemu/target-alpha/cpu.c @@ -19,6 +19,8 @@ * <http://www.gnu.org/licenses/lgpl-2.1.html> */ +#include "qemu/osdep.h" +#include "qapi/error.h" #include "cpu.h" #include "qemu-common.h" #include "migration/vmstate.h" @@ -46,6 +48,12 @@ static bool alpha_cpu_has_work(CPUState *cs) | CPU_INTERRUPT_MCHK); } +static void alpha_cpu_disas_set_info(CPUState *cpu, disassemble_info *info) +{ + info->mach = bfd_mach_alpha_ev6; + info->print_insn = print_insn_alpha; +} + static void alpha_cpu_realizefn(DeviceState *dev, Error **errp) { CPUState *cs = CPU(dev); @@ -297,7 +305,16 @@ static void alpha_cpu_class_init(ObjectClass *oc, void *data) cc->get_phys_page_debug = alpha_cpu_get_phys_page_debug; dc->vmsd = &vmstate_alpha_cpu; #endif + cc->disas_set_info = alpha_cpu_disas_set_info; + cc->gdb_num_core_regs = 67; + + /* + * Reason: alpha_cpu_initfn() calls cpu_exec_init(), which saves + * the object in cpus -> dangling pointer after final + * object_unref(). + */ + dc->cannot_destroy_with_object_finalize_yet = true; } static const TypeInfo alpha_cpu_type_info = { diff --git a/qemu/target-alpha/cpu.h b/qemu/target-alpha/cpu.h index 91c56d6bc..420f2a53f 100644 --- a/qemu/target-alpha/cpu.h +++ b/qemu/target-alpha/cpu.h @@ -20,7 +20,6 @@ #if !defined (__CPU_ALPHA_H__) #define __CPU_ALPHA_H__ -#include "config.h" #include "qemu-common.h" #define TARGET_LONG_BITS 64 @@ -32,8 +31,6 @@ #include "fpu/softfloat.h" -#define ELF_MACHINE EM_ALPHA - #define ICACHE_LINE_SIZE 32 #define DCACHE_LINE_SIZE 32 @@ -289,7 +286,6 @@ struct CPUAlphaState { #define cpu_list alpha_cpu_list #define cpu_exec cpu_alpha_exec -#define cpu_gen_code cpu_alpha_gen_code #define cpu_signal_handler cpu_alpha_signal_handler #include "exec/cpu-all.h" @@ -376,7 +372,7 @@ enum { PS_USER_MODE = 8 }; -static inline int cpu_mmu_index(CPUAlphaState *env) +static inline int cpu_mmu_index(CPUAlphaState *env, bool ifetch) { if (env->pal_mode) { return MMU_KERNEL_IDX; @@ -445,8 +441,9 @@ void QEMU_NORETURN arith_excp(CPUAlphaState *, uintptr_t, int, uint64_t); uint64_t cpu_alpha_load_fpcr (CPUAlphaState *env); void cpu_alpha_store_fpcr (CPUAlphaState *env, uint64_t val); +uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg); +void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val); #ifndef CONFIG_USER_ONLY -void swap_shadow_regs(CPUAlphaState *env); QEMU_NORETURN void alpha_cpu_unassigned_access(CPUState *cpu, hwaddr addr, bool is_write, bool is_exec, int unused, unsigned size); diff --git a/qemu/target-alpha/fpu_helper.c b/qemu/target-alpha/fpu_helper.c index b091aa842..5ab7d5e64 100644 --- a/qemu/target-alpha/fpu_helper.c +++ b/qemu/target-alpha/fpu_helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" @@ -437,7 +438,7 @@ uint64_t helper_cvtqs(CPUAlphaState *env, uint64_t a) return float32_to_s(fr); } -/* Implement float64 to uint64 conversion without saturation -- we must +/* Implement float64 to uint64_t conversion without saturation -- we must supply the truncated result. This behaviour is used by the compiler to get unsigned conversion for free with the same instruction. */ diff --git a/qemu/target-alpha/gdbstub.c b/qemu/target-alpha/gdbstub.c index 980f140e7..199f02842 100644 --- a/qemu/target-alpha/gdbstub.c +++ b/qemu/target-alpha/gdbstub.c @@ -17,7 +17,7 @@ * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" +#include "qemu/osdep.h" #include "qemu-common.h" #include "exec/gdbstub.h" @@ -30,7 +30,7 @@ int alpha_cpu_gdb_read_register(CPUState *cs, uint8_t *mem_buf, int n) switch (n) { case 0 ... 30: - val = env->ir[n]; + val = cpu_alpha_load_gr(env, n); break; case 32 ... 62: d.d = env->fir[n - 32]; @@ -66,7 +66,7 @@ int alpha_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n) switch (n) { case 0 ... 30: - env->ir[n] = tmp; + cpu_alpha_store_gr(env, n, tmp); break; case 32 ... 62: d.ll = tmp; diff --git a/qemu/target-alpha/helper.c b/qemu/target-alpha/helper.c index 46b8ef914..6dec2639b 100644 --- a/qemu/target-alpha/helper.c +++ b/qemu/target-alpha/helper.c @@ -17,9 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include <stdint.h> -#include <stdlib.h> -#include <stdio.h> +#include "qemu/osdep.h" #include "cpu.h" #include "fpu/softfloat.h" @@ -79,6 +77,30 @@ void helper_store_fpcr(CPUAlphaState *env, uint64_t val) cpu_alpha_store_fpcr(env, val); } +static uint64_t *cpu_alpha_addr_gr(CPUAlphaState *env, unsigned reg) +{ +#ifndef CONFIG_USER_ONLY + if (env->pal_mode) { + if (reg >= 8 && reg <= 14) { + return &env->shadow[reg - 8]; + } else if (reg == 25) { + return &env->shadow[7]; + } + } +#endif + return &env->ir[reg]; +} + +uint64_t cpu_alpha_load_gr(CPUAlphaState *env, unsigned reg) +{ + return *cpu_alpha_addr_gr(env, reg); +} + +void cpu_alpha_store_gr(CPUAlphaState *env, unsigned reg, uint64_t val) +{ + *cpu_alpha_addr_gr(env, reg) = val; +} + #if defined(CONFIG_USER_ONLY) int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr address, int rw, int mmu_idx) @@ -90,38 +112,6 @@ int alpha_cpu_handle_mmu_fault(CPUState *cs, vaddr address, return 1; } #else -void swap_shadow_regs(CPUAlphaState *env) -{ - uint64_t i0, i1, i2, i3, i4, i5, i6, i7; - - i0 = env->ir[8]; - i1 = env->ir[9]; - i2 = env->ir[10]; - i3 = env->ir[11]; - i4 = env->ir[12]; - i5 = env->ir[13]; - i6 = env->ir[14]; - i7 = env->ir[25]; - - env->ir[8] = env->shadow[0]; - env->ir[9] = env->shadow[1]; - env->ir[10] = env->shadow[2]; - env->ir[11] = env->shadow[3]; - env->ir[12] = env->shadow[4]; - env->ir[13] = env->shadow[5]; - env->ir[14] = env->shadow[6]; - env->ir[25] = env->shadow[7]; - - env->shadow[0] = i0; - env->shadow[1] = i1; - env->shadow[2] = i2; - env->shadow[3] = i3; - env->shadow[4] = i4; - env->shadow[5] = i5; - env->shadow[6] = i6; - env->shadow[7] = i7; -} - /* Returns the OSF/1 entMM failure indication, or -1 on success. */ static int get_physical_address(CPUAlphaState *env, target_ulong addr, int prot_need, int mmu_idx, @@ -375,10 +365,7 @@ void alpha_cpu_do_interrupt(CPUState *cs) env->pc = env->palbr + i; /* Switch to PALmode. */ - if (!env->pal_mode) { - env->pal_mode = 1; - swap_shadow_regs(env); - } + env->pal_mode = 1; #endif /* !USER_ONLY */ } @@ -443,7 +430,7 @@ void alpha_cpu_dump_state(CPUState *cs, FILE *f, fprintf_function cpu_fprintf, env->pc, env->ps); for (i = 0; i < 31; i++) { cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i, - linux_reg_names[i], env->ir[i]); + linux_reg_names[i], cpu_alpha_load_gr(env, i)); if ((i % 3) == 2) cpu_fprintf(f, "\n"); } diff --git a/qemu/target-alpha/helper.h b/qemu/target-alpha/helper.h index d221f0d7d..c3d8a3ee4 100644 --- a/qemu/target-alpha/helper.h +++ b/qemu/target-alpha/helper.h @@ -10,6 +10,7 @@ DEF_HELPER_FLAGS_1(cttz, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_FLAGS_2(zap, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_FLAGS_2(zapnot, TCG_CALL_NO_RWG_SE, i64, i64, i64) +DEF_HELPER_FLAGS_1(cmpbe0, TCG_CALL_NO_RWG_SE, i64, i64) DEF_HELPER_FLAGS_2(cmpbge, TCG_CALL_NO_RWG_SE, i64, i64, i64) DEF_HELPER_FLAGS_2(minub8, TCG_CALL_NO_RWG_SE, i64, i64, i64) @@ -91,9 +92,6 @@ DEF_HELPER_FLAGS_2(ieee_input_cmp, TCG_CALL_NO_WG, void, env, i64) DEF_HELPER_FLAGS_2(ieee_input_s, TCG_CALL_NO_WG, void, env, i64) #if !defined (CONFIG_USER_ONLY) -DEF_HELPER_2(hw_ret, void, env, i64) -DEF_HELPER_3(call_pal, void, env, i64, i64) - DEF_HELPER_2(ldl_phys, i64, env, i64) DEF_HELPER_2(ldq_phys, i64, env, i64) DEF_HELPER_2(ldl_l_phys, i64, env, i64) diff --git a/qemu/target-alpha/int_helper.c b/qemu/target-alpha/int_helper.c index 74f38cbe7..777e48d08 100644 --- a/qemu/target-alpha/int_helper.c +++ b/qemu/target-alpha/int_helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" #include "qemu/host-utils.h" @@ -58,20 +59,47 @@ uint64_t helper_zap(uint64_t val, uint64_t mask) return helper_zapnot(val, ~mask); } -uint64_t helper_cmpbge(uint64_t op1, uint64_t op2) +uint64_t helper_cmpbe0(uint64_t a) { - uint8_t opa, opb, res; - int i; + uint64_t m = 0x7f7f7f7f7f7f7f7fULL; + uint64_t c = ~(((a & m) + m) | a | m); + /* a.......b.......c.......d.......e.......f.......g.......h....... */ + c |= c << 7; + /* ab......bc......cd......de......ef......fg......gh......h....... */ + c |= c << 14; + /* abcd....bcde....cdef....defg....efgh....fgh.....gh......h....... */ + c |= c << 28; + /* abcdefghbcdefgh.cdefgh..defgh...efgh....fgh.....gh......h....... */ + return c >> 56; +} - res = 0; - for (i = 0; i < 8; i++) { - opa = op1 >> (i * 8); - opb = op2 >> (i * 8); - if (opa >= opb) { - res |= 1 << i; - } - } - return res; +uint64_t helper_cmpbge(uint64_t a, uint64_t b) +{ + uint64_t mask = 0x00ff00ff00ff00ffULL; + uint64_t test = 0x0100010001000100ULL; + uint64_t al, ah, bl, bh, cl, ch; + + /* Separate the bytes to avoid false positives. */ + al = a & mask; + bl = b & mask; + ah = (a >> 8) & mask; + bh = (b >> 8) & mask; + + /* "Compare". If a byte in B is greater than a byte in A, + it will clear the test bit. */ + cl = ((al | test) - bl) & test; + ch = ((ah | test) - bh) & test; + + /* Fold all of the test bits into a contiguous set. */ + /* ch=.......a...............c...............e...............g........ */ + /* cl=.......b...............d...............f...............h........ */ + cl += ch << 1; + /* cl=......ab..............cd..............ef..............gh........ */ + cl |= cl << 14; + /* cl=......abcd............cdef............efgh............gh........ */ + cl |= cl << 28; + /* cl=......abcdefgh........cdefgh..........efgh............gh........ */ + return cl >> 50; } uint64_t helper_minub8(uint64_t op1, uint64_t op2) diff --git a/qemu/target-alpha/machine.c b/qemu/target-alpha/machine.c index e796bbe27..9ab092852 100644 --- a/qemu/target-alpha/machine.c +++ b/qemu/target-alpha/machine.c @@ -1,3 +1,4 @@ +#include "qemu/osdep.h" #include "hw/hw.h" #include "hw/boards.h" @@ -70,8 +71,8 @@ static VMStateField vmstate_env_fields[] = { static const VMStateDescription vmstate_env = { .name = "env", - .version_id = 1, - .minimum_version_id = 1, + .version_id = 2, + .minimum_version_id = 2, .fields = vmstate_env_fields, }; diff --git a/qemu/target-alpha/mem_helper.c b/qemu/target-alpha/mem_helper.c index 7b5e30ddb..7fee9a6e2 100644 --- a/qemu/target-alpha/mem_helper.c +++ b/qemu/target-alpha/mem_helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" #include "exec/cpu_ldst.h" @@ -132,7 +133,7 @@ void alpha_cpu_unassigned_access(CPUState *cs, hwaddr addr, env->error_code = 0; /* ??? We should cpu_restore_state to the faulting insn, but this hook - does not have access to the retaddr value from the orignal helper. + does not have access to the retaddr value from the original helper. It's all moot until the QEMU PALcode grows an MCHK handler. */ cpu_loop_exit(cs); diff --git a/qemu/target-alpha/sys_helper.c b/qemu/target-alpha/sys_helper.c index 1c59e108b..e2dec15b6 100644 --- a/qemu/target-alpha/sys_helper.c +++ b/qemu/target-alpha/sys_helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" #include "sysemu/sysemu.h" @@ -34,34 +35,12 @@ uint64_t helper_load_pcc(CPUAlphaState *env) #else /* In user-mode, QEMU_CLOCK_VIRTUAL doesn't exist. Just pass through the host cpu clock ticks. Also, don't bother taking PCC_OFS into account. */ - return (uint32_t)cpu_get_real_ticks(); + return (uint32_t)cpu_get_host_ticks(); #endif } /* PALcode support special instructions */ #ifndef CONFIG_USER_ONLY -void helper_hw_ret(CPUAlphaState *env, uint64_t a) -{ - env->pc = a & ~3; - env->intr_flag = 0; - env->lock_addr = -1; - if ((a & 1) == 0) { - env->pal_mode = 0; - swap_shadow_regs(env); - } -} - -void helper_call_pal(CPUAlphaState *env, uint64_t pc, uint64_t entry_ofs) -{ - int pal_mode = env->pal_mode; - env->exc_addr = pc | pal_mode; - env->pc = env->palbr + entry_ofs; - if (!pal_mode) { - env->pal_mode = 1; - swap_shadow_regs(env); - } -} - void helper_tbia(CPUAlphaState *env) { tlb_flush(CPU(alpha_env_get_cpu(env)), 1); diff --git a/qemu/target-alpha/translate.c b/qemu/target-alpha/translate.c index 81d4ff827..5b86992dd 100644 --- a/qemu/target-alpha/translate.c +++ b/qemu/target-alpha/translate.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "disas/disas.h" #include "qemu/host-utils.h" @@ -27,6 +28,7 @@ #include "exec/helper-gen.h" #include "trace-tcg.h" +#include "exec/log.h" #undef ALPHA_DEBUG_DISAS @@ -42,6 +44,9 @@ typedef struct DisasContext DisasContext; struct DisasContext { struct TranslationBlock *tb; uint64_t pc; +#ifndef CONFIG_USER_ONLY + uint64_t palbr; +#endif int mem_idx; /* Current rounding mode for this TB. */ @@ -52,6 +57,9 @@ struct DisasContext { /* implver value for this CPU. */ int implver; + /* The set of registers active in the current context. */ + TCGv *ir; + /* Temporaries for $31 and $f31 as source and destination. */ TCGv zero; TCGv sink; @@ -85,14 +93,18 @@ typedef enum { } ExitStatus; /* global register indexes */ -static TCGv_ptr cpu_env; -static TCGv cpu_ir[31]; +static TCGv_env cpu_env; +static TCGv cpu_std_ir[31]; static TCGv cpu_fir[31]; static TCGv cpu_pc; static TCGv cpu_lock_addr; static TCGv cpu_lock_st_addr; static TCGv cpu_lock_value; +#ifndef CONFIG_USER_ONLY +static TCGv cpu_pal_ir[31]; +#endif + #include "exec/gen-icount.h" void alpha_translate_init(void) @@ -122,6 +134,12 @@ void alpha_translate_init(void) "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", "f24", "f25", "f26", "f27", "f28", "f29", "f30" }; +#ifndef CONFIG_USER_ONLY + static const char shadow_names[8][8] = { + "pal_t7", "pal_s0", "pal_s1", "pal_s2", + "pal_s3", "pal_s4", "pal_s5", "pal_t11" + }; +#endif static bool done_init = 0; int i; @@ -134,20 +152,31 @@ void alpha_translate_init(void) cpu_env = tcg_global_reg_new_ptr(TCG_AREG0, "env"); for (i = 0; i < 31; i++) { - cpu_ir[i] = tcg_global_mem_new_i64(TCG_AREG0, - offsetof(CPUAlphaState, ir[i]), - greg_names[i]); + cpu_std_ir[i] = tcg_global_mem_new_i64(cpu_env, + offsetof(CPUAlphaState, ir[i]), + greg_names[i]); } for (i = 0; i < 31; i++) { - cpu_fir[i] = tcg_global_mem_new_i64(TCG_AREG0, + cpu_fir[i] = tcg_global_mem_new_i64(cpu_env, offsetof(CPUAlphaState, fir[i]), freg_names[i]); } +#ifndef CONFIG_USER_ONLY + memcpy(cpu_pal_ir, cpu_std_ir, sizeof(cpu_pal_ir)); + for (i = 0; i < 8; i++) { + int r = (i == 7 ? 25 : i + 8); + cpu_pal_ir[r] = tcg_global_mem_new_i64(cpu_env, + offsetof(CPUAlphaState, + shadow[i]), + shadow_names[i]); + } +#endif + for (i = 0; i < ARRAY_SIZE(vars); ++i) { const GlobalVar *v = &vars[i]; - *v->var = tcg_global_mem_new_i64(TCG_AREG0, v->ofs, v->name); + *v->var = tcg_global_mem_new_i64(cpu_env, v->ofs, v->name); } } @@ -170,7 +199,7 @@ static TCGv dest_sink(DisasContext *ctx) static TCGv load_gpr(DisasContext *ctx, unsigned reg) { if (likely(reg < 31)) { - return cpu_ir[reg]; + return ctx->ir[reg]; } else { return load_zero(ctx); } @@ -183,7 +212,7 @@ static TCGv load_gpr_lit(DisasContext *ctx, unsigned reg, ctx->lit = tcg_const_i64(lit); return ctx->lit; } else if (likely(reg < 31)) { - return cpu_ir[reg]; + return ctx->ir[reg]; } else { return load_zero(ctx); } @@ -192,7 +221,7 @@ static TCGv load_gpr_lit(DisasContext *ctx, unsigned reg, static TCGv dest_gpr(DisasContext *ctx, unsigned reg) { if (likely(reg < 31)) { - return cpu_ir[reg]; + return ctx->ir[reg]; } else { return dest_sink(ctx); } @@ -304,7 +333,7 @@ static inline void gen_load_mem(DisasContext *ctx, addr = tmp; } - va = (fp ? cpu_fir[ra] : cpu_ir[ra]); + va = (fp ? cpu_fir[ra] : ctx->ir[ra]); tcg_gen_qemu_load(va, addr, ctx->mem_idx); tcg_temp_free(tmp); @@ -399,13 +428,13 @@ static ExitStatus gen_store_conditional(DisasContext *ctx, int ra, int rb, tcg_gen_qemu_ld_i64(val, addr, ctx->mem_idx, quad ? MO_LEQ : MO_LESL); tcg_gen_brcond_i64(TCG_COND_NE, val, cpu_lock_value, lab_fail); - tcg_gen_qemu_st_i64(cpu_ir[ra], addr, ctx->mem_idx, + tcg_gen_qemu_st_i64(ctx->ir[ra], addr, ctx->mem_idx, quad ? MO_LEQ : MO_LEUL); - tcg_gen_movi_i64(cpu_ir[ra], 1); + tcg_gen_movi_i64(ctx->ir[ra], 1); tcg_gen_br(lab_done); gen_set_label(lab_fail); - tcg_gen_movi_i64(cpu_ir[ra], 0); + tcg_gen_movi_i64(ctx->ir[ra], 0); gen_set_label(lab_done); tcg_gen_movi_i64(cpu_lock_addr, -1); @@ -444,7 +473,7 @@ static ExitStatus gen_bdirect(DisasContext *ctx, int ra, int32_t disp) uint64_t dest = ctx->pc + (disp << 2); if (ra != 31) { - tcg_gen_movi_i64(cpu_ir[ra], ctx->pc); + tcg_gen_movi_i64(ctx->ir[ra], ctx->pc); } /* Notice branch-to-next; used to initialize RA with the PC. */ @@ -1059,12 +1088,13 @@ static void gen_msk_l(DisasContext *ctx, TCGv vc, TCGv va, int rb, bool islit, } } -static void gen_rx(int ra, int set) +static void gen_rx(DisasContext *ctx, int ra, int set) { TCGv_i32 tmp; if (ra != 31) { - tcg_gen_ld8u_i64(cpu_ir[ra], cpu_env, offsetof(CPUAlphaState, intr_flag)); + tcg_gen_ld8u_i64(ctx->ir[ra], cpu_env, + offsetof(CPUAlphaState, intr_flag)); } tmp = tcg_const_i32(set); @@ -1086,12 +1116,12 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode) break; case 0x9E: /* RDUNIQUE */ - tcg_gen_ld_i64(cpu_ir[IR_V0], cpu_env, + tcg_gen_ld_i64(ctx->ir[IR_V0], cpu_env, offsetof(CPUAlphaState, unique)); break; case 0x9F: /* WRUNIQUE */ - tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env, + tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env, offsetof(CPUAlphaState, unique)); break; default: @@ -1115,17 +1145,17 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode) break; case 0x2D: /* WRVPTPTR */ - tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env, + tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env, offsetof(CPUAlphaState, vptptr)); break; case 0x31: /* WRVAL */ - tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env, + tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env, offsetof(CPUAlphaState, sysval)); break; case 0x32: /* RDVAL */ - tcg_gen_ld_i64(cpu_ir[IR_V0], cpu_env, + tcg_gen_ld_i64(ctx->ir[IR_V0], cpu_env, offsetof(CPUAlphaState, sysval)); break; @@ -1135,12 +1165,12 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode) /* Note that we already know we're in kernel mode, so we know that PS only contains the 3 IPL bits. */ - tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, + tcg_gen_ld8u_i64(ctx->ir[IR_V0], cpu_env, offsetof(CPUAlphaState, ps)); /* But make sure and store only the 3 IPL bits from the user. */ tmp = tcg_temp_new(); - tcg_gen_andi_i64(tmp, cpu_ir[IR_A0], PS_INT_MASK); + tcg_gen_andi_i64(tmp, ctx->ir[IR_A0], PS_INT_MASK); tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUAlphaState, ps)); tcg_temp_free(tmp); break; @@ -1148,22 +1178,22 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode) case 0x36: /* RDPS */ - tcg_gen_ld8u_i64(cpu_ir[IR_V0], cpu_env, + tcg_gen_ld8u_i64(ctx->ir[IR_V0], cpu_env, offsetof(CPUAlphaState, ps)); break; case 0x38: /* WRUSP */ - tcg_gen_st_i64(cpu_ir[IR_A0], cpu_env, + tcg_gen_st_i64(ctx->ir[IR_A0], cpu_env, offsetof(CPUAlphaState, usp)); break; case 0x3A: /* RDUSP */ - tcg_gen_ld_i64(cpu_ir[IR_V0], cpu_env, + tcg_gen_ld_i64(ctx->ir[IR_V0], cpu_env, offsetof(CPUAlphaState, usp)); break; case 0x3C: /* WHAMI */ - tcg_gen_ld32s_i64(cpu_ir[IR_V0], cpu_env, + tcg_gen_ld32s_i64(ctx->ir[IR_V0], cpu_env, -offsetof(AlphaCPU, env) + offsetof(CPUState, cpu_index)); break; @@ -1181,15 +1211,24 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode) return gen_excp(ctx, EXCP_CALL_PAL, palcode); #else { - TCGv pc = tcg_const_i64(ctx->pc); - TCGv entry = tcg_const_i64(palcode & 0x80 - ? 0x2000 + (palcode - 0x80) * 64 - : 0x1000 + palcode * 64); + TCGv tmp = tcg_temp_new(); + uint64_t exc_addr = ctx->pc; + uint64_t entry = ctx->palbr; - gen_helper_call_pal(cpu_env, pc, entry); + if (ctx->tb->flags & TB_FLAGS_PAL_MODE) { + exc_addr |= 1; + } else { + tcg_gen_movi_i64(tmp, 1); + tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUAlphaState, pal_mode)); + } + + tcg_gen_movi_i64(tmp, exc_addr); + tcg_gen_st_i64(tmp, cpu_env, offsetof(CPUAlphaState, exc_addr)); + tcg_temp_free(tmp); - tcg_temp_free(entry); - tcg_temp_free(pc); + entry += (palcode & 0x80 + ? 0x2000 + (palcode - 0x80) * 64 + : 0x1000 + palcode * 64); /* Since the destination is running in PALmode, we don't really need the page permissions check. We'll see the existence of @@ -1197,11 +1236,13 @@ static ExitStatus gen_call_pal(DisasContext *ctx, int palcode) we change the PAL base register. */ if (!ctx->singlestep_enabled && !(ctx->tb->cflags & CF_LAST_IO)) { tcg_gen_goto_tb(0); + tcg_gen_movi_i64(cpu_pc, entry); tcg_gen_exit_tb((uintptr_t)ctx->tb); return EXIT_GOTO_TB; + } else { + tcg_gen_movi_i64(cpu_pc, entry); + return EXIT_PC_UPDATED; } - - return EXIT_PC_UPDATED; } #endif } @@ -1228,8 +1269,6 @@ static int cpu_pr_data(int pr) case 11: return offsetof(CPUAlphaState, sysval); case 12: return offsetof(CPUAlphaState, usp); - case 32 ... 39: - return offsetof(CPUAlphaState, shadow[pr - 32]); case 40 ... 63: return offsetof(CPUAlphaState, scratch[pr - 40]); @@ -1241,36 +1280,48 @@ static int cpu_pr_data(int pr) static ExitStatus gen_mfpr(DisasContext *ctx, TCGv va, int regno) { - int data = cpu_pr_data(regno); - - /* Special help for VMTIME and WALLTIME. */ - if (regno == 250 || regno == 249) { - void (*helper)(TCGv) = gen_helper_get_walltime; - if (regno == 249) { - helper = gen_helper_get_vmtime; - } - if (ctx->tb->cflags & CF_USE_ICOUNT) { + void (*helper)(TCGv); + int data; + + switch (regno) { + case 32 ... 39: + /* Accessing the "non-shadow" general registers. */ + regno = regno == 39 ? 25 : regno - 32 + 8; + tcg_gen_mov_i64(va, cpu_std_ir[regno]); + break; + + case 250: /* WALLTIME */ + helper = gen_helper_get_walltime; + goto do_helper; + case 249: /* VMTIME */ + helper = gen_helper_get_vmtime; + do_helper: + if (use_icount) { gen_io_start(); helper(va); gen_io_end(); return EXIT_PC_STALE; } else { helper(va); - return NO_EXIT; } - } + break; - /* The basic registers are data only, and unknown registers - are read-zero, write-ignore. */ - if (data == 0) { - tcg_gen_movi_i64(va, 0); - } else if (data & PR_BYTE) { - tcg_gen_ld8u_i64(va, cpu_env, data & ~PR_BYTE); - } else if (data & PR_LONG) { - tcg_gen_ld32s_i64(va, cpu_env, data & ~PR_LONG); - } else { - tcg_gen_ld_i64(va, cpu_env, data); + default: + /* The basic registers are data only, and unknown registers + are read-zero, write-ignore. */ + data = cpu_pr_data(regno); + if (data == 0) { + tcg_gen_movi_i64(va, 0); + } else if (data & PR_BYTE) { + tcg_gen_ld8u_i64(va, cpu_env, data & ~PR_BYTE); + } else if (data & PR_LONG) { + tcg_gen_ld32s_i64(va, cpu_env, data & ~PR_LONG); + } else { + tcg_gen_ld_i64(va, cpu_env, data); + } + break; } + return NO_EXIT; } @@ -1316,6 +1367,12 @@ static ExitStatus gen_mtpr(DisasContext *ctx, TCGv vb, int regno) gen_helper_tb_flush(cpu_env); return EXIT_PC_STALE; + case 32 ... 39: + /* Accessing the "non-shadow" general registers. */ + regno = regno == 39 ? 25 : regno - 32 + 8; + tcg_gen_mov_i64(cpu_std_ir[regno], vb); + break; + default: /* The basic registers are data only, and unknown registers are read-zero, write-ignore. */ @@ -1507,7 +1564,12 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) break; case 0x0F: /* CMPBGE */ - gen_helper_cmpbge(vc, va, vb); + if (ra == 31) { + /* Special case 0 >= X as X == 0. */ + gen_helper_cmpbe0(vc, vb); + } else { + gen_helper_cmpbge(vc, va, vb); + } break; case 0x12: /* S8ADDL */ @@ -1952,7 +2014,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) REQUIRE_REG_31(rb); t32 = tcg_temp_new_i32(); va = load_gpr(ctx, ra); - tcg_gen_trunc_i64_i32(t32, va); + tcg_gen_extrl_i64_i32(t32, va); gen_helper_memory_to_s(vc, t32); tcg_temp_free_i32(t32); break; @@ -1972,7 +2034,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) REQUIRE_REG_31(rb); t32 = tcg_temp_new_i32(); va = load_gpr(ctx, ra); - tcg_gen_trunc_i64_i32(t32, va); + tcg_gen_extrl_i64_i32(t32, va); gen_helper_memory_to_f(vc, t32); tcg_temp_free_i32(t32); break; @@ -2295,14 +2357,14 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) break; case 0xE000: /* RC */ - gen_rx(ra, 0); + gen_rx(ctx, ra, 0); break; case 0xE800: /* ECB */ break; case 0xF000: /* RS */ - gen_rx(ra, 1); + gen_rx(ctx, ra, 1); break; case 0xF800: /* WH64 */ @@ -2334,7 +2396,7 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) vb = load_gpr(ctx, rb); tcg_gen_andi_i64(cpu_pc, vb, ~3); if (ra != 31) { - tcg_gen_movi_i64(cpu_ir[ra], ctx->pc); + tcg_gen_movi_i64(ctx->ir[ra], ctx->pc); } ret = EXIT_PC_UPDATED; break; @@ -2374,10 +2436,10 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) goto invalid_opc; break; case 0x6: - /* Incpu_ir[ra]id */ + /* Invalid */ goto invalid_opc; case 0x7: - /* Incpu_ir[ra]id */ + /* Invaliid */ goto invalid_opc; case 0x8: /* Longword virtual access (hw_ldl) */ @@ -2580,13 +2642,18 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) /* Pre-EV6 CPUs interpreted this as HW_REI, loading the return address from EXC_ADDR. This turns out to be useful for our emulation PALcode, so continue to accept it. */ - tmp = tcg_temp_new(); - tcg_gen_ld_i64(tmp, cpu_env, offsetof(CPUAlphaState, exc_addr)); - gen_helper_hw_ret(cpu_env, tmp); - tcg_temp_free(tmp); + ctx->lit = vb = tcg_temp_new(); + tcg_gen_ld_i64(vb, cpu_env, offsetof(CPUAlphaState, exc_addr)); } else { - gen_helper_hw_ret(cpu_env, load_gpr(ctx, rb)); + vb = load_gpr(ctx, rb); } + tmp = tcg_temp_new(); + tcg_gen_movi_i64(tmp, 0); + tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUAlphaState, intr_flag)); + tcg_gen_movi_i64(cpu_lock_addr, -1); + tcg_gen_andi_i64(tmp, vb, 1); + tcg_gen_st8_i64(tmp, cpu_env, offsetof(CPUAlphaState, pal_mode)); + tcg_gen_andi_i64(cpu_pc, vb, ~3); ret = EXIT_PC_UPDATED; break; #else @@ -2793,18 +2860,14 @@ static ExitStatus translate_one(DisasContext *ctx, uint32_t insn) return ret; } -static inline void gen_intermediate_code_internal(AlphaCPU *cpu, - TranslationBlock *tb, - bool search_pc) +void gen_intermediate_code(CPUAlphaState *env, struct TranslationBlock *tb) { + AlphaCPU *cpu = alpha_env_get_cpu(env); CPUState *cs = CPU(cpu); - CPUAlphaState *env = &cpu->env; DisasContext ctx, *ctxp = &ctx; target_ulong pc_start; target_ulong pc_mask; uint32_t insn; - CPUBreakpoint *bp; - int j, lj = -1; ExitStatus ret; int num_insns; int max_insns; @@ -2813,10 +2876,17 @@ static inline void gen_intermediate_code_internal(AlphaCPU *cpu, ctx.tb = tb; ctx.pc = pc_start; - ctx.mem_idx = cpu_mmu_index(env); + ctx.mem_idx = cpu_mmu_index(env, false); ctx.implver = env->implver; ctx.singlestep_enabled = cs->singlestep_enabled; +#ifdef CONFIG_USER_ONLY + ctx.ir = cpu_std_ir; +#else + ctx.palbr = env->palbr; + ctx.ir = (tb->flags & TB_FLAGS_PAL_MODE ? cpu_pal_ir : cpu_std_ir); +#endif + /* ??? Every TB begins with unset rounding mode, to be initialized on the first fp insn of the TB. Alternately we could define a proper default for every TB (e.g. QUAL_RM_N or QUAL_RM_D) and make sure @@ -2832,6 +2902,9 @@ static inline void gen_intermediate_code_internal(AlphaCPU *cpu, if (max_insns == 0) { max_insns = CF_COUNT_MASK; } + if (max_insns > TCG_MAX_INSNS) { + max_insns = TCG_MAX_INSNS; + } if (in_superpage(&ctx, pc_start)) { pc_mask = (1ULL << 41) - 1; @@ -2841,35 +2914,22 @@ static inline void gen_intermediate_code_internal(AlphaCPU *cpu, gen_tb_start(tb); do { - if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) { - QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { - if (bp->pc == ctx.pc) { - gen_excp(&ctx, EXCP_DEBUG, 0); - break; - } - } - } - if (search_pc) { - j = tcg_op_buf_count(); - if (lj < j) { - lj++; - while (lj < j) { - tcg_ctx.gen_opc_instr_start[lj++] = 0; - } - } - tcg_ctx.gen_opc_pc[lj] = ctx.pc; - tcg_ctx.gen_opc_instr_start[lj] = 1; - tcg_ctx.gen_opc_icount[lj] = num_insns; + tcg_gen_insn_start(ctx.pc); + num_insns++; + + if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) { + ret = gen_excp(&ctx, EXCP_DEBUG, 0); + /* The address covered by the breakpoint must be included in + [tb->pc, tb->pc + tb->size) in order to for it to be + properly cleared -- thus we increment the PC here so that + the logic setting tb->size below does the right thing. */ + ctx.pc += 4; + break; } - if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO)) { + if (num_insns == max_insns && (tb->cflags & CF_LAST_IO)) { gen_io_start(); } insn = cpu_ldl_code(env, ctx.pc); - num_insns++; - - if (unlikely(qemu_loglevel_mask(CPU_LOG_TB_OP | CPU_LOG_TB_OP_OPT))) { - tcg_gen_debug_insn_start(ctx.pc); - } TCGV_UNUSED_I64(ctx.zero); TCGV_UNUSED_I64(ctx.sink); @@ -2925,16 +2985,8 @@ static inline void gen_intermediate_code_internal(AlphaCPU *cpu, gen_tb_end(tb, num_insns); - if (search_pc) { - j = tcg_op_buf_count(); - lj++; - while (lj <= j) { - tcg_ctx.gen_opc_instr_start[lj++] = 0; - } - } else { - tb->size = ctx.pc - pc_start; - tb->icount = num_insns; - } + tb->size = ctx.pc - pc_start; + tb->icount = num_insns; #ifdef DEBUG_DISAS if (qemu_loglevel_mask(CPU_LOG_TB_IN_ASM)) { @@ -2945,17 +2997,8 @@ static inline void gen_intermediate_code_internal(AlphaCPU *cpu, #endif } -void gen_intermediate_code (CPUAlphaState *env, struct TranslationBlock *tb) -{ - gen_intermediate_code_internal(alpha_env_get_cpu(env), tb, false); -} - -void gen_intermediate_code_pc (CPUAlphaState *env, struct TranslationBlock *tb) -{ - gen_intermediate_code_internal(alpha_env_get_cpu(env), tb, true); -} - -void restore_state_to_opc(CPUAlphaState *env, TranslationBlock *tb, int pc_pos) +void restore_state_to_opc(CPUAlphaState *env, TranslationBlock *tb, + target_ulong *data) { - env->pc = tcg_ctx.gen_opc_pc[pc_pos]; + env->pc = data[0]; } diff --git a/qemu/target-alpha/vax_helper.c b/qemu/target-alpha/vax_helper.c index 2e2f49971..e74ac3e04 100644 --- a/qemu/target-alpha/vax_helper.c +++ b/qemu/target-alpha/vax_helper.c @@ -17,6 +17,7 @@ * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include "qemu/osdep.h" #include "cpu.h" #include "exec/helper-proto.h" #include "fpu/softfloat.h" |