Search
lxdream.org :: lxdream/src/mem.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/mem.c
changeset 931:430048ea8b71
prev930:07e5b11419db
next932:2602c5603ce2
author nkeynes
date Tue Dec 23 05:48:05 2008 +0000 (12 years ago)
branchlxdream-mem
permissions -rw-r--r--
last change More refactoring and general cleanup. Most things should be working again now.
Split off cache and start real implementation, breaking save states in the process
file annotate diff log raw
nkeynes@10
     1
/**
nkeynes@586
     2
 * $Id$
nkeynes@10
     3
 * mem.c is responsible for creating and maintaining the overall system memory
nkeynes@10
     4
 * map, as visible from the SH4 processor. 
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@35
    18
#define MODULE mem_module
nkeynes@10
    19
nkeynes@488
    20
#include <sys/types.h>
nkeynes@10
    21
#include <sys/mman.h>
nkeynes@19
    22
#include <sys/stat.h>
nkeynes@586
    23
#include <glib/gstrfuncs.h>
nkeynes@10
    24
#include <assert.h>
nkeynes@10
    25
#include <stdint.h>
nkeynes@10
    26
#include <stdlib.h>
nkeynes@10
    27
#include <stdio.h>
nkeynes@10
    28
#include <unistd.h>
nkeynes@10
    29
#include <fcntl.h>
nkeynes@10
    30
#include <errno.h>
nkeynes@10
    31
#include <string.h>
nkeynes@10
    32
#include <zlib.h>
nkeynes@10
    33
#include "dream.h"
nkeynes@10
    34
#include "mem.h"
nkeynes@10
    35
#include "mmio.h"
nkeynes@10
    36
#include "dreamcast.h"
nkeynes@10
    37
nkeynes@502
    38
sh4ptr_t *page_map = NULL;
nkeynes@930
    39
mem_region_fn_t *ext_address_space = NULL;
nkeynes@930
    40
nkeynes@930
    41
extern struct mem_region_fn mem_region_unmapped; 
nkeynes@10
    42
nkeynes@17
    43
int mem_load(FILE *f);
nkeynes@17
    44
void mem_save(FILE *f);
nkeynes@15
    45
struct dreamcast_module mem_module =
nkeynes@736
    46
{ "MEM", mem_init, mem_reset, NULL, NULL, NULL, mem_save, mem_load };
nkeynes@15
    47
nkeynes@10
    48
struct mem_region mem_rgn[MAX_MEM_REGIONS];
nkeynes@10
    49
struct mmio_region *io_rgn[MAX_IO_REGIONS];
nkeynes@10
    50
struct mmio_region *P4_io[4096];
nkeynes@10
    51
nkeynes@674
    52
uint32_t num_io_rgns = 0, num_mem_rgns = 0;
nkeynes@10
    53
nkeynes@931
    54
DEFINE_HOOK( mem_page_remapped_hook, mem_page_remapped_hook_t );
nkeynes@931
    55
static void mem_page_remapped( sh4addr_t addr, mem_region_fn_t fn )
nkeynes@931
    56
{
nkeynes@931
    57
    CALL_HOOKS( mem_page_remapped_hook, addr, fn );
nkeynes@931
    58
}
nkeynes@931
    59
nkeynes@931
    60
/********************* The "unmapped" address space ********************/
nkeynes@931
    61
/* Always reads as 0, writes have no effect */
nkeynes@931
    62
int32_t FASTCALL unmapped_read_long( sh4addr_t addr )
nkeynes@931
    63
{
nkeynes@931
    64
    return 0;
nkeynes@931
    65
}
nkeynes@931
    66
void FASTCALL unmapped_write_long( sh4addr_t addr, uint32_t val )
nkeynes@931
    67
{
nkeynes@931
    68
}
nkeynes@931
    69
void FASTCALL unmapped_read_burst( unsigned char *dest, sh4addr_t addr )
nkeynes@931
    70
{
nkeynes@931
    71
    memset( dest, 0, 32 );
nkeynes@931
    72
}
nkeynes@931
    73
void FASTCALL unmapped_write_burst( sh4addr_t addr, unsigned char *src )
nkeynes@931
    74
{
nkeynes@931
    75
}
nkeynes@931
    76
nkeynes@931
    77
