Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 150:c728a442b43f
prev137:41907543d890
next156:3b93648a3b07
author nkeynes
date Tue May 23 13:10:28 2006 +0000 (14 years ago)
permissions -rw-r--r--
last change Add texcache invalidates on direct writes to 64-bit vram.
Technically we should do it on direct writes to 32-bit vram as well, but
noone (sane) is going to try to write a texture there...
view annotate diff log raw
     1 /**
     2  * $Id: sh4mem.c,v 1.11 2006-05-23 13:10:28 nkeynes Exp $
     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 "sh4core.h"
    27 #include "sh4mmio.h"
    28 #include "dreamcast.h"
    29 #include "pvr2/pvr2.h"
    31 #define OC_BASE 0x1C000000
    32 #define OC_TOP  0x20000000
    34 #define TRANSLATE_VIDEO_64BIT_ADDRESS(a)  ( (((a)&0x00FFFFF8)>>1)|(((a)&0x00000004)<<20)|((a)&0x03)|0x05000000 )
    36 #ifdef ENABLE_WATCH
    37 #define CHECK_READ_WATCH( addr, size ) \
    38     if( mem_is_watched(addr,size,WATCH_READ) != NULL ) { \
    39         WARN( "Watch triggered at %08X by %d byte read", addr, size ); \
    40         dreamcast_stop(); \
    41     }
    42 #define CHECK_WRITE_WATCH( addr, size, val )                  \
    43     if( mem_is_watched(addr,size,WATCH_WRITE) != NULL ) { \
    44         WARN( "Watch triggered at %08X by %d byte write <= %0*X", addr, size, size*2, val ); \
    45         dreamcast_stop(); \
    46     }
    47 #else
    48 #define CHECK_READ_WATCH( addr, size )
    49 #define CHECK_WRITE_WATCH( addr, size )
    50 #endif
    52 #define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag) \
    53 TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
    54     MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
    55     MMIO_REGDESC_BYNUM((uint32_t)p, r) )
    57 extern struct mem_region mem_rgn[];
    58 extern struct mmio_region *P4_io[];
    60 int32_t sh4_read_p4( uint32_t addr )
    61 {
    62     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
    63     if( !io ) {
    64         ERROR( "Attempted read from unknown P4 region: %08X", addr );
    65         return 0;
    66     } else {
    67         return io->io_read( addr&0xFFF );
    68     }    
    69 }
    71 void sh4_write_p4( uint32_t addr, int32_t val )
    72 {
    73     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
    74     if( !io ) {
    75         if( (addr & 0xFC000000) == 0xE0000000 ) {
    76             /* Store queue */
    77             SH4_WRITE_STORE_QUEUE( addr, val );
    78         } else if( (addr & 0xFF000000) != 0xF4000000 ) {
    79 	    /* OC address cache isn't implemented, but don't complain about it.
    80 	     * Complain about anything else though */
    81             ERROR( "Attempted write to unknown P4 region: %08X", addr );
    82         }
    83     } else {
    84         io->io_write( addr&0xFFF, val );
    85     }
    86 }
    88 int32_t sh4_read_phys_word( uint32_t addr )
    89 {
    90     char *page;
    91     if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
    92         return SIGNEXT16(sh4_read_p4( addr ));
    94     if( (addr&0x1F800000) == 0x04000000 ) {
    95         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
    96     }
    98     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
    99     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   100         if( page == NULL ) {
   101             ERROR( "Attempted word read to missing page: %08X",
   102                    addr );
   103             return 0;
   104         }
   105         return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   106     } else {
   107         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   108     }
   109 }
   111 int32_t sh4_read_long( uint32_t addr )
   112 {
   113     char *page;
   115     CHECK_READ_WATCH(addr,4);
   117     if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
   118         return sh4_read_p4( addr );
   120     if( (addr&0x1F800000) == 0x04000000 ) {
   121         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   122     }
   124     if( IS_MMU_ENABLED() ) {
   125         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   126         sh4_stop();
   127         return 0;
   128     }
   130     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   131     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   132         int32_t val;
   133         if( page == NULL ) {
   134             ERROR( "Attempted long read to missing page: %08X", addr );
   135             return 0;
   136         }
   137         val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
   138         TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
   139         return val;
   140     } else {
   141         return *(int32_t *)(page+(addr&0xFFF));
   142     }
   143 }
   145 int32_t sh4_read_word( uint32_t addr )
   146 {
   147     char *page;
   149     CHECK_READ_WATCH(addr,2);
   151     if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
   152         return SIGNEXT16(sh4_read_p4( addr ));
   154     if( (addr&0x1F800000) == 0x04000000 ) {
   155         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   156     }
   158     if( IS_MMU_ENABLED() ) {
   159         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   160         sh4_stop();
   161         return 0;
   162     }
   164     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   165     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   166         int32_t val;
   167         if( page == NULL ) {
   168             ERROR( "Attempted word read to missing page: %08X", addr );
   169             return 0;
   170         }
   171         val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   172         TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   173         return val;
   174     } else {
   175         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   176     }
   177 }
   179 int32_t sh4_read_byte( uint32_t addr )
   180 {
   181     char *page;
   183     CHECK_READ_WATCH(addr,1);
   185     if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
   186         return SIGNEXT8(sh4_read_p4( addr ));
   187     if( (addr&0x1F800000) == 0x04000000 ) {
   188         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   189     }
   191     if( IS_MMU_ENABLED() ) {
   192         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   193         sh4_stop();
   194         return 0;
   195     }
   197     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   198     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   199         int32_t val;
   200         if( page == NULL ) {
   201             ERROR( "Attempted byte read to missing page: %08X", addr );
   202             return 0;
   203         }
   204         val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   205         TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
   206         return val;
   207     } else {
   208         return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
   209     }
   210 }
   212 void sh4_write_long( uint32_t addr, uint32_t val )
   213 {
   214     char *page;
   216     CHECK_WRITE_WATCH(addr,4,val);
   218     if( addr >= 0xE0000000 ) {
   219         sh4_write_p4( addr, val );
   220         return;
   221     }
   222     if( (addr&0x1F800000) == 0x04000000 || 
   223 	(addr&0x1F800000) == 0x11000000 ) {
   224 	texcache_invalidate_page(addr& 0x7FFFFF);
   225         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   226     }
   228     if( IS_MMU_ENABLED() ) {
   229         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   230         sh4_stop();
   231         return;
   232     }
   233     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   234         ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
   235         sh4_stop();
   236         return;
   237     }
   238     if( (addr&0x1F800000) == 0x00800000 )
   239 	asic_g2_write_word();
   241     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   242     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   243         if( page == NULL ) {
   244 	    if( (addr & 0x1F000000) >= 0x04000000 &&
   245 		(addr & 0x1F000000) < 0x07000000 )
   246 		return;
   247             ERROR( "Long write to missing page: %08X => %08X", val, addr );
   248             return;
   249         }
   250         TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
   251         io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
   252     } else {
   253         *(uint32_t *)(page+(addr&0xFFF)) = val;
   254     }
   255 }
   257 void sh4_write_word( uint32_t addr, uint32_t val )
   258 {
   259     char *page;
   261     CHECK_WRITE_WATCH(addr,2,val);
   263     if( addr >= 0xE0000000 ) {
   264         sh4_write_p4( addr, (int16_t)val );
   265         return;
   266     }
   267     if( (addr&0x1F800000) == 0x04000000 ||
   268 	(addr&0x1F800000) == 0x11000000 ) {
   269 	texcache_invalidate_page(addr& 0x7FFFFF);
   270         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   271     }
   272     if( IS_MMU_ENABLED() ) {
   273         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   274         sh4_stop();
   275         return;
   276     }
   277     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   278     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   279         if( page == NULL ) {
   280             ERROR( "Attempted word write to missing page: %08X", addr );
   281             return;
   282         }
   283         TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   284         io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
   285     } else {
   286         *(uint16_t *)(page+(addr&0xFFF)) = val;
   287     }
   288 }
   290 void sh4_write_byte( uint32_t addr, uint32_t val )
   291 {
   292     char *page;
   294     CHECK_WRITE_WATCH(addr,1,val);
   296     if( addr >= 0xE0000000 ) {
   297         sh4_write_p4( addr, (int8_t)val );
   298         return;
   299     }
   300     if( (addr&0x1F800000) == 0x04000000 ||
   301 	(addr&0x1F800000) == 0x11000000 ) {
   302 	texcache_invalidate_page(addr& 0x7FFFFF);
   303         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   304     }
   306     if( IS_MMU_ENABLED() ) {
   307         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   308         sh4_stop();
   309         return;
   310     }
   311     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   312     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   313         if( page == NULL ) {
   314             ERROR( "Attempted byte write to missing page: %08X", addr );
   315             return;
   316         }
   317         TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
   318         io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
   319     } else {
   320         *(uint8_t *)(page+(addr&0xFFF)) = val;
   321     }
   322 }
   326 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
   327  * into the same memory black
   328  */
   329 void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) {
   330     if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
   331 	pvr2_vram64_read( dest, srcaddr, count );
   332     } else {
   333 	char *src = mem_get_region(srcaddr);
   334 	if( src == NULL ) {
   335 	    ERROR( "Attempted block read from unknown address %08X", srcaddr );
   336 	} else {
   337 	    memcpy( dest, src, count );
   338 	}
   339     }
   340 }
   342 void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
   343     if( destaddr >= 0x10000000 && destaddr < 0x11000000 ) {
   344 	pvr2_ta_write( src, count );
   345     } else if( destaddr >= 0x04000000 && destaddr < 0x05000000 ||
   346 	       destaddr >= 0x11000000 && destaddr < 0x12000000 ) {
   347 	pvr2_vram64_write( destaddr, src, count );
   348     } else {
   349 	char *dest = mem_get_region(destaddr);
   350 	if( dest == NULL )
   351 	    ERROR( "Attempted block write to unknown address %08X", destaddr );
   352 	else {
   353 	    memcpy( dest, src, count );
   354 	}
   355     }
   356 }
.