Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 234:8759d0067e9d
prev217:d0b3da720456
next282:01e53698ff38
author nkeynes
date Wed Jan 03 09:00:17 2007 +0000 (17 years ago)
permissions -rw-r--r--
last change Adjust timers when they're read rather than waiting until the next time
slice. Also temporarily cut the CPU time by 4.
Initialize the FRQCR register to 0x0E0A for convenience
file annotate diff log raw
nkeynes@10
     1
/**
nkeynes@234
     2
 * $Id: sh4mem.c,v 1.16 2006-12-12 09:18:47 nkeynes Exp $
nkeynes@10
     3
 * sh4mem.c is responsible for the SH4's access to memory (including memory
nkeynes@10
     4
 * mapped I/O), using the page maps created in mem.c
nkeynes@10
     5
 *
nkeynes@10
     6
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@10
     7
 *
nkeynes@10
     8
 * This program is free software; you can redistribute it and/or modify
nkeynes@10
     9
 * it under the terms of the GNU General Public License as published by
nkeynes@10
    10
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@10
    11
 * (at your option) any later version.
nkeynes@10
    12
 *
nkeynes@10
    13
 * This program is distributed in the hope that it will be useful,
nkeynes@10
    14
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@10
    15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@10
    16
 * GNU General Public License for more details.
nkeynes@10
    17
 */
nkeynes@10
    18
nkeynes@35
    19
#define MODULE sh4_module
nkeynes@35
    20
nkeynes@10
    21
#include <string.h>
nkeynes@10
    22
#include <zlib.h>
nkeynes@10
    23
#include "dream.h"
nkeynes@10
    24
#include "mem.h"
nkeynes@10
    25
#include "mmio.h"
nkeynes@70
    26
#include "sh4core.h"
nkeynes@10
    27
#include "sh4mmio.h"
nkeynes@10
    28
#include "dreamcast.h"
nkeynes@100
    29
#include "pvr2/pvr2.h"
nkeynes@10
    30
nkeynes@10
    31
#define OC_BASE 0x1C000000
nkeynes@10
    32
#define OC_TOP  0x20000000
nkeynes@10
    33
nkeynes@90
    34
#define TRANSLATE_VIDEO_64BIT_ADDRESS(a)  ( (((a)&0x00FFFFF8)>>1)|(((a)&0x00000004)<<20)|((a)&0x03)|0x05000000 )
nkeynes@10
    35
nkeynes@10
    36
#ifdef ENABLE_WATCH
nkeynes@10
    37
#define CHECK_READ_WATCH( addr, size ) \
nkeynes@10
    38
    if( mem_is_watched(addr,size,WATCH_READ) != NULL ) { \
nkeynes@10
    39
        WARN( "Watch triggered at %08X by %d byte read", addr, size ); \
nkeynes@10
    40
        dreamcast_stop(); \
nkeynes@10
    41
    }
nkeynes@10
    42
#define CHECK_WRITE_WATCH( addr, size, val )                  \
nkeynes@10
    43
    if( mem_is_watched(addr,size,WATCH_WRITE) != NULL ) { \
nkeynes@10
    44
        WARN( "Watch triggered at %08X by %d byte write <= %0*X", addr, size, size*2, val ); \
nkeynes@10
    45
        dreamcast_stop(); \
nkeynes@10
    46
    }
nkeynes@10
    47
#else
nkeynes@10
    48
#define CHECK_READ_WATCH( addr, size )
nkeynes@234
    49
#define CHECK_WRITE_WATCH( addr, size, val )
nkeynes@10
    50
#endif
nkeynes@10
    51
nkeynes@172
    52
#define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag && !MMIO_NOTRACE_BYNUM((uint32_t)p,r)) \
nkeynes@172
    53
    TRACE( str " [%s.%s: %s]", __VA_ARGS__,			       \
nkeynes@10
    54
    MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
nkeynes@10
    55
    MMIO_REGDESC_BYNUM((uint32_t)p, r) )
nkeynes@172
    56
