Search
lxdream.org :: lxdream/src/sh4/sh4mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/sh4mem.c
changeset 561:533f6b478071
prev559:06714bc64271
next562:e598411b640b
author nkeynes
date Tue Jan 01 05:08:38 2008 +0000 (16 years ago)
branchlxdream-mmu
permissions -rw-r--r--
last change Enable Id keyword on all source files
file annotate diff log raw
nkeynes@10
     1
/**
nkeynes@561
     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@550
    20
#define ENABLE_TRACE_IO 1
nkeynes@35
    21
nkeynes@10
    22
#include <string.h>
nkeynes@10
    23
#include <zlib.h>
nkeynes@10
    24
#include "dream.h"
nkeynes@10
    25
#include "mem.h"
nkeynes@10
    26
#include "mmio.h"
nkeynes@10
    27
#include "dreamcast.h"
nkeynes@422
    28
#include "sh4/sh4core.h"
nkeynes@422
    29
#include "sh4/sh4mmio.h"
nkeynes@422
    30
#include "sh4/xltcache.h"
nkeynes@100
    31
#include "pvr2/pvr2.h"
nkeynes@422
    32
#include "asic.h"
nkeynes@10
    33
nkeynes@10
    34
#define OC_BASE 0x1C000000
nkeynes@10
    35
#define OC_TOP  0x20000000
nkeynes@10
    36
nkeynes@90
    37
#define TRANSLATE_VIDEO_64BIT_ADDRESS(a)  ( (((a)&0x00FFFFF8)>>1)|(((a)&0x00000004)<<20)|((a)&0x03)|0x05000000 )
nkeynes@10
    38
nkeynes@10
    39
#ifdef ENABLE_WATCH
nkeynes@10
    40
#define CHECK_READ_WATCH( addr, size ) \
nkeynes@10
    41
    if( mem_is_watched(addr,size,WATCH_READ) != NULL ) { \
nkeynes@10
    42
        WARN( "Watch triggered at %08X by %d byte read", addr, size ); \
nkeynes@10
    43
        dreamcast_stop(); \
nkeynes@10
    44
    }
nkeynes@10
    45
#define CHECK_WRITE_WATCH( addr, size, val )                  \
nkeynes@10
    46
    if( mem_is_watched(addr,size,WATCH_WRITE) != NULL ) { \
nkeynes@10
    47
        WARN( "Watch triggered at %08X by %d byte write <= %0*X", addr, size, size*2, val ); \
nkeynes@10
    48
        dreamcast_stop(); \
nkeynes@10
    49
    }
nkeynes@10
    50
#else
nkeynes@10
    51
#define CHECK_READ_WATCH( addr, size )
nkeynes@234
    52
#define CHECK_WRITE_WATCH( addr, size, val )
nkeynes@10
    53
#endif
nkeynes@10
    54
nkeynes@406
    55
#ifdef ENABLE_TRACE_IO
nkeynes@172
    56
#define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag && !MMIO_NOTRACE_BYNUM((uint32_t)p,r)) \
nkeynes@172
    57
    TRACE( str " [%s.%s: %s]", __VA_ARGS__,			       \
nkeynes@10
    58
    MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
nkeynes@10
    59
    MMIO_REGDESC_BYNUM((uint32_t)p, r) )
nkeynes@172
    60
#define TRACE_P4IO( str, io, r, ... ) if(io->trace_flag && !MMIO_NOTRACE_IOBYNUM(io,r)) \
nkeynes@156
    61
TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
nkeynes@156
    62
    io->id, MMIO_REGID_IOBYNUM(io, r), \
nkeynes@156
    63
    MMIO_REGDESC_IOBYNUM(io, r) )
nkeynes@406
    64
#else
nkeynes@406
    65
#define TRACE_IO( str, p, r, ... )
nkeynes@406
    66
#define TRACE_P4IO( str, io, r, ... )
nkeynes@406
    67
#endif
nkeynes@10
    68
nkeynes@10
    69
extern struct mem_region mem_rgn[];
nkeynes@10
    70
extern struct mmio_region *P4_io[];
nkeynes@502
    71
sh4ptr_t sh4_main_ram;
nkeynes@10
    72
nkeynes@527
    73
int32_t sh4_read_p4( sh4addr_t addr )
nkeynes@10
    74
{
nkeynes@10
    75
    struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
nkeynes@10
    76
    if( !io ) {
nkeynes@550
    77
	switch( addr & 0x1F000000 ) {
nkeynes@550
    78
	case 0x00000000: case 0x01000000: case 0x02000000: case 0x03000000: 
nkeynes@550
    79
	    /* Store queue - readable? */
