Diff for /np2/i386c/ia32/cpu_mem.c between versions 1.14 and 1.18

version 1.14, 2004/03/12 13:34:08 version 1.18, 2004/06/15 13:50:13
Line 1 Line 1
 /*      $Id$    */  /*      $Id$    */
   
 /*  /*
  * Copyright (c) 2002-2003 NONAKA Kimihiro   * Copyright (c) 2002-2004 NONAKA Kimihiro
  * All rights reserved.   * All rights reserved.
  *   *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
Line 252  cpu_stack_pop_check(UINT16 s, descriptor Line 252  cpu_stack_pop_check(UINT16 s, descriptor
         }          }
 }  }
   
   
 #if defined(IA32_SUPPORT_PREFETCH_QUEUE)  
 /*  
  * code prefetch  
  */  
 #define CPU_PREFETCHQ_MASK      (CPU_PREFETCH_QUEUE_LENGTH - 1)  
   
 INLINE static MEMCALL void  
 cpu_prefetch(UINT32 address)  
 {  
         UINT offset = address & CPU_PREFETCHQ_MASK;  
         UINT length = CPU_PREFETCH_QUEUE_LENGTH - offset;  
   
         cpu_memory_access_la_region(address, length, CPU_PAGE_READ_CODE, CPU_STAT_USER_MODE, CPU_PREFETCHQ + offset);  
         CPU_PREFETCHQ_REMAIN = (SINT8)length;  
 }  
   
 INLINE static MEMCALL UINT8  
 cpu_prefetchq(UINT32 address)  
 {  
         UINT8 v;  
   
         CPU_PREFETCHQ_REMAIN--;  
         v = CPU_PREFETCHQ[address & CPU_PREFETCHQ_MASK];  
         return v;  
 }  
   
 INLINE static MEMCALL UINT16  
 cpu_prefetchq_w(UINT32 address)  
 {  
         BYTE *p;  
         UINT16 v;  
   
         CPU_PREFETCHQ_REMAIN -= 2;  
         p = CPU_PREFETCHQ + (address & CPU_PREFETCHQ_MASK);  
         v = LOADINTELWORD(p);  
         return v;  
 }  
   
 INLINE static MEMCALL UINT32  
 cpu_prefetchq_3(UINT32 address)  
 {  
         BYTE *p;  
         UINT32 v;  
   
         CPU_PREFETCHQ_REMAIN -= 3;  
         p = CPU_PREFETCHQ + (address & CPU_PREFETCHQ_MASK);  
         v = LOADINTELWORD(p);  
         v += ((UINT32)p[2]) << 16;  
         return v;  
 }  
   
 INLINE static MEMCALL UINT32  
 cpu_prefetchq_d(UINT32 address)  
 {  
         BYTE *p;  
         UINT32 v;  
   
         CPU_PREFETCHQ_REMAIN -= 4;  
         p = CPU_PREFETCHQ + (address & CPU_PREFETCHQ_MASK);  
         v = LOADINTELDWORD(p);  
         return v;  
 }  
 #endif  /* IA32_SUPPORT_PREFETCH_QUEUE */  
   
 #if defined(IA32_SUPPORT_DEBUG_REGISTER)  #if defined(IA32_SUPPORT_DEBUG_REGISTER)
 INLINE static void  INLINE static void
 check_memory_break_point(UINT32 address, UINT length, UINT rw)  check_memory_break_point(UINT32 address, UINT length, UINT rw)
