Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 934:3acd3b3ee6d1
prev933:880c37bb1909
next939:6f2302afeb89
author nkeynes
date Fri Dec 26 14:25:23 2008 +0000 (12 years ago)
branchlxdream-mem
permissions -rw-r--r--
last change Change RAM regions to use static arrays rather than mmap regions, for a 2-3% performance gain.
General mem cleanups, including some save state fixes that break states again.
view annotate diff log raw
     1 /**
     2  * $Id$
     3  * sh4mem.c is responsible for interfacing between the SH4's internal memory
     4  *
     5  * Copyright (c) 2005 Nathan Keynes.
     6  *
     7  * This program is free software; you can redistribute it and/or modify
     8  * it under the terms of the GNU General Public License as published by
     9  * the Free Software Foundation; either version 2 of the License, or
    10  * (at your option) any later version.
    11  *
    12  * This program is distributed in the hope that it will be useful,
    13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    15  * GNU General Public License for more details.
    16  */
    18 #define MODULE sh4_module
    20 #include <string.h>
    21 #include <zlib.h>
    22 #include "dream.h"
    23 #include "mem.h"
    24 #include "mmio.h"
    25 #include "dreamcast.h"
    26 #include "sh4/sh4core.h"
    27 #include "sh4/sh4mmio.h"
    28 #include "sh4/xltcache.h"
    29 #include "pvr2/pvr2.h"
    31 /* System regions (probably should be defined elsewhere) */
    32 extern struct mem_region_fn mem_region_unmapped;
    33 extern struct mem_region_fn mem_region_sdram;
    34 extern struct mem_region_fn mem_region_vram32;
    35 extern struct mem_region_fn mem_region_vram64;
    36 extern struct mem_region_fn mem_region_audioram;
    37 extern struct mem_region_fn mem_region_flashram;
    38 extern struct mem_region_fn mem_region_bootrom;
    40 /* On-chip regions other than defined MMIO regions */
    41 extern struct mem_region_fn p4_region_storequeue;
    42 extern struct mem_region_fn p4_region_icache_addr;
    43 extern struct mem_region_fn p4_region_icache_data;
    44 extern struct mem_region_fn p4_region_ocache_addr;
    45 extern struct mem_region_fn p4_region_ocache_data;
    46 extern struct mem_region_fn p4_region_itlb_addr;
    47 extern struct mem_region_fn p4_region_itlb_data;
    48 extern struct mem_region_fn p4_region_utlb_addr;
    49 extern struct mem_region_fn p4_region_utlb_data;
    51 /********************* The main ram address space **********************/
    52 static int32_t FASTCALL ext_sdram_read_long( sh4addr_t addr )
    53 {
    54     return *((int32_t *)(dc_main_ram + (addr&0x00FFFFFF)));
    55 }
    56 static int32_t FASTCALL ext_sdram_read_word( sh4addr_t addr )
    57 {
    58     return SIGNEXT16(*((int16_t *)(dc_main_ram + (addr&0x00FFFFFF))));
    59 }
    60 static int32_t FASTCALL ext_sdram_read_byte( sh4addr_t addr )
    61 {
    62     return SIGNEXT8(*((int16_t *)(dc_main_ram + (addr&0x00FFFFFF))));
    63 }
    64 static void FASTCALL ext_sdram_write_long( sh4addr_t addr, uint32_t val )
    65 {
    66     *(uint32_t *)(dc_main_ram + (addr&0x00FFFFFF)) = val;
    67     xlat_invalidate_long(addr);
    68 }
    69 static void FASTCALL ext_sdram_write_word( sh4addr_t addr, uint32_t val )
    70 {
    71     *(uint16_t *)(dc_main_ram + (addr&0x00FFFFFF)) = (uint16_t)val;
    72     xlat_invalidate_word(addr);
    73 }
    74 static void FASTCALL ext_sdram_write_byte( sh4addr_t addr, uint32_t val )
    75 {
    76     *(uint8_t *)(dc_main_ram + (addr&0x00FFFFFF)) = (uint8_t)val;
    77     xlat_invalidate_word(addr);
    78 }
    79 static void FASTCALL ext_sdram_read_burst( unsigned char *dest, sh4addr_t addr )
    80 {
    81     memcpy( dest, dc_main_ram+(addr&0x00FFFFFF), 32 );
    82 }
    83 static void FASTCALL ext_sdram_write_burst( sh4addr_t addr, unsigned char *src )
    84 {
    85     memcpy( dc_main_ram+(addr&0x00FFFFFF), src, 32 );
    86 }
    88 struct mem_region_fn mem_region_sdram = { ext_sdram_read_long, ext_sdram_write_long, 
    89         ext_sdram_read_word, ext_sdram_write_word, 
    90         ext_sdram_read_byte, ext_sdram_write_byte, 
    91         ext_sdram_read_burst, ext_sdram_write_burst }; 
    94 /***************************** P4 Regions ************************************/
    96 /* Store-queue (long-write only?) */
    97 static void FASTCALL p4_storequeue_write_long( sh4addr_t addr, uint32_t val )
    98 {
    99     sh4r.store_queue[(addr>>2)&0xF] = val;
   100 }
   101 static int32_t FASTCALL p4_storequeue_read_long( sh4addr_t addr )
   102 {
   103     return sh4r.store_queue[(addr>>2)&0xF];
   104 }
   106 struct mem_region_fn p4_region_storequeue = { 
   107         p4_storequeue_read_long, p4_storequeue_write_long,
   108         p4_storequeue_read_long, p4_storequeue_write_long,
   109         p4_storequeue_read_long, p4_storequeue_write_long,
   110         unmapped_read_burst, unmapped_write_burst }; // No burst access.
   112 /* TLB access */
   113 struct mem_region_fn p4_region_itlb_addr = {
   114         mmu_itlb_addr_read, mmu_itlb_addr_write,
   115         mmu_itlb_addr_read, mmu_itlb_addr_write,
   116         mmu_itlb_addr_read, mmu_itlb_addr_write,
   117         unmapped_read_burst, unmapped_write_burst };
   118 struct mem_region_fn p4_region_itlb_data = {
   119         mmu_itlb_data_read, mmu_itlb_data_write,
   120         mmu_itlb_data_read, mmu_itlb_data_write,
   121         mmu_itlb_data_read, mmu_itlb_data_write,
   122         unmapped_read_burst, unmapped_write_burst };
   123 struct mem_region_fn p4_region_utlb_addr = {
   124         mmu_utlb_addr_read, mmu_utlb_addr_write,
   125         mmu_utlb_addr_read, mmu_utlb_addr_write,
   126         mmu_utlb_addr_read, mmu_utlb_addr_write,
   127         unmapped_read_burst, unmapped_write_burst };
   128 struct mem_region_fn p4_region_utlb_data = {
   129         mmu_utlb_data_read, mmu_utlb_data_write,
   130         mmu_utlb_data_read, mmu_utlb_data_write,
   131         mmu_utlb_data_read, mmu_utlb_data_write,
   132         unmapped_read_burst, unmapped_write_burst };
   134 /********************** Initialization *************************/
   136 mem_region_fn_t *sh4_address_space;
   138 static void sh4_register_mem_region( uint32_t start, uint32_t end, mem_region_fn_t fn )
   139 {
   140     int count = (end - start) >> 12;
   141     mem_region_fn_t *ptr = &sh4_address_space[start>>12];
   142     while( count-- > 0 ) {
   143         *ptr++ = fn;
   144     }
   145 }
   147 static gboolean sh4_ext_page_remapped( sh4addr_t page, mem_region_fn_t fn, void *user_data )
   148 {
   149     int i;
   150     for( i=0; i<= 0xC0000000; i+= 0x20000000 ) {
   151         sh4_address_space[(page|i)>>12] = fn;
   152     }
   153 }
   156 void sh4_mem_init()
   157 {
   158     int i;
   159     mem_region_fn_t *ptr;
   160     sh4_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 );
   161     for( i=0, ptr = sh4_address_space; i<7; i++, ptr += LXDREAM_PAGE_TABLE_ENTRIES ) {
   162         memcpy( ptr, ext_address_space, sizeof(mem_region_fn_t) * LXDREAM_PAGE_TABLE_ENTRIES );
   163     }
   165     /* Setup main P4 regions */
   166     sh4_register_mem_region( 0xE0000000, 0xE4000000, &p4_region_storequeue );
   167     sh4_register_mem_region( 0xE4000000, 0xF0000000, &mem_region_unmapped );
   168     sh4_register_mem_region( 0xF0000000, 0xF1000000, &p4_region_icache_addr );
   169     sh4_register_mem_region( 0xF1000000, 0xF2000000, &p4_region_icache_data );
   170     sh4_register_mem_region( 0xF2000000, 0xF3000000, &p4_region_itlb_addr );
   171     sh4_register_mem_region( 0xF3000000, 0xF4000000, &p4_region_itlb_data );
   172     sh4_register_mem_region( 0xF4000000, 0xF5000000, &p4_region_ocache_addr );
   173     sh4_register_mem_region( 0xF5000000, 0xF6000000, &p4_region_ocache_data );
   174     sh4_register_mem_region( 0xF6000000, 0xF7000000, &p4_region_utlb_addr );
   175     sh4_register_mem_region( 0xF7000000, 0xF8000000, &p4_region_utlb_data );
   176     sh4_register_mem_region( 0xF8000000, 0x00000000, &mem_region_unmapped );
   178     /* Setup P4 control region */
   179     sh4_register_mem_region( 0xFF000000, 0xFF001000, &mmio_region_MMU.fn );
   180     sh4_register_mem_region( 0xFF100000, 0xFF101000, &mmio_region_PMM.fn );
   181     sh4_register_mem_region( 0xFF200000, 0xFF201000, &mmio_region_UBC.fn );
   182     sh4_register_mem_region( 0xFF800000, 0xFF801000, &mmio_region_BSC.fn );
   183     sh4_register_mem_region( 0xFF900000, 0xFFA00000, &mem_region_unmapped ); // SDMR2 + SDMR3
   184     sh4_register_mem_region( 0xFFA00000, 0xFFA01000, &mmio_region_DMAC.fn );
   185     sh4_register_mem_region( 0xFFC00000, 0xFFC01000, &mmio_region_CPG.fn );
   186     sh4_register_mem_region( 0xFFC80000, 0xFFC81000, &mmio_region_RTC.fn );
   187     sh4_register_mem_region( 0xFFD00000, 0xFFD01000, &mmio_region_INTC.fn );
   188     sh4_register_mem_region( 0xFFD80000, 0xFFD81000, &mmio_region_TMU.fn );
   189     sh4_register_mem_region( 0xFFE00000, 0xFFE01000, &mmio_region_SCI.fn );
   190     sh4_register_mem_region( 0xFFE80000, 0xFFE81000, &mmio_region_SCIF.fn );
   191     sh4_register_mem_region( 0xFFF00000, 0xFFF01000, &mem_region_unmapped ); // H-UDI
   193     register_mem_page_remapped_hook( sh4_ext_page_remapped, NULL );
   194 }
   196 /************** Access methods ***************/
   197 #ifdef HAVE_FRAME_ADDRESS
   198 #define RETURN_VIA(exc) do{ *(((void **)__builtin_frame_address(0))+1) = exc; return; } while(0)
   199 #else
   200 #define RETURN_VIA(exc) return NULL
   201 #endif
   204 int32_t FASTCALL sh4_read_long( sh4addr_t addr )
   205 {
   206     return sh4_address_space[addr>>12]->read_long(addr);
   207 }
   209 int32_t FASTCALL sh4_read_word( sh4addr_t addr )
   210 {
   211     return sh4_address_space[addr>>12]->read_word(addr);
   212 }
   214 int32_t FASTCALL sh4_read_byte( sh4addr_t addr )
   215 {
   216     return sh4_address_space[addr>>12]->read_byte(addr);
   217 }
   219 void FASTCALL sh4_write_long( sh4addr_t addr, uint32_t val )
   220 {
   221     sh4_address_space[addr>>12]->write_long(addr, val);
   222 }
   224 void FASTCALL sh4_write_word( sh4addr_t addr, uint32_t val )
   225 {
   226     sh4_address_space[addr>>12]->write_word(addr,val);
   227 }
   229 void FASTCALL sh4_write_byte( sh4addr_t addr, uint32_t val )
   230 {
   231     sh4_address_space[addr>>12]->write_byte(addr, val);
   232 }
   234 /* FIXME: Handle all the many special cases when the range doesn't fall cleanly
   235  * into the same memory block
   236  */
   237 void mem_copy_from_sh4( sh4ptr_t dest, sh4addr_t srcaddr, size_t count ) {
   238     if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
   239         pvr2_vram64_read( dest, srcaddr, count );
   240     } else {
   241         sh4ptr_t src = mem_get_region(srcaddr);
   242         if( src == NULL ) {
   243             WARN( "Attempted block read from unknown address %08X", srcaddr );
   244         } else {
   245             memcpy( dest, src, count );
   246         }
   247     }
   248 }
   250 void mem_copy_to_sh4( sh4addr_t destaddr, sh4ptr_t src, size_t count ) {
   251     if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
   252         pvr2_dma_write( destaddr, src, count );
   253         return;
   254     } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
   255         pvr2_render_buffer_invalidate( destaddr, TRUE );
   256     } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
   257         pvr2_vram64_write( destaddr, src, count );
   258         return;
   259     }
   260     sh4ptr_t dest = mem_get_region(destaddr);
   261     if( dest == NULL )
   262         WARN( "Attempted block write to unknown address %08X", destaddr );
   263     else {
   264         xlat_invalidate_block( destaddr, count );
   265         memcpy( dest, src, count );
   266     }
   267 }
.