--- trunk/src/cpus/cpu_ppc_instr.c 2007/10/08 16:19:11 18 +++ trunk/src/cpus/cpu_ppc_instr.c 2007/10/08 16:19:23 20 @@ -25,7 +25,7 @@ * SUCH DAMAGE. * * - * $Id: cpu_ppc_instr.c,v 1.20 2005/10/27 14:01:13 debug Exp $ + * $Id: cpu_ppc_instr.c,v 1.44 2005/11/24 01:31:54 debug Exp $ * * POWER/PowerPC instructions. * @@ -36,8 +36,15 @@ */ -#define DOT(n) X(n ## _dot) { instr(n)(cpu,ic); \ +#include "float_emul.h" + + +#define DOT0(n) X(n ## _dot) { instr(n)(cpu,ic); \ + update_cr0(cpu, reg(ic->arg[0])); } +#define DOT1(n) X(n ## _dot) { instr(n)(cpu,ic); \ update_cr0(cpu, reg(ic->arg[1])); } +#define DOT2(n) X(n ## _dot) { instr(n)(cpu,ic); \ + update_cr0(cpu, reg(ic->arg[2])); } /* @@ -53,7 +60,7 @@ */ X(invalid) { - fatal("INTERNAL ERROR\n"); + fatal("PPC: invalid(): INTERNAL ERROR\n"); exit(1); } @@ -98,10 +105,10 @@ /* TODO/NOTE: Only for 32-bit mode, so far! */ uint64_t tmp = (uint32_t)reg(ic->arg[0]); uint64_t tmp2 = tmp; - cpu->cd.ppc.xer &= ~PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; tmp2 += (uint32_t)ic->arg[1]; if ((tmp2 >> 32) != (tmp >> 32)) - cpu->cd.ppc.xer |= PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (uint32_t)tmp2; } @@ -116,9 +123,9 @@ X(subfic) { MODE_uint_t tmp = (int64_t)(int32_t)ic->arg[1]; - cpu->cd.ppc.xer &= ~PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (tmp >= reg(ic->arg[0])) - cpu->cd.ppc.xer |= PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = tmp - reg(ic->arg[0]); } @@ -135,10 +142,10 @@ /* TODO/NOTE: Only for 32-bit mode, so far! */ uint64_t tmp = (uint32_t)reg(ic->arg[0]); uint64_t tmp2 = tmp; - cpu->cd.ppc.xer &= ~PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; tmp2 += (uint32_t)ic->arg[1]; if ((tmp2 >> 32) != (tmp >> 32)) - cpu->cd.ppc.xer |= PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (uint32_t)tmp2; update_cr0(cpu, (uint32_t)tmp2); } @@ -148,22 +155,22 @@ * bclr: Branch Conditional to Link Register * * arg[0] = bo - * arg[1] = bi + * arg[1] = 31 - bi * arg[2] = bh */ X(bclr) { - int bo = ic->arg[0], bi = ic->arg[1] /* , bh = ic->arg[2] */; + int bo = ic->arg[0], bi31m = ic->arg[1] /* , bh = ic->arg[2] */; int ctr_ok, cond_ok; uint64_t old_pc = cpu->pc; - MODE_uint_t tmp, addr = cpu->cd.ppc.lr; + MODE_uint_t tmp, addr = cpu->cd.ppc.spr[SPR_LR]; if (!(bo & 4)) - cpu->cd.ppc.ctr --; + cpu->cd.ppc.spr[SPR_CTR] --; ctr_ok = (bo >> 2) & 1; - tmp = cpu->cd.ppc.ctr; + tmp = cpu->cd.ppc.spr[SPR_CTR]; ctr_ok |= ( (tmp != 0) ^ ((bo >> 1) & 1) ); cond_ok = (bo >> 4) & 1; - cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> (31-bi)) & 1) ); + cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> bi31m) & 1) ); if (ctr_ok && cond_ok) { uint64_t mask_within_page = ((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT) @@ -184,25 +191,30 @@ } } } +X(bclr_20) +{ + cpu->pc = cpu->cd.ppc.spr[SPR_LR]; + DYNTRANS_PC_TO_POINTERS(cpu); +} X(bclr_l) { uint64_t low_pc, old_pc = cpu->pc; - int bo = ic->arg[0], bi = ic->arg[1] /* , bh = ic->arg[2] */; + 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.lr; + MODE_uint_t tmp, addr = cpu->cd.ppc.spr[SPR_LR]; if (!(bo & 4)) - cpu->cd.ppc.ctr --; + cpu->cd.ppc.spr[SPR_CTR] --; ctr_ok = (bo >> 2) & 1; - tmp = cpu->cd.ppc.ctr; + tmp = cpu->cd.ppc.spr[SPR_CTR]; ctr_ok |= ( (tmp != 0) ^ ((bo >> 1) & 1) ); cond_ok = (bo >> 4) & 1; - cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> (31-bi)) & 1) ); + cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> bi31m) & 1) ); /* Calculate return PC: */ - low_pc = ((size_t)cpu->cd.ppc.next_ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->cd.ppc.lr = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.lr += (low_pc << 2); + 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); if (ctr_ok && cond_ok) { uint64_t mask_within_page = @@ -232,16 +244,16 @@ * bcctr: Branch Conditional to Count register * * arg[0] = bo - * arg[1] = bi + * arg[1] = 31 - bi * arg[2] = bh */ X(bcctr) { - int bo = ic->arg[0], bi = ic->arg[1] /* , bh = ic->arg[2] */; + 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.ctr; + 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 >> (31-bi)) & 1) ); + cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> bi31m) & 1) ); if (cond_ok) { uint64_t mask_within_page = ((PPC_IC_ENTRIES_PER_PAGE-1) << PPC_INSTR_ALIGNMENT_SHIFT) @@ -265,16 +277,16 @@ X(bcctr_l) { uint64_t low_pc, old_pc = cpu->pc; - int bo = ic->arg[0], bi = ic->arg[1] /* , bh = ic->arg[2] */; - MODE_uint_t addr = cpu->cd.ppc.ctr; + 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 >> (31-bi)) & 1) ); + cond_ok |= ( ((bo >> 3) & 1) == ((cpu->cd.ppc.cr >> bi31m) & 1) ); /* Calculate return PC: */ - low_pc = ((size_t)cpu->cd.ppc.next_ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->cd.ppc.lr = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.lr += (low_pc << 2); + 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); if (cond_ok) { uint64_t mask_within_page = @@ -317,6 +329,11 @@ /* Find the new physical page and update the translation pointers: */ DYNTRANS_PC_TO_POINTERS(cpu); } +X(ba) +{ + cpu->pc = (int32_t)ic->arg[0]; + DYNTRANS_PC_TO_POINTERS(cpu); +} /* @@ -331,9 +348,31 @@ MODE_uint_t tmp; int ctr_ok, cond_ok, bi = ic->arg[2], bo = ic->arg[1]; if (!(bo & 4)) - cpu->cd.ppc.ctr --; + cpu->cd.ppc.spr[SPR_CTR] --; ctr_ok = (bo >> 2) & 1; - tmp = cpu->cd.ppc.ctr; + tmp = cpu->cd.ppc.spr[SPR_CTR]; + 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 (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; + + /* 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); + + if (!(bo & 4)) + cpu->cd.ppc.spr[SPR_CTR] --; + ctr_ok = (bo >> 2) & 1; + tmp = cpu->cd.ppc.spr[SPR_CTR]; ctr_ok |= ( (tmp != 0) ^ ((bo >> 1) & 1) ); cond_ok = (bo >> 4) & 1; cond_ok |= ( ((bo >> 3) & 1) == @@ -366,15 +405,45 @@ MODE_uint_t tmp; int ctr_ok, cond_ok, bi = ic->arg[2], bo = ic->arg[1]; if (!(bo & 4)) - cpu->cd.ppc.ctr --; + cpu->cd.ppc.spr[SPR_CTR] --; ctr_ok = (bo >> 2) & 1; - tmp = cpu->cd.ppc.ctr; + tmp = cpu->cd.ppc.spr[SPR_CTR]; 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 (ctr_ok && cond_ok) - instr(b_samepage)(cpu,ic); + cpu->cd.ppc.next_ic = (struct ppc_instr_call *) ic->arg[0]; +} +X(bc_samepage_no_ctr) +{ + 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) + 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; + + /* 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); + + if (!(bo & 4)) + cpu->cd.ppc.spr[SPR_CTR] --; + ctr_ok = (bo >> 2) & 1; + tmp = cpu->cd.ppc.spr[SPR_CTR]; + 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 (ctr_ok && cond_ok) + cpu->cd.ppc.next_ic = (struct ppc_instr_call *) ic->arg[0]; } @@ -388,10 +457,10 @@ uint32_t low_pc; /* Calculate LR: */ - low_pc = ((size_t)cpu->cd.ppc.next_ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->cd.ppc.lr = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.lr += (low_pc << 2); + 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) @@ -403,6 +472,15 @@ /* Find the new physical page and update the translation pointers: */ DYNTRANS_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); + cpu->pc = (int32_t)ic->arg[0]; + DYNTRANS_PC_TO_POINTERS(cpu); +} /* @@ -415,10 +493,10 @@ uint32_t low_pc; /* Calculate LR: */ - low_pc = ((size_t)cpu->cd.ppc.next_ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->cd.ppc.lr = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.lr += (low_pc << 2); + 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) @@ -432,6 +510,16 @@ /* Find the new physical page and update the translation pointers: */ DYNTRANS_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); + cpu->pc = (int32_t)ic->arg[0]; + cpu_functioncall_trace(cpu, cpu->pc); + DYNTRANS_PC_TO_POINTERS(cpu); +} /* @@ -446,8 +534,8 @@ /* Calculate LR: */ low_pc = ((size_t)ic - (size_t) cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call) + 1; - cpu->cd.ppc.lr = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.lr += (low_pc << 2); + 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.next_ic = (struct ppc_instr_call *) ic->arg[0]; } @@ -463,10 +551,10 @@ uint32_t low_pc; /* Calculate LR: */ - low_pc = ((size_t)cpu->cd.ppc.next_ic - (size_t) - cpu->cd.ppc.cur_ic_page) / sizeof(struct ppc_instr_call); - cpu->cd.ppc.lr = cpu->pc & ~((PPC_IC_ENTRIES_PER_PAGE-1) << 2); - cpu->cd.ppc.lr += (low_pc << 2); + 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.next_ic = (struct ppc_instr_call *) ic->arg[0]; @@ -503,21 +591,22 @@ * * arg[0] = ptr to ra * arg[1] = ptr to rb - * arg[2] = bf + * arg[2] = 28 - 4*bf */ X(cmpd) { int64_t tmp = reg(ic->arg[0]), tmp2 = reg(ic->arg[1]); - int bf = ic->arg[2], c; + int bf_shift = ic->arg[2], c; if (tmp < tmp2) c = 8; else if (tmp > tmp2) c = 4; else c = 2; - c |= ((cpu->cd.ppc.xer >> 31) & 1); /* SO bit, copied from XER */ - cpu->cd.ppc.cr &= ~(0xf << (28 - 4*bf)); - cpu->cd.ppc.cr |= (c << (28 - 4*bf)); + /* SO bit, copied from XER */ + c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); + cpu->cd.ppc.cr &= ~(0xf << bf_shift); + cpu->cd.ppc.cr |= (c << bf_shift); } @@ -526,21 +615,22 @@ * * arg[0] = ptr to ra * arg[1] = ptr to rb - * arg[2] = bf + * arg[2] = 28 - 4*bf */ X(cmpld) { uint64_t tmp = reg(ic->arg[0]), tmp2 = reg(ic->arg[1]); - int bf = ic->arg[2], c; + int bf_shift = ic->arg[2], c; if (tmp < tmp2) c = 8; else if (tmp > tmp2) c = 4; else c = 2; - c |= ((cpu->cd.ppc.xer >> 31) & 1); /* SO bit, copied from XER */ - cpu->cd.ppc.cr &= ~(0xf << (28 - 4*bf)); - cpu->cd.ppc.cr |= (c << (28 - 4*bf)); + /* SO bit, copied from XER */ + c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); + cpu->cd.ppc.cr &= ~(0xf << bf_shift); + cpu->cd.ppc.cr |= (c << bf_shift); } @@ -549,21 +639,22 @@ * * arg[0] = ptr to ra * arg[1] = int32_t imm - * arg[2] = bf + * arg[2] = 28 - 4*bf */ X(cmpdi) { int64_t tmp = reg(ic->arg[0]), imm = (int32_t)ic->arg[1]; - int bf = ic->arg[2], c; + int bf_shift = ic->arg[2], c; if (tmp < imm) c = 8; else if (tmp > imm) c = 4; else c = 2; - c |= ((cpu->cd.ppc.xer >> 31) & 1); /* SO bit, copied from XER */ - cpu->cd.ppc.cr &= ~(0xf << (28 - 4*bf)); - cpu->cd.ppc.cr |= (c << (28 - 4*bf)); + /* SO bit, copied from XER */ + c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); + cpu->cd.ppc.cr &= ~(0xf << bf_shift); + cpu->cd.ppc.cr |= (c << bf_shift); } @@ -572,21 +663,22 @@ * * arg[0] = ptr to ra * arg[1] = int32_t imm - * arg[2] = bf + * arg[2] = 28 - 4*bf */ X(cmpldi) { uint64_t tmp = reg(ic->arg[0]), imm = (uint32_t)ic->arg[1]; - int bf = ic->arg[2], c; + int bf_shift = ic->arg[2], c; if (tmp < imm) c = 8; else if (tmp > imm) c = 4; else c = 2; - c |= ((cpu->cd.ppc.xer >> 31) & 1); /* SO bit, copied from XER */ - cpu->cd.ppc.cr &= ~(0xf << (28 - 4*bf)); - cpu->cd.ppc.cr |= (c << (28 - 4*bf)); + /* SO bit, copied from XER */ + c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); + cpu->cd.ppc.cr &= ~(0xf << bf_shift); + cpu->cd.ppc.cr |= (c << bf_shift); } @@ -595,21 +687,22 @@ * * arg[0] = ptr to ra * arg[1] = ptr to rb - * arg[2] = bf + * arg[2] = 28 - 4*bf */ X(cmpw) { int32_t tmp = reg(ic->arg[0]), tmp2 = reg(ic->arg[1]); - int bf = ic->arg[2], c; + int bf_shift = ic->arg[2], c; if (tmp < tmp2) c = 8; else if (tmp > tmp2) c = 4; else c = 2; - c |= ((cpu->cd.ppc.xer >> 31) & 1); /* SO bit, copied from XER */ - cpu->cd.ppc.cr &= ~(0xf << (28 - 4*bf)); - cpu->cd.ppc.cr |= (c << (28 - 4*bf)); + /* SO bit, copied from XER */ + c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); + cpu->cd.ppc.cr &= ~(0xf << bf_shift); + cpu->cd.ppc.cr |= (c << bf_shift); } @@ -618,21 +711,22 @@ * * arg[0] = ptr to ra * arg[1] = ptr to rb - * arg[2] = bf + * arg[2] = 28 - 4*bf */ X(cmplw) { uint32_t tmp = reg(ic->arg[0]), tmp2 = reg(ic->arg[1]); - int bf = ic->arg[2], c; + int bf_shift = ic->arg[2], c; if (tmp < tmp2) c = 8; else if (tmp > tmp2) c = 4; else c = 2; - c |= ((cpu->cd.ppc.xer >> 31) & 1); /* SO bit, copied from XER */ - cpu->cd.ppc.cr &= ~(0xf << (28 - 4*bf)); - cpu->cd.ppc.cr |= (c << (28 - 4*bf)); + /* SO bit, copied from XER */ + c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); + cpu->cd.ppc.cr &= ~(0xf << bf_shift); + cpu->cd.ppc.cr |= (c << bf_shift); } @@ -641,21 +735,22 @@ * * arg[0] = ptr to ra * arg[1] = int32_t imm - * arg[2] = bf + * arg[2] = 28 - 4*bf */ X(cmpwi) { int32_t tmp = reg(ic->arg[0]), imm = ic->arg[1]; - int bf = ic->arg[2], c; + int bf_shift = ic->arg[2], c; if (tmp < imm) c = 8; else if (tmp > imm) c = 4; else c = 2; - c |= ((cpu->cd.ppc.xer >> 31) & 1); /* SO bit, copied from XER */ - cpu->cd.ppc.cr &= ~(0xf << (28 - 4*bf)); - cpu->cd.ppc.cr |= (c << (28 - 4*bf)); + /* SO bit, copied from XER */ + c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); + cpu->cd.ppc.cr &= ~(0xf << bf_shift); + cpu->cd.ppc.cr |= (c << bf_shift); } @@ -664,21 +759,22 @@ * * arg[0] = ptr to ra * arg[1] = int32_t imm - * arg[2] = bf + * arg[2] = 28 - 4*bf */ X(cmplwi) { uint32_t tmp = reg(ic->arg[0]), imm = ic->arg[1]; - int bf = ic->arg[2], c; + int bf_shift = ic->arg[2], c; if (tmp < imm) c = 8; else if (tmp > imm) c = 4; else c = 2; - c |= ((cpu->cd.ppc.xer >> 31) & 1); /* SO bit, copied from XER */ - cpu->cd.ppc.cr &= ~(0xf << (28 - 4*bf)); - cpu->cd.ppc.cr |= (c << (28 - 4*bf)); + /* SO bit, copied from XER */ + c |= ((cpu->cd.ppc.spr[SPR_XER] >> 31) & 1); + cpu->cd.ppc.cr &= ~(0xf << bf_shift); + cpu->cd.ppc.cr |= (c << bf_shift); } @@ -695,16 +791,20 @@ int cacheline_size = 1 << cpu->cd.ppc.cpu_type.dlinesize; int cleared = 0; + /* Synchronize the PC first: */ + cpu->pc = (cpu->pc & ~0xfff) + ic->arg[2]; + 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) { - fatal("dcbz: error: TODO\n"); - exit(1); + /* exception */ + return; } cleared += to_clear; @@ -714,6 +814,49 @@ /* + * mtfsf: Copy FPR into the FPSCR. + * + * arg[0] = ptr to frb + * arg[1] = mask + */ +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; + } + + cpu->cd.ppc.fpscr &= ~ic->arg[1]; + cpu->cd.ppc.fpscr |= (ic->arg[1] & (*(uint64_t *)ic->arg[0])); +} + + +/* + * mffs: Copy FPSCR into a FPR. + * + * arg[0] = ptr to frt + */ +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; + } + + (*(uint64_t *)ic->arg[0]) = cpu->cd.ppc.fpscr; +} + + +/* * fmr: Floating-point Move * * arg[0] = ptr to frb @@ -721,11 +864,461 @@ */ 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; + } + *(uint64_t *)ic->arg[1] = *(uint64_t *)ic->arg[0]; } /* + * fneg: Floating-point Negate + * + * arg[0] = ptr to frb + * arg[1] = ptr to frt + */ +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; + } + + v = *(uint64_t *)ic->arg[0]; + *(uint64_t *)ic->arg[1] = v ^ 0x8000000000000000ULL; +} + + +/* + * fcmpu: Floating-point Compare Unordered + * + * arg[0] = 28 - 4*bf (bitfield shift) + * arg[1] = ptr to fra + * arg[2] = ptr to frb + */ +X(fcmpu) +{ + 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; + } + + 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); + if (fra.nan | frb.nan) { + c = 1; + } else { + if (fra.f < frb.f) + c = 8; + else if (fra.f > frb.f) + c = 4; + else + c = 2; + } + /* TODO: Signaling vs Quiet NaN */ + cpu->cd.ppc.cr &= ~(0xf << bf_shift); + cpu->cd.ppc.cr |= ((c&0xe) << bf_shift); + cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); + cpu->cd.ppc.fpscr |= (c << PPC_FPSCR_FPCC_SHIFT); +} + + +/* + * frsp: Floating-point Round to Single Precision + * + * arg[0] = ptr to frb + * arg[1] = ptr to frt + */ +X(frsp) +{ + struct ieee_float_value frb; + 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; + } + + ieee_interpret_float_value(*(uint64_t *)ic->arg[0], &frb, IEEE_FMT_D); + if (frb.nan) { + c = 1; + } else { + fl = frb.f; + if (fl < 0.0) + c = 8; + else if (fl > 0.0) + c = 4; + else + c = 2; + } + /* TODO: Signaling vs Quiet NaN */ + cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); + cpu->cd.ppc.fpscr |= (c << PPC_FPSCR_FPCC_SHIFT); + (*(uint64_t *)ic->arg[1]) = + ieee_store_float_value(fl, IEEE_FMT_D, frb.nan); +} + + +/* + * fctiwz: Floating-point Convert to Integer Word, Round to Zero + * + * arg[0] = ptr to frb + * arg[1] = ptr to frt + */ +X(fctiwz) +{ + 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; + } + + ieee_interpret_float_value(*(uint64_t *)ic->arg[0], &frb, IEEE_FMT_D); + if (!frb.nan) { + if (frb.f >= 2147483647.0) + res = 0x7fffffff; + else if (frb.f <= -2147483648.0) + res = 0x80000000; + else + res = frb.f; + } + *(uint64_t *)ic->arg[1] = (uint32_t)res; +} + + +/* + * fmul: Floating-point Multiply + * + * arg[0] = ptr to frt + * arg[1] = ptr to fra + * arg[2] = ptr to frc + */ +X(fmul) +{ + struct ieee_float_value fra; + struct ieee_float_value frc; + 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; + } + + 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); + if (fra.nan || frc.nan) + nan = 1; + else + result = fra.f * frc.f; + if (nan) + c = 1; + else { + if (result < 0.0) + c = 8; + else if (result > 0.0) + c = 4; + else + c = 2; + } + /* TODO: Signaling vs Quiet NaN */ + cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); + cpu->cd.ppc.fpscr |= (c << PPC_FPSCR_FPCC_SHIFT); + + (*(uint64_t *)ic->arg[0]) = + ieee_store_float_value(result, IEEE_FMT_D, nan); +} +X(fmuls) +{ + /* TODO */ + instr(fmul)(cpu, ic); +} + + +/* + * fmadd: Floating-point Multiply and Add + * + * arg[0] = ptr to frt + * arg[1] = ptr to fra + * arg[2] = copy of the instruction word + */ +X(fmadd) +{ + uint32_t iw = ic->arg[2]; + int b = (iw >> 11) & 31, c = (iw >> 6) & 31; + struct ieee_float_value fra; + struct ieee_float_value frb; + struct ieee_float_value frc; + 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; + } + + 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); + ieee_interpret_float_value(cpu->cd.ppc.fpr[c], &frc, IEEE_FMT_D); + if (fra.nan || frb.nan || frc.nan) + nan = 1; + else + result = fra.f * frc.f + frb.f; + if (nan) + cc = 1; + else { + if (result < 0.0) + cc = 8; + else if (result > 0.0) + cc = 4; + else + cc = 2; + } + /* TODO: Signaling vs Quiet NaN */ + cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); + cpu->cd.ppc.fpscr |= (cc << PPC_FPSCR_FPCC_SHIFT); + + (*(uint64_t *)ic->arg[0]) = + ieee_store_float_value(result, IEEE_FMT_D, nan); +} + + +/* + * fmsub: Floating-point Multiply and Sub + * + * arg[0] = ptr to frt + * arg[1] = ptr to fra + * arg[2] = copy of the instruction word + */ +X(fmsub) +{ + uint32_t iw = ic->arg[2]; + int b = (iw >> 11) & 31, c = (iw >> 6) & 31; + struct ieee_float_value fra; + struct ieee_float_value frb; + struct ieee_float_value frc; + 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; + } + + 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); + ieee_interpret_float_value(cpu->cd.ppc.fpr[c], &frc, IEEE_FMT_D); + if (fra.nan || frb.nan || frc.nan) + nan = 1; + else + result = fra.f * frc.f - frb.f; + if (nan) + cc = 1; + else { + if (result < 0.0) + cc = 8; + else if (result > 0.0) + cc = 4; + else + cc = 2; + } + /* TODO: Signaling vs Quiet NaN */ + cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); + cpu->cd.ppc.fpscr |= (cc << PPC_FPSCR_FPCC_SHIFT); + + (*(uint64_t *)ic->arg[0]) = + ieee_store_float_value(result, IEEE_FMT_D, nan); +} + + +/* + * fadd, fsub, fdiv: Various Floating-point operationgs + * + * arg[0] = ptr to fra + * arg[1] = ptr to frb + * arg[2] = ptr to frt + */ +X(fadd) +{ + struct ieee_float_value fra; + struct ieee_float_value frb; + 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; + } + + 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); + if (fra.nan || frb.nan) + nan = 1; + else + result = fra.f + frb.f; + if (nan) + c = 1; + else { + if (result < 0.0) + c = 8; + else if (result > 0.0) + c = 4; + else + c = 2; + } + /* TODO: Signaling vs Quiet NaN */ + cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); + cpu->cd.ppc.fpscr |= (c << PPC_FPSCR_FPCC_SHIFT); + + (*(uint64_t *)ic->arg[2]) = + ieee_store_float_value(result, IEEE_FMT_D, nan); +} +X(fadds) +{ + /* TODO */ + instr(fadd)(cpu, ic); +} +X(fsub) +{ + struct ieee_float_value fra; + struct ieee_float_value frb; + 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; + } + + 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); + if (fra.nan || frb.nan) + nan = 1; + else + result = fra.f - frb.f; + if (nan) + c = 1; + else { + if (result < 0.0) + c = 8; + else if (result > 0.0) + c = 4; + else + c = 2; + } + /* TODO: Signaling vs Quiet NaN */ + cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); + cpu->cd.ppc.fpscr |= (c << PPC_FPSCR_FPCC_SHIFT); + + (*(uint64_t *)ic->arg[2]) = + ieee_store_float_value(result, IEEE_FMT_D, nan); +} +X(fsubs) +{ + /* TODO */ + instr(fsub)(cpu, ic); +} +X(fdiv) +{ + struct ieee_float_value fra; + struct ieee_float_value frb; + 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; + } + + 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); + if (fra.nan || frb.nan || frb.f == 0) + nan = 1; + else + result = fra.f / frb.f; + if (nan) + c = 1; + else { + if (result < 0.0) + c = 8; + else if (result > 0.0) + c = 4; + else + c = 2; + } + /* TODO: Signaling vs Quiet NaN */ + cpu->cd.ppc.fpscr &= ~(PPC_FPSCR_FPCC | PPC_FPSCR_VXNAN); + cpu->cd.ppc.fpscr |= (c << PPC_FPSCR_FPCC_SHIFT); + + (*(uint64_t *)ic->arg[2]) = + ieee_store_float_value(result, IEEE_FMT_D, nan); +} +X(fdivs) +{ + /* TODO */ + instr(fdiv)(cpu, ic); +} + + +/* * llsc: Load-linked and store conditional * * arg[0] = copy of the instruction word. @@ -781,7 +1374,7 @@ cpu->cd.ppc.ll_addr = addr; cpu->cd.ppc.ll_bit = 1; } else { - uint32_t old_so = cpu->cd.ppc.xer & PPC_XER_SO; + uint32_t old_so = cpu->cd.ppc.spr[SPR_XER] & PPC_XER_SO; if (!rc) { fatal("sc: rc-bit not set?\n"); exit(1); @@ -829,33 +1422,42 @@ /* * mtsr: Move To Segment Register * - * arg[0] = segment register nr (0..15) + * arg[0] = sr number, or for indirect mode: ptr to rb * arg[1] = ptr to rt */ X(mtsr) { /* TODO: This only works for 32-bit mode */ cpu->cd.ppc.sr[ic->arg[0]] = reg(ic->arg[1]); + + cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); +} +X(mtsrin) +{ + /* TODO: This only works for 32-bit mode */ + uint32_t sr_num = reg(ic->arg[0]) >> 28; + cpu->cd.ppc.sr[sr_num] = reg(ic->arg[1]); + + cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); } /* * mfsrin, mtsrin: Move From/To Segment Register Indirect * - * arg[0] = ptr to rb + * arg[0] = sr number, or for indirect mode: ptr to rb * arg[1] = ptr to rt */ -X(mfsrin) +X(mfsr) { /* TODO: This only works for 32-bit mode */ - uint32_t sr_num = reg(ic->arg[0]) >> 28; - reg(ic->arg[1]) = cpu->cd.ppc.sr[sr_num]; + reg(ic->arg[1]) = cpu->cd.ppc.sr[ic->arg[0]]; } -X(mtsrin) +X(mfsrin) { /* TODO: This only works for 32-bit mode */ uint32_t sr_num = reg(ic->arg[0]) >> 28; - cpu->cd.ppc.sr[sr_num] = reg(ic->arg[1]); + reg(ic->arg[1]) = cpu->cd.ppc.sr[sr_num]; } @@ -886,42 +1488,44 @@ /* - * rlwinm: + * rlwnm: * - * arg[0] = ptr to rs - * arg[1] = ptr to ra + * arg[0] = ptr to ra + * arg[1] = mask * arg[2] = copy of the instruction word */ -X(rlwinm) +X(rlwnm) { - MODE_uint_t tmp = reg(ic->arg[0]), ra = 0; - uint32_t iword = ic->arg[2]; - int sh, mb, me, rc; + uint32_t tmp, iword = ic->arg[2]; + int rs = (iword >> 21) & 31; + int rb = (iword >> 11) & 31; + int sh = cpu->cd.ppc.gpr[rb] & 0x1f; + tmp = (uint32_t)cpu->cd.ppc.gpr[rs]; + tmp = (tmp << sh) | (tmp >> (32-sh)); + tmp &= (uint32_t)ic->arg[1]; + reg(ic->arg[0]) = tmp; +} +DOT0(rlwnm) - sh = (iword >> 11) & 31; - mb = (iword >> 6) & 31; - me = (iword >> 1) & 31; - rc = iword & 1; - /* TODO: Fix this, its performance is awful: */ - while (sh-- != 0) { - int b = (tmp >> 31) & 1; - tmp = (tmp << 1) | b; - } - for (;;) { - uint64_t mask; - mask = (uint64_t)1 << (31-mb); - ra |= (tmp & mask); - if (mb == me) - break; - mb ++; - if (mb == 32) - mb = 0; - } - reg(ic->arg[1]) = ra; - if (rc) - update_cr0(cpu, ra); +/* + * rlwinm: + * + * arg[0] = ptr to ra + * arg[1] = mask + * arg[2] = copy of the instruction word + */ +X(rlwinm) +{ + uint32_t tmp, iword = ic->arg[2]; + int rs = (iword >> 21) & 31; + int sh = (iword >> 11) & 31; + tmp = (uint32_t)cpu->cd.ppc.gpr[rs]; + tmp = (tmp << sh) | (tmp >> (32-sh)); + tmp &= (uint32_t)ic->arg[1]; + reg(ic->arg[0]) = tmp; } +DOT0(rlwinm) /* @@ -935,18 +1539,13 @@ { MODE_uint_t tmp = reg(ic->arg[0]), ra = reg(ic->arg[1]); uint32_t iword = ic->arg[2]; - int sh, mb, me, rc; + int sh = (iword >> 11) & 31; + int mb = (iword >> 6) & 31; + int me = (iword >> 1) & 31; + int rc = iword & 1; - sh = (iword >> 11) & 31; - mb = (iword >> 6) & 31; - me = (iword >> 1) & 31; - rc = iword & 1; + tmp = (tmp << sh) | (tmp >> (32-sh)); - /* TODO: Fix this, its performance is awful: */ - while (sh-- != 0) { - int b = (tmp >> 31) & 1; - tmp = (tmp << 1) | b; - } for (;;) { uint64_t mask; mask = (uint64_t)1 << (31-mb); @@ -976,7 +1575,7 @@ uint32_t tmp = reg(ic->arg[0]); int i = 0, j = 0, sh = ic->arg[2]; - cpu->cd.ppc.xer &= ~PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (tmp & 0x80000000) i = 1; while (sh-- > 0) { @@ -987,23 +1586,23 @@ tmp |= 0x80000000; } if (i && j>0) - cpu->cd.ppc.xer |= PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[1]) = (int64_t)(int32_t)tmp; } -DOT(srawi) +DOT1(srawi) /* * mcrf: Move inside condition register * - * arg[0] = bf, arg[1] = bfa + * arg[0] = 28-4*bf, arg[1] = 28-4*bfa */ X(mcrf) { - int bf = ic->arg[0], bfa = ic->arg[1]; - uint32_t tmp = (cpu->cd.ppc.cr >> (28 - bfa*4)) & 0xf; - cpu->cd.ppc.cr &= ~(0xf << (28 - bf*4)); - cpu->cd.ppc.cr |= (tmp << (28 - bf*4)); + int bf_shift = ic->arg[0], bfa_shift = ic->arg[1]; + uint32_t tmp = (cpu->cd.ppc.cr >> bfa_shift) & 0xf; + cpu->cd.ppc.cr &= ~(0xf << bf_shift); + cpu->cd.ppc.cr |= (tmp << bf_shift); } @@ -1048,6 +1647,15 @@ 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; + 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(crxor) { uint32_t iword = ic->arg[0]; int bt = (iword >> 21) & 31; int ba = (iword >> 16) & 31, bb = (iword >> 11) & 31; @@ -1060,52 +1668,42 @@ /* - * mflr, etc: Move from Link Register etc. + * mfspr: Move from SPR * * arg[0] = pointer to destination register + * arg[1] = pointer to source SPR */ -X(mflr) { reg(ic->arg[0]) = cpu->cd.ppc.lr; } -X(mfctr) { reg(ic->arg[0]) = cpu->cd.ppc.ctr; } -X(mftb) { reg(ic->arg[0]) = cpu->cd.ppc.tbl; } -X(mftbu) { reg(ic->arg[0]) = cpu->cd.ppc.tbu; } -/* TODO: Check privilege level for mfsprg* */ -X(mfsrr0) { reg(ic->arg[0]) = cpu->cd.ppc.srr0; } -X(mfsrr1) { reg(ic->arg[0]) = cpu->cd.ppc.srr1; } -X(mfsdr1) { reg(ic->arg[0]) = cpu->cd.ppc.sdr1; } -X(mfdbsr) { reg(ic->arg[0]) = cpu->cd.ppc.dbsr; } -X(mfhid1) { reg(ic->arg[0]) = 0; /* TODO */ } -X(mfl2cr) { reg(ic->arg[0]) = 0; /* TODO */ } -X(mfsprg0) { reg(ic->arg[0]) = cpu->cd.ppc.sprg0; } -X(mfsprg1) { reg(ic->arg[0]) = cpu->cd.ppc.sprg1; } -X(mfsprg2) { reg(ic->arg[0]) = cpu->cd.ppc.sprg2; } -X(mfsprg3) { reg(ic->arg[0]) = cpu->cd.ppc.sprg3; } -X(mfpvr) { reg(ic->arg[0]) = cpu->cd.ppc.pvr; } -X(mfibatu) { reg(ic->arg[0]) = cpu->cd.ppc.ibat_u[ic->arg[1]]; } -X(mfibatl) { reg(ic->arg[0]) = cpu->cd.ppc.ibat_l[ic->arg[1]]; } -X(mfdbatu) { reg(ic->arg[0]) = cpu->cd.ppc.dbat_u[ic->arg[1]]; } -X(mfdbatl) { reg(ic->arg[0]) = cpu->cd.ppc.dbat_l[ic->arg[1]]; } +X(mfspr) { + reg(ic->arg[0]) = reg(ic->arg[1]); +} +X(mfspr_pmc1) { + /* + * TODO: This is a temporary hack to make NetBSD/ppc detect + * a CPU of the correct (emulated) speed. + */ + reg(ic->arg[0]) = cpu->machine->emulated_hz / 10; +} +X(mftb) { + /* NOTE/TODO: This increments the time base (slowly) if it + is being polled. */ + if (++cpu->cd.ppc.spr[SPR_TBL] == 0) + cpu->cd.ppc.spr[SPR_TBU] ++; + reg(ic->arg[0]) = cpu->cd.ppc.spr[SPR_TBL]; +} +X(mftbu) { + reg(ic->arg[0]) = cpu->cd.ppc.spr[SPR_TBU]; +} /* - * mtlr etc.: Move to Link Register (or other special register) + * mtspr: Move to SPR. * * arg[0] = pointer to source register + * arg[1] = pointer to the SPR */ -X(mtlr) { cpu->cd.ppc.lr = reg(ic->arg[0]); } -X(mtctr) { cpu->cd.ppc.ctr = reg(ic->arg[0]); } -/* TODO: Check privilege level for these: */ -X(mtsrr0) { cpu->cd.ppc.srr0 = reg(ic->arg[0]); } -X(mtsrr1) { cpu->cd.ppc.srr1 = reg(ic->arg[0]); } -X(mtsdr1) { cpu->cd.ppc.sdr1 = reg(ic->arg[0]); } -X(mtdbsr) { cpu->cd.ppc.dbsr = reg(ic->arg[0]); } -X(mtsprg0) { cpu->cd.ppc.sprg0 = reg(ic->arg[0]); } -X(mtsprg1) { cpu->cd.ppc.sprg1 = reg(ic->arg[0]); } -X(mtsprg2) { cpu->cd.ppc.sprg2 = reg(ic->arg[0]); } -X(mtsprg3) { cpu->cd.ppc.sprg3 = reg(ic->arg[0]); } -X(mtibatu) { cpu->cd.ppc.ibat_u[ic->arg[1]] = reg(ic->arg[0]); } -X(mtibatl) { cpu->cd.ppc.ibat_l[ic->arg[1]] = reg(ic->arg[0]); } -X(mtdbatu) { cpu->cd.ppc.dbat_u[ic->arg[1]] = reg(ic->arg[0]); } -X(mtdbatl) { cpu->cd.ppc.dbat_l[ic->arg[1]] = reg(ic->arg[0]); } +X(mtspr) { + reg(ic->arg[1]) = reg(ic->arg[0]); +} /* @@ -1115,12 +1713,12 @@ { uint64_t tmp; - reg_access_msr(cpu, &tmp, 0); + reg_access_msr(cpu, &tmp, 0, 0); tmp &= ~0xffff; - tmp |= (cpu->cd.ppc.srr1 & 0xffff); - reg_access_msr(cpu, &tmp, 1); + tmp |= (cpu->cd.ppc.spr[SPR_SRR1] & 0xffff); + reg_access_msr(cpu, &tmp, 1, 0); - cpu->pc = cpu->cd.ppc.srr0; + cpu->pc = cpu->cd.ppc.spr[SPR_SRR0]; DYNTRANS_PC_TO_POINTERS(cpu); } @@ -1143,7 +1741,7 @@ */ X(mfmsr) { - reg_access_msr(cpu, (uint64_t*)ic->arg[0], 0); + reg_access_msr(cpu, (uint64_t*)ic->arg[0], 0, 0); } @@ -1154,7 +1752,10 @@ */ X(mtmsr) { - reg_access_msr(cpu, (uint64_t*)ic->arg[0], 1); + /* Synchronize the PC (pointing to _after_ this instruction) */ + cpu->pc = (cpu->pc & ~0xfff) + ic->arg[1]; + + reg_access_msr(cpu, (uint64_t*)ic->arg[0], 1, 1); } @@ -1179,7 +1780,7 @@ */ X(mulli) { - reg(ic->arg[2]) = (uint32_t)(reg(ic->arg[0]) * ic->arg[1]); + reg(ic->arg[2]) = (uint32_t)(reg(ic->arg[0]) * (int32_t)ic->arg[1]); } @@ -1193,12 +1794,20 @@ X(lmw) { MODE_uint_t addr = reg(ic->arg[1]) + (int32_t)ic->arg[2]; unsigned char d[4]; - int n_err = 0, rs = ic->arg[0]; + int rs = ic->arg[0]; + + int 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) + << PPC_INSTR_ALIGNMENT_SHIFT); + cpu->pc |= (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); while (rs <= 31) { if (cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), - MEM_READ, CACHE_DATA) != MEMORY_ACCESS_OK) - n_err ++; + MEM_READ, CACHE_DATA) != MEMORY_ACCESS_OK) { + /* exception */ + return; + } if (cpu->byte_order == EMUL_BIG_ENDIAN) cpu->cd.ppc.gpr[rs] = (d[0] << 24) + (d[1] << 16) @@ -1207,23 +1816,23 @@ cpu->cd.ppc.gpr[rs] = (d[3] << 24) + (d[2] << 16) + (d[1] << 8) + d[0]; - if (n_err > 0) { - fatal("TODO: lmw: exception\n"); - exit(1); - } - rs ++; addr += sizeof(uint32_t); } } X(stmw) { MODE_uint_t addr = reg(ic->arg[1]) + (int32_t)ic->arg[2]; - uint32_t tmp; unsigned char d[4]; - int n_err = 0, rs = ic->arg[0]; + int rs = ic->arg[0]; + + int 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) + << PPC_INSTR_ALIGNMENT_SHIFT); + cpu->pc += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); while (rs <= 31) { - tmp = cpu->cd.ppc.gpr[rs]; + uint32_t tmp = cpu->cd.ppc.gpr[rs]; if (cpu->byte_order == EMUL_BIG_ENDIAN) { d[3] = tmp; d[2] = tmp >> 8; d[1] = tmp >> 16; d[0] = tmp >> 24; @@ -1232,12 +1841,9 @@ d[2] = tmp >> 16; d[3] = tmp >> 24; } if (cpu->memory_rw(cpu, cpu->mem, addr, d, sizeof(d), - MEM_WRITE, CACHE_DATA) != MEMORY_ACCESS_OK) - n_err ++; - - if (n_err > 0) { - fatal("TODO: stmw: exception\n"); - exit(1); + MEM_WRITE, CACHE_DATA) != MEMORY_ACCESS_OK) { + /* exception */ + return; } rs ++; @@ -1247,6 +1853,79 @@ /* + * Load/store string: + * + * arg[0] = rs (well, rt for lswi) + * arg[1] = ptr to ra (or ptr to zero) + * arg[2] = nb + */ +X(lswi) +{ + MODE_uint_t addr = reg(ic->arg[1]); + int rt = ic->arg[0], nb = ic->arg[2]; + int sub = 0; + + int 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) + << PPC_INSTR_ALIGNMENT_SHIFT); + cpu->pc += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); + + while (nb > 0) { + unsigned char d; + if (cpu->memory_rw(cpu, cpu->mem, addr, &d, 1, + MEM_READ, CACHE_DATA) != MEMORY_ACCESS_OK) { + /* exception */ + return; + } + + if (cpu->cd.ppc.mode == MODE_POWER && sub == 0) + cpu->cd.ppc.gpr[rt] = 0; + cpu->cd.ppc.gpr[rt] &= ~(0xff << (24-8*sub)); + cpu->cd.ppc.gpr[rt] |= (d << (24-8*sub)); + sub ++; + if (sub == 4) { + rt = (rt + 1) & 31; + sub = 0; + } + addr ++; + nb --; + } +} +X(stswi) +{ + MODE_uint_t addr = reg(ic->arg[1]); + int rs = ic->arg[0], nb = ic->arg[2]; + uint32_t cur = cpu->cd.ppc.gpr[rs]; + int sub = 0; + + int 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) + << PPC_INSTR_ALIGNMENT_SHIFT); + cpu->pc += (low_pc << PPC_INSTR_ALIGNMENT_SHIFT); + + while (nb > 0) { + unsigned char d = cur >> 24; + if (cpu->memory_rw(cpu, cpu->mem, addr, &d, 1, + MEM_WRITE, CACHE_DATA) != MEMORY_ACCESS_OK) { + /* exception */ + return; + } + cur <<= 8; + sub ++; + if (sub == 4) { + rs = (rs + 1) & 31; + sub = 0; + cur = cpu->cd.ppc.gpr[rs]; + } + addr ++; + nb --; + } +} + + +/* * Shifts, and, or, xor, etc. * * arg[0] = pointer to source register rs @@ -1260,7 +1939,7 @@ reg(ic->arg[2]) = (int64_t)(int8_t)reg(ic->arg[0]); #endif } -DOT(extsb) +DOT2(extsb) X(extsh) { #ifdef MODE32 reg(ic->arg[2]) = (int32_t)(int16_t)reg(ic->arg[0]); @@ -1268,7 +1947,7 @@ reg(ic->arg[2]) = (int64_t)(int16_t)reg(ic->arg[0]); #endif } -DOT(extsh) +DOT2(extsh) X(extsw) { #ifdef MODE32 fatal("TODO: extsw: invalid instruction\n"); exit(1); @@ -1276,42 +1955,47 @@ reg(ic->arg[2]) = (int64_t)(int32_t)reg(ic->arg[0]); #endif } -DOT(extsw) +DOT2(extsw) X(slw) { reg(ic->arg[2]) = (uint64_t)reg(ic->arg[0]) - << (reg(ic->arg[1]) & 63); } -DOT(slw) -X(sraw) { reg(ic->arg[2]) = -#ifdef MODE32 - (int32_t) -#else - (int64_t) -#endif - reg(ic->arg[0]) >> (reg(ic->arg[1]) & 63); } -DOT(sraw) + << (reg(ic->arg[1]) & 31); } +DOT2(slw) +X(sraw) +{ + uint32_t tmp = reg(ic->arg[0]); + int i = 0, j = 0, sh = reg(ic->arg[1]) & 31; + + cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; + if (tmp & 0x80000000) + i = 1; + while (sh-- > 0) { + if (tmp & 1) + j ++; + tmp >>= 1; + if (tmp & 0x40000000) + tmp |= 0x80000000; + } + if (i && j>0) + cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; + reg(ic->arg[2]) = (int64_t)(int32_t)tmp; +} +DOT2(sraw) X(srw) { reg(ic->arg[2]) = (uint64_t)reg(ic->arg[0]) - >> (reg(ic->arg[1]) & 63); } -DOT(srw) + >> (reg(ic->arg[1]) & 31); } +DOT2(srw) X(and) { reg(ic->arg[2]) = reg(ic->arg[0]) & reg(ic->arg[1]); } -X(and_dot) { reg(ic->arg[2]) = reg(ic->arg[0]) & reg(ic->arg[1]); - update_cr0(cpu, reg(ic->arg[2])); } +DOT2(and) X(nand) { reg(ic->arg[2]) = ~(reg(ic->arg[0]) & reg(ic->arg[1])); } -X(nand_dot) { reg(ic->arg[2]) = ~(reg(ic->arg[0]) & reg(ic->arg[1])); - update_cr0(cpu, reg(ic->arg[2])); } +DOT2(nand) X(andc) { reg(ic->arg[2]) = reg(ic->arg[0]) & (~reg(ic->arg[1])); } -X(andc_dot) { reg(ic->arg[2]) = reg(ic->arg[0]) & (~reg(ic->arg[1])); - update_cr0(cpu, reg(ic->arg[2])); } +DOT2(andc) X(nor) { reg(ic->arg[2]) = ~(reg(ic->arg[0]) | reg(ic->arg[1])); } -X(nor_dot) { reg(ic->arg[2]) = ~(reg(ic->arg[0]) | reg(ic->arg[1])); - update_cr0(cpu, reg(ic->arg[2])); } +DOT2(nor) X(or) { reg(ic->arg[2]) = reg(ic->arg[0]) | reg(ic->arg[1]); } -X(or_dot) { reg(ic->arg[2]) = reg(ic->arg[0]) | reg(ic->arg[1]); - update_cr0(cpu, reg(ic->arg[2])); } +DOT2(or) X(orc) { reg(ic->arg[2]) = reg(ic->arg[0]) | (~reg(ic->arg[1])); } -X(orc_dot) { reg(ic->arg[2]) = reg(ic->arg[0]) | (~reg(ic->arg[1])); - update_cr0(cpu, reg(ic->arg[2])); } +DOT2(orc) X(xor) { reg(ic->arg[2]) = reg(ic->arg[0]) ^ reg(ic->arg[1]); } -X(xor_dot) { reg(ic->arg[2]) = reg(ic->arg[0]) ^ reg(ic->arg[1]); - update_cr0(cpu, reg(ic->arg[2])); } +DOT2(xor) /* @@ -1321,7 +2005,7 @@ * arg[1] = pointer to destination register rt */ X(neg) { reg(ic->arg[1]) = -reg(ic->arg[0]); } -X(neg_dot) { instr(neg)(cpu,ic); update_cr0(cpu, reg(ic->arg[1])); } +DOT1(neg) /* @@ -1336,6 +2020,7 @@ int32_t sum = (int32_t)reg(ic->arg[0]) * (int32_t)reg(ic->arg[1]); reg(ic->arg[2]) = (int32_t)sum; } +DOT2(mullw) X(mulhw) { int64_t sum; @@ -1343,6 +2028,7 @@ * (int64_t)(int32_t)reg(ic->arg[1]); reg(ic->arg[2]) = sum >> 32; } +DOT2(mulhw) X(mulhwu) { uint64_t sum; @@ -1350,6 +2036,7 @@ * (uint64_t)(uint32_t)reg(ic->arg[1]); reg(ic->arg[2]) = sum >> 32; } +DOT2(mulhwu) X(divw) { int32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); @@ -1360,6 +2047,7 @@ sum = a / b; reg(ic->arg[2]) = (uint32_t)sum; } +DOT2(divw) X(divwu) { uint32_t a = reg(ic->arg[0]), b = reg(ic->arg[1]); @@ -1370,6 +2058,7 @@ sum = a / b; reg(ic->arg[2]) = sum; } +DOT2(divwu) /* @@ -1380,7 +2069,7 @@ * arg[2] = pointer to destination register rt */ X(add) { reg(ic->arg[2]) = reg(ic->arg[0]) + reg(ic->arg[1]); } -X(add_dot) { instr(add)(cpu,ic); update_cr0(cpu, reg(ic->arg[2])); } +DOT2(add) /* @@ -1395,10 +2084,10 @@ /* TODO: this only works in 32-bit mode */ uint64_t tmp = (uint32_t)reg(ic->arg[0]); uint64_t tmp2 = tmp; - cpu->cd.ppc.xer &= ~PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; tmp += (uint32_t)reg(ic->arg[1]); if ((tmp >> 32) != (tmp2 >> 32)) - cpu->cd.ppc.xer |= PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (uint32_t)tmp; } @@ -1413,47 +2102,47 @@ X(adde) { /* TODO: this only works in 32-bit mode */ - int old_ca = cpu->cd.ppc.xer & PPC_XER_CA; + int old_ca = cpu->cd.ppc.spr[SPR_XER] & PPC_XER_CA; uint64_t tmp = (uint32_t)reg(ic->arg[0]); uint64_t tmp2 = tmp; - cpu->cd.ppc.xer &= ~PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; tmp += (uint32_t)reg(ic->arg[1]); if (old_ca) tmp ++; if ((tmp >> 32) != (tmp2 >> 32)) - cpu->cd.ppc.xer |= PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (uint32_t)tmp; } -X(adde_dot) { instr(adde)(cpu,ic); update_cr0(cpu, reg(ic->arg[2])); } +DOT2(adde) X(addme) { /* TODO: this only works in 32-bit mode */ - int old_ca = cpu->cd.ppc.xer & PPC_XER_CA; + int old_ca = cpu->cd.ppc.spr[SPR_XER] & PPC_XER_CA; uint64_t tmp = (uint32_t)reg(ic->arg[0]); uint64_t tmp2 = tmp; - cpu->cd.ppc.xer &= ~PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (old_ca) tmp ++; tmp += 0xffffffffULL; if ((tmp >> 32) != (tmp2 >> 32)) - cpu->cd.ppc.xer |= PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (uint32_t)tmp; } -X(addme_dot) { instr(addme)(cpu,ic); update_cr0(cpu, reg(ic->arg[2])); } +DOT2(addme) X(addze) { /* TODO: this only works in 32-bit mode */ - int old_ca = cpu->cd.ppc.xer & PPC_XER_CA; + int old_ca = cpu->cd.ppc.spr[SPR_XER] & PPC_XER_CA; uint64_t tmp = (uint32_t)reg(ic->arg[0]); uint64_t tmp2 = tmp; - cpu->cd.ppc.xer &= ~PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (old_ca) tmp ++; if ((tmp >> 32) != (tmp2 >> 32)) - cpu->cd.ppc.xer |= PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (uint32_t)tmp; } -X(addze_dot) { instr(addze)(cpu,ic); update_cr0(cpu, reg(ic->arg[2])); } +DOT2(addze) /* @@ -1463,25 +2152,28 @@ * arg[1] = pointer to source register rb * arg[2] = pointer to destination register rt */ -X(subf) { reg(ic->arg[2]) = reg(ic->arg[1]) - reg(ic->arg[0]); } -X(subf_dot) { instr(subf)(cpu,ic); update_cr0(cpu, reg(ic->arg[2])); } +X(subf) +{ + reg(ic->arg[2]) = reg(ic->arg[1]) - reg(ic->arg[0]); +} +DOT2(subf) X(subfc) { - cpu->cd.ppc.xer &= ~PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (reg(ic->arg[1]) >= reg(ic->arg[0])) - cpu->cd.ppc.xer |= PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = reg(ic->arg[1]) - reg(ic->arg[0]); } -X(subfc_dot) { instr(subfc)(cpu,ic); update_cr0(cpu, reg(ic->arg[2])); } +DOT2(subfc) X(subfe) { - int old_ca = (cpu->cd.ppc.xer & PPC_XER_CA)? 1 : 0; - cpu->cd.ppc.xer &= ~PPC_XER_CA; + int old_ca = (cpu->cd.ppc.spr[SPR_XER] & PPC_XER_CA)? 1 : 0; + cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (reg(ic->arg[1]) == reg(ic->arg[0])) { if (old_ca) - cpu->cd.ppc.xer |= PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; } else if (reg(ic->arg[1]) >= reg(ic->arg[0])) - cpu->cd.ppc.xer |= PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; /* * TODO: The register value calculation should be correct, @@ -1490,20 +2182,33 @@ reg(ic->arg[2]) = reg(ic->arg[1]) - reg(ic->arg[0]) - (old_ca? 0 : 1); } -X(subfe_dot) { instr(subfe)(cpu,ic); update_cr0(cpu, reg(ic->arg[2])); } +DOT2(subfe) +X(subfme) +{ + int old_ca = cpu->cd.ppc.spr[SPR_XER] & PPC_XER_CA; + uint64_t tmp = (uint32_t)(~reg(ic->arg[0])); + tmp += 0xffffffffULL; + cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; + if (old_ca) + tmp ++; + if ((tmp >> 32) != 0) + cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; + reg(ic->arg[2]) = (uint32_t)tmp; +} +DOT2(subfme) X(subfze) { - int old_ca = cpu->cd.ppc.xer & PPC_XER_CA; + int old_ca = cpu->cd.ppc.spr[SPR_XER] & PPC_XER_CA; uint64_t tmp = (uint32_t)(~reg(ic->arg[0])); uint64_t tmp2 = tmp; - cpu->cd.ppc.xer &= ~PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] &= ~PPC_XER_CA; if (old_ca) tmp ++; if ((tmp >> 32) != (tmp2 >> 32)) - cpu->cd.ppc.xer |= PPC_XER_CA; + cpu->cd.ppc.spr[SPR_XER] |= PPC_XER_CA; reg(ic->arg[2]) = (uint32_t)tmp; } -X(subfze_dot) { instr(subfze)(cpu,ic); update_cr0(cpu, reg(ic->arg[2])); } +DOT2(subfze) /* @@ -1517,12 +2222,237 @@ X(xori) { reg(ic->arg[2]) = reg(ic->arg[0]) ^ (uint32_t)ic->arg[1]; } +#include "tmp_ppc_loadstore.c" + + +/* + * lfs, stfs: Load/Store Floating-point Single precision + */ +X(lfs) +{ + /* Sync. PC in case of an exception: */ + 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); + if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { + ppc_exception(cpu, PPC_EXCEPTION_FPU); + return; + } + + /* Perform a 32-bit load: */ +#ifdef MODE32 + ppc32_loadstore +#else + ppc_loadstore +#endif + [2 + 4 + 8](cpu, ic); + + if (old_pc == cpu->pc) { + /* The load succeeded. Let's convert the value: */ + struct ieee_float_value val; + (*(uint64_t *)ic->arg[0]) &= 0xffffffff; + ieee_interpret_float_value(*(uint64_t *)ic->arg[0], + &val, IEEE_FMT_S); + (*(uint64_t *)ic->arg[0]) = + ieee_store_float_value(val.f, IEEE_FMT_D, val.nan); + } +} +X(lfsx) +{ + /* Sync. PC in case of an exception: */ + 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); + if (!(cpu->cd.ppc.msr & PPC_MSR_FP)) { + ppc_exception(cpu, PPC_EXCEPTION_FPU); + return; + } + + /* Perform a 32-bit load: */ +#ifdef MODE32 + ppc32_loadstore_indexed +#else + ppc_loadstore_indexed +#endif + [2 + 4 + 8](cpu, ic); + + if (old_pc == cpu->pc) { + /* The load succeeded. Let's convert the value: */ + struct ieee_float_value val; + (*(uint64_t *)ic->arg[0]) &= 0xffffffff; + ieee_interpret_float_value(*(uint64_t *)ic->arg[0], + &val, IEEE_FMT_S); + (*(uint64_t *)ic->arg[0]) = + ieee_store_float_value(val.f, IEEE_FMT_D, val.nan); + } +} +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; + } + + /* Perform a 64-bit load: */ +#ifdef MODE32 + ppc32_loadstore +#else + ppc_loadstore +#endif + [3 + 4 + 8](cpu, ic); +} +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; + } + /* Perform a 64-bit load: */ +#ifdef MODE32 + ppc32_loadstore_indexed +#else + ppc_loadstore_indexed +#endif + [3 + 4 + 8](cpu, ic); +} +X(stfs) +{ + uint64_t *old_arg0 = (void *)ic->arg[0]; + 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; + } + + ieee_interpret_float_value(*old_arg0, &val, IEEE_FMT_D); + tmp_val = ieee_store_float_value(val.f, IEEE_FMT_S, val.nan); + + ic->arg[0] = (size_t)&tmp_val; + + /* Perform a 32-bit store: */ +#ifdef MODE32 + ppc32_loadstore +#else + ppc_loadstore +#endif + [2 + 4](cpu, ic); + + ic->arg[0] = (size_t)old_arg0; +} +X(stfsx) +{ + uint64_t *old_arg0 = (void *)ic->arg[0]; + 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; + } + + ieee_interpret_float_value(*old_arg0, &val, IEEE_FMT_D); + tmp_val = ieee_store_float_value(val.f, IEEE_FMT_S, val.nan); + + ic->arg[0] = (size_t)&tmp_val; + + /* Perform a 32-bit store: */ +#ifdef MODE32 + ppc32_loadstore_indexed +#else + ppc_loadstore_indexed +#endif + [2 + 4](cpu, ic); + + ic->arg[0] = (size_t)old_arg0; +} +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; + } + /* Perform a 64-bit store: */ +#ifdef MODE32 + ppc32_loadstore +#else + ppc_loadstore +#endif + [3 + 4](cpu, ic); +} +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; + } + /* Perform a 64-bit store: */ +#ifdef MODE32 + ppc32_loadstore_indexed +#else + ppc_loadstore_indexed +#endif + [3 + 4](cpu, ic); +} + + +/* + * tlbia: TLB invalidate all + */ +X(tlbia) +{ +printf("tlbia\n"); +exit(1); + cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); +} + + /* * tlbie: TLB invalidate */ X(tlbie) { - cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); + cpu->invalidate_translation_caches(cpu, reg(ic->arg[0]), + INVALIDATE_VADDR); +} + + +/* + * sc: Syscall. + */ +X(sc) +{ + /* Synchronize the PC (pointing to _after_ this instruction) */ + cpu->pc = (cpu->pc & ~0xfff) + ic->arg[1]; + + ppc_exception(cpu, PPC_EXCEPTION_SC); } @@ -1543,93 +2473,30 @@ X(openfirmware) { of_emul(cpu); - cpu->pc = cpu->cd.ppc.lr; + cpu->pc = cpu->cd.ppc.spr[SPR_LR]; if (cpu->machine->show_trace_tree) cpu_functioncall_trace_return(cpu); DYNTRANS_PC_TO_POINTERS(cpu); } -#include "tmp_ppc_loadstore.c" - - -/*****************************************************************************/ - - /* - * byte_fill_loop: - * - * A byte-fill loop. Fills at most one page at a time. If the page was not - * in the host_store table, then the original sequence (beginning with - * cmpwi crX,rY,0) is executed instead. - * - * L: cmpwi crX,rY,0 ic[0] - * stb rW,0(rZ) ic[1] - * subi rY,rY,1 ic[2] - * addi rZ,rZ,1 ic[3] - * bc 12,4*X+1,L ic[4] - */ -X(byte_fill_loop) -{ - int max_pages_left = 5; - unsigned int x = ic[0].arg[2], n, ofs, maxlen, c; - uint64_t *y = (uint64_t *)ic[0].arg[0]; - uint64_t *z = (uint64_t *)ic[1].arg[1]; - uint64_t *w = (uint64_t *)ic[1].arg[0]; - unsigned char *page; -#ifdef MODE32 - uint32_t addr; -#else - uint64_t addr; - fatal("byte_fill_loop: not for 64-bit mode yet\n"); - exit(1); -#endif - -restart_loop: - addr = reg(z); - /* TODO: This only work with 32-bit addressing: */ - page = cpu->cd.ppc.host_store[addr >> 12]; - if (page == NULL) { - instr(cmpwi)(cpu, ic); - return; - } - - n = reg(y) + 1; ofs = addr & 0xfff; maxlen = 0x1000 - ofs; - if (n > maxlen) - n = maxlen; - - /* fatal("FILL A: x=%i n=%i ofs=0x%x y=0x%x z=0x%x w=0x%x\n", x, - n, ofs, (int)reg(y), (int)reg(z), (int)reg(w)); */ - - memset(page + ofs, *w, n); - - reg(z) = addr + n; - reg(y) -= n; + * tlbli: + */ +X(tlbli) +{ +} - if ((int32_t)reg(y) + 1 < 0) - c = 8; - else if ((int32_t)reg(y) + 1 > 0) - c = 4; - else - c = 2; - c |= ((cpu->cd.ppc.xer >> 31) & 1); /* SO bit, copied from XER */ - cpu->cd.ppc.cr &= ~(0xf << (28 - 4*x)); - cpu->cd.ppc.cr |= (c << (28 - 4*x)); - - cpu->n_translated_instrs += (5 * n); - - if (max_pages_left-- > 0 && - (int32_t)reg(y) > 0) - goto restart_loop; - cpu->n_translated_instrs --; - if ((int32_t)reg(y) > 0) - cpu->cd.ppc.next_ic = ic; - else - cpu->cd.ppc.next_ic = &ic[5]; +/* + * tlbld: + */ +X(tlbld) +{ + /* MODE_uint_t vaddr = reg(ic->arg[0]); + MODE_uint_t paddr = cpu->cd.ppc.spr[SPR_RPA]; */ - /* fatal("FILL B: x=%i n=%i ofs=0x%x y=0x%x z=0x%x w=0x%x\n", x, n, - ofs, (int)reg(y), (int)reg(z), (int)reg(w)); */ + /* TODO? */ } @@ -1654,53 +2521,6 @@ /* - * ppc_combine_instructions(): - * - * Combine two or more instructions, if possible, into a single function call. - */ -void COMBINE_INSTRUCTIONS(struct cpu *cpu, struct ppc_instr_call *ic, - uint32_t addr) -{ - int n_back; - n_back = (addr >> PPC_INSTR_ALIGNMENT_SHIFT) - & (PPC_IC_ENTRIES_PER_PAGE-1); - - if (n_back >= 4) { - /* - * L: cmpwi crX,rY,0 ic[-4] - * stb rW,0(rZ) ic[-3] - * subi rY,rY,1 ic[-2] - * addi rZ,rZ,1 ic[-1] - * bc 12,4*X+1,L ic[0] - */ - if (ic[-4].f == instr(cmpwi) && - ic[-4].arg[0] == ic[-2].arg[0] && ic[-4].arg[1] == 0 && - - ic[-3].f == instr(stb_0) && - ic[-3].arg[1] == ic[-1].arg[0] && ic[-3].arg[2] == 0 && - - ic[-2].f == instr(addi) && - ic[-2].arg[0] == ic[-2].arg[2] && ic[-2].arg[1] == -1 && - - ic[-1].f == instr(addi) && - ic[-1].arg[0] == ic[-1].arg[2] && ic[-1].arg[1] == 1 && - - ic[0].f == instr(bc_samepage) && - ic[0].arg[0] == (size_t)&ic[-4] && - ic[0].arg[1] == 12 && ic[0].arg[2] == 4*ic[-4].arg[2] + 1) { - ic[-4].f = instr(byte_fill_loop); - combined; - } - } - - /* TODO: Combine forward as well */ -} - - -/*****************************************************************************/ - - -/* * ppc_instr_to_be_translated(): * * Translate an instruction word into an ppc_instr_call. ic is filled in with @@ -1711,12 +2531,12 @@ X(to_be_translated) { uint64_t addr, low_pc, tmp_addr; - uint32_t iword; + uint32_t iword, mask; unsigned char *page; unsigned char ib[4]; 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; + bfa, fp, byterev, nb, mb, me; void (*samepage_function)(struct cpu *, struct ppc_instr_call *); void (*rc_f)(struct cpu *, struct ppc_instr_call *); @@ -1739,9 +2559,10 @@ /* fatal("TRANSLATION MISS!\n"); */ if (!cpu->memory_rw(cpu, cpu->mem, addr, ib, sizeof(ib), MEM_READ, CACHE_INSTRUCTION)) { - fatal("to_be_translated(): " + fatal("PPC to_be_translated(): " "read failed: TODO\n"); - goto bad; + exit(1); + /* goto bad; */ } } @@ -1811,7 +2632,7 @@ } ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = (ssize_t)imm; - ic->arg[2] = bf; + ic->arg[2] = 28 - 4 * bf; break; case PPC_HI6_ADDIC: @@ -1828,7 +2649,7 @@ else ic->f = instr(addic_dot); ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); - ic->arg[1] = (ssize_t)imm; + ic->arg[1] = imm; ic->arg[2] = (size_t)(&cpu->cd.ppc.gpr[rt]); break; @@ -1840,7 +2661,7 @@ ic->arg[0] = (size_t)(&cpu->cd.ppc.zero); else ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); - ic->arg[1] = (ssize_t)(int16_t)(iword & 0xffff); + ic->arg[1] = (int16_t)(iword & 0xffff); if (main_opcode == PPC_HI6_ADDIS) ic->arg[1] <<= 16; ic->arg[2] = (size_t)(&cpu->cd.ppc.gpr[rt]); @@ -1879,46 +2700,46 @@ case PPC_HI6_LBZU: case PPC_HI6_LHZ: case PPC_HI6_LHZU: + case PPC_HI6_LHA: + case PPC_HI6_LHAU: case PPC_HI6_LWZ: case PPC_HI6_LWZU: case PPC_HI6_LFD: + case PPC_HI6_LFS: case PPC_HI6_STB: case PPC_HI6_STBU: case PPC_HI6_STH: case PPC_HI6_STHU: case PPC_HI6_STW: case PPC_HI6_STWU: + case PPC_HI6_STFD: + case PPC_HI6_STFS: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; - imm = (int16_t)(iword & 0xffff); + imm = (int16_t)iword; load = 0; zero = 1; size = 0; update = 0; fp = 0; + ic->f = NULL; switch (main_opcode) { - case PPC_HI6_LBZ: load = 1; break; - case PPC_HI6_LBZU: load = 1; update = 1; break; - case PPC_HI6_LHZ: load = 1; size = 1; break; - case PPC_HI6_LHZU: load = 1; size = 1; update = 1; break; - case PPC_HI6_LWZ: load = 1; size = 2; break; - case PPC_HI6_LWZU: load = 1; size = 2; update = 1; break; - case PPC_HI6_LFD: load = 1; size = 3; fp = 1; break; + case PPC_HI6_LBZ: load=1; break; + case PPC_HI6_LBZU: load=1; update=1; break; + case PPC_HI6_LHA: load=1; size=1; zero=0; break; + case PPC_HI6_LHAU: load=1; size=1; zero=0; update=1; break; + case PPC_HI6_LHZ: load=1; size=1; break; + case PPC_HI6_LHZU: load=1; size=1; update=1; break; + case PPC_HI6_LWZ: load=1; size=2; break; + case PPC_HI6_LWZU: load=1; size=2; update=1; break; + case PPC_HI6_LFD: load=1; size=3; fp=1;ic->f=instr(lfd);break; + case PPC_HI6_LFS: load=1; size=2; fp=1;ic->f=instr(lfs);break; case PPC_HI6_STB: break; - case PPC_HI6_STBU: update = 1; break; - case PPC_HI6_STH: size = 1; break; - case PPC_HI6_STHU: size = 1; update = 1; break; - case PPC_HI6_STW: size = 2; break; - case PPC_HI6_STWU: size = 2; update = 1; break; - } - if (fp) { - /* Floating point: */ - if (load && size == 3) { - fatal("TODO: ld is INCORRECT!\n"); - ic->f = instr(nop); - } else { - /* TODO */ - fatal("TODO: fdgasgd\n"); - goto bad; - } - } else { - /* Integer load/store: */ + case PPC_HI6_STBU: update=1; break; + case PPC_HI6_STH: size=1; break; + case PPC_HI6_STHU: size=1; update=1; break; + case PPC_HI6_STW: size=2; break; + case PPC_HI6_STWU: size=2; update=1; break; + case PPC_HI6_STFD: size=3; fp=1; ic->f = instr(stfd); break; + case PPC_HI6_STFS: size=2; fp=1; ic->f = instr(stfs); break; + } + if (ic->f == NULL) { ic->f = #ifdef MODE32 ppc32_loadstore @@ -1949,16 +2770,20 @@ bo = (iword >> 21) & 31; bi = (iword >> 16) & 31; tmp_addr = (int64_t)(int16_t)(iword & 0xfffc); - if (lk_bit) { - fatal("lk_bit: NOT YET\n"); - goto bad; - } if (aa_bit) { fatal("aa_bit: NOT YET\n"); goto bad; } - ic->f = instr(bc); - samepage_function = instr(bc_samepage); + if (lk_bit) { + ic->f = instr(bcl); + samepage_function = instr(bcl_samepage); + } else { + ic->f = instr(bc); + if (bo & 4) + samepage_function = instr(bc_samepage_no_ctr); + else + samepage_function = instr(bc_samepage); + } ic->arg[0] = (ssize_t)tmp_addr; ic->arg[1] = bo; ic->arg[2] = bi; @@ -1981,26 +2806,19 @@ case PPC_HI6_SC: ic->arg[0] = (iword >> 5) & 0x7f; + ic->arg[1] = (addr & 0xfff) + 4; if (cpu->machine->userland_emul != NULL) ic->f = instr(user_syscall); - else { + else if (iword == 0x44ee0002) { /* Special case/magic hack for OpenFirmware emul: */ - if (iword == 0x44ee0002) { - ic->f = instr(openfirmware); - break; - } - fatal("PPC non-userland SYSCALL: TODO\n"); - goto bad; - } + ic->f = instr(openfirmware); + } else + ic->f = instr(sc); break; case PPC_HI6_B: aa_bit = (iword & 2) >> 1; lk_bit = iword & 1; - if (aa_bit) { - fatal("aa_bit: NOT YET\n"); - goto bad; - } tmp_addr = (int64_t)(int32_t)((iword & 0x03fffffc) << 6); tmp_addr = (int64_t)tmp_addr >> 6; if (lk_bit) { @@ -2031,6 +2849,18 @@ ((new_pc & mask_within_page) >> 2)); } } + if (aa_bit) { + if (lk_bit) { + if (cpu->machine->show_trace_tree) { + ic->f = instr(bla_trace); + } else { + ic->f = instr(bla); + } + } else { + ic->f = instr(ba); + } + ic->arg[0] = (ssize_t)tmp_addr; + } break; case PPC_HI6_19: @@ -2046,8 +2876,12 @@ if (xo == PPC_19_BCLR) { if (lk_bit) ic->f = instr(bclr_l); - else + else { ic->f = instr(bclr); + if (!cpu->machine->show_trace_tree && + (bo & 0x14) == 0x14) + ic->f = instr(bclr_20); + } } else { if (lk_bit) ic->f = instr(bcctr_l); @@ -2055,7 +2889,7 @@ ic->f = instr(bcctr); } ic->arg[0] = bo; - ic->arg[1] = bi; + ic->arg[1] = 31 - bi; ic->arg[2] = bh; break; @@ -2071,8 +2905,8 @@ case PPC_19_MCRF: bf = (iword >> 23) & 7; bfa = (iword >> 18) & 7; - ic->arg[0] = bf; - ic->arg[1] = bfa; + ic->arg[0] = 28 - 4*bf; + ic->arg[1] = 28 - 4*bfa; ic->f = instr(mcrf); break; @@ -2080,12 +2914,14 @@ case PPC_19_CRANDC: case PPC_19_CREQV: case PPC_19_CROR: + case PPC_19_CRNOR: case PPC_19_CRXOR: switch (xo) { case PPC_19_CRAND: ic->f = instr(crand); break; 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_CRNOR: ic->f = instr(crnor); break; case PPC_19_CRXOR: ic->f = instr(crxor); break; } ic->arg[0] = iword; @@ -2095,14 +2931,34 @@ } break; - case PPC_HI6_RLWIMI: + case PPC_HI6_RLWNM: case PPC_HI6_RLWINM: + ra = (iword >> 16) & 31; + mb = (iword >> 6) & 31; + me = (iword >> 1) & 31; + rc = iword & 1; + mask = 0; + for (;;) { + mask |= ((uint32_t)0x80000000 >> mb); + if (mb == me) + break; + mb ++; mb &= 31; + } + switch (main_opcode) { + case PPC_HI6_RLWNM: + ic->f = rc? instr(rlwnm_dot) : instr(rlwnm); break; + case PPC_HI6_RLWINM: + ic->f = rc? instr(rlwinm_dot) : instr(rlwinm); break; + } + ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); + ic->arg[1] = mask; + ic->arg[2] = (uint32_t)iword; + break; + + case PPC_HI6_RLWIMI: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; - if (main_opcode == PPC_HI6_RLWIMI) - ic->f = instr(rlwimi); - else - ic->f = instr(rlwinm); + ic->f = instr(rlwimi); ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[2] = (uint32_t)iword; @@ -2169,7 +3025,7 @@ } ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[rb]); - ic->arg[2] = bf; + ic->arg[2] = 28 - 4*bf; break; case PPC_31_CNTLZW: @@ -2188,74 +3044,22 @@ case PPC_31_MFSPR: rt = (iword >> 21) & 31; spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31); + debug_spr_usage(cpu->pc, spr); ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rt]); + ic->arg[1] = (size_t)(&cpu->cd.ppc.spr[spr]); switch (spr) { - case 8: ic->f = instr(mflr); break; - case 9: ic->f = instr(mfctr); break; - case 25: ic->f = instr(mfsdr1); break; - case 26: ic->f = instr(mfsrr0); break; - case 27: ic->f = instr(mfsrr1); break; - case 272: ic->f = instr(mfsprg0); break; - case 273: ic->f = instr(mfsprg1); break; - case 274: ic->f = instr(mfsprg2); break; - case 275: ic->f = instr(mfsprg3); break; - case 287: ic->f = instr(mfpvr); break; - case 1008:ic->f = instr(mfdbsr); break; - case 1009:ic->f = instr(mfhid1); break; - case 1017:ic->f = instr(mfl2cr); break; - default:if (spr >= 528 && spr < 544) { - if (spr & 1) { - if (spr & 16) - ic->f = instr(mfdbatl); - else - ic->f = instr(mfibatl); - } else { - if (spr & 16) - ic->f = instr(mfdbatu); - else - ic->f = instr(mfibatu); - } - ic->arg[1] = (spr >> 1) & 3; - } else { - fatal("UNIMPLEMENTED spr %i\n", spr); - goto bad; - } + case SPR_PMC1: ic->f = instr(mfspr_pmc1); break; + default: ic->f = instr(mfspr); } break; case PPC_31_MTSPR: rs = (iword >> 21) & 31; spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31); + debug_spr_usage(cpu->pc, spr); ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); - switch (spr) { - case 8: ic->f = instr(mtlr); break; - case 9: ic->f = instr(mtctr); break; - case 25: ic->f = instr(mtsdr1); break; - case 26: ic->f = instr(mtsrr0); break; - case 27: ic->f = instr(mtsrr1); break; - case 272: ic->f = instr(mtsprg0); break; - case 273: ic->f = instr(mtsprg1); break; - case 274: ic->f = instr(mtsprg2); break; - case 275: ic->f = instr(mtsprg3); break; - case 1008:ic->f = instr(mtdbsr); break; - default:if (spr >= 528 && spr < 544) { - if (spr & 1) { - if (spr & 16) - ic->f = instr(mtdbatl); - else - ic->f = instr(mtibatl); - } else { - if (spr & 16) - ic->f = instr(mtdbatu); - else - ic->f = instr(mtibatu); - } - ic->arg[1] = (spr >> 1) & 3; - } else { - fatal("UNIMPLEMENTED spr %i\n", spr); - goto bad; - } - } + ic->arg[1] = (size_t)(&cpu->cd.ppc.spr[spr]); + ic->f = instr(mtspr); break; case PPC_31_MFCR: @@ -2278,6 +3082,7 @@ goto bad; } ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); + ic->arg[1] = (addr & 0xfff) + 4; ic->f = instr(mtmsr); break; @@ -2313,11 +3118,15 @@ } break; + case PPC_31_MFSR: case PPC_31_MTSR: rt = (iword >> 21) & 31; ic->arg[0] = (iword >> 16) & 15; ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[rt]); - ic->f = instr(mtsr); + switch (xo) { + case PPC_31_MFSR: ic->f = instr(mfsr); break; + case PPC_31_MTSR: ic->f = instr(mtsr); break; + } if (cpu->cd.ppc.bits == 64) { fatal("Not yet for 64-bit mode\n"); goto bad; @@ -2339,14 +3148,12 @@ break; case PPC_31_SYNC: - case PPC_31_TLBSYNC: case PPC_31_EIEIO: case PPC_31_DCBST: case PPC_31_DCBTST: case PPC_31_DCBF: case PPC_31_DCBT: case PPC_31_ICBI: - /* TODO */ ic->f = instr(nop); break; @@ -2358,14 +3165,41 @@ else ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[rb]); + ic->arg[2] = addr & 0xfff; ic->f = instr(dcbz); break; + case PPC_31_TLBIA: + ic->f = instr(tlbia); + break; + + case PPC_31_TLBSYNC: + /* According to IBM, "Ensures that a tlbie and + tlbia instruction executed by one processor has + completed on all other processors.", which in + GXemul means a nop :-) */ + ic->f = instr(nop); + break; + case PPC_31_TLBIE: - /* TODO */ + /* TODO: POWER also uses ra? */ + rb = (iword >> 11) & 31; + ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rb]); ic->f = instr(tlbie); break; + case PPC_31_TLBLD: /* takes an arg */ + rb = (iword >> 11) & 31; + ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rb]); + ic->f = instr(tlbld); + break; + + case PPC_31_TLBLI: /* takes an arg */ + rb = (iword >> 11) & 31; + ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rb]); + ic->f = instr(tlbli); + break; + case PPC_31_MFTB: rt = (iword >> 21) & 31; spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31); @@ -2398,12 +3232,40 @@ ic->f = instr(llsc); break; + case PPC_31_LSWI: + case PPC_31_STSWI: + rs = (iword >> 21) & 31; + ra = (iword >> 16) & 31; + nb = (iword >> 11) & 31; + ic->arg[0] = rs; + if (ra == 0) + ic->arg[1] = (size_t)(&cpu->cd.ppc.zero); + else + ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[ra]); + ic->arg[2] = nb == 0? 32 : nb; + switch (xo) { + case PPC_31_LSWI: ic->f = instr(lswi); break; + case PPC_31_STSWI: ic->f = instr(stswi); break; + } + break; + + case 0x1c3: + fatal("[ mtdcr: TODO ]\n"); + ic->f = instr(nop); + break; + case PPC_31_LBZX: case PPC_31_LBZUX: + case PPC_31_LHAX: + case PPC_31_LHAUX: case PPC_31_LHZX: case PPC_31_LHZUX: case PPC_31_LWZX: case PPC_31_LWZUX: + case PPC_31_LHBRX: + case PPC_31_LWBRX: + case PPC_31_LFDX: + case PPC_31_LFSX: case PPC_31_STBX: case PPC_31_STBUX: case PPC_31_STHX: @@ -2412,39 +3274,68 @@ case PPC_31_STWUX: case PPC_31_STDX: case PPC_31_STDUX: + case PPC_31_STHBRX: + case PPC_31_STWBRX: + case PPC_31_STFDX: + case PPC_31_STFSX: rs = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; - ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); if (ra == 0) ic->arg[1] = (size_t)(&cpu->cd.ppc.zero); else ic->arg[1] = (size_t)(&cpu->cd.ppc.gpr[ra]); ic->arg[2] = (size_t)(&cpu->cd.ppc.gpr[rb]); load = 0; zero = 1; size = 0; update = 0; + byterev = 0; fp = 0; + ic->f = NULL; switch (xo) { case PPC_31_LBZX: load = 1; break; - case PPC_31_LBZUX: load = update = 1; break; - case PPC_31_LHZX: size = 1; load = 1; break; - case PPC_31_LHZUX: size = 1; load = update = 1; break; - case PPC_31_LWZX: size = 2; load = 1; break; - case PPC_31_LWZUX: size = 2; load = update = 1; break; + case PPC_31_LBZUX: load=update=1; break; + case PPC_31_LHAX: size=1; load=1; zero=0; break; + case PPC_31_LHAUX: size=1; load=update=1; zero=0; break; + case PPC_31_LHZX: size=1; load=1; break; + case PPC_31_LHZUX: size=1; load=update = 1; break; + case PPC_31_LWZX: size=2; load=1; break; + case PPC_31_LWZUX: size=2; load=update = 1; break; + case PPC_31_LHBRX: size=1; load=1; byterev=1; + ic->f = instr(lhbrx); break; + case PPC_31_LWBRX: size=2; load=1; byterev=1; + ic->f = instr(lwbrx); break; + case PPC_31_LFDX: size=3; load=1; fp=1; + ic->f = instr(lfdx); break; + case PPC_31_LFSX: size=2; load=1; fp=1; + ic->f = instr(lfsx); break; case PPC_31_STBX: break; case PPC_31_STBUX: update = 1; break; - case PPC_31_STHX: size = 1; break; - case PPC_31_STHUX: size = 1; update = 1; break; - case PPC_31_STWX: size = 2; break; - case PPC_31_STWUX: size = 2; update = 1; break; - case PPC_31_STDX: size = 3; break; - case PPC_31_STDUX: size = 3; update = 1; break; + case PPC_31_STHX: size=1; break; + case PPC_31_STHUX: size=1; update = 1; break; + case PPC_31_STWX: size=2; break; + case PPC_31_STWUX: size=2; update = 1; break; + case PPC_31_STDX: size=3; break; + case PPC_31_STDUX: size=3; update = 1; break; + case PPC_31_STHBRX:size=1; byterev = 1; + ic->f = instr(sthbrx); break; + case PPC_31_STWBRX:size=2; byterev = 1; + ic->f = instr(stwbrx); break; + case PPC_31_STFDX: size=3; fp=1; + ic->f = instr(stfdx); break; + case PPC_31_STFSX: size=2; fp=1; + ic->f = instr(stfsx); break; } - ic->f = + if (fp) + ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rs]); + else + ic->arg[0] = (size_t)(&cpu->cd.ppc.gpr[rs]); + if (!byterev && ic->f == NULL) { + ic->f = #ifdef MODE32 - ppc32_loadstore_indexed + ppc32_loadstore_indexed #else - ppc_loadstore_indexed + ppc_loadstore_indexed #endif - [size + 4*zero + 8*load + 16*update]; + [size + 4*zero + 8*load + 16*update]; + } if (ra == 0 && update) { fatal("TODO: ra=0 && update?\n"); goto bad; @@ -2517,6 +3408,7 @@ case PPC_31_SUBF: case PPC_31_SUBFC: case PPC_31_SUBFE: + case PPC_31_SUBFME: case PPC_31_SUBFZE: rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; @@ -2541,6 +3433,7 @@ case PPC_31_SUBF: ic->f = instr(subf); break; case PPC_31_SUBFC: ic->f = instr(subfc); break; case PPC_31_SUBFE: ic->f = instr(subfe); n64=1; break; + case PPC_31_SUBFME: ic->f = instr(subfme); n64=1; break; case PPC_31_SUBFZE: ic->f = instr(subfze); n64=1;break; } if (rc) { @@ -2553,12 +3446,24 @@ ic->f = instr(addme_dot); break; case PPC_31_ADDZE: ic->f = instr(addze_dot); break; + case PPC_31_DIVW: + ic->f = instr(divw_dot); break; + case PPC_31_DIVWU: + ic->f = instr(divwu_dot); break; + case PPC_31_MULLW: + ic->f = instr(mullw_dot); break; + case PPC_31_MULHW: + ic->f = instr(mulhw_dot); break; + case PPC_31_MULHWU: + ic->f = instr(mulhwu_dot); break; case PPC_31_SUBF: ic->f = instr(subf_dot); break; case PPC_31_SUBFC: ic->f = instr(subfc_dot); break; case PPC_31_SUBFE: ic->f = instr(subfe_dot); break; + case PPC_31_SUBFME: + ic->f = instr(subfme_dot); break; case PPC_31_SUBFZE: ic->f = instr(subfze_dot); break; default:fatal("RC bit not yet implemented\n"); @@ -2578,26 +3483,128 @@ } break; - case PPC_HI6_63: - xo = (iword >> 1) & 1023; + case PPC_HI6_59: + xo = (iword >> 1) & 1023; rt = (iword >> 21) & 31; ra = (iword >> 16) & 31; rb = (iword >> 11) & 31; + rs = (iword >> 6) & 31; /* actually frc */ rc = iword & 1; - switch (xo) { + if (rc) { + fatal("Floating point (59) with rc bit! TODO\n"); + goto bad; + } - case PPC_63_FMR: - if (rc) { - fatal("FMR with rc-bit: TODO\n"); - goto bad; - } - ic->f = instr(fmr); - ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rb]); - ic->arg[1] = (size_t)(&cpu->cd.ppc.fpr[rt]); + /* NOTE: Some floating-point instructions are selected + using only the lowest 5 bits, not all 10! */ + switch (xo & 31) { + case PPC_59_FDIVS: + case PPC_59_FSUBS: + case PPC_59_FADDS: + switch (xo & 31) { + case PPC_59_FDIVS: ic->f = instr(fdivs); break; + case PPC_59_FSUBS: ic->f = instr(fsubs); break; + case PPC_59_FADDS: ic->f = instr(fadds); break; + } + ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[ra]); + ic->arg[1] = (size_t)(&cpu->cd.ppc.fpr[rb]); + ic->arg[2] = (size_t)(&cpu->cd.ppc.fpr[rt]); + break; + case PPC_59_FMULS: + ic->f = instr(fmuls); + ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rt]); + ic->arg[1] = (size_t)(&cpu->cd.ppc.fpr[ra]); + ic->arg[2] = (size_t)(&cpu->cd.ppc.fpr[rs]); /* frc */ break; + default:/* Use all 10 bits of xo: */ + switch (xo) { + default:goto bad; + } + } + break; - default:goto bad; + case PPC_HI6_63: + xo = (iword >> 1) & 1023; + rt = (iword >> 21) & 31; + ra = (iword >> 16) & 31; + rb = (iword >> 11) & 31; + rs = (iword >> 6) & 31; /* actually frc */ + rc = iword & 1; + + if (rc) { + fatal("Floating point (63) with rc bit! TODO\n"); + goto bad; + } + + /* NOTE: Some floating-point instructions are selected + using only the lowest 5 bits, not all 10! */ + switch (xo & 31) { + case PPC_63_FDIV: + case PPC_63_FSUB: + case PPC_63_FADD: + switch (xo & 31) { + case PPC_63_FDIV: ic->f = instr(fdiv); break; + case PPC_63_FSUB: ic->f = instr(fsub); break; + case PPC_63_FADD: ic->f = instr(fadd); break; + } + ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[ra]); + ic->arg[1] = (size_t)(&cpu->cd.ppc.fpr[rb]); + ic->arg[2] = (size_t)(&cpu->cd.ppc.fpr[rt]); + break; + case PPC_63_FMUL: + ic->f = instr(fmul); + ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rt]); + ic->arg[1] = (size_t)(&cpu->cd.ppc.fpr[ra]); + ic->arg[2] = (size_t)(&cpu->cd.ppc.fpr[rs]); /* frc */ + break; + case PPC_63_FMSUB: + case PPC_63_FMADD: + switch (xo & 31) { + case PPC_63_FMSUB: ic->f = instr(fmsub); break; + case PPC_63_FMADD: ic->f = instr(fmadd); break; + } + ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rt]); + ic->arg[1] = (size_t)(&cpu->cd.ppc.fpr[ra]); + ic->arg[2] = iword; + break; + default:/* Use all 10 bits of xo: */ + switch (xo) { + case PPC_63_FCMPU: + ic->f = instr(fcmpu); + ic->arg[0] = 28 - 4*(rt >> 2); + ic->arg[1] = (size_t)(&cpu->cd.ppc.fpr[ra]); + ic->arg[2] = (size_t)(&cpu->cd.ppc.fpr[rb]); + break; + case PPC_63_FRSP: + case PPC_63_FCTIWZ: + case PPC_63_FNEG: + case PPC_63_FMR: + switch (xo) { + case PPC_63_FRSP: ic->f = instr(frsp); break; + case PPC_63_FCTIWZ: ic->f = instr(fctiwz);break; + case PPC_63_FNEG: ic->f = instr(fneg); break; + case PPC_63_FMR: ic->f = instr(fmr); break; + } + ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rb]); + ic->arg[1] = (size_t)(&cpu->cd.ppc.fpr[rt]); + break; + case PPC_63_MFFS: + ic->f = instr(mffs); + ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rt]); + break; + case PPC_63_MTFSF: + ic->f = instr(mtfsf); + ic->arg[0] = (size_t)(&cpu->cd.ppc.fpr[rb]); + ic->arg[1] = 0; + for (bi=7; bi>=0; bi--) { + ic->arg[1] <<= 8; + if (iword & (1 << (17+bi))) + ic->arg[1] |= 0xf; + } + break; + default:goto bad; + } } break;