struct mem_region_fn mem_region_unmapped = { 
nkeynes@931
    78
        unmapped_read_long, unmapped_write_long, 
nkeynes@931
    79
        unmapped_read_long, unmapped_write_long, 
nkeynes@931
    80
        unmapped_read_long, unmapped_write_long, 
nkeynes@931
    81
        unmapped_read_burst, unmapped_write_burst }; 
nkeynes@931
    82
nkeynes@10
    83
void *mem_alloc_pages( int n )
nkeynes@10
    84
{
nkeynes@10
    85
    void *mem = mmap( NULL, n * 4096,
nkeynes@736
    86
            PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0 );
nkeynes@10
    87
    if( mem == MAP_FAILED ) {
nkeynes@10
    88
        ERROR( "Memory allocation failure! (%s)", strerror(errno) );
nkeynes@10
    89
        return NULL;
nkeynes@10
    90
    }
nkeynes@10
    91
    return mem;
nkeynes@10
    92
}
nkeynes@10
    93
nkeynes@10
    94
nkeynes@10
    95
void mem_init( void )
nkeynes@10
    96
{
nkeynes@930
    97
    int i;
nkeynes@930
    98
    mem_region_fn_t *ptr;
nkeynes@796
    99
    page_map = mmap( NULL, sizeof(sh4ptr_t) * LXDREAM_PAGE_TABLE_ENTRIES,
nkeynes@736
   100
            PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0 );
nkeynes@10
   101
    if( page_map == MAP_FAILED ) {
nkeynes@930
   102
        FATAL( "Unable to allocate page map! (%s)", strerror(errno) );
nkeynes@930
   103
    }
nkeynes@930
   104
    memset( page_map, 0, sizeof(sh4ptr_t) * LXDREAM_PAGE_TABLE_ENTRIES );
nkeynes@930
   105
    
nkeynes@930
   106
    ext_address_space = mmap( NULL, sizeof(mem_region_fn_t) * LXDREAM_PAGE_TABLE_ENTRIES,
nkeynes@930
   107
            PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0 );
nkeynes@930
   108
    if( ext_address_space == MAP_FAILED ) {
nkeynes@930
   109
        FATAL( "Unable to allocate external memory map (%s)", strerror(errno) );
nkeynes@10
   110
    }
nkeynes@10
   111
nkeynes@930
   112
    for( ptr = ext_address_space, i = LXDREAM_PAGE_TABLE_ENTRIES; i > 0; ptr++, i-- ) {
nkeynes@930
   113
        *ptr = &mem_region_unmapped;
nkeynes@930
   114
    }
nkeynes@10
   115
}
nkeynes@10
   116
nkeynes@10
   117
void mem_reset( void )
nkeynes@10
   118
{
nkeynes@10
   119
    /* Restore all mmio registers to their initial settings */
nkeynes@10
   120
    int i, j;
nkeynes@10
   121
    for( i=1; i<num_io_rgns; i++ ) {
nkeynes@10
   122
        for( j=0; io_rgn[i]->ports[j].id != NULL; j++ ) {
nkeynes@10
   123
            if( io_rgn[i]->ports[j].def_val != UNDEFINED &&
nkeynes@736
   124
                    io_rgn[i]->ports[j].def_val != *io_rgn[i]->ports[j].val ) {
nkeynes@929
   125
                io_rgn[i]->fn.write_long( io_rgn[i]->ports[j].offset,
nkeynes@736
   126
                        io_rgn[i]->ports[j].def_val );
nkeynes@10
   127
            }
nkeynes@10
   128
        }
nkeynes@10
   129
    }
nkeynes@10
   130
}
nkeynes@10
   131
nkeynes@17
   132
