Search
lxdream.org :: lxdream/src/dreamcast.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/dreamcast.c
changeset 929:fd8cb0c82f5f
prev892:126aa7db6162
next930:07e5b11419db
author nkeynes
date Sat Dec 20 03:01:40 2008 +0000 (12 years ago)
branchlxdream-mem
permissions -rw-r--r--
last change First pass experiment using cached decoding.
view annotate diff log raw
     1 /**
     2  * $Id$
     3  * Central switchboard for the system. This pulls all the individual modules
     4  * together into some kind of coherent structure. This is also where you'd
     5  * add Naomi support, if I ever get a board to play with...
     6  *
     7  * Copyright (c) 2005 Nathan Keynes.
     8  *
     9  * This program is free software; you can redistribute it and/or modify
    10  * it under the terms of the GNU General Public License as published by
    11  * the Free Software Foundation; either version 2 of the License, or
    12  * (at your option) any later version.
    13  *
    14  * This program is distributed in the hope that it will be useful,
    15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
    16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    17  * GNU General Public License for more details.
    18  */
    20 #include <errno.h>
    21 #include <glib.h>
    22 #include "lxdream.h"
    23 #include "dream.h"
    24 #include "mem.h"
    25 #include "dreamcast.h"
    26 #include "asic.h"
    27 #include "syscall.h"
    28 #include "gui.h"
    29 #include "aica/aica.h"
    30 #include "gdrom/ide.h"
    31 #include "maple/maple.h"
    32 #include "sh4/sh4.h"
    33 #include "sh4/sh4core.h"
    35 /**
    36  * Current state of the DC virtual machine
    37  */
    38 typedef enum { STATE_UNINIT=0, STATE_RUNNING, 
    39                STATE_STOPPING, STATE_STOPPED } dreamcast_state_t;
    41 static volatile dreamcast_state_t dreamcast_state = STATE_UNINIT;
    42 static gboolean dreamcast_has_bios = FALSE;
    43 static gboolean dreamcast_has_flash = FALSE;
    44 static gboolean dreamcast_exit_on_stop = FALSE;
    45 static gchar *dreamcast_program_name = NULL;
    46 static sh4addr_t dreamcast_entry_point = 0xA0000000;
    47 static uint32_t timeslice_length = DEFAULT_TIMESLICE_LENGTH;
    48 static uint64_t run_time_nanosecs = 0;
    50 #define MAX_MODULES 32
    51 static int num_modules = 0;
    52 dreamcast_module_t modules[MAX_MODULES];
    54 /**
    55  * The unknown module is used for logging files without an actual module
    56  * declaration
    57  */
    58 struct dreamcast_module unknown_module = { "****", NULL, NULL, NULL, NULL, 
    59         NULL, NULL, NULL };
    61 extern struct mem_region_fn mem_region_sdram;
    62 extern struct mem_region_fn mem_region_vram32;
    63 extern struct mem_region_fn mem_region_vram64;
    64 extern struct mem_region_fn mem_region_audioram;
    65 extern struct mem_region_fn mem_region_flashram;
    66 extern struct mem_region_fn mem_region_bootrom;
    68 /**
    69  * This function is responsible for defining how all the pieces of the
    70  * dreamcast actually fit together. 
    71  *
    72  * Note currently the locations of the various MMIO pages are hard coded in
    73  * the MMIO definitions - they should probably be moved here.
    74  */
    75 void dreamcast_configure( )
    76 {
    77     const char *bios_path = lxdream_get_config_value(CONFIG_BIOS_PATH);
    78     const char *flash_path = lxdream_get_config_value(CONFIG_FLASH_PATH);
    80     dreamcast_register_module( &eventq_module );
    81     /* Register the memory framework */
    82     dreamcast_register_module( &mem_module );
    84     /* Setup standard memory map */
    85     mem_create_repeating_ram_region( 0x0C000000, 16 MB, MEM_REGION_MAIN, &mem_region_sdram, 0x01000000, 0x0F000000 );
    86     mem_create_ram_region( 0x00800000, 2 MB, MEM_REGION_AUDIO, &mem_region_audioram );
    87     mem_create_ram_region( 0x00703000, 8 KB, MEM_REGION_AUDIO_SCRATCH, NULL );
    88     mem_create_ram_region( 0x05000000, 8 MB, MEM_REGION_VIDEO, &mem_region_vram32 );
    89     dreamcast_has_bios = mem_load_rom( bios_path, 0x00000000, 0x00200000, 0x89f2b1a1, MEM_REGION_BIOS, &mem_region_bootrom );
    90     mem_create_ram_region( 0x00200000, 0x00020000, MEM_REGION_FLASH, &mem_region_flashram );
    91     if( flash_path != NULL && flash_path[0] != '\0' ) {
    92         mem_load_block( flash_path, 0x00200000, 0x00020000 );
    93     }
    94     dreamcast_has_flash = TRUE;
    96     /* Load in the rest of the core modules */
    97     dreamcast_register_module( &sh4_module );
    98     dreamcast_register_module( &asic_module );
    99     dreamcast_register_module( &pvr2_module );
   100     dreamcast_register_module( &aica_module );
   101     dreamcast_register_module( &maple_module );
   102     dreamcast_register_module( &ide_module );
   103 }
   105 void dreamcast_config_changed(void)
   106 {
   107     const char *bios_path = lxdream_get_config_value(CONFIG_BIOS_PATH);
   108     const char *flash_path = lxdream_get_config_value(CONFIG_FLASH_PATH);
   109     dreamcast_has_bios = mem_load_rom( bios_path, 0x00000000, 0x00200000, 0x89f2b1a1, MEM_REGION_BIOS, &mem_region_bootrom );
   110     if( flash_path != NULL && flash_path[0] != '\0' ) {
   111         mem_load_block( flash_path, 0x00200000, 0x00020000 );
   112     }
   113 }
   115 void dreamcast_save_flash()
   116 {
   117     if( dreamcast_has_flash ) {
   118         const char *file = lxdream_get_config_value(CONFIG_FLASH_PATH);
   119         mem_save_block( file, 0x00200000, 0x00020000 );
   120     }
   121 }
   123 /**
   124  * Constructs a system configuration for the AICA in standalone mode,
   125  * ie sound chip only.
   126  */
   127 void dreamcast_configure_aica_only( )
   128 {
   129     dreamcast_register_module( &mem_module );
   130     mem_create_ram_region( 0x00800000, 2 MB, MEM_REGION_AUDIO, &mem_region_audioram );
   131     mem_create_ram_region( 0x00703000, 8 KB, MEM_REGION_AUDIO_SCRATCH, NULL );
   132     dreamcast_register_module( &aica_module );
   133     aica_enable();
   134     dreamcast_state = STATE_STOPPED;
   135 }
   137 void dreamcast_register_module( dreamcast_module_t module ) 
   138 {
   139     modules[num_modules++] = module;
   140     if( module->init != NULL )
   141         module->init();
   142 }
   144 void dreamcast_set_run_time( uint32_t secs, uint32_t nanosecs )
   145 {
   146     run_time_nanosecs = (((uint64_t)secs) * 1000000000) + nanosecs;
   147 }
   149 void dreamcast_set_exit_on_stop( gboolean flag )
   150 {
   151     dreamcast_exit_on_stop = flag;
   152 }
   154 void dreamcast_init( void )
   155 {
   156     dreamcast_configure();
   157     dreamcast_state = STATE_STOPPED;
   158 }
   160 void dreamcast_reset( void )
   161 {
   162     sh4_core_exit(CORE_EXIT_SYSRESET);
   163     int i;
   164     for( i=0; i<num_modules; i++ ) {
   165         if( modules[i]->reset != NULL )
   166             modules[i]->reset();
   167     }
   168 }
   170 void dreamcast_run( void )
   171 {
   172     int i;
   174     if( !dreamcast_can_run() ) {
   175         ERROR(_("No program is loaded, and no BIOS is configured (required to boot a CD image). To continue, either load a binary program, or set the path to your BIOS file in the Path Preferences"));
   176         return;
   177     }
   179     if( dreamcast_state != STATE_RUNNING ) {
   180         for( i=0; i<num_modules; i++ ) {
   181             if( modules[i]->start != NULL )
   182                 modules[i]->start();
   183         }
   184     }
   186     if( maple_should_grab() ) {
   187         gui_set_use_grab(TRUE);
   188     }
   190     dreamcast_state = STATE_RUNNING;
   192     if( run_time_nanosecs != 0 ) {
   193         while( dreamcast_state == STATE_RUNNING ) {
   194             uint32_t time_to_run = timeslice_length;
   195             if( run_time_nanosecs < time_to_run ) {
   196                 time_to_run = (uint32_t)run_time_nanosecs;
   197             }
   199             for( i=0; i<num_modules; i++ ) {
   200                 if( modules[i]->run_time_slice != NULL )
   201                     time_to_run = modules[i]->run_time_slice( time_to_run );
   202             }
   204             if( run_time_nanosecs > time_to_run ) {
   205                 run_time_nanosecs -= time_to_run;
   206             } else {
   207                 run_time_nanosecs = 0; // Finished
   208                 break;
   209             }
   210         }
   211     } else {
   212         while( dreamcast_state == STATE_RUNNING ) {
   213             int time_to_run = timeslice_length;
   214             for( i=0; i<num_modules; i++ ) {
   215                 if( modules[i]->run_time_slice != NULL )
   216                     time_to_run = modules[i]->run_time_slice( time_to_run );
   217             }
   219         }
   220     }
   222     gui_set_use_grab(FALSE);
   224     for( i=0; i<num_modules; i++ ) {
   225         if( modules[i]->stop != NULL )
   226             modules[i]->stop();
   227     }
   228     dreamcast_state = STATE_STOPPED;
   230     if( dreamcast_exit_on_stop ) {
   231         dreamcast_shutdown();
   232         exit(0);
   233     }
   234 }
   236 void dreamcast_stop( void )
   237 {
   238     sh4_core_exit(CORE_EXIT_HALT); // returns only if not inside SH4 core
   239     if( dreamcast_state == STATE_RUNNING )
   240         dreamcast_state = STATE_STOPPING;
   241 }
   243 void dreamcast_shutdown()
   244 {
   245     // Don't do a dreamcast_stop - if we're calling this out of SH4 code,
   246     // it's a shutdown-and-quit event
   247     if( dreamcast_state == STATE_RUNNING )
   248         dreamcast_state = STATE_STOPPING;
   249     dreamcast_save_flash();
   250 #ifdef ENABLE_SH4STATS
   251     sh4_stats_print(stdout);
   252 #endif
   253     print_sh4mem_stats();
   254 }
   256 void dreamcast_program_loaded( const gchar *name, sh4addr_t entry_point )
   257 {
   258     if( dreamcast_program_name != NULL ) {
   259         g_free(dreamcast_program_name);
   260     }
   261     dreamcast_program_name = g_strdup(name);
   262     dreamcast_entry_point = entry_point;
   263     sh4_set_pc(entry_point);
   264     bios_install();
   265     dcload_install();
   266     gui_update_state();
   267 }
   269 gboolean dreamcast_is_running( void )
   270 {
   271     return dreamcast_state == STATE_RUNNING;
   272 }
   274 gboolean dreamcast_can_run(void)
   275 {
   276     return dreamcast_state != STATE_UNINIT &&
   277     (dreamcast_has_bios || dreamcast_program_name != NULL);
   278 }
   280 /********************************* Save States *****************************/
   282 struct save_state_header {
   283     char magic[16];
   284     uint32_t version;
   285     uint32_t module_count;
   286 };
   288 struct chunk_header {
   289     char marker[4]; /* Always BLCK */
   290     char name[8]; /* Block (module) name */
   291     uint32_t block_length;
   292 };
   294 /**
   295  * Check the save state header to ensure that it is a valid, supported
   296  * file. 
   297  * @return the number of blocks following, or 0 if the file is invalid.
   298  */
   299 int dreamcast_read_save_state_header( FILE *f, char *error, int errorlen )
   300 {
   301     struct save_state_header header;
   302     if( fread( &header, sizeof(header), 1, f ) != 1 ) {
   303         return 0;
   304     }
   305     if( strncmp( header.magic, DREAMCAST_SAVE_MAGIC, 16 ) != 0 ) {
   306     	if( error != NULL )
   307     		snprintf( error, errorlen, _("File is not a %s save state"), APP_NAME );
   308         return 0;
   309     }
   310     if( header.version != DREAMCAST_SAVE_VERSION ) {
   311     	if( error != NULL )
   312     		snprintf( error, errorlen, _("Unsupported %s save state version"), APP_NAME );
   313         return 0;
   314     }
   315     if( header.module_count > MAX_MODULES ) {
   316     	if( error != NULL )
   317     		snprintf( error, errorlen, _("%s save state is corrupted (bad module count)"), APP_NAME );
   318         return 0;
   319     }
   320     return header.module_count;
   321 }
   323 int dreamcast_write_chunk_header( const gchar *name, uint32_t length, FILE *f )
   324 {
   325     struct chunk_header head;
   327     memcpy( head.marker, "BLCK", 4 );
   328     memset( head.name, 0, 8 );
   329     memcpy( head.name, name, strlen(name) );
   330     head.block_length = length;
   331     return fwrite( &head, sizeof(head), 1, f );
   332 }
   335 frame_buffer_t dreamcast_load_preview( const gchar *filename )
   336 {
   337     int i;
   338     FILE *f = fopen( filename, "r" );
   339     if( f == NULL ) return NULL;
   341     int module_count = dreamcast_read_save_state_header(f, NULL, 0);
   342     if( module_count <= 0 ) {
   343         fclose(f);
   344         return NULL;
   345     }
   346     for( i=0; i<module_count; i++ ) {
   347         struct chunk_header head;
   348         if( fread( &head, sizeof(head), 1, f ) != 1 ) {
   349             fclose(f);
   350             return NULL;
   351         }
   352         if( memcmp("BLCK", head.marker, 4) != 0 ) {
   353             fclose(f);
   354             return NULL;
   355         }
   357         if( strcmp("PVR2", head.name) == 0 ) {
   358             uint32_t buf_count;
   359             int has_front;
   360             fread( &buf_count, sizeof(buf_count), 1, f );
   361             fread( &has_front, sizeof(has_front), 1, f );
   362             if( buf_count != 0 && has_front ) {
   363                 frame_buffer_t result = read_png_from_stream(f);
   364                 fclose(f);
   365                 return result;
   366             }
   367             break;
   368         } else {
   369             fseek( f, head.block_length, SEEK_CUR );
   370         }
   371     }
   372     return NULL;
   373 }
   375 int dreamcast_load_state( const gchar *filename )
   376 {
   377     int i,j;
   378     int module_count;
   379     char error[128];
   380     int have_read[MAX_MODULES];
   382     FILE *f = fopen( filename, "r" );
   383     if( f == NULL ) return errno;
   385     module_count = dreamcast_read_save_state_header(f, error, sizeof(error));
   386     if( module_count <= 0 ) {
   387     	ERROR( error );
   388         fclose(f);
   389         return 1;
   390     }
   392     for( i=0; i<MAX_MODULES; i++ ) {
   393         have_read[i] = 0;
   394     }
   396     for( i=0; i<module_count; i++ ) {
   397         struct chunk_header chunk;
   398         fread( &chunk, sizeof(chunk), 1, f );
   399         if( strncmp(chunk.marker, "BLCK", 4) != 0 ) {
   400             ERROR( "%s save state is corrupted (missing block header %d)", APP_NAME, i );
   401             fclose(f);
   402             return 2;
   403         }
   405         /* Find the matching module by name */
   406         for( j=0; j<num_modules; j++ ) {
   407             if( strcmp(modules[j]->name,chunk.name) == 0 ) {
   408                 have_read[j] = 1;
   409                 if( modules[j]->load == NULL ) {
   410                     ERROR( "%s save state is corrupted (no loader for %s)", APP_NAME, modules[j]->name );
   411                     fclose(f);
   412                     return 2;
   413                 } else if( modules[j]->load(f) != 0 ) {
   414                     ERROR( "%s save state is corrupted (%s failed)", APP_NAME, modules[j]->name );
   415                     fclose(f);
   416                     return 2;
   417                 }
   418                 break;
   419             }
   420         }
   421         if( j == num_modules ) {
   422             fclose(f);
   423             ERROR( "%s save state contains unrecognized section", APP_NAME );
   424             return 2;
   425         }
   426     }
   428     /* Any modules that we didn't load - reset to the default state.
   429      * (ie it's not an error to skip a module if you don't actually
   430      * care about its state).
   431      */
   432     for( j=0; j<num_modules; j++ ) {
   433         if( have_read[j] == 0 && modules[j]->reset != NULL ) {
   434             modules[j]->reset();
   435         }
   436     }
   437     fclose(f);
   438     INFO( "Save state read from %s", filename );
   439     return 0;
   440 }
   442 int dreamcast_save_state( const gchar *filename )
   443 {
   444     int i;
   445     FILE *f;
   446     struct save_state_header header;
   448     f = fopen( filename, "w" );
   449     if( f == NULL )
   450         return errno;
   451     strcpy( header.magic, DREAMCAST_SAVE_MAGIC );
   452     header.version = DREAMCAST_SAVE_VERSION;
   453     header.module_count = 0;
   455     for( i=0; i<num_modules; i++ ) {
   456         if( modules[i]->save != NULL )
   457             header.module_count++;
   458     }
   459     fwrite( &header, sizeof(header), 1, f );
   460     for( i=0; i<num_modules; i++ ) {
   461         if( modules[i]->save != NULL ) {
   462             uint32_t blocklen, posn1, posn2;
   463             dreamcast_write_chunk_header( modules[i]->name, 0, f );
   464             posn1 = ftell(f);
   465             modules[i]->save(f);
   466             posn2 = ftell(f);
   467             blocklen = posn2 - posn1;
   468             fseek( f, posn1-4, SEEK_SET );
   469             fwrite( &blocklen, sizeof(blocklen), 1, f );
   470             fseek( f, posn2, SEEK_SET );
   471         }
   472     }
   473     fclose( f );
   474     INFO( "Save state written to %s", filename );
   475     return 0;
   476 }
.