Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 598:8798c3f0bf78
prev586:2a3ba82cf243
next736:a02d1475ccfd
author nkeynes
date Tue Jan 22 10:06:41 2008 +0000 (12 years ago)
permissions -rw-r--r--
last change Update sh4_get_region_by_vma (not that anyone uses it...)
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         dreamcast_stop(); \
    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         dreamcast_stop(); \
    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 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 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             WARN( "Attempted write to unknown P4 region: %08X", addr );
   118         }
   119     } else {
   120 	TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
   121         io->io_write( addr&0xFFF, val );
   122     }
   123 }
   125 int32_t sh4_read_phys_word( sh4addr_t addr )
   126 {
   127     sh4ptr_t page;
   128     if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
   129         return SIGNEXT16(sh4_read_p4( addr ));
   131     if( (addr&0x1F800000) == 0x04000000 ) {
   132         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   133     }
   135     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   136     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   137         if( page == NULL ) {
   138             WARN( "Attempted word read to missing page: %08X",
   139                    addr );
   140             return 0;
   141         }
   142         return SIGNEXT16(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
   143     } else {
   144         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   145     }
   146 }
   148 /**
   149  * Convenience function to read a quad-word (implemented as two long reads).
   150  */
   151 int64_t sh4_read_quad( sh4addr_t addr )
   152 {
   153     return ((int64_t)((uint32_t)sh4_read_long(addr))) |
   154 	(((int64_t)((uint32_t)sh4_read_long(addr+4))) << 32);
   155 }
   157 int32_t sh4_read_long( sh4addr_t addr )
   158 {
   159     sh4ptr_t page;
   161     CHECK_READ_WATCH(addr,4);
   163     if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
   164         return ZEROEXT32(sh4_read_p4( addr ));
   165     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   166 	return ZEROEXT32(*(int32_t *)(sh4_main_ram + (addr&0x00FFFFFF)));
   167     } else if( (addr&0x1F800000) == 0x04000000 ) {
   168         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   169 	pvr2_render_buffer_invalidate(addr, FALSE);
   170     } else if( (addr&0x1F800000) == 0x05000000 ) {
   171 	pvr2_render_buffer_invalidate(addr, FALSE);
   172     }
   174     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   175     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   176         int32_t val;
   177         if( page == NULL ) {
   178             WARN( "Attempted long read to missing page: %08X", addr );
   179             return 0;
   180         }
   181         val = io_rgn[(uintptr_t)page]->io_read(addr&0xFFF);
   182         TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
   183         return ZEROEXT32(val);
   184     } else {
   185         return ZEROEXT32(*(int32_t *)(page+(addr&0xFFF)));
   186     }
   187 }
   189 int32_t sh4_read_word( sh4addr_t addr )
   190 {
   191     sh4ptr_t page;
   193     CHECK_READ_WATCH(addr,2);
   195     if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
   196         return ZEROEXT32(SIGNEXT16(sh4_read_p4( addr )));
   197     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   198 	return ZEROEXT32(SIGNEXT16(*(int16_t *)(sh4_main_ram + (addr&0x00FFFFFF))));
   199     } else if( (addr&0x1F800000) == 0x04000000 ) {
   200         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   201 	pvr2_render_buffer_invalidate(addr, FALSE);
   202     } else if( (addr&0x1F800000) == 0x05000000 ) {
   203 	pvr2_render_buffer_invalidate(addr, FALSE);
   204     }
   206     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   207     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   208         int32_t val;
   209         if( page == NULL ) {
   210 	    WARN( "Attempted word read to missing page: %08X", addr );
   211             return 0;
   212         }
   213         val = SIGNEXT16(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
   214         TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   215         return ZEROEXT32(val);
   216     } else {
   217         return ZEROEXT32(SIGNEXT16(*(int16_t *)(page+(addr&0xFFF))));
   218     }
   219 }
   221 int32_t sh4_read_byte( sh4addr_t addr )
   222 {
   223     sh4ptr_t page;
   225     CHECK_READ_WATCH(addr,1);
   227     if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
   228         return ZEROEXT32(SIGNEXT8(sh4_read_p4( addr )));
   229     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   230 	return ZEROEXT32(SIGNEXT8(*(int8_t *)(sh4_main_ram + (addr&0x00FFFFFF))));
   231     } else if( (addr&0x1F800000) == 0x04000000 ) {
   232         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   233     	pvr2_render_buffer_invalidate(addr, FALSE);
   234     } else if( (addr&0x1F800000) == 0x05000000 ) {
   235 	pvr2_render_buffer_invalidate(addr, FALSE);
   236     }
   239     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   240     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   241         int32_t val;
   242         if( page == NULL ) {
   243             WARN( "Attempted byte read to missing page: %08X", addr );
   244             return 0;
   245         }
   246         val = SIGNEXT8(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
   247         TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
   248         return ZEROEXT32(val);
   249     } else {
   250         return ZEROEXT32(SIGNEXT8(*(int8_t *)(page+(addr&0xFFF))));
   251     }
   252 }
   254 /**
   255  * Convenience function to write a quad-word (implemented as two long writes).
   256  */
   257 void sh4_write_quad( sh4addr_t addr, uint64_t val )
   258 {
   259     sh4_write_long( addr, (uint32_t)val );
   260     sh4_write_long( addr+4, (uint32_t)(val>>32) );
   261 }
   263 void sh4_write_long( sh4addr_t addr, uint32_t val )
   264 {
   265     sh4ptr_t page;
   267     CHECK_WRITE_WATCH(addr,4,val);
   269     if( addr >= 0xE0000000 ) {
   270         sh4_write_p4( addr, val );
   271         return;
   272     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   273 	*(uint32_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
   274 	xlat_invalidate_long(addr);
   275 	return;
   276     } else if( (addr&0x1F800000) == 0x04000000 || 
   277 	       (addr&0x1F800000) == 0x11000000 ) {
   278 	texcache_invalidate_page(addr& 0x7FFFFF);
   279         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   280 	pvr2_render_buffer_invalidate(addr, TRUE);
   281     } else if( (addr&0x1F800000) == 0x05000000 ) {
   282 	pvr2_render_buffer_invalidate(addr, TRUE);
   283     }
   285     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   286         WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
   287         sh4_stop();
   288         return;
   289     }
   290     if( (addr&0x1F800000) == 0x00800000 )
   291 	asic_g2_write_word();
   293     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   294     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   295         if( page == NULL ) {
   296 	    if( (addr & 0x1F000000) >= 0x04000000 &&
   297 		(addr & 0x1F000000) < 0x07000000 )
   298 		return;
   299             WARN( "Long write to missing page: %08X => %08X", val, addr );
   300             return;
   301         }
   302         TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
   303         io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
   304     } else {
   305         *(uint32_t *)(page+(addr&0xFFF)) = val;
   306     }
   307 }
   309 void sh4_write_word( sh4addr_t addr, uint32_t val )
   310 {
   311     sh4ptr_t page;
   313     CHECK_WRITE_WATCH(addr,2,val);
   315     if( addr >= 0xE0000000 ) {
   316         sh4_write_p4( addr, (int16_t)val );
   317         return;
   318     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   319 	*(uint16_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
   320 	xlat_invalidate_word(addr);
   321 	return;
   322     } else if( (addr&0x1F800000) == 0x04000000 ||
   323 	(addr&0x1F800000) == 0x11000000 ) {
   324 	texcache_invalidate_page(addr& 0x7FFFFF);
   325         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   326 	pvr2_render_buffer_invalidate(addr, TRUE);
   327     } else if( (addr&0x1F800000) == 0x05000000 ) {
   328 	pvr2_render_buffer_invalidate(addr, TRUE);
   329     }
   331     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   332         WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
   333         sh4_stop();
   334         return;
   335     }
   336     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   337     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   338         if( page == NULL ) {
   339             WARN( "Attempted word write to missing page: %08X", addr );
   340             return;
   341         }
   342         TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   343         io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
   344     } else {
   345         *(uint16_t *)(page+(addr&0xFFF)) = val;
   346     }
   347 }
   349 void sh4_write_byte( sh4addr_t addr, uint32_t val )
   350 {
   351     sh4ptr_t page;
   353     CHECK_WRITE_WATCH(addr,1,val);
   355     if( addr >= 0xE0000000 ) {
   356         sh4_write_p4( addr, (int8_t)val );
   357         return;
   358     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   359 	*(uint8_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
   360 	xlat_invalidate_word(addr);
   361 	return;
   362     } else if( (addr&0x1F800000) == 0x04000000 ||
   363 	       (addr&0x1F800000) == 0x11000000 ) {
   364 	texcache_invalidate_page(addr& 0x7FFFFF);
   365         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   366 	pvr2_render_buffer_invalidate(addr, TRUE);
   367     } else if( (addr&0x1F800000) == 0x05000000 ) {
   368 	pvr2_render_buffer_invalidate(addr, TRUE);
   369     }
   371     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   372         WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
   373         sh4_stop();
   374         return;
   375     }
   376     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   377     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   378         if( page == NULL ) {
   379             WARN( "Attempted byte write to missing page: %08X", addr );
   380             return;
   381         }
   382         TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
   383         io_rgn[(uintptr_t)page]->io_write( (addr&0xFFF), val);
   384     } else {
   385         *(uint8_t *)(page+(addr&0xFFF)) = val;
   386     }
   387 }
   391 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
   392  * into the same memory block
   393  */
   394 void mem_copy_from_sh4( sh4ptr_t dest, sh4addr_t srcaddr, size_t count ) {
   395     if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
   396 	pvr2_vram64_read( dest, srcaddr, count );
   397     } else {
   398 	sh4ptr_t src = mem_get_region(srcaddr);
   399 	if( src == NULL ) {
   400 	    WARN( "Attempted block read from unknown address %08X", srcaddr );
   401 	} else {
   402 	    memcpy( dest, src, count );
   403 	}
   404     }
   405 }
   407 void mem_copy_to_sh4( sh4addr_t destaddr, sh4ptr_t src, size_t count ) {
   408     if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
   409 	pvr2_dma_write( destaddr, src, count );
   410 	return;
   411     } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
   412 	pvr2_render_buffer_invalidate( destaddr, TRUE );
   413     } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
   414 	pvr2_vram64_write( destaddr, src, count );
   415 	return;
   416     }
   417     sh4ptr_t dest = mem_get_region(destaddr);
   418     if( dest == NULL )
   419 	WARN( "Attempted block write to unknown address %08X", destaddr );
   420     else {
   421 	xlat_invalidate_block( destaddr, count );
   422 	memcpy( dest, src, count );
   423     }
   424 }
   426 sh4ptr_t sh4_get_region_by_vma( sh4addr_t vma )
   427 {
   428     sh4addr_t addr = mmu_vma_to_phys_read(vma);
   429     if( addr == MMU_VMA_ERROR ) {
   430 	return NULL;
   431     }
   433     sh4ptr_t page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   434     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   435         return NULL;
   436     } else {
   437         return page+(addr&0xFFF);
   438     }
   439 }
.