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

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

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

revision 14 by dpavlin, Mon Oct 8 16:18:51 2007 UTC revision 26 by dpavlin, Mon Oct 8 16:20:10 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2005  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2006  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: cpu_mips_coproc.c,v 1.2 2005/09/11 10:37:37 debug Exp $   *  $Id: cpu_mips_coproc.c,v 1.37 2006/06/25 02:46:07 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;
80  #else  
81          const int m16 = 0;          /*  Generic case for MIPS32/64:  */
82  #endif          if (cpu->cd.mips.cpu_type.isa_level == 32 ||
83          int cpu_type, IB, DB, SB, IC, DC, SC, IA, DA;              cpu->cd.mips.cpu_type.isa_level == 64) {
84                    /*  According to the MIPS64 (5K) User's Manual:  */
85                    c->reg[COP0_CONFIG] =
86                          (   (uint32_t)1 << 31)/*  Config 1 present bit  */
87                        | (   0 << 20)      /*  ISD:  instruction scheduling
88                                                disable (=1)  */
89                        | (   0 << 17)      /*  DID:  dual issue disable  */
90                        | (   0 << 16)      /*  BM:   burst mode  */
91                        | ((cpu->byte_order == EMUL_BIG_ENDIAN? 1 : 0) << 15)
92                                            /*  endian mode  */
93                        | ((cpu->cd.mips.cpu_type.isa_level == 64? 2 : 0) << 13)
94                                            /*  0=MIPS32, 1=64S, 2=64  */
95                        | (   0 << 10)      /*  Architecture revision  */
96                        | (   1 <<  7)      /*  MMU type: 1=TLB, 3=FMT  */
97                        | (   2 <<  0)      /*  kseg0 cache coherency algorithm  */
98                        ;
99                    /*  Config select 1: caches etc. TODO: Don't use
100                            cpu->machine for this stuff!  */
101                    IB = cpu->machine->cache_picache_linesize - 1;
102                    IB = IB < 0? 0 : (IB > 7? 7 : IB);
103                    DB = cpu->machine->cache_pdcache_linesize - 1;
104                    DB = DB < 0? 0 : (DB > 7? 7 : DB);
105                    IC = cpu->machine->cache_picache -
106                        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          /*  Default values:  */                  return;
127          c->reg[COP0_CONFIG] =          }
               (   0 << 31)      /*  config1 present  */  
             | (0x00 << 16)      /*  implementation dependant  */  
             | ((cpu->byte_order==EMUL_BIG_ENDIAN? 1 : 0) << 15)  
                                 /*  endian mode  */  
             | (   2 << 13)      /*  0 = MIPS32,  
                                     1 = MIPS64 with 32-bit segments,  
                                     2 = MIPS64 with all segments,  
                                     3 = reserved  */  
             | (   0 << 10)      /*  architecture revision level,  
                                     0 = "Revision 1", other  
                                     values are reserved  */  
             | (   1 <<  7)      /*  MMU type:  0 = none,  
                                     1 = Standard TLB,  
                                     2 = Standard BAT,  
                                     3 = fixed mapping, 4-7=reserved  */  
             | (   0 <<  0)      /*  kseg0 coherency algorithm  
                                 (TODO)  */  
             ;  
   
         cpu_type = cpu->cd.mips.cpu_type.rev & 0xff;  
   
         /*  AU1x00 are treated as 4Kc (MIPS32 cores):  */  
         if ((cpu->cd.mips.cpu_type.rev & 0xffff) == 0x0301)  
                 cpu_type = MIPS_4Kc;  
