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

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

revision 36 by dpavlin, Mon Oct 8 16:21:34 2007 UTC revision 44 by dpavlin, Mon Oct 8 16:22:56 2007 UTC
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: cpu_sh.c,v 1.62 2007/03/08 19:04:09 debug Exp $   *  $Id: cpu_sh.c,v 1.76 2007/06/28 13:36:47 debug Exp $
29   *   *
30   *  Hitachi SuperH ("SH") CPU emulation.   *  Hitachi SuperH ("SH") CPU emulation.
31   *   *
32   *  TODO: It would be nice if this could encompass both 64-bit SH5, and   *  TODO: It would be nice if this could encompass both 64-bit SH5, and
33   *        32-bit SH encodings. Right now, it only really supports 32-bit mode.   *        32-bit SH encodings. Right now, it only really supports 32-bit mode.
34     *
35     *  TODO: This actually only works or SH4 so far, not SH3.
36   */   */
37    
38  #include <stdio.h>  #include <stdio.h>
# Line 62  extern int quiet_mode; Line 64  extern int quiet_mode;
64    
65  void sh_pc_to_pointers(struct cpu *);  void sh_pc_to_pointers(struct cpu *);
66    
67    void sh3_cpu_interrupt_assert(struct interrupt *interrupt);
68    void sh3_cpu_interrupt_deassert(struct interrupt *interrupt);
69    
70    
71  /*  /*
72   *  sh_cpu_new():   *  sh_cpu_new():
# Line 92  int sh_cpu_new(struct cpu *cpu, struct m Line 97  int sh_cpu_new(struct cpu *cpu, struct m
97          cpu->cd.sh.cpu_type = cpu_type_defs[i];          cpu->cd.sh.cpu_type = cpu_type_defs[i];
98          cpu->byte_order = EMUL_LITTLE_ENDIAN;          cpu->byte_order = EMUL_LITTLE_ENDIAN;
99          cpu->is_32bit = cpu->cd.sh.cpu_type.bits == 32;          cpu->is_32bit = cpu->cd.sh.cpu_type.bits == 32;
         cpu->cd.sh.compact = 1;         /*  Default to 16-bit opcode mode  */  