void mem_save( FILE *f ) 
nkeynes@17
   133
{
nkeynes@17
   134
    int i;
nkeynes@17
   135
    uint32_t len;
nkeynes@736
   136
nkeynes@17
   137
    /* All memory regions */
nkeynes@17
   138
    fwrite( &num_mem_rgns, sizeof(num_mem_rgns), 1, f );
nkeynes@17
   139
    for( i=0; i<num_mem_rgns; i++ ) {
nkeynes@736
   140
        fwrite_string( mem_rgn[i].name, f );
nkeynes@736
   141
        fwrite( &mem_rgn[i].base, sizeof(uint32_t), 1, f );
nkeynes@736
   142
        fwrite( &mem_rgn[i].flags, sizeof(uint32_t), 1, f );
nkeynes@736
   143
        fwrite( &mem_rgn[i].size, sizeof(uint32_t), 1, f );
nkeynes@736
   144
        if( mem_rgn[i].flags != MEM_FLAG_ROM )
nkeynes@736
   145
            fwrite_gzip( mem_rgn[i].mem, mem_rgn[i].size, 1, f );
nkeynes@17
   146
    }
nkeynes@17
   147
nkeynes@17
   148
    /* All MMIO regions */
nkeynes@17
   149
    fwrite( &num_io_rgns, sizeof(num_io_rgns), 1, f );
nkeynes@17
   150
    for( i=0; i<num_io_rgns; i++ ) {
nkeynes@736
   151
        fwrite_string( io_rgn[i]->id, f );
nkeynes@736
   152
        fwrite( &io_rgn[i]->base, sizeof( uint32_t ), 1, f );
nkeynes@736
   153
        len = 4096;
nkeynes@736
   154
        fwrite( &len, sizeof(len), 1, f );
nkeynes@736
   155
        fwrite_gzip( io_rgn[i]->mem, len, 1, f );
nkeynes@17
   156
    }
nkeynes@17
   157
}
nkeynes@17
   158
nkeynes@17
   159
int mem_load( FILE *f )
nkeynes@17
   160
{
nkeynes@17
   161
    char tmp[64];
nkeynes@17
   162
    uint32_t len;
nkeynes@18
   163
    uint32_t base, size;
nkeynes@510
   164
    uint32_t flags;
nkeynes@17
   165
    int i;
nkeynes@17
   166
nkeynes@17
   167
    /* All memory regions */
nkeynes@18
   168
    fread( &len, sizeof(len), 1, f );
nkeynes@18
   169
    if( len != num_mem_rgns )
nkeynes@736
   170
        return -1;
nkeynes@18
   171
    for( i=0; i<len; i++ ) {
nkeynes@736
   172
        fread_string( tmp, sizeof(tmp), f );
nkeynes@736
   173
        fread( &base, sizeof(base), 1, f );
nkeynes@736
   174
        fread( &flags, sizeof(flags), 1, f );
nkeynes@736
   175
        fread( &size, sizeof(size), 1, f );
nkeynes@736
   176
        if( strcmp( mem_rgn[i].name, tmp ) != 0 ||
nkeynes@736
   177
                base != mem_rgn[i].base ||
nkeynes@736
   178
                flags != mem_rgn[i].flags ||
nkeynes@736
   179
                size != mem_rgn[i].size ) {
nkeynes@736
   180
            ERROR( "Bad memory region %d %s", i, tmp );
nkeynes@736
   181
            return -1;
nkeynes@736
   182
        }
nkeynes@736
   183
        if( flags != MEM_FLAG_ROM )
nkeynes@736
   184
            fread_gzip( mem_rgn[i].mem, size, 1, f );
nkeynes@18
   185
    }
nkeynes@18
   186
nkeynes@18
   187
    /* All MMIO regions */
nkeynes@18
   188
    fread( &len, sizeof(len), 1, f );
nkeynes@18
   189
    if( len != num_io_rgns ) 
nkeynes@736
   190
        return -1;
nkeynes@18
   191
    for( i=0; i<len; i++ ) {
nkeynes@736
   192
        fread_string( tmp, sizeof(tmp), f );
nkeynes@736
   193
        fread( &base, sizeof(base), 1, f );
nkeynes@736
   194
        fread( &size, sizeof(size), 1, f );
nkeynes@736
   195
        if( strcmp( io_rgn[i]->id, tmp ) != 0 ||
nkeynes@736
   196
                base != io_rgn[i]->base ||
nkeynes@736
   197
                size != 4096 ) {
nkeynes@736
   198
            ERROR( "Bad MMIO region %d %s", i, tmp );
nkeynes@736
   199
            return -1;
nkeynes@736
   200
        }
nkeynes@736
   201
        fread_gzip( io_rgn[i]->mem, size, 1, f );
nkeynes@18
   202
    }
nkeynes@18
   203
    return 0;
nkeynes@17
   204
}
nkeynes@17
   205
nkeynes@50
   206
