Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 527:14c9489f647e
prev504:61afb3921c4a
next550:a27e31340147
author nkeynes
date Thu Dec 06 10:37:55 2007 +0000 (16 years ago)
permissions -rw-r--r--
last change Fix stack alignment on x86-64
file annotate diff log raw
nkeynes@10
     1
/**
nkeynes@504
     2
 * $Id: sh4mem.c,v 1.31 2007-11-08 12:01:57 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@10
    26
#include "dreamcast.h"
nkeynes@422
    27
#include "sh4/sh4core.h"
nkeynes@422
    28
#include "sh4/sh4mmio.h"
nkeynes@422
    29
#include "sh4/xltcache.h"
nkeynes@100
    30
#include "pvr2/pvr2.h"
nkeynes@422
    31
#include "asic.h"
nkeynes@10
    32
nkeynes@10
    33
#define OC_BASE 0x1C000000
nkeynes@10
    34
#define OC_TOP  0x20000000
nkeynes@10
    35
nkeynes@90
    36
#define TRANSLATE_VIDEO_64BIT_ADDRESS(a)  ( (((a)&0x00FFFFF8)>>1)|(((a)&0x00000004)<<20)|((a)&0x03)|0x05000000 )
nkeynes@10
    37
nkeynes@10
    38
#ifdef ENABLE_WATCH
nkeynes@10
    39
#define CHECK_READ_WATCH( addr, size ) \
nkeynes@10
    40
    if( mem_is_watched(addr,size,WATCH_READ) != NULL ) { \
nkeynes@10
    41
        WARN( "Watch triggered at %08X by %d byte read", addr, size ); \
nkeynes@10
    42
        dreamcast_stop(); \
nkeynes@10
    43
    }
nkeynes@10
    44
#define CHECK_WRITE_WATCH( addr, size, val )                  \
nkeynes@10
    45
    if( mem_is_watched(addr,size,WATCH_WRITE) != NULL ) { \
nkeynes@10
    46
        WARN( "Watch triggered at %08X by %d byte write <= %0*X", addr, size, size*2, val ); \
nkeynes@10
    47
        dreamcast_stop(); \
nkeynes@10
    48
    }
nkeynes@10
    49
#else
nkeynes@10
    50
#define CHECK_READ_WATCH( addr, size )
nkeynes@234
    51
#define CHECK_WRITE_WATCH( addr, size, val )
nkeynes@10
    52
#endif
nkeynes@10
    53
nkeynes@406
    54
#ifdef ENABLE_TRACE_IO
nkeynes@172
    55
#define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag && !MMIO_NOTRACE_BYNUM((uint32_t)p,r)) \
nkeynes@172
    56
    TRACE( str " [%s.%s: %s]", __VA_ARGS__,			       \
nkeynes@10
    57
    MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
nkeynes@10
    58
    MMIO_REGDESC_BYNUM((uint32_t)p, r) )
nkeynes@172
    59
#define TRACE_P4IO( str, io, r, ... ) if(io->trace_flag && !MMIO_NOTRACE_IOBYNUM(io,r)) \
nkeynes@156
    60
TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
nkeynes@156
    61
    io->id, MMIO_REGID_IOBYNUM(io, r), \
nkeynes@156
    62
    MMIO_REGDESC_IOBYNUM(io, r) )
nkeynes@406
    63
#else
nkeynes@406
    64
#define TRACE_IO( str, p, r, ... )
nkeynes@406
    65
#define TRACE_P4IO( str, io, r, ... )
nkeynes@406
    66
#endif
nkeynes@10
    67
nkeynes@10
    68
extern struct mem_region mem_rgn[];
nkeynes@10
    69
extern struct mmio_region *P4_io[];
nkeynes@502
    70
sh4ptr_t sh4_main_ram;
nkeynes@10
    71
nkeynes@527
    72
int32_t sh4_read_p4( sh4addr_t addr )
nkeynes@10
    73
{
nkeynes@10
    74
    struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
nkeynes@10
    75
    if( !io ) {
nkeynes@282
    76
        if( (addr & 0xFF000000) != 0xF4000000 ) {
nkeynes@282
    77
	    /* OC address cache isn't implemented, but don't complain about it.
nkeynes@282
    78
	     * Complain about anything else though */