nkeynes@550
    80
	    return 0;
nkeynes@550
    81
	    break;
nkeynes@550
    82
	case 0x10000000: return mmu_icache_addr_read( addr );
nkeynes@550
    83
	case 0x11000000: return mmu_icache_data_read( addr );
nkeynes@550
    84
	case 0x12000000: return mmu_itlb_addr_read( addr );
nkeynes@550
    85
	case 0x13000000: return mmu_itlb_data_read( addr );
nkeynes@550
    86
	case 0x14000000: return mmu_ocache_addr_read( addr );
nkeynes@550
    87
	case 0x15000000: return mmu_ocache_data_read( addr );
nkeynes@550
    88
	case 0x16000000: return mmu_utlb_addr_read( addr );
nkeynes@550
    89
	case 0x17000000: return mmu_utlb_data_read( addr );
nkeynes@550
    90
	default:
nkeynes@550
    91
            WARN( "Attempted read from unknown or invalid P4 region: %08X", addr );
nkeynes@550
    92
	    return 0;
nkeynes@282
    93
        }
nkeynes@10
    94
    } else {
nkeynes@156
    95
	int32_t val = io->io_read( addr&0xFFF );
nkeynes@156
    96
	TRACE_P4IO( "Long read %08X <= %08X", io, (addr&0xFFF), val, addr );
nkeynes@156
    97
        return val;
nkeynes@10
    98
    }    
nkeynes@10
    99
}
nkeynes@10
   100
nkeynes@527
   101
void sh4_write_p4( sh4addr_t addr, int32_t val )
nkeynes@10
   102
{
nkeynes@10
   103
    struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
nkeynes@10
   104
    if( !io ) {
nkeynes@550
   105
	switch( addr & 0x1F000000 ) {
nkeynes@550
   106
	case 0x00000000: case 0x01000000: case 0x02000000: case 0x03000000: 
nkeynes@10
   107
            /* Store queue */
nkeynes@10
   108
            SH4_WRITE_STORE_QUEUE( addr, val );
nkeynes@550
   109
	    break;
nkeynes@550
   110
	case 0x10000000: mmu_icache_addr_write( addr, val ); break;
nkeynes@550
   111
	case 0x11000000: mmu_icache_data_write( addr, val ); break;
nkeynes@550
   112
	case 0x12000000: mmu_itlb_addr_write( addr, val ); break;
nkeynes@550
   113
	case 0x13000000: mmu_itlb_data_write( addr, val ); break;
nkeynes@550
   114
	case 0x14000000: mmu_ocache_addr_write( addr, val ); break;
nkeynes@550
   115
	case 0x15000000: mmu_ocache_data_write( addr, val ); break;
nkeynes@550
   116
	case 0x16000000: mmu_utlb_addr_write( addr, val ); break;
nkeynes@550
   117
	case 0x17000000: mmu_utlb_data_write( addr, val ); break;
nkeynes@550
   118
	default:
nkeynes@448
   119
            WARN( "Attempted write to unknown P4 region: %08X", addr );
nkeynes@10
   120
        }
nkeynes@10
   121
    } else {
nkeynes@156
   122
	TRACE_P4IO( "Long write %08X => %08X", io, (addr&0xFFF), val, addr );
nkeynes@10
   123
        io->io_write( addr&0xFFF, val );
nkeynes@10
   124
    }
nkeynes@10
   125
}
nkeynes@10
   126
