Search
lxdream.org :: lxdream/src/sh4/mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/sh4/mem.c
changeset 2:42349f6ea216
prev1:eea311cfd33e
author nkeynes
date Thu Dec 08 13:38:00 2005 +0000 (18 years ago)
permissions -rw-r--r--
last change Generalise the core debug window to allow multiple instances.
Add cpu description structure to define different cpus for use by the
debug window, in preparation for ARM implementation
file annotate diff log raw
nkeynes@1
     1
#include <sys/mman.h>
nkeynes@1
     2
#include <assert.h>
nkeynes@1
     3
#include <stdint.h>
nkeynes@1
     4
#include <stdlib.h>
nkeynes@1
     5
#include <stdio.h>
nkeynes@1
     6
#include <unistd.h>
nkeynes@1
     7
#include <fcntl.h>
nkeynes@1
     8
#include <errno.h>
nkeynes@1
     9
#include <string.h>
nkeynes@1
    10
#include <zlib.h>
nkeynes@1
    11
#include "dream.h"
nkeynes@1
    12
#include "sh4core.h"
nkeynes@1
    13
#include "mem.h"
nkeynes@2
    14
#include "dreamcast.h"
nkeynes@1
    15
nkeynes@1
    16
#define OC_BASE 0x1C000000
nkeynes@1
    17
#define OC_TOP  0x20000000
nkeynes@1
    18
nkeynes@2
    19
#ifdef ENABLE_WATCH
nkeynes@2
    20
#define CHECK_READ_WATCH( addr, size ) \
nkeynes@2
    21
    if( mem_is_watched(addr,size,WATCH_READ) != NULL ) { \
nkeynes@2
    22
        WARN( "Watch triggered at %08X by %d byte read", addr, size ); \
nkeynes@2
    23
        dreamcast_stop(); \
nkeynes@2
    24
    }
nkeynes@2
    25
#define CHECK_WRITE_WATCH( addr, size, val )                  \
nkeynes@2
    26
    if( mem_is_watched(addr,size,WATCH_WRITE) != NULL ) { \
nkeynes@2
    27
        WARN( "Watch triggered at %08X by %d byte write <= %0*X", addr, size, size*2, val ); \
nkeynes@2
    28
        dreamcast_stop(); \
nkeynes@2
    29
    }
nkeynes@2
    30
#else
nkeynes@2
    31
#define CHECK_READ_WATCH( addr, size )
nkeynes@2
    32
#define CHECK_WRITE_WATCH( addr, size )
nkeynes@2
    33
#endif
nkeynes@2
    34
nkeynes@2
    35
#define TRANSLATE_VIDEO_64BIT_ADDRESS(a)  ( (((a)&0x00FFFFF8)>>1)|(((a)&0x00000004)<<20)|((a)&0x03)|0x05000000 );
nkeynes@2
    36
nkeynes@1
    37
static char **page_map = NULL;
nkeynes@1
    38
static char *cache = NULL;
nkeynes@1
    39
nkeynes@1
    40
struct mem_region mem_rgn[MAX_MEM_REGIONS];
nkeynes@1
    41
struct mmio_region *io_rgn[MAX_IO_REGIONS];
nkeynes@1
    42
struct mmio_region *P4_io[4096];
nkeynes@1
    43
nkeynes@1
    44
int num_io_rgns = 1, num_mem_rgns = 0;
nkeynes@1
    45
nkeynes@1
    46
void *mem_alloc_pages( int n )
nkeynes@1
    47
{
nkeynes@1
    48
    void *mem = mmap( NULL, n * 4096,
nkeynes@1
    49
                      PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0 );
nkeynes@1
    50
    if( mem == MAP_FAILED ) {
nkeynes@1
    51
        ERROR( "Memory allocation failure! (%s)", strerror(errno) );
nkeynes@1
    52
        return NULL;
nkeynes@1
    53
    }
nkeynes@1
    54
    return mem;
nkeynes@1
    55
}
nkeynes@1
    56
nkeynes@1
    57
nkeynes@1
    58