nkeynes@448
    79
            WARN( "Attempted read from unknown P4 region: %08X", addr );
nkeynes@282
    80
        }
nkeynes@10
    81
        return 0;
nkeynes@10
    82
    } else {
nkeynes@156
    83
	int32_t val = io->io_read( addr&0xFFF );
nkeynes@156
    84
	TRACE_P4IO( "Long read %08X <= %08X", io, (addr&0xFFF), val, addr );
nkeynes@156
    85
        return val;
nkeynes@10
    86
    }    
nkeynes@10
    87
}
nkeynes@10
    88
nkeynes@527
    89
void sh4_write_p4( sh4addr_t addr, int32_t val )
nkeynes@10
    90
{
nkeynes@10
    91
    struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
nkeynes@10
    92
    if( !io ) {
nkeynes@10
    93
        if( (addr & 0xFC000000) == 0xE0000000 ) {
nkeynes@10
    94
            /* Store queue */
nkeynes@10
    95
            SH4_WRITE_STORE_QUEUE( addr, val );
nkeynes@38
    96
        } else if( (addr & 0xFF000000) != 0xF4000000 ) {
nkeynes@38
    97
	    /* OC address cache isn't implemented, but don't complain about it.
nkeynes@38
    98
	     * Complain about anything else though */
nkeynes@448
    99
            WARN( "Attempted write to unknown P4 region: %08X", addr );
nkeynes@10
   100
        }
nkeynes@10
   101
    } else {
nkeynes@156
   102
	TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
nkeynes@10
   103
        io->io_write( addr&0xFFF, val );
nkeynes@10
   104
    }
nkeynes@10
   105
}
nkeynes@10
   106
nkeynes@527
   107
int32_t sh4_read_phys_word( sh4addr_t addr )
nkeynes@10
   108
{
nkeynes@502
   109
    sh4ptr_t page;
nkeynes@83
   110
    if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
nkeynes@10
   111
        return SIGNEXT16(sh4_read_p4( addr ));
nkeynes@10
   112
    
nkeynes@10
   113
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   114
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@10
   115
    }
nkeynes@10
   116
nkeynes@10
   117
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   118
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   119
        if( page == NULL ) {
nkeynes@448
   120
            WARN( "Attempted word read to missing page: %08X",
nkeynes@10
   121
                   addr );
nkeynes@10
   122
            return 0;
nkeynes@10
   123
        }
nkeynes@504
   124
        return SIGNEXT16(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
nkeynes@10
   125
    } else {
nkeynes@10
   126
        return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
nkeynes@10
   127
    }
nkeynes@10
   128
}
nkeynes@10
   129
nkeynes@527
   130
/**
nkeynes@527
   131
 * Convenience function to read a quad-word (implemented as two long reads).
nkeynes@527
   132
 */
nkeynes@527
   133
int64_t sh4_read_quad( sh4addr_t addr )
nkeynes@527
   134
{
nkeynes@527
   135
    return ((int64_t)((uint32_t)sh4_read_long(addr))) |
nkeynes@527
   136
	(((int64_t)((uint32_t)sh4_read_long(addr+4))) << 32);
nkeynes@527
   137
}
nkeynes@527
   138
nkeynes@527
   139
int32_t sh4_read_long( sh4addr_t addr )
nkeynes@10
   140
{
nkeynes@502
   141
    sh4ptr_t page;
nkeynes@10
   142
    
nkeynes@10
   143
    CHECK_READ_WATCH(addr,4);
nkeynes@10
   144
nkeynes@418
   145
    if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
nkeynes@10
   146
        return sh4_read_p4( addr );
nkeynes@418
   147
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@418
   148
	return *(int32_t *)(sh4_main_ram + (addr&0x00FFFFFF));
nkeynes@418
   149
    } else if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   150
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@355
   151
	pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@217
   152
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@355
   153
	pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@10
   154
    }
nkeynes@10
   155
nkeynes@10
   156
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   157
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   158
        int32_t val;
nkeynes@10
   159
        if( page == NULL ) {
nkeynes@448
   160
            WARN( "Attempted long read to missing page: %08X", addr );
nkeynes@10
   161
            return 0;
nkeynes@10
   162
        }
nkeynes@504
   163
        val = io_rgn[(uintptr_t)page]->io_read(addr&0xFFF);
