/[gxemul]/trunk/src/cpus/cpu_mips_coproc.c
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Diff of /trunk/src/cpus/cpu_mips_coproc.c

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

revision 14 by dpavlin, Mon Oct 8 16:18:51 2007 UTC revision 30 by dpavlin, Mon Oct 8 16:20:40 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2006  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: cpu_mips_coproc.c,v 1.2 2005/09/11 10:37:37 debug Exp $   *  $Id: cpu_mips_coproc.c,v 1.53 2006/08/11 17:43:30 debug Exp $
29   *   *
30   *  Emulation of MIPS coprocessors.   *  Emulation of MIPS coprocessors.
31   */   */
# Line 35  Line 35 
35  #include <string.h>  #include <string.h>
36  #include <math.h>  #include <math.h>
37    
 #include "bintrans.h"  
38  #include "cop0.h"  #include "cop0.h"
39  #include "cpu.h"  #include "cpu.h"
40  #include "cpu_mips.h"  #include "cpu_mips.h"
41  #include "emul.h"  #include "emul.h"
42    #include "float_emul.h"
43  #include "machine.h"  #include "machine.h"
44  #include "memory.h"  #include "memory.h"
45  #include "mips_cpu_types.h"  #include "mips_cpu_types.h"
# Line 68  static char *cop0_names[] = COP0_NAMES; Line 68  static char *cop0_names[] = COP0_NAMES;
68  static char *regnames[] = MIPS_REGISTER_NAMES;  static char *regnames[] = MIPS_REGISTER_NAMES;
69    
70    
 /*  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  
   
   
71  /*  /*
72   *  initialize_cop0_config():   *  initialize_cop0_config():
73   *   *
# Line 83  static char *regnames[] = MIPS_REGISTER_ Line 75  static char *regnames[] = MIPS_REGISTER_
75   */   */
76  static void initialize_cop0_config(struct cpu *cpu, struct mips_coproc *c)  static void initialize_cop0_config(struct cpu *cpu, struct mips_coproc *c)
77  {  {
78  #ifdef ENABLE_MIPS16          const int m16 = 0;      /*  TODO: MIPS16 support  */
79          const int m16 = 1;          int IB, DB, SB, IC, DC, SC, IA, DA;
 #else  
         const int m16 = 0;  
 #endif  
         int cpu_type, IB, DB, SB, IC, DC, SC, IA, DA;  
80    
81          /*  Default values:  */          /*  Generic case for MIPS32/64:  */
82          c->reg[COP0_CONFIG] =          if (cpu->cd.mips.cpu_type.isa_level == 32 ||
83                (   0 << 31)      /*  config1 present  */              cpu->cd.mips.cpu_type.isa_level == 64) {
84              | (0x00 << 16)      /*  implementation dependant  */                  /*  According to the MIPS64 (5K) User's Manual:  */
85              | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)                  c->reg[COP0_CONFIG] =
86                                  /*  endian mode  */                        (   (uint32_t)1 << 31)/*  Config 1 present bit  */
87              | (   2 << 13)      /*  0 = MIPS32,                      | (   0 << 20)      /*  ISD:  instruction scheduling
88                                      1 = MIPS64 with 32-bit segments,                                              disable (=1)  */
89                                      2 = MIPS64 with all segments,                      | (   0 << 17)      /*  DID:  dual issue disable  */
90                                      3 = reserved  */                      | (   0 << 16)      /*  BM:   burst mode  */
91              | (   0 << 10)      /*  architecture revision level,                      | ((cpu->byte_order == EMUL_BIG_ENDIAN? 1 : 0) << 15)
92                                      0 = "Revision 1", other                                          /*  endian mode  */
93                                      values are reserved  */                      | ((cpu->cd.mips.cpu_type.isa_level == 64? 2 : 0) << 13)
94              | (   1 <<  7)      /*  MMU type:  0 = none,                                          /*  0=MIPS32, 1=64S, 2=64  */
95                                      1 = Standard TLB,                      | (   0 << 10)      /*  Architecture revision  */
96                                      2 = Standard BAT,                      | (   1 <<  7)      /*  MMU type: 1=TLB, 3=FMT  */
97                                      3 = fixed mapping, 4-7=reserved  */                      | (   2 <<  0)      /*  kseg0 cache coherency algorithm  */
98              | (   0 <<  0)      /*  kseg0 coherency algorithm                      ;
99                                  (TODO)  */                  /*  Config select 1: caches etc. TODO: Don't use
100              ;                          cpu->machine for this stuff!  */
101                    IB = cpu->machine->cache_picache_linesize - 1;
102          cpu_type = cpu->cd.mips.cpu_type.rev & 0xff;                  IB = IB < 0? 0 : (IB > 7? 7 : IB);
103                    DB = cpu->machine->cache_pdcache_linesize - 1;
104          /*  AU1x00 are treated as 4Kc (MIPS32 cores):  */                  DB = DB < 0? 0 : (DB > 7? 7 : DB);
105          if ((cpu->cd.mips.cpu_type.rev & 0xffff) == 0x0301)                  IC = cpu->machine->cache_picache -
106                  cpu_type = MIPS_4Kc;                      cpu->machine->cache_picache_linesize - 7;
107                    DC = cpu->machine->cache_pdcache -
108                        cpu->machine->cache_pdcache_linesize - 7;
109                    IA = cpu->cd.mips.cpu_type.piways - 1;
110                    DA = cpu->cd.mips.cpu_type.pdways - 1;
111                    cpu->cd.mips.cop0_config_select1 =
112                        ((cpu->cd.mips.cpu_type.nr_of_tlb_entries - 1) << 25)
113                        | (IC << 22)        /*  IS: I-cache sets per way  */
114                        | (IB << 19)        /*  IL: I-cache line-size  */
115                        | (IA << 16)        /*  IA: I-cache assoc. (ways-1)  */
116                        | (DC << 13)        /*  DS: D-cache sets per way  */
117                        | (DB << 10)        /*  DL: D-cache line-size  */
118                        | (DA <<  7)        /*  DA: D-cache assoc. (ways-1)  */
119                        | (16 * 0)          /*  Existance of PerformanceCounters  */
120                        | ( 8 * 0)          /*  Existance of Watch Registers  */
121                        | ( 4 * m16)        /*  Existance of MIPS16  */
122                        | ( 2 * 0)          /*  Existance of EJTAG  */
123                        | ( 1 * 1)          /*  Existance of FPU  */
124                        ;
125    
126          switch (cpu_type) {                  return;
127            }
128    
129            switch (cpu->cd.mips.cpu_type.rev) {
130            case MIPS_R2000:
131            case MIPS_R3000:
132                    /*  No config register.  */
133                    break;
134          case MIPS_R4000:        /*  according to the R4000 manual  */          case MIPS_R4000:        /*  according to the R4000 manual  */
135          case MIPS_R4600:          case MIPS_R4600:
136                  IB = cpu->machine->cache_picache_linesize - 4;                  IB = cpu->machine->cache_picache_linesize - 4;
# Line 302  static void initialize_cop0_config(struc Line 315  static void initialize_cop0_config(struc
315                                                  (TODO)  */                                                  (TODO)  */
316                      ;                      ;
317                  break;                  break;
318          case MIPS_4Kc:          default:fatal("Internal error: No initialization code for"
319          case MIPS_5Kc:                      " config0? cpu rev = 0x%x", cpu->cd.mips.cpu_type.rev);
320                  /*  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:  
                 ;  
321          }          }
322  }  }
323    
# Line 414  struct mips_coproc *mips_coproc_new(stru Line 384  struct mips_coproc *mips_coproc_new(stru
384    
385          if (coproc_nr == 0) {          if (coproc_nr == 0) {
386                  c->nr_of_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries;                  c->nr_of_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries;
387                  c->tlbs = malloc(c->nr_of_tlbs * sizeof(struct mips_tlb));                  c->tlbs = zeroed_alloc(c->nr_of_tlbs * sizeof(struct mips_tlb));
                 if (c->tlbs == NULL) {  
                         fprintf(stderr, "mips_coproc_new(): out of memory\n");  
                         exit(1);  
                 }  
388    
389                  /*                  /*
390                   *  Start with nothing in the status register. This makes sure                   *  Start with nothing in the status register. This makes sure
# Line 441  struct mips_coproc *mips_coproc_new(stru Line 407  struct mips_coproc *mips_coproc_new(stru
407                  if (!cpu->machine->prom_emulation)                  if (!cpu->machine->prom_emulation)
408                          c->reg[COP0_STATUS] |= STATUS_BEV;                          c->reg[COP0_STATUS] |= STATUS_BEV;
409    
410                  /*  Default pagesize = 4 KB.  */                  /*  Ugly hack for R5900/TX79/C790:  */
411                    if (cpu->cd.mips.cpu_type.rev == MIPS_R5900)
412                            c->reg[COP0_STATUS] |= R5900_STATUS_EIE;
413    
414                    /*  Default pagesize = 4 KB  (i.e. dualpage = 8KB)  */
415                  c->reg[COP0_PAGEMASK] = 0x1fff;                  c->reg[COP0_PAGEMASK] = 0x1fff;
416    
417                  /*  Note: .rev may contain the company ID as well!  */                  /*  Note: .rev may contain the company ID as well!  */
418                  c->reg[COP0_PRID] =                  c->reg[COP0_PRID] =
419                        (0x00 << 24)              /*  Company Options  */                        (0x00 << 24)                      /*  Company Options  */
420                      | (0x00 << 16)              /*  Company ID       */                      | (0x00 << 16)                      /*  Company ID       */
421                      | (cpu->cd.mips.cpu_type.rev <<  8) /*  Processor ID     */                      | (cpu->cd.mips.cpu_type.rev <<  8) /*  Processor ID     */
422                      | (cpu->cd.mips.cpu_type.sub)       /*  Revision         */                      | (cpu->cd.mips.cpu_type.sub)       /*  Revision         */
423                      ;                      ;
# Line 457  struct mips_coproc *mips_coproc_new(stru Line 427  struct mips_coproc *mips_coproc_new(stru
427                  initialize_cop0_config(cpu, c);                  initialize_cop0_config(cpu, c);
428    
429                  /*  Make sure the status register is sign-extended nicely:  */                  /*  Make sure the status register is sign-extended nicely:  */
430                  c->reg[COP0_STATUS] = (int64_t)(int32_t)c->reg[COP0_STATUS];                  c->reg[COP0_STATUS] = (int32_t)c->reg[COP0_STATUS];
431          }          }
432    
433          if (coproc_nr == 1)          if (coproc_nr == 1)
# Line 539  void mips_coproc_tlb_set_entry(struct cp Line 509  void mips_coproc_tlb_set_entry(struct cp
509    
510    
511  /*  /*
512   *  old_update_translation_table():   *  invalidate_asid():
513     *
514     *  Go through all entries in the TLB. If an entry has a matching asid, is
515     *  valid, and is not global (i.e. the ASID matters), then its virtual address
516     *  translation is invalidated.
517     *
518     *  Note: In the R3000 case, the asid argument is shifted 6 bits.
519   */   */
520  static void old_update_translation_table(struct cpu *cpu, uint64_t vaddr_page,  static void invalidate_asid(struct cpu *cpu, int asid)
         unsigned char *host_page, int writeflag, uint64_t paddr_page)  
521  {  {
522          int a, b, index;          struct mips_coproc *cp = cpu->cd.mips.coproc[0];
523          struct vth32_table *tbl1;          int i, ntlbs = cp->nr_of_tlbs;
524          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;  
         }  
525    
526          a = (vaddr_page >> 22) & 0x3ff;          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
527          b = (vaddr_page >> 12) & 0x3ff;                  for (i=0; i<ntlbs; i++)
528          index = (vaddr_page >> 12) & 0xfffff;                          if ((tlb[i].hi & R2K3K_ENTRYHI_ASID_MASK) == asid
529                                && (tlb[i].lo0 & R2K3K_ENTRYLO_V)
530          /*  printf("vaddr = %08x, a = %03x, b = %03x\n",                              && !(tlb[i].lo0 & R2K3K_ENTRYLO_G)) {
531              (int)vaddr_page,a, b);  */                                  cpu->invalidate_translation_caches(cpu,
532                                        tlb[i].hi & R2K3K_ENTRYHI_VPN_MASK,
533          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);  
534                          }                          }
                         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.  */  
535          } else {          } else {
536                  if (host_page != NULL) {                  int non4kpages = 0;
537                          tbl1->haddr_entry[b*2] = host_page;                  uint64_t topbit = 1, fillmask = 0xffffff0000000000ULL;
                         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;  
                         }  
                 }  
                 tbl1->paddr_entry[b] = paddr_page;  
         }  
         tbl1->bintrans_chunks[b] = NULL;  
 }  
   