void mem_init( void )
nkeynes@1
    59
{
nkeynes@1
    60
    page_map = mmap( NULL, sizeof(char *) * PAGE_TABLE_ENTRIES,
nkeynes@1
    61
                     PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0 );
nkeynes@1
    62
    if( page_map == MAP_FAILED ) {
nkeynes@1
    63
        ERROR( "Unable to allocate page map! (%s)", strerror(errno) );
nkeynes@1
    64
        page_map = NULL;
nkeynes@1
    65
        return;
nkeynes@1
    66
    }
nkeynes@1
    67
nkeynes@1
    68
    memset( page_map, 0, sizeof(uint32_t) * PAGE_TABLE_ENTRIES );
nkeynes@1
    69
    cache = mem_alloc_pages(2);
nkeynes@1
    70
}
nkeynes@1
    71
nkeynes@1
    72
void mem_reset( void )
nkeynes@1
    73
{
nkeynes@1
    74
    /* Restore all mmio registers to their initial settings */
nkeynes@1
    75
    int i, j;
nkeynes@1
    76
    for( i=1; i<num_io_rgns; i++ ) {
nkeynes@1
    77
        for( j=0; io_rgn[i]->ports[j].id != NULL; j++ ) {
nkeynes@1
    78
            if( io_rgn[i]->ports[j].def_val != UNDEFINED &&
nkeynes@1
    79
                io_rgn[i]->ports[j].def_val != *io_rgn[i]->ports[j].val ) {
nkeynes@1
    80
                io_rgn[i]->io_write( io_rgn[i]->ports[j].offset,
nkeynes@1
    81
                                    io_rgn[i]->ports[j].def_val );
nkeynes@1
    82
            }
nkeynes@1
    83
        }
nkeynes@1
    84
    }
nkeynes@1
    85
}
nkeynes@1
    86
nkeynes@1
    87
struct mem_region *mem_map_region( void *mem, uint32_t base, uint32_t size,
nkeynes@1
    88
                                   char *name, int flags )
nkeynes@1
    89
{
nkeynes@1
    90
    int i;
nkeynes@1
    91
    mem_rgn[num_mem_rgns].base = base;
nkeynes@1
    92
    mem_rgn[num_mem_rgns].size = size;
nkeynes@1
    93
    mem_rgn[num_mem_rgns].flags = flags;
nkeynes@1
    94
    mem_rgn[num_mem_rgns].name = name;
nkeynes@1
    95
    mem_rgn[num_mem_rgns].mem = mem;
nkeynes@1
    96
    num_mem_rgns++;
nkeynes@1
    97
nkeynes@1
    98
    for( i=0; i<size>>PAGE_BITS; i++ )
nkeynes@1
    99
        page_map[(base>>PAGE_BITS)+i] = mem + (i<<PAGE_BITS);
nkeynes@1
   100
nkeynes@1
   101
    return &mem_rgn[num_mem_rgns-1];
nkeynes@1
   102
}
nkeynes@1
   103
nkeynes@1
   104
void *mem_create_ram_region( uint32_t base, uint32_t size, char *name )
nkeynes@1
   105
{
nkeynes@1
   106
    char *mem;
nkeynes@1
   107
    
nkeynes@1
   108
    assert( (base&0xFFFFF000) == base ); /* must be page aligned */
nkeynes@1
   109
    assert( (size&0x00000FFF) == 0 );
nkeynes@1
   110
    assert( num_mem_rgns < MAX_MEM_REGIONS );
nkeynes@1
   111
    assert( page_map != NULL );
nkeynes@1
   112
nkeynes@1
   113
    mem = mem_alloc_pages( size>>PAGE_BITS );
nkeynes@1
   114
nkeynes@1
   115
    mem_map_region( mem, base, size, name, 6 );
nkeynes@1
   116
    return mem;
nkeynes@1
   117
}
nkeynes@1
   118
nkeynes@1
   119
