/[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 24 by dpavlin, Mon Oct 8 16:19:56 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.33 2006/06/22 13:30:38 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 1017  void coproc_register_read(struct cpu *cp Line 558  void coproc_register_read(struct cpu *cp
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) {
561    #if 0
562                  /*                  /*
563                   *  This speeds up delay-loops that just read the count                   *  This speeds up delay-loops that just read the count
564                   *  register until it has reached a certain value. (Only for                   *  register until it has reached a certain value. (Only for
# Line 1037  void coproc_register_read(struct cpu *cp Line 579  void coproc_register_read(struct cpu *cp
579                          cp->reg[COP0_COUNT] = (int64_t)                          cp->reg[COP0_COUNT] = (int64_t)
580                              (int32_t)(cp->reg[COP0_COUNT] + increase);                              (int32_t)(cp->reg[COP0_COUNT] + increase);
581                  }                  }
582    #endif
583                  unimpl = 0;                  unimpl = 0;
584          }          }
585          if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI)   unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI)   unimpl = 0;
# Line 1121  void coproc_register_write(struct cpu *c Line 663  void coproc_register_write(struct cpu *c
663                              (tmp & 0xff)!=0) {                              (tmp & 0xff)!=0) {
664                                  /*  char *symbol;                                  /*  char *symbol;
665                                      uint64_t offset;                                      uint64_t offset;
666                                      symbol = get_symbol_name(                                      symbol = get_symbol_name(cpu->pc, &offset);
                                     cpu->cd.mips.pc_last, &offset);  
667                                      fatal("YO! pc = 0x%08llx <%s> "                                      fatal("YO! pc = 0x%08llx <%s> "
668                                      "lo=%016llx\n", (long long)                                      "lo=%016llx\n", (long long)
669                                      cpu->cd.mips.pc_last, symbol? symbol :                                      cpu->pc, symbol? symbol :
670                                      "no symbol", (long long)tmp); */                                      "no symbol", (long long)tmp); */
671                                  tmp &= (R2K3K_ENTRYLO_PFN_MASK |                                  tmp &= (R2K3K_ENTRYLO_PFN_MASK |
672                                      R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |                                      R2K3K_ENTRYLO_N | R2K3K_ENTRYLO_D |
# Line 1191  void coproc_register_write(struct cpu *c Line 732  void coproc_register_write(struct cpu *c
732                          unimpl = 0;                          unimpl = 0;
733                          break;                          break;
734                  case COP0_COUNT:                  case COP0_COUNT:
735                          if (tmp != (int64_t)(int32_t)tmp)                          if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
736                                  fatal("WARNING: trying to write a 64-bit value"                                  fatal("WARNING: trying to write a 64-bit value"
737                                      " to the COUNT register!\n");                                      " to the COUNT register!\n");
738                          tmp = (int64_t)(int32_t)tmp;                          tmp = (int64_t)(int32_t)tmp;
# Line 1201  void coproc_register_write(struct cpu *c Line 742  void coproc_register_write(struct cpu *c
742                          /*  Clear the timer interrupt bit (bit 7):  */                          /*  Clear the timer interrupt bit (bit 7):  */
743                          cpu->cd.mips.compare_register_set = 1;                          cpu->cd.mips.compare_register_set = 1;
744                          mips_cpu_interrupt_ack(cpu, 7);                          mips_cpu_interrupt_ack(cpu, 7);
745                          if (tmp != (int64_t)(int32_t)tmp)                          if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
746                                  fatal("WARNING: trying to write a 64-bit value"                                  fatal("WARNING: trying to write a 64-bit value"
747                                      " to the COMPARE register!\n");                                      " to the COMPARE register!\n");
748                          tmp = (int64_t)(int32_t)tmp;                          tmp = (int64_t)(int32_t)tmp;
# Line 1209  void coproc_register_write(struct cpu *c Line 750  void coproc_register_write(struct cpu *c
750                          break;                          break;
751                  case COP0_ENTRYHI:                  case COP0_ENTRYHI:
752                          /*                          /*
753                           *  Translation caches must be invalidated, because the                           *  Translation caches must be invalidated if the
754                           *  address space might change (if the ASID changes).                           *  ASID changes:
755                           */                           */
756                          switch (cpu->cd.mips.cpu_type.mmu_model) {                          switch (cpu->cd.mips.cpu_type.mmu_model) {
757                          case MMU3K:                          case MMU3K:
758                                  old_asid = (cp->reg[COP0_ENTRYHI] &                                  old_asid = cp->reg[COP0_ENTRYHI] &
759                                      R2K3K_ENTRYHI_ASID_MASK) >>                                      R2K3K_ENTRYHI_ASID_MASK;
                                     R2K3K_ENTRYHI_ASID_SHIFT;  
760                                  if ((cp->reg[COP0_ENTRYHI] &                                  if ((cp->reg[COP0_ENTRYHI] &
761                                      R2K3K_ENTRYHI_ASID_MASK) !=                                      R2K3K_ENTRYHI_ASID_MASK) !=
762                                      (tmp & R2K3K_ENTRYHI_ASID_MASK))                                      (tmp & R2K3K_ENTRYHI_ASID_MASK))
# Line 1229  void coproc_register_write(struct cpu *c Line 769  void coproc_register_write(struct cpu *c
769                                          inval = 1;                                          inval = 1;
770                                  break;                                  break;
771                          }                          }
772    
773                          if (inval)                          if (inval)
774                                  invalidate_translation_caches(cpu, 1, 0, 0,                                  invalidate_asid(cpu, old_asid);
775                                      old_asid);  
776                          unimpl = 0;                          unimpl = 0;
777                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
778                              (tmp & 0x3f)!=0) {                              (tmp & 0x3f)!=0) {
779                                  /* char *symbol;                                  /* char *symbol;
780                                     uint64_t offset;                                     uint64_t offset;
781                                     symbol = get_symbol_name(cpu->                                     symbol = get_symbol_name(cpu->pc,
782                                      cd.mips.pc_last, &offset);                                      &offset);
783                                     fatal("YO! pc = 0x%08llx <%s> "                                     fatal("YO! pc = 0x%08llx <%s> "
784                                      "hi=%016llx\n", (long long)cpu->                                      "hi=%016llx\n", (long long)cpu->pc,
785                                      cd.mips.pc_last, symbol? symbol :                                      symbol? symbol :
786                                      "no symbol", (long long)tmp);  */                                      "no symbol", (long long)tmp);  */
787                                  tmp &= ~0x3f;                                  tmp &= ~0x3f;
788                          }                          }
# Line 1287  void coproc_register_write(struct cpu *c Line 828  void coproc_register_write(struct cpu *c
828                  case COP0_STATUS:                  case COP0_STATUS:
829                          oldmode = cp->reg[COP0_STATUS];                          oldmode = cp->reg[COP0_STATUS];
830                          tmp &= ~(1 << 21);      /*  bit 21 is read-only  */                          tmp &= ~(1 << 21);      /*  bit 21 is read-only  */
831  #if 0                          /*
832  /*  Why was this here? It should not be necessary.  */                           *  TODO: Perhaps this can be solved some other
833                             *  way, like in the old bintrans system?
834                          /*  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  
   
835                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
836                              (oldmode & MIPS1_ISOL_CACHES) !=                              (oldmode & MIPS1_ISOL_CACHES) !=
837                              (tmp & MIPS1_ISOL_CACHES)) {                              (tmp & MIPS1_ISOL_CACHES)) {
838                                  /*  R3000-style caches when isolated are                                  cpu->invalidate_translation_caches(
839                                      treated in bintrans mode by changing                                      cpu, 0, INVALIDATE_ALL);
840                                      the vaddr_to_hostaddr_table0 pointer:  */  
841                                  if (tmp & MIPS1_ISOL_CACHES) {                                  /*  Perhaps add some kind of INVALIDATE_
842                                          /*  2-level table:  */                                      ALL_PADDR_WHICH_HAS_A_CORRESPONDING_
843                                          cpu->cd.mips.vaddr_to_hostaddr_table0 =                                      VADDR of some kind? :-)  */
844                                            tmp & MIPS1_SWAP_CACHES?                                  cpu_create_or_reset_tc(cpu);
                                           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;  
                                 }  
