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

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

revision 14 by dpavlin, Mon Oct 8 16:18:51 2007 UTC revision 32 by dpavlin, Mon Oct 8 16:20:58 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2006  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_coproc.c,v 1.2 2005/09/11 10:37:37 debug Exp $   *  $Id: cpu_mips_coproc.c,v 1.60 2006/10/14 23:47:37 debug Exp $
29   *   *
30   *  Emulation of MIPS coprocessors.   *  Emulation of MIPS coprocessors.
31   */   */
# Line 35  Line 35 
35  #include <string.h>  #include <string.h>
36  #include <math.h>  #include <math.h>
37    
 #include "bintrans.h"  
38  #include "cop0.h"  #include "cop0.h"
39  #include "cpu.h"  #include "cpu.h"
40  #include "cpu_mips.h"  #include "cpu_mips.h"
41  #include "emul.h"  #include "emul.h"
42    #include "float_emul.h"
43  #include "machine.h"  #include "machine.h"
44  #include "memory.h"  #include "memory.h"
45  #include "mips_cpu_types.h"  #include "mips_cpu_types.h"
46  #include "misc.h"  #include "misc.h"
47  #include "opcodes_mips.h"  #include "opcodes_mips.h"
48    #include "timer.h"
49    
50    
51  #ifndef ENABLE_MIPS  #ifndef ENABLE_MIPS
# Line 68  static char *cop0_names[] = COP0_NAMES; Line 69  static char *cop0_names[] = COP0_NAMES;
69  static char *regnames[] = MIPS_REGISTER_NAMES;  static char *regnames[] = MIPS_REGISTER_NAMES;
70    
71    
 /*  FPU control registers:  */  
 #define FPU_FCIR        0  
 #define FPU_FCCR        25  
 #define FPU_FCSR        31  
 #define   FCSR_FCC0_SHIFT         23  
 #define   FCSR_FCC1_SHIFT         25  
   
   
72  /*  /*
73   *  initialize_cop0_config():   *  initialize_cop0_config():
74   *   *
# Line 83  static char *regnames[] = MIPS_REGISTER_ Line 76  static char *regnames[] = MIPS_REGISTER_
76   */   */
77  static void initialize_cop0_config(struct cpu *cpu, struct mips_coproc *c)  static void initialize_cop0_config(struct cpu *cpu, struct mips_coproc *c)
78  {  {
79  #ifdef ENABLE_MIPS16          const int m16 = 0;      /*  TODO: MIPS16 support  */
80          const int m16 = 1;          int IB, DB, SB, IC, DC, SC, IA, DA;
81  #else  
82          const int m16 = 0;          /*  Generic case for MIPS32/64:  */
83  #endif          if (cpu->cd.mips.cpu_type.isa_level == 32 ||
84          int cpu_type, IB, DB, SB, IC, DC, SC, IA, DA;              cpu->cd.mips.cpu_type.isa_level == 64) {
85                    /*  According to the MIPS64 (5K) User's Manual:  */
86                    c->reg[COP0_CONFIG] =
87                          (   (uint32_t)1 << 31)/*  Config 1 present bit  */
88                        | (   0 << 20)      /*  ISD:  instruction scheduling
89                                                disable (=1)  */
90                        | (   0 << 17)      /*  DID:  dual issue disable  */
91                        | (   0 << 16)      /*  BM:   burst mode  */
92                        | ((cpu->byte_order == EMUL_BIG_ENDIAN? 1 : 0) << 15)
93                                            /*  endian mode  */
94                        | ((cpu->cd.mips.cpu_type.isa_level == 64? 2 : 0) << 13)
95                                            /*  0=MIPS32, 1=64S, 2=64  */
96                        | (   0 << 10)      /*  Architecture revision  */
97                        | (   1 <<  7)      /*  MMU type: 1=TLB, 3=FMT  */
98                        | (   2 <<  0)      /*  kseg0 cache coherency algorithm  */
99                        ;
100                    /*  Config select 1: caches etc. TODO: Don't use
101                            cpu->machine for this stuff!  */
102                    IB = cpu->machine->cache_picache_linesize - 1;
103                    IB = IB < 0? 0 : (IB > 7? 7 : IB);
104                    DB = cpu->machine->cache_pdcache_linesize - 1;
105                    DB = DB < 0? 0 : (DB > 7? 7 : DB);
106                    IC = cpu->machine->cache_picache -
107                        cpu->machine->cache_picache_linesize - 7;
108                    DC = cpu->machine->cache_pdcache -
109                        cpu->machine->cache_pdcache_linesize - 7;
110                    IA = cpu->cd.mips.cpu_type.piways - 1;
111                    DA = cpu->cd.mips.cpu_type.pdways - 1;
112                    cpu->cd.mips.cop0_config_select1 =
113                        ((cpu->cd.mips.cpu_type.nr_of_tlb_entries - 1) << 25)
114                        | (IC << 22)        /*  IS: I-cache sets per way  */
115                        | (IB << 19)        /*  IL: I-cache line-size  */
116                        | (IA << 16)        /*  IA: I-cache assoc. (ways-1)  */
117                        | (DC << 13)        /*  DS: D-cache sets per way  */
118                        | (DB << 10)        /*  DL: D-cache line-size  */
119                        | (DA <<  7)        /*  DA: D-cache assoc. (ways-1)  */
120                        | (16 * 0)          /*  Existance of PerformanceCounters  */
121                        | ( 8 * 0)          /*  Existance of Watch Registers  */
122                        | ( 4 * m16)        /*  Existance of MIPS16  */
123                        | ( 2 * 0)          /*  Existance of EJTAG  */
124                        | ( 1 * 1)          /*  Existance of FPU  */
125                        ;
126    
127          /*  Default values:  */                  return;
128          c->reg[COP0_CONFIG] =          }
               (   0 << 31)      /*  config1 present  */  
             | (0x00 << 16)      /*  implementation dependant  */  
             | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)  
                                 /*  endian mode  */  
             | (   2 << 13)      /*  0 = MIPS32,  
                                     1 = MIPS64 with 32-bit segments,  
                                     2 = MIPS64 with all segments,  
                                     3 = reserved  */  
             | (   0 << 10)      /*  architecture revision level,  
                                     0 = "Revision 1", other  
                                     values are reserved  */  
             | (   1 <<  7)      /*  MMU type:  0 = none,  
                                     1 = Standard TLB,  
                                     2 = Standard BAT,  
                                     3 = fixed mapping, 4-7=reserved  */  
             | (   0 <<  0)      /*  kseg0 coherency algorithm  
                                 (TODO)  */  
             ;  
   
         cpu_type = cpu->cd.mips.cpu_type.rev & 0xff;  
   
         /*  AU1x00 are treated as 4Kc (MIPS32 cores):  */  
         if ((cpu->cd.mips.cpu_type.rev & 0xffff) == 0x0301)  
                 cpu_type = MIPS_4Kc;  
129    
130          switch (cpu_type) {          switch (cpu->cd.mips.cpu_type.rev) {
131            case MIPS_R2000:
132            case MIPS_R3000:
133                    /*  No config register.  */
134                    break;
135          case MIPS_R4000:        /*  according to the R4000 manual  */          case MIPS_R4000:        /*  according to the R4000 manual  */
136          case MIPS_R4600:          case MIPS_R4600:
137                  IB = cpu->machine->cache_picache_linesize - 4;                  IB = cpu->machine->cache_picache_linesize - 4;
# Line 302  static void initialize_cop0_config(struc Line 316  static void initialize_cop0_config(struc
316                                                  (TODO)  */                                                  (TODO)  */
317                      ;                      ;
318                  break;                  break;
319          case MIPS_4Kc:          default:fatal("Internal error: No initialization code for"
320          case MIPS_5Kc:                      " config0? cpu rev = 0x%x", cpu->cd.mips.cpu_type.rev);
321                  /*  According to the MIPS64 (5K) User's Manual:  */                  exit(1);
                 c->reg[COP0_CONFIG] =  
                       (   (uint32_t)1 << 31)/*  Config 1 present bit  */  
                     | (   0 << 20)      /*  ISD:  instruction scheduling  
                                             disable (=1)  */  
                     | (   0 << 17)      /*  DID:  dual issue disable  */  
                     | (   0 << 16)      /*  BM:   burst mode  */  
                     | ((cpu->byte_order == EMUL_BIG_ENDIAN? 1 : 0) << 15)  
                                         /*  endian mode  */  
                     | ((cpu_type == MIPS_5Kc? 2 : 0) << 13)  
                                         /*  0=MIPS32, 1=64S, 2=64  */  
                     | (   0 << 10)      /*  Architecture revision  */  
                     | (   1 <<  7)      /*  MMU type: 1=TLB, 3=FMT  */  
                     | (   2 <<  0)      /*  kseg0 cache coherency algorithm  */  
                     ;  
                 /*  Config select 1: caches etc. TODO: Don't use  
                         cpu->machine for this stuff!  */  
                 IB = cpu->machine->cache_picache_linesize - 1;  
                 IB = IB < 0? 0 : (IB > 7? 7 : IB);  
                 DB = cpu->machine->cache_pdcache_linesize - 1;  
                 DB = DB < 0? 0 : (DB > 7? 7 : DB);  
                 IC = cpu->machine->cache_picache -  
                     cpu->machine->cache_picache_linesize - 7;  
                 DC = cpu->machine->cache_pdcache -  
                     cpu->machine->cache_pdcache_linesize - 7;  
                 IA = cpu->cd.mips.cpu_type.piways - 1;  
                 DA = cpu->cd.mips.cpu_type.pdways - 1;  
                 cpu->cd.mips.cop0_config_select1 =  
                     ((cpu->cd.mips.cpu_type.nr_of_tlb_entries - 1) << 25)  
                     | (IC << 22)        /*  IS: I-cache sets per way  */  
                     | (IB << 19)        /*  IL: I-cache line-size  */  
                     | (IA << 16)        /*  IA: I-cache assoc. (ways-1)  */  
                     | (DC << 13)        /*  DS: D-cache sets per way  */  
                     | (DB << 10)        /*  DL: D-cache line-size  */  
                     | (DA <<  7)        /*  DA: D-cache assoc. (ways-1)  */  
                     | (16 * 0)          /*  Existance of PerformanceCounters  */  
                     | ( 8 * 0)          /*  Existance of Watch Registers  */  
                     | ( 4 * m16)        /*  Existance of MIPS16  */  
                     | ( 2 * 0)          /*  Existance of EJTAG  */  
                     | ( 1 * 1)          /*  Existance of FPU  */  
                     ;  
                 break;  
         default:  
                 ;  
322          }          }
323  }  }
324    
# Line 414  struct mips_coproc *mips_coproc_new(stru Line 385  struct mips_coproc *mips_coproc_new(stru
385    
386          if (coproc_nr == 0) {          if (coproc_nr == 0) {
387                  c->nr_of_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries;                  c->nr_of_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries;
388                  c->tlbs = malloc(c->nr_of_tlbs * sizeof(struct mips_tlb));                  c->tlbs = zeroed_alloc(c->nr_of_tlbs * sizeof(struct mips_tlb));
                 if (c->tlbs == NULL) {  
                         fprintf(stderr, "mips_coproc_new(): out of memory\n");  
                         exit(1);  
                 }  
389    
390                  /*                  /*
391                   *  Start with nothing in the status register. This makes sure                   *  Start with nothing in the status register. This makes sure
# Line 441  struct mips_coproc *mips_coproc_new(stru Line 408  struct mips_coproc *mips_coproc_new(stru
408                  if (!cpu->machine->prom_emulation)                  if (!cpu->machine->prom_emulation)
409                          c->reg[COP0_STATUS] |= STATUS_BEV;                          c->reg[COP0_STATUS] |= STATUS_BEV;
410    
411                  /*  Default pagesize = 4 KB.  */                  /*  Ugly hack for R5900/TX79/C790:  */
412                    if (cpu->cd.mips.cpu_type.rev == MIPS_R5900)
413                            c->reg[COP0_STATUS] |= R5900_STATUS_EIE;
414    
415                    /*  Default pagesize = 4 KB  (i.e. dualpage = 8KB)  */
416                  c->reg[COP0_PAGEMASK] = 0x1fff;                  c->reg[COP0_PAGEMASK] = 0x1fff;
417    
418                  /*  Note: .rev may contain the company ID as well!  */                  /*  Note: .rev may contain the company ID as well!  */
419                  c->reg[COP0_PRID] =                  c->reg[COP0_PRID] =
420                        (0x00 << 24)              /*  Company Options  */                        (0x00 << 24)                      /*  Company Options  */
421                      | (0x00 << 16)              /*  Company ID       */                      | (0x00 << 16)                      /*  Company ID       */
422                      | (cpu->cd.mips.cpu_type.rev <<  8) /*  Processor ID     */                      | (cpu->cd.mips.cpu_type.rev <<  8) /*  Processor ID     */
423                      | (cpu->cd.mips.cpu_type.sub)       /*  Revision         */                      | (cpu->cd.mips.cpu_type.sub)       /*  Revision         */
424                      ;                      ;
# Line 457  struct mips_coproc *mips_coproc_new(stru Line 428  struct mips_coproc *mips_coproc_new(stru
428                  initialize_cop0_config(cpu, c);                  initialize_cop0_config(cpu, c);
429    
430                  /*  Make sure the status register is sign-extended nicely:  */                  /*  Make sure the status register is sign-extended nicely:  */
431                  c->reg[COP0_STATUS] = (int64_t)(int32_t)c->reg[COP0_STATUS];                  c->reg[COP0_STATUS] = (int32_t)c->reg[COP0_STATUS];
432          }          }
433    
434          if (coproc_nr == 1)          if (coproc_nr == 1)
# Line 468  struct mips_coproc *mips_coproc_new(stru Line 439  struct mips_coproc *mips_coproc_new(stru
439    
440    
441  /*  /*
442     *  mips_timer_tick():
443     */
444    static void mips_timer_tick(struct timer *timer, void *extra)
445    {
446            struct cpu *cpu = (struct cpu *) extra;
447    
448            cpu->cd.mips.compare_interrupts_pending ++;
449    
450            if ((int32_t) (cpu->cd.mips.coproc[0]->reg[COP0_COUNT] -
451                cpu->cd.mips.coproc[0]->reg[COP0_COMPARE]) < 0) {
452                    cpu->cd.mips.coproc[0]->reg[COP0_COUNT] =
453                        cpu->cd.mips.coproc[0]->reg[COP0_COMPARE];
454            }
455    }
456    
457    
458    /*
459   *  mips_coproc_tlb_set_entry():   *  mips_coproc_tlb_set_entry():
460   *   *
461   *  Used by machine setup code, if a specific machine emulation starts up   *  Used by machine setup code, if a specific machine emulation starts up
# Line 539  void mips_coproc_tlb_set_entry(struct cp Line 527  void mips_coproc_tlb_set_entry(struct cp
527    
528    
529  /*  /*
530   *  old_update_translation_table():   *  invalidate_asid():
531     *
532     *  Go through all entries in the TLB. If an entry has a matching asid, is
533     *  valid, and is not global (i.e. the ASID matters), then its virtual address
534     *  translation is invalidated.
535     *
536     *  Note: In the R3000 case, the asid argument is shifted 6 bits.
537   */   */
538  static void old_update_translation_table(struct cpu *cpu, uint64_t vaddr_page,  static void invalidate_asid(struct cpu *cpu, int asid)
         unsigned char *host_page, int writeflag, uint64_t paddr_page)  
