Commit 9fddaa0c0cabb610947146a79b4a9a38b0a216e5
1 parent
4a0fb71e
PowerPC merge: real time TB and decrementer - faster and simpler exception handling (Jocelyn Mayer)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@841 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
14 changed files
with
463 additions
and
297 deletions
cpu-all.h
| ... | ... | @@ -627,14 +627,15 @@ void cpu_single_step(CPUState *env, int enabled); |
| 627 | 627 | if no page found. */ |
| 628 | 628 | target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr); |
| 629 | 629 | |
| 630 | -#define CPU_LOG_TB_OUT_ASM (1 << 0) | |
| 631 | -#define CPU_LOG_TB_IN_ASM (1 << 1) | |
| 630 | +#define CPU_LOG_TB_OUT_ASM (1 << 0) | |
| 631 | +#define CPU_LOG_TB_IN_ASM (1 << 1) | |
| 632 | 632 | #define CPU_LOG_TB_OP (1 << 2) |
| 633 | 633 | #define CPU_LOG_TB_OP_OPT (1 << 3) |
| 634 | 634 | #define CPU_LOG_INT (1 << 4) |
| 635 | 635 | #define CPU_LOG_EXEC (1 << 5) |
| 636 | 636 | #define CPU_LOG_PCALL (1 << 6) |
| 637 | 637 | #define CPU_LOG_IOPORT (1 << 7) |
| 638 | +#define CPU_LOG_TB_CPU (1 << 8) | |
| 638 | 639 | |
| 639 | 640 | /* define log items */ |
| 640 | 641 | typedef struct CPULogItem { | ... | ... |
cpu-exec.c
| ... | ... | @@ -241,11 +241,25 @@ int cpu_exec(CPUState *env1) |
| 241 | 241 | #endif |
| 242 | 242 | } |
| 243 | 243 | #elif defined(TARGET_PPC) |
| 244 | +#if 0 | |
| 245 | + if ((interrupt_request & CPU_INTERRUPT_RESET)) { | |
| 246 | + cpu_ppc_reset(env); | |
| 247 | + } | |
| 248 | +#endif | |
| 249 | + if (msr_ee != 0) { | |
| 244 | 250 | if ((interrupt_request & CPU_INTERRUPT_HARD)) { |
| 245 | - do_queue_exception(EXCP_EXTERNAL); | |
| 246 | - if (check_exception_state(env)) | |
| 251 | + /* Raise it */ | |
| 252 | + env->exception_index = EXCP_EXTERNAL; | |
| 253 | + env->error_code = 0; | |
| 247 | 254 | do_interrupt(env); |
| 248 | 255 | env->interrupt_request &= ~CPU_INTERRUPT_HARD; |
| 256 | + } else if ((interrupt_request & CPU_INTERRUPT_TIMER)) { | |
| 257 | + /* Raise it */ | |
| 258 | + env->exception_index = EXCP_DECR; | |
| 259 | + env->error_code = 0; | |
| 260 | + do_interrupt(env); | |
| 261 | + env->interrupt_request &= ~CPU_INTERRUPT_TIMER; | |
| 262 | + } | |
| 249 | 263 | } |
| 250 | 264 | #endif |
| 251 | 265 | if (interrupt_request & CPU_INTERRUPT_EXITTB) { |
| ... | ... | @@ -757,7 +771,7 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, |
| 757 | 771 | /* we restore the process signal mask as the sigreturn should |
| 758 | 772 | do it (XXX: use sigsetjmp) */ |
| 759 | 773 | sigprocmask(SIG_SETMASK, old_set, NULL); |
| 760 | - do_queue_exception_err(env->exception_index, env->error_code); | |
| 774 | + do_raise_exception_err(env->exception_index, env->error_code); | |
| 761 | 775 | } else { |
| 762 | 776 | /* activate soft MMU for this block */ |
| 763 | 777 | cpu_resume_from_signal(env, puc); | ... | ... |
exec.c
| ... | ... | @@ -1132,6 +1132,8 @@ CPULogItem cpu_log_items[] = { |
| 1132 | 1132 | "show interrupts/exceptions in short format" }, |
| 1133 | 1133 | { CPU_LOG_EXEC, "exec", |
| 1134 | 1134 | "show trace before each executed TB (lots of logs)" }, |
| 1135 | + { CPU_LOG_TB_CPU, "cpu", | |
| 1136 | + "show CPU state before bloc translation" }, | |
| 1135 | 1137 | #ifdef TARGET_I386 |
| 1136 | 1138 | { CPU_LOG_PCALL, "pcall", |
| 1137 | 1139 | "show protected mode far calls/returns/exceptions" }, | ... | ... |
hw/ppc.c
| ... | ... | @@ -28,6 +28,181 @@ void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device, |
| 28 | 28 | const char *kernel_filename, const char *kernel_cmdline, |
| 29 | 29 | const char *initrd_filename); |
| 30 | 30 | |
| 31 | +/*****************************************************************************/ | |
| 32 | +/* PPC time base and decrementer emulation */ | |
| 33 | +//#define DEBUG_TB | |
| 34 | + | |
| 35 | +struct ppc_tb_t { | |
| 36 | + /* Time base management */ | |
| 37 | + int64_t tb_offset; /* Compensation */ | |
| 38 | + uint32_t tb_freq; /* TB frequency */ | |
| 39 | + /* Decrementer management */ | |
| 40 | + uint64_t decr_next; /* Tick for next decr interrupt */ | |
| 41 | + struct QEMUTimer *decr_timer; | |
| 42 | +}; | |
| 43 | + | |
| 44 | +static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env) | |
| 45 | +{ | |
| 46 | + /* TB time in tb periods */ | |
| 47 | + return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset, | |
| 48 | + tb_env->tb_freq, ticks_per_sec); | |
| 49 | +} | |
| 50 | + | |
| 51 | +uint32_t cpu_ppc_load_tbl (CPUState *env) | |
| 52 | +{ | |
| 53 | + ppc_tb_t *tb_env = env->tb_env; | |
| 54 | + uint64_t tb; | |
| 55 | + | |
| 56 | + tb = cpu_ppc_get_tb(tb_env); | |
| 57 | +#ifdef DEBUG_TB | |
| 58 | + { | |
| 59 | + static int last_time; | |
| 60 | + int now; | |
| 61 | + now = time(NULL); | |
| 62 | + if (last_time != now) { | |
| 63 | + last_time = now; | |
| 64 | + printf("%s: tb=0x%016lx %d %08lx\n", | |
| 65 | + __func__, tb, now, tb_env->tb_offset); | |
| 66 | + } | |
| 67 | + } | |
| 68 | +#endif | |
| 69 | + | |
| 70 | + return tb & 0xFFFFFFFF; | |
| 71 | +} | |
| 72 | + | |
| 73 | +uint32_t cpu_ppc_load_tbu (CPUState *env) | |
| 74 | +{ | |
| 75 | + ppc_tb_t *tb_env = env->tb_env; | |
| 76 | + uint64_t tb; | |
| 77 | + | |
| 78 | + tb = cpu_ppc_get_tb(tb_env); | |
| 79 | +#ifdef DEBUG_TB | |
| 80 | + printf("%s: tb=0x%016lx\n", __func__, tb); | |
| 81 | +#endif | |
| 82 | + return tb >> 32; | |
| 83 | +} | |
| 84 | + | |
| 85 | +static void cpu_ppc_store_tb (ppc_tb_t *tb_env, uint64_t value) | |
| 86 | +{ | |
| 87 | + tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq) | |
| 88 | + - qemu_get_clock(vm_clock); | |
| 89 | +#ifdef DEBUG_TB | |
| 90 | + printf("%s: tb=0x%016lx offset=%08x\n", __func__, value); | |
| 91 | +#endif | |
| 92 | +} | |
| 93 | + | |
| 94 | +void cpu_ppc_store_tbu (CPUState *env, uint32_t value) | |
| 95 | +{ | |
| 96 | + ppc_tb_t *tb_env = env->tb_env; | |
| 97 | + | |
| 98 | + cpu_ppc_store_tb(tb_env, | |
| 99 | + ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); | |
| 100 | +} | |
| 101 | + | |
| 102 | +void cpu_ppc_store_tbl (CPUState *env, uint32_t value) | |
| 103 | +{ | |
| 104 | + ppc_tb_t *tb_env = env->tb_env; | |
| 105 | + | |
| 106 | + cpu_ppc_store_tb(tb_env, | |
| 107 | + ((uint64_t)cpu_ppc_load_tbu(env) << 32) | value); | |
| 108 | +} | |
| 109 | + | |
| 110 | +uint32_t cpu_ppc_load_decr (CPUState *env) | |
| 111 | +{ | |
| 112 | + ppc_tb_t *tb_env = env->tb_env; | |
| 113 | + uint32_t decr; | |
| 114 | + | |
| 115 | + decr = muldiv64(tb_env->decr_next - qemu_get_clock(vm_clock), | |
| 116 | + tb_env->tb_freq, ticks_per_sec); | |
| 117 | +#ifdef DEBUG_TB | |
| 118 | + printf("%s: 0x%08x\n", __func__, decr); | |
| 119 | +#endif | |
| 120 | + | |
| 121 | + return decr; | |
| 122 | +} | |
| 123 | + | |
| 124 | +/* When decrementer expires, | |
| 125 | + * all we need to do is generate or queue a CPU exception | |
| 126 | + */ | |
| 127 | +static inline void cpu_ppc_decr_excp (CPUState *env) | |
| 128 | +{ | |
| 129 | + /* Raise it */ | |
| 130 | +#ifdef DEBUG_TB | |
| 131 | + printf("raise decrementer exception\n"); | |
| 132 | +#endif | |
| 133 | + cpu_interrupt(env, CPU_INTERRUPT_TIMER); | |
| 134 | +} | |
| 135 | + | |
| 136 | +static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr, | |
| 137 | + uint32_t value, int is_excp) | |
| 138 | +{ | |
| 139 | + ppc_tb_t *tb_env = env->tb_env; | |
| 140 | + uint64_t now, next; | |
| 141 | + | |
| 142 | +#ifdef DEBUG_TB | |
| 143 | + printf("%s: 0x%08x => 0x%08x\n", __func__, decr, value); | |
| 144 | +#endif | |
| 145 | + now = qemu_get_clock(vm_clock); | |
| 146 | + next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq); | |
| 147 | + if (is_excp) | |
| 148 | + next += tb_env->decr_next - now; | |
| 149 | + if (next == now) | |
| 150 | + next++; | |
| 151 | + tb_env->decr_next = next; | |
| 152 | + /* Adjust timer */ | |
| 153 | + qemu_mod_timer(tb_env->decr_timer, next); | |
| 154 | + /* If we set a negative value and the decrementer was positive, | |
| 155 | + * raise an exception. | |
| 156 | + */ | |
| 157 | + if ((value & 0x80000000) && !(decr & 0x80000000)) | |
| 158 | + cpu_ppc_decr_excp(env); | |
| 159 | +} | |
| 160 | + | |
| 161 | +void cpu_ppc_store_decr (CPUState *env, uint32_t value) | |
| 162 | +{ | |
| 163 | + _cpu_ppc_store_decr(env, cpu_ppc_load_decr(env), value, 0); | |
| 164 | +} | |
| 165 | + | |
| 166 | +static void cpu_ppc_decr_cb (void *opaque) | |
| 167 | +{ | |
| 168 | + _cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1); | |
| 169 | +} | |
| 170 | + | |
| 171 | +/* Set up (once) timebase frequency (in Hz) */ | |
| 172 | +ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq) | |
| 173 | +{ | |
| 174 | + ppc_tb_t *tb_env; | |
| 175 | + | |
| 176 | + tb_env = qemu_mallocz(sizeof(ppc_tb_t)); | |
| 177 | + if (tb_env == NULL) | |
| 178 | + return NULL; | |
| 179 | + env->tb_env = tb_env; | |
| 180 | + if (tb_env->tb_freq == 0 || 1) { | |
| 181 | + tb_env->tb_freq = freq; | |
| 182 | + /* Create new timer */ | |
| 183 | + tb_env->decr_timer = | |
| 184 | + qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env); | |
| 185 | + /* There is a bug in 2.4 kernels: | |
| 186 | + * if a decrementer exception is pending when it enables msr_ee, | |
| 187 | + * it's not ready to handle it... | |
| 188 | + */ | |
| 189 | + _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0); | |
| 190 | + } | |
| 191 | + | |
| 192 | + return tb_env; | |
| 193 | +} | |
| 194 | + | |
| 195 | +#if 0 | |
| 196 | +/*****************************************************************************/ | |
| 197 | +/* Handle system reset (for now, just stop emulation) */ | |
| 198 | +void cpu_ppc_reset (CPUState *env) | |
| 199 | +{ | |
| 200 | + printf("Reset asked... Stop emulation\n"); | |
| 201 | + abort(); | |
| 202 | +} | |
| 203 | +#endif | |
| 204 | + | |
| 205 | +/*****************************************************************************/ | |
| 31 | 206 | void ppc_init (int ram_size, int vga_ram_size, int boot_device, |
| 32 | 207 | DisplayState *ds, const char **fd_filename, int snapshot, |
| 33 | 208 | const char *kernel_filename, const char *kernel_cmdline, | ... | ... |
hw/ppc_prep.c
| ... | ... | @@ -24,6 +24,9 @@ |
| 24 | 24 | #include "vl.h" |
| 25 | 25 | #include "m48t59.h" |
| 26 | 26 | |
| 27 | +/* XXX: move all TB related stuff in ppc_prep.c and suppress ppc.c ? */ | |
| 28 | +ppc_tb_t *cpu_ppc_tb_init (CPUPPCState *env, uint32_t freq); | |
| 29 | + | |
| 27 | 30 | //#define HARD_DEBUG_PPC_IO |
| 28 | 31 | //#define DEBUG_PPC_IO |
| 29 | 32 | |
| ... | ... | @@ -663,7 +666,6 @@ static void VGA_printf (uint8_t *s) |
| 663 | 666 | static void VGA_init (void) |
| 664 | 667 | { |
| 665 | 668 | /* Basic VGA init, inspired by plex86 VGAbios */ |
| 666 | - printf("Init VGA...\n"); | |
| 667 | 669 | #if 1 |
| 668 | 670 | /* switch to color mode and enable CPU access 480 lines */ |
| 669 | 671 | PPC_io_writeb(PPC_IO_BASE + 0x3C2, 0xC3); |
| ... | ... | @@ -725,7 +727,6 @@ void PPC_init_hw (/*CPUPPCState *env,*/ uint32_t mem_size, |
| 725 | 727 | * if a decrementer exception is pending when it enables msr_ee, |
| 726 | 728 | * it's not ready to handle it... |
| 727 | 729 | */ |
| 728 | - env->decr = 0xFFFFFFFF; | |
| 729 | 730 | p = phys_ram_base + kernel_addr; |
| 730 | 731 | #if !defined (USE_OPEN_FIRMWARE) |
| 731 | 732 | /* Let's register the whole memory available only in supervisor mode */ |
| ... | ... | @@ -948,6 +949,8 @@ void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device, |
| 948 | 949 | } |
| 949 | 950 | } |
| 950 | 951 | |
| 952 | + cpu_ppc_tb_init(cpu_single_env, 100UL * 1000UL * 1000UL); | |
| 953 | + | |
| 951 | 954 | /* init basic PC hardware */ |
| 952 | 955 | vga_initialize(ds, phys_ram_base + ram_size, ram_size, |
| 953 | 956 | vga_ram_size, 0); | ... | ... |
linux-user/main.c
| ... | ... | @@ -504,6 +504,49 @@ void cpu_loop (CPUSPARCState *env) |
| 504 | 504 | #endif |
| 505 | 505 | |
| 506 | 506 | #ifdef TARGET_PPC |
| 507 | + | |
| 508 | +static inline uint64_t cpu_ppc_get_tb (CPUState *env) | |
| 509 | +{ | |
| 510 | + /* TO FIX */ | |
| 511 | + return 0; | |
| 512 | +} | |
| 513 | + | |
| 514 | +uint32_t cpu_ppc_load_tbl (CPUState *env) | |
| 515 | +{ | |
| 516 | + return cpu_ppc_get_tb(env) & 0xFFFFFFFF; | |
| 517 | +} | |
| 518 | + | |
| 519 | +uint32_t cpu_ppc_load_tbu (CPUState *env) | |
| 520 | +{ | |
| 521 | + return cpu_ppc_get_tb(env) >> 32; | |
| 522 | +} | |
| 523 | + | |
| 524 | +static void cpu_ppc_store_tb (CPUState *env, uint64_t value) | |
| 525 | +{ | |
| 526 | + /* TO FIX */ | |
| 527 | +} | |
| 528 | + | |
| 529 | +void cpu_ppc_store_tbu (CPUState *env, uint32_t value) | |
| 530 | +{ | |
| 531 | + cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env)); | |
| 532 | +} | |
| 533 | + | |
| 534 | +void cpu_ppc_store_tbl (CPUState *env, uint32_t value) | |
| 535 | +{ | |
| 536 | + cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value); | |
| 537 | +} | |
| 538 | + | |
| 539 | +uint32_t cpu_ppc_load_decr (CPUState *env) | |
| 540 | +{ | |
| 541 | + /* TO FIX */ | |
| 542 | + return -1; | |
| 543 | +} | |
| 544 | + | |
| 545 | +void cpu_ppc_store_decr (CPUState *env, uint32_t value) | |
| 546 | +{ | |
| 547 | + /* TO FIX */ | |
| 548 | +} | |
| 549 | + | |
| 507 | 550 | void cpu_loop(CPUPPCState *env) |
| 508 | 551 | { |
| 509 | 552 | target_siginfo_t info; |
| ... | ... | @@ -812,7 +855,7 @@ void cpu_loop(CPUPPCState *env) |
| 812 | 855 | abort(); |
| 813 | 856 | case EXCP_MTMSR: |
| 814 | 857 | /* We reloaded the msr, just go on */ |
| 815 | - if (msr_pr) { | |
| 858 | + if (msr_pr == 0) { | |
| 816 | 859 | fprintf(stderr, "Tried to go into supervisor mode !\n"); |
| 817 | 860 | if (loglevel) |
| 818 | 861 | fprintf(logfile, "Tried to go into supervisor mode !\n"); |
| ... | ... | @@ -842,12 +885,7 @@ void cpu_loop(CPUPPCState *env) |
| 842 | 885 | } |
| 843 | 886 | abort(); |
| 844 | 887 | } |
| 845 | - if (trapnr < EXCP_PPC_MAX) | |
| 846 | - env->exceptions &= ~(1 << trapnr); | |
| 847 | 888 | process_pending_signals(env); |
| 848 | - if (env->exceptions != 0) { | |
| 849 | - check_exception_state(env); | |
| 850 | - } | |
| 851 | 889 | } |
| 852 | 890 | } |
| 853 | 891 | #endif | ... | ... |
monitor.c
| ... | ... | @@ -589,6 +589,24 @@ static int monitor_get_xer (struct MonitorDef *md) |
| 589 | 589 | (cpu_single_env->xer[XER_CA] << XER_CA) | |
| 590 | 590 | (cpu_single_env->xer[XER_BC] << XER_BC); |
| 591 | 591 | } |
| 592 | + | |
| 593 | +uint32_t cpu_ppc_load_decr (CPUState *env); | |
| 594 | +static int monitor_get_decr (struct MonitorDef *md) | |
| 595 | +{ | |
| 596 | + return cpu_ppc_load_decr(cpu_single_env); | |
| 597 | +} | |
| 598 | + | |
| 599 | +uint32_t cpu_ppc_load_tbu (CPUState *env); | |
| 600 | +static int monitor_get_tbu (struct MonitorDef *md) | |
| 601 | +{ | |
| 602 | + return cpu_ppc_load_tbu(cpu_single_env); | |
| 603 | +} | |
| 604 | + | |
| 605 | +uint32_t cpu_ppc_load_tbl (CPUState *env); | |
| 606 | +static int monitor_get_tbl (struct MonitorDef *md) | |
| 607 | +{ | |
| 608 | + return cpu_ppc_load_tbl(cpu_single_env); | |
| 609 | +} | |
| 592 | 610 | #endif |
| 593 | 611 | |
| 594 | 612 | static MonitorDef monitor_defs[] = { |
| ... | ... | @@ -651,12 +669,12 @@ static MonitorDef monitor_defs[] = { |
| 651 | 669 | { "nip|pc", offsetof(CPUState, nip) }, |
| 652 | 670 | { "lr", offsetof(CPUState, lr) }, |
| 653 | 671 | { "ctr", offsetof(CPUState, ctr) }, |
| 654 | - { "decr", offsetof(CPUState, decr) }, | |
| 672 | + { "decr", 0, &monitor_get_decr, }, | |
| 655 | 673 | { "ccr", 0, &monitor_get_ccr, }, |
| 656 | 674 | { "msr", 0, &monitor_get_msr, }, |
| 657 | 675 | { "xer", 0, &monitor_get_xer, }, |
| 658 | - { "tbu", offsetof(CPUState, tb[0]) }, | |
| 659 | - { "tbl", offsetof(CPUState, tb[1]) }, | |
| 676 | + { "tbu", 0, &monitor_get_tbu, }, | |
| 677 | + { "tbl", 0, &monitor_get_tbl, }, | |
| 660 | 678 | { "sdr1", offsetof(CPUState, sdr1) }, |
| 661 | 679 | { "sr0", offsetof(CPUState, sr[0]) }, |
| 662 | 680 | { "sr1", offsetof(CPUState, sr[1]) }, | ... | ... |
target-ppc/cpu.h
| ... | ... | @@ -78,6 +78,8 @@ enum { |
| 78 | 78 | #define PPC_750 (PPC_INTEGER | PPC_FLOAT | PPC_FLOW | PPC_MEM | \ |
| 79 | 79 | PPC_RES | PPC_CACHE | PPC_MISC | PPC_EXTERN | PPC_SEGMENT) |
| 80 | 80 | |
| 81 | +typedef struct ppc_tb_t ppc_tb_t; | |
| 82 | + | |
| 81 | 83 | /* Supervisor mode registers */ |
| 82 | 84 | /* Machine state register */ |
| 83 | 85 | #define MSR_POW 18 |
| ... | ... | @@ -134,10 +136,6 @@ typedef struct CPUPPCState { |
| 134 | 136 | /* special purpose registers */ |
| 135 | 137 | uint32_t lr; |
| 136 | 138 | uint32_t ctr; |
| 137 | - /* Time base */ | |
| 138 | - uint32_t tb[2]; | |
| 139 | - /* decrementer */ | |
| 140 | - uint32_t decr; | |
| 141 | 139 | /* BATs */ |
| 142 | 140 | uint32_t DBAT[2][8]; |
| 143 | 141 | uint32_t IBAT[2][8]; |
| ... | ... | @@ -154,13 +152,6 @@ typedef struct CPUPPCState { |
| 154 | 152 | int error_code; |
| 155 | 153 | int access_type; /* when a memory exception occurs, the access |
| 156 | 154 | type is stored here */ |
| 157 | -#if 0 /* TODO */ | |
| 158 | - uint32_t pending_exceptions; /* For external & decr exception, | |
| 159 | - * that can be delayed */ | |
| 160 | -#else | |
| 161 | - uint32_t exceptions; /* exception queue */ | |
| 162 | - uint32_t errors[32]; | |
| 163 | -#endif | |
| 164 | 155 | int user_mode_only; /* user mode only simulation */ |
| 165 | 156 | struct TranslationBlock *current_tb; /* currently executing TB */ |
| 166 | 157 | /* soft mmu support */ |
| ... | ... | @@ -178,8 +169,13 @@ typedef struct CPUPPCState { |
| 178 | 169 | /* ice debug support */ |
| 179 | 170 | uint32_t breakpoints[MAX_BREAKPOINTS]; |
| 180 | 171 | int nb_breakpoints; |
| 181 | - int brkstate; | |
| 182 | - int singlestep_enabled; | |
| 172 | + int singlestep_enabled; /* XXX: should use CPU single step mode instead */ | |
| 173 | + | |
| 174 | + /* Time base and decrementer */ | |
| 175 | + ppc_tb_t *tb_env; | |
| 176 | + | |
| 177 | + /* Power management */ | |
| 178 | + int power_mode; | |
| 183 | 179 | |
| 184 | 180 | /* user data */ |
| 185 | 181 | void *opaque; |
| ... | ... | @@ -206,10 +202,15 @@ void _store_xer (CPUPPCState *env, uint32_t value); |
| 206 | 202 | uint32_t _load_msr (CPUPPCState *env); |
| 207 | 203 | void _store_msr (CPUPPCState *env, uint32_t value); |
| 208 | 204 | |
| 209 | -void PPC_init_hw (uint32_t mem_size, | |
| 210 | - uint32_t kernel_addr, uint32_t kernel_size, | |
| 211 | - uint32_t stack_addr, int boot_device, | |
| 212 | - const unsigned char *initrd_file); | |
| 205 | +/* Time-base and decrementer management */ | |
| 206 | +#ifndef NO_CPU_IO_DEFS | |
| 207 | +uint32_t cpu_ppc_load_tbl (CPUPPCState *env); | |
| 208 | +uint32_t cpu_ppc_load_tbu (CPUPPCState *env); | |
| 209 | +void cpu_ppc_store_tbu (CPUPPCState *env, uint32_t value); | |
| 210 | +void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value); | |
| 211 | +uint32_t cpu_ppc_load_decr (CPUPPCState *env); | |
| 212 | +void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value); | |
| 213 | +#endif | |
| 213 | 214 | |
| 214 | 215 | #define TARGET_PAGE_BITS 12 |
| 215 | 216 | #include "cpu-all.h" | ... | ... |
target-ppc/exec.h
| ... | ... | @@ -119,12 +119,8 @@ static inline uint32_t rotl (uint32_t i, int n) |
| 119 | 119 | |
| 120 | 120 | #endif /* !defined(CONFIG_USER_ONLY) */ |
| 121 | 121 | |
| 122 | -int check_exception_state (CPUState *env); | |
| 123 | - | |
| 124 | -void do_queue_exception_err (uint32_t exception, int error_code); | |
| 125 | -void do_queue_exception (uint32_t exception); | |
| 126 | -void do_process_exceptions (void); | |
| 127 | -void do_check_exception_state (void); | |
| 122 | +void do_raise_exception_err (uint32_t exception, int error_code); | |
| 123 | +void do_raise_exception (uint32_t exception); | |
| 128 | 124 | |
| 129 | 125 | void do_load_cr (void); |
| 130 | 126 | void do_store_cr (uint32_t mask); | ... | ... |
target-ppc/helper.c
| ... | ... | @@ -27,49 +27,10 @@ |
| 27 | 27 | //#define DEBUG_BATS |
| 28 | 28 | //#define DEBUG_EXCEPTIONS |
| 29 | 29 | |
| 30 | -extern FILE *logfile, *stdout, *stderr; | |
| 31 | -void exit (int); | |
| 30 | +extern FILE *stdout, *stderr; | |
| 32 | 31 | void abort (void); |
| 33 | 32 | |
| 34 | -void cpu_loop_exit(void) | |
| 35 | -{ | |
| 36 | - longjmp(env->jmp_env, 1); | |
| 37 | -} | |
| 38 | - | |
| 39 | -void do_process_exceptions (void) | |
| 40 | -{ | |
| 41 | - cpu_loop_exit(); | |
| 42 | -} | |
| 43 | - | |
| 44 | -int check_exception_state (CPUState *env) | |
| 45 | -{ | |
| 46 | - int i; | |
| 47 | - | |
| 48 | - /* Process PPC exceptions */ | |
| 49 | - for (i = 1; i < EXCP_PPC_MAX; i++) { | |
| 50 | - if (env->exceptions & (1 << i)) { | |
| 51 | - switch (i) { | |
| 52 | - case EXCP_EXTERNAL: | |
| 53 | - case EXCP_DECR: | |
| 54 | - if (msr_ee == 0) | |
| 55 | - return 0; | |
| 56 | - break; | |
| 57 | - case EXCP_PROGRAM: | |
| 58 | - if (env->errors[EXCP_PROGRAM] == EXCP_FP && | |
| 59 | - msr_fe0 == 0 && msr_fe1 == 0) | |
| 60 | - return 0; | |
| 61 | - break; | |
| 62 | - default: | |
| 63 | - break; | |
| 64 | - } | |
| 65 | - env->exception_index = i; | |
| 66 | - env->error_code = env->errors[i]; | |
| 67 | - return 1; | |
| 68 | - } | |
| 69 | - } | |
| 70 | - | |
| 71 | - return 0; | |
| 72 | -} | |
| 33 | +/*****************************************************************************/ | |
| 73 | 34 | |
| 74 | 35 | /*****************************************************************************/ |
| 75 | 36 | /* PPC MMU emulation */ |
| ... | ... | @@ -500,8 +461,7 @@ void tlb_fill(unsigned long addr, int is_write, int is_user, void *retaddr) |
| 500 | 461 | cpu_restore_state(tb, env, pc, NULL); |
| 501 | 462 | } |
| 502 | 463 | } |
| 503 | - do_queue_exception_err(env->exception_index, env->error_code); | |
| 504 | - do_process_exceptions(); | |
| 464 | + do_raise_exception_err(env->exception_index, env->error_code); | |
| 505 | 465 | } |
| 506 | 466 | { |
| 507 | 467 | unsigned long tlb_addrr, tlb_addrw; |
| ... | ... | @@ -701,9 +661,6 @@ void do_interrupt (CPUState *env) |
| 701 | 661 | uint32_t msr; |
| 702 | 662 | int excp = env->exception_index; |
| 703 | 663 | |
| 704 | - /* Dequeue PPC exceptions */ | |
| 705 | - if (excp < EXCP_PPC_MAX) | |
| 706 | - env->exceptions &= ~(1 << excp); | |
| 707 | 664 | msr = _load_msr(env); |
| 708 | 665 | #if defined (DEBUG_EXCEPTIONS) |
| 709 | 666 | if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) |
| ... | ... | @@ -812,7 +769,7 @@ void do_interrupt (CPUState *env) |
| 812 | 769 | } |
| 813 | 770 | #endif |
| 814 | 771 | /* Requeue it */ |
| 815 | - do_queue_exception(EXCP_EXTERNAL); | |
| 772 | + do_raise_exception(EXCP_EXTERNAL); | |
| 816 | 773 | return; |
| 817 | 774 | } |
| 818 | 775 | goto store_next; |
| ... | ... | @@ -864,7 +821,7 @@ void do_interrupt (CPUState *env) |
| 864 | 821 | case EXCP_DECR: |
| 865 | 822 | if (msr_ee == 0) { |
| 866 | 823 | /* Requeue it */ |
| 867 | - do_queue_exception(EXCP_DECR); | |
| 824 | + do_raise_exception(EXCP_DECR); | |
| 868 | 825 | return; |
| 869 | 826 | } |
| 870 | 827 | goto store_next; |
| ... | ... | @@ -937,4 +894,5 @@ void do_interrupt (CPUState *env) |
| 937 | 894 | T0 = 0; |
| 938 | 895 | #endif |
| 939 | 896 | #endif |
| 897 | + env->exception_index = -1; | |
| 940 | 898 | } | ... | ... |
target-ppc/op.c
| ... | ... | @@ -208,32 +208,28 @@ PPC_OP(set_T2) |
| 208 | 208 | } |
| 209 | 209 | |
| 210 | 210 | /* Generate exceptions */ |
| 211 | -PPC_OP(queue_exception_err) | |
| 211 | +PPC_OP(raise_exception_err) | |
| 212 | 212 | { |
| 213 | - do_queue_exception_err(PARAM(1), PARAM(2)); | |
| 213 | + do_raise_exception_err(PARAM(1), PARAM(2)); | |
| 214 | 214 | } |
| 215 | 215 | |
| 216 | -PPC_OP(queue_exception) | |
| 216 | +PPC_OP(raise_exception) | |
| 217 | 217 | { |
| 218 | - do_queue_exception(PARAM(1)); | |
| 218 | + do_raise_exception(PARAM(1)); | |
| 219 | 219 | } |
| 220 | 220 | |
| 221 | -PPC_OP(process_exceptions) | |
| 221 | +PPC_OP(update_nip) | |
| 222 | 222 | { |
| 223 | 223 | env->nip = PARAM(1); |
| 224 | - if (env->exceptions != 0) { | |
| 225 | - do_check_exception_state(); | |
| 226 | - } | |
| 227 | 224 | } |
| 228 | 225 | |
| 229 | 226 | PPC_OP(debug) |
| 230 | 227 | { |
| 231 | 228 | env->nip = PARAM(1); |
| 232 | - env->brkstate = 1; | |
| 233 | 229 | #if defined (DEBUG_OP) |
| 234 | 230 | dump_state(); |
| 235 | 231 | #endif |
| 236 | - do_queue_exception(EXCP_DEBUG); | |
| 232 | + do_raise_exception(EXCP_DEBUG); | |
| 237 | 233 | RETURN(); |
| 238 | 234 | } |
| 239 | 235 | |
| ... | ... | @@ -364,58 +360,38 @@ PPC_OP(store_ctr) |
| 364 | 360 | RETURN(); |
| 365 | 361 | } |
| 366 | 362 | |
| 367 | -/* Update time base */ | |
| 368 | -PPC_OP(update_tb) | |
| 363 | +PPC_OP(load_tbl) | |
| 369 | 364 | { |
| 370 | - T0 = regs->tb[0]; | |
| 371 | - T1 = T0; | |
| 372 | - T0 += PARAM(1); | |
| 373 | -#if defined (DEBUG_OP) | |
| 374 | - dump_update_tb(PARAM(1)); | |
| 375 | -#endif | |
| 376 | - if (T0 < T1) { | |
| 377 | - T1 = regs->tb[1] + 1; | |
| 378 | - regs->tb[1] = T1; | |
| 379 | - } | |
| 380 | - regs->tb[0] = T0; | |
| 365 | + T0 = cpu_ppc_load_tbl(regs); | |
| 381 | 366 | RETURN(); |
| 382 | 367 | } |
| 383 | 368 | |
| 384 | -PPC_OP(load_tb) | |
| 369 | +PPC_OP(load_tbu) | |
| 385 | 370 | { |
| 386 | - T0 = regs->tb[PARAM(1)]; | |
| 371 | + T0 = cpu_ppc_load_tbu(regs); | |
| 387 | 372 | RETURN(); |
| 388 | 373 | } |
| 389 | 374 | |
| 390 | -PPC_OP(store_tb) | |
| 375 | +PPC_OP(store_tbl) | |
| 391 | 376 | { |
| 392 | - regs->tb[PARAM(1)] = T0; | |
| 393 | -#if defined (DEBUG_OP) | |
| 394 | - dump_store_tb(PARAM(1)); | |
| 395 | -#endif | |
| 377 | + cpu_ppc_store_tbl(regs, T0); | |
| 396 | 378 | RETURN(); |
| 397 | 379 | } |
| 398 | 380 | |
| 399 | -/* Update decrementer */ | |
| 400 | -PPC_OP(update_decr) | |
| 381 | +PPC_OP(store_tbu) | |
| 401 | 382 | { |
| 402 | - T0 = regs->decr; | |
| 403 | - T1 = T0; | |
| 404 | - T0 -= PARAM(1); | |
| 405 | - regs->decr = T0; | |
| 406 | - if (PARAM(1) > T1) { | |
| 407 | - do_queue_exception(EXCP_DECR); | |
| 408 | - } | |
| 383 | + cpu_ppc_store_tbu(regs, T0); | |
| 409 | 384 | RETURN(); |
| 410 | 385 | } |
| 411 | 386 | |
| 412 | -PPC_OP(store_decr) | |
| 387 | +PPC_OP(load_decr) | |
| 413 | 388 | { |
| 414 | - T1 = regs->decr; | |
| 415 | - regs->decr = T0; | |
| 416 | - if (Ts0 < 0 && Ts1 > 0) { | |
| 417 | - do_queue_exception(EXCP_DECR); | |
| 389 | + T0 = cpu_ppc_load_decr(regs); | |
| 418 | 390 | } |
| 391 | + | |
| 392 | +PPC_OP(store_decr) | |
| 393 | +{ | |
| 394 | + cpu_ppc_store_decr(regs, T0); | |
| 419 | 395 | RETURN(); |
| 420 | 396 | } |
| 421 | 397 | |
| ... | ... | @@ -1471,17 +1447,14 @@ PPC_OP(fneg) |
| 1471 | 1447 | /* Return from interrupt */ |
| 1472 | 1448 | PPC_OP(rfi) |
| 1473 | 1449 | { |
| 1450 | + regs->nip = regs->spr[SRR0] & ~0x00000003; | |
| 1474 | 1451 | T0 = regs->spr[SRR1] & ~0xFFFF0000; |
| 1475 | 1452 | do_store_msr(); |
| 1476 | - do_tlbia(); | |
| 1477 | 1453 | #if defined (DEBUG_OP) |
| 1478 | 1454 | dump_rfi(); |
| 1479 | 1455 | #endif |
| 1480 | - regs->nip = regs->spr[SRR0] & ~0x00000003; | |
| 1481 | - do_queue_exception(EXCP_RFI); | |
| 1482 | - if (env->exceptions != 0) { | |
| 1483 | - do_check_exception_state(); | |
| 1484 | - } | |
| 1456 | + // do_tlbia(); | |
| 1457 | + do_raise_exception(EXCP_RFI); | |
| 1485 | 1458 | RETURN(); |
| 1486 | 1459 | } |
| 1487 | 1460 | |
| ... | ... | @@ -1493,7 +1466,7 @@ PPC_OP(tw) |
| 1493 | 1466 | (Ts0 == Ts1 && (PARAM(1) & 0x04)) || |
| 1494 | 1467 | (T0 < T1 && (PARAM(1) & 0x02)) || |
| 1495 | 1468 | (T0 > T1 && (PARAM(1) & 0x01))) |
| 1496 | - do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP); | |
| 1469 | + do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); | |
| 1497 | 1470 | RETURN(); |
| 1498 | 1471 | } |
| 1499 | 1472 | |
| ... | ... | @@ -1504,7 +1477,7 @@ PPC_OP(twi) |
| 1504 | 1477 | (Ts0 == SPARAM(1) && (PARAM(2) & 0x04)) || |
| 1505 | 1478 | (T0 < (uint32_t)SPARAM(1) && (PARAM(2) & 0x02)) || |
| 1506 | 1479 | (T0 > (uint32_t)SPARAM(1) && (PARAM(2) & 0x01))) |
| 1507 | - do_queue_exception_err(EXCP_PROGRAM, EXCP_TRAP); | |
| 1480 | + do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP); | |
| 1508 | 1481 | RETURN(); |
| 1509 | 1482 | } |
| 1510 | 1483 | ... | ... |
target-ppc/op_helper.c
| ... | ... | @@ -31,31 +31,38 @@ |
| 31 | 31 | |
| 32 | 32 | /*****************************************************************************/ |
| 33 | 33 | /* Exceptions processing helpers */ |
| 34 | -void do_queue_exception_err (uint32_t exception, int error_code) | |
| 34 | +void cpu_loop_exit(void) | |
| 35 | 35 | { |
| 36 | - /* Queue real PPC exceptions */ | |
| 37 | - if (exception < EXCP_PPC_MAX) { | |
| 38 | - env->exceptions |= 1 << exception; | |
| 39 | - env->errors[exception] = error_code; | |
| 40 | - } else { | |
| 41 | - /* Preserve compatibility with qemu core */ | |
| 42 | - env->exceptions |= 1; | |
| 43 | - env->exception_index = exception; | |
| 44 | - env->error_code = error_code; | |
| 45 | - } | |
| 36 | + longjmp(env->jmp_env, 1); | |
| 46 | 37 | } |
| 47 | 38 | |
| 48 | -void do_queue_exception (uint32_t exception) | |
| 39 | +void do_raise_exception_err (uint32_t exception, int error_code) | |
| 49 | 40 | { |
| 50 | - do_queue_exception_err(exception, 0); | |
| 51 | -} | |
| 52 | - | |
| 53 | -void do_check_exception_state (void) | |
| 54 | -{ | |
| 55 | - if ((env->exceptions & 1) == 1 || check_exception_state(env)) { | |
| 56 | - env->exceptions &= ~1; | |
| 41 | +#if 0 | |
| 42 | + printf("Raise exception %3x code : %d\n", exception, error_code); | |
| 43 | +#endif | |
| 44 | + switch (exception) { | |
| 45 | + case EXCP_EXTERNAL: | |
| 46 | + case EXCP_DECR: | |
| 47 | + printf("DECREMENTER & EXTERNAL exceptions should be hard interrupts !\n"); | |
| 48 | + if (msr_ee == 0) | |
| 49 | + return; | |
| 50 | + break; | |
| 51 | + case EXCP_PROGRAM: | |
| 52 | + if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0) | |
| 53 | + return; | |
| 54 | + break; | |
| 55 | + default: | |
| 56 | + break; | |
| 57 | +} | |
| 58 | + env->exception_index = exception; | |
| 59 | + env->error_code = error_code; | |
| 57 | 60 | cpu_loop_exit(); |
| 58 | 61 | } |
| 62 | + | |
| 63 | +void do_raise_exception (uint32_t exception) | |
| 64 | +{ | |
| 65 | + do_raise_exception_err(exception, 0); | |
| 59 | 66 | } |
| 60 | 67 | |
| 61 | 68 | /*****************************************************************************/ |
| ... | ... | @@ -125,13 +132,6 @@ void do_store_msr (void) |
| 125 | 132 | /* Flush all tlb when changing translation mode or privilege level */ |
| 126 | 133 | do_tlbia(); |
| 127 | 134 | } |
| 128 | -#if 0 | |
| 129 | - if ((T0 >> MSR_IP) & 0x01) { | |
| 130 | - printf("Halting CPU. Stop emulation\n"); | |
| 131 | - do_queue_exception(EXCP_HLT); | |
| 132 | - cpu_loop_exit(); | |
| 133 | - } | |
| 134 | -#endif | |
| 135 | 135 | msr_pow = (T0 >> MSR_POW) & 0x03; |
| 136 | 136 | msr_ile = (T0 >> MSR_ILE) & 0x01; |
| 137 | 137 | msr_ee = (T0 >> MSR_EE) & 0x01; | ... | ... |
target-ppc/op_mem.h
| ... | ... | @@ -97,8 +97,7 @@ PPC_OP(glue(lswx, MEMSUFFIX)) |
| 97 | 97 | if (T1 > 0) { |
| 98 | 98 | if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) || |
| 99 | 99 | (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) { |
| 100 | - do_queue_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); | |
| 101 | - do_process_exceptions(); | |
| 100 | + do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); | |
| 102 | 101 | } else { |
| 103 | 102 | glue(do_lsw, MEMSUFFIX)(PARAM(1)); |
| 104 | 103 | } |
| ... | ... | @@ -138,8 +137,7 @@ PPC_LDF_OP(fs, ldfl); |
| 138 | 137 | PPC_OP(glue(lwarx, MEMSUFFIX)) |
| 139 | 138 | { |
| 140 | 139 | if (T0 & 0x03) { |
| 141 | - do_queue_exception(EXCP_ALIGN); | |
| 142 | - do_process_exceptions(); | |
| 140 | + do_raise_exception(EXCP_ALIGN); | |
| 143 | 141 | } else { |
| 144 | 142 | T1 = glue(ldl, MEMSUFFIX)((void *)T0); |
| 145 | 143 | regs->reserve = T0; |
| ... | ... | @@ -151,8 +149,7 @@ PPC_OP(glue(lwarx, MEMSUFFIX)) |
| 151 | 149 | PPC_OP(glue(stwcx, MEMSUFFIX)) |
| 152 | 150 | { |
| 153 | 151 | if (T0 & 0x03) { |
| 154 | - do_queue_exception(EXCP_ALIGN); | |
| 155 | - do_process_exceptions(); | |
| 152 | + do_raise_exception(EXCP_ALIGN); | |
| 156 | 153 | } else { |
| 157 | 154 | if (regs->reserve != T0) { |
| 158 | 155 | env->crf[0] = xer_ov; | ... | ... |
target-ppc/translate.c
| ... | ... | @@ -30,6 +30,7 @@ |
| 30 | 30 | //#define DO_SINGLE_STEP |
| 31 | 31 | //#define DO_STEP_FLUSH |
| 32 | 32 | //#define DEBUG_DISAS |
| 33 | +//#define PPC_DEBUG_DISAS | |
| 33 | 34 | |
| 34 | 35 | enum { |
| 35 | 36 | #define DEF(s, n, copy_size) INDEX_op_ ## s, |
| ... | ... | @@ -135,10 +136,6 @@ typedef struct DisasContext { |
| 135 | 136 | uint32_t nip; |
| 136 | 137 | uint32_t opcode; |
| 137 | 138 | uint32_t exception; |
| 138 | - /* Time base offset */ | |
| 139 | - uint32_t tb_offset; | |
| 140 | - /* Decrementer offset */ | |
| 141 | - uint32_t decr_offset; | |
| 142 | 139 | /* Execution mode */ |
| 143 | 140 | #if !defined(CONFIG_USER_ONLY) |
| 144 | 141 | int supervisor; |
| ... | ... | @@ -156,21 +153,26 @@ typedef struct opc_handler_t { |
| 156 | 153 | void (*handler)(DisasContext *ctx); |
| 157 | 154 | } opc_handler_t; |
| 158 | 155 | |
| 159 | -#define RET_EXCP(excp, error) \ | |
| 156 | +#define RET_EXCP(ctx, excp, error) \ | |
| 160 | 157 | do { \ |
| 161 | - gen_op_queue_exception_err(excp, error); \ | |
| 162 | - ctx->exception = excp; \ | |
| 163 | - return; \ | |
| 158 | + if ((ctx)->exception == EXCP_NONE) { \ | |
| 159 | + gen_op_update_nip((ctx)->nip); \ | |
| 160 | + } \ | |
| 161 | + gen_op_raise_exception_err((excp), (error)); \ | |
| 162 | + ctx->exception = (excp); \ | |
| 164 | 163 | } while (0) |
| 165 | 164 | |
| 166 | -#define RET_INVAL() \ | |
| 167 | -RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL) | |
| 165 | +#define RET_INVAL(ctx) \ | |
| 166 | +RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL) | |
| 167 | + | |
| 168 | +#define RET_PRIVOPC(ctx) \ | |
| 169 | +RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC) | |
| 168 | 170 | |
| 169 | -#define RET_PRIVOPC() \ | |
| 170 | -RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_OPC) | |
| 171 | +#define RET_PRIVREG(ctx) \ | |
| 172 | +RET_EXCP((ctx), EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG) | |
| 171 | 173 | |
| 172 | -#define RET_PRIVREG() \ | |
| 173 | -RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG) | |
| 174 | +#define RET_MTMSR(ctx) \ | |
| 175 | +RET_EXCP((ctx), EXCP_MTMSR, 0) | |
| 174 | 176 | |
| 175 | 177 | #define GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \ |
| 176 | 178 | static void gen_##name (DisasContext *ctx); \ |
| ... | ... | @@ -312,29 +314,26 @@ GEN_OPCODE_MARK(start); |
| 312 | 314 | /* Invalid instruction */ |
| 313 | 315 | GEN_HANDLER(invalid, 0x00, 0x00, 0x00, 0xFFFFFFFF, PPC_NONE) |
| 314 | 316 | { |
| 315 | - RET_INVAL(); | |
| 317 | + RET_INVAL(ctx); | |
| 316 | 318 | } |
| 317 | 319 | |
| 318 | 320 | /* Special opcode to stop emulation */ |
| 319 | 321 | GEN_HANDLER(stop, 0x06, 0x00, 0xFF, 0x03FFFFC1, PPC_COMMON) |
| 320 | 322 | { |
| 321 | - gen_op_queue_exception(EXCP_HLT); | |
| 322 | - ctx->exception = EXCP_HLT; | |
| 323 | + RET_EXCP(ctx, EXCP_HLT, 0); | |
| 323 | 324 | } |
| 324 | 325 | |
| 325 | 326 | /* Special opcode to call open-firmware */ |
| 326 | 327 | GEN_HANDLER(of_enter, 0x06, 0x01, 0xFF, 0x03FFFFC1, PPC_COMMON) |
| 327 | 328 | { |
| 328 | - gen_op_queue_exception(EXCP_OFCALL); | |
| 329 | - ctx->exception = EXCP_OFCALL; | |
| 329 | + RET_EXCP(ctx, EXCP_OFCALL, 0); | |
| 330 | 330 | } |
| 331 | 331 | |
| 332 | 332 | /* Special opcode to call RTAS */ |
| 333 | 333 | GEN_HANDLER(rtas_enter, 0x06, 0x02, 0xFF, 0x03FFFFC1, PPC_COMMON) |
| 334 | 334 | { |
| 335 | 335 | printf("RTAS entry point !\n"); |
| 336 | - gen_op_queue_exception(EXCP_RTASCALL); | |
| 337 | - ctx->exception = EXCP_RTASCALL; | |
| 336 | + RET_EXCP(ctx, EXCP_RTASCALL, 0); | |
| 338 | 337 | } |
| 339 | 338 | |
| 340 | 339 | static opc_handler_t invalid_handler = { |
| ... | ... | @@ -1010,7 +1009,8 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ |
| 1010 | 1009 | uint32_t simm = SIMM(ctx->opcode); \ |
| 1011 | 1010 | if (rA(ctx->opcode) == 0 || \ |
| 1012 | 1011 | rA(ctx->opcode) == rD(ctx->opcode)) { \ |
| 1013 | - RET_INVAL(); \ | |
| 1012 | + RET_INVAL(ctx); \ | |
| 1013 | + return; \ | |
| 1014 | 1014 | } \ |
| 1015 | 1015 | gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
| 1016 | 1016 | if (simm != 0) \ |
| ... | ... | @@ -1025,7 +1025,8 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ |
| 1025 | 1025 | { \ |
| 1026 | 1026 | if (rA(ctx->opcode) == 0 || \ |
| 1027 | 1027 | rA(ctx->opcode) == rD(ctx->opcode)) { \ |
| 1028 | - RET_INVAL(); \ | |
| 1028 | + RET_INVAL(ctx); \ | |
| 1029 | + return; \ | |
| 1029 | 1030 | } \ |
| 1030 | 1031 | gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
| 1031 | 1032 | gen_op_load_gpr_T1(rB(ctx->opcode)); \ |
| ... | ... | @@ -1086,7 +1087,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ |
| 1086 | 1087 | { \ |
| 1087 | 1088 | uint32_t simm = SIMM(ctx->opcode); \ |
| 1088 | 1089 | if (rA(ctx->opcode) == 0) { \ |
| 1089 | - RET_INVAL(); \ | |
| 1090 | + RET_INVAL(ctx); \ | |
| 1091 | + return; \ | |
| 1090 | 1092 | } \ |
| 1091 | 1093 | gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
| 1092 | 1094 | if (simm != 0) \ |
| ... | ... | @@ -1100,7 +1102,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ |
| 1100 | 1102 | GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ |
| 1101 | 1103 | { \ |
| 1102 | 1104 | if (rA(ctx->opcode) == 0) { \ |
| 1103 | - RET_INVAL(); \ | |
| 1105 | + RET_INVAL(ctx); \ | |
| 1106 | + return; \ | |
| 1104 | 1107 | } \ |
| 1105 | 1108 | gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
| 1106 | 1109 | gen_op_load_gpr_T1(rB(ctx->opcode)); \ |
| ... | ... | @@ -1236,7 +1239,8 @@ GEN_HANDLER(lswi, 0x1F, 0x15, 0x12, 0x00000001, PPC_INTEGER) |
| 1236 | 1239 | nr = nb / 4; |
| 1237 | 1240 | if (((start + nr) > 32 && start <= ra && (start + nr - 32) > ra) || |
| 1238 | 1241 | ((start + nr) <= 32 && start <= ra && (start + nr) > ra)) { |
| 1239 | - RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); | |
| 1242 | + RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX); | |
| 1243 | + return; | |
| 1240 | 1244 | } |
| 1241 | 1245 | if (ra == 0) { |
| 1242 | 1246 | gen_op_set_T0(0); |
| ... | ... | @@ -1376,7 +1380,8 @@ GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ |
| 1376 | 1380 | uint32_t simm = SIMM(ctx->opcode); \ |
| 1377 | 1381 | if (rA(ctx->opcode) == 0 || \ |
| 1378 | 1382 | rA(ctx->opcode) == rD(ctx->opcode)) { \ |
| 1379 | - RET_INVAL(); \ | |
| 1383 | + RET_INVAL(ctx); \ | |
| 1384 | + return; \ | |
| 1380 | 1385 | } \ |
| 1381 | 1386 | gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
| 1382 | 1387 | if (simm != 0) \ |
| ... | ... | @@ -1391,7 +1396,8 @@ GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ |
| 1391 | 1396 | { \ |
| 1392 | 1397 | if (rA(ctx->opcode) == 0 || \ |
| 1393 | 1398 | rA(ctx->opcode) == rD(ctx->opcode)) { \ |
| 1394 | - RET_INVAL(); \ | |
| 1399 | + RET_INVAL(ctx); \ | |
| 1400 | + return; \ | |
| 1395 | 1401 | } \ |
| 1396 | 1402 | gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
| 1397 | 1403 | gen_op_load_gpr_T1(rB(ctx->opcode)); \ |
| ... | ... | @@ -1448,7 +1454,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ |
| 1448 | 1454 | { \ |
| 1449 | 1455 | uint32_t simm = SIMM(ctx->opcode); \ |
| 1450 | 1456 | if (rA(ctx->opcode) == 0) { \ |
| 1451 | - RET_INVAL(); \ | |
| 1457 | + RET_INVAL(ctx); \ | |
| 1458 | + return; \ | |
| 1452 | 1459 | } \ |
| 1453 | 1460 | gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
| 1454 | 1461 | if (simm != 0) \ |
| ... | ... | @@ -1462,7 +1469,8 @@ GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \ |
| 1462 | 1469 | GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \ |
| 1463 | 1470 | { \ |
| 1464 | 1471 | if (rA(ctx->opcode) == 0) { \ |
| 1465 | - RET_INVAL(); \ | |
| 1472 | + RET_INVAL(ctx); \ | |
| 1473 | + return; \ | |
| 1466 | 1474 | } \ |
| 1467 | 1475 | gen_op_load_gpr_T0(rA(ctx->opcode)); \ |
| 1468 | 1476 | gen_op_load_gpr_T1(rB(ctx->opcode)); \ |
| ... | ... | @@ -1502,7 +1510,7 @@ GEN_STFS(fs, 0x14); |
| 1502 | 1510 | /* stfiwx */ |
| 1503 | 1511 | GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT) |
| 1504 | 1512 | { |
| 1505 | - RET_INVAL(); | |
| 1513 | + RET_INVAL(ctx); | |
| 1506 | 1514 | } |
| 1507 | 1515 | |
| 1508 | 1516 | /*** Branch ***/ |
| ... | ... | @@ -1512,9 +1520,6 @@ GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW) |
| 1512 | 1520 | { |
| 1513 | 1521 | uint32_t li = s_ext24(LI(ctx->opcode)), target; |
| 1514 | 1522 | |
| 1515 | - gen_op_update_tb(ctx->tb_offset); | |
| 1516 | - gen_op_update_decr(ctx->decr_offset); | |
| 1517 | - gen_op_process_exceptions(ctx->nip - 4); | |
| 1518 | 1523 | if (AA(ctx->opcode) == 0) |
| 1519 | 1524 | target = ctx->nip + li - 4; |
| 1520 | 1525 | else |
| ... | ... | @@ -1538,10 +1543,6 @@ static inline void gen_bcond(DisasContext *ctx, int type) |
| 1538 | 1543 | uint32_t mask; |
| 1539 | 1544 | uint32_t li; |
| 1540 | 1545 | |
| 1541 | - gen_op_update_tb(ctx->tb_offset); | |
| 1542 | - gen_op_update_decr(ctx->decr_offset); | |
| 1543 | - gen_op_process_exceptions(ctx->nip - 4); | |
| 1544 | - | |
| 1545 | 1546 | if ((bo & 0x4) == 0) |
| 1546 | 1547 | gen_op_dec_ctr(); |
| 1547 | 1548 | switch(type) { |
| ... | ... | @@ -1683,14 +1684,15 @@ GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER) |
| 1683 | 1684 | GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW) |
| 1684 | 1685 | { |
| 1685 | 1686 | #if defined(CONFIG_USER_ONLY) |
| 1686 | - RET_PRIVOPC(); | |
| 1687 | + RET_PRIVOPC(ctx); | |
| 1687 | 1688 | #else |
| 1688 | 1689 | /* Restore CPU state */ |
| 1689 | 1690 | if (!ctx->supervisor) { |
| 1690 | - RET_PRIVOPC(); | |
| 1691 | + RET_PRIVOPC(ctx); | |
| 1692 | + return; | |
| 1691 | 1693 | } |
| 1692 | 1694 | gen_op_rfi(); |
| 1693 | - ctx->exception = EXCP_RFI; | |
| 1695 | + RET_EXCP(ctx, EXCP_RFI, 0); | |
| 1694 | 1696 | #endif |
| 1695 | 1697 | } |
| 1696 | 1698 | |
| ... | ... | @@ -1698,11 +1700,10 @@ GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW) |
| 1698 | 1700 | GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW) |
| 1699 | 1701 | { |
| 1700 | 1702 | #if defined(CONFIG_USER_ONLY) |
| 1701 | - gen_op_queue_exception(EXCP_SYSCALL_USER); | |
| 1703 | + RET_EXCP(ctx, EXCP_SYSCALL_USER, 0); | |
| 1702 | 1704 | #else |
| 1703 | - gen_op_queue_exception(EXCP_SYSCALL); | |
| 1705 | + RET_EXCP(ctx, EXCP_SYSCALL, 0); | |
| 1704 | 1706 | #endif |
| 1705 | - ctx->exception = EXCP_SYSCALL; | |
| 1706 | 1707 | } |
| 1707 | 1708 | |
| 1708 | 1709 | /*** Trap ***/ |
| ... | ... | @@ -1770,10 +1771,11 @@ GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC) |
| 1770 | 1771 | GEN_HANDLER(mfmsr, 0x1F, 0x13, 0x02, 0x001FF801, PPC_MISC) |
| 1771 | 1772 | { |
| 1772 | 1773 | #if defined(CONFIG_USER_ONLY) |
| 1773 | - RET_PRIVREG(); | |
| 1774 | + RET_PRIVREG(ctx); | |
| 1774 | 1775 | #else |
| 1775 | 1776 | if (!ctx->supervisor) { |
| 1776 | - RET_PRIVREG(); | |
| 1777 | + RET_PRIVREG(ctx); | |
| 1778 | + return; | |
| 1777 | 1779 | } |
| 1778 | 1780 | gen_op_load_msr(); |
| 1779 | 1781 | gen_op_store_T0_gpr(rD(ctx->opcode)); |
| ... | ... | @@ -1792,11 +1794,11 @@ GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC) |
| 1792 | 1794 | #endif |
| 1793 | 1795 | { |
| 1794 | 1796 | case -1: |
| 1795 | - RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); | |
| 1796 | - break; | |
| 1797 | + RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); | |
| 1798 | + return; | |
| 1797 | 1799 | case 0: |
| 1798 | - RET_PRIVREG(); | |
| 1799 | - break; | |
| 1800 | + RET_PRIVREG(ctx); | |
| 1801 | + return; | |
| 1800 | 1802 | default: |
| 1801 | 1803 | break; |
| 1802 | 1804 | } |
| ... | ... | @@ -1910,19 +1912,13 @@ GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC) |
| 1910 | 1912 | gen_op_load_sdr1(); |
| 1911 | 1913 | break; |
| 1912 | 1914 | case V_TBL: |
| 1913 | - gen_op_update_tb(ctx->tb_offset); | |
| 1914 | - ctx->tb_offset = 0; | |
| 1915 | - /* TBL is still in T0 */ | |
| 1915 | + gen_op_load_tbl(); | |
| 1916 | 1916 | break; |
| 1917 | 1917 | case V_TBU: |
| 1918 | - gen_op_update_tb(ctx->tb_offset); | |
| 1919 | - ctx->tb_offset = 0; | |
| 1920 | - gen_op_load_tb(1); | |
| 1918 | + gen_op_load_tbu(); | |
| 1921 | 1919 | break; |
| 1922 | 1920 | case DECR: |
| 1923 | - gen_op_update_decr(ctx->decr_offset); | |
| 1924 | - ctx->decr_offset = 0; | |
| 1925 | - /* decr is still in T0 */ | |
| 1921 | + gen_op_load_decr(); | |
| 1926 | 1922 | break; |
| 1927 | 1923 | default: |
| 1928 | 1924 | gen_op_load_spr(sprn); |
| ... | ... | @@ -1939,18 +1935,16 @@ GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_MISC) |
| 1939 | 1935 | /* We need to update the time base before reading it */ |
| 1940 | 1936 | switch (sprn) { |
| 1941 | 1937 | case V_TBL: |
| 1942 | - gen_op_update_tb(ctx->tb_offset); | |
| 1943 | 1938 | /* TBL is still in T0 */ |
| 1939 | + gen_op_load_tbl(); | |
| 1944 | 1940 | break; |
| 1945 | 1941 | case V_TBU: |
| 1946 | - gen_op_update_tb(ctx->tb_offset); | |
| 1947 | - gen_op_load_tb(1); | |
| 1942 | + gen_op_load_tbu(); | |
| 1948 | 1943 | break; |
| 1949 | 1944 | default: |
| 1950 | - RET_INVAL(); | |
| 1951 | - break; | |
| 1945 | + RET_INVAL(ctx); | |
| 1946 | + return; | |
| 1952 | 1947 | } |
| 1953 | - ctx->tb_offset = 0; | |
| 1954 | 1948 | gen_op_store_T0_gpr(rD(ctx->opcode)); |
| 1955 | 1949 | } |
| 1956 | 1950 | |
| ... | ... | @@ -1965,15 +1959,16 @@ GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00100801, PPC_MISC) |
| 1965 | 1959 | GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC) |
| 1966 | 1960 | { |
| 1967 | 1961 | #if defined(CONFIG_USER_ONLY) |
| 1968 | - RET_PRIVREG(); | |
| 1962 | + RET_PRIVREG(ctx); | |
| 1969 | 1963 | #else |
| 1970 | 1964 | if (!ctx->supervisor) { |
| 1971 | - RET_PRIVREG(); | |
| 1965 | + RET_PRIVREG(ctx); | |
| 1966 | + return; | |
| 1972 | 1967 | } |
| 1973 | 1968 | gen_op_load_gpr_T0(rS(ctx->opcode)); |
| 1974 | 1969 | gen_op_store_msr(); |
| 1975 | 1970 | /* Must stop the translation as machine state (may have) changed */ |
| 1976 | - ctx->exception = EXCP_MTMSR; | |
| 1971 | + RET_MTMSR(ctx); | |
| 1977 | 1972 | #endif |
| 1978 | 1973 | } |
| 1979 | 1974 | |
| ... | ... | @@ -1995,10 +1990,10 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) |
| 1995 | 1990 | #endif |
| 1996 | 1991 | { |
| 1997 | 1992 | case -1: |
| 1998 | - RET_EXCP(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); | |
| 1993 | + RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_SPR); | |
| 1999 | 1994 | break; |
| 2000 | 1995 | case 0: |
| 2001 | - RET_PRIVREG(); | |
| 1996 | + RET_PRIVREG(ctx); | |
| 2002 | 1997 | break; |
| 2003 | 1998 | default: |
| 2004 | 1999 | break; |
| ... | ... | @@ -2147,16 +2142,13 @@ GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC) |
| 2147 | 2142 | gen_op_tlbia(); |
| 2148 | 2143 | break; |
| 2149 | 2144 | case O_TBL: |
| 2150 | - gen_op_store_tb(0); | |
| 2151 | - ctx->tb_offset = 0; | |
| 2145 | + gen_op_store_tbl(); | |
| 2152 | 2146 | break; |
| 2153 | 2147 | case O_TBU: |
| 2154 | - gen_op_store_tb(1); | |
| 2155 | - ctx->tb_offset = 0; | |
| 2148 | + gen_op_store_tbu(); | |
| 2156 | 2149 | break; |
| 2157 | 2150 | case DECR: |
| 2158 | 2151 | gen_op_store_decr(); |
| 2159 | - ctx->decr_offset = 0; | |
| 2160 | 2152 | break; |
| 2161 | 2153 | default: |
| 2162 | 2154 | gen_op_store_spr(sprn); |
| ... | ... | @@ -2186,10 +2178,11 @@ GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE) |
| 2186 | 2178 | GEN_HANDLER(dcbi, 0x1F, 0x16, 0x0E, 0x03E00001, PPC_CACHE) |
| 2187 | 2179 | { |
| 2188 | 2180 | #if defined(CONFIG_USER_ONLY) |
| 2189 | - RET_PRIVOPC(); | |
| 2181 | + RET_PRIVOPC(ctx); | |
| 2190 | 2182 | #else |
| 2191 | 2183 | if (!ctx->supervisor) { |
| 2192 | - RET_PRIVOPC(); | |
| 2184 | + RET_PRIVOPC(ctx); | |
| 2185 | + return; | |
| 2193 | 2186 | } |
| 2194 | 2187 | if (rA(ctx->opcode) == 0) { |
| 2195 | 2188 | gen_op_load_gpr_T0(rB(ctx->opcode)); |
| ... | ... | @@ -2274,10 +2267,11 @@ GEN_HANDLER(dcba, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE_OPT) |
| 2274 | 2267 | GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT) |
| 2275 | 2268 | { |
| 2276 | 2269 | #if defined(CONFIG_USER_ONLY) |
| 2277 | - RET_PRIVREG(); | |
| 2270 | + RET_PRIVREG(ctx); | |
| 2278 | 2271 | #else |
| 2279 | 2272 | if (!ctx->supervisor) { |
| 2280 | - RET_PRIVREG(); | |
| 2273 | + RET_PRIVREG(ctx); | |
| 2274 | + return; | |
| 2281 | 2275 | } |
| 2282 | 2276 | gen_op_load_sr(SR(ctx->opcode)); |
| 2283 | 2277 | gen_op_store_T0_gpr(rD(ctx->opcode)); |
| ... | ... | @@ -2288,10 +2282,11 @@ GEN_HANDLER(mfsr, 0x1F, 0x13, 0x12, 0x0010F801, PPC_SEGMENT) |
| 2288 | 2282 | GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT) |
| 2289 | 2283 | { |
| 2290 | 2284 | #if defined(CONFIG_USER_ONLY) |
| 2291 | - RET_PRIVREG(); | |
| 2285 | + RET_PRIVREG(ctx); | |
| 2292 | 2286 | #else |
| 2293 | 2287 | if (!ctx->supervisor) { |
| 2294 | - RET_PRIVREG(); | |
| 2288 | + RET_PRIVREG(ctx); | |
| 2289 | + return; | |
| 2295 | 2290 | } |
| 2296 | 2291 | gen_op_load_gpr_T1(rB(ctx->opcode)); |
| 2297 | 2292 | gen_op_load_srin(); |
| ... | ... | @@ -2303,14 +2298,18 @@ GEN_HANDLER(mfsrin, 0x1F, 0x13, 0x14, 0x001F0001, PPC_SEGMENT) |
| 2303 | 2298 | GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) |
| 2304 | 2299 | { |
| 2305 | 2300 | #if defined(CONFIG_USER_ONLY) |
| 2306 | - RET_PRIVREG(); | |
| 2301 | + RET_PRIVREG(ctx); | |
| 2307 | 2302 | #else |
| 2308 | 2303 | if (!ctx->supervisor) { |
| 2309 | - RET_PRIVREG(); | |
| 2304 | + RET_PRIVREG(ctx); | |
| 2305 | + return; | |
| 2310 | 2306 | } |
| 2311 | 2307 | gen_op_load_gpr_T0(rS(ctx->opcode)); |
| 2312 | 2308 | gen_op_store_sr(SR(ctx->opcode)); |
| 2309 | +#if 0 | |
| 2313 | 2310 | gen_op_tlbia(); |
| 2311 | + RET_MTMSR(ctx); | |
| 2312 | +#endif | |
| 2314 | 2313 | #endif |
| 2315 | 2314 | } |
| 2316 | 2315 | |
| ... | ... | @@ -2318,10 +2317,11 @@ GEN_HANDLER(mtsr, 0x1F, 0x12, 0x06, 0x0010F801, PPC_SEGMENT) |
| 2318 | 2317 | GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) |
| 2319 | 2318 | { |
| 2320 | 2319 | #if defined(CONFIG_USER_ONLY) |
| 2321 | - RET_PRIVREG(); | |
| 2320 | + RET_PRIVREG(ctx); | |
| 2322 | 2321 | #else |
| 2323 | 2322 | if (!ctx->supervisor) { |
| 2324 | - RET_PRIVREG(); | |
| 2323 | + RET_PRIVREG(ctx); | |
| 2324 | + return; | |
| 2325 | 2325 | } |
| 2326 | 2326 | gen_op_load_gpr_T0(rS(ctx->opcode)); |
| 2327 | 2327 | gen_op_load_gpr_T1(rB(ctx->opcode)); |
| ... | ... | @@ -2336,10 +2336,13 @@ GEN_HANDLER(mtsrin, 0x1F, 0x12, 0x07, 0x001F0001, PPC_SEGMENT) |
| 2336 | 2336 | GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT) |
| 2337 | 2337 | { |
| 2338 | 2338 | #if defined(CONFIG_USER_ONLY) |
| 2339 | - RET_PRIVOPC(); | |
| 2339 | + RET_PRIVOPC(ctx); | |
| 2340 | 2340 | #else |
| 2341 | 2341 | if (!ctx->supervisor) { |
| 2342 | - RET_PRIVOPC(); | |
| 2342 | + if (loglevel) | |
| 2343 | + fprintf(logfile, "%s: ! supervisor\n", __func__); | |
| 2344 | + RET_PRIVOPC(ctx); | |
| 2345 | + return; | |
| 2343 | 2346 | } |
| 2344 | 2347 | gen_op_tlbia(); |
| 2345 | 2348 | #endif |
| ... | ... | @@ -2349,10 +2352,11 @@ GEN_HANDLER(tlbia, 0x1F, 0x12, 0x0B, 0x03FFFC01, PPC_MEM_OPT) |
| 2349 | 2352 | GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM) |
| 2350 | 2353 | { |
| 2351 | 2354 | #if defined(CONFIG_USER_ONLY) |
| 2352 | - RET_PRIVOPC(); | |
| 2355 | + RET_PRIVOPC(ctx); | |
| 2353 | 2356 | #else |
| 2354 | 2357 | if (!ctx->supervisor) { |
| 2355 | - RET_PRIVOPC(); | |
| 2358 | + RET_PRIVOPC(ctx); | |
| 2359 | + return; | |
| 2356 | 2360 | } |
| 2357 | 2361 | gen_op_load_gpr_T0(rB(ctx->opcode)); |
| 2358 | 2362 | gen_op_tlbie(); |
| ... | ... | @@ -2363,10 +2367,11 @@ GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM) |
| 2363 | 2367 | GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM) |
| 2364 | 2368 | { |
| 2365 | 2369 | #if defined(CONFIG_USER_ONLY) |
| 2366 | - RET_PRIVOPC(); | |
| 2370 | + RET_PRIVOPC(ctx); | |
| 2367 | 2371 | #else |
| 2368 | 2372 | if (!ctx->supervisor) { |
| 2369 | - RET_PRIVOPC(); | |
| 2373 | + RET_PRIVOPC(ctx); | |
| 2374 | + return; | |
| 2370 | 2375 | } |
| 2371 | 2376 | /* This has no effect: it should ensure that all previous |
| 2372 | 2377 | * tlbie have completed |
| ... | ... | @@ -2916,7 +2921,8 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) |
| 2916 | 2921 | fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' '); |
| 2917 | 2922 | } |
| 2918 | 2923 | fprintf(f, " ] "); |
| 2919 | - fprintf(f, "TB: 0x%08x %08x\n", env->tb[1], env->tb[0]); | |
| 2924 | + fprintf(f, "TB: 0x%08x %08x\n", cpu_ppc_load_tbu(env), | |
| 2925 | + cpu_ppc_load_tbl(env)); | |
| 2920 | 2926 | for (i = 0; i < 16; i++) { |
| 2921 | 2927 | if ((i & 3) == 0) |
| 2922 | 2928 | fprintf(f, "FPR%02d:", i); |
| ... | ... | @@ -2924,8 +2930,8 @@ void cpu_ppc_dump_state(CPUPPCState *env, FILE *f, int flags) |
| 2924 | 2930 | if ((i & 3) == 3) |
| 2925 | 2931 | fprintf(f, "\n"); |
| 2926 | 2932 | } |
| 2927 | - fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x excp:0x%08x\n", | |
| 2928 | - env->spr[SRR0], env->spr[SRR1], env->decr, env->exceptions); | |
| 2933 | + fprintf(f, "SRR0 0x%08x SRR1 0x%08x DECR=0x%08x\n", | |
| 2934 | + env->spr[SRR0], env->spr[SRR1], cpu_ppc_load_decr(env)); | |
| 2929 | 2935 | fprintf(f, "reservation 0x%08x\n", env->reserve); |
| 2930 | 2936 | fflush(f); |
| 2931 | 2937 | } |
| ... | ... | @@ -2952,7 +2958,6 @@ CPUPPCState *cpu_ppc_init(void) |
| 2952 | 2958 | // env->spr[PVR] = 0x00083100; /* MPC755 (G3 embedded) */ |
| 2953 | 2959 | // env->spr[PVR] = 0x00070100; /* IBM 750FX */ |
| 2954 | 2960 | #endif |
| 2955 | - env->decr = 0xFFFFFFFF; | |
| 2956 | 2961 | if (create_ppc_proc(ppc_opcodes, env->spr[PVR]) < 0) |
| 2957 | 2962 | return NULL; |
| 2958 | 2963 | init_spr_rights(env->spr[PVR]); |
| ... | ... | @@ -2976,14 +2981,13 @@ void cpu_ppc_close(CPUPPCState *env) |
| 2976 | 2981 | } |
| 2977 | 2982 | |
| 2978 | 2983 | /*****************************************************************************/ |
| 2979 | -void raise_exception_err (int exception_index, int error_code); | |
| 2980 | 2984 | int print_insn_powerpc (FILE *out, unsigned long insn, unsigned memaddr, |
| 2981 | 2985 | int dialect); |
| 2982 | 2986 | |
| 2983 | 2987 | int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, |
| 2984 | 2988 | int search_pc) |
| 2985 | 2989 | { |
| 2986 | - DisasContext ctx; | |
| 2990 | + DisasContext ctx, *ctxp = &ctx; | |
| 2987 | 2991 | opc_handler_t **table, *handler; |
| 2988 | 2992 | uint32_t pc_start; |
| 2989 | 2993 | uint16_t *gen_opc_end; |
| ... | ... | @@ -2994,8 +2998,6 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, |
| 2994 | 2998 | gen_opc_end = gen_opc_buf + OPC_MAX_SIZE; |
| 2995 | 2999 | gen_opparam_ptr = gen_opparam_buf; |
| 2996 | 3000 | ctx.nip = pc_start; |
| 2997 | - ctx.tb_offset = 0; | |
| 2998 | - ctx.decr_offset = 0; | |
| 2999 | 3001 | ctx.tb = tb; |
| 3000 | 3002 | ctx.exception = EXCP_NONE; |
| 3001 | 3003 | #if defined(CONFIG_USER_ONLY) |
| ... | ... | @@ -3023,26 +3025,22 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, |
| 3023 | 3025 | gen_opc_instr_start[lj] = 1; |
| 3024 | 3026 | } |
| 3025 | 3027 | } |
| 3026 | -#if defined DEBUG_DISAS | |
| 3027 | - if (loglevel > 0) { | |
| 3028 | +#if defined PPC_DEBUG_DISAS | |
| 3029 | + if (loglevel & CPU_LOG_TB_IN_ASM) { | |
| 3028 | 3030 | fprintf(logfile, "----------------\n"); |
| 3029 | 3031 | fprintf(logfile, "nip=%08x super=%d ir=%d\n", |
| 3030 | 3032 | ctx.nip, 1 - msr_pr, msr_ir); |
| 3031 | 3033 | } |
| 3032 | 3034 | #endif |
| 3033 | 3035 | ctx.opcode = ldl_code((void *)ctx.nip); |
| 3034 | -#if defined DEBUG_DISAS | |
| 3035 | - if (loglevel > 0) { | |
| 3036 | +#if defined PPC_DEBUG_DISAS | |
| 3037 | + if (loglevel & CPU_LOG_TB_IN_ASM) { | |
| 3036 | 3038 | fprintf(logfile, "translate opcode %08x (%02x %02x %02x)\n", |
| 3037 | 3039 | ctx.opcode, opc1(ctx.opcode), opc2(ctx.opcode), |
| 3038 | 3040 | opc3(ctx.opcode)); |
| 3039 | 3041 | } |
| 3040 | 3042 | #endif |
| 3041 | 3043 | ctx.nip += 4; |
| 3042 | - ctx.tb_offset++; | |
| 3043 | - /* Check decrementer exception */ | |
| 3044 | - if (++ctx.decr_offset == env->decr + 1) | |
| 3045 | - ctx.exception = EXCP_DECR; | |
| 3046 | 3044 | table = ppc_opcodes; |
| 3047 | 3045 | handler = table[opc1(ctx.opcode)]; |
| 3048 | 3046 | if (is_indirect_opcode(handler)) { |
| ... | ... | @@ -3098,26 +3096,17 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, |
| 3098 | 3096 | (ctx.nip & 0xFC) != 0x04) && |
| 3099 | 3097 | ctx.exception != EXCP_SYSCALL && ctx.exception != EXCP_RFI && |
| 3100 | 3098 | ctx.exception != EXCP_TRAP)) { |
| 3101 | -#if !defined(CONFIG_USER_ONLY) | |
| 3102 | - gen_op_queue_exception(EXCP_TRACE); | |
| 3103 | -#endif | |
| 3104 | - if (ctx.exception == EXCP_NONE) { | |
| 3105 | - ctx.exception = EXCP_TRACE; | |
| 3106 | - } | |
| 3099 | + RET_EXCP(ctxp, EXCP_TRACE, 0); | |
| 3107 | 3100 | } |
| 3108 | 3101 | /* if we reach a page boundary, stop generation */ |
| 3109 | 3102 | if ((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) { |
| 3110 | - if (ctx.exception == EXCP_NONE) { | |
| 3111 | - gen_op_b((long)ctx.tb, ctx.nip); | |
| 3112 | - ctx.exception = EXCP_BRANCH; | |
| 3113 | - } | |
| 3103 | + RET_EXCP(ctxp, EXCP_BRANCH, 0); | |
| 3114 | 3104 | } |
| 3115 | 3105 | } |
| 3116 | - /* In case of branch, this has already been done *BEFORE* the branch */ | |
| 3117 | - if (ctx.exception != EXCP_BRANCH && ctx.exception != EXCP_RFI) { | |
| 3118 | - gen_op_update_tb(ctx.tb_offset); | |
| 3119 | - gen_op_update_decr(ctx.decr_offset); | |
| 3120 | - gen_op_process_exceptions(ctx.nip); | |
| 3106 | + if (ctx.exception == EXCP_NONE) { | |
| 3107 | + gen_op_b((unsigned long)ctx.tb, ctx.nip); | |
| 3108 | + } else if (ctx.exception != EXCP_BRANCH) { | |
| 3109 | + gen_op_set_T0(0); | |
| 3121 | 3110 | } |
| 3122 | 3111 | #if 1 |
| 3123 | 3112 | /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump |
| ... | ... | @@ -3144,15 +3133,16 @@ int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb, |
| 3144 | 3133 | } |
| 3145 | 3134 | env->access_type = ACCESS_INT; |
| 3146 | 3135 | #ifdef DEBUG_DISAS |
| 3147 | - if (loglevel > 0) { | |
| 3136 | + if (loglevel & CPU_LOG_TB_CPU) { | |
| 3148 | 3137 | fprintf(logfile, "---------------- excp: %04x\n", ctx.exception); |
| 3149 | 3138 | cpu_ppc_dump_state(env, logfile, 0); |
| 3139 | + } | |
| 3140 | + if (loglevel & CPU_LOG_TB_IN_ASM) { | |
| 3150 | 3141 | fprintf(logfile, "IN: %s\n", lookup_symbol((void *)pc_start)); |
| 3151 | -#if defined(CONFIG_USER_ONLY) | |
| 3152 | 3142 | disas(logfile, (void *)pc_start, ctx.nip - pc_start, 0, 0); |
| 3153 | -#endif | |
| 3154 | 3143 | fprintf(logfile, "\n"); |
| 3155 | - | |
| 3144 | + } | |
| 3145 | + if (loglevel & CPU_LOG_TB_OP) { | |
| 3156 | 3146 | fprintf(logfile, "OP:\n"); |
| 3157 | 3147 | dump_ops(gen_opc_buf, gen_opparam_buf); |
| 3158 | 3148 | fprintf(logfile, "\n"); | ... | ... |