#define TRACE_P4IO( str, io, r, ... ) if(io->trace_flag && !MMIO_NOTRACE_IOBYNUM(io,r)) \
nkeynes@156
    57
TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
nkeynes@156
    58
    io->id, MMIO_REGID_IOBYNUM(io, r), \
nkeynes@156
    59
    MMIO_REGDESC_IOBYNUM(io, r) )
nkeynes@10
    60
nkeynes@10
    61
extern struct mem_region mem_rgn[];
nkeynes@10
    62
extern struct mmio_region *P4_io[];
nkeynes@10
    63
nkeynes@10
    64
int32_t sh4_read_p4( uint32_t addr )
nkeynes@10
    65
{
nkeynes@10
    66
    struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
nkeynes@10
    67
    if( !io ) {
nkeynes@10
    68
        ERROR( "Attempted read from unknown P4 region: %08X", addr );
nkeynes@10
    69
        return 0;
nkeynes@10
    70
    } else {
nkeynes@156
    71
	int32_t val = io->io_read( addr&0xFFF );
nkeynes@156
    72
	TRACE_P4IO( "Long read %08X <= %08X", io, (addr&0xFFF), val, addr );
nkeynes@156
    73
        return val;
nkeynes@10
    74
    }    
nkeynes@10
    75
}
nkeynes@10
    76
nkeynes@10
    77
void sh4_write_p4( uint32_t addr, int32_t val )
nkeynes@10
    78
{
nkeynes@10
    79
    struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
nkeynes@10
    80
    if( !io ) {
nkeynes@10
    81
        if( (addr & 0xFC000000) == 0xE0000000 ) {
nkeynes@10
    82
            /* Store queue */
nkeynes@10
    83
            SH4_WRITE_STORE_QUEUE( addr, val );
nkeynes@38
    84
        } else if( (addr & 0xFF000000) != 0xF4000000 ) {
nkeynes@38
    85
	    /* OC address cache isn't implemented, but don't complain about it.
nkeynes@38
    86
	     * Complain about anything else though */
nkeynes@10
    87
            ERROR( "Attempted write to unknown P4 region: %08X", addr );
nkeynes@10
    88
        }
nkeynes@10
    89
    } else {
nkeynes@156
    90
	TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
nkeynes@10
    91
        io->io_write( addr&0xFFF, val );
nkeynes@10
    92
    }
nkeynes@10
    93
}
nkeynes@10
    94
nkeynes@10
    95
int32_t sh4_read_phys_word( uint32_t addr )
nkeynes@10
    96
{
nkeynes@10
    97
    char *page;
nkeynes@83
    98
    if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
nkeynes@10
    99
        return SIGNEXT16(sh4_read_p4( addr ));
nkeynes@10
   100
    
nkeynes@10
   101
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   102
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@10
   103
    }
nkeynes@10
   104
nkeynes@10
   105
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
   106
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   107
        if( page == NULL ) {
nkeynes@10
   108
            ERROR( "Attempted word read to missing page: %08X",
nkeynes@10
   109
                   addr );
nkeynes@10
   110
            return 0;
nkeynes@10
   111
        }
nkeynes@10
   112
        return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
nkeynes@10
   113
    } else {
nkeynes@10
   114
        return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
nkeynes@10
   115
    }
nkeynes@10
   116
}
nkeynes@10
   117
nkeynes@10
   118
int32_t sh4_read_long( uint32_t addr )
nkeynes@10
   119
{
nkeynes@10
   120
    char *page;
nkeynes@10
   121
    
nkeynes@10
   122
    CHECK_READ_WATCH(addr,4);
nkeynes@10
   123
nkeynes@83
   124
    if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
nkeynes@10
   125
        return sh4_read_p4( addr );
nkeynes@10
   126
    
nkeynes@10
   127
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   128
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@217
   129
	pvr2_render_invalidate(addr);
nkeynes@217
   130
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@217
   131
	pvr2_render_invalidate(addr);
nkeynes@10
   132
    }
nkeynes@10
   133
