/[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 33 by dpavlin, Mon Oct 8 16:20:58 2007 UTC revision 34 by dpavlin, Mon Oct 8 16:21:17 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2005-2006  Anders Gavare.  All rights reserved.   *  Copyright (C) 2005-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_sh.c,v 1.53 2006/10/31 11:07:05 debug Exp $   *  $Id: cpu_sh.c,v 1.60 2007/01/05 17:42:23 debug Exp $
29   *   *
30   *  Hitachi SuperH ("SH") CPU emulation.   *  Hitachi SuperH ("SH") CPU emulation.
31   *   *
# Line 42  Line 42 
42  #include "cpu.h"  #include "cpu.h"
43  #include "device.h"  #include "device.h"
44  #include "float_emul.h"  #include "float_emul.h"
45    #include "interrupt.h"
46  #include "machine.h"  #include "machine.h"
47  #include "memory.h"  #include "memory.h"
48  #include "misc.h"  #include "misc.h"
# Line 132  int sh_cpu_new(struct cpu *cpu, struct m Line 133  int sh_cpu_new(struct cpu *cpu, struct m
133          CPU_SETTINGS_ADD_REGISTER32("gbr", cpu->cd.sh.gbr);          CPU_SETTINGS_ADD_REGISTER32("gbr", cpu->cd.sh.gbr);
134          CPU_SETTINGS_ADD_REGISTER32("macl", cpu->cd.sh.macl);          CPU_SETTINGS_ADD_REGISTER32("macl", cpu->cd.sh.macl);
135          CPU_SETTINGS_ADD_REGISTER32("mach", cpu->cd.sh.mach);          CPU_SETTINGS_ADD_REGISTER32("mach", cpu->cd.sh.mach);
136            CPU_SETTINGS_ADD_REGISTER32("expevt", cpu->cd.sh.expevt);
137            CPU_SETTINGS_ADD_REGISTER32("intevt", cpu->cd.sh.intevt);
138            CPU_SETTINGS_ADD_REGISTER32("tra", cpu->cd.sh.tra);
139          CPU_SETTINGS_ADD_REGISTER32("fpscr", cpu->cd.sh.fpscr);          CPU_SETTINGS_ADD_REGISTER32("fpscr", cpu->cd.sh.fpscr);
140          CPU_SETTINGS_ADD_REGISTER32("fpul", cpu->cd.sh.fpul);          CPU_SETTINGS_ADD_REGISTER32("fpul", cpu->cd.sh.fpul);
141          for (i=0; i<SH_N_GPRS; i++) {          for (i=0; i<SH_N_GPRS; i++) {
# Line 166  int sh_cpu_new(struct cpu *cpu, struct m Line 170  int sh_cpu_new(struct cpu *cpu, struct m
170                  CPU_SETTINGS_ADD_REGISTER32(tmpstr, cpu->cd.sh.utlb_lo[i]);                  CPU_SETTINGS_ADD_REGISTER32(tmpstr, cpu->cd.sh.utlb_lo[i]);
171          }          }
172    
173            /*  Register the CPU's interrupts:  */
174            for (i=SH_INTEVT_NMI; i<0x1000; i+=0x20) {
175                    struct interrupt template;
176                    char name[100];
177                    snprintf(name, sizeof(name), "%s.irq[0x%x]", cpu->path, i);
178                    memset(&template, 0, sizeof(template));
179                    template.line = i;
180                    template.name = name;
181                    template.extra = cpu;
182                    template.interrupt_assert = sh_cpu_interrupt_assert;
183                    template.interrupt_deassert = sh_cpu_interrupt_deassert;
184                    interrupt_handler_register(&template);
185            }
186    
187          /*  SH4-specific memory mapped registers, TLBs, caches, etc:  */          /*  SH4-specific memory mapped registers, TLBs, caches, etc:  */
188          if (cpu->cd.sh.cpu_type.arch == 4)          if (cpu->cd.sh.cpu_type.arch == 4)
189                  device_add(machine, "sh4");                  device_add(machine, "sh4");
# Line 175  int sh_cpu_new(struct cpu *cpu, struct m Line 193  int sh_cpu_new(struct cpu *cpu, struct m
193    
194    
195  /*  /*
196     *  sh_cpu_interrupt_assert():
197     */
198    void sh_cpu_interrupt_assert(struct interrupt *interrupt)
199    {
200            struct cpu *cpu = interrupt->extra;
201            int irq_nr = interrupt->line;
202            int word_index, bit_index;
203    
204            /*
205             *  Note: This gives higher interrupt priority to lower number
206             *  interrupts. Hopefully this is correct.
207             */
208    
209            if (cpu->cd.sh.int_to_assert == 0 || irq_nr < cpu->cd.sh.int_to_assert)
210                    cpu->cd.sh.int_to_assert = irq_nr;
211    
212            /*
213             *  TODO: Keep track of all pending interrupts at multiple levels...
214             *
215             *  This is just a quick hack:
216             */
217            cpu->cd.sh.int_level = 1;
218            if (irq_nr == SH_INTEVT_TMU0_TUNI0)
219                    cpu->cd.sh.int_level = (cpu->cd.sh.intc_ipra >> 12) & 0xf;
220            if (irq_nr == SH_INTEVT_TMU1_TUNI1)
221                    cpu->cd.sh.int_level = (cpu->cd.sh.intc_ipra >> 8) & 0xf;
222            if (irq_nr == SH_INTEVT_TMU2_TUNI2)
223                    cpu->cd.sh.int_level = (cpu->cd.sh.intc_ipra >> 4) & 0xf;
224            if (irq_nr >= SH4_INTEVT_SCIF_ERI &&
225                irq_nr <= SH4_INTEVT_SCIF_TXI)
226                    cpu->cd.sh.int_level = (cpu->cd.sh.intc_iprc >> 4) & 0xf;
227    
228            irq_nr /= 0x20;
229            word_index = irq_nr / (sizeof(uint32_t)*8);
230            bit_index = irq_nr & ((sizeof(uint32_t)*8) - 1);
231    
232            cpu->cd.sh.int_pending[word_index] |= (1 << bit_index);
233    }
234    
235    
236    /*
237     *  sh_cpu_interrupt_deassert():
238     */
239    void sh_cpu_interrupt_deassert(struct interrupt *interrupt)
240    {
241            struct cpu *cpu = interrupt->extra;
242            int irq_nr = interrupt->line;
243            int word_index, bit_index;
244    
245            if (cpu->cd.sh.int_to_assert == irq_nr) {
246                    /*
247                     *  Rescan all interrupts to see if any are still asserted.
248                     *
249                     *  Note: The scan only has to go from irq_nr + 0x20 to the max
250                     *        index, since any lower interrupt cannot be asserted
251                     *        at this time.
252                     */
253                    int i, max = 0x1000;
254                    cpu->cd.sh.int_to_assert = 0;
255    
256                    for (i=irq_nr+0x20; i<max; i+=0x20) {
257                            int j = i / 0x20;
258                            int word_index = j / (sizeof(uint32_t)*8);
259                            int bit_index = j & ((sizeof(uint32_t)*8) - 1);
260    
261                            /*  Skip entire word if no bits are set:  */
262                            if (bit_index == 0 &&
263                                cpu->cd.sh.int_pending[word_index] == 0)
264                                    i += (sizeof(uint32_t)*8 - 1) * 0x20;
265                            else if (cpu->cd.sh.int_pending[word_index]
266                                & (1 << bit_index)) {
267                                    cpu->cd.sh.int_to_assert = i;
268    
269    
270    /*  Hack. TODO: Fix.  */
271            cpu->cd.sh.int_level = 1;
272            if (i == SH_INTEVT_TMU0_TUNI0)
273                    cpu->cd.sh.int_level = (cpu->cd.sh.intc_ipra >> 12) & 0xf;
274            if (i == SH_INTEVT_TMU1_TUNI1)
275                    cpu->cd.sh.int_level = (cpu->cd.sh.intc_ipra >> 8) & 0xf;
276            if (i == SH_INTEVT_TMU2_TUNI2)
277                    cpu->cd.sh.int_level = (cpu->cd.sh.intc_ipra >> 4) & 0xf;
278            if (i >= SH4_INTEVT_SCIF_ERI &&
279                i <= SH4_INTEVT_SCIF_TXI)
280                    cpu->cd.sh.int_level = (cpu->cd.sh.intc_iprc >> 4) & 0xf;
281    
282    
283                                    break;
284                            }
285                    }
286            }
287    
288            irq_nr /= 0x20;
289            word_index = irq_nr / (sizeof(uint32_t)*8);
290            bit_index = irq_nr & ((sizeof(uint32_t)*8) - 1);
291    
292            cpu->cd.sh.int_pending[word_index] &= ~(1 << bit_index);
293    }
294    
295    
296    /*
297   *  sh_cpu_list_available_types():   *  sh_cpu_list_available_types():
298   *   *
299   *  Print a list of available SH CPU types.   *  Print a list of available SH CPU types.
# Line 402  char *sh_cpu_gdb_stub(struct cpu *cpu, c Line 521  char *sh_cpu_gdb_stub(struct cpu *cpu, c
521    
522    
523  /*  /*
  *  sh_cpu_interrupt():  
  *  
  *  Note: This gives higher interrupt priority to lower number interrupts.  
  *        Hopefully this is correct.  
  */  
 int sh_cpu_interrupt(struct cpu *cpu, uint64_t irq_nr)  
 {  
         int word_index, bit_index;  
   
         if (cpu->cd.sh.int_to_assert == 0 || irq_nr < cpu->cd.sh.int_to_assert)  
                 cpu->cd.sh.int_to_assert = irq_nr;  
   
         /*  
          *  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);  
   
         cpu->cd.sh.int_pending[word_index] |= (1 << bit_index);  
   
         return 0;  
 }  
   
   
 /*  
  *  sh_cpu_interrupt_ack():  
  */  
 int sh_cpu_interrupt_ack(struct cpu *cpu, uint64_t irq_nr)  
 {  
         int word_index, bit_index;  
   
         if (cpu->cd.sh.int_to_assert == irq_nr) {  
                 /*  
                  *  Rescan all interrupts to see if any are still 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;  
                                 break;  
                         }  
                 }  
         }  
   
         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);  
   
         return 0;  
 }  
   
   
 /*  
524   *  sh_update_sr():   *  sh_update_sr():
525   *   *
526   *  Writes a new value to the status register.   *  Writes a new value to the status register.
# Line 624  void sh_exception(struct cpu *cpu, int e Line 659  void sh_exception(struct cpu *cpu, int e
659                  cpu->cd.sh.spc += sizeof(uint16_t);                  cpu->cd.sh.spc += sizeof(uint16_t);
660                  break;                  break;
661    
662    #if 0
663            /*  Not yet. It's probably better to abort the emulator for now,
664                to detect this condition. It is unlikely to happen in normal
665                software.  */
666            case EXPEVT_RES_INST:
667                    break;
668    #endif
669    
670            case EXPEVT_FPU_DISABLE:
671                    break;
672    
673          default:fatal("sh_exception(): exception 0x%x is not yet "          default:fatal("sh_exception(): exception 0x%x is not yet "
674                      "implemented.\n", expevt);                      "implemented.\n", expevt);
675                  exit(1);                  exit(1);
# Line 666  int sh_cpu_disassemble_instr_compact(str Line 712  int sh_cpu_disassemble_instr_compact(str
712                          debug("stc\tsr,r%i\n", r8);                          debug("stc\tsr,r%i\n", r8);
713                  else if (lo8 == 0x03)                  else if (lo8 == 0x03)
714                          debug("bsrf\tr%i\n", r8);                          debug("bsrf\tr%i\n", r8);
715                  else if (lo4 == 0x4)                  else if (lo4 >= 4 && lo4 <= 6) {
716                          debug("mov.b\tr%i,@(r0,r%i)\n", r4, r8);                          if (lo4 == 0x4)
717                  else if (lo4 == 0x5)                                  debug("mov.b\tr%i,@(r0,r%i)", r4, r8);
718                          debug("mov.w\tr%i,@(r0,r%i)\n", r4, r8);                          else if (lo4 == 0x5)
719                  else if (lo4 == 0x6)                                  debug("mov.w\tr%i,@(r0,r%i)", r4, r8);
720                          debug("mov.l\tr%i,@(r0,r%i)\n", r4, r8);                          else if (lo4 == 0x6)
721                  else if (lo4 == 0x7)                                  debug("mov.l\tr%i,@(r0,r%i)", r4, r8);
722                            if (running) {
723                                    debug("\t; r0+r%i = 0x%08"PRIx32, r8,
724                                        cpu->cd.sh.r[0] + cpu->cd.sh.r[r8]);
725                            }
726                            debug("\n");
727                    } else if (lo4 == 0x7)
728                          debug("mul.l\tr%i,r%i\n", r4, r8);                          debug("mul.l\tr%i,r%i\n", r4, r8);
729                  else if (iword == 0x0008)                  else if (iword == 0x0008)
730                          debug("clrt\n");                          debug("clrt\n");
# Line 682  int sh_cpu_disassemble_instr_compact(str Line 734  int sh_cpu_disassemble_instr_compact(str
734                          debug("sts\tmach,r%i\n", r8);                          debug("sts\tmach,r%i\n", r8);
735                  else if (iword == 0x000b)                  else if (iword == 0x000b)
736                          debug("rts\n");                          debug("rts\n");
737                  else if (lo4 == 0xc)                  else if (lo4 >= 0xc && lo4 <= 0xe) {
738                          debug("mov.b\t@(r0,r%i),r%i\n", r4, r8);                          if (lo4 == 0xc)
739                  else if (lo4 == 0xd)                                  debug("mov.b\t@(r0,r%i),r%i", r4, r8);
740                          debug("mov.w\t@(r0,r%i),r%i\n", r4, r8);                          else if (lo4 == 0xd)
741                  else if (lo4 == 0xe)                                  debug("mov.w\t@(r0,r%i),r%i", r4, r8);
742                          debug("mov.l\t@(r0,r%i),r%i\n", r4, r8);                          else if (lo4 == 0xe)
743                  else if (lo8 == 0x12)                                  debug("mov.l\t@(r0,r%i),r%i", r4, r8);
744                            if (running) {
745                                    debug("\t; r0+r%i = 0x%08"PRIx32, r4,
746                                        cpu->cd.sh.r[0] + cpu->cd.sh.r[r4]);
747                            }
748                            debug("\n");
749                    } else if (lo8 == 0x12)
750                          debug("stc\tgbr,r%i\n", r8);                          debug("stc\tgbr,r%i\n", r8);
751                  else if (iword == 0x0018)                  else if (iword == 0x0018)
752                          debug("sett\n");                          debug("sett\n");
# Line 740  int sh_cpu_disassemble_instr_compact(str Line 798  int sh_cpu_disassemble_instr_compact(str
798                          debug("movca.l\tr0,@r%i\n", r8);                          debug("movca.l\tr0,@r%i\n", r8);
799                  else if (lo8 == 0xfa)                  else if (lo8 == 0xfa)
800                          debug("stc\tdbr,r%i\n", r8);                          debug("stc\tdbr,r%i\n", r8);
801                  else if (iword == 0x00ff)                  else if (iword == SH_INVALID_INSTR)
802                          debug("gxemul_dreamcast_prom_emul\n");                          debug("gxemul_dreamcast_prom_emul\n");
803                  else                  else
804                          debug("UNIMPLEMENTED hi4=0x%x, lo8=0x%02x\n", hi4, lo8);                          debug("UNIMPLEMENTED hi4=0x%x, lo8=0x%02x\n", hi4, lo8);
805                  break;                  break;
806          case 0x1:          case 0x1:
807                  debug("mov.l\tr%i,@(%i,r%i)\n", r4, lo4 * 4, r8);                  debug("mov.l\tr%i,@(%i,r%i)", r4, lo4 * 4, r8);
808                    if (running) {
809                            debug("\t; r%i+%i = 0x%08"PRIx32, r8, lo4 * 4,
810                                cpu->cd.sh.r[r8] + lo4 * 4);
811                    }
812                    debug("\n");
813                  break;                  break;
814          case 0x2:          case 0x2:
815                  if (lo4 == 0x0)                  if (lo4 == 0x0)
# Line 931  int sh_cpu_disassemble_instr_compact(str Line 994  int sh_cpu_disassemble_instr_compact(str
994                          debug("UNIMPLEMENTED hi4=0x%x, lo8=0x%02x\n", hi4, lo8);                          debug("UNIMPLEMENTED hi4=0x%x, lo8=0x%02x\n", hi4, lo8);
995                  break;                  break;
996          case 0x5:          case 0x5:
997                  debug("mov.l\t@(%i,r%i),r%i\n", lo4 * 4, r4, r8);                  debug("mov.l\t@(%i,r%i),r%i", lo4 * 4, r4, r8);
998                    if (running) {
999                            debug("\t; r%i+%i = 0x%08"PRIx32, r4, lo4 * 4,
1000                                cpu->cd.sh.r[r4] + lo4 * 4);
1001                    }
1002                    debug("\n");
1003                  break;                  break;
1004          case 0x6:          case 0x6:
1005                  if (lo4 == 0x0)                  if (lo4 == 0x0)
# Line 973  int sh_cpu_disassemble_instr_compact(str Line 1041  int sh_cpu_disassemble_instr_compact(str
1041                  debug("add\t#%i,r%i\n", (int8_t)lo8, r8);                  debug("add\t#%i,r%i\n", (int8_t)lo8, r8);
1042                  break;                  break;
1043          case 0x8:          case 0x8:
1044                  if (r8 == 0x0) {                  if (r8 == 0 || r8 == 4) {
1045                          debug("mov.b\tr0,@(%i,r%i)\n", lo4, r4);                          if (r8 == 0x0)
1046                  } else if (r8 == 0x1) {                                  debug("mov.b\tr0,@(%i,r%i)", lo4, r4);
1047                          debug("mov.w\tr0,@(%i,r%i)\n", lo4 * 2, r4);                          else if (r8 == 0x4)
1048                  } else if (r8 == 0x4) {                                  debug("mov.b\t@(%i,r%i),r0", lo4, r4);
1049                          debug("mov.b\t@(%i,r%i),r0\n", lo4, r4);                          if (running) {
1050                  } else if (r8 == 0x5) {                                  debug("\t; r%i+%i = 0x%08"PRIx32, r4, lo4,
1051                          debug("mov.w\t@(%i,r%i),r0\n", lo4 * 2, r4);                                      cpu->cd.sh.r[r4] + lo4);
1052                            }
1053                            debug("\n");
1054                    } else if (r8 == 1 || r8 == 5) {
1055                            if (r8 == 0x1)
1056                                    debug("mov.w\tr0,@(%i,r%i)", lo4 * 2, r4);
1057                            else if (r8 == 0x5)
1058                                    debug("mov.w\t@(%i,r%i),r0", lo4 * 2, r4);
1059                            if (running) {
1060                                    debug("\t; r%i+%i = 0x%08"PRIx32, r4, lo4 * 2,
1061                                        cpu->cd.sh.r[r4] + lo4 * 2);
1062                            }
1063                            debug("\n");
1064                  } else if (r8 == 0x8) {                  } else if (r8 == 0x8) {
1065                          debug("cmp/eq\t#%i,r0\n", (int8_t)lo8);                          debug("cmp/eq\t#%i,r0\n", (int8_t)lo8);
1066                  } else if (r8 == 0x9 || r8 == 0xb || r8 == 0xd || r8 == 0xf) {                  } else if (r8 == 0x9 || r8 == 0xb || r8 == 0xd || r8 == 0xf) {

Legend:
Removed from v.33  
changed lines
  Added in v.34

  ViewVC Help
Powered by ViewVC 1.1.26