/[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 18 by dpavlin, Mon Oct 8 16:19:11 2007 UTC revision 28 by dpavlin, Mon Oct 8 16:20:26 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.3 2005/10/26 14:37:03 debug Exp $   *  $Id: cpu_mips_coproc.c,v 1.49 2006/07/21 20:39:40 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 dependent  */                  /*  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);  
                         }  
                         memset(tbl1, 0, sizeof(struct vth32_table));  
                 } else {  
                         tbl1 = cpu->cd.mips.next_free_vth_table;  
                         cpu->cd.mips.next_free_vth_table = tbl1->next_free;  
                         tbl1->next_free = NULL;  
                 }  
                 cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a] = tbl1;  
                 if (tbl1->refcount != 0) {  
                         printf("INTERNAL ERROR in coproc.c\n");  
                         exit(1);  
                 }  
         }  
         p_r = tbl1->haddr_entry[b*2];  
         p_w = tbl1->haddr_entry[b*2+1];  
         p_paddr = tbl1->paddr_entry[b];  
         /*  printf("   p_r=%p p_w=%p\n", p_r, p_w);  */  
         if (p_r == NULL && p_paddr == 0 &&  
             (host_page != NULL || paddr_page != 0)) {  
                 tbl1->refcount ++;  
                 /*  printf("ADDING %08x -> %p wf=%i (refcount is "  
                     "now %i)\n", (int)vaddr_page, host_page,  
                     writeflag, tbl1->refcount);  */  
         }  
         if (writeflag == -1) {  
                 /*  Forced downgrade to read-only:  */  
                 tbl1->haddr_entry[b*2 + 1] = NULL;  
                 if (cpu->cd.mips.host_store ==  
                     cpu->cd.mips.host_store_orig)  
                         cpu->cd.mips.host_store[index] = NULL;  
         } else if (writeflag==0 && p_w != NULL && host_page != NULL) {  
                 /*  Don't degrade a page from writable to readonly.  */  
         } else {  
                 if (host_page != NULL) {  
                         tbl1->haddr_entry[b*2] = host_page;  
                         if (cpu->cd.mips.host_load ==  
                             cpu->cd.mips.host_load_orig)  
                                 cpu->cd.mips.host_load[index] = host_page;  
                         if (writeflag) {  
                                 tbl1->haddr_entry[b*2+1] = host_page;  
                                 if (cpu->cd.mips.host_store ==  
                                     cpu->cd.mips.host_store_orig)  
                                         cpu->cd.mips.host_store[index] =  
                                             host_page;  
                         } else {  
                                 tbl1->haddr_entry[b*2+1] = NULL;  
                                 if (cpu->cd.mips.host_store ==  
                                     cpu->cd.mips.host_store_orig)  
                                         cpu->cd.mips.host_store[index] = NULL;  
                         }  
                 } else {  
                         tbl1->haddr_entry[b*2] = NULL;  
                         tbl1->haddr_entry[b*2+1] = NULL;  
                         if (cpu->cd.mips.host_store ==  
                             cpu->cd.mips.host_store_orig) {  
                                 cpu->cd.mips.host_load[index] = NULL;  
                                 cpu->cd.mips.host_store[index] = NULL;  
534                          }                          }
                 }  
                 tbl1->paddr_entry[b] = paddr_page;  
         }  
         tbl1->bintrans_chunks[b] = NULL;  
 }  
   
   
 /*  
  *  mips_update_translation_table():  
  */  
 void mips_update_translation_table(struct cpu *cpu, uint64_t vaddr_page,  
         unsigned char *host_page, int writeflag, uint64_t paddr_page)  
 {  
         if (!cpu->machine->bintrans_enable)  
                 return;  
   
         if (writeflag > 0)  
                 bintrans_invalidate(cpu, paddr_page);  
   
         if (cpu->machine->old_bintrans_enable) {  
                 old_update_translation_table(cpu, vaddr_page, host_page,  
                     writeflag, paddr_page);  
                 return;  
         }  
   
         /*  TODO  */  
         /*  printf("update_translation_table(): TODO\n");  */  
 }  
   
   
 /*  
  *  invalidate_table_entry():  
  */  
 static void invalidate_table_entry(struct cpu *cpu, uint64_t vaddr)  
 {  
         int a, b, index;  
         struct vth32_table *tbl1;  
         void *p_r, *p_w;  
         uint32_t p_paddr;  
   
         if (!cpu->machine->old_bintrans_enable) {  
                 /*  printf("invalidate_table_entry(): New: TODO\n");  */  
                 return;  
         }  
   
         /*  This table stuff only works for 32-bit mode:  */  
         if (vaddr & 0x80000000ULL) {  
                 if ((vaddr >> 32) != 0xffffffffULL) {  
                         fatal("invalidate_table_entry(): vaddr = 0x%016llx\n",  
                             (long long)vaddr);  
                         return;  
                 }  
535          } else {          } else {
536                  if ((vaddr >> 32) != 0) {                  int non4kpages = 0;
537                          fatal("invalidate_table_entry(): vaddr = 0x%016llx\n",                  uint64_t topbit = 1, fillmask = 0xffffff0000000000ULL;
                             (long long)vaddr);  
                         return;  
                 }  
         }  
538    
539          a = (vaddr >> 22) & 0x3ff;                  if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
540          b = (vaddr >> 12) & 0x3ff;                          topbit <<= 43;
541          index = (vaddr >> 12) & 0xfffff;                          fillmask <<= 4;
542                    } else {
543          /*  printf("vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b);  */                          topbit <<= 39;
   
         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;  
544                  }                  }
         }  
 }  
   
   
 /*  
  *  clear_all_chunks_from_all_tables():  
  */  
 void clear_all_chunks_from_all_tables(struct cpu *cpu)  
 {  
         int a, b;  
         struct vth32_table *tbl1;  
545    
546          if (!cpu->machine->old_bintrans_enable) {                  for (i=0; i<ntlbs; i++) {
547                  printf("clear_all_chunks_from_all_tables(): New: TODO\n");                          if (tlb[i].mask != 0 && tlb[i].mask != 0x1800) {
548                  return;                                  non4kpages = 1;
549          }                                  continue;
   
         for (a=0; a<0x400; a++) {  
                 tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];  
                 if (tbl1 != cpu->cd.mips.vaddr_to_hostaddr_nulltable) {  
                         for (b=0; b<0x400; b++) {  
                                 int index;  
   
                                 tbl1->haddr_entry[b*2] = NULL;  
                                 tbl1->haddr_entry[b*2+1] = NULL;  
                                 tbl1->paddr_entry[b] = 0;  
                                 tbl1->bintrans_chunks[b] = NULL;  
   
                                 if (cpu->cd.mips.host_store ==  
                                     cpu->cd.mips.host_store_orig) {  
                                         index = (a << 10) + b;  
                                         cpu->cd.mips.host_load[index] = NULL;  
                                         cpu->cd.mips.host_store[index] = NULL;  
                                 }  
550                          }                          }
                 }  
         }  
 }  
   
   
 /*  
  *  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;  
551    
552          if (cpu->machine->bintrans_enable) {                          if ((tlb[i].hi & ENTRYHI_ASID) == asid &&
553  #if 1                              !(tlb[i].hi & TLB_G)) {
554                  int i;                                  uint64_t vaddr0, vaddr1;
555                  uint64_t tlb_paddr0, tlb_paddr1;                                  vaddr0 = cp->tlbs[i].hi & ~fillmask;
556                  uint64_t tlb_vaddr;                                  if (vaddr0 & topbit)
557                  uint64_t p, p2;                                          vaddr0 |= fillmask;
558                                    vaddr1 = vaddr0 | 0x1000;  /*  TODO: mask  */
559                  switch (cpu->cd.mips.cpu_type.mmu_model) {  
560                  case MMU3K:                                  if (tlb[i].lo0 & ENTRYLO_V)
561                          for (i=0; i<64; i++) {                                          cpu->invalidate_translation_caches(cpu,
562                                  tlb_paddr0 = cpu->cd.mips.coproc[0]->                                              vaddr0, INVALIDATE_VADDR);
563                                      tlbs[i].lo0 & R2K3K_ENTRYLO_PFN_MASK;                                  if (tlb[i].lo1 & ENTRYLO_V)
564                                  tlb_vaddr = cpu->cd.mips.coproc[0]->                                          cpu->invalidate_translation_caches(cpu,
565                                      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));  
                                 }  
