/[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 26 by dpavlin, Mon Oct 8 16:20:10 2007 UTC revision 28 by dpavlin, Mon Oct 8 16:20:26 2007 UTC
# Line 25  Line 25 
25   *  SUCH DAMAGE.   *  SUCH DAMAGE.
26   *   *
27   *   *
28   *  $Id: cpu_mips_coproc.c,v 1.37 2006/06/25 02:46:07 debug Exp $   *  $Id: cpu_mips_coproc.c,v 1.49 2006/07/21 20:39:40 debug Exp $
29   *   *
30   *  Emulation of MIPS coprocessors.   *  Emulation of MIPS coprocessors.
31   */   */
# Line 533  static void invalidate_asid(struct cpu * Line 533  static void invalidate_asid(struct cpu *
533                                      INVALIDATE_VADDR);                                      INVALIDATE_VADDR);
534                          }                          }
535          } else {          } else {
536                  /*  TODO: Implement support for other.  */                  int non4kpages = 0;
537                  cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL);                  uint64_t topbit = 1, fillmask = 0xffffff0000000000ULL;
538    
539                    if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
540                            topbit <<= 43;
541                            fillmask <<= 4;
542                    } else {
543                            topbit <<= 39;
544                    }
545    
546                    for (i=0; i<ntlbs; i++) {
547                            if (tlb[i].mask != 0 && tlb[i].mask != 0x1800) {
548                                    non4kpages = 1;
549                                    continue;
550                            }
551    
552                            if ((tlb[i].hi & ENTRYHI_ASID) == asid &&
553                                !(tlb[i].hi & TLB_G)) {
554                                    uint64_t vaddr0, vaddr1;
555                                    vaddr0 = cp->tlbs[i].hi & ~fillmask;
556                                    if (vaddr0 & topbit)
557                                            vaddr0 |= fillmask;
558                                    vaddr1 = vaddr0 | 0x1000;  /*  TODO: mask  */
559    
560                                    if (tlb[i].lo0 & ENTRYLO_V)
561                                            cpu->invalidate_translation_caches(cpu,
562                                                vaddr0, INVALIDATE_VADDR);
563                                    if (tlb[i].lo1 & ENTRYLO_V)
564                                            cpu->invalidate_translation_caches(cpu,
565                                                vaddr1, INVALIDATE_VADDR);
566                            }
567                    }
568    
569                    if (non4kpages) {
570                            cpu->invalidate_translation_caches(cpu,
571                                0, INVALIDATE_ALL);
572                    }
573          }          }
574  }  }
575    
# Line 821  void coproc_register_write(struct cpu *c Line 856  void coproc_register_write(struct cpu *c
856                                          cpu->invalidate_translation_caches(                                          cpu->invalidate_translation_caches(
857                                              cpu, 0, INVALIDATE_ALL);                                              cpu, 0, INVALIDATE_ALL);
858                                  }                                  }
   
 #if 1  
                                 /*  
                                  *  NOTE: This is not needed for NetBSD, but  
                                  *  Ultrix and Linux still needs this. They  
                                  *  shouldn't, though. Something else is buggy.  
                                  */  
                                 cpu_create_or_reset_tc(cpu);  
 #endif  