128    
129          switch (cpu_type) {          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():
  */  
 static void old_update_translation_table(struct cpu *cpu, uint64_t vaddr_page,  
         unsigned char *host_page, int writeflag, uint64_t paddr_page)  
 {  
         int a, b, index;  
         struct vth32_table *tbl1;  
         void *p_r, *p_w;  
         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;  
         }  
   
         a = (vaddr_page >> 22) & 0x3ff;  
         b = (vaddr_page >> 12) & 0x3ff;  
         index = (vaddr_page >> 12) & 0xfffff;  
   
         /*  printf("vaddr = %08x, a = %03x, b = %03x\n",  
             (int)vaddr_page,a, b);  */  
   
         tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];  
         /*  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;  
                         }  
                 }  
                 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;  
                 }  
         } else {  
                 if ((vaddr >> 32) != 0) {  
                         fatal("invalidate_table_entry(): vaddr = 0x%016llx\n",  
                             (long long)vaddr);  
                         return;  
                 }  
         }  
   
         a = (vaddr >> 22) & 0x3ff;  
         b = (vaddr >> 12) & 0x3ff;  
         index = (vaddr >> 12) & 0xfffff;  
   
         /*  printf("vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b);  */  
   
         tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];  
         /*  printf("tbl1 = %p\n", tbl1);  */  
         p_r = tbl1->haddr_entry[b*2];  
         p_w = tbl1->haddr_entry[b*2+1];  
         p_paddr = tbl1->paddr_entry[b];  
         tbl1->bintrans_chunks[b] = NULL;  
         /*  printf("B:  p_r=%p p_w=%p\n", p_r,p_w);  */  
         cpu->cd.mips.host_load_orig[index] = NULL;  
         cpu->cd.mips.host_store_orig[index] = NULL;  
         if (p_r != NULL || p_paddr != 0) {  
                 /*  printf("Found a mapping, "  
                     "vaddr = %08x, a = %03x, b = %03x\n", (int)vaddr,a, b);  */  
                 tbl1->haddr_entry[b*2] = NULL;  
                 tbl1->haddr_entry[b*2+1] = NULL;  
                 tbl1->paddr_entry[b] = 0;  
                 tbl1->refcount --;  
                 if (tbl1->refcount == 0) {  
                         cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a] =  
                             cpu->cd.mips.vaddr_to_hostaddr_nulltable;  
                         /*  "free" tbl1:  */  
                         tbl1->next_free = cpu->cd.mips.next_free_vth_table;  
                         cpu->cd.mips.next_free_vth_table = tbl1;  
                 }  
         }  
 }  
   
   
 /*  
  *  clear_all_chunks_from_all_tables():  
  */  
 void clear_all_chunks_from_all_tables(struct cpu *cpu)  
 {  
         int a, b;  
         struct vth32_table *tbl1;  
   
         if (!cpu->machine->old_bintrans_enable) {  
                 printf("clear_all_chunks_from_all_tables(): New: TODO\n");  
                 return;  
         }  
   
         for (a=0; a<0x400; a++) {  
                 tbl1 = cpu->cd.mips.vaddr_to_hostaddr_table0_kernel[a];  
                 if (tbl1 != cpu->cd.mips.vaddr_to_hostaddr_nulltable) {  
                         for (b=0; b<0x400; b++) {  
                                 int index;  
   
                                 tbl1->haddr_entry[b*2] = NULL;  
                                 tbl1->haddr_entry[b*2+1] = NULL;  
                                 tbl1->paddr_entry[b] = 0;  
                                 tbl1->bintrans_chunks[b] = NULL;  
   
                                 if (cpu->cd.mips.host_store ==  
                                     cpu->cd.mips.host_store_orig) {  
                                         index = (a << 10) + b;  
                                         cpu->cd.mips.host_load[index] = NULL;  
                                         cpu->cd.mips.host_store[index] = NULL;  
                                 }  
                         }  
                 }  
         }  
 }  
   
   
 /*  
  *  mips_invalidate_translation_caches_paddr():  
513   *   *
514   *  Invalidate based on physical address.   *  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  void mips_invalidate_translation_caches_paddr(struct cpu *cpu,   *  translation is invalidated.
         uint64_t paddr, int flags)  
 {  
         paddr &= ~0xfff;  
   
         if (cpu->machine->bintrans_enable) {  
 #if 1  
                 int i;  
                 uint64_t tlb_paddr0, tlb_paddr1;  
                 uint64_t tlb_vaddr;  
                 uint64_t p, p2;  
   
                 switch (cpu->cd.mips.cpu_type.mmu_model) {  
                 case MMU3K:  
                         for (i=0; i<64; i++) {  
                                 tlb_paddr0 = cpu->cd.mips.coproc[0]->  
                                     tlbs[i].lo0 & R2K3K_ENTRYLO_PFN_MASK;  
                                 tlb_vaddr = cpu->cd.mips.coproc[0]->  
                                     tlbs[i].hi & R2K3K_ENTRYHI_VPN_MASK;  
                                 tlb_vaddr = (int64_t)(int32_t)tlb_vaddr;  
                                 if ((cpu->cd.mips.coproc[0]->tlbs[i].lo0 &  
                                     R2K3K_ENTRYLO_V) && tlb_paddr0 == paddr)  
                                         invalidate_table_entry(cpu, tlb_vaddr);  
                         }  
                         break;  
                 default:  
                         for (i=0; i<cpu->cd.mips.coproc[0]->nr_of_tlbs; i++) {  
                                 int psize = 12;  
                                 int or_pmask = 0x1fff;  
                                 int phys_shift = 12;  
   
                                 if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {  
                                         or_pmask = 0x7ff;  
                                         phys_shift = 10;  
                                 }  
                                 switch (cpu->cd.mips.coproc[0]->  
                                     tlbs[i].mask | or_pmask) {  
                                 case 0x000007ff:        psize = 10; break;  
                                 case 0x00001fff:        psize = 12; break;  
                                 case 0x00007fff:        psize = 14; break;  
                                 case 0x0001ffff:        psize = 16; break;  
                                 case 0x0007ffff:        psize = 18; break;  
                                 case 0x001fffff:        psize = 20; break;  
                                 case 0x007fffff:        psize = 22; break;  
                                 case 0x01ffffff:        psize = 24; break;  
                                 case 0x07ffffff:        psize = 26; break;  
                                 default:  
                                         printf("invalidate_translation_caches"  
                                             "_paddr(): bad pagemask?\n");  
                                 }  
                                 tlb_paddr0 = (cpu->cd.mips.coproc[0]->tlbs[i].  
                                     lo0 & ENTRYLO_PFN_MASK)>>ENTRYLO_PFN_SHIFT;  
                                 tlb_paddr1 = (cpu->cd.mips.coproc[0]->tlbs[i].  
                                     lo1 & ENTRYLO_PFN_MASK)>>ENTRYLO_PFN_SHIFT;  
                                 tlb_paddr0 <<= phys_shift;  
                                 tlb_paddr1 <<= phys_shift;  
                                 if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {  
                                         tlb_vaddr = cpu->cd.mips.coproc[0]->  
                                             tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;  
                                         if (tlb_vaddr & ((int64_t)1 << 43))  
                                                 tlb_vaddr |=  
                                                     0xfffff00000000000ULL;  
                                 } else {  
                                         tlb_vaddr = cpu->cd.mips.coproc[0]->  
                                             tlbs[i].hi & ENTRYHI_VPN2_MASK;  
                                         if (tlb_vaddr & ((int64_t)1 << 39))  
                                                 tlb_vaddr |=  
                                                     0xffffff0000000000ULL;  
                                 }  
                                 if ((cpu->cd.mips.coproc[0]->tlbs[i].lo0 &  
                                     ENTRYLO_V) && paddr >= tlb_paddr0 &&  
                                     paddr < tlb_paddr0 + (1<<psize)) {  
                                         p2 = 1 << psize;  
                                         for (p=0; p<p2; p+=4096)  
                                                 invalidate_table_entry(cpu,  
                                                     tlb_vaddr + p);  
                                 }  
                                 if ((cpu->cd.mips.coproc[0]->tlbs[i].lo1 &  
                                     ENTRYLO_V) && paddr >= tlb_paddr1 &&  
                                     paddr < tlb_paddr1 + (1<<psize)) {  
                                         p2 = 1 << psize;  
                                         for (p=0; p<p2; p+=4096)  
                                                 invalidate_table_entry(cpu,  
                                                     tlb_vaddr + p +  
                                                     (1 << psize));  
                                 }  
                         }  
                 }  
 #endif  
   
                 if (paddr < 0x20000000) {  
                         invalidate_table_entry(cpu, 0xffffffff80000000ULL  
                             + paddr);  
                         invalidate_table_entry(cpu, 0xffffffffa0000000ULL  
                             + paddr);  
                 }  
         }  
   
 #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():  
517   *   *
518   *  This is necessary for every change to the TLB, and when the ASID is changed,   *  Note: In the R3000 case, the asid argument is shifted 6 bits.
  *  so that for example user-space addresses are not cached when they should  
  *  not be.  
519   */   */
520  static void invalidate_translation_caches(struct cpu *cpu,  static void invalidate_asid(struct cpu *cpu, int asid)
         int all, uint64_t vaddr, int kernelspace, int old_asid_to_invalidate)  
521  {  {
522          int i;          struct mips_coproc *cp = cpu->cd.mips.coproc[0];
523            int i, ntlbs = cp->nr_of_tlbs;
524          /*  printf("inval(all=%i, kernel=%i, addr=%016llx)\n",          struct mips_tlb *tlb = cp->tlbs;
             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.  */  
525    
526                                  invalidate_table_entry(cpu, tlb_vaddr);          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
527                                  invalidate_table_entry(cpu, tlb_vaddr |                  for (i=0; i<ntlbs; i++)
528                                      (1 << psize));                          if ((tlb[i].hi & R2K3K_ENTRYHI_ASID_MASK) == asid
529                                && (tlb[i].lo0 & R2K3K_ENTRYLO_V)
530                                && !(tlb[i].lo0 & R2K3K_ENTRYLO_G)) {
531                                    cpu->invalidate_translation_caches(cpu,
532                                        tlb[i].hi & R2K3K_ENTRYHI_VPN_MASK,
533                                        INVALIDATE_VADDR);
534                          }                          }
535                  }          } else {
536          } else                  /*  TODO: Implement support for other.  */
537                  invalidate_table_entry(cpu, vaddr);                  cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL);
538            }
 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  
539  }  }
540    
541    
# Line 1016  void coproc_register_read(struct cpu *cp Line 557  void coproc_register_read(struct cpu *cp
557          if (cp->coproc_nr==0 && reg_nr==COP0_PAGEMASK)  unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_PAGEMASK)  unimpl = 0;
558          if (cp->coproc_nr==0 && reg_nr==COP0_WIRED)     unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_WIRED)     unimpl = 0;
559          if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR)  unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR)  unimpl = 0;
560          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;  
         }  
