Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 912:c5606ea44232
prev911:2f6ba75b84d1
next927:17b6b9e245d8
author nkeynes
date Fri Oct 31 03:24:49 2008 +0000 (15 years ago)
permissions -rw-r--r--
last change Remove FASTCALL from mem_copy_*, not really helping atm (and sometimes hurting)
file annotate diff log raw
nkeynes@10
     1
/**
nkeynes@586
     2
 * $Id$
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@740
    42
        sh4_core_exit(CORE_EXIT_HALT); \
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@740
    47
        sh4_core_exit(CORE_EXIT_HALT); \
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@736
    57
            MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
nkeynes@736
    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@736
    60
    TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
nkeynes@736
    61
            io->id, MMIO_REGID_IOBYNUM(io, r), \
nkeynes@736
    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@10
    70
nkeynes@905
    71
int32_t FASTCALL sh4_read_p4( sh4addr_t addr )
nkeynes@10
    72
{
nkeynes@10
    73
    struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
nkeynes@10
    74
    if( !io ) {
nkeynes@736
    75
        switch( addr & 0x1F000000 ) {
nkeynes@736
    76
        case 0x00000000: case 0x01000000: case 0x02000000: case 0x03000000: 
nkeynes@736
    77
            /* Store queue - readable? */
nkeynes@736
    78
            return 0;
nkeynes@736
    79
            break;
nkeynes@736
    80
        case 0x10000000: return mmu_icache_addr_read( addr );
nkeynes@736
    81
        case 0x11000000: return mmu_icache_data_read( addr );
nkeynes@736
    82
        case 0x12000000: return mmu_itlb_addr_read( addr );
nkeynes@736
    83
        case 0x13000000: return mmu_itlb_data_read( addr );
nkeynes@736
    84
        case 0x14000000: return mmu_ocache_addr_read( addr );
nkeynes@736
    85
        case 0x15000000: return mmu_ocache_data_read( addr );
nkeynes@736
    86
        case 0x16000000: return mmu_utlb_addr_read( addr );
nkeynes@736
    87
        case 0x17000000: return mmu_utlb_data_read( addr );
nkeynes@736
    88
        default:
nkeynes@550
    89
            WARN( "Attempted read from unknown or invalid P4 region: %08X", addr );
nkeynes@736
    90
            return 0;
nkeynes@282
    91
        }
nkeynes@10
    92
    } else {
nkeynes@736
    93
        int32_t val = io->io_read( addr&0xFFF );
nkeynes@736
    94
        TRACE_P4IO( "Long read %08X <= %08X", io, (addr&0xFFF), val, addr );
nkeynes@156
    95
        return val;
nkeynes@10
    96
    }    
nkeynes@10
    97
}
nkeynes@10
    98
nkeynes@905
    99
void FASTCALL sh4_write_p4( sh4addr_t addr, int32_t val )
nkeynes@10
   100
{
nkeynes@10
   101
    struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
nkeynes@10
   102
    if( !io ) {
nkeynes@736
   103
        switch( addr & 0x1F000000 ) {
nkeynes@736
   104
        case 0x00000000: case 0x01000000: case 0x02000000: case 0x03000000: 
nkeynes@10
   105
            /* Store queue */
nkeynes@10
   106
            SH4_WRITE_STORE_QUEUE( addr, val );
nkeynes@736
   107
            break;
nkeynes@736
   108
        case 0x10000000: mmu_icache_addr_write( addr, val ); break;
nkeynes@736
   109
        case 0x11000000: mmu_icache_data_write( addr, val ); break;
nkeynes@736
   110
        case 0x12000000: mmu_itlb_addr_write( addr, val ); break;
nkeynes@736
   111
        case 0x13000000: mmu_itlb_data_write( addr, val ); break;
nkeynes@736
   112
        case 0x14000000: mmu_ocache_addr_write( addr, val ); break;
nkeynes@736
   113
        case 0x15000000: mmu_ocache_data_write( addr, val ); break;
nkeynes@736
   114
        case 0x16000000: mmu_utlb_addr_write( addr, val ); break;
nkeynes@736
   115
        case 0x17000000: mmu_utlb_data_write( addr, val ); break;
nkeynes@736
   116
        default:
nkeynes@828
   117
            if( (addr & 0xFFFF0000 ) == 0xFF940000 ||
nkeynes@828
   118
                (addr & 0xFFFF0000 ) == 0xFF900000 ) {
nkeynes@828
   119
                // SDRAM configuration, ignore for now
nkeynes@828
   120
            } else {
nkeynes@828
   121
                WARN( "Attempted write to unknown P4 region: %08X", addr );
nkeynes@828
   122
            }
nkeynes@10
   123
        }
nkeynes@10
   124
    } else {
nkeynes@736
   125
        TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
nkeynes@10
   126
        io->io_write( addr&0xFFF, val );
nkeynes@10
   127
    }
nkeynes@10
   128
}
nkeynes@10
   129