nkeynes@10
   164
        TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
nkeynes@10
   165
        return val;
nkeynes@10
   166
    } else {
nkeynes@10
   167
        return *(int32_t *)(page+(addr&0xFFF));
nkeynes@10
   168
    }
nkeynes@10
   169
}
nkeynes@10
   170
nkeynes@527
   171
int32_t sh4_read_word( sh4addr_t addr )
nkeynes@10
   172
{
nkeynes@502
   173
    sh4ptr_t page;
nkeynes@10
   174
nkeynes@10
   175
    CHECK_READ_WATCH(addr,2);
nkeynes@10
   176
nkeynes@418
   177
    if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
nkeynes@10
   178
        return SIGNEXT16(sh4_read_p4( addr ));
nkeynes@418
   179
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@418
   180
	return SIGNEXT16(*(int16_t *)(sh4_main_ram + (addr&0x00FFFFFF)));
nkeynes@418
   181
    } else if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   182
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@355
   183
	pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@217
   184
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@355
   185
	pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@10
   186
    }
nkeynes@217
   187
    
nkeynes@10
   188
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   189
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   190
        int32_t val;
nkeynes@10
   191
        if( page == NULL ) {
nkeynes@448
   192
	    WARN( "Attempted word read to missing page: %08X", addr );
nkeynes@10
   193
            return 0;
nkeynes@10
   194
        }
nkeynes@504
   195
        val = SIGNEXT16(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
nkeynes@10
   196
        TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
nkeynes@10
   197
        return val;
nkeynes@10
   198
    } else {
nkeynes@10
   199
        return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
nkeynes@10
   200
    }
nkeynes@10
   201
}
nkeynes@10
   202
nkeynes@527
   203
int32_t sh4_read_byte( sh4addr_t addr )
nkeynes@10
   204
{
nkeynes@502
   205
    sh4ptr_t page;
nkeynes@10
   206
nkeynes@10
   207
    CHECK_READ_WATCH(addr,1);
nkeynes@10
   208
nkeynes@418
   209
    if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
nkeynes@10
   210
        return SIGNEXT8(sh4_read_p4( addr ));
nkeynes@418
   211
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@418
   212
	return SIGNEXT8(*(int8_t *)(sh4_main_ram + (addr&0x00FFFFFF)));
nkeynes@418
   213
    } else if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   214
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@355
   215
    	pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@217
   216
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@355
   217
	pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@10
   218
    }
nkeynes@217
   219
nkeynes@10
   220
    
nkeynes@10
   221
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   222
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   223
        int32_t val;
nkeynes@10
   224
        if( page == NULL ) {
nkeynes@448
   225
            WARN( "Attempted byte read to missing page: %08X", addr );
nkeynes@10
   226
            return 0;
nkeynes@10
   227
        }
nkeynes@504
   228
        val = SIGNEXT8(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
nkeynes@10
   229
        TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
nkeynes@10
   230
        return val;
nkeynes@10
   231
    } else {
nkeynes@10
   232
        return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
nkeynes@10
   233
    }
nkeynes@10
   234
}
nkeynes@10
   235
nkeynes@527
   236
/**
nkeynes@527
   237
 * Convenience function to write a quad-word (implemented as two long writes).
nkeynes@527
   238
 */
nkeynes@527
   239
void sh4_write_quad( sh4addr_t addr, uint64_t val )
nkeynes@527
   240
{
nkeynes@527
   241
    sh4_write_long( addr, (uint32_t)val );
nkeynes@527
   242
    sh4_write_long( addr+4, (uint32_t)(val>>32) );
nkeynes@527
   243
}
nkeynes@527
   244
nkeynes@527
   245
