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