Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 550:a27e31340147
prev527:14c9489f647e
next559:06714bc64271
next586:2a3ba82cf243
author nkeynes
date Thu Dec 06 10:43:30 2007 +0000 (12 years ago)
permissions -rw-r--r--
last change Add support for the MMIO side of the TLB (and LDTLB)
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 int32_t sh4_read_long( sh4addr_t addr )
   160 {
   161     sh4ptr_t page;
   163     CHECK_READ_WATCH(addr,4);
   165     if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
   166         return sh4_read_p4( addr );
   167     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   168 	return *(int32_t *)(sh4_main_ram + (addr&0x00FFFFFF));
   169     } else 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     }
   176     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   177     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   178         int32_t val;
   179         if( page == NULL ) {
   180             WARN( "Attempted long read to missing page: %08X", addr );
   181             return 0;
   182         }
   183         val = io_rgn[(uintptr_t)page]->io_read(addr&0xFFF);
   184         TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
   185         return val;
   186     } else {
   187         return *(int32_t *)(page+(addr&0xFFF));
   188     }
   189 }
   191 int32_t sh4_read_word( sh4addr_t addr )
   192 {
   193     sh4ptr_t page;
   195     CHECK_READ_WATCH(addr,2);
   197     if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
   198         return SIGNEXT16(sh4_read_p4( addr ));
   199     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   200 	return SIGNEXT16(*(int16_t *)(sh4_main_ram + (addr&0x00FFFFFF)));
   201     } else if( (addr&0x1F800000) == 0x04000000 ) {
   202         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   203 	pvr2_render_buffer_invalidate(addr, FALSE);
   204     } else if( (addr&0x1F800000) == 0x05000000 ) {
   205 	pvr2_render_buffer_invalidate(addr, FALSE);
   206     }
   208     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   209     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   210         int32_t val;
   211         if( page == NULL ) {
   212 	    WARN( "Attempted word read to missing page: %08X", addr );
   213             return 0;
   214         }
   215         val = SIGNEXT16(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
   216         TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   217         return val;
   218     } else {
   219         return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
   220     }
   221 }
   223 int32_t sh4_read_byte( sh4addr_t addr )
   224 {
   225     sh4ptr_t page;
   227     CHECK_READ_WATCH(addr,1);
   229     if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
   230         return SIGNEXT8(sh4_read_p4( addr ));
   231     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   232 	return SIGNEXT8(*(int8_t *)(sh4_main_ram + (addr&0x00FFFFFF)));
   233     } else if( (addr&0x1F800000) == 0x04000000 ) {
   234         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   235     	pvr2_render_buffer_invalidate(addr, FALSE);
   236     } else if( (addr&0x1F800000) == 0x05000000 ) {
   237 	pvr2_render_buffer_invalidate(addr, FALSE);
   238     }
   241     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   242     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   243         int32_t val;
   244         if( page == NULL ) {
   245             WARN( "Attempted byte read to missing page: %08X", addr );
   246             return 0;
   247         }
   248         val = SIGNEXT8(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
   249         TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
   250         return val;
   251     } else {
   252         return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
   253     }
   254 }
   256 /**
   257  * Convenience function to write a quad-word (implemented as two long writes).
   258  */
   259 void sh4_write_quad( sh4addr_t addr, uint64_t val )
   260 {
   261     sh4_write_long( addr, (uint32_t)val );
   262     sh4_write_long( addr+4, (uint32_t)(val>>32) );
   263 }
   265 void sh4_write_long( sh4addr_t addr, uint32_t val )
   266 {
   267     sh4ptr_t page;
   269     CHECK_WRITE_WATCH(addr,4,val);
   271     if( addr >= 0xE0000000 ) {
   272         sh4_write_p4( addr, val );
   273         return;
   274     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   275 	*(uint32_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
   276 	xlat_invalidate_long(addr);
   277 	return;
   278     } else if( (addr&0x1F800000) == 0x04000000 || 
   279 	       (addr&0x1F800000) == 0x11000000 ) {
   280 	texcache_invalidate_page(addr& 0x7FFFFF);
   281         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   282 	pvr2_render_buffer_invalidate(addr, TRUE);
   283     } else if( (addr&0x1F800000) == 0x05000000 ) {
   284 	pvr2_render_buffer_invalidate(addr, TRUE);
   285     }
   287     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   288         WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
   289         sh4_stop();
   290         return;
   291     }
   292     if( (addr&0x1F800000) == 0x00800000 )
   293 	asic_g2_write_word();
   295     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   296     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   297         if( page == NULL ) {
   298 	    if( (addr & 0x1F000000) >= 0x04000000 &&
   299 		(addr & 0x1F000000) < 0x07000000 )
   300 		return;
   301             WARN( "Long write to missing page: %08X => %08X", val, addr );
   302             return;
   303         }
   304         TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
   305         io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
   306     } else {
   307         *(uint32_t *)(page+(addr&0xFFF)) = val;
   308     }
   309 }
   311 void sh4_write_word( sh4addr_t addr, uint32_t val )
   312 {
   313     sh4ptr_t page;
   315     CHECK_WRITE_WATCH(addr,2,val);
   317     if( addr >= 0xE0000000 ) {
   318         sh4_write_p4( addr, (int16_t)val );
   319         return;
   320     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   321 	*(uint16_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
   322 	xlat_invalidate_word(addr);
   323 	return;
   324     } else if( (addr&0x1F800000) == 0x04000000 ||
   325 	(addr&0x1F800000) == 0x11000000 ) {
   326 	texcache_invalidate_page(addr& 0x7FFFFF);
   327         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   328 	pvr2_render_buffer_invalidate(addr, TRUE);
   329     } else if( (addr&0x1F800000) == 0x05000000 ) {
   330 	pvr2_render_buffer_invalidate(addr, TRUE);
   331     }
   333     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   334         WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
   335         sh4_stop();
   336         return;
   337     }
   338     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   339     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   340         if( page == NULL ) {
   341             WARN( "Attempted word write to missing page: %08X", addr );
   342             return;
   343         }
   344         TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
   345         io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
   346     } else {
   347         *(uint16_t *)(page+(addr&0xFFF)) = val;
   348     }
   349 }
   351 void sh4_write_byte( sh4addr_t addr, uint32_t val )
   352 {
   353     sh4ptr_t page;
   355     CHECK_WRITE_WATCH(addr,1,val);
   357     if( addr >= 0xE0000000 ) {
   358         sh4_write_p4( addr, (int8_t)val );
   359         return;
   360     } else if( (addr&0x1C000000) == 0x0C000000 ) {
   361 	*(uint8_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
   362 	xlat_invalidate_word(addr);
   363 	return;
   364     } else if( (addr&0x1F800000) == 0x04000000 ||
   365 	       (addr&0x1F800000) == 0x11000000 ) {
   366 	texcache_invalidate_page(addr& 0x7FFFFF);
   367         addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
   368 	pvr2_render_buffer_invalidate(addr, TRUE);
   369     } else if( (addr&0x1F800000) == 0x05000000 ) {
   370 	pvr2_render_buffer_invalidate(addr, TRUE);
   371     }
   373     if( (addr&0x1FFFFFFF) < 0x200000 ) {
   374         WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
   375         sh4_stop();
   376         return;
   377     }
   378     page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   379     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   380         if( page == NULL ) {
   381             WARN( "Attempted byte write to missing page: %08X", addr );
   382             return;
   383         }
   384         TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
   385         io_rgn[(uintptr_t)page]->io_write( (addr&0xFFF), val);
   386     } else {
   387         *(uint8_t *)(page+(addr&0xFFF)) = val;
   388     }
   389 }
   393 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
   394  * into the same memory block
   395  */
   396 void mem_copy_from_sh4( sh4ptr_t dest, sh4addr_t srcaddr, size_t count ) {
   397     if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
   398 	pvr2_vram64_read( dest, srcaddr, count );
   399     } else {
   400 	sh4ptr_t src = mem_get_region(srcaddr);
   401 	if( src == NULL ) {
   402 	    WARN( "Attempted block read from unknown address %08X", srcaddr );
   403 	} else {
   404 	    memcpy( dest, src, count );
   405 	}
   406     }
   407 }
   409 void mem_copy_to_sh4( sh4addr_t destaddr, sh4ptr_t src, size_t count ) {
   410     if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
   411 	pvr2_dma_write( destaddr, src, count );
   412 	return;
   413     } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
   414 	pvr2_render_buffer_invalidate( destaddr, TRUE );
   415     } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
   416 	pvr2_vram64_write( destaddr, src, count );
   417 	return;
   418     }
   419     sh4ptr_t dest = mem_get_region(destaddr);
   420     if( dest == NULL )
   421 	WARN( "Attempted block write to unknown address %08X", destaddr );
   422     else {
   423 	xlat_invalidate_block( destaddr, count );
   424 	memcpy( dest, src, count );
   425     }
   426 }
   428 void sh4_flush_store_queue( sh4addr_t addr )
   429 {
   430     /* Store queue operation */
   431     int queue = (addr&0x20)>>2;
   432     sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
   433     uint32_t hi = (MMIO_READ( MMU, (queue == 0 ? QACR0 : QACR1) ) & 0x1C) << 24;
   434     uint32_t target = (addr&0x03FFFFE0) | hi;
   435     mem_copy_to_sh4( target, src, 32 );
   436 }
.