/[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 20 by dpavlin, Mon Oct 8 16:19:23 2007 UTC revision 40 by dpavlin, Mon Oct 8 16:22:11 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2007  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: cpu_mips_coproc.c,v 1.8 2005/11/23 02:17:41 debug Exp $   *  $Id: cpu_mips_coproc.c,v 1.64 2007/04/28 09:19:51 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"
# Line 46  Line 45 
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 69  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 84  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 dependent  */  
             | ((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 303  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 438  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 454  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 465  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 536  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, unsigned 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;          unsigned 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                  }                  }
         }  
 }  
566    
567                    for (i=0; i<ntlbs; i++) {
568  /*                          if (tlb[i].mask != 0 && tlb[i].mask != 0x1800) {
569   *  clear_all_chunks_from_all_tables():                                  non4kpages = 1;
570   */                                  continue;
 void clear_all_chunks_from_all_tables(struct cpu *cpu)  
 {  
         int a, b;  
         struct vth32_table *tbl1;  
   
         if (!cpu->machine->old_bintrans_enable) {  
                 printf("clear_all_chunks_from_all_tables(): New: TODO\n");  
                 return;  
         }  
   
         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                          }                          }
                 }  
         }  
 }  
   
   
 /*  
  *  mips_invalidate_translation_caches_paddr():  
  *  
  *  Invalidate based on physical address.  
  */  
 void mips_invalidate_translation_caches_paddr(struct cpu *cpu,  
         uint64_t paddr, int flags)  
 {  
         paddr &= ~0xfff;  
572    
573          if (cpu->machine->bintrans_enable) {                          if ((tlb[i].hi & ENTRYHI_ASID) == asid &&
574  #if 1                              !(tlb[i].hi & TLB_G)) {
575                  int i;                                  uint64_t vaddr0, vaddr1;
576                  uint64_t tlb_paddr0, tlb_paddr1;                                  vaddr0 = cp->tlbs[i].hi & ~fillmask;
577                  uint64_t tlb_vaddr;                                  if (vaddr0 & topbit)
578                  uint64_t p, p2;                                          vaddr0 |= fillmask;
579                                    vaddr1 = vaddr0 | 0x1000;  /*  TODO: mask  */
580                  switch (cpu->cd.mips.cpu_type.mmu_model) {  
581                  case MMU3K:                                  if (tlb[i].lo0 & ENTRYLO_V)
582                          for (i=0; i<64; i++) {                                          cpu->invalidate_translation_caches(cpu,
583                                  tlb_paddr0 = cpu->cd.mips.coproc[0]->                                              vaddr0, INVALIDATE_VADDR);
584                                      tlbs[i].lo0 & R2K3K_ENTRYLO_PFN_MASK;                                  if (tlb[i].lo1 & ENTRYLO_V)
585                                  tlb_vaddr = cpu->cd.mips.coproc[0]->                                          cpu->invalidate_translation_caches(cpu,
586                                      tlbs[i].hi & R2K3K_ENTRYHI_VPN_MASK;                                              vaddr1, INVALIDATE_VADDR);
                                 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;  
                                 int tmp_pmask = cpu->cd.mips.coproc[0]->  
                                     tlbs[i].mask | or_pmask;  
   
                                 if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {  
                                         or_pmask = 0x7ff;  
                                         phys_shift = 10;  
                                 }  
                                 switch (tmp_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: 0x%x\n",  
                                             (int)tmp_pmask);  
                                 }  
                                 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 1016  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  #if 0                  /*  TODO: Increase count in a more meaningful way!  */
618                  /*                  cp->reg[COP0_COUNT] = (int32_t) (cp->reg[COP0_COUNT] + 1);
                  *  This speeds up delay-loops that just read the count  
                  *  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);  
                 }  
 #endif  
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 1105  void coproc_register_write(struct cpu *c Line 683  void coproc_register_write(struct cpu *c
683          int readonly = 0;          int readonly = 0;
684          uint64_t tmp = *ptr;          uint64_t tmp = *ptr;
685          uint64_t tmp2 = 0, old;          uint64_t tmp2 = 0, old;
686          int inval = 0, old_asid, oldmode;          int inval = 0;
687            unsigned int old_asid;
688            uint64_t oldmode;
689    
690          switch (cp->coproc_nr) {          switch (cp->coproc_nr) {
691          case 0:          case 0:
# Line 1121  void coproc_register_write(struct cpu *c Line 701  void coproc_register_write(struct cpu *c
701                              (tmp & 0xff)!=0) {                              (tmp & 0xff)!=0) {
702                                  /*  char *symbol;                                  /*  char *symbol;
703                                      uint64_t offset;                                      uint64_t offset;
704                                      symbol = get_symbol_name(                                      symbol = get_symbol_name(cpu->pc, &offset);
                                     cpu->cd.mips.pc_last, &offset);  
705                                      fatal("YO! pc = 0x%08llx <%s> "                                      fatal("YO! pc = 0x%08llx <%s> "
706                                      "lo=%016llx\n", (long long)                                      "lo=%016llx\n", (long long)
707                                      cpu->cd.mips.pc_last, symbol? symbol :                                      cpu->pc, symbol? symbol :
708                                      "no symbol", (long long)tmp); */                                      "no symbol", (long long)tmp); */
709                                  tmp &= (R2K3K_ENTRYLO_PFN_MASK |                                  tmp &= (R2K3K_ENTRYLO_PFN_MASK |
710                                      R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |                                      R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |
# Line 1191  void coproc_register_write(struct cpu *c Line 770  void coproc_register_write(struct cpu *c
770                          unimpl = 0;                          unimpl = 0;
771                          break;                          break;
772                  case COP0_COUNT:                  case COP0_COUNT:
773                          if (tmp != (int64_t)(int32_t)tmp)                          if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
774                                  fatal("WARNING: trying to write a 64-bit value"                                  fatal("WARNING: trying to write a 64-bit value"
775                                      " to the COUNT register!\n");                                      " to the COUNT register!\n");
776                          tmp = (int64_t)(int32_t)tmp;                          tmp = (int64_t)(int32_t)tmp;
777                          unimpl = 0;                          unimpl = 0;
778                          break;                          break;
779                  case COP0_COMPARE:                  case COP0_COMPARE:
780                          /*  Clear the timer interrupt bit (bit 7):  */                          if (cpu->machine->emulated_hz > 0) {
781                          cpu->cd.mips.compare_register_set = 1;                                  int32_t compare_diff = tmp -
782                          mips_cpu_interrupt_ack(cpu, 7);                                      cp->reg[COP0_COMPARE];
783                          if (tmp != (int64_t)(int32_t)tmp)                                  double hz;
784    
785                                    if (compare_diff < 0)
786                                            hz = tmp - cp->reg[COP0_COUNT];
787    
788                                    if (compare_diff == 0)
789                                            hz = 0;
790                                    else
791                                            hz = (double)cpu->machine->emulated_hz
792                                                / (double)compare_diff;
793    /*
794     *  TODO: DON'T HARDCODE THIS!
795     */
796    hz = 100.0;
797    
798                                    /*  Initialize or re-set the periodic timer:  */
799                                    if (hz > 0) {
800                                            if (cpu->cd.mips.timer == NULL)
801                                                    cpu->cd.mips.timer = timer_add(
802                                                        hz, mips_timer_tick, cpu);
803                                            else
804                                                    timer_update_frequency(
805                                                        cpu->cd.mips.timer, hz);
806                                    }
807                            }
808    
809                            /*  Ack the periodic timer, if it was asserted:  */
810                            if (cp->reg[COP0_CAUSE] & 0x8000 &&
811                                cpu->cd.mips.compare_interrupts_pending > 0)
812                                    cpu->cd.mips.compare_interrupts_pending --;
813    
814                            /*  Clear the timer interrupt assertion (bit 7):  */
815                            cp->reg[COP0_CAUSE] &= ~0x8000;
816    
817                            if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
818                                  fatal("WARNING: trying to write a 64-bit value"                                  fatal("WARNING: trying to write a 64-bit value"
819                                      " to the COMPARE register!\n");                                      " to the COMPARE register!\n");
820    
821                          tmp = (int64_t)(int32_t)tmp;                          tmp = (int64_t)(int32_t)tmp;
822                            cpu->cd.mips.compare_register_set = 1;
823                          unimpl = 0;                          unimpl = 0;
824                          break;                          break;
825                  case COP0_ENTRYHI:                  case COP0_ENTRYHI:
826                          /*                          /*
827                           *  Translation caches must be invalidated, because the                           *  Translation caches must be invalidated if the
828                           *  address space might change (if the ASID changes).                           *  ASID changes:
829                           */                           */
830                          switch (cpu->cd.mips.cpu_type.mmu_model) {                          switch (cpu->cd.mips.cpu_type.mmu_model) {
831                          case MMU3K:                          case MMU3K:
832                                  old_asid = (cp->reg[COP0_ENTRYHI] &                                  old_asid = cp->reg[COP0_ENTRYHI] &
833                                      R2K3K_ENTRYHI_ASID_MASK) >>                                      R2K3K_ENTRYHI_ASID_MASK;
                                     R2K3K_ENTRYHI_ASID_SHIFT;  
834                                  if ((cp->reg[COP0_ENTRYHI] &                                  if ((cp->reg[COP0_ENTRYHI] &
835                                      R2K3K_ENTRYHI_ASID_MASK) !=                                      R2K3K_ENTRYHI_ASID_MASK) !=
836                                      (tmp & R2K3K_ENTRYHI_ASID_MASK))                                      (tmp & R2K3K_ENTRYHI_ASID_MASK))
# Line 1229  void coproc_register_write(struct cpu *c Line 843  void coproc_register_write(struct cpu *c
843                                          inval = 1;                                          inval = 1;
844                                  break;                                  break;
845                          }                          }
846    
847                          if (inval)                          if (inval)
848                                  invalidate_translation_caches(cpu, 1, 0, 0,                                  invalidate_asid(cpu, old_asid);
849                                      old_asid);  
850                          unimpl = 0;                          unimpl = 0;
851                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
852                              (tmp & 0x3f)!=0) {                              (tmp & 0x3f)!=0) {
853                                  /* char *symbol;                                  /* char *symbol;
854                                     uint64_t offset;                                     uint64_t offset;
855                                     symbol = get_symbol_name(cpu->                                     symbol = get_symbol_name(cpu->pc,
856                                      cd.mips.pc_last, &offset);                                      &offset);
857                                     fatal("YO! pc = 0x%08llx <%s> "                                     fatal("YO! pc = 0x%08llx <%s> "
858                                      "hi=%016llx\n", (long long)cpu->                                      "hi=%016llx\n", (long long)cpu->pc,
859                                      cd.mips.pc_last, symbol? symbol :                                      symbol? symbol :
860                                      "no symbol", (long long)tmp);  */                                      "no symbol", (long long)tmp);  */
861                                  tmp &= ~0x3f;                                  tmp &= ~0x3f;
862                          }                          }
# Line 1287  void coproc_register_write(struct cpu *c Line 902  void coproc_register_write(struct cpu *c
902                  case COP0_STATUS:                  case COP0_STATUS:
903                          oldmode = cp->reg[COP0_STATUS];                          oldmode = cp->reg[COP0_STATUS];
904                          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  
905    
906                            /*
907                             *  When isolating caches, invalidate all translations.
908                             *  During the isolation, a special hack in memory_rw.c
909                             *  prevents translation tables from being updated, so
910                             *  the translation caches don't have to be invalidated
911                             *  when switching back to normal mode.
912                             */
913                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
914                              (oldmode & MIPS1_ISOL_CACHES) !=                              (oldmode & MIPS1_ISOL_CACHES) !=
915                              (tmp & MIPS1_ISOL_CACHES)) {                              (tmp & MIPS1_ISOL_CACHES)) {
916                                  /*  R3000-style caches when isolated are                                  /*  Invalidate everything if we are switching
917                                      treated in bintrans mode by changing                                      to isolated mode:  */
                                     the vaddr_to_hostaddr_table0 pointer:  */  
918                                  if (tmp & MIPS1_ISOL_CACHES) {                                  if (tmp & MIPS1_ISOL_CACHES) {
919                                          /*  2-level table:  */                                          cpu->invalidate_translation_caches(
920                                          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;  
921                                  }                                  }
922                          }                          }
923                          unimpl = 0;                          unimpl = 0;
# Line 1347  void coproc_register_write(struct cpu *c Line 927  void coproc_register_write(struct cpu *c
927                              affects IM bits 0 and 1:  */                              affects IM bits 0 and 1:  */
928                          cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);                          cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);
929                          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;  
930                          return;                          return;
931                  case COP0_FRAMEMASK:                  case COP0_FRAMEMASK:
932                          /*  TODO: R10000  */                          /*  TODO: R10000  */
# Line 1433  static int mips_fmt_to_ieee_fmt[32] = { Line 1009  static int mips_fmt_to_ieee_fmt[32] = {
1009          IEEE_FMT_W, IEEE_FMT_L, /* PS (Paired Single) */ 0, 0,          IEEE_FMT_W, IEEE_FMT_L, /* PS (Paired Single) */ 0, 0,
1010          0, 0, 0, 0,  0, 0, 0, 0  };          0, 0, 0, 0,  0, 0, 0, 0  };
1011    
1012  /*  MIPS floating point types:  */  static char *fmtname[32] = {
1013  #define FMT_S           16           "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
1014  #define FMT_D           17           "8",  "9", "10", "11", "12", "13", "14", "15",
1015  #define FMT_W           20           "s",  "d", "18", "19",  "w",  "l", "ps", "23",
1016  #define FMT_L           21          "24", "25", "26", "27", "28", "29", "30", "31"  };
1017  #define FMT_PS          22  
1018    static char *ccname[16] = {
1019            "f",  "un",   "eq",  "ueq", "olt", "ult", "ole", "ule",
1020            "sf", "ngle", "seq", "ngl", "lt",  "nge", "le",  "ngt"  };
1021    
1022  #define FPU_OP_ADD      1  #define FPU_OP_ADD      1
1023  #define FPU_OP_SUB      2  #define FPU_OP_SUB      2
# Line 1468  static void fpu_store_float_value(struct Line 1047  static void fpu_store_float_value(struct
1047           *  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
1048           *        for 64-bit coprocessor functionality!           *        for 64-bit coprocessor functionality!
1049           */           */
1050          if (fmt == FMT_D || fmt == FMT_L) {          if (fmt == COP1_FMT_D || fmt == COP1_FMT_L) {
1051                  cp->reg[fd] = r & 0xffffffffULL;                  cp->reg[fd] = r & 0xffffffffULL;
1052                  cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;                  cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;
1053    
# Line 1507  static int fpu_op(struct cpu *cpu, struc Line 1086  static int fpu_op(struct cpu *cpu, struc
1086                  fs_v = cp->reg[fs];                  fs_v = cp->reg[fs];
1087                  /*  TODO: register-pair mode and plain                  /*  TODO: register-pair mode and plain
1088                      register mode? "FR" bit?  */                      register mode? "FR" bit?  */
1089                  if (fmt == FMT_D || fmt == FMT_L)                  if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1090                          fs_v = (fs_v & 0xffffffffULL) +                          fs_v = (fs_v & 0xffffffffULL) +
1091                              (cp->reg[(fs + 1) & 31] << 32);                              (cp->reg[(fs + 1) & 31] << 32);
1092                  ieee_interpret_float_value(fs_v, &float_value[0], ieee_fmt);                  ieee_interpret_float_value(fs_v, &float_value[0], ieee_fmt);
# Line 1516  static int fpu_op(struct cpu *cpu, struc Line 1095  static int fpu_op(struct cpu *cpu, struc
1095                  uint64_t v = cp->reg[ft];                  uint64_t v = cp->reg[ft];
1096                  /*  TODO: register-pair mode and                  /*  TODO: register-pair mode and
1097                      plain register mode? "FR" bit?  */                      plain register mode? "FR" bit?  */
1098                  if (fmt == FMT_D || fmt == FMT_L)                  if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1099                          v = (v & 0xffffffffULL) +                          v = (v & 0xffffffffULL) +
1100                              (cp->reg[(ft + 1) & 31] << 32);                              (cp->reg[(ft + 1) & 31] << 32);
1101                  ieee_interpret_float_value(v, &float_value[1], ieee_fmt);                  ieee_interpret_float_value(v, &float_value[1], ieee_fmt);
# Line 1594  static int fpu_op(struct cpu *cpu, struc Line 1173  static int fpu_op(struct cpu *cpu, struc
1173                   *  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
1174                   *              for 64-bit coprocessor stuff.                   *              for 64-bit coprocessor stuff.
1175                   */                   */
1176                  if (output_fmt == FMT_D || output_fmt == FMT_L) {                  if (output_fmt == COP1_FMT_D || output_fmt == COP1_FMT_L) {
1177                          cp->reg[fd] = fs_v & 0xffffffffULL;                          cp->reg[fd] = fs_v & 0xffffffffULL;
1178                          cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;                          cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;
1179                          if (cp->reg[fd] & 0x80000000ULL)                          if (cp->reg[fd] & 0x80000000ULL)
# Line 1685  static int fpu_function(struct cpu *cpu, Line 1264  static int fpu_function(struct cpu *cpu,
1264    
1265          /*  bc1f, bc1t, bc1fl, bc1tl:  */          /*  bc1f, bc1t, bc1fl, bc1tl:  */
1266          if ((function & 0x03e00000) == 0x01000000) {          if ((function & 0x03e00000) == 0x01000000) {
1267                  int nd, tf, imm, cond_true;                  int nd, tf, imm;
1268                  char *instr_mnem;                  char *instr_mnem;
1269    
1270                  /*  cc are bits 20..18:  */                  /*  cc are bits 20..18:  */
# Line 1708  static int fpu_function(struct cpu *cpu, Line 1287  static int fpu_function(struct cpu *cpu,
1287                  if (unassemble_only)                  if (unassemble_only)
1288                          return 1;                          return 1;
1289    
1290                  if (cpu->cd.mips.delay_slot) {                  fatal("INTERNAL ERROR: MIPS coprocessor branches should not"
1291                          fatal("%s: jump inside a jump's delay slot, "                      " be implemented in cpu_mips_coproc.c, but in"
1292                              "or similar. TODO\n", instr_mnem);                      " cpu_mips_instr.c!\n");
1293                          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;  
1294          }          }
1295    
1296          /*  add.fmt: Floating-point add  */          /*  add.fmt: Floating-point add  */
1297          if ((function & 0x0000003f) == 0x00000000) {          if ((function & 0x0000003f) == 0x00000000) {
1298                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1299                          debug("add.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("add.%s\tr%i,r%i,r%i\n",
1300                                fmtname[fmt], fd, fs, ft);
1301                  if (unassemble_only)                  if (unassemble_only)
1302                          return 1;                          return 1;
1303    
# Line 1753  static int fpu_function(struct cpu *cpu, Line 1308  static int fpu_function(struct cpu *cpu,
1308          /*  sub.fmt: Floating-point subtract  */          /*  sub.fmt: Floating-point subtract  */
1309          if ((function & 0x0000003f) == 0x00000001) {          if ((function & 0x0000003f) == 0x00000001) {
1310                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1311                          debug("sub.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("sub.%s\tr%i,r%i,r%i\n",
1312                                fmtname[fmt], fd, fs, ft);
1313                  if (unassemble_only)                  if (unassemble_only)
1314                          return 1;                          return 1;
1315    
# Line 1764  static int fpu_function(struct cpu *cpu, Line 1320  static int fpu_function(struct cpu *cpu,
1320          /*  mul.fmt: Floating-point multiply  */          /*  mul.fmt: Floating-point multiply  */
1321          if ((function & 0x0000003f) == 0x00000002) {          if ((function & 0x0000003f) == 0x00000002) {
1322                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1323                          debug("mul.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("mul.%s\tr%i,r%i,r%i\n",
1324                                fmtname[fmt], fd, fs, ft);
1325                  if (unassemble_only)                  if (unassemble_only)
1326                          return 1;                          return 1;
1327    
# Line 1775  static int fpu_function(struct cpu *cpu, Line 1332  static int fpu_function(struct cpu *cpu,
1332          /*  div.fmt: Floating-point divide  */          /*  div.fmt: Floating-point divide  */
1333          if ((function & 0x0000003f) == 0x00000003) {          if ((function & 0x0000003f) == 0x00000003) {
1334                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1335                          debug("div.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("div.%s\tr%i,r%i,r%i\n",
1336                                fmtname[fmt], fd, fs, ft);
1337                  if (unassemble_only)                  if (unassemble_only)
1338                          return 1;                          return 1;
1339    
# Line 1786  static int fpu_function(struct cpu *cpu, Line 1344  static int fpu_function(struct cpu *cpu,
1344          /*  sqrt.fmt: Floating-point square-root  */          /*  sqrt.fmt: Floating-point square-root  */
1345          if ((function & 0x001f003f) == 0x00000004) {          if ((function & 0x001f003f) == 0x00000004) {
1346                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1347                          debug("sqrt.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("sqrt.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1348                  if (unassemble_only)                  if (unassemble_only)
1349                          return 1;                          return 1;
1350    
# Line 1797  static int fpu_function(struct cpu *cpu, Line 1355  static int fpu_function(struct cpu *cpu,
1355          /*  abs.fmt: Floating-point absolute value  */          /*  abs.fmt: Floating-point absolute value  */
1356          if ((function & 0x001f003f) == 0x00000005) {          if ((function & 0x001f003f) == 0x00000005) {
1357                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1358                          debug("abs.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("abs.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1359                  if (unassemble_only)                  if (unassemble_only)
1360                          return 1;                          return 1;
1361    
# Line 1808  static int fpu_function(struct cpu *cpu, Line 1366  static int fpu_function(struct cpu *cpu,
1366          /*  mov.fmt: Floating-point (non-arithmetic) move  */          /*  mov.fmt: Floating-point (non-arithmetic) move  */
1367          if ((function & 0x0000003f) == 0x00000006) {          if ((function & 0x0000003f) == 0x00000006) {
1368                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1369                          debug("mov.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("mov.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1370                  if (unassemble_only)                  if (unassemble_only)
1371                          return 1;                          return 1;
1372    
# Line 1819  static int fpu_function(struct cpu *cpu, Line 1377  static int fpu_function(struct cpu *cpu,
1377          /*  neg.fmt: Floating-point negate  */          /*  neg.fmt: Floating-point negate  */
1378          if ((function & 0x001f003f) == 0x00000007) {          if ((function & 0x001f003f) == 0x00000007) {
1379                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1380                          debug("neg.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("neg.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1381                  if (unassemble_only)                  if (unassemble_only)
1382                          return 1;                          return 1;
1383    
# Line 1830  static int fpu_function(struct cpu *cpu, Line 1388  static int fpu_function(struct cpu *cpu,
1388          /*  trunc.l.fmt: Truncate  */          /*  trunc.l.fmt: Truncate  */
1389          if ((function & 0x001f003f) == 0x00000009) {          if ((function & 0x001f003f) == 0x00000009) {
1390                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1391                          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);
1392                  if (unassemble_only)                  if (unassemble_only)
1393                          return 1;                          return 1;
1394    
1395                  /*  TODO: not CVT?  */                  /*  TODO: not CVT?  */
1396    
1397                  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);
1398                  return 1;                  return 1;
1399          }          }
1400    
1401          /*  trunc.w.fmt: Truncate  */          /*  trunc.w.fmt: Truncate  */
1402          if ((function & 0x001f003f) == 0x0000000d) {          if ((function & 0x001f003f) == 0x0000000d) {
1403                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1404                          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);
1405                  if (unassemble_only)                  if (unassemble_only)
1406                          return 1;                          return 1;
1407    
1408                  /*  TODO: not CVT?  */                  /*  TODO: not CVT?  */
1409    
1410                  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);
1411                  return 1;                  return 1;
1412          }          }
1413    
# Line 1859  static int fpu_function(struct cpu *cpu, Line 1417  static int fpu_function(struct cpu *cpu,
1417                  int bit;                  int bit;
1418    
1419                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1420                          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],
1421                                fmtname[fmt], cc, fs, ft);
1422                  if (unassemble_only)                  if (unassemble_only)
1423                          return 1;                          return 1;
1424    
# Line 1871  static int fpu_function(struct cpu *cpu, Line 1430  static int fpu_function(struct cpu *cpu,
1430                   *      FCCR:  bits 7..0                   *      FCCR:  bits 7..0
1431                   *      FCSR:  bits 31..25 and 23                   *      FCSR:  bits 31..25 and 23
1432                   */                   */
1433                  cp->fcr[FPU_FCCR] &= ~(1 << cc);                  cp->fcr[MIPS_FPU_FCCR] &= ~(1 << cc);
1434                  if (cond_true)                  if (cond_true)
1435                          cp->fcr[FPU_FCCR] |= (1 << cc);                          cp->fcr[MIPS_FPU_FCCR] |= (1 << cc);
1436    
1437                  if (cc == 0) {                  if (cc == 0) {
1438                          bit = 1 << FCSR_FCC0_SHIFT;                          bit = 1 << MIPS_FCSR_FCC0_SHIFT;
1439                          cp->fcr[FPU_FCSR] &= ~bit;                          cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1440                          if (cond_true)                          if (cond_true)
1441                                  cp->fcr[FPU_FCSR] |= bit;                                  cp->fcr[MIPS_FPU_FCSR] |= bit;
1442                  } else {                  } else {
1443                          bit = 1 << (FCSR_FCC1_SHIFT + cc-1);                          bit = 1 << (MIPS_FCSR_FCC1_SHIFT + cc-1);
1444                          cp->fcr[FPU_FCSR] &= ~bit;                          cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1445                          if (cond_true)                          if (cond_true)
1446                                  cp->fcr[FPU_FCSR] |= bit;                                  cp->fcr[MIPS_FPU_FCSR] |= bit;
1447                  }                  }
1448    
1449                  return 1;                  return 1;
# Line 1893  static int fpu_function(struct cpu *cpu, Line 1452  static int fpu_function(struct cpu *cpu,
1452          /*  cvt.s.fmt: Convert to single floating-point  */          /*  cvt.s.fmt: Convert to single floating-point  */
1453          if ((function & 0x001f003f) == 0x00000020) {          if ((function & 0x001f003f) == 0x00000020) {
1454                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1455                          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);
1456                  if (unassemble_only)                  if (unassemble_only)
1457                          return 1;                          return 1;
1458    
1459                  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);
1460                  return 1;                  return 1;
1461          }          }
1462    
1463          /*  cvt.d.fmt: Convert to double floating-point  */          /*  cvt.d.fmt: Convert to double floating-point  */
1464          if ((function & 0x001f003f) == 0x00000021) {          if ((function & 0x001f003f) == 0x00000021) {
1465                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1466                          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);
1467                  if (unassemble_only)                  if (unassemble_only)
1468                          return 1;                          return 1;
1469    
1470                  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);
1471                  return 1;                  return 1;
1472          }          }
1473    
1474          /*  cvt.w.fmt: Convert to word fixed-point  */          /*  cvt.w.fmt: Convert to word fixed-point  */
1475          if ((function & 0x001f003f) == 0x00000024) {          if ((function & 0x001f003f) == 0x00000024) {
1476                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1477                          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);
1478                  if (unassemble_only)                  if (unassemble_only)
1479                          return 1;                          return 1;
1480    
1481                  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);
1482                  return 1;                  return 1;
1483          }          }
1484    
# Line 1945  void coproc_tlbpr(struct cpu *cpu, int r Line 1504  void coproc_tlbpr(struct cpu *cpu, int r
1504                              R2K3K_INDEX_SHIFT;                              R2K3K_INDEX_SHIFT;
1505                          if (i >= cp->nr_of_tlbs) {                          if (i >= cp->nr_of_tlbs) {
1506                                  /*  TODO:  exception?  */                                  /*  TODO:  exception?  */
1507                                  fatal("warning: tlbr from index %i (too "                                  fatal("[ warning: tlbr from index %i (too "
1508                                      "high)\n", i);                                      "high) ]\n", i);
1509                                  return;                                  return;
1510                          }                          }
1511    
1512                          /*                          cp->reg[COP0_ENTRYHI]  = cp->tlbs[i].hi;
1513                           *  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; */  
1514                  } else {                  } else {
1515                          /*  R4000:  */                          /*  R4000:  */
1516                          i = cp->reg[COP0_INDEX] & INDEX_MASK;                          i = cp->reg[COP0_INDEX] & INDEX_MASK;
# Line 2049  void coproc_tlbpr(struct cpu *cpu, int r Line 1602  void coproc_tlbpr(struct cpu *cpu, int r
1602  /*  /*
1603   *  coproc_tlbwri():   *  coproc_tlbwri():
1604   *   *
1605   *  'tlbwr' and 'tlbwi'   *  MIPS TLB write random (tlbwr) and write indexed (tlbwi) instructions.
1606   */   */
1607  void coproc_tlbwri(struct cpu *cpu, int randomflag)  void coproc_tlbwri(struct cpu *cpu, int randomflag)
1608  {  {
1609          struct mips_coproc *cp = cpu->cd.mips.coproc[0];          struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1610          int index, g_bit;          int index, g_bit;
1611          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;  
1612    
1613          if (randomflag) {          if (randomflag) {
1614                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
1615                          index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)                          index = ((cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
1616                              >> R2K3K_RANDOM_SHIFT;                              >> R2K3K_RANDOM_SHIFT) - 1;
1617                  else                          /*  R3000 always has 8 wired entries:  */
1618                            if (index < 8)
1619                                    index = cp->nr_of_tlbs - 1;
1620                            cp->reg[COP0_RANDOM] = index << R2K3K_RANDOM_SHIFT;
1621                    } else {
1622                            cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
1623                                % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
1624                          index = cp->reg[COP0_RANDOM] & RANDOM_MASK;                          index = cp->reg[COP0_RANDOM] & RANDOM_MASK;
1625                    }
1626          } else {          } else {
1627                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1628                          index = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK)                          index = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK)
# Line 2102  void coproc_tlbwri(struct cpu *cpu, int Line 1638  void coproc_tlbwri(struct cpu *cpu, int
1638                  return;                  return;
1639          }          }
1640    
1641    
1642  #if 0  #if 0
1643          /*  Debug dump of the previous entry at that index:  */          /*  Debug dump of the previous entry at that index:  */
1644          debug(" old entry at index = %04x", index);          fatal("{ old TLB entry at index %02x:", index);
1645          debug(" mask = %016llx", (long long) cp->tlbs[index].mask);          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1646          debug(" hi = %016llx", (long long) cp->tlbs[index].hi);                  fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1647          debug(" lo0 = %016llx", (long long) cp->tlbs[index].lo0);                  fatal(" lo=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1648          debug(" lo1 = %016llx\n", (long long) cp->tlbs[index].lo1);          } else {
1649                    if (cpu->is_32bit) {
1650                            fatal(" mask=%08"PRIx32,(uint32_t)cp->tlbs[index].mask);
1651                            fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1652                            fatal(" lo0=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1653                            fatal(" lo1=%08"PRIx32, (uint32_t)cp->tlbs[index].lo1);
1654                    } else {
1655                            fatal(" mask=%016"PRIx64, cp->tlbs[index].mask);
1656                            fatal(" hi=%016"PRIx64, cp->tlbs[index].hi);
1657                            fatal(" lo0=%016"PRIx64, cp->tlbs[index].lo0);
1658                            fatal(" lo1=%016"PRIx64, cp->tlbs[index].lo1);
1659                    }
1660            }
1661            fatal(" }\n");
1662  #endif  #endif
1663    
1664          /*  Translation caches must be invalidated:  */          /*
1665             *  Any virtual address translation for the old TLB entry must be
1666             *  invalidated first:
1667             *
1668             *  (Only Valid entries need to be invalidated, and only those that
1669             *  are either Global, or have the same ASID as the new entry will
1670             *  have. No other address translations should be active anyway.)
1671             */
1672    
1673          switch (cpu->cd.mips.cpu_type.mmu_model) {          switch (cpu->cd.mips.cpu_type.mmu_model) {
1674    
1675          case MMU3K:          case MMU3K:
1676                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;
1677                  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;  
1678    
1679  /*  TODO: Bug? Why does this if need to be commented out?  */                  if (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_V &&
1680                        (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_G ||
1681                        (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK) ==
1682                        (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK) ))
1683                            cpu->invalidate_translation_caches(cpu, oldvaddr,
1684                                INVALIDATE_VADDR);
1685    
                 /*  if (cp->tlbs[index].lo0 & ENTRYLO_V)  */  
                         invalidate_translation_caches(cpu, 0, oldvaddr, 0, 0);  
1686                  break;                  break;
1687          default:  
1688                  if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {          default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1689                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;                          oldvaddr = cp->tlbs[index].hi &
1690                                (ENTRYHI_VPN2_MASK_R10K | ENTRYHI_R_MASK);
1691                          /*  44 addressable bits:  */                          /*  44 addressable bits:  */
1692                          if (oldvaddr & 0x80000000000ULL)                          if (oldvaddr & 0x80000000000ULL)
1693                                  oldvaddr |= 0xfffff00000000000ULL;                                  oldvaddr |= 0x3ffff00000000000ULL;
1694                    } else if (cpu->is_32bit) {
1695                            /*  MIPS32 etc.:  */
1696                            oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1697                            oldvaddr = (int32_t)oldvaddr;
1698                  } else {                  } else {
1699                          /*  Assume MMU4K  */                          /*  Assume MMU4K  */
1700                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;                          oldvaddr = cp->tlbs[index].hi &
1701                                (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK);
1702                          /*  40 addressable bits:  */                          /*  40 addressable bits:  */
1703                          if (oldvaddr & 0x8000000000ULL)                          if (oldvaddr & 0x8000000000ULL)
1704                                  oldvaddr |= 0xffffff0000000000ULL;                                  oldvaddr |= 0x3fffff0000000000ULL;
1705                  }                  }
1706    
1707                  /*                  /*
                  *  Both pages:  
                  *  
1708                   *  TODO: non-4KB page sizes!                   *  TODO: non-4KB page sizes!
1709                   */                   */
1710                  invalidate_translation_caches(                  if (cp->tlbs[index].lo0 & ENTRYLO_V)
1711                      cpu, 0, oldvaddr & ~0x1fff, 0, 0);                          cpu->invalidate_translation_caches(cpu, oldvaddr,
1712                  invalidate_translation_caches(                              INVALIDATE_VADDR);
1713                      cpu, 0, (oldvaddr & ~0x1fff) | 0x1000, 0, 0);                  if (cp->tlbs[index].lo1 & ENTRYLO_V)
1714                            cpu->invalidate_translation_caches(cpu, oldvaddr|0x1000,
1715                                INVALIDATE_VADDR);
1716          }          }
1717    
1718    #if 0
1719          /*          /*
1720           *  Check for duplicate entries.  (There should not be two mappings           *  Check for duplicate entries.  (There should not be two mappings
1721           *  from one virtual address to physical addresses.)           *  from one virtual address to physical addresses.)
# Line 2163  void coproc_tlbwri(struct cpu *cpu, int Line 1727  void coproc_tlbwri(struct cpu *cpu, int
1727          if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&          if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&
1728              cpu->cd.mips.cpu_type.rev != MIPS_R4100) {              cpu->cd.mips.cpu_type.rev != MIPS_R4100) {
1729                  uint64_t vaddr1, vaddr2;                  uint64_t vaddr1, vaddr2;
1730                  int i, asid;                  int i;
1731                    unsigned int asid;
1732    
1733                  vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K;                  vaddr1 = cp->reg[COP0_ENTRYHI] &
1734                        (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1735                  asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;                  asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
1736                  /*  Since this is just a warning, it's probably not necessary                  /*  Since this is just a warning, it's probably not necessary
1737                      to use R4000 masks etc.  */                      to use R4000 masks etc.  */
# Line 2178  void coproc_tlbwri(struct cpu *cpu, int Line 1744  void coproc_tlbwri(struct cpu *cpu, int
1744                              (cp->tlbs[i].hi & ENTRYHI_ASID) != asid)                              (cp->tlbs[i].hi & ENTRYHI_ASID) != asid)
1745                                  continue;                                  continue;
1746    
1747                          vaddr2 = cp->tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;                          vaddr2 = cp->tlbs[i].hi &
1748                                (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1749                          if (vaddr1 == vaddr2 && ((cp->tlbs[i].lo0 &                          if (vaddr1 == vaddr2 && ((cp->tlbs[i].lo0 &
1750                              ENTRYLO_V) || (cp->tlbs[i].lo1 & ENTRYLO_V)))                              ENTRYLO_V) || (cp->tlbs[i].lo1 & ENTRYLO_V)))
1751                                  fatal("\n[ WARNING! tlbw%s to index 0x%02x "                                  fatal("\n[ WARNING! tlbw%s to index 0x%02x "
# Line 2188  void coproc_tlbwri(struct cpu *cpu, int Line 1755  void coproc_tlbwri(struct cpu *cpu, int
1755                                      (long long)vaddr1, asid, i);                                      (long long)vaddr1, asid, i);
1756                  }                  }
1757          }          }
1758    #endif
1759    
1760          /*  Write the new entry:  */          /*  Write the new entry:  */
1761    
1762          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1763                  uint64_t vaddr, paddr;                  uint32_t vaddr, paddr;
1764                  int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;                  int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;
1765                  unsigned char *memblock = NULL;                  unsigned char *memblock = NULL;
1766    
# Line 2203  void coproc_tlbwri(struct cpu *cpu, int Line 1770  void coproc_tlbwri(struct cpu *cpu, int
1770                  vaddr =  cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;                  vaddr =  cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
1771                  paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;                  paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;
1772    
1773                  /*  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));  
1774    
1775                          /*                  /*  Invalidate any code translation, if we are writing
1776                           *  TODO: Hahaha, this is even uglier than the thing                      a Dirty page to the TLB:  */
1777                           *  above. Some OSes seem to map code pages read/write,                  if (wf) {
1778                           *  which causes the bintrans cache to be invalidated                          cpu->invalidate_code_translation(cpu, paddr,
1779                           *  even when it doesn't have to be.                              INVALIDATE_PADDR);
1780                           */                  }
1781  /*                      if (vaddr < 0x10000000)  */  
1782                                  wf = 0;                  /*  Set new last_written_tlb_index hint:  */
1783                    cpu->cd.mips.last_written_tlb_index = index;
1784    
1785                    if (cp->reg[COP0_STATUS] & MIPS1_ISOL_CACHES) {
1786                            fatal("Wow! Interesting case; tlbw* while caches"
1787                                " are isolated. TODO\n");
1788                            /*  Don't update the translation table in this
1789                                case...  */
1790                            exit(1);
1791                    }
1792    
1793                    /*  If we have a memblock (host page) for the physical
1794                        page, then add a translation for it immediately:  */
1795                    if (memblock != NULL &&
1796                        cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V)
1797                          cpu->update_translation_table(cpu, vaddr, memblock,                          cpu->update_translation_table(cpu, vaddr, memblock,
1798                              wf, paddr);                              wf, paddr);
                 }  
1799          } else {          } else {
1800                  /*  R4000:  */                  /*  R4000 etc.:  */
1801                  g_bit = (cp->reg[COP0_ENTRYLO0] &                  unsigned char *memblock = NULL;
1802                      cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;                  int pfn_shift = 12, vpn_shift = 12;
1803                    int wf0, wf1, mask;
1804                    uint64_t vaddr0, vaddr1, paddr0, paddr1, ptmp;
1805                    uint64_t psize;
1806    
1807                  cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];                  cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];
1808                  cp->tlbs[index].hi   = cp->reg[COP0_ENTRYHI];                  cp->tlbs[index].hi   = cp->reg[COP0_ENTRYHI];
1809                  cp->tlbs[index].lo1  = cp->reg[COP0_ENTRYLO1];                  cp->tlbs[index].lo1  = cp->reg[COP0_ENTRYLO1];
1810                  cp->tlbs[index].lo0  = cp->reg[COP0_ENTRYLO0];                  cp->tlbs[index].lo0  = cp->reg[COP0_ENTRYLO0];
1811    
1812                    wf0 = cp->tlbs[index].lo0 & ENTRYLO_D;
1813                    wf1 = cp->tlbs[index].lo1 & ENTRYLO_D;
1814    
1815                    mask = cp->reg[COP0_PAGEMASK];
1816                    if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1817                            pfn_shift = 10;
1818                            mask |= 0x07ff;
1819                    } else {
1820                            mask |= 0x1fff;
1821                    }
1822                    switch (mask) {
1823                    case 0x00007ff:
1824                            if (cp->tlbs[index].lo0 & ENTRYLO_V ||
1825                                cp->tlbs[index].lo1 & ENTRYLO_V) {
1826                                    fatal("1KB pages don't work with dyntrans.\n");
1827                                    exit(1);
1828                            }
1829                            vpn_shift = 10;
1830                            break;
1831                    case 0x0001fff: break;
1832                    case 0x0007fff: vpn_shift = 14; break;
1833                    case 0x001ffff: vpn_shift = 16; break;
1834                    case 0x007ffff: vpn_shift = 18; break;
1835                    case 0x01fffff: vpn_shift = 20; break;
1836                    case 0x07fffff: vpn_shift = 22; break;
1837                    case 0x1ffffff: vpn_shift = 24; break;
1838                    case 0x7ffffff: vpn_shift = 26; break;
1839                    default:fatal("Unimplemented MASK = 0x%016x\n", mask);
1840                            exit(1);
1841                    }
1842    
1843                    paddr0 = ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK)
1844                        >> ENTRYLO_PFN_SHIFT) << pfn_shift
1845                        >> vpn_shift << vpn_shift;
1846                    paddr1 = ((cp->tlbs[index].lo1 & ENTRYLO_PFN_MASK)
1847                        >> ENTRYLO_PFN_SHIFT) << pfn_shift
1848                        >> vpn_shift << vpn_shift;
1849    
1850                    if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1851                            vaddr0 = cp->tlbs[index].hi &
1852                                (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1853                            /*  44 addressable bits:  */
1854                            if (vaddr0 & 0x80000000000ULL)
1855                                    vaddr0 |= 0x3ffff00000000000ULL;
1856                    } else if (cpu->is_32bit) {
1857                            /*  MIPS32 etc.:  */
1858                            vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1859                            vaddr0 = (int32_t)vaddr0;
1860                    } else {
1861                            /*  Assume MMU4K  */
1862                            vaddr0 = cp->tlbs[index].hi &
1863                                (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK);
1864                            /*  40 addressable bits:  */
1865                            if (vaddr0 & 0x8000000000ULL)
1866                                    vaddr0 |= 0x3fffff0000000000ULL;
1867                    }
1868    
1869                    vaddr1 = vaddr0 | (1 << vpn_shift);
1870    
1871                    g_bit = (cp->reg[COP0_ENTRYLO0] &
1872                        cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;
1873    
1874                  if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {                  if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1875                          /*  NOTE: The VR4131 (and possibly others) don't have                          /*  NOTE: The VR4131 (and possibly others) don't have
1876                              a Global bit in entryhi  */                              a Global bit in entryhi  */
# Line 2245  void coproc_tlbwri(struct cpu *cpu, int Line 1883  void coproc_tlbwri(struct cpu *cpu, int
1883                          if (g_bit)                          if (g_bit)
1884                                  cp->tlbs[index].hi |= TLB_G;                                  cp->tlbs[index].hi |= TLB_G;
1885                  }                  }
         }  
1886    
1887          if (randomflag) {                  /*
1888                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {                   *  Invalidate any code translations, if we are writing Dirty
1889                          cp->reg[COP0_RANDOM] =                   *  pages to the TLB:  (TODO: 4KB hardcoded... ugly)
1890                              ((random() % (cp->nr_of_tlbs - 8)) + 8)                   */
1891                              << R2K3K_RANDOM_SHIFT;                  psize = 1 << pfn_shift;
1892                  } else {                  for (ptmp = 0; ptmp < psize; ptmp += 0x1000) {
1893                          cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()                          if (wf0)
1894                              % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));                                  cpu->invalidate_code_translation(cpu,
1895                                        paddr0 + ptmp, INVALIDATE_PADDR);
1896                            if (wf1)
1897                                    cpu->invalidate_code_translation(cpu,
1898                                        paddr1 + ptmp, INVALIDATE_PADDR);
1899                  }                  }
         }  
 }  