538    
539  /*                  if (cpu->is_32bit) {
540   *  mips_update_translation_table():                          topbit = 0x80000000;
541   */                          fillmask = 0xffffffff00000000ULL;
542  void mips_update_translation_table(struct cpu *cpu, uint64_t vaddr_page,                  } else if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
543          unsigned char *host_page, int writeflag, uint64_t paddr_page)                          topbit <<= 43;
544  {                          fillmask <<= 4;
545          if (!cpu->machine->bintrans_enable)                  } else {
546                  return;                          topbit <<= 39;
   
         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;  
                 }  
         } else {  
                 if ((vaddr >> 32) != 0) {  
                         fatal("invalidate_table_entry(): vaddr = 0x%016llx\n",  
                             (long long)vaddr);  
                         return;  
                 }  
         }  
   
         a = (vaddr >> 22) & 0x3ff;  
         b = (vaddr >> 12) & 0x3ff;  
         index = (vaddr >> 12) & 0xfffff;  
   
         /*  printf("vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b);  */  
   
         tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];  
         /*  printf("tbl1 = %p\n", tbl1);  */  
         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;  
547                  }                  }
         }  
 }  
   
548    
549  /*                  for (i=0; i<ntlbs; i++) {
550   *  clear_all_chunks_from_all_tables():                          if (tlb[i].mask != 0 && tlb[i].mask != 0x1800) {
551   */                                  non4kpages = 1;
552  void clear_all_chunks_from_all_tables(struct cpu *cpu)                                  continue;
 {  
         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;  
                                 }  
553                          }                          }
                 }  
         }  
 }  
   
   
 /*  
  *  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;  
554    
555          if (cpu->machine->bintrans_enable) {                          if ((tlb[i].hi & ENTRYHI_ASID) == asid &&
556  #if 1                              !(tlb[i].hi & TLB_G)) {
557                  int i;                                  uint64_t vaddr0, vaddr1;
558                  uint64_t tlb_paddr0, tlb_paddr1;                                  vaddr0 = cp->tlbs[i].hi & ~fillmask;
559                  uint64_t tlb_vaddr;                                  if (vaddr0 & topbit)
560                  uint64_t p, p2;                                          vaddr0 |= fillmask;
561                                    vaddr1 = vaddr0 | 0x1000;  /*  TODO: mask  */
562                  switch (cpu->cd.mips.cpu_type.mmu_model) {  
563                  case MMU3K:                                  if (tlb[i].lo0 & ENTRYLO_V)
564                          for (i=0; i<64; i++) {                                          cpu->invalidate_translation_caches(cpu,
565                                  tlb_paddr0 = cpu->cd.mips.coproc[0]->                                              vaddr0, INVALIDATE_VADDR);
566                                      tlbs[i].lo0 & R2K3K_ENTRYLO_PFN_MASK;                                  if (tlb[i].lo1 & ENTRYLO_V)
567                                  tlb_vaddr = cpu->cd.mips.coproc[0]->                                          cpu->invalidate_translation_caches(cpu,
568                                      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;  
   
                                 if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {  
                                         or_pmask = 0x7ff;  
                                         phys_shift = 10;  
                                 }  
                                 switch (cpu->cd.mips.coproc[0]->  
                                     tlbs[i].mask | or_pmask) {  
                                 case 0x000007ff:        psize = 10; break;  
                                 case 0x00001fff:        psize = 12; break;  
                                 case 0x00007fff:        psize = 14; break;  
                                 case 0x0001ffff:        psize = 16; break;  
                                 case 0x0007ffff:        psize = 18; break;  
                                 case 0x001fffff:        psize = 20; break;  
                                 case 0x007fffff:        psize = 22; break;  
                                 case 0x01ffffff:        psize = 24; break;  
                                 case 0x07ffffff:        psize = 26; break;  
                                 default:  
                                         printf("invalidate_translation_caches"  
                                             "_paddr(): bad pagemask?\n");  
                                 }  
                                 tlb_paddr0 = (cpu->cd.mips.coproc[0]->tlbs[i].  
                                     lo0 & ENTRYLO_PFN_MASK)>>ENTRYLO_PFN_SHIFT;  
                                 tlb_paddr1 = (cpu->cd.mips.coproc[0]->tlbs[i].  
                                     lo1 & ENTRYLO_PFN_MASK)>>ENTRYLO_PFN_SHIFT;  
                                 tlb_paddr0 <<= phys_shift;  
                                 tlb_paddr1 <<= phys_shift;  
                                 if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {  
                                         tlb_vaddr = cpu->cd.mips.coproc[0]->  
                                             tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;  
                                         if (tlb_vaddr & ((int64_t)1 << 43))  
                                                 tlb_vaddr |=  
                                                     0xfffff00000000000ULL;  
                                 } else {  
                                         tlb_vaddr = cpu->cd.mips.coproc[0]->  
                                             tlbs[i].hi & ENTRYHI_VPN2_MASK;  
                                         if (tlb_vaddr & ((int64_t)1 << 39))  
                                                 tlb_vaddr |=  
                                                     0xffffff0000000000ULL;  
                                 }  
                                 if ((cpu->cd.mips.coproc[0]->tlbs[i].lo0 &  
                                     ENTRYLO_V) && paddr >= tlb_paddr0 &&  
                                     paddr < tlb_paddr0 + (1<<psize)) {  
                                         p2 = 1 << psize;  
                                         for (p=0; p<p2; p+=4096)  
                                                 invalidate_table_entry(cpu,  
                                                     tlb_vaddr + p);  
                                 }  
                                 if ((cpu->cd.mips.coproc[0]->tlbs[i].lo1 &  
                                     ENTRYLO_V) && paddr >= tlb_paddr1 &&  
                                     paddr < tlb_paddr1 + (1<<psize)) {  
                                         p2 = 1 << psize;  
                                         for (p=0; p<p2; p+=4096)  
                                                 invalidate_table_entry(cpu,  
                                                     tlb_vaddr + p +  
                                                     (1 << psize));  
                                 }  
569                          }                          }
570                  }                  }
 #endif  
571    
572                  if (paddr < 0x20000000) {                  if (non4kpages) {
573                          invalidate_table_entry(cpu, 0xffffffff80000000ULL                          cpu->invalidate_translation_caches(cpu,
574                              + paddr);                              0, INVALIDATE_ALL);
                         invalidate_table_entry(cpu, 0xffffffffa0000000ULL  
                             + paddr);  
575                  }                  }
576          }          }
   
 #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  