539  {  {
540          int a, b, index;          struct mips_coproc *cp = cpu->cd.mips.coproc[0];
541          struct vth32_table *tbl1;          int i, ntlbs = cp->nr_of_tlbs;
542          void *p_r, *p_w;          struct mips_tlb *tlb = cp->tlbs;
         uint32_t p_paddr;  
   
         /*  This table stuff only works for 32-bit mode:  */  
         if (vaddr_page & 0x80000000ULL) {  
                 if ((vaddr_page >> 32) != 0xffffffffULL)  
                         return;  
         } else {  
                 if ((vaddr_page >> 32) != 0)  
                         return;  
         }  
543    
544          a = (vaddr_page >> 22) & 0x3ff;          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
545          b = (vaddr_page >> 12) & 0x3ff;                  for (i=0; i<ntlbs; i++)
546          index = (vaddr_page >> 12) & 0xfffff;                          if ((tlb[i].hi & R2K3K_ENTRYHI_ASID_MASK) == asid
547                                && (tlb[i].lo0 & R2K3K_ENTRYLO_V)
548          /*  printf("vaddr = %08x, a = %03x, b = %03x\n",                              && !(tlb[i].lo0 & R2K3K_ENTRYLO_G)) {
549              (int)vaddr_page,a, b);  */                                  cpu->invalidate_translation_caches(cpu,
550                                        tlb[i].hi & R2K3K_ENTRYHI_VPN_MASK,
551          tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];                                      INVALIDATE_VADDR);
         /*  printf("tbl1 = %p\n", tbl1);  */  
         if (tbl1 == cpu->cd.mips.vaddr_to_hostaddr_nulltable) {  
                 /*  Allocate a new table1:  */  
                 /*  printf("ALLOCATING a new table1, 0x%08x - "  
                     "0x%08x\n", a << 22, (a << 22) + 0x3fffff);  */  
                 if (cpu->cd.mips.next_free_vth_table == NULL) {  
                         tbl1 = malloc(sizeof(struct vth32_table));  
                         if (tbl1 == NULL) {  
                                 fprintf(stderr, "out of mem\n");  
                                 exit(1);  
                         }  
                         memset(tbl1, 0, sizeof(struct vth32_table));  
                 } else {  
                         tbl1 = cpu->cd.mips.next_free_vth_table;  
                         cpu->cd.mips.next_free_vth_table = tbl1->next_free;  
                         tbl1->next_free = NULL;  
                 }  
                 cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a] = tbl1;  
                 if (tbl1->refcount != 0) {  
                         printf("INTERNAL ERROR in coproc.c\n");  
                         exit(1);  
                 }  
         }  
         p_r = tbl1->haddr_entry[b*2];  
         p_w = tbl1->haddr_entry[b*2+1];  
         p_paddr = tbl1->paddr_entry[b];  
         /*  printf("   p_r=%p p_w=%p\n", p_r, p_w);  */  
         if (p_r == NULL && p_paddr == 0 &&  
             (host_page != NULL || paddr_page != 0)) {  
                 tbl1->refcount ++;  
                 /*  printf("ADDING %08x -> %p wf=%i (refcount is "  
                     "now %i)\n", (int)vaddr_page, host_page,  
                     writeflag, tbl1->refcount);  */  
         }  
         if (writeflag == -1) {  
                 /*  Forced downgrade to read-only:  */  
                 tbl1->haddr_entry[b*2 + 1] = NULL;  
                 if (cpu->cd.mips.host_store ==  
                     cpu->cd.mips.host_store_orig)  
                         cpu->cd.mips.host_store[index] = NULL;  
         } else if (writeflag==0 && p_w != NULL && host_page != NULL) {  
                 /*  Don't degrade a page from writable to readonly.  */  
         } else {  
                 if (host_page != NULL) {  
                         tbl1->haddr_entry[b*2] = host_page;  
                         if (cpu->cd.mips.host_load ==  
                             cpu->cd.mips.host_load_orig)  
                                 cpu->cd.mips.host_load[index] = host_page;  
                         if (writeflag) {  
                                 tbl1->haddr_entry[b*2+1] = host_page;  
                                 if (cpu->cd.mips.host_store ==  
                                     cpu->cd.mips.host_store_orig)  
                                         cpu->cd.mips.host_store[index] =  
                                             host_page;  
                         } else {  
                                 tbl1->haddr_entry[b*2+1] = NULL;  
                                 if (cpu->cd.mips.host_store ==  
                                     cpu->cd.mips.host_store_orig)  
                                         cpu->cd.mips.host_store[index] = NULL;  
                         }  
                 } else {  
                         tbl1->haddr_entry[b*2] = NULL;  
                         tbl1->haddr_entry[b*2+1] = NULL;  
                         if (cpu->cd.mips.host_store ==  
                             cpu->cd.mips.host_store_orig) {  
                                 cpu->cd.mips.host_load[index] = NULL;  
                                 cpu->cd.mips.host_store[index] = NULL;  
552                          }                          }
                 }  
                 tbl1->paddr_entry[b] = paddr_page;  
         }  
         tbl1->bintrans_chunks[b] = NULL;  
 }  
   
   
 /*  
  *  mips_update_translation_table():  
  */  
 void mips_update_translation_table(struct cpu *cpu, uint64_t vaddr_page,  
         unsigned char *host_page, int writeflag, uint64_t paddr_page)  
 {  
         if (!cpu->machine->bintrans_enable)  
                 return;  
   
         if (writeflag > 0)  
                 bintrans_invalidate(cpu, paddr_page);  
   
         if (cpu->machine->old_bintrans_enable) {  
                 old_update_translation_table(cpu, vaddr_page, host_page,  
                     writeflag, paddr_page);  
                 return;  
         }  
   
         /*  TODO  */  
         /*  printf("update_translation_table(): TODO\n");  */  
 }  
   
   
 /*  
  *  invalidate_table_entry():  
  */  
 static void invalidate_table_entry(struct cpu *cpu, uint64_t vaddr)  
 {  
         int a, b, index;  
         struct vth32_table *tbl1;  
         void *p_r, *p_w;  
         uint32_t p_paddr;  
   
         if (!cpu->machine->old_bintrans_enable) {  
                 /*  printf("invalidate_table_entry(): New: TODO\n");  */  
                 return;  
         }  
   
         /*  This table stuff only works for 32-bit mode:  */  
         if (vaddr & 0x80000000ULL) {  
                 if ((vaddr >> 32) != 0xffffffffULL) {  
                         fatal("invalidate_table_entry(): vaddr = 0x%016llx\n",  
                             (long long)vaddr);  
                         return;  
                 }  
553          } else {          } else {
554                  if ((vaddr >> 32) != 0) {                  int non4kpages = 0;
555                          fatal("invalidate_table_entry(): vaddr = 0x%016llx\n",                  uint64_t topbit = 1, fillmask = 0xffffff0000000000ULL;
                             (long long)vaddr);  
                         return;  
                 }  
         }  
556    
557          a = (vaddr >> 22) & 0x3ff;                  if (cpu->is_32bit) {
558          b = (vaddr >> 12) & 0x3ff;                          topbit = 0x80000000;
559          index = (vaddr >> 12) & 0xfffff;                          fillmask = 0xffffffff00000000ULL;
560                    } else if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
561          /*  printf("vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b);  */                          topbit <<= 43;
562                            fillmask <<= 4;
563          tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];                  } else {
564          /*  printf("tbl1 = %p\n", tbl1);  */                          topbit <<= 39;
         p_r = tbl1->haddr_entry[b*2];  
         p_w = tbl1->haddr_entry[b*2+1];  
         p_paddr = tbl1->paddr_entry[b];  
         tbl1->bintrans_chunks[b] = NULL;  
         /*  printf("B:  p_r=%p p_w=%p\n", p_r,p_w);  */  
         cpu->cd.mips.host_load_orig[index] = NULL;  
         cpu->cd.mips.host_store_orig[index] = NULL;  
         if (p_r != NULL || p_paddr != 0) {  
                 /*  printf("Found a mapping, "  
                     "vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b);  */  
                 tbl1->haddr_entry[b*2] = NULL;  
                 tbl1->haddr_entry[b*2+1] = NULL;  
                 tbl1->paddr_entry[b] = 0;  
                 tbl1->refcount --;  
                 if (tbl1->refcount == 0) {  
                         cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a] =  
                             cpu->cd.mips.vaddr_to_hostaddr_nulltable;  
                         /*  "free" tbl1:  */  
                         tbl1->next_free = cpu->cd.mips.next_free_vth_table;  
                         cpu->cd.mips.next_free_vth_table = tbl1;  
565                  }                  }
         }  
 }  
   
   
 /*  
  *  clear_all_chunks_from_all_tables():  
  */  
 void clear_all_chunks_from_all_tables(struct cpu *cpu)  
 {  
         int a, b;  
         struct vth32_table *tbl1;  
566    
567          if (!cpu->machine->old_bintrans_enable) {                  for (i=0; i<ntlbs; i++) {
568                  printf("clear_all_chunks_from_all_tables(): New: TODO\n");                          if (tlb[i].mask != 0 && tlb[i].mask != 0x1800) {
569                  return;                                  non4kpages = 1;
570          }                                  continue;
   
         for (a=0; a<0x400; a++) {  
                 tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];  
                 if (tbl1 != cpu->cd.mips.vaddr_to_hostaddr_nulltable) {  
                         for (b=0; b<0x400; b++) {  
                                 int index;  
   
                                 tbl1->haddr_entry[b*2] = NULL;  
                                 tbl1->haddr_entry[b*2+1] = NULL;  
                                 tbl1->paddr_entry[b] = 0;  
                                 tbl1->bintrans_chunks[b] = NULL;  
   
                                 if (cpu->cd.mips.host_store ==  
                                     cpu->cd.mips.host_store_orig) {  
                                         index = (a << 10) + b;  
                                         cpu->cd.mips.host_load[index] = NULL;  
                                         cpu->cd.mips.host_store[index] = NULL;  
                                 }  
571                          }                          }
                 }  
         }  
 }  
572    
573                            if ((tlb[i].hi & ENTRYHI_ASID) == asid &&
574  /*                              !(tlb[i].hi & TLB_G)) {
575   *  mips_invalidate_translation_caches_paddr():                                  uint64_t vaddr0, vaddr1;
576   *                                  vaddr0 = cp->tlbs[i].hi & ~fillmask;
577   *  Invalidate based on physical address.                                  if (vaddr0 & topbit)
578   */                                          vaddr0 |= fillmask;
579  void mips_invalidate_translation_caches_paddr(struct cpu *cpu,                                  vaddr1 = vaddr0 | 0x1000;  /*  TODO: mask  */
580          uint64_t paddr, int flags)  
581  {                                  if (tlb[i].lo0 & ENTRYLO_V)
582          paddr &= ~0xfff;                                          cpu->invalidate_translation_caches(cpu,
583                                                vaddr0, INVALIDATE_VADDR);
584          if (cpu->machine->bintrans_enable) {                                  if (tlb[i].lo1 & ENTRYLO_V)
585  #if 1                                          cpu->invalidate_translation_caches(cpu,
586                  int i;                                              vaddr1, INVALIDATE_VADDR);
                 uint64_t tlb_paddr0, tlb_paddr1;  
                 uint64_t tlb_vaddr;  
                 uint64_t p, p2;  
   
                 switch (cpu->cd.mips.cpu_type.mmu_model) {  
                 case MMU3K:  
                         for (i=0; i<64; i++) {  
                                 tlb_paddr0 = cpu->cd.mips.coproc[0]->  
                                     tlbs[i].lo0 & R2K3K_ENTRYLO_PFN_MASK;  
                                 tlb_vaddr = cpu->cd.mips.coproc[0]->  
                                     tlbs[i].hi & R2K3K_ENTRYHI_VPN_MASK;  
                                 tlb_vaddr = (int64_t)(int32_t)tlb_vaddr;  
                                 if ((cpu->cd.mips.coproc[0]->tlbs[i].lo0 &  
                                     R2K3K_ENTRYLO_V) && tlb_paddr0 == paddr)  
                                         invalidate_table_entry(cpu, tlb_vaddr);  
                         }  
                         break;  
                 default:  
                         for (i=0; i<cpu->cd.mips.coproc[0]->nr_of_tlbs; i++) {  
                                 int psize = 12;  
                                 int or_pmask = 0x1fff;  
                                 int phys_shift = 12;  
   
                                 if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {  
                                         or_pmask = 0x7ff;  
                                         phys_shift = 10;  
                                 }  
                                 switch (cpu->cd.mips.coproc[0]->  
                                     tlbs[i].mask | or_pmask) {  
                                 case 0x000007ff:        psize = 10; break;  
                                 case 0x00001fff:        psize = 12; break;  
                                 case 0x00007fff:        psize = 14; break;  
                                 case 0x0001ffff:        psize = 16; break;  
                                 case 0x0007ffff:        psize = 18; break;  
                                 case 0x001fffff:        psize = 20; break;  
                                 case 0x007fffff:        psize = 22; break;  
                                 case 0x01ffffff:        psize = 24; break;  
                                 case 0x07ffffff:        psize = 26; break;  
                                 default:  
                                         printf("invalidate_translation_caches"  
                                             "_paddr(): bad pagemask?\n");  
                                 }  
                                 tlb_paddr0 = (cpu->cd.mips.coproc[0]->tlbs[i].  
                                     lo0 & ENTRYLO_PFN_MASK)>>ENTRYLO_PFN_SHIFT;  
                                 tlb_paddr1 = (cpu->cd.mips.coproc[0]->tlbs[i].  
                                     lo1 & ENTRYLO_PFN_MASK)>>ENTRYLO_PFN_SHIFT;  
                                 tlb_paddr0 <<= phys_shift;  
                                 tlb_paddr1 <<= phys_shift;  
                                 if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {  
                                         tlb_vaddr = cpu->cd.mips.coproc[0]->  
                                             tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;  
                                         if (tlb_vaddr & ((int64_t)1 << 43))  
                                                 tlb_vaddr |=  
                                                     0xfffff00000000000ULL;  
                                 } else {  
                                         tlb_vaddr = cpu->cd.mips.coproc[0]->  
                                             tlbs[i].hi & ENTRYHI_VPN2_MASK;  
                                         if (tlb_vaddr & ((int64_t)1 << 39))  
                                                 tlb_vaddr |=  
                                                     0xffffff0000000000ULL;  
                                 }  
                                 if ((cpu->cd.mips.coproc[0]->tlbs[i].lo0 &  
                                     ENTRYLO_V) && paddr >= tlb_paddr0 &&  
                                     paddr < tlb_paddr0 + (1<<psize)) {  
                                         p2 = 1 << psize;  
                                         for (p=0; p<p2; p+=4096)  
                                                 invalidate_table_entry(cpu,  
                                                     tlb_vaddr + p);  
                                 }  
                                 if ((cpu->cd.mips.coproc[0]->tlbs[i].lo1 &  
                                     ENTRYLO_V) && paddr >= tlb_paddr1 &&  
                                     paddr < tlb_paddr1 + (1<<psize)) {  
                                         p2 = 1 << psize;  
                                         for (p=0; p<p2; p+=4096)  
                                                 invalidate_table_entry(cpu,  
                                                     tlb_vaddr + p +  
                                                     (1 << psize));  
                                 }  
587                          }                          }
588                  }                  }
 #endif  