859                          }                          }
860                          unimpl = 0;                          unimpl = 0;
861                          break;                          break;
# Line 1550  void coproc_tlbpr(struct cpu *cpu, int r Line 1576  void coproc_tlbpr(struct cpu *cpu, int r
1576  void coproc_tlbwri(struct cpu *cpu, int randomflag)  void coproc_tlbwri(struct cpu *cpu, int randomflag)
1577  {  {
1578          struct mips_coproc *cp = cpu->cd.mips.coproc[0];          struct mips_coproc *cp = cpu->cd.mips.coproc[0];
1579          int index, g_bit, old_asid = -1;          int index, g_bit;
1580          uint64_t oldvaddr;          uint64_t oldvaddr;
1581    
1582          if (randomflag) {          if (randomflag) {
1583                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {                  if (cpu->cd.mips.cpu_type.exc_model == EXC3K) {
1584                          cp->reg[COP0_RANDOM] =                          index = ((cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)
1585                              ((random() % (cp->nr_of_tlbs - 8)) + 8)                              >> R2K3K_RANDOM_SHIFT) - 1;
1586                              << R2K3K_RANDOM_SHIFT;                          /*  R3000 always has 8 wired entries:  */
1587                          index = (cp->reg[COP0_RANDOM] & R2K3K_RANDOM_MASK)                          if (index < 8)
1588                              >> R2K3K_RANDOM_SHIFT;                                  index = cp->nr_of_tlbs - 1;
1589                            cp->reg[COP0_RANDOM] = index << R2K3K_RANDOM_SHIFT;
1590                  } else {                  } else {
1591                          cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()                          cp->reg[COP0_RANDOM] = cp->reg[COP0_WIRED] + (random()
1592                              % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));                              % (cp->nr_of_tlbs - cp->reg[COP0_WIRED]));
# Line 1606  void coproc_tlbwri(struct cpu *cpu, int Line 1633  void coproc_tlbwri(struct cpu *cpu, int
1633          /*          /*
1634           *  Any virtual address translation for the old TLB entry must be           *  Any virtual address translation for the old TLB entry must be
1635           *  invalidated first:           *  invalidated first:
1636             *
1637             *  (Only Valid entries need to be invalidated, and only those that
1638             *  are either Global, or have the same ASID as the new entry will
1639             *  have. No other address translations should be active anyway.)
1640           */           */
1641    
1642          switch (cpu->cd.mips.cpu_type.mmu_model) {          switch (cpu->cd.mips.cpu_type.mmu_model) {
1643    
1644          case MMU3K:          case MMU3K:
1645                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;                  oldvaddr = cp->tlbs[index].hi & R2K3K_ENTRYHI_VPN_MASK;
1646                  oldvaddr &= 0xffffffffULL;                  oldvaddr = (int32_t) oldvaddr;
                 if (oldvaddr & 0x80000000ULL)  
                         oldvaddr |= 0xffffffff00000000ULL;  
                 old_asid = (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK)  
                     >> R2K3K_ENTRYHI_ASID_SHIFT;  
1647    
1648                  cpu->invalidate_translation_caches(cpu, oldvaddr,                  if (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_V &&
1649                      INVALIDATE_VADDR);                      (cp->tlbs[index].lo0 & R2K3K_ENTRYLO_G ||
1650                        (cp->tlbs[index].hi & R2K3K_ENTRYHI_ASID_MASK) ==
1651                        (cp->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK) ))
1652                            cpu->invalidate_translation_caches(cpu, oldvaddr,
1653                                INVALIDATE_VADDR);
1654                  break;                  break;
1655    
1656          default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {          default:if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
# Line 1639  void coproc_tlbwri(struct cpu *cpu, int Line 1670  void coproc_tlbwri(struct cpu *cpu, int
1670                                  oldvaddr |= 0xffffff0000000000ULL;                                  oldvaddr |= 0xffffff0000000000ULL;
1671                  }                  }
1672    
1673  #if 1  #if 0
1674                    /*  TODO: FIX THIS! It shouldn't be needed!  */
1675                  cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL);                  cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL);
1676  #else  #else
1677                  /*                  /*
1678                   *  TODO: non-4KB page sizes!                   *  TODO: non-4KB page sizes!
1679                   */                   */
1680                  cpu->invalidate_translation_caches(cpu, oldvaddr,                  if (cp->tlbs[index].lo0 & ENTRYLO_V)
1681                      INVALIDATE_VADDR);                          cpu->invalidate_translation_caches(cpu, oldvaddr,
1682                  cpu->invalidate_translation_caches(cpu, oldvaddr | 0x1000,                              INVALIDATE_VADDR);
1683                      INVALIDATE_VADDR);                  if (cp->tlbs[index].lo1 & ENTRYLO_V)
1684                            cpu->invalidate_translation_caches(cpu, oldvaddr|0x1000,
1685                                INVALIDATE_VADDR);
1686  #endif  #endif
1687          }          }
1688    
1689    #if 0
1690          /*          /*
1691           *  Check for duplicate entries.  (There should not be two mappings           *  Check for duplicate entries.  (There should not be two mappings
1692           *  from one virtual address to physical addresses.)           *  from one virtual address to physical addresses.)
# Line 1690  void coproc_tlbwri(struct cpu *cpu, int Line 1724  void coproc_tlbwri(struct cpu *cpu, int
1724                                      (long long)vaddr1, asid, i);                                      (long long)vaddr1, asid, i);
1725                  }                  }
1726          }          }
1727    #endif
1728    
1729          /*  Write the new entry:  */          /*  Write the new entry:  */
1730    
# Line 1714  void coproc_tlbwri(struct cpu *cpu, int Line 1748  void coproc_tlbwri(struct cpu *cpu, int
1748                              INVALIDATE_PADDR);                              INVALIDATE_PADDR);
1749                  }                  }
1750    
1751                    if (cp->reg[COP0_STATUS] & MIPS1_ISOL_CACHES) {
1752                            fatal("Wow! Interesting case; tlbw* while caches"
1753                                " are isolated. TODO\n");
1754                            /*  Don't update the translation table in this
1755                                case...  */
1756                            exit(1);
1757                    }
1758    
1759                  /*  If we have a memblock (host page) for the physical                  /*  If we have a memblock (host page) for the physical
1760                      page, then add a translation for it immediately:  */                      page, then add a translation for it immediately:  */
1761                  if (memblock != NULL &&                  if (memblock != NULL &&
1762                      cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V) {                      cp->reg[COP0_ENTRYLO0] & R2K3K_ENTRYLO_V)
                         memblock += (paddr & ((1 << BITS_PER_PAGETABLE) - 1));  
1763                          cpu->update_translation_table(cpu, vaddr, memblock,                          cpu->update_translation_table(cpu, vaddr, memblock,
1764                              wf, paddr);                              wf, paddr);
                 }  