1900    
1901                    /*
1902                     *  If we have a memblock (host page) for the physical page,
1903                     *  then add a translation for it immediately, to save some
1904                     *  time. (It would otherwise be added later on anyway,
1905                     *  because of a translation miss.)
1906                     *
1907                     *  NOTE/TODO: This is only for 4KB pages so far. It would
1908                     *             be too expensive to add e.g. 16MB pages like
1909                     *             this.
1910                     */
1911                    memblock = memory_paddr_to_hostaddr(cpu->mem, paddr0, 0);
1912                    if (memblock != NULL && cp->reg[COP0_ENTRYLO0] & ENTRYLO_V)
1913                            cpu->update_translation_table(cpu, vaddr0, memblock,
1914                                wf0, paddr0);
1915                    memblock = memory_paddr_to_hostaddr(cpu->mem, paddr1, 0);
1916                    if (memblock != NULL && cp->reg[COP0_ENTRYLO1] & ENTRYLO_V)
1917                            cpu->update_translation_table(cpu, vaddr1, memblock,
1918                                wf1, paddr1);
1919    
1920  /*                  /*  Set new last_written_tlb_index hint:  */
1921   *  coproc_rfe():                  cpu->cd.mips.last_written_tlb_index = index;
1922   *          }
  *  Return from exception. (R3000 etc.)  
  */  
 void coproc_rfe(struct cpu *cpu)  
 {  
         int oldmode;  
   
         oldmode = cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_SR_KU_CUR;  
   
         cpu->cd.mips.coproc[0]->reg[COP0_STATUS] =  
             (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) |  
             ((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);  
1923  }  }
1924    
1925    
# Line 2290  void coproc_rfe(struct cpu *cpu) Line 1930  void coproc_rfe(struct cpu *cpu)
1930   */   */
1931  void coproc_eret(struct cpu *cpu)  void coproc_eret(struct cpu *cpu)
1932  {  {
         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;  
   
1933          if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {          if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {
1934                  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];  
1935                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;
1936          } else {          } else {
1937                  cpu->pc = cpu->cd.mips.pc_last =                  cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_EPC];
1938                      cpu->cd.mips.coproc[0]->reg[COP0_EPC];                  cpu->delay_slot = 0;
                 cpu->cd.mips.delay_slot = 0;  
1939                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;
1940          }          }
1941    
1942          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  
1943  }  }
1944    
1945    
# Line 2358  void coproc_function(struct cpu *cpu, st Line 1969  void coproc_function(struct cpu *cpu, st
1969                  return;                  return;
1970          }          }
1971    
 #if 0  
