/[gxemul]/trunk/src/cpus/cpu_mips.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/cpus/cpu_mips.c

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

revision 18 by dpavlin, Mon Oct 8 16:19:11 2007 UTC revision 42 by dpavlin, Mon Oct 8 16:22:32 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2007  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: cpu_mips.c,v 1.6 2005/10/26 14:37:02 debug Exp $   *  $Id: cpu_mips.c,v 1.83 2007/06/15 18:07:08 debug Exp $
29   *   *
30   *  MIPS core CPU emulation.   *  MIPS core CPU emulation.
31   */   */
# Line 35  Line 35 
35  #include <string.h>  #include <string.h>
36  #include <sys/types.h>  #include <sys/types.h>
37  #include <ctype.h>  #include <ctype.h>
38    #include <unistd.h>
39    
40  #include "../../config.h"  #include "../../config.h"
41    
   
 #ifndef ENABLE_MIPS  
   
   
 #include "cpu_mips.h"  
   
 /*  
  *  mips_cpu_family_init():  
  *  
  *  Bogus function.  
  */  
 int mips_cpu_family_init(struct cpu_family *fp)  
 {  
         return 0;  
 }  
   
   
 /*  TODO: Maybe it isn't very nice to have these global like this...  */  
 void mips_cpu_exception(struct cpu *cpu, int exccode, int tlb, uint64_t vaddr,  
         int coproc_nr, uint64_t vaddr_vpn2, int vaddr_asid, int x_64)  { }  
   
   
 #else   /*  ENABLE_MIPS  */  
   
   
42  #include "arcbios.h"  #include "arcbios.h"
 #include "bintrans.h"  
43  #include "cop0.h"  #include "cop0.h"
44  #include "cpu.h"  #include "cpu.h"
45  #include "cpu_mips.h"  #include "cpu_mips.h"
# Line 75  void mips_cpu_exception(struct cpu *cpu, Line 50  void mips_cpu_exception(struct cpu *cpu,
50  #include "memory.h"  #include "memory.h"
51  #include "mips_cpu_types.h"  #include "mips_cpu_types.h"
52  #include "opcodes_mips.h"  #include "opcodes_mips.h"
53    #include "settings.h"
54  #include "symbol.h"  #include "symbol.h"
55    #include "timer.h"
56    
57    
58  extern volatile int single_step;  extern int native_code_translation_enabled;
 extern int show_opcode_statistics;  
 extern int old_show_trace_tree;  
 extern int old_instruction_trace;  
 extern int old_quiet_mode;  
 extern int quiet_mode;  
59    
60  static char *exception_names[] = EXCEPTION_NAMES;  static char *exception_names[] = EXCEPTION_NAMES;
61    
62  static char *hi6_names[] = HI6_NAMES;  static char *hi6_names[] = HI6_NAMES;
63  static char *regimm_names[] = REGIMM_NAMES;  static char *regimm_names[] = REGIMM_NAMES;
64  static char *special_names[] = SPECIAL_NAMES;  static char *special_names[] = SPECIAL_NAMES;
65    static char *special_rot_names[] = SPECIAL_ROT_NAMES;
66  static char *special2_names[] = SPECIAL2_NAMES;  static char *special2_names[] = SPECIAL2_NAMES;
67    static char *mmi_names[] = MMI_NAMES;
68    static char *mmi0_names[] = MMI0_NAMES;
69    static char *mmi1_names[] = MMI1_NAMES;
70    static char *mmi2_names[] = MMI2_NAMES;
71    static char *mmi3_names[] = MMI3_NAMES;
72    static char *special3_names[] = SPECIAL3_NAMES;
73    
74  static char *regnames[] = MIPS_REGISTER_NAMES;  static char *regnames[] = MIPS_REGISTER_NAMES;
75  static char *cop0_names[] = COP0_NAMES;  static char *cop0_names[] = COP0_NAMES;
76    
 #include "cpu_mips16.c"  
77    
78    #define DYNTRANS_DUALMODE_32
79    #define DYNTRANS_DELAYSLOT
80    #include "tmp_mips_head.c"
81    
82  /*  void mips_pc_to_pointers(struct cpu *);
83   *  regname():  void mips32_pc_to_pointers(struct cpu *);
  *  
  *  Convert a register number into either 'r0', 'r31' etc, or a symbolic  
  *  name, depending on machine->show_symbolic_register_names.  
  *  
  *  NOTE: _NOT_ reentrant.  
  */  
 static char *regname(struct machine *machine, int r)  
 {  
         static char ch[4];  
         ch[3] = ch[2] = '\0';  
   
         if (r<0 || r>=32)  
                 strlcpy(ch, "xx", sizeof(ch));  
         else if (machine->show_symbolic_register_names)  
                 strlcpy(ch, regnames[r], sizeof(ch));  
         else  
                 snprintf(ch, sizeof(ch), "r%i", r);  
   
         return ch;  
 }  
84    
85    
86  /*  /*
# Line 152  int mips_cpu_new(struct cpu *cpu, struct Line 113  int mips_cpu_new(struct cpu *cpu, struct
113          if (found == -1)          if (found == -1)
114                  return 0;                  return 0;
115    
116          cpu->memory_rw          = mips_memory_rw;          cpu->memory_rw                = mips_memory_rw;
117          cpu->cd.mips.cpu_type   = cpu_type_defs[found];          cpu->cd.mips.cpu_type         = cpu_type_defs[found];
118          cpu->name               = cpu->cd.mips.cpu_type.name;          cpu->name                     = cpu->cd.mips.cpu_type.name;
119          cpu->byte_order         = EMUL_LITTLE_ENDIAN;          cpu->byte_order               = EMUL_LITTLE_ENDIAN;
120          cpu->cd.mips.gpr[MIPS_GPR_SP] = INITIAL_STACK_POINTER;          cpu->cd.mips.gpr[MIPS_GPR_SP] = INITIAL_STACK_POINTER;
         cpu->update_translation_table = mips_update_translation_table;  
         cpu->invalidate_translation_caches =  
             mips_invalidate_translation_caches_paddr;  
121    
122          if (cpu->cd.mips.cpu_type.isa_level <= 2 ||          if (cpu->cd.mips.cpu_type.isa_level <= 2 ||
123              cpu->cd.mips.cpu_type.isa_level == 32)              cpu->cd.mips.cpu_type.isa_level == 32)
124                  cpu->is_32bit = 1;                  cpu->is_32bit = 1;
125    
126            if (cpu->is_32bit) {
127                    cpu->run_instr = mips32_run_instr;
128                    cpu->update_translation_table = mips32_update_translation_table;
129                    cpu->invalidate_translation_caches =
130                        mips32_invalidate_translation_caches;
131                    cpu->invalidate_code_translation =
132                        mips32_invalidate_code_translation;
133            } else {
134                    cpu->run_instr = mips_run_instr;
135                    cpu->update_translation_table = mips_update_translation_table;
136                    cpu->invalidate_translation_caches =
137                        mips_invalidate_translation_caches;
138                    cpu->invalidate_code_translation =
139                        mips_invalidate_code_translation;
140            }
141    
142            cpu->instruction_has_delayslot = mips_cpu_instruction_has_delayslot;
143    
144          if (cpu_id == 0)          if (cpu_id == 0)
145                  debug("%s", cpu->cd.mips.cpu_type.name);                  debug("%s", cpu->cd.mips.cpu_type.name);
146    
# Line 183  int mips_cpu_new(struct cpu *cpu, struct Line 159  int mips_cpu_new(struct cpu *cpu, struct
159          x = DEFAULT_PCACHE_SIZE;          x = DEFAULT_PCACHE_SIZE;
160          if (cpu->cd.mips.cpu_type.pdcache)          if (cpu->cd.mips.cpu_type.pdcache)
161                  x = cpu->cd.mips.cpu_type.pdcache;                  x = cpu->cd.mips.cpu_type.pdcache;
162          if (machine->cache_pdcache == 0)          if (cpu->cd.mips.cache_pdcache == 0)
163                  machine->cache_pdcache = x;                  cpu->cd.mips.cache_pdcache = x;
164    
165          x = DEFAULT_PCACHE_SIZE;          x = DEFAULT_PCACHE_SIZE;
166          if (cpu->cd.mips.cpu_type.picache)          if (cpu->cd.mips.cpu_type.picache)
167                  x = cpu->cd.mips.cpu_type.picache;                  x = cpu->cd.mips.cpu_type.picache;
168          if (machine->cache_picache == 0)          if (cpu->cd.mips.cache_picache == 0)
169                  machine->cache_picache = x;                  cpu->cd.mips.cache_picache = x;
170    
171          if (machine->cache_secondary == 0)          if (cpu->cd.mips.cache_secondary == 0)
172                  machine->cache_secondary = cpu->cd.mips.cpu_type.scache;                  cpu->cd.mips.cache_secondary = cpu->cd.mips.cpu_type.scache;
173    
174          linesize = DEFAULT_PCACHE_LINESIZE;          linesize = DEFAULT_PCACHE_LINESIZE;
175          if (cpu->cd.mips.cpu_type.pdlinesize)          if (cpu->cd.mips.cpu_type.pdlinesize)
176                  linesize = cpu->cd.mips.cpu_type.pdlinesize;                  linesize = cpu->cd.mips.cpu_type.pdlinesize;
177          if (machine->cache_pdcache_linesize == 0)          if (cpu->cd.mips.cache_pdcache_linesize == 0)
178                  machine->cache_pdcache_linesize = linesize;                  cpu->cd.mips.cache_pdcache_linesize = linesize;
179    
180          linesize = DEFAULT_PCACHE_LINESIZE;          linesize = DEFAULT_PCACHE_LINESIZE;
181          if (cpu->cd.mips.cpu_type.pilinesize)          if (cpu->cd.mips.cpu_type.pilinesize)
182                  linesize = cpu->cd.mips.cpu_type.pilinesize;                  linesize = cpu->cd.mips.cpu_type.pilinesize;
183          if (machine->cache_picache_linesize == 0)          if (cpu->cd.mips.cache_picache_linesize == 0)
184                  machine->cache_picache_linesize = linesize;                  cpu->cd.mips.cache_picache_linesize = linesize;
185    
186          linesize = 0;          linesize = 0;
187          if (cpu->cd.mips.cpu_type.slinesize)          if (cpu->cd.mips.cpu_type.slinesize)
188                  linesize = cpu->cd.mips.cpu_type.slinesize;                  linesize = cpu->cd.mips.cpu_type.slinesize;
189          if (machine->cache_secondary_linesize == 0)          if (cpu->cd.mips.cache_secondary_linesize == 0)
190                  machine->cache_secondary_linesize = linesize;                  cpu->cd.mips.cache_secondary_linesize = linesize;
191    
192    
193          /*          /*
# Line 220  int mips_cpu_new(struct cpu *cpu, struct Line 196  int mips_cpu_new(struct cpu *cpu, struct
196          for (i=CACHE_DATA; i<=CACHE_INSTRUCTION; i++) {          for (i=CACHE_DATA; i<=CACHE_INSTRUCTION; i++) {
197                  switch (i) {                  switch (i) {
198                  case CACHE_DATA:                  case CACHE_DATA:
199                          x = 1 << machine->cache_pdcache;                          x = 1 << cpu->cd.mips.cache_pdcache;
200                          linesize = 1 << machine->cache_pdcache_linesize;                          linesize = 1 << cpu->cd.mips.cache_pdcache_linesize;
201                          break;                          break;
202                  case CACHE_INSTRUCTION:                  case CACHE_INSTRUCTION:
203                          x = 1 << machine->cache_picache;                          x = 1 << cpu->cd.mips.cache_picache;
204                          linesize = 1 << machine->cache_picache_linesize;                          linesize = 1 << cpu->cd.mips.cache_picache_linesize;
205                          break;                          break;
206                  }                  }
207    
# Line 239  int mips_cpu_new(struct cpu *cpu, struct Line 215  int mips_cpu_new(struct cpu *cpu, struct
215                          size_per_cache_line = sizeof(struct r3000_cache_line);                          size_per_cache_line = sizeof(struct r3000_cache_line);
216                          break;                          break;
217                  default:                  default:
218                          size_per_cache_line = sizeof(struct r4000_cache_line);                          size_per_cache_line = 32;       /*  TODO  */
219                  }                  }
220    
221                  cpu->cd.mips.cache_mask[i] = cpu->cd.mips.cache_size[i] - 1;                  cpu->cd.mips.cache_mask[i] = cpu->cd.mips.cache_size[i] - 1;
                 cpu->cd.mips.cache_miss_penalty[i] = 10;        /*  TODO ?  */  
222    
223                  cpu->cd.mips.cache[i] = malloc(cpu->cd.mips.cache_size[i]);                  CHECK_ALLOCATION(cpu->cd.mips.cache[i] =
224                  if (cpu->cd.mips.cache[i] == NULL) {                      malloc(cpu->cd.mips.cache_size[i]));
                         fprintf(stderr, "out of memory\n");  
                 }  
225    
226                  n_cache_lines = cpu->cd.mips.cache_size[i] /                  n_cache_lines = cpu->cd.mips.cache_size[i] /
227                      cpu->cd.mips.cache_linesize[i];                      cpu->cd.mips.cache_linesize[i];
228                  tags_size = n_cache_lines * size_per_cache_line;                  tags_size = n_cache_lines * size_per_cache_line;
229    
230                  cpu->cd.mips.cache_tags[i] = malloc(tags_size);                  CHECK_ALLOCATION(cpu->cd.mips.cache_tags[i] =
231                  if (cpu->cd.mips.cache_tags[i] == NULL) {                      malloc(tags_size));
                         fprintf(stderr, "out of memory\n");  
                 }  
