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