100    
101          if (!cpu->is_32bit) {          if (!cpu->is_32bit) {
102                  fatal("SH64 emulation not implemented. Sorry.\n");                  fatal("SH64 emulation not implemented. Sorry.\n");
# Line 171  int sh_cpu_new(struct cpu *cpu, struct m Line 175  int sh_cpu_new(struct cpu *cpu, struct m
175          }          }
176    
177          /*  Register the CPU's interrupts:  */          /*  Register the CPU's interrupts:  */
178          for (i=SH_INTEVT_NMI; i<0x1000; i+=0x20) {          if (cpu->cd.sh.cpu_type.arch == 4) {
179                    for (i=SH_INTEVT_NMI; i<0x1000; i+=0x20) {
180                            struct interrupt template;
181                            char name[100];
182                            snprintf(name, sizeof(name), "%s.irq[0x%x]",
183                                cpu->path, i);
184                            memset(&template, 0, sizeof(template));
185                            template.line = i;
186                            template.name = name;
187                            template.extra = cpu;
188                            template.interrupt_assert = sh_cpu_interrupt_assert;
189                            template.interrupt_deassert = sh_cpu_interrupt_deassert;
190                            interrupt_handler_register(&template);
191                    }
192            } else {
193                  struct interrupt template;                  struct interrupt template;
                 char name[100];  
                 snprintf(name, sizeof(name), "%s.irq[0x%x]", cpu->path, i);  
194                  memset(&template, 0, sizeof(template));                  memset(&template, 0, sizeof(template));
195                  template.line = i;                  template.line = i;
196                  template.name = name;                  template.name = cpu->path;
197                  template.extra = cpu;                  template.extra = cpu;
198                  template.interrupt_assert = sh_cpu_interrupt_assert;                  template.interrupt_assert = sh3_cpu_interrupt_assert;
199                  template.interrupt_deassert = sh_cpu_interrupt_deassert;                  template.interrupt_deassert = sh3_cpu_interrupt_deassert;
200                  interrupt_handler_register(&template);                  interrupt_handler_register(&template);
201          }          }
202    
203          /*  SH4-specific memory mapped registers, TLBs, caches, etc:  */          /*  SH4-specific memory mapped registers, TLBs, caches, etc:  */
204          if (cpu->cd.sh.cpu_type.arch == 4)          if (cpu->cd.sh.cpu_type.arch == 4) {
205                  device_add(machine, "sh4");                  cpu->cd.sh.pcic_pcibus = device_add(machine, "sh4");
206    
207                    /*
208                     *  Interrupt Controller initial values, according to the
209                     *  SH7760 manual:
210                     */
211                    cpu->cd.sh.intc_iprd = 0xda74;
212                    cpu->cd.sh.intc_intmsk00 = 0xf3ff7fff;
213                    cpu->cd.sh.intc_intmsk04 = 0x00ffffff;
214                    /*  All others are zero.  */
215    
216                    /*  TODO: Initial priorities?  */
217                    cpu->cd.sh.intc_intpri00 = 0x33333333;
218                    cpu->cd.sh.intc_intpri04 = 0x33333333;
219                    cpu->cd.sh.intc_intpri08 = 0x33333333;
220                    cpu->cd.sh.intc_intpri0c = 0x33333333;
221            }
222    
223            sh_update_interrupt_priorities(cpu);
224    
225          return 1;          return 1;
226  }  }
227    
228    
229  /*  /*
230   *  sh_cpu_interrupt_assert():   *  sh_update_interrupt_priorities():
231     *
232     *  SH interrupts are a bit complicated; there are several intc registers
233     *  controlling priorities for various peripherals:
234     *
235     *  Register:  Bits 15..12  11..8  7..4      3..0
236     *  ---------  -----------  -----  ----      ----
237     *  ipra       TMU0         TMU1   TMU2      Reserved
238     *  iprb       WDT          REF    Reserved  Reserved
239     *  iprc       GPIO         DMAC   Reserved  H-UDI
240     *  iprd       IRL0         IRL1   IRL2      IRL3
241     *
242     *  Register:  31..28  27..24  23..20  19..16  15..12  11..8   7..4   3..0
243     *  ---------  ------  ------  ------  ------  ------  -----   ----   ----
244     *  intpri00   IRQ4    IRQ5    IRQ6    IRQ7    Rsrvd.  Rsrvd.  Rsrvd. Reserved
245     *  intpri04   HCAN2,0 HCAN2,1 SSI(0)  SSI(1)  HAC(0)  HAC(1)  I2C(0) I2C(1)
246     *  intpri08   USB     LCDC    DMABRG  SCIF(0) SCIF(1) SCIF(2) SIM    HSPI
247     *  intpri0c   Reserv. Reserv. MMCIF   Reserv. MFI     Rsrvd.  ADC    CMT
248   */   */
249  void sh_cpu_interrupt_assert(struct interrupt *interrupt)  void sh_update_interrupt_priorities(struct cpu *cpu)
250  {  {
251          struct cpu *cpu = interrupt->extra;          int i;
         int irq_nr = interrupt->line;  
         int word_index, bit_index;  
252    
253          /*          /*
254           *  Note: This gives higher interrupt priority to lower number           *  Set priorities of known interrupts, without affecting the
255           *  interrupts. Hopefully this is correct.           *  SH_INT_ASSERTED bit:
256           */           */
257    
258          if (cpu->cd.sh.int_to_assert == 0 || irq_nr < cpu->cd.sh.int_to_assert)          for (i=SH4_INTEVT_IRQ0; i<=SH4_INTEVT_IRQ14; i+=0x20) {
259                  cpu->cd.sh.int_to_assert = irq_nr;                  cpu->cd.sh.int_prio_and_pending[i/0x20] &= ~SH_INT_PRIO_MASK;
260                    cpu->cd.sh.int_prio_and_pending[i/0x20] |= (15 - ((i -
261                        SH4_INTEVT_IRQ0) / 0x20));
262            }
263    
264            cpu->cd.sh.int_prio_and_pending[SH_INTEVT_TMU0_TUNI0 / 0x20] &=
265                ~SH_INT_PRIO_MASK;
266            cpu->cd.sh.int_prio_and_pending[SH_INTEVT_TMU0_TUNI0 / 0x20] |=
267                (cpu->cd.sh.intc_ipra >> 12) & 0xf;
268    
269            cpu->cd.sh.int_prio_and_pending[SH_INTEVT_TMU1_TUNI1 / 0x20] &=
270                ~SH_INT_PRIO_MASK;
271            cpu->cd.sh.int_prio_and_pending[SH_INTEVT_TMU1_TUNI1 / 0x20] |=
272                (cpu->cd.sh.intc_ipra >> 8) & 0xf;
273    
274            cpu->cd.sh.int_prio_and_pending[SH_INTEVT_TMU2_TUNI2 / 0x20] &=
275                ~SH_INT_PRIO_MASK;
276            cpu->cd.sh.int_prio_and_pending[SH_INTEVT_TMU2_TUNI2 / 0x20] |=
277                (cpu->cd.sh.intc_ipra >> 4) & 0xf;
278    
279            for (i=SH4_INTEVT_SCIF_ERI; i<=SH4_INTEVT_SCIF_TXI; i+=0x20) {
280                    cpu->cd.sh.int_prio_and_pending[i/0x20] &= ~SH_INT_PRIO_MASK;
281                    cpu->cd.sh.int_prio_and_pending[i/0x20] |=
282                        ((cpu->cd.sh.intc_intpri08 >> 16) & 0xf);
283            }
284    }
285    
         /*  
          *  TODO: Keep track of all pending interrupts at multiple levels...  
          *  
          *  This is just a quick hack:  
          */  
         cpu->cd.sh.int_level = 1;  
         if (irq_nr == SH_INTEVT_TMU0_TUNI0)  
                 cpu->cd.sh.int_level = (cpu->cd.sh.intc_ipra >> 12) & 0xf;  
         if (irq_nr == SH_INTEVT_TMU1_TUNI1)  
                 cpu->cd.sh.int_level = (cpu->cd.sh.intc_ipra >> 8) & 0xf;  
         if (irq_nr == SH_INTEVT_TMU2_TUNI2)  
                 cpu->cd.sh.int_level = (cpu->cd.sh.intc_ipra >> 4) & 0xf;  
         if (irq_nr >= SH4_INTEVT_SCIF_ERI &&  
             irq_nr <= SH4_INTEVT_SCIF_TXI)  
                 cpu->cd.sh.int_level = (cpu->cd.sh.intc_iprc >> 4) & 0xf;  
   
         irq_nr /= 0x20;  
         word_index = irq_nr / (sizeof(uint32_t)*8);  
         bit_index = irq_nr & ((sizeof(uint32_t)*8) - 1);  
286    
287          cpu->cd.sh.int_pending[word_index] |= (1 << bit_index);  /*
288     *  sh3_cpu_interrupt_assert():
289     *  sh3_cpu_interrupt_deassert():
290     */
291    void sh3_cpu_interrupt_assert(struct interrupt *interrupt)
292    {
293            /*  TODO  */
294    }
295    void sh3_cpu_interrupt_deassert(struct interrupt *interrupt)
296    {
297            /*  TODO  */
298    }      
299    
300    
301    /*
302     *  sh_cpu_interrupt_assert():
303     */
304    void sh_cpu_interrupt_assert(struct interrupt *interrupt)
305    {
306            struct cpu *cpu = interrupt->extra;
307            unsigned int irq_nr = interrupt->line;
308            unsigned int index = irq_nr / 0x20;
309            unsigned int prio;
310    
311            /*  Assert the interrupt, and check its priority level:  */
312            cpu->cd.sh.int_prio_and_pending[index] |= SH_INT_ASSERTED;
313            prio = cpu->cd.sh.int_prio_and_pending[index] & SH_INT_PRIO_MASK;
314    
315            if (prio == 0) {
316                    /*  Interrupt not implemented? Hm.  */
317                    fatal("[ SH interrupt 0x%x, prio 0 (?), aborting ]\n", irq_nr);
318                    exit(1);
319            }
320    
321            if (cpu->cd.sh.int_to_assert == 0 || prio > cpu->cd.sh.int_level) {
322                    cpu->cd.sh.int_to_assert = irq_nr;
323                    cpu->cd.sh.int_level = prio;
324            }
325  }  }
326    
327    
# Line 240  void sh_cpu_interrupt_deassert(struct in Line 332  void sh_cpu_interrupt_deassert(struct in
332  {  {
333          struct cpu *cpu = interrupt->extra;          struct cpu *cpu = interrupt->extra;
334          int irq_nr = interrupt->line;          int irq_nr = interrupt->line;
335          int word_index, bit_index;          int index = irq_nr / 0x20;
336    
337          if (cpu->cd.sh.int_to_assert == irq_nr) {          /*  Deassert the interrupt:  */
338                  /*          if (cpu->cd.sh.int_prio_and_pending[index] & SH_INT_ASSERTED) {
339                   *  Rescan all interrupts to see if any are still asserted.                  cpu->cd.sh.int_prio_and_pending[index] &= ~SH_INT_ASSERTED;
                  *  
                  *  Note: The scan only has to go from irq_nr + 0x20 to the max  
                  *        index, since any lower interrupt cannot be asserted  
                  *        at this time.  
                  */  
                 int i, max = 0x1000;  
                 cpu->cd.sh.int_to_assert = 0;  
   
                 for (i=irq_nr+0x20; i<max; i+=0x20) {  
                         int j = i / 0x20;  
                         int word_index = j / (sizeof(uint32_t)*8);  
                         int bit_index = j & ((sizeof(uint32_t)*8) - 1);  
   
                         /*  Skip entire word if no bits are set:  */  
                         if (bit_index == 0 &&  
                             cpu->cd.sh.int_pending[word_index] == 0)  
                                 i += (sizeof(uint32_t)*8 - 1) * 0x20;  
                         else if (cpu->cd.sh.int_pending[word_index]  
                             & (1 << bit_index)) {  
                                 cpu->cd.sh.int_to_assert = i;  
   
   
 /*  Hack. TODO: Fix.  */  
         cpu->cd.sh.int_level = 1;  
         if (i == SH_INTEVT_TMU0_TUNI0)  
                 cpu->cd.sh.int_level = (cpu->cd.sh.intc_ipra >> 12) & 0xf;  
         if (i == SH_INTEVT_TMU1_TUNI1)  
                 cpu->cd.sh.int_level = (cpu->cd.sh.intc_ipra >> 8) & 0xf;  
         if (i == SH_INTEVT_TMU2_TUNI2)  
                 cpu->cd.sh.int_level = (cpu->cd.sh.intc_ipra >> 4) & 0xf;  
         if (i >= SH4_INTEVT_SCIF_ERI &&  
             i <= SH4_INTEVT_SCIF_TXI)  
                 cpu->cd.sh.int_level = (cpu->cd.sh.intc_iprc >> 4) & 0xf;  
340    
341                    /*  Calculate new interrupt assertion:  */
342                    cpu->cd.sh.int_to_assert = 0;
343                    cpu->cd.sh.int_level = 0;
344    
345                                  break;                  /*  NOTE/TODO: This is slow, but should hopefully work:  */
346                    for (index=0; index<0x1000/0x20; index++) {
347                            uint8_t x = cpu->cd.sh.int_prio_and_pending[index];
348                            uint8_t prio = x & SH_INT_PRIO_MASK;
349                            if (x & SH_INT_ASSERTED &&
350                                prio > cpu->cd.sh.int_level) {
351                                    cpu->cd.sh.int_to_assert = index * 0x20;
352                                    cpu->cd.sh.int_level = prio;
353                          }                          }
354                  }                  }
355          }          }
   
         irq_nr /= 0x20;  
         word_index = irq_nr / (sizeof(uint32_t)*8);  
         bit_index = irq_nr & ((sizeof(uint32_t)*8) - 1);  
   
         cpu->cd.sh.int_pending[word_index] &= ~(1 << bit_index);  
356  }  }
357    
358    
# Line 390  void sh_cpu_register_dump(struct cpu *cp Line 453  void sh_cpu_register_dump(struct cpu *cp
453  {  {
454          char *symbol;          char *symbol;
455          uint64_t offset;          uint64_t offset;
456          int i, x = cpu->cpu_id, nregs = cpu->cd.sh.compact? 16 : 64;          int i, x = cpu->cpu_id;
457    
458          if (gprs) {          if (gprs) {
459                  /*  Special registers (pc, ...) first:  */                  /*  Special registers (pc, ...) first:  */
# Line 421  void sh_cpu_register_dump(struct cpu *cp Line 484  void sh_cpu_register_dump(struct cpu *cp
484                      "  gbr = 0x%08"PRIx32"\n", x, (uint32_t)cpu->cd.sh.mach,                      "  gbr = 0x%08"PRIx32"\n", x, (uint32_t)cpu->cd.sh.mach,
485                      (uint32_t)cpu->cd.sh.macl, (uint32_t)cpu->cd.sh.gbr);                      (uint32_t)cpu->cd.sh.macl, (uint32_t)cpu->cd.sh.gbr);
486    
487                  for (i=0; i<nregs; i++) {                  for (i=0; i<SH_N_GPRS; i++) {
488                          if ((i % 4) == 0)                          if ((i % 4) == 0)
489                                  debug("cpu%i:", x);                                  debug("cpu%i:", x);
490                          debug(" r%-2i = 0x%08x ", i, (int)cpu->cd.sh.r[i]);                          debug(" r%-2i = 0x%08x ", i, (int)cpu->cd.sh.r[i]);
# Line 432  void sh_cpu_register_dump(struct cpu *cp Line 495  void sh_cpu_register_dump(struct cpu *cp
495    
496          if (coprocs & 1) {          if (coprocs & 1) {
497                  /*  Floating point:  */                  /*  Floating point:  */
498                  debug("cpu%i: fpscr = 0x%08"PRIx32"  fpul = 0x%08"PRIx32                  debug("cpu%i: fpscr = 0x%08"PRIx32" (%s,%s,%s)  fpul = 0x%08"
499                      "\n", x, cpu->cd.sh.fpscr, cpu->cd.sh.fpul);                      PRIx32"\n", x, cpu->cd.sh.fpscr,
500                        cpu->cd.sh.fpscr & SH_FPSCR_PR? "PR" : "!pr",
501                        cpu->cd.sh.fpscr & SH_FPSCR_SZ? "SZ" : "!sz",
502                        cpu->cd.sh.fpscr & SH_FPSCR_FR? "FR" : "!fr",
503                        cpu->cd.sh.fpul);
504    
505                  for (i=0; i<SH_N_FPRS; i++) {                  for (i=0; i<SH_N_FPRS; i++) {
506                          if ((i % 4) == 0)                          if ((i % 4) == 0)
# Line 508  void sh_cpu_tlbdump(struct machine *m, i Line 575  void sh_cpu_tlbdump(struct machine *m, i
575    
576    
577  /*  /*
  *  sh_cpu_gdb_stub():  
  *  
  *  Execute a "remote GDB" command. Returns a newly allocated response string  
  *  on success, NULL on failure.  
  */  
 char *sh_cpu_gdb_stub(struct cpu *cpu, char *cmd)  
 {  
         fatal("sh_cpu_gdb_stub(): TODO\n");  
         return NULL;  
 }  
   
   
 /*  
578   *  sh_update_sr():   *  sh_update_sr():
579   *   *
580   *  Writes a new value to the status register.   *  Writes a new value to the status register.
# Line 569  void sh_update_fpscr(struct cpu *cpu, ui Line 623  void sh_update_fpscr(struct cpu *cpu, ui
623   *   *
624   *  Causes a transfer of control to an exception or interrupt handler.   *  Causes a transfer of control to an exception or interrupt handler.
625   *  If intevt > 0, then it is an interrupt, otherwise an exception.   *  If intevt > 0, then it is an interrupt, otherwise an exception.
626     *
627     *  vaddr contains the faulting address, on TLB exceptions.
628   */   */
629  void sh_exception(struct cpu *cpu, int expevt, int intevt, uint32_t vaddr)  void sh_exception(struct cpu *cpu, int expevt, int intevt, uint32_t vaddr)
630  {  {
# Line 580  void sh_exception(struct cpu *cpu, int e Line 636  void sh_exception(struct cpu *cpu, int e
636                  else                  else
637                          debug("[ exception 0x%03x", expevt);                          debug("[ exception 0x%03x", expevt);
638    
639                  debug(", pc=0x%08"PRIx32" ", (uint32_t)vaddr);                  debug(", pc=0x%08"PRIx32" ", (uint32_t)cpu->pc);
640                  if (intevt == 0)                  if (intevt == 0)
641                          debug("vaddr=0x%08"PRIx32" ", vaddr);                          debug("vaddr=0x%08"PRIx32" ", vaddr);
642    
# Line 588  void sh_exception(struct cpu *cpu, int e Line 644  void sh_exception(struct cpu *cpu, int e
644          }          }
645    
646          if (cpu->cd.sh.sr & SH_SR_BL) {          if (cpu->cd.sh.sr & SH_SR_BL) {
647                  fatal("sh_exception(): BL bit already set. TODO\n");                  fatal("[ sh_exception(): BL bit already set. ]\n");
648    
649                  /*  This is actually OK in two cases: a User Break,                  /*  This is actually OK in two cases: a User Break,
650                      or on NMI interrupts if a special flag is set?  */                      or on NMI interrupts if a special flag is set?  */
# Line 613  void sh_exception(struct cpu *cpu, int e Line 669  void sh_exception(struct cpu *cpu, int e
669                  cpu->pc -= sizeof(uint16_t);                  cpu->pc -= sizeof(uint16_t);
670          }          }
671    
672          /*  Stuff common to all exceptions:  */  
673            /*
674             *  Stuff common to all exceptions:
675             */
676    
677          cpu->cd.sh.spc = cpu->pc;          cpu->cd.sh.spc = cpu->pc;
678          cpu->cd.sh.ssr = cpu->cd.sh.sr;          cpu->cd.sh.ssr = cpu->cd.sh.sr;
679          cpu->cd.sh.sgr = cpu->cd.sh.r[15];          cpu->cd.sh.sgr = cpu->cd.sh.r[15];
680    
681          if (intevt > 0) {          if (intevt > 0) {
682                  cpu->cd.sh.intevt = intevt;                  cpu->cd.sh.intevt = intevt;
683                  expevt = -1;                  expevt = -1;
684          } else          } else {
685                  cpu->cd.sh.expevt = expevt;                  cpu->cd.sh.expevt = expevt;
686            }
687    
688          sh_update_sr(cpu, cpu->cd.sh.sr | SH_SR_MD | SH_SR_RB | SH_SR_BL);          sh_update_sr(cpu, cpu->cd.sh.sr | SH_SR_MD | SH_SR_RB | SH_SR_BL);
689    
690          /*  Most exceptions set PC to VBR + 0x100.  */          /*  Most exceptions set PC to VBR + 0x100.  */
691          cpu->pc = vbr + 0x100;          cpu->pc = vbr + 0x100;
692    
693    
694          /*  Specific cases:  */          /*  Specific cases:  */
695          switch (expevt) {          switch (expevt) {
696    
# Line 653  void sh_exception(struct cpu *cpu, int e Line 717  void sh_exception(struct cpu *cpu, int e
717                  break;                  break;
718    
719          case EXPEVT_TRAPA:          case EXPEVT_TRAPA:
720                  /*  Note: The TRA register is already set by the                  /*
721                      implementation of the trapa instruction. See                   *  Note: The TRA register is already set by the implementation
722                      cpu_sh_instr.c.  */                   *  of the trapa instruction. See cpu_sh_instr.c for details.
723                     *  Here, spc is incremented, so that a return from the trap
724                     *  handler transfers control to the instruction _following_
725                     *  the trapa.
726                     */
727                  cpu->cd.sh.spc += sizeof(uint16_t);                  cpu->cd.sh.spc += sizeof(uint16_t);
728                  break;                  break;
729    
# Line 686  void sh_exception(struct cpu *cpu, int e Line 754  void sh_exception(struct cpu *cpu, int e
754    
755    
756  /*  /*
757   *  sh_cpu_disassemble_instr_compact():   *  sh_cpu_disassemble_instr():
758   *   *
759   *  SHcompact instruction disassembly. The top 4 bits of each 16-bit   *  SHcompact instruction disassembly. The top 4 bits of each 16-bit
760   *  instruction word is used as the main opcode. For most instructions, the   *  instruction word is used as the main opcode. For most instructions, the
761   *  lowest 4 or 8 bits then select sub-opcode.   *  lowest 4 or 8 bits then select sub-opcode.
762     *
763     *  This function convert an instruction word into human readable format,
764     *  for instruction tracing.
765     *
766     *  If running is 1, cpu->pc should be the address of the instruction.
767     *
768     *  If running is 0, things that depend on the runtime environment (eg.
769     *  register contents) will not be shown, and addr will be used instead of
770     *  cpu->pc for relative addresses.
771   */   */
772  int sh_cpu_disassemble_instr_compact(struct cpu *cpu, unsigned char *instr,  int sh_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,
773          int running, uint64_t dumpaddr)          int running, uint64_t dumpaddr)
774  {  {
775          uint64_t addr;          char *symbol;
776            uint64_t offset, addr;
777          uint16_t iword;          uint16_t iword;
778          int hi4, lo4, lo8, r8, r4;          int hi4, lo4, lo8, r8, r4;
779    
780            if (running)
781                    dumpaddr = cpu->pc;
782    
783            symbol = get_symbol_name(&cpu->machine->symbol_context,
784                dumpaddr, &offset);
785            if (symbol != NULL && offset==0)
786                    debug("<%s>\n", symbol);
787    
788            if (cpu->machine->ncpus > 1 && running)
789                    debug("cpu%i: ", cpu->cpu_id);
790    
791            debug("%08"PRIx32, (uint32_t) dumpaddr);
792    
793          if (cpu->byte_order == EMUL_BIG_ENDIAN)          if (cpu->byte_order == EMUL_BIG_ENDIAN)
794                  iword = (instr[0] << 8) + instr[1];                  iword = (instr[0] << 8) + instr[1];
795          else          else
# Line 708  int sh_cpu_disassemble_instr_compact(str Line 799  int sh_cpu_disassemble_instr_compact(str
799          hi4 = iword >> 12; lo4 = iword & 15; lo8 = iword & 255;          hi4 = iword >> 12; lo4 = iword & 15; lo8 = iword & 255;
800          r8 = (iword >> 8) & 15; r4 = (iword >> 4) & 15;          r8 = (iword >> 8) & 15; r4 = (iword >> 4) & 15;
801    
802    
803          /*          /*
804           *  Decode the instruction:           *  Decode the instruction:
805           */           */
# Line 726  int sh_cpu_disassemble_instr_compact(str Line 818  int sh_cpu_disassemble_instr_compact(str
818                          else if (lo4 == 0x6)                          else if (lo4 == 0x6)
819                                  debug("mov.l\tr%i,@(r0,r%i)", r4, r8);                                  debug("mov.l\tr%i,@(r0,r%i)", r4, r8);
820                          if (running) {                          if (running) {
821                                  debug("\t; r0+r%i = 0x%08"PRIx32, r8,                                  uint32_t addr = cpu->cd.sh.r[0] +
822                                      cpu->cd.sh.r[0] + cpu->cd.sh.r[r8]);                                      cpu->cd.sh.r[r8];
823                                    debug("\t; r0+r%i = ", r8);
824                                    symbol = get_symbol_name(
825                                        &cpu->machine->symbol_context,
826                                        addr, &offset);
827                                    if (symbol != NULL)
828                                            debug("<%s>", symbol);
829                                    else
830                                            debug("0x%08"PRIx32, addr);
831                          }                          }
832                          debug("\n");                          debug("\n");
833                  } else if (lo4 == 0x7)                  } else if (lo4 == 0x7)
# Line 748  int sh_cpu_disassemble_instr_compact(str Line 848  int sh_cpu_disassemble_instr_compact(str
848                          else if (lo4 == 0xe)                          else if (lo4 == 0xe)
849                                  debug("mov.l\t@(r0,r%i),r%i", r4, r8);                                  debug("mov.l\t@(r0,r%i),r%i", r4, r8);
850                          if (running) {                          if (running) {
851                                  debug("\t; r0+r%i = 0x%08"PRIx32, r4,                                  uint32_t addr = cpu->cd.sh.r[0] +
852                                      cpu->cd.sh.r[0] + cpu->cd.sh.r[r4]);                                      cpu->cd.sh.r[r4];
853                                    debug("\t; r0+r%i = ", r4);
854                                    symbol = get_symbol_name(
855                                        &cpu->machine->symbol_context,
856                                        addr, &offset);
857                                    if (symbol != NULL)
858                                            debug("<%s>", symbol);
859                                    else
860                                            debug("0x%08"PRIx32, addr);
861                          }                          }
862                          debug("\n");                          debug("\n");
863                  } else if (lo8 == 0x12)                  } else if (lo8 == 0x12)
# Line 812  int sh_cpu_disassemble_instr_compact(str Line 920  int sh_cpu_disassemble_instr_compact(str
920          case 0x1:          case 0x1:
921                  debug("mov.l\tr%i,@(%i,r%i)", r4, lo4 * 4, r8);                  debug("mov.l\tr%i,@(%i,r%i)", r4, lo4 * 4, r8);
922                  if (running) {                  if (running) {
923                          debug("\t; r%i+%i = 0x%08"PRIx32, r8, lo4 * 4,                          uint32_t addr = cpu->cd.sh.r[r8] + lo4 * 4;
924                              cpu->cd.sh.r[r8] + lo4 * 4);                          debug("\t; r%i+%i = ", r8, lo4 * 4);
925                            symbol = get_symbol_name(&cpu->machine->symbol_context,
926                                addr, &offset);
927                            if (symbol != NULL)
928                                    debug("<%s>", symbol);
929                            else
930                                    debug("0x%08"PRIx32, addr);
931                  }                  }
932                  debug("\n");                  debug("\n");
933                  break;                  break;
# Line 960  int sh_cpu_disassemble_instr_compact(str Line 1074  int sh_cpu_disassemble_instr_compact(str
1074                          debug("shlr16\tr%i\n", r8);                          debug("shlr16\tr%i\n", r8);
1075                  else if (lo8 == 0x2a)                  else if (lo8 == 0x2a)
1076                          debug("lds\tr%i,pr\n", r8);                          debug("lds\tr%i,pr\n", r8);
1077                  else if (lo8 == 0x2b)                  else if (lo8 == 0x2b) {
1078                          debug("jmp\t@r%i\n", r8);                          debug("jmp\t@r%i", r8);
1079                  else if (lo8 == 0x2e)                          if (running) {
1080                                    symbol = get_symbol_name(
1081                                        &cpu->machine->symbol_context,
1082                                        cpu->cd.sh.r[r8], &offset);
1083                                    if (symbol != NULL)
1084                                            debug("\t\t; <%s>", symbol);
1085                            }
1086                            debug("\n");
1087                    } else if (lo8 == 0x2e)
1088                          debug("ldc\tr%i,vbr\n", r8);                          debug("ldc\tr%i,vbr\n", r8);
1089                  else if (lo8 == 0x33)                  else if (lo8 == 0x33)
1090                          debug("stc.l\tssr,@-r%i\n", r8);                          debug("stc.l\tssr,@-r%i\n", r8);
# Line 1072  int sh_cpu_disassemble_instr_compact(str Line 1194  int sh_cpu_disassemble_instr_compact(str
1194                  } else if (r8 == 0x9 || r8 == 0xb || r8 == 0xd || r8 == 0xf) {                  } else if (r8 == 0x9 || r8 == 0xb || r8 == 0xd || r8 == 0xf) {
1195                          addr = (int8_t)lo8;                          addr = (int8_t)lo8;
1196                          addr = dumpaddr + 4 + (addr << 1);                          addr = dumpaddr + 4 + (addr << 1);
1197                          debug("b%s%s\t0x%x\n",                          debug("b%s%s\t0x%x",
1198                              (r8 == 0x9 || r8 == 0xd)? "t" : "f",                              (r8 == 0x9 || r8 == 0xd)? "t" : "f",
1199                              (r8 == 0x9 || r8 == 0xb)? "" : "/s", (int)addr);                              (r8 == 0x9 || r8 == 0xb)? "" : "/s", (int)addr);
1200                            symbol = get_symbol_name(&cpu->machine->symbol_context,
1201                                addr, &offset);
1202                            if (symbol != NULL)
1203                                    debug("\t; <%s>", symbol);
1204                            debug("\n");
1205                  } else                  } else
1206                          debug("UNIMPLEMENTED hi4=0x%x,0x%x\n", hi4, r8);                          debug("UNIMPLEMENTED hi4=0x%x,0x%x\n", hi4, r8);
1207                  break;                  break;
# Line 1082  int sh_cpu_disassemble_instr_compact(str Line 1209  int sh_cpu_disassemble_instr_compact(str
1209          case 0xd:          case 0xd:
1210                  addr = lo8 * (hi4==9? 2 : 4);                  addr = lo8 * (hi4==9? 2 : 4);
1211                  addr += (dumpaddr & ~(hi4==9? 1 : 3)) + 4;                  addr += (dumpaddr & ~(hi4==9? 1 : 3)) + 4;
1212                  debug("mov.%s\t0x%x,r%i\n", hi4==9? "w":"l", (int)addr, r8);                  debug("mov.%s\t0x%x,r%i", hi4==9? "w":"l", (int)addr, r8);
1213                    symbol = get_symbol_name(&cpu->machine->symbol_context,
1214                        addr, &offset);
1215                    if (symbol != NULL)
1216                            debug("\t; <%s>", symbol);
1217                    debug("\n");
1218                  break;                  break;
1219          case 0xa:          case 0xa:
1220          case 0xb:          case 0xb:
1221                  addr = (int32_t)(int16_t)((iword & 0xfff) << 4);                  addr = (int32_t)(int16_t)((iword & 0xfff) << 4);
1222                  addr = ((int32_t)addr >> 3);                  addr = ((int32_t)addr >> 3);
1223                  addr += dumpaddr + 4;                  addr += dumpaddr + 4;
1224                  debug("%s\t0x%x\n", hi4==0xa? "bra":"bsr", (int)addr);                  debug("%s\t0x%x", hi4==0xa? "bra":"bsr", (int)addr);
1225    
1226                    symbol = get_symbol_name(&cpu->machine->symbol_context,
1227                        addr, &offset);
1228                    if (symbol != NULL)
1229                            debug("\t; <%s>", symbol);
1230                    debug("\n");
1231                  break;                  break;
1232          case 0xc:          case 0xc:
1233                  if (r8 == 0x0)                  if (r8 == 0x0)
# Line 1229  int sh_cpu_disassemble_instr_compact(str Line 1367  int sh_cpu_disassemble_instr_compact(str
1367                          debug("fldi0\tfr%i\n", r8);                          debug("fldi0\tfr%i\n", r8);
1368                  else if (lo8 == 0x9d)                  else if (lo8 == 0x9d)
1369                          debug("fldi1\tfr%i\n", r8);                          debug("fldi1\tfr%i\n", r8);
1370                    else if (lo8 == 0xad)
1371                            debug("fcnvsd\tfpul,dr%i\n", r8);
1372                    else if (lo8 == 0xbd)
1373                            debug("fcnvds\tdr%i,fpul\n", r8);
1374                  else if ((iword & 0x01ff) == 0x00fd)                  else if ((iword & 0x01ff) == 0x00fd)
1375                          debug("fsca\tfpul,dr%i\n", r8);                          debug("fsca\tfpul,dr%i\n", r8);
1376                  else if (iword == 0xf3fd)                  else if (iword == 0xf3fd)
# Line 1247  int sh_cpu_disassemble_instr_compact(str Line 1389  int sh_cpu_disassemble_instr_compact(str
1389    
1390          return sizeof(iword);          return sizeof(iword);
1391  }  }
   
   
 /*  
  *  sh_cpu_disassemble_instr():  
  *  
  *  Convert an instruction word into human readable format, for instruction  
  *  tracing.  
  *  
  *  If running is 1, cpu->pc should be the address of the instruction.  
  *  
  *  If running is 0, things that depend on the runtime environment (eg.  
  *  register contents) will not be shown, and addr will be used instead of  
  *  cpu->pc for relative addresses.  
  */  
 int sh_cpu_disassemble_instr(struct cpu *cpu, unsigned char *instr,  
         int running, uint64_t dumpaddr)  
 {  
         uint64_t offset;  
         uint32_t iword;  
         char *symbol;  
   
         if (running)  
                 dumpaddr = cpu->pc;  
   
         symbol = get_symbol_name(&cpu->machine->symbol_context,  
             dumpaddr, &offset);  
         if (symbol != NULL && offset==0)  
                 debug("<%s>\n", symbol);  
   
         if (cpu->machine->ncpus > 1 && running)  
                 debug("cpu%i: ", cpu->cpu_id);  
   
         if (cpu->cd.sh.cpu_type.bits == 32)  
                 debug("%08x", (int)dumpaddr);  
         else  
                 debug("%016llx", (long long)dumpaddr);  
   
         if (cpu->cd.sh.compact)  
                 return sh_cpu_disassemble_instr_compact(cpu, instr,  
                     running, dumpaddr);  
   
         if (cpu->byte_order == EMUL_BIG_ENDIAN)  
                 iword = (instr[0] << 24) + (instr[1] << 16) + (instr[2] << 8)  
                     + instr[3];  
         else  
                 iword = (instr[3] << 24) + (instr[2] << 16) + (instr[1] << 8)  
                     + instr[0];  
   
         debug(": %08x\t", iword);  
   
         /*  
          *  Decode the instruction:  
          */  
   
         debug("TODO\n");  
   
         return sizeof(iword);  
 }  
1392    
1393    
1394  #include "tmp_sh_tail.c"  #include "tmp_sh_tail.c"

Legend:
Removed from v.36  
changed lines
  Added in v.44

  ViewVC Help
Powered by ViewVC 1.1.26