589    
590                  if (paddr < 0x20000000) {                  if (non4kpages) {
591                          invalidate_table_entry(cpu, 0xffffffff80000000ULL                          cpu->invalidate_translation_caches(cpu,
592                              + paddr);                              0, INVALIDATE_ALL);
                         invalidate_table_entry(cpu, 0xffffffffa0000000ULL  
                             + paddr);  
593                  }                  }
594          }          }
   
 #if 0  
 {  
         int i;  
   
         /*  TODO: Don't invalidate everything.  */  
         for (i=0; i<N_BINTRANS_VADDR_TO_HOST; i++)  
                 cpu->bintrans_data_hostpage[i] = NULL;  
 }  
 #endif  
 }  
   
   
 /*  
  *  invalidate_translation_caches():  
  *  
  *  This is necessary for every change to the TLB, and when the ASID is changed,  
  *  so that for example user-space addresses are not cached when they should  
  *  not be.  
  */  
 static void invalidate_translation_caches(struct cpu *cpu,  
         int all, uint64_t vaddr, int kernelspace, int old_asid_to_invalidate)  
 {  
         int i;  
   
         /*  printf("inval(all=%i, kernel=%i, addr=%016llx)\n",  
             all, kernelspace, (long long)vaddr);  */  
   
         if (!cpu->machine->bintrans_enable)  
                 goto nobintrans;  
   
         if (all) {  
                 int i;  
                 uint64_t tlb_vaddr;  
                 switch (cpu->cd.mips.cpu_type.mmu_model) {  
                 case MMU3K:  
                         for (i=0; i<64; i++) {  
                                 tlb_vaddr = cpu->cd.mips.coproc[0]->tlbs[i].hi  
                                     & R2K3K_ENTRYHI_VPN_MASK;  
                                 tlb_vaddr = (int64_t)(int32_t)tlb_vaddr;  
                                 if ((cpu->cd.mips.coproc[0]->tlbs[i].lo0 &  
                                     R2K3K_ENTRYLO_V) && (tlb_vaddr &  
                                     0xc0000000ULL) != 0x80000000ULL) {  
                                         int asid = (cpu->cd.mips.coproc[0]->  
                                             tlbs[i].hi & R2K3K_ENTRYHI_ASID_MASK  
                                             ) >> R2K3K_ENTRYHI_ASID_SHIFT;  
                                         if (old_asid_to_invalidate < 0 ||  
                                             old_asid_to_invalidate == asid)  
                                                 invalidate_table_entry(cpu,  
                                                     tlb_vaddr);  
                                 }  
                         }  
                         break;  
                 default:  
                         for (i=0; i<cpu->cd.mips.coproc[0]->nr_of_tlbs; i++) {  
                                 int psize = 10, or_pmask = 0x1fff;  
                                 int phys_shift = 12;  
   
                                 if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {  
                                         or_pmask = 0x7ff;  
                                         phys_shift = 10;  
                                 }  
   
                                 switch (cpu->cd.mips.coproc[0]->tlbs[i].mask  
                                     | or_pmask) {  
                                 case 0x000007ff:        psize = 10; break;  
                                 case 0x00001fff:        psize = 12; break;  
                                 case 0x00007fff:        psize = 14; break;  
                                 case 0x0001ffff:        psize = 16; break;  
                                 case 0x0007ffff:        psize = 18; break;  
                                 case 0x001fffff:        psize = 20; break;  
                                 case 0x007fffff:        psize = 22; break;  
                                 case 0x01ffffff:        psize = 24; break;  
                                 case 0x07ffffff:        psize = 26; break;  
                                 default:  
                                         printf("invalidate_translation_caches"  
                                             "(): bad pagemask?\n");  
                                 }  
   
                                 if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {  
                                         tlb_vaddr = cpu->cd.mips.coproc[0]->  
                                             tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;  
                                         if (tlb_vaddr & ((int64_t)1 << 43))  
                                                 tlb_vaddr |=  
                                                     0xfffff00000000000ULL;  
                                 } else {  
                                         tlb_vaddr = cpu->cd.mips.coproc[0]->  
                                             tlbs[i].hi & ENTRYHI_VPN2_MASK;  
                                         if (tlb_vaddr & ((int64_t)1 << 39))  
                                                 tlb_vaddr |=  
                                                     0xffffff0000000000ULL;  
                                 }  
   
                                 /*  TODO: Check the ASID etc.  */  
   
                                 invalidate_table_entry(cpu, tlb_vaddr);  
                                 invalidate_table_entry(cpu, tlb_vaddr |  
                                     (1 << psize));  
                         }  
                 }  
         } else  
                 invalidate_table_entry(cpu, vaddr);  
   
 nobintrans:  
   
         /*  TODO: Don't invalidate everything.  */  
         for (i=0; i<N_BINTRANS_VADDR_TO_HOST; i++)  
                 cpu->cd.mips.bintrans_data_hostpage[i] = NULL;  
   
         if (kernelspace)  
                 all = 1;  
   
 #ifdef USE_TINY_CACHE  
 {  
         vaddr >>= 12;  
   
         /*  Invalidate the tiny translation cache...  */  
         if (!cpu->machine->bintrans_enable)  
                 for (i=0; i<N_TRANSLATION_CACHE_INSTR; i++)  
                         if (all || vaddr == (cpu->cd.mips.  
                             translation_cache_instr[i].vaddr_pfn))  
                                 cpu->cd.mips.translation_cache_instr[i].wf = 0;  
   
         if (!cpu->machine->bintrans_enable)  
                 for (i=0; i<N_TRANSLATION_CACHE_DATA; i++)  
                         if (all || vaddr == (cpu->cd.mips.  
                             translation_cache_data[i].vaddr_pfn))  
                                 cpu->cd.mips.translation_cache_data[i].wf = 0;  
 }  
 #endif  
595  }  }
596    
597    
# Line 1017  void coproc_register_read(struct cpu *cp Line 614  void coproc_register_read(struct cpu *cp
614          if (cp->coproc_nr==0 && reg_nr==COP0_WIRED)     unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_WIRED)     unimpl = 0;
615          if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR)  unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR)  unimpl = 0;
616          if (cp->coproc_nr==0 && reg_nr==COP0_COUNT) {          if (cp->coproc_nr==0 && reg_nr==COP0_COUNT) {
617                  /*                  /*  TODO: Increase count in a more meaningful way!  */
618                   *  This speeds up delay-loops that just read the count                  cp->reg[COP0_COUNT] = (int32_t) (cp->reg[COP0_COUNT] + 1);
                  *  register until it has reached a certain value. (Only for  
                  *  R4000 etc.)  
                  *  
                  *  TODO: Maybe this should be optional?  
                  */  
                 if (cpu->cd.mips.cpu_type.exc_model != EXC3K) {  
                         int increase = 500;  
                         int32_t x = cp->reg[COP0_COUNT];  
                         int32_t y = cp->reg[COP0_COMPARE];  
                         int32_t diff = x - y;  
                         if (diff < 0 && diff + increase >= 0  
                             && cpu->cd.mips.compare_register_set) {  
                                 mips_cpu_interrupt(cpu, 7);  
                                 cpu->cd.mips.compare_register_set = 0;  
                         }  
                         cp->reg[COP0_COUNT] = (int64_t)  
                             (int32_t)(cp->reg[COP0_COUNT] + increase);  
                 }  
   
619                  unimpl = 0;                  unimpl = 0;
620          }          }
621          if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI)   unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI)   unimpl = 0;
# Line 1121  void coproc_register_write(struct cpu *c Line 699  void coproc_register_write(struct cpu *c
699                              (tmp & 0xff)!=0) {                              (tmp & 0xff)!=0) {
700                                  /*  char *symbol;                                  /*  char *symbol;
701                                      uint64_t offset;                                      uint64_t offset;
702                                      symbol = get_symbol_name(                                      symbol = get_symbol_name(cpu->pc, &offset);
                                     cpu->cd.mips.pc_last, &offset);  
703                                      fatal("YO! pc = 0x%08llx <%s> "                                      fatal("YO! pc = 0x%08llx <%s> "
704                                      "lo=%016llx\n", (long long)                                      "lo=%016llx\n", (long long)
705                                      cpu->cd.mips.pc_last, symbol? symbol :                                      cpu->pc, symbol? symbol :
706                                      "no symbol", (long long)tmp); */                                      "no symbol", (long long)tmp); */
707                                  tmp &= (R2K3K_ENTRYLO_PFN_MASK |                                  tmp &= (R2K3K_ENTRYLO_PFN_MASK |
708                                      R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |                                      R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |
# Line 1191  void coproc_register_write(struct cpu *c Line 768  void coproc_register_write(struct cpu *c
768                          unimpl = 0;                          unimpl = 0;
769                          break;                          break;
770                  case COP0_COUNT:                  case COP0_COUNT:
771                          if (tmp != (int64_t)(int32_t)tmp)                          if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
772                                  fatal("WARNING: trying to write a 64-bit value"                                  fatal("WARNING: trying to write a 64-bit value"
773                                      " to the COUNT register!\n");                                      " to the COUNT register!\n");
774                          tmp = (int64_t)(int32_t)tmp;                          tmp = (int64_t)(int32_t)tmp;
775                          unimpl = 0;                          unimpl = 0;
776                          break;                          break;
777                  case COP0_COMPARE:                  case COP0_COMPARE:
778                          /*  Clear the timer interrupt bit (bit 7):  */                          if (cpu->machine->emulated_hz > 0) {
779                          cpu->cd.mips.compare_register_set = 1;                                  int32_t compare_diff = tmp -
780                                        cp->reg[COP0_COMPARE];
781                                    double hz;
782    
783                                    if (compare_diff < 0)
784                                            hz = tmp - cp->reg[COP0_COUNT];
785    
786                                    if (compare_diff == 0)
787                                            hz = 0;
788                                    else
789                                            hz = (double)cpu->machine->emulated_hz
790                                                / (double)compare_diff;
791    /*
792     *  TODO: DON'T HARDCODE THIS!
793     */
794    hz = 100.0;
795    
796                                    /*  Initialize or re-set the periodic timer:  */
797                                    if (hz > 0) {
798                                            if (cpu->cd.mips.timer == NULL)
799                                                    cpu->cd.mips.timer = timer_add(
800                                                        hz, mips_timer_tick, cpu);
801                                            else
802                                                    timer_update_frequency(
803                                                        cpu->cd.mips.timer, hz);
804                                    }
805                            }
806    
807                            /*  Ack the periodic timer, if it was asserted:  */
808                            if (cp->reg[COP0_CAUSE] & 0x8000 &&
809                                cpu->cd.mips.compare_interrupts_pending > 0)
810                                    cpu->cd.mips.compare_interrupts_pending --;
811    
812                            /*  Clear the timer interrupt assertion (bit 7):  */
813                          mips_cpu_interrupt_ack(cpu, 7);                          mips_cpu_interrupt_ack(cpu, 7);
814                          if (tmp != (int64_t)(int32_t)tmp)  
815                            if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
816                                  fatal("WARNING: trying to write a 64-bit value"                                  fatal("WARNING: trying to write a 64-bit value"
817                                      " to the COMPARE register!\n");                                      " to the COMPARE register!\n");
818    
819                          tmp = (int64_t)(int32_t)tmp;                          tmp = (int64_t)(int32_t)tmp;
820                            cpu->cd.mips.compare_register_set = 1;
821                          unimpl = 0;                          unimpl = 0;
822                          break;                          break;
823                  case COP0_ENTRYHI:                  case COP0_ENTRYHI:
824                          /*                          /*
825                           *  Translation caches must be invalidated, because the                           *  Translation caches must be invalidated if the
826                           *  address space might change (if the ASID changes).                           *  ASID changes:
827                           */                           */
828                          switch (cpu->cd.mips.cpu_type.mmu_model) {                          switch (cpu->cd.mips.cpu_type.mmu_model) {
829                          case MMU3K:                          case MMU3K:
830                                  old_asid = (cp->reg[COP0_ENTRYHI] &                                  old_asid = cp->reg[COP0_ENTRYHI] &
831                                      R2K3K_ENTRYHI_ASID_MASK) >>                                      R2K3K_ENTRYHI_ASID_MASK;
                                     R2K3K_ENTRYHI_ASID_SHIFT;  
832                                  if ((cp->reg[COP0_ENTRYHI] &                                  if ((cp->reg[COP0_ENTRYHI] &
833                                      R2K3K_ENTRYHI_ASID_MASK) !=                                      R2K3K_ENTRYHI_ASID_MASK) !=
834                                      (tmp & R2K3K_ENTRYHI_ASID_MASK))                                      (tmp & R2K3K_ENTRYHI_ASID_MASK))
# Line 1229  void coproc_register_write(struct cpu *c Line 841  void coproc_register_write(struct cpu *c
841                                          inval = 1;                                          inval = 1;
842                                  break;                                  break;
843                          }                          }
844    
845                          if (inval)                          if (inval)
846                                  invalidate_translation_caches(cpu, 1, 0, 0,                                  invalidate_asid(cpu, old_asid);
847                                      old_asid);  
848                          unimpl = 0;                          unimpl = 0;
849                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
850                              (tmp & 0x3f)!=0) {                              (tmp & 0x3f)!=0) {
851                                  /* char *symbol;                                  /* char *symbol;
852                                     uint64_t offset;                                     uint64_t offset;
853                                     symbol = get_symbol_name(cpu->                                     symbol = get_symbol_name(cpu->pc,
854                                      cd.mips.pc_last, &offset);                                      &offset);
855                                     fatal("YO! pc = 0x%08llx <%s> "                                     fatal("YO! pc = 0x%08llx <%s> "
856                                      "hi=%016llx\n", (long long)cpu->                                      "hi=%016llx\n", (long long)cpu->pc,
857                                      cd.mips.pc_last, symbol? symbol :                                      symbol? symbol :
858                                      "no symbol", (long long)tmp);  */                                      "no symbol", (long long)tmp);  */
859                                  tmp &= ~0x3f;                                  tmp &= ~0x3f;
860                          }                          }
# Line 1287  void coproc_register_write(struct cpu *c Line 900  void coproc_register_write(struct cpu *c
900                  case COP0_STATUS:                  case COP0_STATUS:
901                          oldmode = cp->reg[COP0_STATUS];                          oldmode = cp->reg[COP0_STATUS];
902                          tmp &= ~(1 << 21);      /*  bit 21 is read-only  */                          tmp &= ~(1 << 21);      /*  bit 21 is read-only  */
 #if 0  
 /*  Why was this here? It should not be necessary.  */  
   
                         /*  Changing from kernel to user mode? Then  
                             invalidate some translation caches:  */  
                         if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {  
                                 if (!(oldmode & MIPS1_SR_KU_CUR)  
                                     && (tmp & MIPS1_SR_KU_CUR))  
                                         invalidate_translation_caches(cpu,  
                                             0, 0, 1, 0);  
                         } else {  
                                 /*  TODO: don't hardcode  */  
                                 if ((oldmode & 0xff) != (tmp & 0xff))  
                                         invalidate_translation_caches(  
                                             cpu, 0, 0, 1, 0);  
                         }  
 #endif  