1972          /*  No FPU?  */          /*  No FPU?  */
1973          if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {          if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {
1974                  mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);                  mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);
1975                  return;                  return;
1976          }          }
 #endif  
1977    
1978          /*  For quick reference:  */          /*  For quick reference:  */
1979          copz = (function >> 21) & 31;          copz = (function >> 21) & 31;
# Line 2379  void coproc_function(struct cpu *cpu, st Line 1988  void coproc_function(struct cpu *cpu, st
1988                          if (cpnr == 0)                          if (cpnr == 0)
1989                                  debug("%s", cop0_names[rd]);                                  debug("%s", cop0_names[rd]);
1990                          else                          else
1991                                  debug("cpreg%i", rd);                                  debug("r%i", rd);
1992                          if (function & 7)                          if (function & 7)
1993                                  debug(",%i", (int)(function & 7));                                  debug(",%i", (int)(function & 7));
1994                          debug("\n");                          debug("\n");
# Line 2405  void coproc_function(struct cpu *cpu, st Line 2014  void coproc_function(struct cpu *cpu, st
2014                          if (cpnr == 0)                          if (cpnr == 0)
2015                                  debug("%s", cop0_names[rd]);                                  debug("%s", cop0_names[rd]);
2016                          else                          else
2017                                  debug("cpreg%i", rd);                                  debug("r%i", rd);
2018                          if (function & 7)                          if (function & 7)
2019                                  debug(",%i", (int)(function & 7));                                  debug(",%i", (int)(function & 7));
2020                          debug("\n");                          debug("\n");
# Line 2434  void coproc_function(struct cpu *cpu, st Line 2043  void coproc_function(struct cpu *cpu, st
2043                                      regnames[rt], fs);                                      regnames[rt], fs);
2044                                  return;                                  return;
2045                          }                          }
2046                          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;  
2047                          /*  TODO: implement delay for gpr[rt]                          /*  TODO: implement delay for gpr[rt]
2048                              (for MIPS I,II,III only)  */                              (for MIPS I,II,III only)  */
2049                          return;                          return;
# Line 2468  void coproc_function(struct cpu *cpu, st Line 2075  void coproc_function(struct cpu *cpu, st
2075                                              on status bits!  */                                              on status bits!  */
2076    
2077                                          switch (fs) {                                          switch (fs) {
2078                                          case FPU_FCCR:                                          case MIPS_FPU_FCCR:
2079                                                  cp->fcr[FPU_FCSR] =                                                  cp->fcr[MIPS_FPU_FCSR] =
2080                                                      (cp->fcr[FPU_FCSR] &                                                      (cp->fcr[MIPS_FPU_FCSR] &
2081                                                      0x017fffffULL) | ((tmp & 1)                                                      0x017fffffULL) | ((tmp & 1)
2082                                                      << FCSR_FCC0_SHIFT)                                                      << MIPS_FCSR_FCC0_SHIFT)
2083                                                      | (((tmp & 0xfe) >> 1) <<                                                      | (((tmp & 0xfe) >> 1) <<
2084                                                      FCSR_FCC1_SHIFT);                                                      MIPS_FCSR_FCC1_SHIFT);
2085                                                  break;                                                  break;
2086                                          case FPU_FCSR:                                          case MIPS_FPU_FCSR:
2087                                                  cp->fcr[FPU_FCCR] =                                                  cp->fcr[MIPS_FPU_FCCR] =
2088                                                      (cp->fcr[FPU_FCCR] &                                                      (cp->fcr[MIPS_FPU_FCCR] &
2089                                                      0xffffff00ULL) | ((tmp >>                                                      0xffffff00ULL) | ((tmp >>
2090                                                      FCSR_FCC0_SHIFT) & 1) |                                                      MIPS_FCSR_FCC0_SHIFT) & 1) |
2091                                                      (((tmp >> FCSR_FCC1_SHIFT)                                                      (((tmp >>
2092                                                        MIPS_FCSR_FCC1_SHIFT)
2093                                                      & 0x7f) << 1);                                                      & 0x7f) << 1);
2094                                                  break;                                                  break;
2095                                          default:                                          default:
# Line 2505  void coproc_function(struct cpu *cpu, st Line 2113  void coproc_function(struct cpu *cpu, st
2113                          return;                          return;
2114          }          }
2115    
         /*  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;  
         }  
   
2116    
2117          /*  Ugly R5900 hacks:  */          /*  Ugly R5900 hacks:  */
2118          if ((function & 0xfffff) == 0x38) {             /*  ei  */          if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) {
2119                  if (unassemble_only) {                  if ((function & 0xfffff) == COP0_EI) {
2120                          debug("ei\n");                          if (unassemble_only) {
2121                                    debug("ei\n");
2122                                    return;
2123                            }
2124                            cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |=
2125                                R5900_STATUS_EIE;
2126                          return;                          return;
2127                  }                  }
                 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= R5900_STATUS_EIE;  
                 return;  
         }  
