Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 559:06714bc64271
prev550:a27e31340147
next561:533f6b478071
author nkeynes
date Tue Jan 01 04:58:57 2008 +0000 (12 years ago)
branchlxdream-mmu
permissions -rw-r--r--
last change Commit first pass at full TLB support - still needs a lot more work
view annotate diff log raw
     1 /**
     2  * $Id: sh4mem.c,v 1.31 2007-11-08 12:01:57 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
    20 #define ENABLE_TRACE_IO 1
    22 #include <string.h>
    23 #include <zlib.h>
    24 #include "dream.h"
    25 #include "mem.h"
    26 #include "mmio.h"
    27 #include "dreamcast.h"
    28 #include "sh4/sh4core.h"
    29 #include "sh4/sh4mmio.h"
    30 #include "sh4/xltcache.h"
    31 #include "pvr2/pvr2.h"
    32 #include "asic.h"
    34 #define OC_BASE 0x1C000000
    35 #define OC_TOP  0x20000000
    37 #define TRANSLATE_VIDEO_64BIT_ADDRESS(a)  ( (((a)&0x00FFFFF8)>>1)|(((a)&0x00000004)<<20)|((a)&0x03)|0x05000000 )
    39 #ifdef ENABLE_WATCH
    40 #define CHECK_READ_WATCH( addr, size ) \
    41     if( mem_is_watched(addr,size,WATCH_READ) != NULL ) { \
    42         WARN( "Watch triggered at %08X by %d byte read", addr, size ); \
    43         dreamcast_stop(); \
    44     }
    45 #define CHECK_WRITE_WATCH( addr, size, val )                  \
    46     if( mem_is_watched(addr,size,WATCH_WRITE) != NULL ) { \
    47         WARN( "Watch triggered at %08X by %d byte write <= %0*X", addr, size, size*2, val ); \
    48         dreamcast_stop(); \
    49     }
    50 #else
    51 #define CHECK_READ_WATCH( addr, size )
    52 #define CHECK_WRITE_WATCH( addr, size, val )
    53 #endif
    55 #ifdef ENABLE_TRACE_IO
    56 #define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag && !MMIO_NOTRACE_BYNUM((uint32_t)p,r)) \
    57     TRACE( str " [%s.%s: %s]", __VA_ARGS__,			       \
    58     MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
    59     MMIO_REGDESC_BYNUM((uint32_t)p, r) )
    60 #define TRACE_P4IO( str, io, r, ... ) if(io->trace_flag && !MMIO_NOTRACE_IOBYNUM(io,r)) \
    61 TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
    62     io->id, MMIO_REGID_IOBYNUM(io, r), \
    63     MMIO_REGDESC_IOBYNUM(io, r) )
    64 #else
    65 #define TRACE_IO( str, p, r, ... )
    66 #define TRACE_P4IO( str, io, r, ... )
    67 #endif
    69 extern struct mem_region mem_rgn[];
    70 extern struct mmio_region *P4_io[];
    71 sh4ptr_t sh4_main_ram;
    73 int32_t sh4_read_p4( sh4addr_t addr )
    74 {
    75     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
    76     if( !io ) {
    77 	switch( addr & 0x1F000000 ) {
    78 	case 0x00000000: case 0x01000000: case 0x02000000: case 0x03000000: 
    79 	    /* Store queue - readable? */
    80 	    return 0;
    81 	    break;
    82 	case 0x10000000: return mmu_icache_addr_read( addr );
    83 	case 0x11000000: return mmu_icache_data_read( addr );
    84 	case 0x12000000: return mmu_itlb_addr_read( addr );
    85 	case 0x13000000: return mmu_itlb_data_read( addr );
    86 	case 0x14000000: return mmu_ocache_addr_read( addr );
    87 	case 0x15000000: return mmu_ocache_data_read( addr );
    88 	case 0x16000000: return mmu_utlb_addr_read( addr );
    89 	case 0x17000000: return mmu_utlb_data_read( addr );
    90 	default:
    91             WARN( "Attempted read from unknown or invalid P4 region: %08X", addr );
    92 	    return 0;
    93         }
    94     } else {
    95 	int32_t val = io->io_read( addr&0xFFF );
    96 	TRACE_P4IO( "Long read %08X <= %08X", io, (addr&0xFFF), val, addr );
    97         return val;
    98     }    
    99 }
   101 void sh4_write_p4( sh4addr_t addr, int32_t val )
   102 {
   103     struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
   104     if( !io ) {
   105 	switch( addr & 0x1F000000 ) {
   106 	case 0x00000000: case 0x01000000: case 0x02000000: case 0x03000000: 
   107             /* Store queue */
   108             SH4_WRITE_STORE_QUEUE( addr, val );
   109 	    break;
   110 	case 0x10000000: mmu_icache_addr_write( addr, val ); break;
   111 	case 0x11000000: mmu_icache_data_write( addr, val ); break;
   112 	case 0x12000000: mmu_itlb_addr_write( addr, val ); break;
   113 	case 0x13000000: mmu_itlb_data_write( addr, val ); break;
   114 	case 0x14000000: mmu_ocache_addr_write( addr, val ); break;
   115 	case 0x15000000: mmu_ocache_data_write( addr, val ); break;
   116 	case 0x16000000: mmu_utlb_addr_write( addr, val ); break;
   117 	case 0x17000000: mmu_utlb_data_write( addr, val ); break;
   118 	default:
   119             WARN( "Attempted write to unknown P4 region: %08X", addr );
   120         }
   121     } else {
   122 	TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
   123         io->io_write( addr&0xFFF, val );
   124     }
   125 }
   127 int32_t sh4_read_phys_word( sh4addr_t addr )
   128 {
   129     sh4ptr_t page;
   130     if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
   131         return SIGNEXT16(sh4_read_p4( addr ));
   133     if( (addr&0x1F800000) == 0x04000000 ) {
   134         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   135     }
   137     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   138     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   139         if( page == NULL ) {
   140             WARN( "Attempted word read to missing page: %08X",
   141                    addr );
   142             return 0;
   143         }
   144         return SIGNEXT16(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
   145     } else {
   146         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   147     }
   148 }
   150 /**
   151  * Convenience function to read a quad-word (implemented as two long reads).
   152  */
   153 int64_t sh4_read_quad( sh4addr_t addr )
   154 {
   155     return ((int64_t)((uint32_t)sh4_read_long(addr))) |
   156 	(((int64_t)((uint32_t)sh4_read_long(addr+4))) << 32);
   157 }
   159 int64_t sh4_read_long( sh4addr_t vma )
   160 {
   161     sh4ptr_t page;
   163     CHECK_READ_WATCH(addr,4);
   165     uint64_t ppa = mmu_vma_to_phys_read(vma);
   166     if( ppa>>32 ) {
   167 	return ppa;
   168     }
   169     sh4addr_t addr = (sh4addr_t)ppa;
   171     if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
   172         return ZEROEXT32(sh4_read_p4( addr ));
   173     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   174 	return ZEROEXT32(*(int32_t *)(sh4_main_ram + (addr&0x00FFFFFF)));
   175     } else if( (addr&0x1F800000) == 0x04000000 ) {
   176         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   177 	pvr2_render_buffer_invalidate(addr, FALSE);
   178     } else if( (addr&0x1F800000) == 0x05000000 ) {
   179 	pvr2_render_buffer_invalidate(addr, FALSE);
   180     }
   182     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   183     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   184         int32_t val;
   185         if( page == NULL ) {
   186             WARN( "Attempted long read to missing page: %08X", addr );
   187             return 0;
   188         }
   189         val = io_rgn[(uintptr_t)page]->io_read(addr&0xFFF);
   190         TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
   191         return ZEROEXT32(val);
   192     } else {
   193         return ZEROEXT32(*(int32_t *)(page+(addr&0xFFF)));
   194     }
   195 }
   197 int64_t sh4_read_word( sh4addr_t vma )
   198 {
   199     sh4ptr_t page;
   201     CHECK_READ_WATCH(addr,2);
   203     uint64_t ppa = mmu_vma_to_phys_read(vma);
   204     if( ppa>>32 ) {
   205 	return ppa;
   206     }
   207     sh4addr_t addr = (sh4addr_t)ppa;
   209     if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
   210         return ZEROEXT32(SIGNEXT16(sh4_read_p4( addr )));
   211     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   212 	return ZEROEXT32(SIGNEXT16(*(int16_t *)(sh4_main_ram + (addr&0x00FFFFFF))));
   213     } else if( (addr&0x1F800000) == 0x04000000 ) {
   214         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   215 	pvr2_render_buffer_invalidate(addr, FALSE);
   216     } else if( (addr&0x1F800000) == 0x05000000 ) {
   217 	pvr2_render_buffer_invalidate(addr, FALSE);
   218     }
   220     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   221     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   222         int32_t val;
   223         if( page == NULL ) {
   224 	    WARN( "Attempted word read to missing page: %08X", addr );
   225             return 0;
   226         }
   227         val = SIGNEXT16(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
   228         TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   229         return ZEROEXT32(val);
   230     } else {
   231         return ZEROEXT32(SIGNEXT16(*(int16_t *)(page+(addr&0xFFF))));
   232     }
   233 }
   235 int64_t sh4_read_byte( sh4addr_t vma )
   236 {
   237     sh4ptr_t page;
   239     CHECK_READ_WATCH(addr,1);
   241     uint64_t ppa = mmu_vma_to_phys_read(vma);
   242     if( ppa>>32 ) {
   243 	return ppa;
   244     }
   245     sh4addr_t addr = (sh4addr_t)ppa;
   247     if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
   248         return ZEROEXT32(SIGNEXT8(sh4_read_p4( addr )));
   249     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   250 	return ZEROEXT32(SIGNEXT8(*(int8_t *)(sh4_main_ram + (addr&0x00FFFFFF))));
   251     } else if( (addr&0x1F800000) == 0x04000000 ) {
   252         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   253     	pvr2_render_buffer_invalidate(addr, FALSE);
   254     } else if( (addr&0x1F800000) == 0x05000000 ) {
   255 	pvr2_render_buffer_invalidate(addr, FALSE);
   256     }
   259     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   260     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   261         int32_t val;
   262         if( page == NULL ) {
   263             WARN( "Attempted byte read to missing page: %08X", addr );
   264             return 0;
   265         }
   266         val = SIGNEXT8(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
   267         TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
   268         return ZEROEXT32(val);
   269     } else {
   270         return ZEROEXT32(SIGNEXT8(*(int8_t *)(page+(addr&0xFFF))));
   271     }
   272 }
   274 /**
   275  * Convenience function to write a quad-word (implemented as two long writes).
   276  */
   277 void sh4_write_quad( sh4addr_t addr, uint64_t val )
   278 {
   279     sh4_write_long( addr, (uint32_t)val );
   280     sh4_write_long( addr+4, (uint32_t)(val>>32) );
   281 }
   283 int32_t sh4_write_long( sh4addr_t vma, uint32_t val )
   284 {
   285     sh4ptr_t page;
   287     uint64_t ppa = mmu_vma_to_phys_write(vma);
   288     if( ppa>>32 ) {
   289 	return ppa>>32;
   290     }
   291     sh4addr_t addr = (sh4addr_t)ppa;
   293     CHECK_WRITE_WATCH(addr,4,val);
   295     if( addr >= 0xE0000000 ) {
   296         sh4_write_p4( addr, val );
   297         return 0;
   298     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   299 	*(uint32_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
   300 	xlat_invalidate_long(addr);
   301 	return 0;
   302     } else if( (addr&0x1F800000) == 0x04000000 || 
   303 	       (addr&0x1F800000) == 0x11000000 ) {
   304 	texcache_invalidate_page(addr& 0x7FFFFF);
   305         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   306 	pvr2_render_buffer_invalidate(addr, TRUE);
   307     } else if( (addr&0x1F800000) == 0x05000000 ) {
   308 	pvr2_render_buffer_invalidate(addr, TRUE);
   309     }
   311     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   312         WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
   313         sh4_stop();
   314         return 0;
   315     }
   316     if( (addr&0x1F800000) == 0x00800000 )
   317 	asic_g2_write_word();
   319     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   320     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   321         if( page == NULL ) {
   322 	    if( (addr & 0x1F000000) >= 0x04000000 &&
   323 		(addr & 0x1F000000) < 0x07000000 )
   324 		return 0;
   325             WARN( "Long write to missing page: %08X => %08X", val, addr );
   326             return 0;
   327         }
   328         TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
   329         io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
   330     } else {
   331         *(uint32_t *)(page+(addr&0xFFF)) = val;
   332     }
   333     return 0;
   334 }
   336 int32_t sh4_write_word( sh4addr_t vma, uint32_t val )
   337 {
   338     sh4ptr_t page;
   340     uint64_t ppa = mmu_vma_to_phys_write(vma);
   341     if( ppa>>32 ) {
   342 	return ppa>>32;
   343     }
   344     sh4addr_t addr = (sh4addr_t)ppa;
   346     CHECK_WRITE_WATCH(addr,2,val);
   348     if( addr >= 0xE0000000 ) {
   349         sh4_write_p4( addr, (int16_t)val );
   350         return 0;
   351     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   352 	*(uint16_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
   353 	xlat_invalidate_word(addr);
   354 	return 0;
   355     } else if( (addr&0x1F800000) == 0x04000000 ||
   356 	(addr&0x1F800000) == 0x11000000 ) {
   357 	texcache_invalidate_page(addr& 0x7FFFFF);
   358         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   359 	pvr2_render_buffer_invalidate(addr, TRUE);
   360     } else if( (addr&0x1F800000) == 0x05000000 ) {
   361 	pvr2_render_buffer_invalidate(addr, TRUE);
   362     }
   364     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   365         WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
   366         sh4_stop();
   367         return 0;
   368     }
   369     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   370     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   371         if( page == NULL ) {
   372             WARN( "Attempted word write to missing page: %08X", addr );
   373             return 0;
   374         }
   375         TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   376         io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
   377     } else {
   378         *(uint16_t *)(page+(addr&0xFFF)) = val;
   379     }
   380     return 0;
   381 }
   383 int32_t sh4_write_byte( sh4addr_t vma, uint32_t val )
   384 {
   385     sh4ptr_t page;
   387     uint64_t ppa = mmu_vma_to_phys_write(vma);
   388     if( ppa>>32 ) {
   389 	return ppa>>32;
   390     }
   391     sh4addr_t addr = (sh4addr_t)ppa;
   393     CHECK_WRITE_WATCH(addr,1,val);
   395     if( addr >= 0xE0000000 ) {
   396         sh4_write_p4( addr, (int8_t)val );
   397         return 0;
   398     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   399 	*(uint8_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
   400 	xlat_invalidate_word(addr);
   401 	return 0;
   402     } else if( (addr&0x1F800000) == 0x04000000 ||
   403 	       (addr&0x1F800000) == 0x11000000 ) {
   404 	texcache_invalidate_page(addr& 0x7FFFFF);
   405         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   406 	pvr2_render_buffer_invalidate(addr, TRUE);
   407     } else if( (addr&0x1F800000) == 0x05000000 ) {
   408 	pvr2_render_buffer_invalidate(addr, TRUE);
   409     }
   411     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   412         WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
   413         sh4_stop();
   414         return 0;
   415     }
   416     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   417     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   418         if( page == NULL ) {
   419             WARN( "Attempted byte write to missing page: %08X", addr );
   420             return 0;
   421         }
   422         TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
   423         io_rgn[(uintptr_t)page]->io_write( (addr&0xFFF), val);
   424     } else {
   425         *(uint8_t *)(page+(addr&0xFFF)) = val;
   426     }
   427     return 0;
   428 }
   432 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
   433  * into the same memory block
   434  */
   435 void mem_copy_from_sh4( sh4ptr_t dest, sh4addr_t srcaddr, size_t count ) {
   436     if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
   437 	pvr2_vram64_read( dest, srcaddr, count );
   438     } else {
   439 	sh4ptr_t src = mem_get_region(srcaddr);
   440 	if( src == NULL ) {
   441 	    WARN( "Attempted block read from unknown address %08X", srcaddr );
   442 	} else {
   443 	    memcpy( dest, src, count );
   444 	}
   445     }
   446 }
   448 void mem_copy_to_sh4( sh4addr_t destaddr, sh4ptr_t src, size_t count ) {
   449     if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
   450 	pvr2_dma_write( destaddr, src, count );
   451 	return;
   452     } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
   453 	pvr2_render_buffer_invalidate( destaddr, TRUE );
   454     } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
   455 	pvr2_vram64_write( destaddr, src, count );
   456 	return;
   457     }
   458     sh4ptr_t dest = mem_get_region(destaddr);
   459     if( dest == NULL )
   460 	WARN( "Attempted block write to unknown address %08X", destaddr );
   461     else {
   462 	xlat_invalidate_block( destaddr, count );
   463 	memcpy( dest, src, count );
   464     }
   465 }
   467 void sh4_flush_store_queue( sh4addr_t addr )
   468 {
   469     /* Store queue operation */
   470     int queue = (addr&0x20)>>2;
   471     sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
   472     uint32_t hi = (MMIO_READ( MMU, (queue == 0 ? QACR0 : QACR1) ) & 0x1C) << 24;
   473     uint32_t target = (addr&0x03FFFFE0) | hi;
   474     mem_copy_to_sh4( target, src, 32 );
   475 }
   477 sh4ptr_t sh4_get_region_by_vma( sh4addr_t vma )
   478 {
   479     uint64_t ppa = mmu_vma_to_phys_read(vma);
   480     if( ppa>>32 ) {
   481 	return 0;
   482     }
   484     sh4addr_t addr = (sh4addr_t)ppa;
   485     sh4ptr_t page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   486     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   487         return NULL;
   488     } else {
   489         return page+(addr&0xFFF);
   490     }
   491 }
.