1765          } else {          } else {
1766                  /*  R4000:  */                  /*  R4000 etc.:  */
1767                  g_bit = (cp->reg[COP0_ENTRYLO0] &                  unsigned char *memblock = NULL;
1768                      cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;                  int pfn_shift = 12, vpn_shift = 12;
1769                    int wf0, wf1, mask;
1770                    uint64_t vaddr0, vaddr1, paddr0, paddr1, ptmp;
1771    
1772                  cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];                  cp->tlbs[index].mask = cp->reg[COP0_PAGEMASK];
1773                  cp->tlbs[index].hi   = cp->reg[COP0_ENTRYHI];                  cp->tlbs[index].hi   = cp->reg[COP0_ENTRYHI];
1774                  cp->tlbs[index].lo1  = cp->reg[COP0_ENTRYLO1];                  cp->tlbs[index].lo1  = cp->reg[COP0_ENTRYLO1];
1775                  cp->tlbs[index].lo0  = cp->reg[COP0_ENTRYLO0];                  cp->tlbs[index].lo0  = cp->reg[COP0_ENTRYLO0];
1776    
1777                    wf0 = cp->tlbs[index].lo0 & ENTRYLO_D;
1778                    wf1 = cp->tlbs[index].lo1 & ENTRYLO_D;
1779    
1780                    mask = cp->reg[COP0_PAGEMASK];
1781                  if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {                  if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1782                          /*  NOTE: The VR4131 (and possibly others) don't have                          pfn_shift = 10;
1783                              a Global bit in entryhi  */                          mask |= 0x07ff;
                         cp->tlbs[index].hi &= ~cp->reg[COP0_PAGEMASK];  
1784                  } else {                  } else {
1785                          cp->tlbs[index].lo0 &= ~ENTRYLO_G;                          mask |= 0x1fff;
                         cp->tlbs[index].lo1 &= ~ENTRYLO_G;  
   
                         cp->tlbs[index].hi &= ~TLB_G;  
                         if (g_bit)  
                                 cp->tlbs[index].hi |= TLB_G;  
1786                  }                  }
1787                    switch (mask) {
1788                  /*  Invalidate any code translations, if we are writing                  case 0x00007ff:
1789                      Dirty pages to the TLB:  */                          if (cp->tlbs[index].lo0 & ENTRYLO_V ||
1790                  if (cp->reg[COP0_PAGEMASK] != 0 &&                              cp->tlbs[index].lo1 & ENTRYLO_V) {
1791                      cp->reg[COP0_PAGEMASK] != 0x1800) {                                  fatal("1KB pages don't work with dyntrans.\n");
1792                          printf("TODO: MASK = %08"PRIx32"\n",                                  exit(1);
1793                              (uint32_t)cp->reg[COP0_PAGEMASK]);                          }
1794                            vpn_shift = 10;
1795                            break;
1796                    case 0x0001fff: break;
1797                    case 0x0007fff: vpn_shift = 14; break;
1798                    case 0x001ffff: vpn_shift = 16; break;
1799                    case 0x007ffff: vpn_shift = 18; break;
1800                    case 0x01fffff: vpn_shift = 20; break;
1801                    case 0x07fffff: vpn_shift = 22; break;
1802                    case 0x1ffffff: vpn_shift = 24; break;
1803                    case 0x7ffffff: vpn_shift = 26; break;
1804                    default:fatal("Unimplemented MASK = 0x%016x\n", mask);
1805                          exit(1);                          exit(1);
1806                  }                  }
1807    
1808                  if (cp->tlbs[index].lo0 & ENTRYLO_D)                  paddr0 = ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK)
1809                          cpu->invalidate_code_translation(cpu,                      >> ENTRYLO_PFN_SHIFT) << pfn_shift;
1810                              ((cp->tlbs[index].lo0 & ENTRYLO_PFN_MASK)                  paddr1 = ((cp->tlbs[index].lo1 & ENTRYLO_PFN_MASK)
1811                              >> ENTRYLO_PFN_SHIFT) << 12,                      >> ENTRYLO_PFN_SHIFT) << pfn_shift;
                             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);  