void *mem_load_rom( char *file, uint32_t base, uint32_t size, uint32_t crc )
nkeynes@1
   120
{
nkeynes@1
   121
    char buf[512], *mem;
nkeynes@1
   122
    int fd;
nkeynes@1
   123
    uint32_t calc_crc;
nkeynes@1
   124
    snprintf( buf, 512, "%s/%s",BIOS_PATH, file );
nkeynes@1
   125
    fd = open( buf, O_RDONLY );
nkeynes@1
   126
    if( fd == -1 ) {
nkeynes@1
   127
        ERROR( "Bios file not found: %s", buf );
nkeynes@1
   128
        return NULL;
nkeynes@1
   129
    }
nkeynes@1
   130
    mem = mmap( NULL, size, PROT_READ, MAP_PRIVATE, fd, 0 );
nkeynes@1
   131
    if( mem == MAP_FAILED ) {
nkeynes@1
   132
        ERROR( "Unable to map bios file: %s (%s)", file, strerror(errno) );
nkeynes@1
   133
        close(fd);
nkeynes@1
   134
        return NULL;
nkeynes@1
   135
    }
nkeynes@1
   136
    mem_map_region( mem, base, size, file, 4 );
nkeynes@1
   137
nkeynes@1
   138
    /* CRC check */
nkeynes@1
   139
    calc_crc = crc32(0L, mem, size);
nkeynes@1
   140
    if( calc_crc != crc ) {
nkeynes@1
   141
        WARN( "Bios CRC Mismatch in %s: %08X (expected %08X)",
nkeynes@1
   142
              file, calc_crc, crc);
nkeynes@1
   143
    }
nkeynes@1
   144
    return mem;
nkeynes@1
   145
}
nkeynes@1
   146
nkeynes@1
   147
char *mem_get_region_by_name( char *name )
nkeynes@1
   148
{
nkeynes@1
   149
    int i;
nkeynes@1
   150
    for( i=0; i<num_mem_rgns; i++ ) {
nkeynes@1
   151
        if( strcmp( mem_rgn[i].name, name ) == 0 )
nkeynes@1
   152
            return mem_rgn[i].mem;
nkeynes@1
   153
    }
nkeynes@1
   154
    return NULL;
nkeynes@1
   155
}
nkeynes@1
   156
nkeynes@1
   157
#define OCRAM_START (0x1C000000>>PAGE_BITS)
nkeynes@1
   158
#define OCRAM_END   (0x20000000>>PAGE_BITS)
nkeynes@1
   159
nkeynes@1
   160
void mem_set_cache_mode( int mode )
nkeynes@1
   161
{
nkeynes@1
   162
    uint32_t i;
nkeynes@1
   163
    switch( mode ) {
nkeynes@1
   164
        case MEM_OC_INDEX0: /* OIX=0 */
nkeynes@1
   165
            for( i=OCRAM_START; i<OCRAM_END; i++ )
nkeynes@1
   166
                page_map[i] = cache + ((i&0x02)<<(PAGE_BITS-1));
nkeynes@1
   167
            break;
nkeynes@1
   168
        case MEM_OC_INDEX1: /* OIX=1 */
nkeynes@1
   169
            for( i=OCRAM_START; i<OCRAM_END; i++ )
nkeynes@1
   170
                page_map[i] = cache + ((i&0x02000000)>>(25-PAGE_BITS));
nkeynes@1
   171
            break;
nkeynes@1
   172
        default: /* disabled */
nkeynes@1
   173
            for( i=OCRAM_START; i<OCRAM_END; i++ )
nkeynes@1
   174
                page_map[i] = NULL;
nkeynes@1
   175
            break;
nkeynes@1
   176
    }
nkeynes@1
   177
}
nkeynes@1
   178
nkeynes@1
   179
