/[gxemul]/trunk/src/cpus/memory_mips_v2p.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/memory_mips_v2p.c

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

revision 22 by dpavlin, Mon Oct 8 16:19:37 2007 UTC revision 32 by dpavlin, Mon Oct 8 16:20:58 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: memory_mips_v2p.c,v 1.3 2005/12/26 12:32:10 debug Exp $   *  $Id: memory_mips_v2p.c,v 1.14 2006/10/14 23:47:37 debug Exp $
  *  
  *  Included from memory.c.  
29   */   */
30    
31    
32  /*  /*
33   *  translate_address():   *  translate_v2p():
34     *
35     *  Translate a virtual MIPS address to a physical address, by looking up the
36     *  address in the TLB. On failure, an exception is generated (except for the
37     *  case when FLAG_NOEXCEPTIONS is used).
38     *
39     *  Note: This function is long and hairy, it is included several times with
40     *        various defines set, to produce more or less optimized versions of
41     *        the function for different emulated CPU types.
42   *   *
43   *  Don't call this function is userland_emul is non-NULL, or cpu is NULL.   *  V2P_MMU3K       Defined for R2000/R3000 emulation. If it is not defined,
44     *                  R4000+/MIPS32/MIPS64 is presumed.
45     *  V2P_MMU10K      This enables the use of 44 userspace bits, instead of 40.
46     *  V2P_MMU4100     VR41xx processors support 1 KB pages, so their page mask
47     *                  is slightly different. (The emulator only supports 4 KB
48     *                  pages, though.)
49     *  V2P_MMU8K       Not yet. (TODO.)
50   *   *
51   *  TODO:  vpn2 is a bad name for R2K/R3K, as it is the actual framenumber.   *
52     *  Note:  Unfortunately, the variable name vpn2 is poorly choosen for R2K/R3K,
53     *         since it actual contains the vpn.
54   *   *
55   *  Return values:   *  Return values:
56   *      0  Failure   *      0  Failure
# Line 44  Line 58 
58   *      2  Success, the page is read/write   *      2  Success, the page is read/write
59   */   */
60  int TRANSLATE_ADDRESS(struct cpu *cpu, uint64_t vaddr,  int TRANSLATE_ADDRESS(struct cpu *cpu, uint64_t vaddr,
61          uint64_t *return_addr, int flags)          uint64_t *return_paddr, int flags)
62  {  {
63          int writeflag = flags & FLAG_WRITEFLAG? MEM_WRITE : MEM_READ;          int writeflag = flags & FLAG_WRITEFLAG? MEM_WRITE : MEM_READ;
64          int no_exceptions = flags & FLAG_NOEXCEPTIONS;          int no_exceptions = flags & FLAG_NOEXCEPTIONS;
         int instr = flags & FLAG_INSTR;  
65          int ksu, use_tlb, status, i;          int ksu, use_tlb, status, i;
66          uint64_t vaddr_vpn2=0, vaddr_asid=0;          uint64_t vaddr_vpn2=0, vaddr_asid=0;
67          int exccode, tlb_refill;          int exccode, tlb_refill;
68          struct mips_coproc *cp0;          struct mips_coproc *cp0;
         int bintrans_cached = cpu->machine->bintrans_enable;  
69    
70  #ifdef V2P_MMU3K  #ifdef V2P_MMU3K
71          const int x_64 = 0;          const int x_64 = 0;
72          const int n_tlbs = 64;          const int n_tlbs = 64;
73          const int pmask = 0xfff;          const int pmask = 0xfff;
74            uint64_t xuseg_top;             /*  Well, useg actually.  */
75  #else  #else
76  #ifdef V2P_MMU10K  #ifdef V2P_MMU10K
77          const uint64_t vpn2_mask = ENTRYHI_VPN2_MASK_R10K;          const uint64_t vpn2_mask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK_R10K;
78            uint64_t xuseg_top = ENTRYHI_VPN2_MASK_R10K | 0x1fffULL;
79  #else  #else
80  #ifdef V2P_MMU4100  #ifdef V2P_MMU4100
81  /* This is ugly  */          const uint64_t vpn2_mask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK | 0x1800;
         const uint64_t vpn2_mask = ENTRYHI_VPN2_MASK | 0x1800;  
82  #else  #else
83          const uint64_t vpn2_mask = ENTRYHI_VPN2_MASK;          const uint64_t vpn2_mask = ENTRYHI_R_MASK | ENTRYHI_VPN2_MASK;
84  #endif  #endif
85            uint64_t xuseg_top = ENTRYHI_VPN2_MASK | 0x1fffULL;
86  #endif  #endif
87          int x_64;       /*  non-zero for 64-bit address space accesses  */          int x_64;       /*  non-zero for 64-bit address space accesses  */
88          int pageshift, n_tlbs;          int pageshift, n_tlbs;
# Line 85  int TRANSLATE_ADDRESS(struct cpu *cpu, u Line 99  int TRANSLATE_ADDRESS(struct cpu *cpu, u
99  #endif  /*  !V2P_MMU3K  */  #endif  /*  !V2P_MMU3K  */
100    
101    
 #ifdef USE_TINY_CACHE  
         /*  
          *  Check the tiny translation cache first:  
          *  
          *  Only userland addresses are checked, because other addresses  
          *  are probably better of being statically translated, or through  
          *  the TLB.  (Note: When running with 64-bit addresses, this  
          *  will still produce the correct result. At worst, we check the  
          *  cache in vain, but the result should still be correct.)  
          */  
         if (!bintrans_cached &&  
             (vaddr & 0xc0000000ULL) != 0x80000000ULL) {  
                 int i, wf = 1 + (writeflag == MEM_WRITE);  
                 uint64_t vaddr_shift_12 = vaddr >> 12;  
   
                 if (instr) {  
                         /*  Code:  */  
                         for (i=0; i<N_TRANSLATION_CACHE_INSTR; i++) {  
                                 if (cpu->cd.mips.translation_cache_instr[i].wf  
                                     >= wf && vaddr_shift_12 == (cpu->cd.mips.  
                                     translation_cache_instr[i].vaddr_pfn)) {  
                                         *return_addr = cpu->cd.mips.  
                                             translation_cache_instr[i].paddr  
                                             | (vaddr & 0xfff);  
                                         return cpu->cd.mips.  
                                             translation_cache_instr[i].wf;  
                                 }  
                         }  
                 } else {  
                         /*  Data:  */  
                         for (i=0; i<N_TRANSLATION_CACHE_DATA; i++) {  
                                 if (cpu->cd.mips.translation_cache_data[i].wf  
                                     >= wf && vaddr_shift_12 == (cpu->cd.mips.  
                                     translation_cache_data[i].vaddr_pfn)) {  
                                         *return_addr = cpu->cd.mips.  
                                             translation_cache_data[i].paddr  
                                             | (vaddr & 0xfff);  
                                         return cpu->cd.mips.  
                                             translation_cache_data[i].wf;  
                                 }  
                         }  
                 }  
         }  
 #endif  
   
102          exccode = -1;          exccode = -1;
103          tlb_refill = 1;          tlb_refill = 1;
104    
# Line 138  int TRANSLATE_ADDRESS(struct cpu *cpu, u Line 107  int TRANSLATE_ADDRESS(struct cpu *cpu, u
107          status = cp0->reg[COP0_STATUS];          status = cp0->reg[COP0_STATUS];
108    
109          /*          /*
110           *  R4000 Address Translation:           *  MIPS R4000+ and MIPS64 Address Translation:
111           *           *
112           *  An address may be in one of the kernel segments, that           *  An address may be in one of the kernel segments, that are directly
113           *  are directly mapped, or the address can go through the           *  mapped to physical addresses, or the address needs to be looked up
114           *  TLBs to be turned into a physical address.           *  in the TLB entries.
115           *           *
116           *  KSU: EXL: ERL: X:  Name:   Range:           *  KSU: EXL: ERL: X:  Name:   Range:
117           *  ---- ---- ---- --  -----   ------           *  ---- ---- ---- --  -----   ------
# Line 163  int TRANSLATE_ADDRESS(struct cpu *cpu, u Line 132  int TRANSLATE_ADDRESS(struct cpu *cpu, u
132           *                                        unmapped, cached           *                                        unmapped, cached
133           *   00   x    x    0  kseg1   0xa0000000 - 0xbfffffff (0.5GB)           *   00   x    x    0  kseg1   0xa0000000 - 0xbfffffff (0.5GB)
134           *                                        unmapped, uncached           *                                        unmapped, uncached
135           *   00   x    x    0  ksseg   0xc0000000 - 0xdfffffff (0.5GB)           *   00   x    x    0  ksseg   0xc0000000 - 0xdfffffff (0.5GB) (via TLB)
136           *                                        (via TLB)           *   00   x    x    0  kseg3   0xe0000000 - 0xffffffff (0.5GB) (via TLB)
          *   00   x    x    0  kseg3   0xe0000000 - 0xffffffff (0.5GB)  
          *                                        (via TLB)  
137           *   00   x    x    1  xksuseg 0 - 0xffffffffff (1TB) (via TLB) (*)           *   00   x    x    1  xksuseg 0 - 0xffffffffff (1TB) (via TLB) (*)
138           *   00   x    x    1  xksseg  0x4000000000000000 - 0x400000ffffffffff           *   00   x    x    1  xksseg  0x4000000000000000 - 0x400000ffffffffff
139           *                                        (1TB)  (via TLB)           *                                        (1TB)  (via TLB)
140           *   00   x    x    1  xkphys  0x8000000000000000 - 0xbfffffffffffffff           *   00   x    x    1  xkphys  0x8000000000000000 - 0xbfffffffffffffff
          *                                        todo  
141           *   00   x    x    1  xkseg   0xc000000000000000 - 0xc00000ff7fffffff           *   00   x    x    1  xkseg   0xc000000000000000 - 0xc00000ff7fffffff
          *                                        todo  
142           *   00   x    x    1  ckseg0  0xffffffff80000000 - 0xffffffff9fffffff           *   00   x    x    1  ckseg0  0xffffffff80000000 - 0xffffffff9fffffff
          *                                        like kseg0  
143           *   00   x    x    1  ckseg1  0xffffffffa0000000 - 0xffffffffbfffffff           *   00   x    x    1  ckseg1  0xffffffffa0000000 - 0xffffffffbfffffff
          *                                        like kseg1  
144           *   00   x    x    1  cksseg  0xffffffffc0000000 - 0xffffffffdfffffff           *   00   x    x    1  cksseg  0xffffffffc0000000 - 0xffffffffdfffffff
          *                                        like ksseg  
145           *   00   x    x    1  ckseg3  0xffffffffe0000000 - 0xffffffffffffffff           *   00   x    x    1  ckseg3  0xffffffffe0000000 - 0xffffffffffffffff
146           *                                        like kseg2           *                                        like 0x80000000 - 0xffffffff
147           *           *
148           *  (*) = if ERL=1 then kuseg is not via TLB, but unmapped,           *  (*) = if ERL=1 then kuseg is not via TLB, but unmapped,
149           *  uncached physical memory.           *  uncached physical memory.
# Line 203  int TRANSLATE_ADDRESS(struct cpu *cpu, u Line 165  int TRANSLATE_ADDRESS(struct cpu *cpu, u
165          vaddr_asid = cp0->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK;          vaddr_asid = cp0->reg[COP0_ENTRYHI] & R2K3K_ENTRYHI_ASID_MASK;
166          vaddr_vpn2 = vaddr & R2K3K_ENTRYHI_VPN_MASK;          vaddr_vpn2 = vaddr & R2K3K_ENTRYHI_VPN_MASK;
167  #else  #else
168          /*          /*  kx,sx,ux = 0 for 32-bit addressing, 1 for 64-bit addressing.  */
          *  R4000 and others:  
          *  
          *  kx,sx,ux = 0 for 32-bit addressing,  
          *  1 for 64-bit addressing.  
          */  
         n_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries;  
   
169          ksu = (status & STATUS_KSU_MASK) >> STATUS_KSU_SHIFT;          ksu = (status & STATUS_KSU_MASK) >> STATUS_KSU_SHIFT;
170          if (status & (STATUS_EXL | STATUS_ERL))          if (status & (STATUS_EXL | STATUS_ERL))
171                  ksu = KSU_KERNEL;                  ksu = KSU_KERNEL;
172    
173          /*  Assume KSU_USER.  */          switch (ksu) {
174          x_64 = status & STATUS_UX;          case KSU_USER:
175                    x_64 = status & STATUS_UX;
176          if (ksu == KSU_KERNEL)                  break;
177            case KSU_KERNEL:
178                  x_64 = status & STATUS_KX;                  x_64 = status & STATUS_KX;
179          else if (ksu == KSU_SUPERVISOR)                  break;
180            case KSU_SUPERVISOR:
181                  x_64 = status & STATUS_SX;                  x_64 = status & STATUS_SX;
182                    /*  FALLTHROUGH, since supervisor address spaces are not
183                        really implemented yet.  */
184            default:fatal("memory_mips_v2p.c: ksu=%i not yet implemented yet\n",
185                        ksu);
186                    exit(1);
187            }
188    
189          /*  This suppresses a compiler warning:  */          n_tlbs = cpu->cd.mips.cpu_type.nr_of_tlb_entries;
190    
191            /*  Having this here suppresses a compiler warning:  */
192          pageshift = 12;          pageshift = 12;
193    
194            /*  KUSEG: 0x00000000 - 0x7fffffff if ERL = 1 and KSU = kernel:  */
195            if (ksu == KSU_KERNEL && (status & STATUS_ERL) &&
196                vaddr <= 0x7fffffff) {
197                    *return_paddr = vaddr & 0x7fffffff;
198                    return 2;
199            }
200    
201          /*          /*
202           *  Physical addressing on R10000 etc:           *  XKPHYS: 0x8000000000000000 - 0xbfffffffffffffff
203           *           *
204           *  TODO: Probably only accessible in kernel mode.           *  TODO: Is the correct error generated if accessing XKPHYS from
205             *        usermode?
206           *           *
207           *  0x9000000080000000 = disable L2 cache (?)           *  TODO: Magic on SGI machines... Cache control, NUMA, etc.:
208           *  TODO:  Make this correct.           *        0x9000000080000000   = disable L2 cache (?)
209             *        0x90000000a0000000   = something on IP30?
210             *        0x92.... and 0x96... = NUMA on IP27
211           */           */
212          if ((vaddr >> 62) == 0x2) {          if (ksu == KSU_KERNEL && (vaddr & ENTRYHI_R_MASK) == ENTRYHI_R_XKPHYS) {
213                  /*                  *return_paddr = vaddr & (((uint64_t)1 << 44) - 1);
                  *  On IP30, addresses such as 0x900000001f600050 are used,  
                  *  but also things like 0x90000000a0000000.  (TODO)  
                  *  
                  *  On IP27 (and probably others), addresses such as  
                  *  0x92... and 0x96... have to do with NUMA stuff.  
                  */  
                 *return_addr = vaddr & (((uint64_t)1 << 44) - 1);  
214                  return 2;                  return 2;
215          }          }
216    
# Line 251  int TRANSLATE_ADDRESS(struct cpu *cpu, u Line 219  int TRANSLATE_ADDRESS(struct cpu *cpu, u
219          /*  vpn2 depends on pagemask, which is not fixed on R4000  */          /*  vpn2 depends on pagemask, which is not fixed on R4000  */
220  #endif  #endif
221    
222            /*  If 32-bit, truncate address and sign extend:  */
223            if (x_64 == 0) {
224                    vaddr = (int32_t) vaddr;
225                    xuseg_top = 0x7fffffff;
226                    /*  (Actually useg for R2000/R3000)  */
227            }
228    
229          if (vaddr <= 0x7fffffff)          if (vaddr <= xuseg_top) {
230                  use_tlb = 1;                  use_tlb = 1;
231          else {          } else {
 #if 1  
 /*  TODO: This should be removed, but it seems that other  
 bugs are triggered.  */  
                 /*  Sign-extend vaddr, if necessary:  */  
                 if ((vaddr >> 32) == 0 && vaddr & (uint32_t)0x80000000ULL)  
                         vaddr |= 0xffffffff00000000ULL;  
 #endif  
232                  if (ksu == KSU_KERNEL) {                  if (ksu == KSU_KERNEL) {
233                          /*  kseg0, kseg1:  */                          /*  kseg0, kseg1:  */
234                          if (vaddr >= (uint64_t)0xffffffff80000000ULL &&                          if (vaddr >= (uint64_t)0xffffffff80000000ULL &&
235                              vaddr <= (uint64_t)0xffffffffbfffffffULL) {                              vaddr <= (uint64_t)0xffffffffbfffffffULL) {
236                                  *return_addr = vaddr & 0x1fffffff;                                  *return_paddr = vaddr & 0x1fffffff;
237                                  return 2;                                  return 2;
238                          }                          }
239    
                         /*  TODO: supervisor stuff  */  
   
240                          /*  other segments:  */                          /*  other segments:  */
241                          use_tlb = 1;                          use_tlb = 1;
242                  } else                  } else {
243                          use_tlb = 0;                          use_tlb = 0;
244                    }
245          }          }
246    
247          if (use_tlb) {          if (use_tlb) {
# Line 286  bugs are triggered.  */ Line 252  bugs are triggered.  */
252                  int g_bit, v_bit, d_bit;                  int g_bit, v_bit, d_bit;
253                  uint64_t cached_hi, cached_lo0;                  uint64_t cached_hi, cached_lo0;
254                  uint64_t entry_vpn2 = 0, entry_asid, pfn;                  uint64_t entry_vpn2 = 0, entry_asid, pfn;
255                    int i_end;
256    
257                  for (i=0; i<n_tlbs; i++) {                  i = cpu->cd.mips.last_written_tlb_index;
258                    i_end = i == 0? n_tlbs-1 : i - 1;
259    
260                    /*  Scan all TLB entries:  */
261                    for (;;) {
262  #ifdef V2P_MMU3K  #ifdef V2P_MMU3K
263                          /*  R3000 or similar:  */                          /*  R3000 or similar:  */
264                          cached_hi = cp0->tlbs[i].hi;                          cached_hi = cp0->tlbs[i].hi;
# Line 379  bugs are triggered.  */ Line 350  bugs are triggered.  */
350                          /*  Is there a VPN and ASID match?  */                          /*  Is there a VPN and ASID match?  */
351                          if (entry_vpn2 == vaddr_vpn2 &&                          if (entry_vpn2 == vaddr_vpn2 &&
352                              (entry_asid == vaddr_asid || g_bit)) {                              (entry_asid == vaddr_asid || g_bit)) {
353                                  /*  debug("OK MAP 1, i=%i { vaddr=%016llx "                                  /*  debug("OK MAP 1, i=%i { vaddr=%016"PRIx64" "
354                                      "==> paddr %016llx v=%i d=%i "                                      "==> paddr %016"PRIx64" v=%i d=%i "
355                                      "asid=0x%02x }\n", i, (long long)vaddr,                                      "asid=0x%02x }\n", i, (uint64_t) vaddr,
356                                      (long long) *return_addr, v_bit?1:0,                                      (uint64_t) *return_paddr, v_bit?1:0,
357                                      d_bit?1:0, vaddr_asid);  */                                      d_bit?1:0, vaddr_asid);  */
358                                  if (v_bit) {                                  if (v_bit) {
359                                          if (d_bit || (!d_bit &&                                          if (d_bit || (!d_bit &&
360                                              writeflag == MEM_READ)) {                                              writeflag == MEM_READ)) {
361                                                  uint64_t paddr;                                                  uint64_t paddr;
362                                                  /*  debug("OK MAP 2!!! { w=%i "                                                  /*  debug("OK MAP 2!!! { w=%i "
363                                                      "vaddr=%016llx ==> d=%i v="                                                      "vaddr=%016"PRIx64" ==> "
364                                                      "%i paddr %016llx ",                                                      "d=%i v=%i paddr %016"
365                                                      writeflag, (long long)vaddr,                                                      PRIx64" ",
366                                                        writeflag, (uint64_t)vaddr,
367                                                      d_bit?1:0, v_bit?1:0,                                                      d_bit?1:0, v_bit?1:0,
368                                                      (long long) *return_addr);                                                      (uint64_t) *return_paddr);
369                                                      debug(", tlb entry %2i: ma"                                                      debug(", tlb entry %2i: ma"
370                                                      "sk=%016llx hi=%016llx lo0"                                                      "sk=%016"PRIx64" hi=%016"
371                                                      "=%016llx lo1=%016llx\n",                                                      PRIx64" lo0=%016"PRIx64
372                                                        " lo1=%016"PRIx64"\n",
373                                                      i, cp0->tlbs[i].mask, cp0->                                                      i, cp0->tlbs[i].mask, cp0->
374                                                      tlbs[i].hi, cp0->tlbs[i].                                                      tlbs[i].hi, cp0->tlbs[i].
375                                                      lo0, cp0->tlbs[i].lo1);                                                      lo0, cp0->tlbs[i].lo1);
# Line 414  bugs are triggered.  */ Line 387  bugs are triggered.  */
387                                                      (vaddr & pmask);                                                      (vaddr & pmask);
388  #endif  #endif
389    
390                                                  /*                                                  *return_paddr = paddr;
                                                  *  Enter into the tiny trans-  
                                                  *  lation cache (if enabled)  
                                                  *  and return:  
                                                  */  
                                                 if (!bintrans_cached)  
                                                         insert_into_tiny_cache(  
                                                             cpu, instr, d_bit?  
                                                             MEM_WRITE :  
                                                             MEM_READ,  
                                                             vaddr, paddr);  
   
                                                 *return_addr = paddr;  
391                                                  return d_bit? 2 : 1;                                                  return d_bit? 2 : 1;
392                                          } else {                                          } else {
393                                                  /*  TLB modif. exception  */                                                  /*  TLB modif. exception  */
# Line 440  bugs are triggered.  */ Line 401  bugs are triggered.  */
401                                          goto exception;                                          goto exception;
402                                  }                                  }
403                          }                          }
404    
405                            if (i == i_end)
406                                    break;
407    
408                            /*  Go to the next TLB entry:  */
409                            i ++;
410                            if (i == n_tlbs)
411                                    i = 0;
412                  }                  }
413          }          }
414    

Legend:
Removed from v.22  
changed lines
  Added in v.32

  ViewVC Help
Powered by ViewVC 1.1.26