561          if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI)   unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI)   unimpl = 0;
562          if (cp->coproc_nr==0 && reg_nr==COP0_COMPARE)   unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_COMPARE)   unimpl = 0;
563          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 639  void coproc_register_write(struct cpu *c
639                              (tmp & 0xff)!=0) {                              (tmp & 0xff)!=0) {
640                                  /*  char *symbol;                                  /*  char *symbol;
641                                      uint64_t offset;                                      uint64_t offset;
642                                      symbol = get_symbol_name(                                      symbol = get_symbol_name(cpu->pc, &offset);
                                     cpu->cd.mips.pc_last, &offset);  
643                                      fatal("YO! pc = 0x%08llx <%s> "                                      fatal("YO! pc = 0x%08llx <%s> "
644                                      "lo=%016llx\n", (long long)                                      "lo=%016llx\n", (long long)
645                                      cpu->cd.mips.pc_last, symbol? symbol :                                      cpu->pc, symbol? symbol :
646                                      "no symbol", (long long)tmp); */                                      "no symbol", (long long)tmp); */
647                                  tmp &= (R2K3K_ENTRYLO_PFN_MASK |                                  tmp &= (R2K3K_ENTRYLO_PFN_MASK |
648                                      R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |                                      R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |
# Line 1191  void coproc_register_write(struct cpu *c Line 708  void coproc_register_write(struct cpu *c
708                          unimpl = 0;                          unimpl = 0;
709                          break;                          break;
710                  case COP0_COUNT:                  case COP0_COUNT:
711                          if (tmp != (int64_t)(int32_t)tmp)                          if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
712                                  fatal("WARNING: trying to write a 64-bit value"                                  fatal("WARNING: trying to write a 64-bit value"
713                                      " to the COUNT register!\n");                                      " to the COUNT register!\n");
714                          tmp = (int64_t)(int32_t)tmp;                          tmp = (int64_t)(int32_t)tmp;
# Line 1201  void coproc_register_write(struct cpu *c Line 718  void coproc_register_write(struct cpu *c
718                          /*  Clear the timer interrupt bit (bit 7):  */                          /*  Clear the timer interrupt bit (bit 7):  */
719                          cpu->cd.mips.compare_register_set = 1;                          cpu->cd.mips.compare_register_set = 1;
720                          mips_cpu_interrupt_ack(cpu, 7);                          mips_cpu_interrupt_ack(cpu, 7);
721                          if (tmp != (int64_t)(int32_t)tmp)                          if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
722                                  fatal("WARNING: trying to write a 64-bit value"                                  fatal("WARNING: trying to write a 64-bit value"
723                                      " to the COMPARE register!\n");                                      " to the COMPARE register!\n");
724                          tmp = (int64_t)(int32_t)tmp;                          tmp = (int64_t)(int32_t)tmp;
# Line 1209  void coproc_register_write(struct cpu *c Line 726  void coproc_register_write(struct cpu *c
726                          break;                          break;
727                  case COP0_ENTRYHI:                  case COP0_ENTRYHI:
728                          /*                          /*
729                           *  Translation caches must be invalidated, because the                           *  Translation caches must be invalidated if the
730                           *  address space might change (if the ASID changes).                           *  ASID changes:
731                           */                           */
732                          switch (cpu->cd.mips.cpu_type.mmu_model) {                          switch (cpu->cd.mips.cpu_type.mmu_model) {
733                          case MMU3K:                          case MMU3K:
734                                  old_asid = (cp->reg[COP0_ENTRYHI] &                                  old_asid = cp->reg[COP0_ENTRYHI] &
735                                      R2K3K_ENTRYHI_ASID_MASK) >>                                      R2K3K_ENTRYHI_ASID_MASK;
                                     R2K3K_ENTRYHI_ASID_SHIFT;  
736                                  if ((cp->reg[COP0_ENTRYHI] &                                  if ((cp->reg[COP0_ENTRYHI] &
737                                      R2K3K_ENTRYHI_ASID_MASK) !=                                      R2K3K_ENTRYHI_ASID_MASK) !=
738                                      (tmp & R2K3K_ENTRYHI_ASID_MASK))                                      (tmp & R2K3K_ENTRYHI_ASID_MASK))
# Line 1229  void coproc_register_write(struct cpu *c Line 745  void coproc_register_write(struct cpu *c
745                                          inval = 1;                                          inval = 1;
746                                  break;                                  break;
747                          }                          }
748    
749                          if (inval)                          if (inval)
750                                  invalidate_translation_caches(cpu, 1, 0, 0,                                  invalidate_asid(cpu, old_asid);
751                                      old_asid);  
752                          unimpl = 0;                          unimpl = 0;
753                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
754                              (tmp & 0x3f)!=0) {                              (tmp & 0x3f)!=0) {
755                                  /* char *symbol;                                  /* char *symbol;
756                                     uint64_t offset;                                     uint64_t offset;
757                                     symbol = get_symbol_name(cpu->                                     symbol = get_symbol_name(cpu->pc,
758                                      cd.mips.pc_last, &offset);                                      &offset);
759                                     fatal("YO! pc = 0x%08llx <%s> "                                     fatal("YO! pc = 0x%08llx <%s> "
760                                      "hi=%016llx\n", (long long)cpu->                                      "hi=%016llx\n", (long long)cpu->pc,
761                                      cd.mips.pc_last, symbol? symbol :                                      symbol? symbol :
762                                      "no symbol", (long long)tmp);  */                                      "no symbol", (long long)tmp);  */
763                                  tmp &= ~0x3f;                                  tmp &= ~0x3f;
764                          }                          }
# Line 1287  void coproc_register_write(struct cpu *c Line 804  void coproc_register_write(struct cpu *c
804                  case COP0_STATUS:                  case COP0_STATUS:
805                          oldmode = cp->reg[COP0_STATUS];                          oldmode = cp->reg[COP0_STATUS];
806                          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  
807    
808                            /*
809                             *  When isolating caches, invalidate all translations.
810                             *  During the isolation, a special hack in memory_rw.c
811                             *  prevents translation tables from being updated, so
812                             *  the translation caches don't have to be invalidated
813                             *  when switching back to normal mode.
814                             */
815                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
816                              (oldmode & MIPS1_ISOL_CACHES) !=                              (oldmode & MIPS1_ISOL_CACHES) !=
817                              (tmp & MIPS1_ISOL_CACHES)) {                              (tmp & MIPS1_ISOL_CACHES)) {
818                                  /*  R3000-style caches when isolated are                                  /*  Invalidate everything if we are switching
819                                      treated in bintrans mode by changing                                      to isolated mode:  */
                                     the vaddr_to_hostaddr_table0 pointer:  */  
820                                  if (tmp & MIPS1_ISOL_CACHES) {                                  if (tmp & MIPS1_ISOL_CACHES) {
821                                          /*  2-level table:  */                                          cpu->invalidate_translation_caches(
822                                          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;  
823                                  }                                  }
824    
825    #if 1
826                                    /*
827                                     *  NOTE: This is not needed for NetBSD, but
828                                     *  Ultrix and Linux still needs this. They
829                                     *  shouldn't, though. Something else is buggy.
830                                     */
831                                    cpu_create_or_reset_tc(cpu);
832    #endif
833                          }                          }
834                          unimpl = 0;                          unimpl = 0;
835                          break;                          break;
# Line 1347  void coproc_register_write(struct cpu *c Line 838  void coproc_register_write(struct cpu *c
838                              affects IM bits 0 and 1:  */                              affects IM bits 0 and 1:  */
839                          cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);                          cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);
840                          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;  
841                          return;                          return;
842                  case COP0_FRAMEMASK:                  case COP0_FRAMEMASK:
843                          /*  TODO: R10000  */                          /*  TODO: R10000  */
# Line 1426  void coproc_register_write(struct cpu *c Line 913  void coproc_register_write(struct cpu *c
913   *   *
914   *  TODO:  Move this to some other file?   *  TODO:  Move this to some other file?
915   */   */
916  #define FMT_S           16  static int mips_fmt_to_ieee_fmt[32] = {
917  #define FMT_D           17          0, 0, 0, 0,  0, 0, 0, 0,
918  #define FMT_W           20          0, 0, 0, 0,  0, 0, 0, 0,
919  #define FMT_L           21          IEEE_FMT_S, IEEE_FMT_D, 0, 0,
920  #define FMT_PS          22          IEEE_FMT_W, IEEE_FMT_L, /* PS (Paired Single) */ 0, 0,
921            0, 0, 0, 0,  0, 0, 0, 0  };
922    
923    static char *fmtname[32] = {
924             "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
925             "8",  "9", "10", "11", "12", "13", "14", "15",
926             "s",  "d", "18", "19",  "w",  "l", "ps", "23",
927            "24", "25", "26", "27", "28", "29", "30", "31"  };
928    
929    static char *ccname[16] = {
930            "f",  "un",   "eq",  "ueq", "olt", "ult", "ole", "ule",
931            "sf", "ngle", "seq", "ngl", "lt",  "nge", "le",  "ngt"  };
932    
933  #define FPU_OP_ADD      1  #define FPU_OP_ADD      1
934  #define FPU_OP_SUB      2  #define FPU_OP_SUB      2
# Line 1442  void coproc_register_write(struct cpu *c Line 940  void coproc_register_write(struct cpu *c
940  #define FPU_OP_C        8  #define FPU_OP_C        8
941  #define FPU_OP_ABS      9  #define FPU_OP_ABS      9
942  #define FPU_OP_NEG      10  #define FPU_OP_NEG      10
943  /*  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);  */  
 }  