nkeynes@527
   130
int32_t sh4_read_phys_word( sh4addr_t addr )
nkeynes@10
   131
{
nkeynes@502
   132
    sh4ptr_t page;
nkeynes@83
   133
    if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
nkeynes@10
   134
        return SIGNEXT16(sh4_read_p4( addr ));
nkeynes@736
   135
nkeynes@10
   136
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   137
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@10
   138
    }
nkeynes@10
   139
nkeynes@10
   140
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   141
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   142
        if( page == NULL ) {
nkeynes@448
   143
            WARN( "Attempted word read to missing page: %08X",
nkeynes@736
   144
                    addr );
nkeynes@10
   145
            return 0;
nkeynes@10
   146
        }
nkeynes@504
   147
        return SIGNEXT16(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
nkeynes@10
   148
    } else {
nkeynes@10
   149
        return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
nkeynes@10
   150
    }
nkeynes@10
   151
}
nkeynes@10
   152
nkeynes@527
   153
/**
nkeynes@527
   154
 * Convenience function to read a quad-word (implemented as two long reads).
nkeynes@527
   155
 */
nkeynes@905
   156
int64_t FASTCALL sh4_read_quad( sh4addr_t addr )
nkeynes@527
   157
{
nkeynes@527
   158
    return ((int64_t)((uint32_t)sh4_read_long(addr))) |
nkeynes@736
   159
    (((int64_t)((uint32_t)sh4_read_long(addr+4))) << 32);
nkeynes@527
   160
}
nkeynes@527
   161
nkeynes@905
   162
int32_t FASTCALL sh4_read_long( sh4addr_t addr )
nkeynes@10
   163
{
nkeynes@502
   164
    sh4ptr_t page;
nkeynes@736
   165
nkeynes@10
   166
    CHECK_READ_WATCH(addr,4);
nkeynes@10
   167
nkeynes@418
   168
    if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
nkeynes@586
   169
        return ZEROEXT32(sh4_read_p4( addr ));
nkeynes@418
   170
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@736
   171
        return ZEROEXT32(*(int32_t *)(sh4_main_ram + (addr&0x00FFFFFF)));
nkeynes@418
   172
    } else if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   173
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@736
   174
        pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@217
   175
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@736
   176
        pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@10
   177
    }
nkeynes@10
   178
nkeynes@10
   179
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   180
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   181
        int32_t val;
nkeynes@10
   182
        if( page == NULL ) {
nkeynes@448
   183
            WARN( "Attempted long read to missing page: %08X", addr );
nkeynes@10
   184
            return 0;
nkeynes@10
   185
        }
nkeynes@504
   186
        val = io_rgn[(uintptr_t)page]->io_read(addr&0xFFF);
nkeynes@10
   187
        TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
nkeynes@586
   188
        return ZEROEXT32(val);
nkeynes@10
   189
    } else {
nkeynes@586
   190
        return ZEROEXT32(*(int32_t *)(page+(addr&0xFFF)));
nkeynes@10
   191
    }
nkeynes@10
   192
}
nkeynes@10
   193
nkeynes@905
   194
int32_t FASTCALL sh4_read_word( sh4addr_t addr )
nkeynes@10
   195
{
nkeynes@502
   196
    sh4ptr_t page;
nkeynes@10
   197
nkeynes@10
   198
    CHECK_READ_WATCH(addr,2);
nkeynes@10
   199
nkeynes@418
   200
    if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
nkeynes@586
   201
        return ZEROEXT32(SIGNEXT16(sh4_read_p4( addr )));
nkeynes@418
   202
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@736
   203
        return ZEROEXT32(SIGNEXT16(*(int16_t *)(sh4_main_ram + (addr&0x00FFFFFF))));
nkeynes@418
   204
    } else if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   205
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@736
   206
        pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@217
   207
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@736
   208
        pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@10
   209
    }