Line 339  check_memory_break_point(UINT32 address, Line 274  check_memory_break_point(UINT32 address,
 #define check_memory_break_point(address, length, rw)  #define check_memory_break_point(address, length, rw)
 #endif  #endif
   
   
 /*  /*
  * code fetch   * code fetch
  */   */
   #define ucrw    (CPU_PAGE_READ_CODE | CPU_STAT_USER_MODE)
   
 UINT8 MEMCALL  UINT8 MEMCALL
 cpu_codefetch(UINT32 offset)  cpu_codefetch(UINT32 offset)
 {  {
         descriptor_t *sd;          descriptor_t *sd;
         UINT32 addr;          UINT32 addr;
   #if defined(IA32_SUPPORT_TLB)
           TLB_ENTRY_T *ep;
   #endif
   
         sd = &CPU_STAT_SREG(CPU_CS_INDEX);          sd = &CPU_STAT_SREG(CPU_CS_INDEX);
         if (offset <= sd->u.seg.limit) {          if (offset <= sd->u.seg.limit) {
                 addr = sd->u.seg.segbase + offset;                  addr = sd->u.seg.segbase + offset;
 #if defined(IA32_SUPPORT_PREFETCH_QUEUE)                  if (!CPU_STAT_PAGING)
                 if (CPU_PREFETCHQ_REMAIN <= 0) {  
                         cpu_prefetch(addr);  
                 }  
                 return cpu_prefetchq(addr);  
 #else   /* !IA32_SUPPORT_PREFETCH_QUEUE */  
                 if (!CPU_STAT_PM)  
                         return cpu_memoryread(addr);                          return cpu_memoryread(addr);
                 return cpu_lcmemoryread(addr);  #if defined(IA32_SUPPORT_TLB)
 #endif  /* IA32_SUPPORT_PREFETCH_QUEUE */                  ep = tlb_lookup(addr, ucrw);
                   if (ep != NULL && ep->memp != NULL) {
                           return ep->memp[addr & 0xfff];
                   }
   #endif
                   return cpu_linear_memory_read_b(addr, ucrw);
         }          }
         EXCEPTION(GP_EXCEPTION, 0);          EXCEPTION(GP_EXCEPTION, 0);
         return 0;       /* compiler happy */          return 0;       /* compiler happy */
Line 371  cpu_codefetch_w(UINT32 offset) Line 311  cpu_codefetch_w(UINT32 offset)
 {  {
         descriptor_t *sd;          descriptor_t *sd;
         UINT32 addr;          UINT32 addr;
 #if defined(IA32_SUPPORT_PREFETCH_QUEUE)  #if defined(IA32_SUPPORT_TLB)
         UINT16 v;          TLB_ENTRY_T *ep;
           UINT16 value;
 #endif  #endif
   
         sd = &CPU_STAT_SREG(CPU_CS_INDEX);          sd = &CPU_STAT_SREG(CPU_CS_INDEX);
         if (offset <= sd->u.seg.limit - 1) {          if (offset <= sd->u.seg.limit - 1) {
                 addr = sd->u.seg.segbase + offset;                  addr = sd->u.seg.segbase + offset;
 #if defined(IA32_SUPPORT_PREFETCH_QUEUE)                  if (!CPU_STAT_PAGING)
                 if (CPU_PREFETCHQ_REMAIN <= 0) {  
                         cpu_prefetch(addr);  
                 }  
                 if (CPU_PREFETCHQ_REMAIN >= 2) {  
                         return cpu_prefetchq_w(addr);  
                 }  
   
                 v = cpu_prefetchq(addr);  
                 addr++;  
                 cpu_prefetch(addr);  
                 v += (UINT16)cpu_prefetchq(addr) << 8;  
                 return v;  
 #else   /* !IA32_SUPPORT_PREFETCH_QUEUE */  
                 if (!CPU_STAT_PM)  
                         return cpu_memoryread_w(addr);                          return cpu_memoryread_w(addr);
                 return cpu_lcmemoryread_w(addr);  #if defined(IA32_SUPPORT_TLB)
 #endif  /* IA32_SUPPORT_PREFETCH_QUEUE */                  ep = tlb_lookup(addr, ucrw);
                   if (ep != NULL && ep->memp != NULL) {
                           if ((addr + 1) & 0x00000fff) {
                                   return LOADINTELWORD(ep->memp + (addr & 0xfff));
                           }
                           value = ep->memp[0xfff];
                           ep = tlb_lookup(addr + 1, ucrw);
                           if (ep != NULL && ep->memp != NULL) {
                                   value += (UINT16)ep->memp[0] << 8;
                                   return value;
                           }
                   }
   #endif
                   return cpu_linear_memory_read_w(addr, ucrw);
         }          }
         EXCEPTION(GP_EXCEPTION, 0);          EXCEPTION(GP_EXCEPTION, 0);
         return 0;       /* compiler happy */          return 0;       /* compiler happy */
Line 406  cpu_codefetch_d(UINT32 offset) Line 346  cpu_codefetch_d(UINT32 offset)
 {  {
         descriptor_t *sd;          descriptor_t *sd;
         UINT32 addr;          UINT32 addr;
 #if defined(IA32_SUPPORT_PREFETCH_QUEUE)  #if defined(IA32_SUPPORT_TLB)
         UINT32 v;          TLB_ENTRY_T *ep[2];
           UINT32 value;
           UINT remain;
 #endif  #endif
   
         sd = &CPU_STAT_SREG(CPU_CS_INDEX);          sd = &CPU_STAT_SREG(CPU_CS_INDEX);
         if (offset <= sd->u.seg.limit - 3) {          if (offset <= sd->u.seg.limit - 3) {
                 addr = sd->u.seg.segbase + offset;                  addr = sd->u.seg.segbase + offset;
 #if defined(IA32_SUPPORT_PREFETCH_QUEUE)                  if (!CPU_STAT_PAGING)
                 if (CPU_PREFETCHQ_REMAIN <= 0) {                          return cpu_memoryread_d(addr);
                         cpu_prefetch(addr);  #if defined(IA32_SUPPORT_TLB)
                 }                  ep[0] = tlb_lookup(addr, ucrw);
                 if (CPU_PREFETCHQ_REMAIN >= 4) {                  if (ep[0] != NULL && ep[0]->memp != NULL) {
                         return cpu_prefetchq_d(addr);                          remain = 0x1000 - (addr & 0xfff);
                 } else {                          if (remain >= 4) {
                         switch (CPU_PREFETCHQ_REMAIN) {                                  return LOADINTELDWORD(ep[0]->memp + (addr & 0xfff));
                         case 1:                          }
                                 v = cpu_prefetchq(addr);                          ep[1] = tlb_lookup(addr + remain, ucrw);
                                 addr++;                          if (ep[1] != NULL && ep[1]->memp != NULL) {
                                 cpu_prefetch(addr);                                  switch (remain) {
                                 v += (UINT32)cpu_prefetchq_3(addr) << 8;                                  case 3:
                                 break;                                          value = ep[0]->memp[0xffd];
                                           value += (UINT32)LOADINTELWORD(ep[0]->memp + 0xffe) << 8;
                         case 2:                                          value += (UINT32)ep[1]->memp[0] << 24;
                                 v = cpu_prefetchq_w(addr);                                          break;
                                 addr += 2;  
                                 cpu_prefetch(addr);                                  case 2:
                                 v += (UINT32)cpu_prefetchq_w(addr) << 16;                                          value = LOADINTELWORD(ep[0]->memp + 0xffe);
                                 break;                                          value += (UINT32)LOADINTELWORD(ep[1]->memp + 0) << 16;
                                           break;
                         case 3:  
                                 v = cpu_prefetchq_3(addr);                                  case 1:
                                 addr += 3;                                          value = ep[0]->memp[0xfff];
                                 cpu_prefetch(addr);                                          value += (UINT32)LOADINTELWORD(ep[1]->memp + 0) << 8;
                                 v += (UINT32)cpu_prefetchq(addr) << 24;                                          value += (UINT32)ep[1]->memp[2] << 24;
                                 break;                                          break;
   
                                   default:
                                           ia32_panic("cpu_codefetch_d(): out of range. (remain = %d)\n", remain);
                                           return (UINT32)-1;
                                   }
                                   return value;
                         }                          }
                         return v;  
                 }                  }
 #else   /* !IA32_SUPPORT_PREFETCH_QUEUE */  #endif
                 if (!CPU_STAT_PM)                  return cpu_linear_memory_read_d(addr, ucrw);
                         return cpu_memoryread_d(addr);  
                 return cpu_lcmemoryread_d(addr);  
 #endif  /* IA32_SUPPORT_PREFETCH_QUEUE */  
         }          }
         EXCEPTION(GP_EXCEPTION, 0);          EXCEPTION(GP_EXCEPTION, 0);
         return 0;       /* compiler happy */          return 0;       /* compiler happy */
Line 456  cpu_codefetch_d(UINT32 offset) Line 400  cpu_codefetch_d(UINT32 offset)
   
   
 /*  /*
  * virtual address -> linear address   * virtual address memory access functions
  */   */
 UINT8 MEMCALL  #include "cpu_mem.mcr"
 cpu_vmemoryread(int idx, UINT32 offset)  
 {  
         descriptor_t *sd;  
         UINT32 addr;  
         int exc;  
   
         __ASSERT((unsigned int)idx < CPU_SEGREG_NUM);  
   
         sd = &CPU_STAT_SREG(idx);  
         if (!sd->valid) {  
                 exc = GP_EXCEPTION;  
                 goto err;  
         }  
   
         if (!(sd->flag & CPU_DESC_FLAG_READABLE)) {  
                 cpu_memoryread_check(sd, offset, 1,  
                     (idx == CPU_SS_INDEX) ? SS_EXCEPTION : GP_EXCEPTION);  
         } else {  
                 switch (sd->type) {  
                 case 4: case 5: case 6: case 7:  
                         if (offset <= sd->u.seg.limit)  
                                 goto range_failure;  
                         break;  
   
                 default:  
                         if (offset > sd->u.seg.limit)  
                                 goto range_failure;  
                         break;  
                 }  
         }  
         addr = sd->u.seg.segbase + offset;  
         check_memory_break_point(addr, 1, CPU_DR7_RW_RO);  
         if (!CPU_STAT_PM)  
                 return cpu_memoryread(addr);  
         return cpu_lmemoryread(addr, CPU_STAT_USER_MODE);  
   
 range_failure:  
         if (idx == CPU_SS_INDEX) {  
                 exc = SS_EXCEPTION;  
         } else {  
                 exc = GP_EXCEPTION;  
         }  
         VERBOSE(("cpu_vmemoryread: type = %d, offset = %08x, limit = %08x", sd->type, offset, sd->u.seg.limit));  
 err:  
         EXCEPTION(exc, 0);  
         return 0;       /* compiler happy */  
 }  
   
 UINT16 MEMCALL  
 cpu_vmemoryread_w(int idx, UINT32 offset)  
 {  
         descriptor_t *sd;  
         UINT32 addr;  
         int exc;  
   
         __ASSERT((unsigned int)idx < CPU_SEGREG_NUM);  
   
         sd = &CPU_STAT_SREG(idx);  VIRTUAL_ADDRESS_MEMORY_ACCESS_FUNCTION(b, UINT8, 1)
         if (!sd->valid) {  VIRTUAL_ADDRESS_MEMORY_ACCESS_FUNCTION(w, UINT16, 2)
                 exc = GP_EXCEPTION;  VIRTUAL_ADDRESS_MEMORY_ACCESS_FUNCTION(d, UINT32, 4)
                 goto err;  
         }  
   
         if (!(sd->flag & CPU_DESC_FLAG_READABLE)) {  
                 cpu_memoryread_check(sd, offset, 2,  
                     (idx == CPU_SS_INDEX) ? SS_EXCEPTION : GP_EXCEPTION);  
         } else {  
                 switch (sd->type) {  
                 case 4: case 5: case 6: case 7:  
                         if (offset - 1 <= sd->u.seg.limit)  
                                 goto range_failure;  
                         break;  
   
                 default:  
                         if (offset > sd->u.seg.limit - 1)  
                                 goto range_failure;  
                         break;  
                 }  
         }   
         addr = sd->u.seg.segbase + offset;  
         check_memory_break_point(addr, 2, CPU_DR7_RW_RO);  
         if (!CPU_STAT_PM)  
                 return cpu_memoryread_w(addr);  
         return cpu_lmemoryread_w(addr, CPU_STAT_USER_MODE);  
   
 range_failure:  
         if (idx == CPU_SS_INDEX) {  
                 exc = SS_EXCEPTION;  
         } else {  
                 exc = GP_EXCEPTION;  
         }  
         VERBOSE(("cpu_vmemoryread_w: type = %d, offset = %08x, limit = %08x", sd->type, offset, sd->u.seg.limit));  
 err:  
         EXCEPTION(exc, 0);  
         return 0;       /* compiler happy */  
 }  
   
 UINT32 MEMCALL  
 cpu_vmemoryread_d(int idx, UINT32 offset)  
 {  
         descriptor_t *sd;  
         UINT32 addr;  
         int exc;  
   
         __ASSERT((unsigned int)idx < CPU_SEGREG_NUM);  
   
         sd = &CPU_STAT_SREG(idx);  
         if (!sd->valid) {  
                 exc = GP_EXCEPTION;  
                 goto err;  
         }  
   
         if (!(sd->flag & CPU_DESC_FLAG_READABLE)) {  
                 cpu_memoryread_check(sd, offset, 4,  
                     (idx == CPU_SS_INDEX) ? SS_EXCEPTION : GP_EXCEPTION);  
         } else {  
                 switch (sd->type) {  
                 case 4: case 5: case 6: case 7:  
                         if (offset - 3 <= sd->u.seg.limit)  
                                 goto range_failure;  
                         break;  
   
                 default:  
                         if (offset > sd->u.seg.limit - 3)  
                                 goto range_failure;  
                         break;  
                 }  
         }  
         addr = sd->u.seg.segbase + offset;  
         check_memory_break_point(addr, 4, CPU_DR7_RW_RO);  
         if (!CPU_STAT_PM)  
                 return cpu_memoryread_d(addr);  
         return cpu_lmemoryread_d(addr, CPU_STAT_USER_MODE);  
   
 range_failure:  
         if (idx == CPU_SS_INDEX) {  
                 exc = SS_EXCEPTION;  
         } else {  
                 exc = GP_EXCEPTION;  
         }  
         VERBOSE(("cpu_vmemoryread_d: type = %d, offset = %08x, limit = %08x", sd->type, offset, sd->u.seg.limit));  
 err:  
         EXCEPTION(exc, 0);  
         return 0;       /* compiler happy */  
 }  
   
 /* vaddr memory write */  
 void MEMCALL  
 cpu_vmemorywrite(int idx, UINT32 offset, UINT8 val)  
 {  
         descriptor_t *sd;  
         UINT32 addr;  
         int exc;  
   
         __ASSERT((unsigned int)idx < CPU_SEGREG_NUM);  
   
         sd = &CPU_STAT_SREG(idx);  
         if (!sd->valid) {  
                 exc = GP_EXCEPTION;  
                 goto err;  
         }  
   
         if (!(sd->flag & CPU_DESC_FLAG_WRITABLE)) {  
                 cpu_memorywrite_check(sd, offset, 1,  
                     (idx == CPU_SS_INDEX) ? SS_EXCEPTION : GP_EXCEPTION);  
         } else {  
                 switch (sd->type) {  
                 case 6: case 7:  
                         if (offset <= sd->u.seg.limit)  
                                 goto range_failure;  
                         break;  
   
                 default:  
                         if (offset > sd->u.seg.limit)  
                                 goto range_failure;  
                         break;  
                 }  
         }  
         addr = sd->u.seg.segbase + offset;  
         check_memory_break_point(addr, 1, CPU_DR7_RW_RW);  
         if (!CPU_STAT_PM) {  
                 /* real mode */  
                 cpu_memorywrite(addr, val);  
         } else {  
                 /* protected mode */  
                 cpu_lmemorywrite(addr, val, CPU_STAT_USER_MODE);  
         }  
         return;  
   
 range_failure:  
         if (idx == CPU_SS_INDEX) {  
                 exc = SS_EXCEPTION;  
         } else {  
                 exc = GP_EXCEPTION;  
         }  
         VERBOSE(("cpu_vmemorywrite: type = %d, offset = %08x, limit = %08x", sd->type, offset, sd->u.seg.limit));  
 err:  
         EXCEPTION(exc, 0);  
 }  
   
 void MEMCALL  
 cpu_vmemorywrite_w(int idx, UINT32 offset, UINT16 val)  
 {  
         descriptor_t *sd;  
         UINT32 addr;  
         int exc;  
   
         __ASSERT((unsigned int)idx < CPU_SEGREG_NUM);  
   
         sd = &CPU_STAT_SREG(idx);  
         if (!sd->valid) {  
                 exc = GP_EXCEPTION;  
                 goto err;  
         }  
   
         if (!(sd->flag & CPU_DESC_FLAG_WRITABLE)) {  
                 cpu_memorywrite_check(sd, offset, 2,  
                     (idx == CPU_SS_INDEX) ? SS_EXCEPTION : GP_EXCEPTION);  
         } else {  
                 switch (sd->type) {  
                 case 6: case 7:  
                         if (offset - 1 <= sd->u.seg.limit)  
                                 goto range_failure;  
                         break;  
   
                 default:  
                         if (offset > sd->u.seg.limit - 1)  
                                 goto range_failure;  
                         break;  
                 }  
         }  
         addr = sd->u.seg.segbase + offset;  
         check_memory_break_point(addr, 2, CPU_DR7_RW_RW);  
         if (!CPU_STAT_PM) {  
                 /* real mode */  
                 cpu_memorywrite_w(addr, val);  
         } else {  
                 /* protected mode */  
                 cpu_lmemorywrite_w(addr, val, CPU_STAT_USER_MODE);  
         }  
         return;  
   
 range_failure:  
         if (idx == CPU_SS_INDEX) {  
                 exc = SS_EXCEPTION;  
         } else {  
                 exc = GP_EXCEPTION;  
         }  
         VERBOSE(("cpu_vmemorywrite_w: type = %d, offset = %08x, limit = %08x", sd->type, offset, sd->u.seg.limit));  
 err:  
         EXCEPTION(exc, 0);  
 }  
   
 void MEMCALL  
 cpu_vmemorywrite_d(int idx, UINT32 offset, UINT32 val)  
 {  
         descriptor_t *sd;  
         UINT32 addr;  
         int exc;  
   
         __ASSERT((unsigned int)idx < CPU_SEGREG_NUM);  
   
         sd = &CPU_STAT_SREG(idx);  
         if (!sd->valid) {  
                 exc = GP_EXCEPTION;  
                 goto err;  
         }  
   
         if (!(sd->flag & CPU_DESC_FLAG_WRITABLE)) {  
                 cpu_memorywrite_check(sd, offset, 4,  
                     (idx == CPU_SS_INDEX) ? SS_EXCEPTION : GP_EXCEPTION);  
         } else {  
                 switch (sd->type) {  
                 case 6: case 7:  
                         if (offset - 3 <= sd->u.seg.limit)  
                                 goto range_failure;  
                         break;  
   
                 default:  
                         if (offset > sd->u.seg.limit - 3)  
                                 goto range_failure;  
                         break;  
                 }  
         }  
         addr = sd->u.seg.segbase + offset;  
         check_memory_break_point(addr, 4, CPU_DR7_RW_RW);  
         if (!CPU_STAT_PM) {  
                 /* real mode */  
                 cpu_memorywrite_d(addr, val);  
         } else {  
                 /* protected mode */  
                 cpu_lmemorywrite_d(addr, val, CPU_STAT_USER_MODE);  
         }  
         return;  
   
 range_failure:  
         if (idx == CPU_SS_INDEX) {  
                 exc = SS_EXCEPTION;  
         } else {  
                 exc = GP_EXCEPTION;  
         }  
         VERBOSE(("cpu_vmemorywrite_d: type = %d, offset = %08x, limit = %08x", sd->type, offset, sd->u.seg.limit));  
 err:  
         EXCEPTION(exc, 0);  
 }  

Removed from v.1.14  
changed lines
  Added in v.1.18


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