Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 217:d0b3da720456
prev172:59cf18b4cfb2
next234:8759d0067e9d
author nkeynes
date Tue Aug 29 08:09:51 2006 +0000 (14 years ago)
permissions -rw-r--r--
last change Flush render buffer back to vram on read as well as write
view annotate diff log raw
     1 /**
     2  * $Id: sh4mem.c,v 1.15 2006-08-29 08:09:51 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 && !MMIO_NOTRACE_BYNUM((uint32_t)p,r)) \
    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) )
    56 #define TRACE_P4IO( str, io, r, ... ) if(io->trace_flag && !MMIO_NOTRACE_IOBYNUM(io,r)) \
    57 TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
    58     io->id, MMIO_REGID_IOBYNUM(io, r), \
    59     MMIO_REGDESC_IOBYNUM(io, r) )
    61 extern struct mem_region mem_rgn[];
    62 extern struct mmio_region *P4_io[];
    64 int32_t sh4_read_p4( uint32_t addr )
    65 {
    66     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
    67     if( !io ) {
    68         ERROR( "Attempted read from unknown P4 region: %08X", addr );
    69         return 0;
    70     } else {
    71 	int32_t val = io->io_read( addr&0xFFF );
    72 	TRACE_P4IO( "Long read %08X <= %08X", io, (addr&0xFFF), val, addr );
    73         return val;
    74     }    
    75 }
    77 void sh4_write_p4( uint32_t addr, int32_t val )
    78 {
    79     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
    80     if( !io ) {
    81         if( (addr & 0xFC000000) == 0xE0000000 ) {
    82             /* Store queue */
    83             SH4_WRITE_STORE_QUEUE( addr, val );
    84         } else if( (addr & 0xFF000000) != 0xF4000000 ) {
    85 	    /* OC address cache isn't implemented, but don't complain about it.
    86 	     * Complain about anything else though */
    87             ERROR( "Attempted write to unknown P4 region: %08X", addr );
    88         }
    89     } else {
    90 	TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
    91         io->io_write( addr&0xFFF, val );
    92     }
    93 }
    95 int32_t sh4_read_phys_word( uint32_t addr )
    96 {
    97     char *page;
    98     if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
    99         return SIGNEXT16(sh4_read_p4( addr ));
   101     if( (addr&0x1F800000) == 0x04000000 ) {
   102         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   103     }
   105     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   106     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   107         if( page == NULL ) {
   108             ERROR( "Attempted word read to missing page: %08X",
   109                    addr );
   110             return 0;
   111         }
   112         return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   113     } else {
   114         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   115     }
   116 }
   118 int32_t sh4_read_long( uint32_t addr )
   119 {
   120     char *page;
   122     CHECK_READ_WATCH(addr,4);
   124     if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
   125         return sh4_read_p4( addr );
   127     if( (addr&0x1F800000) == 0x04000000 ) {
   128         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   129 	pvr2_render_invalidate(addr);
   130     } else if( (addr&0x1F800000) == 0x05000000 ) {
   131 	pvr2_render_invalidate(addr);
   132     }
   134     if( IS_MMU_ENABLED() ) {
   135         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   136         sh4_stop();
   137         return 0;
   138     }
   140     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   141     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   142         int32_t val;
   143         if( page == NULL ) {
   144             ERROR( "Attempted long read to missing page: %08X", addr );
   145             return 0;
   146         }
   147         val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
   148         TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
   149         return val;
   150     } else {
   151         return *(int32_t *)(page+(addr&0xFFF));
   152     }
   153 }
   155 int32_t sh4_read_word( uint32_t addr )
   156 {
   157     char *page;
   159     CHECK_READ_WATCH(addr,2);
   161     if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
   162         return SIGNEXT16(sh4_read_p4( addr ));
   164     if( (addr&0x1F800000) == 0x04000000 ) {
   165         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   166 	pvr2_render_invalidate(addr);
   167     } else if( (addr&0x1F800000) == 0x05000000 ) {
   168 	pvr2_render_invalidate(addr);
   169     }
   172     if( IS_MMU_ENABLED() ) {
   173         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   174         sh4_stop();
   175         return 0;
   176     }
   178     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   179     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   180         int32_t val;
   181         if( page == NULL ) {
   182             ERROR( "Attempted word read to missing page: %08X", addr );
   183             return 0;
   184         }
   185         val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   186         TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   187         return val;
   188     } else {
   189         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   190     }
   191 }
   193 int32_t sh4_read_byte( uint32_t addr )
   194 {
   195     char *page;
   197     CHECK_READ_WATCH(addr,1);
   199     if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
   200         return SIGNEXT8(sh4_read_p4( addr ));
   201     if( (addr&0x1F800000) == 0x04000000 ) {
   202         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   203     	pvr2_render_invalidate(addr);
   204     } else if( (addr&0x1F800000) == 0x05000000 ) {
   205 	pvr2_render_invalidate(addr);
   206     }
   209     if( IS_MMU_ENABLED() ) {
   210         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   211         sh4_stop();
   212         return 0;
   213     }
   215     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   216     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   217         int32_t val;
   218         if( page == NULL ) {
   219             ERROR( "Attempted byte read to missing page: %08X", addr );
   220             return 0;
   221         }
   222         val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   223         TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
   224         return val;
   225     } else {
   226         return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
   227     }
   228 }
   230 void sh4_write_long( uint32_t addr, uint32_t val )
   231 {
   232     char *page;
   234     CHECK_WRITE_WATCH(addr,4,val);
   236     if( addr >= 0xE0000000 ) {
   237         sh4_write_p4( addr, val );
   238         return;
   239     }
   240     if( (addr&0x1F800000) == 0x04000000 || 
   241 	(addr&0x1F800000) == 0x11000000 ) {
   242 	texcache_invalidate_page(addr& 0x7FFFFF);
   243         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   244 	pvr2_render_invalidate(addr);
   245     } else if( (addr&0x1F800000) == 0x05000000 ) {
   246 	pvr2_render_invalidate(addr);
   247     }
   249     if( IS_MMU_ENABLED() ) {
   250         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   251         sh4_stop();
   252         return;
   253     }
   254     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   255         ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
   256         sh4_stop();
   257         return;
   258     }
   259     if( (addr&0x1F800000) == 0x00800000 )
   260 	asic_g2_write_word();
   262     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   263     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   264         if( page == NULL ) {
   265 	    if( (addr & 0x1F000000) >= 0x04000000 &&
   266 		(addr & 0x1F000000) < 0x07000000 )
   267 		return;
   268             ERROR( "Long write to missing page: %08X => %08X", val, addr );
   269             return;
   270         }
   271         TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
   272         io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
   273     } else {
   274         *(uint32_t *)(page+(addr&0xFFF)) = val;
   275     }
   276 }
   278 void sh4_write_word( uint32_t addr, uint32_t val )
   279 {
   280     char *page;
   282     CHECK_WRITE_WATCH(addr,2,val);
   284     if( addr >= 0xE0000000 ) {
   285         sh4_write_p4( addr, (int16_t)val );
   286         return;
   287     }
   288     if( (addr&0x1F800000) == 0x04000000 ||
   289 	(addr&0x1F800000) == 0x11000000 ) {
   290 	texcache_invalidate_page(addr& 0x7FFFFF);
   291         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   292 	pvr2_render_invalidate(addr);
   293     } else if( (addr&0x1F800000) == 0x05000000 ) {
   294 	pvr2_render_invalidate(addr);
   295     }
   296     if( IS_MMU_ENABLED() ) {
   297         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   298         sh4_stop();
   299         return;
   300     }
   301     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   302     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   303         if( page == NULL ) {
   304             ERROR( "Attempted word write to missing page: %08X", addr );
   305             return;
   306         }
   307         TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   308         io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
   309     } else {
   310         *(uint16_t *)(page+(addr&0xFFF)) = val;
   311     }
   312 }
   314 void sh4_write_byte( uint32_t addr, uint32_t val )
   315 {
   316     char *page;
   318     CHECK_WRITE_WATCH(addr,1,val);
   320     if( addr >= 0xE0000000 ) {
   321         sh4_write_p4( addr, (int8_t)val );
   322         return;
   323     }
   324     if( (addr&0x1F800000) == 0x04000000 ||
   325 	(addr&0x1F800000) == 0x11000000 ) {
   326 	texcache_invalidate_page(addr& 0x7FFFFF);
   327         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   328 	pvr2_render_invalidate(addr);
   329     } else if( (addr&0x1F800000) == 0x05000000 ) {
   330 	pvr2_render_invalidate(addr);
   331     }
   333     if( IS_MMU_ENABLED() ) {
   334         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   335         sh4_stop();
   336         return;
   337     }
   338     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   339     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   340         if( page == NULL ) {
   341             ERROR( "Attempted byte write to missing page: %08X", addr );
   342             return;
   343         }
   344         TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
   345         io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
   346     } else {
   347         *(uint8_t *)(page+(addr&0xFFF)) = val;
   348     }
   349 }
   353 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
   354  * into the same memory black
   355  */
   356 void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) {
   357     if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
   358 	pvr2_vram64_read( dest, srcaddr, count );
   359     } else {
   360 	char *src = mem_get_region(srcaddr);
   361 	if( src == NULL ) {
   362 	    ERROR( "Attempted block read from unknown address %08X", srcaddr );
   363 	} else {
   364 	    memcpy( dest, src, count );
   365 	}
   366     }
   367 }
   369 void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
   370     if( destaddr >= 0x10000000 && destaddr < 0x11000000 ) {
   371 	pvr2_ta_write( src, count );
   372     } else if( destaddr >= 0x04000000 && destaddr < 0x05000000 ||
   373 	       destaddr >= 0x11000000 && destaddr < 0x12000000 ) {
   374 	pvr2_vram64_write( destaddr, src, count );
   375     } else {
   376 	if( (destaddr & 0x1F800000) == 0x05000000 )
   377 	    pvr2_render_invalidate( destaddr );
   378 	char *dest = mem_get_region(destaddr);
   379 	if( dest == NULL )
   380 	    ERROR( "Attempted block write to unknown address %08X", destaddr );
   381 	else {
   382 	    memcpy( dest, src, count );
   383 	}
   384     }
   385 }
.