void register_io_region( struct mmio_region *io )
nkeynes@1
   180
{
nkeynes@1
   181
    int i;
nkeynes@1
   182
    
nkeynes@1
   183
    assert(io);
nkeynes@1
   184
    io->mem = mem_alloc_pages(2);
nkeynes@1
   185
    io->save_mem = io->mem + PAGE_SIZE;
nkeynes@1
   186
    io->index = (struct mmio_port **)malloc(1024*sizeof(struct mmio_port *));
nkeynes@1
   187
    io->trace_flag = 1;
nkeynes@1
   188
    memset( io->index, 0, 1024*sizeof(struct mmio_port *) );
nkeynes@1
   189
    for( i=0; io->ports[i].id != NULL; i++ ) {
nkeynes@1
   190
        io->ports[i].val = (uint32_t *)(io->mem + io->ports[i].offset);
nkeynes@1
   191
        *io->ports[i].val = io->ports[i].def_val;
nkeynes@1
   192
        io->index[io->ports[i].offset>>2] = &io->ports[i];
nkeynes@1
   193
    }
nkeynes@1
   194
    memcpy( io->save_mem, io->mem, PAGE_SIZE );
nkeynes@1
   195
    if( (io->base & 0xFF000000) == 0xFF000000 ) {
nkeynes@1
   196
        /* P4 area (on-chip I/O channels */
nkeynes@1
   197
        P4_io[(io->base&0x1FFFFFFF)>>19] = io;
nkeynes@1
   198
    } else {
nkeynes@1
   199
        page_map[io->base>>12] = (char *)num_io_rgns;
nkeynes@1
   200
    }
nkeynes@1
   201
    io_rgn[num_io_rgns] = io;
nkeynes@1
   202
    num_io_rgns++;
nkeynes@1
   203
}
nkeynes@1
   204
nkeynes@1
   205
void register_io_regions( struct mmio_region **io )
nkeynes@1
   206
{
nkeynes@1
   207
    while( *io ) register_io_region( *io++ );
nkeynes@1
   208
}
nkeynes@1
   209
nkeynes@1
   210
#define TRACE_IO( str, p, r, ... ) if(io_rgn[(uint32_t)p]->trace_flag) \
nkeynes@1
   211
TRACE( str " [%s.%s: %s]", __VA_ARGS__, \
nkeynes@1
   212
    MMIO_NAME_BYNUM((uint32_t)p), MMIO_REGID_BYNUM((uint32_t)p, r), \
nkeynes@1
   213
    MMIO_REGDESC_BYNUM((uint32_t)p, r) )
nkeynes@1
   214
nkeynes@1
   215
nkeynes@1
   216
int32_t mem_read_p4( uint32_t addr )
nkeynes@1
   217
{
nkeynes@1
   218
    struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
nkeynes@1
   219
    if( !io ) {
nkeynes@1
   220
        ERROR( "Attempted read from unknown P4 region: %08X", addr );
nkeynes@1
   221
        return 0;
nkeynes@1
   222
    } else {
nkeynes@1
   223
        return io->io_read( addr&0xFFF );
nkeynes@1
   224
    }    
nkeynes@1
   225
}
nkeynes@1
   226
nkeynes@1
   227
void mem_write_p4( uint32_t addr, int32_t val )
nkeynes@1
   228
{
nkeynes@1
   229
    struct mmio_region *io = P4_io[(addr&0x1FFFFFFF)>>19];
nkeynes@1
   230
    if( !io ) {
nkeynes@2
   231
        if( (addr & 0xFC000000) == 0xE0000000 ) {
nkeynes@2
   232
            /* Store queue */
nkeynes@2
   233
            SH4_WRITE_STORE_QUEUE( addr, val );
nkeynes@2
   234
        } else {
nkeynes@2
   235
            ERROR( "Attempted write to unknown P4 region: %08X", addr );
nkeynes@2
   236
        }
nkeynes@1
   237
    } else {
nkeynes@1
   238
        io->io_write( addr&0xFFF, val );
nkeynes@1
   239
    }
nkeynes@1
   240
}
nkeynes@1
   241
nkeynes@1
   242
int mem_has_page( uint32_t addr )
nkeynes@1
   243
{
nkeynes@1
   244
    char *page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@1
   245
    return page != NULL;
nkeynes@1
   246
}
nkeynes@1
   247
nkeynes@1
   248
int32_t mem_read_phys_word( uint32_t addr )
nkeynes@1
   249
{
nkeynes@1
   250
    char *page;
nkeynes@1
   251
    if( addr > 0xE0000000 ) /* P4 Area, handled specially */
nkeynes@1
   252
        return SIGNEXT16(mem_read_p4( addr ));
nkeynes@1
   253
    
nkeynes@2
   254
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@2
   255
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@2
   256
    }
