/[gxemul]/trunk/src/cpu_ppc.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/src/cpu_ppc.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 11 by dpavlin, Mon Oct 8 16:18:27 2007 UTC revision 12 by dpavlin, Mon Oct 8 16:18:38 2007 UTC
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $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 $
29   *   *
30   *  PowerPC/POWER CPU emulation.   *  PowerPC/POWER CPU emulation.
31   */   */
# Line 65  int ppc_cpu_family_init(struct cpu_famil Line 65  int ppc_cpu_family_init(struct cpu_famil
65  #include "opcodes_ppc.h"  #include "opcodes_ppc.h"
66  #include "symbol.h"  #include "symbol.h"
67    
68    #define DYNTRANS_DUALMODE_32
69  extern volatile int single_step;  #define DYNTRANS_32
70  extern int old_show_trace_tree;    #include "tmp_ppc_head.c"
 extern int old_instruction_trace;  
 extern int old_quiet_mode;  
 extern int quiet_mode;  
71    
72    
73  /*  /*
# Line 101  int ppc_cpu_new(struct cpu *cpu, struct Line 98  int ppc_cpu_new(struct cpu *cpu, struct
98          if (found == -1)          if (found == -1)
99                  return 0;                  return 0;
100    
101          cpu->memory_rw          = ppc_memory_rw;          cpu->memory_rw = ppc_memory_rw;
102            cpu->update_translation_table = ppc_update_translation_table;
103            cpu->invalidate_translation_caches_paddr =
104                ppc_invalidate_translation_caches_paddr;
105            cpu->invalidate_code_translation_caches =
106                ppc_invalidate_code_translation_caches;
107    
108          cpu->cd.ppc.cpu_type    = cpu_type_defs[found];          cpu->cd.ppc.cpu_type    = cpu_type_defs[found];
109          cpu->name               = cpu->cd.ppc.cpu_type.name;          cpu->name               = cpu->cd.ppc.cpu_type.name;
110          cpu->byte_order         = EMUL_BIG_ENDIAN;          cpu->byte_order         = EMUL_BIG_ENDIAN;
# Line 111  int ppc_cpu_new(struct cpu *cpu, struct Line 114  int ppc_cpu_new(struct cpu *cpu, struct
114          /*  Current operating mode:  */          /*  Current operating mode:  */
115          cpu->cd.ppc.bits        = cpu->cd.ppc.cpu_type.bits;          cpu->cd.ppc.bits        = cpu->cd.ppc.cpu_type.bits;
116    
117            cpu->is_32bit = (cpu->cd.ppc.bits == 32)? 1 : 0;
118    
119          /*  Only show name and caches etc for CPU nr 0 (in SMP machines):  */          /*  Only show name and caches etc for CPU nr 0 (in SMP machines):  */
120          if (cpu_id == 0) {          if (cpu_id == 0) {
121                  debug("%s", cpu->cd.ppc.cpu_type.name);                  debug("%s", cpu->cd.ppc.cpu_type.name);
# Line 204  void ppc_cpu_dumpinfo(struct cpu *cpu) Line 209  void ppc_cpu_dumpinfo(struct cpu *cpu)
209  /*  /*
210   *  reg_access_msr():   *  reg_access_msr():
211   */   */
212  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)
213  {  {
214          if (valuep == NULL) {          if (valuep == NULL) {
215                  fatal("reg_access_msr(): NULL\n");                  fatal("reg_access_msr(): NULL\n");
# Line 257  void ppc_cpu_register_dump(struct cpu *c Line 262  void ppc_cpu_register_dump(struct cpu *c
262                          debug("%08x", (int)cpu->cd.ppc.lr);                          debug("%08x", (int)cpu->cd.ppc.lr);
263                  else                  else
264                          debug("%016llx", (long long)cpu->cd.ppc.lr);                          debug("%016llx", (long long)cpu->cd.ppc.lr);
265                  debug("  cr = 0x%08x\n", (int)cpu->cd.ppc.cr);                  debug("  cr  = 0x%08x\n", (int)cpu->cd.ppc.cr);
266    
267                  debug("cpu%i: ctr = 0x", x);                  debug("cpu%i: ctr = 0x", x);
268                  if (bits32)                  if (bits32)
# Line 284  void ppc_cpu_register_dump(struct cpu *c Line 289  void ppc_cpu_register_dump(struct cpu *c
289                  } else {                  } else {
290                          /*  64-bit:  */                          /*  64-bit:  */
291                          for (i=0; i<PPC_NGPRS; i++) {                          for (i=0; i<PPC_NGPRS; i++) {
292                                    int r = (i >> 1) + ((i & 1) << 4);
293                                  if ((i % 2) == 0)                                  if ((i % 2) == 0)
294                                          debug("cpu%i:", x);                                          debug("cpu%i:", x);
295                                  debug(" r%02i = 0x%016llx ", i,                                  debug(" r%02i = 0x%016llx ", r,
296                                      (long long)cpu->cd.ppc.gpr[i]);                                      (long long)cpu->cd.ppc.gpr[r]);
297                                  if ((i % 2) == 1)                                  if ((i % 2) == 1)
298                                          debug("\n");                                          debug("\n");
299                          }                          }
# Line 296  void ppc_cpu_register_dump(struct cpu *c Line 302  void ppc_cpu_register_dump(struct cpu *c
302                  /*  Other special registers:  */                  /*  Other special registers:  */
303                  reg_access_msr(cpu, &tmp, 0);                  reg_access_msr(cpu, &tmp, 0);
304                  debug("cpu%i: msr = 0x%016llx  ", x, (long long)tmp);                  debug("cpu%i: msr = 0x%016llx  ", x, (long long)tmp);
305                  debug("tb = 0x%08x%08x\n",                  debug("tb  = 0x%08x%08x\n",
306                      (int)cpu->cd.ppc.tbu, (int)cpu->cd.ppc.tbl);                      (int)cpu->cd.ppc.tbu, (int)cpu->cd.ppc.tbl);
307                  debug("cpu%i: dec = 0x%08x  hdec = 0x%08x\n",                  debug("cpu%i: dec = 0x%08x  hdec = 0x%08x\n",
308                      x, (int)cpu->cd.ppc.dec, (int)cpu->cd.ppc.hdec);                      x, (int)cpu->cd.ppc.dec, (int)cpu->cd.ppc.hdec);
# Line 411  void ppc_cpu_register_match(struct machi Line 417  void ppc_cpu_register_match(struct machi
417    
418    
419  /*  /*
420     *  ppc_cpu_show_full_statistics():
421     *
422     *  Show detailed statistics on opcode usage on each cpu.
423     */
424    void ppc_cpu_show_full_statistics(struct machine *m)
425    {
426            fatal("ppc_cpu_show_full_statistics(): TODO\n");
427    }
428    
429    
430    /*
431     *  ppc_cpu_tlbdump():
432     *
433     *  Called from the debugger to dump the TLB in a readable format.
434     *  x is the cpu number to dump, or -1 to dump all CPUs.
435     *
436     *  If rawflag is nonzero, then the TLB contents isn't formated nicely,
437     *  just dumped.
438     */
439    void ppc_cpu_tlbdump(struct machine *m, int x, int rawflag)
440    {
441            fatal("ppc_cpu_tlbdump(): TODO\n");
442    }
443    
444    
445    /*
446     *  ppc_cpu_interrupt():
447     */
448    int ppc_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)
449    {
450            fatal("ppc_cpu_interrupt(): TODO\n");
451            return 0;
452    }
453    
454    
455    /*
456     *  ppc_cpu_interrupt_ack():
457     */
458    int ppc_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)
459    {
460            /*  fatal("ppc_cpu_interrupt_ack(): TODO\n");  */
461            return 0;
462    }
463    
464    
465    /*
466   *  ppc_cpu_disassemble_instr():   *  ppc_cpu_disassemble_instr():
467   *   *
468   *  Convert an instruction word into human readable format, for instruction   *  Convert an instruction word into human readable format, for instruction
# Line 455  int ppc_cpu_disassemble_instr(struct cpu Line 507  int ppc_cpu_disassemble_instr(struct cpu
507    
508          debug(": %08x\t", iword);          debug(": %08x\t", iword);
509    
         if (bintrans && !running) {  
                 debug("(bintrans)");  
                 goto disasm_ret;  
         }  
   
510          /*          /*
511           *  Decode the instruction:           *  Decode the instruction:
512           */           */
# Line 740  int ppc_cpu_disassemble_instr(struct cpu Line 787  int ppc_cpu_disassemble_instr(struct cpu
787                          rt = (iword >> 21) & 31;                          rt = (iword >> 21) & 31;
788                          debug("mfcr\tr%i", rt);                          debug("mfcr\tr%i", rt);
789                          break;                          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;  
790                  case PPC_31_MFMSR:                  case PPC_31_MFMSR:
791                          rt = (iword >> 21) & 31;                          rt = (iword >> 21) & 31;
792                          debug("mfmsr\tr%i", rt);                          debug("mfmsr\tr%i", rt);
# Line 778  int ppc_cpu_disassemble_instr(struct cpu Line 815  int ppc_cpu_disassemble_instr(struct cpu
815                  case PPC_31_STHUX:                  case PPC_31_STHUX:
816                  case PPC_31_STWX:                  case PPC_31_STWX:
817                  case PPC_31_STWUX:                  case PPC_31_STWUX:
818                    case PPC_31_STDX:
819                    case PPC_31_STDUX:
820                          /*  rs for stores, rt for loads, actually  */                          /*  rs for stores, rt for loads, actually  */
821                          rs = (iword >> 21) & 31;                          rs = (iword >> 21) & 31;
822                          ra = (iword >> 16) & 31;                          ra = (iword >> 16) & 31;
# Line 803  int ppc_cpu_disassemble_instr(struct cpu Line 842  int ppc_cpu_disassemble_instr(struct cpu
842                          case PPC_31_STWUX:                          case PPC_31_STWUX:
843                                  mnem = power? "stux" : "stwux";                                  mnem = power? "stux" : "stwux";
844                                  break;                                  break;
845                            case PPC_31_STDX:  mnem = "stdx"; break;
846                            case PPC_31_STDUX: mnem = "stdux"; break;
847                          }                          }
848                          debug("%s\tr%i,r%i,r%i", mnem, rs, ra, rb);                          debug("%s\tr%i,r%i,r%i", mnem, rs, ra, rb);
                         if (running)  
                                 goto disasm_ret_nonewline;  
849                          break;                          break;
850                  case PPC_31_NEG:                  case PPC_31_NEG:
851                  case PPC_31_NEGO:                  case PPC_31_NEGO:
# Line 929  int ppc_cpu_disassemble_instr(struct cpu Line 968  int ppc_cpu_disassemble_instr(struct cpu
968                  case PPC_31_MFSPR:                  case PPC_31_MFSPR:
969                          rt = (iword >> 21) & 31;                          rt = (iword >> 21) & 31;
970                          spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31);                          spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31);
971                          debug("mfspr\tr%i,spr%i", rt, spr);                          switch (spr) {
972                            case 8:    debug("mflr\tr%i", rt); break;
973                            case 272:  debug("mfsprg\t0,r%i", rt); break;
974                            case 273:  debug("mfsprg\t1,r%i", rt); break;
975                            case 274:  debug("mfsprg\t2,r%i", rt); break;
976                            case 275:  debug("mfsprg\t3,r%i", rt); break;
977                            case 1008: debug("mfdbsr\tr%i", rt); break;
978                            default:debug("mfspr\tr%i,spr%i", rt, spr);
979                            }
980                          break;                          break;
981                  case PPC_31_TLBIE:                  case PPC_31_TLBIE:
982                          /*  TODO: what is ra? The IBM online docs didn't say  */                          /*  TODO: what is ra? The IBM online docs didn't say  */
# Line 956  int ppc_cpu_disassemble_instr(struct cpu Line 1003  int ppc_cpu_disassemble_instr(struct cpu
1003                          mnem = power? "cntlz" : "cntlzw";                          mnem = power? "cntlz" : "cntlzw";
1004                          debug("%s\tr%i,r%i", mnem, rc? "." : "", ra, rs);                          debug("%s\tr%i,r%i", mnem, rc? "." : "", ra, rs);
1005                          break;                          break;
1006                    case PPC_31_CLF:        /*  POWER only  */
1007                    case PPC_31_CLI:        /*  POWER only  */
1008                    case PPC_31_DCLST:      /*  POWER only  */
1009                    case PPC_31_DCBF:       /*  PowerPC only  */
1010                    case PPC_31_DCBI:       /*  PowerPC only  */
1011                    case PPC_31_DCBST:      /*  PowerPC only  */
1012                    case PPC_31_DCBTST:     /*  PowerPC only  */
1013                    case PPC_31_DCBT:       /*  PowerPC only  */
1014                    case PPC_31_ICBI:       /*  PowerPC only  */
1015                    case PPC_31_DCBZ:       /*  POWER/PowerPC  */
1016                            ra = (iword >> 16) & 31;
1017                            rb = (iword >> 11) & 31;
1018                            switch (xo) {
1019                            case PPC_31_CLF:   mnem = "clf"; break;
1020                            case PPC_31_CLI:   mnem = "cli"; break;
1021                            case PPC_31_DCLST: mnem = "dclst"; break;
1022                            case PPC_31_DCBF:  mnem = "dcbf"; break;
1023                            case PPC_31_DCBI:  mnem = "dcbi"; break;
1024                            case PPC_31_DCBST: mnem = "dcbst"; break;
1025                            case PPC_31_DCBTST:mnem = "dcbtst"; break;
1026                            case PPC_31_DCBT:  mnem = "dcbt"; break;
1027                            case PPC_31_ICBI:  mnem = "icbi"; break;
1028                            case PPC_31_DCBZ:  mnem = power ?
1029                                               "dclz" : "dcbz"; break;
1030                            }
1031                            debug("%s\tr%i,r%i", mnem, ra, rb);
1032                            break;
1033                  case PPC_31_SLW:                  case PPC_31_SLW:
1034                  case PPC_31_SRAW:                  case PPC_31_SRAW:
1035                  case PPC_31_SRW:                  case PPC_31_SRW:
# Line 1023  int ppc_cpu_disassemble_instr(struct cpu Line 1097  int ppc_cpu_disassemble_instr(struct cpu
1097                  case PPC_31_MTSPR:                  case PPC_31_MTSPR:
1098                          rs = (iword >> 21) & 31;                          rs = (iword >> 21) & 31;
1099                          spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31);                          spr = ((iword >> 6) & 0x3e0) + ((iword >> 16) & 31);
1100                          debug("mtspr\tspr%i,r%i", spr, rs);                          switch (spr) {
1101                            case 8:    debug("mtlr\tr%i", rs); break;
1102                            case 272:  debug("mtsprg\t0,r%i", rs); break;
1103                            case 273:  debug("mtsprg\t1,r%i", rs); break;
1104                            case 274:  debug("mtsprg\t2,r%i", rs); break;
1105                            case 275:  debug("mtsprg\t3,r%i", rs); break;
1106                            default:debug("mtspr\tspr%i,r%i", spr, rs);
1107                            }
1108                          break;                          break;
1109                  case PPC_31_SYNC:                  case PPC_31_SYNC:
1110                          debug("%s", power? "dcs" : "sync");                          debug("%s", power? "dcs" : "sync");
# Line 1040  int ppc_cpu_disassemble_instr(struct cpu Line 1121  int ppc_cpu_disassemble_instr(struct cpu
1121                                  mnem = power? "stsi" : "stswi"; break;                                  mnem = power? "stsi" : "stswi"; break;
1122                          }                          }
1123                          debug("%s\tr%i,r%i,%i", mnem, rs, ra, nb);                          debug("%s\tr%i,r%i,%i", mnem, rs, ra, nb);
1124                          if (running)                          break;
1125                                  goto disasm_ret_nonewline;                  case PPC_31_LHBRX:
1126                    case PPC_31_LWBRX:
1127                    case PPC_31_STHBRX:
1128                    case PPC_31_STWBRX:
1129                            rt = (iword >> 21) & 31;        /*  stores use rs  */
1130                            ra = (iword >> 16) & 31;
1131                            rb = (iword >> 11) & 31;
1132                            switch (xo) {
1133                            case PPC_31_LHBRX:  mnem = "lhbrx"; break;
1134                            case PPC_31_LWBRX:  mnem = power?
1135                                                "lbrx" : "lwbrx"; break;
1136                            case PPC_31_STHBRX: mnem = "sthbrx"; break;
1137                            case PPC_31_STWBRX: mnem = power?
1138                                                "stbrx" : "stwbrx"; break;
1139                            }
1140                            debug("%s\tr%i,r%i,r%i", mnem, rt, ra, rb);
1141                          break;                          break;
1142                  case PPC_31_SRAWI:                  case PPC_31_SRAWI:
1143                          rs = (iword >> 21) & 31;                          rs = (iword >> 21) & 31;
# Line 1086  int ppc_cpu_disassemble_instr(struct cpu Line 1182  int ppc_cpu_disassemble_instr(struct cpu
1182          case PPC_HI6_LHAU:          case PPC_HI6_LHAU:
1183          case PPC_HI6_LBZ:          case PPC_HI6_LBZ:
1184          case PPC_HI6_LBZU:          case PPC_HI6_LBZU:
1185            case PPC_HI6_LMW:
1186          case PPC_HI6_STW:          case PPC_HI6_STW:
1187          case PPC_HI6_STWU:          case PPC_HI6_STWU:
1188          case PPC_HI6_STH:          case PPC_HI6_STH:
# Line 1127  int ppc_cpu_disassemble_instr(struct cpu Line 1224  int ppc_cpu_disassemble_instr(struct cpu
1224                  else                  else
1225                          debug("r");                          debug("r");
1226                  debug("%i,%i(r%i)", rs, imm, ra);                  debug("%i,%i(r%i)", rs, imm, ra);
                 if (running)  
                         goto disasm_ret_nonewline;  
