Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 400:049d72a7a229
prev371:f2fe152cfc9b
next406:9289b62f8f33
author nkeynes
date Thu Sep 20 08:37:19 2007 +0000 (16 years ago)
permissions -rw-r--r--
last change Move support routines to sh4.c
view annotate diff log raw
     1 /**
     2  * $Id: sh4mem.c,v 1.23 2007-09-20 08:35:04 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 #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         if( (addr & 0xFF000000) != 0xF4000000 ) {
    69 	    /* OC address cache isn't implemented, but don't complain about it.
    70 	     * Complain about anything else though */
    71             ERROR( "Attempted read from unknown P4 region: %08X", addr );
    72         }
    73         return 0;
    74     } else {
    75 	int32_t val = io->io_read( addr&0xFFF );
    76 	TRACE_P4IO( "Long read %08X <= %08X", io, (addr&0xFFF), val, addr );
    77         return val;
    78     }    
    79 }
    81 void sh4_write_p4( uint32_t addr, int32_t val )
    82 {
    83     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
    84     if( !io ) {
    85         if( (addr & 0xFC000000) == 0xE0000000 ) {
    86             /* Store queue */
    87             SH4_WRITE_STORE_QUEUE( addr, val );
    88         } else if( (addr & 0xFF000000) != 0xF4000000 ) {
    89 	    /* OC address cache isn't implemented, but don't complain about it.
    90 	     * Complain about anything else though */
    91             ERROR( "Attempted write to unknown P4 region: %08X", addr );
    92         }
    93     } else {
    94 	TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
    95         io->io_write( addr&0xFFF, val );
    96     }
    97 }
    99 int32_t sh4_read_phys_word( uint32_t addr )
   100 {
   101     char *page;
   102     if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
   103         return SIGNEXT16(sh4_read_p4( addr ));
   105     if( (addr&0x1F800000) == 0x04000000 ) {
   106         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   107     }
   109     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   110     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   111         if( page == NULL ) {
   112             ERROR( "Attempted word read to missing page: %08X",
   113                    addr );
   114             return 0;
   115         }
   116         return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   117     } else {
   118         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   119     }
   120 }
   122 int32_t sh4_read_long( uint32_t addr )
   123 {
   124     char *page;
   126     CHECK_READ_WATCH(addr,4);
   128     if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
   129         return sh4_read_p4( addr );
   131     if( (addr&0x1F800000) == 0x04000000 ) {
   132         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   133 	pvr2_render_buffer_invalidate(addr, FALSE);
   134     } else if( (addr&0x1F800000) == 0x05000000 ) {
   135 	pvr2_render_buffer_invalidate(addr, FALSE);
   136     }
   138     if( IS_MMU_ENABLED() ) {
   139         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   140         sh4_stop();
   141         return 0;
   142     }
   144     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   145     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   146         int32_t val;
   147         if( page == NULL ) {
   148             ERROR( "Attempted long read to missing page: %08X", addr );
   149             return 0;
   150         }
   151         val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
   152         TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
   153         return val;
   154     } else {
   155 	// fprintf( stderr, "MOV.L %08X <= %08X\n",*(int32_t *)(page+(addr&0xFFF)), addr );
   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 ));
   169     if( (addr&0x1F800000) == 0x04000000 ) {
   170         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   171 	pvr2_render_buffer_invalidate(addr, FALSE);
   172     } else if( (addr&0x1F800000) == 0x05000000 ) {
   173 	pvr2_render_buffer_invalidate(addr, FALSE);
   174     }
   177     if( IS_MMU_ENABLED() ) {
   178         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   179         sh4_stop();
   180         return 0;
   181     }
   183     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   184     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   185         int32_t val;
   186         if( page == NULL ) {
   187             ERROR( "Attempted word read to missing page: %08X", addr );
   188             return 0;
   189         }
   190         val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   191         TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   192         return val;
   193     } else {
   194         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   195     }
   196 }
   198 int32_t sh4_read_byte( uint32_t addr )
   199 {
   200     char *page;
   202     CHECK_READ_WATCH(addr,1);
   204     if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
   205         return SIGNEXT8(sh4_read_p4( addr ));
   206     if( (addr&0x1F800000) == 0x04000000 ) {
   207         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   208     	pvr2_render_buffer_invalidate(addr, FALSE);
   209     } else if( (addr&0x1F800000) == 0x05000000 ) {
   210 	pvr2_render_buffer_invalidate(addr, FALSE);
   211     }
   214     if( IS_MMU_ENABLED() ) {
   215         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   216         sh4_stop();
   217         return 0;
   218     }
   220     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   221     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   222         int32_t val;
   223         if( page == NULL ) {
   224             ERROR( "Attempted byte read to missing page: %08X", addr );
   225             return 0;
   226         }
   227         val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
   228         TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
   229         return val;
   230     } else {
   231 	//	fprintf( stderr, "MOV.B %02X <= %08X\n",(uint32_t)*(uint8_t *)(page+(addr&0xFFF)), addr );
   232         return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
   233     }
   234 }
   236 void sh4_write_long( uint32_t addr, uint32_t val )
   237 {
   238     char *page;
   240     // fprintf( stderr, "MOV.L %08X => %08X\n", val, addr );
   241     CHECK_WRITE_WATCH(addr,4,val);
   243     if( addr >= 0xE0000000 ) {
   244         sh4_write_p4( addr, val );
   245         return;
   246     }
   247     if( (addr&0x1F800000) == 0x04000000 || 
   248 	(addr&0x1F800000) == 0x11000000 ) {
   249 	texcache_invalidate_page(addr& 0x7FFFFF);
   250         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   251 	pvr2_render_buffer_invalidate(addr, TRUE);
   252     } else if( (addr&0x1F800000) == 0x05000000 ) {
   253 	pvr2_render_buffer_invalidate(addr, TRUE);
   254     }
   256     if( IS_MMU_ENABLED() ) {
   257         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   258         sh4_stop();
   259         return;
   260     }
   261     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   262         ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
   263         sh4_stop();
   264         return;
   265     }
   266     if( (addr&0x1F800000) == 0x00800000 )
   267 	asic_g2_write_word();
   269     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   270     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   271         if( page == NULL ) {
   272 	    if( (addr & 0x1F000000) >= 0x04000000 &&
   273 		(addr & 0x1F000000) < 0x07000000 )
   274 		return;
   275             ERROR( "Long write to missing page: %08X => %08X", val, addr );
   276             return;
   277         }
   278         TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
   279         io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
   280     } else {
   281 	xlat_invalidate_long(addr);
   282         *(uint32_t *)(page+(addr&0xFFF)) = val;
   283     }
   284 }
   286 void sh4_write_word( uint32_t addr, uint32_t val )
   287 {
   288     char *page;
   290     //    fprintf( stderr, "MOV.W %04X => %08X\n", val, addr );
   291     CHECK_WRITE_WATCH(addr,2,val);
   293     if( addr >= 0xE0000000 ) {
   294         sh4_write_p4( addr, (int16_t)val );
   295         return;
   296     }
   297     if( (addr&0x1F800000) == 0x04000000 ||
   298 	(addr&0x1F800000) == 0x11000000 ) {
   299 	texcache_invalidate_page(addr& 0x7FFFFF);
   300         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   301 	pvr2_render_buffer_invalidate(addr, TRUE);
   302     } else if( (addr&0x1F800000) == 0x05000000 ) {
   303 	pvr2_render_buffer_invalidate(addr, TRUE);
   304     }
   305     if( IS_MMU_ENABLED() ) {
   306         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   307         sh4_stop();
   308         return;
   309     }
   310     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   311         ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
   312         sh4_stop();
   313         return;
   314     }
   315     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   316     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   317         if( page == NULL ) {
   318             ERROR( "Attempted word write to missing page: %08X", addr );
   319             return;
   320         }
   321         TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   322         io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
   323     } else {
   324 	xlat_invalidate_word(addr);
   325         *(uint16_t *)(page+(addr&0xFFF)) = val;
   326     }
   327 }
   329 void sh4_write_byte( uint32_t addr, uint32_t val )
   330 {
   331     char *page;
   333     //    fprintf( stderr, "MOV.B %02X => %08X\n", val, addr );
   334     CHECK_WRITE_WATCH(addr,1,val);
   336     if( addr >= 0xE0000000 ) {
   337         sh4_write_p4( addr, (int8_t)val );
   338         return;
   339     }
   340     if( (addr&0x1F800000) == 0x04000000 ||
   341 	(addr&0x1F800000) == 0x11000000 ) {
   342 	texcache_invalidate_page(addr& 0x7FFFFF);
   343         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   344 	pvr2_render_buffer_invalidate(addr, TRUE);
   345     } else if( (addr&0x1F800000) == 0x05000000 ) {
   346 	pvr2_render_buffer_invalidate(addr, TRUE);
   347     }
   349     if( IS_MMU_ENABLED() ) {
   350         ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
   351         sh4_stop();
   352         return;
   353     }
   354     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   355         ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
   356         sh4_stop();
   357         return;
   358     }
   359     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   360     if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   361         if( page == NULL ) {
   362             ERROR( "Attempted byte write to missing page: %08X", addr );
   363             return;
   364         }
   365         TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
   366         io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
   367     } else {
   368 	xlat_invalidate_word(addr);
   369         *(uint8_t *)(page+(addr&0xFFF)) = val;
   370     }
   371 }
   375 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
   376  * into the same memory block
   377  */
   378 void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) {
   379     if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
   380 	pvr2_vram64_read( dest, srcaddr, count );
   381     } else {
   382 	char *src = mem_get_region(srcaddr);
   383 	if( src == NULL ) {
   384 	    ERROR( "Attempted block read from unknown address %08X", srcaddr );
   385 	} else {
   386 	    memcpy( dest, src, count );
   387 	}
   388     }
   389 }
   391 void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
   392     int region;
   394     if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
   395 	pvr2_dma_write( destaddr, src, count );
   396 	return;
   397     } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
   398 	pvr2_render_buffer_invalidate( destaddr, TRUE );
   399     } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
   400 	pvr2_vram64_write( destaddr, src, count );
   401 	return;
   402     }
   403     char *dest = mem_get_region(destaddr);
   404     if( dest == NULL )
   405 	ERROR( "Attempted block write to unknown address %08X", destaddr );
   406     else {
   407 	xlat_invalidate_block( destaddr, count );
   408 	memcpy( dest, src, count );
   409     }
   410 }
   412 void sh4_flush_store_queue( uint32_t addr )
   413 {
   414     /* Store queue operation */
   415     int queue = (addr&0x20)>>2;
   416     char *src = (char *)&sh4r.store_queue[queue];
   417     uint32_t hi = (MMIO_READ( MMU, (queue == 0 ? QACR0 : QACR1) ) & 0x1C) << 24;
   418     uint32_t target = addr&0x03FFFFE0 | hi;
   419     mem_copy_to_sh4( target, src, 32 );
   420 }
.