nkeynes@527
   127
int32_t sh4_read_phys_word( sh4addr_t addr )
nkeynes@10
   128
{
nkeynes@502
   129
    sh4ptr_t page;
nkeynes@83
   130
    if( addr >= 0xE0000000 ) /* P4 Area, handled specially */
nkeynes@10
   131
        return SIGNEXT16(sh4_read_p4( addr ));
nkeynes@10
   132
    
nkeynes@10
   133
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   134
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@10
   135
    }
nkeynes@10
   136
nkeynes@10
   137
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   138
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   139
        if( page == NULL ) {
nkeynes@448
   140
            WARN( "Attempted word read to missing page: %08X",
nkeynes@10
   141
                   addr );
nkeynes@10
   142
            return 0;
nkeynes@10
   143
        }
nkeynes@504
   144
        return SIGNEXT16(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
nkeynes@10
   145
    } else {
nkeynes@10
   146
        return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
nkeynes@10
   147
    }
nkeynes@10
   148
}
nkeynes@10
   149
nkeynes@527
   150
/**
nkeynes@527
   151
 * Convenience function to read a quad-word (implemented as two long reads).
nkeynes@527
   152
 */
nkeynes@527
   153
int64_t sh4_read_quad( sh4addr_t addr )
nkeynes@527
   154
{
nkeynes@527
   155
    return ((int64_t)((uint32_t)sh4_read_long(addr))) |
nkeynes@527
   156
	(((int64_t)((uint32_t)sh4_read_long(addr+4))) << 32);
nkeynes@527
   157
}
nkeynes@527
   158
nkeynes@559
   159
int64_t sh4_read_long( sh4addr_t vma )
nkeynes@10
   160
{
nkeynes@502
   161
    sh4ptr_t page;
nkeynes@10
   162
    
nkeynes@10
   163
    CHECK_READ_WATCH(addr,4);
nkeynes@10
   164
nkeynes@559
   165
    uint64_t ppa = mmu_vma_to_phys_read(vma);
nkeynes@559
   166
    if( ppa>>32 ) {
nkeynes@559
   167
	return ppa;
nkeynes@559
   168
    }
nkeynes@559
   169
    sh4addr_t addr = (sh4addr_t)ppa;
nkeynes@559
   170
nkeynes@418
   171
    if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
nkeynes@559
   172
        return ZEROEXT32(sh4_read_p4( addr ));
nkeynes@418
   173
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@559
   174
	return ZEROEXT32(*(int32_t *)(sh4_main_ram + (addr&0x00FFFFFF)));
nkeynes@418
   175
    } else if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   176
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@355
   177
	pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@217
   178
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@355
   179
	pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@10
   180
    }
nkeynes@10
   181
nkeynes@10
   182
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   183
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   184
        int32_t val;
nkeynes@10
   185
        if( page == NULL ) {
nkeynes@448
   186
            WARN( "Attempted long read to missing page: %08X", addr );
nkeynes@10
   187
            return 0;
nkeynes@10
   188
        }
nkeynes@504
   189
        val = io_rgn[(uintptr_t)page]->io_read(addr&0xFFF);
nkeynes@10
   190
        TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
nkeynes@559
   191
        return ZEROEXT32(val);
nkeynes@10
   192
    } else {
nkeynes@559
   193
        return ZEROEXT32(*(int32_t *)(page+(addr&0xFFF)));
nkeynes@10
   194
    }
nkeynes@10
   195
}
nkeynes@10
   196
nkeynes@559
   197