int mem_save_block( const gchar *file, uint32_t start, uint32_t length )
nkeynes@19
   207
{
nkeynes@502
   208
    sh4ptr_t region;
nkeynes@50
   209
    int len = 4096, total = 0;
nkeynes@50
   210
    uint32_t addr = start;
nkeynes@50
   211
    FILE *f = fopen(file,"w");
nkeynes@19
   212
nkeynes@50
   213
    if( f == NULL )
nkeynes@736
   214
        return errno;
nkeynes@736
   215
nkeynes@50
   216
    while( total < length ) {
nkeynes@736
   217
        region = mem_get_region(addr);
nkeynes@736
   218
        len = 4096 - (addr & 0x0FFF);
nkeynes@736
   219
        if( len > (length-total) ) 
nkeynes@736
   220
            len = (length-total);
nkeynes@736
   221
        if( fwrite( region, len, 1, f ) != 1 ) {
nkeynes@736
   222
            ERROR( "Unexpected error writing blocks: %d (%s)", len, strerror(errno) );
nkeynes@736
   223
            break;
nkeynes@736
   224
        }
nkeynes@736
   225
nkeynes@736
   226
        addr += len;
nkeynes@736
   227
        total += len;
nkeynes@50
   228
    }
nkeynes@50
   229
    fclose( f );
nkeynes@743
   230
    INFO( "Saved %d of %d bytes to %08X", total, length, start );
nkeynes@50
   231
    return 0;
nkeynes@19
   232
}
nkeynes@19
   233
nkeynes@19
   234
int mem_load_block( const gchar *file, uint32_t start, uint32_t length )
nkeynes@19
   235
{
nkeynes@502
   236
    sh4ptr_t region;
nkeynes@19
   237
    int len = 4096, total = 0;
nkeynes@19
   238
    uint32_t addr = start;
nkeynes@19
   239
    struct stat st;
nkeynes@19
   240
    FILE *f = fopen(file,"r");
nkeynes@19
   241
nkeynes@180
   242
    if( f == NULL ) {
nkeynes@736
   243
        WARN( "Unable to load file '%s': %s", file, strerror(errno) );
nkeynes@736
   244
        return -1;
nkeynes@180
   245
    }
nkeynes@19
   246
    fstat( fileno(f), &st );
nkeynes@72
   247
    if( length == 0 || length == -1 || length > st.st_size )
nkeynes@736
   248
        length = st.st_size;
nkeynes@736
   249
nkeynes@19
   250
    while( total < length ) {
nkeynes@736
   251
        region = mem_get_region(addr);
nkeynes@736
   252
        len = 4096 - (addr & 0x0FFF);
nkeynes@736
   253
        if( len > (length-total) ) 
nkeynes@736
   254
            len = (length-total);
nkeynes@736
   255
        if( fread( region, len, 1, f ) != 1 ) {
nkeynes@736
   256
            ERROR( "Unexpected error reading: %d (%s)", len, strerror(errno) );
nkeynes@736
   257
            break;
nkeynes@736
   258
        }
nkeynes@736
   259
nkeynes@736
   260
        addr += len;
nkeynes@736
   261
        total += len;
nkeynes@19
   262
    }
nkeynes@19
   263
    fclose( f );
nkeynes@19
   264
    INFO( "Loaded %d of %d bytes to %08X", total, length, start );
nkeynes@19
   265
    return 0;
nkeynes@19
   266
}
nkeynes@19
   267
nkeynes@10
   268
struct mem_region *mem_map_region( void *mem, uint32_t base, uint32_t size,
nkeynes@929
   269
                                   const char *name, mem_region_fn_t fn, int flags, uint32_t repeat_offset,
nkeynes@736
   270
                                   uint32_t repeat_until )