577  }  }
578    
579    
# Line 1016  void coproc_register_read(struct cpu *cp Line 595  void coproc_register_read(struct cpu *cp
595          if (cp->coproc_nr==0 && reg_nr==COP0_PAGEMASK)  unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_PAGEMASK)  unimpl = 0;
596          if (cp->coproc_nr==0 && reg_nr==COP0_WIRED)     unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_WIRED)     unimpl = 0;
597          if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR)  unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR)  unimpl = 0;
598          if (cp->coproc_nr==0 && reg_nr==COP0_COUNT) {          if (cp->coproc_nr==0 && reg_nr==COP0_COUNT)     unimpl = 0;
                 /*  
                  *  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);  
                 }  
   
                 unimpl = 0;  
         }  
599          if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI)   unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI)   unimpl = 0;
600          if (cp->coproc_nr==0 && reg_nr==COP0_COMPARE)   unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_COMPARE)   unimpl = 0;
601          if (cp->coproc_nr==0 && reg_nr==COP0_STATUS)    unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_STATUS)    unimpl = 0;
# Line 1121  void coproc_register_write(struct cpu *c Line 677  void coproc_register_write(struct cpu *c
677                              (tmp & 0xff)!=0) {                              (tmp & 0xff)!=0) {
678                                  /*  char *symbol;                                  /*  char *symbol;
679                                      uint64_t offset;                                      uint64_t offset;
680                                      symbol = get_symbol_name(                                      symbol = get_symbol_name(cpu->pc, &offset);
                                     cpu->cd.mips.pc_last, &offset);  
681                                      fatal("YO! pc = 0x%08llx <%s> "                                      fatal("YO! pc = 0x%08llx <%s> "
682                                      "lo=%016llx\n", (long long)                                      "lo=%016llx\n", (long long)
683                                      cpu->cd.mips.pc_last, symbol? symbol :                                      cpu->pc, symbol? symbol :
684                                      "no symbol", (long long)tmp); */                                      "no symbol", (long long)tmp); */
685                                  tmp &= (R2K3K_ENTRYLO_PFN_MASK |                                  tmp &= (R2K3K_ENTRYLO_PFN_MASK |
686                                      R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |                                      R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |
# Line 1191  void coproc_register_write(struct cpu *c Line 746  void coproc_register_write(struct cpu *c
746                          unimpl = 0;                          unimpl = 0;
747                          break;                          break;
748                  case COP0_COUNT:                  case COP0_COUNT:
749                          if (tmp != (int64_t)(int32_t)tmp)                          if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
750                                  fatal("WARNING: trying to write a 64-bit value"                                  fatal("WARNING: trying to write a 64-bit value"
751                                      " to the COUNT register!\n");                                      " to the COUNT register!\n");
752                          tmp = (int64_t)(int32_t)tmp;                          tmp = (int64_t)(int32_t)tmp;
# Line 1201  void coproc_register_write(struct cpu *c Line 756  void coproc_register_write(struct cpu *c
756                          /*  Clear the timer interrupt bit (bit 7):  */                          /*  Clear the timer interrupt bit (bit 7):  */
757                          cpu->cd.mips.compare_register_set = 1;                          cpu->cd.mips.compare_register_set = 1;
758                          mips_cpu_interrupt_ack(cpu, 7);                          mips_cpu_interrupt_ack(cpu, 7);
759                          if (tmp != (int64_t)(int32_t)tmp)                          if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
760                                  fatal("WARNING: trying to write a 64-bit value"                                  fatal("WARNING: trying to write a 64-bit value"
761                                      " to the COMPARE register!\n");                                      " to the COMPARE register!\n");
762                          tmp = (int64_t)(int32_t)tmp;                          tmp = (int64_t)(int32_t)tmp;
# Line 1209  void coproc_register_write(struct cpu *c Line 764  void coproc_register_write(struct cpu *c
764                          break;                          break;
765                  case COP0_ENTRYHI:                  case COP0_ENTRYHI:
766                          /*                          /*
767                           *  Translation caches must be invalidated, because the                           *  Translation caches must be invalidated if the
768                           *  address space might change (if the ASID changes).                           *  ASID changes:
769                           */                           */
770                          switch (cpu->cd.mips.cpu_type.mmu_model) {                          switch (cpu->cd.mips.cpu_type.mmu_model) {
771                          case MMU3K:                          case MMU3K:
772                                  old_asid = (cp->reg[COP0_ENTRYHI] &                                  old_asid = cp->reg[COP0_ENTRYHI] &
773                                      R2K3K_ENTRYHI_ASID_MASK) >>                                      R2K3K_ENTRYHI_ASID_MASK;
                                     R2K3K_ENTRYHI_ASID_SHIFT;  
774                                  if ((cp->reg[COP0_ENTRYHI] &                                  if ((cp->reg[COP0_ENTRYHI] &
775                                      R2K3K_ENTRYHI_ASID_MASK) !=                                      R2K3K_ENTRYHI_ASID_MASK) !=
776                                      (tmp & R2K3K_ENTRYHI_ASID_MASK))                                      (tmp & R2K3K_ENTRYHI_ASID_MASK))
# Line 1229  void coproc_register_write(struct cpu *c Line 783  void coproc_register_write(struct cpu *c
783                                          inval = 1;                                          inval = 1;
784                                  break;                                  break;
785                          }                          }
786    
787                          if (inval)                          if (inval)
788                                  invalidate_translation_caches(cpu, 1, 0, 0,                                  invalidate_asid(cpu, old_asid);
789                                      old_asid);  
790                          unimpl = 0;                          unimpl = 0;
791                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
792                              (tmp & 0x3f)!=0) {                              (tmp & 0x3f)!=0) {
793                                  /* char *symbol;                                  /* char *symbol;
794                                     uint64_t offset;                                     uint64_t offset;
795                                     symbol = get_symbol_name(cpu->                                     symbol = get_symbol_name(cpu->pc,
796                                      cd.mips.pc_last, &offset);                                      &offset);
797                                     fatal("YO! pc = 0x%08llx <%s> "                                     fatal("YO! pc = 0x%08llx <%s> "
798                                      "hi=%016llx\n", (long long)cpu->                                      "hi=%016llx\n", (long long)cpu->pc,
799                                      cd.mips.pc_last, symbol? symbol :                                      symbol? symbol :
800                                      "no symbol", (long long)tmp);  */                                      "no symbol", (long long)tmp);  */
801                                  tmp &= ~0x3f;                                  tmp &= ~0x3f;
802                          }                          }
# Line 1287  void coproc_register_write(struct cpu *c Line 842  void coproc_register_write(struct cpu *c
842                  case COP0_STATUS:                  case COP0_STATUS:
843                          oldmode = cp->reg[COP0_STATUS];                          oldmode = cp->reg[COP0_STATUS];
844                          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  
845    
846                            /*
847                             *  When isolating caches, invalidate all translations.
848                             *  During the isolation, a special hack in memory_rw.c
849                             *  prevents translation tables from being updated, so
850                             *  the translation caches don't have to be invalidated
851                             *  when switching back to normal mode.
852                             */
853                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
854                              (oldmode & MIPS1_ISOL_CACHES) !=                              (oldmode & MIPS1_ISOL_CACHES) !=
855                              (tmp & MIPS1_ISOL_CACHES)) {                              (tmp & MIPS1_ISOL_CACHES)) {
856                                  /*  R3000-style caches when isolated are                                  /*  Invalidate everything if we are switching
857                                      treated in bintrans mode by changing                                      to isolated mode:  */
                                     the vaddr_to_hostaddr_table0 pointer:  */  
858                                  if (tmp & MIPS1_ISOL_CACHES) {                                  if (tmp & MIPS1_ISOL_CACHES) {
859                                          /*  2-level table:  */                                          cpu->invalidate_translation_caches(
860                                          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;  
861                                  }                                  }
862                          }                          }
863                          unimpl = 0;                          unimpl = 0;
# Line 1347  void coproc_register_write(struct cpu *c Line 867  void coproc_register_write(struct cpu *c
867                              affects IM bits 0 and 1:  */                              affects IM bits 0 and 1:  */
868                          cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);                          cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);
869                          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;  
870                          return;                          return;
871                  case COP0_FRAMEMASK:                  case COP0_FRAMEMASK:
872                          /*  TODO: R10000  */                          /*  TODO: R10000  */
# Line 1426  void coproc_register_write(struct cpu *c Line 942  void coproc_register_write(struct cpu *c
942   *   *
943   *  TODO:  Move this to some other file?   *  TODO:  Move this to some other file?
944   */   */
945  #define FMT_S           16  static int mips_fmt_to_ieee_fmt[32] = {
946  #define FMT_D           17          0, 0, 0, 0,  0, 0, 0, 0,
947  #define FMT_W           20          0, 0, 0, 0,  0, 0, 0, 0,
948  #define FMT_L           21          IEEE_FMT_S, IEEE_FMT_D, 0, 0,
949  #define FMT_PS          22          IEEE_FMT_W, IEEE_FMT_L, /* PS (Paired Single) */ 0, 0,
950            0, 0, 0, 0,  0, 0, 0, 0  };
951    
952    static char *fmtname[32] = {
953             "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
954             "8",  "9", "10", "11", "12", "13", "14", "15",
955             "s",  "d", "18", "19",  "w",  "l", "ps", "23",
956            "24", "25", "26", "27", "28", "29", "30", "31"  };
957    
958    static char *ccname[16] = {
959            "f",  "un",   "eq",  "ueq", "olt", "ult", "ole", "ule",
960            "sf", "ngle", "seq", "ngl", "lt",  "nge", "le",  "ngt"  };
961    
962  #define FPU_OP_ADD      1  #define FPU_OP_ADD      1
963  #define FPU_OP_SUB      2  #define FPU_OP_SUB      2
# Line 1442  void coproc_register_write(struct cpu *c Line 969  void coproc_register_write(struct cpu *c
969  #define FPU_OP_C        8  #define FPU_OP_C        8
970  #define FPU_OP_ABS      9  #define FPU_OP_ABS      9
971  #define FPU_OP_NEG      10  #define FPU_OP_NEG      10
972  /*  TODO: CEIL.L, CEIL.W, FLOOR.L, FLOOR.W, RECIP, ROUND.L, ROUND.W,  /*  TODO: CEIL.L, CEIL.W, FLOOR.L, FLOOR.W, RECIP, ROUND.L, ROUND.W, RSQRT  */
  RSQRT  */  
   
   
 struct internal_float_value {  
         double  f;  
         int     nan;  
 };  
   
   
 /*  
  *  fpu_interpret_float_value():  
  *  
  *  Interprets a float value from binary IEEE format into an  
  *  internal_float_value struct.  
  */  
 static void fpu_interpret_float_value(uint64_t reg,  
         struct internal_float_value *fvp, int fmt)  
 {  
         int n_frac = 0, n_exp = 0;  
         int i, nan, sign = 0, exponent;  
         double fraction;  
   
         memset(fvp, 0, sizeof(struct internal_float_value));  
   
         /*  n_frac and n_exp:  */  
         switch (fmt) {  
         case FMT_S:     n_frac = 23; n_exp = 8; break;  
         case FMT_W:     n_frac = 31; n_exp = 0; break;  
         case FMT_D:     n_frac = 52; n_exp = 11; break;  
         case FMT_L:     n_frac = 63; n_exp = 0; break;  
         default:  
                 fatal("fpu_interpret_float_value(): "  
                     "unimplemented format %i\n", fmt);  
         }  
   
         /*  exponent:  */  
         exponent = 0;  
         switch (fmt) {  
         case FMT_W:  
                 reg &= 0xffffffffULL;  
         case FMT_L:  
                 break;  
         case FMT_S:  
                 reg &= 0xffffffffULL;  
         case FMT_D:  
                 exponent = (reg >> n_frac) & ((1 << n_exp) - 1);  
                 exponent -= (1 << (n_exp-1)) - 1;  
                 break;  
         default:  
                 fatal("fpu_interpret_float_value(): unimplemented "  
                     "format %i\n", fmt);  
         }  
   
         /*  nan:  */  
         nan = 0;  
         switch (fmt) {  
         case FMT_S:  
                 if (reg == 0x7fffffffULL || reg == 0x7fbfffffULL)  
                         nan = 1;  
                 break;  
         case FMT_D:  
                 if (reg == 0x7fffffffffffffffULL ||  
                     reg == 0x7ff7ffffffffffffULL)  
                         nan = 1;  
                 break;  
         }  
   
         if (nan) {  
                 fvp->f = 1.0;  
                 goto no_reasonable_result;  
         }  
   
         /*  fraction:  */  
         fraction = 0.0;  
         switch (fmt) {  
         case FMT_W:  
                 {  
                         int32_t r_int = reg;  
                         fraction = r_int;  
                 }  
                 break;  
         case FMT_L:  
                 {  
                         int64_t r_int = reg;  
                         fraction = r_int;  
                 }  
                 break;  
         case FMT_S:  
         case FMT_D:  
                 /*  sign:  */  
                 sign = (reg >> 31) & 1;  
                 if (fmt == FMT_D)  
                         sign = (reg >> 63) & 1;  
   
                 fraction = 0.0;  
                 for (i=0; i<n_frac; i++) {  
                         int bit = (reg >> i) & 1;  
                         fraction /= 2.0;  
                         if (bit)  
                                 fraction += 1.0;  
                 }  
                 /*  Add implicit bit 0:  */  
                 fraction = (fraction / 2.0) + 1.0;  
                 break;  
         default:  
                 fatal("fpu_interpret_float_value(): "  
                     "unimplemented format %i\n", fmt);  
         }  
   
         /*  form the value:  */  
         fvp->f = fraction;  
   
         /*  fatal("load  reg=%016llx sign=%i exponent=%i fraction=%f ",  
             (long long)reg, sign, exponent, fraction);  */  
   
         /*  TODO: this is awful for exponents of large magnitude.  */  
         if (exponent > 0) {  
                 /*  
                  *  NOTE / TODO:  
                  *  
                  *  This is an ulgy workaround on Alpha, where it seems that  
                  *  multiplying by 2, 1024 times causes a floating point  
                  *  exception. (Triggered by running for example NetBSD/pmax  
                  *  2.0 on an Alpha.)  
                  */  
                 if (exponent == 1024)  
                         exponent = 1023;  
   
                 while (exponent-- > 0)  
                         fvp->f *= 2.0;  
         } else if (exponent < 0) {  
                 while (exponent++ < 0)  
                         fvp->f /= 2.0;  
         }  
   
         if (sign)  
                 fvp->f = -fvp->f;  
   
 no_reasonable_result:  
         fvp->nan = nan;  
   
         /*  fatal("f = %f\n", fvp->f);  */  
 }  
