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 Sat Aug 21 06:15:49 2004 +0000 (16 years ago)
permissions -rw-r--r--
last change Commit changes into cvs
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
}
.