nkeynes@10
   271
{
nkeynes@10
   272
    int i;
nkeynes@10
   273
    mem_rgn[num_mem_rgns].base = base;
nkeynes@10
   274
    mem_rgn[num_mem_rgns].size = size;
nkeynes@10
   275
    mem_rgn[num_mem_rgns].flags = flags;
nkeynes@10
   276
    mem_rgn[num_mem_rgns].name = name;
nkeynes@10
   277
    mem_rgn[num_mem_rgns].mem = mem;
nkeynes@929
   278
    mem_rgn[num_mem_rgns].fn = fn;
nkeynes@10
   279
    num_mem_rgns++;
nkeynes@10
   280
nkeynes@146
   281
    do {
nkeynes@930
   282
        for( i=0; i<size>>LXDREAM_PAGE_BITS; i++ ) {
nkeynes@796
   283
            page_map[(base>>LXDREAM_PAGE_BITS)+i] = mem + (i<<LXDREAM_PAGE_BITS);
nkeynes@930
   284
            ext_address_space[(base>>LXDREAM_PAGE_BITS)+i] = fn;
nkeynes@931
   285
            mem_page_remapped( base + (i<<LXDREAM_PAGE_BITS), fn );
nkeynes@930
   286
        }
nkeynes@736
   287
        base += repeat_offset;	
nkeynes@146
   288
    } while( base <= repeat_until );
nkeynes@10
   289
nkeynes@10
   290
    return &mem_rgn[num_mem_rgns-1];
nkeynes@10
   291
}
nkeynes@10
   292
nkeynes@931
   293
void register_misc_region( uint32_t base, uint32_t size, const char *name, mem_region_fn_t fn )
nkeynes@931
   294
{
nkeynes@931
   295
    mem_rgn[num_mem_rgns].base = base;
nkeynes@931
   296
    mem_rgn[num_mem_rgns].size = size;
nkeynes@931
   297
    mem_rgn[num_mem_rgns].flags = 0;
nkeynes@931
   298
    mem_rgn[num_mem_rgns].name = name;
nkeynes@931
   299
    mem_rgn[num_mem_rgns].mem = NULL;
nkeynes@931
   300
    mem_rgn[num_mem_rgns].fn = fn;
nkeynes@931
   301
    num_mem_rgns++;
nkeynes@931
   302
nkeynes@931
   303
    int count = size >> 12;
nkeynes@931
   304
    mem_region_fn_t *ptr = &ext_address_space[base>>12];
nkeynes@931
   305
    while( count-- > 0 ) {
nkeynes@931
   306
        *ptr++ = fn;
nkeynes@931
   307
    }
nkeynes@931
   308
}
nkeynes@931
   309
nkeynes@929
   310
void *mem_create_ram_region( uint32_t base, uint32_t size, const char *name, mem_region_fn_t fn )
nkeynes@10
   311
{
nkeynes@929
   312
    return mem_create_repeating_ram_region( base, size, name, fn, size, base );
nkeynes@146
   313
}
nkeynes@146
   314
nkeynes@422
   315
void *mem_create_repeating_ram_region( uint32_t base, uint32_t size, const char *name,
nkeynes@929
   316
                                       mem_region_fn_t fn,
nkeynes@736
   317
                                       uint32_t repeat_offset, uint32_t repeat_until )
nkeynes@146
   318
{
nkeynes@10
   319
    char *mem;
nkeynes@736
   320
nkeynes@10
   321
    assert( (base&0xFFFFF000) == base ); /* must be page aligned */
nkeynes@10
   322
    assert( (size&0x00000FFF) == 0 );
nkeynes@10
   323
    assert( num_mem_rgns < MAX_MEM_REGIONS );
nkeynes@10
   324
    assert( page_map != NULL );
nkeynes@10
   325
nkeynes@796
   326
    mem = mem_alloc_pages( size>>LXDREAM_PAGE_BITS );
nkeynes@10
   327
nkeynes@929
   328
    mem_map_region( mem, base, size, name, fn, MEM_FLAG_RAM, repeat_offset, repeat_until );
nkeynes@736
   329
nkeynes@10
   330
    return mem;
nkeynes@10
   331
}
nkeynes@10
   332
nkeynes@543
   333
gboolean mem_load_rom( const gchar *file, uint32_t base, uint32_t size, uint32_t crc,
nkeynes@929
   334
                       const gchar *region_name, mem_region_fn_t fn )