973    
974    
975  /*  /*
# Line 1596  no_reasonable_result: Line 980  no_reasonable_result:
980  static void fpu_store_float_value(struct mips_coproc *cp, int fd,  static void fpu_store_float_value(struct mips_coproc *cp, int fd,
981          double nf, int fmt, int nan)          double nf, int fmt, int nan)
982  {  {
983          int n_frac = 0, n_exp = 0, signofs=0;          int ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
984          int i, exponent;          uint64_t r = ieee_store_float_value(nf, ieee_fmt, nan);
         uint64_t r = 0, r2;  
         int64_t r3;  
   
         /*  n_frac and n_exp:  */  
         switch (fmt) {  
         case FMT_S:     n_frac = 23; n_exp = 8; signofs = 31; break;  
         case FMT_W:     n_frac = 31; n_exp = 0; signofs = 31; break;  
         case FMT_D:     n_frac = 52; n_exp = 11; signofs = 63; break;  
         case FMT_L:     n_frac = 63; n_exp = 0; signofs = 63; break;  
         default:  
                 fatal("fpu_store_float_value(): unimplemented format"  
                     " %i\n", fmt);  
         }  
   
         if ((fmt == FMT_S || fmt == FMT_D) && nan)  
                 goto store_nan;  
   
         /*  fraction:  */  
         switch (fmt) {  
         case FMT_W:  
         case FMT_L:  
                 /*  
                  *  This causes an implicit conversion of double to integer.  
                  *  If nf < 0.0, then r2 will begin with a sequence of binary  
                  *  1's, which is ok.  
                  */  
                 r3 = nf;  
                 r2 = r3;  
                 r |= r2;  
   
                 if (fmt == FMT_W)  
                         r &= 0xffffffffULL;  
                 break;  
         case FMT_S:  
         case FMT_D:  
                 /*  fatal("store f=%f ", nf);  */  
   
                 /*  sign bit:  */  
                 if (nf < 0.0) {  
                         r |= ((uint64_t)1 << signofs);  
                         nf = -nf;  
                 }  
   
                 /*  
                  *  How to convert back from double to exponent + fraction:  
                  *  We want fraction to be 1.xxx, that is  
                  *  1.0 <= fraction < 2.0  
                  *  
                  *  This method is very slow but should work:  
                  */  
                 exponent = 0;  
                 while (nf < 1.0 && exponent > -1023) {  
                         nf *= 2.0;  
                         exponent --;  
                 }  
                 while (nf >= 2.0 && exponent < 1023) {  
                         nf /= 2.0;  
                         exponent ++;  
                 }  
   
                 /*  Here:   1.0 <= nf < 2.0  */  
                 /*  fatal(" nf=%f", nf);  */  
                 nf -= 1.0;      /*  remove implicit first bit  */  
                 for (i=n_frac-1; i>=0; i--) {  
                         nf *= 2.0;  
                         if (nf >= 1.0) {  
                                 r |= ((uint64_t)1 << i);  
                                 nf -= 1.0;  
                         }  
                         /*  printf("\n i=%2i r=%016llx\n", i, (long long)r);  */  
                 }  
   
                 /*  Insert the exponent into the resulting word:  */  
                 /*  (First bias, then make sure it's within range)  */  
                 exponent += (((uint64_t)1 << (n_exp-1)) - 1);  
                 if (exponent < 0)  
                         exponent = 0;  
                 if (exponent >= ((int64_t)1 << n_exp))  
                         exponent = ((int64_t)1 << n_exp) - 1;  
                 r |= (uint64_t)exponent << n_frac;  
   
                 /*  Special case for 0.0:  */  
                 if (exponent == 0)  
                         r = 0;  
   
                 /*  fatal(" exp=%i, r = %016llx\n", exponent, (long long)r);  */  
   
                 break;  
         default:  
                 /*  TODO  */  
                 fatal("fpu_store_float_value(): unimplemented format "  
                     "%i\n", fmt);  
         }  
   
 store_nan:  
         if (nan) {  
                 if (fmt == FMT_S)  
                         r = 0x7fffffffULL;  
                 else if (fmt == FMT_D)  
                         r = 0x7fffffffffffffffULL;  
                 else  
                         r = 0x7fffffffULL;  
         }  