944    
945    
946  /*  /*
# Line 1596  no_reasonable_result: Line 951  no_reasonable_result:
951  static void fpu_store_float_value(struct mips_coproc *cp, int fd,  static void fpu_store_float_value(struct mips_coproc *cp, int fd,
952          double nf, int fmt, int nan)          double nf, int fmt, int nan)
953  {  {
954          int n_frac = 0, n_exp = 0, signofs=0;          int ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
955          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;  
         }  
956    
957          /*          /*
958           *  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
959           *              for 64-bit coprocessor stuff.           *        for 64-bit coprocessor functionality!
960           */           */
961          if (fmt == FMT_D || fmt == FMT_L) {          if (fmt == COP1_FMT_D || fmt == COP1_FMT_L) {
962                  cp->reg[fd] = r & 0xffffffffULL;                  cp->reg[fd] = r & 0xffffffffULL;
963                  cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;                  cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;
964    
# Line 1726  store_nan: Line 978  store_nan:
978  /*  /*
979   *  fpu_op():   *  fpu_op():
980   *   *
981   *  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,
982   *  that are >= 0, those numbers are interpreted into local   *  those numbers are interpreted into local variables.
  *  variables.  
983   *   *
984   *  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
985   *  true, 0 for false.   *  false.
986   */   */
987  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,
988          int ft, int fs, int fd, int cond, int output_fmt)          int ft, int fs, int fd, int cond, int output_fmt)
989  {  {
990          /*  Potentially two input registers, fs and ft  */          /*  Potentially two input registers, fs and ft  */
991          struct internal_float_value float_value[2];          struct ieee_float_value float_value[2];
992          int unordered, nan;          int unordered, nan, ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
993          uint64_t fs_v = 0;          uint64_t fs_v = 0;
994          double nf;          double nf;
995    
# Line 1746  static int fpu_op(struct cpu *cpu, struc Line 997  static int fpu_op(struct cpu *cpu, struc
997                  fs_v = cp->reg[fs];                  fs_v = cp->reg[fs];
998                  /*  TODO: register-pair mode and plain                  /*  TODO: register-pair mode and plain
999                      register mode? "FR" bit?  */                      register mode? "FR" bit?  */
1000                  if (fmt == FMT_D || fmt == FMT_L)                  if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1001                          fs_v = (fs_v & 0xffffffffULL) +                          fs_v = (fs_v & 0xffffffffULL) +
1002                              (cp->reg[(fs + 1) & 31] << 32);                              (cp->reg[(fs + 1) & 31] << 32);
1003                  fpu_interpret_float_value(fs_v, &float_value[0], fmt);                  ieee_interpret_float_value(fs_v, &float_value[0], ieee_fmt);
1004          }          }
1005          if (ft >= 0) {          if (ft >= 0) {
1006                  uint64_t v = cp->reg[ft];                  uint64_t v = cp->reg[ft];
1007                  /*  TODO: register-pair mode and                  /*  TODO: register-pair mode and
1008                      plain register mode? "FR" bit?  */                      plain register mode? "FR" bit?  */
1009                  if (fmt == FMT_D || fmt == FMT_L)                  if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1010                          v = (v & 0xffffffffULL) +                          v = (v & 0xffffffffULL) +
1011                              (cp->reg[(ft + 1) & 31] << 32);                              (cp->reg[(ft + 1) & 31] << 32);
1012                  fpu_interpret_float_value(v, &float_value[1], fmt);                  ieee_interpret_float_value(v, &float_value[1], ieee_fmt);
1013          }          }
1014    
1015          switch (op) {          switch (op) {
# Line 1833  static int fpu_op(struct cpu *cpu, struc Line 1084  static int fpu_op(struct cpu *cpu, struc
1084                   *  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
1085                   *              for 64-bit coprocessor stuff.                   *              for 64-bit coprocessor stuff.
1086                   */                   */
1087                  if (output_fmt == FMT_D || output_fmt == FMT_L) {                  if (output_fmt == COP1_FMT_D || output_fmt == COP1_FMT_L) {
1088                          cp->reg[fd] = fs_v & 0xffffffffULL;                          cp->reg[fd] = fs_v & 0xffffffffULL;
1089                          cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;                          cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;
1090                          if (cp->reg[fd] & 0x80000000ULL)                          if (cp->reg[fd] & 0x80000000ULL)
# Line 1947  static int fpu_function(struct cpu *cpu, Line 1198  static int fpu_function(struct cpu *cpu,
1198                  if (unassemble_only)                  if (unassemble_only)
1199                          return 1;                          return 1;
1200    
1201                  if (cpu->cd.mips.delay_slot) {                  if (cpu->delay_slot) {
1202                          fatal("%s: jump inside a jump's delay slot, "                          fatal("%s: jump inside a jump's delay slot, "
1203                              "or similar. TODO\n", instr_mnem);                              "or similar. TODO\n", instr_mnem);
1204                          cpu->running = 0;                          cpu->running = 0;
# Line 1956  static int fpu_function(struct cpu *cpu, Line 1207  static int fpu_function(struct cpu *cpu,
1207    
1208                  /*  Both the FCCR and FCSR contain condition code bits...  */                  /*  Both the FCCR and FCSR contain condition code bits...  */
1209                  if (cc == 0)                  if (cc == 0)
1210                          cond_true = (cp->fcr[FPU_FCSR] >> FCSR_FCC0_SHIFT) & 1;                          cond_true = (cp->fcr[MIPS_FPU_FCSR] >>
1211                                MIPS_FCSR_FCC0_SHIFT) & 1;
1212                  else                  else
1213                          cond_true = (cp->fcr[FPU_FCSR] >>                          cond_true = (cp->fcr[MIPS_FPU_FCSR] >>
1214                              (FCSR_FCC1_SHIFT + cc-1)) & 1;                              (MIPS_FCSR_FCC1_SHIFT + cc-1)) & 1;
1215    
1216                  if (!tf)                  if (!tf)
1217                          cond_true = !cond_true;                          cond_true = !cond_true;
1218    
1219                  if (cond_true) {                  if (cond_true) {
1220                          cpu->cd.mips.delay_slot = TO_BE_DELAYED;                          cpu->delay_slot = TO_BE_DELAYED;
1221                          cpu->cd.mips.delay_jmpaddr = cpu->pc + (imm << 2);                          cpu->delay_jmpaddr = cpu->pc + (imm << 2);
1222                  } else {                  } else {
1223                          /*  "likely":  */                          /*  "likely":  */
1224                          if (nd) {                          if (nd) {
# Line 1981  static int fpu_function(struct cpu *cpu, Line 1233  static int fpu_function(struct cpu *cpu,
1233          /*  add.fmt: Floating-point add  */          /*  add.fmt: Floating-point add  */
1234          if ((function & 0x0000003f) == 0x00000000) {          if ((function & 0x0000003f) == 0x00000000) {
1235                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1236                          debug("add.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("add.%s\tr%i,r%i,r%i\n",
1237                                fmtname[fmt], fd, fs, ft);
1238                  if (unassemble_only)                  if (unassemble_only)
1239                          return 1;                          return 1;
1240    
# Line 1992  static int fpu_function(struct cpu *cpu, Line 1245  static int fpu_function(struct cpu *cpu,
1245          /*  sub.fmt: Floating-point subtract  */          /*  sub.fmt: Floating-point subtract  */
1246          if ((function & 0x0000003f) == 0x00000001) {          if ((function & 0x0000003f) == 0x00000001) {
1247                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1248                          debug("sub.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("sub.%s\tr%i,r%i,r%i\n",
1249                                fmtname[fmt], fd, fs, ft);
1250                  if (unassemble_only)                  if (unassemble_only)
1251                          return 1;                          return 1;
1252    
# Line 2003  static int fpu_function(struct cpu *cpu, Line 1257  static int fpu_function(struct cpu *cpu,
1257          /*  mul.fmt: Floating-point multiply  */          /*  mul.fmt: Floating-point multiply  */
1258          if ((function & 0x0000003f) == 0x00000002) {          if ((function & 0x0000003f) == 0x00000002) {
1259                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1260                          debug("mul.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("mul.%s\tr%i,r%i,r%i\n",
1261                                fmtname[fmt], fd, fs, ft);
1262                  if (unassemble_only)                  if (unassemble_only)
1263                          return 1;                          return 1;
1264    
# Line 2014  static int fpu_function(struct cpu *cpu, Line 1269  static int fpu_function(struct cpu *cpu,
1269          /*  div.fmt: Floating-point divide  */          /*  div.fmt: Floating-point divide  */
1270          if ((function & 0x0000003f) == 0x00000003) {          if ((function & 0x0000003f) == 0x00000003) {
1271                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1272                          debug("div.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("div.%s\tr%i,r%i,r%i\n",
1273                                fmtname[fmt], fd, fs, ft);
1274                  if (unassemble_only)                  if (unassemble_only)
1275                          return 1;                          return 1;
1276    
# Line 2025  static int fpu_function(struct cpu *cpu, Line 1281  static int fpu_function(struct cpu *cpu,
1281          /*  sqrt.fmt: Floating-point square-root  */          /*  sqrt.fmt: Floating-point square-root  */
1282          if ((function & 0x001f003f) == 0x00000004) {          if ((function & 0x001f003f) == 0x00000004) {
1283                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1284                          debug("sqrt.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("sqrt.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1285                  if (unassemble_only)                  if (unassemble_only)
1286                          return 1;                          return 1;
1287    
# Line 2036  static int fpu_function(struct cpu *cpu, Line 1292  static int fpu_function(struct cpu *cpu,
1292          /*  abs.fmt: Floating-point absolute value  */          /*  abs.fmt: Floating-point absolute value  */
1293          if ((function & 0x001f003f) == 0x00000005) {          if ((function & 0x001f003f) == 0x00000005) {
1294                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1295                          debug("abs.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("abs.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1296                  if (unassemble_only)                  if (unassemble_only)
1297                          return 1;                          return 1;
1298    
# Line 2047  static int fpu_function(struct cpu *cpu, Line 1303  static int fpu_function(struct cpu *cpu,
1303          /*  mov.fmt: Floating-point (non-arithmetic) move  */          /*  mov.fmt: Floating-point (non-arithmetic) move  */
1304          if ((function & 0x0000003f) == 0x00000006) {          if ((function & 0x0000003f) == 0x00000006) {
1305                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1306                          debug("mov.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("mov.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1307                  if (unassemble_only)                  if (unassemble_only)
1308                          return 1;                          return 1;
1309    
# Line 2058  static int fpu_function(struct cpu *cpu, Line 1314  static int fpu_function(struct cpu *cpu,
1314          /*  neg.fmt: Floating-point negate  */          /*  neg.fmt: Floating-point negate  */
1315          if ((function & 0x001f003f) == 0x00000007) {          if ((function & 0x001f003f) == 0x00000007) {
1316                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1317                          debug("neg.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("neg.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1318                  if (unassemble_only)                  if (unassemble_only)
1319                          return 1;                          return 1;
1320    
# Line 2069  static int fpu_function(struct cpu *cpu, Line 1325  static int fpu_function(struct cpu *cpu,
1325          /*  trunc.l.fmt: Truncate  */          /*  trunc.l.fmt: Truncate  */
1326          if ((function & 0x001f003f) == 0x00000009) {          if ((function & 0x001f003f) == 0x00000009) {
1327                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1328                          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);
1329                  if (unassemble_only)                  if (unassemble_only)
1330                          return 1;                          return 1;
1331    
1332                  /*  TODO: not CVT?  */                  /*  TODO: not CVT?  */
1333    
1334                  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);
1335                  return 1;                  return 1;
1336          }          }
1337    
1338          /*  trunc.w.fmt: Truncate  */          /*  trunc.w.fmt: Truncate  */
1339          if ((function & 0x001f003f) == 0x0000000d) {          if ((function & 0x001f003f) == 0x0000000d) {
1340                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1341                          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);
1342                  if (unassemble_only)                  if (unassemble_only)
1343                          return 1;                          return 1;
1344    
1345                  /*  TODO: not CVT?  */                  /*  TODO: not CVT?  */
1346    
1347                  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);
1348                  return 1;                  return 1;
1349          }          }
1350    
# Line 2098  static int fpu_function(struct cpu *cpu, Line 1354  static int fpu_function(struct cpu *cpu,
1354                  int bit;                  int bit;
1355    
1356                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1357                          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],
1358                                fmtname[fmt], cc, fs, ft);
1359                  if (unassemble_only)                  if (unassemble_only)
1360                          return 1;                          return 1;
1361    
# Line 2110  static int fpu_function(struct cpu *cpu, Line 1367  static int fpu_function(struct cpu *cpu,
1367                   *      FCCR:  bits 7..0                   *      FCCR:  bits 7..0
1368                   *      FCSR:  bits 31..25 and 23                   *      FCSR:  bits 31..25 and 23
1369                   */                   */
1370                  cp->fcr[FPU_FCCR] &= ~(1 << cc);                  cp->fcr[MIPS_FPU_FCCR] &= ~(1 << cc);
1371                  if (cond_true)                  if (cond_true)
1372                          cp->fcr[FPU_FCCR] |= (1 << cc);                          cp->fcr[MIPS_FPU_FCCR] |= (1 << cc);
1373    
1374                  if (cc == 0) {                  if (cc == 0) {
1375                          bit = 1 << FCSR_FCC0_SHIFT;                          bit = 1 << MIPS_FCSR_FCC0_SHIFT;
1376                          cp->fcr[FPU_FCSR] &= ~bit;                          cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1377                          if (cond_true)                          if (cond_true)
1378                                  cp->fcr[FPU_FCSR] |= bit;                                  cp->fcr[MIPS_FPU_FCSR] |= bit;
1379                  } else {                  } else {
1380                          bit = 1 << (FCSR_FCC1_SHIFT + cc-1);                          bit = 1 << (MIPS_FCSR_FCC1_SHIFT + cc-1);
1381                          cp->fcr[FPU_FCSR] &= ~bit;                          cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1382                          if (cond_true)                          if (cond_true)
1383                                  cp->fcr[FPU_FCSR] |= bit;                                  cp->fcr[MIPS_FPU_FCSR] |= bit;
1384                  }                  }
1385    
1386                  return 1;                  return 1;
# Line 2132  static int fpu_function(struct cpu *cpu, Line 1389  static int fpu_function(struct cpu *cpu,
1389          /*  cvt.s.fmt: Convert to single floating-point  */          /*  cvt.s.fmt: Convert to single floating-point  */
1390          if ((function & 0x001f003f) == 0x00000020) {          if ((function & 0x001f003f) == 0x00000020) {
1391                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1392                          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);
1393                  if (unassemble_only)                  if (unassemble_only)
1394                          return 1;                          return 1;
1395    
1396                  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);
1397                  return 1;                  return 1;
1398          }          }
1399    
1400          /*  cvt.d.fmt: Convert to double floating-point  */          /*  cvt.d.fmt: Convert to double floating-point  */
1401          if ((function & 0x001f003f) == 0x00000021) {          if ((function & 0x001f003f) == 0x00000021) {
1402                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1403                          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);
1404                  if (unassemble_only)                  if (unassemble_only)
1405                          return 1;                          return 1;
1406    
1407                  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);
1408                  return 1;                  return 1;
1409          }          }
1410    
1411          /*  cvt.w.fmt: Convert to word fixed-point  */          /*  cvt.w.fmt: Convert to word fixed-point  */
1412          if ((function & 0x001f003f) == 0x00000024) {          if ((function & 0x001f003f) == 0x00000024) {
1413                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1414                          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);
1415                  if (unassemble_only)                  if (unassemble_only)
1416                          return 1;                          return 1;
1417    
1418                  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);
1419                  return 1;                  return 1;
1420          }          }
1421    
# Line 2288  void coproc_tlbpr(struct cpu *cpu, int r Line 1545  void coproc_tlbpr(struct cpu *cpu, int r
1545  /*  /*
1546   *  coproc_tlbwri():   *  coproc_tlbwri():
1547   *   *
1548   *  'tlbwr' and 'tlbwi'   *  MIPS TLB write random (tlbwr) and write indexed (tlbwi) instructions.
1549   */   */
1550  void coproc_tlbwri(struct cpu *cpu, int randomflag)  void coproc_tlbwri(struct cpu *cpu, int randomflag)
1551  {  {
1552          struct mips_coproc *cp = cpu->cd.mips.coproc[0];          struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1553          int index, g_bit;          int index, g_bit, old_asid = -1;
1554          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;  
1555    
1556          if (randomflag) {          if (randomflag) {
1557                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
1558                            cp->reg[COP0_RANDOM] =
1559                                ((random() % (cp->nr_of_tlbs - 8)) + 8)
1560                                << R2K3K_RANDOM_SHIFT;
1561                          index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)                          index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
1562                              >> R2K3K_RANDOM_SHIFT;                              >> R2K3K_RANDOM_SHIFT;
1563                  else                  } else {
1564                            cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
1565                                % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
1566                          index = cp->reg[COP0_RANDOM] & RANDOM_MASK;                          index = cp->reg[COP0_RANDOM] & RANDOM_MASK;
1567                    }
1568          } else {          } else {
1569                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1570                          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 1580  void coproc_tlbwri(struct cpu *cpu, int
1580                  return;                  return;
1581          }          }
1582    
1583    
1584  #if 0  #if 0
1585          /*  Debug dump of the previous entry at that index:  */          /*  Debug dump of the previous entry at that index:  */
1586          debug(" old entry at index = %04x", index);          fatal("{ old TLB entry at index %02x:", index);
1587          debug(" mask = %016llx", (long long) cp->tlbs[index].mask);          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1588          debug(" hi = %016llx", (long long) cp->tlbs[index].hi);                  fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1589          debug(" lo0 = %016llx", (long long) cp->tlbs[index].lo0);                  fatal(" lo=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1590          debug(" lo1 = %016llx\n", (long long) cp->tlbs[index].lo1);          } else {
1591                    if (cpu->is_32bit) {
1592                            fatal(" mask=%08"PRIx32,(uint32_t)cp->tlbs[index].mask);
1593                            fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1594                            fatal(" lo0=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1595                            fatal(" lo1=%08"PRIx32, (uint32_t)cp->tlbs[index].lo1);
1596                    } else {
1597                            fatal(" mask=%016"PRIx64, cp->tlbs[index].mask);
1598                            fatal(" hi=%016"PRIx64, cp->tlbs[index].hi);
1599                            fatal(" lo0=%016"PRIx64, cp->tlbs[index].lo0);
1600                            fatal(" lo1=%016"PRIx64, cp->tlbs[index].lo1);
1601                    }
1602            }
1603            fatal(" }\n");
1604  #endif  #endif
1605    
1606          /*  Translation caches must be invalidated:  */          /*
1607             *  Any virtual address translation for the old TLB entry must be
1608             *  invalidated first:
1609             */
1610    
1611          switch (cpu->cd.mips.cpu_type.mmu_model) {          switch (cpu->cd.mips.cpu_type.mmu_model) {
1612    
1613          case MMU3K:          case MMU3K:
1614                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;
1615                  oldvaddr &= 0xffffffffULL;                  oldvaddr &= 0xffffffffULL;
# Line 2360  void coproc_tlbwri(struct cpu *cpu, int Line 1618  void coproc_tlbwri(struct cpu *cpu, int
1618                  old_asid = (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK)                  old_asid = (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK)
1619                      >> R2K3K_ENTRYHI_ASID_SHIFT;                      >> R2K3K_ENTRYHI_ASID_SHIFT;
1620    
1621  /*  TODO: Bug? Why does this if need to be commented out?  */                  cpu->invalidate_translation_caches(cpu, oldvaddr,
1622                        INVALIDATE_VADDR);
                 /*  if (cp->tlbs[index].lo0 & ENTRYLO_V)  */  
                         invalidate_translation_caches(cpu, 0, oldvaddr, 0, 0);  
1623                  break;                  break;
1624          default:  
1625                  if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {          default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1626                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;
1627                          /*  44 addressable bits:  */                          /*  44 addressable bits:  */
1628                          if (oldvaddr & 0x80000000000ULL)                          if (oldvaddr & 0x80000000000ULL)
1629                                  oldvaddr |= 0xfffff00000000000ULL;                                  oldvaddr |= 0xfffff00000000000ULL;
1630                    } else if (cpu->is_32bit) {
1631                            /*  MIPS32 etc.:  */
1632                            oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1633                            oldvaddr = (int32_t)oldvaddr;
1634                  } else {                  } else {
1635                          /*  Assume MMU4K  */                          /*  Assume MMU4K  */
1636                          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 1639  void coproc_tlbwri(struct cpu *cpu, int
1639                                  oldvaddr |= 0xffffff0000000000ULL;                                  oldvaddr |= 0xffffff0000000000ULL;
1640                  }                  }
1641    
1642    #if 1
1643                    cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL);
1644    #else
1645                  /*                  /*
                  *  Both pages:  
                  *  
1646                   *  TODO: non-4KB page sizes!                   *  TODO: non-4KB page sizes!
1647                   */                   */
1648                  invalidate_translation_caches(                  cpu->invalidate_translation_caches(cpu, oldvaddr,
1649                      cpu, 0, oldvaddr & ~0x1fff, 0, 0);                      INVALIDATE_VADDR);
1650                  invalidate_translation_caches(                  cpu->invalidate_translation_caches(cpu, oldvaddr | 0x1000,
1651                      cpu, 0, (oldvaddr & ~0x1fff) | 0x1000, 0, 0);                      INVALIDATE_VADDR);
1652    #endif
1653          }          }
1654    
1655    
# Line 2402  void coproc_tlbwri(struct cpu *cpu, int Line 1664  void coproc_tlbwri(struct cpu *cpu, int
1664          if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&          if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&
1665              cpu->cd.mips.cpu_type.rev != MIPS_R4100) {              cpu->cd.mips.cpu_type.rev != MIPS_R4100) {
1666                  uint64_t vaddr1, vaddr2;                  uint64_t vaddr1, vaddr2;
1667                  int i, asid;                  int i;
1668                    unsigned int asid;
1669    
1670                  vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K;                  vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K;
1671                  asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;                  asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
# Line 2432  void coproc_tlbwri(struct cpu *cpu, int Line 1695  void coproc_tlbwri(struct cpu *cpu, int
1695          /*  Write the new entry:  */          /*  Write the new entry:  */
1696    
1697          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1698                  uint64_t vaddr, paddr;                  uint32_t vaddr, paddr;
1699                  int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;                  int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;
1700                  unsigned char *memblock = NULL;                  unsigned char *memblock = NULL;
1701    
# Line 2442  void coproc_tlbwri(struct cpu *cpu, int Line 1705  void coproc_tlbwri(struct cpu *cpu, int
1705                  vaddr =  cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;                  vaddr =  cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
1706                  paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;                  paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;
1707    
1708                  /*  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);  
1709    
1710                    /*  Invalidate any code translation, if we are writing
1711                        a Dirty page to the TLB:  */
1712                    if (wf) {
1713                            cpu->invalidate_code_translation(cpu, paddr,
1714                                INVALIDATE_PADDR);
1715                    }
1716    
1717                    /*  If we have a memblock (host page) for the physical
1718                        page, then add a translation for it immediately:  */
1719                  if (memblock != NULL &&                  if (memblock != NULL &&
1720                      cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) {                      cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) {
1721                          memblock += (paddr & ((1 << BITS_PER_PAGETABLE) - 1));                          memblock += (paddr & ((1 << BITS_PER_PAGETABLE) - 1));
   
                         /*  
                          *  TODO: Hahaha, this is even uglier than the thing  
                          *  above. Some OSes seem to map code pages read/write,  
                          *  which causes the bintrans cache to be invalidated  
                          *  even when it doesn't have to be.  
                          */  
 /*                      if (vaddr < 0x10000000)  */  
                                 wf = 0;  
   
1722                          cpu->update_translation_table(cpu, vaddr, memblock,                          cpu->update_translation_table(cpu, vaddr, memblock,
1723                              wf, paddr);                              wf, paddr);
1724                  }                  }
# Line 2484  void coproc_tlbwri(struct cpu *cpu, int Line 1743  void coproc_tlbwri(struct cpu *cpu, int
1743                          if (g_bit)                          if (g_bit)
1744                                  cp->tlbs[index].hi |= TLB_G;                                  cp->tlbs[index].hi |= TLB_G;
1745                  }                  }
         }  
1746    
1747          if (randomflag) {                  /*  Invalidate any code translations, if we are writing
1748                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {                      Dirty pages to the TLB:  */
1749                          cp->reg[COP0_RANDOM] =                  if (cp->reg[COP0_PAGEMASK] != 0 &&
1750                              ((random() % (cp->nr_of_tlbs - 8)) + 8)                      cp->reg[COP0_PAGEMASK] != 0x1800) {
1751                              << R2K3K_RANDOM_SHIFT;                          printf("TODO: MASK = %08"PRIx32"\n",
1752                                (uint32_t)cp->reg[COP0_PAGEMASK]);
1753                            exit(1);
1754                    }
1755    
1756                    if (cp->tlbs[index].lo0 & ENTRYLO_D)
1757                            cpu->invalidate_code_translation(cpu,
1758                                ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK)
1759                                >> ENTRYLO_PFN_SHIFT) << 12,
1760                                INVALIDATE_PADDR);
1761                    if (cp->tlbs[index].lo1 & ENTRYLO_D)
1762                            cpu->invalidate_code_translation(cpu,
1763                                ((cp->tlbs[index].lo1 & ENTRYLO_PFN_MASK)
1764                                >> ENTRYLO_PFN_SHIFT) << 12,
1765                                INVALIDATE_PADDR);
1766    
1767    #if 1
1768            if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1769                            oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;
1770                            /*  44 addressable bits:  */
1771                            if (oldvaddr & 0x80000000000ULL)
1772                                    oldvaddr |= 0xfffff00000000000ULL;
1773                    } else if (cpu->is_32bit) {
1774                            /*  MIPS32 etc.:  */
1775                            oldvaddr = (int32_t)oldvaddr;
1776                  } else {                  } else {
1777                          cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()                          /*  Assume MMU4K  */
1778                              % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1779                            /*  40 addressable bits:  */
1780                            if (oldvaddr & 0x8000000000ULL)
1781                                    oldvaddr |= 0xffffff0000000000ULL;
1782                  }                  }
1783    
1784    cpu->invalidate_translation_caches(cpu, ((cp->tlbs[index].lo0 &
1785    ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << 12, INVALIDATE_PADDR);
1786    cpu->invalidate_translation_caches(cpu, ((cp->tlbs[index].lo1 &
1787    ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << 12, INVALIDATE_PADDR);
1788    
1789    #endif
1790          }          }
1791  }  }
1792    
# Line 2506  void coproc_tlbwri(struct cpu *cpu, int Line 1798  void coproc_tlbwri(struct cpu *cpu, int
1798   */   */
1799  void coproc_rfe(struct cpu *cpu)  void coproc_rfe(struct cpu *cpu)
1800  {  {
         int oldmode;  
   
         oldmode = cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_SR_KU_CUR;  
   
1801          cpu->cd.mips.coproc[0]->reg[COP0_STATUS] =          cpu->cd.mips.coproc[0]->reg[COP0_STATUS] =
1802              (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) |              (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) |
1803              ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 0x3c) >> 2);              ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 0x3c) >> 2);
   
         /*  Changing from kernel to user mode? Then this is necessary:  */  
         if (!oldmode &&  
             (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &  
             MIPS1_SR_KU_CUR))  
                 invalidate_translation_caches(cpu, 0, 0, 1, 0);  
1804  }  }
1805    
1806    
# Line 2529  void coproc_rfe(struct cpu *cpu) Line 1811  void coproc_rfe(struct cpu *cpu)
1811   */   */
1812  void coproc_eret(struct cpu *cpu)  void coproc_eret(struct cpu *cpu)
1813  {  {
         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;  
   
1814          if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {          if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {
1815                  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];  
1816                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;
1817          } else {          } else {
1818                  cpu->pc = cpu->cd.mips.pc_last =                  cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_EPC];
1819                      cpu->cd.mips.coproc[0]->reg[COP0_EPC];                  cpu->delay_slot = 0;
                 cpu->cd.mips.delay_slot = 0;  
1820                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;
1821          }          }
1822    
1823          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  
1824  }  }
1825    
1826    
# Line 2597  void coproc_function(struct cpu *cpu, st Line 1850  void coproc_function(struct cpu *cpu, st
1850                  return;                  return;
1851          }          }
1852    
 #if 0  
1853          /*  No FPU?  */          /*  No FPU?  */
1854          if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {          if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {
1855                  mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);                  mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);
1856                  return;                  return;
1857          }          }
 #endif  
1858    
1859          /*  For quick reference:  */          /*  For quick reference:  */
1860          copz = (function >> 21) & 31;          copz = (function >> 21) & 31;
# Line 2618  void coproc_function(struct cpu *cpu, st Line 1869  void coproc_function(struct cpu *cpu, st
1869                          if (cpnr == 0)                          if (cpnr == 0)
1870                                  debug("%s", cop0_names[rd]);                                  debug("%s", cop0_names[rd]);
1871                          else                          else
1872                                  debug("cpreg%i", rd);                                  debug("r%i", rd);
1873                          if (function & 7)                          if (function & 7)
1874                                  debug(",%i", (int)(function & 7));                                  debug(",%i", (int)(function & 7));
1875                          debug("\n");                          debug("\n");
# Line 2644  void coproc_function(struct cpu *cpu, st Line 1895  void coproc_function(struct cpu *cpu, st
1895                          if (cpnr == 0)                          if (cpnr == 0)
1896                                  debug("%s", cop0_names[rd]);                                  debug("%s", cop0_names[rd]);
1897                          else                          else
1898                                  debug("cpreg%i", rd);                                  debug("r%i", rd);
1899                          if (function & 7)                          if (function & 7)
1900                                  debug(",%i", (int)(function & 7));                                  debug(",%i", (int)(function & 7));
1901                          debug("\n");                          debug("\n");
# Line 2673  void coproc_function(struct cpu *cpu, st Line 1924  void coproc_function(struct cpu *cpu, st
1924                                      regnames[rt], fs);                                      regnames[rt], fs);
1925                                  return;                                  return;
1926                          }                          }
1927                          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;  
1928                          /*  TODO: implement delay for gpr[rt]                          /*  TODO: implement delay for gpr[rt]
1929                              (for MIPS I,II,III only)  */                              (for MIPS I,II,III only)  */
1930                          return;                          return;
# Line 2707  void coproc_function(struct cpu *cpu, st Line 1956  void coproc_function(struct cpu *cpu, st
1956                                              on status bits!  */                                              on status bits!  */
1957    
1958                                          switch (fs) {                                          switch (fs) {
1959                                          case FPU_FCCR:                                          case MIPS_FPU_FCCR:
1960                                                  cp->fcr[FPU_FCSR] =                                                  cp->fcr[MIPS_FPU_FCSR] =
1961                                                      (cp->fcr[FPU_FCSR] &                                                      (cp->fcr[MIPS_FPU_FCSR] &
1962                                                      0x017fffffULL) | ((tmp & 1)                                                      0x017fffffULL) | ((tmp & 1)
1963                                                      << FCSR_FCC0_SHIFT)                                                      << MIPS_FCSR_FCC0_SHIFT)
1964                                                      | (((tmp & 0xfe) >> 1) <<                                                      | (((tmp & 0xfe) >> 1) <<
1965                                                      FCSR_FCC1_SHIFT);                                                      MIPS_FCSR_FCC1_SHIFT);
1966                                                  break;                                                  break;
1967                                          case FPU_FCSR:                                          case MIPS_FPU_FCSR:
1968                                                  cp->fcr[FPU_FCCR] =                                                  cp->fcr[MIPS_FPU_FCCR] =
1969                                                      (cp->fcr[FPU_FCCR] &                                                      (cp->fcr[MIPS_FPU_FCCR] &
1970                                                      0xffffff00ULL) | ((tmp >>                                                      0xffffff00ULL) | ((tmp >>
1971                                                      FCSR_FCC0_SHIFT) & 1) |                                                      MIPS_FCSR_FCC0_SHIFT) & 1) |
1972                                                      (((tmp >> FCSR_FCC1_SHIFT)                                                      (((tmp >>
1973                                                        MIPS_FCSR_FCC1_SHIFT)
1974                                                      & 0x7f) << 1);                                                      & 0x7f) << 1);
1975                                                  break;                                                  break;
1976                                          default:                                          default:
# Line 2744  void coproc_function(struct cpu *cpu, st Line 1994  void coproc_function(struct cpu *cpu, st
1994                          return;                          return;
1995          }          }
1996    
         /*  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;  
         }  
   
1997    
1998          /*  Ugly R5900 hacks:  */          /*  Ugly R5900 hacks:  */
1999          if ((function & 0xfffff) == 0x38) {             /*  ei  */          if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) {
2000                  if (unassemble_only) {                  if ((function & 0xfffff) == COP0_EI) {
2001                          debug("ei\n");                          if (unassemble_only) {
2002                                    debug("ei\n");
2003                                    return;
2004                            }
2005                            cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |=
2006                                R5900_STATUS_EIE;
2007                          return;                          return;
2008                  }                  }
                 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= R5900_STATUS_EIE;  
                 return;  
         }  
