Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 911:2f6ba75b84d1
prev910:661367ef919d
next912:c5606ea44232
author nkeynes
date Fri Oct 31 02:57:59 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Declare mem_copy_* functions as FASTCALL
Split sh4_flush_store_queue into TLB/non-TLB versions, and optimize
slightly based on that
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 FASTCALL 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 FASTCALL 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 }
.