--- trunk/src/cpus/cpu_ppc_instr.c 2007/10/08 16:19:23 20 +++ trunk/src/cpus/cpu_ppc_instr.c 2007/10/08 16:19:37 22 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2005 Anders Gavare. All rights reserved. + * Copyright (C) 2005-2006 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_ppc_instr.c,v 1.44 2005/11/24 01:31:54 debug Exp $ + * $Id: cpu_ppc_instr.c,v 1.59 2006/02/09 22:40:27 debug Exp $ * * POWER/PowerPC instructions. * @@ -46,6 +46,20 @@ #define DOT2(n) X(n ## _dot) { instr(n)(cpu,ic); \ update_cr0(cpu, reg(ic->arg[2])); } +#ifndef CHECK_FOR_FPU_EXCEPTION +#define CHECK_FOR_FPU_EXCEPTION { if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { \ + /* Synchronize the PC, and cause an FPU exception: */ \ + uint64_t low_pc = ((size_t)ic - \ + (size_t)cpu->cd.ppc.cur_ic_page) \ + / sizeof(struct ppc_instr_call); \ + cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << \ + PPC_INSTR_ALIGNMENT_SHIFT)) + (low_pc << \ + PPC_INSTR_ALIGNMENT_SHIFT); \ + ppc_exception(cpu, PPC_EXCEPTION_FPU); \ + return; } } +#endif + + /* * nop: Do nothing. @@ -76,6 +90,14 @@ { reg(ic->arg[2]) = reg(ic->arg[0]) + (int32_t)ic->arg[1]; } +X(li) +{ + reg(ic->arg[2]) = (int32_t)ic->arg[1]; +} +X(li_0) +{ + reg(ic->arg[2]) = 0; +} /* @@ -160,7 +182,7 @@ */ X(bclr) { - int bo = ic->arg[0], bi31m = ic->arg[1] /* , bh = ic->arg[2] */; + unsigned int bo = ic->arg[0], bi31m = ic->arg[1]; int ctr_ok, cond_ok; uint64_t old_pc = cpu->pc; MODE_uint_t tmp, addr = cpu->cd.ppc.spr[SPR_LR]; @@ -187,19 +209,19 @@ PPC_INSTR_ALIGNMENT_SHIFT); } else { /* Find the new physical page and update pointers: */ - DYNTRANS_PC_TO_POINTERS(cpu); + quick_pc_to_pointers(cpu); } } } X(bclr_20) { cpu->pc = cpu->cd.ppc.spr[SPR_LR]; - DYNTRANS_PC_TO_POINTERS(cpu); + quick_pc_to_pointers(cpu); } X(bclr_l) { uint64_t low_pc, old_pc = cpu->pc; - int bo = ic->arg[0], bi31m = ic->arg[1] /* , bh = ic->arg[2] */; + unsigned int bo = ic->arg[0], bi31m = ic->arg[1] /* ,bh = ic->arg[2]*/; int ctr_ok, cond_ok; MODE_uint_t tmp, addr = cpu->cd.ppc.spr[SPR_LR]; if (!(bo & 4)) @@ -213,8 +235,9 @@ /* Calculate return PC: */ low_pc = ((size_t)ic - (size_t) cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call) + 1; - cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.spr[SPR_LR] += (low_pc << 2); + cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) + << PPC_INSTR_ALIGNMENT_SHIFT); + cpu->cd.ppc.spr[SPR_LR] += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); if (ctr_ok && cond_ok) { uint64_t mask_within_page = @@ -234,7 +257,7 @@ PPC_INSTR_ALIGNMENT_SHIFT); } else { /* Find the new physical page and update pointers: */ - DYNTRANS_PC_TO_POINTERS(cpu); + quick_pc_to_pointers(cpu); } } } @@ -249,7 +272,7 @@ */ X(bcctr) { - int bo = ic->arg[0], bi31m = ic->arg[1] /* , bh = ic->arg[2] */; + unsigned int bo = ic->arg[0], bi31m = ic->arg[1] /*,bh = ic->arg[2]*/; uint64_t old_pc = cpu->pc; MODE_uint_t addr = cpu->cd.ppc.spr[SPR_CTR]; int cond_ok = (bo >> 4) & 1; @@ -270,14 +293,14 @@ PPC_INSTR_ALIGNMENT_SHIFT); } else { /* Find the new physical page and update pointers: */ - DYNTRANS_PC_TO_POINTERS(cpu); + quick_pc_to_pointers(cpu); } } } X(bcctr_l) { uint64_t low_pc, old_pc = cpu->pc; - int bo = ic->arg[0], bi31m = ic->arg[1] /* , bh = ic->arg[2] */; + unsigned int bo = ic->arg[0], bi31m = ic->arg[1] /*,bh = ic->arg[2] */; MODE_uint_t addr = cpu->cd.ppc.spr[SPR_CTR]; int cond_ok = (bo >> 4) & 1; cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> bi31m) & 1) ); @@ -285,8 +308,9 @@ /* Calculate return PC: */ low_pc = ((size_t)ic - (size_t) cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call) + 1; - cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.spr[SPR_LR] += (low_pc << 2); + cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) + << PPC_INSTR_ALIGNMENT_SHIFT); + cpu->cd.ppc.spr[SPR_LR] += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); if (cond_ok) { uint64_t mask_within_page = @@ -304,7 +328,7 @@ PPC_INSTR_ALIGNMENT_SHIFT); } else { /* Find the new physical page and update pointers: */ - DYNTRANS_PC_TO_POINTERS(cpu); + quick_pc_to_pointers(cpu); } } } @@ -313,40 +337,34 @@ /* * b: Branch (to a different translated page) * - * arg[0] = relative offset (as an int32_t) + * arg[0] = relative offset (as an int32_t) from start of page */ X(b) { - uint64_t low_pc; - - /* Calculate new PC from this instruction + arg[0] */ - low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->pc += (low_pc << 2); + cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->pc += (int32_t)ic->arg[0]; /* Find the new physical page and update the translation pointers: */ - DYNTRANS_PC_TO_POINTERS(cpu); + quick_pc_to_pointers(cpu); } X(ba) { cpu->pc = (int32_t)ic->arg[0]; - DYNTRANS_PC_TO_POINTERS(cpu); + quick_pc_to_pointers(cpu); } /* * bc: Branch Conditional (to a different translated page) * - * arg[0] = relative offset (as an int32_t) + * arg[0] = relative offset (as an int32_t) from start of page * arg[1] = bo - * arg[2] = bi + * arg[2] = 31-bi */ X(bc) { MODE_uint_t tmp; - int ctr_ok, cond_ok, bi = ic->arg[2], bo = ic->arg[1]; + unsigned int ctr_ok, cond_ok, bi31m = ic->arg[2], bo = ic->arg[1]; if (!(bo & 4)) cpu->cd.ppc.spr[SPR_CTR] --; ctr_ok = (bo >> 2) & 1; @@ -354,20 +372,22 @@ ctr_ok |= ( (tmp != 0) ^ ((bo >> 1) & 1) ); cond_ok = (bo >> 4) & 1; cond_ok |= ( ((bo >> 3) & 1) == - ((cpu->cd.ppc.cr >> (31-bi)) & 1) ); + ((cpu->cd.ppc.cr >> (bi31m)) & 1) ); if (ctr_ok && cond_ok) instr(b)(cpu,ic); } X(bcl) { MODE_uint_t tmp; - int ctr_ok, cond_ok, bi = ic->arg[2], bo = ic->arg[1], low_pc; + unsigned int ctr_ok, cond_ok, bi31m = ic->arg[2], bo = ic->arg[1]; + int low_pc; /* Calculate LR: */ low_pc = ((size_t)ic - (size_t) cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call) + 1; - cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.spr[SPR_LR] += (low_pc << 2); + cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) + << PPC_INSTR_ALIGNMENT_SHIFT); + cpu->cd.ppc.spr[SPR_LR] += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); if (!(bo & 4)) cpu->cd.ppc.spr[SPR_CTR] --; @@ -376,7 +396,7 @@ ctr_ok |= ( (tmp != 0) ^ ((bo >> 1) & 1) ); cond_ok = (bo >> 4) & 1; cond_ok |= ( ((bo >> 3) & 1) == - ((cpu->cd.ppc.cr >> (31-bi)) & 1) ); + ((cpu->cd.ppc.cr >> bi31m) & 1) ); if (ctr_ok && cond_ok) instr(b)(cpu,ic); } @@ -398,12 +418,12 @@ * * arg[0] = new ic ptr * arg[1] = bo - * arg[2] = bi + * arg[2] = 31-bi */ X(bc_samepage) { MODE_uint_t tmp; - int ctr_ok, cond_ok, bi = ic->arg[2], bo = ic->arg[1]; + unsigned int ctr_ok, cond_ok, bi31m = ic->arg[2], bo = ic->arg[1]; if (!(bo & 4)) cpu->cd.ppc.spr[SPR_CTR] --; ctr_ok = (bo >> 2) & 1; @@ -411,28 +431,34 @@ ctr_ok |= ( (tmp != 0) ^ ((bo >> 1) & 1) ); cond_ok = (bo >> 4) & 1; cond_ok |= ( ((bo >> 3) & 1) == - ((cpu->cd.ppc.cr >> (31-bi)) & 1) ); + ((cpu->cd.ppc.cr >> bi31m) & 1) ); if (ctr_ok && cond_ok) cpu->cd.ppc.next_ic = (struct ppc_instr_call *) ic->arg[0]; } -X(bc_samepage_no_ctr) +X(bc_samepage_simple0) { - int cond_ok, bi = ic->arg[2], bo = ic->arg[1]; - cond_ok = (bo >> 4) & 1; - cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> (31-bi)) & 1) ); - if (cond_ok) + int bi31m = ic->arg[2]; + if (!((cpu->cd.ppc.cr >> bi31m) & 1)) + cpu->cd.ppc.next_ic = (struct ppc_instr_call *) ic->arg[0]; +} +X(bc_samepage_simple1) +{ + int bi31m = ic->arg[2]; + if ((cpu->cd.ppc.cr >> bi31m) & 1) cpu->cd.ppc.next_ic = (struct ppc_instr_call *) ic->arg[0]; } X(bcl_samepage) { MODE_uint_t tmp; - int ctr_ok, cond_ok, bi = ic->arg[2], bo = ic->arg[1], low_pc; + unsigned int ctr_ok, cond_ok, bi31m = ic->arg[2], bo = ic->arg[1]; + int low_pc; /* Calculate LR: */ low_pc = ((size_t)ic - (size_t) cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call) + 1; - cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.spr[SPR_LR] += (low_pc << 2); + cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) + << PPC_INSTR_ALIGNMENT_SHIFT); + cpu->cd.ppc.spr[SPR_LR] += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); if (!(bo & 4)) cpu->cd.ppc.spr[SPR_CTR] --; @@ -441,7 +467,7 @@ ctr_ok |= ( (tmp != 0) ^ ((bo >> 1) & 1) ); cond_ok = (bo >> 4) & 1; cond_ok |= ( ((bo >> 3) & 1) == - ((cpu->cd.ppc.cr >> (31-bi)) & 1) ); + ((cpu->cd.ppc.cr >> bi31m) & 1) ); if (ctr_ok && cond_ok) cpu->cd.ppc.next_ic = (struct ppc_instr_call *) ic->arg[0]; } @@ -450,75 +476,60 @@ /* * bl: Branch and Link (to a different translated page) * - * arg[0] = relative offset (as an int32_t) + * arg[0] = relative offset (as an int32_t) from start of page + * arg[1] = lr offset (relative to start of current page) */ X(bl) { - uint32_t low_pc; - - /* Calculate LR: */ - low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call) + 1; - cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.spr[SPR_LR] += (low_pc << 2); - - /* Calculate new PC from this instruction + arg[0] */ - low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->pc += (low_pc << 2); + /* Calculate LR and new PC: */ + cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); + cpu->cd.ppc.spr[SPR_LR] = cpu->pc + ic->arg[1]; cpu->pc += (int32_t)ic->arg[0]; /* Find the new physical page and update the translation pointers: */ - DYNTRANS_PC_TO_POINTERS(cpu); + quick_pc_to_pointers(cpu); } X(bla) { - uint32_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call) + 1; - cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.spr[SPR_LR] += (low_pc << 2); + /* Calculate LR: */ + cpu->cd.ppc.spr[SPR_LR] = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) + << PPC_INSTR_ALIGNMENT_SHIFT)) + ic->arg[1]; + cpu->pc = (int32_t)ic->arg[0]; - DYNTRANS_PC_TO_POINTERS(cpu); + quick_pc_to_pointers(cpu); } /* * bl_trace: Branch and Link (to a different translated page) (with trace) * - * arg[0] = relative offset (as an int32_t) + * arg[0] = relative offset (as an int32_t) from start of page + * arg[1] = lr offset (relative to start of current page) */ X(bl_trace) { - uint32_t low_pc; - /* Calculate LR: */ - low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call) + 1; - cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.spr[SPR_LR] += (low_pc << 2); + cpu->cd.ppc.spr[SPR_LR] = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) + << PPC_INSTR_ALIGNMENT_SHIFT)) + ic->arg[1]; - /* Calculate new PC from this instruction + arg[0] */ - low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->pc += (low_pc << 2); + /* Calculate new PC from start of page + arg[0] */ + cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); cpu->pc += (int32_t)ic->arg[0]; cpu_functioncall_trace(cpu, cpu->pc); /* Find the new physical page and update the translation pointers: */ - DYNTRANS_PC_TO_POINTERS(cpu); + quick_pc_to_pointers(cpu); } X(bla_trace) { - uint32_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call) + 1; - cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.spr[SPR_LR] += (low_pc << 2); + /* Calculate LR: */ + cpu->cd.ppc.spr[SPR_LR] = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) + << PPC_INSTR_ALIGNMENT_SHIFT)) + ic->arg[1]; + cpu->pc = (int32_t)ic->arg[0]; cpu_functioncall_trace(cpu, cpu->pc); - DYNTRANS_PC_TO_POINTERS(cpu); + quick_pc_to_pointers(cpu); } @@ -526,16 +537,13 @@ * bl_samepage: Branch and Link (to within the same translated page) * * arg[0] = pointer to new ppc_instr_call + * arg[1] = lr offset (relative to start of current page) */ X(bl_samepage) { - uint32_t low_pc; - /* Calculate LR: */ - low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call) + 1; - cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.spr[SPR_LR] += (low_pc << 2); + cpu->cd.ppc.spr[SPR_LR] = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) + << PPC_INSTR_ALIGNMENT_SHIFT)) + ic->arg[1]; cpu->cd.ppc.next_ic = (struct ppc_instr_call *) ic->arg[0]; } @@ -545,24 +553,23 @@ * bl_samepage_trace: Branch and Link (to within the same translated page) * * arg[0] = pointer to new ppc_instr_call + * arg[1] = lr offset (relative to start of current page) */ X(bl_samepage_trace) { uint32_t low_pc; /* Calculate LR: */ - low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call) + 1; - cpu->cd.ppc.spr[SPR_LR] = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.spr[SPR_LR] += (low_pc << 2); + cpu->cd.ppc.spr[SPR_LR] = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) + << PPC_INSTR_ALIGNMENT_SHIFT)) + ic->arg[1]; cpu->cd.ppc.next_ic = (struct ppc_instr_call *) ic->arg[0]; /* Calculate new PC (for the trace) */ low_pc = ((size_t)cpu->cd.ppc.next_ic - (size_t) cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->pc += (low_pc << 2); + cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); + cpu->pc += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); cpu_functioncall_trace(cpu, cpu->pc); } @@ -704,6 +711,19 @@ cpu->cd.ppc.cr &= ~(0xf << bf_shift); cpu->cd.ppc.cr |= (c << bf_shift); } +X(cmpw_cr0) +{ + /* arg[2] is assumed to be 28 */ + int32_t tmp = reg(ic->arg[0]), tmp2 = reg(ic->arg[1]); + cpu->cd.ppc.cr &= ~(0xf0000000); + if (tmp < tmp2) + cpu->cd.ppc.cr |= 0x80000000; + else if (tmp > tmp2) + cpu->cd.ppc.cr |= 0x40000000; + else + cpu->cd.ppc.cr |= 0x20000000; + cpu->cd.ppc.cr |= ((cpu->cd.ppc.spr[SPR_XER] >> 3) & 0x10000000); +} /* @@ -752,6 +772,19 @@ cpu->cd.ppc.cr &= ~(0xf << bf_shift); cpu->cd.ppc.cr |= (c << bf_shift); } +X(cmpwi_cr0) +{ + /* arg[2] is assumed to be 28 */ + int32_t tmp = reg(ic->arg[0]), imm = ic->arg[1]; + cpu->cd.ppc.cr &= ~(0xf0000000); + if (tmp < imm) + cpu->cd.ppc.cr |= 0x80000000; + else if (tmp > imm) + cpu->cd.ppc.cr |= 0x40000000; + else + cpu->cd.ppc.cr |= 0x20000000; + cpu->cd.ppc.cr |= ((cpu->cd.ppc.spr[SPR_XER] >> 3) & 0x10000000); +} /* @@ -788,8 +821,8 @@ { MODE_uint_t addr = reg(ic->arg[0]) + reg(ic->arg[1]); unsigned char cacheline[128]; - int cacheline_size = 1 << cpu->cd.ppc.cpu_type.dlinesize; - int cleared = 0; + size_t cacheline_size = 1 << cpu->cd.ppc.cpu_type.dlinesize; + size_t cleared = 0; /* Synchronize the PC first: */ cpu->pc = (cpu->pc & ~0xfff) + ic->arg[2]; @@ -797,12 +830,17 @@ addr &= ~(cacheline_size - 1); memset(cacheline, 0, sizeof(cacheline)); - /* TODO: Don't use memory_rw() unless it is necessary. */ while (cleared < cacheline_size) { int to_clear = cacheline_size < sizeof(cacheline)? cacheline_size : sizeof(cacheline); - if (cpu->memory_rw(cpu, cpu->mem, addr, cacheline, to_clear, - MEM_WRITE, CACHE_DATA) != MEMORY_ACCESS_OK) { +#ifdef MODE32 + unsigned char *page = cpu->cd.ppc.host_store[addr >> 12]; + if (page != NULL) { + memset(page + (addr & 0xfff), 0, to_clear); + } else +#endif + if (cpu->memory_rw(cpu, cpu->mem, addr, cacheline, + to_clear, MEM_WRITE, CACHE_DATA) != MEMORY_ACCESS_OK) { /* exception */ return; } @@ -821,16 +859,7 @@ */ X(mtfsf) { - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) - + (low_pc << 2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } - + CHECK_FOR_FPU_EXCEPTION; cpu->cd.ppc.fpscr &= ~ic->arg[1]; cpu->cd.ppc.fpscr |= (ic->arg[1] & (*(uint64_t *)ic->arg[0])); } @@ -843,15 +872,7 @@ */ X(mffs) { - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) + (low_pc<<2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } - + CHECK_FOR_FPU_EXCEPTION; (*(uint64_t *)ic->arg[0]) = cpu->cd.ppc.fpscr; } @@ -864,15 +885,12 @@ */ X(fmr) { - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) + (low_pc<<2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } - + /* + * This works like a normal register to register copy, but + * a) it can cause an FPU exception, and b) the move is always + * 64-bit, even when running in 32-bit mode. + */ + CHECK_FOR_FPU_EXCEPTION; *(uint64_t *)ic->arg[1] = *(uint64_t *)ic->arg[0]; } @@ -886,16 +904,7 @@ X(fneg) { uint64_t v; - - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) + (low_pc<<2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } - + CHECK_FOR_FPU_EXCEPTION; v = *(uint64_t *)ic->arg[0]; *(uint64_t *)ic->arg[1] = v ^ 0x8000000000000000ULL; } @@ -913,14 +922,7 @@ struct ieee_float_value fra, frb; int bf_shift = ic->arg[0], c = 0; - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) + (low_pc<<2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } + CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[1], &fra, IEEE_FMT_D); ieee_interpret_float_value(*(uint64_t *)ic->arg[2], &frb, IEEE_FMT_D); @@ -954,14 +956,7 @@ float fl = 0.0; int c = 0; - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) + (low_pc<<2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } + CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[0], &frb, IEEE_FMT_D); if (frb.nan) { @@ -994,14 +989,7 @@ struct ieee_float_value frb; int32_t res = 0; - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) + (low_pc<<2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } + CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[0], &frb, IEEE_FMT_D); if (!frb.nan) { @@ -1030,15 +1018,7 @@ double result = 0.0; int c, nan = 0; - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) - + (low_pc << 2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } + CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[1], &fra, IEEE_FMT_D); ieee_interpret_float_value(*(uint64_t *)ic->arg[2], &frc, IEEE_FMT_D); @@ -1087,15 +1067,7 @@ double result = 0.0; int nan = 0, cc; - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) - + (low_pc << 2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } + CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[1], &fra, IEEE_FMT_D); ieee_interpret_float_value(cpu->cd.ppc.fpr[b], &frb, IEEE_FMT_D); @@ -1140,15 +1112,7 @@ double result = 0.0; int nan = 0, cc; - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) - + (low_pc << 2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } + CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[1], &fra, IEEE_FMT_D); ieee_interpret_float_value(cpu->cd.ppc.fpr[b], &frb, IEEE_FMT_D); @@ -1190,15 +1154,7 @@ double result = 0.0; int nan = 0, c; - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) - + (low_pc << 2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } + CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[0], &fra, IEEE_FMT_D); ieee_interpret_float_value(*(uint64_t *)ic->arg[1], &frb, IEEE_FMT_D); @@ -1235,14 +1191,7 @@ double result = 0.0; int nan = 0, c; - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) + (low_pc<<2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } + CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[0], &fra, IEEE_FMT_D); ieee_interpret_float_value(*(uint64_t *)ic->arg[1], &frb, IEEE_FMT_D); @@ -1279,14 +1228,7 @@ double result = 0.0; int nan = 0, c; - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) + (low_pc<<2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } + CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*(uint64_t *)ic->arg[0], &fra, IEEE_FMT_D); ieee_interpret_float_value(*(uint64_t *)ic->arg[1], &frb, IEEE_FMT_D); @@ -1420,25 +1362,32 @@ /* - * mtsr: Move To Segment Register + * mtsr, mtsrin: Move To Segment Register [Indirect] * * arg[0] = sr number, or for indirect mode: ptr to rb * arg[1] = ptr to rt + * + * TODO: These only work for 32-bit mode! */ X(mtsr) { - /* TODO: This only works for 32-bit mode */ - cpu->cd.ppc.sr[ic->arg[0]] = reg(ic->arg[1]); + int sr_num = ic->arg[0]; + uint32_t old = cpu->cd.ppc.sr[sr_num]; + cpu->cd.ppc.sr[sr_num] = reg(ic->arg[1]); - cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); + if (cpu->cd.ppc.sr[sr_num] != old) + cpu->invalidate_translation_caches(cpu, ic->arg[0] << 28, + INVALIDATE_ALL | INVALIDATE_VADDR_UPPER4); } X(mtsrin) { - /* TODO: This only works for 32-bit mode */ - uint32_t sr_num = reg(ic->arg[0]) >> 28; + int sr_num = reg(ic->arg[0]) >> 28; + uint32_t old = cpu->cd.ppc.sr[sr_num]; cpu->cd.ppc.sr[sr_num] = reg(ic->arg[1]); - cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); + if (cpu->cd.ppc.sr[sr_num] != old) + cpu->invalidate_translation_caches(cpu, sr_num << 28, + INVALIDATE_ALL | INVALIDATE_VADDR_UPPER4); } @@ -1647,6 +1596,15 @@ if (ba | bb) cpu->cd.ppc.cr |= (1 << (31-bt)); } +X(crorc) { + uint32_t iword = ic->arg[0]; int bt = (iword >> 21) & 31; + int ba = (iword >> 16) & 31, bb = (iword >> 11) & 31; + ba = (cpu->cd.ppc.cr >> (31-ba)) & 1; + bb = (cpu->cd.ppc.cr >> (31-bb)) & 1; + cpu->cd.ppc.cr &= ~(1 << (31-bt)); + if (!(ba | bb)) + cpu->cd.ppc.cr |= (1 << (31-bt)); +} X(crnor) { uint32_t iword = ic->arg[0]; int bt = (iword >> 21) & 31; int ba = (iword >> 16) & 31, bb = (iword >> 11) & 31; @@ -1674,6 +1632,7 @@ * arg[1] = pointer to source SPR */ X(mfspr) { + /* TODO: Check permission */ reg(ic->arg[0]) = reg(ic->arg[1]); } X(mfspr_pmc1) { @@ -1702,8 +1661,15 @@ * arg[1] = pointer to the SPR */ X(mtspr) { + /* TODO: Check permission */ reg(ic->arg[1]) = reg(ic->arg[0]); } +X(mtlr) { + cpu->cd.ppc.spr[SPR_LR] = reg(ic->arg[0]); +} +X(mtctr) { + cpu->cd.ppc.spr[SPR_CTR] = reg(ic->arg[0]); +} /* @@ -1719,7 +1685,7 @@ reg_access_msr(cpu, &tmp, 1, 0); cpu->pc = cpu->cd.ppc.spr[SPR_SRR0]; - DYNTRANS_PC_TO_POINTERS(cpu); + quick_pc_to_pointers(cpu); } @@ -1752,10 +1718,42 @@ */ X(mtmsr) { + MODE_uint_t old_pc; + + /* TODO: check permission! */ + /* Synchronize the PC (pointing to _after_ this instruction) */ cpu->pc = (cpu->pc & ~0xfff) + ic->arg[1]; + old_pc = cpu->pc; reg_access_msr(cpu, (uint64_t*)ic->arg[0], 1, 1); + + /* + * Super-ugly hack: If the pc wasn't changed (i.e. if there was no + * exception while accessing the msr), then we _decrease_ the PC by 4 + * again. This is because the next ic could be an end_of_page. + */ + if ((MODE_uint_t)cpu->pc == old_pc) + cpu->pc -= 4; +} + + +/* + * wrteei: Write EE immediate (on PPC405GP) + * + * arg[0] = either 0 or 0x8000 + */ +X(wrteei) +{ + /* TODO: check permission! */ + uint64_t x; + + /* Synchronize the PC (pointing to _after_ this instruction) */ + cpu->pc = (cpu->pc & ~0xfff) + ic->arg[1]; + + reg_access_msr(cpu, &x, 0, 0); + x = (x & ~0x8000) | ic->arg[0]; + reg_access_msr(cpu, &x, 1, 1); } @@ -1990,6 +1988,7 @@ DOT2(andc) X(nor) { reg(ic->arg[2]) = ~(reg(ic->arg[0]) | reg(ic->arg[1])); } DOT2(nor) +X(mr) { reg(ic->arg[2]) = reg(ic->arg[1]); } X(or) { reg(ic->arg[2]) = reg(ic->arg[0]) | reg(ic->arg[1]); } DOT2(or) X(orc) { reg(ic->arg[2]) = reg(ic->arg[0]) | (~reg(ic->arg[1])); } @@ -2230,11 +2229,11 @@ */ X(lfs) { - /* Sync. PC in case of an exception: */ + /* Sync. PC in case of an exception, and remember it: */ uint64_t old_pc, low_pc = ((size_t)ic - (size_t) cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - old_pc = cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) - + (low_pc << 2); + old_pc = cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << + PPC_INSTR_ALIGNMENT_SHIFT)) + (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { ppc_exception(cpu, PPC_EXCEPTION_FPU); return; @@ -2260,11 +2259,11 @@ } X(lfsx) { - /* Sync. PC in case of an exception: */ + /* Sync. PC in case of an exception, and remember it: */ uint64_t old_pc, low_pc = ((size_t)ic - (size_t) cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - old_pc = cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) - + (low_pc << 2); + old_pc = cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << + PPC_INSTR_ALIGNMENT_SHIFT)) + (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { ppc_exception(cpu, PPC_EXCEPTION_FPU); return; @@ -2290,14 +2289,7 @@ } X(lfd) { - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) + (low_pc<<2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } + CHECK_FOR_FPU_EXCEPTION; /* Perform a 64-bit load: */ #ifdef MODE32 @@ -2309,14 +2301,8 @@ } X(lfdx) { - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) + (low_pc<<2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } + CHECK_FOR_FPU_EXCEPTION; + /* Perform a 64-bit load: */ #ifdef MODE32 ppc32_loadstore_indexed @@ -2331,14 +2317,7 @@ struct ieee_float_value val; uint64_t tmp_val; - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) + (low_pc<<2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } + CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*old_arg0, &val, IEEE_FMT_D); tmp_val = ieee_store_float_value(val.f, IEEE_FMT_S, val.nan); @@ -2361,14 +2340,7 @@ struct ieee_float_value val; uint64_t tmp_val; - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) + (low_pc<<2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } + CHECK_FOR_FPU_EXCEPTION; ieee_interpret_float_value(*old_arg0, &val, IEEE_FMT_D); tmp_val = ieee_store_float_value(val.f, IEEE_FMT_S, val.nan); @@ -2387,14 +2359,8 @@ } X(stfd) { - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) + (low_pc<<2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } + CHECK_FOR_FPU_EXCEPTION; + /* Perform a 64-bit store: */ #ifdef MODE32 ppc32_loadstore @@ -2405,14 +2371,8 @@ } X(stfdx) { - /* Sync. PC in case of an exception: */ - uint64_t low_pc = ((size_t)ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->pc = (cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2)) + (low_pc<<2); - if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { - ppc_exception(cpu, PPC_EXCEPTION_FPU); - return; - } + CHECK_FOR_FPU_EXCEPTION; + /* Perform a 64-bit store: */ #ifdef MODE32 ppc32_loadstore_indexed @@ -2428,8 +2388,7 @@ */ X(tlbia) { -printf("tlbia\n"); -exit(1); + printf("[ tlbia ]\n"); cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); } @@ -2453,6 +2412,9 @@ cpu->pc = (cpu->pc & ~0xfff) + ic->arg[1]; ppc_exception(cpu, PPC_EXCEPTION_SC); + + /* This caused an update to the PC register, so there is no need + to worry about the next instruction being an end_of_page. */ } @@ -2473,10 +2435,25 @@ X(openfirmware) { of_emul(cpu); + if (cpu->running == 0) { + cpu->running_translated = 0; + } cpu->pc = cpu->cd.ppc.spr[SPR_LR]; if (cpu->machine->show_trace_tree) cpu_functioncall_trace_return(cpu); - DYNTRANS_PC_TO_POINTERS(cpu); + quick_pc_to_pointers(cpu); +} + + +/* + * tlbsx_dot: TLB scan + */ +X(tlbsx_dot) +{ + /* TODO */ + cpu->cd.ppc.cr &= ~(0xf0000000); + cpu->cd.ppc.cr |= 0x20000000; + cpu->cd.ppc.cr |= ((cpu->cd.ppc.spr[SPR_XER] >> 3) & 0x10000000); } @@ -2485,6 +2462,8 @@ */ X(tlbli) { + fatal("tlbli\n"); + cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); } @@ -2496,7 +2475,8 @@ /* MODE_uint_t vaddr = reg(ic->arg[0]); MODE_uint_t paddr = cpu->cd.ppc.spr[SPR_RPA]; */ - /* TODO? */ + fatal("tlbld\n"); + cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); } @@ -2506,11 +2486,11 @@ X(end_of_page) { /* Update the PC: (offset 0, but on the next page) */ - cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->pc += (PPC_IC_ENTRIES_PER_PAGE << 2); + cpu->pc &= ~((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT); + cpu->pc += (PPC_IC_ENTRIES_PER_PAGE << PPC_INSTR_ALIGNMENT_SHIFT); /* Find the new physical page and update the translation pointers: */ - DYNTRANS_PC_TO_POINTERS(cpu); + quick_pc_to_pointers(cpu); /* end_of_page doesn't count as an executed instruction: */ cpu->n_translated_instrs --; @@ -2534,6 +2514,9 @@ uint32_t iword, mask; unsigned char *page; unsigned char ib[4]; +#ifdef DYNTRANS_BACKEND + int simple = 0; +#endif int main_opcode, rt, rs, ra, rb, rc, aa_bit, l_bit, lk_bit, spr, sh, xo, imm, load, size, update, zero, bf, bo, bi, bh, oe_bit, n64=0, bfa, fp, byterev, nb, mb, me; @@ -2567,16 +2550,7 @@ } iword = *((uint32_t *)&ib[0]); - -#ifdef HOST_LITTLE_ENDIAN - if (cpu->byte_order == EMUL_BIG_ENDIAN) -#else - if (cpu->byte_order == EMUL_LITTLE_ENDIAN) -#endif - iword = ((iword & 0xff) << 24) | - ((iword & 0xff00) << 8) | - ((iword & 0xff0000) >> 8) | - ((iword & 0xff000000) >> 24); + iword = BE32_TO_HOST(iword); #define DYNTRANS_TO_BE_TRANSLATED_HEAD @@ -2592,6 +2566,11 @@ switch (main_opcode) { + case 0x04: + fatal("[ TODO: ALTIVEC ]\n"); + ic->f = instr(nop); + break; + case PPC_HI6_MULLI: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; @@ -2627,8 +2606,12 @@ imm = (int16_t)(iword & 0xffff); if (l_bit) ic->f = instr(cmpdi); - else - ic->f = instr(cmpwi); + else { + if (bf == 0) + ic->f = instr(cmpwi_cr0); + else + ic->f = instr(cmpwi); + } } ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = (ssize_t)imm; @@ -2658,12 +2641,14 @@ rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; ic->f = instr(addi); if (ra == 0) - ic->arg[0] = (size_t)(&cpu->cd.ppc.zero); + ic->f = instr(li); else ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = (int16_t)(iword & 0xffff); if (main_opcode == PPC_HI6_ADDIS) ic->arg[1] <<= 16; + if (ra == 0 && ic->arg[1] == 0) + ic->f = instr(li_0); ic->arg[2] = (size_t)(&cpu->cd.ppc.gpr[rt]); break; @@ -2779,21 +2764,23 @@ samepage_function = instr(bcl_samepage); } else { ic->f = instr(bc); - if (bo & 4) - samepage_function = instr(bc_samepage_no_ctr); - else + if ((bo & 0x14) == 0x04) { + samepage_function = bo & 8? + instr(bc_samepage_simple1) : + instr(bc_samepage_simple0); + } else samepage_function = instr(bc_samepage); } - ic->arg[0] = (ssize_t)tmp_addr; + ic->arg[0] = (ssize_t)(tmp_addr + (addr & 0xffc)); ic->arg[1] = bo; - ic->arg[2] = bi; + ic->arg[2] = 31-bi; /* Branches are calculated as cur PC + offset. */ /* Special case: branch within the same page: */ { uint64_t mask_within_page = ((PPC_IC_ENTRIES_PER_PAGE-1) << 2) | 3; uint64_t old_pc = addr; - uint64_t new_pc = old_pc + (int32_t)ic->arg[0]; + uint64_t new_pc = old_pc + (int32_t)tmp_addr; if ((old_pc & ~mask_within_page) == (new_pc & ~mask_within_page)) { ic->f = samepage_function; @@ -2833,14 +2820,15 @@ ic->f = instr(b); samepage_function = instr(b_samepage); } - ic->arg[0] = (ssize_t)tmp_addr; + ic->arg[0] = (ssize_t)(tmp_addr + (addr & 0xffc)); + ic->arg[1] = (addr & 0xffc) + 4; /* Branches are calculated as cur PC + offset. */ /* Special case: branch within the same page: */ { uint64_t mask_within_page = ((PPC_IC_ENTRIES_PER_PAGE-1) << 2) | 3; uint64_t old_pc = addr; - uint64_t new_pc = old_pc + (int32_t)ic->arg[0]; + uint64_t new_pc = old_pc + (int32_t)tmp_addr; if ((old_pc & ~mask_within_page) == (new_pc & ~mask_within_page)) { ic->f = samepage_function; @@ -2914,6 +2902,7 @@ case PPC_19_CRANDC: case PPC_19_CREQV: case PPC_19_CROR: + case PPC_19_CRORC: case PPC_19_CRNOR: case PPC_19_CRXOR: switch (xo) { @@ -2921,6 +2910,7 @@ case PPC_19_CRANDC: ic->f = instr(crandc); break; case PPC_19_CREQV: ic->f = instr(creqv); break; case PPC_19_CROR: ic->f = instr(cror); break; + case PPC_19_CRORC: ic->f = instr(crorc); break; case PPC_19_CRNOR: ic->f = instr(crnor); break; case PPC_19_CRXOR: ic->f = instr(crxor); break; } @@ -3020,8 +3010,12 @@ } else { if (l_bit) ic->f = instr(cmpd); - else - ic->f = instr(cmpw); + else { + if (bf == 0) + ic->f = instr(cmpw_cr0); + else + ic->f = instr(cmpw); + } } ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[rb]); @@ -3059,7 +3053,15 @@ debug_spr_usage(cpu->pc, spr); ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); ic->arg[1] = (size_t)(&cpu->cd.ppc.spr[spr]); - ic->f = instr(mtspr); + switch (spr) { + case SPR_LR: + ic->f = instr(mtlr); + break; + case SPR_CTR: + ic->f = instr(mtctr); + break; + default:ic->f = instr(mtspr); + } break; case PPC_31_MFCR: @@ -3200,6 +3202,11 @@ ic->f = instr(tlbli); break; + case PPC_31_TLBSX_DOT: + /* TODO */ + ic->f = instr(tlbsx_dot); + break; + case PPC_31_MFTB: rt = (iword >> 21) & 31; spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31); @@ -3249,6 +3256,11 @@ } break; + case PPC_31_WRTEEI: + ic->arg[0] = iword & 0x8000; + ic->f = instr(wrteei); + break; + case 0x1c3: fatal("[ mtdcr: TODO ]\n"); ic->f = instr(nop); @@ -3381,7 +3393,8 @@ rc_f = instr(andc_dot); break; case PPC_31_NOR: ic->f = instr(nor); rc_f = instr(nor_dot); break; - case PPC_31_OR: ic->f = instr(or); + case PPC_31_OR: ic->f = rs == rb? instr(mr) + : instr(or); rc_f = instr(or_dot); break; case PPC_31_ORC: ic->f = instr(orc); rc_f = instr(orc_dot); break; @@ -3479,6 +3492,23 @@ } break; + case 359: + fatal("[ TODO: 359 ]\n"); + ic->f = instr(nop); + break; + case PPC_31_LVX: + fatal("[ TODO: lvx ]\n"); + ic->f = instr(nop); + break; + case PPC_31_STVX: + fatal("[ TODO: stvx ]\n"); + ic->f = instr(nop); + break; + case PPC_31_STVXL: + fatal("[ TODO: stvxl ]\n"); + ic->f = instr(nop); + break; + default:goto bad; } break;