845                          }                          }
846                          unimpl = 0;                          unimpl = 0;
847                          break;                          break;
# Line 1347  void coproc_register_write(struct cpu *c Line 850  void coproc_register_write(struct cpu *c
850                              affects IM bits 0 and 1:  */                              affects IM bits 0 and 1:  */
851                          cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);                          cp->reg[reg_nr] &= ~(0x3 << STATUS_IM_SHIFT);
852                          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;  
853                          return;                          return;
854                  case COP0_FRAMEMASK:                  case COP0_FRAMEMASK:
855                          /*  TODO: R10000  */                          /*  TODO: R10000  */
# Line 1426  void coproc_register_write(struct cpu *c Line 925  void coproc_register_write(struct cpu *c
925   *   *
926   *  TODO:  Move this to some other file?   *  TODO:  Move this to some other file?
927   */   */
928  #define FMT_S           16  static int mips_fmt_to_ieee_fmt[32] = {
929  #define FMT_D           17          0, 0, 0, 0,  0, 0, 0, 0,
930  #define FMT_W           20          0, 0, 0, 0,  0, 0, 0, 0,
931  #define FMT_L           21          IEEE_FMT_S, IEEE_FMT_D, 0, 0,
932  #define FMT_PS          22          IEEE_FMT_W, IEEE_FMT_L, /* PS (Paired Single) */ 0, 0,
933            0, 0, 0, 0,  0, 0, 0, 0  };
934    
935    static char *fmtname[32] = {
936             "0",  "1",  "2",  "3",  "4",  "5",  "6",  "7",
937             "8",  "9", "10", "11", "12", "13", "14", "15",
938             "s",  "d", "18", "19",  "w",  "l", "ps", "23",
939            "24", "25", "26", "27", "28", "29", "30", "31"  };
940    
941    static char *ccname[16] = {
942            "f",  "un",   "eq",  "ueq", "olt", "ult", "ole", "ule",
943            "sf", "ngle", "seq", "ngl", "lt",  "nge", "le",  "ngt"  };
944    
945  #define FPU_OP_ADD      1  #define FPU_OP_ADD      1
946  #define FPU_OP_SUB      2  #define FPU_OP_SUB      2
# Line 1442  void coproc_register_write(struct cpu *c Line 952  void coproc_register_write(struct cpu *c
952  #define FPU_OP_C        8  #define FPU_OP_C        8
953  #define FPU_OP_ABS      9  #define FPU_OP_ABS      9
954  #define FPU_OP_NEG      10  #define FPU_OP_NEG      10
955  /*  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);  */  
 }  