985    
986          /*          /*
987           *  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
988           *              for 64-bit coprocessor stuff.           *        for 64-bit coprocessor functionality!
989           */           */
990          if (fmt == FMT_D || fmt == FMT_L) {          if (fmt == COP1_FMT_D || fmt == COP1_FMT_L) {
991                  cp->reg[fd] = r & 0xffffffffULL;                  cp->reg[fd] = r & 0xffffffffULL;
992                  cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;                  cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;
993    
# Line 1726  store_nan: Line 1007  store_nan:
1007  /*  /*
1008   *  fpu_op():   *  fpu_op():
1009   *   *
1010   *  Perform a floating-point operation.  For those of fs and ft   *  Perform a floating-point operation. For those of fs and ft that are >= 0,
1011   *  that are >= 0, those numbers are interpreted into local   *  those numbers are interpreted into local variables.
  *  variables.  
1012   *   *
1013   *  Only FPU_OP_C (compare) returns anything of interest, 1 for   *  Only FPU_OP_C (compare) returns anything of interest, 1 for true, 0 for
1014   *  true, 0 for false.   *  false.
1015   */   */
1016  static int fpu_op(struct cpu *cpu, struct mips_coproc *cp, int op, int fmt,  static int fpu_op(struct cpu *cpu, struct mips_coproc *cp, int op, int fmt,
1017          int ft, int fs, int fd, int cond, int output_fmt)          int ft, int fs, int fd, int cond, int output_fmt)
1018  {  {
1019          /*  Potentially two input registers, fs and ft  */          /*  Potentially two input registers, fs and ft  */
1020          struct internal_float_value float_value[2];          struct ieee_float_value float_value[2];
1021          int unordered, nan;          int unordered, nan, ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
1022          uint64_t fs_v = 0;          uint64_t fs_v = 0;
1023          double nf;          double nf;
1024    
# Line 1746  static int fpu_op(struct cpu *cpu, struc Line 1026  static int fpu_op(struct cpu *cpu, struc
1026                  fs_v = cp->reg[fs];                  fs_v = cp->reg[fs];
1027                  /*  TODO: register-pair mode and plain                  /*  TODO: register-pair mode and plain
1028                      register mode? "FR" bit?  */                      register mode? "FR" bit?  */
1029                  if (fmt == FMT_D || fmt == FMT_L)                  if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1030                          fs_v = (fs_v & 0xffffffffULL) +                          fs_v = (fs_v & 0xffffffffULL) +
1031                              (cp->reg[(fs + 1) & 31] << 32);                              (cp->reg[(fs + 1) & 31] << 32);
1032                  fpu_interpret_float_value(fs_v, &float_value[0], fmt);                  ieee_interpret_float_value(fs_v, &float_value[0], ieee_fmt);
1033          }          }
1034          if (ft >= 0) {          if (ft >= 0) {
1035                  uint64_t v = cp->reg[ft];                  uint64_t v = cp->reg[ft];
1036                  /*  TODO: register-pair mode and                  /*  TODO: register-pair mode and
1037                      plain register mode? "FR" bit?  */                      plain register mode? "FR" bit?  */
1038                  if (fmt == FMT_D || fmt == FMT_L)                  if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1039                          v = (v & 0xffffffffULL) +                          v = (v & 0xffffffffULL) +
1040                              (cp->reg[(ft + 1) & 31] << 32);                              (cp->reg[(ft + 1) & 31] << 32);
1041                  fpu_interpret_float_value(v, &float_value[1], fmt);                  ieee_interpret_float_value(v, &float_value[1], ieee_fmt);
1042          }          }
1043    
1044          switch (op) {          switch (op) {
# Line 1833  static int fpu_op(struct cpu *cpu, struc Line 1113  static int fpu_op(struct cpu *cpu, struc
1113                   *  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
1114                   *              for 64-bit coprocessor stuff.                   *              for 64-bit coprocessor stuff.
1115                   */                   */
1116                  if (output_fmt == FMT_D || output_fmt == FMT_L) {                  if (output_fmt == COP1_FMT_D || output_fmt == COP1_FMT_L) {
1117                          cp->reg[fd] = fs_v & 0xffffffffULL;                          cp->reg[fd] = fs_v & 0xffffffffULL;
1118                          cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;                          cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;
1119                          if (cp->reg[fd] & 0x80000000ULL)                          if (cp->reg[fd] & 0x80000000ULL)
# Line 1924  static int fpu_function(struct cpu *cpu, Line 1204  static int fpu_function(struct cpu *cpu,
1204    
1205          /*  bc1f, bc1t, bc1fl, bc1tl:  */          /*  bc1f, bc1t, bc1fl, bc1tl:  */
1206          if ((function & 0x03e00000) == 0x01000000) {          if ((function & 0x03e00000) == 0x01000000) {
1207                  int nd, tf, imm, cond_true;                  int nd, tf, imm;
1208                  char *instr_mnem;                  char *instr_mnem;
1209    
1210                  /*  cc are bits 20..18:  */                  /*  cc are bits 20..18:  */
# Line 1947  static int fpu_function(struct cpu *cpu, Line 1227  static int fpu_function(struct cpu *cpu,
1227                  if (unassemble_only)                  if (unassemble_only)
1228                          return 1;                          return 1;
1229    
1230                  if (cpu->cd.mips.delay_slot) {                  fatal("INTERNAL ERROR: MIPS coprocessor branches should not"
1231                          fatal("%s: jump inside a jump's delay slot, "                      " be implemented in cpu_mips_coproc.c, but in"
1232                              "or similar. TODO\n", instr_mnem);                      " cpu_mips_instr.c!\n");
1233                          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;  
1234          }          }
1235    
1236          /*  add.fmt: Floating-point add  */          /*  add.fmt: Floating-point add  */
1237          if ((function & 0x0000003f) == 0x00000000) {          if ((function & 0x0000003f) == 0x00000000) {
1238                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1239                          debug("add.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("add.%s\tr%i,r%i,r%i\n",
1240                                fmtname[fmt], fd, fs, ft);
1241                  if (unassemble_only)                  if (unassemble_only)
1242                          return 1;                          return 1;
1243    
# Line 1992  static int fpu_function(struct cpu *cpu, Line 1248  static int fpu_function(struct cpu *cpu,
1248          /*  sub.fmt: Floating-point subtract  */          /*  sub.fmt: Floating-point subtract  */
1249          if ((function & 0x0000003f) == 0x00000001) {          if ((function & 0x0000003f) == 0x00000001) {
1250                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1251                          debug("sub.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("sub.%s\tr%i,r%i,r%i\n",
1252                                fmtname[fmt], fd, fs, ft);
1253                  if (unassemble_only)                  if (unassemble_only)
1254                          return 1;                          return 1;
1255    
# Line 2003  static int fpu_function(struct cpu *cpu, Line 1260  static int fpu_function(struct cpu *cpu,
1260          /*  mul.fmt: Floating-point multiply  */          /*  mul.fmt: Floating-point multiply  */
1261          if ((function & 0x0000003f) == 0x00000002) {          if ((function & 0x0000003f) == 0x00000002) {
1262                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1263                          debug("mul.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("mul.%s\tr%i,r%i,r%i\n",
1264                                fmtname[fmt], fd, fs, ft);
1265                  if (unassemble_only)                  if (unassemble_only)
1266                          return 1;                          return 1;
1267    
# Line 2014  static int fpu_function(struct cpu *cpu, Line 1272  static int fpu_function(struct cpu *cpu,
1272          /*  div.fmt: Floating-point divide  */          /*  div.fmt: Floating-point divide  */
1273          if ((function & 0x0000003f) == 0x00000003) {          if ((function & 0x0000003f) == 0x00000003) {
1274                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1275                          debug("div.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("div.%s\tr%i,r%i,r%i\n",
1276                                fmtname[fmt], fd, fs, ft);
1277                  if (unassemble_only)                  if (unassemble_only)
1278                          return 1;                          return 1;
1279    
# Line 2025  static int fpu_function(struct cpu *cpu, Line 1284  static int fpu_function(struct cpu *cpu,
1284          /*  sqrt.fmt: Floating-point square-root  */          /*  sqrt.fmt: Floating-point square-root  */
1285          if ((function & 0x001f003f) == 0x00000004) {          if ((function & 0x001f003f) == 0x00000004) {
1286                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1287                          debug("sqrt.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("sqrt.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1288                  if (unassemble_only)                  if (unassemble_only)
1289                          return 1;                          return 1;
1290    
# Line 2036  static int fpu_function(struct cpu *cpu, Line 1295  static int fpu_function(struct cpu *cpu,
1295          /*  abs.fmt: Floating-point absolute value  */          /*  abs.fmt: Floating-point absolute value  */
1296          if ((function & 0x001f003f) == 0x00000005) {          if ((function & 0x001f003f) == 0x00000005) {
1297                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1298                          debug("abs.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("abs.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1299                  if (unassemble_only)                  if (unassemble_only)
1300                          return 1;                          return 1;
1301    
# Line 2047  static int fpu_function(struct cpu *cpu, Line 1306  static int fpu_function(struct cpu *cpu,
1306          /*  mov.fmt: Floating-point (non-arithmetic) move  */          /*  mov.fmt: Floating-point (non-arithmetic) move  */
1307          if ((function & 0x0000003f) == 0x00000006) {          if ((function & 0x0000003f) == 0x00000006) {
1308                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1309                          debug("mov.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("mov.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1310                  if (unassemble_only)                  if (unassemble_only)
1311                          return 1;                          return 1;
1312    
# Line 2058  static int fpu_function(struct cpu *cpu, Line 1317  static int fpu_function(struct cpu *cpu,
1317          /*  neg.fmt: Floating-point negate  */          /*  neg.fmt: Floating-point negate  */
1318          if ((function & 0x001f003f) == 0x00000007) {          if ((function & 0x001f003f) == 0x00000007) {
1319                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1320                          debug("neg.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("neg.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1321                  if (unassemble_only)                  if (unassemble_only)
1322                          return 1;                          return 1;
1323    
# Line 2069  static int fpu_function(struct cpu *cpu, Line 1328  static int fpu_function(struct cpu *cpu,
1328          /*  trunc.l.fmt: Truncate  */          /*  trunc.l.fmt: Truncate  */
1329          if ((function & 0x001f003f) == 0x00000009) {          if ((function & 0x001f003f) == 0x00000009) {
1330                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1331                          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);
1332                  if (unassemble_only)                  if (unassemble_only)
1333                          return 1;                          return 1;
1334    
1335                  /*  TODO: not CVT?  */                  /*  TODO: not CVT?  */
1336    
1337                  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);
1338                  return 1;                  return 1;
1339          }          }
1340    
1341          /*  trunc.w.fmt: Truncate  */          /*  trunc.w.fmt: Truncate  */
1342          if ((function & 0x001f003f) == 0x0000000d) {          if ((function & 0x001f003f) == 0x0000000d) {
1343                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1344                          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);
1345                  if (unassemble_only)                  if (unassemble_only)
1346                          return 1;                          return 1;
1347    
1348                  /*  TODO: not CVT?  */                  /*  TODO: not CVT?  */
1349    
1350                  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);
1351                  return 1;                  return 1;
1352          }          }
1353    
# Line 2098  static int fpu_function(struct cpu *cpu, Line 1357  static int fpu_function(struct cpu *cpu,
1357                  int bit;                  int bit;
1358    
1359                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1360                          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],
1361                                fmtname[fmt], cc, fs, ft);
1362                  if (unassemble_only)                  if (unassemble_only)
1363                          return 1;                          return 1;
1364    
# Line 2110  static int fpu_function(struct cpu *cpu, Line 1370  static int fpu_function(struct cpu *cpu,
1370                   *      FCCR:  bits 7..0                   *      FCCR:  bits 7..0
1371                   *      FCSR:  bits 31..25 and 23                   *      FCSR:  bits 31..25 and 23
1372                   */                   */
1373                  cp->fcr[FPU_FCCR] &= ~(1 << cc);                  cp->fcr[MIPS_FPU_FCCR] &= ~(1 << cc);
1374                  if (cond_true)                  if (cond_true)
1375                          cp->fcr[FPU_FCCR] |= (1 << cc);                          cp->fcr[MIPS_FPU_FCCR] |= (1 << cc);
1376    
1377                  if (cc == 0) {                  if (cc == 0) {
1378                          bit = 1 << FCSR_FCC0_SHIFT;                          bit = 1 << MIPS_FCSR_FCC0_SHIFT;
1379                          cp->fcr[FPU_FCSR] &= ~bit;                          cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1380                          if (cond_true)                          if (cond_true)
1381                                  cp->fcr[FPU_FCSR] |= bit;                                  cp->fcr[MIPS_FPU_FCSR] |= bit;
1382                  } else {                  } else {
1383                          bit = 1 << (FCSR_FCC1_SHIFT + cc-1);                          bit = 1 << (MIPS_FCSR_FCC1_SHIFT + cc-1);
1384                          cp->fcr[FPU_FCSR] &= ~bit;                          cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1385                          if (cond_true)                          if (cond_true)
1386                                  cp->fcr[FPU_FCSR] |= bit;                                  cp->fcr[MIPS_FPU_FCSR] |= bit;
1387                  }                  }
1388    
1389                  return 1;                  return 1;
# Line 2132  static int fpu_function(struct cpu *cpu, Line 1392  static int fpu_function(struct cpu *cpu,
1392          /*  cvt.s.fmt: Convert to single floating-point  */          /*  cvt.s.fmt: Convert to single floating-point  */
1393          if ((function & 0x001f003f) == 0x00000020) {          if ((function & 0x001f003f) == 0x00000020) {
1394                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1395                          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);
1396                  if (unassemble_only)                  if (unassemble_only)
1397                          return 1;                          return 1;
1398    
1399                  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);
1400                  return 1;                  return 1;
1401          }          }
1402    
1403          /*  cvt.d.fmt: Convert to double floating-point  */          /*  cvt.d.fmt: Convert to double floating-point  */
1404          if ((function & 0x001f003f) == 0x00000021) {          if ((function & 0x001f003f) == 0x00000021) {
1405                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1406                          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);
1407                  if (unassemble_only)                  if (unassemble_only)
1408                          return 1;                          return 1;
1409    
1410                  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);
1411                  return 1;                  return 1;
1412          }          }
1413    
1414          /*  cvt.w.fmt: Convert to word fixed-point  */          /*  cvt.w.fmt: Convert to word fixed-point  */
1415          if ((function & 0x001f003f) == 0x00000024) {          if ((function & 0x001f003f) == 0x00000024) {
1416                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1417                          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);
1418                  if (unassemble_only)                  if (unassemble_only)
1419                          return 1;                          return 1;
1420    
1421                  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);
1422                  return 1;                  return 1;
1423          }          }
1424    
# Line 2184  void coproc_tlbpr(struct cpu *cpu, int r Line 1444  void coproc_tlbpr(struct cpu *cpu, int r
1444                              R2K3K_INDEX_SHIFT;                              R2K3K_INDEX_SHIFT;
1445                          if (i >= cp->nr_of_tlbs) {                          if (i >= cp->nr_of_tlbs) {
1446                                  /*  TODO:  exception?  */                                  /*  TODO:  exception?  */
1447                                  fatal("warning: tlbr from index %i (too "                                  fatal("[ warning: tlbr from index %i (too "
1448                                      "high)\n", i);                                      "high) ]\n", i);
1449                                  return;                                  return;
1450                          }                          }
1451    
1452                          /*                          cp->reg[COP0_ENTRYHI]  = cp->tlbs[i].hi;
1453                           *  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; */  
1454                  } else {                  } else {
1455                          /*  R4000:  */                          /*  R4000:  */
1456                          i = cp->reg[COP0_INDEX] & INDEX_MASK;                          i = cp->reg[COP0_INDEX] & INDEX_MASK;
# Line 2288  void coproc_tlbpr(struct cpu *cpu, int r Line 1542  void coproc_tlbpr(struct cpu *cpu, int r
1542  /*  /*
1543   *  coproc_tlbwri():   *  coproc_tlbwri():
1544   *   *
1545   *  'tlbwr' and 'tlbwi'   *  MIPS TLB write random (tlbwr) and write indexed (tlbwi) instructions.
1546   */   */
1547  void coproc_tlbwri(struct cpu *cpu, int randomflag)  void coproc_tlbwri(struct cpu *cpu, int randomflag)
1548  {  {
1549          struct mips_coproc *cp = cpu->cd.mips.coproc[0];          struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1550          int index, g_bit;          int index, g_bit;
1551          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;  
1552    
1553          if (randomflag) {          if (randomflag) {
1554                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
1555                          index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)                          index = ((cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
1556                              >> R2K3K_RANDOM_SHIFT;                              >> R2K3K_RANDOM_SHIFT) - 1;
1557                  else                          /*  R3000 always has 8 wired entries:  */
1558                            if (index < 8)
1559                                    index = cp->nr_of_tlbs - 1;
1560                            cp->reg[COP0_RANDOM] = index << R2K3K_RANDOM_SHIFT;
1561                    } else {
1562                            cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
1563                                % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
1564                          index = cp->reg[COP0_RANDOM] & RANDOM_MASK;                          index = cp->reg[COP0_RANDOM] & RANDOM_MASK;
1565                    }
1566          } else {          } else {
1567                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1568                          index = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK)                          index = (cp->reg[COP0_INDEX] & R2K3K_INDEX_MASK)
# Line 2341  void coproc_tlbwri(struct cpu *cpu, int Line 1578  void coproc_tlbwri(struct cpu *cpu, int
1578                  return;                  return;
1579          }          }
1580    
1581    
1582  #if 0  #if 0
1583          /*  Debug dump of the previous entry at that index:  */          /*  Debug dump of the previous entry at that index:  */
1584          debug(" old entry at index = %04x", index);          fatal("{ old TLB entry at index %02x:", index);
1585          debug(" mask = %016llx", (long long) cp->tlbs[index].mask);          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1586          debug(" hi = %016llx", (long long) cp->tlbs[index].hi);                  fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1587          debug(" lo0 = %016llx", (long long) cp->tlbs[index].lo0);                  fatal(" lo=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1588          debug(" lo1 = %016llx\n", (long long) cp->tlbs[index].lo1);          } else {
1589                    if (cpu->is_32bit) {
1590                            fatal(" mask=%08"PRIx32,(uint32_t)cp->tlbs[index].mask);
1591                            fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1592                            fatal(" lo0=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1593                            fatal(" lo1=%08"PRIx32, (uint32_t)cp->tlbs[index].lo1);
1594                    } else {
1595                            fatal(" mask=%016"PRIx64, cp->tlbs[index].mask);
1596                            fatal(" hi=%016"PRIx64, cp->tlbs[index].hi);
1597                            fatal(" lo0=%016"PRIx64, cp->tlbs[index].lo0);
1598                            fatal(" lo1=%016"PRIx64, cp->tlbs[index].lo1);
1599                    }
1600            }
1601            fatal(" }\n");
1602  #endif  #endif
1603    
1604          /*  Translation caches must be invalidated:  */          /*
1605             *  Any virtual address translation for the old TLB entry must be
1606             *  invalidated first:
1607             *
1608             *  (Only Valid entries need to be invalidated, and only those that
1609             *  are either Global, or have the same ASID as the new entry will
1610             *  have. No other address translations should be active anyway.)
1611             */
1612    
1613          switch (cpu->cd.mips.cpu_type.mmu_model) {          switch (cpu->cd.mips.cpu_type.mmu_model) {
1614    
1615          case MMU3K:          case MMU3K:
1616                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;
1617                  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;  
   
 /*  TODO: Bug? Why does this if need to be commented out?  */  
1618    
1619                  /*  if (cp->tlbs[index].lo0 & ENTRYLO_V)  */                  if (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_V &&
1620                          invalidate_translation_caches(cpu, 0, oldvaddr, 0, 0);                      (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_G ||
1621                        (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK) ==
1622                        (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK) ))
1623                            cpu->invalidate_translation_caches(cpu, oldvaddr,
1624                                INVALIDATE_VADDR);
1625                  break;                  break;
1626          default:  
1627                  if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {          default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1628                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;
1629                          /*  44 addressable bits:  */                          /*  44 addressable bits:  */
1630                          if (oldvaddr & 0x80000000000ULL)                          if (oldvaddr & 0x80000000000ULL)
1631                                  oldvaddr |= 0xfffff00000000000ULL;                                  oldvaddr |= 0xfffff00000000000ULL;
1632                    } else if (cpu->is_32bit) {
1633                            /*  MIPS32 etc.:  */
1634                            oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1635                            oldvaddr = (int32_t)oldvaddr;
1636                  } else {                  } else {
1637                          /*  Assume MMU4K  */                          /*  Assume MMU4K  */
1638                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
# Line 2379  void coproc_tlbwri(struct cpu *cpu, int Line 1641  void coproc_tlbwri(struct cpu *cpu, int
1641                                  oldvaddr |= 0xffffff0000000000ULL;                                  oldvaddr |= 0xffffff0000000000ULL;
1642                  }                  }
1643    
1644    #if 0
1645                    /*  TODO: FIX THIS! It shouldn't be needed!  */
1646                    cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL);
1647    #else
1648                  /*                  /*
                  *  Both pages:  
                  *  
1649                   *  TODO: non-4KB page sizes!                   *  TODO: non-4KB page sizes!
1650                   */                   */
1651                  invalidate_translation_caches(                  if (cp->tlbs[index].lo0 & ENTRYLO_V)
1652                      cpu, 0, oldvaddr & ~0x1fff, 0, 0);                          cpu->invalidate_translation_caches(cpu, oldvaddr,
1653                  invalidate_translation_caches(                              INVALIDATE_VADDR);
1654                      cpu, 0, (oldvaddr & ~0x1fff) | 0x1000, 0, 0);                  if (cp->tlbs[index].lo1 & ENTRYLO_V)
1655                            cpu->invalidate_translation_caches(cpu, oldvaddr|0x1000,
1656                                INVALIDATE_VADDR);
1657    #endif
1658          }          }
1659    
1660    #if 0
1661          /*          /*
1662           *  Check for duplicate entries.  (There should not be two mappings           *  Check for duplicate entries.  (There should not be two mappings
1663           *  from one virtual address to physical addresses.)           *  from one virtual address to physical addresses.)
# Line 2402  void coproc_tlbwri(struct cpu *cpu, int Line 1669  void coproc_tlbwri(struct cpu *cpu, int
1669          if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&          if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&
1670              cpu->cd.mips.cpu_type.rev != MIPS_R4100) {              cpu->cd.mips.cpu_type.rev != MIPS_R4100) {
1671                  uint64_t vaddr1, vaddr2;                  uint64_t vaddr1, vaddr2;
1672                  int i, asid;                  int i;
1673                    unsigned int asid;
1674    
1675                  vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K;                  vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K;
1676                  asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;                  asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
# Line 2427  void coproc_tlbwri(struct cpu *cpu, int Line 1695  void coproc_tlbwri(struct cpu *cpu, int
1695                                      (long long)vaddr1, asid, i);                                      (long long)vaddr1, asid, i);
1696                  }                  }
1697          }          }
1698    #endif
1699    
1700          /*  Write the new entry:  */          /*  Write the new entry:  */
1701    
1702          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1703                  uint64_t vaddr, paddr;                  uint32_t vaddr, paddr;
1704                  int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;                  int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;
1705                  unsigned char *memblock = NULL;                  unsigned char *memblock = NULL;
1706    
# Line 2442  void coproc_tlbwri(struct cpu *cpu, int Line 1710  void coproc_tlbwri(struct cpu *cpu, int
1710                  vaddr =  cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;                  vaddr =  cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
1711                  paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;                  paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;
1712    
1713                  /*  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);  
1714    
1715                  if (memblock != NULL &&                  /*  Invalidate any code translation, if we are writing
1716                      cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) {                      a Dirty page to the TLB:  */
1717                          memblock += (paddr & ((1 << BITS_PER_PAGETABLE) - 1));                  if (wf) {
1718                            cpu->invalidate_code_translation(cpu, paddr,
1719                                INVALIDATE_PADDR);
1720                    }
1721    
1722                          /*                  if (cp->reg[COP0_STATUS] & MIPS1_ISOL_CACHES) {
1723                           *  TODO: Hahaha, this is even uglier than the thing                          fatal("Wow! Interesting case; tlbw* while caches"
1724                           *  above. Some OSes seem to map code pages read/write,                              " are isolated. TODO\n");
1725                           *  which causes the bintrans cache to be invalidated                          /*  Don't update the translation table in this
1726                           *  even when it doesn't have to be.                              case...  */
1727                           */                          exit(1);
1728  /*                      if (vaddr < 0x10000000)  */                  }
                                 wf = 0;  
1729    
1730                    /*  If we have a memblock (host page) for the physical
1731                        page, then add a translation for it immediately:  */
1732                    if (memblock != NULL &&
1733                        cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V)
1734                          cpu->update_translation_table(cpu, vaddr, memblock,                          cpu->update_translation_table(cpu, vaddr, memblock,
1735                              wf, paddr);                              wf, paddr);
                 }  
1736          } else {          } else {
1737                  /*  R4000:  */                  /*  R4000 etc.:  */
1738                  g_bit = (cp->reg[COP0_ENTRYLO0] &                  unsigned char *memblock = NULL;
1739                      cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;                  int pfn_shift = 12, vpn_shift = 12;
1740                    int wf0, wf1, mask;
1741                    uint64_t vaddr0, vaddr1, paddr0, paddr1, ptmp;
1742    
1743                  cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];                  cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];
1744                  cp->tlbs[index].hi   = cp->reg[COP0_ENTRYHI];                  cp->tlbs[index].hi   = cp->reg[COP0_ENTRYHI];
1745                  cp->tlbs[index].lo1  = cp->reg[COP0_ENTRYLO1];                  cp->tlbs[index].lo1  = cp->reg[COP0_ENTRYLO1];
1746                  cp->tlbs[index].lo0  = cp->reg[COP0_ENTRYLO0];                  cp->tlbs[index].lo0  = cp->reg[COP0_ENTRYLO0];
1747    
1748                    wf0 = cp->tlbs[index].lo0 & ENTRYLO_D;
1749                    wf1 = cp->tlbs[index].lo1 & ENTRYLO_D;
1750    
1751                    mask = cp->reg[COP0_PAGEMASK];
1752                    if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1753                            pfn_shift = 10;
1754                            mask |= 0x07ff;
1755                    } else {
1756                            mask |= 0x1fff;
1757                    }
1758                    switch (mask) {
1759                    case 0x00007ff:
1760                            if (cp->tlbs[index].lo0 & ENTRYLO_V ||
1761                                cp->tlbs[index].lo1 & ENTRYLO_V) {
1762                                    fatal("1KB pages don't work with dyntrans.\n");
1763                                    exit(1);
1764                            }
1765                            vpn_shift = 10;
1766                            break;
1767                    case 0x0001fff: break;
1768                    case 0x0007fff: vpn_shift = 14; break;
1769                    case 0x001ffff: vpn_shift = 16; break;
1770                    case 0x007ffff: vpn_shift = 18; break;
1771                    case 0x01fffff: vpn_shift = 20; break;
1772                    case 0x07fffff: vpn_shift = 22; break;
1773                    case 0x1ffffff: vpn_shift = 24; break;
1774                    case 0x7ffffff: vpn_shift = 26; break;
1775                    default:fatal("Unimplemented MASK = 0x%016x\n", mask);
1776                            exit(1);
1777                    }
1778    
1779                    paddr0 = ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK)
1780                        >> ENTRYLO_PFN_SHIFT) << pfn_shift;
1781                    paddr1 = ((cp->tlbs[index].lo1 & ENTRYLO_PFN_MASK)
1782                        >> ENTRYLO_PFN_SHIFT) << pfn_shift;
1783    
1784                    if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1785                            vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;
1786                            /*  44 addressable bits:  */
1787                            if (vaddr0 & 0x80000000000ULL)
1788                                    vaddr0 |= 0xfffff00000000000ULL;
1789                    } else if (cpu->is_32bit) {
1790                            /*  MIPS32 etc.:  */
1791                            vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1792                            vaddr0 = (int32_t)vaddr0;
1793                    } else {
1794                            /*  Assume MMU4K  */
1795                            vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1796                            /*  40 addressable bits:  */
1797                            if (vaddr0 & 0x8000000000ULL)
1798                                    vaddr0 |= 0xffffff0000000000ULL;
1799                    }
1800    
1801                    vaddr1 = vaddr0 | (1 << vpn_shift);
1802    
1803                    g_bit = (cp->reg[COP0_ENTRYLO0] &
1804                        cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;
1805    
1806                  if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {                  if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1807                          /*  NOTE: The VR4131 (and possibly others) don't have                          /*  NOTE: The VR4131 (and possibly others) don't have
1808                              a Global bit in entryhi  */                              a Global bit in entryhi  */
# Line 2484  void coproc_tlbwri(struct cpu *cpu, int Line 1815  void coproc_tlbwri(struct cpu *cpu, int
1815                          if (g_bit)                          if (g_bit)
1816                                  cp->tlbs[index].hi |= TLB_G;                                  cp->tlbs[index].hi |= TLB_G;
1817                  }                  }
         }  
1818    
1819          if (randomflag) {                  /*
1820                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {                   *  Invalidate any code translations, if we are writing Dirty
1821                          cp->reg[COP0_RANDOM] =                   *  pages to the TLB:  (TODO: 4KB hardcoded... ugly)
1822                              ((random() % (cp->nr_of_tlbs - 8)) + 8)                   */
1823                              << R2K3K_RANDOM_SHIFT;                  for (ptmp = 0; ptmp < (1 << pfn_shift); ptmp += 0x1000) {
1824                  } else {                          if (wf0)
1825                          cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()                                  cpu->invalidate_code_translation(cpu,
1826                              % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));                                      paddr0 + ptmp, INVALIDATE_PADDR);
1827                            if (wf1)
1828                                    cpu->invalidate_code_translation(cpu,
1829                                        paddr1 + ptmp, INVALIDATE_PADDR);
1830                  }                  }
         }  
 }  
   
1831    
1832  /*                  /*
1833   *  coproc_rfe():                   *  If we have a memblock (host page) for the physical page,
1834   *                   *  then add a translation for it immediately, to save some
1835   *  Return from exception. (R3000 etc.)                   *  time. (It would otherwise be added later on anyway,
1836   */                   *  because of a translation miss.)
1837  void coproc_rfe(struct cpu *cpu)                   *
1838  {                   *  NOTE/TODO: This is only for 4KB pages so far. It would
1839          int oldmode;                   *             be too expensive to add e.g. 16MB pages like
1840                     *             this.
1841          oldmode = cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_SR_KU_CUR;                   */
1842                    memblock = memory_paddr_to_hostaddr(cpu->mem, paddr0, 0);
1843          cpu->cd.mips.coproc[0]->reg[COP0_STATUS] =                  if (memblock != NULL && cp->reg[COP0_ENTRYLO0] & ENTRYLO_V)
1844              (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) |                          cpu->update_translation_table(cpu, vaddr0, memblock,
1845              ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 0x3c) >> 2);                              wf0, paddr0);
1846                    memblock = memory_paddr_to_hostaddr(cpu->mem, paddr1, 0);
1847          /*  Changing from kernel to user mode? Then this is necessary:  */                  if (memblock != NULL && cp->reg[COP0_ENTRYLO1] & ENTRYLO_V)
1848          if (!oldmode &&                          cpu->update_translation_table(cpu, vaddr1, memblock,
1849              (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &                              wf1, paddr1);
1850              MIPS1_SR_KU_CUR))          }
                 invalidate_translation_caches(cpu, 0, 0, 1, 0);  