1227                  break;                  break;
1228          default:          default:
1229                  /*  TODO  */                  /*  TODO  */
1230                  debug("unimplemented hi6 = 0x%02x", hi6);                  debug("unimplemented hi6 = 0x%02x", hi6);
1231          }          }
1232    
 disasm_ret:  
1233          debug("\n");          debug("\n");
 disasm_ret_nonewline:  
1234          return sizeof(iword);          return sizeof(iword);
1235  }  }
1236    
1237    
1238  /*  /*
  *  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; x<cpu->cd.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; x<n_args_to_print; x++) {  
                 int64_t d = cpu->cd.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");  
 }  
   
   
 /*  
1239   *  update_cr0():   *  update_cr0():
1240   *   *
1241   *  Sets the top 4 bits of the CR register.   *  Sets the top 4 bits of the CR register.
1242   */   */
1243  static void update_cr0(struct cpu *cpu, uint64_t value)  void update_cr0(struct cpu *cpu, uint64_t value)
1244  {  {
1245          int c;          int c;
1246    
# Line 1251  static void update_cr0(struct cpu *cpu, Line 1268  static void update_cr0(struct cpu *cpu,
1268  }  }
1269    
1270    
1271  /*  #include "tmp_ppc_tail.c"
  *  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; i<cpu->machine->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; i<tmp_data_len; i++) {  
                                                         tmp <<= 8;  
                                                         tmp += tmp_data[i];  
                                                 }  
                                         } else {  
                                                 for (i=0; i<tmp_data_len; i++) {  
                                                         tmp <<= 8;  
                                                         tmp += tmp_data[  
                                                             tmp_data_len - 1  
                                                             - i];  
                                                 }  
                                         }  
                                         cpu->cd.ppc.gpr[rs] = tmp;  
                                 }  
                         } else {  
                                 tmp = cpu->cd.ppc.gpr[rs];  
                                 if (cpu->byte_order == EMUL_BIG_ENDIAN) {  
                                         for (i=0; i<tmp_data_len; i++)  
                                                 tmp_data[tmp_data_len-1-i] =  
                                                     tmp >> (8*i);  
                                 } else {  
                                         for (i=0; i<tmp_data_len; i++)  
                                                 tmp_data[i] = tmp >> (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; i<tmp_data_len; i++) {  
                                                 tmp <<= 8;  
                                                 tmp += tmp_data[i];  
                                         }  
                                 } else {  
                                         for (i=0; i<tmp_data_len; i++) {  
                                                 tmp <<= 8;  
                                                 tmp += tmp_data[  
                                                     tmp_data_len - 1 -i];  
                                         }  
                                 }  
   
                                 if (!fpreg)  
                                         cpu->cd.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<tmp_data_len; i++)  
                                         tmp_data[tmp_data_len-1-i] =  
                                             tmp >> (8*i);  
                         } else {  
                                 for (i=0; i<tmp_data_len; i++)  
                                         tmp_data[i] = tmp >> (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; i<tmp_data_len; i++) {  
                                                         tmp <<= 8;  
                                                         tmp += tmp_data[i];  
                                                 }  
                                         } else {  
                                                 for (i=0; i<tmp_data_len; i++) {  
                                                         tmp <<= 8;  
                                                         tmp += tmp_data[  
                                                             tmp_data_len - 1  
                                                             - i];  
                                                 }  
                                         }  
   
                                         cpu->cd.ppc.gpr[rs] = tmp;  
                                 }  
                         } else {  
                                 tmp = cpu->cd.ppc.gpr[rs];  
   
                                 if (cpu->byte_order == EMUL_BIG_ENDIAN) {  
                                         for (i=0; i<tmp_data_len; i++)  
                                                 tmp_data[tmp_data_len-1-i] =  
                                                     tmp >> (8*i);  
                                 } else {  
                                         for (i=0; i<tmp_data_len; i++)  
                                                 tmp_data[i] = tmp >> (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;  
 }  
1272    
1273    
1274  #endif  /*  ENABLE_PPC  */  #endif  /*  ENABLE_PPC  */

Legend:
Removed from v.11  
changed lines
  Added in v.12

  ViewVC Help
Powered by ViewVC 1.1.26