903    
904                            /*
905                             *  When isolating caches, invalidate all translations.
906                             *  During the isolation, a special hack in memory_rw.c
907                             *  prevents translation tables from being updated, so
908                             *  the translation caches don't have to be invalidated
909                             *  when switching back to normal mode.
910                             */
911                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
912                              (oldmode & MIPS1_ISOL_CACHES) !=                              (oldmode & MIPS1_ISOL_CACHES) !=
913                              (tmp & MIPS1_ISOL_CACHES)) {                              (tmp & MIPS1_ISOL_CACHES)) {
914                                  /*  R3000-style caches when isolated are                                  /*  Invalidate everything if we are switching
915                                      treated in bintrans mode by changing                                      to isolated mode:  */
                                     the vaddr_to_hostaddr_table0 pointer:  */  
916                                  if (tmp & MIPS1_ISOL_CACHES) {                                  if (tmp & MIPS1_ISOL_CACHES) {
917                                          /*  2-level table:  */                                          cpu->invalidate_translation_caches(
918                                          cpu->cd.mips.vaddr_to_hostaddr_table0 =                                              cpu, 0, INVALIDATE_ALL);
                                           tmp & MIPS1_SWAP_CACHES?  
                                           cpu->cd.mips.  
                                           vaddr_to_hostaddr_table0_cacheisol_i  
                                           : cpu->cd.mips.  
                                           vaddr_to_hostaddr_table0_cacheisol_d;  
   
                                         /*  1M-entry table:  */  
                                         cpu->cd.mips.host_load =  
                                             cpu->cd.mips.host_store =  
                                             cpu->cd.mips.huge_r2k3k_cache_table;  
                                 } else {  
                                         /*  2-level table:  */  
                                         cpu->cd.mips.vaddr_to_hostaddr_table0 =  
                                             cpu->cd.mips.  
                                                 vaddr_to_hostaddr_table0_kernel;  
   
                                         /*  TODO: cpu->cd.mips.  
                                             vaddr_to_hostaddr_table0_user;  */  
   
                                         /*  1M-entry table:  */  
                                         cpu->cd.mips.host_load =  
                                             cpu->cd.mips.host_load_orig;  
                                         cpu->cd.mips.host_store =  
                                             cpu->cd.mips.host_store_orig;  
919                                  }                                  }
920                          }                          }
921                          unimpl = 0;                          unimpl = 0;
# Line 1347  void coproc_register_write(struct cpu *c Line 925  void coproc_register_write(struct cpu *c
925                              affects IM bits 0 and 1:  */                              affects IM bits 0 and 1:  */
926                          cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);                          cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);
927                          cp->reg[reg_nr] |= (tmp & (0x3 << STATUS_IM_SHIFT));                          cp->reg[reg_nr] |= (tmp & (0x3 << STATUS_IM_SHIFT));
                         if (!(cp->reg[COP0_CAUSE] & STATUS_IM_MASK))  
                                 cpu->cd.mips.cached_interrupt_is_possible = 0;  
                         else  
                                 cpu->cd.mips.cached_interrupt_is_possible = 1;  
928                          return;                          return;
929                  case COP0_FRAMEMASK:                  case COP0_FRAMEMASK:
930                          /*  TODO: R10000  */                          /*  TODO: R10000  */
# Line 1426  void coproc_register_write(struct cpu *c Line 1000  void coproc_register_write(struct cpu *c
1000   *   *
1001   *  TODO:  Move this to some other file?   *  TODO:  Move this to some other file?
1002   */   */
1003  #define FMT_S           16  static int mips_fmt_to_ieee_fmt[32] = {
1004  #define FMT_D           17          0, 0, 0, 0,  0, 0, 0, 0,
1005  #define FMT_W           20          0, 0, 0, 0,  0, 0, 0, 0,
1006  #define FMT_L           21          IEEE_FMT_S, IEEE_FMT_D, 0, 0,
1007  #define FMT_PS          22          IEEE_FMT_W, IEEE_FMT_L, /* PS (Paired Single) */ 0, 0,
1008            0, 0, 0, 0,  0, 0, 0, 0  };
1009    
1010    static char *fmtname[32] = {
1011             "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
1012             "8",  "9", "10", "11", "12", "13", "14", "15",
1013             "s",  "d", "18", "19",  "w",  "l", "ps", "23",
1014            "24", "25", "26", "27", "28", "29", "30", "31"  };
1015    
1016    static char *ccname[16] = {
1017            "f",  "un",   "eq",  "ueq", "olt", "ult", "ole", "ule",
1018            "sf", "ngle", "seq", "ngl", "lt",  "nge", "le",  "ngt"  };
1019    
1020  #define FPU_OP_ADD      1  #define FPU_OP_ADD      1
1021  #define FPU_OP_SUB      2  #define FPU_OP_SUB      2
# Line 1442  void coproc_register_write(struct cpu *c Line 1027  void coproc_register_write(struct cpu *c
1027  #define FPU_OP_C        8  #define FPU_OP_C        8
1028  #define FPU_OP_ABS      9  #define FPU_OP_ABS      9
1029  #define FPU_OP_NEG      10  #define FPU_OP_NEG      10
1030  /*  TODO: CEIL.L, CEIL.W, FLOOR.L, FLOOR.W, RECIP, ROUND.L, ROUND.W,  /*  TODO: CEIL.L, CEIL.W, FLOOR.L, FLOOR.W, RECIP, ROUND.L, ROUND.W, RSQRT  */
  RSQRT  */  
   
   
 struct internal_float_value {  
         double  f;  
         int     nan;  
 };  
   
   
 /*  
  *  fpu_interpret_float_value():  
  *  
  *  Interprets a float value from binary IEEE format into an  
  *  internal_float_value struct.  
  */  
 static void fpu_interpret_float_value(uint64_t reg,  
         struct internal_float_value *fvp, int fmt)  
 {  
         int n_frac = 0, n_exp = 0;  
         int i, nan, sign = 0, exponent;  
         double fraction;  
   
         memset(fvp, 0, sizeof(struct internal_float_value));  
   
         /*  n_frac and n_exp:  */  
         switch (fmt) {  
         case FMT_S:     n_frac = 23; n_exp = 8; break;  
         case FMT_W:     n_frac = 31; n_exp = 0; break;  
         case FMT_D:     n_frac = 52; n_exp = 11; break;  
         case FMT_L:     n_frac = 63; n_exp = 0; break;  
         default:  
                 fatal("fpu_interpret_float_value(): "  
                     "unimplemented format %i\n", fmt);  
         }  
   
         /*  exponent:  */  
         exponent = 0;  
         switch (fmt) {  
         case FMT_W:  
                 reg &= 0xffffffffULL;  
         case FMT_L:  
                 break;  
         case FMT_S:  
                 reg &= 0xffffffffULL;  
         case FMT_D:  
                 exponent = (reg >> n_frac) & ((1 << n_exp) - 1);  
                 exponent -= (1 << (n_exp-1)) - 1;  
                 break;  
         default:  
                 fatal("fpu_interpret_float_value(): unimplemented "  
                     "format %i\n", fmt);  
         }  
   
         /*  nan:  */  
         nan = 0;  
         switch (fmt) {  
         case FMT_S:  
                 if (reg == 0x7fffffffULL || reg == 0x7fbfffffULL)  
                         nan = 1;  
                 break;  
         case FMT_D:  
                 if (reg == 0x7fffffffffffffffULL ||  
                     reg == 0x7ff7ffffffffffffULL)  
                         nan = 1;  
                 break;  
         }  
   
         if (nan) {  
                 fvp->f = 1.0;  
                 goto no_reasonable_result;  
         }  
   
         /*  fraction:  */  
         fraction = 0.0;  
         switch (fmt) {  
         case FMT_W:  
                 {  
                         int32_t r_int = reg;  
                         fraction = r_int;  
                 }  
                 break;  
         case FMT_L:  
                 {  
                         int64_t r_int = reg;  
                         fraction = r_int;  
                 }  
                 break;  
         case FMT_S:  
         case FMT_D:  
                 /*  sign:  */  
                 sign = (reg >> 31) & 1;  
                 if (fmt == FMT_D)  
                         sign = (reg >> 63) & 1;  
   
                 fraction = 0.0;  
                 for (i=0; i<n_frac; i++) {  
                         int bit = (reg >> i) & 1;  
                         fraction /= 2.0;  
                         if (bit)  
                                 fraction += 1.0;  
                 }  
                 /*  Add implicit bit 0:  */  
                 fraction = (fraction / 2.0) + 1.0;  
                 break;  
         default:  
                 fatal("fpu_interpret_float_value(): "  
                     "unimplemented format %i\n", fmt);  
         }  
   
         /*  form the value:  */  
         fvp->f = fraction;  
   
         /*  fatal("load  reg=%016llx sign=%i exponent=%i fraction=%f ",  
             (long long)reg, sign, exponent, fraction);  */  
   
         /*  TODO: this is awful for exponents of large magnitude.  */  
         if (exponent > 0) {  
                 /*  
                  *  NOTE / TODO:  
                  *  
                  *  This is an ulgy workaround on Alpha, where it seems that  
                  *  multiplying by 2, 1024 times causes a floating point  
                  *  exception. (Triggered by running for example NetBSD/pmax  
                  *  2.0 on an Alpha.)  
                  */  
                 if (exponent == 1024)  
                         exponent = 1023;  
   
                 while (exponent-- > 0)  
                         fvp->f *= 2.0;  
         } else if (exponent < 0) {  
                 while (exponent++ < 0)  
                         fvp->f /= 2.0;  
         }  
   
         if (sign)  
                 fvp->f = -fvp->f;  
   
 no_reasonable_result:  
         fvp->nan = nan;  
   
         /*  fatal("f = %f\n", fvp->f);  */  
 }  