nkeynes@736
   210
nkeynes@10
   211
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   212
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   213
        int32_t val;
nkeynes@10
   214
        if( page == NULL ) {
nkeynes@736
   215
            WARN( "Attempted word read to missing page: %08X", addr );
nkeynes@10
   216
            return 0;
nkeynes@10
   217
        }
nkeynes@504
   218
        val = SIGNEXT16(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
nkeynes@10
   219
        TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
nkeynes@586
   220
        return ZEROEXT32(val);
nkeynes@10
   221
    } else {
nkeynes@586
   222
        return ZEROEXT32(SIGNEXT16(*(int16_t *)(page+(addr&0xFFF))));
nkeynes@10
   223
    }
nkeynes@10
   224
}
nkeynes@10
   225
nkeynes@905
   226
int32_t FASTCALL sh4_read_byte( sh4addr_t addr )
nkeynes@10
   227
{
nkeynes@502
   228
    sh4ptr_t page;
nkeynes@10
   229
nkeynes@10
   230
    CHECK_READ_WATCH(addr,1);
nkeynes@10
   231
nkeynes@418
   232
    if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
nkeynes@586
   233
        return ZEROEXT32(SIGNEXT8(sh4_read_p4( addr )));
nkeynes@418
   234
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@736
   235
        return ZEROEXT32(SIGNEXT8(*(int8_t *)(sh4_main_ram + (addr&0x00FFFFFF))));
nkeynes@418
   236
    } else if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   237
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@736
   238
        pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@217
   239
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@736
   240
        pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@10
   241
    }
nkeynes@217
   242
nkeynes@736
   243
nkeynes@10
   244
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   245
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   246
        int32_t val;
nkeynes@10
   247
        if( page == NULL ) {
nkeynes@448
   248
            WARN( "Attempted byte read to missing page: %08X", addr );
nkeynes@10
   249
            return 0;
nkeynes@10
   250
        }
nkeynes@504
   251
        val = SIGNEXT8(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
nkeynes@10
   252
        TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
nkeynes@586
   253
        return ZEROEXT32(val);
nkeynes@10
   254
    } else {
nkeynes@586
   255
        return ZEROEXT32(SIGNEXT8(*(int8_t *)(page+(addr&0xFFF))));
nkeynes@10
   256
    }
nkeynes@10
   257
}
nkeynes@10
   258
nkeynes@527
   259
/**
nkeynes@527
   260
 * Convenience function to write a quad-word (implemented as two long writes).
nkeynes@527
   261
 */
nkeynes@905
   262
void FASTCALL sh4_write_quad( sh4addr_t addr, uint64_t val )
nkeynes@527
   263
{
nkeynes@527
   264
    sh4_write_long( addr, (uint32_t)val );
nkeynes@527
   265
    sh4_write_long( addr+4, (uint32_t)(val>>32) );
nkeynes@527
   266
}
nkeynes@527
   267
nkeynes@905
   268