1851  }  }
1852    
1853    
# Line 2529  void coproc_rfe(struct cpu *cpu) Line 1858  void coproc_rfe(struct cpu *cpu)
1858   */   */
1859  void coproc_eret(struct cpu *cpu)  void coproc_eret(struct cpu *cpu)
1860  {  {
         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;  
   
1861          if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {          if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {
1862                  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];  
1863                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;
1864          } else {          } else {
1865                  cpu->pc = cpu->cd.mips.pc_last =                  cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_EPC];
1866                      cpu->cd.mips.coproc[0]->reg[COP0_EPC];                  cpu->delay_slot = 0;
                 cpu->cd.mips.delay_slot = 0;  
1867                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;
1868          }          }
1869    
1870          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  
1871  }  }
1872    
1873    
# Line 2597  void coproc_function(struct cpu *cpu, st Line 1897  void coproc_function(struct cpu *cpu, st
1897                  return;                  return;
1898          }          }
1899    
 #if 0  
1900          /*  No FPU?  */          /*  No FPU?  */
1901          if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {          if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {
1902                  mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);                  mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);
1903                  return;                  return;
1904          }          }
 #endif  
1905    
1906          /*  For quick reference:  */          /*  For quick reference:  */
1907          copz = (function >> 21) & 31;          copz = (function >> 21) & 31;
# Line 2618  void coproc_function(struct cpu *cpu, st Line 1916  void coproc_function(struct cpu *cpu, st
1916                          if (cpnr == 0)                          if (cpnr == 0)
1917                                  debug("%s", cop0_names[rd]);                                  debug("%s", cop0_names[rd]);
1918                          else                          else
1919                                  debug("cpreg%i", rd);                                  debug("r%i", rd);
1920                          if (function & 7)                          if (function & 7)
1921                                  debug(",%i", (int)(function & 7));                                  debug(",%i", (int)(function & 7));
1922                          debug("\n");                          debug("\n");
# Line 2644  void coproc_function(struct cpu *cpu, st Line 1942  void coproc_function(struct cpu *cpu, st
1942                          if (cpnr == 0)                          if (cpnr == 0)
1943                                  debug("%s", cop0_names[rd]);                                  debug("%s", cop0_names[rd]);
1944                          else                          else
1945                                  debug("cpreg%i", rd);                                  debug("r%i", rd);
1946                          if (function & 7)                          if (function & 7)
1947                                  debug(",%i", (int)(function & 7));                                  debug(",%i", (int)(function & 7));
1948                          debug("\n");                          debug("\n");
# Line 2673  void coproc_function(struct cpu *cpu, st Line 1971  void coproc_function(struct cpu *cpu, st
1971                                      regnames[rt], fs);                                      regnames[rt], fs);
1972                                  return;                                  return;
1973                          }                          }
1974                          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;  
1975                          /*  TODO: implement delay for gpr[rt]                          /*  TODO: implement delay for gpr[rt]
1976                              (for MIPS I,II,III only)  */                              (for MIPS I,II,III only)  */
1977                          return;                          return;
# Line 2707  void coproc_function(struct cpu *cpu, st Line 2003  void coproc_function(struct cpu *cpu, st
2003                                              on status bits!  */                                              on status bits!  */
2004    
2005                                          switch (fs) {                                          switch (fs) {
2006                                          case FPU_FCCR:                                          case MIPS_FPU_FCCR:
2007                                                  cp->fcr[FPU_FCSR] =                                                  cp->fcr[MIPS_FPU_FCSR] =
2008                                                      (cp->fcr[FPU_FCSR] &                                                      (cp->fcr[MIPS_FPU_FCSR] &
2009                                                      0x017fffffULL) | ((tmp & 1)                                                      0x017fffffULL) | ((tmp & 1)
2010                                                      << FCSR_FCC0_SHIFT)                                                      << MIPS_FCSR_FCC0_SHIFT)
2011                                                      | (((tmp & 0xfe) >> 1) <<                                                      | (((tmp & 0xfe) >> 1) <<
2012                                                      FCSR_FCC1_SHIFT);                                                      MIPS_FCSR_FCC1_SHIFT);
2013                                                  break;                                                  break;
2014                                          case FPU_FCSR:                                          case MIPS_FPU_FCSR:
2015                                                  cp->fcr[FPU_FCCR] =                                                  cp->fcr[MIPS_FPU_FCCR] =
2016                                                      (cp->fcr[FPU_FCCR] &                                                      (cp->fcr[MIPS_FPU_FCCR] &
2017                                                      0xffffff00ULL) | ((tmp >>                                                      0xffffff00ULL) | ((tmp >>
2018                                                      FCSR_FCC0_SHIFT) & 1) |                                                      MIPS_FCSR_FCC0_SHIFT) & 1) |
2019                                                      (((tmp >> FCSR_FCC1_SHIFT)                                                      (((tmp >>
2020                                                        MIPS_FCSR_FCC1_SHIFT)
2021                                                      & 0x7f) << 1);                                                      & 0x7f) << 1);
2022                                                  break;                                                  break;
2023                                          default:                                          default:
# Line 2744  void coproc_function(struct cpu *cpu, st Line 2041  void coproc_function(struct cpu *cpu, st
2041                          return;                          return;
2042          }          }
2043    
         /*  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;  
         }  
   
2044    
2045          /*  Ugly R5900 hacks:  */          /*  Ugly R5900 hacks:  */
2046          if ((function & 0xfffff) == 0x38) {             /*  ei  */          if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) {
2047                  if (unassemble_only) {                  if ((function & 0xfffff) == COP0_EI) {
2048                          debug("ei\n");                          if (unassemble_only) {
2049                                    debug("ei\n");
2050                                    return;
2051                            }
2052                            cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |=
2053                                R5900_STATUS_EIE;
2054                          return;                          return;
2055                  }                  }
                 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= R5900_STATUS_EIE;  
                 return;  
         }  
