/[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 24 by dpavlin, Mon Oct 8 16:19:56 2007 UTC revision 34 by dpavlin, Mon Oct 8 16:21:17 2007 UTC
# Line 1  Line 1 
1  /*  /*
2   *  Copyright (C) 2003-2006  Anders Gavare.  All rights reserved.   *  Copyright (C) 2003-2007  Anders Gavare.  All rights reserved.
3   *   *
4   *  Redistribution and use in source and binary forms, with or without   *  Redistribution and use in source and binary forms, with or without
5   *  modification, are permitted provided that the following conditions are met:   *  modification, are permitted provided that the following conditions are met:
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: cpu_mips_coproc.c,v 1.33 2006/06/22 13:30:38 debug Exp $   *  $Id: cpu_mips_coproc.c,v 1.62 2007/02/03 16:18:56 debug Exp $
29   *   *
30   *  Emulation of MIPS coprocessors.   *  Emulation of MIPS coprocessors.
31   */   */
# Line 45  Line 45 
45  #include "mips_cpu_types.h"  #include "mips_cpu_types.h"
46  #include "misc.h"  #include "misc.h"
47  #include "opcodes_mips.h"  #include "opcodes_mips.h"
48    #include "timer.h"
49    
50    
51  #ifndef ENABLE_MIPS  #ifndef ENABLE_MIPS
# Line 438  struct mips_coproc *mips_coproc_new(stru Line 439  struct mips_coproc *mips_coproc_new(stru
439    
440    
441  /*  /*
442     *  mips_timer_tick():
443     */
444    static void mips_timer_tick(struct timer *timer, void *extra)
445    {
446            struct cpu *cpu = (struct cpu *) extra;
447    
448            cpu->cd.mips.compare_interrupts_pending ++;
449    
450            if ((int32_t) (cpu->cd.mips.coproc[0]->reg[COP0_COUNT] -
451                cpu->cd.mips.coproc[0]->reg[COP0_COMPARE]) < 0) {
452                    cpu->cd.mips.coproc[0]->reg[COP0_COUNT] =
453                        cpu->cd.mips.coproc[0]->reg[COP0_COMPARE];
454            }
455    }
456    
457    
458    /*
459   *  mips_coproc_tlb_set_entry():   *  mips_coproc_tlb_set_entry():
460   *   *
461   *  Used by machine setup code, if a specific machine emulation starts up   *  Used by machine setup code, if a specific machine emulation starts up
# Line 533  static void invalidate_asid(struct cpu * Line 551  static void invalidate_asid(struct cpu *
551                                      INVALIDATE_VADDR);                                      INVALIDATE_VADDR);
552                          }                          }
553          } else {          } else {
554                  /*  TODO: Implement support for other.  */                  int non4kpages = 0;
555                  cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL);                  uint64_t topbit = 1, fillmask = 0xffffff0000000000ULL;
556    
557                    if (cpu->is_32bit) {
558                            topbit = 0x80000000;
559                            fillmask = 0xffffffff00000000ULL;
560                    } else if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
561                            topbit <<= 43;
562                            fillmask <<= 4;
563                    } else {
564                            topbit <<= 39;
565                    }
566    
567                    for (i=0; i<ntlbs; i++) {
568                            if (tlb[i].mask != 0 && tlb[i].mask != 0x1800) {
569                                    non4kpages = 1;
570                                    continue;
571                            }
572    
573                            if ((tlb[i].hi & ENTRYHI_ASID) == asid &&
574                                !(tlb[i].hi & TLB_G)) {
575                                    uint64_t vaddr0, vaddr1;
576                                    vaddr0 = cp->tlbs[i].hi & ~fillmask;
577                                    if (vaddr0 & topbit)
578                                            vaddr0 |= fillmask;
579                                    vaddr1 = vaddr0 | 0x1000;  /*  TODO: mask  */
580    
581                                    if (tlb[i].lo0 & ENTRYLO_V)
582                                            cpu->invalidate_translation_caches(cpu,
583                                                vaddr0, INVALIDATE_VADDR);
584                                    if (tlb[i].lo1 & ENTRYLO_V)
585                                            cpu->invalidate_translation_caches(cpu,
586                                                vaddr1, INVALIDATE_VADDR);
587                            }
588                    }
589    
590                    if (non4kpages) {
591                            cpu->invalidate_translation_caches(cpu,
592                                0, INVALIDATE_ALL);
593                    }
594          }          }
595  }  }
596    
# Line 558  void coproc_register_read(struct cpu *cp Line 614  void coproc_register_read(struct cpu *cp
614          if (cp->coproc_nr==0 && reg_nr==COP0_WIRED)     unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_WIRED)     unimpl = 0;
615          if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR)  unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_BADVADDR)  unimpl = 0;
616          if (cp->coproc_nr==0 && reg_nr==COP0_COUNT) {          if (cp->coproc_nr==0 && reg_nr==COP0_COUNT) {
617  #if 0                  /*  TODO: Increase count in a more meaningful way!  */
618                  /*                  cp->reg[COP0_COUNT] = (int32_t) (cp->reg[COP0_COUNT] + 1);
                  *  This speeds up delay-loops that just read the count  
                  *  register until it has reached a certain value. (Only for  
                  *  R4000 etc.)  
                  *  
                  *  TODO: Maybe this should be optional?  
                  */  
                 if (cpu->cd.mips.cpu_type.exc_model != EXC3K) {  
                         int increase = 500;  
                         int32_t x = cp->reg[COP0_COUNT];  
                         int32_t y = cp->reg[COP0_COMPARE];  
                         int32_t diff = x - y;  
                         if (diff < 0 && diff + increase >= 0  
                             && cpu->cd.mips.compare_register_set) {  
                                 mips_cpu_interrupt(cpu, 7);  
                                 cpu->cd.mips.compare_register_set = 0;  
                         }  
                         cp->reg[COP0_COUNT] = (int64_t)  
                             (int32_t)(cp->reg[COP0_COUNT] + increase);  
                 }  
 #endif  
619                  unimpl = 0;                  unimpl = 0;
620          }          }
621          if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI)   unimpl = 0;          if (cp->coproc_nr==0 && reg_nr==COP0_ENTRYHI)   unimpl = 0;
# Line 739  void coproc_register_write(struct cpu *c Line 775  void coproc_register_write(struct cpu *c
775                          unimpl = 0;                          unimpl = 0;
776                          break;                          break;
777                  case COP0_COMPARE:                  case COP0_COMPARE:
778                          /*  Clear the timer interrupt bit (bit 7):  */                          if (cpu->machine->emulated_hz > 0) {
779                          cpu->cd.mips.compare_register_set = 1;                                  int32_t compare_diff = tmp -
780                          mips_cpu_interrupt_ack(cpu, 7);                                      cp->reg[COP0_COMPARE];
781                                    double hz;
782    
783                                    if (compare_diff < 0)
784                                            hz = tmp - cp->reg[COP0_COUNT];
785    
786                                    if (compare_diff == 0)
787                                            hz = 0;
788                                    else
789                                            hz = (double)cpu->machine->emulated_hz
790                                                / (double)compare_diff;
791    /*
792     *  TODO: DON'T HARDCODE THIS!
793     */
794    hz = 100.0;
795    
796                                    /*  Initialize or re-set the periodic timer:  */
797                                    if (hz > 0) {
798                                            if (cpu->cd.mips.timer == NULL)
799                                                    cpu->cd.mips.timer = timer_add(
800                                                        hz, mips_timer_tick, cpu);
801                                            else
802                                                    timer_update_frequency(
803                                                        cpu->cd.mips.timer, hz);
804                                    }
805                            }
806    
807                            /*  Ack the periodic timer, if it was asserted:  */
808                            if (cp->reg[COP0_CAUSE] & 0x8000 &&
809                                cpu->cd.mips.compare_interrupts_pending > 0)
810                                    cpu->cd.mips.compare_interrupts_pending --;
811    
812                            /*  Clear the timer interrupt assertion (bit 7):  */
813                            cp->reg[COP0_CAUSE] &= ~0x8000;
814    
815                          if (tmp != (uint64_t)(int64_t)(int32_t)tmp)                          if (tmp != (uint64_t)(int64_t)(int32_t)tmp)
816                                  fatal("WARNING: trying to write a 64-bit value"                                  fatal("WARNING: trying to write a 64-bit value"
817                                      " to the COMPARE register!\n");                                      " to the COMPARE register!\n");
818    
819                          tmp = (int64_t)(int32_t)tmp;                          tmp = (int64_t)(int32_t)tmp;
820                            cpu->cd.mips.compare_register_set = 1;
821                          unimpl = 0;                          unimpl = 0;
822                          break;                          break;
823                  case COP0_ENTRYHI:                  case COP0_ENTRYHI:
# Line 828  void coproc_register_write(struct cpu *c Line 900  void coproc_register_write(struct cpu *c
900                  case COP0_STATUS:                  case COP0_STATUS:
901                          oldmode = cp->reg[COP0_STATUS];                          oldmode = cp->reg[COP0_STATUS];
902                          tmp &= ~(1 << 21);      /*  bit 21 is read-only  */                          tmp &= ~(1 << 21);      /*  bit 21 is read-only  */
903    
904                          /*                          /*
905                           *  TODO: Perhaps this can be solved some other                           *  When isolating caches, invalidate all translations.
906                           *  way, like in the old bintrans system?                           *  During the isolation, a special hack in memory_rw.c
907                             *  prevents translation tables from being updated, so
908                             *  the translation caches don't have to be invalidated
909                             *  when switching back to normal mode.
910                           */                           */
911                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&                          if (cpu->cd.mips.cpu_type.mmu_model == MMU3K &&
912                              (oldmode & MIPS1_ISOL_CACHES) !=                              (oldmode & MIPS1_ISOL_CACHES) !=
913                              (tmp & MIPS1_ISOL_CACHES)) {                              (tmp & MIPS1_ISOL_CACHES)) {
914                                  cpu->invalidate_translation_caches(                                  /*  Invalidate everything if we are switching
915                                      cpu, 0, INVALIDATE_ALL);                                      to isolated mode:  */
916                                    if (tmp & MIPS1_ISOL_CACHES) {
917                                  /*  Perhaps add some kind of INVALIDATE_                                          cpu->invalidate_translation_caches(
918                                      ALL_PADDR_WHICH_HAS_A_CORRESPONDING_                                              cpu, 0, INVALIDATE_ALL);
919                                      VADDR of some kind? :-)  */                                  }
                                 cpu_create_or_reset_tc(cpu);  
920                          }                          }
921                          unimpl = 0;                          unimpl = 0;
922                          break;                          break;
# Line 1187  static int fpu_function(struct cpu *cpu, Line 1262  static int fpu_function(struct cpu *cpu,
1262    
1263          /*  bc1f, bc1t, bc1fl, bc1tl:  */          /*  bc1f, bc1t, bc1fl, bc1tl:  */
1264          if ((function & 0x03e00000) == 0x01000000) {          if ((function & 0x03e00000) == 0x01000000) {
1265                  int nd, tf, imm, cond_true;                  int nd, tf, imm;
1266                  char *instr_mnem;                  char *instr_mnem;
1267    
1268                  /*  cc are bits 20..18:  */                  /*  cc are bits 20..18:  */
# Line 1210  static int fpu_function(struct cpu *cpu, Line 1285  static int fpu_function(struct cpu *cpu,
1285                  if (unassemble_only)                  if (unassemble_only)
1286                          return 1;                          return 1;
1287    
1288                  if (cpu->delay_slot) {                  fatal("INTERNAL ERROR: MIPS coprocessor branches should not"
1289                          fatal("%s: jump inside a jump's delay slot, "                      " be implemented in cpu_mips_coproc.c, but in"
1290                              "or similar. TODO\n", instr_mnem);                      " cpu_mips_instr.c!\n");
1291                          cpu->running = 0;                  exit(1);
                         return 1;  
                 }  
   
                 /*  Both the FCCR and FCSR contain condition code bits...  */  
                 if (cc == 0)  
                         cond_true = (cp->fcr[MIPS_FPU_FCSR] >>  
                             MIPS_FCSR_FCC0_SHIFT) & 1;  
                 else  
                         cond_true = (cp->fcr[MIPS_FPU_FCSR] >>  
                             (MIPS_FCSR_FCC1_SHIFT + cc-1)) & 1;  
   
                 if (!tf)  
                         cond_true = !cond_true;  
   
                 if (cond_true) {  
                         cpu->delay_slot = TO_BE_DELAYED;  
                         cpu->delay_jmpaddr = cpu->pc + (imm << 2);  
                 } else {  
                         /*  "likely":  */  
                         if (nd) {  
                                 /*  nullify the delay slot  */  
                                 cpu->cd.mips.nullify_next = 1;  
                         }  
                 }  
   
                 return 1;  
1292          }          }
1293    
1294          /*  add.fmt: Floating-point add  */          /*  add.fmt: Floating-point add  */
# Line 1453  void coproc_tlbpr(struct cpu *cpu, int r Line 1502  void coproc_tlbpr(struct cpu *cpu, int r
1502                              R2K3K_INDEX_SHIFT;                              R2K3K_INDEX_SHIFT;
1503                          if (i >= cp->nr_of_tlbs) {                          if (i >= cp->nr_of_tlbs) {
1504                                  /*  TODO:  exception?  */                                  /*  TODO:  exception?  */
1505                                  fatal("warning: tlbr from index %i (too "                                  fatal("[ warning: tlbr from index %i (too "
1506                                      "high)\n", i);                                      "high) ]\n", i);
1507                                  return;                                  return;
1508                          }                          }
1509    
1510                          /*                          cp->reg[COP0_ENTRYHI]  = cp->tlbs[i].hi;
1511                           *  TODO: Hm. Earlier I had an & ~0x3f on the high                          cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;
                          *  assignment and an & ~0xff on the lo0 assignment.  
                          *  I wonder why.  
                          */  
   
                         cp->reg[COP0_ENTRYHI]  = cp->tlbs[i].hi; /* & ~0x3f; */  
                         cp->reg[COP0_ENTRYLO0] = cp->tlbs[i].lo0;/* & ~0xff; */  