1031    
1032    
1033  /*  /*
# Line 1596  no_reasonable_result: Line 1038  no_reasonable_result:
1038  static void fpu_store_float_value(struct mips_coproc *cp, int fd,  static void fpu_store_float_value(struct mips_coproc *cp, int fd,
1039          double nf, int fmt, int nan)          double nf, int fmt, int nan)
1040  {  {
1041          int n_frac = 0, n_exp = 0, signofs=0;          int ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
1042          int i, exponent;          uint64_t r = ieee_store_float_value(nf, ieee_fmt, nan);
         uint64_t r = 0, r2;  
         int64_t r3;  
   
         /*  n_frac and n_exp:  */  
         switch (fmt) {  
         case FMT_S:     n_frac = 23; n_exp = 8; signofs = 31; break;  
         case FMT_W:     n_frac = 31; n_exp = 0; signofs = 31; break;  
         case FMT_D:     n_frac = 52; n_exp = 11; signofs = 63; break;  
         case FMT_L:     n_frac = 63; n_exp = 0; signofs = 63; break;  
         default:  
                 fatal("fpu_store_float_value(): unimplemented format"  
                     " %i\n", fmt);  
         }  
   
         if ((fmt == FMT_S || fmt == FMT_D) && nan)  
                 goto store_nan;  
   
         /*  fraction:  */  
         switch (fmt) {  
         case FMT_W:  
         case FMT_L:  
                 /*  
                  *  This causes an implicit conversion of double to integer.  
                  *  If nf < 0.0, then r2 will begin with a sequence of binary  
                  *  1's, which is ok.  
                  */  
                 r3 = nf;  
                 r2 = r3;  
                 r |= r2;  
   
                 if (fmt == FMT_W)  
                         r &= 0xffffffffULL;  
                 break;  
         case FMT_S:  
         case FMT_D:  
                 /*  fatal("store f=%f ", nf);  */  
   
                 /*  sign bit:  */  
                 if (nf < 0.0) {  
                         r |= ((uint64_t)1 << signofs);  
                         nf = -nf;  
                 }  
   
                 /*  
                  *  How to convert back from double to exponent + fraction:  
                  *  We want fraction to be 1.xxx, that is  
                  *  1.0 <= fraction < 2.0  
                  *  
                  *  This method is very slow but should work:  
                  */  
                 exponent = 0;  
                 while (nf < 1.0 && exponent > -1023) {  
                         nf *= 2.0;  
                         exponent --;  
                 }  
                 while (nf >= 2.0 && exponent < 1023) {  
                         nf /= 2.0;  
                         exponent ++;  
                 }  
   
                 /*  Here:   1.0 <= nf < 2.0  */  
                 /*  fatal(" nf=%f", nf);  */  
                 nf -= 1.0;      /*  remove implicit first bit  */  
                 for (i=n_frac-1; i>=0; i--) {  
                         nf *= 2.0;  
                         if (nf >= 1.0) {  
                                 r |= ((uint64_t)1 << i);  
                                 nf -= 1.0;  
                         }  
                         /*  printf("\n i=%2i r=%016llx\n", i, (long long)r);  */  
                 }  
   
                 /*  Insert the exponent into the resulting word:  */  
                 /*  (First bias, then make sure it's within range)  */  
                 exponent += (((uint64_t)1 << (n_exp-1)) - 1);  
                 if (exponent < 0)  
                         exponent = 0;  
                 if (exponent >= ((int64_t)1 << n_exp))  
                         exponent = ((int64_t)1 << n_exp) - 1;  
                 r |= (uint64_t)exponent << n_frac;  
   
                 /*  Special case for 0.0:  */  
                 if (exponent == 0)  
                         r = 0;  
   
                 /*  fatal(" exp=%i, r = %016llx\n", exponent, (long long)r);  */  
   
                 break;  
         default:  
                 /*  TODO  */  
                 fatal("fpu_store_float_value(): unimplemented format "  
                     "%i\n", fmt);  
         }  
   
 store_nan:  
         if (nan) {  
                 if (fmt == FMT_S)  
                         r = 0x7fffffffULL;  
                 else if (fmt == FMT_D)  
                         r = 0x7fffffffffffffffULL;  
                 else  
                         r = 0x7fffffffULL;  
         }  