nkeynes@2
   257
nkeynes@1
   258
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@1
   259
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@1
   260
        if( page == NULL ) {
nkeynes@1
   261
            ERROR( "Attempted word read to missing page: %08X",
nkeynes@1
   262
                   addr );
nkeynes@1
   263
            return 0;
nkeynes@1
   264
        }
nkeynes@1
   265
        return SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
nkeynes@1
   266
    } else {
nkeynes@1
   267
        return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
nkeynes@1
   268
    }
nkeynes@1
   269
}
nkeynes@1
   270
nkeynes@1
   271
int32_t mem_read_long( uint32_t addr )
nkeynes@1
   272
{
nkeynes@1
   273
    char *page;
nkeynes@2
   274
    
nkeynes@2
   275
    CHECK_READ_WATCH(addr,4);
nkeynes@2
   276
nkeynes@1
   277
    if( addr > 0xE0000000 ) /* P4 Area, handled specially */
nkeynes@1
   278
        return mem_read_p4( addr );
nkeynes@1
   279
    
nkeynes@2
   280
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@2
   281
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@2
   282
    }
nkeynes@2
   283
nkeynes@1
   284
    if( IS_MMU_ENABLED() ) {
nkeynes@1
   285
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@1
   286
        sh4_stop();
nkeynes@1
   287
        return 0;
nkeynes@1
   288
    }
nkeynes@1
   289
nkeynes@1
   290
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@1
   291
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@1
   292
        int32_t val;
nkeynes@1
   293
        if( page == NULL ) {
nkeynes@1
   294
            ERROR( "Attempted long read to missing page: %08X", addr );
nkeynes@1
   295
            return 0;
nkeynes@1
   296
        }
nkeynes@1
   297
        val = io_rgn[(uint32_t)page]->io_read(addr&0xFFF);
nkeynes@1
   298
        TRACE_IO( "Long read %08X <= %08X", page, (addr&0xFFF), val, addr );
nkeynes@1
   299
        return val;
nkeynes@1
   300
    } else {
nkeynes@1
   301
        return *(int32_t *)(page+(addr&0xFFF));
nkeynes@1
   302
    }
nkeynes@1
   303
}
nkeynes@1
   304
nkeynes@1
   305
int32_t mem_read_word( uint32_t addr )
nkeynes@1
   306
{
nkeynes@1
   307
    char *page;
nkeynes@2
   308
nkeynes@2
   309
    CHECK_READ_WATCH(addr,2);
nkeynes@2
   310
nkeynes@1
   311
    if( addr > 0xE0000000 ) /* P4 Area, handled specially */
nkeynes@1
   312
        return SIGNEXT16(mem_read_p4( addr ));
nkeynes@1
   313
    
nkeynes@2
   314
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@2
   315
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@2
   316
    }
nkeynes@2
   317
nkeynes@1
   318
    if( IS_MMU_ENABLED() ) {
nkeynes@1
   319
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@1
   320
        sh4_stop();
nkeynes@1
   321
        return 0;
nkeynes@1
   322
    }
nkeynes@1
   323
nkeynes@1
   324
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@1
   325
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@1
   326
        int32_t val;
nkeynes@1
   327
        if( page == NULL ) {
nkeynes@1
   328
            ERROR( "Attempted word read to missing page: %08X", addr );
nkeynes@1
   329
            return 0;
nkeynes@1
   330
        }
nkeynes@1
   331
        val = SIGNEXT16(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
nkeynes@1
   332
        TRACE_IO( "Word read %04X <= %08X", page, (addr&0xFFF), val&0xFFFF, addr );
nkeynes@1
   333
        return val;
nkeynes@1
   334
    } else {
nkeynes@1
   335
        return SIGNEXT16(*(int16_t *)(page+(addr&0xFFF)));
nkeynes@1
   336
    }
nkeynes@1
   337
}
nkeynes@1
   338
nkeynes@1
   339