1512                  } else {                  } else {
1513                          /*  R4000:  */                          /*  R4000:  */
1514                          i = cp->reg[COP0_INDEX] & INDEX_MASK;                          i = cp->reg[COP0_INDEX] & INDEX_MASK;
# Line 1562  void coproc_tlbpr(struct cpu *cpu, int r Line 1605  void coproc_tlbpr(struct cpu *cpu, int r
1605  void coproc_tlbwri(struct cpu *cpu, int randomflag)  void coproc_tlbwri(struct cpu *cpu, int randomflag)
1606  {  {
1607          struct mips_coproc *cp = cpu->cd.mips.coproc[0];          struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1608          int index, g_bit, old_asid = -1;          int index, g_bit;
1609          uint64_t oldvaddr;          uint64_t oldvaddr;
1610    
1611          if (randomflag) {          if (randomflag) {
1612                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
1613                          cp->reg[COP0_RANDOM] =                          index = ((cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
1614                              ((random() % (cp->nr_of_tlbs - 8)) + 8)                              >> R2K3K_RANDOM_SHIFT) - 1;
1615                              << R2K3K_RANDOM_SHIFT;                          /*  R3000 always has 8 wired entries:  */
1616                          index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)                          if (index < 8)
1617                              >> R2K3K_RANDOM_SHIFT;                                  index = cp->nr_of_tlbs - 1;
1618                            cp->reg[COP0_RANDOM] = index << R2K3K_RANDOM_SHIFT;
1619                  } else {                  } else {
1620                          cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()                          cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
1621                              % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));                              % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
# Line 1618  void coproc_tlbwri(struct cpu *cpu, int Line 1662  void coproc_tlbwri(struct cpu *cpu, int
1662          /*          /*
1663           *  Any virtual address translation for the old TLB entry must be           *  Any virtual address translation for the old TLB entry must be
1664           *  invalidated first:           *  invalidated first:
1665             *
1666             *  (Only Valid entries need to be invalidated, and only those that
1667             *  are either Global, or have the same ASID as the new entry will
1668             *  have. No other address translations should be active anyway.)
1669           */           */
1670    
1671          switch (cpu->cd.mips.cpu_type.mmu_model) {          switch (cpu->cd.mips.cpu_type.mmu_model) {
1672    
1673          case MMU3K:          case MMU3K:
1674                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;
1675                  oldvaddr &= 0xffffffffULL;                  oldvaddr = (int32_t) oldvaddr;
1676                  if (oldvaddr & 0x80000000ULL)  
1677                          oldvaddr |= 0xffffffff00000000ULL;                  if (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_V &&
1678                  old_asid = (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK)                      (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_G ||
1679                      >> R2K3K_ENTRYHI_ASID_SHIFT;                      (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK) ==
1680                        (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK) ))
1681                            cpu->invalidate_translation_caches(cpu, oldvaddr,
1682                                INVALIDATE_VADDR);
1683    
                 cpu->invalidate_translation_caches(cpu, oldvaddr,  
                     INVALIDATE_VADDR);  
1684                  break;                  break;
1685    
1686          default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {          default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1687                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;                          oldvaddr = cp->tlbs[index].hi &
1688                                (ENTRYHI_VPN2_MASK_R10K | ENTRYHI_R_MASK);
1689                          /*  44 addressable bits:  */                          /*  44 addressable bits:  */
1690                          if (oldvaddr & 0x80000000000ULL)                          if (oldvaddr & 0x80000000000ULL)
1691                                  oldvaddr |= 0xfffff00000000000ULL;                                  oldvaddr |= 0x3ffff00000000000ULL;
1692                  } else if (cpu->is_32bit) {                  } else if (cpu->is_32bit) {
1693                          /*  MIPS32 etc.:  */                          /*  MIPS32 etc.:  */
1694                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1695                          oldvaddr = (int32_t)oldvaddr;                          oldvaddr = (int32_t)oldvaddr;
1696                  } else {                  } else {
1697                          /*  Assume MMU4K  */                          /*  Assume MMU4K  */
1698                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;                          oldvaddr = cp->tlbs[index].hi &
1699                                (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK);
1700                          /*  40 addressable bits:  */                          /*  40 addressable bits:  */
1701                          if (oldvaddr & 0x8000000000ULL)                          if (oldvaddr & 0x8000000000ULL)
1702                                  oldvaddr |= 0xffffff0000000000ULL;                                  oldvaddr |= 0x3fffff0000000000ULL;
1703                  }                  }
1704    
 #if 1  
                 cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL);  
 #else  
1705                  /*                  /*
1706                   *  TODO: non-4KB page sizes!                   *  TODO: non-4KB page sizes!
1707                   */                   */
1708                  cpu->invalidate_translation_caches(cpu, oldvaddr,                  if (cp->tlbs[index].lo0 & ENTRYLO_V)
1709                      INVALIDATE_VADDR);                          cpu->invalidate_translation_caches(cpu, oldvaddr,
1710                  cpu->invalidate_translation_caches(cpu, oldvaddr | 0x1000,                              INVALIDATE_VADDR);
1711                      INVALIDATE_VADDR);                  if (cp->tlbs[index].lo1 & ENTRYLO_V)
1712  #endif                          cpu->invalidate_translation_caches(cpu, oldvaddr|0x1000,
1713                                INVALIDATE_VADDR);
1714          }          }
1715    
1716    #if 0
1717          /*          /*
1718           *  Check for duplicate entries.  (There should not be two mappings           *  Check for duplicate entries.  (There should not be two mappings
1719           *  from one virtual address to physical addresses.)           *  from one virtual address to physical addresses.)
# Line 1679  void coproc_tlbwri(struct cpu *cpu, int Line 1728  void coproc_tlbwri(struct cpu *cpu, int
1728                  int i;                  int i;
1729                  unsigned int asid;                  unsigned int asid;
1730    
1731                  vaddr1 = cp->reg[COP0_ENTRYHI] & ENTRYHI_VPN2_MASK_R10K;                  vaddr1 = cp->reg[COP0_ENTRYHI] &
1732                        (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1733                  asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;                  asid = cp->reg[COP0_ENTRYHI] & ENTRYHI_ASID;
1734                  /*  Since this is just a warning, it's probably not necessary                  /*  Since this is just a warning, it's probably not necessary
1735                      to use R4000 masks etc.  */                      to use R4000 masks etc.  */
# Line 1692  void coproc_tlbwri(struct cpu *cpu, int Line 1742  void coproc_tlbwri(struct cpu *cpu, int
1742                              (cp->tlbs[i].hi & ENTRYHI_ASID) != asid)                              (cp->tlbs[i].hi & ENTRYHI_ASID) != asid)
1743                                  continue;                                  continue;
1744    
1745                          vaddr2 = cp->tlbs[i].hi & ENTRYHI_VPN2_MASK_R10K;                          vaddr2 = cp->tlbs[i].hi &
1746                                (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
1747                          if (vaddr1 == vaddr2 && ((cp->tlbs[i].lo0 &                          if (vaddr1 == vaddr2 && ((cp->tlbs[i].lo0 &
1748                              ENTRYLO_V) || (cp->tlbs[i].lo1 & ENTRYLO_V)))                              ENTRYLO_V) || (cp->tlbs[i].lo1 & ENTRYLO_V)))
1749                                  fatal("\n[ WARNING! tlbw%s to index 0x%02x "                                  fatal("\n[ WARNING! tlbw%s to index 0x%02x "
# Line 1702  void coproc_tlbwri(struct cpu *cpu, int Line 1753  void coproc_tlbwri(struct cpu *cpu, int
1753                                      (long long)vaddr1, asid, i);                                      (long long)vaddr1, asid, i);
1754                  }                  }
1755          }          }
1756    #endif
1757    
1758          /*  Write the new entry:  */          /*  Write the new entry:  */
1759    
# Line 1726  void coproc_tlbwri(struct cpu *cpu, int Line 1777  void coproc_tlbwri(struct cpu *cpu, int
1777                              INVALIDATE_PADDR);                              INVALIDATE_PADDR);
1778                  }                  }
1779    
1780                    /*  Set new last_written_tlb_index hint:  */
1781                    cpu->cd.mips.last_written_tlb_index = index;
1782    
1783                    if (cp->reg[COP0_STATUS] & MIPS1_ISOL_CACHES) {
1784                            fatal("Wow! Interesting case; tlbw* while caches"
1785                                " are isolated. TODO\n");
1786                            /*  Don't update the translation table in this
1787                                case...  */
1788                            exit(1);
1789                    }
1790    
1791                  /*  If we have a memblock (host page) for the physical                  /*  If we have a memblock (host page) for the physical
1792                      page, then add a translation for it immediately:  */                      page, then add a translation for it immediately:  */
1793                  if (memblock != NULL &&                  if (memblock != NULL &&
1794                      cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) {                      cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V)
                         memblock += (paddr & ((1 << BITS_PER_PAGETABLE) - 1));  
1795                          cpu->update_translation_table(cpu, vaddr, memblock,                          cpu->update_translation_table(cpu, vaddr, memblock,
1796                              wf, paddr);                              wf, paddr);
                 }  
