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 (15 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
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         fwrite_string( mem_rgn[i].name, f );
   141         fwrite( &mem_rgn[i].base, sizeof(uint32_t), 1, f );
   142         fwrite( &mem_rgn[i].flags, sizeof(uint32_t), 1, f );
   143         fwrite( &mem_rgn[i].size, sizeof(uint32_t), 1, f );
   144         if( mem_rgn[i].flags != MEM_FLAG_ROM )
   145             fwrite_gzip( mem_rgn[i].mem, mem_rgn[i].size, 1, f );
   146     }
   148     /* All MMIO regions */
   149     fwrite( &num_io_rgns, sizeof(num_io_rgns), 1, f );
   150     for( i=0; i<num_io_rgns; i++ ) {
   151         fwrite_string( io_rgn[i]->id, f );
   152         fwrite( &io_rgn[i]->base, sizeof( uint32_t ), 1, f );
   153         len = 4096;
   154         fwrite( &len, sizeof(len), 1, f );
   155         fwrite_gzip( io_rgn[i]->mem, len, 1, f );
   156     }
   157 }
   159 int mem_load( FILE *f )
   160 {
   161     char tmp[64];
   162     uint32_t len;
   163     uint32_t base, size;
   164     uint32_t flags;
   165     int i;
   167     /* All memory regions */
   168     fread( &len, sizeof(len), 1, f );
   169     if( len != num_mem_rgns )
   170         return -1;
   171     for( i=0; i<len; i++ ) {
   172         fread_string( tmp, sizeof(tmp), f );
   173         fread( &base, sizeof(base), 1, f );
   174         fread( &flags, sizeof(flags), 1, f );
   175         fread( &size, sizeof(size), 1, f );
   176         if( strcmp( mem_rgn[i].name, tmp ) != 0 ||
   177                 base != mem_rgn[i].base ||
   178                 flags != mem_rgn[i].flags ||
   179                 size != mem_rgn[i].size ) {
   180             ERROR( "Bad memory region %d %s", i, tmp );
   181             return -1;
   182         }
   183         if( flags != MEM_FLAG_ROM )
   184             fread_gzip( mem_rgn[i].mem, size, 1, f );
   185     }
   187     /* All MMIO regions */
   188     fread( &len, sizeof(len), 1, f );
   189     if( len != num_io_rgns ) 
   190         return -1;
   191     for( i=0; i<len; i++ ) {
   192         fread_string( tmp, sizeof(tmp), f );
   193         fread( &base, sizeof(base), 1, f );
   194         fread( &size, sizeof(size), 1, f );
   195         if( strcmp( io_rgn[i]->id, tmp ) != 0 ||
   196                 base != io_rgn[i]->base ||
   197                 size != 4096 ) {
   198             ERROR( "Bad MMIO region %d %s", i, tmp );
   199             return -1;
   200         }
   201         fread_gzip( io_rgn[i]->mem, size, 1, f );
   202     }
   203     return 0;
   204 }
   206 int mem_save_block( const gchar *file, uint32_t start, uint32_t length )
   207 {
   208     sh4ptr_t region;
   209     int len = 4096, total = 0;
   210     uint32_t addr = start;
   211     FILE *f = fopen(file,"w");
   213     if( f == NULL )
   214         return errno;
   216     while( total < length ) {
   217         region = mem_get_region(addr);
   218         len = 4096 - (addr & 0x0FFF);
   219         if( len > (length-total) ) 
   220             len = (length-total);
   221         if( fwrite( region, len, 1, f ) != 1 ) {
   222             ERROR( "Unexpected error writing blocks: %d (%s)", len, strerror(errno) );
   223             break;
   224         }
   226         addr += len;
   227         total += len;
   228     }
   229     fclose( f );
   230     INFO( "Saved %d of %d bytes to %08X", total, length, start );
   231     return 0;
   232 }
   234 int mem_load_block( const gchar *file, uint32_t start, uint32_t length )
   235 {
   236     sh4ptr_t region;
   237     int len = 4096, total = 0;
   238     uint32_t addr = start;
   239     struct stat st;
   240     FILE *f = fopen(file,"r");
   242     if( f == NULL ) {
   243         WARN( "Unable to load file '%s': %s", file, strerror(errno) );
   244         return -1;
   245     }
   246     fstat( fileno(f), &st );
   247     if( length == 0 || length == -1 || length > st.st_size )
   248         length = st.st_size;
   250     while( total < length ) {
   251         region = mem_get_region(addr);
   252         len = 4096 - (addr & 0x0FFF);
   253         if( len > (length-total) ) 
   254             len = (length-total);
   255         if( fread( region, len, 1, f ) != 1 ) {
   256             ERROR( "Unexpected error reading: %d (%s)", len, strerror(errno) );
   257             break;
   258         }
   260         addr += len;
   261         total += len;
   262     }
   263     fclose( f );
   264     INFO( "Loaded %d of %d bytes to %08X", total, length, start );
   265     return 0;
   266 }
   268 struct mem_region *mem_map_region( void *mem, uint32_t base, uint32_t size,
   269                                    const char *name, mem_region_fn_t fn, int flags, uint32_t repeat_offset,
   270                                    uint32_t repeat_until )
   271 {
   272     int i;
   273     mem_rgn[num_mem_rgns].base = base;
   274     mem_rgn[num_mem_rgns].size = size;
   275     mem_rgn[num_mem_rgns].flags = flags;
   276     mem_rgn[num_mem_rgns].name = name;
   277     mem_rgn[num_mem_rgns].mem = mem;
   278     mem_rgn[num_mem_rgns].fn = fn;
   279     num_mem_rgns++;
   281     do {
   282         for( i=0; i<size>>LXDREAM_PAGE_BITS; i++ ) {
   283             page_map[(base>>LXDREAM_PAGE_BITS)+i] = mem + (i<<LXDREAM_PAGE_BITS);
   284             ext_address_space[(base>>LXDREAM_PAGE_BITS)+i] = fn;
   285             mem_page_remapped( base + (i<<LXDREAM_PAGE_BITS), fn );
   286         }
   287         base += repeat_offset;	
   288     } while( base <= repeat_until );
   290     return &mem_rgn[num_mem_rgns-1];
   291 }
   293 void register_misc_region( uint32_t base, uint32_t size, const char *name, mem_region_fn_t fn )
   294 {
   295     mem_rgn[num_mem_rgns].base = base;
   296     mem_rgn[num_mem_rgns].size = size;
   297     mem_rgn[num_mem_rgns].flags = 0;
   298     mem_rgn[num_mem_rgns].name = name;
   299     mem_rgn[num_mem_rgns].mem = NULL;
   300     mem_rgn[num_mem_rgns].fn = fn;
   301     num_mem_rgns++;
   303     int count = size >> 12;
   304     mem_region_fn_t *ptr = &ext_address_space[base>>12];
   305     while( count-- > 0 ) {
   306         *ptr++ = fn;
   307     }
   308 }
   310 void *mem_create_ram_region( uint32_t base, uint32_t size, const char *name, mem_region_fn_t fn )
   311 {
   312     return mem_create_repeating_ram_region( base, size, name, fn, size, base );
   313 }
   315 void *mem_create_repeating_ram_region( uint32_t base, uint32_t size, const char *name,
   316                                        mem_region_fn_t fn,
   317                                        uint32_t repeat_offset, uint32_t repeat_until )
   318 {
   319     char *mem;
   321     assert( (base&0xFFFFF000) == base ); /* must be page aligned */
   322     assert( (size&0x00000FFF) == 0 );
   323     assert( num_mem_rgns < MAX_MEM_REGIONS );
   324     assert( page_map != NULL );
   326     mem = mem_alloc_pages( size>>LXDREAM_PAGE_BITS );
   328     mem_map_region( mem, base, size, name, fn, MEM_FLAG_RAM, repeat_offset, repeat_until );
   330     return mem;
   331 }
   333 gboolean mem_load_rom( const gchar *file, uint32_t base, uint32_t size, uint32_t crc,
   334                        const gchar *region_name, mem_region_fn_t fn )
   335 {
   336     sh4ptr_t mem;
   337     uint32_t calc_crc;
   338     int status;
   340     mem = mem_get_region(base);
   341     if( mem == NULL ) {
   342         mem = mmap( NULL, size, PROT_WRITE|PROT_READ, MAP_ANON|MAP_PRIVATE, -1, 0 );
   343         if( mem == MAP_FAILED ) {
   344             ERROR( "Unable to allocate ROM memory: %s (%s)", file, strerror(errno) );
   345             return FALSE;
   346         }
   347         mem_map_region( mem, base, size, region_name, fn, MEM_FLAG_ROM, size, base );
   348     } else {
   349         mprotect( mem, size, PROT_READ|PROT_WRITE );
   350     }
   352     if( file != NULL && file[0] != '\0' ) {
   353         status = mem_load_block( file, base, size );
   354         mprotect( mem, size, PROT_READ );
   356         if( status == 0 ) {
   357             /* CRC check only if we loaded something */
   358             calc_crc = crc32(0L, (sh4ptr_t)mem, size);
   359             if( calc_crc != crc ) {
   360                 WARN( "Bios CRC Mismatch in %s: %08X (expected %08X)",
   361                         file, calc_crc, crc);
   362             }
   363             return TRUE;
   364         }
   365     }
   366     return FALSE;
   367 }
   369 sh4ptr_t mem_get_region_by_name( const char *name )
   370 {
   371     int i;
   372     for( i=0; i<num_mem_rgns; i++ ) {
   373         if( strcmp( mem_rgn[i].name, name ) == 0 )
   374             return mem_rgn[i].mem;
   375     }
   376     return NULL;
   377 }
   379 void register_io_region( struct mmio_region *io )
   380 {
   381     int i;
   383     assert(io);
   384     io->mem = mem_alloc_pages(2);
   385     io->save_mem = io->mem + LXDREAM_PAGE_SIZE;
   386     io->index = (struct mmio_port **)malloc(1024*sizeof(struct mmio_port *));
   387     io->trace_flag = 0;
   388     memset( io->index, 0, 1024*sizeof(struct mmio_port *) );
   389     for( i=0; io->ports[i].id != NULL; i++ ) {
   390         io->ports[i].val = (uint32_t *)(io->mem + io->ports[i].offset);
   391         *io->ports[i].val = io->ports[i].def_val;
   392         io->index[io->ports[i].offset>>2] = &io->ports[i];
   393     }
   394     memcpy( io->save_mem, io->mem, LXDREAM_PAGE_SIZE );
   395     if( (io->base & 0xFF000000) == 0xFF000000 ) {
   396         /* P4 area (on-chip I/O channels */
   397         P4_io[(io->base&0x1FFFFFFF)>>19] = io;
   398     } else {
   399         page_map[io->base>>12] = (sh4ptr_t)(uintptr_t)num_io_rgns;
   400         ext_address_space[io->base>>12] = &io->fn;
   401         mem_page_remapped( io->base, &io->fn );
   402     }
   403     io_rgn[num_io_rgns] = io;
   404     num_io_rgns++;
   405 }
   407 void register_io_regions( struct mmio_region **io )
   408 {
   409     while( *io ) register_io_region( *io++ );
   410 }
   412 int mem_has_page( uint32_t addr )
   413 {
   414     sh4ptr_t page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   415     return page != NULL;
   416 }
   418 sh4ptr_t mem_get_page( uint32_t addr )
   419 {
   420     sh4ptr_t page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   421     return page;
   422 }
   424 sh4ptr_t mem_get_region( uint32_t addr )
   425 {
   426     sh4ptr_t page = page_map[ (addr & 0x1FFFFFFF) >> 12 ];
   427     if( ((uintptr_t)page) < MAX_IO_REGIONS ) { /* IO Region */
   428         return NULL;
   429     } else {
   430         return page+(addr&0xFFF);
   431     }
   432 }
   434 void mem_write_long( sh4addr_t addr, uint32_t value )
   435 {
   436     sh4ptr_t ptr = mem_get_region(addr);
   437     assert(ptr != NULL);
   438     *((uint32_t *)ptr) = value;
   439 }
   441 struct mmio_region *mem_get_io_region( uint32_t addr )
   442 {
   443     if( addr > 0xFF000000 ) {
   444         return P4_io[(addr&0x00FFFFFF)>>12];
   445     }
   446     sh4ptr_t page = page_map[(addr&0x1FFFFFFF)>>12];
   447     if( ((uintptr_t)page) < MAX_IO_REGIONS ) {
   448         return io_rgn[(uintptr_t)page];
   449     } else {
   450         return NULL;
   451     }
   452 }
   454 struct mmio_region *mem_get_io_region_by_name( const gchar *name )
   455 {
   456     int i;
   457     for( i=0; i<num_io_rgns; i++ ) {
   458         if( strcasecmp(io_rgn[i]->id, name) == 0 ) {
   459             return io_rgn[i];
   460         }
   461     }
   462     return NULL;
   463 }
   465 void mem_set_trace( const gchar *tracelist, gboolean flag )
   466 {
   467     if( tracelist != NULL ) {
   468         gchar ** tracev = g_strsplit_set( tracelist, ",:; \t\r\n", 0 );
   469         int i;
   470         for( i=0; tracev[i] != NULL; i++ ) {
   471             // Special case "all" - trace everything
   472             if( strcasecmp(tracev[i], "all") == 0 ) {
   473                 int j;
   474                 for( j=0; j<num_io_rgns; j++ ) {
   475                     io_rgn[j]->trace_flag = flag ? 1 : 0;
   476                 }
   477                 break;
   478             }
   479             struct mmio_region *region = mem_get_io_region_by_name( tracev[i] );
   480             if( region == NULL ) {
   481                 WARN( "Unknown IO region '%s'", tracev[i] );
   482             } else {
   483                 region->trace_flag = flag ? 1 : 0;
   484             }
   485         }
   486         g_strfreev( tracev );
   487     }
   488 }
.