232    
233                  /*  Initialize the cache tags:  */                  /*  Initialize the cache tags:  */
234                  switch (cpu->cd.mips.cpu_type.rev) {                  switch (cpu->cd.mips.cpu_type.rev) {
# Line 283  int mips_cpu_new(struct cpu *cpu, struct Line 254  int mips_cpu_new(struct cpu *cpu, struct
254           *  Secondary cache:           *  Secondary cache:
255           */           */
256          secondary_cache_size = 0;          secondary_cache_size = 0;
257          if (machine->cache_secondary)          if (cpu->cd.mips.cache_secondary)
258                  secondary_cache_size = 1 << machine->cache_secondary;                  secondary_cache_size = 1 << cpu->cd.mips.cache_secondary;
259          /*  TODO: linesize...  */          /*  TODO: linesize...  */
260    
261          if (cpu_id == 0) {          if (cpu_id == 0) {
# Line 305  int mips_cpu_new(struct cpu *cpu, struct Line 276  int mips_cpu_new(struct cpu *cpu, struct
276                  debug(")");                  debug(")");
277          }          }
278    
279            /*  Register the CPU's interrupts:  */
280            for (i=2; i<8; i++) {
281                    struct interrupt template;
282                    char name[50];
283                    snprintf(name, sizeof(name), "%s.%i", cpu->path, i);
284                    memset(&template, 0, sizeof(template));
285                    template.line = 1 << (STATUS_IM_SHIFT + i);
286                    template.name = name;
287                    template.extra = cpu;
288                    template.interrupt_assert = mips_cpu_interrupt_assert;
289                    template.interrupt_deassert = mips_cpu_interrupt_deassert;
290                    interrupt_handler_register(&template);
291    
292                    if (i == 7)
293                            INTERRUPT_CONNECT(name, cpu->cd.mips.irq_compare);
294            }
295    
296          /*  System coprocessor (0), and FPU (1):  */          /*  System coprocessor (0), and FPU (1):  */
297          cpu->cd.mips.coproc[0] = mips_coproc_new(cpu, 0);          cpu->cd.mips.coproc[0] = mips_coproc_new(cpu, 0);
298          cpu->cd.mips.coproc[1] = mips_coproc_new(cpu, 1);          cpu->cd.mips.coproc[1] = mips_coproc_new(cpu, 1);
299    
         /*  
          *  Initialize the cpu->cd.mips.pc_last_* cache (a 1-entry cache of the  
          *  last program counter value).  For pc_last_virtual_page, any  
          *  "impossible" value will do.  The pc should never ever get this  
          *  value.  (The other pc_last* variables do not need initialization,  
          *  as they are not used before pc_last_virtual_page.)  
          */  
         cpu->cd.mips.pc_last_virtual_page = PC_LAST_PAGE_IMPOSSIBLE_VALUE;  
   
300          switch (cpu->cd.mips.cpu_type.mmu_model) {          switch (cpu->cd.mips.cpu_type.mmu_model) {
301          case MMU3K:          case MMU3K:
302                  cpu->translate_address = translate_address_mmu3k;                  cpu->translate_v2p = translate_v2p_mmu3k;
303                  break;                  break;
304          case MMU8K:          case MMU8K:
305                  cpu->translate_address = translate_address_mmu8k;                  cpu->translate_v2p = translate_v2p_mmu8k;
306                  break;                  break;
307          case MMU10K:          case MMU10K:
308                  cpu->translate_address = translate_address_mmu10k;                  cpu->translate_v2p = translate_v2p_mmu10k;
309                  break;                  break;
310          default:          default:
311                  if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)                  if (cpu->cd.mips.cpu_type.rev == MIPS_R4100)
312                          cpu->translate_address = translate_address_mmu4100;                          cpu->translate_v2p = translate_v2p_mmu4100;
313                  else                  else
314                          cpu->translate_address = translate_address_generic;                          cpu->translate_v2p = translate_v2p_generic;
315            }
316    
317            if (cpu->machine->prom_emulation) {
318                    /*
319                     *  Default behaviour of jumping to 0xbfc00000 should be
320                     *  a reboot, unless machine-specific initialization code
321                     *  overrides this.
322                     *
323                     *  Note: Specifically big-endian machines should override
324                     *  this, since the default MIPS CPU is little-endian!
325                     */
326                    store_32bit_word(cpu, 0xffffffff9fc00000ULL, 0x00c0de0d);
327          }          }
328    
329  /*  Testing:  */          /*  Add all register names to the settings:  */
330          cpu->cd.mips.host_load = zeroed_alloc(1048576 *          CPU_SETTINGS_ADD_REGISTER64("pc", cpu->pc);
331              sizeof(unsigned char *));          CPU_SETTINGS_ADD_REGISTER64("hi", cpu->cd.mips.hi);
332          cpu->cd.mips.host_store = zeroed_alloc(1048576 *          CPU_SETTINGS_ADD_REGISTER64("lo", cpu->cd.mips.lo);
333              sizeof(unsigned char *));          for (i=0; i<N_MIPS_GPRS; i++)
334          cpu->cd.mips.host_load_orig = cpu->cd.mips.host_load;                  CPU_SETTINGS_ADD_REGISTER64(regnames[i], cpu->cd.mips.gpr[i]);
335          cpu->cd.mips.host_store_orig = cpu->cd.mips.host_store;          /*  TODO: Write via special handler function!  */
336            for (i=0; i<N_MIPS_COPROC_REGS; i++)
337                    CPU_SETTINGS_ADD_REGISTER64(cop0_names[i],
338                        cpu->cd.mips.coproc[0]->reg[i]);
339    
340            if (native_code_translation_enabled)
341                    cpu->sampling_timer = timer_add(CPU_SAMPLE_TIMER_HZ,
342                        mips_timer_sample_tick, cpu);
343    
344          return 1;          return 1;
345  }  }
346    
347    
348  /*  /*
349   *  mips_cpu_show_full_statistics():   *  mips_cpu_dumpinfo():
350   *   *
351   *  Show detailed statistics on opcode usage on each cpu.   *  Debug dump of MIPS-specific CPU data for specific CPU.
352   */   */
353  void mips_cpu_show_full_statistics(struct machine *m)  void mips_cpu_dumpinfo(struct cpu *cpu)
354  {  {
355          int i, s1, s2, iadd = 4;          int iadd = DEBUG_INDENTATION;
356            struct mips_cpu_type_def *ct = &cpu->cd.mips.cpu_type;
357    
358          if (m->bintrans_enable)          debug_indentation(iadd);
                 fatal("NOTE: Dynamic binary translation is used; this list"  
                     " of opcode usage\n      only includes instructions that"  
                     " were interpreted manually!\n");  
359    
360          for (i=0; i<m->ncpus; i++) {          debug("\n%i-bit %s-endian (MIPS",
361                  fatal("cpu%i opcode statistics:\n", i);              cpu->is_32bit? 32 : 64,
362                  debug_indentation(iadd);              cpu->byte_order == EMUL_BIG_ENDIAN? "Big" : "Little");
363    
364                  for (s1=0; s1<N_HI6; s1++) {          switch (ct->isa_level) {
365                          if (m->cpus[i]->cd.mips.stats_opcode[s1] > 0)          case 1: debug(" ISA I"); break;
366                                  fatal("opcode %02x (%7s): %li\n", s1,          case 2: debug(" ISA II"); break;
367                                      hi6_names[s1],          case 3: debug(" ISA III"); break;
368                                      m->cpus[i]->cd.mips.stats_opcode[s1]);          case 4: debug(" ISA IV"); break;
369            case 5: debug(" ISA V"); break;
370                          debug_indentation(iadd);          case 32:
371                          if (s1 == HI6_SPECIAL)          case 64:debug("%i, revision %i", ct->isa_level, ct->isa_revision);
372                                  for (s2=0; s2<N_SPECIAL; s2++)                  break;
373                                          if (m->cpus[i]->cd.mips.stats__special[          default:debug(" ISA level %i", ct->isa_level);
374                                              s2] > 0)          }
375                                                  fatal("special %02x (%7s): "  
376                                                      "%li\n", s2, special_names[          debug("), ");
377                                                      s2], m->cpus[i]->cd.mips.          if (ct->nr_of_tlb_entries)
378                                                      stats__special[s2]);                  debug("%i TLB entries", ct->nr_of_tlb_entries);
379                          if (s1 == HI6_REGIMM)          else
380                                  for (s2=0; s2<N_REGIMM; s2++)                  debug("no TLB");
381                                          if (m->cpus[i]->cd.mips.stats__regimm[          debug("\n");
382                                              s2] > 0)  
383                                                  fatal("regimm %02x (%7s): "          if (ct->picache) {
384                                                      "%li\n", s2, regimm_names[                  debug("L1 I-cache: %i KB", (1 << ct->picache) / 1024);
385                                                      s2], m->cpus[i]->cd.mips.                  if (ct->pilinesize)
386                                                      stats__regimm[s2]);                          debug(", %i bytes per line", 1 << ct->pilinesize);
387                          if (s1 == HI6_SPECIAL2)                  if (ct->piways > 1)
388                                  for (s2=0; s2<N_SPECIAL; s2++)                          debug(", %i-way", ct->piways);
389                                          if (m->cpus[i]->cd.mips.stats__special2                  else
390                                              [s2] > 0)                          debug(", direct-mapped");
391                                                  fatal("special2 %02x (%7s): "                  debug("\n");
392                                                      "%li\n", s2,          }
393                                                      special2_names[s2], m->  
394                                                      cpus[i]->cd.mips.          if (ct->pdcache) {
395                                                      stats__special2[s2]);                  debug("L1 D-cache: %i KB", (1 << ct->pdcache) / 1024);
396                          debug_indentation(-iadd);                  if (ct->pdlinesize)
397                  }                          debug(", %i bytes per line", 1 << ct->pdlinesize);
398                    if (ct->pdways > 1)
399                            debug(", %i-way", ct->pdways);
400                    else
401                            debug(", direct-mapped");
402                    debug("\n");
403            }
404    
405            if (ct->scache) {
406                    int kb = (1 << ct->scache) / 1024;
407                    debug("L2 cache: %i %s",
408                        kb >= 1024? kb / 1024 : kb, kb >= 1024? "MB":"KB");
409                    if (ct->slinesize)
410                            debug(", %i bytes per line", 1 << ct->slinesize);
411                    if (ct->sways > 1)
412                            debug(", %i-way", ct->sways);
413                    else
414                            debug(", direct-mapped");
415                    debug("\n");
416            }
417    
418            debug_indentation(-iadd);
419    }
420    
421                  debug_indentation(-iadd);  
422    /*
423     *  mips_cpu_list_available_types():
424     *
425     *  Print a list of available MIPS CPU types.
426     */
427    void mips_cpu_list_available_types(void)
428    {
429            int i, j;
430            struct mips_cpu_type_def cpu_type_defs[] = MIPS_CPU_TYPE_DEFS;
431    
432            i = 0;
433            while (cpu_type_defs[i].name != NULL) {
434                    debug("%s", cpu_type_defs[i].name);
435                    for (j=10 - strlen(cpu_type_defs[i].name); j>0; j--)
436                            debug(" ");
437                    i++;
438                    if ((i % 6) == 0 || cpu_type_defs[i].name == NULL)
439                            debug("\n");
440          }          }
441  }  }
442    
443    
444  /*  /*
445     *  mips_cpu_instruction_has_delayslot():
446     *
447     *  Return 1 if an opcode is a branch, 0 otherwise.
448     */
449    int mips_cpu_instruction_has_delayslot(struct cpu *cpu, unsigned char *ib)
450    {
451            uint32_t iword = *((uint32_t *)&ib[0]);
452    
453            if (cpu->byte_order == EMUL_LITTLE_ENDIAN)
454                    iword = LE32_TO_HOST(iword);
455            else
456                    iword = BE32_TO_HOST(iword);
457    
458            switch (iword >> 26) {
459            case HI6_SPECIAL:
460                    switch (iword & 0x3f) {
461                    case SPECIAL_JR:
462                    case SPECIAL_JALR:
463                            return 1;
464                    }
465                    break;
466            case HI6_REGIMM:
467                    switch ((iword >> 16) & 0x1f) {
468                    case REGIMM_BLTZ:
469                    case REGIMM_BGEZ:
470                    case REGIMM_BLTZL:
471                    case REGIMM_BGEZL:
472                    case REGIMM_BLTZAL:
473                    case REGIMM_BLTZALL:
474                    case REGIMM_BGEZAL:
475                    case REGIMM_BGEZALL:
476                            return 1;
477                    }
478                    break;
479            case HI6_BEQ:
480            case HI6_BEQL:
481            case HI6_BNE:
482            case HI6_BNEL:
483            case HI6_BGTZ:
484            case HI6_BGTZL:
485            case HI6_BLEZ:
486            case HI6_BLEZL:
487            case HI6_J:
488            case HI6_JAL:
489                    return 1;
490            }
491    
492            return 0;
493    }
494    
495    
496    /*
497   *  mips_cpu_tlbdump():   *  mips_cpu_tlbdump():
498   *   *
499   *  Called from the debugger to dump the TLB in a readable format.   *  Called from the debugger to dump the TLB in a readable format.
# Line 418  void mips_cpu_tlbdump(struct machine *m, Line 506  void mips_cpu_tlbdump(struct machine *m,
506  {  {
507          int i, j;          int i, j;
508    
509          /*  Nicely formatted output:  */          /*  Raw output:  */
510          if (!rawflag) {          if (rawflag) {
511                  for (i=0; i<m->ncpus; i++) {                  for (i=0; i<m->ncpus; i++) {
512                          int pageshift = 12;                          struct mips_coproc *cop0 =
513                                m->cpus[i]->cd.mips.coproc[0];
514    
515                          if (x >= 0 && i != x)                          if (x >= 0 && i != x)
516                                  continue;                                  continue;
517    
                         if (m->cpus[i]->cd.mips.cpu_type.rev == MIPS_R4100)  
                                 pageshift = 10;  
   
518                          /*  Print index, random, and wired:  */                          /*  Print index, random, and wired:  */
519                          printf("cpu%i: (", i);                          printf("cpu%i: (", i);
520                          switch (m->cpus[i]->cd.mips.cpu_type.isa_level) {  
521                          case 1:                          if (m->cpus[i]->is_32bit)
522                          case 2:                                  printf("index=0x%08x random=0x%08x",
523                                  printf("index=0x%x random=0x%x",                                      (int) cop0->reg[COP0_INDEX],
524                                      (int) ((m->cpus[i]->cd.mips.coproc[0]->                                      (int) cop0->reg[COP0_RANDOM]);
525                                      reg[COP0_INDEX] & R2K3K_INDEX_MASK)                          else
526                                      >> R2K3K_INDEX_SHIFT),                                  printf("index=0x%016"PRIx64
527                                      (int) ((m->cpus[i]->cd.mips.coproc[0]->                                      " random=0x%016"PRIx64,
528                                      reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)                                      (uint64_t) cop0->reg[COP0_INDEX],
529                                      >> R2K3K_RANDOM_SHIFT));                                      (uint64_t) cop0->reg[COP0_RANDOM]);
530                                  break;  
531                          default:                          if (m->cpus[i]->cd.mips.cpu_type.isa_level >= 3)
532                                  printf("index=0x%x random=0x%x",                                  printf(" wired=0x%"PRIx64,
533                                      (int) (m->cpus[i]->cd.mips.coproc[0]->                                      (uint64_t) cop0->reg[COP0_WIRED]);
                                     reg[COP0_INDEX] & INDEX_MASK),  
                                     (int) (m->cpus[i]->cd.mips.coproc[0]->  
                                     reg[COP0_RANDOM] & RANDOM_MASK));  
                                 printf(" wired=0x%llx", (long long)  
                                     m->cpus[i]->cd.mips.coproc[0]->  
                                     reg[COP0_WIRED]);  
                         }  
534    
535                          printf(")\n");                          printf(")\n");
536    
537                          for (j=0; j<m->cpus[i]->cd.mips.cpu_type.                          for (j=0; j<m->cpus[i]->cd.mips.cpu_type.
538                              nr_of_tlb_entries; j++) {                              nr_of_tlb_entries; j++) {
539                                  uint64_t hi,lo0,lo1,mask;                                  if (m->cpus[i]->cd.mips.cpu_type.mmu_model ==
540                                  hi = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi;                                      MMU3K)
541                                  lo0 = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0;                                          printf("%3i: hi=0x%08"PRIx32" lo=0x%08"
542                                  lo1 = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1;                                              PRIx32"\n", j,
543                                  mask = m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask;                                              (uint32_t) cop0->tlbs[j].hi,
544                                                (uint32_t) cop0->tlbs[j].lo0);
545                                  printf("%3i: ", j);                                  else if (m->cpus[i]->is_32bit)
546                                  switch (m->cpus[i]->cd.mips.cpu_type.mmu_model) {                                          printf("%3i: hi=0x%08"PRIx32" mask=0x"
547                                  case MMU3K:                                              "%08"PRIx32" lo0=0x%08"PRIx32
548                                          if (!(lo0 & R2K3K_ENTRYLO_V)) {                                              " lo1=0x%08"PRIx32"\n", j,
549                                                  printf("(invalid)\n");                                              (uint32_t) cop0->tlbs[j].hi,
550                                                  continue;                                              (uint32_t) cop0->tlbs[j].mask,
551                                          }                                              (uint32_t) cop0->tlbs[j].lo0,
552                                          printf("vaddr=0x%08x ",                                              (uint32_t) cop0->tlbs[j].lo1);
553                                              (int) (hi&R2K3K_ENTRYHI_VPN_MASK));                                  else
554                                          if (lo0 & R2K3K_ENTRYLO_G)                                          printf("%3i: hi=0x%016"PRIx64" mask="
555                                                  printf("(global), ");                                              "0x%016"PRIx64" lo0=0x%016"PRIx64
556                                          else                                              " lo1=0x%016"PRIx64"\n", j,
557                                                  printf("(asid %02x),",                                              (uint64_t) cop0->tlbs[j].hi,
558                                                      (int) ((hi & R2K3K_ENTRYHI_ASID_MASK)                                              (uint64_t) cop0->tlbs[j].mask,
559                                                      >> R2K3K_ENTRYHI_ASID_SHIFT));                                              (uint64_t) cop0->tlbs[j].lo0,
560                                          printf(" paddr=0x%08x ",                                              (uint64_t) cop0->tlbs[j].lo1);
                                             (int) (lo0&R2K3K_ENTRYLO_PFN_MASK));  
                                         if (lo0 & R2K3K_ENTRYLO_N)  
                                                 printf("N");  
                                         if (lo0 & R2K3K_ENTRYLO_D)  
                                                 printf("D");  
                                         printf("\n");  
                                         break;  
                                 default:  
                                         switch (m->cpus[i]->cd.mips.cpu_type.mmu_model) {  
                                         case MMU10K:  
                                                 printf("vaddr=0x%1x..%011llx ",  
                                                     (int) (hi >> 60),  
                                                     (long long) (hi&ENTRYHI_VPN2_MASK_R10K));  
                                                 break;  
                                         case MMU32:  
                                                 printf("vaddr=0x%08x ", (int)(hi&ENTRYHI_VPN2_MASK));  
                                                 break;  
                                         default:/*  R4000 etc.  */  
                                                 printf("vaddr=0x%1x..%010llx ",  
                                                     (int) (hi >> 60),  
                                                     (long long) (hi&ENTRYHI_VPN2_MASK));  
                                         }  
                                         if (hi & TLB_G)  
                                                 printf("(global): ");  
                                         else  
                                                 printf("(asid %02x):",  
                                                     (int) (hi & ENTRYHI_ASID));  
   
                                         /*  TODO: Coherency bits  */  
   
                                         if (!(lo0 & ENTRYLO_V))  
                                                 printf(" p0=(invalid)   ");  
                                         else  
                                                 printf(" p0=0x%09llx ", (long long)  
                                                     (((lo0&ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << pageshift));  
                                         printf(lo0 & ENTRYLO_D? "D" : " ");  
   
                                         if (!(lo1 & ENTRYLO_V))  
                                                 printf(" p1=(invalid)   ");  
                                         else  
                                                 printf(" p1=0x%09llx ", (long long)  
                                                     (((lo1&ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << pageshift));  
                                         printf(lo1 & ENTRYLO_D? "D" : " ");  
                                         mask |= (1 << (pageshift+1)) - 1;  
                                         switch (mask) {  
                                         case 0x7ff:     printf(" (1KB)"); break;  
                                         case 0x1fff:    printf(" (4KB)"); break;  
                                         case 0x7fff:    printf(" (16KB)"); break;  
                                         case 0x1ffff:   printf(" (64KB)"); break;  
                                         case 0x7ffff:   printf(" (256KB)"); break;  
                                         case 0x1fffff:  printf(" (1MB)"); break;  
                                         case 0x7fffff:  printf(" (4MB)"); break;  
                                         case 0x1ffffff: printf(" (16MB)"); break;  
                                         case 0x7ffffff: printf(" (64MB)"); break;  
                                         default:  
                                                 printf(" (mask=%08x?)", (int)mask);  
                                         }  
                                         printf("\n");  
                                 }  
561                          }                          }
562                  }                  }
563    
564                  return;                  return;
565          }          }
566    
567          /*  Raw output:  */          /*  Nicely formatted output:  */
568          for (i=0; i<m->ncpus; i++) {          for (i=0; i<m->ncpus; i++) {
569                    int pageshift = 12;
570                    struct mips_coproc *cop0 = m->cpus[i]->cd.mips.coproc[0];
571    
572                  if (x >= 0 && i != x)                  if (x >= 0 && i != x)
573                          continue;                          continue;
574    
575                    if (m->cpus[i]->cd.mips.cpu_type.rev == MIPS_R4100)
576                            pageshift = 10;
577    
578                  /*  Print index, random, and wired:  */                  /*  Print index, random, and wired:  */
579                  printf("cpu%i: (", i);                  printf("cpu%i: (", i);
580                    switch (m->cpus[i]->cd.mips.cpu_type.isa_level) {
581                  if (m->cpus[i]->is_32bit)                  case 1:
582                          printf("index=0x%08x random=0x%08x",                  case 2: printf("index=0x%x random=0x%x",
583                              (int)m->cpus[i]->cd.mips.coproc[0]->reg[COP0_INDEX],                              (int) ((cop0->reg[COP0_INDEX] & R2K3K_INDEX_MASK)
584                              (int)m->cpus[i]->cd.mips.coproc[0]->reg[COP0_RANDOM]);                              >> R2K3K_INDEX_SHIFT),
585                  else                              (int) ((cop0->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
586                          printf("index=0x%016llx random=0x%016llx", (long long)                              >> R2K3K_RANDOM_SHIFT));
587                              m->cpus[i]->cd.mips.coproc[0]->reg[COP0_INDEX],                          break;
588                              (long long)m->cpus[i]->cd.mips.coproc[0]->reg                  default:printf("index=0x%x random=0x%x",
589                              [COP0_RANDOM]);                              (int) (cop0->reg[COP0_INDEX] & INDEX_MASK),
590                                (int) (cop0->reg[COP0_RANDOM] & RANDOM_MASK));
591                  if (m->cpus[i]->cd.mips.cpu_type.isa_level >= 3)                          printf(" wired=0x%"PRIx64,
592                          printf(" wired=0x%llx", (long long)                              (uint64_t) cop0->reg[COP0_WIRED]);
                             m->cpus[i]->cd.mips.coproc[0]->reg[COP0_WIRED]);  
   
                 printf(")\n");  
   
                 for (j=0; j<m->cpus[i]->cd.mips.cpu_type.nr_of_tlb_entries; j++) {  
                         if (m->cpus[i]->cd.mips.cpu_type.mmu_model == MMU3K)  
                                 printf("%3i: hi=0x%08x lo=0x%08x\n",  
                                     j,  
                                     (int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi,  
                                     (int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0);  
                         else if (m->cpus[i]->is_32bit)  
                                 printf("%3i: hi=0x%08x mask=0x%08x "  
                                     "lo0=0x%08x lo1=0x%08x\n", j,  
                                     (int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi,  
                                     (int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask,  
                                     (int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0,  
                                     (int)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1);  
                         else  
                                 printf("%3i: hi=0x%016llx mask=0x%016llx "  
                                     "lo0=0x%016llx lo1=0x%016llx\n", j,  
                                     (long long)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].hi,  
                                     (long long)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].mask,  
                                     (long long)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo0,  
                                     (long long)m->cpus[i]->cd.mips.coproc[0]->tlbs[j].lo1);  
593                  }                  }
         }  
 }  
   
   
 /*  
  *  mips_cpu_register_match():  
  */  
 void mips_cpu_register_match(struct machine *m, char *name,  
         int writeflag, uint64_t *valuep, int *match_register)  
 {  
         int cpunr = 0;  
   
         /*  CPU number:  */  
594    
595          /*  TODO  */                  printf(")\n");
596    
597          /*  Register name:  */                  for (j=0; j<m->cpus[i]->cd.mips.cpu_type.
598          if (strcasecmp(name, "pc") == 0) {                      nr_of_tlb_entries; j++) {
599                  if (writeflag) {                          uint64_t hi = cop0->tlbs[j].hi;
600                          m->cpus[cpunr]->pc = *valuep;                          uint64_t lo0 = cop0->tlbs[j].lo0;
601                          if (m->cpus[cpunr]->cd.mips.delay_slot) {                          uint64_t lo1 = cop0->tlbs[j].lo1;
602                                  printf("NOTE: Clearing the delay slot"                          uint64_t mask = cop0->tlbs[j].mask;
603                                      " flag! (It was set before.)\n");                          uint64_t psize;
604                                  m->cpus[cpunr]->cd.mips.delay_slot = 0;  
605                          }                          mask |= (1 << (pageshift+1)) - 1;
606                          if (m->cpus[cpunr]->cd.mips.nullify_next) {                          /*  here mask = e.g. 0x1fff for 4KB pages  */
607                                  printf("NOTE: Clearing the nullify-ne"  
608                                      "xt flag! (It was set before.)\n");                          printf("%3i: ", j);
609                                  m->cpus[cpunr]->cd.mips.nullify_next = 0;  
610                          }                          switch (m->cpus[i]->cd.mips.cpu_type.mmu_model) {
611                  } else                          case MMU3K:
612                          *valuep = m->cpus[cpunr]->pc;                                  if (!(lo0 & R2K3K_ENTRYLO_V)) {
613                  *match_register = 1;                                          printf("(invalid)\n");
614          } else if (strcasecmp(name, "hi") == 0) {                                          continue;
615                  if (writeflag)                                  }
616                          m->cpus[cpunr]->cd.mips.hi = *valuep;                                  printf("vaddr=0x%08x ",
617                  else                                      (int) (hi&R2K3K_ENTRYHI_VPN_MASK));
618                          *valuep = m->cpus[cpunr]->cd.mips.hi;                                  if (lo0 & R2K3K_ENTRYLO_G)
619                  *match_register = 1;                                          printf("(global), ");
         } else if (strcasecmp(name, "lo") == 0) {  
                 if (writeflag)  
                         m->cpus[cpunr]->cd.mips.lo = *valuep;  
                 else  
                         *valuep = m->cpus[cpunr]->cd.mips.lo;  
                 *match_register = 1;  
         } else if (name[0] == 'r' && isdigit((int)name[1])) {  
                 int nr = atoi(name + 1);  
                 if (nr >= 0 && nr < N_MIPS_GPRS) {  
                         if (writeflag) {  
                                 if (nr != 0)  
                                         m->cpus[cpunr]->cd.mips.gpr[nr] = *valuep;  
620                                  else                                  else
621                                          printf("WARNING: Attempt to modify r0.\n");                                          printf("(asid %02x),", (int) ((hi &
622                          } else                                              R2K3K_ENTRYHI_ASID_MASK)
623                                  *valuep = m->cpus[cpunr]->cd.mips.gpr[nr];                                              >> R2K3K_ENTRYHI_ASID_SHIFT));
624                          *match_register = 1;                                  printf(" paddr=0x%08x ",
625                  }                                      (int) (lo0&R2K3K_ENTRYLO_PFN_MASK));
626          } else {                                  if (lo0 & R2K3K_ENTRYLO_N)
627                  /*  Check for a symbolic name such as "t6" or "at":  */                                          printf("N");
628                  int nr;                                  if (lo0 & R2K3K_ENTRYLO_D)
629                  for (nr=0; nr<N_MIPS_GPRS; nr++)                                          printf("D");
630                          if (strcmp(name, regnames[nr]) == 0) {                                  printf("\n");
631                                  if (writeflag) {                                  break;
632                                          if (nr != 0)                          default:switch (m->cpus[i]->cd.mips.cpu_type.mmu_model){
633                                                  m->cpus[cpunr]->cd.mips.gpr[nr] = *valuep;                                  case MMU32:
634                                          else                                          printf("vaddr=0x%08"PRIx32" ",
635                                                  printf("WARNING: Attempt to modify r0.\n");                                              (uint32_t) (hi & ~mask));
636                                  } else                                          break;
637                                          *valuep = m->cpus[cpunr]->cd.mips.gpr[nr];                                  default:/*  R4x00, R1x000, MIPS64, etc.  */
638                                  *match_register = 1;                                          printf("vaddr=%016"PRIx64" ",
639                          }                                              (uint64_t) (hi & ~mask));
         }  
   
         if (!(*match_register)) {  
                 /*  Check for a symbolic coproc0 name:  */  
                 int nr;  
                 for (nr=0; nr<32; nr++)  
                         if (strcmp(name, cop0_names[nr]) == 0) {  
                                 if (writeflag) {  
                                         coproc_register_write(m->cpus[cpunr],  
                                             m->cpus[cpunr]->cd.mips.coproc[0], nr,  
                                             valuep, 1, 0);  
                                 } else {  
                                         /*  TODO: Use coproc_register_read instead?  */  
                                         *valuep = m->cpus[cpunr]->cd.mips.coproc[0]->reg[nr];  
640                                  }                                  }
641                                  *match_register = 1;                                  if (hi & TLB_G)
642                          }                                          printf("(global): ");
643          }                                  else
644                                            printf("(asid %02x):",
645                                                (int) (hi & ENTRYHI_ASID));
646    
647          /*  TODO: Coprocessor 1,2,3 registers.  */                                  /*  TODO: Coherency bits  */
 }  
648    
649                                    if (!(lo0 & ENTRYLO_V))
650                                            printf(" p0=(invalid)   ");
651                                    else {
652                                            uint64_t paddr = lo0 & ENTRYLO_PFN_MASK;
653                                            paddr >>= ENTRYLO_PFN_SHIFT;
654                                            paddr <<= pageshift;
655                                            paddr &= ~(mask >> 1);
656                                            printf(" p0=0x%09"PRIx64" ",
657                                                (uint64_t) paddr);
658                                    }
659                                    printf(lo0 & ENTRYLO_D? "D" : " ");
660    
661                                    if (!(lo1 & ENTRYLO_V))
662                                            printf(" p1=(invalid)   ");
663                                    else {
664                                            uint64_t paddr = lo1 & ENTRYLO_PFN_MASK;
665                                            paddr >>= ENTRYLO_PFN_SHIFT;
666                                            paddr <<= pageshift;
667                                            paddr &= ~(mask >> 1);
668                                            printf(" p1=0x%09"PRIx64" ",
669                                                (uint64_t) paddr);
670                                    }
671                                    printf(lo1 & ENTRYLO_D? "D" : " ");
672    
673                                    /*  convert e.g. 0x1fff to 4096  */
674                                    psize = (mask + 1) >> 1;
675    
676                                    if (psize >= 1024 && psize <= 256*1024)
677                                            printf(" (%iKB)", (int) (psize >> 10));
678                                    else if (psize >= 1024*1024 && psize <=
679                                        64*1024*1024)
680                                            printf(" (%iMB)", (int) (psize >> 20));
681                                    else
682                                            printf(" (?)");
683    
684  /*                                  printf("\n");
685   *  cpu_flags():                          }
686   *                  }
  *  Returns a pointer to a string containing "(d)" "(j)" "(dj)" or "",  
  *  depending on the cpu's current delay_slot and last_was_jumptoself  
  *  flags.  
  */  
 static const char *cpu_flags(struct cpu *cpu)  
 {  
         if (cpu->cd.mips.delay_slot) {  
                 if (cpu->cd.mips.last_was_jumptoself)  
                         return " (dj)";  
                 else  
                         return " (d)";  
         } else {  
                 if (cpu->cd.mips.last_was_jumptoself)  
                         return " (j)";  
                 else  
                         return "";  
687          }          }
688  }  }
689    
# Line 721  static const char *cpu_flags(struct cpu Line 703  static const char *cpu_flags(struct cpu
703   *  NOTE 2:  coprocessor instructions are not decoded nicely yet  (TODO)   *  NOTE 2:  coprocessor instructions are not decoded nicely yet  (TODO)
704   */   */
705  int mips_cpu_disassemble_instr(struct cpu *cpu, unsigned char *originstr,  int mips_cpu_disassemble_instr(struct cpu *cpu, unsigned char *originstr,
706          int running, uint64_t dumpaddr, int bintrans)          int running, uint64_t dumpaddr)
707  {  {
708          int hi6, special6, regimm5;          int hi6, special6, regimm5, sub;
709          int rt, rd, rs, sa, imm, copz, cache_op, which_cache, showtag;          int rt, rd, rs, sa, imm, copz, cache_op, which_cache, showtag;
710          uint64_t addr, offset;          uint64_t addr, offset;
711          uint32_t instrword;          uint32_t instrword;
# Line 745  int mips_cpu_disassemble_instr(struct cp Line 727  int mips_cpu_disassemble_instr(struct cp
727                  debug("cpu%i: ", cpu->cpu_id);                  debug("cpu%i: ", cpu->cpu_id);
728    
729          if (cpu->is_32bit)          if (cpu->is_32bit)
730                  debug("%08x", (int)dumpaddr);                  debug("%08"PRIx32, (uint32_t)dumpaddr);
731          else          else
732                  debug("%016llx", (long long)dumpaddr);                  debug("%016"PRIx64, (uint64_t)dumpaddr);
733    
734          *((uint32_t *)&instr[0]) = *((uint32_t *)&originstr[0]);          *((uint32_t *)&instr[0]) = *((uint32_t *)&originstr[0]);
735    
# Line 765  int mips_cpu_disassemble_instr(struct cp Line 747  int mips_cpu_disassemble_instr(struct cp
747          debug(": %02x%02x%02x%02x",          debug(": %02x%02x%02x%02x",
748              instr[3], instr[2], instr[1], instr[0]);              instr[3], instr[2], instr[1], instr[0]);
749    
750          if (running)          if (running && cpu->delay_slot)
751                  debug("%s", cpu_flags(cpu));                  debug(" (d)");
752    
753          debug("\t");          debug("\t");
754    
         if (bintrans && running) {  
                 debug("(bintrans)");  
                 goto disasm_ret;  
         }  
   
755          /*          /*
756           *  Decode the instruction:           *  Decode the instruction:
757           */           */
758    
         if (cpu->cd.mips.nullify_next && running) {  
                 debug("(nullified)");  
                 goto disasm_ret;  
         }  
   
759          hi6 = (instr[3] >> 2) & 0x3f;          hi6 = (instr[3] >> 2) & 0x3f;
760    
761          switch (hi6) {          switch (hi6) {
# Line 799  int mips_cpu_disassemble_instr(struct cp Line 771  int mips_cpu_disassemble_instr(struct cp
771                  case SPECIAL_DSLL32:                  case SPECIAL_DSLL32:
772                  case SPECIAL_DSRL32:                  case SPECIAL_DSRL32:
773                  case SPECIAL_DSRA32:                  case SPECIAL_DSRA32:
774                            sub = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);
775                          rt = instr[2] & 31;                          rt = instr[2] & 31;
776                          rd = (instr[1] >> 3) & 31;                          rd = (instr[1] >> 3) & 31;
777                          sa = ((instr[1] & 7) << 2) + ((instr[0] >> 6) & 3);                          sa = ((instr[1] & 7) << 2) + ((instr[0] >> 6) & 3);
# Line 808  int mips_cpu_disassemble_instr(struct cp Line 781  int mips_cpu_disassemble_instr(struct cp
781                                          debug("nop");                                          debug("nop");
782                                  else if (sa == 1)                                  else if (sa == 1)
783                                          debug("ssnop");                                          debug("ssnop");
784                                    else if (sa == 3)
785                                            debug("ehb");
786                                  else                                  else
787                                          debug("nop (weird, sa=%i)", sa);                                          debug("nop (weird, sa=%i)", sa);
788                                  goto disasm_ret;                                  break;
789                          } else                          }
790    
791                            switch (sub) {
792                            case 0x00:
793                                    debug("%s\t%s,", special_names[special6],
794                                        regnames[rd]);
795                                    debug("%s,%i", regnames[rt], sa);
796                                    break;
797                            case 0x01:
798                                  debug("%s\t%s,",                                  debug("%s\t%s,",
799                                      special_names[special6],                                      special_rot_names[special6],
800                                      regname(cpu->machine, rd));                                      regnames[rd]);
801                                  debug("%s,%i", regname(cpu->machine, rt), sa);                                  debug("%s,%i", regnames[rt], sa);
802                                    break;
803                            default:debug("UNIMPLEMENTED special, sub=0x%02x\n",
804                                        sub);
805                            }
806                          break;                          break;
807                  case SPECIAL_DSRLV:                  case SPECIAL_DSRLV:
808                  case SPECIAL_DSRAV:                  case SPECIAL_DSRAV:
# Line 826  int mips_cpu_disassemble_instr(struct cp Line 813  int mips_cpu_disassemble_instr(struct cp
813                          rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);                          rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);
814                          rt = instr[2] & 31;                          rt = instr[2] & 31;
815                          rd = (instr[1] >> 3) & 31;                          rd = (instr[1] >> 3) & 31;
816                          debug("%s\t%s",                          sub = ((instr[1] & 7) << 2) + ((instr[0] >> 6) & 3);
817                              special_names[special6], regname(cpu->machine, rd));  
818                          debug(",%s", regname(cpu->machine, rt));                          switch (sub) {
819                          debug(",%s", regname(cpu->machine, rs));                          case 0x00:
820                                    debug("%s\t%s", special_names[special6],
821                                        regnames[rd]);
822                                    debug(",%s", regnames[rt]);
823                                    debug(",%s", regnames[rs]);
824                                    break;
825                            case 0x01:
826                                    debug("%s\t%s", special_rot_names[special6],
827                                        regnames[rd]);
828                                    debug(",%s", regnames[rt]);
829                                    debug(",%s", regnames[rs]);
830                                    break;
831                            default:debug("UNIMPLEMENTED special, sub=0x%02x\n",
832                                        sub);
833                            }
834                          break;                          break;
835                  case SPECIAL_JR:                  case SPECIAL_JR:
836                          rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);                          rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);
837                          symbol = get_symbol_name(&cpu->machine->symbol_context,                          symbol = get_symbol_name(&cpu->machine->symbol_context,
838                              cpu->cd.mips.gpr[rs], &offset);                              cpu->cd.mips.gpr[rs], &offset);
839                          debug("jr\t%s", regname(cpu->machine, rs));                          /*  .hb = hazard barrier hint on MIPS32/64 rev 2  */
840                            debug("jr%s\t%s",
841                                (instr[1] & 0x04) ? ".hb" : "",
842                                regnames[rs]);
843                          if (running && symbol != NULL)                          if (running && symbol != NULL)
844                                  debug("\t<%s>", symbol);                                  debug("\t<%s>", symbol);
845                          break;                          break;
# Line 844  int mips_cpu_disassemble_instr(struct cp Line 848  int mips_cpu_disassemble_instr(struct cp
848                          rd = (instr[1] >> 3) & 31;                          rd = (instr[1] >> 3) & 31;
849                          symbol = get_symbol_name(&cpu->machine->symbol_context,                          symbol = get_symbol_name(&cpu->machine->symbol_context,
850                              cpu->cd.mips.gpr[rs], &offset);                              cpu->cd.mips.gpr[rs], &offset);
851                          debug("jalr\t%s", regname(cpu->machine, rd));                          /*  .hb = hazard barrier hint on MIPS32/64 rev 2  */
852                          debug(",%s", regname(cpu->machine, rs));                          debug("jalr%s\t%s",
853                                (instr[1] & 0x04) ? ".hb" : "",
854                                regnames[rd]);
855                            debug(",%s", regnames[rs]);
856                          if (running && symbol != NULL)                          if (running && symbol != NULL)
857                                  debug("\t<%s>", symbol);                                  debug("\t<%s>", symbol);
858                          break;                          break;
859                  case SPECIAL_MFHI:                  case SPECIAL_MFHI:
860                  case SPECIAL_MFLO:                  case SPECIAL_MFLO:
861                          rd = (instr[1] >> 3) & 31;                          rd = (instr[1] >> 3) & 31;
862                          debug("%s\t%s", special_names[special6],                          debug("%s\t%s", special_names[special6], regnames[rd]);
                             regname(cpu->machine, rd));  
863                          break;                          break;
864                  case SPECIAL_MTLO:                  case SPECIAL_MTLO:
865                  case SPECIAL_MTHI:                  case SPECIAL_MTHI:
866                          rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);                          rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);
867                          debug("%s\t%s", special_names[special6],                          debug("%s\t%s", special_names[special6], regnames[rs]);
                             regname(cpu->machine, rs));  
868                          break;                          break;
869                  case SPECIAL_ADD:                  case SPECIAL_ADD:
870                  case SPECIAL_ADDU:                  case SPECIAL_ADDU:
# Line 880  int mips_cpu_disassemble_instr(struct cp Line 885  int mips_cpu_disassemble_instr(struct cp
885                          rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);                          rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);
886                          rt = instr[2] & 31;                          rt = instr[2] & 31;
887                          rd = (instr[1] >> 3) & 31;                          rd = (instr[1] >> 3) & 31;
888                          if ((special6 == SPECIAL_ADDU ||                          if (cpu->is_32bit && (special6 == SPECIAL_ADDU ||
889                              special6 == SPECIAL_DADDU ||                              special6 == SPECIAL_SUBU) && rt == 0) {
890                              special6 == SPECIAL_SUBU ||                                  /*  Special case 1: addu/subu with
                             special6 == SPECIAL_DSUBU) && rt == 0) {  
                                 /*  Special case 1: addu/daddu/subu/dsubu with  
891                                      rt = the zero register ==> move  */                                      rt = the zero register ==> move  */
892                                  debug("move\t%s", regname(cpu->machine, rd));                                  debug("move\t%s", regnames[rd]);
893                                  debug(",%s", regname(cpu->machine, rs));                                  debug(",%s", regnames[rs]);
894                          } else if ((special6 == SPECIAL_ADDU ||                          } else if (special6 == SPECIAL_ADDU && cpu->is_32bit
895                              special6 == SPECIAL_DADDU) && rs == 0) {                              && rs == 0) {
896                                  /*  Special case 2: addu/daddu with                                  /*  Special case 2: addu with
897                                      rs = the zero register ==> move  */                                      rs = the zero register ==> move  */
898                                  debug("move\t%s", regname(cpu->machine, rd));                                  debug("move\t%s", regnames[rd]);
899                                  debug(",%s", regname(cpu->machine, rt));                                  debug(",%s", regnames[rt]);
900                          } else {                          } else {
901                                  debug("%s\t%s", special_names[special6],                                  debug("%s\t%s", special_names[special6],
902                                      regname(cpu->machine, rd));                                      regnames[rd]);
903                                  debug(",%s", regname(cpu->machine, rs));                                  debug(",%s", regnames[rs]);
904                                  debug(",%s", regname(cpu->machine, rt));                                  debug(",%s", regnames[rt]);
905                          }                          }
906                          break;                          break;
907                  case SPECIAL_MULT:                  case SPECIAL_MULT:
# Line 918  int mips_cpu_disassemble_instr(struct cp Line 921  int mips_cpu_disassemble_instr(struct cp
921                          rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);                          rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);
922                          rt = instr[2] & 31;                          rt = instr[2] & 31;
923                          rd = (instr[1] >> 3) & 31;                          rd = (instr[1] >> 3) & 31;
924                          if (special6 == SPECIAL_MULT) {                          debug("%s\t", special_names[special6]);
925                                  if (rd != 0) {                          if (rd != 0) {
926                                          debug("mult_xx\t%s",                                  if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) {
927                                              regname(cpu->machine, rd));                                          if (special6 == SPECIAL_MULT ||
928                                          debug(",%s", regname(cpu->machine, rs));                                              special6 == SPECIAL_MULTU)
929                                          debug(",%s", regname(cpu->machine, rt));                                                  debug("%s,", regnames[rd]);
930                                          goto disasm_ret;                                          else
931                                                    debug("WEIRD_R5900_RD,");
932                                    } else {
933                                            debug("WEIRD_RD_NONZERO,");
934                                  }                                  }
935                          }                          }
936                          debug("%s\t%s", special_names[special6],                          debug("%s", regnames[rs]);
937                              regname(cpu->machine, rs));                          debug(",%s", regnames[rt]);
                         debug(",%s", regname(cpu->machine, rt));  