nkeynes@10
   134
    if( IS_MMU_ENABLED() ) {
nkeynes@10
   135
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@10
   136
        sh4_stop();
nkeynes@10
   137
        return 0;
nkeynes@10
   138
    }
nkeynes@10
   139
nkeynes@10
   140
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
   141
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   142
        int32_t val;
nkeynes@10
   143
        if( page == NULL ) {
nkeynes@10
   144
            ERROR( "Attempted long read to missing page: %08X", addr );
nkeynes@10
   145
            return 0;
nkeynes@10
   146
        }
nkeynes@10
   147
        val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
nkeynes@10
   148
        TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
nkeynes@10
   149
        return val;
nkeynes@10
   150
    } else {
nkeynes@10
   151
        return *(int32_t *)(page+(addr&0xFFF));
nkeynes@10
   152
    }
nkeynes@10
   153
}
nkeynes@10
   154
nkeynes@10
   155
int32_t sh4_read_word( uint32_t addr )
nkeynes@10
   156
{
nkeynes@10
   157
    char *page;
nkeynes@10
   158
nkeynes@10
   159
    CHECK_READ_WATCH(addr,2);
nkeynes@10
   160
nkeynes@83
   161
    if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
nkeynes@10
   162
        return SIGNEXT16(sh4_read_p4( addr ));
nkeynes@10
   163
    
nkeynes@10
   164
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   165
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@217
   166
	pvr2_render_invalidate(addr);
nkeynes@217
   167
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@217
   168
	pvr2_render_invalidate(addr);
nkeynes@10
   169
    }
nkeynes@217
   170
    
nkeynes@10
   171
nkeynes@10
   172
    if( IS_MMU_ENABLED() ) {
nkeynes@10
   173
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@10
   174
        sh4_stop();
nkeynes@10
   175
        return 0;
nkeynes@10
   176
    }
nkeynes@10
   177
nkeynes@10
   178
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
   179
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   180
        int32_t val;
nkeynes@10
   181
        if( page == NULL ) {
nkeynes@10
   182
            ERROR( "Attempted word read to missing page: %08X", addr );
nkeynes@10
   183
            return 0;
nkeynes@10
   184
        }
nkeynes@10
   185
        val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
nkeynes@10
   186
        TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
nkeynes@10
   187
        return val;
nkeynes@10
   188
    } else {
nkeynes@10
   189
        return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
nkeynes@10
   190
    }
nkeynes@10
   191
}
nkeynes@10
   192
nkeynes@10
   193
int32_t sh4_read_byte( uint32_t addr )
nkeynes@10
   194
{
nkeynes@10
   195
    char *page;
nkeynes@10
   196
nkeynes@10
   197
    CHECK_READ_WATCH(addr,1);
nkeynes@10
   198
nkeynes@83
   199
    if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
nkeynes@10
   200
        return SIGNEXT8(sh4_read_p4( addr ));
nkeynes@10
   201
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   202
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@217
   203
    	pvr2_render_invalidate(addr);
nkeynes@217
   204
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@217
   205
	pvr2_render_invalidate(addr);
nkeynes@10
   206
    }
nkeynes@217
   207
nkeynes@10
   208
    
nkeynes@10
   209
    if( IS_MMU_ENABLED() ) {
nkeynes@10
   210
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@10
   211
        sh4_stop();
nkeynes@10
   212
        return 0;
nkeynes@10
   213
    }
nkeynes@10
   214
nkeynes@10
   215
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
   216
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   217
        int32_t val;
nkeynes@10
   218
        if( page == NULL ) {
nkeynes@10
   219
            ERROR( "Attempted byte read to missing page: %08X", addr );
nkeynes@10
   220
            return 0;
nkeynes@10
   221
        }
nkeynes@10
   222
        val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
nkeynes@10
   223
        TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
nkeynes@10
   224
        return val;
nkeynes@10
   225
    } else {
nkeynes@10
   226
        return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
nkeynes@10
   227
    }
nkeynes@10
   228
}
nkeynes@10
   229
nkeynes@10
   230