void FASTCALL sh4_write_long( sh4addr_t addr, uint32_t val )
nkeynes@10
   269
{
nkeynes@502
   270
    sh4ptr_t page;
nkeynes@400
   271
nkeynes@10
   272
    CHECK_WRITE_WATCH(addr,4,val);
nkeynes@10
   273
nkeynes@83
   274
    if( addr >= 0xE0000000 ) {
nkeynes@910
   275
    	if( addr < 0xE4000000 ) { // Shortcut for the extremely common case
nkeynes@910
   276
            SH4_WRITE_STORE_QUEUE( addr, val );
nkeynes@910
   277
    	} else {
nkeynes@910
   278
            sh4_write_p4( addr, val );
nkeynes@910
   279
    	}
nkeynes@10
   280
        return;
nkeynes@418
   281
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@736
   282
        *(uint32_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
nkeynes@736
   283
        xlat_invalidate_long(addr);
nkeynes@736
   284
        return;
nkeynes@418
   285
    } else if( (addr&0x1F800000) == 0x04000000 || 
nkeynes@736
   286
            (addr&0x1F800000) == 0x11000000 ) {
nkeynes@736
   287
        texcache_invalidate_page(addr& 0x7FFFFF);
nkeynes@10
   288
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@736
   289
        pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@165
   290
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@736
   291
        pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@10
   292
    }
nkeynes@10
   293
nkeynes@10
   294
    if( (addr&0x1FFFFFFF) < 0x200000 ) {
nkeynes@448
   295
        WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
nkeynes@10
   296
        sh4_stop();
nkeynes@10
   297
        return;
nkeynes@10
   298
    }
nkeynes@137
   299
    if( (addr&0x1F800000) == 0x00800000 )
nkeynes@736
   300
        asic_g2_write_word();
nkeynes@137
   301
nkeynes@10
   302
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   303
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   304
        if( page == NULL ) {
nkeynes@736
   305
            if( (addr & 0x1F000000) >= 0x04000000 &&
nkeynes@736
   306
                    (addr & 0x1F000000) < 0x07000000 )
nkeynes@736
   307
                return;
nkeynes@448
   308
            WARN( "Long write to missing page: %08X => %08X", val, addr );
nkeynes@10
   309
            return;
nkeynes@10
   310
        }
nkeynes@10
   311
        TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
nkeynes@504
   312
        io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
nkeynes@10
   313
    } else {
nkeynes@10
   314
        *(uint32_t *)(page+(addr&0xFFF)) = val;
nkeynes@10
   315
    }
nkeynes@10
   316
}
nkeynes@10
   317
nkeynes@905
   318
void FASTCALL sh4_write_word( sh4addr_t addr, uint32_t val )
nkeynes@10
   319
{
nkeynes@502
   320
    sh4ptr_t page;
nkeynes@10
   321
nkeynes@10
   322
    CHECK_WRITE_WATCH(addr,2,val);
nkeynes@10
   323
nkeynes@83
   324
    if( addr >= 0xE0000000 ) {
nkeynes@10
   325
        sh4_write_p4( addr, (int16_t)val );
nkeynes@10
   326
        return;
nkeynes@418
   327
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@736
   328
        *(uint16_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
nkeynes@736
   329
        xlat_invalidate_word(addr);
nkeynes@736
   330
        return;
nkeynes@418
   331
    } else if( (addr&0x1F800000) == 0x04000000 ||
nkeynes@736
   332
            (addr&0x1F800000) == 0x11000000 ) {
nkeynes@736
   333
        texcache_invalidate_page(addr& 0x7FFFFF);
nkeynes@10
   334
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@736
   335
        pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@165
   336
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@736
   337
        pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@10
   338
    }
nkeynes@406
   339
nkeynes@400
   340
    if( (addr&0x1FFFFFFF) < 0x200000 ) {
nkeynes@448
   341
        WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
nkeynes@400
   342
        sh4_stop();
nkeynes@400
   343
        return;
nkeynes@400
   344
    }
nkeynes@10
   345
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   346
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   347
        if( page == NULL ) {
nkeynes@448
   348
            WARN( "Attempted word write to missing page: %08X", addr );
nkeynes@10
   349
            return;
nkeynes@10
   350
        }
nkeynes@10
   351
        TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
nkeynes@504
   352
        io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
nkeynes@10
   353
    } else {
nkeynes@10
   354
        *(uint16_t *)(page+(addr&0xFFF)) = val;
nkeynes@10
   355
    }
nkeynes@10
   356
}
nkeynes@10
   357
nkeynes@905
   358