938                          break;                          break;
939                  case SPECIAL_SYNC:                  case SPECIAL_SYNC:
940                          imm = ((instr[1] & 7) << 2) + (instr[0] >> 6);                          imm = ((instr[1] & 7) << 2) + (instr[0] >> 6);
# Line 952  int mips_cpu_disassemble_instr(struct cp Line 957  int mips_cpu_disassemble_instr(struct cp
957                                  debug("break");                                  debug("break");
958                          break;                          break;
959                  case SPECIAL_MFSA:                  case SPECIAL_MFSA:
960                          rd = (instr[1] >> 3) & 31;                          if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) {
961                          debug("mfsa\t%s", regname(cpu->machine, rd));                                  rd = (instr[1] >> 3) & 31;
962                                    debug("mfsa\t%s", regnames[rd]);
963                            } else {
964                                    debug("unimplemented special 0x28");
965                            }
966                          break;                          break;
967                  case SPECIAL_MTSA:                  case SPECIAL_MTSA:
968                          rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);                          if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) {
969                          debug("mtsa\t%s", regname(cpu->machine, rs));                                  rs = ((instr[3] & 3) << 3) +
970                                        ((instr[2] >> 5) & 7);
971                                    debug("mtsa\t%s", regnames[rs]);
972                            } else {
973                                    debug("unimplemented special 0x29");
974                            }
975                          break;                          break;
976                  default:                  default:
977                          debug("unimplemented special6 = 0x%02x", special6);                          debug("%s\t= UNIMPLEMENTED", special_names[special6]);
978                  }                  }
979                  break;                  break;
980          case HI6_BEQ:          case HI6_BEQ:
# Line 977  int mips_cpu_disassemble_instr(struct cp Line 991  int mips_cpu_disassemble_instr(struct cp
991                  if (imm >= 32768)                  if (imm >= 32768)
992                          imm -= 65536;                          imm -= 65536;
993                  addr = (dumpaddr + 4) + (imm << 2);                  addr = (dumpaddr + 4) + (imm << 2);
                 debug("%s\t", hi6_names[hi6]);  
994    
995                  switch (hi6) {                  if (hi6 == HI6_BEQ && rt == MIPS_GPR_ZERO &&
996                  case HI6_BEQ:                      rs == MIPS_GPR_ZERO)
997                  case HI6_BEQL:                          debug("b\t");
998                  case HI6_BNE:                  else {
999                  case HI6_BNEL:                          debug("%s\t", hi6_names[hi6]);
1000                          debug("%s,", regname(cpu->machine, rt));                          switch (hi6) {
1001                            case HI6_BEQ:
1002                            case HI6_BEQL:
1003                            case HI6_BNE:
1004                            case HI6_BNEL:
1005                                    debug("%s,", regnames[rt]);
1006                            }
1007                            debug("%s,", regnames[rs]);
1008                  }                  }
1009    
                 debug("%s,", regname(cpu->machine, rs));  
   
1010                  if (cpu->is_32bit)                  if (cpu->is_32bit)
1011                          debug("0x%08x", (int)addr);                          debug("0x%08"PRIx32, (uint32_t)addr);
1012                  else                  else
1013                          debug("0x%016llx", (long long)addr);                          debug("0x%016"PRIx64, (uint64_t)addr);
1014    
1015                  symbol = get_symbol_name(&cpu->machine->symbol_context,                  symbol = get_symbol_name(&cpu->machine->symbol_context,
1016                      addr, &offset);                      addr, &offset);
# Line 1013  int mips_cpu_disassemble_instr(struct cp Line 1031  int mips_cpu_disassemble_instr(struct cp
1031                  imm = (instr[1] << 8) + instr[0];                  imm = (instr[1] << 8) + instr[0];
1032                  if (imm >= 32768)                  if (imm >= 32768)
1033                          imm -= 65536;                          imm -= 65536;
1034                  debug("%s\t%s,", hi6_names[hi6], regname(cpu->machine, rt));                  debug("%s\t%s,", hi6_names[hi6], regnames[rt]);
1035                  debug("%s,", regname(cpu->machine, rs));                  debug("%s,", regnames[rs]);
1036                  if (hi6 == HI6_ANDI || hi6 == HI6_ORI || hi6 == HI6_XORI)                  if (hi6 == HI6_ANDI || hi6 == HI6_ORI || hi6 == HI6_XORI)
1037                          debug("0x%04x", imm & 0xffff);                          debug("0x%04x", imm & 0xffff);
1038                  else                  else
# Line 1023  int mips_cpu_disassemble_instr(struct cp Line 1041  int mips_cpu_disassemble_instr(struct cp
1041          case HI6_LUI:          case HI6_LUI:
1042                  rt = instr[2] & 31;                  rt = instr[2] & 31;
1043                  imm = (instr[1] << 8) + instr[0];                  imm = (instr[1] << 8) + instr[0];
1044                  debug("lui\t%s,0x%x", regname(cpu->machine, rt), imm);                  debug("lui\t%s,0x%x", regnames[rt], imm);
1045                  break;                  break;
1046          case HI6_LB:          case HI6_LB:
1047          case HI6_LBU:          case HI6_LBU:
# Line 1044  int mips_cpu_disassemble_instr(struct cp Line 1062  int mips_cpu_disassemble_instr(struct cp
1062          case HI6_SH:          case HI6_SH:
1063          case HI6_SW:          case HI6_SW:
1064          case HI6_SD:          case HI6_SD:
1065          case HI6_SQ:          case HI6_SQ_SPECIAL3:
1066          case HI6_SC:          case HI6_SC:
1067          case HI6_SCD:          case HI6_SCD:
1068          case HI6_SWC1:          case HI6_SWC1:
# Line 1060  int mips_cpu_disassemble_instr(struct cp Line 1078  int mips_cpu_disassemble_instr(struct cp
1078          case HI6_SWR:          case HI6_SWR:
1079          case HI6_SDL:          case HI6_SDL:
1080          case HI6_SDR:          case HI6_SDR:
1081                    if (hi6 == HI6_LQ_MDMX &&
1082                        cpu->cd.mips.cpu_type.rev != MIPS_R5900) {
1083                            debug("mdmx\t(UNIMPLEMENTED)");
1084                            break;
1085                    }
1086                    if (hi6 == HI6_SQ_SPECIAL3 &&
1087                        cpu->cd.mips.cpu_type.rev != MIPS_R5900) {
1088                            int msbd, lsb, sub10;
1089                            special6 = instr[0] & 0x3f;
1090                            rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);
1091                            rt = instr[2] & 31;
1092                            rd = msbd = (instr[1] >> 3) & 31;
1093                            lsb = ((instr[1] & 7) << 2) | (instr[0] >> 6);
1094                            sub10 = (rs << 5) | lsb;
1095    
1096                            switch (special6) {
1097    
1098                            case SPECIAL3_EXT:
1099                            case SPECIAL3_DEXT:
1100                            case SPECIAL3_DEXTM:
1101                            case SPECIAL3_DEXTU:
1102                                    debug("%s", special3_names[special6]);
1103                                    if (special6 == SPECIAL3_DEXTM)
1104                                            msbd += 32;
1105                                    if (special6 == SPECIAL3_DEXTU)
1106                                            lsb += 32;
1107                                    debug("\t%s", regnames[rt]);
1108                                    debug(",%s", regnames[rs]);
1109                                    debug(",%i,%i", lsb, msbd + 1);
1110                                    break;
1111    
1112                            case SPECIAL3_INS:
1113                            case SPECIAL3_DINS:
1114                            case SPECIAL3_DINSM:
1115                            case SPECIAL3_DINSU:
1116                                    debug("%s", special3_names[special6]);
1117                                    if (special6 == SPECIAL3_DINSM)
1118                                            msbd += 32;
1119                                    if (special6 == SPECIAL3_DINSU) {
1120                                            lsb += 32;
1121                                            msbd += 32;
1122                                    }
1123                                    msbd -= lsb;
1124                                    debug("\t%s", regnames[rt]);
1125                                    debug(",%s", regnames[rs]);
1126                                    debug(",%i,%i", lsb, msbd + 1);
1127                                    break;
1128    
1129                            case SPECIAL3_BSHFL:
1130                                    switch (sub10) {
1131                                    case BSHFL_WSBH:
1132                                    case BSHFL_SEB:
1133                                    case BSHFL_SEH:
1134                                            switch (sub10) {
1135                                            case BSHFL_WSBH: debug("wsbh"); break;
1136                                            case BSHFL_SEB:  debug("seb"); break;
1137                                            case BSHFL_SEH:  debug("seh"); break;
1138                                            }
1139                                            debug("\t%s", regnames[rd]);
1140                                            debug(",%s", regnames[rt]);
1141                                            break;
1142                                    default:debug("%s", special3_names[special6]);
1143                                            debug("\t(UNIMPLEMENTED)");
1144                                    }
1145                                    break;
1146    
1147                            case SPECIAL3_DBSHFL:
1148                                    switch (sub10) {
1149                                    case BSHFL_DSBH:
1150                                    case BSHFL_DSHD:
1151                                            switch (sub10) {
1152                                            case BSHFL_DSBH: debug("dsbh"); break;
1153                                            case BSHFL_DSHD: debug("dshd"); break;
1154                                            }
1155                                            debug("\t%s", regnames[rd]);
1156                                            debug(",%s", regnames[rt]);
1157                                            break;
1158                                    default:debug("%s", special3_names[special6]);
1159                                            debug("\t(UNIMPLEMENTED)");
1160                                    }
1161                                    break;
1162    
1163                            case SPECIAL3_RDHWR:
1164                                    debug("%s", special3_names[special6]);
1165                                    debug("\t%s", regnames[rt]);
1166                                    debug(",hwr%i", rd);
1167                                    break;
1168    
1169                            default:debug("%s", special3_names[special6]);
1170                                    debug("\t(UNIMPLEMENTED)");
1171                            }
1172                            break;
1173                    }
1174    
1175                  rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);                  rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);
1176                  rt = instr[2] & 31;                  rt = instr[2] & 31;
1177                  imm = (instr[1] << 8) + instr[0];                  imm = (instr[1] << 8) + instr[0];
# Line 1072  int mips_cpu_disassemble_instr(struct cp Line 1184  int mips_cpu_disassemble_instr(struct cp
1184                  /*  TODO: Which ISAs? IV? V? 32? 64?  */                  /*  TODO: Which ISAs? IV? V? 32? 64?  */
1185                  if (cpu->cd.mips.cpu_type.isa_level >= 4 && hi6 == HI6_LWC3) {                  if (cpu->cd.mips.cpu_type.isa_level >= 4 && hi6 == HI6_LWC3) {
1186                          debug("pref\t0x%x,%i(%s)",                          debug("pref\t0x%x,%i(%s)",
1187                              rt, imm, regname(cpu->machine, rs));                              rt, imm, regnames[rs]);
1188    
1189                          if (running) {                          if (running) {
1190                                  debug("\t[0x%016llx = %s]",                                  debug("\t[0x%016"PRIx64" = %s]",
1191                                      (long long)(cpu->cd.mips.gpr[rs] + imm));                                      (uint64_t)(cpu->cd.mips.gpr[rs] + imm));
1192                                  if (symbol != NULL)                                  if (symbol != NULL)
1193                                          debug(" = %s", symbol);                                          debug(" = %s", symbol);
1194                                  debug("]");                                  debug("]");
# Line 1092  int mips_cpu_disassemble_instr(struct cp Line 1204  int mips_cpu_disassemble_instr(struct cp
1204                      hi6 == HI6_LDC1 || hi6 == HI6_LDC2)                      hi6 == HI6_LDC1 || hi6 == HI6_LDC2)
1205                          debug("r%i", rt);                          debug("r%i", rt);
1206                  else                  else
1207                          debug("%s", regname(cpu->machine, rt));                          debug("%s", regnames[rt]);
1208    
1209                  debug(",%i(%s)", imm, regname(cpu->machine, rs));                  debug(",%i(%s)", imm, regnames[rs]);
1210    
1211                  if (running) {                  if (running) {
1212                          debug("\t[");                          debug("\t[");
1213    
1214                          if (cpu->is_32bit)                          if (cpu->is_32bit)
1215                                  debug("0x%08x", (int)(cpu->cd.mips.gpr[rs] + imm));                                  debug("0x%08"PRIx32,
1216                                        (uint32_t) (cpu->cd.mips.gpr[rs] + imm));
1217                          else                          else
1218                                  debug("0x%016llx",                                  debug("0x%016"PRIx64,
1219                                      (long long)(cpu->cd.mips.gpr[rs] + imm));                                      (uint64_t) (cpu->cd.mips.gpr[rs] + imm));
1220    
1221                          if (symbol != NULL)                          if (symbol != NULL)
1222                                  debug(" = %s", symbol);                                  debug(" = %s", symbol);
1223    
1224                          debug(", data=");                          /*  TODO: In some cases, it is possible to peek into
1225                  } else                              memory, and display that data here, like for the
1226                          break;                              other emulation modes.  */
1227                  /*  NOTE: No break here (if we are running) as it is up  
1228                      to the caller to print 'data'.  */                          debug("]");
1229                  return sizeof(instrword);                  }
1230                    break;
1231    
1232          case HI6_J:          case HI6_J:
1233          case HI6_JAL:          case HI6_JAL:
1234                  imm = (((instr[3] & 3) << 24) + (instr[2] << 16) +                  imm = (((instr[3] & 3) << 24) + (instr[2] << 16) +
# Line 1124  int mips_cpu_disassemble_instr(struct cp Line 1239  int mips_cpu_disassemble_instr(struct cp
1239                      addr, &offset);                      addr, &offset);
1240                  debug("%s\t0x", hi6_names[hi6]);                  debug("%s\t0x", hi6_names[hi6]);
1241                  if (cpu->is_32bit)                  if (cpu->is_32bit)
1242                          debug("%08x", (int)addr);                          debug("%08"PRIx32, (uint32_t) addr);
1243                  else                  else
1244                          debug("%016llx", (long long)addr);                          debug("%016"PRIx64, (uint64_t) addr);
1245                  if (symbol != NULL)                  if (symbol != NULL)
1246                          debug("\t<%s>", symbol);                          debug("\t<%s>", symbol);
1247                  break;                  break;
1248    
1249          case HI6_COP0:          case HI6_COP0:
1250          case HI6_COP1:          case HI6_COP1:
1251          case HI6_COP2:          case HI6_COP2:
# Line 1142  int mips_cpu_disassemble_instr(struct cp Line 1258  int mips_cpu_disassemble_instr(struct cp
1258                  coproc_function(cpu, cpu->cd.mips.coproc[hi6 - HI6_COP0],                  coproc_function(cpu, cpu->cd.mips.coproc[hi6 - HI6_COP0],
1259                      hi6 - HI6_COP0, imm, 1, running);                      hi6 - HI6_COP0, imm, 1, running);
1260                  return sizeof(instrword);                  return sizeof(instrword);
1261    
1262          case HI6_CACHE:          case HI6_CACHE:
1263                  rt   = ((instr[3] & 3) << 3) + (instr[2] >> 5); /*  base  */                  rt   = ((instr[3] & 3) << 3) + (instr[2] >> 5); /*  base  */
1264                  copz = instr[2] & 31;                  copz = instr[2] & 31;
# Line 1149  int mips_cpu_disassemble_instr(struct cp Line 1266  int mips_cpu_disassemble_instr(struct cp
1266                  cache_op    = copz >> 2;                  cache_op    = copz >> 2;
1267                  which_cache = copz & 3;                  which_cache = copz & 3;
1268                  showtag = 0;                  showtag = 0;
1269                  debug("cache\t0x%02x,0x%04x(%s)", copz, imm,                  debug("cache\t0x%02x,0x%04x(%s)", copz, imm, regnames[rt]);
                     regname(cpu->machine, rt));  
1270                  if (which_cache==0)     debug("  [ primary I-cache");                  if (which_cache==0)     debug("  [ primary I-cache");
1271                  if (which_cache==1)     debug("  [ primary D-cache");                  if (which_cache==1)     debug("  [ primary D-cache");
1272                  if (which_cache==2)     debug("  [ secondary I-cache");                  if (which_cache==2)     debug("  [ secondary I-cache");
# Line 1161  int mips_cpu_disassemble_instr(struct cp Line 1277  int mips_cpu_disassemble_instr(struct cp
1277                  if (cache_op==2)        debug("index store tag"), showtag=1;                  if (cache_op==2)        debug("index store tag"), showtag=1;
1278                  if (cache_op==3)        debug("create dirty exclusive");                  if (cache_op==3)        debug("create dirty exclusive");
1279                  if (cache_op==4)        debug("hit invalidate");                  if (cache_op==4)        debug("hit invalidate");
1280                  if (cache_op==5)        debug("fill OR hit writeback invalidate");                  if (cache_op==5)     debug("fill OR hit writeback invalidate");
1281                  if (cache_op==6)        debug("hit writeback");                  if (cache_op==6)        debug("hit writeback");
1282                  if (cache_op==7)        debug("hit set virtual");                  if (cache_op==7)        debug("hit set virtual");
1283                  if (running)                  if (running)
1284                          debug(", addr 0x%016llx",                          debug(", addr 0x%016"PRIx64,
1285                              (long long)(cpu->cd.mips.gpr[rt] + imm));                              (uint64_t)(cpu->cd.mips.gpr[rt] + imm));
1286                  if (showtag)                  if (showtag)
1287                  debug(", taghi=%08lx lo=%08lx",                  debug(", taghi=%08lx lo=%08lx",
1288                      (long)cpu->cd.mips.coproc[0]->reg[COP0_TAGDATA_HI],                      (long)cpu->cd.mips.coproc[0]->reg[COP0_TAGDATA_HI],
1289                      (long)cpu->cd.mips.coproc[0]->reg[COP0_TAGDATA_LO]);                      (long)cpu->cd.mips.coproc[0]->reg[COP0_TAGDATA_LO]);
1290                  debug(" ]");                  debug(" ]");
1291                  break;                  break;
1292    
1293          case HI6_SPECIAL2:          case HI6_SPECIAL2:
1294                  special6 = instr[0] & 0x3f;                  special6 = instr[0] & 0x3f;
1295                  instrword = (instr[3] << 24) + (instr[2] << 16) +                  instrword = (instr[3] << 24) + (instr[2] << 16) +
# Line 1180  int mips_cpu_disassemble_instr(struct cp Line 1297  int mips_cpu_disassemble_instr(struct cp
1297                  rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);                  rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);
1298                  rt = instr[2] & 31;                  rt = instr[2] & 31;
1299                  rd = (instr[1] >> 3) & 31;                  rd = (instr[1] >> 3) & 31;
1300                  if ((instrword & 0xfc0007ffULL) == 0x70000000) {  
1301                          debug("madd\t%s", regname(cpu->machine, rd));                  if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) {
1302                          debug(",%s", regname(cpu->machine, rs));                          int c790mmifunc = (instrword >> 6) & 0x1f;
1303                          debug(",%s", regname(cpu->machine, rt));                          if (special6 != MMI_MMI0 && special6 != MMI_MMI1 &&
1304                  } else if (special6 == SPECIAL2_MUL) {                              special6 != MMI_MMI2 && special6 != MMI_MMI3)
1305                          /*  TODO: this is just a guess, I don't have the                                  debug("%s\t", mmi_names[special6]);
1306                                  docs in front of me  */  
1307                          debug("mul\t%s", regname(cpu->machine, rd));                          switch (special6) {
1308                          debug(",%s", regname(cpu->machine, rs));  
1309                          debug(",%s", regname(cpu->machine, rt));                          case MMI_MADD:
1310                  } else if (special6 == SPECIAL2_CLZ) {                          case MMI_MADDU:
1311                          debug("clz\t%s", regname(cpu->machine, rd));                                  if (rd != MIPS_GPR_ZERO) {
1312                          debug(",%s", regname(cpu->machine, rs));                                          debug("%s,", regnames[rd]);
1313                  } else if (special6 == SPECIAL2_CLO) {                                  }
1314                          debug("clo\t%s", regname(cpu->machine, rd));                                  debug("%s,%s", regnames[rs], regnames[rt]);
1315                          debug(",%s", regname(cpu->machine, rs));                                  break;
1316                  } else if (special6 == SPECIAL2_DCLZ) {  
1317                          debug("dclz\t%s", regname(cpu->machine, rd));                          case MMI_MMI0:
1318                          debug(",%s", regname(cpu->machine, rs));                                  debug("%s\t", mmi0_names[c790mmifunc]);
1319                  } else if (special6 == SPECIAL2_DCLO) {                                  switch (c790mmifunc) {
1320                          debug("dclo\t%s", regname(cpu->machine, rd));  
1321                          debug(",%s", regname(cpu->machine, rs));                                  case MMI0_PEXTLB:
1322                  } else if ((instrword & 0xffff07ffULL) == 0x70000209                                  case MMI0_PEXTLH:
1323                      || (instrword & 0xffff07ffULL) == 0x70000249) {                                  case MMI0_PEXTLW:
1324                          if (instr[0] == 0x49) {                                  case MMI0_PMAXH:
1325                                  debug("pmflo\t%s", regname(cpu->machine, rd));                                  case MMI0_PMAXW:
1326                                  debug("  (rs=%s)", regname(cpu->machine, rs));                                  case MMI0_PPACB:
1327                          } else {                                  case MMI0_PPACH:
1328                                  debug("pmfhi\t%s", regname(cpu->machine, rd));                                  case MMI0_PPACW:
1329                                  debug("  (rs=%s)", regname(cpu->machine, rs));                                          debug("%s,%s,%s", regnames[rd],
1330                                                regnames[rs], regnames[rt]);
1331                                            break;
1332    
1333                                    default:debug("(UNIMPLEMENTED)");
1334                                    }
1335                                    break;
1336    
1337                            case MMI_MMI1:
1338                                    debug("%s\t", mmi1_names[c790mmifunc]);
1339                                    switch (c790mmifunc) {
1340    
1341                                    case MMI1_PEXTUB:
1342                                    case MMI1_PEXTUH:
1343                                    case MMI1_PEXTUW:
1344                                    case MMI1_PMINH:
1345                                    case MMI1_PMINW:
1346                                            debug("%s,%s,%s", regnames[rd],
1347                                                regnames[rs], regnames[rt]);
1348                                            break;
1349    
1350                                    default:debug("(UNIMPLEMENTED)");
1351                                    }
1352                                    break;
1353    
1354                            case MMI_MMI2:
1355                                    debug("%s\t", mmi2_names[c790mmifunc]);
1356                                    switch (c790mmifunc) {
1357    
1358                                    case MMI2_PMFHI:
1359                                    case MMI2_PMFLO:
1360                                            debug("%s", regnames[rd]);
1361                                            break;
1362    
1363                                    case MMI2_PHMADH:
1364                                    case MMI2_PHMSBH:
1365                                    case MMI2_PINTH:
1366                                    case MMI2_PMADDH:
1367                                    case MMI2_PMADDW:
1368                                    case MMI2_PMSUBH:
1369                                    case MMI2_PMSUBW:
1370                                    case MMI2_PMULTH:
1371                                    case MMI2_PMULTW:
1372                                    case MMI2_PSLLVW:
1373                                            debug("%s,%s,%s", regnames[rd],
1374                                                regnames[rs], regnames[rt]);
1375                                            break;
1376    
1377                                    default:debug("(UNIMPLEMENTED)");
1378                                    }
1379                                    break;
1380    
1381                            case MMI_MMI3:
1382                                    debug("%s\t", mmi3_names[c790mmifunc]);
1383                                    switch (c790mmifunc) {
1384    
1385                                    case MMI3_PMTHI:
1386                                    case MMI3_PMTLO:
1387                                            debug("%s", regnames[rs]);
1388                                            break;
1389    
1390                                    case MMI3_PINTEH:
1391                                    case MMI3_PMADDUW:
1392                                    case MMI3_PMULTUW:
1393                                    case MMI3_PNOR:
1394                                    case MMI3_POR:
1395                                    case MMI3_PSRAVW:
1396                                            debug("%s,%s,%s", regnames[rd],
1397                                                regnames[rs], regnames[rt]);
1398                                            break;
1399    
1400                                    default:debug("(UNIMPLEMENTED)");
1401                                    }
1402                                    break;
1403    
1404                            default:debug("(UNIMPLEMENTED)");
1405                          }                          }
1406                  } else if ((instrword & 0xfc1fffff) == 0x70000269                          break;
1407                      || (instrword & 0xfc1fffff) == 0x70000229) {                  }
1408                          if (instr[0] == 0x69) {  
1409                                  debug("pmtlo\t%s", regname(cpu->machine, rs));                  /*  SPECIAL2:  */
1410                          } else {                  debug("%s\t", special2_names[special6]);
1411                                  debug("pmthi\t%s", regname(cpu->machine, rs));  
1412                          }                  switch (special6) {
1413                  } else if ((instrword & 0xfc0007ff) == 0x700004a9) {  
1414                          debug("por\t%s", regname(cpu->machine, rd));                  case SPECIAL2_MADD:
1415                          debug(",%s", regname(cpu->machine, rs));                  case SPECIAL2_MADDU:
1416                          debug(",%s", regname(cpu->machine, rt));                  case SPECIAL2_MSUB:
1417                  } else if ((instrword & 0xfc0007ff) == 0x70000488) {                  case SPECIAL2_MSUBU:
1418                          debug("pextlw\t%s", regname(cpu->machine, rd));                          if (rd != MIPS_GPR_ZERO) {
1419                          debug(",%s", regname(cpu->machine, rs));                                  debug("WEIRD_NONZERO_RD(%s),",
1420                          debug(",%s", regname(cpu->machine, rt));                                      regnames[rd]);
1421                  } else {                          }
1422                          debug("unimplemented special2 = 0x%02x", special6);                          debug("%s,%s", regnames[rs], regnames[rt]);
1423                            break;
1424    
1425                    case SPECIAL2_MUL:
1426                            /*  Apparently used both on R5900 and MIPS32:  */
1427                            debug("%s,%s,%s", regnames[rd],
1428                                regnames[rs], regnames[rt]);
1429                            break;
1430    
1431                    case SPECIAL2_CLZ:
1432                    case SPECIAL2_CLO:
1433                    case SPECIAL2_DCLZ:
1434                    case SPECIAL2_DCLO:
1435                            debug("%s,%s", regnames[rd], regnames[rs]);
1436                            break;
1437    
1438                    default:
1439                            debug("(UNIMPLEMENTED)");
1440                  }                  }
1441                  break;                  break;
1442    
1443          case HI6_REGIMM:          case HI6_REGIMM:
1444                  regimm5 = instr[2] & 0x1f;                  regimm5 = instr[2] & 0x1f;
1445                    rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);
1446                    imm = (instr[1] << 8) + instr[0];
1447                    if (imm >= 32768)              
1448                            imm -= 65536;
1449    
1450                  switch (regimm5) {                  switch (regimm5) {
1451    
1452                  case REGIMM_BLTZ:                  case REGIMM_BLTZ:
1453                  case REGIMM_BGEZ:                  case REGIMM_BGEZ:
1454                  case REGIMM_BLTZL:                  case REGIMM_BLTZL:
# Line 1241  int mips_cpu_disassemble_instr(struct cp Line 1457  int mips_cpu_disassemble_instr(struct cp
1457                  case REGIMM_BLTZALL:                  case REGIMM_BLTZALL:
1458                  case REGIMM_BGEZAL:                  case REGIMM_BGEZAL:
1459                  case REGIMM_BGEZALL:                  case REGIMM_BGEZALL:
1460                          rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);                          debug("%s\t%s,", regimm_names[regimm5], regnames[rs]);
                         imm = (instr[1] << 8) + instr[0];  
                         if (imm >= 32768)                
                                 imm -= 65536;  
   
                         debug("%s\t%s,", regimm_names[regimm5],  
                             regname(cpu->machine, rs));  
1461    
1462                          addr = (dumpaddr + 4) + (imm << 2);                          addr = (dumpaddr + 4) + (imm << 2);
1463    
1464                          if (cpu->is_32bit)                          if (cpu->is_32bit)
1465                                  debug("0x%08x", (int)addr);                                  debug("0x%08"PRIx32, (uint32_t) addr);
1466                          else                          else
1467                                  debug("0x%016llx", (long long)addr);                                  debug("0x%016"PRIx64, (uint64_t) addr);
1468                            break;
1469    
1470                    case REGIMM_SYNCI:
1471                            debug("%s\t%i(%s)", regimm_names[regimm5],
1472                                imm, regnames[rs]);
1473                          break;                          break;
1474    
1475                  default:                  default:
1476                          debug("unimplemented regimm5 = 0x%02x", regimm5);                          debug("unimplemented regimm5 = 0x%02x", regimm5);
1477                  }                  }
# Line 1283  void mips_cpu_register_dump(struct cpu * Line 1499  void mips_cpu_register_dump(struct cpu *
1499          int coprocnr, i, bits32;          int coprocnr, i, bits32;
1500          uint64_t offset;          uint64_t offset;
1501          char *symbol;          char *symbol;
1502            int bits128 = cpu->cd.mips.cpu_type.rev == MIPS_R5900;
1503    
1504          bits32 = cpu->is_32bit;          bits32 = cpu->is_32bit;
1505    
# Line 1292  void mips_cpu_register_dump(struct cpu * Line 1509  void mips_cpu_register_dump(struct cpu *
1509                      cpu->pc, &offset);                      cpu->pc, &offset);
1510    
1511                  if (bits32)                  if (bits32)
1512                          debug("cpu%i:  pc = %08x", cpu->cpu_id, (int)cpu->pc);                          debug("cpu%i:  pc = %08"PRIx32,
1513                                cpu->cpu_id, (uint32_t) cpu->pc);
1514                    else if (bits128)
1515                            debug("cpu%i:  pc=%016"PRIx64,
1516                                cpu->cpu_id, (uint64_t) cpu->pc);
1517                  else                  else
1518                          debug("cpu%i:    pc = 0x%016llx",                          debug("cpu%i:    pc = 0x%016"PRIx64,
1519                              cpu->cpu_id, (long long)cpu->pc);                              cpu->cpu_id, (uint64_t) cpu->pc);
1520    
1521                  debug("    <%s>\n", symbol != NULL? symbol :                  debug("    <%s>\n", symbol != NULL? symbol :
1522                      " no symbol ");                      " no symbol ");
1523    
1524                  if (bits32)                  if (bits32)
1525                          debug("cpu%i:  hi = %08x  lo = %08x\n",                          debug("cpu%i:  hi = %08"PRIx32"  lo = %08"PRIx32"\n",
1526                              cpu->cpu_id, (int)cpu->cd.mips.hi, (int)cpu->cd.mips.lo);                              cpu->cpu_id, (uint32_t) cpu->cd.mips.hi,
1527                  else                              (uint32_t) cpu->cd.mips.lo);
1528                          debug("cpu%i:    hi = 0x%016llx    lo = 0x%016llx\n",                  else if (bits128) {
1529                              cpu->cpu_id, (long long)cpu->cd.mips.hi,                          debug("cpu%i:  hi=%016"PRIx64"%016"PRIx64"  lo="
1530                              (long long)cpu->cd.mips.lo);                              "%016"PRIx64"%016"PRIx64"\n", cpu->cpu_id,
1531                                cpu->cd.mips.hi1, cpu->cd.mips.hi,
1532                                cpu->cd.mips.lo1, cpu->cd.mips.lo);
1533                    } else {
1534                            debug("cpu%i:    hi = 0x%016"PRIx64"    lo = 0x%016"
1535                                PRIx64"\n", cpu->cpu_id,
1536                                (uint64_t) cpu->cd.mips.hi,
1537                                (uint64_t) cpu->cd.mips.lo);
1538                    }
1539    
1540                  /*  General registers:  */                  /*  General registers:  */
1541                  if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) {                  if (bits128) {
1542                          /*  128-bit:  */                          /*  128-bit:  */
1543                          for (i=0; i<32; i++) {                          for (i=0; i<32; i++) {
1544                                    int r = (i >> 1) + ((i & 1) << 4);
1545                                  if ((i & 1) == 0)                                  if ((i & 1) == 0)
1546                                          debug("cpu%i:", cpu->cpu_id);                                          debug("cpu%i:", cpu->cpu_id);
1547                                  debug(" %3s=%016llx%016llx",                                  if (r == MIPS_GPR_ZERO)
1548                                      regname(cpu->machine, i),                                          debug("                           "
1549                                      (long long)cpu->cd.mips.gpr_quadhi[i],                                              "          ");
1550                                      (long long)cpu->cd.mips.gpr[i]);                                  else
1551                                            debug(" %3s=%016"PRIx64"%016"PRIx64,
1552                                                regnames[r], (uint64_t)
1553                                                cpu->cd.mips.gpr_quadhi[r],
1554                                                (uint64_t)cpu->cd.mips.gpr[r]);
1555                                  if ((i & 1) == 1)                                  if ((i & 1) == 1)
1556                                          debug("\n");                                          debug("\n");
1557                          }                          }
# Line 1329  void mips_cpu_register_dump(struct cpu * Line 1563  void mips_cpu_register_dump(struct cpu *
1563                                  if (i == MIPS_GPR_ZERO)                                  if (i == MIPS_GPR_ZERO)
1564                                          debug("               ");                                          debug("               ");
1565                                  else                                  else
1566                                          debug(" %3s = %08x", regname(cpu->machine, i), (int)cpu->cd.mips.gpr[i]);                                          debug(" %3s = %08"PRIx32, regnames[i],
1567                                                (uint32_t)cpu->cd.mips.gpr[i]);
1568                                  if ((i & 3) == 3)                                  if ((i & 3) == 3)
1569                                          debug("\n");                                          debug("\n");
1570                          }                          }
# Line 1342  void mips_cpu_register_dump(struct cpu * Line 1577  void mips_cpu_register_dump(struct cpu *
1577                                  if (r == MIPS_GPR_ZERO)                                  if (r == MIPS_GPR_ZERO)
1578                                          debug("                           ");                                          debug("                           ");
1579                                  else                                  else
1580                                          debug("   %3s = 0x%016llx", regname(cpu->machine, r), (long long)cpu->cd.mips.gpr[r]);                                          debug("   %3s = 0x%016"PRIx64,
1581                                                regnames[r],
1582                                                (uint64_t)cpu->cd.mips.gpr[r]);
1583                                  if ((i & 1) == 1)                                  if ((i & 1) == 1)
1584                                          debug("\n");                                          debug("\n");
1585                          }                          }
# Line 1364  void mips_cpu_register_dump(struct cpu * Line 1601  void mips_cpu_register_dump(struct cpu *
1601                  }                  }
1602    
1603                  /*  Coprocessor registers:  */                  /*  Coprocessor registers:  */
                 /*  TODO: multiple selections per register?  */  