1797          } else {          } else {
1798                  /*  R4000:  */                  /*  R4000 etc.:  */
1799                  g_bit = (cp->reg[COP0_ENTRYLO0] &                  unsigned char *memblock = NULL;
1800                      cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;                  int pfn_shift = 12, vpn_shift = 12;
1801                    int wf0, wf1, mask;
1802                    uint64_t vaddr0, vaddr1, paddr0, paddr1, ptmp;
1803    
1804                  cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];                  cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];
1805                  cp->tlbs[index].hi   = cp->reg[COP0_ENTRYHI];                  cp->tlbs[index].hi   = cp->reg[COP0_ENTRYHI];
1806                  cp->tlbs[index].lo1  = cp->reg[COP0_ENTRYLO1];                  cp->tlbs[index].lo1  = cp->reg[COP0_ENTRYLO1];
1807                  cp->tlbs[index].lo0  = cp->reg[COP0_ENTRYLO0];                  cp->tlbs[index].lo0  = cp->reg[COP0_ENTRYLO0];
1808    
1809                    wf0 = cp->tlbs[index].lo0 & ENTRYLO_D;
1810                    wf1 = cp->tlbs[index].lo1 & ENTRYLO_D;
1811    
1812                    mask = cp->reg[COP0_PAGEMASK];
1813                  if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {                  if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1814                          /*  NOTE: The VR4131 (and possibly others) don't have                          pfn_shift = 10;
1815                              a Global bit in entryhi  */                          mask |= 0x07ff;
                         cp->tlbs[index].hi &= ~cp->reg[COP0_PAGEMASK];  
1816                  } else {                  } else {
1817                          cp->tlbs[index].lo0 &= ~ENTRYLO_G;                          mask |= 0x1fff;
1818                          cp->tlbs[index].lo1 &= ~ENTRYLO_G;                  }
1819                    switch (mask) {
1820                          cp->tlbs[index].hi &= ~TLB_G;                  case 0x00007ff:
1821                          if (g_bit)                          if (cp->tlbs[index].lo0 & ENTRYLO_V ||
1822                                  cp->tlbs[index].hi |= TLB_G;                              cp->tlbs[index].lo1 & ENTRYLO_V) {
1823                                    fatal("1KB pages don't work with dyntrans.\n");
1824                                    exit(1);
1825                            }
1826                            vpn_shift = 10;
1827                            break;
1828                    case 0x0001fff: break;
1829                    case 0x0007fff: vpn_shift = 14; break;
1830                    case 0x001ffff: vpn_shift = 16; break;
1831                    case 0x007ffff: vpn_shift = 18; break;
1832                    case 0x01fffff: vpn_shift = 20; break;
1833                    case 0x07fffff: vpn_shift = 22; break;
1834                    case 0x1ffffff: vpn_shift = 24; break;
1835                    case 0x7ffffff: vpn_shift = 26; break;
1836                    default:fatal("Unimplemented MASK = 0x%016x\n", mask);
1837                            exit(1);
1838                  }                  }
1839    
1840  #if 1                  paddr0 = ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK)
1841                  cpu_create_or_reset_tc(cpu);                      >> ENTRYLO_PFN_SHIFT) << pfn_shift;
1842  #else                  paddr1 = ((cp->tlbs[index].lo1 & ENTRYLO_PFN_MASK)
1843                  /*  Invalidate any code translations, if we are writing                      >> ENTRYLO_PFN_SHIFT) << pfn_shift;
1844                      Dirty pages to the TLB:  */  
1845  if (cp->reg[COP0_PAGEMASK] != 0)                  if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1846  printf("MASK = %08"PRIx32"\n", (uint32_t)cp->reg[COP0_PAGEMASK]);                          vaddr0 = cp->tlbs[index].hi &
1847                                (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K);
 //              if (cp->tlbs[index].lo0 & ENTRYLO_D)  
                         cpu->invalidate_code_translation(cpu,  
                             ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK)  
                             >> ENTRYLO_PFN_SHIFT) << 12,  
                             INVALIDATE_PADDR);  
 //              if (cp->tlbs[index].lo1 & ENTRYLO_D)  
                         cpu->invalidate_code_translation(cpu,  
                             ((cp->tlbs[index].lo1 & ENTRYLO_PFN_MASK)  
                             >> ENTRYLO_PFN_SHIFT) << 12,  
                             INVALIDATE_PADDR);  
   
   
         if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {  
                         oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;  
1848                          /*  44 addressable bits:  */                          /*  44 addressable bits:  */
1849                          if (oldvaddr & 0x80000000000ULL)                          if (vaddr0 & 0x80000000000ULL)
1850                                  oldvaddr |= 0xfffff00000000000ULL;                                  vaddr0 |= 0x3ffff00000000000ULL;
1851                  } else if (cpu->is_32bit) {                  } else if (cpu->is_32bit) {
1852                          /*  MIPS32 etc.:  */                          /*  MIPS32 etc.:  */
1853                          oldvaddr = (int32_t)oldvaddr;                          vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1854                            vaddr0 = (int32_t)vaddr0;
1855                  } else {                  } else {
1856                          /*  Assume MMU4K  */                          /*  Assume MMU4K  */
1857                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;                          vaddr0 = cp->tlbs[index].hi &
1858                                (ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK);
1859                          /*  40 addressable bits:  */                          /*  40 addressable bits:  */
1860                          if (oldvaddr & 0x8000000000ULL)                          if (vaddr0 & 0x8000000000ULL)
1861                                  oldvaddr |= 0xffffff0000000000ULL;                                  vaddr0 |= 0x3fffff0000000000ULL;
1862                  }                  }
1863    
1864  cpu->invalidate_translation_caches(cpu, ((cp->tlbs[index].lo0 &                  vaddr1 = vaddr0 | (1 << vpn_shift);
 ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << 12, INVALIDATE_PADDR);  
 cpu->invalidate_translation_caches(cpu, ((cp->tlbs[index].lo1 &  
 ENTRYLO_PFN_MASK) >> ENTRYLO_PFN_SHIFT) << 12, INVALIDATE_PADDR);  
1865    
1866  cpu->invalidate_translation_caches(cpu, oldvaddr, INVALIDATE_VADDR);                  g_bit = (cp->reg[COP0_ENTRYLO0] &
1867  cpu->invalidate_translation_caches(cpu, oldvaddr | 0x1000, INVALIDATE_VADDR);                      cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;
1868    
1869                    if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1870                            /*  NOTE: The VR4131 (and possibly others) don't have
1871                                a Global bit in entryhi  */
1872                            cp->tlbs[index].hi &= ~cp->reg[COP0_PAGEMASK];
1873                    } else {
1874                            cp->tlbs[index].lo0 &= ~ENTRYLO_G;
1875                            cp->tlbs[index].lo1 &= ~ENTRYLO_G;
1876    
1877  #endif                          cp->tlbs[index].hi &= ~TLB_G;
1878          }                          if (g_bit)
1879  }                                  cp->tlbs[index].hi |= TLB_G;
1880                    }
1881    
1882                    /*
1883                     *  Invalidate any code translations, if we are writing Dirty
1884                     *  pages to the TLB:  (TODO: 4KB hardcoded... ugly)
1885                     */
1886                    for (ptmp = 0; ptmp < (1 << pfn_shift); ptmp += 0x1000) {
1887                            if (wf0)
1888                                    cpu->invalidate_code_translation(cpu,
1889                                        paddr0 + ptmp, INVALIDATE_PADDR);
1890                            if (wf1)
1891                                    cpu->invalidate_code_translation(cpu,
1892                                        paddr1 + ptmp, INVALIDATE_PADDR);
1893                    }
1894    
1895                    /*
1896                     *  If we have a memblock (host page) for the physical page,
1897                     *  then add a translation for it immediately, to save some
1898                     *  time. (It would otherwise be added later on anyway,
1899                     *  because of a translation miss.)
1900                     *
1901                     *  NOTE/TODO: This is only for 4KB pages so far. It would
1902                     *             be too expensive to add e.g. 16MB pages like
1903                     *             this.
1904                     */
1905                    memblock = memory_paddr_to_hostaddr(cpu->mem, paddr0, 0);
1906                    if (memblock != NULL && cp->reg[COP0_ENTRYLO0] & ENTRYLO_V)
1907                            cpu->update_translation_table(cpu, vaddr0, memblock,
1908                                wf0, paddr0);
1909                    memblock = memory_paddr_to_hostaddr(cpu->mem, paddr1, 0);
1910                    if (memblock != NULL && cp->reg[COP0_ENTRYLO1] & ENTRYLO_V)
1911                            cpu->update_translation_table(cpu, vaddr1, memblock,
1912                                wf1, paddr1);
1913    
1914  /*                  /*  Set new last_written_tlb_index hint:  */
1915   *  coproc_rfe():                  cpu->cd.mips.last_written_tlb_index = index;
1916   *          }
  *  Return from exception. (R3000 etc.)  
  */  
 void coproc_rfe(struct cpu *cpu)  
 {  
         cpu->cd.mips.coproc[0]->reg[COP0_STATUS] =  
             (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) |  
             ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 0x3c) >> 2);  
