Search
lxdream.org :: lxdream/src/mem.c :: diff
lxdream 0.9.1
released Jun 29
Download Now
filename src/mem.c
changeset 953:f4a156508ad1
prev825:2ac7ceccd775
next959:f6b45ab24349
author nkeynes
date Tue Jan 13 11:56:28 2009 +0000 (13 years ago)
permissions -rw-r--r--
last change Merge lxdream-mem branch back to trunk
file annotate diff log raw
1.1 --- a/src/mem.c Sun Aug 24 01:58:09 2008 +0000
1.2 +++ b/src/mem.c Tue Jan 13 11:56:28 2009 +0000
1.3 @@ -35,7 +35,14 @@
1.4 #include "mmio.h"
1.5 #include "dreamcast.h"
1.6
1.7 +#ifndef PAGE_SIZE
1.8 +#define PAGE_SIZE 4096
1.9 +#endif
1.10 +
1.11 sh4ptr_t *page_map = NULL;
1.12 +mem_region_fn_t *ext_address_space = NULL;
1.13 +
1.14 +extern struct mem_region_fn mem_region_unmapped;
1.15
1.16 int mem_load(FILE *f);
1.17 void mem_save(FILE *f);
1.18 @@ -48,6 +55,41 @@
1.19
1.20 uint32_t num_io_rgns = 0, num_mem_rgns = 0;
1.21
1.22 +DEFINE_HOOK( mem_page_remapped_hook, mem_page_remapped_hook_t );
1.23 +static void mem_page_remapped( sh4addr_t addr, mem_region_fn_t fn )
1.24 +{
1.25 + CALL_HOOKS( mem_page_remapped_hook, addr, fn );
1.26 +}
1.27 +
1.28 +/********************* The "unmapped" address space ********************/
1.29 +/* Always reads as 0, writes have no effect */
1.30 +int32_t FASTCALL unmapped_read_long( sh4addr_t addr )
1.31 +{
1.32 + return 0;
1.33 +}
1.34 +void FASTCALL unmapped_write_long( sh4addr_t addr, uint32_t val )
1.35 +{
1.36 +}
1.37 +void FASTCALL unmapped_read_burst( unsigned char *dest, sh4addr_t addr )
1.38 +{
1.39 + memset( dest, 0, 32 );
1.40 +}
1.41 +void FASTCALL unmapped_write_burst( sh4addr_t addr, unsigned char *src )
1.42 +{
1.43 +}
1.44 +
1.45 +void FASTCALL unmapped_prefetch( sh4addr_t addr )
1.46 +{
1.47 + /* No effect */
1.48 +}
1.49 +
1.50 +struct mem_region_fn mem_region_unmapped = {
1.51 + unmapped_read_long, unmapped_write_long,
1.52 + unmapped_read_long, unmapped_write_long,
1.53 + unmapped_read_long, unmapped_write_long,
1.54 + unmapped_read_burst, unmapped_write_burst,
1.55 + unmapped_prefetch };
1.56 +
1.57 void *mem_alloc_pages( int n )
1.58 {
1.59 void *mem = mmap( NULL, n * 4096,
1.60 @@ -59,18 +101,39 @@
1.61 return mem;
1.62 }
1.63
1.64 +void mem_unprotect( void *region, uint32_t size )
1.65 +{
1.66 + /* Force page alignment */
1.67 + uintptr_t i = (uintptr_t)region;
1.68 + uintptr_t mask = ~(PAGE_SIZE-1);
1.69 + void *ptr = (void *)(i & mask);
1.70 + size_t len = i & (PAGE_SIZE-1) + size;
1.71 + len = (len + (PAGE_SIZE-1)) & mask;
1.72 +
1.73 + int status = mprotect( ptr, len, PROT_READ|PROT_WRITE|PROT_EXEC );
1.74 + assert( status == 0 );
1.75 +}
1.76
1.77 void mem_init( void )
1.78 {
1.79 + int i;
1.80 + mem_region_fn_t *ptr;
1.81 page_map = mmap( NULL, sizeof(sh4ptr_t) * LXDREAM_PAGE_TABLE_ENTRIES,
1.82 PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0 );
1.83 if( page_map == MAP_FAILED ) {
1.84 - ERROR( "Unable to allocate page map! (%s)", strerror(errno) );
1.85 - page_map = NULL;
1.86 - return;
1.87 + FATAL( "Unable to allocate page map! (%s)", strerror(errno) );
1.88 + }
1.89 + memset( page_map, 0, sizeof(sh4ptr_t) * LXDREAM_PAGE_TABLE_ENTRIES );
1.90 +
1.91 + ext_address_space = mmap( NULL, sizeof(mem_region_fn_t) * LXDREAM_PAGE_TABLE_ENTRIES,
1.92 + PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0 );
1.93 + if( ext_address_space == MAP_FAILED ) {
1.94 + FATAL( "Unable to allocate external memory map (%s)", strerror(errno) );
1.95 }
1.96
1.97 - memset( page_map, 0, sizeof(sh4ptr_t) * LXDREAM_PAGE_TABLE_ENTRIES );
1.98 + for( ptr = ext_address_space, i = LXDREAM_PAGE_TABLE_ENTRIES; i > 0; ptr++, i-- ) {
1.99 + *ptr = &mem_region_unmapped;
1.100 + }
1.101 }
1.102
1.103 void mem_reset( void )
1.104 @@ -81,7 +144,7 @@
1.105 for( j=0; io_rgn[i]->ports[j].id != NULL; j++ ) {
1.106 if( io_rgn[i]->ports[j].def_val != UNDEFINED &&
1.107 io_rgn[i]->ports[j].def_val != *io_rgn[i]->ports[j].val ) {
1.108 - io_rgn[i]->io_write( io_rgn[i]->ports[j].offset,
1.109 + io_rgn[i]->fn.write_long( io_rgn[i]->ports[j].offset,
1.110 io_rgn[i]->ports[j].def_val );
1.111 }
1.112 }
1.113 @@ -90,18 +153,26 @@
1.114
1.115 void mem_save( FILE *f )
1.116 {
1.117 - int i;
1.118 + int i, num_ram_regions = 0;
1.119 uint32_t len;
1.120
1.121 - /* All memory regions */
1.122 - fwrite( &num_mem_rgns, sizeof(num_mem_rgns), 1, f );
1.123 + /* All RAM regions (ROM and non-memory regions don't need to be saved)
1.124 + * Flash is questionable - for now we save it too */
1.125 for( i=0; i<num_mem_rgns; i++ ) {
1.126 - fwrite_string( mem_rgn[i].name, f );
1.127 - fwrite( &mem_rgn[i].base, sizeof(uint32_t), 1, f );
1.128 - fwrite( &mem_rgn[i].flags, sizeof(uint32_t), 1, f );
1.129 - fwrite( &mem_rgn[i].size, sizeof(uint32_t), 1, f );
1.130 - if( mem_rgn[i].flags != MEM_FLAG_ROM )
1.131 + if( mem_rgn[i].flags == MEM_FLAG_RAM ) {
1.132 + num_ram_regions++;
1.133 + }
1.134 + }
1.135 + fwrite( &num_ram_regions, sizeof(num_ram_regions), 1, f );
1.136 +
1.137 + for( i=0; i<num_mem_rgns; i++ ) {
1.138 + if( mem_rgn[i].flags == MEM_FLAG_RAM ) {
1.139 + fwrite_string( mem_rgn[i].name, f );
1.140 + fwrite( &mem_rgn[i].base, sizeof(uint32_t), 1, f );
1.141 + fwrite( &mem_rgn[i].flags, sizeof(uint32_t), 1, f );
1.142 + fwrite( &mem_rgn[i].size, sizeof(uint32_t), 1, f );
1.143 fwrite_gzip( mem_rgn[i].mem, mem_rgn[i].size, 1, f );
1.144 + }
1.145 }
1.146
1.147 /* All MMIO regions */
1.148 @@ -121,32 +192,51 @@
1.149 uint32_t len;
1.150 uint32_t base, size;
1.151 uint32_t flags;
1.152 - int i;
1.153 + int i, j;
1.154 + int mem_region_loaded[MAX_MEM_REGIONS];
1.155
1.156 - /* All memory regions */
1.157 + /* All RAM regions */
1.158 + memset( mem_region_loaded, 0, sizeof(mem_region_loaded) );
1.159 fread( &len, sizeof(len), 1, f );
1.160 - if( len != num_mem_rgns )
1.161 - return -1;
1.162 for( i=0; i<len; i++ ) {
1.163 fread_string( tmp, sizeof(tmp), f );
1.164 - fread( &base, sizeof(base), 1, f );
1.165 - fread( &flags, sizeof(flags), 1, f );
1.166 - fread( &size, sizeof(size), 1, f );
1.167 - if( strcmp( mem_rgn[i].name, tmp ) != 0 ||
1.168 - base != mem_rgn[i].base ||
1.169 - flags != mem_rgn[i].flags ||
1.170 - size != mem_rgn[i].size ) {
1.171 - ERROR( "Bad memory region %d %s", i, tmp );
1.172 +
1.173 + for( j=0; j<num_mem_rgns; j++ ) {
1.174 + if( strcasecmp( mem_rgn[j].name, tmp ) == 0 ) {
1.175 + fread( &base, sizeof(base), 1, f );
1.176 + fread( &flags, sizeof(flags), 1, f );
1.177 + fread( &size, sizeof(size), 1, f );
1.178 + if( base != mem_rgn[j].base ||
1.179 + flags != mem_rgn[j].flags ||
1.180 + size != mem_rgn[j].size ) {
1.181 + ERROR( "Bad memory block %d %s (not mapped to expected region)", i, tmp );
1.182 + return -1;
1.183 + }
1.184 + if( flags != MEM_FLAG_RAM ) {
1.185 + ERROR( "Unexpected memory block %d %s (Not a RAM region)", i, tmp );
1.186 + return -1;
1.187 + }
1.188 + fread_gzip( mem_rgn[j].mem, size, 1, f );
1.189 + mem_region_loaded[j] = 1;
1.190 + }
1.191 + }
1.192 + }
1.193 + /* Make sure we got all the memory regions we expected */
1.194 + for( i=0; i<num_mem_rgns; i++ ) {
1.195 + if( mem_rgn[i].flags == MEM_FLAG_RAM &&
1.196 + mem_region_loaded[i] == 0 ) {
1.197 + ERROR( "Missing memory block %s (not found in save state)", mem_rgn[i].name );
1.198 return -1;
1.199 }
1.200 - if( flags != MEM_FLAG_ROM )
1.201 - fread_gzip( mem_rgn[i].mem, size, 1, f );
1.202 }
1.203
1.204 /* All MMIO regions */
1.205 fread( &len, sizeof(len), 1, f );
1.206 - if( len != num_io_rgns )
1.207 + if( len != num_io_rgns ) {
1.208 + ERROR( "Unexpected IO region count %d (expected %d)", len, num_io_rgns );
1.209 return -1;
1.210 + }
1.211 +
1.212 for( i=0; i<len; i++ ) {
1.213 fread_string( tmp, sizeof(tmp), f );
1.214 fread( &base, sizeof(base), 1, f );
1.215 @@ -225,8 +315,8 @@
1.216 }
1.217
1.218 struct mem_region *mem_map_region( void *mem, uint32_t base, uint32_t size,
1.219 - const char *name, int flags, uint32_t repeat_offset,
1.220 - uint32_t repeat_until )
1.221 + const char *name, mem_region_fn_t fn, int flags,
1.222 + uint32_t repeat_offset, uint32_t repeat_until )
1.223 {
1.224 int i;
1.225 mem_rgn[num_mem_rgns].base = base;
1.226 @@ -234,71 +324,57 @@
1.227 mem_rgn[num_mem_rgns].flags = flags;
1.228 mem_rgn[num_mem_rgns].name = name;
1.229 mem_rgn[num_mem_rgns].mem = mem;
1.230 + mem_rgn[num_mem_rgns].fn = fn;
1.231 + fn->prefetch = unmapped_prefetch;
1.232 num_mem_rgns++;
1.233
1.234 do {
1.235 - for( i=0; i<size>>LXDREAM_PAGE_BITS; i++ )
1.236 - page_map[(base>>LXDREAM_PAGE_BITS)+i] = mem + (i<<LXDREAM_PAGE_BITS);
1.237 + for( i=0; i<size>>LXDREAM_PAGE_BITS; i++ ) {
1.238 + if( mem != NULL ) {
1.239 + page_map[(base>>LXDREAM_PAGE_BITS)+i] = mem + (i<<LXDREAM_PAGE_BITS);
1.240 + }
1.241 + ext_address_space[(base>>LXDREAM_PAGE_BITS)+i] = fn;
1.242 + mem_page_remapped( base + (i<<LXDREAM_PAGE_BITS), fn );
1.243 + }
1.244 base += repeat_offset;
1.245 } while( base <= repeat_until );
1.246
1.247 return &mem_rgn[num_mem_rgns-1];
1.248 }
1.249
1.250 -void *mem_create_ram_region( uint32_t base, uint32_t size, const char *name )
1.251 +gboolean mem_load_rom( void *output, const gchar *file, uint32_t size, uint32_t crc )
1.252 {
1.253 - return mem_create_repeating_ram_region( base, size, name, size, base );
1.254 -}
1.255 + if( file != NULL && file[0] != '\0' ) {
1.256 + FILE *f = fopen(file,"r");
1.257 + struct stat st;
1.258 + uint32_t calc_crc;
1.259
1.260 -void *mem_create_repeating_ram_region( uint32_t base, uint32_t size, const char *name,
1.261 - uint32_t repeat_offset, uint32_t repeat_until )
1.262 -{
1.263 - char *mem;
1.264 -
1.265 - assert( (base&0xFFFFF000) == base ); /* must be page aligned */
1.266 - assert( (size&0x00000FFF) == 0 );
1.267 - assert( num_mem_rgns < MAX_MEM_REGIONS );
1.268 - assert( page_map != NULL );
1.269 -
1.270 - mem = mem_alloc_pages( size>>LXDREAM_PAGE_BITS );
1.271 -
1.272 - mem_map_region( mem, base, size, name, MEM_FLAG_RAM, repeat_offset, repeat_until );
1.273 -
1.274 - return mem;
1.275 -}
1.276 -
1.277 -gboolean mem_load_rom( const gchar *file, uint32_t base, uint32_t size, uint32_t crc,
1.278 - const gchar *region_name )
1.279 -{
1.280 - sh4ptr_t mem;
1.281 - uint32_t calc_crc;
1.282 - int status;
1.283 -
1.284 - mem = mem_get_region(base);
1.285 - if( mem == NULL ) {
1.286 - mem = mmap( NULL, size, PROT_WRITE|PROT_READ, MAP_ANON|MAP_PRIVATE, -1, 0 );
1.287 - if( mem == MAP_FAILED ) {
1.288 - ERROR( "Unable to allocate ROM memory: %s (%s)", file, strerror(errno) );
1.289 + if( f == NULL ) {
1.290 + ERROR( "Unable to load file '%s': %s", file, strerror(errno) );
1.291 return FALSE;
1.292 }
1.293 - mem_map_region( mem, base, size, region_name, MEM_FLAG_ROM, size, base );
1.294 - } else {
1.295 - mprotect( mem, size, PROT_READ|PROT_WRITE );
1.296 - }
1.297
1.298 - if( file != NULL && file[0] != '\0' ) {
1.299 - status = mem_load_block( file, base, size );
1.300 - mprotect( mem, size, PROT_READ );
1.301 + fstat( fileno(f), &st );
1.302 + if( st.st_size != size ) {
1.303 + ERROR( "File '%s' is invalid, expected %d bytes but was %d bytes long.", file, size, st.st_size );
1.304 + fclose(f);
1.305 + return FALSE;
1.306 + }
1.307 +
1.308 + if( fread( output, 1, size, f ) != size ) {
1.309 + ERROR( "Failed to load file '%s': %s", file, strerror(errno) );
1.310 + fclose(f);
1.311 + return FALSE;
1.312 + }
1.313
1.314 - if( status == 0 ) {
1.315 - /* CRC check only if we loaded something */
1.316 - calc_crc = crc32(0L, (sh4ptr_t)mem, size);
1.317 - if( calc_crc != crc ) {
1.318 - WARN( "Bios CRC Mismatch in %s: %08X (expected %08X)",
1.319 - file, calc_crc, crc);
1.320 - }
1.321 - return TRUE;
1.322 + /* CRC check only if we loaded something */
1.323 + calc_crc = crc32(0L, output, size);
1.324 + if( calc_crc != crc ) {
1.325 + WARN( "Bios CRC Mismatch in %s: %08X (expected %08X)",
1.326 + file, calc_crc, crc);
1.327 }
1.328 + /* Even if the CRC fails, continue normally */
1.329 + return TRUE;
1.330 }
1.331 return FALSE;
1.332 }
1.333 @@ -334,6 +410,8 @@
1.334 P4_io[(io->base&0x1FFFFFFF)>>19] = io;
1.335 } else {
1.336 page_map[io->base>>12] = (sh4ptr_t)(uintptr_t)num_io_rgns;
1.337 + ext_address_space[io->base>>12] = &io->fn;
1.338 + mem_page_remapped( io->base, &io->fn );
1.339 }
1.340 io_rgn[num_io_rgns] = io;
1.341 num_io_rgns++;
1.342 @@ -344,16 +422,9 @@
1.343 while( *io ) register_io_region( *io++ );
1.344 }
1.345
1.346 -int mem_has_page( uint32_t addr )
1.347 +gboolean mem_has_page( uint32_t addr )
1.348 {
1.349 - sh4ptr_t page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.350 - return page != NULL;
1.351 -}
1.352 -
1.353 -sh4ptr_t mem_get_page( uint32_t addr )
1.354 -{
1.355 - sh4ptr_t page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
1.356 - return page;
1.357 + return ext_address_space[ (addr&0x1FFFFFFF)>>12 ] != &mem_region_unmapped;
1.358 }
1.359
1.360 sh4ptr_t mem_get_region( uint32_t addr )
1.361 @@ -368,22 +439,7 @@
1.362
1.363 void mem_write_long( sh4addr_t addr, uint32_t value )
1.364 {
1.365 - sh4ptr_t ptr = mem_get_region(addr);
1.366 - assert(ptr != NULL);
1.367 - *((uint32_t *)ptr) = value;
1.368 -}
1.369 -
1.370 -struct mmio_region *mem_get_io_region( uint32_t addr )
1.371 -{
1.372 - if( addr > 0xFF000000 ) {
1.373 - return P4_io[(addr&0x00FFFFFF)>>12];
1.374 - }
1.375 - sh4ptr_t page = page_map[(addr&0x1FFFFFFF)>>12];
1.376 - if( ((uintptr_t)page) < MAX_IO_REGIONS ) {
1.377 - return io_rgn[(uintptr_t)page];
1.378 - } else {
1.379 - return NULL;
1.380 - }
1.381 + ext_address_space[(addr&0x1FFFFFFF)>>12]->write_long(addr, value);
1.382 }
1.383
1.384 struct mmio_region *mem_get_io_region_by_name( const gchar *name )
.