int64_t sh4_read_word( sh4addr_t vma )
nkeynes@10
   198
{
nkeynes@502
   199
    sh4ptr_t page;
nkeynes@10
   200
nkeynes@10
   201
    CHECK_READ_WATCH(addr,2);
nkeynes@10
   202
nkeynes@559
   203
    uint64_t ppa = mmu_vma_to_phys_read(vma);
nkeynes@559
   204
    if( ppa>>32 ) {
nkeynes@559
   205
	return ppa;
nkeynes@559
   206
    }
nkeynes@559
   207
    sh4addr_t addr = (sh4addr_t)ppa;
nkeynes@559
   208
nkeynes@418
   209
    if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
nkeynes@559
   210
        return ZEROEXT32(SIGNEXT16(sh4_read_p4( addr )));
nkeynes@418
   211
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@559
   212
	return ZEROEXT32(SIGNEXT16(*(int16_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
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   221
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   222
        int32_t val;
nkeynes@10
   223
        if( page == NULL ) {
nkeynes@448
   224
	    WARN( "Attempted word read to missing page: %08X", addr );
nkeynes@10
   225
            return 0;
nkeynes@10
   226
        }
nkeynes@504
   227
        val = SIGNEXT16(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
nkeynes@10
   228
        TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
nkeynes@559
   229
        return ZEROEXT32(val);
nkeynes@10
   230
    } else {
nkeynes@559
   231
        return ZEROEXT32(SIGNEXT16(*(int16_t *)(page+(addr&0xFFF))));
nkeynes@10
   232
    }
nkeynes@10
   233
}
nkeynes@10
   234
nkeynes@559
   235
int64_t sh4_read_byte( sh4addr_t vma )
nkeynes@10
   236
{
nkeynes@502
   237
    sh4ptr_t page;
nkeynes@10
   238
nkeynes@10
   239
    CHECK_READ_WATCH(addr,1);
nkeynes@10
   240
nkeynes@559
   241
    uint64_t ppa = mmu_vma_to_phys_read(vma);
nkeynes@559
   242
    if( ppa>>32 ) {
nkeynes@559
   243
	return ppa;
nkeynes@559
   244
    }
nkeynes@559
   245
    sh4addr_t addr = (sh4addr_t)ppa;
nkeynes@559
   246
nkeynes@418
   247
    if( addr >= 0xE0000000 ) { /* P4 Area, handled specially */
nkeynes@559
   248
        return ZEROEXT32(SIGNEXT8(sh4_read_p4( addr )));
nkeynes@418
   249
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@559
   250
	return ZEROEXT32(SIGNEXT8(*(int8_t *)(sh4_main_ram + (addr&0x00FFFFFF))));
nkeynes@418
   251
    } else if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@10
   252
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@355
   253
    	pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@217
   254
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@355
   255
	pvr2_render_buffer_invalidate(addr, FALSE);
nkeynes@10
   256
    }
nkeynes@217
   257
nkeynes@10
   258
    
nkeynes@10
   259
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   260
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   261
        int32_t val;
nkeynes@10
   262
        if( page == NULL ) {
nkeynes@448
   263
            WARN( "Attempted byte read to missing page: %08X", addr );
nkeynes@10
   264
            return 0;
nkeynes@10
   265
        }
nkeynes@504
   266
        val = SIGNEXT8(io_rgn[(uintptr_t)page]->io_read(addr&0xFFF));
nkeynes@10
   267
        TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
nkeynes@559
   268
        return ZEROEXT32(val);
nkeynes@10
   269
    } else {
nkeynes@559
   270
        return ZEROEXT32(SIGNEXT8(*(int8_t *)(page+(addr&0xFFF))));
nkeynes@10
   271
    }
nkeynes@10
   272
}
nkeynes@10
   273
nkeynes@527
   274
/**
nkeynes@527
   275
 * Convenience function to write a quad-word (implemented as two long writes).
nkeynes@527
   276
 */
nkeynes@527
   277
void sh4_write_quad( sh4addr_t addr, uint64_t val )
nkeynes@527
   278
{
nkeynes@527
   279
    sh4_write_long( addr, (uint32_t)val );
nkeynes@527
   280
    sh4_write_long( addr+4, (uint32_t)(val>>32) );
nkeynes@527
   281
}
nkeynes@527
   282
nkeynes@559
   283
int32_t sh4_write_long( sh4addr_t vma, uint32_t val )
nkeynes@10
   284
{
nkeynes@502
   285
    sh4ptr_t page;
nkeynes@400
   286
nkeynes@559
   287
    uint64_t ppa = mmu_vma_to_phys_write(vma);
nkeynes@559
   288
    if( ppa>>32 ) {
nkeynes@559
   289
	return ppa>>32;
nkeynes@559
   290
    }
nkeynes@559
   291
    sh4addr_t addr = (sh4addr_t)ppa;
nkeynes@559
   292
nkeynes@10
   293
    CHECK_WRITE_WATCH(addr,4,val);
nkeynes@10
   294
nkeynes@83
   295
    if( addr >= 0xE0000000 ) {
nkeynes@10
   296
        sh4_write_p4( addr, val );
nkeynes@559
   297
        return 0;
nkeynes@418
   298
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@418
   299
	*(uint32_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
nkeynes@419
   300
	xlat_invalidate_long(addr);
nkeynes@559
   301
	return 0;
nkeynes@418
   302
    } else if( (addr&0x1F800000) == 0x04000000 || 
nkeynes@418
   303
	       (addr&0x1F800000) == 0x11000000 ) {
nkeynes@150
   304
	texcache_invalidate_page(addr& 0x7FFFFF);
nkeynes@10
   305
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@355
   306
	pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@165
   307
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@355
   308
	pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@10
   309
    }
nkeynes@10
   310
nkeynes@10
   311
    if( (addr&0x1FFFFFFF) < 0x200000 ) {
nkeynes@448
   312
        WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
nkeynes@10
   313
        sh4_stop();
nkeynes@559
   314
        return 0;
nkeynes@10
   315
    }
nkeynes@137
   316
    if( (addr&0x1F800000) == 0x00800000 )
nkeynes@137
   317
	asic_g2_write_word();
nkeynes@137
   318
nkeynes@10
   319
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   320
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   321
        if( page == NULL ) {
nkeynes@137
   322
	    if( (addr & 0x1F000000) >= 0x04000000 &&
nkeynes@137
   323
		(addr & 0x1F000000) < 0x07000000 )
nkeynes@559
   324
		return 0;
nkeynes@448
   325
            WARN( "Long write to missing page: %08X => %08X", val, addr );
nkeynes@559
   326
            return 0;
nkeynes@10
   327
        }
nkeynes@10
   328
        TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
nkeynes@504
   329
        io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
nkeynes@10
   330
    } else {
nkeynes@10
   331
        *(uint32_t *)(page+(addr&0xFFF)) = val;
nkeynes@10
   332
    }
nkeynes@559
   333
    return 0;
nkeynes@10
   334
}
nkeynes@10
   335
nkeynes@559
   336
int32_t sh4_write_word( sh4addr_t vma, uint32_t val )
nkeynes@10
   337
{
nkeynes@502
   338
    sh4ptr_t page;
nkeynes@10
   339
nkeynes@559
   340
    uint64_t ppa = mmu_vma_to_phys_write(vma);
nkeynes@559
   341
    if( ppa>>32 ) {
nkeynes@559
   342
	return ppa>>32;
nkeynes@559
   343
    }
nkeynes@559
   344
    sh4addr_t addr = (sh4addr_t)ppa;
nkeynes@559
   345
nkeynes@10
   346
    CHECK_WRITE_WATCH(addr,2,val);
nkeynes@10
   347
nkeynes@83
   348
    if( addr >= 0xE0000000 ) {
nkeynes@10
   349
        sh4_write_p4( addr, (int16_t)val );
nkeynes@559
   350
        return 0;
nkeynes@418
   351
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@418
   352
	*(uint16_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
nkeynes@419
   353
	xlat_invalidate_word(addr);
nkeynes@559
   354
	return 0;
nkeynes@418
   355
    } else if( (addr&0x1F800000) == 0x04000000 ||
nkeynes@130
   356
	(addr&0x1F800000) == 0x11000000 ) {
nkeynes@150
   357
	texcache_invalidate_page(addr& 0x7FFFFF);
nkeynes@10
   358
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@355
   359
	pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@165
   360
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@355
   361
	pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@10
   362
    }
nkeynes@406
   363
nkeynes@400
   364
    if( (addr&0x1FFFFFFF) < 0x200000 ) {
nkeynes@448
   365
        WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
nkeynes@400
   366
        sh4_stop();
nkeynes@559
   367
        return 0;
nkeynes@400
   368
    }
nkeynes@10
   369
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   370
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   371
        if( page == NULL ) {
nkeynes@448
   372
            WARN( "Attempted word write to missing page: %08X", addr );
nkeynes@559
   373
            return 0;
nkeynes@10
   374
        }
nkeynes@10
   375
        TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
nkeynes@504
   376
        io_rgn[(uintptr_t)page]->io_write(addr&0xFFF, val);
nkeynes@10
   377
    } else {
nkeynes@10
   378
        *(uint16_t *)(page+(addr&0xFFF)) = val;
nkeynes@10
   379
    }
nkeynes@559
   380
    return 0;
nkeynes@10
   381
}
nkeynes@10
   382
nkeynes@559
   383
int32_t sh4_write_byte( sh4addr_t vma, uint32_t val )
nkeynes@10
   384
{
nkeynes@502
   385
    sh4ptr_t page;
nkeynes@559
   386
nkeynes@559
   387
    uint64_t ppa = mmu_vma_to_phys_write(vma);
nkeynes@559
   388
    if( ppa>>32 ) {
nkeynes@559
   389
	return ppa>>32;
nkeynes@559
   390
    }
nkeynes@559
   391
    sh4addr_t addr = (sh4addr_t)ppa;
nkeynes@10
   392
    
nkeynes@10
   393
    CHECK_WRITE_WATCH(addr,1,val);
nkeynes@10
   394
nkeynes@83
   395
    if( addr >= 0xE0000000 ) {
nkeynes@10
   396
        sh4_write_p4( addr, (int8_t)val );
nkeynes@559
   397
        return 0;
nkeynes@418
   398
    } else if( (addr&0x1C000000) == 0x0C000000 ) {
nkeynes@418
   399
	*(uint8_t *)(sh4_main_ram + (addr&0x00FFFFFF)) = val;
nkeynes@419
   400
	xlat_invalidate_word(addr);
nkeynes@559
   401
	return 0;
nkeynes@418
   402
    } else if( (addr&0x1F800000) == 0x04000000 ||
nkeynes@418
   403
	       (addr&0x1F800000) == 0x11000000 ) {
nkeynes@150
   404
	texcache_invalidate_page(addr& 0x7FFFFF);
nkeynes@10
   405
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@355
   406
	pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@165
   407
    } else if( (addr&0x1F800000) == 0x05000000 ) {
nkeynes@355
   408
	pvr2_render_buffer_invalidate(addr, TRUE);
nkeynes@10
   409
    }
nkeynes@10
   410
    
nkeynes@400
   411
    if( (addr&0x1FFFFFFF) < 0x200000 ) {
nkeynes@448
   412
        WARN( "Attempted write to read-only memory: %08X => %08X", val, addr);
nkeynes@400
   413
        sh4_stop();
nkeynes@559
   414
        return 0;
nkeynes@400
   415
    }
nkeynes@10
   416
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@504
   417
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   418
        if( page == NULL ) {
nkeynes@448
   419
            WARN( "Attempted byte write to missing page: %08X", addr );
nkeynes@559
   420
            return 0;
nkeynes@10
   421
        }
nkeynes@10
   422
        TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
nkeynes@504
   423
        io_rgn[(uintptr_t)page]->io_write( (addr&0xFFF), val);
nkeynes@10
   424
    } else {
nkeynes@10
   425
        *(uint8_t *)(page+(addr&0xFFF)) = val;
nkeynes@10
   426
    }
nkeynes@559
   427
    return 0;
nkeynes@10
   428
}
nkeynes@10
   429