void sh4_write_long( uint32_t addr, uint32_t val )
nkeynes@10
   231
{
nkeynes@10
   232
    char *page;
nkeynes@10
   233
    
nkeynes@10
   234
    CHECK_WRITE_WATCH(addr,4,val);
nkeynes@10
   235
nkeynes@83
   236
    if( addr >= 0xE0000000 ) {
nkeynes@10
   237
        sh4_write_p4( addr, val );
nkeynes@10
   238
        return;
nkeynes@10
   239
    }
nkeynes@130
   240
    if( (addr&0x1F800000) == 0x04000000 || 
nkeynes@130
   241
	(addr&0x1F800000) == 0x11000000 ) {
nkeynes@150
   242
	texcache_invalidate_page(addr& 0x7FFFFF);
nkeynes@10
   243
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@165
   244
	pvr2_render_invalidate(addr);
nkeynes@165
   245
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@165
   246
	pvr2_render_invalidate(addr);
nkeynes@10
   247
    }
nkeynes@10
   248
nkeynes@10
   249
    if( IS_MMU_ENABLED() ) {
nkeynes@10
   250
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@10
   251
        sh4_stop();
nkeynes@10
   252
        return;
nkeynes@10
   253
    }
nkeynes@10
   254
    if( (addr&0x1FFFFFFF) < 0x200000 ) {
nkeynes@10
   255
        ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
nkeynes@10
   256
        sh4_stop();
nkeynes@10
   257
        return;
nkeynes@10
   258
    }
nkeynes@137
   259
    if( (addr&0x1F800000) == 0x00800000 )
nkeynes@137
   260
	asic_g2_write_word();
nkeynes@137
   261
nkeynes@10
   262
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
   263
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   264
        if( page == NULL ) {
nkeynes@137
   265
	    if( (addr & 0x1F000000) >= 0x04000000 &&
nkeynes@137
   266
		(addr & 0x1F000000) < 0x07000000 )
nkeynes@137
   267
		return;
nkeynes@10
   268
            ERROR( "Long write to missing page: %08X => %08X", val, addr );
nkeynes@10
   269
            return;
nkeynes@10
   270
        }
nkeynes@10
   271
        TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
nkeynes@10
   272
        io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
nkeynes@10
   273
    } else {
nkeynes@10
   274
        *(uint32_t *)(page+(addr&0xFFF)) = val;
nkeynes@10
   275
    }
nkeynes@10
   276
}
nkeynes@10
   277
nkeynes@10
   278
void sh4_write_word( uint32_t addr, uint32_t val )
nkeynes@10
   279
{
nkeynes@10
   280
    char *page;
nkeynes@10
   281
nkeynes@10
   282
    CHECK_WRITE_WATCH(addr,2,val);
nkeynes@10
   283
nkeynes@83
   284
    if( addr >= 0xE0000000 ) {
nkeynes@10
   285
        sh4_write_p4( addr, (int16_t)val );
nkeynes@10
   286
        return;
nkeynes@10
   287
    }
nkeynes@130
   288
    if( (addr&0x1F800000) == 0x04000000 ||
nkeynes@130
   289
	(addr&0x1F800000) == 0x11000000 ) {
nkeynes@150
   290
	texcache_invalidate_page(addr& 0x7FFFFF);
nkeynes@10
   291
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@165
   292
	pvr2_render_invalidate(addr);
nkeynes@165
   293
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@165
   294
	pvr2_render_invalidate(addr);
nkeynes@10
   295
    }
nkeynes@10
   296
    if( IS_MMU_ENABLED() ) {
nkeynes@10
   297
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@10
   298
        sh4_stop();
nkeynes@10
   299
        return;
nkeynes@10
   300
    }
nkeynes@10
   301
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
   302
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   303
        if( page == NULL ) {
nkeynes@10
   304
            ERROR( "Attempted word write to missing page: %08X", addr );
nkeynes@10
   305
            return;
nkeynes@10
   306
        }
nkeynes@10
   307
        TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
nkeynes@10
   308
        io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
nkeynes@10
   309
    } else {
nkeynes@10
   310
        *(uint16_t *)(page+(addr&0xFFF)) = val;
nkeynes@10
   311
    }
