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

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

revision 20 by dpavlin, Mon Oct 8 16:19:23 2007 UTC revision 24 by dpavlin, Mon Oct 8 16:19:56 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_rw.c,v 1.80 2005/11/20 11:28:44 debug Exp $   *  $Id: memory_rw.c,v 1.87 2006/06/22 11:43:03 debug Exp $
29   *   *
30   *  Generic memory_rw(), with special hacks for specific CPU families.   *  Generic memory_rw(), with special hacks for specific CPU families.
31   *   *
# Line 53  Line 53 
53   *  If the address indicates access to a memory mapped device, that device'   *  If the address indicates access to a memory mapped device, that device'
54   *  read/write access function is called.   *  read/write access function is called.
55   *   *
  *  If instruction latency/delay support is enabled, then  
  *  cpu->instruction_delay is increased by the number of instruction to  
  *  delay execution.  
  *  
56   *  This function should not be called with cpu == NULL.   *  This function should not be called with cpu == NULL.
57   *   *
58   *  Returns one of the following:   *  Returns one of the following:
# Line 80  int MEMORY_RW(struct cpu *cpu, struct me Line 76  int MEMORY_RW(struct cpu *cpu, struct me
76          uint64_t paddr;          uint64_t paddr;
77          int cache, no_exceptions, offset;          int cache, no_exceptions, offset;
78          unsigned char *memblock;          unsigned char *memblock;
79  #ifdef MEM_MIPS          int dyntrans_device_danger = 0;
         int bintrans_cached = cpu->machine->bintrans_enable;  
 #endif  
         int bintrans_device_danger = 0;  