void sh4_write_long( sh4addr_t addr, uint32_t val )
nkeynes@10
   246
{
nkeynes@502
   247
    sh4ptr_t page;
nkeynes@400
   248
nkeynes@10
   249
    CHECK_WRITE_WATCH(addr,4,val);
nkeynes@10
   250
nkeynes@83
   251
    if( addr >= 0xE0000000 ) {
nkeynes@10
   252
        sh4_write_p4( addr, val );
nkeynes@10
   253
        return;
nkeynes@418
   254
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@418
   255
	*(uint32_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
nkeynes@419
   256
	xlat_invalidate_long(addr);
nkeynes@418
   257
	return;
nkeynes@418
   258
    } else if( (addr&0x1F800000) == 0x04000000 || 
nkeynes@418
   259
	       (addr&0x1F800000) == 0x11000000 ) {
nkeynes@150
   260
	texcache_invalidate_page(addr& 0x7FFFFF);
nkeynes@10
   261
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@355
   262
	pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@165
   263
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@355
   264
	pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@10
   265
    }
nkeynes@10
   266
nkeynes@10
   267
    if( (addr&0x1FFFFFFF) < 0x200000 ) {
nkeynes@448
   268
        WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
nkeynes@10
   269
        sh4_stop();
nkeynes@10
   270
        return;
nkeynes@10
   271
    }
nkeynes@137
   272
    if( (addr&0x1F800000) == 0x00800000 )
nkeynes@137
   273
	asic_g2_write_word();
nkeynes@137
   274
nkeynes@10
   275
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   276
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   277
        if( page == NULL ) {
nkeynes@137
   278
	    if( (addr & 0x1F000000) >= 0x04000000 &&
nkeynes@137
   279
		(addr & 0x1F000000) < 0x07000000 )
nkeynes@137
   280
		return;
nkeynes@448
   281
            WARN( "Long write to missing page: %08X => %08X", val, addr );
nkeynes@10
   282
            return;
nkeynes@10
   283
        }
nkeynes@10
   284
        TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
nkeynes@504
   285
        io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
nkeynes@10
   286
    } else {
nkeynes@10
   287
        *(uint32_t *)(page+(addr&0xFFF)) = val;
nkeynes@10
   288
    }
nkeynes@10
   289
}
nkeynes@10
   290
nkeynes@527
   291
void sh4_write_word( sh4addr_t addr, uint32_t val )
nkeynes@10
   292
{
nkeynes@502
   293
    sh4ptr_t page;
nkeynes@10
   294
nkeynes@10
   295
    CHECK_WRITE_WATCH(addr,2,val);
nkeynes@10
   296
nkeynes@83
   297
    if( addr >= 0xE0000000 ) {
nkeynes@10
   298
        sh4_write_p4( addr, (int16_t)val );
nkeynes@10
   299
        return;
nkeynes@418
   300
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@418
   301
	*(uint16_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
nkeynes@419
   302
	xlat_invalidate_word(addr);
nkeynes@418
   303
	return;
nkeynes@418
   304
    } else if( (addr&0x1F800000) == 0x04000000 ||
nkeynes@130
   305
	(addr&0x1F800000) == 0x11000000 ) {
nkeynes@150
   306
	texcache_invalidate_page(addr& 0x7FFFFF);
nkeynes@10
   307
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@355
   308
	pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@165
   309
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@355
   310
	pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@10
   311
    }
nkeynes@406
   312
nkeynes@400
   313
    if( (addr&0x1FFFFFFF) < 0x200000 ) {
nkeynes@448
   314
        WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
nkeynes@400
   315
        sh4_stop();
nkeynes@400
   316
        return;
nkeynes@400
   317
    }
nkeynes@10
   318
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   319
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   320
        if( page == NULL ) {
nkeynes@448
   321
            WARN( "Attempted word write to missing page: %08X", addr );
nkeynes@10
   322
            return;
nkeynes@10
   323
        }
nkeynes@10
   324
        TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
nkeynes@504
   325
        io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
nkeynes@10
   326
    } else {
nkeynes@10
   327
        *(uint16_t *)(page+(addr&0xFFF)) = val;
nkeynes@10
   328
    }
nkeynes@10
   329
}
nkeynes@10
   330
nkeynes@527
   331