nkeynes@10
   335
{
nkeynes@502
   336
    sh4ptr_t mem;
nkeynes@10
   337
    uint32_t calc_crc;
nkeynes@488
   338
    int status;
nkeynes@461
   339
nkeynes@461
   340
    mem = mem_get_region(base);
nkeynes@461
   341
    if( mem == NULL ) {
nkeynes@736
   342
        mem = mmap( NULL, size, PROT_WRITE|PROT_READ, MAP_ANON|MAP_PRIVATE, -1, 0 );
nkeynes@736
   343
        if( mem == MAP_FAILED ) {
nkeynes@736
   344
            ERROR( "Unable to allocate ROM memory: %s (%s)", file, strerror(errno) );
nkeynes@736
   345
            return FALSE;
nkeynes@736
   346
        }
nkeynes@929
   347
        mem_map_region( mem, base, size, region_name, fn, MEM_FLAG_ROM, size, base );
nkeynes@461
   348
    } else {
nkeynes@736
   349
        mprotect( mem, size, PROT_READ|PROT_WRITE );
nkeynes@10
   350
    }
nkeynes@461
   351
nkeynes@825
   352
    if( file != NULL && file[0] != '\0' ) {
nkeynes@825
   353
        status = mem_load_block( file, base, size );
nkeynes@825
   354
        mprotect( mem, size, PROT_READ );
nkeynes@10
   355
nkeynes@825
   356
        if( status == 0 ) {
nkeynes@825
   357
            /* CRC check only if we loaded something */
nkeynes@825
   358
            calc_crc = crc32(0L, (sh4ptr_t)mem, size);
nkeynes@825
   359
            if( calc_crc != crc ) {
nkeynes@825
   360
                WARN( "Bios CRC Mismatch in %s: %08X (expected %08X)",
nkeynes@825
   361
                        file, calc_crc, crc);
nkeynes@825
   362
            }
nkeynes@825
   363
            return TRUE;
nkeynes@736
   364
        }
nkeynes@10
   365
    }
nkeynes@543
   366
    return FALSE;
nkeynes@10
   367
}
nkeynes@10
   368
nkeynes@502
   369
sh4ptr_t mem_get_region_by_name( const char *name )
nkeynes@10
   370
{
nkeynes@10
   371
    int i;
nkeynes@10
   372
    for( i=0; i<num_mem_rgns; i++ ) {
nkeynes@10
   373
        if( strcmp( mem_rgn[i].name, name ) == 0 )
nkeynes@10
   374
            return mem_rgn[i].mem;
nkeynes@10
   375
    }
nkeynes@10
   376
    return NULL;
nkeynes@10
   377
}
nkeynes@10
   378
nkeynes@10
   379
void register_io_region( struct mmio_region *io )
nkeynes@10
   380
{
nkeynes@10
   381
    int i;
nkeynes@736
   382
nkeynes@10
   383
    assert(io);
nkeynes@10
   384
    io->mem = mem_alloc_pages(2);
nkeynes@796
   385
    io->save_mem = io->mem + LXDREAM_PAGE_SIZE;
nkeynes@10
   386
    io->index = (struct mmio_port **)malloc(1024*sizeof(struct mmio_port *));
nkeynes@41
   387
    io->trace_flag = 0;
nkeynes@10
   388
    memset( io->index, 0, 1024*sizeof(struct mmio_port *) );
nkeynes@10
   389
    for( i=0; io->ports[i].id != NULL; i++ ) {
nkeynes@10
   390
        io->ports[i].val = (uint32_t *)(io->mem + io->ports[i].offset);
nkeynes@10
   391
        *io->ports[i].val = io->ports[i].def_val;
nkeynes@10
   392
        io->index[io->ports[i].offset>>2] = &io->ports[i];
nkeynes@10
   393
    }
nkeynes@796
   394
    memcpy( io->save_mem, io->mem, LXDREAM_PAGE_SIZE );
nkeynes@10
   395
    if( (io->base & 0xFF000000) == 0xFF000000 ) {
nkeynes@10
   396
        /* P4 area (on-chip I/O channels */
nkeynes@10
   397
        P4_io[(io->base&0x1FFFFFFF)>>19] = io;
nkeynes@10
   398
    } else {
nkeynes@674
   399
        page_map[io->base>>12] = (sh4ptr_t)(uintptr_t)num_io_rgns;
nkeynes@930
   400
        ext_address_space[io->base>>12] = &io->fn;
nkeynes@931
   401
        mem_page_remapped( io->base, &io->fn );
nkeynes@10
   402
    }
nkeynes@10
   403
    io_rgn[num_io_rgns] = io;
nkeynes@10
   404
    num_io_rgns++;
nkeynes@10
   405
}
nkeynes@10
   406
nkeynes@10
   407
void register_io_regions( struct mmio_region **io )
nkeynes@10
   408
{
nkeynes@10
   409
    while( *io ) register_io_region( *io++ );
nkeynes@10
   410
}
nkeynes@10
   411