80    
81          no_exceptions = misc_flags & NO_EXCEPTIONS;          no_exceptions = misc_flags & NO_EXCEPTIONS;
82          cache = misc_flags & CACHE_FLAGS_MASK;          cache = misc_flags & CACHE_FLAGS_MASK;
# Line 93  int MEMORY_RW(struct cpu *cpu, struct me Line 86  int MEMORY_RW(struct cpu *cpu, struct me
86          if (REAL_MODE && !(misc_flags & PHYSICAL)) {          if (REAL_MODE && !(misc_flags & PHYSICAL)) {
87                  if ((vaddr & 0xffff) + len > 0x10000) {                  if ((vaddr & 0xffff) + len > 0x10000) {
88                          /*  Do one byte at a time:  */                          /*  Do one byte at a time:  */
89                          int res = 0, i;                          int res = 0;
90                            size_t i;
91                          for (i=0; i<len; i++)                          for (i=0; i<len; i++)
92                                  res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1,                                  res = MEMORY_RW(cpu, mem, vaddr+i, &data[i], 1,
93                                      writeflag, misc_flags);                                      writeflag, misc_flags);
# Line 108  int MEMORY_RW(struct cpu *cpu, struct me Line 102  int MEMORY_RW(struct cpu *cpu, struct me
102                      Then do a write of all the new bytes. This is to make sure                      Then do a write of all the new bytes. This is to make sure
103                      than both pages around the boundary are writable so we don't                      than both pages around the boundary are writable so we don't
104                      do a partial write.  */                      do a partial write.  */
105                  int res = 0, i;                  int res = 0;
106                    size_t i;
107                  if (writeflag == MEM_WRITE) {                  if (writeflag == MEM_WRITE) {
108                          unsigned char tmp;                          unsigned char tmp;
109                          for (i=0; i<len; i++) {                          for (i=0; i<len; i++) {
# Line 148  int MEMORY_RW(struct cpu *cpu, struct me Line 143  int MEMORY_RW(struct cpu *cpu, struct me
143          }          }
144  #endif  /*  X86  */  #endif  /*  X86  */
145    
 #ifdef MEM_MIPS  
         if (bintrans_cached) {  
                 if (cache == CACHE_INSTRUCTION) {  
                         cpu->cd.mips.pc_bintrans_host_4kpage = NULL;  
                         cpu->cd.mips.pc_bintrans_paddr_valid = 0;  
                 }  
         }  
 #endif  /*  MEM_MIPS  */  
146    
147  #ifdef MEM_USERLAND  #ifdef MEM_USERLAND
148  #ifdef MEM_ALPHA  #ifdef MEM_ALPHA
# Line 163  int MEMORY_RW(struct cpu *cpu, struct me Line 150  int MEMORY_RW(struct cpu *cpu, struct me
150  #else  #else
151          paddr = vaddr & 0x7fffffff;          paddr = vaddr & 0x7fffffff;
152  #endif  #endif
153          goto have_paddr;  #else   /*  !MEM_USERLAND  */
 #endif  
   
 #ifndef MEM_USERLAND  
 #ifdef MEM_MIPS  
         /*  
          *  For instruction fetch, are we on the same page as the last  
          *  instruction we fetched?  
          *  
          *  NOTE: There's no need to check this stuff here if this address  
          *  is known to be in host ram, as it's done at instruction fetch  
          *  time in cpu.c!  Only check if _host_4k_page == NULL.  
          */  
         if (cache == CACHE_INSTRUCTION &&  
             cpu->cd.mips.pc_last_host_4k_page == NULL &&  
             (vaddr & ~0xfff) == cpu->cd.mips.pc_last_virtual_page) {  
                 paddr = cpu->cd.mips.pc_last_physical_page | (vaddr & 0xfff);  
                 goto have_paddr;  
         }  
 #endif  /*  MEM_MIPS  */  
   
154          if (misc_flags & PHYSICAL || cpu->translate_address == NULL) {          if (misc_flags & PHYSICAL || cpu->translate_address == NULL) {
155                  paddr = vaddr;                  paddr = vaddr;
 #ifdef MEM_ALPHA  
                 /*  paddr &= 0x1fffffff;  For testalpha  */  
                 paddr &= 0x000003ffffffffffULL;  
 #endif  
156          } else {          } else {
157                  ok = cpu->translate_address(cpu, vaddr, &paddr,                  ok = cpu->translate_address(cpu, vaddr, &paddr,
158                      (writeflag? FLAG_WRITEFLAG : 0) +                      (writeflag? FLAG_WRITEFLAG : 0) +
# Line 224  int MEMORY_RW(struct cpu *cpu, struct me Line 187  int MEMORY_RW(struct cpu *cpu, struct me
187  #endif  #endif
188          }          }
189  #endif  #endif
190    #endif  /*  !MEM_USERLAND  */
 #ifdef MEM_MIPS  
         /*  
          *  If correct cache emulation is enabled, and we need to simluate  
          *  cache misses even from the instruction cache, we can't run directly  
          *  from a host page. :-/  
          */  
 #if defined(ENABLE_CACHE_EMULATION) && defined(ENABLE_INSTRUCTION_DELAYS)  
 #else  
         if (cache == CACHE_INSTRUCTION) {  
                 cpu->cd.mips.pc_last_virtual_page = vaddr & ~0xfff;  
                 cpu->cd.mips.pc_last_physical_page = paddr & ~0xfff;  
                 cpu->cd.mips.pc_last_host_4k_page = NULL;  
   
                 /*  _last_host_4k_page will be set to 1 further down,  
                     if the page is actually in host ram  */  
         }  
 #endif  
 #endif  /*  MEM_MIPS  */  
 #endif  /*  ifndef MEM_USERLAND  */  
   
   
 #if defined(MEM_MIPS) || defined(MEM_USERLAND)  
 have_paddr:  
 #endif  
   
   
 #ifdef MEM_MIPS  
         /*  TODO: How about bintrans vs cache emulation?  */  
         if (bintrans_cached) {  
                 if (cache == CACHE_INSTRUCTION) {  
                         cpu->cd.mips.pc_bintrans_paddr_valid = 1;  
                         cpu->cd.mips.pc_bintrans_paddr = paddr;  
                 }  
         }  
 #endif  /*  MEM_MIPS  */  
   
191    
192    
193  #ifndef MEM_USERLAND  #ifndef MEM_USERLAND
194          /*          /*
195           *  Memory mapped device?           *  Memory mapped device?
196           *           *
197           *  TODO: this is utterly slow.           *  TODO: if paddr < base, but len enough, then the device should
198           *  TODO2: if paddr<base, but len enough, then we should write           *  still be written to!
          *  to a device to  
199           */           */
200          if (paddr >= mem->mmap_dev_minaddr && paddr < mem->mmap_dev_maxaddr) {          if (paddr >= mem->mmap_dev_minaddr && paddr < mem->mmap_dev_maxaddr) {
201                  uint64_t orig_paddr = paddr;                  uint64_t orig_paddr = paddr;
202                  int i, start, res;                  int i, start, end, res;
203    
204                  /*                  /*
205                   *  Really really slow, but unfortunately necessary. This is                   *  Really really slow, but unfortunately necessary. This is
# Line 283  have_paddr: Line 209  have_paddr:
209                   *      b) offsets 0x124..0x777 are a device                   *      b) offsets 0x124..0x777 are a device
210                   *                   *
211                   *      1) a read is done from offset 0x100. the page is                   *      1) a read is done from offset 0x100. the page is
212                   *         added to the bintrans system as a "RAM" page                   *         added to the dyntrans system as a "RAM" page
213                   *      2) a bintranslated read is done from offset 0x200,                   *      2) a dyntranslated read is done from offset 0x200,
214                   *         which should access the device, but since the                   *         which should access the device, but since the
215                   *         entire page is added, it will access non-existant                   *         entire page is added, it will access non-existant
216                   *         RAM instead, without warning.                   *         RAM instead, without warning.
217                   *                   *
218                   *  Setting bintrans_device_danger = 1 on accesses which are                   *  Setting dyntrans_device_danger = 1 on accesses which are
219                   *  on _any_ offset on pages that are device mapped avoids                   *  on _any_ offset on pages that are device mapped avoids
220                   *  this problem, but it is probably not very fast.                   *  this problem, but it is probably not very fast.
221                     *
222                     *  TODO: Convert this into a quick (multi-level, 64-bit)
223                     *  address space lookup, to find dangerous pages.
224                   */                   */
225    #if 1
226                  for (i=0; i<mem->n_mmapped_devices; i++)                  for (i=0; i<mem->n_mmapped_devices; i++)
227                          if (paddr >= (mem->dev_baseaddr[i] & ~offset_mask) &&                          if (paddr >= (mem->dev_baseaddr[i] & ~offset_mask) &&
228                              paddr <= ((mem->dev_endaddr[i]-1) | offset_mask)) {                              paddr <= ((mem->dev_endaddr[i]-1) | offset_mask)) {
229                                  bintrans_device_danger = 1;                                  dyntrans_device_danger = 1;
230                                  break;                                  break;
231                          }                          }
232    #endif
233    
234                  i = start = mem->last_accessed_device;                  start = 0; end = mem->n_mmapped_devices - 1;
235                    i = mem->last_accessed_device;
236    
237                  /*  Scan through all devices:  */                  /*  Scan through all devices:  */
238                  do {                  do {
# Line 369  have_paddr: Line 301  have_paddr:
301                                              data, len, writeflag,                                              data, len, writeflag,
302                                              mem->dev_extra[i]);                                              mem->dev_extra[i]);
303    
 #ifdef ENABLE_INSTRUCTION_DELAYS  
304                                  if (res == 0)                                  if (res == 0)
305                                          res = -1;                                          res = -1;
306    
 #ifdef MEM_MIPS  
                                 cpu->cd.mips.instruction_delay +=  
                                     ( (abs(res) - 1) *  
                                      cpu->cd.mips.cpu_type.instrs_per_cycle );  
 #endif  
 #endif  
   
307  #ifndef MEM_X86  #ifndef MEM_X86
308                                  /*                                  /*
309                                   *  If accessing the memory mapped device                                   *  If accessing the memory mapped device
# Line 400  have_paddr: Line 324  have_paddr:
324                                  goto do_return_ok;                                  goto do_return_ok;
325                          }                          }
326    
327                          i ++;                          if (paddr < mem->dev_baseaddr[i])
328                          if (i == mem->n_mmapped_devices)                                  end = i - 1;
329                                  i = 0;                          if (paddr >= mem->dev_endaddr[i])
330                  } while (i != start);                                  start = i + 1;
331                            i = (start + end) >> 1;
332                    } while (start <= end);
333          }          }
334    
335    
# Line 446  have_paddr: Line 372  have_paddr:
372  #endif /* MIPS */  #endif /* MIPS */
373                  {                  {
374                          if (paddr >= mem->physical_max) {                          if (paddr >= mem->physical_max) {
375                                    uint64_t offset, old_pc = cpu->pc;
376                                  char *symbol;                                  char *symbol;
                                 uint64_t offset;  
 #ifdef MEM_MIPS  
                                 uint64_t old_pc = cpu->cd.mips.pc_last;  
 #else  
                                 uint64_t old_pc = cpu->pc;  
 #endif  
377    
378                                  /*  This allows for example OS kernels to probe                                  /*  This allows for example OS kernels to probe
379                                      memory a few KBs past the end of memory,                                      memory a few KBs past the end of memory,
# Line 499  have_paddr: Line 420  have_paddr:
420                                          fatal(" <%s> ]\n",                                          fatal(" <%s> ]\n",
421                                              symbol? symbol : " no symbol ");                                              symbol? symbol : " no symbol ");
422                                  }                                  }
   
                                 if (cpu->machine->single_step_on_bad_addr) {  
                                         fatal("[ unimplemented access to "  
                                             "0x%llx, pc=0x",(long long)paddr);  
                                         if (cpu->is_32bit)  
                                                 fatal("%08x ]\n",  
                                                     (int)old_pc);  
                                         else  
                                                 fatal("%016llx ]\n",  
                                                     (long long)old_pc);  
                                         single_step = 1;  
                                 }  
423                          }                          }
424    
425                          if (writeflag == MEM_READ) {                          if (writeflag == MEM_READ) {
# Line 569  have_paddr: Line 478  have_paddr:
478    
479          offset = paddr & ((1 << BITS_PER_MEMBLOCK) - 1);          offset = paddr & ((1 << BITS_PER_MEMBLOCK) - 1);
480    
481          if (cpu->update_translation_table != NULL && !bintrans_device_danger          if (cpu->update_translation_table != NULL && !dyntrans_device_danger
482  #ifndef MEM_MIPS  #ifndef MEM_MIPS
483  /*          && !(misc_flags & MEMORY_USER_ACCESS)  */  /*          && !(misc_flags & MEMORY_USER_ACCESS)  */
484  #ifndef MEM_USERLAND  #ifndef MEM_USERLAND
# Line 613  have_paddr: Line 522  have_paddr:
522                          *(uint8_t *)data = *(uint8_t *)(memblock + offset);                          *(uint8_t *)data = *(uint8_t *)(memblock + offset);
523                  else                  else
524                          memcpy(data, memblock + offset, len);                          memcpy(data, memblock + offset, len);
   
 #ifdef MEM_MIPS  
                 if (cache == CACHE_INSTRUCTION) {  
                         cpu->cd.mips.pc_last_host_4k_page = memblock  
                             + (offset & ~offset_mask);  
                         if (bintrans_cached) {  
                                 cpu->cd.mips.pc_bintrans_host_4kpage =  
                                     cpu->cd.mips.pc_last_host_4k_page;  
                         }  
                 }  
 #endif  /*  MIPS  */  
525          }          }
526    
527    

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

  ViewVC Help
Powered by ViewVC 1.1.26