Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 418:b9b14afa0959
prev406:9289b62f8f33
next419:09f85e586ff2
author nkeynes
date Thu Oct 04 08:47:52 2007 +0000 (13 years ago)
permissions -rw-r--r--
last change Add explicit branch cases for main ram - yes it's faster...
view annotate diff log raw
     1 /**
     2  * $Id: sh4mem.c,v 1.25 2007-10-04 08:47:52 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, val )
    50 #endif
    52 #ifdef ENABLE_TRACE_IO
    53 #define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag && !MMIO_NOTRACE_BYNUM((uint32_t)p,r)) \
    54     TRACE( str " [%s.%s: %s]", __VA_ARGS__,			       \
    55     MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
    56     MMIO_REGDESC_BYNUM((uint32_t)p, r) )
    57 #define TRACE_P4IO( str, io, r, ... ) if(io->trace_flag && !MMIO_NOTRACE_IOBYNUM(io,r)) \
    58 TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
    59     io->id, MMIO_REGID_IOBYNUM(io, r), \
    60     MMIO_REGDESC_IOBYNUM(io, r) )
    61 #else
    62 #define TRACE_IO( str, p, r, ... )
    63 #define TRACE_P4IO( str, io, r, ... )
    64 #endif
    66 extern struct mem_region mem_rgn[];
    67 extern struct mmio_region *P4_io[];
    68 char *sh4_main_ram;
    70 int32_t sh4_read_p4( uint32_t addr )
    71 {
    72     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
    73     if( !io ) {
    74         if( (addr & 0xFF000000) != 0xF4000000 ) {
    75 	    /* OC address cache isn't implemented, but don't complain about it.
    76 	     * Complain about anything else though */
    77             ERROR( "Attempted read from unknown P4 region: %08X", addr );
    78         }
    79         return 0;
    80     } else {
    81 	int32_t val = io->io_read( addr&0xFFF );
    82 	TRACE_P4IO( "Long read %08X <= %08X", io, (addr&0xFFF), val, addr );
    83         return val;
    84     }    
    85 }
    87 void sh4_write_p4( uint32_t addr, int32_t val )
    88 {
    89     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
    90     if( !io ) {
    91         if( (addr & 0xFC000000) == 0xE0000000 ) {
    92             /* Store queue */
    93             SH4_WRITE_STORE_QUEUE( addr, val );
    94         } else if( (addr & 0xFF000000) != 0xF4000000 ) {
    95 	    /* OC address cache isn't implemented, but don't complain about it.
    96 	     * Complain about anything else though */
    97             ERROR( "Attempted write to unknown P4 region: %08X", addr );
    98         }
    99     } else {
   100 	TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
   101         io->io_write( addr&0xFFF, val );
   102     }
   103 }
   105 int32_t sh4_read_phys_word( uint32_t addr )
   106 {
   107     char *page;
   108     if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
   109         return SIGNEXT16(sh4_read_p4( addr ));
   111     if( (addr&0x1F800000) == 0x04000000 ) {
   112         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   113     }
   115     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   116     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   117         if( page == NULL ) {
   118             ERROR( "Attempted word read to missing page: %08X",
   119                    addr );
   120             return 0;
   121         }
   122         return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   123     } else {
   124         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   125     }
   126 }
   128 int32_t sh4_read_long( uint32_t addr )
   129 {
   130     char *page;
   132     CHECK_READ_WATCH(addr,4);
   134     if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
   135         return sh4_read_p4( addr );
   136     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   137 	return *(int32_t *)(sh4_main_ram + (addr&0x00FFFFFF));
   138     } else if( (addr&0x1F800000) == 0x04000000 ) {
   139         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   140 	pvr2_render_buffer_invalidate(addr, FALSE);
   141     } else if( (addr&0x1F800000) == 0x05000000 ) {
   142 	pvr2_render_buffer_invalidate(addr, FALSE);
   143     }
   145     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   146     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   147         int32_t val;
   148         if( page == NULL ) {
   149             ERROR( "Attempted long read to missing page: %08X", addr );
   150             return 0;
   151         }
   152         val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
   153         TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
   154         return val;
   155     } else {
   156         return *(int32_t *)(page+(addr&0xFFF));
   157     }
   158 }
   160 int32_t sh4_read_word( uint32_t addr )
   161 {
   162     char *page;
   164     CHECK_READ_WATCH(addr,2);
   166     if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
   167         return SIGNEXT16(sh4_read_p4( addr ));
   168     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   169 	return SIGNEXT16(*(int16_t *)(sh4_main_ram + (addr&0x00FFFFFF)));
   170     } else if( (addr&0x1F800000) == 0x04000000 ) {
   171         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   172 	pvr2_render_buffer_invalidate(addr, FALSE);
   173     } else if( (addr&0x1F800000) == 0x05000000 ) {
   174 	pvr2_render_buffer_invalidate(addr, FALSE);
   175     }
   177     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   178     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   179         int32_t val;
   180         if( page == NULL ) {
   181             ERROR( "Attempted word read to missing page: %08X", addr );
   182             return 0;
   183         }
   184         val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   185         TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   186         return val;
   187     } else {
   188         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   189     }
   190 }
   192 int32_t sh4_read_byte( uint32_t addr )
   193 {
   194     char *page;
   196     CHECK_READ_WATCH(addr,1);
   198     if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
   199         return SIGNEXT8(sh4_read_p4( addr ));
   200     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   201 	return SIGNEXT8(*(int8_t *)(sh4_main_ram + (addr&0x00FFFFFF)));
   202     } else if( (addr&0x1F800000) == 0x04000000 ) {
   203         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   204     	pvr2_render_buffer_invalidate(addr, FALSE);
   205     } else if( (addr&0x1F800000) == 0x05000000 ) {
   206 	pvr2_render_buffer_invalidate(addr, FALSE);
   207     }
   210     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   211     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   212         int32_t val;
   213         if( page == NULL ) {
   214             ERROR( "Attempted byte read to missing page: %08X", addr );
   215             return 0;
   216         }
   217         val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   218         TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
   219         return val;
   220     } else {
   221         return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
   222     }
   223 }
   225 void sh4_write_long( uint32_t addr, uint32_t val )
   226 {
   227     char *page;
   229     // fprintf( stderr, "MOV.L %08X => %08X\n", val, addr );
   230     CHECK_WRITE_WATCH(addr,4,val);
   232     if( addr >= 0xE0000000 ) {
   233         sh4_write_p4( addr, val );
   234         return;
   235     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   236 	*(uint32_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
   237 	return;
   238     } else if( (addr&0x1F800000) == 0x04000000 || 
   239 	       (addr&0x1F800000) == 0x11000000 ) {
   240 	texcache_invalidate_page(addr& 0x7FFFFF);
   241         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   242 	pvr2_render_buffer_invalidate(addr, TRUE);
   243     } else if( (addr&0x1F800000) == 0x05000000 ) {
   244 	pvr2_render_buffer_invalidate(addr, TRUE);
   245     }
   247     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   248         ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
   249         sh4_stop();
   250         return;
   251     }
   252     if( (addr&0x1F800000) == 0x00800000 )
   253 	asic_g2_write_word();
   255     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   256     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   257         if( page == NULL ) {
   258 	    if( (addr & 0x1F000000) >= 0x04000000 &&
   259 		(addr & 0x1F000000) < 0x07000000 )
   260 		return;
   261             ERROR( "Long write to missing page: %08X => %08X", val, addr );
   262             return;
   263         }
   264         TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
   265         io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
   266     } else {
   267 	xlat_invalidate_long(addr);
   268         *(uint32_t *)(page+(addr&0xFFF)) = val;
   269     }
   270 }
   272 void sh4_write_word( uint32_t addr, uint32_t val )
   273 {
   274     char *page;
   276     //    fprintf( stderr, "MOV.W %04X => %08X\n", val, addr );
   277     CHECK_WRITE_WATCH(addr,2,val);
   279     if( addr >= 0xE0000000 ) {
   280         sh4_write_p4( addr, (int16_t)val );
   281         return;
   282     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   283 	*(uint16_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
   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         ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
   296         sh4_stop();
   297         return;
   298     }
   299     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   300     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   301         if( page == NULL ) {
   302             ERROR( "Attempted word write to missing page: %08X", addr );
   303             return;
   304         }
   305         TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   306         io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
   307     } else {
   308 	xlat_invalidate_word(addr);
   309         *(uint16_t *)(page+(addr&0xFFF)) = val;
   310     }
   311 }
   313 void sh4_write_byte( uint32_t addr, uint32_t val )
   314 {
   315     char *page;
   317     //    fprintf( stderr, "MOV.B %02X => %08X\n", val, addr );
   318     CHECK_WRITE_WATCH(addr,1,val);
   320     if( addr >= 0xE0000000 ) {
   321         sh4_write_p4( addr, (int8_t)val );
   322         return;
   323     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   324 	*(uint8_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
   325 	return;
   326     } else if( (addr&0x1F800000) == 0x04000000 ||
   327 	       (addr&0x1F800000) == 0x11000000 ) {
   328 	texcache_invalidate_page(addr& 0x7FFFFF);
   329         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   330 	pvr2_render_buffer_invalidate(addr, TRUE);
   331     } else if( (addr&0x1F800000) == 0x05000000 ) {
   332 	pvr2_render_buffer_invalidate(addr, TRUE);
   333     }
   335     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   336         ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
   337         sh4_stop();
   338         return;
   339     }
   340     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   341     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   342         if( page == NULL ) {
   343             ERROR( "Attempted byte write to missing page: %08X", addr );
   344             return;
   345         }
   346         TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
   347         io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
   348     } else {
   349 	xlat_invalidate_word(addr);
   350         *(uint8_t *)(page+(addr&0xFFF)) = val;
   351     }
   352 }
   356 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
   357  * into the same memory block
   358  */
   359 void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) {
   360     if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
   361 	pvr2_vram64_read( dest, srcaddr, count );
   362     } else {
   363 	char *src = mem_get_region(srcaddr);
   364 	if( src == NULL ) {
   365 	    ERROR( "Attempted block read from unknown address %08X", srcaddr );
   366 	} else {
   367 	    memcpy( dest, src, count );
   368 	}
   369     }
   370 }
   372 void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
   373     int region;
   375     if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
   376 	pvr2_dma_write( destaddr, src, count );
   377 	return;
   378     } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
   379 	pvr2_render_buffer_invalidate( destaddr, TRUE );
   380     } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
   381 	pvr2_vram64_write( destaddr, src, count );
   382 	return;
   383     }
   384     char *dest = mem_get_region(destaddr);
   385     if( dest == NULL )
   386 	ERROR( "Attempted block write to unknown address %08X", destaddr );
   387     else {
   388 	xlat_invalidate_block( destaddr, count );
   389 	memcpy( dest, src, count );
   390     }
   391 }
   393 void sh4_flush_store_queue( uint32_t addr )
   394 {
   395     /* Store queue operation */
   396     int queue = (addr&0x20)>>2;
   397     char *src = (char *)&sh4r.store_queue[queue];
   398     uint32_t hi = (MMIO_READ( MMU, (queue == 0 ? QACR0 : QACR1) ) & 0x1C) << 24;
   399     uint32_t target = addr&0x03FFFFE0 | hi;
   400     mem_copy_to_sh4( target, src, 32 );
   401 }
.