int32_t mem_read_byte( uint32_t addr )
nkeynes@1
   340
{
nkeynes@1
   341
    char *page;
nkeynes@2
   342
nkeynes@2
   343
    CHECK_READ_WATCH(addr,1);
nkeynes@2
   344
nkeynes@1
   345
    if( addr > 0xE0000000 ) /* P4 Area, handled specially */
nkeynes@1
   346
        return SIGNEXT8(mem_read_p4( addr ));
nkeynes@2
   347
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@2
   348
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@2
   349
    }
nkeynes@1
   350
    
nkeynes@1
   351
    if( IS_MMU_ENABLED() ) {
nkeynes@1
   352
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@1
   353
        sh4_stop();
nkeynes@1
   354
        return 0;
nkeynes@1
   355
    }
nkeynes@1
   356
nkeynes@1
   357
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@1
   358
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@1
   359
        int32_t val;
nkeynes@1
   360
        if( page == NULL ) {
nkeynes@1
   361
            ERROR( "Attempted byte read to missing page: %08X", addr );
nkeynes@1
   362
            return 0;
nkeynes@1
   363
        }
nkeynes@1
   364
        val = SIGNEXT8(io_rgn[(uint32_t)page]->io_read(addr&0xFFF));
nkeynes@1
   365
        TRACE_IO( "Byte read %02X <= %08X", page, (addr&0xFFF), val&0xFF, addr );
nkeynes@1
   366
        return val;
nkeynes@1
   367
    } else {
nkeynes@1
   368
        return SIGNEXT8(*(int8_t *)(page+(addr&0xFFF)));
nkeynes@1
   369
    }
nkeynes@1
   370
}
nkeynes@1
   371
nkeynes@1
   372
void mem_write_long( uint32_t addr, uint32_t val )
nkeynes@1
   373
{
nkeynes@1
   374
    char *page;
nkeynes@1
   375
    
nkeynes@2
   376
    CHECK_WRITE_WATCH(addr,4,val);
nkeynes@2
   377
nkeynes@1
   378
    if( addr > 0xE0000000 ) {
nkeynes@1
   379
        mem_write_p4( addr, val );
nkeynes@1
   380
        return;
nkeynes@1
   381
    }
nkeynes@2
   382
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@2
   383
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@1
   384
    }
nkeynes@1
   385
nkeynes@1
   386
    if( IS_MMU_ENABLED() ) {
nkeynes@1
   387
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@1
   388
        sh4_stop();
nkeynes@1
   389
        return;
nkeynes@1
   390
    }
nkeynes@2
   391
    if( (addr&0x1FFFFFFF) < 0x200000 ) {
nkeynes@2
   392
        ERROR( "Attempted write to read-only memory: %08X => %08X", val, addr);
nkeynes@2
   393
        sh4_stop();
nkeynes@2
   394
        return;
nkeynes@2
   395
    }
nkeynes@1
   396
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@1
   397
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@1
   398
        if( page == NULL ) {
nkeynes@1
   399
            ERROR( "Long write to missing page: %08X => %08X", val, addr );
nkeynes@1
   400
            return;
nkeynes@1
   401
        }
nkeynes@1
   402
        TRACE_IO( "Long write %08X => %08X", page, (addr&0xFFF), val, addr );
nkeynes@1
   403
        io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
nkeynes@1
   404
    } else {
nkeynes@1
   405
        *(uint32_t *)(page+(addr&0xFFF)) = val;
nkeynes@1
   406
    }
nkeynes@1
   407
}
nkeynes@1
   408
nkeynes@1
   409
void mem_write_word( uint32_t addr, uint32_t val )
nkeynes@1
   410
{
nkeynes@1
   411
    char *page;
nkeynes@1
   412
nkeynes@2
   413
    CHECK_WRITE_WATCH(addr,2,val);
nkeynes@2
   414
nkeynes@1
   415
    if( addr > 0xE0000000 ) {
nkeynes@1
   416
        mem_write_p4( addr, (int16_t)val );
nkeynes@1
   417
        return;
nkeynes@1
   418
    }
nkeynes@2
   419
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@2
   420
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@2
   421
    }