void sh4_write_byte( sh4addr_t addr, uint32_t val )
nkeynes@10
   332
{
nkeynes@502
   333
    sh4ptr_t page;
nkeynes@10
   334
    
nkeynes@10
   335
    CHECK_WRITE_WATCH(addr,1,val);
nkeynes@10
   336
nkeynes@83
   337
    if( addr >= 0xE0000000 ) {
nkeynes@10
   338
        sh4_write_p4( addr, (int8_t)val );
nkeynes@10
   339
        return;
nkeynes@418
   340
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@418
   341
	*(uint8_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
nkeynes@419
   342
	xlat_invalidate_word(addr);
nkeynes@418
   343
	return;
nkeynes@418
   344
    } else if( (addr&0x1F800000) == 0x04000000 ||
nkeynes@418
   345
	       (addr&0x1F800000) == 0x11000000 ) {
nkeynes@150
   346
	texcache_invalidate_page(addr& 0x7FFFFF);
nkeynes@10
   347
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@355
   348
	pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@165
   349
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@355
   350
	pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@10
   351
    }
nkeynes@10
   352
    
nkeynes@400
   353
    if( (addr&0x1FFFFFFF) < 0x200000 ) {
nkeynes@448
   354
        WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
nkeynes@400
   355
        sh4_stop();
nkeynes@400
   356
        return;
nkeynes@400
   357
    }
nkeynes@10
   358
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   359
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   360
        if( page == NULL ) {
nkeynes@448
   361
            WARN( "Attempted byte write to missing page: %08X", addr );
nkeynes@10
   362
            return;
nkeynes@10
   363
        }
nkeynes@10
   364
        TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
nkeynes@504
   365
        io_rgn[(uintptr_t)page]->io_write( (addr&0xFFF), val);
nkeynes@10
   366
    } else {
nkeynes@10
   367
        *(uint8_t *)(page+(addr&0xFFF)) = val;
nkeynes@10
   368
    }
nkeynes@10
   369
}
nkeynes@10
   370
nkeynes@10
   371
nkeynes@10
   372
nkeynes@10
   373
/* FIXME: Handle all the many special cases when the range doesn't fall cleanly
nkeynes@400
   374
 * into the same memory block
nkeynes@10
   375
 */
nkeynes@527
   376
void mem_copy_from_sh4( sh4ptr_t dest, sh4addr_t srcaddr, size_t count ) {
nkeynes@103
   377
    if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
nkeynes@103
   378
	pvr2_vram64_read( dest, srcaddr, count );
nkeynes@103
   379
    } else {
nkeynes@502
   380
	sh4ptr_t src = mem_get_region(srcaddr);
nkeynes@103
   381
	if( src == NULL ) {
nkeynes@448
   382
	    WARN( "Attempted block read from unknown address %08X", srcaddr );
nkeynes@103
   383
	} else {
nkeynes@103
   384
	    memcpy( dest, src, count );
nkeynes@103
   385
	}
nkeynes@103
   386
    }
nkeynes@10
   387
}
nkeynes@10
   388
nkeynes@527
   389
void mem_copy_to_sh4( sh4addr_t destaddr, sh4ptr_t src, size_t count ) {
nkeynes@325
   390
    if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
nkeynes@325
   391
	pvr2_dma_write( destaddr, src, count );
nkeynes@325
   392
	return;
nkeynes@325
   393
    } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
nkeynes@355
   394
	pvr2_render_buffer_invalidate( destaddr, TRUE );
nkeynes@325
   395
    } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
nkeynes@103
   396
	pvr2_vram64_write( destaddr, src, count );
nkeynes@325
   397
	return;
nkeynes@325
   398
    }
nkeynes@502
   399
    sh4ptr_t dest = mem_get_region(destaddr);
nkeynes@325
   400
    if( dest == NULL )
nkeynes@448
   401
	WARN( "Attempted block write to unknown address %08X", destaddr );
nkeynes@325
   402
    else {
nkeynes@400
   403
	xlat_invalidate_block( destaddr, count );
nkeynes@325
   404
	memcpy( dest, src, count );
nkeynes@90
   405
    }
nkeynes@10
   406
}
nkeynes@369
   407
nkeynes@527
   408
void sh4_flush_store_queue( sh4addr_t addr )
nkeynes@369
   409
{
nkeynes@369
   410
    /* Store queue operation */
nkeynes@369
   411
    int queue = (addr&0x20)>>2;
nkeynes@502
   412
    sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
nkeynes@369
   413
    uint32_t hi = (MMIO_READ( MMU, (queue == 0 ? QACR0 : QACR1) ) & 0x1C) << 24;
nkeynes@422
   414
    uint32_t target = (addr&0x03FFFFE0) | hi;
nkeynes@369
   415
    mem_copy_to_sh4( target, src, 32 );
nkeynes@369
   416
}
.