956    
957    
958  /*  /*
# Line 1596  no_reasonable_result: Line 963  no_reasonable_result:
963  static void fpu_store_float_value(struct mips_coproc *cp, int fd,  static void fpu_store_float_value(struct mips_coproc *cp, int fd,
964          double nf, int fmt, int nan)          double nf, int fmt, int nan)
965  {  {
966          int n_frac = 0, n_exp = 0, signofs=0;          int ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
967          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;  
         }  
968    
969          /*          /*
970           *  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
971           *              for 64-bit coprocessor stuff.           *        for 64-bit coprocessor functionality!
972           */           */
973          if (fmt == FMT_D || fmt == FMT_L) {          if (fmt == COP1_FMT_D || fmt == COP1_FMT_L) {
974                  cp->reg[fd] = r & 0xffffffffULL;                  cp->reg[fd] = r & 0xffffffffULL;
975                  cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;                  cp->reg[(fd+1) & 31] = (r >> 32) & 0xffffffffULL;
976    
# Line 1726  store_nan: Line 990  store_nan:
990  /*  /*
991   *  fpu_op():   *  fpu_op():
992   *   *
993   *  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,
994   *  that are >= 0, those numbers are interpreted into local   *  those numbers are interpreted into local variables.
  *  variables.  
995   *   *
996   *  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
997   *  true, 0 for false.   *  false.
998   */   */
999  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,
1000          int ft, int fs, int fd, int cond, int output_fmt)          int ft, int fs, int fd, int cond, int output_fmt)
1001  {  {
1002          /*  Potentially two input registers, fs and ft  */          /*  Potentially two input registers, fs and ft  */
1003          struct internal_float_value float_value[2];          struct ieee_float_value float_value[2];
1004          int unordered, nan;          int unordered, nan, ieee_fmt = mips_fmt_to_ieee_fmt[fmt];
1005          uint64_t fs_v = 0;          uint64_t fs_v = 0;
1006          double nf;          double nf;
1007    
# Line 1746  static int fpu_op(struct cpu *cpu, struc Line 1009  static int fpu_op(struct cpu *cpu, struc
1009                  fs_v = cp->reg[fs];                  fs_v = cp->reg[fs];
1010                  /*  TODO: register-pair mode and plain                  /*  TODO: register-pair mode and plain
1011                      register mode? "FR" bit?  */                      register mode? "FR" bit?  */
1012                  if (fmt == FMT_D || fmt == FMT_L)                  if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1013                          fs_v = (fs_v & 0xffffffffULL) +                          fs_v = (fs_v & 0xffffffffULL) +
1014                              (cp->reg[(fs + 1) & 31] << 32);                              (cp->reg[(fs + 1) & 31] << 32);
1015                  fpu_interpret_float_value(fs_v, &float_value[0], fmt);                  ieee_interpret_float_value(fs_v, &float_value[0], ieee_fmt);
1016          }          }
1017          if (ft >= 0) {          if (ft >= 0) {
1018                  uint64_t v = cp->reg[ft];                  uint64_t v = cp->reg[ft];
1019                  /*  TODO: register-pair mode and                  /*  TODO: register-pair mode and
1020                      plain register mode? "FR" bit?  */                      plain register mode? "FR" bit?  */
1021                  if (fmt == FMT_D || fmt == FMT_L)                  if (fmt == COP1_FMT_D || fmt == COP1_FMT_L)
1022                          v = (v & 0xffffffffULL) +                          v = (v & 0xffffffffULL) +
1023                              (cp->reg[(ft + 1) & 31] << 32);                              (cp->reg[(ft + 1) & 31] << 32);
1024                  fpu_interpret_float_value(v, &float_value[1], fmt);                  ieee_interpret_float_value(v, &float_value[1], ieee_fmt);
1025          }          }
1026    
1027          switch (op) {          switch (op) {
# Line 1833  static int fpu_op(struct cpu *cpu, struc Line 1096  static int fpu_op(struct cpu *cpu, struc
1096                   *  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
1097                   *              for 64-bit coprocessor stuff.                   *              for 64-bit coprocessor stuff.
1098                   */                   */
1099                  if (output_fmt == FMT_D || output_fmt == FMT_L) {                  if (output_fmt == COP1_FMT_D || output_fmt == COP1_FMT_L) {
1100                          cp->reg[fd] = fs_v & 0xffffffffULL;                          cp->reg[fd] = fs_v & 0xffffffffULL;
1101                          cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;                          cp->reg[(fd+1) & 31] = (fs_v >> 32) & 0xffffffffULL;
1102                          if (cp->reg[fd] & 0x80000000ULL)                          if (cp->reg[fd] & 0x80000000ULL)
# Line 1947  static int fpu_function(struct cpu *cpu, Line 1210  static int fpu_function(struct cpu *cpu,
1210                  if (unassemble_only)                  if (unassemble_only)
1211                          return 1;                          return 1;
1212    
1213                  if (cpu->cd.mips.delay_slot) {                  if (cpu->delay_slot) {
1214                          fatal("%s: jump inside a jump's delay slot, "                          fatal("%s: jump inside a jump's delay slot, "
1215                              "or similar. TODO\n", instr_mnem);                              "or similar. TODO\n", instr_mnem);
1216                          cpu->running = 0;                          cpu->running = 0;
# Line 1956  static int fpu_function(struct cpu *cpu, Line 1219  static int fpu_function(struct cpu *cpu,
1219    
1220                  /*  Both the FCCR and FCSR contain condition code bits...  */                  /*  Both the FCCR and FCSR contain condition code bits...  */
1221                  if (cc == 0)                  if (cc == 0)
1222                          cond_true = (cp->fcr[FPU_FCSR] >> FCSR_FCC0_SHIFT) & 1;                          cond_true = (cp->fcr[MIPS_FPU_FCSR] >>
1223                                MIPS_FCSR_FCC0_SHIFT) & 1;
1224                  else                  else
1225                          cond_true = (cp->fcr[FPU_FCSR] >>                          cond_true = (cp->fcr[MIPS_FPU_FCSR] >>
1226                              (FCSR_FCC1_SHIFT + cc-1)) & 1;                              (MIPS_FCSR_FCC1_SHIFT + cc-1)) & 1;
1227    
1228                  if (!tf)                  if (!tf)
1229                          cond_true = !cond_true;                          cond_true = !cond_true;
1230    
1231                  if (cond_true) {                  if (cond_true) {
1232                          cpu->cd.mips.delay_slot = TO_BE_DELAYED;                          cpu->delay_slot = TO_BE_DELAYED;
1233                          cpu->cd.mips.delay_jmpaddr = cpu->pc + (imm << 2);                          cpu->delay_jmpaddr = cpu->pc + (imm << 2);
1234                  } else {                  } else {
1235                          /*  "likely":  */                          /*  "likely":  */
1236                          if (nd) {                          if (nd) {
# Line 1981  static int fpu_function(struct cpu *cpu, Line 1245  static int fpu_function(struct cpu *cpu,
1245          /*  add.fmt: Floating-point add  */          /*  add.fmt: Floating-point add  */
1246          if ((function & 0x0000003f) == 0x00000000) {          if ((function & 0x0000003f) == 0x00000000) {
1247                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1248                          debug("add.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("add.%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 1992  static int fpu_function(struct cpu *cpu, Line 1257  static int fpu_function(struct cpu *cpu,
1257          /*  sub.fmt: Floating-point subtract  */          /*  sub.fmt: Floating-point subtract  */
1258          if ((function & 0x0000003f) == 0x00000001) {          if ((function & 0x0000003f) == 0x00000001) {
1259                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1260                          debug("sub.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("sub.%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 2003  static int fpu_function(struct cpu *cpu, Line 1269  static int fpu_function(struct cpu *cpu,
1269          /*  mul.fmt: Floating-point multiply  */          /*  mul.fmt: Floating-point multiply  */
1270          if ((function & 0x0000003f) == 0x00000002) {          if ((function & 0x0000003f) == 0x00000002) {
1271                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1272                          debug("mul.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("mul.%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 2014  static int fpu_function(struct cpu *cpu, Line 1281  static int fpu_function(struct cpu *cpu,
1281          /*  div.fmt: Floating-point divide  */          /*  div.fmt: Floating-point divide  */
1282          if ((function & 0x0000003f) == 0x00000003) {          if ((function & 0x0000003f) == 0x00000003) {
1283                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1284                          debug("div.%i\tr%i,r%i,r%i\n", fmt, fd, fs, ft);                          debug("div.%s\tr%i,r%i,r%i\n",
1285                                fmtname[fmt], fd, fs, ft);
1286                  if (unassemble_only)                  if (unassemble_only)
1287                          return 1;                          return 1;
1288    
# Line 2025  static int fpu_function(struct cpu *cpu, Line 1293  static int fpu_function(struct cpu *cpu,
1293          /*  sqrt.fmt: Floating-point square-root  */          /*  sqrt.fmt: Floating-point square-root  */
1294          if ((function & 0x001f003f) == 0x00000004) {          if ((function & 0x001f003f) == 0x00000004) {
1295                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1296                          debug("sqrt.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("sqrt.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1297                  if (unassemble_only)                  if (unassemble_only)
1298                          return 1;                          return 1;
1299    
# Line 2036  static int fpu_function(struct cpu *cpu, Line 1304  static int fpu_function(struct cpu *cpu,
1304          /*  abs.fmt: Floating-point absolute value  */          /*  abs.fmt: Floating-point absolute value  */
1305          if ((function & 0x001f003f) == 0x00000005) {          if ((function & 0x001f003f) == 0x00000005) {
1306                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1307                          debug("abs.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("abs.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1308                  if (unassemble_only)                  if (unassemble_only)
1309                          return 1;                          return 1;
1310    
# Line 2047  static int fpu_function(struct cpu *cpu, Line 1315  static int fpu_function(struct cpu *cpu,
1315          /*  mov.fmt: Floating-point (non-arithmetic) move  */          /*  mov.fmt: Floating-point (non-arithmetic) move  */
1316          if ((function & 0x0000003f) == 0x00000006) {          if ((function & 0x0000003f) == 0x00000006) {
1317                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1318                          debug("mov.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("mov.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1319                  if (unassemble_only)                  if (unassemble_only)
1320                          return 1;                          return 1;
1321    
# Line 2058  static int fpu_function(struct cpu *cpu, Line 1326  static int fpu_function(struct cpu *cpu,
1326          /*  neg.fmt: Floating-point negate  */          /*  neg.fmt: Floating-point negate  */
1327          if ((function & 0x001f003f) == 0x00000007) {          if ((function & 0x001f003f) == 0x00000007) {
1328                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1329                          debug("neg.%i\tr%i,r%i\n", fmt, fd, fs);                          debug("neg.%s\tr%i,r%i\n", fmtname[fmt], fd, fs);
1330                  if (unassemble_only)                  if (unassemble_only)
1331                          return 1;                          return 1;
1332    
# Line 2069  static int fpu_function(struct cpu *cpu, Line 1337  static int fpu_function(struct cpu *cpu,
1337          /*  trunc.l.fmt: Truncate  */          /*  trunc.l.fmt: Truncate  */
1338          if ((function & 0x001f003f) == 0x00000009) {          if ((function & 0x001f003f) == 0x00000009) {
1339                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1340                          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);
1341                  if (unassemble_only)                  if (unassemble_only)
1342                          return 1;                          return 1;
1343    
1344                  /*  TODO: not CVT?  */                  /*  TODO: not CVT?  */
1345    
1346                  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);
1347                  return 1;                  return 1;
1348          }          }
1349    
1350          /*  trunc.w.fmt: Truncate  */          /*  trunc.w.fmt: Truncate  */
1351          if ((function & 0x001f003f) == 0x0000000d) {          if ((function & 0x001f003f) == 0x0000000d) {
1352                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1353                          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);
1354                  if (unassemble_only)                  if (unassemble_only)
1355                          return 1;                          return 1;
1356    
1357                  /*  TODO: not CVT?  */                  /*  TODO: not CVT?  */
1358    
1359                  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);
1360                  return 1;                  return 1;
1361          }          }
1362    
# Line 2098  static int fpu_function(struct cpu *cpu, Line 1366  static int fpu_function(struct cpu *cpu,
1366                  int bit;                  int bit;
1367    
1368                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1369                          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],
1370                                fmtname[fmt], cc, fs, ft);
1371                  if (unassemble_only)                  if (unassemble_only)
1372                          return 1;                          return 1;
1373    
# Line 2110  static int fpu_function(struct cpu *cpu, Line 1379  static int fpu_function(struct cpu *cpu,
1379                   *      FCCR:  bits 7..0                   *      FCCR:  bits 7..0
1380                   *      FCSR:  bits 31..25 and 23                   *      FCSR:  bits 31..25 and 23
1381                   */                   */
1382                  cp->fcr[FPU_FCCR] &= ~(1 << cc);                  cp->fcr[MIPS_FPU_FCCR] &= ~(1 << cc);
1383                  if (cond_true)                  if (cond_true)
1384                          cp->fcr[FPU_FCCR] |= (1 << cc);                          cp->fcr[MIPS_FPU_FCCR] |= (1 << cc);
1385    
1386                  if (cc == 0) {                  if (cc == 0) {
1387                          bit = 1 << FCSR_FCC0_SHIFT;                          bit = 1 << MIPS_FCSR_FCC0_SHIFT;
1388                          cp->fcr[FPU_FCSR] &= ~bit;                          cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1389                          if (cond_true)                          if (cond_true)
1390                                  cp->fcr[FPU_FCSR] |= bit;                                  cp->fcr[MIPS_FPU_FCSR] |= bit;
1391                  } else {                  } else {
1392                          bit = 1 << (FCSR_FCC1_SHIFT + cc-1);                          bit = 1 << (MIPS_FCSR_FCC1_SHIFT + cc-1);
1393                          cp->fcr[FPU_FCSR] &= ~bit;                          cp->fcr[MIPS_FPU_FCSR] &= ~bit;
1394                          if (cond_true)                          if (cond_true)
1395                                  cp->fcr[FPU_FCSR] |= bit;                                  cp->fcr[MIPS_FPU_FCSR] |= bit;
1396                  }                  }
1397    
1398                  return 1;                  return 1;
# Line 2132  static int fpu_function(struct cpu *cpu, Line 1401  static int fpu_function(struct cpu *cpu,
1401          /*  cvt.s.fmt: Convert to single floating-point  */          /*  cvt.s.fmt: Convert to single floating-point  */
1402          if ((function & 0x001f003f) == 0x00000020) {          if ((function & 0x001f003f) == 0x00000020) {
1403                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1404                          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);
1405                  if (unassemble_only)                  if (unassemble_only)
1406                          return 1;                          return 1;
1407    
1408                  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);
1409                  return 1;                  return 1;
1410          }          }
1411    
1412          /*  cvt.d.fmt: Convert to double floating-point  */          /*  cvt.d.fmt: Convert to double floating-point  */
1413          if ((function & 0x001f003f) == 0x00000021) {          if ((function & 0x001f003f) == 0x00000021) {
1414                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1415                          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);
1416                  if (unassemble_only)                  if (unassemble_only)
1417                          return 1;                          return 1;
1418    
1419                  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);
1420                  return 1;                  return 1;
1421          }          }
1422    
1423          /*  cvt.w.fmt: Convert to word fixed-point  */          /*  cvt.w.fmt: Convert to word fixed-point  */
1424          if ((function & 0x001f003f) == 0x00000024) {          if ((function & 0x001f003f) == 0x00000024) {
1425                  if (cpu->machine->instruction_trace || unassemble_only)                  if (cpu->machine->instruction_trace || unassemble_only)
1426                          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);
1427                  if (unassemble_only)                  if (unassemble_only)
1428                          return 1;                          return 1;
1429    
1430                  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);
1431                  return 1;                  return 1;
1432          }          }
1433    
# Line 2288  void coproc_tlbpr(struct cpu *cpu, int r Line 1557  void coproc_tlbpr(struct cpu *cpu, int r
1557  /*  /*
1558   *  coproc_tlbwri():   *  coproc_tlbwri():
1559   *   *
1560   *  'tlbwr' and 'tlbwi'   *  MIPS TLB write random (tlbwr) and write indexed (tlbwi) instructions.
1561   */   */
1562  void coproc_tlbwri(struct cpu *cpu, int randomflag)  void coproc_tlbwri(struct cpu *cpu, int randomflag)
1563  {  {
1564          struct mips_coproc *cp = cpu->cd.mips.coproc[0];          struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1565          int index, g_bit;          int index, g_bit, old_asid = -1;
1566          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;  
1567    
1568          if (randomflag) {          if (randomflag) {
1569                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
1570                            cp->reg[COP0_RANDOM] =
1571                                ((random() % (cp->nr_of_tlbs - 8)) + 8)
1572                                << R2K3K_RANDOM_SHIFT;
1573                          index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)                          index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
1574                              >> R2K3K_RANDOM_SHIFT;                              >> R2K3K_RANDOM_SHIFT;
1575                  else                  } else {
1576                            cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
1577                                % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
1578                          index = cp->reg[COP0_RANDOM] & RANDOM_MASK;                          index = cp->reg[COP0_RANDOM] & RANDOM_MASK;
1579                    }
1580          } else {          } else {
1581                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)                  if (cpu->cd.mips.cpu_type.mmu_model == MMU3K)
1582                          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 1592  void coproc_tlbwri(struct cpu *cpu, int
1592                  return;                  return;
1593          }          }
1594    
1595    
1596  #if 0  #if 0
1597          /*  Debug dump of the previous entry at that index:  */          /*  Debug dump of the previous entry at that index:  */
1598          debug(" old entry at index = %04x", index);          fatal("{ old TLB entry at index %02x:", index);
1599          debug(" mask = %016llx", (long long) cp->tlbs[index].mask);          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1600          debug(" hi = %016llx", (long long) cp->tlbs[index].hi);                  fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1601          debug(" lo0 = %016llx", (long long) cp->tlbs[index].lo0);                  fatal(" lo=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1602          debug(" lo1 = %016llx\n", (long long) cp->tlbs[index].lo1);          } else {
1603                    if (cpu->is_32bit) {
1604                            fatal(" mask=%08"PRIx32,(uint32_t)cp->tlbs[index].mask);
1605                            fatal(" hi=%08"PRIx32, (uint32_t)cp->tlbs[index].hi);
1606                            fatal(" lo0=%08"PRIx32, (uint32_t)cp->tlbs[index].lo0);
1607                            fatal(" lo1=%08"PRIx32, (uint32_t)cp->tlbs[index].lo1);
1608                    } else {
1609                            fatal(" mask=%016"PRIx64, cp->tlbs[index].mask);
1610                            fatal(" hi=%016"PRIx64, cp->tlbs[index].hi);
1611                            fatal(" lo0=%016"PRIx64, cp->tlbs[index].lo0);
1612                            fatal(" lo1=%016"PRIx64, cp->tlbs[index].lo1);
1613                    }
1614            }
1615            fatal(" }\n");
1616  #endif  #endif
1617    
1618          /*  Translation caches must be invalidated:  */          /*
1619             *  Any virtual address translation for the old TLB entry must be
1620             *  invalidated first:
1621             */
1622    
1623          switch (cpu->cd.mips.cpu_type.mmu_model) {          switch (cpu->cd.mips.cpu_type.mmu_model) {
1624    
1625          case MMU3K:          case MMU3K:
1626                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;
1627                  oldvaddr &= 0xffffffffULL;                  oldvaddr &= 0xffffffffULL;
# Line 2360  void coproc_tlbwri(struct cpu *cpu, int Line 1630  void coproc_tlbwri(struct cpu *cpu, int
1630                  old_asid = (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK)                  old_asid = (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK)
1631                      >> R2K3K_ENTRYHI_ASID_SHIFT;                      >> R2K3K_ENTRYHI_ASID_SHIFT;
1632    
1633  /*  TODO: Bug? Why does this if need to be commented out?  */                  cpu->invalidate_translation_caches(cpu, oldvaddr,
1634                        INVALIDATE_VADDR);
                 /*  if (cp->tlbs[index].lo0 & ENTRYLO_V)  */  
                         invalidate_translation_caches(cpu, 0, oldvaddr, 0, 0);  
1635                  break;                  break;
1636          default:  
1637                  if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {          default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1638                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;
1639                          /*  44 addressable bits:  */                          /*  44 addressable bits:  */
1640                          if (oldvaddr & 0x80000000000ULL)                          if (oldvaddr & 0x80000000000ULL)
1641                                  oldvaddr |= 0xfffff00000000000ULL;                                  oldvaddr |= 0xfffff00000000000ULL;
1642                    } else if (cpu->is_32bit) {
1643                            /*  MIPS32 etc.:  */
1644                            oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1645                            oldvaddr = (int32_t)oldvaddr;
1646                  } else {                  } else {
1647                          /*  Assume MMU4K  */                          /*  Assume MMU4K  */
1648                          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 1651  void coproc_tlbwri(struct cpu *cpu, int
1651                                  oldvaddr |= 0xffffff0000000000ULL;                                  oldvaddr |= 0xffffff0000000000ULL;
1652                  }                  }
1653    
1654    #if 1
1655                    cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL);
1656    #else
1657                  /*                  /*
                  *  Both pages:  
                  *  
1658                   *  TODO: non-4KB page sizes!                   *  TODO: non-4KB page sizes!
1659                   */                   */
1660                  invalidate_translation_caches(                  cpu->invalidate_translation_caches(cpu, oldvaddr,
1661                      cpu, 0, oldvaddr & ~0x1fff, 0, 0);                      INVALIDATE_VADDR);
1662                  invalidate_translation_caches(                  cpu->invalidate_translation_caches(cpu, oldvaddr | 0x1000,
1663                      cpu, 0, (oldvaddr & ~0x1fff) | 0x1000, 0, 0);                      INVALIDATE_VADDR);
1664    #endif
1665          }          }
1666    
1667    
# Line 2402  void coproc_tlbwri(struct cpu *cpu, int Line 1676  void coproc_tlbwri(struct cpu *cpu, int
1676          if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&          if (cpu->cd.mips.cpu_type.mmu_model != MMU3K &&
1677              cpu->cd.mips.cpu_type.rev != MIPS_R4100) {              cpu->cd.mips.cpu_type.rev != MIPS_R4100) {
1678                  uint64_t vaddr1, vaddr2;                  uint64_t vaddr1, vaddr2;
1679                  int i, asid;                  int i;
1680                    unsigned int asid;
1681    
1682                  vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K;                  vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K;
1683                  asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;                  asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
# Line 2432  void coproc_tlbwri(struct cpu *cpu, int Line 1707  void coproc_tlbwri(struct cpu *cpu, int
1707          /*  Write the new entry:  */          /*  Write the new entry:  */
1708    
1709          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K) {
1710                  uint64_t vaddr, paddr;                  uint32_t vaddr, paddr;
1711                  int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;                  int wf = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_D? 1 : 0;
1712                  unsigned char *memblock = NULL;                  unsigned char *memblock = NULL;
1713    
# Line 2442  void coproc_tlbwri(struct cpu *cpu, int Line 1717  void coproc_tlbwri(struct cpu *cpu, int
1717                  vaddr =  cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;                  vaddr =  cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_VPN_MASK;
1718                  paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;                  paddr = cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_PFN_MASK;
1719    
1720                  /*  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);  
1721    
1722                    /*  Invalidate any code translation, if we are writing
1723                        a Dirty page to the TLB:  */
1724                    if (wf) {
1725                            cpu->invalidate_code_translation(cpu, paddr,
1726                                INVALIDATE_PADDR);
1727                    }
1728    
1729                    /*  If we have a memblock (host page) for the physical
1730                        page, then add a translation for it immediately:  */
1731                  if (memblock != NULL &&                  if (memblock != NULL &&
1732                      cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) {                      cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) {
1733                          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;  
   
1734                          cpu->update_translation_table(cpu, vaddr, memblock,                          cpu->update_translation_table(cpu, vaddr, memblock,
1735                              wf, paddr);                              wf, paddr);
1736                  }                  }
# Line 2484  void coproc_tlbwri(struct cpu *cpu, int Line 1755  void coproc_tlbwri(struct cpu *cpu, int
1755                          if (g_bit)                          if (g_bit)
1756                                  cp->tlbs[index].hi |= TLB_G;                                  cp->tlbs[index].hi |= TLB_G;
1757                  }                  }
         }  
1758    
1759          if (randomflag) {  #if 1
1760                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {                  cpu_create_or_reset_tc(cpu);
1761                          cp->reg[COP0_RANDOM] =  #else
1762                              ((random() % (cp->nr_of_tlbs - 8)) + 8)                  /*  Invalidate any code translations, if we are writing
1763                              << R2K3K_RANDOM_SHIFT;                      Dirty pages to the TLB:  */
1764    if (cp->reg[COP0_PAGEMASK] != 0)
1765    printf("MASK = %08"PRIx32"\n", (uint32_t)cp->reg[COP0_PAGEMASK]);
1766    
1767    //              if (cp->tlbs[index].lo0 & ENTRYLO_D)
1768                            cpu->invalidate_code_translation(cpu,
1769                                ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK)
1770                                >> ENTRYLO_PFN_SHIFT) << 12,
1771                                INVALIDATE_PADDR);
1772    //              if (cp->tlbs[index].lo1 & ENTRYLO_D)
1773                            cpu->invalidate_code_translation(cpu,
1774                                ((cp->tlbs[index].lo1 & ENTRYLO_PFN_MASK)
1775                                >> ENTRYLO_PFN_SHIFT) << 12,
1776                                INVALIDATE_PADDR);
1777    
1778    
1779            if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1780                            oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;
1781                            /*  44 addressable bits:  */
1782                            if (oldvaddr & 0x80000000000ULL)
1783                                    oldvaddr |= 0xfffff00000000000ULL;
1784                    } else if (cpu->is_32bit) {
1785                            /*  MIPS32 etc.:  */
1786                            oldvaddr = (int32_t)oldvaddr;
1787                  } else {                  } else {
1788                          cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()                          /*  Assume MMU4K  */
1789                              % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1790                            /*  40 addressable bits:  */
1791                            if (oldvaddr & 0x8000000000ULL)
1792                                    oldvaddr |= 0xffffff0000000000ULL;
1793                  }                  }
1794    
1795    cpu->invalidate_translation_caches(cpu, ((cp->tlbs[index].lo0 &
1796    ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << 12, INVALIDATE_PADDR);
1797    cpu->invalidate_translation_caches(cpu, ((cp->tlbs[index].lo1 &
1798    ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << 12, INVALIDATE_PADDR);
1799    
1800    cpu->invalidate_translation_caches(cpu, oldvaddr, INVALIDATE_VADDR);
1801    cpu->invalidate_translation_caches(cpu, oldvaddr | 0x1000, INVALIDATE_VADDR);
1802    
1803    
1804    #endif
1805          }          }
1806  }  }
1807    
# Line 2506  void coproc_tlbwri(struct cpu *cpu, int Line 1813  void coproc_tlbwri(struct cpu *cpu, int
1813   */   */
1814  void coproc_rfe(struct cpu *cpu)  void coproc_rfe(struct cpu *cpu)
1815  {  {
         int oldmode;  
   
         oldmode = cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & MIPS1_SR_KU_CUR;  
   
1816          cpu->cd.mips.coproc[0]->reg[COP0_STATUS] =          cpu->cd.mips.coproc[0]->reg[COP0_STATUS] =
1817              (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) |              (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) |
1818              ((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);  
1819  }  }
1820    
1821    
# Line 2529  void coproc_rfe(struct cpu *cpu) Line 1826  void coproc_rfe(struct cpu *cpu)
1826   */   */
1827  void coproc_eret(struct cpu *cpu)  void coproc_eret(struct cpu *cpu)
1828  {  {
         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;  
   
1829          if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {          if (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & STATUS_ERL) {
1830                  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];  
1831                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_ERL;
1832          } else {          } else {
1833                  cpu->pc = cpu->cd.mips.pc_last =                  cpu->pc = cpu->cd.mips.coproc[0]->reg[COP0_EPC];
1834                      cpu->cd.mips.coproc[0]->reg[COP0_EPC];                  cpu->delay_slot = 0;
                 cpu->cd.mips.delay_slot = 0;  
1835                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;                  cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~STATUS_EXL;
1836          }          }
1837    
1838          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  
1839  }  }
1840    
1841    
# Line 2597  void coproc_function(struct cpu *cpu, st Line 1865  void coproc_function(struct cpu *cpu, st
1865                  return;                  return;
1866          }          }
1867    
 #if 0  
1868          /*  No FPU?  */          /*  No FPU?  */
1869          if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {          if (cpnr == 1 && (cpu->cd.mips.cpu_type.flags & NOFPU)) {
1870                  mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);                  mips_cpu_exception(cpu, EXCEPTION_CPU, 0, 0, cpnr, 0, 0, 0);
1871                  return;                  return;
1872          }          }
 #endif  
1873    
1874          /*  For quick reference:  */          /*  For quick reference:  */
1875          copz = (function >> 21) & 31;          copz = (function >> 21) & 31;
# Line 2618  void coproc_function(struct cpu *cpu, st Line 1884  void coproc_function(struct cpu *cpu, st
1884                          if (cpnr == 0)                          if (cpnr == 0)
1885                                  debug("%s", cop0_names[rd]);                                  debug("%s", cop0_names[rd]);
1886                          else                          else
1887                                  debug("cpreg%i", rd);                                  debug("r%i", rd);
1888                          if (function & 7)                          if (function & 7)
1889                                  debug(",%i", (int)(function & 7));                                  debug(",%i", (int)(function & 7));
1890                          debug("\n");                          debug("\n");
# Line 2644  void coproc_function(struct cpu *cpu, st Line 1910  void coproc_function(struct cpu *cpu, st
1910                          if (cpnr == 0)                          if (cpnr == 0)
1911                                  debug("%s", cop0_names[rd]);                                  debug("%s", cop0_names[rd]);
1912                          else                          else
1913                                  debug("cpreg%i", rd);                                  debug("r%i", rd);
1914                          if (function & 7)                          if (function & 7)
1915                                  debug(",%i", (int)(function & 7));                                  debug(",%i", (int)(function & 7));
1916                          debug("\n");                          debug("\n");
# Line 2673  void coproc_function(struct cpu *cpu, st Line 1939  void coproc_function(struct cpu *cpu, st
1939                                      regnames[rt], fs);                                      regnames[rt], fs);
1940                                  return;                                  return;
1941                          }                          }
1942                          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;  
1943                          /*  TODO: implement delay for gpr[rt]                          /*  TODO: implement delay for gpr[rt]
1944                              (for MIPS I,II,III only)  */                              (for MIPS I,II,III only)  */
1945                          return;                          return;
# Line 2707  void coproc_function(struct cpu *cpu, st Line 1971  void coproc_function(struct cpu *cpu, st
1971                                              on status bits!  */                                              on status bits!  */
1972    
1973                                          switch (fs) {                                          switch (fs) {
1974                                          case FPU_FCCR:                                          case MIPS_FPU_FCCR:
1975                                                  cp->fcr[FPU_FCSR] =                                                  cp->fcr[MIPS_FPU_FCSR] =
1976                                                      (cp->fcr[FPU_FCSR] &                                                      (cp->fcr[MIPS_FPU_FCSR] &
1977                                                      0x017fffffULL) | ((tmp & 1)                                                      0x017fffffULL) | ((tmp & 1)
1978                                                      << FCSR_FCC0_SHIFT)                                                      << MIPS_FCSR_FCC0_SHIFT)
1979                                                      | (((tmp & 0xfe) >> 1) <<                                                      | (((tmp & 0xfe) >> 1) <<
1980                                                      FCSR_FCC1_SHIFT);                                                      MIPS_FCSR_FCC1_SHIFT);
1981                                                  break;                                                  break;
1982                                          case FPU_FCSR:                                          case MIPS_FPU_FCSR:
1983                                                  cp->fcr[FPU_FCCR] =                                                  cp->fcr[MIPS_FPU_FCCR] =
1984                                                      (cp->fcr[FPU_FCCR] &                                                      (cp->fcr[MIPS_FPU_FCCR] &
1985                                                      0xffffff00ULL) | ((tmp >>                                                      0xffffff00ULL) | ((tmp >>
1986                                                      FCSR_FCC0_SHIFT) & 1) |                                                      MIPS_FCSR_FCC0_SHIFT) & 1) |
1987                                                      (((tmp >> FCSR_FCC1_SHIFT)                                                      (((tmp >>
1988                                                        MIPS_FCSR_FCC1_SHIFT)
1989                                                      & 0x7f) << 1);                                                      & 0x7f) << 1);
1990                                                  break;                                                  break;
1991                                          default:                                          default:
# Line 2744  void coproc_function(struct cpu *cpu, st Line 2009  void coproc_function(struct cpu *cpu, st
2009                          return;                          return;
2010          }          }
2011    
         /*  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;  
         }  
   
2012    
2013          /*  Ugly R5900 hacks:  */          /*  Ugly R5900 hacks:  */
2014          if ((function & 0xfffff) == 0x38) {             /*  ei  */          if (cpu->cd.mips.cpu_type.rev == MIPS_R5900) {
2015                  if (unassemble_only) {                  if ((function & 0xfffff) == COP0_EI) {
2016                          debug("ei\n");                          if (unassemble_only) {
2017                                    debug("ei\n");
2018                                    return;
2019                            }
2020                            cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |=
2021                                R5900_STATUS_EIE;
2022                          return;                          return;
2023                  }                  }
                 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] |= R5900_STATUS_EIE;  
                 return;  
         }  
2024    
2025          if ((function & 0xfffff) == 0x39) {             /*  di  */                  if ((function & 0xfffff) == COP0_DI) {
2026                  if (unassemble_only) {                          if (unassemble_only) {
2027                          debug("di\n");                                  debug("di\n");
2028                                    return;
2029                            }
2030                            cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &=
2031                                ~R5900_STATUS_EIE;
2032                          return;                          return;
2033                  }                  }
                 cpu->cd.mips.coproc[0]->reg[COP0_STATUS] &= ~R5900_STATUS_EIE;  
                 return;  
2034          }          }
2035    
2036          co_bit = (function >> 25) & 1;          co_bit = (function >> 25) & 1;
# Line 2826  void coproc_function(struct cpu *cpu, st Line 2071  void coproc_function(struct cpu *cpu, st
2071                                              (long long)cp->reg[COP0_ENTRYLO0]);                                              (long long)cp->reg[COP0_ENTRYLO0]);
2072                                          debug(", lo1=%016llx\n",                                          debug(", lo1=%016llx\n",
2073                                              (long long)cp->reg[COP0_ENTRYLO1]);                                              (long long)cp->reg[COP0_ENTRYLO1]);
2074                                            return;
2075                                  }                                  }
2076                                  coproc_tlbwri(cpu, op == COP0_TLBWR);                                  coproc_tlbwri(cpu, op == COP0_TLBWR);
2077                                  return;                                  return;
# Line 2852  void coproc_function(struct cpu *cpu, st Line 2098  void coproc_function(struct cpu *cpu, st
2098                                  }                                  }
2099                                  coproc_eret(cpu);                                  coproc_eret(cpu);
2100                                  return;                                  return;
2101                            case COP0_DERET:
2102                                    if (unassemble_only) {
2103                                            debug("deret\n");
2104                                            return;
2105                                    }
2106                                    /*
2107                                     *  According to the MIPS64 manual, deret
2108                                     *  loads PC from the DEPC cop0 register, and
2109                                     *  jumps there immediately. No delay slot.
2110                                     *
2111                                     *  TODO: This instruction is only available
2112                                     *  if the processor is in debug mode. (What
2113                                     *  does that mean?) TODO: This instruction
2114                                     *  is undefined in a delay slot.
2115                                     */
2116                                    cpu->pc = cp->reg[COP0_DEPC];
2117                                    cpu->delay_slot = 0;
2118                                    cp->reg[COP0_STATUS] &= ~STATUS_EXL;
2119                                    return;
2120                          case COP0_STANDBY:                          case COP0_STANDBY:
2121                                  if (unassemble_only) {                                  if (unassemble_only) {
2122                                          debug("standby\n");                                          debug("standby\n");
# Line 2907  void coproc_function(struct cpu *cpu, st Line 2172  void coproc_function(struct cpu *cpu, st
2172                  return;                  return;
2173          }          }
2174    
2175          fatal("cpu%i: UNIMPLEMENTED coproc%i function %08lx "          fatal("cpu%i: UNIMPLEMENTED coproc%i function %08"PRIx32" "
2176              "(pc = %016llx)\n", cpu->cpu_id, cp->coproc_nr, function,              "(pc = %016"PRIx64")\n", cpu->cpu_id, cp->coproc_nr,
2177              (long long)cpu->cd.mips.pc_last);              (uint32_t)function, cpu->pc);
2178  #if 1  
         single_step = 1;  
 #else  
2179          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  
2180  }  }
2181    
2182  #endif  /*  ENABLE_MIPS  */  #endif  /*  ENABLE_MIPS  */

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

  ViewVC Help
Powered by ViewVC 1.1.26