nkeynes@10
   430
nkeynes@10
   431
nkeynes@10
   432
/* FIXME: Handle all the many special cases when the range doesn't fall cleanly
nkeynes@400
   433
 * into the same memory block
nkeynes@10
   434
 */
nkeynes@527
   435
void mem_copy_from_sh4( sh4ptr_t dest, sh4addr_t srcaddr, size_t count ) {
nkeynes@103
   436
    if( srcaddr >= 0x04000000 && srcaddr < 0x05000000 ) {
nkeynes@103
   437
	pvr2_vram64_read( dest, srcaddr, count );
nkeynes@103
   438
    } else {
nkeynes@502
   439
	sh4ptr_t src = mem_get_region(srcaddr);
nkeynes@103
   440
	if( src == NULL ) {
nkeynes@448
   441
	    WARN( "Attempted block read from unknown address %08X", srcaddr );
nkeynes@103
   442
	} else {
nkeynes@103
   443
	    memcpy( dest, src, count );
nkeynes@103
   444
	}
nkeynes@103
   445
    }
nkeynes@10
   446
}
nkeynes@10
   447
nkeynes@527
   448
void mem_copy_to_sh4( sh4addr_t destaddr, sh4ptr_t src, size_t count ) {
nkeynes@325
   449
    if( destaddr >= 0x10000000 && destaddr < 0x14000000 ) {
nkeynes@325
   450
	pvr2_dma_write( destaddr, src, count );
nkeynes@325
   451
	return;
nkeynes@325
   452
    } else if( (destaddr & 0x1F800000) == 0x05000000 ) {
nkeynes@355
   453
	pvr2_render_buffer_invalidate( destaddr, TRUE );
nkeynes@325
   454
    } else if( (destaddr & 0x1F800000) == 0x04000000 ) {
nkeynes@103
   455
	pvr2_vram64_write( destaddr, src, count );
nkeynes@325
   456
	return;
nkeynes@325
   457
    }
nkeynes@502
   458
    sh4ptr_t dest = mem_get_region(destaddr);
nkeynes@325
   459
    if( dest == NULL )
nkeynes@448
   460
	WARN( "Attempted block write to unknown address %08X", destaddr );
nkeynes@325
   461
    else {
nkeynes@400
   462
	xlat_invalidate_block( destaddr, count );
nkeynes@325
   463
	memcpy( dest, src, count );
nkeynes@90
   464
    }
nkeynes@10
   465
}
nkeynes@369
   466