1043    
1044          /*          /*
1045           *  TODO:  this is for 32-bit mode. It has to be updated later           *  TODO: This is for 32-bit mode. It has to be updated later
1046           *              for 64-bit coprocessor stuff.           *        for 64-bit coprocessor functionality!
1047           */           */
1048          if (fmt == FMT_D || fmt == FMT_L) {          if (fmt == COP1_FMT_D || fmt == COP1_FMT_L) {
1049                  cp->reg[fd] = r & 0xffffffffULL;                  cp->reg[fd] = r & 0xffffffffULL;
1050                  cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;                  cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;
1051    
# Line 1726  store_nan: Line 1065  store_nan:
1065  /*  /*
1066   *  fpu_op():   *  fpu_op():
1067   *   *
1068   *  Perform a floating-point operation.  For those of fs and ft   *  Perform a floating-point operation. For those of fs and ft that are >= 0,
1069   *  that are >= 0, those numbers are interpreted into local   *  those numbers are interpreted into local variables.
  *  variables.  
1070   *   *
1071   *  Only FPU_OP_C (compare) returns anything of interest, 1 for   *  Only FPU_OP_C (compare) returns anything of interest, 1 for true, 0 for
1072   *  true, 0 for false.   *  false.
1073   */   */
1074  static int fpu_op(struct cpu *cpu, struct mips_coproc *cp, int op, int fmt,  static int fpu_op(struct cpu *cpu, struct mips_coproc *cp, int op, int fmt,
1075          int ft, int fs, int fd, int cond, int output_fmt)          int ft, int fs, int fd, int cond, int output_fmt)
1076  {  {
1077          /*  Potentially two input registers, fs and ft  */          /*  Potentially two input registers, fs and ft  */
1078          struct internal_float_value float_value[2];          struct ieee_float_value float_value[2];
1079          int unordered, nan;          int unordered, nan, ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
1080          uint64_t fs_v = 0;          uint64_t fs_v = 0;
1081          double nf;          double nf;
1082    
# Line 1746  static int fpu_op(struct cpu *cpu, struc Line 1084  static int fpu_op(struct cpu *cpu, struc
1084                  fs_v = cp->reg[fs];                  fs_v = cp->reg[fs];
1085                  /*  TODO: register-pair mode and plain                  /*  TODO: register-pair mode and plain
1086                      register mode? "FR" bit?  */                      register mode? "FR" bit?  */
1087                  if (fmt == FMT_D || fmt == FMT_L)                  if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1088                          fs_v = (fs_v & 0xffffffffULL) +                          fs_v = (fs_v & 0xffffffffULL) +
1089                              (cp->reg[(fs + 1) & 31] << 32);                              (cp->reg[(fs + 1) & 31] << 32);
1090                  fpu_interpret_float_value(fs_v, &float_value[0], fmt);                  ieee_interpret_float_value(fs_v, &float_value[0], ieee_fmt);
1091          }          }
1092          if (ft >= 0) {          if (ft >= 0) {
1093                  uint64_t v = cp->reg[ft];                  uint64_t v = cp->reg[ft];
1094                  /*  TODO: register-pair mode and                  /*  TODO: register-pair mode and
1095                      plain register mode? "FR" bit?  */                      plain register mode? "FR" bit?  */
1096                  if (fmt == FMT_D || fmt == FMT_L)                  if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1097                          v = (v & 0xffffffffULL) +                          v = (v & 0xffffffffULL) +
1098                              (cp->reg[(ft + 1) & 31] << 32);                              (cp->reg[(ft + 1) & 31] << 32);
1099                  fpu_interpret_float_value(v, &float_value[1], fmt);                  ieee_interpret_float_value(v, &float_value[1], ieee_fmt);
1100          }          }
1101    
1102          switch (op) {          switch (op) {
# Line 1833  static int fpu_op(struct cpu *cpu, struc Line 1171  static int fpu_op(struct cpu *cpu, struc
1171                   *  TODO:  this is for 32-bit mode. It has to be updated later                   *  TODO:  this is for 32-bit mode. It has to be updated later
1172                   *              for 64-bit coprocessor stuff.                   *              for 64-bit coprocessor stuff.
1173                   */                   */
1174                  if (output_fmt == FMT_D || output_fmt == FMT_L) {                  if (output_fmt == COP1_FMT_D || output_fmt == COP1_FMT_L) {
1175                          cp->reg[fd] = fs_v & 0xffffffffULL;                          cp->reg[fd] = fs_v & 0xffffffffULL;
1176                          cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;                          cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;
1177                          if (cp->reg[fd] & 0x80000000ULL)                          if (cp->reg[fd] & 0x80000000ULL)
# Line 1924  static int fpu_function(struct cpu *cpu, Line 1262  static int fpu_function(struct cpu *cpu,
1262    
1263          /*  bc1f, bc1t, bc1fl, bc1tl:  */          /*  bc1f, bc1t, bc1fl, bc1tl:  */
1264          if ((function & 0x03e00000) == 0x01000000) {          if ((function & 0x03e00000) == 0x01000000) {
1265                  int nd, tf, imm, cond_true;                  int nd, tf, imm;
1266                  char *instr_mnem;                  char *instr_mnem;
1267    
1268                  /*  cc are bits 20..18:  */                  /*  cc are bits 20..18:  */
# Line 1947  static int fpu_function(struct cpu *cpu, Line 1285  static int fpu_function(struct cpu *cpu,
1285                  if (unassemble_only)                  if (unassemble_only)
1286                          return 1;                          return 1;
1287    
1288                  if (cpu->cd.mips.delay_slot) {                  fatal("INTERNAL ERROR: MIPS coprocessor branches should not"
1289                          fatal("%s: jump inside a jump's delay slot, "                      " be implemented in cpu_mips_coproc.c, but in"
1290                              "or similar. TODO\n", instr_mnem);                      " cpu_mips_instr.c!\n");
1291                          cpu->running = 0;                  exit(1);
                         return 1;  
                 }  
   
                 /*  Both the FCCR and FCSR contain condition code bits...  */  
                 if (cc == 0)  
                         cond_true = (cp->fcr[FPU_FCSR] >> FCSR_FCC0_SHIFT) & 1;  
                 else  
                         cond_true = (cp->fcr[FPU_FCSR] >>  
                             (FCSR_FCC1_SHIFT + cc-1)) & 1;  
   
                 if (!tf)  
                         cond_true = !cond_true;  
   
                 if (cond_true) {  
                         cpu->cd.mips.delay_slot = TO_BE_DELAYED;  
                         cpu->cd.mips.delay_jmpaddr = cpu->pc + (imm << 2);  
                 } else {  
                         /*  "likely":  */  
                         if (nd) {  
                                 /*  nullify the delay slot  */  
                                 cpu->cd.mips.nullify_next = 1;  
                         }  
                 }  
   
                 return 1;  
1292          }          }
1293    
1294          /*  add.fmt: Floating-point add  */          /*  add.fmt: Floating-point add  */
1295          if ((function & 0x0000003f) == 0x00000000) {          if ((function & 0x0000003f) == 0x00000000) {
1296                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1297                          debug("add.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("add.%s\tr%i,r%i,r%i\n",
1298                                fmtname[fmt], fd, fs, ft);
1299                  if (unassemble_only)                  if (unassemble_only)
1300                          return 1;                          return 1;
1301    
# Line 1992  static int fpu_function(struct cpu *cpu, Line 1306  static int fpu_function(struct cpu *cpu,
1306          /*  sub.fmt: Floating-point subtract  */          /*  sub.fmt: Floating-point subtract  */
1307          if ((function & 0x0000003f) == 0x00000001) {          if ((function & 0x0000003f) == 0x00000001) {
1308                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1309                          debug("sub.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("sub.%s\tr%i,r%i,r%i\n",
1310                                fmtname[fmt], fd, fs, ft);
1311                  if (unassemble_only)                  if (unassemble_only)
1312                          return 1;                          return 1;
1313    
# Line 2003  static int fpu_function(struct cpu *cpu, Line 1318  static int fpu_function(struct cpu *cpu,
1318          /*  mul.fmt: Floating-point multiply  */          /*  mul.fmt: Floating-point multiply  */
1319          if ((function & 0x0000003f) == 0x00000002) {          if ((function & 0x0000003f) == 0x00000002) {
1320                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1321                          debug("mul.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("mul.%s\tr%i,r%i,r%i\n",
1322                                fmtname[fmt], fd, fs, ft);
1323                  if (unassemble_only)                  if (unassemble_only)
1324                          return 1;                          return 1;
1325    
# Line 2014  static int fpu_function(struct cpu *cpu, Line 1330  static int fpu_function(struct cpu *cpu,
1330          /*  div.fmt: Floating-point divide  */          /*  div.fmt: Floating-point divide  */
1331          if ((function & 0x0000003f) == 0x00000003) {          if ((function & 0x0000003f) == 0x00000003) {
1332                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1333                          debug("div.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("div.%s\tr%i,r%i,r%i\n",
1334                                fmtname[fmt], fd, fs, ft);
1335                  if (unassemble_only)                  if (unassemble_only)
1336                          return 1;                          return 1;
1337    
# Line 2025  static int fpu_function(struct cpu *cpu, Line 1342  static int fpu_function(struct cpu *cpu,
1342          /*  sqrt.fmt: Floating-point square-root  */          /*  sqrt.fmt: Floating-point square-root  */
1343          if ((function & 0x001f003f) == 0x00000004) {          if ((function & 0x001f003f) == 0x00000004) {
1344                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1345                          debug("sqrt.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("sqrt.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1346                  if (unassemble_only)                  if (unassemble_only)
1347                          return 1;                          return 1;
1348    
# Line 2036  static int fpu_function(struct cpu *cpu, Line 1353  static int fpu_function(struct cpu *cpu,
1353          /*  abs.fmt: Floating-point absolute value  */          /*  abs.fmt: Floating-point absolute value  */
1354          if ((function & 0x001f003f) == 0x00000005) {          if ((function & 0x001f003f) == 0x00000005) {
1355                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1356                          debug("abs.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("abs.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1357                  if (unassemble_only)                  if (unassemble_only)
1358                          return 1;                          return 1;
1359    
# Line 2047  static int fpu_function(struct cpu *cpu, Line 1364  static int fpu_function(struct cpu *cpu,
1364          /*  mov.fmt: Floating-point (non-arithmetic) move  */          /*  mov.fmt: Floating-point (non-arithmetic) move  */
1365          if ((function & 0x0000003f) == 0x00000006) {          if ((function & 0x0000003f) == 0x00000006) {
1366                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1367                          debug("mov.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("mov.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1368                  if (unassemble_only)                  if (unassemble_only)
1369                          return 1;                          return 1;
1370    
# Line 2058  static int fpu_function(struct cpu *cpu, Line 1375  static int fpu_function(struct cpu *cpu,
1375          /*  neg.fmt: Floating-point negate  */          /*  neg.fmt: Floating-point negate  */
1376          if ((function & 0x001f003f) == 0x00000007) {          if ((function & 0x001f003f) == 0x00000007) {
1377                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1378                          debug("neg.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("neg.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1379                  if (unassemble_only)                  if (unassemble_only)
1380                          return 1;                          return 1;
1381    
# Line 2069  static int fpu_function(struct cpu *cpu, Line 1386  static int fpu_function(struct cpu *cpu,
1386          /*  trunc.l.fmt: Truncate  */          /*  trunc.l.fmt: Truncate  */
1387          if ((function & 0x001f003f) == 0x00000009) {          if ((function & 0x001f003f) == 0x00000009) {
1388                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1389                          debug("trunc.l.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("trunc.l.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1390                  if (unassemble_only)                  if (unassemble_only)
1391                          return 1;                          return 1;
1392    
1393                  /*  TODO: not CVT?  */                  /*  TODO: not CVT?  */
1394    
1395                  fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_L);                  fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_L);
1396                  return 1;                  return 1;
1397          }          }
1398    
1399          /*  trunc.w.fmt: Truncate  */          /*  trunc.w.fmt: Truncate  */
1400          if ((function & 0x001f003f) == 0x0000000d) {          if ((function & 0x001f003f) == 0x0000000d) {
1401                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1402                          debug("trunc.w.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("trunc.w.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1403                  if (unassemble_only)                  if (unassemble_only)
1404                          return 1;                          return 1;
1405    
1406                  /*  TODO: not CVT?  */                  /*  TODO: not CVT?  */
1407    
1408                  fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_W);                  fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_W);
1409                  return 1;                  return 1;
1410          }          }
1411    
# Line 2098  static int fpu_function(struct cpu *cpu, Line 1415  static int fpu_function(struct cpu *cpu,
1415                  int bit;                  int bit;
1416    
1417                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1418                          debug("c.%i.%i\tr%i,r%i,r%i\n", cond, fmt, cc, fs, ft);                          debug("c.%s.%s\tcc%i,r%i,r%i\n", ccname[cond],
1419                                fmtname[fmt], cc, fs, ft);
1420                  if (unassemble_only)                  if (unassemble_only)
1421                          return 1;                          return 1;
1422    
# Line 2110  static int fpu_function(struct cpu *cpu, Line 1428  static int fpu_function(struct cpu *cpu,
1428                   *      FCCR:  bits 7..0                   *      FCCR:  bits 7..0
1429                   *      FCSR:  bits 31..25 and 23                   *      FCSR:  bits 31..25 and 23
1430                   */                   */
1431                  cp->fcr[FPU_FCCR] &= ~(1 << cc);                  cp->fcr[MIPS_FPU_FCCR] &= ~(1 << cc);
1432                  if (cond_true)                  if (cond_true)
1433                          cp->fcr[FPU_FCCR] |= (1 << cc);                          cp->fcr[MIPS_FPU_FCCR] |= (1 << cc);
1434    
1435                  if (cc == 0) {                  if (cc == 0) {
1436                          bit = 1 << FCSR_FCC0_SHIFT;                          bit = 1 << MIPS_FCSR_FCC0_SHIFT;
1437                          cp->fcr[FPU_FCSR] &= ~bit;                          cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1438                          if (cond_true)                          if (cond_true)
1439                                  cp->fcr[FPU_FCSR] |= bit;                                  cp->fcr[MIPS_FPU_FCSR] |= bit;
1440                  } else {                  } else {
1441                          bit = 1 << (FCSR_FCC1_SHIFT + cc-1);                          bit = 1 << (MIPS_FCSR_FCC1_SHIFT + cc-1);
1442                          cp->fcr[FPU_FCSR] &= ~bit;                          cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1443                          if (cond_true)                          if (cond_true)
1444                                  cp->fcr[FPU_FCSR] |= bit;                                  cp->fcr[MIPS_FPU_FCSR] |= bit;
1445                  }                  }
1446    
1447                  return 1;                  return 1;
# Line 2132  static int fpu_function(struct cpu *cpu, Line 1450  static int fpu_function(struct cpu *cpu,
1450          /*  cvt.s.fmt: Convert to single floating-point  */          /*  cvt.s.fmt: Convert to single floating-point  */
1451          if ((function & 0x001f003f) == 0x00000020) {          if ((function & 0x001f003f) == 0x00000020) {
1452                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1453                          debug("cvt.s.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("cvt.s.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1454                  if (unassemble_only)                  if (unassemble_only)
1455                          return 1;                          return 1;
1456    
1457                  fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_S);                  fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_S);
1458                  return 1;                  return 1;
1459          }          }
1460    
1461          /*  cvt.d.fmt: Convert to double floating-point  */          /*  cvt.d.fmt: Convert to double floating-point  */
1462          if ((function & 0x001f003f) == 0x00000021) {          if ((function & 0x001f003f) == 0x00000021) {
1463                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1464                          debug("cvt.d.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("cvt.d.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1465                  if (unassemble_only)                  if (unassemble_only)
1466                          return 1;                          return 1;
1467    
1468                  fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_D);                  fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_D);
1469                  return 1;                  return 1;
1470          }          }
1471    
1472          /*  cvt.w.fmt: Convert to word fixed-point  */          /*  cvt.w.fmt: Convert to word fixed-point  */
1473          if ((function & 0x001f003f) == 0x00000024) {          if ((function & 0x001f003f) == 0x00000024) {
1474                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1475                          debug("cvt.w.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("cvt.w.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1476                  if (unassemble_only)                  if (unassemble_only)
1477                          return 1;                          return 1;
1478    
1479                  fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, FMT_W);                  fpu_op(cpu, cp, FPU_OP_CVT, fmt, -1, fs, fd, -1, COP1_FMT_W);
1480                  return 1;                  return 1;
1481          }          }
1482    
# Line 2184  void coproc_tlbpr(struct cpu *cpu, int r Line 1502  void coproc_tlbpr(struct cpu *cpu, int r
1502                              R2K3K_INDEX_SHIFT;                              R2K3K_INDEX_SHIFT;
1503                          if (i >= cp->nr_of_tlbs) {                          if (i >= cp->nr_of_tlbs) {
1504                                  /*  TODO:  exception?  */                                  /*  TODO:  exception?  */
1505                                  fatal("warning: tlbr from index %i (too "                                  fatal("[ warning: tlbr from index %i (too "
1506                                      "high)\n", i);                                      "high) ]\n", i);
1507                                  return;                                  return;
1508                          }                          }
1509    
1510                          /*                          cp->reg[COP0_ENTRYHI]  = cp->tlbs[i].hi;
1511                           *  TODO: Hm. Earlier I had an & ~0x3f on the high                          cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;
                          *  assignment and an & ~0xff on the lo0 assignment.  
                          *  I wonder why.  
                          */  
   
                         cp->reg[COP0_ENTRYHI]  = cp->tlbs[i].hi; /* & ~0x3f; */  
                         cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;/* & ~0xff; */  
1512                  } else {                  } else {
1513                          /*  R4000:  */                          /*  R4000:  */
1514                          i = cp->reg[COP0_INDEX] & INDEX_MASK;                          i = cp->reg[COP0_INDEX] & INDEX_MASK;
# Line 2288  void coproc_tlbpr(struct cpu *cpu, int r Line 1600  void coproc_tlbpr(struct cpu *cpu, int r
1600  /*  /*
1601   *  coproc_tlbwri():   *  coproc_tlbwri():
1602   *   *
1603   *  'tlbwr' and 'tlbwi'   *  MIPS TLB write random (tlbwr) and write indexed (tlbwi) instructions.
1604   */   */
1605  void coproc_tlbwri(struct cpu *cpu, int randomflag)  void coproc_tlbwri(struct cpu *cpu, int randomflag)
1606  {  {
1607          struct mips_coproc *cp = cpu->cd.mips.coproc[0];          struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1608          int index, g_bit;          int index, g_bit;
1609          uint64_t oldvaddr;          uint64_t oldvaddr;
         int old_asid = -1;  
   
         /*  
          *  ... and the last instruction page:  
          *  
          *  Some thoughts about this:  Code running in  
          *  the kernel's physical address space has the  
          *  same vaddr->paddr translation, so the last  
          *  virtual page invalidation only needs to  
          *  happen if we are for some extremely weird  
          *  reason NOT running in the kernel's physical  
          *  address space.  
          *  
          *  (An even insaner (but probably useless)  
          *  optimization would be to only invalidate  
          *  the last virtual page stuff if the TLB  
          *  update actually affects the vaddr in  
          *  question.)  
          */  
   
         if (cpu->pc < (uint64_t)0xffffffff80000000ULL ||  
             cpu->pc >= (uint64_t)0xffffffffc0000000ULL)  
                 cpu->cd.mips.pc_last_virtual_page =  
                     PC_LAST_PAGE_IMPOSSIBLE_VALUE;  
1610    
1611          if (randomflag) {          if (randomflag) {
1612                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
1613                          index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)                          index = ((cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
1614                              >> R2K3K_RANDOM_SHIFT;                              >> R2K3K_RANDOM_SHIFT) - 1;
1615                  else                          /*  R3000 always has 8 wired entries:  */
1616                            if (index < 8)
1617                                    index = cp->nr_of_tlbs - 1;
1618                            cp->reg[COP0_RANDOM] = index << R2K3K_RANDOM_SHIFT;
1619                    } else {
1620                            cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
1621                                % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
1622                          index = cp->reg[COP0_RANDOM] & RANDOM_MASK;                          index = cp->reg[COP0_RANDOM] & RANDOM_MASK;
1623                    }
1624          } else {          } else {
1625                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1626                          index = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK)                          index = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK)
# Line 2341  void coproc_tlbwri(struct cpu *cpu, int Line 1636  void coproc_tlbwri(struct cpu *cpu, int
1636                  return;                  return;
1637          }          }
1638    
1639    
1640  #if 0  #if 0
1641          /*  Debug dump of the previous entry at that index:  */          /*  Debug dump of the previous entry at that index:  */
1642          debug(" old entry at index = %04x", index);          fatal("{ old TLB entry at index %02x:", index);
1643          debug(" mask = %016llx", (long long) cp->tlbs[index].mask);          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1644          debug(" hi = %016llx", (long long) cp->tlbs[index].hi);                  fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1645          debug(" lo0 = %016llx", (long long) cp->tlbs[index].lo0);                  fatal(" lo=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1646          debug(" lo1 = %016llx\n", (long long) cp->tlbs[index].lo1);          } else {
1647                    if (cpu->is_32bit) {
1648                            fatal(" mask=%08"PRIx32,(uint32_t)cp->tlbs[index].mask);
1649                            fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1650                            fatal(" lo0=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1651                            fatal(" lo1=%08"PRIx32, (uint32_t)cp->tlbs[index].lo1);
1652                    } else {
1653                            fatal(" mask=%016"PRIx64, cp->tlbs[index].mask);
1654                            fatal(" hi=%016"PRIx64, cp->tlbs[index].hi);
1655                            fatal(" lo0=%016"PRIx64, cp->tlbs[index].lo0);
1656                            fatal(" lo1=%016"PRIx64, cp->tlbs[index].lo1);
1657                    }
1658            }
1659            fatal(" }\n");
1660  #endif  #endif
1661    
1662          /*  Translation caches must be invalidated:  */          /*
1663             *  Any virtual address translation for the old TLB entry must be
1664             *  invalidated first:
1665             *
1666             *  (Only Valid entries need to be invalidated, and only those that
1667             *  are either Global, or have the same ASID as the new entry will
1668             *  have. No other address translations should be active anyway.)
1669             */
1670    
1671          switch (cpu->cd.mips.cpu_type.mmu_model) {          switch (cpu->cd.mips.cpu_type.mmu_model) {
1672    
1673          case MMU3K:          case MMU3K:
1674                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;
1675                  oldvaddr &= 0xffffffffULL;                  oldvaddr = (int32_t) oldvaddr;
                 if (oldvaddr & 0x80000000ULL)  
                         oldvaddr |= 0xffffffff00000000ULL;  
                 old_asid = (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK)  
                     >> R2K3K_ENTRYHI_ASID_SHIFT;  
1676    
1677  /*  TODO: Bug? Why does this if need to be commented out?  */                  if (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_V &&
1678                        (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_G ||
1679                        (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK) ==
1680                        (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK) ))
1681                            cpu->invalidate_translation_caches(cpu, oldvaddr,
1682                                INVALIDATE_VADDR);
1683    
                 /*  if (cp->tlbs[index].lo0 & ENTRYLO_V)  */  
                         invalidate_translation_caches(cpu, 0, oldvaddr, 0, 0);  
1684                  break;                  break;
1685          default:  
1686                  if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {          default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1687                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;                          oldvaddr = cp->tlbs[index].hi &
1688                                (ENTRYHI_VPN2_MASK_R10K | ENTRYHI_R_MASK);
1689                          /*  44 addressable bits:  */                          /*  44 addressable bits:  */
1690                          if (oldvaddr & 0x80000000000ULL)                          if (oldvaddr & 0x80000000000ULL)
1691                                  oldvaddr |= 0xfffff00000000000ULL;                                  oldvaddr |= 0x3ffff00000000000ULL;
1692                    } else if (cpu->is_32bit) {
1693                            /*  MIPS32 etc.:  */
1694                            oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1695                            oldvaddr = (int32_t)oldvaddr;
1696                  } else {                  } else {
1697                          /*  Assume MMU4K  */                          /*  Assume MMU4K  */
1698                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;                          oldvaddr = cp->tlbs[index].hi &
1699                                (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK);
1700                          /*  40 addressable bits:  */                          /*  40 addressable bits:  */
1701                          if (oldvaddr & 0x8000000000ULL)                          if (oldvaddr & 0x8000000000ULL)
1702                                  oldvaddr |= 0xffffff0000000000ULL;                                  oldvaddr |= 0x3fffff0000000000ULL;
1703                  }                  }
1704    
1705                  /*                  /*
                  *  Both pages:  
                  *  
1706                   *  TODO: non-4KB page sizes!                   *  TODO: non-4KB page sizes!
1707                   */                   */
1708                  invalidate_translation_caches(                  if (cp->tlbs[index].lo0 & ENTRYLO_V)
1709                      cpu, 0, oldvaddr & ~0x1fff, 0, 0);                          cpu->invalidate_translation_caches(cpu, oldvaddr,
1710                  invalidate_translation_caches(                              INVALIDATE_VADDR);
1711                      cpu, 0, (oldvaddr & ~0x1fff) | 0x1000, 0, 0);                  if (cp->tlbs[index].lo1 & ENTRYLO_V)
1712                            cpu->invalidate_translation_caches(cpu, oldvaddr|0x1000,
1713                                INVALIDATE_VADDR);
1714          }          }
1715    
1716    #if 0
1717          /*          /*
1718           *  Check for duplicate entries.  (There should not be two mappings           *  Check for duplicate entries.  (There should not be two mappings
1719           *  from one virtual address to physical addresses.)           *  from one virtual address to physical addresses.)
# Line 2402  void coproc_tlbwri(struct cpu *cpu, int Line 1725  void coproc_tlbwri(struct cpu *cpu, int
1725          if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&          if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&
1726              cpu->cd.mips.cpu_type.rev != MIPS_R4100) {              cpu->cd.mips.cpu_type.rev != MIPS_R4100) {
1727                  uint64_t vaddr1, vaddr2;                  uint64_t vaddr1, vaddr2;
1728                  int i, asid;                  int i;
1729                    unsigned int asid;
1730    
1731                  vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K;                  vaddr1 = cp->reg[COP0_ENTRYHI] &
1732                        (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1733                  asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;                  asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
1734                  /*  Since this is just a warning, it's probably not necessary                  /*  Since this is just a warning, it's probably not necessary
1735                      to use R4000 masks etc.  */                      to use R4000 masks etc.  */
# Line 2417  void coproc_tlbwri(struct cpu *cpu, int Line 1742  void coproc_tlbwri(struct cpu *cpu, int
1742                              (cp->tlbs[i].hi & ENTRYHI_ASID) != asid)                              (cp->tlbs[i].hi & ENTRYHI_ASID) != asid)
1743                                  continue;                                  continue;
1744    
1745                          vaddr2 = cp->tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;                          vaddr2 = cp->tlbs[i].hi &
1746                                (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1747                          if (vaddr1 == vaddr2 && ((cp->tlbs[i].lo0 &                          if (vaddr1 == vaddr2 && ((cp->tlbs[i].lo0 &
1748                              ENTRYLO_V) || (cp->tlbs[i].lo1 & ENTRYLO_V)))                              ENTRYLO_V) || (cp->tlbs[i].lo1 & ENTRYLO_V)))
1749                                  fatal("\n[ WARNING! tlbw%s to index 0x%02x "                                  fatal("\n[ WARNING! tlbw%s to index 0x%02x "
# Line 2427  void coproc_tlbwri(struct cpu *cpu, int Line 1753  void coproc_tlbwri(struct cpu *cpu, int
1753                                      (long long)vaddr1, asid, i);                                      (long long)vaddr1, asid, i);
1754                  }                  }
1755          }          }
1756    #endif
1757    
1758          /*  Write the new entry:  */          /*  Write the new entry:  */
1759    
1760          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1761                  uint64_t vaddr, paddr;                  uint32_t vaddr, paddr;
1762                  int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;                  int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;
1763                  unsigned char *memblock = NULL;                  unsigned char *memblock = NULL;
1764    
# Line 2442  void coproc_tlbwri(struct cpu *cpu, int Line 1768  void coproc_tlbwri(struct cpu *cpu, int
1768                  vaddr =  cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;                  vaddr =  cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
1769                  paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;                  paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;
1770    
1771                  /*  TODO: This is ugly.  */                  memblock = memory_paddr_to_hostaddr(cpu->mem, paddr, 0);
                 if (paddr < 0x10000000)  
                         memblock = memory_paddr_to_hostaddr(  
                             cpu->mem, paddr, 1);  
   
                 if (memblock != NULL &&  
                     cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) {  
                         memblock += (paddr & ((1 << BITS_PER_PAGETABLE) - 1));  
1772    
1773                          /*                  /*  Invalidate any code translation, if we are writing
1774                           *  TODO: Hahaha, this is even uglier than the thing                      a Dirty page to the TLB:  */
1775                           *  above. Some OSes seem to map code pages read/write,                  if (wf) {
1776                           *  which causes the bintrans cache to be invalidated                          cpu->invalidate_code_translation(cpu, paddr,
1777                           *  even when it doesn't have to be.                              INVALIDATE_PADDR);
1778                           */                  }
1779  /*                      if (vaddr < 0x10000000)  */  
1780                                  wf = 0;                  /*  Set new last_written_tlb_index hint:  */
1781                    cpu->cd.mips.last_written_tlb_index = index;
1782    
1783                    if (cp->reg[COP0_STATUS] & MIPS1_ISOL_CACHES) {
1784                            fatal("Wow! Interesting case; tlbw* while caches"
1785                                " are isolated. TODO\n");
1786                            /*  Don't update the translation table in this
1787                                case...  */
1788                            exit(1);
1789                    }
1790    
1791                    /*  If we have a memblock (host page) for the physical
1792                        page, then add a translation for it immediately:  */
1793                    if (memblock != NULL &&
1794                        cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V)
1795                          cpu->update_translation_table(cpu, vaddr, memblock,                          cpu->update_translation_table(cpu, vaddr, memblock,
1796                              wf, paddr);                              wf, paddr);
                 }  
1797          } else {          } else {
1798                  /*  R4000:  */                  /*  R4000 etc.:  */
1799                  g_bit = (cp->reg[COP0_ENTRYLO0] &                  unsigned char *memblock = NULL;
1800                      cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;                  int pfn_shift = 12, vpn_shift = 12;
1801                    int wf0, wf1, mask;
1802                    uint64_t vaddr0, vaddr1, paddr0, paddr1, ptmp;
1803    
1804                  cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];                  cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];
1805                  cp->tlbs[index].hi   = cp->reg[COP0_ENTRYHI];                  cp->tlbs[index].hi   = cp->reg[COP0_ENTRYHI];
1806                  cp->tlbs[index].lo1  = cp->reg[COP0_ENTRYLO1];                  cp->tlbs[index].lo1  = cp->reg[COP0_ENTRYLO1];
1807                  cp->tlbs[index].lo0  = cp->reg[COP0_ENTRYLO0];                  cp->tlbs[index].lo0  = cp->reg[COP0_ENTRYLO0];
1808    
1809                    wf0 = cp->tlbs[index].lo0 & ENTRYLO_D;
1810                    wf1 = cp->tlbs[index].lo1 & ENTRYLO_D;
1811    
1812                    mask = cp->reg[COP0_PAGEMASK];
1813                    if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1814                            pfn_shift = 10;
1815                            mask |= 0x07ff;
1816                    } else {
1817                            mask |= 0x1fff;
1818                    }
1819                    switch (mask) {
1820                    case 0x00007ff:
1821                            if (cp->tlbs[index].lo0 & ENTRYLO_V ||
1822                                cp->tlbs[index].lo1 & ENTRYLO_V) {
1823                                    fatal("1KB pages don't work with dyntrans.\n");
1824                                    exit(1);
1825                            }
1826                            vpn_shift = 10;
1827                            break;
1828                    case 0x0001fff: break;
1829                    case 0x0007fff: vpn_shift = 14; break;
1830                    case 0x001ffff: vpn_shift = 16; break;
1831                    case 0x007ffff: vpn_shift = 18; break;
1832                    case 0x01fffff: vpn_shift = 20; break;
1833                    case 0x07fffff: vpn_shift = 22; break;
1834                    case 0x1ffffff: vpn_shift = 24; break;
1835                    case 0x7ffffff: vpn_shift = 26; break;
1836                    default:fatal("Unimplemented MASK = 0x%016x\n", mask);
1837                            exit(1);
1838                    }
1839    
1840                    paddr0 = ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK)
1841                        >> ENTRYLO_PFN_SHIFT) << pfn_shift;
1842                    paddr1 = ((cp->tlbs[index].lo1 & ENTRYLO_PFN_MASK)
1843                        >> ENTRYLO_PFN_SHIFT) << pfn_shift;
1844    
1845                    if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1846                            vaddr0 = cp->tlbs[index].hi &
1847                                (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1848                            /*  44 addressable bits:  */
1849                            if (vaddr0 & 0x80000000000ULL)
1850                                    vaddr0 |= 0x3ffff00000000000ULL;
1851                    } else if (cpu->is_32bit) {
1852                            /*  MIPS32 etc.:  */
1853                            vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1854                            vaddr0 = (int32_t)vaddr0;
1855                    } else {
1856                            /*  Assume MMU4K  */
1857                            vaddr0 = cp->tlbs[index].hi &
1858                                (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK);
1859                            /*  40 addressable bits:  */
1860                            if (vaddr0 & 0x8000000000ULL)
1861                                    vaddr0 |= 0x3fffff0000000000ULL;
1862                    }
1863    
1864                    vaddr1 = vaddr0 | (1 << vpn_shift);
1865    
1866                    g_bit = (cp->reg[COP0_ENTRYLO0] &
1867                        cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;
1868    
1869                  if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {                  if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1870                          /*  NOTE: The VR4131 (and possibly others) don't have                          /*  NOTE: The VR4131 (and possibly others) don't have
1871                              a Global bit in entryhi  */                              a Global bit in entryhi  */
# Line 2484  void coproc_tlbwri(struct cpu *cpu, int Line 1878  void coproc_tlbwri(struct cpu *cpu, int
1878                          if (g_bit)                          if (g_bit)
1879                                  cp->tlbs[index].hi |= TLB_G;                                  cp->tlbs[index].hi |= TLB_G;
1880                  }                  }
         }  
1881    
1882          if (randomflag) {                  /*
1883                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {                   *  Invalidate any code translations, if we are writing Dirty
1884                          cp->reg[COP0_RANDOM] =                   *  pages to the TLB:  (TODO: 4KB hardcoded... ugly)
1885                              ((random() % (cp->nr_of_tlbs - 8)) + 8)                   */
1886                              << R2K3K_RANDOM_SHIFT;                  for (ptmp = 0; ptmp < (1 << pfn_shift); ptmp += 0x1000) {
1887                  } else {                          if (wf0)
1888                          cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()                                  cpu->invalidate_code_translation(cpu,
1889                              % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));                                      paddr0 + ptmp, INVALIDATE_PADDR);
1890                            if (wf1)
1891                                    cpu->invalidate_code_translation(cpu,
1892                                        paddr1 + ptmp, INVALIDATE_PADDR);
1893                  }                  }
         }  
 }  
   
   
 /*  
  *  coproc_rfe():  
  *  
  *  Return from exception. (R3000 etc.)  
  */  
 void coproc_rfe(struct cpu *cpu)  
 {  
         int oldmode;  
1894    
1895          oldmode = cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_SR_KU_CUR;                  /*
1896                     *  If we have a memblock (host page) for the physical page,
1897                     *  then add a translation for it immediately, to save some
1898                     *  time. (It would otherwise be added later on anyway,
1899                     *  because of a translation miss.)
1900                     *
1901                     *  NOTE/TODO: This is only for 4KB pages so far. It would
1902                     *             be too expensive to add e.g. 16MB pages like
1903                     *             this.
1904                     */
1905                    memblock = memory_paddr_to_hostaddr(cpu->mem, paddr0, 0);
1906                    if (memblock != NULL && cp->reg[COP0_ENTRYLO0] & ENTRYLO_V)
1907                            cpu->update_translation_table(cpu, vaddr0, memblock,
1908                                wf0, paddr0);
1909                    memblock = memory_paddr_to_hostaddr(cpu->mem, paddr1, 0);
1910                    if (memblock != NULL && cp->reg[COP0_ENTRYLO1] & ENTRYLO_V)
1911                            cpu->update_translation_table(cpu, vaddr1, memblock,
1912                                wf1, paddr1);
1913    
1914          cpu->cd.mips.coproc[0]->reg[COP0_STATUS] =                  /*  Set new last_written_tlb_index hint:  */
1915              (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) |                  cpu->cd.mips.last_written_tlb_index = index;
1916              ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 0x3c) >> 2);          }
   
         /*  Changing from kernel to user mode? Then this is necessary:  */  
         if (!oldmode &&  
             (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &  
             MIPS1_SR_KU_CUR))  
                 invalidate_translation_caches(cpu, 0, 0, 1, 0);  
1917  }  }
1918    
1919    
# Line 2529  void coproc_rfe(struct cpu *cpu) Line 1924  void coproc_rfe(struct cpu *cpu)
1924   */   */
1925  void coproc_eret(struct cpu *cpu)  void coproc_eret(struct cpu *cpu)
1926  {  {
         int oldmode, newmode;  
   
         /*  Kernel mode flag:  */  
         oldmode = 0;  
         if ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS3_SR_KSU_MASK)  
                         != MIPS3_SR_KSU_USER  
             || (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & (STATUS_EXL |  
             STATUS_ERL)) ||  
             (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 1) == 0)  
                 oldmode = 1;  
   
1927          if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {          if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {
1928                  cpu->pc = cpu->cd.mips.pc_last =                  cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC];
                     cpu->cd.mips.coproc[0]->reg[COP0_ERROREPC];  
1929                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;
1930          } else {          } else {
1931                  cpu->pc = cpu->cd.mips.pc_last =                  cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_EPC];
1932                      cpu->cd.mips.coproc[0]->reg[COP0_EPC];                  cpu->delay_slot = 0;
                 cpu->cd.mips.delay_slot = 0;  
1933                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;
1934          }          }
1935    
1936          cpu->cd.mips.rmw = 0;   /*  the "LL bit"  */          cpu->cd.mips.rmw = 0;   /*  the "LL bit"  */
   
         /*  New kernel mode flag:  */  
         newmode = 0;  
         if ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS3_SR_KSU_MASK)  
                         != MIPS3_SR_KSU_USER  
             || (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & (STATUS_EXL |  
             STATUS_ERL)) ||  
             (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 1) == 0)  
                 newmode = 1;  
   
 #if 0  
         /*  Changing from kernel to user mode?  
             Then this is necessary:  TODO  */  
         if (oldmode && !newmode)  
                 invalidate_translation_caches(cpu, 0, 0, 1, 0);  
 #endif  
