Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 931:430048ea8b71
prev930:07e5b11419db
next933:880c37bb1909
author nkeynes
date Tue Dec 23 05:48:05 2008 +0000 (12 years ago)
branchlxdream-mem
permissions -rw-r--r--
last change More refactoring and general cleanup. Most things should be working again now.
Split off cache and start real implementation, breaking save states in the process
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@929
    41
extern struct mem_region_fn mem_region_storequeue;
nkeynes@929
    42
extern struct mem_region_fn mem_region_icache_addr;
nkeynes@929
    43
extern struct mem_region_fn mem_region_icache_data;
nkeynes@929
    44
extern struct mem_region_fn mem_region_ocache_addr;
nkeynes@929
    45
extern struct mem_region_fn mem_region_ocache_data;
nkeynes@929
    46
extern struct mem_region_fn mem_region_itlb_addr;
nkeynes@929
    47
extern struct mem_region_fn mem_region_itlb_data;
nkeynes@929
    48
extern struct mem_region_fn mem_region_utlb_addr;
nkeynes@929
    49
extern struct mem_region_fn mem_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@929
    54
    return *((int32_t *)(sh4_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@929
    58
    return SIGNEXT16(*((int16_t *)(sh4_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@929
    62
    return SIGNEXT8(*((int16_t *)(sh4_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@929
    66
    *(uint32_t *)(sh4_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@929
    71
    *(uint16_t *)(sh4_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@929
    76
    *(uint8_t *)(sh4_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@929
    81
    memcpy( dest, sh4_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@929
    85
    memcpy( sh4_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@929
    94
/********************* The Boot ROM address space **********************/
nkeynes@929
    95
extern sh4ptr_t dc_boot_rom;
nkeynes@929
    96
extern sh4ptr_t dc_flash_ram;
nkeynes@929
    97
extern sh4ptr_t dc_audio_ram;
nkeynes@929
    98
static int32_t FASTCALL ext_bootrom_read_long( sh4addr_t addr )
nkeynes@929
    99
{
nkeynes@929
   100
    return *((int32_t *)(dc_boot_rom + (addr&0x001FFFFF)));
nkeynes@929
   101
}
nkeynes@929
   102
static int32_t FASTCALL ext_bootrom_read_word( sh4addr_t addr )
nkeynes@929
   103
{
nkeynes@929
   104
    return SIGNEXT16(*((int16_t *)(dc_boot_rom + (addr&0x001FFFFF))));
nkeynes@929
   105
}
nkeynes@929
   106
static int32_t FASTCALL ext_bootrom_read_byte( sh4addr_t addr )
nkeynes@929
   107
{
nkeynes@929
   108
    return SIGNEXT8(*((int16_t *)(dc_boot_rom + (addr&0x001FFFFF))));
nkeynes@929
   109
}
nkeynes@929
   110
static void FASTCALL ext_bootrom_read_burst( unsigned char *dest, sh4addr_t addr )
nkeynes@929
   111
{
nkeynes@929
   112
    memcpy( dest, sh4_main_ram+(addr&0x001FFFFF), 32 );
nkeynes@929
   113
}
nkeynes@929
   114
nkeynes@929
   115
struct mem_region_fn mem_region_bootrom = { 
nkeynes@929
   116
        ext_bootrom_read_long, unmapped_write_long, 
nkeynes@929
   117
        ext_bootrom_read_word, unmapped_write_long, 
nkeynes@929
   118
        ext_bootrom_read_byte, unmapped_write_long, 
nkeynes@929
   119
        ext_bootrom_read_burst, unmapped_write_burst }; 
nkeynes@929
   120
nkeynes@929
   121
/********************* The Flash RAM address space **********************/
nkeynes@929
   122
static int32_t FASTCALL ext_flashram_read_long( sh4addr_t addr )
nkeynes@929
   123
{
nkeynes@929
   124
    return *((int32_t *)(dc_flash_ram + (addr&0x0001FFFF)));
nkeynes@929
   125
}
nkeynes@929
   126
static int32_t FASTCALL ext_flashram_read_word( sh4addr_t addr )
nkeynes@929
   127
{
nkeynes@929
   128
    return SIGNEXT16(*((int16_t *)(dc_flash_ram + (addr&0x0001FFFF))));
nkeynes@929
   129
}
nkeynes@929
   130
static int32_t FASTCALL ext_flashram_read_byte( sh4addr_t addr )
nkeynes@929
   131
{
nkeynes@929
   132
    return SIGNEXT8(*((int16_t *)(dc_flash_ram + (addr&0x0001FFFF))));
nkeynes@929
   133
}
nkeynes@929
   134
static void FASTCALL ext_flashram_write_long( sh4addr_t addr, uint32_t val )
nkeynes@929
   135
{
nkeynes@929
   136
    *(uint32_t *)(dc_flash_ram + (addr&0x0001FFFF)) = val;
nkeynes@929
   137
    asic_g2_write_word();
nkeynes@929
   138
}
nkeynes@929
   139
static void FASTCALL ext_flashram_write_word( sh4addr_t addr, uint32_t val )
nkeynes@929
   140
{
nkeynes@929
   141
    *(uint16_t *)(dc_flash_ram + (addr&0x0001FFFF)) = (uint16_t)val;
nkeynes@929
   142
    asic_g2_write_word();
nkeynes@929
   143
}
nkeynes@929
   144
static void FASTCALL ext_flashram_write_byte( sh4addr_t addr, uint32_t val )
nkeynes@929
   145
{
nkeynes@929
   146
    *(uint8_t *)(dc_flash_ram + (addr&0x0001FFFF)) = (uint8_t)val;
nkeynes@929
   147
    asic_g2_write_word();
nkeynes@929
   148
}
nkeynes@929
   149
static void FASTCALL ext_flashram_read_burst( unsigned char *dest, sh4addr_t addr )
nkeynes@929
   150
{
nkeynes@929
   151
    memcpy( dest, dc_flash_ram+(addr&0x0001FFFF), 32 );
nkeynes@929
   152
}
nkeynes@929
   153
static void FASTCALL ext_flashram_write_burst( sh4addr_t addr, unsigned char *src )
nkeynes@929
   154
{
nkeynes@929
   155
    memcpy( dc_flash_ram+(addr&0x0001FFFF), src, 32 );
nkeynes@929
   156
}
nkeynes@929
   157
nkeynes@929
   158
struct mem_region_fn mem_region_flashram = { ext_flashram_read_long, ext_flashram_write_long, 
nkeynes@929
   159
        ext_flashram_read_word, ext_flashram_write_word, 
nkeynes@929
   160
        ext_flashram_read_byte, ext_flashram_write_byte, 
nkeynes@929
   161
        ext_flashram_read_burst, ext_flashram_write_burst }; 
nkeynes@929
   162
nkeynes@931
   163
/***************************** P4 Regions ************************************/
nkeynes@929
   164
nkeynes@931
   165
/* Store-queue (long-write only?) */
nkeynes@931
   166
static void FASTCALL p4_storequeue_write_long( sh4addr_t addr, uint32_t val )
nkeynes@931
   167
{
nkeynes@931
   168
    sh4r.store_queue[(addr>>2)&0xF] = val;
nkeynes@931
   169
}
nkeynes@931
   170
static int32_t FASTCALL p4_storequeue_read_long( sh4addr_t addr )
nkeynes@931
   171
{
nkeynes@931
   172
    return sh4r.store_queue[(addr>>2)&0xF];
nkeynes@931
   173
}
nkeynes@931
   174
nkeynes@931
   175
struct mem_region_fn p4_region_storequeue = { 
nkeynes@931
   176
        p4_storequeue_read_long, p4_storequeue_write_long,
nkeynes@931
   177
        p4_storequeue_read_long, p4_storequeue_write_long,
nkeynes@931
   178
        p4_storequeue_read_long, p4_storequeue_write_long,
nkeynes@931
   179
        unmapped_read_burst, unmapped_write_burst }; // No burst access.
nkeynes@931
   180
nkeynes@931
   181
/* Cache access */
nkeynes@929
   182
struct mem_region_fn p4_region_icache_addr = {
nkeynes@929
   183
        mmu_icache_addr_read, mmu_icache_addr_write,
nkeynes@929
   184
        mmu_icache_addr_read, mmu_icache_addr_write,
nkeynes@929
   185
        mmu_icache_addr_read, mmu_icache_addr_write,
nkeynes@929
   186
        unmapped_read_burst, unmapped_write_burst };
nkeynes@929
   187
struct mem_region_fn p4_region_icache_data = {
nkeynes@929
   188
        mmu_icache_data_read, mmu_icache_data_write,
nkeynes@929
   189
        mmu_icache_data_read, mmu_icache_data_write,
nkeynes@929
   190
        mmu_icache_data_read, mmu_icache_data_write,
nkeynes@929
   191
        unmapped_read_burst, unmapped_write_burst };
nkeynes@929
   192
struct mem_region_fn p4_region_ocache_addr = {
nkeynes@929
   193
        mmu_ocache_addr_read, mmu_ocache_addr_write,
nkeynes@929
   194
        mmu_ocache_addr_read, mmu_ocache_addr_write,
nkeynes@929
   195
        mmu_ocache_addr_read, mmu_ocache_addr_write,
nkeynes@929
   196
        unmapped_read_burst, unmapped_write_burst };
nkeynes@929
   197
struct mem_region_fn p4_region_ocache_data = {
nkeynes@929
   198
        mmu_ocache_data_read, mmu_ocache_data_write,
nkeynes@929
   199
        mmu_ocache_data_read, mmu_ocache_data_write,
nkeynes@929
   200
        mmu_ocache_data_read, mmu_ocache_data_write,
nkeynes@929
   201
        unmapped_read_burst, unmapped_write_burst };
nkeynes@931
   202
nkeynes@931
   203
/* TLB access */
nkeynes@929
   204
struct mem_region_fn p4_region_itlb_addr = {
nkeynes@929
   205
        mmu_itlb_addr_read, mmu_itlb_addr_write,
nkeynes@929
   206
        mmu_itlb_addr_read, mmu_itlb_addr_write,
nkeynes@929
   207
        mmu_itlb_addr_read, mmu_itlb_addr_write,
nkeynes@929
   208
        unmapped_read_burst, unmapped_write_burst };
nkeynes@929
   209
struct mem_region_fn p4_region_itlb_data = {
nkeynes@929
   210
        mmu_itlb_data_read, mmu_itlb_data_write,
nkeynes@929
   211
        mmu_itlb_data_read, mmu_itlb_data_write,
nkeynes@929
   212
        mmu_itlb_data_read, mmu_itlb_data_write,
nkeynes@929
   213
        unmapped_read_burst, unmapped_write_burst };
nkeynes@929
   214
struct mem_region_fn p4_region_utlb_addr = {
nkeynes@929
   215
        mmu_utlb_addr_read, mmu_utlb_addr_write,
nkeynes@929
   216
        mmu_utlb_addr_read, mmu_utlb_addr_write,
nkeynes@929
   217
        mmu_utlb_addr_read, mmu_utlb_addr_write,
nkeynes@929
   218
        unmapped_read_burst, unmapped_write_burst };
nkeynes@929
   219
struct mem_region_fn p4_region_utlb_data = {
nkeynes@929
   220
        mmu_utlb_data_read, mmu_utlb_data_write,
nkeynes@929
   221
        mmu_utlb_data_read, mmu_utlb_data_write,
nkeynes@929
   222
        mmu_utlb_data_read, mmu_utlb_data_write,
nkeynes@929
   223
        unmapped_read_burst, unmapped_write_burst };
nkeynes@929
   224
nkeynes@931
   225
/********************** Initialization *************************/
nkeynes@931
   226
nkeynes@931
   227
mem_region_fn_t *sh4_address_space;
nkeynes@931
   228
nkeynes@931
   229
static void sh4_register_mem_region( uint32_t start, uint32_t end, mem_region_fn_t fn )
nkeynes@931
   230
{
nkeynes@931
   231
    int count = (end - start) >> 12;
nkeynes@931
   232
    mem_region_fn_t *ptr = &sh4_address_space[start>>12];
nkeynes@931
   233
    while( count-- > 0 ) {
nkeynes@931
   234
        *ptr++ = fn;
nkeynes@931
   235
    }
nkeynes@931
   236
}
nkeynes@931
   237
nkeynes@931
   238
static gboolean sh4_ext_page_remapped( sh4addr_t page, mem_region_fn_t fn, void *user_data )
nkeynes@931
   239
{
nkeynes@931
   240
    int i;
nkeynes@931
   241
    for( i=0; i<= 0xC0000000; i+= 0x20000000 ) {
nkeynes@931
   242
        sh4_address_space[(page|i)>>12] = fn;
nkeynes@931
   243
    }
nkeynes@931
   244
}
nkeynes@931
   245
nkeynes@931
   246
nkeynes@931
   247
void sh4_mem_init()
nkeynes@931
   248
{
nkeynes@931
   249
    int i;
nkeynes@931
   250
    mem_region_fn_t *ptr;
nkeynes@931
   251
    sh4_address_space = mem_alloc_pages( sizeof(mem_region_fn_t) * 256 );
nkeynes@931
   252
    for( i=0, ptr = sh4_address_space; i<7; i++, ptr += LXDREAM_PAGE_TABLE_ENTRIES ) {
nkeynes@931
   253
        memcpy( ptr, ext_address_space, sizeof(mem_region_fn_t) * LXDREAM_PAGE_TABLE_ENTRIES );
nkeynes@931
   254
    }
nkeynes@931
   255
    
nkeynes@931
   256
    /* Setup main P4 regions */
nkeynes@931
   257
    sh4_register_mem_region( 0xE0000000, 0xE4000000, &p4_region_storequeue );
nkeynes@931
   258
    sh4_register_mem_region( 0xE4000000, 0xF0000000, &mem_region_unmapped );
nkeynes@931
   259
    sh4_register_mem_region( 0xF0000000, 0xF1000000, &p4_region_icache_addr );
nkeynes@931
   260
    sh4_register_mem_region( 0xF1000000, 0xF2000000, &p4_region_icache_data );
nkeynes@931
   261
    sh4_register_mem_region( 0xF2000000, 0xF3000000, &p4_region_itlb_addr );
nkeynes@931
   262
    sh4_register_mem_region( 0xF3000000, 0xF4000000, &p4_region_itlb_data );
nkeynes@931
   263
    sh4_register_mem_region( 0xF4000000, 0xF5000000, &p4_region_ocache_addr );
nkeynes@931
   264
    sh4_register_mem_region( 0xF5000000, 0xF6000000, &p4_region_ocache_data );
nkeynes@931
   265
    sh4_register_mem_region( 0xF6000000, 0xF7000000, &p4_region_utlb_addr );
nkeynes@931
   266
    sh4_register_mem_region( 0xF7000000, 0xF8000000, &p4_region_utlb_data );
nkeynes@931
   267
    sh4_register_mem_region( 0xF8000000, 0x00000000, &mem_region_unmapped );
nkeynes@931
   268
    
nkeynes@931
   269
    /* Setup P4 control region */
nkeynes@931
   270
    sh4_register_mem_region( 0xFF000000, 0xFF001000, &mmio_region_MMU.fn );
nkeynes@931
   271
    sh4_register_mem_region( 0xFF100000, 0xFF101000, &mmio_region_PMM.fn );
nkeynes@931
   272
    sh4_register_mem_region( 0xFF200000, 0xFF201000, &mmio_region_UBC.fn );
nkeynes@931
   273
    sh4_register_mem_region( 0xFF800000, 0xFF801000, &mmio_region_BSC.fn );
nkeynes@931
   274
    sh4_register_mem_region( 0xFF900000, 0xFFA00000, &mem_region_unmapped ); // SDMR2 + SDMR3
nkeynes@931
   275
    sh4_register_mem_region( 0xFFA00000, 0xFFA01000, &mmio_region_DMAC.fn );
nkeynes@931
   276
    sh4_register_mem_region( 0xFFC00000, 0xFFC01000, &mmio_region_CPG.fn );
nkeynes@931
   277
    sh4_register_mem_region( 0xFFC80000, 0xFFC81000, &mmio_region_RTC.fn );
nkeynes@931
   278
    sh4_register_mem_region( 0xFFD00000, 0xFFD01000, &mmio_region_INTC.fn );
nkeynes@931
   279
    sh4_register_mem_region( 0xFFD80000, 0xFFD81000, &mmio_region_TMU.fn );
nkeynes@931
   280
    sh4_register_mem_region( 0xFFE00000, 0xFFE01000, &mmio_region_SCI.fn );
nkeynes@931
   281
    sh4_register_mem_region( 0xFFE80000, 0xFFE81000, &mmio_region_SCIF.fn );
nkeynes@931
   282
    sh4_register_mem_region( 0xFFF00000, 0xFFF01000, &mem_region_unmapped ); // H-UDI
nkeynes@931
   283
    
nkeynes@931
   284
    register_mem_page_remapped_hook( sh4_ext_page_remapped, NULL );
nkeynes@931
   285
}
nkeynes@931
   286
                           
nkeynes@931
   287
/************** Access methods ***************/
nkeynes@929
   288
#ifdef HAVE_FRAME_ADDRESS
nkeynes@929
   289
#define RETURN_VIA(exc) do{ *(((void **)__builtin_frame_address(0))+1) = exc; return; } while(0)
nkeynes@10
   290
#else
nkeynes@929
   291
#define RETURN_VIA(exc) return NULL
nkeynes@10
   292
#endif
nkeynes@10
   293
nkeynes@931
   294
nkeynes@931
   295
int32_t FASTCALL sh4_read_long( sh4addr_t addr )
nkeynes@10
   296
{
nkeynes@931
   297
    return sh4_address_space[addr>>12]->read_long(addr);
nkeynes@10
   298
}
nkeynes@10
   299
nkeynes@931
   300
int32_t FASTCALL sh4_read_word( sh4addr_t addr )
nkeynes@10
   301
{
nkeynes@931
   302
    return sh4_address_space[addr>>12]->read_word(addr);
nkeynes@10
   303
}
nkeynes@10
   304
nkeynes@931
   305
int32_t FASTCALL sh4_read_byte( sh4addr_t addr )
nkeynes@10
   306
{
nkeynes@931
   307
    return sh4_address_space[addr>>12]->read_byte(addr);
nkeynes@931
   308
}
nkeynes@931
   309
nkeynes@931
   310
void FASTCALL sh4_write_long( sh4addr_t addr, uint32_t val )
nkeynes@931
   311
{
nkeynes@931
   312
    sh4_address_space[addr>>12]->write_long(addr, val);
nkeynes@931
   313
}
nkeynes@931
   314
nkeynes@931
   315
void FASTCALL sh4_write_word( sh4addr_t addr, uint32_t val )
nkeynes@931
   316
{
nkeynes@931
   317
    sh4_address_space[addr>>12]->write_word(addr,val);
nkeynes@931
   318
}
nkeynes@931
   319
nkeynes@931
   320
void FASTCALL sh4_write_byte( sh4addr_t addr, uint32_t val )
nkeynes@931
   321
{
nkeynes@931
   322
    sh4_address_space[addr>>12]->write_byte(addr, val);
nkeynes@10
   323
}
nkeynes@10
   324
nkeynes@10
   325
/* FIXME: Handle all the many special cases when the range doesn't fall cleanly
nkeynes@400
   326
 * into the same memory block
nkeynes@10
   327
 */
nkeynes@912
   328
void mem_copy_from_sh4( sh4ptr_t dest, sh4addr_t srcaddr, size_t count ) {
nkeynes@103
   329
    if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
nkeynes@736
   330
        pvr2_vram64_read( dest, srcaddr, count );
nkeynes@103
   331
    } else {
nkeynes@736
   332
        sh4ptr_t src = mem_get_region(srcaddr);
nkeynes@736
   333
        if( src == NULL ) {
nkeynes@736
   334
            WARN( "Attempted block read from unknown address %08X", srcaddr );
nkeynes@736
   335
        } else {
nkeynes@736
   336
            memcpy( dest, src, count );
nkeynes@736
   337
        }
nkeynes@103
   338
    }
nkeynes@10
   339
}
nkeynes@10
   340
nkeynes@912
   341
void mem_copy_to_sh4( sh4addr_t destaddr, sh4ptr_t src, size_t count ) {
nkeynes@325
   342
    if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
nkeynes@736
   343
        pvr2_dma_write( destaddr, src, count );
nkeynes@736
   344
        return;
nkeynes@325
   345
    } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
nkeynes@736
   346
        pvr2_render_buffer_invalidate( destaddr, TRUE );
nkeynes@325
   347
    } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
nkeynes@736
   348
        pvr2_vram64_write( destaddr, src, count );
nkeynes@736
   349
        return;
nkeynes@325
   350
    }
nkeynes@502
   351
    sh4ptr_t dest = mem_get_region(destaddr);
nkeynes@325
   352
    if( dest == NULL )
nkeynes@736
   353
        WARN( "Attempted block write to unknown address %08X", destaddr );
nkeynes@325
   354
    else {
nkeynes@736
   355
        xlat_invalidate_block( destaddr, count );
nkeynes@736
   356
        memcpy( dest, src, count );
nkeynes@90
   357
    }
nkeynes@10
   358
}
.