2009    
2010          if ((function & 0xfffff) == 0x39) {             /*  di  */                  if ((function & 0xfffff) == COP0_DI) {
2011                  if (unassemble_only) {                          if (unassemble_only) {
2012                          debug("di\n");                                  debug("di\n");
2013                                    return;
2014                            }
2015                            cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &=
2016                                ~R5900_STATUS_EIE;
2017                          return;                          return;
2018                  }                  }
                 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~R5900_STATUS_EIE;  
                 return;  
2019          }          }
2020    
2021          co_bit = (function >> 25) & 1;          co_bit = (function >> 25) & 1;
# Line 2826  void coproc_function(struct cpu *cpu, st Line 2056  void coproc_function(struct cpu *cpu, st
2056                                              (long long)cp->reg[COP0_ENTRYLO0]);                                              (long long)cp->reg[COP0_ENTRYLO0]);
2057                                          debug(", lo1=%016llx\n",                                          debug(", lo1=%016llx\n",
2058                                              (long long)cp->reg[COP0_ENTRYLO1]);                                              (long long)cp->reg[COP0_ENTRYLO1]);
2059                                            return;
2060                                  }                                  }
2061                                  coproc_tlbwri(cpu, op == COP0_TLBWR);                                  coproc_tlbwri(cpu, op == COP0_TLBWR);
2062                                  return;                                  return;
# Line 2852  void coproc_function(struct cpu *cpu, st Line 2083  void coproc_function(struct cpu *cpu, st
2083                                  }                                  }
2084                                  coproc_eret(cpu);                                  coproc_eret(cpu);
2085                                  return;                                  return;
2086                            case COP0_DERET:
2087                                    if (unassemble_only) {
2088                                            debug("deret\n");
2089                                            return;
2090                                    }
2091                                    /*
2092                                     *  According to the MIPS64 manual, deret
2093                                     *  loads PC from the DEPC cop0 register, and
2094                                     *  jumps there immediately. No delay slot.
2095                                     *
2096                                     *  TODO: This instruction is only available
2097                                     *  if the processor is in debug mode. (What
2098                                     *  does that mean?) TODO: This instruction
2099                                     *  is undefined in a delay slot.
2100                                     */
2101                                    cpu->pc = cp->reg[COP0_DEPC];
2102                                    cpu->delay_slot = 0;
2103                                    cp->reg[COP0_STATUS] &= ~STATUS_EXL;
2104                                    return;
2105                          case COP0_STANDBY:                          case COP0_STANDBY:
2106                                  if (unassemble_only) {                                  if (unassemble_only) {
2107                                          debug("standby\n");                                          debug("standby\n");
# Line 2907  void coproc_function(struct cpu *cpu, st Line 2157  void coproc_function(struct cpu *cpu, st
2157                  return;                  return;
2158          }          }
2159    
2160          fatal("cpu%i: UNIMPLEMENTED coproc%i function %08lx "          fatal("cpu%i: UNIMPLEMENTED coproc%i function %08"PRIx32" "
2161              "(pc = %016llx)\n", cpu->cpu_id, cp->coproc_nr, function,              "(pc = %016"PRIx64")\n", cpu->cpu_id, cp->coproc_nr,
2162              (long long)cpu->cd.mips.pc_last);              (uint32_t)function, cpu->pc);
2163  #if 1  
         single_step = 1;  
 #else  
2164          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  
2165  }  }
2166    
2167  #endif  /*  ENABLE_MIPS  */  #endif  /*  ENABLE_MIPS  */

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

  ViewVC Help
Powered by ViewVC 1.1.26