566                          }                          }
567                  }                  }
 #endif  
568    
569                  if (paddr < 0x20000000) {                  if (non4kpages) {
570                          invalidate_table_entry(cpu, 0xffffffff80000000ULL                          cpu->invalidate_translation_caches(cpu,
571                              + paddr);                              0, INVALIDATE_ALL);
                         invalidate_table_entry(cpu, 0xffffffffa0000000ULL  
                             + paddr);  
572                  }                  }
573          }          }
   
 #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  
574  }  }
575    
576    
# Line 1016  void coproc_register_read(struct cpu *cp Line 592  void coproc_register_read(struct cpu *cp
592          if (cp->coproc_nr==0 && reg_nr==COP0_PAGEMASK)  unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_PAGEMASK)  unimpl = 0;
593          if (cp->coproc_nr==0 && reg_nr==COP0_WIRED)     unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_WIRED)     unimpl = 0;
594          if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR)  unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR)  unimpl = 0;
595          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;  
         }  
596          if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI)   unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI)   unimpl = 0;
597          if (cp->coproc_nr==0 && reg_nr==COP0_COMPARE)   unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_COMPARE)   unimpl = 0;
598          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 674  void coproc_register_write(struct cpu *c
674                              (tmp & 0xff)!=0) {                              (tmp & 0xff)!=0) {
675                                  /*  char *symbol;                                  /*  char *symbol;
676                                      uint64_t offset;                                      uint64_t offset;
677                                      symbol = get_symbol_name(                                      symbol = get_symbol_name(cpu->pc, &offset);
                                     cpu->cd.mips.pc_last, &offset);  
678                                      fatal("YO! pc = 0x%08llx <%s> "                                      fatal("YO! pc = 0x%08llx <%s> "
679                                      "lo=%016llx\n", (long long)                                      "lo=%016llx\n", (long long)
680                                      cpu->cd.mips.pc_last, symbol? symbol :                                      cpu->pc, symbol? symbol :
681                                      "no symbol", (long long)tmp); */                                      "no symbol", (long long)tmp); */
682                                  tmp &= (R2K3K_ENTRYLO_PFN_MASK |                                  tmp &= (R2K3K_ENTRYLO_PFN_MASK |
683                                      R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |                                      R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |
# Line 1191  void coproc_register_write(struct cpu *c Line 743  void coproc_register_write(struct cpu *c
743                          unimpl = 0;                          unimpl = 0;
744                          break;                          break;
745                  case COP0_COUNT:                  case COP0_COUNT:
746                          if (tmp != (int64_t)(int32_t)tmp)                          if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
747                                  fatal("WARNING: trying to write a 64-bit value"                                  fatal("WARNING: trying to write a 64-bit value"
748                                      " to the COUNT register!\n");                                      " to the COUNT register!\n");
749                          tmp = (int64_t)(int32_t)tmp;                          tmp = (int64_t)(int32_t)tmp;
# Line 1201  void coproc_register_write(struct cpu *c Line 753  void coproc_register_write(struct cpu *c
753                          /*  Clear the timer interrupt bit (bit 7):  */                          /*  Clear the timer interrupt bit (bit 7):  */
754                          cpu->cd.mips.compare_register_set = 1;                          cpu->cd.mips.compare_register_set = 1;
755                          mips_cpu_interrupt_ack(cpu, 7);                          mips_cpu_interrupt_ack(cpu, 7);
756                          if (tmp != (int64_t)(int32_t)tmp)                          if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
757                                  fatal("WARNING: trying to write a 64-bit value"                                  fatal("WARNING: trying to write a 64-bit value"
758                                      " to the COMPARE register!\n");                                      " to the COMPARE register!\n");
759                          tmp = (int64_t)(int32_t)tmp;                          tmp = (int64_t)(int32_t)tmp;
# Line 1209  void coproc_register_write(struct cpu *c Line 761  void coproc_register_write(struct cpu *c
761                          break;                          break;
762                  case COP0_ENTRYHI:                  case COP0_ENTRYHI:
763                          /*                          /*
764                           *  Translation caches must be invalidated, because the                           *  Translation caches must be invalidated if the
765                           *  address space might change (if the ASID changes).                           *  ASID changes:
766                           */                           */
767                          switch (cpu->cd.mips.cpu_type.mmu_model) {                          switch (cpu->cd.mips.cpu_type.mmu_model) {
768                          case MMU3K:                          case MMU3K:
769                                  old_asid = (cp->reg[COP0_ENTRYHI] &                                  old_asid = cp->reg[COP0_ENTRYHI] &
770                                      R2K3K_ENTRYHI_ASID_MASK) >>                                      R2K3K_ENTRYHI_ASID_MASK;
                                     R2K3K_ENTRYHI_ASID_SHIFT;  
771                                  if ((cp->reg[COP0_ENTRYHI] &                                  if ((cp->reg[COP0_ENTRYHI] &
772                                      R2K3K_ENTRYHI_ASID_MASK) !=                                      R2K3K_ENTRYHI_ASID_MASK) !=
773                                      (tmp & R2K3K_ENTRYHI_ASID_MASK))                                      (tmp & R2K3K_ENTRYHI_ASID_MASK))
# Line 1229  void coproc_register_write(struct cpu *c Line 780  void coproc_register_write(struct cpu *c
780                                          inval = 1;                                          inval = 1;
781                                  break;                                  break;
782                          }                          }
783    
784                          if (inval)                          if (inval)
785                                  invalidate_translation_caches(cpu, 1, 0, 0,                                  invalidate_asid(cpu, old_asid);
786                                      old_asid);  
787                          unimpl = 0;                          unimpl = 0;
788                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
789                              (tmp & 0x3f)!=0) {                              (tmp & 0x3f)!=0) {
790                                  /* char *symbol;                                  /* char *symbol;
791                                     uint64_t offset;                                     uint64_t offset;
792                                     symbol = get_symbol_name(cpu->                                     symbol = get_symbol_name(cpu->pc,
793                                      cd.mips.pc_last, &offset);                                      &offset);
794                                     fatal("YO! pc = 0x%08llx <%s> "                                     fatal("YO! pc = 0x%08llx <%s> "
795                                      "hi=%016llx\n", (long long)cpu->                                      "hi=%016llx\n", (long long)cpu->pc,
796                                      cd.mips.pc_last, symbol? symbol :                                      symbol? symbol :
797                                      "no symbol", (long long)tmp);  */                                      "no symbol", (long long)tmp);  */
798                                  tmp &= ~0x3f;                                  tmp &= ~0x3f;
799                          }                          }
# Line 1287  void coproc_register_write(struct cpu *c Line 839  void coproc_register_write(struct cpu *c
839                  case COP0_STATUS:                  case COP0_STATUS:
840                          oldmode = cp->reg[COP0_STATUS];                          oldmode = cp->reg[COP0_STATUS];
841                          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  
842    
843                            /*
844                             *  When isolating caches, invalidate all translations.
845                             *  During the isolation, a special hack in memory_rw.c
846                             *  prevents translation tables from being updated, so
847                             *  the translation caches don't have to be invalidated
848                             *  when switching back to normal mode.
849                             */
850                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
851                              (oldmode & MIPS1_ISOL_CACHES) !=                              (oldmode & MIPS1_ISOL_CACHES) !=
852                              (tmp & MIPS1_ISOL_CACHES)) {                              (tmp & MIPS1_ISOL_CACHES)) {
853                                  /*  R3000-style caches when isolated are                                  /*  Invalidate everything if we are switching
854                                      treated in bintrans mode by changing                                      to isolated mode:  */
                                     the vaddr_to_hostaddr_table0 pointer:  */  
855                                  if (tmp & MIPS1_ISOL_CACHES) {                                  if (tmp & MIPS1_ISOL_CACHES) {
856                                          /*  2-level table:  */                                          cpu->invalidate_translation_caches(
857                                          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;  
858                                  }                                  }
859                          }                          }
860                          unimpl = 0;                          unimpl = 0;
# Line 1347  void coproc_register_write(struct cpu *c Line 864  void coproc_register_write(struct cpu *c
864                              affects IM bits 0 and 1:  */                              affects IM bits 0 and 1:  */
865                          cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);                          cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);
866                          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;  
867                          return;                          return;
868                  case COP0_FRAMEMASK:                  case COP0_FRAMEMASK:
869                          /*  TODO: R10000  */                          /*  TODO: R10000  */
# Line 1426  void coproc_register_write(struct cpu *c Line 939  void coproc_register_write(struct cpu *c
939   *   *
940   *  TODO:  Move this to some other file?   *  TODO:  Move this to some other file?
941   */   */
942  #define FMT_S           16  static int mips_fmt_to_ieee_fmt[32] = {
943  #define FMT_D           17          0, 0, 0, 0,  0, 0, 0, 0,
944  #define FMT_W           20          0, 0, 0, 0,  0, 0, 0, 0,
945  #define FMT_L           21          IEEE_FMT_S, IEEE_FMT_D, 0, 0,
946  #define FMT_PS          22          IEEE_FMT_W, IEEE_FMT_L, /* PS (Paired Single) */ 0, 0,
947            0, 0, 0, 0,  0, 0, 0, 0  };
948    
949    static char *fmtname[32] = {
950             "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
951             "8",  "9", "10", "11", "12", "13", "14", "15",
952             "s",  "d", "18", "19",  "w",  "l", "ps", "23",
953            "24", "25", "26", "27", "28", "29", "30", "31"  };
954    
955    static char *ccname[16] = {
956            "f",  "un",   "eq",  "ueq", "olt", "ult", "ole", "ule",
957            "sf", "ngle", "seq", "ngl", "lt",  "nge", "le",  "ngt"  };
958    
959  #define FPU_OP_ADD      1  #define FPU_OP_ADD      1
960  #define FPU_OP_SUB      2  #define FPU_OP_SUB      2
# Line 1442  void coproc_register_write(struct cpu *c Line 966  void coproc_register_write(struct cpu *c
966  #define FPU_OP_C        8  #define FPU_OP_C        8
967  #define FPU_OP_ABS      9  #define FPU_OP_ABS      9
968  #define FPU_OP_NEG      10  #define FPU_OP_NEG      10
969  /*  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);  */  
 }  