2056    
2057          if ((function & 0xfffff) == 0x39) {             /*  di  */                  if ((function & 0xfffff) == COP0_DI) {
2058                  if (unassemble_only) {                          if (unassemble_only) {
2059                          debug("di\n");                                  debug("di\n");
2060                                    return;
2061                            }
2062                            cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &=
2063                                ~R5900_STATUS_EIE;
2064                          return;                          return;
2065                  }                  }
                 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~R5900_STATUS_EIE;  
                 return;  
2066          }          }
2067    
2068          co_bit = (function >> 25) & 1;          co_bit = (function >> 25) & 1;
2069    
2070          /*  TLB operations and other things:  */          /*  TLB operations and other things:  */
2071          if (cp->coproc_nr == 0) {          if (cp->coproc_nr == 0) {
2072                    if (!unassemble_only) {
2073                            fatal("FATAL INTERNAL ERROR: Should be implemented"
2074                                " with dyntrans instead.\n");
2075                            exit(1);
2076                    }
2077    
2078                  op = (function) & 0xff;                  op = (function) & 0xff;
2079                  switch (co_bit) {                  switch (co_bit) {
2080                  case 1:                  case 1:
2081                          switch (op) {                          switch (op) {
2082                          case COP0_TLBR:         /*  Read indexed TLB entry  */                          case COP0_TLBR:         /*  Read indexed TLB entry  */
2083                                  if (unassemble_only) {                                  debug("tlbr\n");
                                         debug("tlbr\n");  
                                         return;  
                                 }  
                                 coproc_tlbpr(cpu, 1);  
2084                                  return;                                  return;
2085                          case COP0_TLBWI:        /*  Write indexed  */                          case COP0_TLBWI:        /*  Write indexed  */
2086                          case COP0_TLBWR:        /*  Write random  */                          case COP0_TLBWR:        /*  Write random  */
2087                                  if (unassemble_only) {                                  if (op == COP0_TLBWI)
2088                                          if (op == COP0_TLBWI)                                          debug("tlbwi");
2089                                                  debug("tlbwi");                                  else
2090                                          else                                          debug("tlbwr");
2091                                                  debug("tlbwr");                                  if (!running) {
2092                                          if (!running) {                                          debug("\n");
2093                                                  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]);  
2094                                  }                                  }
2095                                  coproc_tlbwri(cpu, op == COP0_TLBWR);                                  debug("\tindex=%08llx",
2096                                        (long long)cp->reg[COP0_INDEX]);
2097                                    debug(", random=%08llx",
2098                                        (long long)cp->reg[COP0_RANDOM]);
2099                                    debug(", mask=%016llx",
2100                                        (long long)cp->reg[COP0_PAGEMASK]);
2101                                    debug(", hi=%016llx",
2102                                        (long long)cp->reg[COP0_ENTRYHI]);
2103                                    debug(", lo0=%016llx",
2104                                        (long long)cp->reg[COP0_ENTRYLO0]);
2105                                    debug(", lo1=%016llx\n",
2106                                        (long long)cp->reg[COP0_ENTRYLO1]);
2107                                  return;                                  return;
2108                          case COP0_TLBP:         /*  Probe TLB for                          case COP0_TLBP:         /*  Probe TLB for
2109                                                      matching entry  */                                                      matching entry  */
2110                                  if (unassemble_only) {                                  debug("tlbp\n");
                                         debug("tlbp\n");  
                                         return;  
                                 }  
                                 coproc_tlbpr(cpu, 0);  
2111                                  return;                                  return;
2112                          case COP0_RFE:          /*  R2000/R3000 only:                          case COP0_RFE:          /*  R2000/R3000 only:
2113                                                      Return from Exception  */                                                      Return from Exception  */
2114                                  if (unassemble_only) {                                  debug("rfe\n");
                                         debug("rfe\n");  
                                         return;  
                                 }  
                                 coproc_rfe(cpu);  
2115                                  return;                                  return;
2116                          case COP0_ERET: /*  R4000: Return from exception  */                          case COP0_ERET: /*  R4000: Return from exception  */
2117                                  if (unassemble_only) {                                  debug("eret\n");
2118                                          debug("eret\n");                                  return;
2119                                          return;                          case COP0_DERET:
2120                                    debug("deret\n");
2121                                    return;
2122                            case COP0_WAIT:
2123                                    {
2124                                            int code = (function >> 6) & 0x7ffff;
2125                                            debug("wait");
2126                                            if (code > 0)
2127                                                    debug("\t0x%x", code);
2128                                            debug("\n");
2129                                  }                                  }
                                 coproc_eret(cpu);  
2130                                  return;                                  return;
2131                          case COP0_STANDBY:                          case COP0_STANDBY:
2132                                  if (unassemble_only) {                                  debug("standby\n");
                                         debug("standby\n");  
                                         return;  
                                 }  
                                 /*  TODO: Hm. Do something here?  */  
2133                                  return;                                  return;
2134                          case COP0_SUSPEND:                          case COP0_SUSPEND:
2135                                  if (unassemble_only) {                                  debug("suspend\n");
                                         debug("suspend\n");  
                                         return;  
                                 }  
                                 /*  TODO: Hm. Do something here?  */  
2136                                  return;                                  return;
2137                          case COP0_HIBERNATE:                          case COP0_HIBERNATE:
2138                                  if (unassemble_only) {                                  debug("hibernate\n");
                                         debug("hibernate\n");  
                                         return;  
                                 }  
                                 /*  TODO: Hm. Do something here?  */  
2139                                  return;                                  return;
2140                          default:                          default:
2141                                  ;                                  ;
# Line 2891  void coproc_function(struct cpu *cpu, st Line 2155  void coproc_function(struct cpu *cpu, st
2155                  return;                  return;
2156          }          }
2157    
         /*  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;  
         }  
   
2158          if (unassemble_only) {          if (unassemble_only) {
2159                  debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function);                  debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function);
2160                  return;                  return;
2161          }          }
2162    
2163          fatal("cpu%i: UNIMPLEMENTED coproc%i function %08lx "          fatal("cpu%i: UNIMPLEMENTED coproc%i function %08"PRIx32" "
2164              "(pc = %016llx)\n", cpu->cpu_id, cp->coproc_nr, function,              "(pc = %016"PRIx64")\n", cpu->cpu_id, cp->coproc_nr,
2165              (long long)cpu->cd.mips.pc_last);              (uint32_t)function, cpu->pc);
2166  #if 1  
         single_step = 1;  
 #else  
2167          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  
2168  }  }
2169    
2170  #endif  /*  ENABLE_MIPS  */  #endif  /*  ENABLE_MIPS  */

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

  ViewVC Help
Powered by ViewVC 1.1.26