nkeynes@10
   312
}
nkeynes@10
   313
nkeynes@10
   314
void sh4_write_byte( uint32_t addr, uint32_t val )
nkeynes@10
   315
{
nkeynes@10
   316
    char *page;
nkeynes@10
   317
    
nkeynes@10
   318
    CHECK_WRITE_WATCH(addr,1,val);
nkeynes@10
   319
nkeynes@83
   320
    if( addr >= 0xE0000000 ) {
nkeynes@10
   321
        sh4_write_p4( addr, (int8_t)val );
nkeynes@10
   322
        return;
nkeynes@10
   323
    }
nkeynes@130
   324
    if( (addr&0x1F800000) == 0x04000000 ||
nkeynes@130
   325
	(addr&0x1F800000) == 0x11000000 ) {
nkeynes@150
   326
	texcache_invalidate_page(addr& 0x7FFFFF);
nkeynes@10
   327
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@165
   328
	pvr2_render_invalidate(addr);
nkeynes@165
   329
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@165
   330
	pvr2_render_invalidate(addr);
nkeynes@10
   331
    }
nkeynes@10
   332
    
nkeynes@10
   333
    if( IS_MMU_ENABLED() ) {
nkeynes@10
   334
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@10
   335
        sh4_stop();
nkeynes@10
   336
        return;
nkeynes@10
   337
    }
nkeynes@10
   338
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
   339
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   340
        if( page == NULL ) {
nkeynes@10
   341
            ERROR( "Attempted byte write to missing page: %08X", addr );
nkeynes@10
   342
            return;
nkeynes@10
   343
        }
nkeynes@10
   344
        TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
nkeynes@10
   345
        io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
nkeynes@10
   346
    } else {
nkeynes@10
   347
        *(uint8_t *)(page+(addr&0xFFF)) = val;
nkeynes@10
   348
    }
nkeynes@10
   349
}
nkeynes@10
   350
nkeynes@10
   351
nkeynes@10
   352
nkeynes@10
   353
/* FIXME: Handle all the many special cases when the range doesn't fall cleanly
nkeynes@10
   354
 * into the same memory black
nkeynes@10
   355
 */
nkeynes@10
   356
void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) {
nkeynes@103
   357
    if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
nkeynes@103
   358
	pvr2_vram64_read( dest, srcaddr, count );
nkeynes@103
   359
    } else {
nkeynes@103
   360
	char *src = mem_get_region(srcaddr);
nkeynes@103
   361
	if( src == NULL ) {
nkeynes@103
   362
	    ERROR( "Attempted block read from unknown address %08X", srcaddr );
nkeynes@103
   363
	} else {
nkeynes@103
   364
	    memcpy( dest, src, count );
nkeynes@103
   365
	}
nkeynes@103
   366
    }
nkeynes@10
   367
}
nkeynes@10
   368
nkeynes@10
   369
void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
nkeynes@130
   370
    if( destaddr >= 0x10000000 && destaddr < 0x11000000 ) {
nkeynes@100
   371
	pvr2_ta_write( src, count );
nkeynes@130
   372
    } else if( destaddr >= 0x04000000 && destaddr < 0x05000000 ||
nkeynes@130
   373
	       destaddr >= 0x11000000 && destaddr < 0x12000000 ) {
nkeynes@103
   374
	pvr2_vram64_write( destaddr, src, count );
nkeynes@90
   375
    } else {
nkeynes@165
   376
	if( (destaddr & 0x1F800000) == 0x05000000 )
nkeynes@165
   377
	    pvr2_render_invalidate( destaddr );
nkeynes@90
   378
	char *dest = mem_get_region(destaddr);
nkeynes@90
   379
	if( dest == NULL )
nkeynes@103
   380
	    ERROR( "Attempted block write to unknown address %08X", destaddr );
nkeynes@103
   381
	else {
nkeynes@90
   382
	    memcpy( dest, src, count );
nkeynes@103
   383
	}
nkeynes@90
   384
    }
nkeynes@10
   385
}
.