1812    
1813  #if 1                  if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {
1814          if (cpu->cd.mips.cpu_type.mmu_model == MMU10K) {                          vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;
                         oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK_R10K;  
1815                          /*  44 addressable bits:  */                          /*  44 addressable bits:  */
1816                          if (oldvaddr & 0x80000000000ULL)                          if (vaddr0 & 0x80000000000ULL)
1817                                  oldvaddr |= 0xfffff00000000000ULL;                                  vaddr0 |= 0xfffff00000000000ULL;
1818                  } else if (cpu->is_32bit) {                  } else if (cpu->is_32bit) {
1819                          /*  MIPS32 etc.:  */                          /*  MIPS32 etc.:  */
1820                          oldvaddr = (int32_t)oldvaddr;                          vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1821                            vaddr0 = (int32_t)vaddr0;
1822                  } else {                  } else {
1823                          /*  Assume MMU4K  */                          /*  Assume MMU4K  */
1824                          oldvaddr = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;                          vaddr0 = cp->tlbs[index].hi & ENTRYHI_VPN2_MASK;
1825                          /*  40 addressable bits:  */                          /*  40 addressable bits:  */
1826                          if (oldvaddr & 0x8000000000ULL)                          if (vaddr0 & 0x8000000000ULL)
1827                                  oldvaddr |= 0xffffff0000000000ULL;                                  vaddr0 |= 0xffffff0000000000ULL;
1828                  }                  }
1829    
1830  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);  
1831    
1832  #endif                  g_bit = (cp->reg[COP0_ENTRYLO0] &
1833          }                      cp->reg[COP0_ENTRYLO1]) & ENTRYLO_G;
 }  