2128    
2129          if ((function & 0xfffff) == 0x39) {             /*  di  */                  if ((function & 0xfffff) == COP0_DI) {
2130                  if (unassemble_only) {                          if (unassemble_only) {
2131                          debug("di\n");                                  debug("di\n");
2132                                    return;
2133                            }
2134                            cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &=
2135                                ~R5900_STATUS_EIE;
2136                          return;                          return;
2137                  }                  }
                 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~R5900_STATUS_EIE;  
                 return;  
2138          }          }
2139    
2140          co_bit = (function >> 25) & 1;          co_bit = (function >> 25) & 1;
2141    
2142          /*  TLB operations and other things:  */          /*  TLB operations and other things:  */
2143          if (cp->coproc_nr == 0) {          if (cp->coproc_nr == 0) {
2144                    if (!unassemble_only) {
2145                            fatal("FATAL INTERNAL ERROR: Should be implemented"
2146                                " with dyntrans instead.\n");
2147                            exit(1);
2148                    }
2149    
2150                  op = (function) & 0xff;                  op = (function) & 0xff;
2151                  switch (co_bit) {                  switch (co_bit) {
2152                  case 1:                  case 1:
2153                          switch (op) {                          switch (op) {
2154                          case COP0_TLBR:         /*  Read indexed TLB entry  */                          case COP0_TLBR:         /*  Read indexed TLB entry  */
2155                                  if (unassemble_only) {                                  debug("tlbr\n");
                                         debug("tlbr\n");  
                                         return;  
                                 }  
                                 coproc_tlbpr(cpu, 1);  
2156                                  return;                                  return;
2157                          case COP0_TLBWI:        /*  Write indexed  */                          case COP0_TLBWI:        /*  Write indexed  */
2158                          case COP0_TLBWR:        /*  Write random  */                          case COP0_TLBWR:        /*  Write random  */
2159                                  if (unassemble_only) {                                  if (op == COP0_TLBWI)
2160                                          if (op == COP0_TLBWI)                                          debug("tlbwi");
2161                                                  debug("tlbwi");                                  else
2162                                          else                                          debug("tlbwr");
2163                                                  debug("tlbwr");                                  if (!running) {
2164                                          if (!running) {                                          debug("\n");
2165                                                  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]);  
2166                                  }                                  }
2167                                  coproc_tlbwri(cpu, op == COP0_TLBWR);                                  debug("\tindex=%08llx",
2168                                        (long long)cp->reg[COP0_INDEX]);
2169                                    debug(", random=%08llx",
2170                                        (long long)cp->reg[COP0_RANDOM]);
2171                                    debug(", mask=%016llx",
2172                                        (long long)cp->reg[COP0_PAGEMASK]);
2173                                    debug(", hi=%016llx",
2174                                        (long long)cp->reg[COP0_ENTRYHI]);
2175                                    debug(", lo0=%016llx",
2176                                        (long long)cp->reg[COP0_ENTRYLO0]);
2177                                    debug(", lo1=%016llx\n",
2178                                        (long long)cp->reg[COP0_ENTRYLO1]);
2179                                  return;                                  return;
2180                          case COP0_TLBP:         /*  Probe TLB for                          case COP0_TLBP:         /*  Probe TLB for
2181                                                      matching entry  */                                                      matching entry  */
2182                                  if (unassemble_only) {                                  debug("tlbp\n");
                                         debug("tlbp\n");  
                                         return;  
                                 }  
                                 coproc_tlbpr(cpu, 0);  
2183                                  return;                                  return;
2184                          case COP0_RFE:          /*  R2000/R3000 only:                          case COP0_RFE:          /*  R2000/R3000 only:
2185                                                      Return from Exception  */                                                      Return from Exception  */
2186                                  if (unassemble_only) {                                  debug("rfe\n");
                                         debug("rfe\n");  
                                         return;  
                                 }  
                                 coproc_rfe(cpu);  
2187                                  return;                                  return;
2188                          case COP0_ERET: /*  R4000: Return from exception  */                          case COP0_ERET: /*  R4000: Return from exception  */
2189                                  if (unassemble_only) {                                  debug("eret\n");
2190                                          debug("eret\n");                                  return;
2191                                          return;                          case COP0_DERET:
2192                                    debug("deret\n");
2193                                    return;
2194                            case COP0_WAIT:
2195                                    {
2196                                            int code = (function >> 6) & 0x7ffff;
2197                                            debug("wait");
2198                                            if (code > 0)
2199                                                    debug("\t0x%x", code);
2200                                            debug("\n");
2201                                  }                                  }
                                 coproc_eret(cpu);  
2202                                  return;                                  return;
2203                          case COP0_STANDBY:                          case COP0_STANDBY:
2204                                  if (unassemble_only) {                                  debug("standby\n");
                                         debug("standby\n");  
                                         return;  
                                 }  
                                 /*  TODO: Hm. Do something here?  */  
2205                                  return;                                  return;
2206                          case COP0_SUSPEND:                          case COP0_SUSPEND:
2207                                  if (unassemble_only) {                                  debug("suspend\n");
                                         debug("suspend\n");  
                                         return;  
                                 }  
                                 /*  TODO: Hm. Do something here?  */  
2208                                  return;                                  return;
2209                          case COP0_HIBERNATE:                          case COP0_HIBERNATE:
2210                                  if (unassemble_only) {                                  debug("hibernate\n");
                                         debug("hibernate\n");  
                                         return;  
                                 }  
                                 /*  TODO: Hm. Do something here?  */  
2211                                  return;                                  return;
2212                          default:                          default:
2213                                  ;                                  ;
# Line 2652  void coproc_function(struct cpu *cpu, st Line 2227  void coproc_function(struct cpu *cpu, st
2227                  return;                  return;
2228          }          }
2229    
         /*  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;  
         }  
   
2230          if (unassemble_only) {          if (unassemble_only) {
2231                  debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function);                  debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function);
2232                  return;                  return;
2233          }          }
2234    
2235          fatal("cpu%i: UNIMPLEMENTED coproc%i function %08lx "          fatal("cpu%i: UNIMPLEMENTED coproc%i function %08"PRIx32" "
2236              "(pc = %016llx)\n", cpu->cpu_id, cp->coproc_nr, function,              "(pc = %016"PRIx64")\n", cpu->cpu_id, cp->coproc_nr,
2237              (long long)cpu->cd.mips.pc_last);              (uint32_t)function, cpu->pc);
2238  #if 1  
         single_step = 1;  
 #else  
2239          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  
2240  }  }
2241    
2242  #endif  /*  ENABLE_MIPS  */  #endif  /*  ENABLE_MIPS  */

Legend:
Removed from v.20  
changed lines
  Added in v.40

  ViewVC Help
Powered by ViewVC 1.1.26