--- trunk/src/cpu_ppc.c 2007/10/08 16:18:31 11 +++ trunk/src/cpu_ppc.c 2007/10/08 16:18:38 12 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_ppc.c,v 1.63 2005/06/26 22:23:42 debug Exp $ + * $Id: cpu_ppc.c,v 1.85 2005/08/15 05:59:53 debug Exp $ * * PowerPC/POWER CPU emulation. */ @@ -65,12 +65,9 @@ #include "opcodes_ppc.h" #include "symbol.h" - -extern volatile int single_step; -extern int old_show_trace_tree; -extern int old_instruction_trace; -extern int old_quiet_mode; -extern int quiet_mode; +#define DYNTRANS_DUALMODE_32 +#define DYNTRANS_32 +#include "tmp_ppc_head.c" /* @@ -101,7 +98,13 @@ if (found == -1) return 0; - cpu->memory_rw = ppc_memory_rw; + cpu->memory_rw = ppc_memory_rw; + cpu->update_translation_table = ppc_update_translation_table; + cpu->invalidate_translation_caches_paddr = + ppc_invalidate_translation_caches_paddr; + cpu->invalidate_code_translation_caches = + ppc_invalidate_code_translation_caches; + cpu->cd.ppc.cpu_type = cpu_type_defs[found]; cpu->name = cpu->cd.ppc.cpu_type.name; cpu->byte_order = EMUL_BIG_ENDIAN; @@ -111,6 +114,8 @@ /* Current operating mode: */ cpu->cd.ppc.bits = cpu->cd.ppc.cpu_type.bits; + cpu->is_32bit = (cpu->cd.ppc.bits == 32)? 1 : 0; + /* Only show name and caches etc for CPU nr 0 (in SMP machines): */ if (cpu_id == 0) { debug("%s", cpu->cd.ppc.cpu_type.name); @@ -204,7 +209,7 @@ /* * reg_access_msr(): */ -static void reg_access_msr(struct cpu *cpu, uint64_t *valuep, int writeflag) +void reg_access_msr(struct cpu *cpu, uint64_t *valuep, int writeflag) { if (valuep == NULL) { fatal("reg_access_msr(): NULL\n"); @@ -257,7 +262,7 @@ debug("%08x", (int)cpu->cd.ppc.lr); else debug("%016llx", (long long)cpu->cd.ppc.lr); - debug(" cr = 0x%08x\n", (int)cpu->cd.ppc.cr); + debug(" cr = 0x%08x\n", (int)cpu->cd.ppc.cr); debug("cpu%i: ctr = 0x", x); if (bits32) @@ -284,10 +289,11 @@ } else { /* 64-bit: */ for (i=0; i> 1) + ((i & 1) << 4); if ((i % 2) == 0) debug("cpu%i:", x); - debug(" r%02i = 0x%016llx ", i, - (long long)cpu->cd.ppc.gpr[i]); + debug(" r%02i = 0x%016llx ", r, + (long long)cpu->cd.ppc.gpr[r]); if ((i % 2) == 1) debug("\n"); } @@ -296,7 +302,7 @@ /* Other special registers: */ reg_access_msr(cpu, &tmp, 0); debug("cpu%i: msr = 0x%016llx ", x, (long long)tmp); - debug("tb = 0x%08x%08x\n", + debug("tb = 0x%08x%08x\n", (int)cpu->cd.ppc.tbu, (int)cpu->cd.ppc.tbl); debug("cpu%i: dec = 0x%08x hdec = 0x%08x\n", x, (int)cpu->cd.ppc.dec, (int)cpu->cd.ppc.hdec); @@ -411,6 +417,52 @@ /* + * ppc_cpu_show_full_statistics(): + * + * Show detailed statistics on opcode usage on each cpu. + */ +void ppc_cpu_show_full_statistics(struct machine *m) +{ + fatal("ppc_cpu_show_full_statistics(): TODO\n"); +} + + +/* + * ppc_cpu_tlbdump(): + * + * Called from the debugger to dump the TLB in a readable format. + * x is the cpu number to dump, or -1 to dump all CPUs. + * + * If rawflag is nonzero, then the TLB contents isn't formated nicely, + * just dumped. + */ +void ppc_cpu_tlbdump(struct machine *m, int x, int rawflag) +{ + fatal("ppc_cpu_tlbdump(): TODO\n"); +} + + +/* + * ppc_cpu_interrupt(): + */ +int ppc_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr) +{ + fatal("ppc_cpu_interrupt(): TODO\n"); + return 0; +} + + +/* + * ppc_cpu_interrupt_ack(): + */ +int ppc_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr) +{ + /* fatal("ppc_cpu_interrupt_ack(): TODO\n"); */ + return 0; +} + + +/* * ppc_cpu_disassemble_instr(): * * Convert an instruction word into human readable format, for instruction @@ -455,11 +507,6 @@ debug(": %08x\t", iword); - if (bintrans && !running) { - debug("(bintrans)"); - goto disasm_ret; - } - /* * Decode the instruction: */ @@ -740,16 +787,6 @@ rt = (iword >> 21) & 31; debug("mfcr\tr%i", rt); break; - case PPC_31_DCBST: - case PPC_31_ICBI: - ra = (iword >> 16) & 31; - rb = (iword >> 11) & 31; - switch (xo) { - case PPC_31_DCBST: mnem = "dcbst"; break; - case PPC_31_ICBI: mnem = "icbi"; break; - } - debug("%s\tr%i,r%i", mnem, ra, rb); - break; case PPC_31_MFMSR: rt = (iword >> 21) & 31; debug("mfmsr\tr%i", rt); @@ -778,6 +815,8 @@ case PPC_31_STHUX: case PPC_31_STWX: case PPC_31_STWUX: + case PPC_31_STDX: + case PPC_31_STDUX: /* rs for stores, rt for loads, actually */ rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; @@ -803,10 +842,10 @@ case PPC_31_STWUX: mnem = power? "stux" : "stwux"; break; + case PPC_31_STDX: mnem = "stdx"; break; + case PPC_31_STDUX: mnem = "stdux"; break; } debug("%s\tr%i,r%i,r%i", mnem, rs, ra, rb); - if (running) - goto disasm_ret_nonewline; break; case PPC_31_NEG: case PPC_31_NEGO: @@ -929,7 +968,15 @@ case PPC_31_MFSPR: rt = (iword >> 21) & 31; spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31); - debug("mfspr\tr%i,spr%i", rt, spr); + switch (spr) { + case 8: debug("mflr\tr%i", rt); break; + case 272: debug("mfsprg\t0,r%i", rt); break; + case 273: debug("mfsprg\t1,r%i", rt); break; + case 274: debug("mfsprg\t2,r%i", rt); break; + case 275: debug("mfsprg\t3,r%i", rt); break; + case 1008: debug("mfdbsr\tr%i", rt); break; + default:debug("mfspr\tr%i,spr%i", rt, spr); + } break; case PPC_31_TLBIE: /* TODO: what is ra? The IBM online docs didn't say */ @@ -956,6 +1003,33 @@ mnem = power? "cntlz" : "cntlzw"; debug("%s\tr%i,r%i", mnem, rc? "." : "", ra, rs); break; + case PPC_31_CLF: /* POWER only */ + case PPC_31_CLI: /* POWER only */ + case PPC_31_DCLST: /* POWER only */ + case PPC_31_DCBF: /* PowerPC only */ + case PPC_31_DCBI: /* PowerPC only */ + case PPC_31_DCBST: /* PowerPC only */ + case PPC_31_DCBTST: /* PowerPC only */ + case PPC_31_DCBT: /* PowerPC only */ + case PPC_31_ICBI: /* PowerPC only */ + case PPC_31_DCBZ: /* POWER/PowerPC */ + ra = (iword >> 16) & 31; + rb = (iword >> 11) & 31; + switch (xo) { + case PPC_31_CLF: mnem = "clf"; break; + case PPC_31_CLI: mnem = "cli"; break; + case PPC_31_DCLST: mnem = "dclst"; break; + case PPC_31_DCBF: mnem = "dcbf"; break; + case PPC_31_DCBI: mnem = "dcbi"; break; + case PPC_31_DCBST: mnem = "dcbst"; break; + case PPC_31_DCBTST:mnem = "dcbtst"; break; + case PPC_31_DCBT: mnem = "dcbt"; break; + case PPC_31_ICBI: mnem = "icbi"; break; + case PPC_31_DCBZ: mnem = power ? + "dclz" : "dcbz"; break; + } + debug("%s\tr%i,r%i", mnem, ra, rb); + break; case PPC_31_SLW: case PPC_31_SRAW: case PPC_31_SRW: @@ -1023,7 +1097,14 @@ case PPC_31_MTSPR: rs = (iword >> 21) & 31; spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31); - debug("mtspr\tspr%i,r%i", spr, rs); + switch (spr) { + case 8: debug("mtlr\tr%i", rs); break; + case 272: debug("mtsprg\t0,r%i", rs); break; + case 273: debug("mtsprg\t1,r%i", rs); break; + case 274: debug("mtsprg\t2,r%i", rs); break; + case 275: debug("mtsprg\t3,r%i", rs); break; + default:debug("mtspr\tspr%i,r%i", spr, rs); + } break; case PPC_31_SYNC: debug("%s", power? "dcs" : "sync"); @@ -1040,8 +1121,23 @@ mnem = power? "stsi" : "stswi"; break; } debug("%s\tr%i,r%i,%i", mnem, rs, ra, nb); - if (running) - goto disasm_ret_nonewline; + break; + case PPC_31_LHBRX: + case PPC_31_LWBRX: + case PPC_31_STHBRX: + case PPC_31_STWBRX: + rt = (iword >> 21) & 31; /* stores use rs */ + ra = (iword >> 16) & 31; + rb = (iword >> 11) & 31; + switch (xo) { + case PPC_31_LHBRX: mnem = "lhbrx"; break; + case PPC_31_LWBRX: mnem = power? + "lbrx" : "lwbrx"; break; + case PPC_31_STHBRX: mnem = "sthbrx"; break; + case PPC_31_STWBRX: mnem = power? + "stbrx" : "stwbrx"; break; + } + debug("%s\tr%i,r%i,r%i", mnem, rt, ra, rb); break; case PPC_31_SRAWI: rs = (iword >> 21) & 31; @@ -1086,6 +1182,7 @@ case PPC_HI6_LHAU: case PPC_HI6_LBZ: case PPC_HI6_LBZU: + case PPC_HI6_LMW: case PPC_HI6_STW: case PPC_HI6_STWU: case PPC_HI6_STH: @@ -1127,103 +1224,23 @@ else debug("r"); debug("%i,%i(r%i)", rs, imm, ra); - if (running) - goto disasm_ret_nonewline; break; default: /* TODO */ debug("unimplemented hi6 = 0x%02x", hi6); } -disasm_ret: debug("\n"); -disasm_ret_nonewline: return sizeof(iword); } /* - * show_trace(): - * - * Show trace tree. This function should be called every time - * a function is called. cpu->cd.ppc.trace_tree_depth is increased here - * and should not be increased by the caller. - * - * Note: This function should not be called if show_trace_tree == 0. - */ -static void show_trace(struct cpu *cpu) -{ - uint64_t offset, addr = cpu->pc; - int x, n_args_to_print; - char strbuf[60]; - char *symbol; - - cpu->cd.ppc.trace_tree_depth ++; - - if (cpu->machine->ncpus > 1) - debug("cpu%i:", cpu->cpu_id); - - symbol = get_symbol_name(&cpu->machine->symbol_context, addr, &offset); - - for (x=0; xcd.ppc.trace_tree_depth; x++) - debug(" "); - - /* debug("<%s>\n", symbol!=NULL? symbol : "no symbol"); */ - - if (symbol != NULL) - debug("<%s(", symbol); - else { - debug("<0x"); - if (cpu->cd.ppc.bits == 32) - debug("%08x", (int)addr); - else - debug("%016llx", (long long)addr); - debug("("); - } - - /* - * TODO: The number of arguments and the symbol type of each - * argument should be taken from the symbol table, in some way. - */ - n_args_to_print = 5; - - for (x=0; xcd.ppc.gpr[x + 3]; - - if (d > -256 && d < 256) - debug("%i", (int)d); - else if (memory_points_to_string(cpu, cpu->mem, d, 1)) { - debug("\"%s\"", memory_conv_to_string(cpu, - cpu->mem, d, strbuf, sizeof(strbuf))); - if (strlen(strbuf) >= sizeof(strbuf)-1) - debug(".."); - } else { - if (cpu->cd.ppc.bits == 32) - debug("0x%x", (int)d); - else - debug("0x%llx", (long long)d); - } - - if (x < n_args_to_print - 1) - debug(","); - - if (x == n_args_to_print - 1) - break; - } - - if (n_args_to_print > 9) - debug(".."); - - debug(")>\n"); -} - - -/* * update_cr0(): * * Sets the top 4 bits of the CR register. */ -static void update_cr0(struct cpu *cpu, uint64_t value) +void update_cr0(struct cpu *cpu, uint64_t value) { int c; @@ -1251,1671 +1268,7 @@ } -/* - * ppc_cpu_run_instr(): - * - * Execute one instruction on a specific CPU. - * - * Return value is the number of instructions executed during this call, - * 0 if no instruction was executed. - */ -int ppc_cpu_run_instr(struct emul *emul, struct cpu *cpu) -{ - uint32_t iword; - unsigned char buf[4]; - unsigned char tmp_data[8]; - size_t tmp_data_len; - char *mnem = NULL; - int r, hi6, rt, rs, ra, rb, xo, lev, sh, me, rc, imm, l_bit, oe_bit; - int c, i, spr, aa_bit, bo, bi, bh, lk_bit, bf, ctr_ok, cond_ok; - int update, load, mb, nb, bt, ba, bb, fpreg, arithflag, old_ca, bfa; - uint64_t tmp=0, tmp2, addr; - uint64_t cached_pc; - - cached_pc = cpu->cd.ppc.pc_last = cpu->pc & ~3; - - /* Check PC against breakpoints: */ - if (!single_step) - for (i=0; imachine->n_breakpoints; i++) - if (cached_pc == cpu->machine->breakpoint_addr[i]) { - fatal("Breakpoint reached, pc=0x"); - if (cpu->cd.ppc.bits == 32) - fatal("%08x", (int)cached_pc); - else - fatal("%016llx", (long long)cached_pc); - fatal("\n"); - single_step = 1; - return 0; - } - - /* Update the Time Base and Decrementer: */ - if ((++ cpu->cd.ppc.tbl) == 0) - cpu->cd.ppc.tbu ++; - - cpu->cd.ppc.dec --; - /* TODO: dec interrupt! */ - - /* TODO: hdec for POWER4+ */ - - /* ROM emulation: (TODO: non-OF-emuls) */ - if (cpu->pc == cpu->cd.ppc.of_emul_addr && - cpu->machine->prom_emulation) { - int res = of_emul(cpu); - if (res) { - cpu->pc = cpu->cd.ppc.lr; - } - return 100; - } - - r = cpu->memory_rw(cpu, cpu->mem, cached_pc, &buf[0], sizeof(buf), - MEM_READ, CACHE_INSTRUCTION | PHYSICAL); - if (!r) - return 0; - - iword = (buf[0] << 24) + (buf[1] << 16) + (buf[2] << 8) + buf[3]; - - if (cpu->machine->instruction_trace) - ppc_cpu_disassemble_instr(cpu, buf, 1, 0, 0); - - cpu->pc += sizeof(iword); - cached_pc += sizeof(iword); - - hi6 = iword >> 26; - - switch (hi6) { - - case PPC_HI6_MULLI: - rt = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - imm = (int16_t)(iword & 0xffff); - cpu->cd.ppc.gpr[rt] = (int64_t)cpu->cd.ppc.gpr[ra] - * (int64_t)imm; - break; - - case PPC_HI6_SUBFIC: - rt = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - imm = (int16_t)(iword & 0xffff); - cpu->cd.ppc.xer &= ~PPC_XER_CA; - if (cpu->cd.ppc.bits == 32) { - tmp = (~cpu->cd.ppc.gpr[ra]) & 0xffffffff; - cpu->cd.ppc.gpr[rt] = tmp + imm + 1; - /* TODO: is this CA correct? */ - /* printf("subfic: tmp = %016llx\n", (long long)tmp); - printf("subfic: rt = %016llx\n\n", - (long long)cpu->cd.ppc.gpr[rt]); */ - if ((tmp >> 32) != (cpu->cd.ppc.gpr[rt] >> 32)) - cpu->cd.ppc.xer |= PPC_XER_CA; - /* High 32 bits are probably undefined in - 32-bit mode (I hope) */ - } else { - /* - * Ugly, but I can't figure out a way right now how - * to get the carry bit out of a 64-bit addition, - * without access to more-than-64-bit operations in C. - */ - tmp = ~cpu->cd.ppc.gpr[ra]; - tmp2 = (tmp >> 32); /* High 32 bits */ - tmp &= 0xffffffff; /* Low 32 bits */ - - tmp += imm + 1; - if ((tmp >> 32) == 0) { - /* No change to upper 32 bits */ - } else if ((tmp >> 32) == 1) { - /* Positive change: */ - tmp2 ++; - } else { - /* Negative change: */ - tmp2 --; - } - - tmp &= 0xffffffff; - - /* TODO: is this CA calculation correct? */ - if ((tmp2 >> 32) != 0) - cpu->cd.ppc.xer |= PPC_XER_CA; - - cpu->cd.ppc.gpr[rt] = (tmp2 << 32) + tmp; - } - break; - - case PPC_HI6_CMPLI: - case PPC_HI6_CMPI: - bf = (iword >> 23) & 7; - l_bit = (iword >> 21) & 1; - ra = (iword >> 16) & 31; - if (hi6 == PPC_HI6_CMPLI) - imm = iword & 0xffff; - else - imm = (int16_t)(iword & 0xffff); - tmp = cpu->cd.ppc.gpr[ra]; - - if (hi6 == PPC_HI6_CMPI) { - if (!l_bit) - tmp = (int64_t)(int32_t)tmp; - if ((int64_t)tmp < (int64_t)imm) - c = 8; - else if ((int64_t)tmp > (int64_t)imm) - c = 4; - else - c = 2; - } else { - if (!l_bit) - tmp &= 0xffffffff; - if ((uint64_t)tmp < (uint64_t)imm) - c = 8; - else if ((uint64_t)tmp > (uint64_t)imm) - c = 4; - else - c = 2; - } - - /* SO bit, copied from XER: */ - c |= ((cpu->cd.ppc.xer >> 31) & 1); - - cpu->cd.ppc.cr &= ~(0xf << (28 - 4*bf)); - cpu->cd.ppc.cr |= (c << (28 - 4*bf)); - break; - - case PPC_HI6_ADDIC: - case PPC_HI6_ADDIC_DOT: - rt = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - rc = hi6 == PPC_HI6_ADDIC_DOT; - imm = (int16_t)(iword & 0xffff); - /* NOTE: Addic doesn't clear CA! */ - if (cpu->cd.ppc.bits == 32) { - tmp = cpu->cd.ppc.gpr[ra] & 0xffffffff; - cpu->cd.ppc.gpr[rt] = tmp + (uint32_t)imm; - /* TODO: is this CA correct? */ - /* printf("addic: tmp = %016llx\n", (long long)tmp); - printf("addic: rt = %016llx\n\n", - (long long)cpu->cd.ppc.gpr[rt]); */ - if ((tmp >> 32) != (cpu->cd.ppc.gpr[rt] >> 32)) - cpu->cd.ppc.xer |= PPC_XER_CA; - /* High 32 bits are probably undefined in - 32-bit mode (I hope) */ - } else { - /* See comment about ugliness regarding SUBFIC */ - tmp = cpu->cd.ppc.gpr[ra]; - tmp2 = (tmp >> 32); /* High 32 bits */ - tmp &= 0xffffffff; /* Low 32 bits */ - - tmp += (int64_t)imm; - if ((tmp >> 32) == 0) { - /* No change to upper 32 bits */ - } else if ((tmp >> 32) == 1) { - /* Positive change: */ - tmp2 ++; - } else { - /* Negative change: */ - tmp2 --; - } - - tmp &= 0xffffffff; - - /* TODO: is this CA calculation correct? */ - if ((tmp2 >> 32) != 0) - cpu->cd.ppc.xer |= PPC_XER_CA; - - cpu->cd.ppc.gpr[rt] = (tmp2 << 32) + tmp; - } - if (rc) - update_cr0(cpu, cpu->cd.ppc.gpr[rt]); - break; - - case PPC_HI6_ADDI: - case PPC_HI6_ADDIS: - rt = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - if (hi6 == PPC_HI6_ADDI) - imm = (int16_t)(iword & 0xffff); - else - imm = (int32_t)((iword & 0xffff) << 16); - if (ra == 0) - tmp = 0; - else - tmp = cpu->cd.ppc.gpr[ra]; - cpu->cd.ppc.gpr[rt] = tmp + imm; - break; - - case PPC_HI6_BC: - aa_bit = (iword >> 1) & 1; - lk_bit = iword & 1; - bo = (iword >> 21) & 31; - bi = (iword >> 16) & 31; - /* Sign-extend addr: */ - addr = (int64_t)(int16_t)(iword & 0xfffc); - - if (!aa_bit) - addr += cpu->cd.ppc.pc_last; - - if (cpu->cd.ppc.bits == 32) - addr &= 0xffffffff; - - if (!(bo & 4)) - cpu->cd.ppc.ctr --; - ctr_ok = (bo >> 2) & 1; - tmp = cpu->cd.ppc.ctr; - if (cpu->cd.ppc.bits == 32) - tmp &= 0xffffffff; - ctr_ok |= ( (tmp != 0) ^ ((bo >> 1) & 1) ); - - cond_ok = (bo >> 4) & 1; - cond_ok |= ( ((bo >> 3) & 1) == - ((cpu->cd.ppc.cr >> (31-bi)) & 1) ); - - if (lk_bit) - cpu->cd.ppc.lr = cpu->pc; - if (ctr_ok && cond_ok) - cpu->pc = addr & ~3; - if (lk_bit && cpu->machine->show_trace_tree) - show_trace(cpu); - break; - - case PPC_HI6_SC: - lev = (iword >> 5) & 0x7f; - if (cpu->machine->userland_emul != NULL) { - useremul_syscall(cpu, lev); - } else { - fatal("[ PPC: pc = 0x%016llx, sc not yet " - "implemented ]\n", (long long)cached_pc); - cpu->running = 0; - return 0; - } - break; - - case PPC_HI6_B: - aa_bit = (iword & 2) >> 1; - lk_bit = iword & 1; - /* Sign-extend addr: */ - addr = (int64_t)(int32_t)((iword & 0x03fffffc) << 6); - addr = (int64_t)addr >> 6; - - if (!aa_bit) - addr += cpu->cd.ppc.pc_last; - - if (cpu->cd.ppc.bits == 32) - addr &= 0xffffffff; - - if (lk_bit) - cpu->cd.ppc.lr = cpu->pc; - - cpu->pc = addr; - - if (lk_bit && cpu->machine->show_trace_tree) - show_trace(cpu); - break; - - case PPC_HI6_19: - xo = (iword >> 1) & 1023; - switch (xo) { - - case PPC_19_MCRF: - bf = (iword >> 23) & 7; - bfa = (iword >> 18) & 7; - tmp = cpu->cd.ppc.cr >> (28 - bfa*4); - tmp &= 0xf; - cpu->cd.ppc.cr &= ~(0xf << (28 - bf*4)); - cpu->cd.ppc.cr |= (tmp << (28 - bf*4)); - break; - - case PPC_19_BCLR: - case PPC_19_BCCTR: - bo = (iword >> 21) & 31; - bi = (iword >> 16) & 31; - bh = (iword >> 11) & 3; - lk_bit = iword & 1; - if (xo == PPC_19_BCLR) { - addr = cpu->cd.ppc.lr; - if (!(bo & 4)) - cpu->cd.ppc.ctr --; - ctr_ok = (bo >> 2) & 1; - tmp = cpu->cd.ppc.ctr; - if (cpu->cd.ppc.bits == 32) - tmp &= 0xffffffff; - ctr_ok |= ( (tmp != 0) ^ ((bo >> 1) & 1) ); - if (!quiet_mode && !lk_bit && - cpu->machine->show_trace_tree) { - cpu->cd.ppc.trace_tree_depth --; - /* TODO: show return value? */ - } - } else { - addr = cpu->cd.ppc.ctr; - ctr_ok = 1; - } - cond_ok = (bo >> 4) & 1; - cond_ok |= ( ((bo >> 3) & 1) == - ((cpu->cd.ppc.cr >> (31-bi)) & 1) ); - if (lk_bit) - cpu->cd.ppc.lr = cpu->pc; - if (ctr_ok && cond_ok) { - cpu->pc = addr & ~3; - if (cpu->cd.ppc.bits == 32) - cpu->pc &= 0xffffffff; - } - if (lk_bit && cpu->machine->show_trace_tree) - show_trace(cpu); - break; - - case PPC_19_ISYNC: - /* TODO: actually sync */ - break; - - case PPC_19_CRAND: - case PPC_19_CRXOR: - case PPC_19_CROR: - case PPC_19_CRNAND: - case PPC_19_CRNOR: - case PPC_19_CRANDC: - case PPC_19_CREQV: - case PPC_19_CRORC: - bt = (iword >> 21) & 31; - 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)); - switch (xo) { - case PPC_19_CRXOR: - if (ba ^ bb) - cpu->cd.ppc.cr |= (1 << (31-bt)); - break; - case PPC_19_CROR: - if (ba | bb) - cpu->cd.ppc.cr |= (1 << (31-bt)); - break; - default: - fatal("[ TODO: crXXX, xo = %i, " - "pc = 0x%016llx ]\n", - xo, (long long) (cpu->cd.ppc.pc_last)); - cpu->running = 0; - return 0; - } - break; - - default: - fatal("[ unimplemented PPC hi6_19, xo = 0x%04x, " - "pc = 0x%016llx ]\n", - xo, (long long) (cpu->cd.ppc.pc_last)); - cpu->running = 0; - return 0; - } - break; - - case PPC_HI6_RLWIMI: - case PPC_HI6_RLWINM: - rs = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - sh = (iword >> 11) & 31; - mb = (iword >> 6) & 31; - me = (iword >> 1) & 31; - rc = iword & 1; - tmp = cpu->cd.ppc.gpr[rs]; - /* TODO: Fix this, its performance is awful: */ - while (sh-- != 0) { - int b = (tmp >> 31) & 1; - tmp = (tmp << 1) | b; - } - - switch (hi6) { - case PPC_HI6_RLWIMI: - for (;;) { - uint64_t mask; - mask = (uint64_t)1 << (31-mb); - cpu->cd.ppc.gpr[ra] &= ~mask; - cpu->cd.ppc.gpr[ra] |= (tmp & mask); - if (mb == me) - break; - mb ++; - if (mb == 32) - mb = 0; - } - break; - case PPC_HI6_RLWINM: - cpu->cd.ppc.gpr[ra] = 0; - for (;;) { - uint64_t mask; - mask = (uint64_t)1 << (31-mb); - cpu->cd.ppc.gpr[ra] |= (tmp & mask); - if (mb == me) - break; - mb ++; - if (mb == 32) - mb = 0; - } - break; - } - if (rc) - update_cr0(cpu, cpu->cd.ppc.gpr[ra]); - break; - - case PPC_HI6_ORI: - case PPC_HI6_ORIS: - rs = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - if (hi6 == PPC_HI6_ORI) - imm = (iword & 0xffff); - else - imm = (iword & 0xffff) << 16; - tmp = cpu->cd.ppc.gpr[rs]; - cpu->cd.ppc.gpr[ra] = tmp | (uint32_t)imm; - break; - - case PPC_HI6_XORI: - case PPC_HI6_XORIS: - rs = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - if (hi6 == PPC_HI6_XORI) - imm = (iword & 0xffff); - else - imm = (iword & 0xffff) << 16; - tmp = cpu->cd.ppc.gpr[rs]; - cpu->cd.ppc.gpr[ra] = tmp ^ (uint32_t)imm; - break; - - case PPC_HI6_ANDI_DOT: - case PPC_HI6_ANDIS_DOT: - rs = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - if (hi6 == PPC_HI6_ANDI_DOT) - imm = (iword & 0xffff); - else - imm = (iword & 0xffff) << 16; - tmp = cpu->cd.ppc.gpr[rs]; - cpu->cd.ppc.gpr[ra] = tmp & (uint32_t)imm; - update_cr0(cpu, cpu->cd.ppc.gpr[ra]); - break; - - case PPC_HI6_30: - xo = (iword >> 2) & 7; - switch (xo) { - case PPC_30_RLDICR: - if (cpu->cd.ppc.bits == 32) { - /* TODO: Illegal instruction. */ - break; - } - rs = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - sh = ((iword >> 11) & 31) | ((iword & 2) << 4); - me = ((iword >> 6) & 31) | (iword & 0x20); - rc = iword & 1; - tmp = cpu->cd.ppc.gpr[rs]; - /* TODO: Fix this, its performance is awful: */ - while (sh-- != 0) { - int b = (tmp >> 63) & 1; - tmp = (tmp << 1) | b; - } - while (me++ < 63) - tmp &= ~((uint64_t)1 << (63-me)); - cpu->cd.ppc.gpr[ra] = tmp; - if (rc) - update_cr0(cpu, cpu->cd.ppc.gpr[ra]); - break; - default: - fatal("[ unimplemented PPC hi6_30, xo = 0x%04x, " - "pc = 0x%016llx ]\n", - xo, (long long) (cpu->cd.ppc.pc_last)); - cpu->running = 0; - return 0; - } - break; - - case PPC_HI6_31: - xo = (iword >> 1) & 1023; - switch (xo) { - - case PPC_31_CMPL: - case PPC_31_CMP: - bf = (iword >> 23) & 7; - l_bit = (iword >> 21) & 1; - ra = (iword >> 16) & 31; - rb = (iword >> 11) & 31; - - tmp = cpu->cd.ppc.gpr[ra]; - tmp2 = cpu->cd.ppc.gpr[rb]; - - if (hi6 == PPC_31_CMP) { - if (!l_bit) { - tmp = (int64_t)(int32_t)tmp; - tmp2 = (int64_t)(int32_t)tmp2; - } - if ((int64_t)tmp < (int64_t)tmp2) - c = 8; - else if ((int64_t)tmp > (int64_t)tmp2) - c = 4; - else - c = 2; - } else { - if (!l_bit) { - tmp &= 0xffffffff; - tmp2 &= 0xffffffff; - } - if ((uint64_t)tmp < (uint64_t)tmp2) - c = 8; - else if ((uint64_t)tmp > (uint64_t)tmp2) - c = 4; - else - c = 2; - } - - /* SO bit, copied from XER: */ - c |= ((cpu->cd.ppc.xer >> 31) & 1); - - cpu->cd.ppc.cr &= ~(0xf << (28 - 4*bf)); - cpu->cd.ppc.cr |= (c << (28 - 4*bf)); - break; - - case PPC_31_MFCR: - rt = (iword >> 21) & 31; - cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.cr; - break; - - case PPC_31_DCBST: - case PPC_31_ICBI: - ra = (iword >> 16) & 31; - rb = (iword >> 11) & 31; - switch (xo) { - case PPC_31_DCBST: mnem = "dcbst"; break; - case PPC_31_ICBI: mnem = "icbi"; break; - } - /* debug("[ %s r%i,r%i: TODO ]\n", mnem, ra, rb); */ - break; - - case PPC_31_MFMSR: - rt = (iword >> 21) & 31; - /* TODO: check pr */ - reg_access_msr(cpu, &cpu->cd.ppc.gpr[rt], 0); - break; - - case PPC_31_MTCRF: - rs = (iword >> 21) & 31; - mb = (iword >> 12) & 255; /* actually fxm, not mb */ - tmp = 0; - for (i=0; i<8; i++, mb <<= 1, tmp <<= 4) - if (mb & 128) - tmp |= 0xf; - cpu->cd.ppc.cr &= ~tmp; - cpu->cd.ppc.cr |= (cpu->cd.ppc.gpr[rs] & tmp); - break; - - case PPC_31_MTMSR: - rs = (iword >> 21) & 31; - l_bit = (iword >> 16) & 1; - /* TODO: the l_bit */ - reg_access_msr(cpu, &cpu->cd.ppc.gpr[rs], 1); - break; - - case PPC_31_LBZX: - case PPC_31_LBZUX: - case PPC_31_LHZX: - case PPC_31_LHZUX: - case PPC_31_LWZX: - case PPC_31_LWZUX: - case PPC_31_STBX: - case PPC_31_STBUX: - case PPC_31_STHX: - case PPC_31_STHUX: - case PPC_31_STWX: - case PPC_31_STWUX: - rs = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - rb = (iword >> 11) & 31; - update = 0; - switch (xo) { - case PPC_31_LBZUX: - case PPC_31_LHZUX: - case PPC_31_LWZUX: - case PPC_31_STBUX: - case PPC_31_STHUX: - case PPC_31_STWUX: - update = 1; - } - if (ra == 0) - addr = 0; - else - addr = cpu->cd.ppc.gpr[ra]; - addr += cpu->cd.ppc.gpr[rb]; - load = 0; - switch (xo) { - case PPC_31_LBZX: - case PPC_31_LBZUX: - case PPC_31_LHZX: - case PPC_31_LHZUX: - case PPC_31_LWZX: - case PPC_31_LWZUX: - load = 1; - } - - if (cpu->machine->instruction_trace) { - if (cpu->cd.ppc.bits == 32) - debug("\t[0x%08llx", (long long)addr); - else - debug("\t[0x%016llx", (long long)addr); - } - - tmp_data_len = 4; - switch (xo) { - case PPC_31_LBZX: - case PPC_31_LBZUX: - case PPC_31_STBX: - case PPC_31_STBUX: - tmp_data_len = 1; - break; - case PPC_31_LHZX: - case PPC_31_LHZUX: - case PPC_31_STHX: - case PPC_31_STHUX: - tmp_data_len = 2; - break; - } - - tmp = 0; - - if (load) { - r = cpu->memory_rw(cpu, cpu->mem, addr, - tmp_data, tmp_data_len, MEM_READ, - CACHE_DATA); - if (r == MEMORY_ACCESS_OK) { - if (cpu->byte_order == - EMUL_BIG_ENDIAN) { - for (i=0; icd.ppc.gpr[rs] = tmp; - } - } else { - tmp = cpu->cd.ppc.gpr[rs]; - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - for (i=0; i> (8*i); - } else { - for (i=0; i> (8*i); - } - - r = cpu->memory_rw(cpu, cpu->mem, addr, - tmp_data, tmp_data_len, MEM_WRITE, - CACHE_DATA); - } - - if (cpu->machine->instruction_trace) { - if (r == MEMORY_ACCESS_OK) { - switch (tmp_data_len) { - case 1: debug(", data = 0x%02x]\n", - (int)tmp); - break; - case 2: debug(", data = 0x%04x]\n", - (int)tmp); - break; - case 4: debug(", data = 0x%08x]\n", - (int)tmp); - break; - default:debug(", data = 0x%016llx]\n", - (long long)tmp); - } - } else - debug(", FAILED]\n"); - } - - if (r != MEMORY_ACCESS_OK) { - /* TODO: exception? */ - return 0; - } - - if (update && ra != 0) - cpu->cd.ppc.gpr[ra] = addr; - break; - - case PPC_31_NEG: - case PPC_31_NEGO: - rt = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - oe_bit = (iword >> 10) & 1; - rc = iword & 1; - if (oe_bit) { - fatal("[ neg: PPC oe not yet implemeted ]\n"); - cpu->running = 0; - return 0; - } - cpu->cd.ppc.gpr[rt] = ~cpu->cd.ppc.gpr[ra] + 1; - if (rc) - update_cr0(cpu, cpu->cd.ppc.gpr[rt]); - break; - - case PPC_31_ADDZE: - case PPC_31_ADDZEO: - rt = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - oe_bit = (iword >> 10) & 1; - rc = iword & 1; - if (oe_bit) { - fatal("[ addz: PPC oe not yet implemeted ]\n"); - cpu->running = 0; - return 0; - } - old_ca = cpu->cd.ppc.xer & PPC_XER_CA; - cpu->cd.ppc.xer &= PPC_XER_CA; - if (cpu->cd.ppc.bits == 32) { - tmp = (uint32_t)cpu->cd.ppc.gpr[ra]; - tmp2 = tmp; - /* printf("addze: tmp2 = %016llx\n", - (long long)tmp2); */ - if (old_ca) - tmp ++; - /* printf("addze: tmp = %016llx\n\n", - (long long)tmp); */ - /* TODO: is this CA correct? */ - if ((tmp >> 32) != (tmp2 >> 32)) - cpu->cd.ppc.xer |= PPC_XER_CA; - /* High 32 bits are probably undefined - in 32-bit mode (I hope) */ - cpu->cd.ppc.gpr[rt] = tmp; - } else { - fatal("ADDZE 64-bit, TODO\n"); - } - if (rc) - update_cr0(cpu, cpu->cd.ppc.gpr[rt]); - break; - - case PPC_31_MTSR: - /* Move to segment register (?) */ - /* TODO */ - break; - - case PPC_31_MFSRIN: - case PPC_31_MTSRIN: - /* mfsrin: Move to segment register indirect (?) */ - /* mtsrin: Move to segment register indirect (?) */ - rt = (iword >> 21) & 31; - rb = (iword >> 11) & 31; - - /* TODO */ - - if (xo == PPC_31_MFSRIN) - cpu->cd.ppc.gpr[rt] = 0; - break; - - case PPC_31_ADDC: - case PPC_31_ADDCO: - case PPC_31_ADDE: - case PPC_31_ADDEO: - case PPC_31_ADD: - case PPC_31_ADDO: - case PPC_31_MULHW: - case PPC_31_MULHWU: - case PPC_31_MULLW: - case PPC_31_MULLWO: - case PPC_31_SUBFE: - case PPC_31_SUBFEO: - case PPC_31_SUBFZE: - case PPC_31_SUBFZEO: - case PPC_31_SUBFC: - case PPC_31_SUBFCO: - case PPC_31_SUBF: - case PPC_31_SUBFO: - rt = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - rb = (iword >> 11) & 31; - oe_bit = (iword >> 10) & 1; - rc = iword & 1; - if (oe_bit) { - fatal("[ add: PPC oe not yet implemeted ]\n"); - cpu->running = 0; - return 0; - } - switch (xo) { - case PPC_31_ADD: - case PPC_31_ADDO: - cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.gpr[ra] + - cpu->cd.ppc.gpr[rb]; - break; - case PPC_31_ADDC: - case PPC_31_ADDCO: - case PPC_31_ADDE: - case PPC_31_ADDEO: - old_ca = cpu->cd.ppc.xer & PPC_XER_CA; - cpu->cd.ppc.xer &= PPC_XER_CA; - if (cpu->cd.ppc.bits == 32) { - tmp = (uint32_t)cpu->cd.ppc.gpr[ra]; - tmp2 = tmp; - /* printf("adde: tmp2 = %016llx\n", - (long long)tmp2); */ - tmp += (uint32_t)cpu->cd.ppc.gpr[rb]; - if ((xo == PPC_31_ADDE || - xo == PPC_31_ADDEO) && old_ca) - tmp ++; - /* printf("adde: tmp = %016llx\n\n", - (long long)tmp); */ - /* TODO: is this CA correct? */ - if ((tmp >> 32) != (tmp2 >> 32)) - cpu->cd.ppc.xer |= PPC_XER_CA; - /* High 32 bits are probably undefined - in 32-bit mode (I hope) */ - cpu->cd.ppc.gpr[rt] = tmp; - } else { - fatal("ADDE 64-bit, TODO\n"); - } - break; - case PPC_31_MULHW: - cpu->cd.ppc.gpr[rt] = (int64_t) ( - (int64_t)(int32_t)cpu->cd.ppc.gpr[ra] * - (int64_t)(int32_t)cpu->cd.ppc.gpr[rb]); - cpu->cd.ppc.gpr[rt] >>= 32; - break; - case PPC_31_MULHWU: - cpu->cd.ppc.gpr[rt] = (uint64_t) ( - (uint64_t)(uint32_t)cpu->cd.ppc.gpr[ra] * - (uint64_t)(uint32_t)cpu->cd.ppc.gpr[rb]); - cpu->cd.ppc.gpr[rt] >>= 32; - break; - case PPC_31_MULLW: - case PPC_31_MULLWO: - cpu->cd.ppc.gpr[rt] = (int64_t) ( - (int32_t)cpu->cd.ppc.gpr[ra] * - (int32_t)cpu->cd.ppc.gpr[rb]); - break; - case PPC_31_SUBF: - case PPC_31_SUBFO: - cpu->cd.ppc.gpr[rt] = ~cpu->cd.ppc.gpr[ra] + - cpu->cd.ppc.gpr[rb] + 1; - break; - case PPC_31_SUBFC: - case PPC_31_SUBFCO: - case PPC_31_SUBFE: - case PPC_31_SUBFEO: - case PPC_31_SUBFZE: - case PPC_31_SUBFZEO: - old_ca = cpu->cd.ppc.xer & PPC_XER_CA; - if (xo == PPC_31_SUBFC || xo == PPC_31_SUBFCO) - old_ca = 1; - cpu->cd.ppc.xer &= PPC_XER_CA; - if (cpu->cd.ppc.bits == 32) { - tmp = (~cpu->cd.ppc.gpr[ra]) - & 0xffffffff; - tmp2 = tmp; - if (xo != PPC_31_SUBFZE && - xo != PPC_31_SUBFZEO) - tmp += (cpu->cd.ppc.gpr[rb] & - 0xffffffff); - if (old_ca) - tmp ++; - /* printf("subfe: tmp2 = %016llx\n", - (long long)tmp2); - printf("subfe: tmp = %016llx\n\n", - (long long)tmp); */ - /* TODO: is this CA correct? */ - if ((tmp >> 32) != (tmp2 >> 32)) - cpu->cd.ppc.xer |= PPC_XER_CA; - /* High 32 bits are probably undefined - in 32-bit mode (I hope) */ - cpu->cd.ppc.gpr[rt] = tmp; - } else { - fatal("SUBFE 64-bit, TODO\n"); - } - break; - } - if (rc) - update_cr0(cpu, cpu->cd.ppc.gpr[rt]); - break; - - case PPC_31_MFSPR: - case PPC_31_MFTB: - rt = (iword >> 21) & 31; - spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31); - switch (spr) { - case 1: cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.xer; - break; - case 8: cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.lr; - break; - case 9: cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.ctr; - break; - case 22:/* TODO: check pr */ - cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.dec; - break; - case 259: /* NOTE: no pr check */ - cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.sprg3; - break; - case 268: /* MFTB, NOTE: no pr check */ - cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.tbl; - break; - case 269: /* MFTBU, NOTE: no pr check */ - cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.tbu; - break; - case 272: - /* TODO: check pr */ - cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.sprg0; - break; - case 273: - /* TODO: check pr */ - cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.sprg1; - break; - case 274: - /* TODO: check pr */ - cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.sprg2; - break; - case 275: - /* TODO: check pr */ - cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.sprg3; - break; - case 287: - /* TODO: check pr */ - cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.pvr; - break; - case 310:/* TODO: check pr */ - cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.hdec; - break; - case 1023: - /* TODO: check pr */ - cpu->cd.ppc.gpr[rt] = cpu->cd.ppc.pir; - break; - default: - fatal("[ unimplemented PPC spr 0x%04x, " - "pc = 0x%016llx ]\n", - spr, (long long) (cpu->cd.ppc.pc_last)); - /* cpu->running = 0; - return 0; */ - break; - } - - /* TODO: is this correct? */ - if (cpu->cd.ppc.bits == 32) - cpu->cd.ppc.gpr[rt] &= 0xffffffff; - break; - - case PPC_31_CNTLZW: - rs = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - rc = iword & 1; - cpu->cd.ppc.gpr[ra] = 0; - for (i=0; i<32; i++) { - if (cpu->cd.ppc.gpr[rs] & - ((uint64_t)1 << (31-i))) - break; - cpu->cd.ppc.gpr[ra] ++; - } - if (rc) - update_cr0(cpu, cpu->cd.ppc.gpr[ra]); - break; - - case PPC_31_SLW: - case PPC_31_SRAW: - case PPC_31_SRW: - case PPC_31_AND: - case PPC_31_ANDC: - case PPC_31_NOR: - case PPC_31_OR: - case PPC_31_ORC: - case PPC_31_XOR: - case PPC_31_NAND: - rs = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - rb = (iword >> 11) & 31; - rc = iword & 1; - switch (xo) { - case PPC_31_SLW: - sh = cpu->cd.ppc.gpr[rb] & 0x3f; - cpu->cd.ppc.gpr[ra] = cpu->cd.ppc.gpr[rs]; - while (sh-- > 0) - cpu->cd.ppc.gpr[ra] <<= 1; - cpu->cd.ppc.gpr[ra] &= 0xffffffff; - break; - case PPC_31_SRAW: - tmp = cpu->cd.ppc.gpr[rs] & 0xffffffff; - cpu->cd.ppc.xer &= ~PPC_XER_CA; - i = 0; - sh = cpu->cd.ppc.gpr[rb] & 0x3f; - if (tmp & 0x80000000) - i = 1; - while (sh-- > 0) { - if (tmp & 1) - i++; - tmp >>= 1; - if (tmp & 0x40000000) - tmp |= 0x80000000; - } - cpu->cd.ppc.gpr[ra] = (int64_t)(int32_t)tmp; - /* Set the CA bit if rs contained a negative - number to begin with, and any 1-bits were - shifted out: */ - if (i > 1) - cpu->cd.ppc.xer |= PPC_XER_CA; - break; - case PPC_31_SRW: - sh = cpu->cd.ppc.gpr[rb] & 0x3f; - cpu->cd.ppc.gpr[ra] = cpu->cd.ppc.gpr[rs] - & 0xffffffff; - while (sh-- > 0) - cpu->cd.ppc.gpr[ra] >>= 1; - break; - case PPC_31_AND: - cpu->cd.ppc.gpr[ra] = cpu->cd.ppc.gpr[rs] & - cpu->cd.ppc.gpr[rb]; - break; - case PPC_31_ANDC: - cpu->cd.ppc.gpr[ra] = cpu->cd.ppc.gpr[rs] & - (~cpu->cd.ppc.gpr[rb]); - break; - case PPC_31_NOR: - cpu->cd.ppc.gpr[ra] = ~(cpu->cd.ppc.gpr[rs] | - cpu->cd.ppc.gpr[rb]); - break; - case PPC_31_OR: - cpu->cd.ppc.gpr[ra] = cpu->cd.ppc.gpr[rs] | - cpu->cd.ppc.gpr[rb]; - break; - case PPC_31_ORC: - cpu->cd.ppc.gpr[ra] = cpu->cd.ppc.gpr[rs] | - (~cpu->cd.ppc.gpr[rb]); - break; - case PPC_31_XOR: - cpu->cd.ppc.gpr[ra] = cpu->cd.ppc.gpr[rs] ^ - cpu->cd.ppc.gpr[rb]; - break; - case PPC_31_NAND: - cpu->cd.ppc.gpr[ra] = ~(cpu->cd.ppc.gpr[rs] - & cpu->cd.ppc.gpr[rb]); - break; - } - if (rc) - update_cr0(cpu, cpu->cd.ppc.gpr[ra]); - break; - - case PPC_31_TLBIE: - rb = (iword >> 11) & 31; - /* TODO */ - break; - - case PPC_31_TLBSYNC: - /* Only on 603 and 604 (?) */ - - /* TODO */ - break; - - case PPC_31_DCCCI: - case PPC_31_ICCCI: - /* Supervisor IBM 4xx Data Cache Congruence Class - Invalidate, see www.xilinx.com/publications/ - xcellonline/partners/xc_pdf/xc_ibm_pwrpc42.pdf - or similar */ - /* ICCCI is probably Instruction... blah blah */ - /* TODO */ - break; - - case PPC_31_DIVWU: - case PPC_31_DIVWUO: - case PPC_31_DIVW: - case PPC_31_DIVWO: - rt = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - rb = (iword >> 11) & 31; - oe_bit = (iword >> 10) & 1; - rc = iword & 1; - switch (xo) { - case PPC_31_DIVWU: - case PPC_31_DIVWUO: - tmp = cpu->cd.ppc.gpr[ra] & 0xffffffff; - tmp2 = cpu->cd.ppc.gpr[rb] & 0xffffffff; - if (tmp2 == 0) { - /* Undefined: */ - tmp = 0; - } else { - tmp = tmp / tmp2; - } - cpu->cd.ppc.gpr[rt] = (int64_t)(int32_t)tmp; - break; - case PPC_31_DIVW: - case PPC_31_DIVWO: - tmp = (int64_t)(int32_t)cpu->cd.ppc.gpr[ra]; - tmp2 = (int64_t)(int32_t)cpu->cd.ppc.gpr[rb]; - if (tmp2 == 0) { - /* Undefined: */ - tmp = 0; - } else { - tmp = (int64_t)tmp / (int64_t)tmp2; - } - cpu->cd.ppc.gpr[rt] = (int64_t)(int32_t)tmp; - break; - } - if (rc) - update_cr0(cpu, cpu->cd.ppc.gpr[rt]); - if (oe_bit) { - fatal("[ divwu: PPC oe not yet implemeted ]\n"); - cpu->running = 0; - return 0; - } - break; - - case PPC_31_MTSPR: - rs = (iword >> 21) & 31; - spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31); - switch (spr) { - case 1: cpu->cd.ppc.xer = cpu->cd.ppc.gpr[rs]; - break; - case 8: cpu->cd.ppc.lr = cpu->cd.ppc.gpr[rs]; - break; - case 9: cpu->cd.ppc.ctr = cpu->cd.ppc.gpr[rs]; - break; - case 22: /* TODO: check pr */ - cpu->cd.ppc.dec = cpu->cd.ppc.gpr[rs]; - break; - case 272: - /* TODO: check hypv */ - cpu->cd.ppc.sprg0 = cpu->cd.ppc.gpr[rs]; - break; - case 273: - /* TODO: check pr */ - cpu->cd.ppc.sprg1 = cpu->cd.ppc.gpr[rs]; - break; - case 274: - /* TODO: check pr */ - cpu->cd.ppc.sprg2 = cpu->cd.ppc.gpr[rs]; - break; - case 275: - /* TODO: check pr */ - cpu->cd.ppc.sprg3 = cpu->cd.ppc.gpr[rs]; - break; - case 284: - /* TODO: check pr */ - cpu->cd.ppc.tbl = cpu->cd.ppc.gpr[rs]; - break; - case 285: - /* TODO: check pr */ - cpu->cd.ppc.tbu = cpu->cd.ppc.gpr[rs]; - break; - case 287: - fatal("[ PPC: attempt to write to PVR ]\n"); - break; - case 310: /* TODO: check hypv */ - cpu->cd.ppc.hdec = cpu->cd.ppc.gpr[rs]; - break; - case 1023: - /* TODO: check pr */ - cpu->cd.ppc.pir = cpu->cd.ppc.gpr[rs]; - break; - default: - fatal("[ unimplemented PPC spr 0x%04x, " - "pc = 0x%016llx ]\n", - spr, (long long) (cpu->cd.ppc.pc_last)); - /* cpu->running = 0; - return 0; */ - break; - } - break; - - case PPC_31_SYNC: - /* TODO: actually sync */ - break; - - case PPC_31_LSWI: - case PPC_31_STSWI: - rs = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - nb = (iword >> 11) & 31; - if (nb == 0) - nb = 32; - if (ra == 0) - addr = 0; - else - addr = cpu->cd.ppc.gpr[ra]; - - load = 0; - if (xo == PPC_31_LSWI) - load = 1; - - if (cpu->machine->instruction_trace) { - if (cpu->cd.ppc.bits == 32) - debug("\t[0x%08llx", (long long)addr); - else - debug("\t[0x%016llx", (long long)addr); - } - - i = 24; - r = 0; /* Error count. */ - while (nb-- > 0) { - if (load) { - /* (Actually rt should be used.) */ - if (cpu->memory_rw(cpu, cpu->mem, addr, - tmp_data, 1, MEM_READ, CACHE_DATA) - != MEMORY_ACCESS_OK) { - r++; - break; - } - if (i == 24) - cpu->cd.ppc.gpr[rs] = 0; - cpu->cd.ppc.gpr[rs] |= - (tmp_data[0] << i); - } else { - tmp_data[0] = cpu->cd.ppc.gpr[rs] >> i; - if (cpu->memory_rw(cpu, cpu->mem, addr, - tmp_data, 1, MEM_WRITE, CACHE_DATA) - != MEMORY_ACCESS_OK) { - r++; - break; - } - } - addr++; i-=8; - if (i < 0) { - i = 24; - rs = (rs + 1) % 32; - } - } - - if (cpu->machine->instruction_trace) { - if (r == 0) - debug(", ...]\n"); - else - debug(", FAILED]\n"); - } - - if (r > 0) { - /* TODO: exception */ - fatal("TODO: exception.\n"); - return 0; - } - break; - - case PPC_31_SRAWI: - rs = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - sh = (iword >> 11) & 31; - rc = iword & 1; - tmp = cpu->cd.ppc.gpr[rs] & 0xffffffff; - cpu->cd.ppc.xer &= ~PPC_XER_CA; - i = 0; - if (tmp & 0x80000000) - i = 1; - while (sh-- > 0) { - if (tmp & 1) - i++; - tmp >>= 1; - if (tmp & 0x40000000) - tmp |= 0x80000000; - } - cpu->cd.ppc.gpr[ra] = (int64_t)(int32_t)tmp; - /* Set the CA bit if rs contained a negative - number to begin with, and any 1-bits were - shifted out: */ - if (i > 1) - cpu->cd.ppc.xer |= PPC_XER_CA; - if (rc) - update_cr0(cpu, cpu->cd.ppc.gpr[ra]); - break; - - case PPC_31_EIEIO: - /* TODO: actually eieio */ - break; - - case PPC_31_EXTSB: - case PPC_31_EXTSH: - case PPC_31_EXTSW: - rs = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - rc = iword & 1; - switch (xo) { - case PPC_31_EXTSB: - cpu->cd.ppc.gpr[ra] = (int64_t) - (int8_t)cpu->cd.ppc.gpr[rs]; - break; - case PPC_31_EXTSH: - cpu->cd.ppc.gpr[ra] = (int64_t) - (int16_t)cpu->cd.ppc.gpr[rs]; - break; - case PPC_31_EXTSW: - cpu->cd.ppc.gpr[ra] = (int64_t) - (int32_t)cpu->cd.ppc.gpr[rs]; - break; - } - if (rc) - update_cr0(cpu, cpu->cd.ppc.gpr[ra]); - break; - - default: - fatal("[ unimplemented PPC hi6_31, xo = 0x%04x, " - "pc = 0x%016llx ]\n", - xo, (long long) (cpu->cd.ppc.pc_last)); - cpu->running = 0; - return 0; - } - break; - - case PPC_HI6_LWZ: - case PPC_HI6_LWZU: - case PPC_HI6_LHZ: - case PPC_HI6_LHZU: - case PPC_HI6_LHA: - case PPC_HI6_LHAU: - case PPC_HI6_LBZ: - case PPC_HI6_LBZU: - case PPC_HI6_STW: - case PPC_HI6_STWU: - case PPC_HI6_STH: - case PPC_HI6_STHU: - case PPC_HI6_STB: - case PPC_HI6_STBU: - case PPC_HI6_LFD: - case PPC_HI6_STFD: - /* NOTE: Loads use rt, not rs, but are otherwise similar - to stores. This code uses rs for both. */ - rs = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - imm = (int16_t)(iword & 0xffff); - - fpreg = 0; load = 1; update = 0; tmp_data_len = 4; - arithflag = 0; - - switch (hi6) { - case PPC_HI6_LWZU: - case PPC_HI6_LHZU: - case PPC_HI6_LHAU: - case PPC_HI6_LBZU: - case PPC_HI6_STBU: - case PPC_HI6_STHU: - case PPC_HI6_STWU: - update = 1; - } - - switch (hi6) { - case PPC_HI6_STW: - case PPC_HI6_STWU: - case PPC_HI6_STH: - case PPC_HI6_STHU: - case PPC_HI6_STB: - case PPC_HI6_STBU: - case PPC_HI6_STFD: - load = 0; - } - - switch (hi6) { - case PPC_HI6_LFD: - case PPC_HI6_STFD: - tmp_data_len = 8; - break; - case PPC_HI6_LBZ: - case PPC_HI6_LBZU: - case PPC_HI6_STB: - case PPC_HI6_STBU: - tmp_data_len = 1; - break; - case PPC_HI6_LHZ: - case PPC_HI6_LHZU: - case PPC_HI6_LHA: - case PPC_HI6_LHAU: - case PPC_HI6_STH: - case PPC_HI6_STHU: - tmp_data_len = 2; - break; - } - - switch (hi6) { - case PPC_HI6_LFD: - case PPC_HI6_STFD: - fpreg = 1; - } - - switch (hi6) { - case PPC_HI6_LHA: - case PPC_HI6_LHAU: - arithflag = 1; - } - - if (ra == 0) { - if (update) - fatal("[ PPC WARNING: invalid Update form ]\n"); - addr = 0; - } else - addr = cpu->cd.ppc.gpr[ra]; - - if (load && update && ra == rs) - fatal("[ PPC WARNING: invalid Update load form ]\n"); - - addr += imm; - - /* TODO: alignment check? */ - - if (cpu->machine->instruction_trace) { - if (cpu->cd.ppc.bits == 32) - debug("\t[0x%08llx", (long long)addr); - else - debug("\t[0x%016llx", (long long)addr); - } - - if (load) { - r = cpu->memory_rw(cpu, cpu->mem, addr, tmp_data, - tmp_data_len, MEM_READ, CACHE_DATA); - - if (r == MEMORY_ACCESS_OK) { - tmp = 0; - if (arithflag) { - if (cpu->byte_order == - EMUL_BIG_ENDIAN) { - if (tmp_data[0] & 0x80) - tmp --; - } else { - if (tmp_data[tmp_data_len-1] - & 0x80) - tmp --; - } - } - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - for (i=0; icd.ppc.gpr[rs] = tmp; - else - cpu->cd.ppc.fpr[rs] = tmp; - } - } else { - if (!fpreg) - tmp = cpu->cd.ppc.gpr[rs]; - else - tmp = cpu->cd.ppc.fpr[rs]; - - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - for (i=0; i> (8*i); - } else { - for (i=0; i> (8*i); - } - - r = cpu->memory_rw(cpu, cpu->mem, addr, tmp_data, - tmp_data_len, MEM_WRITE, CACHE_DATA); - } - - if (cpu->machine->instruction_trace) { - if (r == MEMORY_ACCESS_OK) { - switch (tmp_data_len) { - case 1: debug(", data = 0x%02x]\n", (int)tmp); - break; - case 2: debug(", data = 0x%04x]\n", (int)tmp); - break; - case 4: debug(", data = 0x%08x]\n", (int)tmp); - break; - default:debug(", data = 0x%016llx]\n", - (long long)tmp); - } - } else - debug(", FAILED]\n"); - } - - if (r != MEMORY_ACCESS_OK) { - /* TODO: exception? */ - return 0; - } - - if (update && ra != 0) - cpu->cd.ppc.gpr[ra] = addr; - break; - - case PPC_HI6_LMW: - case PPC_HI6_STMW: - /* NOTE: Loads use rt, not rs, but are otherwise similar - to stores. This code uses rs for both. */ - rs = (iword >> 21) & 31; - ra = (iword >> 16) & 31; - imm = (int16_t)(iword & 0xffff); - - load = 1; tmp_data_len = 4; - - switch (hi6) { - case PPC_HI6_STMW: - load = 0; - } - - if (ra == 0) { - addr = 0; - } else - addr = cpu->cd.ppc.gpr[ra]; - - if (load && rs == 0) - fatal("[ PPC WARNING: invalid LMW form ]\n"); - - addr += imm; - - /* TODO: alignment check? */ - - if (cpu->machine->instruction_trace) { - if (cpu->cd.ppc.bits == 32) - debug("\t[0x%08llx", (long long)addr); - else - debug("\t[0x%016llx", (long long)addr); - } - - /* There can be multiple errors! */ - r = 0; - - while (rs <= 31) { - if (load) { - if (cpu->memory_rw(cpu, cpu->mem, addr, - tmp_data, tmp_data_len, MEM_READ, - CACHE_DATA) != MEMORY_ACCESS_OK) - r++; - - if (r == 0) { - tmp = 0; - if (cpu->byte_order == - EMUL_BIG_ENDIAN) { - for (i=0; icd.ppc.gpr[rs] = tmp; - } - } else { - tmp = cpu->cd.ppc.gpr[rs]; - - if (cpu->byte_order == EMUL_BIG_ENDIAN) { - for (i=0; i> (8*i); - } else { - for (i=0; i> (8*i); - } - - if (cpu->memory_rw(cpu, cpu->mem, addr, - tmp_data, tmp_data_len, MEM_WRITE, - CACHE_DATA) != MEMORY_ACCESS_OK) - r ++; - } - - /* TODO: Exception! */ - - /* Go to next register, multiword... */ - rs ++; - addr += tmp_data_len; - } - - if (cpu->machine->instruction_trace) { - if (r == 0) { - debug(", data = ...]\n"); - } else - debug(", FAILED]\n"); - } - - if (r > 0) - return 0; - break; - - default: - fatal("[ unimplemented PPC hi6 = 0x%02x, pc = 0x%016llx ]\n", - hi6, (long long) (cpu->cd.ppc.pc_last)); - cpu->running = 0; - return 0; - } - - return 1; -} - - -#define CPU_RUN ppc_cpu_run -#define CPU_RINSTR ppc_cpu_run_instr -#define CPU_RUN_PPC -#include "cpu_run.c" -#undef CPU_RINSTR -#undef CPU_RUN_PPC -#undef CPU_RUN - - -#define MEMORY_RW ppc_memory_rw -#define MEM_PPC -#include "memory_rw.c" -#undef MEM_PPC -#undef MEMORY_RW - - -/* - * ppc_cpu_family_init(): - * - * Fill in the cpu_family struct for PPC. - */ -int ppc_cpu_family_init(struct cpu_family *fp) -{ - fp->name = "PPC"; - fp->cpu_new = ppc_cpu_new; - fp->list_available_types = ppc_cpu_list_available_types; - fp->register_match = ppc_cpu_register_match; - fp->disassemble_instr = ppc_cpu_disassemble_instr; - fp->register_dump = ppc_cpu_register_dump; - fp->run = ppc_cpu_run; - fp->dumpinfo = ppc_cpu_dumpinfo; - /* fp->show_full_statistics = ppc_cpu_show_full_statistics; */ - /* fp->tlbdump = ppc_cpu_tlbdump; */ - /* fp->interrupt = ppc_cpu_interrupt; */ - /* fp->interrupt_ack = ppc_cpu_interrupt_ack; */ - return 1; -} +#include "tmp_ppc_tail.c" #endif /* ENABLE_PPC */