Diff for /np2/i386c/ia32/paging.c between versions 1.33 and 1.37

version 1.33, 2011/12/16 09:05:42 version 1.37, 2012/01/08 19:15:40
Line 28 Line 28
 #include "ia32.mcr"  #include "ia32.mcr"
   
 /*  /*
  * ¡¦¥ì¡£¥·¡¦¥¯¡¦¥æ¡¦¥¥¡¦ö§¥Í¥Û浡¼   * åãÔ妾å⥯åãÊ夫å㥩åã°æ¥»¶ç¡¢  *
  * 4-31: ͽÌóºÑ¤ß   * 4-31: 人Ѥß
  *    3: RSVD: 0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤ÏͽÌó¥Ó¥Ã¥È°ãÈ¿¤Ç¤Ï¤Ê¤«¤Ã¤¿¡¥   *    3: RSVD: 0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤ÏͽÌó¥Ó¥Ã¥È°ãÈ¿¤Ç¤Ï¤Ê¤«¤Ã¤¿¡¥
  *             1 = ¥Ú¡¼¥¸¡¦¥Õ¥©¥ë¥È¤Î¸¶°ø¤Ï¡¤°ãÈ¿¤È¥Þ¡¼¥¯¤µ¤ì¤¿ PTE ¤Þ¤¿¤Ï   *             1 = ¥Ú¡¼¥¸¡¦¥Õ¥©¥ë¥È¤Î¸¶°ø¤Ï¡¤°ãÈ¿¤È¥Þ¡¼¥¯¤µ¤ì¤¿ PTE ¤Þ¤¿¤Ï
  *                 PDE ¤ÎͽÌó¥Ó¥Ã¥È°ÌÃ֤Τ¦¤Á°ì¤Ä¤Ç¡¤1 ¤¬¸¡½Ð¤µ¤ì¤¿¤³¤È¤Ç¤¢¤ë¡¥   *                 PDE ¤ÎͽÌó¥Ó¥Ã¥È°ÌÃ֤Τ¦¤Á°ì¤Ä¤Ç¡¤1 ¤¬¸¡½Ð¤µ¤ì¤¿¤³¤È¤Ç¤¢¤ë¡¥
  *    2: U/S:  0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤Ï¥×¥í¥»¥Ã¥µ¤¬¥¹¡¼¥Ñ¥Ð¥¤¥¶¡¦   *    2: U/S:  0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤Ï¥×¥í¥»¥Ã¥µ¤¬¥¹¡¼¥Ñ¥Ð¥¤¥¶¡¦
  *                 ¥â¡¼¥É¤Ç¼Â¹ÔÃæ¤Ë¹Ô¤ï¤ì¤¿¡¥   *                 ¥â¡¼¥É¤Ç¼Â¹ÔÃæ¤Ë¹Ô¤ï¤ì¤¿¡¥
  *             1 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤Ï¥×¥í¥»¥Ã¥µ¤¬¥æ¡¼¥¶¡¦¥â¡¼¥É¤Ç   *             1 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤Ï¥×¥í¥»¥Ã¥µ¤¬¥æ¡¼¥¶¡¦¥â¡¼¥É¤Ç
  *                 ¼Â¹ÔÃæ¤Ë¹Ô¤ï¤ì¤¿¡¥   *                 ¼Â¹ÔÃæ¤Ë¹Ô¤ï¤ì¤¿¡¥
  *    1: W/R:  0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤¬ÆÉ¤ß¼è¤ê¤Ç¤¢¤Ã¤¿¡¥   *    1: W/R:  0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤¬ÆÉ¤ß¼è¤ê¤Ç¤¢¤Ã¤¿¡¥
  *             1 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤¬½ñ¤­¹þ¤ß¤Ç¤¢¤Ã¤¿¡¥   *             1 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤È¤Ê¤Ã¤¿¥¢¥¯¥»¥¹¤¬½ñ¤­¹þ¤ß¤Ç¤¢¤Ã¤¿¡¥
  *    0: P:    0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤¬ÉԺߥڡ¼¥¸¤Ç¤¢¤Ã¤¿¡¥   *    0: P:    0 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤¬ÉԺߥڡ¼¥¸¤Ç¤¢¤Ã¤¿¡¥
  *             1 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤¬¥Ú¡¼¥¸¡¦¥ì¥Ù¥ëÊݸî°ãÈ¿¤Ç¤¢¤Ã¤¿¡¥   *             1 = ¥Õ¥©¥ë¥È¤Î¸¶°ø¤¬¥Ú¡¼¥¸¡¦¥ì¥Ù¥ëÊݸî°ãÈ¿¤Ç¤¢¤Ã¤¿¡¥
  */   */
   
 /*  /*
  * ²¼´¬ 4.12. ¥Ú¡¼¥¸Êݸî¤È¥»¥°¥á¥ó¥ÈÊݸî¤ÎÁȤ߹ç¤ï¤»   * ä¸ 4.12. ¥Ú¡¼¥¸Êݸî¤È¥»¥°¥á¥ó¥ÈÊݸî¤ÎÁȤ߹ç¤ï¤»
  * ¡Öɽ 4-2. ¥Ú¡¼¥¸¡¦¥Ç¥£¥ì¥¯¥È¥ê¤È¥Ú¡¼¥¸¡¦¥Æ¡¼¥Ö¥ë¤ÎÊݸî¤ÎÁȤ߹ç¤ï¤»¡×   * ¡Öɽ 4-2. ¥Ú¡¼¥¸¡¦¥Ç¥£¥ì¥¯¥È¥ê¤È¥Ú¡¼¥¸¡¦¥Æ¡¼¥Ö¥ë¤ÎÊݸî¤ÎÁȤ߹ç¤ï¤»¡×
  *   *
  * +------------+------------+------------+   * +------------+------------+------------+
  * |    PDE     |    PTE     |   merge    |   * |    PDE     |    PTE     |   merge    |
Line 71 Line 71
  * |  s  |  rw  |  s  |  rw  |  s  |  rw  |   * |  s  |  rw  |  s  |  rw  |  s  |  rw  |
  * +-----+------+-----+------+-----+------+   * +-----+------+-----+------+-----+------+
  *   *
  * ¡Ö¥£ rw/p : CR0 ¡¢¥Û WP ¡¦¥â¡¦¥Æ¡¦¥Í¡¢¥ã ON ¡¢¥Û¥»ø»î¦¥Ò¡¢¥Þ ro   * ãॵ rw/p : CR0 åá¥ç WP åãÆå¥ãåã°å¡ì ON åá¥çꢥ¨éð°å¢­åá¥Ã ro
  */   */
   
 /*  /*
  * ¡¦â§ä§ô§¡Ö¡¦¥Ã¡¦¥µ¡¦¥±/PxE(¥»ê·¥å¥µ¥¤¥»¥Í)/CPL/CR0 ¡¢¥Í¡¦¥ì¡£¥·¡¦¥¯¡¦¡Ö¡¦¥Ã¡¦¥µ¡¦¥±¥¯¡Ö¡¢¥Û¥¨¥ê¥­¥¯   * åã¡£åã¡Öå㥧åâ¡Öåâ¥Ãå⥵å⥱/PxE(躴ꥣÐç½âí奡)/CPL/CR0 åᥣåãÔ妾å⥯åâ¡Öåâ¥Ãå⥵å⥱쪥¥åá¥çñö¡ÖèÁ  *
  * +-----+-----+-----+-----+-----+---+   * +-----+-----+-----+-----+-----+---+
  * | CR0 | CPL | PxE | PxE | ope |   |   * | CR0 | CPL | PxE | PxE | ope |   |
Line 155  static const UINT8 page_access_bit[32] = Line 155  static const UINT8 page_access_bit[32] =
   
 /*  /*
  *--   *--
  * 32bit ʪÍý¥¢¥É¥ì¥¹ 4k ¥Ú¡¼¥¸   * 32bit í饥íð¬å¤¤åã²å¦®å⥱ 4k åãÔ妾å⥯
  *   *
  * ¡¦ô§¥Ò¡¦¡Ö¡£¥ò¡¦¡Ö¡¦¥Î¡¦ø§¥±   * å㥧åã¶å¤¤å㥵åâ¡Öåã²å¦®å⥱
  *  31                    22 21                  12 11                       0   *  31                    22 21                  12 11                       0
  * +------------------------+----------------------+--------------------------+   * +------------------------+----------------------+--------------------------+
  * |  ¡¦¥ì¡£¥·¡¦¥¯¡£¥ò¡¦¥Ì¡¦¡×¡¦ø§¥Ã¡¦¥Í¡¦ |   ¥Ú¡¼¥¸¡¦¥Æ¡¼¥Ö¥ë   |        ¥ª¥Õ¥»¥Ã¥È        |   * |  åãÔ妾å⥯å㥵åã®å¤¥åã¥ãåâ¥Ãåã°å¦¬  |   åãÔ妾å⥯å㥵åã¬å¦¾åãÌ妭   |        å⥧åãÊ夽åã¦å¥è        |
  * +------------------------+----------------------+--------------------------+   * +------------------------+----------------------+--------------------------+
  *             |                        |                       |   *             |                        |                       |
  * +-----------+            +-----------+                       +----------+   * +-----------+            +-----------+                       +----------+
  * |                        |                                              |   * |                        |                                              |
  * |  ¡¦¥ì¡£¥·¡¦¥¯¡£¥ò¡¦¥Ì¡¦¡×¡¦ø§¥Ã¡¦¥Í¡¦ |   ¥Ú¡¼¥¸¡¦¥Æ¡¼¥Ö¥ë            ¥Ú¡¼¥¸         |   * |  ¥Ú¡¼¥¸¡¦¥Ç¥£¥ì¥¯¥È¥ê  |   ¥Ú¡¼¥¸¡¦¥Æ¡¼¥Ö¥ë            ¥Ú¡¼¥¸         |
  * | +--------------------+ | +-------------------+   +------------------+ |   * | +--------------------+ | +-------------------+   +------------------+ |
  * | |                    | | |                   |   |                  | |   * | |                    | | |                   |   |                  | |
  * | |                    | | +-------------------+   |                  | |   * | |                    | | +-------------------+   |                  | |
Line 177  static const UINT8 page_access_bit[32] = Line 177  static const UINT8 page_access_bit[32] =
  *   |                    | | |                   | | |                  |   *   |                    | | |                   | | |                  |
  * +>+--------------------+ +>+-------------------+ +>+------------------+   * +>+--------------------+ +>+-------------------+ +>+------------------+
  * |   * |
  * +- CR3()   * +- CR3(ʪÍý¥¢¥É¥ì¥¹)
  */   */
   
 static UINT32 MEMCALL paging(const UINT32 laddr, const int ucrw);  /* TLB */
 static void MEMCALL tlb_update(const UINT32 laddr, const UINT entry, const int ucrw);  struct tlb_entry {
           UINT32  tag;    /* linear address */
   #define TLB_ENTRY_TAG_VALID             (1 << 0)
   /*      pde & pte & CPU_PTE_WRITABLE    (1 << 1)        */
   /*      pde & pte & CPU_PTE_USER_MODE   (1 << 2)        */
   #define TLB_ENTRY_TAG_DIRTY             CPU_PTE_DIRTY           /* (1 << 6) */
   #define TLB_ENTRY_TAG_GLOBAL            CPU_PTE_GLOBAL_PAGE     /* (1 << 8) */
   #define TLB_ENTRY_TAG_MAX_SHIFT         12
           UINT32  paddr;  /* physical address */
   };
   static void MEMCALL tlb_update(UINT32 laddr, UINT entry, int ucrw);
   
 #define PAGE_SIZE       0x1000  /* paging */
 #define PAGE_MASK       (PAGE_SIZE - 1)  static UINT32 MEMCALL paging(UINT32 laddr, int ucrw);
   
   /*
    * linear memory access
    */
   /* RMW */
 UINT8 MEMCALL  UINT8 MEMCALL
 cpu_memory_access_la_RMW_b(UINT32 laddr, UINT32 (*func)(UINT32, void *), void *arg)  cpu_memory_access_la_RMW_b(UINT32 laddr, UINT32 (CPUCALL *func)(UINT32, void *), void *arg)
 {  {
         const int ucrw = CPU_PAGE_WRITE_DATA|CPU_STAT_USER_MODE;          const int ucrw = CPU_PAGE_WRITE_DATA | CPU_STAT_USER_MODE;
         UINT32 result, value;          struct tlb_entry *ep;
         UINT32 paddr;          UINT32 paddr;
           UINT32 result;
           UINT8 value;
   
           /* TLB */
           ep = tlb_lookup(laddr, ucrw);
           if (ep != NULL) {
                   paddr = ep->paddr + (laddr & PAGE_MASK);
                   goto onepage;
           }
   
           /* paging */
         paddr = paging(laddr, ucrw);          paddr = paging(laddr, ucrw);
   onepage:
         value = cpu_memoryread(paddr);          value = cpu_memoryread(paddr);
         result = (*func)(value, arg);          result = (*func)(value, arg);
         cpu_memorywrite(paddr, (UINT8)result);          cpu_memorywrite(paddr, (UINT8)result);
   
         return value;          return value;
 }  }
   
 UINT16 MEMCALL  UINT16 MEMCALL
 cpu_memory_access_la_RMW_w(UINT32 laddr, UINT32 (*func)(UINT32, void *), void *arg)  cpu_memory_access_la_RMW_w(UINT32 laddr, UINT32 (CPUCALL *func)(UINT32, void *), void *arg)
 {  {
         const int ucrw = CPU_PAGE_WRITE_DATA|CPU_STAT_USER_MODE;          const int ucrw = CPU_PAGE_WRITE_DATA | CPU_STAT_USER_MODE;
         UINT32 result, value;          struct tlb_entry *ep[2];
         UINT32 paddr[2];          UINT32 paddr[2];
           UINT32 result;
           UINT16 value;
   
           /* TLB */
           ep[0] = tlb_lookup(laddr, ucrw);
           if (ep[0] != NULL) {
                   paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK);
                   if ((laddr + 1) & PAGE_MASK)
                           goto onepage;
   
                   ep[1] = tlb_lookup(laddr + 1, ucrw);
                   if (ep[1] != NULL) {
                           paddr[1] = ep[1]->paddr + (laddr & PAGE_MASK);
                           goto separate;
                   }
           }
   
           /* paging */
         paddr[0] = paging(laddr, ucrw);          paddr[0] = paging(laddr, ucrw);
         if ((laddr + 1) & PAGE_MASK) {          if ((laddr + 1) & PAGE_MASK) {
   onepage:
                 value = cpu_memoryread_w(paddr[0]);                  value = cpu_memoryread_w(paddr[0]);
                 result = (*func)(value, arg);                  result = (*func)(value, arg);
                 cpu_memorywrite_w(paddr[0], (UINT16)result);                  cpu_memorywrite_w(paddr[0], (UINT16)result);
         } else {                  return value;
                 paddr[1] = paging(laddr + 1, ucrw);  
                 value = cpu_memoryread_b(paddr[0]);  
                 value += (UINT16)cpu_memoryread_b(paddr[1]) << 8;  
                 result = (*func)(value, arg);  
                 cpu_memorywrite(paddr[0], (UINT8)result);  
                 cpu_memorywrite(paddr[1], (UINT8)(result >> 8));  
         }          }
   
           paddr[1] = paging(laddr + 1, ucrw);
   separate:
           value = cpu_memoryread_b(paddr[0]);
           value += (UINT16)cpu_memoryread_b(paddr[1]) << 8;
           result = (*func)(value, arg);
           cpu_memorywrite(paddr[0], (UINT8)result);
           cpu_memorywrite(paddr[1], (UINT8)(result >> 8));
         return value;          return value;
 }  }
   
 UINT32 MEMCALL  UINT32 MEMCALL
 cpu_memory_access_la_RMW_d(UINT32 laddr, UINT32 (*func)(UINT32, void *), void *arg)  cpu_memory_access_la_RMW_d(UINT32 laddr, UINT32 (CPUCALL *func)(UINT32, void *), void *arg)
 {  {
         const int ucrw = CPU_PAGE_WRITE_DATA|CPU_STAT_USER_MODE;          const int ucrw = CPU_PAGE_WRITE_DATA | CPU_STAT_USER_MODE;
         UINT32 result, value;          struct tlb_entry *ep[2];
         UINT32 paddr[2];          UINT32 paddr[2];
         UINT remain;          UINT32 result;
           UINT32 value;
           int remain;
   
           /* TLB */
           ep[0] = tlb_lookup(laddr, ucrw);
           if (ep[0] != NULL) {
                   paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK);
                   remain = PAGE_SIZE - (laddr & PAGE_MASK);
                   if (remain >= 4)
                           goto onepage;
   
                   ep[1] = tlb_lookup(laddr + remain, ucrw);
                   if (ep[1] != NULL) {
                           paddr[1] = ep[1]->paddr + (laddr & PAGE_MASK);
                           goto separate;
                   }
           }
   
           /* paging */
         paddr[0] = paging(laddr, ucrw);          paddr[0] = paging(laddr, ucrw);
         remain = PAGE_SIZE - (laddr & PAGE_MASK);          remain = PAGE_SIZE - (laddr & PAGE_MASK);
         if (remain >= 4) {          if (remain >= 4) {
   onepage:
                 value = cpu_memoryread_d(paddr[0]);                  value = cpu_memoryread_d(paddr[0]);
                 result = (*func)(value, arg);                  result = (*func)(value, arg);
                 cpu_memorywrite_d(paddr[0], result);                  cpu_memorywrite_d(paddr[0], result);
         } else {                  return value;
                 paddr[1] = paging(laddr + remain, ucrw);          }
                 switch (remain) {  
                 case 3:  
                         value = cpu_memoryread(paddr[0]);  
                         value += (UINT32)cpu_memoryread_w(paddr[0] + 1) << 8;  
                         value += (UINT32)cpu_memoryread(paddr[1]) << 24;  
                         result = (*func)(value, arg);  
                         cpu_memorywrite(paddr[0], (UINT8)result);  
                         cpu_memorywrite_w(paddr[0] + 1, (UINT16)(result >> 8));  
                         cpu_memorywrite(paddr[1], (UINT8)(result >> 24));  
                         break;  
   
                 case 2:          paddr[1] = paging(laddr + remain, ucrw);
                         value = cpu_memoryread_w(paddr[0]);  separate:
                         value += (UINT32)cpu_memoryread_w(paddr[1]) << 16;          switch (remain) {
                         result = (*func)(value, arg);          case 3:
                         cpu_memorywrite_w(paddr[0], (UINT16)result);                  value = cpu_memoryread(paddr[0]);
                         cpu_memorywrite_w(paddr[1], (UINT16)(result >> 16));                  value += (UINT32)cpu_memoryread_w(paddr[0] + 1) << 8;
                         break;                  value += (UINT32)cpu_memoryread(paddr[1]) << 24;
                   result = (*func)(value, arg);
                   cpu_memorywrite(paddr[0], (UINT8)result);
                   cpu_memorywrite_w(paddr[0] + 1, (UINT16)(result >> 8));
                   cpu_memorywrite(paddr[1], (UINT8)(result >> 24));
                   break;
   
                 case 1:          case 2:
                         value = cpu_memoryread(paddr[0]);                  value = cpu_memoryread_w(paddr[0]);
                         value += (UINT32)cpu_memoryread_w(paddr[1]) << 8;                  value += (UINT32)cpu_memoryread_w(paddr[1]) << 16;
                         value += (UINT32)cpu_memoryread(paddr[1] + 2) << 24;                  result = (*func)(value, arg);
                         result = (*func)(value, arg);                  cpu_memorywrite_w(paddr[0], (UINT16)result);
                         cpu_memorywrite(paddr[0], (UINT8)result);                  cpu_memorywrite_w(paddr[1], (UINT16)(result >> 16));
                         cpu_memorywrite_w(paddr[1], (UINT16)(result >> 8));                  break;
                         cpu_memorywrite(paddr[1] + 2, (UINT8)(result >> 24));  
                         break;  
   
                 default:          case 1:
                         ia32_panic("cpu_memory_access_la_RMW_d(): out of range (remain = %d)\n", remain);                  value = cpu_memoryread(paddr[0]);
                         return (UINT32)-1;                  value += (UINT32)cpu_memoryread_w(paddr[1]) << 8;
                 }                  value += (UINT32)cpu_memoryread(paddr[1] + 2) << 24;
                   result = (*func)(value, arg);
                   cpu_memorywrite(paddr[0], (UINT8)result);
                   cpu_memorywrite_w(paddr[1], (UINT16)(result >> 8));
                   cpu_memorywrite(paddr[1] + 2, (UINT8)(result >> 24));
                   break;
   
           default:
                   ia32_panic("cpu_memory_access_la_RMW_d: out of range (remain=%d)\n", remain);
                   value = 0;      /* XXX compiler happy */
                   break;
         }          }
         return value;          return value;
 }  }
   
   /* read */
 UINT8 MEMCALL  UINT8 MEMCALL
 cpu_linear_memory_read_b(UINT32 laddr, const int ucrw)  cpu_linear_memory_read_b(UINT32 laddr, int ucrw)
 {  {
           struct tlb_entry *ep;
         UINT32 paddr;          UINT32 paddr;
   
           /* TLB */
           ep = tlb_lookup(laddr, ucrw);
           if (ep != NULL) {
                   paddr = ep->paddr + (laddr & PAGE_MASK);
                   return cpu_memoryread(paddr);
           }
   
           /* paging */
         paddr = paging(laddr, ucrw);          paddr = paging(laddr, ucrw);
         return cpu_memoryread(paddr);          return cpu_memoryread(paddr);
 }  }
   
 UINT16 MEMCALL  UINT16 MEMCALL
 cpu_linear_memory_read_w(UINT32 laddr, const int ucrw)  cpu_linear_memory_read_w(UINT32 laddr, int ucrw)
 {  {
           struct tlb_entry *ep[2];
         UINT32 paddr[2];          UINT32 paddr[2];
         UINT16 value;          UINT16 value;
   
           /* TLB */
           ep[0] = tlb_lookup(laddr, ucrw);
           if (ep[0] != NULL) {
                   paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK);
                   if ((laddr + 1) & PAGE_MASK)
                           return cpu_memoryread_w(paddr[0]);
   
                   ep[1] = tlb_lookup(laddr + 1, ucrw);
                   if (ep[1] != NULL) {
                           paddr[1] = ep[1]->paddr;
                           goto separate;
                   }
           }
   
           /* paging */
         paddr[0] = paging(laddr, ucrw);          paddr[0] = paging(laddr, ucrw);
         if ((laddr + 1) & PAGE_MASK) {          if ((laddr + 1) & PAGE_MASK)
                 return cpu_memoryread_w(paddr[0]);                  return cpu_memoryread_w(paddr[0]);
         } else {  
                 paddr[1] = paging(laddr + 1, ucrw);          paddr[1] = paging(laddr + 1, ucrw);
                 value = cpu_memoryread_b(paddr[0]);  separate:
                 value += (UINT16)cpu_memoryread_b(paddr[1]) << 8;          value = cpu_memoryread_b(paddr[0]);
                 return value;          value += (UINT16)cpu_memoryread_b(paddr[1]) << 8;
         }          return value;
 }  }
   
 UINT32 MEMCALL  UINT32 MEMCALL
 cpu_linear_memory_read_d(UINT32 laddr, const int ucrw)  cpu_linear_memory_read_d(UINT32 laddr, int ucrw)
 {  {
           struct tlb_entry *ep[2];
         UINT32 paddr[2];          UINT32 paddr[2];
         UINT32 value;          UINT32 value;
         UINT remain;          UINT remain;
   
           /* TLB */
           ep[0] = tlb_lookup(laddr, ucrw);
           if (ep[0] != NULL) {
                   paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK);
                   remain = PAGE_SIZE - (laddr & PAGE_MASK);
                   if (remain >= sizeof(value))
                           return cpu_memoryread_d(paddr[0]);
   
                   ep[1] = tlb_lookup(laddr + remain, ucrw);
                   if (ep[1] != NULL) {
                           paddr[1] = ep[1]->paddr;
                           goto separate;
                   }
           }
   
           /* paging */
         paddr[0] = paging(laddr, ucrw);          paddr[0] = paging(laddr, ucrw);
         remain = PAGE_SIZE - (laddr & PAGE_MASK);          remain = PAGE_SIZE - (laddr & PAGE_MASK);
         if (remain >= 4) {          if (remain >= sizeof(value))
                 return cpu_memoryread_d(paddr[0]);                  return cpu_memoryread_d(paddr[0]);
         } else {  
                 paddr[1] = paging(laddr + remain, ucrw);  
                 switch (remain) {  
                 case 3:  
                         value = cpu_memoryread(paddr[0]);  
                         value += (UINT32)cpu_memoryread_w(paddr[0] + 1) << 8;  
                         value += (UINT32)cpu_memoryread(paddr[1]) << 24;  
                         break;  
   
                 case 2:          paddr[1] = paging(laddr + remain, ucrw);
                         value = cpu_memoryread_w(paddr[0]);  separate:
                         value += (UINT32)cpu_memoryread_w(paddr[1]) << 16;          switch (remain) {
                         break;          case 3:
                   value = cpu_memoryread(paddr[0]);
                   value += (UINT32)cpu_memoryread_w(paddr[0] + 1) << 8;
                   value += (UINT32)cpu_memoryread(paddr[1]) << 24;
                   break;
   
                 case 1:          case 2:
                         value = cpu_memoryread(paddr[0]);                  value = cpu_memoryread_w(paddr[0]);
                         value += (UINT32)cpu_memoryread_w(paddr[1]) << 8;                  value += (UINT32)cpu_memoryread_w(paddr[1]) << 16;
                         value += (UINT32)cpu_memoryread(paddr[1] + 2) << 24;                  break;
                         break;  
   
                 default:          case 1:
                         ia32_panic("cpu_linear_memory_read_d(): out of range (remain = %d)\n", remain);                  value = cpu_memoryread(paddr[0]);
                         value = (UINT32)-1;                  value += (UINT32)cpu_memoryread_w(paddr[1]) << 8;
                         break;                  value += (UINT32)cpu_memoryread(paddr[1] + 2) << 24;
                 }                  break;
                 return value;  
           default:
                   ia32_panic("cpu_linear_memory_read_d: out of range (remain=%d)\n", remain);
                   value = 0;      /* XXX compiler happy */
                   break;
         }          }
           return value;
 }  }
   
 UINT64 MEMCALL  UINT64 MEMCALL
 cpu_linear_memory_read_q(UINT32 laddr, const int ucrw)  cpu_linear_memory_read_q(UINT32 laddr, int ucrw)
 {  {
           struct tlb_entry *ep[2];
         UINT32 paddr[2];          UINT32 paddr[2];
         UINT64 value;          UINT64 value;
         UINT remain;          UINT remain;
   
           /* TLB */
           ep[0] = tlb_lookup(laddr, ucrw);
           if (ep[0] != NULL) {
                   paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK);
                   remain = PAGE_SIZE - (laddr & PAGE_MASK);
                   if (remain >= sizeof(value))
                           return cpu_memoryread_d(paddr[0]);
   
                   ep[1] = tlb_lookup(laddr + remain, ucrw);
                   if (ep[1] != NULL) {
                           paddr[1] = ep[1]->paddr;
                           goto separate;
                   }
           }
   
           /* paging */
         paddr[0] = paging(laddr, ucrw);          paddr[0] = paging(laddr, ucrw);
         remain = PAGE_SIZE - (laddr & PAGE_MASK);          remain = PAGE_SIZE - (laddr & PAGE_MASK);
         if (remain >= 8) {          if (remain >= sizeof(value))
                 return cpu_memoryread_q(paddr[0]);                  return cpu_memoryread_q(paddr[0]);
         } else {  
                 paddr[1] = paging(laddr + remain, ucrw);  
                 switch (remain) {  
                 case 7:  
                         value = cpu_memoryread(paddr[0]);  
                         value += (UINT64)cpu_memoryread_w(paddr[0] + 1) << 8;  
                         value += (UINT64)cpu_memoryread_d(paddr[0] + 3) << 24;  
                         value += (UINT64)cpu_memoryread(paddr[1]) << 56;  
                         break;  
   
                 case 6:          paddr[1] = paging(laddr + remain, ucrw);
                         value = cpu_memoryread_w(paddr[0]);  separate:
                         value += (UINT64)cpu_memoryread_d(paddr[0] + 2) << 16;          switch (remain) {
                         value += (UINT64)cpu_memoryread_w(paddr[1]) << 48;          case 7:
                         break;                  value = cpu_memoryread(paddr[0]);
                   value += (UINT64)cpu_memoryread_w(paddr[0] + 1) << 8;
                   value += (UINT64)cpu_memoryread_d(paddr[0] + 3) << 24;
                   value += (UINT64)cpu_memoryread(paddr[1]) << 56;
                   break;
   
                 case 5:          case 6:
                         value = cpu_memoryread(paddr[0]);                  value = cpu_memoryread_w(paddr[0]);
                         value += (UINT64)cpu_memoryread_d(paddr[0] + 1) << 8;                  value += (UINT64)cpu_memoryread_d(paddr[0] + 2) << 16;
                         value += (UINT64)cpu_memoryread_w(paddr[1]) << 40;                  value += (UINT64)cpu_memoryread_w(paddr[1]) << 48;
                         value += (UINT64)cpu_memoryread(paddr[1] + 2) << 56;                  break;
                         break;  
           case 5:
                 case 4:                  value = cpu_memoryread(paddr[0]);
                         value = cpu_memoryread_d(paddr[0]);                  value += (UINT64)cpu_memoryread_d(paddr[0] + 1) << 8;
                         value += (UINT64)cpu_memoryread_d(paddr[1]) << 32;                  value += (UINT64)cpu_memoryread_w(paddr[1]) << 40;
                         break;                  value += (UINT64)cpu_memoryread(paddr[1] + 2) << 56;
                   break;
                 case 3:  
                         value = cpu_memoryread(paddr[0]);  
                         value += (UINT64)cpu_memoryread_w(paddr[0] + 1) << 8;  
                         value += (UINT64)cpu_memoryread_d(paddr[1]) << 24;  
                         value += (UINT64)cpu_memoryread(paddr[1] + 4) << 56;  
                         break;  
   
                 case 2:          case 4:
                         value = cpu_memoryread_w(paddr[0]);                  value = cpu_memoryread_d(paddr[0]);
                         value += (UINT64)cpu_memoryread_d(paddr[1]) << 16;                  value += (UINT64)cpu_memoryread_d(paddr[1]) << 32;
                         value += (UINT64)cpu_memoryread_w(paddr[1] + 4) << 48;                  break;
                         break;  
   
                 case 1:          case 3:
                         value = cpu_memoryread(paddr[0]);                  value = cpu_memoryread(paddr[0]);
                         value += (UINT64)cpu_memoryread_d(paddr[1]) << 8;                  value += (UINT64)cpu_memoryread_w(paddr[0] + 1) << 8;
                         value += (UINT64)cpu_memoryread_w(paddr[1] + 4) << 40;                  value += (UINT64)cpu_memoryread_d(paddr[1]) << 24;
                         value += (UINT64)cpu_memoryread(paddr[1] + 6) << 56;                  value += (UINT64)cpu_memoryread(paddr[1] + 4) << 56;
                         break;                  break;
   
                 default:          case 2:
                         ia32_panic("cpu_linear_memory_read_q(): out of range (remain = %d)\n", remain);                  value = cpu_memoryread_w(paddr[0]);
                         value = (UINT64)-1;                  value += (UINT64)cpu_memoryread_d(paddr[1]) << 16;
                         break;                  value += (UINT64)cpu_memoryread_w(paddr[1] + 4) << 48;
                 }                  break;
   
           case 1:
                   value = cpu_memoryread(paddr[0]);
                   value += (UINT64)cpu_memoryread_d(paddr[1]) << 8;
                   value += (UINT64)cpu_memoryread_w(paddr[1] + 4) << 40;
                   value += (UINT64)cpu_memoryread(paddr[1] + 6) << 56;
                   break;
   
           default:
                   ia32_panic("cpu_linear_memory_read_q: out of range (remain=%d)\n", remain);
                   value = 0;      /* XXX compiler happy */
                   break;
         }          }
         return value;          return value;
 }  }
   
 REG80 MEMCALL  REG80 MEMCALL
 cpu_linear_memory_read_f(UINT32 laddr, const int ucrw)  cpu_linear_memory_read_f(UINT32 laddr, int ucrw)
 {  {
           struct tlb_entry *ep[2];
         UINT32 paddr[2];          UINT32 paddr[2];
         REG80 value;          REG80 value;
         UINT remain;          UINT remain;
         UINT i, j;          UINT i, j;
   
           /* TLB */
           ep[0] = tlb_lookup(laddr, ucrw);
           if (ep[0] != NULL) {
                   paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK);
                   remain = PAGE_SIZE - (laddr & PAGE_MASK);
                   if (remain >= sizeof(value))
                           return cpu_memoryread_f(paddr[0]);
   
                   ep[1] = tlb_lookup(laddr + remain, ucrw);
                   if (ep[1] != NULL) {
                           paddr[1] = ep[1]->paddr;
                           goto separate;
                   }
           }
   
           /* paging */
         paddr[0] = paging(laddr, ucrw);          paddr[0] = paging(laddr, ucrw);
         remain = PAGE_SIZE - (laddr & PAGE_MASK);          remain = PAGE_SIZE - (laddr & PAGE_MASK);
         if (remain >= 10) {          if (remain >= sizeof(value))
                 return cpu_memoryread_f(paddr[0]);                  return cpu_memoryread_f(paddr[0]);
         } else {  
                 paddr[1] = paging(laddr + remain, ucrw);          paddr[1] = paging(laddr + remain, ucrw);
                 for (i = 0; i < remain; ++i) {  separate:
                         value.b[i] = cpu_memoryread(paddr[0] + i);          for (i = 0; i < remain; ++i) {
                 }                  value.b[i] = cpu_memoryread(paddr[0] + i);
                 for (j = 0; i < 10; ++i, ++j) {          }
                         value.b[i] = cpu_memoryread(paddr[1] + j);          for (j = 0; i < 10; ++i, ++j) {
                 }                  value.b[i] = cpu_memoryread(paddr[1] + j);
                 return value;  
         }          }
           return value;
 }  }
   
   /* write */
 void MEMCALL  void MEMCALL
 cpu_linear_memory_write_b(UINT32 laddr, UINT8 value, const int user_mode)  cpu_linear_memory_write_b(UINT32 laddr, UINT8 value, int ucrw)
 {  {
         const int ucrw = CPU_PAGE_WRITE_DATA|user_mode;          struct tlb_entry *ep;
         UINT32 paddr;          UINT32 paddr;
   
           /* TLB */
           ep = tlb_lookup(laddr, ucrw);
           if (ep != NULL) {
                   paddr = ep->paddr + (laddr & PAGE_MASK);
                   cpu_memorywrite(paddr, value);
                   return;
           }
   
           /* paging */
         paddr = paging(laddr, ucrw);          paddr = paging(laddr, ucrw);
         cpu_memorywrite(paddr, value);          cpu_memorywrite(paddr, value);
 }  }
   
 void MEMCALL  void MEMCALL
 cpu_linear_memory_write_w(UINT32 laddr, UINT16 value, const int user_mode)  cpu_linear_memory_write_w(UINT32 laddr, UINT16 value, int ucrw)
 {  {
         const int ucrw = CPU_PAGE_WRITE_DATA|user_mode;          struct tlb_entry *ep[2];
         UINT32 paddr[2];          UINT32 paddr[2];
   
           /* TLB */
           ep[0] = tlb_lookup(laddr, ucrw);
           if (ep[0] != NULL) {
                   paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK);
                   if ((laddr + 1) & PAGE_MASK) {
                           cpu_memorywrite_w(paddr[0], value);
                           return;
                   }
   
                   ep[1] = tlb_lookup(laddr + 1, ucrw);
                   if (ep[1] != NULL) {
                           paddr[1] = ep[1]->paddr;
                           goto separate;
                   }
           }
   
           /* paging */
         paddr[0] = paging(laddr, ucrw);          paddr[0] = paging(laddr, ucrw);
         if ((laddr + 1) & PAGE_MASK) {          if ((laddr + 1) & PAGE_MASK) {
                 cpu_memorywrite_w(paddr[0], value);                  cpu_memorywrite_w(paddr[0], value);
         } else {                  return;
                 paddr[1] = paging(laddr + 1, ucrw);  
                 cpu_memorywrite(paddr[0], (UINT8)value);  
                 cpu_memorywrite(paddr[1], (UINT8)(value >> 8));  
         }          }
   
           paddr[1] = paging(laddr + 1, ucrw);
   separate:
           cpu_memorywrite(paddr[0], (UINT8)value);
           cpu_memorywrite(paddr[1], (UINT8)(value >> 8));
 }  }
   
 void MEMCALL  void MEMCALL
 cpu_linear_memory_write_d(UINT32 laddr, UINT32 value, const int user_mode)  cpu_linear_memory_write_d(UINT32 laddr, UINT32 value, int ucrw)
 {  {
         const int ucrw = CPU_PAGE_WRITE_DATA|user_mode;          struct tlb_entry *ep[2];
         UINT32 paddr[2];          UINT32 paddr[2];
         UINT remain;          UINT remain;
   
           /* TLB */
           ep[0] = tlb_lookup(laddr, ucrw);
           if (ep[0] != NULL) {
                   paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK);
                   remain = PAGE_SIZE - (laddr & PAGE_MASK);
                   if (remain >= sizeof(value)) {
                           cpu_memorywrite_d(paddr[0], value);
                           return;
                   }
   
                   ep[1] = tlb_lookup(laddr + remain, ucrw);
                   if (ep[1] != NULL) {
                           paddr[1] = ep[1]->paddr;
                           goto separate;
                   }
           }
   
           /* paging */
         paddr[0] = paging(laddr, ucrw);          paddr[0] = paging(laddr, ucrw);
         remain = PAGE_SIZE - (laddr & PAGE_MASK);          remain = PAGE_SIZE - (laddr & PAGE_MASK);
         if (remain >= 4) {          if (remain >= sizeof(value)) {
                 cpu_memorywrite_d(paddr[0], value);                  cpu_memorywrite_d(paddr[0], value);
         } else {                  return;
                 paddr[1] = paging(laddr + remain, ucrw);          }
                 switch (remain) {  
                 case 3:  
                         cpu_memorywrite(paddr[0], (UINT8)value);  
                         cpu_memorywrite_w(paddr[0] + 1, (UINT16)(value >> 8));  
                         cpu_memorywrite(paddr[1], (UINT8)(value >> 24));  
                         break;  
   
                 case 2:          paddr[1] = paging(laddr + remain, ucrw);
                         cpu_memorywrite_w(paddr[0], (UINT16)value);  separate:
                         cpu_memorywrite_w(paddr[1], (UINT16)(value >> 16));          switch (remain) {
                         break;          case 3:
                   cpu_memorywrite(paddr[0], (UINT8)value);
                   cpu_memorywrite_w(paddr[0] + 1, (UINT16)(value >> 8));
                   cpu_memorywrite(paddr[1], (UINT8)(value >> 24));
                   break;
   
           case 2:
                   cpu_memorywrite_w(paddr[0], (UINT16)value);
                   cpu_memorywrite_w(paddr[1], (UINT16)(value >> 16));
                   break;
   
                 case 1:          case 1:
                         cpu_memorywrite(paddr[0], (UINT8)value);                  cpu_memorywrite(paddr[0], (UINT8)value);
                         cpu_memorywrite_w(paddr[1], (UINT16)(value >> 8));                  cpu_memorywrite_w(paddr[1], (UINT16)(value >> 8));
                         cpu_memorywrite(paddr[1] + 2, (UINT8)(value >> 24));                  cpu_memorywrite(paddr[1] + 2, (UINT8)(value >> 24));
                         break;                  break;
                 }  
           default:
                   ia32_panic("cpu_linear_memory_write_d: out of range (remain=%d)\n", remain);
                   break;
         }          }
 }  }
   
 void MEMCALL  void MEMCALL
 cpu_linear_memory_write_q(UINT32 laddr, UINT64 value, const int user_mode)  cpu_linear_memory_write_q(UINT32 laddr, UINT64 value, int ucrw)
 {  {
         const int ucrw = CPU_PAGE_WRITE_DATA|user_mode;          struct tlb_entry *ep[2];
         UINT32 paddr[2];          UINT32 paddr[2];
         UINT remain;          UINT remain;
   
           /* TLB */
           ep[0] = tlb_lookup(laddr, ucrw);
           if (ep[0] != NULL) {
                   paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK);
                   remain = PAGE_SIZE - (laddr & PAGE_MASK);
                   if (remain >= sizeof(value)) {
                           cpu_memorywrite_q(paddr[0], value);
                           return;
                   }
   
                   ep[1] = tlb_lookup(laddr + remain, ucrw);
                   if (ep[1] != NULL) {
                           paddr[1] = ep[1]->paddr;
                           goto separate;
                   }
           }
   
           /* paging */
         paddr[0] = paging(laddr, ucrw);          paddr[0] = paging(laddr, ucrw);
         remain = PAGE_SIZE - (laddr & PAGE_MASK);          remain = PAGE_SIZE - (laddr & PAGE_MASK);
         if (remain >= 8) {          if (remain >= sizeof(value)) {
                 cpu_memorywrite_q(paddr[0], value);                  cpu_memorywrite_q(paddr[0], value);
         } else {                  return;
                 paddr[1] = paging(laddr + remain, ucrw);          }
                 switch (remain) {  
                 case 7:  
                         cpu_memorywrite(paddr[0], (UINT8)value);  
                         cpu_memorywrite_w(paddr[0] + 1, (UINT16)(value >> 8));  
                         cpu_memorywrite_d(paddr[0] + 3, (UINT32)(value >> 24));  
                         cpu_memorywrite(paddr[1], (UINT8)(value >> 56));  
                         break;  
   
                 case 6:  
                         cpu_memorywrite_w(paddr[0], (UINT16)value);  
                         cpu_memorywrite_d(paddr[0] + 2, (UINT32)(value >> 16));  
                         cpu_memorywrite_w(paddr[1], (UINT16)(value >> 48));  
                         break;  
   
                 case 5:  
                         cpu_memorywrite(paddr[0], (UINT8)value);  
                         cpu_memorywrite_d(paddr[0] + 1, (UINT32)(value >> 8));  
                         cpu_memorywrite_w(paddr[1], (UINT16)(value >> 40));  
                         cpu_memorywrite(paddr[1] + 2, (UINT8)(value >> 56));  
                         break;  
   
                 case 4:          paddr[1] = paging(laddr + remain, ucrw);
                         cpu_memorywrite_d(paddr[0], (UINT32)value);  separate:
                         cpu_memorywrite_d(paddr[1], (UINT32)(value >> 32));          switch (remain) {
                         break;          case 7:
                   cpu_memorywrite(paddr[0], (UINT8)value);
                   cpu_memorywrite_w(paddr[0] + 1, (UINT16)(value >> 8));
                   cpu_memorywrite_d(paddr[0] + 3, (UINT32)(value >> 24));
                   cpu_memorywrite(paddr[1], (UINT8)(value >> 56));
                   break;
   
           case 6:
                   cpu_memorywrite_w(paddr[0], (UINT16)value);
                   cpu_memorywrite_d(paddr[0] + 2, (UINT32)(value >> 16));
                   cpu_memorywrite_w(paddr[1], (UINT16)(value >> 48));
                   break;
   
                 case 3:          case 5:
                         cpu_memorywrite(paddr[0], (UINT8)value);                  cpu_memorywrite(paddr[0], (UINT8)value);
                         cpu_memorywrite_w(paddr[0] + 1, (UINT16)(value >> 8));                  cpu_memorywrite_d(paddr[0] + 1, (UINT32)(value >> 8));
                         cpu_memorywrite_d(paddr[1], (UINT32)(value >> 24));                  cpu_memorywrite_w(paddr[1], (UINT16)(value >> 40));
                         cpu_memorywrite(paddr[1] + 4, (UINT8)(value >> 56));                  cpu_memorywrite(paddr[1] + 2, (UINT8)(value >> 56));
                         break;                  break;
   
           case 4:
                   cpu_memorywrite_d(paddr[0], (UINT32)value);
                   cpu_memorywrite_d(paddr[1], (UINT32)(value >> 32));
                   break;
   
                 case 2:          case 3:
                         cpu_memorywrite_w(paddr[0], (UINT16)value);                  cpu_memorywrite(paddr[0], (UINT8)value);
                         cpu_memorywrite_d(paddr[1], (UINT32)(value >> 16));                  cpu_memorywrite_w(paddr[0] + 1, (UINT16)(value >> 8));
                         cpu_memorywrite_w(paddr[1] + 4, (UINT16)(value >> 48));                  cpu_memorywrite_d(paddr[1], (UINT32)(value >> 24));
                         break;                  cpu_memorywrite(paddr[1] + 4, (UINT8)(value >> 56));
                   break;
   
           case 2:
                   cpu_memorywrite_w(paddr[0], (UINT16)value);
                   cpu_memorywrite_d(paddr[1], (UINT32)(value >> 16));
                   cpu_memorywrite_w(paddr[1] + 4, (UINT16)(value >> 48));
                   break;
   
                 case 1:          case 1:
                         cpu_memorywrite(paddr[0], (UINT8)value);                  cpu_memorywrite(paddr[0], (UINT8)value);
                         cpu_memorywrite_d(paddr[1], (UINT32)(value >> 8));                  cpu_memorywrite_d(paddr[1], (UINT32)(value >> 8));
                         cpu_memorywrite_w(paddr[1] + 4, (UINT16)(value >> 40));                  cpu_memorywrite_w(paddr[1] + 4, (UINT16)(value >> 40));
                         cpu_memorywrite(paddr[1] + 6, (UINT8)(value >> 56));                  cpu_memorywrite(paddr[1] + 6, (UINT8)(value >> 56));
                         break;                  break;
                 }  
           default:
                   ia32_panic("cpu_linear_memory_write_q: out of range (remain=%d)\n", remain);
                   break;
         }          }
 }  }
   
 void MEMCALL  void MEMCALL
 cpu_linear_memory_write_f(UINT32 laddr, const REG80 *value, const int user_mode)  cpu_linear_memory_write_f(UINT32 laddr, const REG80 *value, int ucrw)
 {  {
         const int ucrw = CPU_PAGE_WRITE_DATA|user_mode;          struct tlb_entry *ep[2];
         UINT32 paddr[2];          UINT32 paddr[2];
         UINT remain;          UINT remain;
         UINT i, j;          UINT i, j;
   
           /* TLB */
           ep[0] = tlb_lookup(laddr, ucrw);
           if (ep[0] != NULL) {
                   paddr[0] = ep[0]->paddr + (laddr & PAGE_MASK);
                   remain = PAGE_SIZE - (laddr & PAGE_MASK);
                   if (remain >= sizeof(value)) {
                           cpu_memorywrite_f(paddr[0], value);
                           return;
                   }
   
                   ep[1] = tlb_lookup(laddr + remain, ucrw);
                   if (ep[1] != NULL) {
                           paddr[1] = ep[1]->paddr;
                           goto separate;
                   }
           }
   
           /* paging */
         paddr[0] = paging(laddr, ucrw);          paddr[0] = paging(laddr, ucrw);
         remain = PAGE_SIZE - (laddr & PAGE_MASK);          remain = PAGE_SIZE - (laddr & PAGE_MASK);
         if (remain >= 10) {          if (remain >= sizeof(value)) {
                 cpu_memorywrite_f(paddr[0], value);                  cpu_memorywrite_f(paddr[0], value);
         } else {                  return;
                 paddr[1] = paging(laddr + remain, ucrw);  
                 for (i = 0; i < remain; ++i) {  
                         cpu_memorywrite(paddr[0] + i, value->b[i]);  
                 }  
                 for (j = 0; i < 10; ++i, ++j) {  
                         cpu_memorywrite(paddr[1] + j, value->b[i]);  
                 }  
         }          }
 }  
   
           paddr[1] = paging(laddr + remain, ucrw);
   separate:
           for (i = 0; i < remain; ++i) {
                   cpu_memorywrite(paddr[0] + i, value->b[i]);
           }
           for (j = 0; i < 10; ++i, ++j) {
                   cpu_memorywrite(paddr[1] + j, value->b[i]);
           }
   }
   
   /*
    * linear address memory access function
    */
 void MEMCALL  void MEMCALL
 cpu_memory_access_la_region(UINT32 laddr, UINT length, const int ucrw, UINT8 *data)  cpu_memory_access_la_region(UINT32 laddr, UINT length, int ucrw, UINT8 *data)
 {  {
         UINT32 paddr;          UINT32 paddr;
         UINT remain;    /* page remain */          UINT remain;    /* page remain */
Line 621  cpu_memory_access_la_region(UINT32 laddr Line 863  cpu_memory_access_la_region(UINT32 laddr
 }  }
   
 UINT32 MEMCALL  UINT32 MEMCALL
 laddr2paddr(const UINT32 laddr, const int ucrw)  laddr2paddr(UINT32 laddr, int ucrw)
 {  {
   
         return paging(laddr, ucrw);          return paging(laddr, ucrw);
 }  }
   
   /*
    * paging
    */
 static UINT32 MEMCALL  static UINT32 MEMCALL
 paging(const UINT32 laddr, const int ucrw)  paging(UINT32 laddr, int ucrw)
 {  {
         UINT32 paddr;           /* physical address */          UINT32 paddr;           /* physical address */
         UINT32 pde_addr;        /* page directory entry address */          UINT32 pde_addr;        /* page directory entry address */
Line 637  paging(const UINT32 laddr, const int ucr Line 882  paging(const UINT32 laddr, const int ucr
         UINT32 pte;             /* page table entry */          UINT32 pte;             /* page table entry */
         UINT bit;          UINT bit;
         UINT err;          UINT err;
         TLB_ENTRY_T *ep;          struct tlb_entry *ep;
   
         ep = tlb_lookup(laddr, ucrw);          ep = tlb_lookup(laddr, ucrw);
         if (ep != NULL)          if (ep != NULL)
Line 697  paging(const UINT32 laddr, const int ucr Line 942  paging(const UINT32 laddr, const int ucr
                 cpu_memorywrite_d(pte_addr, pte);                  cpu_memorywrite_d(pte_addr, pte);
         }          }
   
         tlb_update(laddr, pte, (bit & (CPU_PTE_WRITABLE|CPU_PTE_USER_MODE)) + ((ucrw & CPU_PAGE_CODE) >> 1));          tlb_update(laddr, pte, (bit & (CPU_PTE_WRITABLE|CPU_PTE_USER_MODE)) + ((ucrw & CPU_PAGE_CODE) ? 1 : 0));
   
         return paddr;          return paddr;
   
Line 712  pf_exception: Line 957  pf_exception:
 /*   /* 
  * TLB   * TLB
  */   */
 #define TLB_GET_PADDR(ep, addr) ((ep)->paddr + ((addr) & ~CPU_PTE_BASEADDR_MASK))  
 #define TLB_SET_PADDR(ep, addr) ((ep)->paddr = (addr) & CPU_PTE_BASEADDR_MASK)  
   
 #define TLB_TAG_SHIFT           TLB_ENTRY_TAG_MAX_SHIFT  #define TLB_TAG_SHIFT           TLB_ENTRY_TAG_MAX_SHIFT
 #define TLB_TAG_MASK            (~((1 << TLB_TAG_SHIFT) - 1))  #define TLB_TAG_MASK            (~((1 << TLB_TAG_SHIFT) - 1))
 #define TLB_GET_TAG_ADDR(ep)    ((ep)->tag & TLB_TAG_MASK)  #define TLB_GET_TAG_ADDR(ep)    ((ep)->tag & TLB_TAG_MASK)
Line 749  do { \ Line 991  do { \
 #define TLB_ENTRY_MASK  (NENTRY - 1)  #define TLB_ENTRY_MASK  (NENTRY - 1)
   
 typedef struct {  typedef struct {
         TLB_ENTRY_T     entry[NENTRY];          struct tlb_entry entry[NENTRY];
 } TLB_T;  } tlb_t;
   static tlb_t tlb[NTLB];
 static TLB_T tlb[NTLB];  
   
 #if defined(IA32_PROFILE_TLB)  
 /* profiling */  
 typedef struct {  
         UINT64 tlb_hits;  
         UINT64 tlb_misses;  
         UINT64 tlb_lookups;  
         UINT64 tlb_updates;  
         UINT64 tlb_flushes;  
         UINT64 tlb_global_flushes;  
         UINT64 tlb_entry_flushes;  
 } TLB_PROFILE_T;  
   
 static TLB_PROFILE_T tlb_profile;  
   
 #define PROFILE_INC(v)  tlb_profile.v++  
 #else   /* !IA32_PROFILE_TLB */  
 #define PROFILE_INC(v)  
 #endif  /* IA32_PROFILE_TLB */  
   
   
 void  void
 tlb_init(void)  tlb_init(void)
 {  {
   
         memset(tlb, 0, sizeof(tlb));          memset(tlb, 0, sizeof(tlb));
 #if defined(IA32_PROFILE_TLB)  
         memset(&tlb_profile, 0, sizeof(tlb_profile));  
 #endif  /* IA32_PROFILE_TLB */  
 }  }
   
 void MEMCALL  void MEMCALL
 tlb_flush(BOOL allflush)  tlb_flush(BOOL allflush)
 {  {
         TLB_ENTRY_T *ep;          struct tlb_entry *ep;
         int i;          int i;
         int n;          int n;
   
         if (allflush) {          if (allflush) {
                 PROFILE_INC(tlb_global_flushes);                  tlb_init();
         } else {                  return;
                 PROFILE_INC(tlb_flushes);  
         }          }
   
         for (n = 0; n < NTLB; n++) {          for (n = 0; n < NTLB; n++) {
                 for (i = 0; i < NENTRY ; i++) {                  for (i = 0; i < NENTRY ; i++) {
                         ep = &tlb[n].entry[i];                          ep = &tlb[n].entry[i];
                         if (TLB_IS_VALID(ep) && (allflush || !TLB_IS_GLOBAL(ep))) {                          if (TLB_IS_VALID(ep) && !TLB_IS_GLOBAL(ep)) {
                                 TLB_SET_INVALID(ep);                                  TLB_SET_INVALID(ep);
                                 PROFILE_INC(tlb_entry_flushes);  
                         }                          }
                 }                  }
         }          }
Line 811  tlb_flush(BOOL allflush) Line 1027  tlb_flush(BOOL allflush)
 void MEMCALL  void MEMCALL
 tlb_flush_page(UINT32 laddr)  tlb_flush_page(UINT32 laddr)
 {  {
         TLB_ENTRY_T *ep;          struct tlb_entry *ep;
         int idx;          int idx;
         int n;          int n;
   
         PROFILE_INC(tlb_flushes);  
   
         idx = (laddr >> TLB_ENTRY_SHIFT) & TLB_ENTRY_MASK;          idx = (laddr >> TLB_ENTRY_SHIFT) & TLB_ENTRY_MASK;
   
         for (n = 0; n < NTLB; n++) {          for (n = 0; n < NTLB; n++) {
Line 824  tlb_flush_page(UINT32 laddr) Line 1038  tlb_flush_page(UINT32 laddr)
                 if (TLB_IS_VALID(ep)) {                  if (TLB_IS_VALID(ep)) {
                         if ((laddr & TLB_TAG_MASK) == TLB_GET_TAG_ADDR(ep)) {                          if ((laddr & TLB_TAG_MASK) == TLB_GET_TAG_ADDR(ep)) {
                                 TLB_SET_INVALID(ep);                                  TLB_SET_INVALID(ep);
                                 PROFILE_INC(tlb_entry_flushes);  
                         }                          }
                 }                  }
         }          }
 }  }
   
 TLB_ENTRY_T * MEMCALL  struct tlb_entry * MEMCALL
 tlb_lookup(const UINT32 laddr, const int ucrw)  tlb_lookup(UINT32 laddr, int ucrw)
 {  {
         TLB_ENTRY_T *ep;          struct tlb_entry *ep;
         UINT bit;          UINT bit;
         int idx;          int idx;
         int n;          int n;
   
         PROFILE_INC(tlb_lookups);          n = (ucrw & CPU_PAGE_CODE) ? 1 : 0;
   
         n = (ucrw & CPU_PAGE_CODE) >> 1;  
         idx = (laddr >> TLB_ENTRY_SHIFT) & TLB_ENTRY_MASK;          idx = (laddr >> TLB_ENTRY_SHIFT) & TLB_ENTRY_MASK;
         ep = &tlb[n].entry[idx];          ep = &tlb[n].entry[idx];
   
Line 856  tlb_lookup(const UINT32 laddr, const int Line 1067  tlb_lookup(const UINT32 laddr, const int
 #endif  #endif
                         {                          {
                                 if (!(ucrw & CPU_PAGE_WRITE) || TLB_IS_DIRTY(ep)) {                                  if (!(ucrw & CPU_PAGE_WRITE) || TLB_IS_DIRTY(ep)) {
                                         PROFILE_INC(tlb_hits);  
                                         return ep;                                          return ep;
                                 }                                  }
                         }                          }
                 }                  }
         }          }
         PROFILE_INC(tlb_misses);  
         return NULL;          return NULL;
 }  }
   
 static void MEMCALL  static void MEMCALL
 tlb_update(const UINT32 laddr, const UINT entry, const int bit)  tlb_update(UINT32 laddr, UINT entry, int bit)
 {  {
         TLB_ENTRY_T *ep;          struct tlb_entry *ep;
         UINT32 pos;  
         int idx;          int idx;
         int n;          int n;
   
         PROFILE_INC(tlb_updates);  
   
         n = bit & 1;          n = bit & 1;
         idx = (laddr >> TLB_ENTRY_SHIFT) & TLB_ENTRY_MASK;          idx = (laddr >> TLB_ENTRY_SHIFT) & TLB_ENTRY_MASK;
         ep = &tlb[n].entry[idx];          ep = &tlb[n].entry[idx];
   
         TLB_SET_VALID(ep);          TLB_SET_VALID(ep);
         TLB_SET_TAG_ADDR(ep, laddr);          TLB_SET_TAG_ADDR(ep, laddr);
         TLB_SET_PADDR(ep, entry);  
         TLB_SET_TAG_FLAGS(ep, entry, bit);          TLB_SET_TAG_FLAGS(ep, entry, bit);
           ep->paddr = entry & CPU_PTE_BASEADDR_MASK;
         if (ep->paddr < CPU_MEMREADMAX) {  
                 ep->memp = mem + ep->paddr;  
                 return;  
         } else if (ep->paddr >= USE_HIMEM) {  
                 pos = (ep->paddr & CPU_ADRSMASK) - 0x100000;  
                 if (pos < CPU_EXTMEMSIZE) {  
                         ep->memp = CPU_EXTMEM + pos;  
                         return;  
                 }  
         }  
         ep->memp = NULL;  
 }  }

Removed from v.1.33  
changed lines
  Added in v.1.37


RetroPC.NET-CVS <cvs@retropc.net>