Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 912:c5606ea44232
prev911:2f6ba75b84d1
next927:17b6b9e245d8
author nkeynes
date Thu Dec 11 23:26:03 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Disable the generational translation cache - I've got no evidence that it
actually helps performance, and it simplifies things to get rid of it (in
particular, translated code doesn't have to worry about being moved now).
view annotate diff log raw
     1 /**
     2  * $Id$
     3  * sh4mem.c is responsible for the SH4's access to memory (including memory
     4  * mapped I/O), using the page maps created in mem.c
     5  *
     6  * Copyright (c) 2005 Nathan Keynes.
     7  *
     8  * This program is free software; you can redistribute it and/or modify
     9  * it under the terms of the GNU General Public License as published by
    10  * the Free Software Foundation; either version 2 of the License, or
    11  * (at your option) any later version.
    12  *
    13  * This program is distributed in the hope that it will be useful,
    14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    16  * GNU General Public License for more details.
    17  */
    19 #define MODULE sh4_module
    21 #include <string.h>
    22 #include <zlib.h>
    23 #include "dream.h"
    24 #include "mem.h"
    25 #include "mmio.h"
    26 #include "dreamcast.h"
    27 #include "sh4/sh4core.h"
    28 #include "sh4/sh4mmio.h"
    29 #include "sh4/xltcache.h"
    30 #include "pvr2/pvr2.h"
    31 #include "asic.h"
    33 #define OC_BASE 0x1C000000
    34 #define OC_TOP  0x20000000
    36 #define TRANSLATE_VIDEO_64BIT_ADDRESS(a)  ( (((a)&0x00FFFFF8)>>1)|(((a)&0x00000004)<<20)|((a)&0x03)|0x05000000 )
    38 #ifdef ENABLE_WATCH
    39 #define CHECK_READ_WATCH( addr, size ) \
    40     if( mem_is_watched(addr,size,WATCH_READ) != NULL ) { \
    41         WARN( "Watch triggered at %08X by %d byte read", addr, size ); \
    42         sh4_core_exit(CORE_EXIT_HALT); \
    43     }
    44 #define CHECK_WRITE_WATCH( addr, size, val )                  \
    45     if( mem_is_watched(addr,size,WATCH_WRITE) != NULL ) { \
    46         WARN( "Watch triggered at %08X by %d byte write <= %0*X", addr, size, size*2, val ); \
    47         sh4_core_exit(CORE_EXIT_HALT); \
    48     }
    49 #else
    50 #define CHECK_READ_WATCH( addr, size )
    51 #define CHECK_WRITE_WATCH( addr, size, val )
    52 #endif
    54 #ifdef ENABLE_TRACE_IO
    55 #define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag && !MMIO_NOTRACE_BYNUM((uint32_t)p,r)) \
    56     TRACE( str " [%s.%s: %s]", __VA_ARGS__,			       \
    57             MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
    58             MMIO_REGDESC_BYNUM((uint32_t)p, r) )
    59 #define TRACE_P4IO( str, io, r, ... ) if(io->trace_flag && !MMIO_NOTRACE_IOBYNUM(io,r)) \
    60     TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
    61             io->id, MMIO_REGID_IOBYNUM(io, r), \
    62             MMIO_REGDESC_IOBYNUM(io, r) )
    63 #else
    64 #define TRACE_IO( str, p, r, ... )
    65 #define TRACE_P4IO( str, io, r, ... )
    66 #endif
    68 extern struct mem_region mem_rgn[];
    69 extern struct mmio_region *P4_io[];
    71 int32_t FASTCALL sh4_read_p4( sh4addr_t addr )
    72 {
    73     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
    74     if( !io ) {
    75         switch( addr & 0x1F000000 ) {
    76         case 0x00000000: case 0x01000000: case 0x02000000: case 0x03000000: 
    77             /* Store queue - readable? */
    78             return 0;
    79             break;
    80         case 0x10000000: return mmu_icache_addr_read( addr );
    81         case 0x11000000: return mmu_icache_data_read( addr );
    82         case 0x12000000: return mmu_itlb_addr_read( addr );
    83         case 0x13000000: return mmu_itlb_data_read( addr );
    84         case 0x14000000: return mmu_ocache_addr_read( addr );
    85         case 0x15000000: return mmu_ocache_data_read( addr );
    86         case 0x16000000: return mmu_utlb_addr_read( addr );
    87         case 0x17000000: return mmu_utlb_data_read( addr );
    88         default:
    89             WARN( "Attempted read from unknown or invalid P4 region: %08X", addr );
    90             return 0;
    91         }
    92     } else {
    93         int32_t val = io->io_read( addr&0xFFF );
    94         TRACE_P4IO( "Long read %08X <= %08X", io, (addr&0xFFF), val, addr );
    95         return val;
    96     }    
    97 }
    99 void FASTCALL sh4_write_p4( sh4addr_t addr, int32_t val )
   100 {
   101     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
   102     if( !io ) {
   103         switch( addr & 0x1F000000 ) {
   104         case 0x00000000: case 0x01000000: case 0x02000000: case 0x03000000: 
   105             /* Store queue */
   106             SH4_WRITE_STORE_QUEUE( addr, val );
   107             break;
   108         case 0x10000000: mmu_icache_addr_write( addr, val ); break;
   109         case 0x11000000: mmu_icache_data_write( addr, val ); break;
   110         case 0x12000000: mmu_itlb_addr_write( addr, val ); break;
   111         case 0x13000000: mmu_itlb_data_write( addr, val ); break;
   112         case 0x14000000: mmu_ocache_addr_write( addr, val ); break;
   113         case 0x15000000: mmu_ocache_data_write( addr, val ); break;
   114         case 0x16000000: mmu_utlb_addr_write( addr, val ); break;
   115         case 0x17000000: mmu_utlb_data_write( addr, val ); break;
   116         default:
   117             if( (addr & 0xFFFF0000 ) == 0xFF940000 ||
   118                 (addr & 0xFFFF0000 ) == 0xFF900000 ) {
   119                 // SDRAM configuration, ignore for now
   120             } else {
   121                 WARN( "Attempted write to unknown P4 region: %08X", addr );
   122             }
   123         }
   124     } else {
   125         TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
   126         io->io_write( addr&0xFFF, val );
   127     }
   128 }
   130 int32_t sh4_read_phys_word( sh4addr_t addr )
   131 {
   132     sh4ptr_t page;
   133     if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
   134         return SIGNEXT16(sh4_read_p4( addr ));
   136     if( (addr&0x1F800000) == 0x04000000 ) {
   137         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   138     }
   140     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   141     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   142         if( page == NULL ) {
   143             WARN( "Attempted word read to missing page: %08X",
   144                     addr );
   145             return 0;
   146         }
   147         return SIGNEXT16(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
   148     } else {
   149         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   150     }
   151 }
   153 /**
   154  * Convenience function to read a quad-word (implemented as two long reads).
   155  */
   156 int64_t FASTCALL sh4_read_quad( sh4addr_t addr )
   157 {
   158     return ((int64_t)((uint32_t)sh4_read_long(addr))) |
   159     (((int64_t)((uint32_t)sh4_read_long(addr+4))) << 32);
   160 }
   162 int32_t FASTCALL sh4_read_long( sh4addr_t addr )
   163 {
   164     sh4ptr_t page;
   166     CHECK_READ_WATCH(addr,4);
   168     if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
   169         return ZEROEXT32(sh4_read_p4( addr ));
   170     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   171         return ZEROEXT32(*(int32_t *)(sh4_main_ram + (addr&0x00FFFFFF)));
   172     } else if( (addr&0x1F800000) == 0x04000000 ) {
   173         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   174         pvr2_render_buffer_invalidate(addr, FALSE);
   175     } else if( (addr&0x1F800000) == 0x05000000 ) {
   176         pvr2_render_buffer_invalidate(addr, FALSE);
   177     }
   179     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   180     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   181         int32_t val;
   182         if( page == NULL ) {
   183             WARN( "Attempted long read to missing page: %08X", addr );
   184             return 0;
   185         }
   186         val = io_rgn[(uintptr_t)page]->io_read(addr&0xFFF);
   187         TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
   188         return ZEROEXT32(val);
   189     } else {
   190         return ZEROEXT32(*(int32_t *)(page+(addr&0xFFF)));
   191     }
   192 }
   194 int32_t FASTCALL sh4_read_word( sh4addr_t addr )
   195 {
   196     sh4ptr_t page;
   198     CHECK_READ_WATCH(addr,2);
   200     if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
   201         return ZEROEXT32(SIGNEXT16(sh4_read_p4( addr )));
   202     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   203         return ZEROEXT32(SIGNEXT16(*(int16_t *)(sh4_main_ram + (addr&0x00FFFFFF))));
   204     } else if( (addr&0x1F800000) == 0x04000000 ) {
   205         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   206         pvr2_render_buffer_invalidate(addr, FALSE);
   207     } else if( (addr&0x1F800000) == 0x05000000 ) {
   208         pvr2_render_buffer_invalidate(addr, FALSE);
   209     }
   211     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   212     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   213         int32_t val;
   214         if( page == NULL ) {
   215             WARN( "Attempted word read to missing page: %08X", addr );
   216             return 0;
   217         }
   218         val = SIGNEXT16(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
   219         TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   220         return ZEROEXT32(val);
   221     } else {
   222         return ZEROEXT32(SIGNEXT16(*(int16_t *)(page+(addr&0xFFF))));
   223     }
   224 }
   226 int32_t FASTCALL sh4_read_byte( sh4addr_t addr )
   227 {
   228     sh4ptr_t page;
   230     CHECK_READ_WATCH(addr,1);
   232     if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
   233         return ZEROEXT32(SIGNEXT8(sh4_read_p4( addr )));
   234     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   235         return ZEROEXT32(SIGNEXT8(*(int8_t *)(sh4_main_ram + (addr&0x00FFFFFF))));
   236     } else if( (addr&0x1F800000) == 0x04000000 ) {
   237         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   238         pvr2_render_buffer_invalidate(addr, FALSE);
   239     } else if( (addr&0x1F800000) == 0x05000000 ) {
   240         pvr2_render_buffer_invalidate(addr, FALSE);
   241     }
   244     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   245     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   246         int32_t val;
   247         if( page == NULL ) {
   248             WARN( "Attempted byte read to missing page: %08X", addr );
   249             return 0;
   250         }
   251         val = SIGNEXT8(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
   252         TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
   253         return ZEROEXT32(val);
   254     } else {
   255         return ZEROEXT32(SIGNEXT8(*(int8_t *)(page+(addr&0xFFF))));
   256     }
   257 }
   259 /**
   260  * Convenience function to write a quad-word (implemented as two long writes).
   261  */
   262 void FASTCALL sh4_write_quad( sh4addr_t addr, uint64_t val )
   263 {
   264     sh4_write_long( addr, (uint32_t)val );
   265     sh4_write_long( addr+4, (uint32_t)(val>>32) );
   266 }
   268 void FASTCALL sh4_write_long( sh4addr_t addr, uint32_t val )
   269 {
   270     sh4ptr_t page;
   272     CHECK_WRITE_WATCH(addr,4,val);
   274     if( addr >= 0xE0000000 ) {
   275     	if( addr < 0xE4000000 ) { // Shortcut for the extremely common case
   276             SH4_WRITE_STORE_QUEUE( addr, val );
   277     	} else {
   278             sh4_write_p4( addr, val );
   279     	}
   280         return;
   281     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   282         *(uint32_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
   283         xlat_invalidate_long(addr);
   284         return;
   285     } else if( (addr&0x1F800000) == 0x04000000 || 
   286             (addr&0x1F800000) == 0x11000000 ) {
   287         texcache_invalidate_page(addr& 0x7FFFFF);
   288         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   289         pvr2_render_buffer_invalidate(addr, TRUE);
   290     } else if( (addr&0x1F800000) == 0x05000000 ) {
   291         pvr2_render_buffer_invalidate(addr, TRUE);
   292     }
   294     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   295         WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
   296         sh4_stop();
   297         return;
   298     }
   299     if( (addr&0x1F800000) == 0x00800000 )
   300         asic_g2_write_word();
   302     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   303     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   304         if( page == NULL ) {
   305             if( (addr & 0x1F000000) >= 0x04000000 &&
   306                     (addr & 0x1F000000) < 0x07000000 )
   307                 return;
   308             WARN( "Long write to missing page: %08X => %08X", val, addr );
   309             return;
   310         }
   311         TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
   312         io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
   313     } else {
   314         *(uint32_t *)(page+(addr&0xFFF)) = val;
   315     }
   316 }
   318 void FASTCALL sh4_write_word( sh4addr_t addr, uint32_t val )
   319 {
   320     sh4ptr_t page;
   322     CHECK_WRITE_WATCH(addr,2,val);
   324     if( addr >= 0xE0000000 ) {
   325         sh4_write_p4( addr, (int16_t)val );
   326         return;
   327     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   328         *(uint16_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
   329         xlat_invalidate_word(addr);
   330         return;
   331     } else if( (addr&0x1F800000) == 0x04000000 ||
   332             (addr&0x1F800000) == 0x11000000 ) {
   333         texcache_invalidate_page(addr& 0x7FFFFF);
   334         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   335         pvr2_render_buffer_invalidate(addr, TRUE);
   336     } else if( (addr&0x1F800000) == 0x05000000 ) {
   337         pvr2_render_buffer_invalidate(addr, TRUE);
   338     }
   340     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   341         WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
   342         sh4_stop();
   343         return;
   344     }
   345     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   346     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   347         if( page == NULL ) {
   348             WARN( "Attempted word write to missing page: %08X", addr );
   349             return;
   350         }
   351         TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   352         io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
   353     } else {
   354         *(uint16_t *)(page+(addr&0xFFF)) = val;
   355     }
   356 }
   358 void FASTCALL sh4_write_byte( sh4addr_t addr, uint32_t val )
   359 {
   360     sh4ptr_t page;
   362     CHECK_WRITE_WATCH(addr,1,val);
   364     if( addr >= 0xE0000000 ) {
   365         sh4_write_p4( addr, (int8_t)val );
   366         return;
   367     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   368         *(uint8_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
   369         xlat_invalidate_word(addr);
   370         return;
   371     } else if( (addr&0x1F800000) == 0x04000000 ||
   372             (addr&0x1F800000) == 0x11000000 ) {
   373         texcache_invalidate_page(addr& 0x7FFFFF);
   374         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   375         pvr2_render_buffer_invalidate(addr, TRUE);
   376     } else if( (addr&0x1F800000) == 0x05000000 ) {
   377         pvr2_render_buffer_invalidate(addr, TRUE);
   378     }
   380     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   381         WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
   382         sh4_stop();
   383         return;
   384     }
   385     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   386     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   387         if( page == NULL ) {
   388             WARN( "Attempted byte write to missing page: %08X", addr );
   389             return;
   390         }
   391         TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
   392         io_rgn[(uintptr_t)page]->io_write( (addr&0xFFF), val);
   393     } else {
   394         *(uint8_t *)(page+(addr&0xFFF)) = val;
   395     }
   396 }
   400 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
   401  * into the same memory block
   402  */
   403 void mem_copy_from_sh4( sh4ptr_t dest, sh4addr_t srcaddr, size_t count ) {
   404     if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
   405         pvr2_vram64_read( dest, srcaddr, count );
   406     } else {
   407         sh4ptr_t src = mem_get_region(srcaddr);
   408         if( src == NULL ) {
   409             WARN( "Attempted block read from unknown address %08X", srcaddr );
   410         } else {
   411             memcpy( dest, src, count );
   412         }
   413     }
   414 }
   416 void mem_copy_to_sh4( sh4addr_t destaddr, sh4ptr_t src, size_t count ) {
   417     if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
   418         pvr2_dma_write( destaddr, src, count );
   419         return;
   420     } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
   421         pvr2_render_buffer_invalidate( destaddr, TRUE );
   422     } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
   423         pvr2_vram64_write( destaddr, src, count );
   424         return;
   425     }
   426     sh4ptr_t dest = mem_get_region(destaddr);
   427     if( dest == NULL )
   428         WARN( "Attempted block write to unknown address %08X", destaddr );
   429     else {
   430         xlat_invalidate_block( destaddr, count );
   431         memcpy( dest, src, count );
   432     }
   433 }
   435 sh4ptr_t sh4_get_region_by_vma( sh4addr_t vma )
   436 {
   437     sh4addr_t addr = mmu_vma_to_phys_read(vma);
   438     if( addr == MMU_VMA_ERROR ) {
   439         return NULL;
   440     }
   442     sh4ptr_t page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   443     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   444         return NULL;
   445     } else {
   446         return page+(addr&0xFFF);
   447     }
   448 }
.