1937  }  }
1938    
1939    
# Line 2597  void coproc_function(struct cpu *cpu, st Line 1963  void coproc_function(struct cpu *cpu, st
1963                  return;                  return;
1964          }          }
1965    
 #if 0  
1966          /*  No FPU?  */          /*  No FPU?  */
1967          if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {          if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {
1968                  mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);                  mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);
1969                  return;                  return;
1970          }          }
 #endif  
1971    
1972          /*  For quick reference:  */          /*  For quick reference:  */
1973          copz = (function >> 21) & 31;          copz = (function >> 21) & 31;
# Line 2618  void coproc_function(struct cpu *cpu, st Line 1982  void coproc_function(struct cpu *cpu, st
1982                          if (cpnr == 0)                          if (cpnr == 0)
1983                                  debug("%s", cop0_names[rd]);                                  debug("%s", cop0_names[rd]);
1984                          else                          else
1985                                  debug("cpreg%i", rd);                                  debug("r%i", rd);
1986                          if (function & 7)                          if (function & 7)
1987                                  debug(",%i", (int)(function & 7));                                  debug(",%i", (int)(function & 7));
1988                          debug("\n");                          debug("\n");
# Line 2644  void coproc_function(struct cpu *cpu, st Line 2008  void coproc_function(struct cpu *cpu, st
2008                          if (cpnr == 0)                          if (cpnr == 0)
2009                                  debug("%s", cop0_names[rd]);                                  debug("%s", cop0_names[rd]);
2010                          else                          else
2011                                  debug("cpreg%i", rd);                                  debug("r%i", rd);
2012                          if (function & 7)                          if (function & 7)
2013                                  debug(",%i", (int)(function & 7));                                  debug(",%i", (int)(function & 7));
2014                          debug("\n");                          debug("\n");
# Line 2673  void coproc_function(struct cpu *cpu, st Line 2037  void coproc_function(struct cpu *cpu, st
2037                                      regnames[rt], fs);                                      regnames[rt], fs);
2038                                  return;                                  return;
2039                          }                          }
2040                          cpu->cd.mips.gpr[rt] = cp->fcr[fs] & 0xffffffffULL;                          cpu->cd.mips.gpr[rt] = (int32_t)cp->fcr[fs];
                         if (cpu->cd.mips.gpr[rt] & 0x80000000ULL)  
                                 cpu->cd.mips.gpr[rt] |= 0xffffffff00000000ULL;  