nkeynes@527
   467
void sh4_flush_store_queue( sh4addr_t addr )
nkeynes@369
   468
{
nkeynes@369
   469
    /* Store queue operation */
nkeynes@369
   470
    int queue = (addr&0x20)>>2;
nkeynes@502
   471
    sh4ptr_t src = (sh4ptr_t)&sh4r.store_queue[queue];
nkeynes@369
   472
    uint32_t hi = (MMIO_READ( MMU, (queue == 0 ? QACR0 : QACR1) ) & 0x1C) << 24;
nkeynes@422
   473
    uint32_t target = (addr&0x03FFFFE0) | hi;
nkeynes@369
   474
    mem_copy_to_sh4( target, src, 32 );
nkeynes@369
   475
}
nkeynes@559
   476
nkeynes@559
   477
sh4ptr_t sh4_get_region_by_vma( sh4addr_t vma )
nkeynes@559
   478
{
nkeynes@559
   479
    uint64_t ppa = mmu_vma_to_phys_read(vma);
nkeynes@559
   480
    if( ppa>>32 ) {
nkeynes@559
   481
	return 0;
nkeynes@559
   482
    }
nkeynes@559
   483
nkeynes@559
   484
    sh4addr_t addr = (sh4addr_t)ppa;
nkeynes@559
   485
    sh4ptr_t page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@559
   486
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@559
   487
        return NULL;
nkeynes@559
   488
    } else {
nkeynes@559
   489
        return page+(addr&0xFFF);
nkeynes@559
   490
    }
nkeynes@559
   491
}
nkeynes@559
   492
.