nkeynes@10
   412
int mem_has_page( uint32_t addr )
nkeynes@10
   413
{
nkeynes@502
   414
    sh4ptr_t page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
   415
    return page != NULL;
nkeynes@10
   416
}
nkeynes@10
   417
nkeynes@502
   418
sh4ptr_t mem_get_page( uint32_t addr )
nkeynes@10
   419
{
nkeynes@502
   420
    sh4ptr_t page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@10
   421
    return page;
nkeynes@10
   422
}
nkeynes@10
   423
nkeynes@502
   424
sh4ptr_t mem_get_region( uint32_t addr )
nkeynes@10
   425
{
nkeynes@502
   426
    sh4ptr_t page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
nkeynes@490
   427
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
nkeynes@10
   428
        return NULL;
nkeynes@10
   429
    } else {
nkeynes@10
   430
        return page+(addr&0xFFF);
nkeynes@10
   431
    }
nkeynes@10
   432
}
nkeynes@11
   433
nkeynes@669
   434
void mem_write_long( sh4addr_t addr, uint32_t value )
nkeynes@669
   435
{
nkeynes@669
   436
    sh4ptr_t ptr = mem_get_region(addr);
nkeynes@669
   437
    assert(ptr != NULL);
nkeynes@669
   438
    *((uint32_t *)ptr) = value;
nkeynes@669
   439
}
nkeynes@669
   440
nkeynes@156
   441
struct mmio_region *mem_get_io_region( uint32_t addr )
nkeynes@156
   442
{
nkeynes@156
   443
    if( addr > 0xFF000000 ) {
nkeynes@736
   444
        return P4_io[(addr&0x00FFFFFF)>>12];
nkeynes@156
   445
    }
nkeynes@502
   446
    sh4ptr_t page = page_map[(addr&0x1FFFFFFF)>>12];
nkeynes@490
   447
    if( ((uintptr_t)page) < MAX_IO_REGIONS ) {
nkeynes@736
   448
        return io_rgn[(uintptr_t)page];
nkeynes@156
   449
    } else {
nkeynes@736
   450
        return NULL;
nkeynes@156
   451
    }
nkeynes@156
   452
}
nkeynes@156
   453
nkeynes@586
   454
struct mmio_region *mem_get_io_region_by_name( const gchar *name )
nkeynes@156
   455
{
nkeynes@586
   456
    int i;
nkeynes@586
   457
    for( i=0; i<num_io_rgns; i++ ) {
nkeynes@736
   458
        if( strcasecmp(io_rgn[i]->id, name) == 0 ) {
nkeynes@736
   459
            return io_rgn[i];
nkeynes@736
   460
        }
nkeynes@586
   461
    }
nkeynes@586
   462
    return NULL;
nkeynes@156
   463
}
nkeynes@156
   464
nkeynes@586
   465
void mem_set_trace( const gchar *tracelist, gboolean flag )
nkeynes@586
   466
{
nkeynes@586
   467
    if( tracelist != NULL ) {
nkeynes@736
   468
        gchar ** tracev = g_strsplit_set( tracelist, ",:; \t\r\n", 0 );
nkeynes@736
   469
        int i;
nkeynes@736
   470
        for( i=0; tracev[i] != NULL; i++ ) {
nkeynes@736
   471
            // Special case "all" - trace everything
nkeynes@736
   472
            if( strcasecmp(tracev[i], "all") == 0 ) {
nkeynes@736
   473
                int j;
nkeynes@736
   474
                for( j=0; j<num_io_rgns; j++ ) {
nkeynes@736
   475
                    io_rgn[j]->trace_flag = flag ? 1 : 0;
nkeynes@736
   476
                }
nkeynes@736
   477
                break;
nkeynes@736
   478
            }
nkeynes@736
   479
            struct mmio_region *region = mem_get_io_region_by_name( tracev[i] );
nkeynes@736
   480
            if( region == NULL ) {
nkeynes@736
   481
                WARN( "Unknown IO region '%s'", tracev[i] );
nkeynes@736
   482
            } else {
nkeynes@736
   483
                region->trace_flag = flag ? 1 : 0;
nkeynes@736
   484
            }
nkeynes@736
   485
        }
nkeynes@736
   486
        g_strfreev( tracev );
nkeynes@586
   487
    }
nkeynes@586
   488
}
nkeynes@586
   489
.