void FASTCALL sh4_write_byte( sh4addr_t addr, uint32_t val )
nkeynes@10
   359
{
nkeynes@502
   360
    sh4ptr_t page;
nkeynes@586
   361
nkeynes@10
   362
    CHECK_WRITE_WATCH(addr,1,val);
nkeynes@10
   363
nkeynes@83
   364
    if( addr >= 0xE0000000 ) {
nkeynes@10
   365
        sh4_write_p4( addr, (int8_t)val );
nkeynes@10
   366
        return;
nkeynes@418
   367
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@736
   368
        *(uint8_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
nkeynes@736
   369
        xlat_invalidate_word(addr);
nkeynes@736
   370
        return;
nkeynes@418
   371
    } else if( (addr&0x1F800000) == 0x04000000 ||
nkeynes@736
   372
            (addr&0x1F800000) == 0x11000000 ) {
nkeynes@736
   373
        texcache_invalidate_page(addr& 0x7FFFFF);
nkeynes@10
   374
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@736
   375
        pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@165
   376
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@736
   377
        pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@10
   378
    }
nkeynes@736
   379
nkeynes@400
   380
    if( (addr&0x1FFFFFFF) < 0x200000 ) {
nkeynes@448
   381
        WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
nkeynes@400
   382
        sh4_stop();
nkeynes@400
   383
        return;
nkeynes@400
   384
    }
nkeynes@10
   385
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   386
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   387
        if( page == NULL ) {
nkeynes@448
   388
            WARN( "Attempted byte write to missing page: %08X", addr );
nkeynes@10
   389
            return;
nkeynes@10
   390
        }
nkeynes@10
   391
        TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
nkeynes@504
   392
        io_rgn[(uintptr_t)page]->io_write( (addr&0xFFF), val);
nkeynes@10
   393
    } else {
nkeynes@10
   394
        *(uint8_t *)(page+(addr&0xFFF)) = val;
nkeynes@10
   395
    }
nkeynes@10
   396
}
nkeynes@10
   397
nkeynes@10
   398
nkeynes@10
   399
nkeynes@10
   400
/* FIXME: Handle all the many special cases when the range doesn't fall cleanly
nkeynes@400
   401
 * into the same memory block
nkeynes@10
   402
 */
nkeynes@912
   403
void mem_copy_from_sh4( sh4ptr_t dest, sh4addr_t srcaddr, size_t count ) {
nkeynes@103
   404
    if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
nkeynes@736
   405
        pvr2_vram64_read( dest, srcaddr, count );
nkeynes@103
   406
    } else {
nkeynes@736
   407
        sh4ptr_t src = mem_get_region(srcaddr);
nkeynes@736
   408
        if( src == NULL ) {
nkeynes@736
   409
            WARN( "Attempted block read from unknown address %08X", srcaddr );
nkeynes@736
   410
        } else {
nkeynes@736
   411
            memcpy( dest, src, count );
nkeynes@736
   412
        }
nkeynes@103
   413
    }
nkeynes@10
   414
}
nkeynes@10
   415
nkeynes@912
   416
void mem_copy_to_sh4( sh4addr_t destaddr, sh4ptr_t src, size_t count ) {
nkeynes@325
   417
    if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
nkeynes@736
   418
        pvr2_dma_write( destaddr, src, count );
nkeynes@736
   419
        return;
nkeynes@325
   420
    } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
nkeynes@736
   421
        pvr2_render_buffer_invalidate( destaddr, TRUE );
nkeynes@325
   422
    } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
nkeynes@736
   423
        pvr2_vram64_write( destaddr, src, count );
nkeynes@736
   424
        return;
nkeynes@325
   425
    }
nkeynes@502
   426
    sh4ptr_t dest = mem_get_region(destaddr);
nkeynes@325
   427
    if( dest == NULL )
nkeynes@736
   428
        WARN( "Attempted block write to unknown address %08X", destaddr );
nkeynes@325
   429
    else {
nkeynes@736
   430
        xlat_invalidate_block( destaddr, count );
nkeynes@736
   431
        memcpy( dest, src, count );
nkeynes@90
   432
    }
nkeynes@10
   433
}
nkeynes@369
   434
nkeynes@586
   435
sh4ptr_t sh4_get_region_by_vma( sh4addr_t vma )
nkeynes@369
   436
{
nkeynes@598
   437
    sh4addr_t addr = mmu_vma_to_phys_read(vma);
nkeynes@598
   438
    if( addr == MMU_VMA_ERROR ) {
nkeynes@736
   439
        return NULL;
nkeynes@586
   440
    }
nkeynes@586
   441
nkeynes@586
   442
    sh4ptr_t page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@586
   443
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@586
   444
        return NULL;
nkeynes@586
   445
    } else {
nkeynes@586
   446
        return page+(addr&0xFFF);
nkeynes@586
   447
    }
nkeynes@369
   448
}
nkeynes@586
   449
.