2041                          /*  TODO: implement delay for gpr[rt]                          /*  TODO: implement delay for gpr[rt]
2042                              (for MIPS I,II,III only)  */                              (for MIPS I,II,III only)  */
2043                          return;                          return;
# Line 2707  void coproc_function(struct cpu *cpu, st Line 2069  void coproc_function(struct cpu *cpu, st
2069                                              on status bits!  */                                              on status bits!  */
2070    
2071                                          switch (fs) {                                          switch (fs) {
2072                                          case FPU_FCCR:                                          case MIPS_FPU_FCCR:
2073                                                  cp->fcr[FPU_FCSR] =                                                  cp->fcr[MIPS_FPU_FCSR] =
2074                                                      (cp->fcr[FPU_FCSR] &                                                      (cp->fcr[MIPS_FPU_FCSR] &
2075                                                      0x017fffffULL) | ((tmp & 1)                                                      0x017fffffULL) | ((tmp & 1)
2076                                                      << FCSR_FCC0_SHIFT)                                                      << MIPS_FCSR_FCC0_SHIFT)
2077                                                      | (((tmp & 0xfe) >> 1) <<                                                      | (((tmp & 0xfe) >> 1) <<
2078                                                      FCSR_FCC1_SHIFT);                                                      MIPS_FCSR_FCC1_SHIFT);
2079                                                  break;                                                  break;
2080                                          case FPU_FCSR:                                          case MIPS_FPU_FCSR:
2081                                                  cp->fcr[FPU_FCCR] =                                                  cp->fcr[MIPS_FPU_FCCR] =
2082                                                      (cp->fcr[FPU_FCCR] &                                                      (cp->fcr[MIPS_FPU_FCCR] &
2083                                                      0xffffff00ULL) | ((tmp >>                                                      0xffffff00ULL) | ((tmp >>
2084                                                      FCSR_FCC0_SHIFT) & 1) |                                                      MIPS_FCSR_FCC0_SHIFT) & 1) |
2085                                                      (((tmp >> FCSR_FCC1_SHIFT)                                                      (((tmp >>
2086                                                        MIPS_FCSR_FCC1_SHIFT)
2087                                                      & 0x7f) << 1);                                                      & 0x7f) << 1);
2088                                                  break;                                                  break;
2089                                          default:                                          default:
# Line 2744  void coproc_function(struct cpu *cpu, st Line 2107  void coproc_function(struct cpu *cpu, st
2107                          return;                          return;
2108          }          }
2109    
         /*  For AU1500 and probably others:  deret  */  
         if (function == 0x0200001f) {  
                 if (unassemble_only) {  
                         debug("deret\n");  
                         return;  
                 }  
   
                 /*  
                  *  According to the MIPS64 manual, deret loads PC from the  
                  *  DEPC cop0 register, and jumps there immediately. No  
                  *  delay slot.  
                  *  
                  *  TODO: This instruction is only available if the processor  
                  *  is in debug mode. (What does that mean?)  
                  *  TODO: This instruction is undefined in a delay slot.  
                  */  
   
                 cpu->pc = cpu->cd.mips.pc_last = cp->reg[COP0_DEPC];  
                 cpu->cd.mips.delay_slot = 0;  
                 cp->reg[COP0_STATUS] &= ~STATUS_EXL;  
   
                 return;  
         }  
   
2110    
2111          /*  Ugly R5900 hacks:  */          /*  Ugly R5900 hacks:  */
2112          if ((function & 0xfffff) == 0x38) {             /*  ei  */          if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) {
2113                  if (unassemble_only) {                  if ((function & 0xfffff) == COP0_EI) {
2114                          debug("ei\n");                          if (unassemble_only) {
2115                                    debug("ei\n");
2116                                    return;
2117                            }
2118                            cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |=
2119                                R5900_STATUS_EIE;
2120                          return;                          return;
2121                  }                  }
                 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= R5900_STATUS_EIE;  
                 return;  
         }  
2122    
2123          if ((function & 0xfffff) == 0x39) {             /*  di  */                  if ((function & 0xfffff) == COP0_DI) {
2124                  if (unassemble_only) {                          if (unassemble_only) {
2125                          debug("di\n");                                  debug("di\n");
2126                                    return;
2127                            }
2128                            cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &=
2129                                ~R5900_STATUS_EIE;
2130                          return;                          return;
2131                  }                  }
                 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~R5900_STATUS_EIE;  
                 return;  
2132          }          }
2133    
2134          co_bit = (function >> 25) & 1;          co_bit = (function >> 25) & 1;
2135    
2136          /*  TLB operations and other things:  */          /*  TLB operations and other things:  */
2137          if (cp->coproc_nr == 0) {          if (cp->coproc_nr == 0) {
2138                    if (!unassemble_only) {
2139                            fatal("FATAL INTERNAL ERROR: Should be implemented"
2140                                " with dyntrans instead.\n");
2141                            exit(1);
2142                    }
2143    
2144                  op = (function) & 0xff;                  op = (function) & 0xff;
2145                  switch (co_bit) {                  switch (co_bit) {
2146                  case 1:                  case 1:
2147                          switch (op) {                          switch (op) {
2148                          case COP0_TLBR:         /*  Read indexed TLB entry  */                          case COP0_TLBR:         /*  Read indexed TLB entry  */
2149                                  if (unassemble_only) {                                  debug("tlbr\n");
                                         debug("tlbr\n");  
                                         return;  
                                 }  
                                 coproc_tlbpr(cpu, 1);  
2150                                  return;                                  return;
2151                          case COP0_TLBWI:        /*  Write indexed  */                          case COP0_TLBWI:        /*  Write indexed  */
2152                          case COP0_TLBWR:        /*  Write random  */                          case COP0_TLBWR:        /*  Write random  */
2153                                  if (unassemble_only) {                                  if (op == COP0_TLBWI)
2154                                          if (op == COP0_TLBWI)                                          debug("tlbwi");
2155                                                  debug("tlbwi");                                  else
2156                                          else                                          debug("tlbwr");
2157                                                  debug("tlbwr");                                  if (!running) {
2158                                          if (!running) {                                          debug("\n");
2159                                                  debug("\n");                                          return;
                                                 return;  
                                         }  
                                         debug("\tindex=%08llx",  
                                             (long long)cp->reg[COP0_INDEX]);  
                                         debug(", random=%08llx",  
                                             (long long)cp->reg[COP0_RANDOM]);  
                                         debug(", mask=%016llx",  
                                             (long long)cp->reg[COP0_PAGEMASK]);  
                                         debug(", hi=%016llx",  
                                             (long long)cp->reg[COP0_ENTRYHI]);  
                                         debug(", lo0=%016llx",  
                                             (long long)cp->reg[COP0_ENTRYLO0]);  
                                         debug(", lo1=%016llx\n",  
                                             (long long)cp->reg[COP0_ENTRYLO1]);  
2160                                  }                                  }
2161                                  coproc_tlbwri(cpu, op == COP0_TLBWR);                                  debug("\tindex=%08llx",
2162                                        (long long)cp->reg[COP0_INDEX]);
2163                                    debug(", random=%08llx",
2164                                        (long long)cp->reg[COP0_RANDOM]);
2165                                    debug(", mask=%016llx",
2166                                        (long long)cp->reg[COP0_PAGEMASK]);
2167                                    debug(", hi=%016llx",
2168                                        (long long)cp->reg[COP0_ENTRYHI]);
2169                                    debug(", lo0=%016llx",
2170                                        (long long)cp->reg[COP0_ENTRYLO0]);
2171                                    debug(", lo1=%016llx\n",
2172                                        (long long)cp->reg[COP0_ENTRYLO1]);
2173                                  return;                                  return;
2174                          case COP0_TLBP:         /*  Probe TLB for                          case COP0_TLBP:         /*  Probe TLB for
2175                                                      matching entry  */                                                      matching entry  */
2176                                  if (unassemble_only) {                                  debug("tlbp\n");
                                         debug("tlbp\n");  
                                         return;  
                                 }  
                                 coproc_tlbpr(cpu, 0);  
2177                                  return;                                  return;
2178                          case COP0_RFE:          /*  R2000/R3000 only:                          case COP0_RFE:          /*  R2000/R3000 only:
2179                                                      Return from Exception  */                                                      Return from Exception  */
2180                                  if (unassemble_only) {                                  debug("rfe\n");
                                         debug("rfe\n");  
                                         return;  
                                 }  
                                 coproc_rfe(cpu);  
2181                                  return;                                  return;
2182                          case COP0_ERET: /*  R4000: Return from exception  */                          case COP0_ERET: /*  R4000: Return from exception  */
2183                                  if (unassemble_only) {                                  debug("eret\n");
2184                                          debug("eret\n");                                  return;
2185                                          return;                          case COP0_DERET:
2186                                    debug("deret\n");
2187                                    return;
2188                            case COP0_WAIT:
2189                                    {
2190                                            int code = (function >> 6) & 0x7ffff;
2191                                            debug("wait");
2192                                            if (code > 0)
2193                                                    debug("\t0x%x", code);
2194                                            debug("\n");
2195                                  }                                  }
                                 coproc_eret(cpu);  
2196                                  return;                                  return;
2197                          case COP0_STANDBY:                          case COP0_STANDBY:
2198                                  if (unassemble_only) {                                  debug("standby\n");
                                         debug("standby\n");  
                                         return;  
                                 }  
                                 /*  TODO: Hm. Do something here?  */  
2199                                  return;                                  return;
2200                          case COP0_SUSPEND:                          case COP0_SUSPEND:
2201                                  if (unassemble_only) {                                  debug("suspend\n");
                                         debug("suspend\n");  
                                         return;  
                                 }  
                                 /*  TODO: Hm. Do something here?  */  
2202                                  return;                                  return;
2203                          case COP0_HIBERNATE:                          case COP0_HIBERNATE:
2204                                  if (unassemble_only) {                                  debug("hibernate\n");
                                         debug("hibernate\n");  
                                         return;  
                                 }  
                                 /*  TODO: Hm. Do something here?  */  
2205                                  return;                                  return;
2206                          default:                          default:
2207                                  ;                                  ;
# Line 2891  void coproc_function(struct cpu *cpu, st Line 2221  void coproc_function(struct cpu *cpu, st
2221                  return;                  return;
2222          }          }
2223    
         /*  TODO: RM5200 idle (?)  */  
         if ((cp->coproc_nr==0 || cp->coproc_nr==3) && function == 0x02000020) {  
                 if (unassemble_only) {  
                         debug("idle(?)\n");     /*  TODO  */  
                         return;  
                 }  
   
                 /*  Idle? TODO  */  
                 return;  
         }  
   
2224          if (unassemble_only) {          if (unassemble_only) {
2225                  debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function);                  debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function);
2226                  return;                  return;
2227          }          }
2228    
2229          fatal("cpu%i: UNIMPLEMENTED coproc%i function %08lx "          fatal("cpu%i: UNIMPLEMENTED coproc%i function %08"PRIx32" "
2230              "(pc = %016llx)\n", cpu->cpu_id, cp->coproc_nr, function,              "(pc = %016"PRIx64")\n", cpu->cpu_id, cp->coproc_nr,
2231              (long long)cpu->cd.mips.pc_last);              (uint32_t)function, cpu->pc);
2232  #if 1  
         single_step = 1;  
 #else  
2233          mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cp->coproc_nr, 0, 0, 0);          mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cp->coproc_nr, 0, 0, 0);
 #endif  
2234  }  }
2235    
2236  #endif  /*  ENABLE_MIPS  */  #endif  /*  ENABLE_MIPS  */

Legend:
Removed from v.14  
changed lines
  Added in v.32

  ViewVC Help
Powered by ViewVC 1.1.26