1604                  for (i=0; i<32; i++) {                  for (i=0; i<32; i++) {
1605                          /*  32-bit:  */                          /*  32-bit:  */
1606                          if ((i & nm1) == 0)                          if ((i & nm1) == 0)
1607                                  debug("cpu%i:", cpu->cpu_id);                                  debug("cpu%i:", cpu->cpu_id);
1608    
1609                          if (cpu->machine->show_symbolic_register_names &&                          if (coprocnr == 0)
                             coprocnr == 0)  
1610                                  debug(" %8s", cop0_names[i]);                                  debug(" %8s", cop0_names[i]);
1611                          else                          else
1612                                  debug(" c%i,%02i", coprocnr, i);                                  debug(" c%i,%02i", coprocnr, i);
1613    
1614                          if (bits32)                          if (bits32)
1615                                  debug("=%08x", (int)cpu->cd.mips.coproc[coprocnr]->reg[i]);                                  debug("=%08x", (int)cpu->cd.mips.
1616                                        coproc[coprocnr]->reg[i]);
1617                          else {                          else {
1618                                  if (coprocnr == 0 && (i == COP0_COUNT                                  if (coprocnr == 0 && (i == COP0_COUNT
1619                                      || i == COP0_COMPARE || i == COP0_INDEX                                      || i == COP0_COMPARE || i == COP0_INDEX
1620                                      || i == COP0_RANDOM || i == COP0_WIRED))                                      || i == COP0_RANDOM || i == COP0_WIRED))
1621                                          debug(" =         0x%08x", (int)cpu->cd.mips.coproc[coprocnr]->reg[i]);                                          debug(" =         0x%08x",
1622                                                (int) cpu->cd.mips.coproc[
1623                                                coprocnr]->reg[i]);
1624                                  else                                  else
1625                                          debug(" = 0x%016llx", (long long)                                          debug(" = 0x%016"PRIx64, (uint64_t)
1626                                              cpu->cd.mips.coproc[coprocnr]->reg[i]);                                              cpu->cd.mips.coproc[
1627                                                coprocnr]->reg[i]);
1628                          }                          }
1629    
1630                          if ((i & nm1) == nm1)                          if ((i & nm1) == nm1)
# Line 1401  void mips_cpu_register_dump(struct cpu * Line 1640  void mips_cpu_register_dump(struct cpu *
1640                          debug("cpu%i: ", cpu->cpu_id);                          debug("cpu%i: ", cpu->cpu_id);
1641                          debug("config_select1 = 0x");                          debug("config_select1 = 0x");
1642                          if (cpu->is_32bit)                          if (cpu->is_32bit)
1643                                  debug("%08x", (int)cpu->cd.mips.cop0_config_select1);                                  debug("%08"PRIx32,
1644                                        (uint32_t)cpu->cd.mips.cop0_config_select1);
1645                          else                          else
1646                                  debug("%016llx", (long long)cpu->cd.mips.cop0_config_select1);                                  debug("%016"PRIx64,
1647                                        (uint64_t)cpu->cd.mips.cop0_config_select1);
1648                          debug("\n");                          debug("\n");
1649                  }                  }
1650    
# Line 1411  void mips_cpu_register_dump(struct cpu * Line 1652  void mips_cpu_register_dump(struct cpu *
1652                  if (coprocnr == 1) {                  if (coprocnr == 1) {
1653                          for (i=0; i<32; i++)                          for (i=0; i<32; i++)
1654                                  switch (i) {                                  switch (i) {
1655                                  case 0: printf("cpu%i: fcr0  (fcir) = 0x%08x\n",                                  case MIPS_FPU_FCIR:
1656                                              cpu->cpu_id, (int)cpu->cd.mips.coproc[coprocnr]->fcr[i]);                                          printf("cpu%i: fcr0  (fcir) = 0x%08x\n",
1657                                                cpu->cpu_id, (int)cpu->cd.mips.
1658                                                coproc[coprocnr]->fcr[i]);
1659                                          break;                                          break;
1660                                  case 25:printf("cpu%i: fcr25 (fccr) = 0x%08x\n",                                  case MIPS_FPU_FCCR:
1661                                              cpu->cpu_id, (int)cpu->cd.mips.coproc[coprocnr]->fcr[i]);                                          printf("cpu%i: fcr25 (fccr) = 0x%08x\n",
1662                                                cpu->cpu_id, (int)cpu->cd.mips.
1663                                                coproc[coprocnr]->fcr[i]);
1664                                          break;                                          break;
1665                                  case 31:printf("cpu%i: fcr31 (fcsr) = 0x%08x\n",                                  case MIPS_FPU_FCSR:
1666                                              cpu->cpu_id, (int)cpu->cd.mips.coproc[coprocnr]->fcr[i]);                                          printf("cpu%i: fcr31 (fcsr) = 0x%08x\n",
1667                                                cpu->cpu_id, (int)cpu->cd.mips.
1668                                                coproc[coprocnr]->fcr[i]);
1669                                          break;                                          break;
1670                                  }                                  }
1671                  }                  }
1672          }          }
 }  
1673    
1674            if (cpu->cd.mips.rmw) {
1675  #define DYNTRANS_FUNCTION_TRACE mips_cpu_functioncall_trace                  printf("cpu%i: Read-Modify-Write in progress, address "
1676  #define DYNTRANS_MIPS                      "0x%016"PRIx64"\n", cpu->cpu_id, cpu->cd.mips.rmw_addr);
 #define DYNTRANS_ARCH mips  
 #include "cpu_dyntrans.c"  
 #undef DYNTRANS_MIPS  
 #undef DYNTRANS_ARCH  
 #undef DYNTRANS_FUNCTION_TRACE  
   
   
 /*  
  *  mips_cpu_interrupt():  
  *  
  *  Cause an interrupt. If irq_nr is 2..7, then it is a MIPS hardware  
  *  interrupt. 0 and 1 are ignored (software interrupts).  
  *  
  *  If irq_nr is >= 8, then this function calls md_interrupt().  
  */  
 int mips_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)  
 {  
         if (irq_nr >= 8) {  
                 if (cpu->machine->md_interrupt != NULL)  
                         cpu->machine->md_interrupt(cpu->machine, cpu, irq_nr, 1);  
                 else  
                         fatal("mips_cpu_interrupt(): irq_nr = %i, but md_interrupt = NULL ?\n", irq_nr);  
                 return 1;  
1677          }          }
   
         if (irq_nr < 2)  
                 return 0;  
   
         cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] |= ((1 << irq_nr) << STATUS_IM_SHIFT);  
         cpu->cd.mips.cached_interrupt_is_possible = 1;  
         return 1;  
1678  }  }
1679    
1680    
1681  /*  /*
1682   *  mips_cpu_interrupt_ack():   *  mips_cpu_interrupt_assert(), mips_cpu_interrupt_deassert():
1683   *   *
1684   *  Acknowledge an interrupt. If irq_nr is 2..7, then it is a MIPS hardware   *  Assert or deassert a MIPS CPU interrupt by masking in or out bits
1685   *  interrupt.  Interrupts 0..1 are ignored (software interrupts).   *  in the CAUSE register of coprocessor 0.
  *  
  *  If irq_nr is >= 8, then it is machine dependent, and md_interrupt() is  
  *  called.  
1686   */   */
1687  int mips_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)  void mips_cpu_interrupt_assert(struct interrupt *interrupt)
1688  {  {
1689          if (irq_nr >= 8) {          struct cpu *cpu = interrupt->extra;
1690                  if (cpu->machine->md_interrupt != NULL)          cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] |= interrupt->line;
1691                          cpu->machine->md_interrupt(cpu->machine, cpu, irq_nr, 0);  }
1692                  else  void mips_cpu_interrupt_deassert(struct interrupt *interrupt)
1693                          fatal("mips_cpu_interrupt_ack(): irq_nr = %i, but md_interrupt = NULL ?\n", irq_nr);  {
1694                  return 1;          struct cpu *cpu = interrupt->extra;
1695          }          cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] &= ~interrupt->line;
   
         if (irq_nr < 2)  
                 return 0;  
   
         cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] &= ~((1 << irq_nr) << STATUS_IM_SHIFT);  
         if (!(cpu->cd.mips.coproc[0]->reg[COP0_CAUSE] & STATUS_IM_MASK))  
                 cpu->cd.mips.cached_interrupt_is_possible = 0;  
   
         return 1;  