nkeynes@1
   422
    if( IS_MMU_ENABLED() ) {
nkeynes@1
   423
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@1
   424
        sh4_stop();
nkeynes@1
   425
        return;
nkeynes@1
   426
    }
nkeynes@1
   427
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@1
   428
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@1
   429
        if( page == NULL ) {
nkeynes@1
   430
            ERROR( "Attempted word write to missing page: %08X", addr );
nkeynes@1
   431
            return;
nkeynes@1
   432
        }
nkeynes@1
   433
        TRACE_IO( "Word write %04X => %08X", page, (addr&0xFFF), val&0xFFFF, addr );
nkeynes@1
   434
        io_rgn[(uint32_t)page]->io_write(addr&0xFFF, val);
nkeynes@1
   435
    } else {
nkeynes@1
   436
        *(uint16_t *)(page+(addr&0xFFF)) = val;
nkeynes@1
   437
    }
nkeynes@1
   438
}
nkeynes@1
   439
nkeynes@1
   440
void mem_write_byte( uint32_t addr, uint32_t val )
nkeynes@1
   441
{
nkeynes@1
   442
    char *page;
nkeynes@1
   443
    
nkeynes@2
   444
    CHECK_WRITE_WATCH(addr,1,val);
nkeynes@2
   445
nkeynes@1
   446
    if( addr > 0xE0000000 ) {
nkeynes@1
   447
        mem_write_p4( addr, (int8_t)val );
nkeynes@1
   448
        return;
nkeynes@1
   449
    }
nkeynes@2
   450
    if( (addr&0x1F800000) == 0x04000000 ) {
nkeynes@2
   451
        addr = TRANSLATE_VIDEO_64BIT_ADDRESS(addr);
nkeynes@2
   452
    }
nkeynes@2
   453
    
nkeynes@1
   454
    if( IS_MMU_ENABLED() ) {
nkeynes@1
   455
        ERROR( "user-mode & mmu translation not implemented, aborting", NULL );
nkeynes@1
   456
        sh4_stop();
nkeynes@1
   457
        return;
nkeynes@1
   458
    }
nkeynes@1
   459
    page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@1
   460
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@1
   461
        if( page == NULL ) {
nkeynes@1
   462
            ERROR( "Attempted byte write to missing page: %08X", addr );
nkeynes@1
   463
            return;
nkeynes@1
   464
        }
nkeynes@1
   465
        TRACE_IO( "Byte write %02X => %08X", page, (addr&0xFFF), val&0xFF, addr );
nkeynes@1
   466
        io_rgn[(uint32_t)page]->io_write( (addr&0xFFF), val);
nkeynes@1
   467
    } else {
nkeynes@1
   468
        *(uint8_t *)(page+(addr&0xFFF)) = val;
nkeynes@1
   469
    }
nkeynes@1
   470
}
nkeynes@1
   471
nkeynes@1
   472
char *mem_get_region( uint32_t addr )
nkeynes@1
   473
{
nkeynes@1
   474
    char *page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@1
   475
    if( ((uint32_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@1
   476
        return NULL;
nkeynes@1
   477
    } else {
nkeynes@1
   478
        return page+(addr&0xFFF);
nkeynes@1
   479
    }
nkeynes@1
   480
}
nkeynes@2
   481
nkeynes@2
   482
/* FIXME: Handle all the many special cases when the range doesn't fall cleanly
nkeynes@2
   483
 * into the same memory black
nkeynes@2
   484
 */
nkeynes@2
   485
nkeynes@2
   486
void mem_copy_from_sh4( char *dest, uint32_t srcaddr, size_t count ) {
nkeynes@2
   487
    char *src = mem_get_region(srcaddr);
nkeynes@2
   488
    memcpy( dest, src, count );
nkeynes@2
   489
}
nkeynes@2
   490
nkeynes@2
   491
void mem_copy_to_sh4( uint32_t destaddr, char *src, size_t count ) {
nkeynes@2
   492
    char *dest = mem_get_region(destaddr);
nkeynes@2
   493
    memcpy( dest, src, count );
nkeynes@2
   494
}
.