1834    
1835                    if (cpu->cd.mips.cpu_type.rev == MIPS_R4100) {
1836                            /*  NOTE: The VR4131 (and possibly others) don't have
1837                                a Global bit in entryhi  */
1838                            cp->tlbs[index].hi &= ~cp->reg[COP0_PAGEMASK];
1839                    } else {
1840                            cp->tlbs[index].lo0 &= ~ENTRYLO_G;
1841                            cp->tlbs[index].lo1 &= ~ENTRYLO_G;
1842    
1843  /*                          cp->tlbs[index].hi &= ~TLB_G;
1844   *  coproc_rfe():                          if (g_bit)
1845   *                                  cp->tlbs[index].hi |= TLB_G;
1846   *  Return from exception. (R3000 etc.)                  }
1847   */  
1848  void coproc_rfe(struct cpu *cpu)                  /*
1849  {                   *  Invalidate any code translations, if we are writing Dirty
1850          cpu->cd.mips.coproc[0]->reg[COP0_STATUS] =                   *  pages to the TLB:  (TODO: 4KB hardcoded... ugly)
1851              (cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & ~0x3f) |                   */
1852              ((cpu->cd.mips.coproc[0]->reg[COP0_STATUS] & 0x3c) >> 2);                  for (ptmp = 0; ptmp < (1 << pfn_shift); ptmp += 0x1000) {
1853                            if (wf0)
1854                                    cpu->invalidate_code_translation(cpu,
1855                                        paddr0 + ptmp, INVALIDATE_PADDR);
1856                            if (wf1)
1857                                    cpu->invalidate_code_translation(cpu,
1858                                        paddr1 + ptmp, INVALIDATE_PADDR);
1859                    }
1860    
1861                    /*
1862                     *  If we have a memblock (host page) for the physical page,
1863                     *  then add a translation for it immediately, to save some
1864                     *  time. (It would otherwise be added later on anyway,
1865                     *  because of a translation miss.)
1866                     *
1867                     *  NOTE/TODO: This is only for 4KB pages so far. It would
1868                     *             be too expensive to add e.g. 16MB pages like
1869                     *             this.
1870                     */
1871                    memblock = memory_paddr_to_hostaddr(cpu->mem, paddr0, 0);
1872                    if (memblock != NULL && cp->reg[COP0_ENTRYLO0] & ENTRYLO_V)
1873                            cpu->update_translation_table(cpu, vaddr0, memblock,
1874                                wf0, paddr0);
1875                    memblock = memory_paddr_to_hostaddr(cpu->mem, paddr1, 0);
1876                    if (memblock != NULL && cp->reg[COP0_ENTRYLO1] & ENTRYLO_V)
1877                            cpu->update_translation_table(cpu, vaddr1, memblock,
1878                                wf1, paddr1);
1879            }
1880  }  }
1881    
1882    
# Line 2074  void coproc_function(struct cpu *cpu, st Line 2150  void coproc_function(struct cpu *cpu, st
2150                                          debug("rfe\n");                                          debug("rfe\n");
2151                                          return;                                          return;
2152                                  }                                  }
2153                                  coproc_rfe(cpu);                                  fatal("Internal error (rfe): Should be "
2154                                  return;                                      "implemented in dyntrans instead.\n");
2155                                    exit(1);
2156                          case COP0_ERET: /*  R4000: Return from exception  */                          case COP0_ERET: /*  R4000: Return from exception  */
2157                                  if (unassemble_only) {                                  if (unassemble_only) {
2158                                          debug("eret\n");                                          debug("eret\n");
2159                                          return;                                          return;
2160                                  }                                  }
2161                                  coproc_eret(cpu);                                  fatal("Internal error (eret): Should be "
2162                                  return;                                      "implemented in dyntrans instead.\n");
2163                                    exit(1);
2164                          case COP0_DERET:                          case COP0_DERET:
2165                                  if (unassemble_only) {                                  if (unassemble_only) {
2166                                          debug("deret\n");                                          debug("deret\n");

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

  ViewVC Help
Powered by ViewVC 1.1.26