1696  }  }
1697    
1698    
# Line 1514  void mips_cpu_exception(struct cpu *cpu, Line 1718  void mips_cpu_exception(struct cpu *cpu,
1718          uint64_t *reg = &cpu->cd.mips.coproc[0]->reg[0];          uint64_t *reg = &cpu->cd.mips.coproc[0]->reg[0];
1719          int exc_model = cpu->cd.mips.cpu_type.exc_model;          int exc_model = cpu->cd.mips.cpu_type.exc_model;
1720    
1721            if (cpu->is_halted) {
1722                    /*
1723                     *  If the exception occurred on a 'wait' instruction, then let
1724                     *  the instruction following the wait instruction be the one
1725                     *  we continue at when the interrupt service routine returns.
1726                     */
1727                    cpu->is_halted = 0;
1728                    cpu->pc += sizeof(uint32_t);
1729            }
1730    
1731          if (!quiet_mode) {          if (!quiet_mode) {
1732                  uint64_t offset;                  uint64_t offset;
1733                  int x;                  int x;
1734                  char *symbol = get_symbol_name(&cpu->machine->symbol_context,                  char *symbol = get_symbol_name(&cpu->machine->symbol_context,
1735                      cpu->cd.mips.pc_last, &offset);                      cpu->pc, &offset);
1736    
1737                  debug("[ ");                  debug("[ ");
1738                  if (cpu->machine->ncpus > 1)                  if (cpu->machine->ncpus > 1)
# Line 1528  void mips_cpu_exception(struct cpu *cpu, Line 1742  void mips_cpu_exception(struct cpu *cpu,
1742                      exception_names[exccode], tlb? " <tlb>" : "");                      exception_names[exccode], tlb? " <tlb>" : "");
1743    
1744                  switch (exccode) {                  switch (exccode) {
1745    
1746                  case EXCEPTION_INT:                  case EXCEPTION_INT:
1747                          debug(" cause_im=0x%02x", (int)((reg[COP0_CAUSE] & CAUSE_IP_MASK) >> CAUSE_IP_SHIFT));                          debug(" cause_im=0x%02x", (int)
1748                                ((reg[COP0_CAUSE] & CAUSE_IP_MASK)
1749                                >> CAUSE_IP_SHIFT));
1750                          break;                          break;
1751    
1752                  case EXCEPTION_SYS:                  case EXCEPTION_SYS:
1753                          debug(" v0=%i", (int)cpu->cd.mips.gpr[MIPS_GPR_V0]);                          debug(" v0=%i", (int)cpu->cd.mips.gpr[MIPS_GPR_V0]);
1754                          for (x=0; x<4; x++) {                          for (x=0; x<4; x++) {
1755                                  int64_t d = cpu->cd.mips.gpr[MIPS_GPR_A0 + x];                                  int64_t d = cpu->cd.mips.gpr[MIPS_GPR_A0 + x];
1756                                  char strbuf[30];                                  char strbuf[30];
1757    
1758                                  if (d > -256 && d < 256)                                  if (d > -256 && d < 256) {
1759                                          debug(" a%i=%i", x, (int)d);                                          debug(" a%i=%i", x, (int)d);
1760                                  else if (memory_points_to_string(cpu, cpu->mem, d, 1))                                  } else if (memory_points_to_string(cpu,
1761                                          debug(" a%i=\"%s\"", x, memory_conv_to_string(cpu, cpu->mem, d, strbuf, sizeof(strbuf)));                                      cpu->mem, d, 1)) {
1762                                  else                                          debug(" a%i=\"%s\"", x,
1763                                          debug(" a%i=0x%llx", x, (long long)d);                                              memory_conv_to_string(cpu, cpu->mem,
1764                                                d, strbuf, sizeof(strbuf)));
1765                                    } else {
1766                                            if (cpu->is_32bit)
1767                                                    debug(" a%i=0x%"PRIx32, x,
1768                                                        (uint32_t)d);
1769                                            else
1770                                                    debug(" a%i=0x%"PRIx64, x,
1771                                                        (uint64_t)d);
1772                                    }
1773                          }                          }
1774                          break;                          break;
1775    
1776                    case EXCEPTION_CPU:
1777                            debug(" coproc_nr=%i", coproc_nr);
1778                            break;
1779    
1780                  default:                  default:
1781                          if (cpu->is_32bit)                          if (cpu->is_32bit)
1782                                  debug(" vaddr=0x%08x", (int)vaddr);                                  debug(" vaddr=0x%08x", (int)vaddr);
1783                          else                          else
1784                                  debug(" vaddr=0x%016llx", (long long)vaddr);                                  debug(" vaddr=0x%016"PRIx64, (uint64_t)vaddr);
1785                  }                  }
1786    
1787                  if (cpu->is_32bit)                  if (cpu->is_32bit)
1788                          debug(" pc=0x%08x ", (int)cpu->cd.mips.pc_last);                          debug(" pc=0x%08"PRIx32" ", (uint32_t)cpu->pc);
1789                  else                  else
1790                          debug(" pc=0x%016llx ", (long long)cpu->cd.mips.pc_last);                          debug(" pc=0x%016"PRIx64" ", (uint64_t)cpu->pc);
1791    
1792                  if (symbol != NULL)                  if (symbol != NULL)
1793                          debug("<%s> ]\n", symbol);                          debug("<%s> ]\n", symbol);
# Line 1566  void mips_cpu_exception(struct cpu *cpu, Line 1798  void mips_cpu_exception(struct cpu *cpu,
1798          if (tlb && vaddr < 0x1000) {          if (tlb && vaddr < 0x1000) {
1799                  uint64_t offset;                  uint64_t offset;
1800                  char *symbol = get_symbol_name(&cpu->machine->symbol_context,                  char *symbol = get_symbol_name(&cpu->machine->symbol_context,
1801                      cpu->cd.mips.pc_last, &offset);                      cpu->pc, &offset);
1802                  fatal("[ ");                  fatal("[ ");
1803                  if (cpu->machine->ncpus > 1)                  if (cpu->machine->ncpus > 1)
1804                          fatal("cpu%i: ", cpu->cpu_id);                          fatal("cpu%i: ", cpu->cpu_id);
1805                  fatal("warning: LOW reference: vaddr=");                  fatal("warning: LOW reference: vaddr=");
1806                  if (cpu->is_32bit)                  if (cpu->is_32bit)
1807                          fatal("0x%08x", (int)vaddr);                          fatal("0x%08"PRIx32, (uint32_t) vaddr);
1808                  else                  else
1809                          fatal("0x%016llx", (long long)vaddr);                          fatal("0x%016"PRIx64, (uint64_t) vaddr);
1810                  fatal(", exception %s, pc=", exception_names[exccode]);                  fatal(", exception %s, pc=", exception_names[exccode]);
1811                  if (cpu->is_32bit)                  if (cpu->is_32bit)
1812                          fatal("0x%08x", (int)cpu->cd.mips.pc_last);                          fatal("0x%08"PRIx32, (uint32_t) cpu->pc);
1813                  else                  else
1814                          fatal("0x%016llx", (long long)cpu->cd.mips.pc_last);                          fatal("0x%016"PRIx64, (uint64_t)cpu->pc);
1815                  fatal(" <%s> ]\n", symbol? symbol : "(no symbol)");                  fatal(" <%s> ]\n", symbol? symbol : "(no symbol)");
   
 #ifdef TRACE_NULL_CRASHES  
                 /*  This can be useful for debugging kernel bugs:  */  
                 {  
                         int i = cpu->trace_null_index;  
                         do {  
                                 fatal("TRACE: 0x%016llx\n",  
                                     cpu->trace_null_addr[i]);  
                                 i ++;  
                                 i %= TRACE_NULL_N_ENTRIES;  
                         } while (i != cpu->trace_null_index);  
                 }  
                 cpu->running = 0;  
                 cpu->dead = 1;  
 #endif  
1816          }          }
1817    
1818          /*  Clear the exception code bits of the cause register...  */          /*  Clear the exception code bits of the cause register...  */
# Line 1614  void mips_cpu_exception(struct cpu *cpu, Line 1831  void mips_cpu_exception(struct cpu *cpu,
1831          if (tlb || (exccode >= EXCEPTION_MOD && exccode <= EXCEPTION_ADES) ||          if (tlb || (exccode >= EXCEPTION_MOD && exccode <= EXCEPTION_ADES) ||
1832              exccode == EXCEPTION_VCEI || exccode == EXCEPTION_VCED) {              exccode == EXCEPTION_VCEI || exccode == EXCEPTION_VCED) {
1833                  reg[COP0_BADVADDR] = vaddr;                  reg[COP0_BADVADDR] = vaddr;
1834  #if 1                  if (cpu->is_32bit)
1835  /*  TODO: This should be removed.  */                          reg[COP0_BADVADDR] = (int32_t)reg[COP0_BADVADDR];
1836                  /*  sign-extend vaddr, if it is 32-bit  */  
                 if ((vaddr >> 32) == 0 && (vaddr & 0x80000000ULL))  
                         reg[COP0_BADVADDR] |=  
                             0xffffffff00000000ULL;  
 #endif  
1837                  if (exc_model == EXC3K) {                  if (exc_model == EXC3K) {
1838                          reg[COP0_CONTEXT] &= ~R2K3K_CONTEXT_BADVPN_MASK;                          reg[COP0_CONTEXT] &= ~R2K3K_CONTEXT_BADVPN_MASK;
1839                          reg[COP0_CONTEXT] |= ((vaddr_vpn2 << R2K3K_CONTEXT_BADVPN_SHIFT) & R2K3K_CONTEXT_BADVPN_MASK);                          reg[COP0_CONTEXT] |= ((vaddr_vpn2 <<
1840                                R2K3K_CONTEXT_BADVPN_SHIFT) &
1841                                R2K3K_CONTEXT_BADVPN_MASK);
1842    
1843                          reg[COP0_ENTRYHI] = (vaddr & R2K3K_ENTRYHI_VPN_MASK)                          reg[COP0_ENTRYHI] = (vaddr & R2K3K_ENTRYHI_VPN_MASK)
1844                              | (vaddr_asid << R2K3K_ENTRYHI_ASID_SHIFT);                              | (vaddr_asid << R2K3K_ENTRYHI_ASID_SHIFT);
# Line 1633  void mips_cpu_exception(struct cpu *cpu, Line 1848  void mips_cpu_exception(struct cpu *cpu,
1848                          reg[COP0_ENTRYHI] = (int64_t)(int32_t)reg[COP0_ENTRYHI];                          reg[COP0_ENTRYHI] = (int64_t)(int32_t)reg[COP0_ENTRYHI];
1849                  } else {                  } else {
1850                          if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {                          if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1851                                  reg[COP0_CONTEXT] &= ~CONTEXT_BADVPN2_MASK_R4100;                                  reg[COP0_CONTEXT] &=
1852                                  reg[COP0_CONTEXT] |= ((vaddr_vpn2 << CONTEXT_BADVPN2_SHIFT) & CONTEXT_BADVPN2_MASK_R4100);                                      ~CONTEXT_BADVPN2_MASK_R4100;
1853                                    reg[COP0_CONTEXT] |= ((vaddr_vpn2 <<
1854                                        CONTEXT_BADVPN2_SHIFT) &
1855                                        CONTEXT_BADVPN2_MASK_R4100);
1856    
1857                                  /*  TODO:  fix these  */                                  /*  TODO:  fix these  */
1858                                  reg[COP0_XCONTEXT] &= ~XCONTEXT_R_MASK;                                  reg[COP0_XCONTEXT] &= ~XCONTEXT_R_MASK;
# Line 1664  void mips_cpu_exception(struct cpu *cpu, Line 1882  void mips_cpu_exception(struct cpu *cpu,
1882                  }                  }
1883          }          }
1884    
1885          if (exc_model == EXC4K && reg[COP0_STATUS] & STATUS_EXL) {          if (exc_model != EXC3K && reg[COP0_STATUS] & STATUS_EXL) {
1886                  /*                  /*
1887                   *  Don't set EPC if STATUS_EXL is set, for R4000 and up.                   *  Don't set EPC if STATUS_EXL is set, for R4000 and up.
1888                   *  This actually happens when running IRIX and Ultrix, when                   *  This actually happens when running IRIX and Ultrix, when
1889                   *  they handle interrupts and/or tlb updates, I think, so                   *  they handle interrupts and/or tlb updates, I think, so
1890                   *  printing this with debug() looks better than with fatal().                   *  printing this with debug() looks better than with fatal().
1891                   */                   */
1892                  /*  debug("[ warning: cpu%i exception while EXL is set, not setting EPC ]\n", cpu->cpu_id);  */                  /*  debug("[ warning: cpu%i exception while EXL is set,"
1893                        " not setting EPC ]\n", cpu->cpu_id);  */
1894          } else {          } else {
1895                  if (cpu->cd.mips.delay_slot || cpu->cd.mips.nullify_next) {                  if (cpu->delay_slot) {
1896                          reg[COP0_EPC] = cpu->cd.mips.pc_last - 4;                          reg[COP0_EPC] = cpu->pc - 4;
1897                          reg[COP0_CAUSE] |= CAUSE_BD;                          reg[COP0_CAUSE] |= CAUSE_BD;
   
                         /*  TODO: Should the BD flag actually be set  
                             on nullified slots?  */  
1898                  } else {                  } else {
1899                          reg[COP0_EPC] = cpu->cd.mips.pc_last;                          reg[COP0_EPC] = cpu->pc;
1900                          reg[COP0_CAUSE] &= ~CAUSE_BD;                          reg[COP0_CAUSE] &= ~CAUSE_BD;
1901                  }                  }
1902          }          }
1903    
1904          cpu->cd.mips.delay_slot = NOT_DELAYED;          if (cpu->delay_slot)
1905          cpu->cd.mips.nullify_next = 0;                  cpu->delay_slot = EXCEPTION_IN_DELAY_SLOT;
1906            else
1907                    cpu->delay_slot = NOT_DELAYED;
1908    
1909          /*  TODO: This is true for MIPS64, but how about others?  */          /*  TODO: This is true for MIPS64, but how about others?  */
1910          if (reg[COP0_STATUS] & STATUS_BEV)          if (reg[COP0_STATUS] & STATUS_BEV)
# Line 1731  void mips_cpu_exception(struct cpu *cpu, Line 1949  void mips_cpu_exception(struct cpu *cpu,
1949          }          }
1950    
1951          if (exc_model == EXC3K) {          if (exc_model == EXC3K) {
1952                  /*  R2000/R3000:  Shift the lowest 6 bits to the left two steps:  */                  /*  R{2,3}000:  Shift the lowest 6 bits to the left two steps:*/
1953                  reg[COP0_STATUS] =                  reg[COP0_STATUS] = (reg[COP0_STATUS] & ~0x3f) +
                     (reg[COP0_STATUS] & ~0x3f) +  
1954                      ((reg[COP0_STATUS] & 0xf) << 2);                      ((reg[COP0_STATUS] & 0xf) << 2);
1955          } else {          } else {
1956                  /*  R4000:  */                  /*  R4000:  */
# Line 1743  void mips_cpu_exception(struct cpu *cpu, Line 1960  void mips_cpu_exception(struct cpu *cpu,
1960          /*  Sign-extend:  */          /*  Sign-extend:  */
1961          reg[COP0_CAUSE] = (int64_t)(int32_t)reg[COP0_CAUSE];          reg[COP0_CAUSE] = (int64_t)(int32_t)reg[COP0_CAUSE];
1962          reg[COP0_STATUS] = (int64_t)(int32_t)reg[COP0_STATUS];          reg[COP0_STATUS] = (int64_t)(int32_t)reg[COP0_STATUS];
 }  
   
   
 #ifdef BINTRANS  
 /*  
  *  mips_cpu_cause_simple_exception():  
  *  
  *  Useful for causing raw exceptions from bintrans, for example  
  *  SYSCALL or BREAK.  
  */  
 void mips_cpu_cause_simple_exception(struct cpu *cpu, int exc_code)  
 {  
         mips_cpu_exception(cpu, exc_code, 0, 0, 0, 0, 0, 0);  
 }  
 #endif  
   
   
 /*  Included here for better cache characteristics:  */  
 #include "memory_mips.c"  
   
   
 /*  
  *  mips_cpu_run_instr():  
  *  
  *  Execute one instruction on a cpu.  
  *  
  *  If we are in a delay slot, set cpu->pc to cpu->cd.mips.delay_jmpaddr  
  *  after the instruction is executed.  
  *  
  *  Return value is the number of instructions executed during this call,  
  *  0 if no instruction was executed.  
  */  
 int mips_cpu_run_instr(struct emul *emul, struct cpu *cpu)  
 {  
         int quiet_mode_cached = quiet_mode;  
         int instruction_trace_cached = cpu->machine->instruction_trace;  
         struct mips_coproc *cp0 = cpu->cd.mips.coproc[0];  
         int i, tmp, ninstrs_executed;  
         unsigned char instr[4];  
         uint32_t instrword;  
         uint64_t cached_pc;  
         int hi6, special6, regimm5, rd, rs, rt, sa, imm;  
         int copz, which_cache, cache_op;  
   
         int cond, likely, and_link;  
   
         /*  for unaligned load/store  */  
         uint64_t dir, is_left, reg_ofs, reg_dir;  
   
         uint64_t tmpvalue, tmpaddr;  
   
         int cpnr;                       /*  coprocessor nr  */  
   
         /*  for load/store  */  
         uint64_t addr, value, value_hi, result_value;  
         int wlen, st, signd, linked;  
         unsigned char d[16];            /*  room for at most 128 bits  */  
   
   
         /*  
          *  Update Coprocessor 0 registers:  
          *  
          *  The COUNT register needs to be updated on every [other] instruction.  
          *  The RANDOM register should decrease for every instruction.  
          */  
   
         if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {  
                 int r = (cp0->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK) >> R2K3K_RANDOM_SHIFT;  
                 r --;  
                 if (r >= cp0->nr_of_tlbs || r < 8)  
                         r = cp0->nr_of_tlbs-1;  
                 cp0->reg[COP0_RANDOM] = r << R2K3K_RANDOM_SHIFT;  
         } else {  
                 cp0->reg[COP0_RANDOM] --;  
                 if ((int64_t)cp0->reg[COP0_RANDOM] >= cp0->nr_of_tlbs ||  
                     (int64_t)cp0->reg[COP0_RANDOM] < (int64_t) cp0->reg[COP0_WIRED])  
                         cp0->reg[COP0_RANDOM] = cp0->nr_of_tlbs-1;  
   
                 /*  
                  *  TODO: only increase count every other instruction,  
                  *  according to the R4000 manual. But according to the  
                  *  R5000 manual: increment every other clock cycle.  
                  *  Which one is it? :-)  
                  */  
                 cp0->reg[COP0_COUNT] = (int64_t)(int32_t)(cp0->reg[COP0_COUNT] + 1);  
   
                 if (cpu->cd.mips.compare_register_set &&  
                     cp0->reg[COP0_COUNT] == cp0->reg[COP0_COMPARE]) {  
                         mips_cpu_interrupt(cpu, 7);  
                         cpu->cd.mips.compare_register_set = 0;  
                 }  
         }  
   
   
 #ifdef ENABLE_INSTRUCTION_DELAYS  
         if (cpu->cd.mips.instruction_delay > 0) {  
                 cpu->cd.mips.instruction_delay --;  
                 return 1;  
         }  
 #endif  
   
         /*  Cache the program counter in a local variable:  */  
         cached_pc = cpu->pc;  
   
 #ifdef TRACE_NULL_CRASHES  
         cpu->trace_null_addr[cpu->trace_null_index] = cached_pc;  
         cpu->trace_null_index ++;  
         cpu->trace_null_index %= TRACE_NULL_N_ENTRIES;  
 #endif  
   
         /*  Hardwire the zero register to 0:  */  
         cpu->cd.mips.gpr[MIPS_GPR_ZERO] = 0;  
   
         if (cpu->cd.mips.delay_slot) {  
                 if (cpu->cd.mips.delay_slot == DELAYED) {  
                         cached_pc = cpu->pc = cpu->cd.mips.delay_jmpaddr;  
                         cpu->cd.mips.delay_slot = NOT_DELAYED;  
                 } else /* if (cpu->cd.mips.delay_slot == TO_BE_DELAYED) */ {  
                         /*  next instruction will be delayed  */  
                         cpu->cd.mips.delay_slot = DELAYED;  
                 }  
         }  
   
         if (cpu->cd.mips.last_was_jumptoself > 0)  
                 cpu->cd.mips.last_was_jumptoself --;  
   
         /*  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->is_32bit)  
                                         fatal("%08x", (int)cached_pc);  
                                 else  
                                         fatal("%016llx", (long long)cached_pc);  
                                 fatal("\n");  
                                 single_step = 1;  
                                 return 0;  
                         }  
   
   
         /*  Remember where we are, in case of interrupt or exception:  */  
         cpu->cd.mips.pc_last = cached_pc;  
   
         /*  
          *  Any pending interrupts?  
          *  
          *  If interrupts are enabled, and any interrupt has arrived (ie its  
          *  bit in the cause register is set) and corresponding enable bits  
          *  in the status register are set, then cause an interrupt exception  
          *  instead of executing the current instruction.  
          *  
          *  NOTE: cached_interrupt_is_possible is set to 1 whenever an  
          *  interrupt bit in the cause register is set to one (in  
          *  mips_cpu_interrupt()) and set to 0 whenever all interrupt bits are  
          *  cleared (in mips_cpu_interrupt_ack()), so we don't need to do a  
          *  full check each time.  
          */  
         if (cpu->cd.mips.cached_interrupt_is_possible && !cpu->cd.mips.nullify_next) {  
                 if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {  
                         /*  R3000:  */  
                         int enabled, mask;  
                         int status = cp0->reg[COP0_STATUS];  
   
                         enabled = status & MIPS_SR_INT_IE;  
                         mask  = status & cp0->reg[COP0_CAUSE] & STATUS_IM_MASK;  
                         if (enabled && mask) {  
                                 mips_cpu_exception(cpu, EXCEPTION_INT, 0, 0, 0, 0, 0, 0);  
                                 return 0;  
                         }  
                 } else {  
                         /*  R4000 and others:  */  
                         int enabled, mask;  
                         int status = cp0->reg[COP0_STATUS];  
   
                         enabled = (status & STATUS_IE)  
                             && !(status & STATUS_EXL)  
                             && !(status & STATUS_ERL);  
   
                         mask = status & cp0->reg[COP0_CAUSE] & STATUS_IM_MASK;  
                         if (enabled && mask) {  
                                 mips_cpu_exception(cpu, EXCEPTION_INT, 0, 0, 0, 0, 0, 0);  
                                 return 0;  
                         }  
                 }  
         }  
   
   
         /*  
          *  ROM emulation:  (0xbfcXXXXX or 0x9fcXXXXX)  
          *  
          *  This assumes that a jal was made to a ROM address,  
          *  and we should return via gpr ra.  
          */  
         if ((cached_pc & 0xdff00000) == 0x9fc00000 &&  
             cpu->machine->prom_emulation) {  
                 int rom_jal = 1, res = 1;  
                 switch (cpu->machine->machine_type) {  
                 case MACHINE_DEC:  
                         res = decstation_prom_emul(cpu);  
                         break;  
                 case MACHINE_PS2:  
                         res = playstation2_sifbios_emul(cpu);  
                         break;  
                 case MACHINE_ARC:  
                 case MACHINE_SGI:  
                         res = arcbios_emul(cpu);  
                         break;  
                 case MACHINE_EVBMIPS:  
                         res = yamon_emul(cpu);  
                         break;  
                 default:  
                         rom_jal = 0;  
                 }  
   
                 if (rom_jal) {  
                         /*  
                          *  Special hack:  If the PROM emulation layer needs  
                          *  to loop (for example when emulating blocking  
                          *  console input) then we should simply return, so  
                          *  that the same PROM routine is called on the next  
                          *  round as well.  
                          *  
                          *  This still has to count as one or more  
                          *  instructions, so 1000 is returned. (Ugly.)  
                          */  
                         if (!res)  
                                 return 1000;  
   
                         cpu->pc = cpu->cd.mips.gpr[MIPS_GPR_RA];  
                         /*  no need to update cached_pc, as we're returning  */  
                         cpu->cd.mips.delay_slot = NOT_DELAYED;  
   
                         if (cpu->machine->show_trace_tree)  
                                 cpu_functioncall_trace_return(cpu);  
   
                         /*  TODO: how many instrs should this count as?  */  
                         return 10;  
                 }  
         }  
1963    
 #ifdef ALWAYS_SIGNEXTEND_32  
         /*  
          *  An extra check for 32-bit mode to make sure that all  
          *  registers are sign-extended:   (Slow, but might be useful  
          *  to detect bugs that have to do with sign-extension.)  
          */  
1964          if (cpu->is_32bit) {          if (cpu->is_32bit) {
1965                  int warning = 0;                  reg[COP0_EPC] = (int64_t)(int32_t)reg[COP0_EPC];
1966                  uint64_t x;                  mips32_pc_to_pointers(cpu);
1967            } else {
1968                  if (cpu->cd.mips.gpr[0] != 0) {                  mips_pc_to_pointers(cpu);
                         fatal("\nWARNING: r0 was not zero! (%016llx)\n\n",  
                             (long long)cpu->cd.mips.gpr[0]);  
                         cpu->cd.mips.gpr[0] = 0;  
                         warning = 1;  
                 }  
   
                 if (cpu->pc != (int64_t)(int32_t)cpu->pc) {  
                         fatal("\nWARNING: pc was not sign-extended correctly"  
                             " (%016llx)\n\n", (long long)cpu->pc);  
                         cpu->pc = (int64_t)(int32_t)cpu->pc;  
                         warning = 1;  
                 }  
   
                 if (cpu->cd.mips.pc_last != (int64_t)(int32_t)cpu->cd.mips.pc_last) {  
                         fatal("\nWARNING: pc_last was not sign-extended correc"  
                             "tly (%016llx)\n\n", (long long)cpu->cd.mips.pc_last);  
                         cpu->cd.mips.pc_last = (int64_t)(int32_t)cpu->cd.mips.pc_last;  
                         warning = 1;  
                 }  
   
                 /*  Sign-extend ALL registers, including coprocessor registers and tlbs:  */  
                 for (i=1; i<32; i++) {  
                         x = cpu->cd.mips.gpr[i];  
                         cpu->cd.mips.gpr[i] &= 0xffffffff;  
                         if (cpu->cd.mips.gpr[i] & 0x80000000ULL)  
                                 cpu->cd.mips.gpr[i] |= 0xffffffff00000000ULL;  
                         if (x != cpu->cd.mips.gpr[i]) {  
                                 fatal("\nWARNING: r%i (%s) was not sign-"  
                                     "extended correctly (%016llx != "  
                                     "%016llx)\n\n", i, regname(cpu->machine, i),  
                                     (long long)x, (long long)cpu->cd.mips.gpr[i]);  
                                 warning = 1;  
                         }  
                 }  
                 for (i=0; i<32; i++) {  
                         x = cpu->cd.mips.coproc[0]->reg[i];  
                         cpu->cd.mips.coproc[0]->reg[i] &= 0xffffffffULL;  
                         if (cpu->cd.mips.coproc[0]->reg[i] & 0x80000000ULL)  
                                 cpu->cd.mips.coproc[0]->reg[i] |=  
                                     0xffffffff00000000ULL;  
                         if (x != cpu->cd.mips.coproc[0]->reg[i]) {  
                                 fatal("\nWARNING: cop0,r%i was not sign-extended correctly (%016llx != %016llx)\n\n",  
                                     i, (long long)x, (long long)cpu->cd.mips.coproc[0]->reg[i]);  
                                 warning = 1;  
                         }  
                 }  
                 for (i=0; i<cpu->cd.mips.coproc[0]->nr_of_tlbs; i++) {  
                         x = cpu->cd.mips.coproc[0]->tlbs[i].hi;  
                         cpu->cd.mips.coproc[0]->tlbs[i].hi &= 0xffffffffULL;  
                         if (cpu->cd.mips.coproc[0]->tlbs[i].hi & 0x80000000ULL)  
                                 cpu->cd.mips.coproc[0]->tlbs[i].hi |=  
                                     0xffffffff00000000ULL;  
                         if (x != cpu->cd.mips.coproc[0]->tlbs[i].hi) {  
                                 fatal("\nWARNING: tlb[%i].hi was not sign-extended correctly (%016llx != %016llx)\n\n",  
                                     i, (long long)x, (long long)cpu->cd.mips.coproc[0]->tlbs[i].hi);  
                                 warning = 1;  
                         }  
   
                         x = cpu->cd.mips.coproc[0]->tlbs[i].lo0;  
                         cpu->cd.mips.coproc[0]->tlbs[i].lo0 &= 0xffffffffULL;  
                         if (cpu->cd.mips.coproc[0]->tlbs[i].lo0 & 0x80000000ULL)  
                                 cpu->cd.mips.coproc[0]->tlbs[i].lo0 |=  
                                     0xffffffff00000000ULL;  
                         if (x != cpu->cd.mips.coproc[0]->tlbs[i].lo0) {  
                                 fatal("\nWARNING: tlb[%i].lo0 was not sign-extended correctly (%016llx != %016llx)\n\n",  
                                     i, (long long)x, (long long)cpu->cd.mips.coproc[0]->tlbs[i].lo0);  
                                 warning = 1;  
                         }  
                 }  
   
                 if (warning) {  
                         fatal("Halting. pc = %016llx\n", (long long)cpu->pc);  
                         cpu->running = 0;  
                 }  
         }  
 #endif  
   
         PREFETCH(cpu->cd.mips.pc_last_host_4k_page + (cached_pc & 0xfff));  
   
 #ifdef HALT_IF_PC_ZERO  
         /*  Halt if PC = 0:  */  
         if (cached_pc == 0) {  
                 debug("cpu%i: pc=0, halting\n", cpu->cpu_id);  
                 cpu->running = 0;  
                 return 0;  
         }  
 #endif  
   
 #ifdef BINTRANS  
         if ((single_step || instruction_trace_cached)  
             && cpu->machine->bintrans_enable)  
                 cpu->cd.mips.dont_run_next_bintrans = 1;  
 #endif  
   
         if (!quiet_mode_cached) {  
                 /*  Dump CPU registers for debugging:  */  
                 if (cpu->machine->register_dump) {  
                         debug("\n");  
                         mips_cpu_register_dump(cpu, 1, 0x1);  
                 }  
         }  
   
         /*  Trace tree:  */  
         if (cpu->machine->show_trace_tree && cpu->cd.mips.show_trace_delay > 0) {  
                 cpu->cd.mips.show_trace_delay --;  
                 if (cpu->cd.mips.show_trace_delay == 0)  
                         cpu_functioncall_trace(cpu, cpu->cd.mips.show_trace_addr);  
         }  
   
 #ifdef MFHILO_DELAY  
         /*  Decrease the MFHI/MFLO delays:  */  
         if (cpu->mfhi_delay > 0)  
                 cpu->mfhi_delay--;  
         if (cpu->mflo_delay > 0)  
                 cpu->mflo_delay--;  
 #endif  
   
         /*  Read an instruction from memory:  */  
 #ifdef ENABLE_MIPS16  
         if (cpu->cd.mips.mips16 && (cached_pc & 1)) {  
                 /*  16-bit instruction word:  */  
                 unsigned char instr16[2];  
                 int mips16_offset = 0;  
   
                 if (!cpu->memory_rw(cpu, cpu->mem, cached_pc ^ 1, &instr16[0],  
                     sizeof(instr16), MEM_READ, CACHE_INSTRUCTION))  
                         return 0;  
   
                 /*  TODO:  If Reverse-endian is set in the status cop0 register, and  
                         we are in usermode, then reverse endianness!  */  
   
                 /*  The rest of the code is written for little endian, so swap if necessary:  */  
                 if (cpu->byte_order == EMUL_BIG_ENDIAN) {  
                         int tmp;  
                         tmp  = instr16[0]; instr16[0] = instr16[1]; instr16[1] = tmp;  
                 }  
   
                 cpu->cd.mips.mips16_extend = 0;  
   
                 /*  
                  *  Translate into 32-bit instruction, little endian (instr[3..0]):  
                  *  
                  *  This ugly loop is necessary because if we would get an exception between  
                  *  reading an extend instruction and the next instruction, and execution  
                  *  continues on the second instruction, the extend data would be lost. So the  
                  *  entire instruction (the two parts) need to be read in. If an exception is  
                  *  caused, it will appear as if it was caused when reading the extend instruction.  
                  */  
                 while (mips16_to_32(cpu, instr16, instr) == 0) {  
                         if (instruction_trace_cached)  
                                 debug("cpu%i @ %016llx: %02x%02x\t\t\textend\n",  
                                     cpu->cpu_id, (cpu->cd.mips.pc_last ^ 1) + mips16_offset,  
                                     instr16[1], instr16[0]);  
   
                         /*  instruction with extend:  */  
                         mips16_offset += 2;  
                         if (!cpu->memory_rw(cpu, cpu->mem, (cached_pc ^ 1) +  
                             mips16_offset, &instr16[0], sizeof(instr16),  
                             MEM_READ, CACHE_INSTRUCTION))  
                                 return 0;  
   
                         if (cpu->byte_order == EMUL_BIG_ENDIAN) {  
                                 int tmp;  
                                 tmp  = instr16[0]; instr16[0] = instr16[1]; instr16[1] = tmp;  
                         }  
                 }  
   
                 /*  TODO: bintrans like in 32-bit mode?  */  
   
                 /*  Advance the program counter:  */  
                 cpu->pc += sizeof(instr16) + mips16_offset;  
                 cached_pc = cpu->pc;  
   
                 if (instruction_trace_cached) {  
                         uint64_t offset;  
                         char *symbol = get_symbol_name(&cpu->machine->  
                             symbol_context, cpu->cd.mips.pc_last ^ 1, &offset);  
                         if (symbol != NULL && offset==0)  
                                 debug("<%s>\n", symbol);  
   
                         debug("cpu%i @ %016llx: %02x%02x => %02x%02x%02x%02x%s\t",  
                             cpu->cpu_id, (cpu->cd.mips.pc_last ^ 1) + mips16_offset,  
                             instr16[1], instr16[0],  
                             instr[3], instr[2], instr[1], instr[0],  
                             cpu_flags(cpu));  
                 }  
         } else  
 #endif  
             {  
                 /*  
                  *  Fetch a 32-bit instruction word from memory:  
                  *  
                  *  1)  The special case of reading an instruction from the  
                  *      same host RAM page as the last one is handled here,  
                  *      to gain a little bit performance.  
                  *  
                  *  2)  Fallback to reading from memory the usual way.  
                  */  
                 if (cached_pc & 3) {  
                         mips_cpu_exception(cpu, EXCEPTION_ADEL,  
                             0, cached_pc, 0, 0, 0, 0);  
                         return 0;  
                 }  
                 if (cpu->cd.mips.pc_last_host_4k_page != NULL &&  
                     (cached_pc & ~0xfff) == cpu->cd.mips.pc_last_virtual_page) {  
                         /*  NOTE: This only works on the host if offset is  
                             aligned correctly!  (TODO)  */  
                         *(uint32_t *)instr = *(uint32_t *)  
                             (cpu->cd.mips.pc_last_host_4k_page + (cached_pc & 0xffc));  
 #ifdef BINTRANS  
                         cpu->cd.mips.pc_bintrans_paddr_valid = 1;  
                         cpu->cd.mips.pc_bintrans_paddr =  
                             cpu->cd.mips.pc_last_physical_page | (cached_pc & 0xfff);  
                         cpu->cd.mips.pc_bintrans_host_4kpage = cpu->cd.mips.pc_last_host_4k_page;  
 #endif  
                 } else {  
                         if (!cpu->memory_rw(cpu, cpu->mem, cached_pc, &instr[0],  
                             sizeof(instr), MEM_READ, CACHE_INSTRUCTION))  
                                 return 0;  
                 }  
   
 #ifdef BINTRANS  
                 if (cpu->cd.mips.dont_run_next_bintrans) {  
                         cpu->cd.mips.dont_run_next_bintrans = 0;  
                 } else if (cpu->machine->bintrans_enable &&  
                     cpu->cd.mips.pc_bintrans_paddr_valid) {  
                         int res;  
                         cpu->cd.mips.bintrans_instructions_executed = 0;  
   
                         res = bintrans_attempt_translate(cpu,  
                             cpu->cd.mips.pc_bintrans_paddr);  
   
                         if (res >= 0) {  
                                 /*  debug("BINTRANS translation + hit,"  
                                     " pc = %016llx\n", (long long)cached_pc);  */  
                                 if (res > 0 || cpu->pc != cached_pc) {  
                                         if (instruction_trace_cached)  
                                                 mips_cpu_disassemble_instr(cpu, instr, 1, 0, 1);  
                                         if (res & BINTRANS_DONT_RUN_NEXT)  
                                                 cpu->cd.mips.dont_run_next_bintrans = 1;  
                                         res &= BINTRANS_N_MASK;  
   
                                         if (cpu->cd.mips.cpu_type.exc_model != EXC3K) {  
                                                 int x = cp0->reg[COP0_COUNT], y = cp0->reg[COP0_COMPARE];  
                                                 int diff = x - y;  
                                                 if (diff < 0 && diff + (res-1) >= 0  
                                                     && cpu->cd.mips.compare_register_set) {  
                                                         mips_cpu_interrupt(cpu, 7);  
                                                         cpu->cd.mips.compare_register_set = 0;  
                                                 }  
   
                                                 cp0->reg[COP0_COUNT] = (int64_t)  
                                                     (int32_t)(cp0->reg[COP0_COUNT] + res-1);  
                                         }  
   
                                         return res;  
                                 }  
                         }  
                 }  
 #endif  
   
                 if (instruction_trace_cached)  
                         mips_cpu_disassemble_instr(cpu, instr, 1, 0, 0);  
   
                 /*  Advance the program counter:  */  
                 cpu->pc += sizeof(instr);  
                 cached_pc = cpu->pc;  
   
                 /*  
                  *  TODO:  If Reverse-endian is set in the status cop0 register  
                  *  and we are in usermode, then reverse endianness!  
                  */  
   
                 /*  
                  *  The rest of the code is written for little endian, so  
                  *  swap if necessary:  
                  */  
                 if (cpu->byte_order == EMUL_BIG_ENDIAN) {  
                         int tmp = instr[0]; instr[0] = instr[3]; instr[3] = tmp;  
                             tmp = instr[1]; instr[1] = instr[2]; instr[2] = tmp;  
                 }  
         }  
   
   
         /*  
          *  Nullify this instruction?  (Set by a previous branch-likely  
          *  instruction.)  
          *  
          *  Note: The return value is 1, even if no instruction was actually  
          *  executed.  
          */  
         if (cpu->cd.mips.nullify_next) {  
                 cpu->cd.mips.nullify_next = 0;  
                 return 1;  
         }  
   
   
         /*  
          *  Execute the instruction:  
          */  
   
         /*  Get the top 6 bits of the instruction:  */  
         hi6 = instr[3] >> 2;    /*  & 0x3f  */  
   
         if (show_opcode_statistics)  
                 cpu->cd.mips.stats_opcode[hi6] ++;  
   
         switch (hi6) {  
         case HI6_SPECIAL:  
                 special6 = instr[0] & 0x3f;  
   
                 if (show_opcode_statistics)  
                         cpu->cd.mips.stats__special[special6] ++;  
   
                 switch (special6) {  
                 case SPECIAL_SLL:  
                 case SPECIAL_SRL:  
                 case SPECIAL_SRA:  
                 case SPECIAL_DSLL:  
                 case SPECIAL_DSRL:  
                 case SPECIAL_DSRA:  
                 case SPECIAL_DSLL32:  
                 case SPECIAL_DSRL32:  
                 case SPECIAL_DSRA32:  
                         rt = instr[2] & 31;  
                         rd = (instr[1] >> 3) & 31;  
                         sa = ((instr[1] & 7) << 2) + ((instr[0] >> 6) & 3);  
   
                         /*  
                          *  Check for NOP:  
                          *  
                          *  The R4000 manual says that a shift amount of zero  
                          *  is treated as a nop by some assemblers. Checking  
                          *  for sa == 0 here would not be correct, though,  
                          *  because instructions such as sll r3,r4,0 are  
                          *  possible, and are definitely not a nop.  
                          *  Instead, check if the destination register is r0.  
                          *  
                          *  TODO:  ssnop should wait until the _next_  
                          *  cycle boundary, or something like that. The  
                          *  code here is incorrect.  
                          */  
                         if (rd == 0 && special6 == SPECIAL_SLL) {  
                                 if (sa == 1) {  
                                         /*  ssnop  */  
 #ifdef ENABLE_INSTRUCTION_DELAYS  
                                         cpu->cd.mips.instruction_delay +=  
                                             cpu->cd.mips.cpu_type.  
                                             instrs_per_cycle - 1;  
 #endif  
                                 }  
                                 return 1;  
                         }  
   
                         if (special6 == SPECIAL_SLL) {  
                                 switch (sa) {  
                                 case 8: cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt] << 8; break;  
                                 case 16:cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt] << 16; break;  
                                 default:cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt] << sa;  
                                 }  
                                 /*  Sign-extend rd:  */  
                                 cpu->cd.mips.gpr[rd] = (int64_t) (int32_t) cpu->cd.mips.gpr[rd];  
                         }  
                         if (special6 == SPECIAL_DSLL) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt] << sa;  
                         }  
                         if (special6 == SPECIAL_DSRL) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt] >> sa;  
                         }  
                         if (special6 == SPECIAL_DSLL32) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt] << (sa + 32);  
                         }  
                         if (special6 == SPECIAL_SRL) {  
                                 /*  
                                  *  Three cases:  
                                  *      shift amount = zero:  just copy  
                                  *      high bit of rt zero:  plain shift right (of all bits)  
                                  *      high bit of rt one:   plain shift right (of lowest 32 bits)  
                                  */  
                                 if (sa == 0)  
                                         cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt];  
                                 else if (!(cpu->cd.mips.gpr[rt] & 0x80000000ULL)) {  
                                         cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt] >> sa;  
                                 } else  
                                         cpu->cd.mips.gpr[rd] = (cpu->cd.mips.gpr[rt] & 0xffffffffULL) >> sa;  
                         }  
                         if (special6 == SPECIAL_SRA) {  
                                 int topbit = cpu->cd.mips.gpr[rt] & 0x80000000ULL;  
                                 switch (sa) {  
                                 case 8: cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt] >> 8; break;  
                                 case 16:cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt] >> 16; break;  
                                 default:cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt] >> sa;  
                                 }  
                                 if (topbit)  
                                         cpu->cd.mips.gpr[rd] |= 0xffffffff00000000ULL;  
                         }  
                         if (special6 == SPECIAL_DSRL32) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt] >> (sa + 32);  
                         }  
                         if (special6 == SPECIAL_DSRA32 || special6 == SPECIAL_DSRA) {  
                                 if (special6 == SPECIAL_DSRA32)  
                                         sa += 32;  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt];  
                                 while (sa > 0) {  
                                         cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rd] >> 1;  
                                         sa--;  
                                         if (cpu->cd.mips.gpr[rd] & ((uint64_t)1 << 62))         /*  old signbit  */  
                                                 cpu->cd.mips.gpr[rd] |= ((uint64_t)1 << 63);  
                                 }  
                         }  
                         return 1;  
                 case SPECIAL_DSRLV:  
                 case SPECIAL_DSRAV:  
                 case SPECIAL_DSLLV:  
                 case SPECIAL_SLLV:  
                 case SPECIAL_SRAV:  
                 case SPECIAL_SRLV:  
                         rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);  
                         rt = instr[2] & 31;  
                         rd = (instr[1] >> 3) & 31;  
   
                         if (special6 == SPECIAL_DSRLV) {  
                                 sa = cpu->cd.mips.gpr[rs] & 63;  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt] >> sa;  
                         }  
                         if (special6 == SPECIAL_DSRAV) {  
                                 sa = cpu->cd.mips.gpr[rs] & 63;  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt];  
                                 while (sa > 0) {  
                                         cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rd] >> 1;  
                                         sa--;  
                                         if (cpu->cd.mips.gpr[rd] & ((uint64_t)1 << 62))         /*  old sign-bit  */  
                                                 cpu->cd.mips.gpr[rd] |= ((uint64_t)1 << 63);  
                                 }  
                         }  
                         if (special6 == SPECIAL_DSLLV) {  
                                 sa = cpu->cd.mips.gpr[rs] & 63;  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt];  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rd] << sa;  
                         }  
                         if (special6 == SPECIAL_SLLV) {  
                                 sa = cpu->cd.mips.gpr[rs] & 31;  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt];  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rd] << sa;  
                                 /*  Sign-extend rd:  */  
                                 cpu->cd.mips.gpr[rd] &= 0xffffffffULL;  
                                 if (cpu->cd.mips.gpr[rd] & 0x80000000ULL)  
                                         cpu->cd.mips.gpr[rd] |= 0xffffffff00000000ULL;  
                         }  
                         if (special6 == SPECIAL_SRAV) {  
                                 sa = cpu->cd.mips.gpr[rs] & 31;  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt];  
                                 /*  Sign-extend rd:  */  
                                 cpu->cd.mips.gpr[rd] &= 0xffffffffULL;  
                                 if (cpu->cd.mips.gpr[rd] & 0x80000000ULL)  
                                         cpu->cd.mips.gpr[rd] |= 0xffffffff00000000ULL;  
                                 while (sa > 0) {  
                                         cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rd] >> 1;  
                                         sa--;  
                                 }  
                                 if (cpu->cd.mips.gpr[rd] & 0x80000000ULL)  
                                         cpu->cd.mips.gpr[rd] |= 0xffffffff00000000ULL;  
                         }  
                         if (special6 == SPECIAL_SRLV) {  
                                 sa = cpu->cd.mips.gpr[rs] & 31;  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rt];  
                                 cpu->cd.mips.gpr[rd] &= 0xffffffffULL;  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rd] >> sa;  
                                 /*  And finally sign-extend rd:  */  
                                 if (cpu->cd.mips.gpr[rd] & 0x80000000ULL)  
                                         cpu->cd.mips.gpr[rd] |= 0xffffffff00000000ULL;  
                         }  
                         return 1;  
                 case SPECIAL_JR:  
                         if (cpu->cd.mips.delay_slot) {  
                                 fatal("jr: jump inside a jump's delay slot, or similar. TODO\n");  
                                 cpu->running = 0;  
                                 return 1;  
                         }  
   
                         rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);  
   
                         cpu->cd.mips.delay_slot = TO_BE_DELAYED;  
                         cpu->cd.mips.delay_jmpaddr = cpu->cd.mips.gpr[rs];  
   
                         if (cpu->machine->show_trace_tree && rs == 31)  
                                 cpu_functioncall_trace_return(cpu);  
   
                         return 1;  
                 case SPECIAL_JALR:  
                         if (cpu->cd.mips.delay_slot) {  
                                 fatal("jalr: jump inside a jump's delay slot, or similar. TODO\n");  
                                 cpu->running = 0;  
                                 return 1;  
                         }  
   
                         rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);  
                         rd = (instr[1] >> 3) & 31;  
   
                         tmpvalue = cpu->cd.mips.gpr[rs];  
                         cpu->cd.mips.gpr[rd] = cached_pc + 4;  
                             /*  already increased by 4 earlier  */  
   
                         if (cpu->machine->show_trace_tree && rd == 31) {  
                                 cpu->cd.mips.show_trace_delay = 2;  
                                 cpu->cd.mips.show_trace_addr = tmpvalue;  
                         }  
   
                         cpu->cd.mips.delay_slot = TO_BE_DELAYED;  
                         cpu->cd.mips.delay_jmpaddr = tmpvalue;  
                         return 1;  
                 case SPECIAL_MFHI:  
                 case SPECIAL_MFLO:  
                         rd = (instr[1] >> 3) & 31;  
   
                         if (special6 == SPECIAL_MFHI) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.hi;  
 #ifdef MFHILO_DELAY  
                                 cpu->mfhi_delay = 3;  
 #endif  
                         }  
                         if (special6 == SPECIAL_MFLO) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.lo;  
 #ifdef MFHILO_DELAY  
                                 cpu->mflo_delay = 3;  
 #endif  
                         }  
                         return 1;  
                 case SPECIAL_ADD:  
                 case SPECIAL_ADDU:  
                 case SPECIAL_SUB:  
                 case SPECIAL_SUBU:  
                 case SPECIAL_AND:  
                 case SPECIAL_OR:  
                 case SPECIAL_XOR:  
                 case SPECIAL_NOR:  
                 case SPECIAL_SLT:  
                 case SPECIAL_SLTU:  
                 case SPECIAL_MTLO:  
                 case SPECIAL_MTHI:  
                 case SPECIAL_MULT:  
                 case SPECIAL_MULTU:  
                 case SPECIAL_DMULT:  
                 case SPECIAL_DMULTU:  
                 case SPECIAL_DIV:  
                 case SPECIAL_DIVU:  
                 case SPECIAL_DDIV:  
                 case SPECIAL_DDIVU:  
                 case SPECIAL_TGE:  
                 case SPECIAL_TGEU:  
                 case SPECIAL_TLT:  
                 case SPECIAL_TLTU:  
                 case SPECIAL_TEQ:  
                 case SPECIAL_TNE:  
                 case SPECIAL_DADD:  
                 case SPECIAL_DADDU:  
                 case SPECIAL_DSUB:  
                 case SPECIAL_DSUBU:  
                 case SPECIAL_MOVZ:  
                 case SPECIAL_MOVN:  
                         rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);  
                         rt = instr[2] & 31;  
                         rd = (instr[1] >> 3) & 31;  
   
 #ifdef MFHILO_DELAY  
                         if (cpu->mflo_delay > 0 && (  
                             special6 == SPECIAL_DDIV ||   special6 == SPECIAL_DDIVU ||  
                             special6 == SPECIAL_DIV ||    special6 == SPECIAL_DIVU ||  
                             special6 == SPECIAL_DMULT ||  special6 == SPECIAL_DMULTU ||  
                             special6 == SPECIAL_MTLO ||   special6 == SPECIAL_MULT  
                             || special6 == SPECIAL_MULTU  
                             ) )  
                                 debug("warning: instruction modifying LO too early after mflo!\n");  
   
                         if (cpu->mfhi_delay > 0 && (  
                             special6 == SPECIAL_DDIV ||  special6 == SPECIAL_DDIVU ||  
                             special6 == SPECIAL_DIV ||   special6 == SPECIAL_DIVU ||  
                             special6 == SPECIAL_DMULT || special6 == SPECIAL_DMULTU ||  
                             special6 == SPECIAL_MTHI ||  special6 == SPECIAL_MULT  
                             || special6 == SPECIAL_MULTU  
                             ) )  
                                 debug("warning: instruction modifying HI too early after mfhi!\n");  
 #endif  
   
                         if (special6 == SPECIAL_ADDU) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rs] + cpu->cd.mips.gpr[rt];  
                                 cpu->cd.mips.gpr[rd] &= 0xffffffffULL;  
                                 if (cpu->cd.mips.gpr[rd] & 0x80000000ULL)  
                                         cpu->cd.mips.gpr[rd] |= 0xffffffff00000000ULL;  
                                 break;  
                         }  
                         if (special6 == SPECIAL_ADD) {  
                                 /*  According to the MIPS64 manual:  */  
                                 uint64_t temp, temp1, temp2;  
                                 temp1 = cpu->cd.mips.gpr[rs] + ((cpu->cd.mips.gpr[rs] & 0x80000000ULL) << 1);  
                                 temp2 = cpu->cd.mips.gpr[rt] + ((cpu->cd.mips.gpr[rt] & 0x80000000ULL) << 1);  
                                 temp = temp1 + temp2;  
 #if 0  
         /*  TODO: apparently this doesn't work (an example of  
         something that breaks is NetBSD/sgimips' mips3_TBIA()  */  
                                 /*  If bits 32 and 31 of temp differ, then it's an overflow  */  
                                 temp1 = temp & 0x100000000ULL;  
                                 temp2 = temp & 0x80000000ULL;  
                                 if ((temp1 && !temp2) || (!temp1 && temp2)) {  
                                         mips_cpu_exception(cpu, EXCEPTION_OV, 0, 0, 0, 0, 0, 0);  
                                         break;  
                                 }  
 #endif  
                                 cpu->cd.mips.gpr[rd] = temp & 0xffffffffULL;  
                                 if (cpu->cd.mips.gpr[rd] & 0x80000000ULL)  
                                         cpu->cd.mips.gpr[rd] |= 0xffffffff00000000ULL;  
                                 break;  
                         }  
                         if (special6 == SPECIAL_SUBU) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rs] - cpu->cd.mips.gpr[rt];  
                                 cpu->cd.mips.gpr[rd] &= 0xffffffffULL;  
                                 if (cpu->cd.mips.gpr[rd] & 0x80000000ULL)  
                                         cpu->cd.mips.gpr[rd] |= 0xffffffff00000000ULL;  
                                 break;  
                         }  
                         if (special6 == SPECIAL_SUB) {  
                                 /*  According to the MIPS64 manual:  */  
                                 uint64_t temp, temp1, temp2;  
                                 temp1 = cpu->cd.mips.gpr[rs] + ((cpu->cd.mips.gpr[rs] & 0x80000000ULL) << 1);  
                                 temp2 = cpu->cd.mips.gpr[rt] + ((cpu->cd.mips.gpr[rt] & 0x80000000ULL) << 1);  
                                 temp = temp1 - temp2;  
 #if 0  
                                 /*  If bits 32 and 31 of temp differ, then it's an overflow  */  
                                 temp1 = temp & 0x100000000ULL;  
                                 temp2 = temp & 0x80000000ULL;  
                                 if ((temp1 && !temp2) || (!temp1 && temp2)) {  
                                         mips_cpu_exception(cpu, EXCEPTION_OV, 0, 0, 0, 0, 0, 0);  
                                         break;  
                                 }  
 #endif  
                                 cpu->cd.mips.gpr[rd] = temp & 0xffffffffULL;  
                                 if (cpu->cd.mips.gpr[rd] & 0x80000000ULL)  
                                         cpu->cd.mips.gpr[rd] |= 0xffffffff00000000ULL;  
                                 break;  
                         }  
   
                         if (special6 == SPECIAL_AND) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rs] & cpu->cd.mips.gpr[rt];  
                                 break;  
                         }  
                         if (special6 == SPECIAL_OR) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rs] | cpu->cd.mips.gpr[rt];  
                                 break;  
                         }  
                         if (special6 == SPECIAL_XOR) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rs] ^ cpu->cd.mips.gpr[rt];  
                                 break;  
                         }  
                         if (special6 == SPECIAL_NOR) {  
                                 cpu->cd.mips.gpr[rd] = ~(cpu->cd.mips.gpr[rs] | cpu->cd.mips.gpr[rt]);  
                                 break;  
                         }  
                         if (special6 == SPECIAL_SLT) {  
                                 cpu->cd.mips.gpr[rd] = (int64_t)cpu->cd.mips.gpr[rs] < (int64_t)cpu->cd.mips.gpr[rt];  
                                 break;  
                         }  
                         if (special6 == SPECIAL_SLTU) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rs] < cpu->cd.mips.gpr[rt];  
                                 break;  
                         }  
                         if (special6 == SPECIAL_MTLO) {  
                                 cpu->cd.mips.lo = cpu->cd.mips.gpr[rs];  
                                 break;  
                         }  
                         if (special6 == SPECIAL_MTHI) {  
                                 cpu->cd.mips.hi = cpu->cd.mips.gpr[rs];  
                                 break;  
                         }  
                         if (special6 == SPECIAL_MULT) {  
                                 int64_t f1, f2, sum;  
                                 f1 = cpu->cd.mips.gpr[rs] & 0xffffffffULL;  
                                 /*  sign extend f1  */  
                                 if (f1 & 0x80000000ULL)  
                                         f1 |= 0xffffffff00000000ULL;  
                                 f2 = cpu->cd.mips.gpr[rt] & 0xffffffffULL;  
                                 /*  sign extend f2  */  
                                 if (f2 & 0x80000000ULL)  
                                         f2 |= 0xffffffff00000000ULL;  
                                 sum = f1 * f2;  
   
                                 cpu->cd.mips.lo = sum & 0xffffffffULL;  
                                 cpu->cd.mips.hi = ((uint64_t)sum >> 32) & 0xffffffffULL;  
   
                                 /*  sign-extend:  */  
                                 if (cpu->cd.mips.lo & 0x80000000ULL)  
                                         cpu->cd.mips.lo |= 0xffffffff00000000ULL;  
                                 if (cpu->cd.mips.hi & 0x80000000ULL)  
                                         cpu->cd.mips.hi |= 0xffffffff00000000ULL;  
   
                                 /*  
                                  *  NOTE:  The stuff about rd!=0 is just a  
                                  *  guess, judging from how some NetBSD code  
                                  *  seems to execute.  It is not documented in  
                                  *  the MIPS64 ISA docs :-/  
                                  */  
   
                                 if (rd != 0) {  
                                         if (cpu->cd.mips.cpu_type.rev != MIPS_R5900)  
                                                 debug("WARNING! mult_xx is an undocumented instruction!");  
                                         cpu->cd.mips.gpr[rd] = cpu->cd.mips.lo;  
                                 }  
                                 break;  
                         }  
                         if (special6 == SPECIAL_MULTU) {  
                                 uint64_t f1, f2, sum;  
                                 /*  zero extend f1 and f2  */  
                                 f1 = cpu->cd.mips.gpr[rs] & 0xffffffffULL;  
                                 f2 = cpu->cd.mips.gpr[rt] & 0xffffffffULL;  
                                 sum = f1 * f2;  
                                 cpu->cd.mips.lo = sum & 0xffffffffULL;  
                                 cpu->cd.mips.hi = (sum >> 32) & 0xffffffffULL;  
   
                                 /*  sign-extend:  */  
                                 if (cpu->cd.mips.lo & 0x80000000ULL)  
                                         cpu->cd.mips.lo |= 0xffffffff00000000ULL;  
                                 if (cpu->cd.mips.hi & 0x80000000ULL)  
                                         cpu->cd.mips.hi |= 0xffffffff00000000ULL;  
                                 break;  
                         }  
                         if (special6 == SPECIAL_DMULT) {  
                                 /*  64x64 = 128 bit multiplication, signed.  */  
                                 uint64_t s1 = cpu->cd.mips.gpr[rt];  
                                 uint64_t s2 = cpu->cd.mips.gpr[rs];  
                                 int n_negative = 0;  
                                 int i;  
   
                                 if ((int64_t)s1 < 0) {  
                                         s1 = -(int64_t)s1;  
                                         n_negative ++;  
                                 }  
                                 if ((int64_t)s2 < 0) {  
                                         s2 = -(int64_t)s2;  
                                         n_negative ++;  
                                 }  
   
                                 cpu->cd.mips.lo = cpu->cd.mips.hi = 0;  
   
                                 for (i=0; i<64; i++) {  
                                         int bit = (s1 & 0x8000000000000000ULL)? 1 : 0;  
                                         s1 <<= 1;  
                                         /*  If bit in s1 set, then add s2 to hi/lo:  */  
                                         if (bit) {  
                                                 uint64_t old_lo = cpu->cd.mips.lo;  
                                                 cpu->cd.mips.lo += s2;  
                                                 if (cpu->cd.mips.lo < old_lo)  
                                                         cpu->cd.mips.hi ++;  
                                         }  
                                         if (i != 63) {  
                                                 cpu->cd.mips.hi <<= 1;  
                                                 cpu->cd.mips.hi +=  
                                                     (cpu->cd.mips.lo & 0x8000000000000000ULL) ? 1 : 0;  
                                                 cpu->cd.mips.lo <<= 1;  
                                         }  
                                 }  
   
                                 if (n_negative == 1) {  
                                         cpu->cd.mips.hi = -(int64_t)cpu->cd.mips.hi;  
                                         cpu->cd.mips.lo = -(int64_t)cpu->cd.mips.lo;  
                                         if ((int64_t)cpu->cd.mips.lo < 0)  
                                                 cpu->cd.mips.hi --;  
                                 }  
                                 break;  
                         }  
                         if (special6 == SPECIAL_DMULTU) {  
                                 /*  64x64 = 128 bit multiplication, unsigned.  */  
                                 uint64_t s1 = cpu->cd.mips.gpr[rt];  
                                 uint64_t s2 = cpu->cd.mips.gpr[rs];  
                                 int i;  
   
                                 cpu->cd.mips.lo = cpu->cd.mips.hi = 0;  
   
                                 for (i=0; i<64; i++) {  
                                         int bit = (s1 & 0x8000000000000000ULL)? 1 : 0;  
                                         s1 <<= 1;  
                                         /*  If bit in s1 set, then add s2 to hi/lo:  */  
                                         if (bit) {  
                                                 uint64_t old_lo = cpu->cd.mips.lo;  
                                                 cpu->cd.mips.lo += s2;  
                                                 if (cpu->cd.mips.lo < old_lo)  
                                                         cpu->cd.mips.hi ++;  
                                         }  
                                         if (i != 63) {  
                                                 cpu->cd.mips.hi <<= 1;  
                                                 cpu->cd.mips.hi +=  
                                                     (cpu->cd.mips.lo & 0x8000000000000000ULL) ? 1 : 0;  
                                                 cpu->cd.mips.lo <<= 1;  
                                         }  
                                 }  
                                 break;  
                         }  
                         if (special6 == SPECIAL_DIV) {  
                                 int64_t a, b;  
                                 /*  Signextend rs and rt:  */  
                                 a = cpu->cd.mips.gpr[rs] & 0xffffffffULL;  
                                 if (a & 0x80000000ULL)  
                                         a |= 0xffffffff00000000ULL;  
                                 b = cpu->cd.mips.gpr[rt] & 0xffffffffULL;  
                                 if (b & 0x80000000ULL)  
                                         b |= 0xffffffff00000000ULL;  
   
                                 if (b == 0) {  
                                         /*  undefined  */  
                                         cpu->cd.mips.lo = cpu->cd.mips.hi = 0;  
                                 } else {  
                                         cpu->cd.mips.lo = a / b;  
                                         cpu->cd.mips.hi = a % b;  
                                 }  
                                 /*  Sign-extend lo and hi:  */  
                                 cpu->cd.mips.lo &= 0xffffffffULL;  
                                 if (cpu->cd.mips.lo & 0x80000000ULL)  
                                         cpu->cd.mips.lo |= 0xffffffff00000000ULL;  
                                 cpu->cd.mips.hi &= 0xffffffffULL;  
                                 if (cpu->cd.mips.hi & 0x80000000ULL)  
                                         cpu->cd.mips.hi |= 0xffffffff00000000ULL;  
                                 break;  
                         }  
                         if (special6 == SPECIAL_DIVU) {  
                                 int64_t a, b;  
                                 /*  Zero-extend rs and rt:  */  
                                 a = cpu->cd.mips.gpr[rs] & 0xffffffffULL;  
                                 b = cpu->cd.mips.gpr[rt] & 0xffffffffULL;  
                                 if (b == 0) {  
                                         /*  undefined  */  
                                         cpu->cd.mips.lo = cpu->cd.mips.hi = 0;  
                                 } else {  
                                         cpu->cd.mips.lo = a / b;  
                                         cpu->cd.mips.hi = a % b;  
                                 }  
                                 /*  Sign-extend lo and hi:  */  
                                 cpu->cd.mips.lo &= 0xffffffffULL;  
                                 if (cpu->cd.mips.lo & 0x80000000ULL)  
                                         cpu->cd.mips.lo |= 0xffffffff00000000ULL;  
                                 cpu->cd.mips.hi &= 0xffffffffULL;  
                                 if (cpu->cd.mips.hi & 0x80000000ULL)  
                                         cpu->cd.mips.hi |= 0xffffffff00000000ULL;  
                                 break;  
                         }  
                         if (special6 == SPECIAL_DDIV) {  
                                 if (cpu->cd.mips.gpr[rt] == 0) {  
                                         cpu->cd.mips.lo = cpu->cd.mips.hi = 0;          /*  undefined  */  
                                 } else {  
                                         cpu->cd.mips.lo = (int64_t)cpu->cd.mips.gpr[rs] / (int64_t)cpu->cd.mips.gpr[rt];  
                                         cpu->cd.mips.hi = (int64_t)cpu->cd.mips.gpr[rs] % (int64_t)cpu->cd.mips.gpr[rt];  
                                 }  
                                 break;  
                         }  
                         if (special6 == SPECIAL_DDIVU) {  
                                 if (cpu->cd.mips.gpr[rt] == 0) {  
                                         cpu->cd.mips.lo = cpu->cd.mips.hi = 0;          /*  undefined  */  
                                 } else {  
                                         cpu->cd.mips.lo = cpu->cd.mips.gpr[rs] / cpu->cd.mips.gpr[rt];  
                                         cpu->cd.mips.hi = cpu->cd.mips.gpr[rs] % cpu->cd.mips.gpr[rt];  
                                 }  
                                 break;  
                         }  
                         if (special6 == SPECIAL_TGE) {  
                                 if ((int64_t)cpu->cd.mips.gpr[rs] >= (int64_t)cpu->cd.mips.gpr[rt])  
                                         mips_cpu_exception(cpu, EXCEPTION_TR, 0, 0, 0, 0, 0, 0);  
                                 break;  
                         }  
                         if (special6 == SPECIAL_TGEU) {  
                                 if (cpu->cd.mips.gpr[rs] >= cpu->cd.mips.gpr[rt])  
                                         mips_cpu_exception(cpu, EXCEPTION_TR, 0, 0, 0, 0, 0, 0);  
                                 break;  
                         }  
                         if (special6 == SPECIAL_TLT) {  
                                 if ((int64_t)cpu->cd.mips.gpr[rs] < (int64_t)cpu->cd.mips.gpr[rt])  
                                         mips_cpu_exception(cpu, EXCEPTION_TR, 0, 0, 0, 0, 0, 0);  
                                 break;  
                         }  
                         if (special6 == SPECIAL_TLTU) {  
                                 if (cpu->cd.mips.gpr[rs] < cpu->cd.mips.gpr[rt])  
                                         mips_cpu_exception(cpu, EXCEPTION_TR, 0, 0, 0, 0, 0, 0);  
                                 break;  
                         }  
                         if (special6 == SPECIAL_TEQ) {  
                                 if (cpu->cd.mips.gpr[rs] == cpu->cd.mips.gpr[rt])  
                                         mips_cpu_exception(cpu, EXCEPTION_TR, 0, 0, 0, 0, 0, 0);  
                                 break;  
                         }  
                         if (special6 == SPECIAL_TNE) {  
                                 if (cpu->cd.mips.gpr[rs] != cpu->cd.mips.gpr[rt])  
                                         mips_cpu_exception(cpu, EXCEPTION_TR, 0, 0, 0, 0, 0, 0);  
                                 break;  
                         }  
                         if (special6 == SPECIAL_DADD) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rs] + cpu->cd.mips.gpr[rt];  
                                 /*  TODO:  exception on overflow  */  
                                 break;  
                         }  
                         if (special6 == SPECIAL_DADDU) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rs] + cpu->cd.mips.gpr[rt];  
                                 break;  
                         }  
                         if (special6 == SPECIAL_DSUB) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rs] - cpu->cd.mips.gpr[rt];  
                                 /*  TODO:  exception on overflow  */  
                                 break;  
                         }  
                         if (special6 == SPECIAL_DSUBU) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rs] - cpu->cd.mips.gpr[rt];  
                                 break;  
                         }  
                         if (special6 == SPECIAL_MOVZ) {  
                                 if (cpu->cd.mips.gpr[rt] == 0)  
                                         cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rs];  
                                 break;  
                         }  
                         if (special6 == SPECIAL_MOVN) {  
                                 if (cpu->cd.mips.gpr[rt] != 0)  
                                         cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rs];  
                                 return 1;  
                         }  
                         return 1;  
                 case SPECIAL_SYNC:  
                         /*  imm = ((instr[1] & 7) << 2) + (instr[0] >> 6);  */  
                         /*  TODO: actually sync  */  
   
                         /*  Clear the LLbit (at least on R10000):  */  
                         cpu->cd.mips.rmw = 0;  
                         return 1;  
                 case SPECIAL_SYSCALL:  
                         imm = ((instr[3] << 24) + (instr[2] << 16) +  
                             (instr[1] << 8) + instr[0]) >> 6;  
                         imm &= 0xfffff;  
   
                         if (cpu->machine->userland_emul != NULL)  
                                 useremul_syscall(cpu, imm);  
                         else  
                                 mips_cpu_exception(cpu, EXCEPTION_SYS,  
                                     0, 0, 0, 0, 0, 0);  
                         return 1;  
                 case SPECIAL_BREAK:  
                         mips_cpu_exception(cpu, EXCEPTION_BP, 0, 0, 0, 0, 0, 0);  
                         return 1;  
                 case SPECIAL_MFSA:  
                         /*  R5900? Move from shift amount register?  */  
                         /*  rd = (instr[1] >> 3) & 31;  */  
                         /*  TODO  */  
                         return 1;  
                 case SPECIAL_MTSA:  
                         /*  R5900? Move to shift amount register?  */  
                         /*  rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);  */  
                         /*  TODO  */  
                         return 1;  
                 default:  
                         if (!instruction_trace_cached) {  
                                 fatal("cpu%i @ %016llx: %02x%02x%02x%02x%s\t",  
                                     cpu->cpu_id, (long long)cpu->cd.mips.pc_last,  
                                     instr[3], instr[2], instr[1], instr[0], cpu_flags(cpu));  
                         }  
                         fatal("unimplemented special6 = 0x%02x\n", special6);  
                         cpu->running = 0;  
                         return 1;  
                 }  
                 return 1;  
         case HI6_BEQ:  
         case HI6_BEQL:  
         case HI6_BNE:  
         case HI6_BGTZ:  
         case HI6_BGTZL:  
         case HI6_BLEZ:  
         case HI6_BLEZL:  
         case HI6_BNEL:  
         case HI6_ADDI:  
         case HI6_ADDIU:  
         case HI6_DADDI:  
         case HI6_DADDIU:  
         case HI6_SLTI:  
         case HI6_SLTIU:  
         case HI6_ANDI:  
         case HI6_ORI:  
         case HI6_XORI:  
         case HI6_LUI:  
         case HI6_LB:  
         case HI6_LBU:  
         case HI6_LH:  
         case HI6_LHU:  
         case HI6_LW:  
         case HI6_LWU:  
         case HI6_LD:  
         case HI6_LQ_MDMX:  
         case HI6_LWC1:  
         case HI6_LWC2:  
         case HI6_LWC3:  
         case HI6_LDC1:  
         case HI6_LDC2:  
         case HI6_LL:  
         case HI6_LLD:  
         case HI6_SB:  
         case HI6_SH:  
         case HI6_SW:  
         case HI6_SD:  
         case HI6_SQ:  
         case HI6_SC:  
         case HI6_SCD:  
         case HI6_SWC1:  
         case HI6_SWC2:  
         case HI6_SWC3:  
         case HI6_SDC1:  
         case HI6_SDC2:  
         case HI6_LWL:   /*  Unaligned load/store  */  
         case HI6_LWR:  
         case HI6_LDL:  
         case HI6_LDR:  
         case HI6_SWL:  
         case HI6_SWR:  
         case HI6_SDL:  
         case HI6_SDR:  
                 rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);  
                 rt = instr[2] & 31;  
                 imm = (instr[1] << 8) + instr[0];  
                 if (imm >= 32768)               /*  signed 16-bit  */  
                         imm -= 65536;  
   
                 tmpvalue = imm;         /*  used later in several cases  */  
   
                 switch (hi6) {  
                 case HI6_ADDI:  
                 case HI6_ADDIU:  
                 case HI6_DADDI:  
                 case HI6_DADDIU:  
                         tmpvalue = cpu->cd.mips.gpr[rs];  
                         result_value = cpu->cd.mips.gpr[rs] + imm;  
   
                         if (hi6 == HI6_ADDI || hi6 == HI6_DADDI) {  
                                 /*  
                                  *  addi and daddi should trap on overflow:  
                                  *  
                                  *  TODO:  This is incorrect? The R4000 manual  
                                  *  says that overflow occurs if the carry bits  
                                  *  out of bit 62 and 63 differ. The  
                                  *  destination register should not be modified  
                                  *  on overflow.  
                                  */  
                                 if (imm >= 0) {  
                                         /*  Turn around from 0x7fff.. to 0x800 ?  Then overflow.  */  
                                         if (   ((hi6 == HI6_ADDI && (result_value &  
                                             0x80000000ULL) && (tmpvalue &  
                                             0x80000000ULL)==0))  
                                             || ((hi6 == HI6_DADDI && (result_value &  
                                             0x8000000000000000ULL) && (tmpvalue &  
                                             0x8000000000000000ULL)==0)) ) {  
                                                 mips_cpu_exception(cpu, EXCEPTION_OV, 0, 0, 0, 0, 0, 0);  
                                                 break;  
                                         }  
                                 } else {  
                                         /*  Turn around from 0x8000.. to 0x7fff.. ?  Then overflow.  */  
                                         if (   ((hi6 == HI6_ADDI && (result_value &  
                                             0x80000000ULL)==0 && (tmpvalue &  
                                             0x80000000ULL)))  
                                             || ((hi6 == HI6_DADDI && (result_value &  
                                             0x8000000000000000ULL)==0 && (tmpvalue &  
                                             0x8000000000000000ULL))) ) {  
                                                 mips_cpu_exception(cpu, EXCEPTION_OV, 0, 0, 0, 0, 0, 0);  
                                                 break;  
                                         }  
                                 }  
                         }  
   
                         cpu->cd.mips.gpr[rt] = result_value;  
   
                         /*  
                          *  Super-ugly speed-hack:  (only if speed_tricks != 0)  
                          *  NOTE: This makes the emulation less correct.  
                          *  
                          *  If we encounter a loop such as:  
                          *  
                          *      8012f5f4: 1c40ffff      bgtz r0,r2,ffffffff8012f5f4  
                          *      8012f5f8: 2442ffff (d)  addiu r2,r2,-1  
                          *  
                          *  then it is a small loop which simply waits for r2  
                          *  to become zero.  
                          *  
                          *  TODO:  increaste the count register, and cause  
                          *  interrupts!!!  For now: return as if we just  
                          *  executed 1 instruction.  
                          */  
                         ninstrs_executed = 1;  
                         if (cpu->machine->speed_tricks && cpu->cd.mips.delay_slot &&  
                             cpu->cd.mips.last_was_jumptoself &&  
                             cpu->cd.mips.jump_to_self_reg == rt &&  
                             cpu->cd.mips.jump_to_self_reg == rs) {  
                                 if ((int64_t)cpu->cd.mips.gpr[rt] > 1 && (int64_t)cpu->cd.mips.gpr[rt] < 0x70000000  
                                     && (imm >= -30000 && imm <= -1)) {  
                                         if (instruction_trace_cached)  
                                                 debug("changing r%i from %016llx to", rt, (long long)cpu->cd.mips.gpr[rt]);  
   
                                         while ((int64_t)cpu->cd.mips.gpr[rt] > 0 && ninstrs_executed < 1000  
                                             && ((int64_t)cpu->cd.mips.gpr[rt] + (int64_t)imm) > 0) {  
                                                 cpu->cd.mips.gpr[rt] += (int64_t)imm;  
                                                 ninstrs_executed += 2;  
                                         }  
   
                                         if (instruction_trace_cached)  
                                                 debug(" %016llx\n", (long long)cpu->cd.mips.gpr[rt]);  
   
                                         /*  TODO: return value, cpu->cd.mips.gpr[rt] * 2;  */  
                                 }  
                                 if ((int64_t)cpu->cd.mips.gpr[rt] > -0x70000000 && (int64_t)cpu->cd.mips.gpr[rt] < -1  
                                      && (imm >= 1 && imm <= 30000)) {  
                                         if (instruction_trace_cached)  
                                                 debug("changing r%i from %016llx to", rt, (long long)cpu->cd.mips.gpr[rt]);  
   
                                         while ((int64_t)cpu->cd.mips.gpr[rt] < 0 && ninstrs_executed < 1000  
                                             && ((int64_t)cpu->cd.mips.gpr[rt] + (int64_t)imm) < 0) {  
                                                 cpu->cd.mips.gpr[rt] += (int64_t)imm;  
                                                 ninstrs_executed += 2;  
                                         }  
   
                                         if (instruction_trace_cached)  
                                                 debug(" %016llx\n", (long long)cpu->cd.mips.gpr[rt]);  
                                 }  
                         }  
   
                         if (hi6 == HI6_ADDI || hi6 == HI6_ADDIU) {  
                                 /*  Sign-extend:  */  
                                 cpu->cd.mips.gpr[rt] &= 0xffffffffULL;  
                                 if (cpu->cd.mips.gpr[rt] & 0x80000000ULL)  
                                         cpu->cd.mips.gpr[rt] |= 0xffffffff00000000ULL;  
                         }  
                         return ninstrs_executed;  
                 case HI6_BEQ:  
                 case HI6_BNE:  
                 case HI6_BGTZ:  
                 case HI6_BGTZL:  
                 case HI6_BLEZ:  
                 case HI6_BLEZL:  
                 case HI6_BEQL:  
                 case HI6_BNEL:  
                         if (cpu->cd.mips.delay_slot) {  
                                 fatal("b*: jump inside a jump's delay slot, or similar. TODO\n");  
                                 cpu->running = 0;  
                                 return 1;  
                         }  
                         likely = cond = 0;  
                         switch (hi6) {  
                         case HI6_BNEL:  likely = 1;  
                         case HI6_BNE:   cond = (cpu->cd.mips.gpr[rt] != cpu->cd.mips.gpr[rs]);  
                                         break;  
                         case HI6_BEQL:  likely = 1;  
                         case HI6_BEQ:   cond = (cpu->cd.mips.gpr[rt] == cpu->cd.mips.gpr[rs]);  
                                         break;  
                         case HI6_BLEZL: likely = 1;  
                         case HI6_BLEZ:  cond = ((int64_t)cpu->cd.mips.gpr[rs] <= 0);  
                                         break;  
                         case HI6_BGTZL: likely = 1;  
                         case HI6_BGTZ:  cond = ((int64_t)cpu->cd.mips.gpr[rs] > 0);  
                                         break;  
                         }  
   
                         if (cond) {  
                                 cpu->cd.mips.delay_slot = TO_BE_DELAYED;  
                                 cpu->cd.mips.delay_jmpaddr = cached_pc + (imm << 2);  
                         } else {  
                                 if (likely)  
                                         cpu->cd.mips.nullify_next = 1;          /*  nullify delay slot  */  
                         }  
   
                         if (imm==-1 && (hi6 == HI6_BGTZ || hi6 == HI6_BLEZ ||  
                             (hi6 == HI6_BGTZL && cond) ||  
                             (hi6 == HI6_BLEZL && cond) ||  
                             (hi6 == HI6_BNE && (rt==0 || rs==0)) ||  
                             (hi6 == HI6_BEQ && (rt==0 || rs==0)))) {  
                                 cpu->cd.mips.last_was_jumptoself = 2;  
                                 if (rs == 0)  
                                         cpu->cd.mips.jump_to_self_reg = rt;  
                                 else  
                                         cpu->cd.mips.jump_to_self_reg = rs;  
                         }  
                         return 1;  
                 case HI6_LUI:  
                         cpu->cd.mips.gpr[rt] = (imm << 16);  
                         /*  No sign-extending necessary, as imm already  
                             was sign-extended if it was negative.  */  
                         break;  
                 case HI6_SLTI:  
                         cpu->cd.mips.gpr[rt] = (int64_t)cpu->cd.mips.gpr[rs] < (int64_t)tmpvalue;  
                         break;  
                 case HI6_SLTIU:  
                         cpu->cd.mips.gpr[rt] = cpu->cd.mips.gpr[rs] < (uint64_t)imm;  
                         break;  
                 case HI6_ANDI:  
                         cpu->cd.mips.gpr[rt] = cpu->cd.mips.gpr[rs] & (tmpvalue & 0xffff);  
                         break;  
                 case HI6_ORI:  
                         cpu->cd.mips.gpr[rt] = cpu->cd.mips.gpr[rs] | (tmpvalue & 0xffff);  
                         break;  
                 case HI6_XORI:  
                         cpu->cd.mips.gpr[rt] = cpu->cd.mips.gpr[rs] ^ (tmpvalue & 0xffff);  
                         break;  
                 case HI6_LB:  
                 case HI6_LBU:  
                 case HI6_LH:  
                 case HI6_LHU:  
                 case HI6_LW:  
                 case HI6_LWU:  
                 case HI6_LD:  
                 case HI6_LQ_MDMX:  
                 case HI6_LWC1:  
                 case HI6_LWC2:  
                 case HI6_LWC3:  /*  pref  */  
                 case HI6_LDC1:  
                 case HI6_LDC2:  
                 case HI6_LL:  
                 case HI6_LLD:  
                 case HI6_SB:  
                 case HI6_SH:  
                 case HI6_SW:  
                 case HI6_SD:  
                 case HI6_SQ:  
                 case HI6_SC:  
                 case HI6_SCD:  
                 case HI6_SWC1:  
                 case HI6_SWC2:  
                 case HI6_SWC3:  
                 case HI6_SDC1:  
                 case HI6_SDC2:  
                         /*  These are the default "assumptions".  */  
                         linked = 0;  
                         st = 1;  
                         signd = 1;  
                         wlen = 4;  
   
                         switch (hi6) {  
                         /*  The most common ones:  */  
                         case HI6_LW:    {           st = 0;            }  break;  
                         case HI6_SW:    {                   signd = 0; }  break;  
   
                         case HI6_LB:    { wlen = 1; st = 0;            }  break;  
                         case HI6_LBU:   { wlen = 1; st = 0; signd = 0; }  break;  
                         case HI6_SB:    { wlen = 1;         signd = 0; }  break;  
   
                         case HI6_LD:    { wlen = 8; st = 0; signd = 0; }  break;  
                         case HI6_SD:    { wlen = 8;         signd = 0; }  break;  
   
                         case HI6_LQ_MDMX:       { wlen = 16; st = 0; signd = 0; }  break;       /*  R5900, otherwise MDMX (TODO)  */  
                         case HI6_SQ:            { wlen = 16;         signd = 0; }  break;       /*  R5900 ?  */  
   
                         /*  The rest:  */  
                         case HI6_LH:    { wlen = 2; st = 0;            }  break;  
                         case HI6_LHU:   { wlen = 2; st = 0; signd = 0; }  break;  
                         case HI6_LWU:   {           st = 0; signd = 0; }  break;  
                         case HI6_LWC1:  {           st = 0;            }  break;  
                         case HI6_LWC2:  {           st = 0;            }  break;  
                         case HI6_LWC3:  {           st = 0;            }  break;  
                         case HI6_LDC1:  { wlen = 8; st = 0; signd = 0; }  break;  
                         case HI6_LDC2:  { wlen = 8; st = 0; signd = 0; }  break;  
   
                         case HI6_SH:    { wlen = 2;         signd = 0; }  break;  
                         case HI6_SDC1:  
                         case HI6_SDC2:  wlen = 8;  
                         case HI6_SWC1:  
                         case HI6_SWC2:  
                         case HI6_SWC3:  {                   signd = 0; }  break;  
   
                         case HI6_LL:    {           st = 0; signd = 1; linked = 1; }  break;  
                         case HI6_LLD:   { wlen = 8; st = 0; signd = 0; linked = 1; }  break;  
   
                         case HI6_SC:    {                   signd = 1; linked = 1; }  break;  
                         case HI6_SCD:   { wlen = 8;         signd = 0; linked = 1; }  break;  
   
                         default:  
                                 fatal("cannot be here\n");  
                                 wlen = 4; st = 0; signd = 0;  
                         }  
   
                         /*  
                          *  In the MIPS IV ISA, the 'lwc3' instruction is changed into 'pref'.  
                          *  The pref instruction is emulated by not doing anything. :-)  TODO  
                          */  
                         if (hi6 == HI6_LWC3 && cpu->cd.mips.cpu_type.isa_level >= 4) {  
                                 /*  Clear the LLbit (at least on R10000):  */  
                                 cpu->cd.mips.rmw = 0;  
                                 break;  
                         }  
   
                         addr = cpu->cd.mips.gpr[rs] + imm;  
   
                         /*  Check for natural alignment:  */  
                         if ((addr & (wlen - 1)) != 0) {  
                                 mips_cpu_exception(cpu, st? EXCEPTION_ADES : EXCEPTION_ADEL,  
                                     0, addr, 0, 0, 0, 0);  
                                 break;  
                         }  
   
 #if 0  
                         if (cpu->cd.mips.cpu_type.isa_level == 4 && (imm & (wlen - 1)) != 0)  
                                 debug("WARNING: low bits of imm value not zero! (MIPS IV) "  
                                     "pc=%016llx", (long long)cpu->cd.mips.pc_last);  
 #endif  
   
                         /*  
                          *  Load Linked: This initiates a Read-Modify-Write  
                          *  sequence.  
                          */  
                         if (linked) {  
                                 if (st==0) {  
                                         /*  st == 0:  Load  */  
                                         cpu->cd.mips.rmw      = 1;  
                                         cpu->cd.mips.rmw_addr = addr;  
                                         cpu->cd.mips.rmw_len  = wlen;  
   
                                         /*  
                                          *  COP0_LLADDR is updated for  
                                          *  diagnostic purposes, except for  
                                          *  CPUs in the R10000 family.  
                                          */  
                                         if (cpu->cd.mips.cpu_type.exc_model != MMU10K)  
                                                 cp0->reg[COP0_LLADDR] =  
                                                     (addr >> 4) & 0xffffffffULL;  
                                 } else {  
                                         /*  
                                          *  st == 1:  Store  
                                          *  If rmw is 0, then the store failed.  
                                          *  (This cache-line was written to by  
                                          *  someone else.)  
                                          */  
                                         if (cpu->cd.mips.rmw == 0 ||  
                                             cpu->cd.mips.rmw_addr != addr ||  
                                             cpu->cd.mips.rmw_len != wlen) {  
                                                 /*  The store failed:  */  
                                                 cpu->cd.mips.gpr[rt] = 0;  
                                                 if (instruction_trace_cached)  
                                                         debug(" [COLLISION] ");  
                                                 break;  
                                         }  
                                 }  
                         } else {  
                                 /*  
                                  *  If any kind of load or store occurs between  
                                  *  an ll and an sc, then the ll-sc sequence  
                                  *  should fail.  (This is local to each cpu.)  
                                  */  
                                 cpu->cd.mips.rmw = 0;  
                         }  
   
                         value_hi = 0;  
   
                         if (st) {  
                                 /*  store:  */  
                                 int cpnr, success;  
   
                                 if (hi6 == HI6_SWC3 || hi6 == HI6_SWC2 ||  
                                     hi6 == HI6_SDC1 || hi6 == HI6_SWC1) {  
                                         cpnr = 1;  
                                         switch (hi6) {  
                                         case HI6_SWC3:  cpnr++;         /*  fallthrough  */  
                                         case HI6_SWC2:  cpnr++;  
                                         case HI6_SDC1:  
                                         case HI6_SWC1:  if (cpu->cd.mips.coproc[cpnr] == NULL ||  
                                                             (!(cp0->reg[COP0_STATUS] & ((1 << cpnr) << STATUS_CU_SHIFT))) ) {  
                                                                 mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);  
                                                                 cpnr = -1;  
                                                                 break;  
                                                         } else {  
                                                                 /*  Special handling of 64-bit stores  
                                                                     on 32-bit CPUs, and on newer CPUs  
                                                                     in 32-bit compatiblity mode:  */  
                                                                 if ((hi6==HI6_SDC1 || hi6==HI6_SDC2) &&  
                                                                     (cpu->cd.mips.cpu_type.isa_level <= 2 ||  
                                                                     !(cp0->reg[COP0_STATUS] & STATUS_FR))) {  
                                                                         uint64_t a, b;  
                                                                         coproc_register_read(cpu,  
                                                                             cpu->cd.mips.coproc[cpnr], rt, &a, 0);  
                                                                         coproc_register_read(cpu,  
                                                                             cpu->cd.mips.coproc[cpnr], rt^1, &b, 0);  
                                                                         if (rt & 1)  
                                                                                 fatal("WARNING: SDCx in 32-bit mode from odd register!\n");  
                                                                         value = (a & 0xffffffffULL)  
                                                                             | (b << 32);  
                                                                 } else  
                                                                         coproc_register_read(cpu, cpu->cd.mips.coproc[cpnr], rt, &value, 0);  
                                                         }  
                                                         break;  
                                         default:  
                                                         ;  
                                         }  
                                         if (cpnr < 0)  
                                                 break;  
                                 } else  
                                         value = cpu->cd.mips.gpr[rt];  
   
                                 if (wlen == 4) {  
                                         /*  Special case for 32-bit stores... (perhaps not worth it)  */  
                                         if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {  
                                                 d[0] = value & 0xff;         d[1] = (value >> 8) & 0xff;  
                                                 d[2] = (value >> 16) & 0xff; d[3] = (value >> 24) & 0xff;  
                                         } else {  
                                                 d[3] = value & 0xff;         d[2] = (value >> 8) & 0xff;  
                                                 d[1] = (value >> 16) & 0xff; d[0] = (value >> 24) & 0xff;  
                                         }  
                                 } else if (wlen == 16) {  
                                         value_hi = cpu->cd.mips.gpr_quadhi[rt];  
                                         /*  Special case for R5900 128-bit stores:  */  
                                         if (cpu->byte_order == EMUL_LITTLE_ENDIAN)  
                                                 for (i=0; i<8; i++) {  
                                                         d[i] = (value >> (i*8)) & 255;  
                                                         d[i+8] = (value_hi >> (i*8)) & 255;  
                                                 }  
                                         else  
                                                 for (i=0; i<8; i++) {  
                                                         d[i] = (value >> ((wlen-1-i)*8)) & 255;  
                                                         d[i + 8] = (value_hi >> ((wlen-1-i)*8)) & 255;  
                                                 }  
                                 } else if (wlen == 1) {  
                                         d[0] = value & 0xff;  
                                 } else {  
                                         /*  General case:  */  
                                         uint64_t v = value;  
                                         if (cpu->byte_order ==  
                                             EMUL_LITTLE_ENDIAN)  
                                                 for (i=0; i<wlen; i++) {  
                                                         d[i] = v & 255;  
                                                         v >>= 8;  
                                                 }  
                                         else  
                                                 for (i=0; i<wlen; i++) {  
                                                         d[wlen-1-i] = v & 255;  
                                                         v >>= 8;  
                                                 }  
                                 }  
   
                                 success = cpu->memory_rw(cpu, cpu->mem, addr,  
                                     d, wlen, MEM_WRITE, CACHE_DATA);  
                                 if (!success) {  
                                         /*  The store failed, and might have caused an exception.  */  
                                         if (instruction_trace_cached)  
                                                 debug("(failed)]\n");  
                                         break;  
                                 }  
                         } else {  
                                 /*  load:  */  
                                 int cpnr = 1;  
                                 int success;  
   
                                 success = cpu->memory_rw(cpu, cpu->mem, addr,  
                                     d, wlen, MEM_READ, CACHE_DATA);  
                                 if (!success) {  
                                         /*  The load failed, and might have caused an exception.  */  
                                         if (instruction_trace_cached)  
                                                 debug("(failed)]\n");  
                                         break;  
                                 }  
   
                                 if (wlen == 1)  
                                         value = d[0] | (signd && (d[0]&128)? (-1 << 8) : 0);  
                                 else if (wlen != 16) {  
                                         /*  General case (except for 128-bit):  */  
                                         int i;  
                                         value = 0;  
                                         if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {  
                                                 if (signd && (d[wlen-1] & 128)!=0)      /*  sign extend  */  
                                                         value = -1;  
                                                 for (i=wlen-1; i>=0; i--) {  
                                                         value <<= 8;  
                                                         value += d[i];  
                                                 }  
                                         } else {  
                                                 if (signd && (d[0] & 128)!=0)           /*  sign extend  */  
                                                         value = -1;  
                                                 for (i=0; i<wlen; i++) {  
                                                         value <<= 8;  
                                                         value += d[i];  
                                                 }  
                                         }  
                                 } else {  
                                         /*  R5900 128-bit quadword:  */  
                                         int i;  
                                         value_hi = 0;  
                                         value = 0;  
                                         if (cpu->byte_order == EMUL_LITTLE_ENDIAN) {  
                                                 for (i=wlen-1; i>=0; i--) {  
                                                         value_hi <<= 8;  
                                                         value_hi += (value >> 56) & 255;  
                                                         value <<= 8;  
                                                         value += d[i];  
                                                 }  
                                         } else {  
                                                 for (i=0; i<wlen; i++) {  
                                                         value_hi <<= 8;  
                                                         value_hi += (value >> 56) & 255;  
                                                         value <<= 8;  
                                                         value += d[i];  
                                                 }  
                                         }  
                                         cpu->cd.mips.gpr_quadhi[rt] = value_hi;  
                                 }  
   
                                 switch (hi6) {  
                                 case HI6_LWC3:  cpnr++;         /*  fallthrough  */  
                                 case HI6_LDC2:  
                                 case HI6_LWC2:  cpnr++;  
                                 case HI6_LDC1:  
                                 case HI6_LWC1:  if (cpu->cd.mips.coproc[cpnr] == NULL ||  
                                                     (!(cp0->reg[COP0_STATUS] & ((1 << cpnr) << STATUS_CU_SHIFT))) ) {  
                                                         mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);  
                                                 } else {  
                                                         /*  Special handling of 64-bit loads  
                                                             on 32-bit CPUs, and on newer CPUs  
                                                             in 32-bit compatiblity mode:  */  
                                                         if ((hi6==HI6_LDC1 || hi6==HI6_LDC2) &&  
                                                             (cpu->cd.mips.cpu_type.isa_level <= 2 ||  
                                                             !(cp0->reg[COP0_STATUS] & STATUS_FR))) {  
                                                                 uint64_t a, b;  
                                                                 a = (int64_t)(int32_t) (value & 0xffffffffULL);  
                                                                 b = (int64_t)(int32_t) (value >> 32);  
                                                                 coproc_register_write(cpu,  
                                                                     cpu->cd.mips.coproc[cpnr], rt, &a,  
                                                                     hi6==HI6_LDC1 || hi6==HI6_LDC2, 0);  
                                                                 coproc_register_write(cpu,  
                                                                     cpu->cd.mips.coproc[cpnr], rt ^ 1, &b,  
                                                                     hi6==HI6_LDC1 || hi6==HI6_LDC2, 0);  
                                                                 if (rt & 1)  
                                                                         fatal("WARNING: LDCx in 32-bit mode to odd register!\n");  
                                                         } else {  
                                                                 coproc_register_write(cpu,  
                                                                     cpu->cd.mips.coproc[cpnr], rt, &value,  
                                                                     hi6==HI6_LDC1 || hi6==HI6_LDC2, 0);  
                                                         }  
                                                 }  
                                                 break;  
                                 default:        if (rt != 0)  
                                                         cpu->cd.mips.gpr[rt] = value;  
                                 }  
                         }  
   
                         if (linked && st==1) {  
                                 /*  
                                  *  The store succeeded. Invalidate any other  
                                  *  cpu's store to this cache line, and then  
                                  *  return 1 in gpr rt:  
                                  *  
                                  *  (this is a semi-ugly hack using global  
                                  * 'cpus')  
                                  *  
                                  *  TODO: How about invalidating other CPUs  
                                  *  stores to this cache line, even if this  
                                  *  was _NOT_ a linked store?  
                                  */  
                                 for (i=0; i<cpu->machine->ncpus; i++) {  
                                         if (cpu->machine->cpus[i]->cd.mips.rmw) {  
                                                 uint64_t yaddr = addr;  
                                                 uint64_t xaddr =  
                                                     cpu->machine->cpus[i]->cd.mips.rmw_addr;  
                                                 uint64_t mask;  
                                                 mask = ~(cpu->machine->cpus[i]->  
                                                     cd.mips.cache_linesize[CACHE_DATA]  
                                                     - 1);  
                                                 xaddr &= mask;  
                                                 yaddr &= mask;  
                                                 if (xaddr == yaddr) {  
                                                         cpu->machine->cpus[i]->cd.mips.rmw = 0;  
                                                         cpu->machine->cpus[i]->cd.mips.rmw_addr = 0;  
                                                 }  
                                         }  
                                 }  
   
                                 if (rt != 0)  
                                         cpu->cd.mips.gpr[rt] = 1;  
   
                                 if (instruction_trace_cached)  
                                         debug(" [no collision] ");  
                                 cpu->cd.mips.rmw = 0;  
                         }  
   
                         if (instruction_trace_cached) {  
                                 switch (wlen) {  
                                 case 2: debug("0x%04x", (int)value); break;  
                                 case 4: debug("0x%08x", (int)value); break;  
                                 case 8: debug("0x%016llx", (long long)value);  
                                         break;  
                                 case 16:debug("0x%016llx", (long long)value_hi);  
                                         debug("%016llx", (long long)value);  
                                         break;  
                                 default:debug("0x%02x", (int)value);  
                                 }  
                                 debug("]\n");  
                         }  
                         return 1;  
                 case HI6_LWL:   /*  Unaligned load/store  */  
                 case HI6_LWR:  
                 case HI6_LDL:  
                 case HI6_LDR:  
                 case HI6_SWL:  
                 case HI6_SWR:  
                 case HI6_SDL:  
                 case HI6_SDR:  
                         /*  For L (Left):   address is the most significant byte  */  
                         /*  For R (Right):  address is the least significant byte  */  
                         addr = cpu->cd.mips.gpr[rs] + imm;  
   
                         is_left = 0;  
                         if (hi6 == HI6_SWL || hi6 == HI6_LWL ||  
                             hi6 == HI6_SDL || hi6 == HI6_LDL)  
                                 is_left = 1;  
   
                         wlen = 0; st = 0;  
                         signd = 0;  
                         if (hi6 == HI6_LWL || hi6 == HI6_LWR)  
                                 signd = 1;  
   
                         if (hi6 == HI6_LWL || hi6 == HI6_LWR)   { wlen = 4; st = 0; }  
                         if (hi6 == HI6_SWL || hi6 == HI6_SWR)   { wlen = 4; st = 1; }  
                         if (hi6 == HI6_LDL || hi6 == HI6_LDR)   { wlen = 8; st = 0; }  
                         if (hi6 == HI6_SDL || hi6 == HI6_SDR)   { wlen = 8; st = 1; }  
   
                         dir = 1;                /*  big endian, Left  */  
                         reg_dir = -1;  
                         reg_ofs = wlen - 1;     /*  byte offset in the register  */  
                         if (!is_left) {  
                                 dir = -dir;  
                                 reg_ofs = 0;  
                                 reg_dir = 1;  
                         }  
                         if (cpu->byte_order == EMUL_LITTLE_ENDIAN)  
                                 dir = -dir;  
   
                         result_value = cpu->cd.mips.gpr[rt];  
   
                         if (st) {  
                                 /*  Store:  */  
                                 uint64_t aligned_addr = addr & ~(wlen-1);  
                                 unsigned char aligned_word[8];  
                                 uint64_t oldpc = cpu->pc;  
                                 /*  
                                  *  NOTE (this is ugly): The memory_rw()  
                                  *  call generates a TLBL exception, if there  
                                  *  is a tlb refill exception. However, since  
                                  *  this is a Store, the exception is converted  
                                  *  to a TLBS:  
                                  */  
                                 int ok = cpu->memory_rw(cpu, cpu->mem,  
                                     aligned_addr, &aligned_word[0], wlen,  
                                     MEM_READ, CACHE_DATA);  
                                 if (!ok) {  
                                         if (cpu->pc != oldpc) {  
                                                 cp0->reg[COP0_CAUSE] &= ~CAUSE_EXCCODE_MASK;  
                                                 cp0->reg[COP0_CAUSE] |= (EXCEPTION_TLBS << CAUSE_EXCCODE_SHIFT);  
                                         }  
                                         return 1;  
                                 }  
   
                                 for (i=0; i<wlen; i++) {  
                                         tmpaddr = addr + i*dir;  
                                         /*  Have we moved into another word/dword? Then stop:  */  
                                         if ( (tmpaddr & ~(wlen-1)) != (addr & ~(wlen-1)) )  
                                                 break;  
   
                                         /*  debug("unaligned byte at %016llx, reg_ofs=%i reg=0x%016llx\n",  
                                             tmpaddr, reg_ofs, (long long)result_value);  */  
   
                                         /*  Store one byte:  */  
                                         aligned_word[tmpaddr & (wlen-1)] = (result_value >> (reg_ofs * 8)) & 255;  
   
                                         reg_ofs += reg_dir;  
                                 }  
   
                                 ok = cpu->memory_rw(cpu, cpu->mem,  
                                     aligned_addr, &aligned_word[0], wlen,  
                                     MEM_WRITE, CACHE_DATA);  
                                 if (!ok)  
                                         return 1;  
                         } else {  
                                 /*  Load:  */  
                                 uint64_t aligned_addr = addr & ~(wlen-1);  
                                 unsigned char aligned_word[8], databyte;  
                                 int ok = cpu->memory_rw(cpu, cpu->mem,  
                                     aligned_addr, &aligned_word[0], wlen,  
                                     MEM_READ, CACHE_DATA);  
                                 if (!ok)  
                                         return 1;  
   
                                 for (i=0; i<wlen; i++) {  
                                         tmpaddr = addr + i*dir;  
                                         /*  Have we moved into another word/dword? Then stop:  */  
                                         if ( (tmpaddr & ~(wlen-1)) != (addr & ~(wlen-1)) )  
                                                 break;  
   
                                         /*  debug("unaligned byte at %016llx, reg_ofs=%i reg=0x%016llx\n",  
                                             tmpaddr, reg_ofs, (long long)result_value);  */  
   
                                         /*  Load one byte:  */  
                                         databyte = aligned_word[tmpaddr & (wlen-1)];  
                                         result_value &= ~((uint64_t)0xff << (reg_ofs * 8));  
                                         result_value |= (uint64_t)databyte << (reg_ofs * 8);  
   
                                         reg_ofs += reg_dir;  
                                 }  
   
                                 if (rt != 0)  
                                         cpu->cd.mips.gpr[rt] = result_value;  
                         }  
   
                         /*  Sign extend for 32-bit load lefts:  */  
                         if (!st && signd && wlen == 4) {  
                                 cpu->cd.mips.gpr[rt] &= 0xffffffffULL;  
                                 if (cpu->cd.mips.gpr[rt] & 0x80000000ULL)  
                                         cpu->cd.mips.gpr[rt] |= 0xffffffff00000000ULL;  
                         }  
   
                         if (instruction_trace_cached) {  
                                 char *t;  
                                 switch (wlen) {  
                                 case 2:         t = "0x%04llx"; break;  
                                 case 4:         t = "0x%08llx"; break;  
                                 case 8:         t = "0x%016llx"; break;  
                                 default:        t = "0x%02llx";  
                                 }  
                                 debug(t, (long long)cpu->cd.mips.gpr[rt]);  
                                 debug("]\n");  
                         }  
   
                         return 1;  
                 }  
                 return 1;  
         case HI6_REGIMM:  
                 regimm5 = instr[2] & 0x1f;  
   
                 if (show_opcode_statistics)  
                         cpu->cd.mips.stats__regimm[regimm5] ++;  
   
                 switch (regimm5) {  
                 case REGIMM_BLTZ:  
                 case REGIMM_BGEZ:  
                 case REGIMM_BLTZL:  
                 case REGIMM_BGEZL:  
                 case REGIMM_BLTZAL:  
                 case REGIMM_BLTZALL:  
                 case REGIMM_BGEZAL:  
                 case REGIMM_BGEZALL:  
                         rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);  
                         imm = (instr[1] << 8) + instr[0];  
                         if (imm >= 32768)               /*  signed 16-bit  */  
                                 imm -= 65536;  
   
                         cond = and_link = likely = 0;  
   
                         switch (regimm5) {  
                         case REGIMM_BLTZL:      likely = 1;  
                         case REGIMM_BLTZ:       cond = (cpu->cd.mips.gpr[rs] & ((uint64_t)1 << 63)) != 0;  
                                                 break;  
                         case REGIMM_BGEZL:      likely = 1;  
                         case REGIMM_BGEZ:       cond = (cpu->cd.mips.gpr[rs] & ((uint64_t)1 << 63)) == 0;  
                                                 break;  
   
                         case REGIMM_BLTZALL:    likely = 1;  
                         case REGIMM_BLTZAL:     and_link = 1;  
                                                 cond = (cpu->cd.mips.gpr[rs] & ((uint64_t)1 << 63)) != 0;  
                                                 break;  
                         case REGIMM_BGEZALL:    likely = 1;  
                         case REGIMM_BGEZAL:     and_link = 1;  
                                                 cond = (cpu->cd.mips.gpr[rs] & ((uint64_t)1 << 63)) == 0;  
                                                 break;  
                         }  
   
                         if (and_link)  
                                 cpu->cd.mips.gpr[31] = cached_pc + 4;  
   
                         if (cond) {  
                                 cpu->cd.mips.delay_slot = TO_BE_DELAYED;  
                                 cpu->cd.mips.delay_jmpaddr = cached_pc + (imm << 2);  
                         } else {  
                                 if (likely)  
                                         cpu->cd.mips.nullify_next = 1;          /*  nullify delay slot  */  
                         }  
   
                         return 1;  
                 default:  
                         if (!instruction_trace_cached) {  
                                 fatal("cpu%i @ %016llx: %02x%02x%02x%02x%s\t",  
                                     cpu->cpu_id, (long long)cpu->cd.mips.pc_last,  
                                     instr[3], instr[2], instr[1], instr[0], cpu_flags(cpu));  
                         }  
                         fatal("unimplemented regimm5 = 0x%02x\n", regimm5);  
                         cpu->running = 0;  
                         return 1;  
                 }  
                 /*  NOT REACHED  */  
         case HI6_J:  
         case HI6_JAL:  
                 if (cpu->cd.mips.delay_slot) {  
                         fatal("j/jal: jump inside a jump's delay slot, or similar. TODO\n");  
                         cpu->running = 0;  
                         return 1;  
                 }  
                 imm = ((instr[3] & 3) << 24) + (instr[2] << 16) + (instr[1] << 8) + instr[0];  
                 imm <<= 2;  
   
                 if (hi6 == HI6_JAL)  
                         cpu->cd.mips.gpr[31] = cached_pc + 4;           /*  pc already increased by 4 earlier  */  
   
                 addr = cached_pc & ~((1 << 28) - 1);  
                 addr |= imm;  
   
                 cpu->cd.mips.delay_slot = TO_BE_DELAYED;  
                 cpu->cd.mips.delay_jmpaddr = addr;  
   
                 if (cpu->machine->show_trace_tree && hi6 == HI6_JAL) {  
                         cpu->cd.mips.show_trace_delay = 2;  
                         cpu->cd.mips.show_trace_addr = addr;  
                 }  
   
                 return 1;  
         case HI6_COP0:  
         case HI6_COP1:  
         case HI6_COP2:  
         case HI6_COP3:  
                 imm = (instr[3] << 24) + (instr[2] << 16) + (instr[1] << 8) + instr[0];  
                 imm &= ((1 << 26) - 1);  
   
                 cpnr = 0;  
                 if (hi6 == HI6_COP0)    cpnr = 0;  
                 if (hi6 == HI6_COP1)    cpnr = 1;  
                 if (hi6 == HI6_COP2)    cpnr = 2;  
                 if (hi6 == HI6_COP3)    cpnr = 3;  
   
                 /*  
                  *  If there is no coprocessor nr cpnr, or we are running in  
                  *  userland and the coprocessor is not marked as Useable in  
                  *  the status register of CP0, then we get an exception.  
                  *  
                  *  An exception (hehe) to this rule is that the kernel should  
                  *  always be able to access CP0.  
                  */  
                 /*  Set tmp = 1 if we're in user mode.  */  
                 tmp = 0;  
                 switch (cpu->cd.mips.cpu_type.exc_model) {  
                 case EXC3K:  
                         /*  
                          *  NOTE: If the KU bit is checked, Linux crashes.  
                          *  It is the PC that counts.  TODO: Check whether  
                          *  this is true or not for R4000 as well.  
                          */  
                         if (cached_pc <= 0x7fffffff) /* if (cp0->reg[COP0_STATUS] & MIPS1_SR_KU_CUR) */  
                                 tmp = 1;  
                         break;  
                 default:  
                         /*  R4000 etc:  (TODO: How about supervisor mode?)  */  
                         if (((cp0->reg[COP0_STATUS] & STATUS_KSU_MASK) >> STATUS_KSU_SHIFT) != KSU_KERNEL)  
                                 tmp = 1;  
                         if (cp0->reg[COP0_STATUS] & STATUS_ERL)  
                                 tmp = 0;  
                         if (cp0->reg[COP0_STATUS] & STATUS_EXL)  
                                 tmp = 0;  
                         break;  
                 }  
                 if (cpu->cd.mips.coproc[cpnr] == NULL ||  
                     (tmp && !(cp0->reg[COP0_STATUS] & ((1 << cpnr) << STATUS_CU_SHIFT))) ||  
                     (!tmp && cpnr >= 1 && !(cp0->reg[COP0_STATUS] & ((1 << cpnr) << STATUS_CU_SHIFT)))  
                     ) {  
                         if (instruction_trace_cached)  
                                 debug("cop%i\t0x%08x => coprocessor unusable\n", cpnr, (int)imm);  
                         mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);  
                 } else {  
                         /*  
                          *  Execute the coprocessor function. The  
                          *  coproc_function code outputs instruction  
                          *  trace, if necessary.  
                          */  
                         coproc_function(cpu, cpu->cd.mips.coproc[cpnr],  
                             cpnr, imm, 0, 1);  
                 }  
                 return 1;  
         case HI6_CACHE:  
                 rt   = ((instr[3] & 3) << 3) + (instr[2] >> 5); /*  base  */  
                 copz = instr[2] & 31;  
                 imm  = (instr[1] << 8) + instr[0];  
   
                 cache_op    = copz >> 2;  
                 which_cache = copz & 3;  
   
                 /*  
                  *  TODO:  The cache instruction is implementation dependant.  
                  */  
   
                 /*  
                  *  Clear the LLbit (at least on R10000):  
                  *  TODO: How about R4000?  
                  */  
                 cpu->cd.mips.rmw = 0;  
   
                 return 1;  
         case HI6_SPECIAL2:  
                 special6 = instr[0] & 0x3f;  
   
                 if (show_opcode_statistics)  
                         cpu->cd.mips.stats__special2[special6] ++;  
   
                 instrword = (instr[3] << 24) + (instr[2] << 16) + (instr[1] << 8) + instr[0];  
   
                 rs = ((instr[3] & 3) << 3) + ((instr[2] >> 5) & 7);  
                 rt = instr[2] & 31;  
                 rd = (instr[1] >> 3) & 31;  
   
                 /*  printf("special2 %08x  rs=0x%02x rt=0x%02x rd=0x%02x\n", instrword, rs,rt,rd);  */  
   
                 /*  
                  *  Many of these can be found in the R5000 docs, or figured out  
                  *  by studying binutils source code for MIPS instructions.  
                  */  
   
                 if ((instrword & 0xfc0007ffULL) == 0x70000000) {  
                         {  
                                 int32_t a, b;  
                                 int64_t c;  
                                 a = (int32_t)cpu->cd.mips.gpr[rs];  
                                 b = (int32_t)cpu->cd.mips.gpr[rt];  
                                 c = a * b;  
                                 c += (cpu->cd.mips.lo & 0xffffffffULL)  
                                     + (cpu->cd.mips.hi << 32);  
                                 cpu->cd.mips.lo = (int64_t)((int32_t)c);  
                                 cpu->cd.mips.hi = (int64_t)((int32_t)(c >> 32));  
   
                                 /*  
                                  *  The R5000 manual says that rd should be all zeros,  
                                  *  but it isn't on R5900.   I'm just guessing here that  
                                  *  it stores the value in register rd, in addition to hi/lo.  
                                  *  TODO  
                                  */  
                                 if (rd != 0)  
                                         cpu->cd.mips.gpr[rd] = cpu->cd.mips.lo;  
                         }  
                 } else if ((instrword & 0xffff07ffULL) == 0x70000209  
                     || (instrword & 0xffff07ffULL) == 0x70000249) {  
                         /*  
                          *  This is just a guess for R5900, I've not found any docs on this one yet.  
                          *  
                          *      pmfhi/pmflo rd  
                          *  
                          *  If the lowest 8 bits of the instruction word are 0x09, it's a pmfhi.  
                          *  If the lowest bits are 0x49, it's a pmflo.  
                          *  
                          *  A wild guess is that this is a 128-bit version of mfhi/mflo.  
                          *  For now, this is implemented as 64-bit only.  (TODO)  
                          */  
                         if (instr[0] == 0x49) {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.lo;  
                         } else {  
                                 cpu->cd.mips.gpr[rd] = cpu->cd.mips.hi;  
                         }  
                 } else if ((instrword & 0xfc1fffff) == 0x70000269 || (instrword & 0xfc1fffff) == 0x70000229) {  
                         /*  
                          *  This is just a guess for R5900, I've not found any docs on this one yet.  
                          *  
                          *      pmthi/pmtlo rs          (pmtlo = 269, pmthi = 229)  
                          *  
                          *  A wild guess is that this is a 128-bit version of mthi/mtlo.  
                          *  For now, this is implemented as 64-bit only.  (TODO)  
                          */  
                         if (instr[0] == 0x69) {  
                                 cpu->cd.mips.lo = cpu->cd.mips.gpr[rs];  
                         } else {  
                                 cpu->cd.mips.hi = cpu->cd.mips.gpr[rs];  
                         }  
                 } else if ((instrword & 0xfc0007ff) == 0x700004a9) {  
                         /*  
                          *  This is just a guess for R5900, I've not found any docs on this one yet.  
                          *  
                          *      por dst,src,src2  ==> rs=src rt=src2 rd=dst  
                          *  
                          *  A wild guess is that this is a 128-bit "or" between two registers.  
                          *  For now, let's just or using 64-bits.  (TODO)  
                          */  
                         cpu->cd.mips.gpr[rd] = cpu->cd.mips.gpr[rs] | cpu->cd.mips.gpr[rt];  
                 } else if ((instrword & 0xfc0007ff) == 0x70000488) {  
                         /*  
                          *  R5900 "undocumented" pextlw. TODO: find out if this is correct.  
                          *  It seems that this instruction is used to combine two 32-bit  
                          *  words into a 64-bit dword, typically before a sd (store dword).  
                          */  
                         cpu->cd.mips.gpr[rd] =  
                             ((cpu->cd.mips.gpr[rs] & 0xffffffffULL) << 32)              /*  TODO: switch rt and rs?  */  
                             | (cpu->cd.mips.gpr[rt] & 0xffffffffULL);  
                 } else if (special6 == SPECIAL2_MUL) {  
                         cpu->cd.mips.gpr[rd] = (int64_t)cpu->cd.mips.gpr[rt] *  
                             (int64_t)cpu->cd.mips.gpr[rs];  
                 } else if (special6 == SPECIAL2_CLZ) {  
                         /*  clz: count leading zeroes  */  
                         int i, n=0;  
                         for (i=31; i>=0; i--) {  
                                 if (cpu->cd.mips.gpr[rs] & ((uint32_t)1 << i))  
                                         break;  
                                 else  
                                         n++;  
                         }  
                         cpu->cd.mips.gpr[rd] = n;  
                 } else if (special6 == SPECIAL2_CLO) {  
                         /*  clo: count leading ones  */  
                         int i, n=0;  
                         for (i=31; i>=0; i--) {  
                                 if (cpu->cd.mips.gpr[rs] & ((uint32_t)1 << i))  
                                         n++;  
                                 else  
                                         break;  
                         }  
                         cpu->cd.mips.gpr[rd] = n;  
                 } else if (special6 == SPECIAL2_DCLZ) {  
                         /*  dclz: count leading zeroes  */  
                         int i, n=0;  
                         for (i=63; i>=0; i--) {  
                                 if (cpu->cd.mips.gpr[rs] & ((uint64_t)1 << i))  
                                         break;  
                                 else  
                                         n++;  
                         }  
                         cpu->cd.mips.gpr[rd] = n;  
                 } else if (special6 == SPECIAL2_DCLO) {  
                         /*  dclo: count leading ones  */  
                         int i, n=0;  
                         for (i=63; i>=0; i--) {  
                                 if (cpu->cd.mips.gpr[rs] & ((uint64_t)1 << i))  
                                         n++;  
                                 else  
                                         break;  
                         }  
                         cpu->cd.mips.gpr[rd] = n;  
                 } else {  
                         if (!instruction_trace_cached) {  
                                 fatal("cpu%i @ %016llx: %02x%02x%02x%02x%s\t",  
                                     cpu->cpu_id, (long long)cpu->cd.mips.pc_last,  
                                     instr[3], instr[2], instr[1], instr[0], cpu_flags(cpu));  
                         }  
                         fatal("unimplemented special_2 = 0x%02x, rs=0x%02x rt=0x%02x rd=0x%02x\n",  
                             special6, rs, rt, rd);  
                         cpu->running = 0;  
                         return 1;  
                 }  
                 return 1;  
         default:  
                 if (!instruction_trace_cached) {  
                         fatal("cpu%i @ %016llx: %02x%02x%02x%02x%s\t",  
                             cpu->cpu_id, (long long)cpu->cd.mips.pc_last,  
                             instr[3], instr[2], instr[1], instr[0], cpu_flags(cpu));  
                 }  
                 fatal("unimplemented hi6 = 0x%02x\n", hi6);  
                 cpu->running = 0;  
                 return 1;  
         }  
   
         /*  NOTREACHED  */  
 }  
   
   
 #define CPU_RUN         mips_cpu_run  
 #define CPU_RUN_MIPS  
 #define CPU_RINSTR      mips_cpu_run_instr  
 #include "cpu_run.c"  
 #undef CPU_RINSTR  
 #undef CPU_RUN_MIPS  
 #undef CPU_RUN  
   
   
 /*  
  *  mips_cpu_dumpinfo():  
  *  
  *  Debug dump of MIPS-specific CPU data for specific CPU.  
  */  
 void mips_cpu_dumpinfo(struct cpu *cpu)  
 {  
         int iadd = 4;  
         struct mips_cpu_type_def *ct = &cpu->cd.mips.cpu_type;  
   
         debug_indentation(iadd);  
   
         debug("\n%i-bit %s (MIPS",  
             cpu->is_32bit? 32 : 64,  
             cpu->byte_order == EMUL_BIG_ENDIAN? "BE" : "LE");  
   
         switch (ct->isa_level) {  
         case 1: debug(" ISA I"); break;  
         case 2: debug(" ISA II"); break;  
         case 3: debug(" ISA III"); break;  
         case 4: debug(" ISA IV"); break;  
         case 5: debug(" ISA V"); break;  
         case 32:  
         case 64:debug("%i", ct->isa_level); break;  
         default:debug(" ISA level %i", ct->isa_level);  
         }  
   
         debug("), ");  
         if (ct->nr_of_tlb_entries)  
                 debug("%i TLB entries", ct->nr_of_tlb_entries);  
         else  
                 debug("no TLB");  
         debug("\n");  
   
         if (ct->picache) {  
                 debug("L1 I-cache: %i KB", (1 << ct->picache) / 1024);  
                 if (ct->pilinesize)  
                         debug(", %i bytes per line", 1 << ct->pilinesize);  
                 if (ct->piways > 1)  
                         debug(", %i-way", ct->piways);  
                 else  
                         debug(", direct-mapped");  
                 debug("\n");  
         }  
   
         if (ct->pdcache) {  
                 debug("L1 D-cache: %i KB", (1 << ct->pdcache) / 1024);  
                 if (ct->pdlinesize)  
                         debug(", %i bytes per line", 1 << ct->pdlinesize);  
                 if (ct->pdways > 1)  
                         debug(", %i-way", ct->pdways);  
                 else  
                         debug(", direct-mapped");  
                 debug("\n");  
         }  
   
         if (ct->scache) {  
                 int kb = (1 << ct->scache) / 1024;  
                 debug("L2 cache: %i %s",  
                     kb >= 1024? kb / 1024 : kb, kb >= 1024? "MB":"KB");  
                 if (ct->slinesize)  
                         debug(", %i bytes per line", 1 << ct->slinesize);  
                 if (ct->sways > 1)  
                         debug(", %i-way", ct->sways);  
                 else  
                         debug(", direct-mapped");  
                 debug("\n");  
1969          }          }
   
         debug_indentation(-iadd);  
1970  }  }
1971    
1972    
1973  /*  #include "memory_mips.c"
  *  mips_cpu_list_available_types():  
  *  
  *  Print a list of available MIPS CPU types.  
  */  
 void mips_cpu_list_available_types(void)  
 {  
         int i, j;  
         struct mips_cpu_type_def cpu_type_defs[] = MIPS_CPU_TYPE_DEFS;  
   
         i = 0;  
         while (cpu_type_defs[i].name != NULL) {  
                 debug("%s", cpu_type_defs[i].name);  
                 for (j=10 - strlen(cpu_type_defs[i].name); j>0; j--)  
                         debug(" ");  
                 i++;  
                 if ((i % 6) == 0 || cpu_type_defs[i].name == NULL)  
                         debug("\n");  
         }  
 }  
   
1974    
 CPU_FAMILY_INIT(mips,"MIPS")  
1975    
1976    #include "tmp_mips_tail.c"
1977    
 #endif  /*  ENABLE_MIPS  */  

Legend:
Removed from v.18  
changed lines
  Added in v.42

  ViewVC Help
Powered by ViewVC 1.1.26