970    
971    
972  /*  /*
# Line 1596  no_reasonable_result: Line 977  no_reasonable_result:
977  static void fpu_store_float_value(struct mips_coproc *cp, int fd,  static void fpu_store_float_value(struct mips_coproc *cp, int fd,
978          double nf, int fmt, int nan)          double nf, int fmt, int nan)
979  {  {
980          int n_frac = 0, n_exp = 0, signofs=0;          int ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
981          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;  
         }  
982    
983          /*          /*
984           *  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
985           *              for 64-bit coprocessor stuff.           *        for 64-bit coprocessor functionality!
986           */           */
987          if (fmt == FMT_D || fmt == FMT_L) {          if (fmt == COP1_FMT_D || fmt == COP1_FMT_L) {
988                  cp->reg[fd] = r & 0xffffffffULL;                  cp->reg[fd] = r & 0xffffffffULL;
989                  cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;                  cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;
990    
# Line 1726  store_nan: Line 1004  store_nan:
1004  /*  /*
1005   *  fpu_op():   *  fpu_op():
1006   *   *
1007   *  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,
1008   *  that are >= 0, those numbers are interpreted into local   *  those numbers are interpreted into local variables.
  *  variables.  
1009   *   *
1010   *  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
1011   *  true, 0 for false.   *  false.
1012   */   */
1013  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,
1014          int ft, int fs, int fd, int cond, int output_fmt)          int ft, int fs, int fd, int cond, int output_fmt)
1015  {  {
1016          /*  Potentially two input registers, fs and ft  */          /*  Potentially two input registers, fs and ft  */
1017          struct internal_float_value float_value[2];          struct ieee_float_value float_value[2];
1018          int unordered, nan;          int unordered, nan, ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
1019          uint64_t fs_v = 0;          uint64_t fs_v = 0;
1020          double nf;          double nf;
1021    
# Line 1746  static int fpu_op(struct cpu *cpu, struc Line 1023  static int fpu_op(struct cpu *cpu, struc
1023                  fs_v = cp->reg[fs];                  fs_v = cp->reg[fs];
1024                  /*  TODO: register-pair mode and plain                  /*  TODO: register-pair mode and plain
1025                      register mode? "FR" bit?  */                      register mode? "FR" bit?  */
1026                  if (fmt == FMT_D || fmt == FMT_L)                  if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1027                          fs_v = (fs_v & 0xffffffffULL) +                          fs_v = (fs_v & 0xffffffffULL) +
1028                              (cp->reg[(fs + 1) & 31] << 32);                              (cp->reg[(fs + 1) & 31] << 32);
1029                  fpu_interpret_float_value(fs_v, &float_value[0], fmt);                  ieee_interpret_float_value(fs_v, &float_value[0], ieee_fmt);
1030          }          }
1031          if (ft >= 0) {          if (ft >= 0) {
1032                  uint64_t v = cp->reg[ft];                  uint64_t v = cp->reg[ft];
1033                  /*  TODO: register-pair mode and                  /*  TODO: register-pair mode and
1034                      plain register mode? "FR" bit?  */                      plain register mode? "FR" bit?  */
1035                  if (fmt == FMT_D || fmt == FMT_L)                  if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1036                          v = (v & 0xffffffffULL) +                          v = (v & 0xffffffffULL) +
1037                              (cp->reg[(ft + 1) & 31] << 32);                              (cp->reg[(ft + 1) & 31] << 32);
1038                  fpu_interpret_float_value(v, &float_value[1], fmt);                  ieee_interpret_float_value(v, &float_value[1], ieee_fmt);
1039          }          }
1040    
1041          switch (op) {          switch (op) {
# Line 1833  static int fpu_op(struct cpu *cpu, struc Line 1110  static int fpu_op(struct cpu *cpu, struc
1110                   *  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
1111                   *              for 64-bit coprocessor stuff.                   *              for 64-bit coprocessor stuff.
1112                   */                   */
1113                  if (output_fmt == FMT_D || output_fmt == FMT_L) {                  if (output_fmt == COP1_FMT_D || output_fmt == COP1_FMT_L) {
1114                          cp->reg[fd] = fs_v & 0xffffffffULL;                          cp->reg[fd] = fs_v & 0xffffffffULL;
1115                          cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;                          cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;
1116                          if (cp->reg[fd] & 0x80000000ULL)                          if (cp->reg[fd] & 0x80000000ULL)
# Line 1947  static int fpu_function(struct cpu *cpu, Line 1224  static int fpu_function(struct cpu *cpu,
1224                  if (unassemble_only)                  if (unassemble_only)
1225                          return 1;                          return 1;
1226    
1227                  if (cpu->cd.mips.delay_slot) {                  if (cpu->delay_slot) {
1228                          fatal("%s: jump inside a jump's delay slot, "                          fatal("%s: jump inside a jump's delay slot, "
1229                              "or similar. TODO\n", instr_mnem);                              "or similar. TODO\n", instr_mnem);
1230                          cpu->running = 0;                          cpu->running = 0;
# Line 1956  static int fpu_function(struct cpu *cpu, Line 1233  static int fpu_function(struct cpu *cpu,
1233    
1234                  /*  Both the FCCR and FCSR contain condition code bits...  */                  /*  Both the FCCR and FCSR contain condition code bits...  */
1235                  if (cc == 0)                  if (cc == 0)
1236                          cond_true = (cp->fcr[FPU_FCSR] >> FCSR_FCC0_SHIFT) & 1;                          cond_true = (cp->fcr[MIPS_FPU_FCSR] >>
1237                                MIPS_FCSR_FCC0_SHIFT) & 1;
1238                  else                  else
1239                          cond_true = (cp->fcr[FPU_FCSR] >>                          cond_true = (cp->fcr[MIPS_FPU_FCSR] >>
1240                              (FCSR_FCC1_SHIFT + cc-1)) & 1;                              (MIPS_FCSR_FCC1_SHIFT + cc-1)) & 1;
1241    
1242                  if (!tf)                  if (!tf)
1243                          cond_true = !cond_true;                          cond_true = !cond_true;
1244    
1245                  if (cond_true) {                  if (cond_true) {
1246                          cpu->cd.mips.delay_slot = TO_BE_DELAYED;                          cpu->delay_slot = TO_BE_DELAYED;
1247                          cpu->cd.mips.delay_jmpaddr = cpu->pc + (imm << 2);                          cpu->delay_jmpaddr = cpu->pc + (imm << 2);
1248                  } else {                  } else {
1249                          /*  "likely":  */                          /*  "likely":  */
1250                          if (nd) {                          if (nd) {
# Line 1981  static int fpu_function(struct cpu *cpu, Line 1259  static int fpu_function(struct cpu *cpu,
1259          /*  add.fmt: Floating-point add  */          /*  add.fmt: Floating-point add  */
1260          if ((function & 0x0000003f) == 0x00000000) {          if ((function & 0x0000003f) == 0x00000000) {
1261                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1262                          debug("add.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("add.%s\tr%i,r%i,r%i\n",
1263                                fmtname[fmt], fd, fs, ft);
1264                  if (unassemble_only)                  if (unassemble_only)
1265                          return 1;                          return 1;
1266    
# Line 1992  static int fpu_function(struct cpu *cpu, Line 1271  static int fpu_function(struct cpu *cpu,
1271          /*  sub.fmt: Floating-point subtract  */          /*  sub.fmt: Floating-point subtract  */
1272          if ((function & 0x0000003f) == 0x00000001) {          if ((function & 0x0000003f) == 0x00000001) {
1273                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1274                          debug("sub.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("sub.%s\tr%i,r%i,r%i\n",
1275                                fmtname[fmt], fd, fs, ft);
1276                  if (unassemble_only)                  if (unassemble_only)
1277                          return 1;                          return 1;
1278    
# Line 2003  static int fpu_function(struct cpu *cpu, Line 1283  static int fpu_function(struct cpu *cpu,
1283          /*  mul.fmt: Floating-point multiply  */          /*  mul.fmt: Floating-point multiply  */
1284          if ((function & 0x0000003f) == 0x00000002) {          if ((function & 0x0000003f) == 0x00000002) {
1285                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1286                          debug("mul.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("mul.%s\tr%i,r%i,r%i\n",
1287                                fmtname[fmt], fd, fs, ft);
1288                  if (unassemble_only)                  if (unassemble_only)
1289                          return 1;                          return 1;
1290    
# Line 2014  static int fpu_function(struct cpu *cpu, Line 1295  static int fpu_function(struct cpu *cpu,
1295          /*  div.fmt: Floating-point divide  */          /*  div.fmt: Floating-point divide  */
1296          if ((function & 0x0000003f) == 0x00000003) {          if ((function & 0x0000003f) == 0x00000003) {
1297                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1298                          debug("div.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("div.%s\tr%i,r%i,r%i\n",
1299                                fmtname[fmt], fd, fs, ft);
1300                  if (unassemble_only)                  if (unassemble_only)
1301                          return 1;                          return 1;
1302    
# Line 2025  static int fpu_function(struct cpu *cpu, Line 1307  static int fpu_function(struct cpu *cpu,
1307          /*  sqrt.fmt: Floating-point square-root  */          /*  sqrt.fmt: Floating-point square-root  */
1308          if ((function & 0x001f003f) == 0x00000004) {          if ((function & 0x001f003f) == 0x00000004) {
1309                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1310                          debug("sqrt.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("sqrt.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1311                  if (unassemble_only)                  if (unassemble_only)
1312                          return 1;                          return 1;
1313    
# Line 2036  static int fpu_function(struct cpu *cpu, Line 1318  static int fpu_function(struct cpu *cpu,
1318          /*  abs.fmt: Floating-point absolute value  */          /*  abs.fmt: Floating-point absolute value  */
1319          if ((function & 0x001f003f) == 0x00000005) {          if ((function & 0x001f003f) == 0x00000005) {
1320                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1321                          debug("abs.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("abs.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1322                  if (unassemble_only)                  if (unassemble_only)
1323                          return 1;                          return 1;
1324    
# Line 2047  static int fpu_function(struct cpu *cpu, Line 1329  static int fpu_function(struct cpu *cpu,
1329          /*  mov.fmt: Floating-point (non-arithmetic) move  */          /*  mov.fmt: Floating-point (non-arithmetic) move  */
1330          if ((function & 0x0000003f) == 0x00000006) {          if ((function & 0x0000003f) == 0x00000006) {
1331                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1332                          debug("mov.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("mov.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1333                  if (unassemble_only)                  if (unassemble_only)
1334                          return 1;                          return 1;
1335    
# Line 2058  static int fpu_function(struct cpu *cpu, Line 1340  static int fpu_function(struct cpu *cpu,
1340          /*  neg.fmt: Floating-point negate  */          /*  neg.fmt: Floating-point negate  */
1341          if ((function & 0x001f003f) == 0x00000007) {          if ((function & 0x001f003f) == 0x00000007) {
1342                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1343                          debug("neg.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("neg.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1344                  if (unassemble_only)                  if (unassemble_only)
1345                          return 1;                          return 1;
1346    
# Line 2069  static int fpu_function(struct cpu *cpu, Line 1351  static int fpu_function(struct cpu *cpu,
1351          /*  trunc.l.fmt: Truncate  */          /*  trunc.l.fmt: Truncate  */
1352          if ((function & 0x001f003f) == 0x00000009) {          if ((function & 0x001f003f) == 0x00000009) {
1353                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1354                          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);
1355                  if (unassemble_only)                  if (unassemble_only)
1356                          return 1;                          return 1;
1357    
1358                  /*  TODO: not CVT?  */                  /*  TODO: not CVT?  */
1359    
1360                  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);
1361                  return 1;                  return 1;
1362          }          }
1363    
1364          /*  trunc.w.fmt: Truncate  */          /*  trunc.w.fmt: Truncate  */
1365          if ((function & 0x001f003f) == 0x0000000d) {          if ((function & 0x001f003f) == 0x0000000d) {
1366                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1367                          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);
1368                  if (unassemble_only)                  if (unassemble_only)
1369                          return 1;                          return 1;
1370    
1371                  /*  TODO: not CVT?  */                  /*  TODO: not CVT?  */
1372    
1373                  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);
1374                  return 1;                  return 1;
1375          }          }
1376    
# Line 2098  static int fpu_function(struct cpu *cpu, Line 1380  static int fpu_function(struct cpu *cpu,
1380                  int bit;                  int bit;
1381    
1382                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1383                          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],
1384                                fmtname[fmt], cc, fs, ft);
1385                  if (unassemble_only)                  if (unassemble_only)
1386                          return 1;                          return 1;
1387    
# Line 2110  static int fpu_function(struct cpu *cpu, Line 1393  static int fpu_function(struct cpu *cpu,
1393                   *      FCCR:  bits 7..0                   *      FCCR:  bits 7..0
1394                   *      FCSR:  bits 31..25 and 23                   *      FCSR:  bits 31..25 and 23
1395                   */                   */
1396                  cp->fcr[FPU_FCCR] &= ~(1 << cc);                  cp->fcr[MIPS_FPU_FCCR] &= ~(1 << cc);
1397                  if (cond_true)                  if (cond_true)
1398                          cp->fcr[FPU_FCCR] |= (1 << cc);                          cp->fcr[MIPS_FPU_FCCR] |= (1 << cc);
1399    
1400                  if (cc == 0) {                  if (cc == 0) {
1401                          bit = 1 << FCSR_FCC0_SHIFT;                          bit = 1 << MIPS_FCSR_FCC0_SHIFT;
1402                          cp->fcr[FPU_FCSR] &= ~bit;                          cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1403                          if (cond_true)                          if (cond_true)
1404                                  cp->fcr[FPU_FCSR] |= bit;                                  cp->fcr[MIPS_FPU_FCSR] |= bit;
1405                  } else {                  } else {
1406                          bit = 1 << (FCSR_FCC1_SHIFT + cc-1);                          bit = 1 << (MIPS_FCSR_FCC1_SHIFT + cc-1);
1407                          cp->fcr[FPU_FCSR] &= ~bit;                          cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1408                          if (cond_true)                          if (cond_true)
1409                                  cp->fcr[FPU_FCSR] |= bit;                                  cp->fcr[MIPS_FPU_FCSR] |= bit;
1410                  }                  }
1411    
1412                  return 1;                  return 1;
# Line 2132  static int fpu_function(struct cpu *cpu, Line 1415  static int fpu_function(struct cpu *cpu,
1415          /*  cvt.s.fmt: Convert to single floating-point  */          /*  cvt.s.fmt: Convert to single floating-point  */
1416          if ((function & 0x001f003f) == 0x00000020) {          if ((function & 0x001f003f) == 0x00000020) {
1417                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1418                          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);
1419                  if (unassemble_only)                  if (unassemble_only)
1420                          return 1;                          return 1;
1421    
1422                  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);
1423                  return 1;                  return 1;
1424          }          }
1425    
1426          /*  cvt.d.fmt: Convert to double floating-point  */          /*  cvt.d.fmt: Convert to double floating-point  */
1427          if ((function & 0x001f003f) == 0x00000021) {          if ((function & 0x001f003f) == 0x00000021) {
1428                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1429                          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);
1430                  if (unassemble_only)                  if (unassemble_only)
1431                          return 1;                          return 1;
1432    
1433                  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);
1434                  return 1;                  return 1;
1435          }          }
1436    
1437          /*  cvt.w.fmt: Convert to word fixed-point  */          /*  cvt.w.fmt: Convert to word fixed-point  */
1438          if ((function & 0x001f003f) == 0x00000024) {          if ((function & 0x001f003f) == 0x00000024) {
1439                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1440                          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);
1441                  if (unassemble_only)                  if (unassemble_only)
1442                          return 1;                          return 1;
1443    
1444                  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);
1445                  return 1;                  return 1;
1446          }          }
1447    
# Line 2288  void coproc_tlbpr(struct cpu *cpu, int r Line 1571  void coproc_tlbpr(struct cpu *cpu, int r
1571  /*  /*
1572   *  coproc_tlbwri():   *  coproc_tlbwri():
1573   *   *
1574   *  'tlbwr' and 'tlbwi'   *  MIPS TLB write random (tlbwr) and write indexed (tlbwi) instructions.
1575   */   */
1576  void coproc_tlbwri(struct cpu *cpu, int randomflag)  void coproc_tlbwri(struct cpu *cpu, int randomflag)
1577  {  {
1578          struct mips_coproc *cp = cpu->cd.mips.coproc[0];          struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1579          int index, g_bit;          int index, g_bit;
1580          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;  
1581    
1582          if (randomflag) {          if (randomflag) {
1583                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
1584                          index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)                          index = ((cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
1585                              >> R2K3K_RANDOM_SHIFT;                              >> R2K3K_RANDOM_SHIFT) - 1;
1586                  else                          /*  R3000 always has 8 wired entries:  */
1587                            if (index < 8)
1588                                    index = cp->nr_of_tlbs - 1;
1589                            cp->reg[COP0_RANDOM] = index << R2K3K_RANDOM_SHIFT;
1590                    } else {
1591                            cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
1592                                % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
1593                          index = cp->reg[COP0_RANDOM] & RANDOM_MASK;                          index = cp->reg[COP0_RANDOM] & RANDOM_MASK;
1594                    }
1595          } else {          } else {
1596                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1597                          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 1607  void coproc_tlbwri(struct cpu *cpu, int
1607                  return;                  return;
1608          }          }
1609    
1610    
1611  #if 0  #if 0
1612          /*  Debug dump of the previous entry at that index:  */          /*  Debug dump of the previous entry at that index:  */
1613          debug(" old entry at index = %04x", index);          fatal("{ old TLB entry at index %02x:", index);
1614          debug(" mask = %016llx", (long long) cp->tlbs[index].mask);          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1615          debug(" hi = %016llx", (long long) cp->tlbs[index].hi);                  fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1616          debug(" lo0 = %016llx", (long long) cp->tlbs[index].lo0);                  fatal(" lo=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1617          debug(" lo1 = %016llx\n", (long long) cp->tlbs[index].lo1);          } else {
1618                    if (cpu->is_32bit) {
1619                            fatal(" mask=%08"PRIx32,(uint32_t)cp->tlbs[index].mask);
1620                            fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1621                            fatal(" lo0=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1622                            fatal(" lo1=%08"PRIx32, (uint32_t)cp->tlbs[index].lo1);
1623                    } else {
1624                            fatal(" mask=%016"PRIx64, cp->tlbs[index].mask);
1625                            fatal(" hi=%016"PRIx64, cp->tlbs[index].hi);
1626                            fatal(" lo0=%016"PRIx64, cp->tlbs[index].lo0);
1627                            fatal(" lo1=%016"PRIx64, cp->tlbs[index].lo1);
1628                    }
1629            }
1630            fatal(" }\n");
1631  #endif  #endif
1632    
1633          /*  Translation caches must be invalidated:  */          /*
1634             *  Any virtual address translation for the old TLB entry must be
1635             *  invalidated first:
1636             *
1637             *  (Only Valid entries need to be invalidated, and only those that
1638             *  are either Global, or have the same ASID as the new entry will
1639             *  have. No other address translations should be active anyway.)
1640             */
1641    
1642          switch (cpu->cd.mips.cpu_type.mmu_model) {          switch (cpu->cd.mips.cpu_type.mmu_model) {
1643    
1644          case MMU3K:          case MMU3K:
1645                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;
1646                  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?  */  
1647    
1648                  /*  if (cp->tlbs[index].lo0 & ENTRYLO_V)  */                  if (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_V &&
1649                          invalidate_translation_caches(cpu, 0, oldvaddr, 0, 0);                      (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_G ||
1650                        (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK) ==
1651                        (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK) ))
1652                            cpu->invalidate_translation_caches(cpu, oldvaddr,
1653                                INVALIDATE_VADDR);
1654                  break;                  break;
1655          default:  
1656                  if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {          default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1657                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;
1658                          /*  44 addressable bits:  */                          /*  44 addressable bits:  */
1659                          if (oldvaddr & 0x80000000000ULL)                          if (oldvaddr & 0x80000000000ULL)
1660                                  oldvaddr |= 0xfffff00000000000ULL;                                  oldvaddr |= 0xfffff00000000000ULL;
1661                    } else if (cpu->is_32bit) {
1662                            /*  MIPS32 etc.:  */
1663                            oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1664                            oldvaddr = (int32_t)oldvaddr;
1665                  } else {                  } else {
1666                          /*  Assume MMU4K  */                          /*  Assume MMU4K  */
1667                          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 1670  void coproc_tlbwri(struct cpu *cpu, int
1670                                  oldvaddr |= 0xffffff0000000000ULL;                                  oldvaddr |= 0xffffff0000000000ULL;
1671                  }                  }
1672    
1673    #if 0
1674                    /*  TODO: FIX THIS! It shouldn't be needed!  */
1675                    cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL);
1676    #else
1677                  /*                  /*
                  *  Both pages:  
                  *  
1678                   *  TODO: non-4KB page sizes!                   *  TODO: non-4KB page sizes!
1679                   */                   */
1680                  invalidate_translation_caches(                  if (cp->tlbs[index].lo0 & ENTRYLO_V)
1681                      cpu, 0, oldvaddr & ~0x1fff, 0, 0);                          cpu->invalidate_translation_caches(cpu, oldvaddr,
1682                  invalidate_translation_caches(                              INVALIDATE_VADDR);
1683                      cpu, 0, (oldvaddr & ~0x1fff) | 0x1000, 0, 0);                  if (cp->tlbs[index].lo1 & ENTRYLO_V)
1684                            cpu->invalidate_translation_caches(cpu, oldvaddr|0x1000,
1685                                INVALIDATE_VADDR);
1686    #endif
1687          }          }
1688    
1689    #if 0
1690          /*          /*
1691           *  Check for duplicate entries.  (There should not be two mappings           *  Check for duplicate entries.  (There should not be two mappings
1692           *  from one virtual address to physical addresses.)           *  from one virtual address to physical addresses.)
# Line 2402  void coproc_tlbwri(struct cpu *cpu, int Line 1698  void coproc_tlbwri(struct cpu *cpu, int
1698          if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&          if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&
1699              cpu->cd.mips.cpu_type.rev != MIPS_R4100) {              cpu->cd.mips.cpu_type.rev != MIPS_R4100) {
1700                  uint64_t vaddr1, vaddr2;                  uint64_t vaddr1, vaddr2;
1701                  int i, asid;                  int i;
1702                    unsigned int asid;
1703    
1704                  vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K;                  vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K;
1705                  asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;                  asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
# Line 2427  void coproc_tlbwri(struct cpu *cpu, int Line 1724  void coproc_tlbwri(struct cpu *cpu, int
1724                                      (long long)vaddr1, asid, i);                                      (long long)vaddr1, asid, i);
1725                  }                  }
1726          }          }
1727    #endif
1728    
1729          /*  Write the new entry:  */          /*  Write the new entry:  */
1730    
1731          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1732                  uint64_t vaddr, paddr;                  uint32_t vaddr, paddr;
1733                  int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;                  int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;
1734                  unsigned char *memblock = NULL;                  unsigned char *memblock = NULL;
1735    
# Line 2442  void coproc_tlbwri(struct cpu *cpu, int Line 1739  void coproc_tlbwri(struct cpu *cpu, int
1739                  vaddr =  cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;                  vaddr =  cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
1740                  paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;                  paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;
1741    
1742                  /*  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);  
1743    
1744                  if (memblock != NULL &&                  /*  Invalidate any code translation, if we are writing
1745                      cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) {                      a Dirty page to the TLB:  */
1746                          memblock += (paddr & ((1 << BITS_PER_PAGETABLE) - 1));                  if (wf) {
1747                            cpu->invalidate_code_translation(cpu, paddr,
1748                                INVALIDATE_PADDR);
1749                    }
1750    
1751                          /*                  if (cp->reg[COP0_STATUS] & MIPS1_ISOL_CACHES) {
1752                           *  TODO: Hahaha, this is even uglier than the thing                          fatal("Wow! Interesting case; tlbw* while caches"
1753                           *  above. Some OSes seem to map code pages read/write,                              " are isolated. TODO\n");
1754                           *  which causes the bintrans cache to be invalidated                          /*  Don't update the translation table in this
1755                           *  even when it doesn't have to be.                              case...  */
1756                           */                          exit(1);
1757  /*                      if (vaddr < 0x10000000)  */                  }
                                 wf = 0;  
1758    
1759                    /*  If we have a memblock (host page) for the physical
1760                        page, then add a translation for it immediately:  */
1761                    if (memblock != NULL &&
1762                        cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V)
1763                          cpu->update_translation_table(cpu, vaddr, memblock,                          cpu->update_translation_table(cpu, vaddr, memblock,
1764                              wf, paddr);                              wf, paddr);
                 }  
1765          } else {          } else {
1766                  /*  R4000:  */                  /*  R4000 etc.:  */
1767                  g_bit = (cp->reg[COP0_ENTRYLO0] &                  unsigned char *memblock = NULL;
1768                      cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;                  int pfn_shift = 12, vpn_shift = 12;
1769                    int wf0, wf1, mask;
1770                    uint64_t vaddr0, vaddr1, paddr0, paddr1, ptmp;
1771    
1772                  cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];                  cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];
1773                  cp->tlbs[index].hi   = cp->reg[COP0_ENTRYHI];                  cp->tlbs[index].hi   = cp->reg[COP0_ENTRYHI];
1774                  cp->tlbs[index].lo1  = cp->reg[COP0_ENTRYLO1];                  cp->tlbs[index].lo1  = cp->reg[COP0_ENTRYLO1];
1775                  cp->tlbs[index].lo0  = cp->reg[COP0_ENTRYLO0];                  cp->tlbs[index].lo0  = cp->reg[COP0_ENTRYLO0];
1776    
1777                    wf0 = cp->tlbs[index].lo0 & ENTRYLO_D;
1778                    wf1 = cp->tlbs[index].lo1 & ENTRYLO_D;
1779    
1780                    mask = cp->reg[COP0_PAGEMASK];
1781                    if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1782                            pfn_shift = 10;
1783                            mask |= 0x07ff;
1784                    } else {
1785                            mask |= 0x1fff;
1786                    }
1787                    switch (mask) {
1788                    case 0x00007ff:
1789                            if (cp->tlbs[index].lo0 & ENTRYLO_V ||
1790                                cp->tlbs[index].lo1 & ENTRYLO_V) {
1791                                    fatal("1KB pages don't work with dyntrans.\n");
1792                                    exit(1);
1793                            }
1794                            vpn_shift = 10;
1795                            break;
1796                    case 0x0001fff: break;
1797                    case 0x0007fff: vpn_shift = 14; break;
1798                    case 0x001ffff: vpn_shift = 16; break;
1799                    case 0x007ffff: vpn_shift = 18; break;
1800                    case 0x01fffff: vpn_shift = 20; break;
1801                    case 0x07fffff: vpn_shift = 22; break;
1802                    case 0x1ffffff: vpn_shift = 24; break;
1803                    case 0x7ffffff: vpn_shift = 26; break;
1804                    default:fatal("Unimplemented MASK = 0x%016x\n", mask);
1805                            exit(1);
1806                    }
1807    
1808                    paddr0 = ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK)
1809                        >> ENTRYLO_PFN_SHIFT) << pfn_shift;
1810                    paddr1 = ((cp->tlbs[index].lo1 & ENTRYLO_PFN_MASK)
1811                        >> ENTRYLO_PFN_SHIFT) << pfn_shift;
1812    
1813                    if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1814                            vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;
1815                            /*  44 addressable bits:  */
1816                            if (vaddr0 & 0x80000000000ULL)
1817                                    vaddr0 |= 0xfffff00000000000ULL;
1818                    } else if (cpu->is_32bit) {
1819                            /*  MIPS32 etc.:  */
1820                            vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1821                            vaddr0 = (int32_t)vaddr0;
1822                    } else {
1823                            /*  Assume MMU4K  */
1824                            vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1825                            /*  40 addressable bits:  */
1826                            if (vaddr0 & 0x8000000000ULL)
1827                                    vaddr0 |= 0xffffff0000000000ULL;
1828                    }
1829    
1830                    vaddr1 = vaddr0 | (1 << vpn_shift);
1831    
1832                    g_bit = (cp->reg[COP0_ENTRYLO0] &
1833                        cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;
1834    
1835                  if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {                  if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1836                          /*  NOTE: The VR4131 (and possibly others) don't have                          /*  NOTE: The VR4131 (and possibly others) don't have
1837                              a Global bit in entryhi  */                              a Global bit in entryhi  */
# Line 2484  void coproc_tlbwri(struct cpu *cpu, int Line 1844  void coproc_tlbwri(struct cpu *cpu, int
1844                          if (g_bit)                          if (g_bit)
1845                                  cp->tlbs[index].hi |= TLB_G;                                  cp->tlbs[index].hi |= TLB_G;
1846                  }                  }
         }  
1847    
1848          if (randomflag) {                  /*
1849                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {                   *  Invalidate any code translations, if we are writing Dirty
1850                          cp->reg[COP0_RANDOM] =                   *  pages to the TLB:  (TODO: 4KB hardcoded... ugly)
1851                              ((random() % (cp->nr_of_tlbs - 8)) + 8)                   */
1852                              << R2K3K_RANDOM_SHIFT;                  for (ptmp = 0; ptmp < (1 << pfn_shift); ptmp += 0x1000) {
1853                  } else {                          if (wf0)
1854                          cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()                                  cpu->invalidate_code_translation(cpu,
1855                              % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));                                      paddr0 + ptmp, INVALIDATE_PADDR);
1856                            if (wf1)
1857                                    cpu->invalidate_code_translation(cpu,
1858                                        paddr1 + ptmp, INVALIDATE_PADDR);
1859                  }                  }
         }  
 }  
1860    
1861                    /*
1862  /*                   *  If we have a memblock (host page) for the physical page,
1863   *  coproc_rfe():                   *  then add a translation for it immediately, to save some
1864   *                   *  time. (It would otherwise be added later on anyway,
1865   *  Return from exception. (R3000 etc.)                   *  because of a translation miss.)
1866   */                   *
1867  void coproc_rfe(struct cpu *cpu)                   *  NOTE/TODO: This is only for 4KB pages so far. It would
1868  {                   *             be too expensive to add e.g. 16MB pages like
1869          int oldmode;                   *             this.
1870                     */
1871          oldmode = cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_SR_KU_CUR;                  memblock = memory_paddr_to_hostaddr(cpu->mem, paddr0, 0);
1872                    if (memblock != NULL && cp->reg[COP0_ENTRYLO0] & ENTRYLO_V)
1873          cpu->cd.mips.coproc[0]->reg[COP0_STATUS] =                          cpu->update_translation_table(cpu, vaddr0, memblock,
1874              (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) |                              wf0, paddr0);
1875              ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 0x3c) >> 2);                  memblock = memory_paddr_to_hostaddr(cpu->mem, paddr1, 0);
1876                    if (memblock != NULL && cp->reg[COP0_ENTRYLO1] & ENTRYLO_V)
1877          /*  Changing from kernel to user mode? Then this is necessary:  */                          cpu->update_translation_table(cpu, vaddr1, memblock,
1878          if (!oldmode &&                              wf1, paddr1);
1879              (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &          }
             MIPS1_SR_KU_CUR))  
                 invalidate_translation_caches(cpu, 0, 0, 1, 0);  
1880  }  }
1881    
1882    
# Line 2529  void coproc_rfe(struct cpu *cpu) Line 1887  void coproc_rfe(struct cpu *cpu)
1887   */   */
1888  void coproc_eret(struct cpu *cpu)  void coproc_eret(struct cpu *cpu)
1889  {  {
         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;  
   
1890          if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {          if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {
1891                  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];  
1892                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;
1893          } else {          } else {
1894                  cpu->pc = cpu->cd.mips.pc_last =                  cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_EPC];
1895                      cpu->cd.mips.coproc[0]->reg[COP0_EPC];                  cpu->delay_slot = 0;
                 cpu->cd.mips.delay_slot = 0;  
1896                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;
1897          }          }
1898    
1899          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  
1900  }  }
1901    
1902    
# Line 2597  void coproc_function(struct cpu *cpu, st Line 1926  void coproc_function(struct cpu *cpu, st
1926                  return;                  return;
1927          }          }
1928    
 #if 0  