1917  }  }
1918    
1919    
# Line 2037  void coproc_function(struct cpu *cpu, st Line 2135  void coproc_function(struct cpu *cpu, st
2135    
2136          /*  TLB operations and other things:  */          /*  TLB operations and other things:  */
2137          if (cp->coproc_nr == 0) {          if (cp->coproc_nr == 0) {
2138                    if (!unassemble_only) {
2139                            fatal("FATAL INTERNAL ERROR: Should be implemented"
2140                                " with dyntrans instead.\n");
2141                            exit(1);
2142                    }
2143    
2144                  op = (function) & 0xff;                  op = (function) & 0xff;
2145                  switch (co_bit) {                  switch (co_bit) {
2146                  case 1:                  case 1:
2147                          switch (op) {                          switch (op) {
2148                          case COP0_TLBR:         /*  Read indexed TLB entry  */                          case COP0_TLBR:         /*  Read indexed TLB entry  */
2149                                  if (unassemble_only) {                                  debug("tlbr\n");
                                         debug("tlbr\n");  
                                         return;  
                                 }  
                                 coproc_tlbpr(cpu, 1);  
2150                                  return;                                  return;
2151                          case COP0_TLBWI:        /*  Write indexed  */                          case COP0_TLBWI:        /*  Write indexed  */
2152                          case COP0_TLBWR:        /*  Write random  */                          case COP0_TLBWR:        /*  Write random  */
2153                                  if (unassemble_only) {                                  if (op == COP0_TLBWI)
2154                                          if (op == COP0_TLBWI)                                          debug("tlbwi");
2155                                                  debug("tlbwi");                                  else
2156                                          else                                          debug("tlbwr");
2157                                                  debug("tlbwr");                                  if (!running) {
2158                                          if (!running) {                                          debug("\n");
                                                 debug("\n");  
                                                 return;  
                                         }  
                                         debug("\tindex=%08llx",  
                                             (long long)cp->reg[COP0_INDEX]);  
                                         debug(", random=%08llx",  
                                             (long long)cp->reg[COP0_RANDOM]);  
                                         debug(", mask=%016llx",  
                                             (long long)cp->reg[COP0_PAGEMASK]);  
                                         debug(", hi=%016llx",  
                                             (long long)cp->reg[COP0_ENTRYHI]);  
                                         debug(", lo0=%016llx",  
                                             (long long)cp->reg[COP0_ENTRYLO0]);  
                                         debug(", lo1=%016llx\n",  
                                             (long long)cp->reg[COP0_ENTRYLO1]);  
2159                                          return;                                          return;
2160                                  }                                  }
2161                                  coproc_tlbwri(cpu, op == COP0_TLBWR);                                  debug("\tindex=%08llx",
2162                                        (long long)cp->reg[COP0_INDEX]);
2163                                    debug(", random=%08llx",
2164                                        (long long)cp->reg[COP0_RANDOM]);
2165                                    debug(", mask=%016llx",
2166                                        (long long)cp->reg[COP0_PAGEMASK]);
2167                                    debug(", hi=%016llx",
2168                                        (long long)cp->reg[COP0_ENTRYHI]);
2169                                    debug(", lo0=%016llx",
2170                                        (long long)cp->reg[COP0_ENTRYLO0]);
2171                                    debug(", lo1=%016llx\n",
2172                                        (long long)cp->reg[COP0_ENTRYLO1]);
2173                                  return;                                  return;
2174                          case COP0_TLBP:         /*  Probe TLB for                          case COP0_TLBP:         /*  Probe TLB for
2175                                                      matching entry  */                                                      matching entry  */
2176                                  if (unassemble_only) {                                  debug("tlbp\n");
                                         debug("tlbp\n");  
                                         return;  
                                 }  
                                 coproc_tlbpr(cpu, 0);  
2177                                  return;                                  return;
2178                          case COP0_RFE:          /*  R2000/R3000 only:                          case COP0_RFE:          /*  R2000/R3000 only:
2179                                                      Return from Exception  */                                                      Return from Exception  */
2180                                  if (unassemble_only) {                                  debug("rfe\n");
                                         debug("rfe\n");  
                                         return;  
                                 }  
                                 coproc_rfe(cpu);  
2181                                  return;                                  return;
2182                          case COP0_ERET: /*  R4000: Return from exception  */                          case COP0_ERET: /*  R4000: Return from exception  */
2183                                  if (unassemble_only) {                                  debug("eret\n");
                                         debug("eret\n");  
                                         return;  
                                 }  
                                 coproc_eret(cpu);  
2184                                  return;                                  return;
2185                          case COP0_DERET:                          case COP0_DERET:
2186                                  if (unassemble_only) {                                  debug("deret\n");
2187                                          debug("deret\n");                                  return;
2188                                          return;                          case COP0_WAIT:
2189                                    {
2190                                            int code = (function >> 6) & 0x7ffff;
2191                                            debug("wait");
2192                                            if (code > 0)
2193                                                    debug("\t0x%x", code);
2194                                            debug("\n");
2195                                  }                                  }
                                 /*  
                                  *  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 = cp->reg[COP0_DEPC];  
                                 cpu->delay_slot = 0;  
                                 cp->reg[COP0_STATUS] &= ~STATUS_EXL;  
2196                                  return;                                  return;
2197                          case COP0_STANDBY:                          case COP0_STANDBY:
2198                                  if (unassemble_only) {                                  debug("standby\n");
                                         debug("standby\n");  
                                         return;  
                                 }  
                                 /*  TODO: Hm. Do something here?  */  
2199                                  return;                                  return;
2200                          case COP0_SUSPEND:                          case COP0_SUSPEND:
2201                                  if (unassemble_only) {                                  debug("suspend\n");
                                         debug("suspend\n");  
                                         return;  
                                 }  
                                 /*  TODO: Hm. Do something here?  */  
2202                                  return;                                  return;
2203                          case COP0_HIBERNATE:                          case COP0_HIBERNATE:
2204                                  if (unassemble_only) {                                  debug("hibernate\n");
                                         debug("hibernate\n");  
                                         return;  
                                 }  
                                 /*  TODO: Hm. Do something here?  */  
2205                                  return;                                  return;
2206                          default:                          default:
2207                                  ;                                  ;
# Line 2156  void coproc_function(struct cpu *cpu, st Line 2221  void coproc_function(struct cpu *cpu, st
2221                  return;                  return;
2222          }          }
2223    
         /*  TODO: RM5200 idle (?)  */  
         if ((cp->coproc_nr==0 || cp->coproc_nr==3) && function == 0x02000020) {  
                 if (unassemble_only) {  
                         debug("idle(?)\n");     /*  TODO  */  
                         return;  
                 }  
   
                 /*  Idle? TODO  */  
                 return;  
         }  
   
2224          if (unassemble_only) {          if (unassemble_only) {
2225                  debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function);                  debug("cop%i\t0x%08x (unimplemented)\n", cpnr, (int)function);
2226                  return;                  return;

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

  ViewVC Help
Powered by ViewVC 1.1.26