1929          /*  No FPU?  */          /*  No FPU?  */
1930          if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {          if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {
1931                  mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);                  mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);
1932                  return;                  return;
1933          }          }
 #endif  
1934    
1935          /*  For quick reference:  */          /*  For quick reference:  */
1936          copz = (function >> 21) & 31;          copz = (function >> 21) & 31;
# Line 2618  void coproc_function(struct cpu *cpu, st Line 1945  void coproc_function(struct cpu *cpu, st
1945                          if (cpnr == 0)                          if (cpnr == 0)
1946                                  debug("%s", cop0_names[rd]);                                  debug("%s", cop0_names[rd]);
1947                          else                          else
1948                                  debug("cpreg%i", rd);                                  debug("r%i", rd);
1949                          if (function & 7)                          if (function & 7)
1950                                  debug(",%i", (int)(function & 7));                                  debug(",%i", (int)(function & 7));
1951                          debug("\n");                          debug("\n");
# Line 2644  void coproc_function(struct cpu *cpu, st Line 1971  void coproc_function(struct cpu *cpu, st
1971                          if (cpnr == 0)                          if (cpnr == 0)
1972                                  debug("%s", cop0_names[rd]);                                  debug("%s", cop0_names[rd]);
1973                          else                          else
1974                                  debug("cpreg%i", rd);                                  debug("r%i", rd);
1975                          if (function & 7)                          if (function & 7)
1976                                  debug(",%i", (int)(function & 7));                                  debug(",%i", (int)(function & 7));
1977                          debug("\n");                          debug("\n");
# Line 2673  void coproc_function(struct cpu *cpu, st Line 2000  void coproc_function(struct cpu *cpu, st
2000                                      regnames[rt], fs);                                      regnames[rt], fs);
2001                                  return;                                  return;
2002                          }                          }
2003                          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;  
2004                          /*  TODO: implement delay for gpr[rt]                          /*  TODO: implement delay for gpr[rt]
2005                              (for MIPS I,II,III only)  */                              (for MIPS I,II,III only)  */
2006                          return;                          return;
# Line 2707  void coproc_function(struct cpu *cpu, st Line 2032  void coproc_function(struct cpu *cpu, st
2032                                              on status bits!  */                                              on status bits!  */
2033    
2034                                          switch (fs) {                                          switch (fs) {
2035                                          case FPU_FCCR:                                          case MIPS_FPU_FCCR:
2036                                                  cp->fcr[FPU_FCSR] =                                                  cp->fcr[MIPS_FPU_FCSR] =
2037                                                      (cp->fcr[FPU_FCSR] &                                                      (cp->fcr[MIPS_FPU_FCSR] &
2038                                                      0x017fffffULL) | ((tmp & 1)                                                      0x017fffffULL) | ((tmp & 1)
2039                                                      << FCSR_FCC0_SHIFT)                                                      << MIPS_FCSR_FCC0_SHIFT)
2040                                                      | (((tmp & 0xfe) >> 1) <<                                                      | (((tmp & 0xfe) >> 1) <<
2041                                                      FCSR_FCC1_SHIFT);                                                      MIPS_FCSR_FCC1_SHIFT);
2042                                                  break;                                                  break;
2043                                          case FPU_FCSR:                                          case MIPS_FPU_FCSR:
2044                                                  cp->fcr[FPU_FCCR] =                                                  cp->fcr[MIPS_FPU_FCCR] =
2045                                                      (cp->fcr[FPU_FCCR] &                                                      (cp->fcr[MIPS_FPU_FCCR] &
2046                                                      0xffffff00ULL) | ((tmp >>                                                      0xffffff00ULL) | ((tmp >>
2047                                                      FCSR_FCC0_SHIFT) & 1) |                                                      MIPS_FCSR_FCC0_SHIFT) & 1) |
2048                                                      (((tmp >> FCSR_FCC1_SHIFT)                                                      (((tmp >>
2049                                                        MIPS_FCSR_FCC1_SHIFT)
2050                                                      & 0x7f) << 1);                                                      & 0x7f) << 1);
2051                                                  break;                                                  break;
2052                                          default:                                          default:
# Line 2744  void coproc_function(struct cpu *cpu, st Line 2070  void coproc_function(struct cpu *cpu, st
2070                          return;                          return;
2071          }          }
2072    
         /*  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;  
         }  
   
2073    
2074          /*  Ugly R5900 hacks:  */          /*  Ugly R5900 hacks:  */
2075          if ((function & 0xfffff) == 0x38) {             /*  ei  */          if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) {
2076                  if (unassemble_only) {                  if ((function & 0xfffff) == COP0_EI) {
2077                          debug("ei\n");                          if (unassemble_only) {
2078                                    debug("ei\n");
2079                                    return;
2080                            }
2081                            cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |=
2082                                R5900_STATUS_EIE;
2083                          return;                          return;
2084                  }                  }
                 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= R5900_STATUS_EIE;  
                 return;  
         }  
2085    
2086          if ((function & 0xfffff) == 0x39) {             /*  di  */                  if ((function & 0xfffff) == COP0_DI) {
2087                  if (unassemble_only) {                          if (unassemble_only) {
2088                          debug("di\n");                                  debug("di\n");
2089                                    return;
2090                            }
2091                            cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &=
2092                                ~R5900_STATUS_EIE;
2093                          return;                          return;
2094                  }                  }
                 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~R5900_STATUS_EIE;  
                 return;  
2095          }          }
2096    
2097          co_bit = (function >> 25) & 1;          co_bit = (function >> 25) & 1;
# Line 2826  void coproc_function(struct cpu *cpu, st Line 2132  void coproc_function(struct cpu *cpu, st
2132                                              (long long)cp->reg[COP0_ENTRYLO0]);                                              (long long)cp->reg[COP0_ENTRYLO0]);
2133                                          debug(", lo1=%016llx\n",                                          debug(", lo1=%016llx\n",
2134                                              (long long)cp->reg[COP0_ENTRYLO1]);                                              (long long)cp->reg[COP0_ENTRYLO1]);
2135                                            return;
2136                                  }                                  }
2137                                  coproc_tlbwri(cpu, op == COP0_TLBWR);                                  coproc_tlbwri(cpu, op == COP0_TLBWR);
2138                                  return;                                  return;
# Line 2843  void coproc_function(struct cpu *cpu, st Line 2150  void coproc_function(struct cpu *cpu, st
2150                                          debug("rfe\n");                                          debug("rfe\n");
2151                                          return;                                          return;
2152                                  }                                  }
2153                                  coproc_rfe(cpu);                                  fatal("Internal error (rfe): Should be "
2154                                  return;                                      "implemented in dyntrans instead.\n");
2155                                    exit(1);
2156                          case COP0_ERET: /*  R4000: Return from exception  */                          case COP0_ERET: /*  R4000: Return from exception  */
2157                                  if (unassemble_only) {                                  if (unassemble_only) {
2158                                          debug("eret\n");                                          debug("eret\n");
2159                                          return;                                          return;
2160                                  }                                  }
2161                                  coproc_eret(cpu);                                  fatal("Internal error (eret): Should be "
2162                                        "implemented in dyntrans instead.\n");
2163                                    exit(1);
2164                            case COP0_DERET:
2165                                    if (unassemble_only) {
2166                                            debug("deret\n");
2167                                            return;
2168                                    }
2169                                    /*
2170                                     *  According to the MIPS64 manual, deret
2171                                     *  loads PC from the DEPC cop0 register, and
2172                                     *  jumps there immediately. No delay slot.
2173                                     *
2174                                     *  TODO: This instruction is only available
2175                                     *  if the processor is in debug mode. (What
2176                                     *  does that mean?) TODO: This instruction
2177                                     *  is undefined in a delay slot.
2178                                     */
2179                                    cpu->pc = cp->reg[COP0_DEPC];
2180                                    cpu->delay_slot = 0;
2181                                    cp->reg[COP0_STATUS] &= ~STATUS_EXL;
2182                                  return;                                  return;
2183                          case COP0_STANDBY:                          case COP0_STANDBY:
2184                                  if (unassemble_only) {                                  if (unassemble_only) {
# Line 2907  void coproc_function(struct cpu *cpu, st Line 2235  void coproc_function(struct cpu *cpu, st
2235                  return;                  return;
2236          }          }
2237    
2238          fatal("cpu%i: UNIMPLEMENTED coproc%i function %08lx "          fatal("cpu%i: UNIMPLEMENTED coproc%i function %08"PRIx32" "
2239              "(pc = %016llx)\n", cpu->cpu_id, cp->coproc_nr, function,              "(pc = %016"PRIx64")\n", cpu->cpu_id, cp->coproc_nr,
2240              (long long)cpu->cd.mips.pc_last);              (uint32_t)function, cpu->pc);
2241  #if 1  
         single_step = 1;  
 #else  
2242          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  
2243  }  }
2244    
2245  #endif  /*  ENABLE_MIPS  */  #endif  /*  ENABLE_MIPS  */

Legend:
Removed from v.18  
changed lines
  Added in v.28

  ViewVC Help
Powered by ViewVC 1.1.26