Search
lxdream.org :: lxdream/src/main.c
lxdream 0.9.1
released Jun 29
Download Now
filename src/main.c
changeset 1129:7b16bbd6209c
prev1125:9dd5dee45db9
next1134:f502f3d32f90
author nkeynes
date Fri Sep 17 20:08:50 2010 +1000 (13 years ago)
permissions -rw-r--r--
last change Refactor shader management to support multiple programs, which are all
defined in the shaders.glsl, rather than split up into one file per
fragment.
file annotate diff log raw
nkeynes@30
     1
/**
nkeynes@561
     2
 * $Id$
nkeynes@30
     3
 *
nkeynes@30
     4
 * Main program, initializes dreamcast and gui, then passes control off to
nkeynes@537
     5
 * the main loop. 
nkeynes@30
     6
 *
nkeynes@30
     7
 * Copyright (c) 2005 Nathan Keynes.
nkeynes@30
     8
 *
nkeynes@30
     9
 * This program is free software; you can redistribute it and/or modify
nkeynes@30
    10
 * it under the terms of the GNU General Public License as published by
nkeynes@30
    11
 * the Free Software Foundation; either version 2 of the License, or
nkeynes@30
    12
 * (at your option) any later version.
nkeynes@30
    13
 *
nkeynes@30
    14
 * This program is distributed in the hope that it will be useful,
nkeynes@30
    15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
nkeynes@30
    16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
nkeynes@30
    17
 * GNU General Public License for more details.
nkeynes@1
    18
 */
nkeynes@1
    19
nkeynes@678
    20
#include <stdlib.h>
nkeynes@68
    21
#include <unistd.h>
nkeynes@94
    22
#include <getopt.h>
nkeynes@1111
    23
#include <libisofs.h>
nkeynes@772
    24
#include "lxdream.h"
nkeynes@1041
    25
#include "lxpaths.h"
nkeynes@755
    26
#include "gettext.h"
nkeynes@1129
    27
#include "dream.h"
nkeynes@27
    28
#include "dreamcast.h"
nkeynes@422
    29
#include "display.h"
nkeynes@759
    30
#include "gui.h"
nkeynes@759
    31
#include "gdlist.h"
nkeynes@1129
    32
#include "hotkeys.h"
nkeynes@1129
    33
#include "loader.h"
nkeynes@1129
    34
#include "mem.h"
nkeynes@1129
    35
#include "plugin.h"
nkeynes@1129
    36
#include "serial.h"
nkeynes@759
    37
#include "syscall.h"
nkeynes@106
    38
#include "aica/audio.h"
nkeynes@1129
    39
#include "aica/armdasm.h"
nkeynes@422
    40
#include "gdrom/gdrom.h"
nkeynes@144
    41
#include "maple/maple.h"
nkeynes@1129
    42
#include "pvr2/glutil.h"
nkeynes@564
    43
#include "sh4/sh4.h"
nkeynes@1034
    44
#include "vmu/vmulist.h"
nkeynes@1129
    45
nkeynes@1129
    46
#define GL_INFO_OPT 1
nkeynes@11
    47
nkeynes@1125
    48
char *option_list = "a:A:bc:e:dfg:G:hHl:m:npt:T:uvV:xX?";
nkeynes@700
    49
struct option longopts[] = {
nkeynes@700
    50
        { "aica", required_argument, NULL, 'a' },
nkeynes@700
    51
        { "audio", required_argument, NULL, 'A' },
nkeynes@1100
    52
        { "biosless", no_argument, NULL, 'b' },
nkeynes@700
    53
        { "config", required_argument, NULL, 'c' },
nkeynes@1108
    54
        { "debugger", no_argument, NULL, 'd' },
nkeynes@1109
    55
        { "execute", required_argument, NULL, 'e' },
nkeynes@1015
    56
        { "fullscreen", no_argument, NULL, 'f' },
nkeynes@998
    57
        { "gdb-sh4", required_argument, NULL, 'g' },  
nkeynes@1129
    58
        { "gdb-arm", required_argument, NULL, 'G' },
nkeynes@1129
    59
        { "gl-info", no_argument, NULL, GL_INFO_OPT },
nkeynes@700
    60
        { "help", no_argument, NULL, 'h' },
nkeynes@700
    61
        { "headless", no_argument, NULL, 'H' },
nkeynes@700
    62
        { "log", required_argument, NULL,'l' }, 
nkeynes@700
    63
        { "multiplier", required_argument, NULL, 'm' },
nkeynes@700
    64
        { "run-time", required_argument, NULL, 't' },
nkeynes@1125
    65
        { "shadow", no_argument, NULL, 'X' },
nkeynes@700
    66
        { "trace", required_argument, NULL, 'T' },
nkeynes@700
    67
        { "unsafe", no_argument, NULL, 'u' },
nkeynes@700
    68
        { "video", no_argument, NULL, 'V' },
nkeynes@700
    69
        { "version", no_argument, NULL, 'v' }, 
nkeynes@700
    70
        { NULL, 0, 0, 0 } };
nkeynes@68
    71
char *aica_program = NULL;
nkeynes@531
    72
char *display_driver_name = NULL;
nkeynes@531
    73
char *audio_driver_name = NULL;
nkeynes@562
    74
char *trace_regions = NULL;
nkeynes@998
    75
char *sh4_gdb_port = NULL;
nkeynes@998
    76
char *arm_gdb_port = NULL;
nkeynes@68
    77
gboolean start_immediately = FALSE;
nkeynes@575
    78
gboolean no_start = FALSE;
nkeynes@77
    79
gboolean headless = FALSE;
nkeynes@1125
    80
sh4core_t sh4_core = SH4_TRANSLATE;
nkeynes@392
    81
gboolean show_debugger = FALSE;
nkeynes@1015
    82
gboolean show_fullscreen = FALSE;
nkeynes@1100
    83
gboolean use_bootrom = TRUE;
nkeynes@414
    84
extern uint32_t sh4_cpu_multiplier;
nkeynes@68
    85
nkeynes@968
    86
static void print_version()
nkeynes@700
    87
{
nkeynes@738
    88
    printf( "lxdream %s\n", lxdream_full_version );
nkeynes@700
    89
}
nkeynes@700
    90
nkeynes@968
    91
static void print_usage()
nkeynes@700
    92
{
nkeynes@700
    93
    print_version();
nkeynes@1109
    94
    printf( "Usage: lxdream %s [options] [disc-file] [save-state]\n\n", lxdream_full_version );
nkeynes@736
    95
nkeynes@700
    96
    printf( "Options:\n" );
nkeynes@700
    97
    printf( "   -a, --aica=PROGFILE    %s\n", _("Run the AICA SPU only, with the supplied program") );
nkeynes@700
    98
    printf( "   -A, --audio=DRIVER     %s\n", _("Use the specified audio driver (? to list)") );
nkeynes@1100
    99
    printf( "   -b, --biosless         %s\n", _("Run without the BIOS boot rom even if available") );
nkeynes@700
   100
    printf( "   -c, --config=CONFFILE  %s\n", _("Load configuration from CONFFILE") );
nkeynes@1109
   101
    printf( "   -e, --execute=PROGRAM  %s\n", _("Load and execute the given SH4 program") );
nkeynes@700
   102
    printf( "   -d, --debugger         %s\n", _("Start in debugger mode") );
nkeynes@1015
   103
    printf( "   -f, --fullscreen       %s\n", _("Start in fullscreen mode") );
nkeynes@998
   104
    printf( "   -g, --gdb-sh4=PORT     %s\n", _("Start GDB remote server on PORT for SH4") );
nkeynes@998
   105
    printf( "   -G, --gdb-arm=PORT     %s\n", _("Start GDB remote server on PORT for ARM") );
nkeynes@700
   106
    printf( "   -h, --help             %s\n", _("Display this usage information") );
nkeynes@700
   107
    printf( "   -H, --headless         %s\n", _("Run in headless (no video) mode") );
nkeynes@700
   108
    printf( "   -l, --log=LEVEL        %s\n", _("Set the output log level") );
nkeynes@700
   109
    printf( "   -m, --multiplier=SCALE %s\n", _("Set the SH4 multiplier (1.0 = fullspeed)") );
nkeynes@700
   110
    printf( "   -n                     %s\n", _("Don't start running immediately") );
nkeynes@700
   111
    printf( "   -p                     %s\n", _("Start running immediately on startup") );
nkeynes@700
   112
    printf( "   -t, --run-time=SECONDS %s\n", _("Run for the specified number of seconds") );
nkeynes@700
   113
    printf( "   -T, --trace=REGIONS    %s\n", _("Output trace information for the named regions") );
nkeynes@700
   114
    printf( "   -u, --unsafe           %s\n", _("Allow unsafe dcload syscalls") );
nkeynes@700
   115
    printf( "   -v, --version          %s\n", _("Print the lxdream version string") );
nkeynes@700
   116
    printf( "   -V, --video=DRIVER     %s\n", _("Use the specified video driver (? to list)") );
nkeynes@700
   117
    printf( "   -x                     %s\n", _("Disable the SH4 translator") );
nkeynes@1125
   118
    printf( "   -X                     %s\n", _("Run both SH4 interpreter and translator") );
nkeynes@700
   119
}
nkeynes@700
   120
nkeynes@968
   121
static void bind_gettext_domain()
nkeynes@723
   122
{
nkeynes@723
   123
#ifdef ENABLE_NLS
nkeynes@866
   124
    bindtextdomain( PACKAGE, get_locale_path() );
nkeynes@723
   125
    textdomain(PACKAGE);
nkeynes@723
   126
#endif
nkeynes@723
   127
}
nkeynes@723
   128
nkeynes@30
   129
int main (int argc, char *argv[])
nkeynes@1
   130
{
nkeynes@669
   131
    int opt;
nkeynes@372
   132
    double t;
nkeynes@1109
   133
    gboolean display_ok, have_disc = FALSE, have_save = FALSE, have_exec = FALSE;
nkeynes@1129
   134
    gboolean print_glinfo = FALSE;
nkeynes@689
   135
    uint32_t time_secs, time_nanos;
nkeynes@1109
   136
    const char *exec_name = NULL;
nkeynes@495
   137
nkeynes@495
   138
    install_crash_handler();
nkeynes@723
   139
    bind_gettext_domain();
nkeynes@531
   140
    display_ok = gui_parse_cmdline(&argc, &argv);
nkeynes@464
   141
nkeynes@94
   142
    while( (opt = getopt_long( argc, argv, option_list, longopts, NULL )) != -1 ) {
nkeynes@736
   143
        switch( opt ) {
nkeynes@736
   144
        case 'a': /* AICA only mode - argument is an AICA program */
nkeynes@736
   145
            aica_program = optarg;
nkeynes@77
   146
            break;
nkeynes@736
   147
        case 'A': /* Audio driver */
nkeynes@736
   148
            audio_driver_name = optarg;
nkeynes@736
   149
            break;
nkeynes@1100
   150
        case 'b': /* No Boot rom */
nkeynes@1100
   151
            use_bootrom = FALSE;
nkeynes@736
   152
        case 'c': /* Config file */
nkeynes@736
   153
            lxdream_set_config_filename(optarg);
nkeynes@736
   154
            break;
nkeynes@736
   155
        case 'd': /* Launch w/ debugger */
nkeynes@736
   156
            show_debugger = TRUE;
nkeynes@736
   157
            break;
nkeynes@1109
   158
        case 'e':
nkeynes@1109
   159
            exec_name = optarg;
nkeynes@1109
   160
            break;
nkeynes@1015
   161
        case 'f':
nkeynes@1015
   162
            show_fullscreen = TRUE;
nkeynes@1015
   163
            break;
nkeynes@998
   164
        case 'g':
nkeynes@998
   165
            sh4_gdb_port = optarg;
nkeynes@998
   166
            break;
nkeynes@998
   167
        case 'G':
nkeynes@998
   168
            arm_gdb_port = optarg;
nkeynes@998
   169
            break;
nkeynes@736
   170
        case 'h': /* help */
nkeynes@736
   171
        case '?':
nkeynes@736
   172
            print_usage();
nkeynes@736
   173
            exit(0);
nkeynes@736
   174
            break;
nkeynes@736
   175
        case 'H': /* Headless - shorthand for -V null */
nkeynes@736
   176
            display_driver_name = "null";
nkeynes@736
   177
            break;
nkeynes@736
   178
        case 'l': /* Log verbosity */
nkeynes@736
   179
            if( !set_global_log_level(optarg) ) {
nkeynes@736
   180
                ERROR( "Unrecognized log level '%s'", optarg );
nkeynes@736
   181
            }
nkeynes@736
   182
            break;
nkeynes@736
   183
        case 'm': /* Set SH4 CPU clock multiplier (default 0.5) */
nkeynes@736
   184
            t = strtod(optarg, NULL);
nkeynes@736
   185
            sh4_cpu_multiplier = (int)(1000.0/t);
nkeynes@736
   186
            break;
nkeynes@736
   187
        case 'n': /* Don't start immediately */
nkeynes@736
   188
            no_start = TRUE;
nkeynes@736
   189
            start_immediately = FALSE;
nkeynes@736
   190
            break;
nkeynes@736
   191
        case 'p': /* Start immediately */
nkeynes@736
   192
            start_immediately = TRUE;
nkeynes@736
   193
            no_start = FALSE;
nkeynes@736
   194
            break;
nkeynes@736
   195
        case 't': /* Time limit + auto quit */
nkeynes@736
   196
            t = strtod(optarg, NULL);
nkeynes@736
   197
            time_secs = (uint32_t)t;
nkeynes@736
   198
            time_nanos = (int)((t - time_secs) * 1000000000);
nkeynes@736
   199
            dreamcast_set_run_time( time_secs, time_nanos );
nkeynes@736
   200
            dreamcast_set_exit_on_stop( TRUE );
nkeynes@736
   201
            break;
nkeynes@736
   202
        case 'T': /* trace regions */
nkeynes@736
   203
            trace_regions = optarg;
nkeynes@736
   204
            set_global_log_level("trace");
nkeynes@736
   205
            break;
nkeynes@736
   206
        case 'u': /* Allow unsafe dcload syscalls */
nkeynes@736
   207
            dcload_set_allow_unsafe(TRUE);
nkeynes@736
   208
            break;
nkeynes@736
   209
        case 'v': 
nkeynes@700
   210
            print_version();
nkeynes@700
   211
            exit(0);
nkeynes@736
   212
            break;
nkeynes@736
   213
        case 'V': /* Video driver */
nkeynes@736
   214
            display_driver_name = optarg;
nkeynes@736
   215
            break;
nkeynes@736
   216
        case 'x': /* Disable translator */
nkeynes@1125
   217
            sh4_core = SH4_INTERPRET;
nkeynes@1125
   218
            break;
nkeynes@1125
   219
        case 'X': /* Shadow translator */
nkeynes@1125
   220
            sh4_core = SH4_SHADOW;
nkeynes@736
   221
            break;
nkeynes@1129
   222
        case GL_INFO_OPT:
nkeynes@1129
   223
            print_glinfo = TRUE;
nkeynes@1129
   224
            break;
nkeynes@700
   225
        }
nkeynes@68
   226
    }
nkeynes@30
   227
nkeynes@1024
   228
#ifdef ENABLE_SHARED
nkeynes@1027
   229
    plugin_init();
nkeynes@1024
   230
#endif
nkeynes@1024
   231
nkeynes@1038
   232
    lxdream_make_config_dir( );
nkeynes@450
   233
    lxdream_load_config( );
nkeynes@144
   234
nkeynes@1024
   235
    if( audio_driver_name != NULL && strcmp(audio_driver_name, "?") == 0 ) {
nkeynes@1024
   236
        print_version();
nkeynes@1024
   237
        print_audio_drivers(stdout);
nkeynes@1024
   238
        exit(0);
nkeynes@1024
   239
    }
nkeynes@1024
   240
nkeynes@1024
   241
    if( display_driver_name != NULL && strcmp(display_driver_name,"?") == 0 ) {
nkeynes@1024
   242
        print_version();
nkeynes@1024
   243
        print_display_drivers(stdout);
nkeynes@1024
   244
        exit(0);
nkeynes@1024
   245
    }
nkeynes@1024
   246
nkeynes@1129
   247
    if( print_glinfo ) {
nkeynes@1129
   248
        gui_init(FALSE, FALSE);
nkeynes@1129
   249
        display_driver_t display_driver = get_display_driver_by_name(display_driver_name);
nkeynes@1129
   250
        if( display_driver == NULL ) {
nkeynes@1129
   251
            ERROR( "Video driver '%s' not found, aborting.", display_driver_name );
nkeynes@1129
   252
            exit(2);
nkeynes@1129
   253
        } else if( display_set_driver( display_driver ) == FALSE ) {
nkeynes@1129
   254
            ERROR( "Video driver '%s' failed to initialize (could not connect to display?)",
nkeynes@1129
   255
                    display_driver->name );
nkeynes@1129
   256
            exit(2);
nkeynes@1129
   257
        }
nkeynes@1129
   258
        glPrintInfo(stdout);
nkeynes@1129
   259
        exit(0);
nkeynes@1129
   260
nkeynes@1129
   261
    }
nkeynes@1129
   262
nkeynes@1129
   263
nkeynes@1107
   264
    iso_init();
nkeynes@691
   265
    gdrom_list_init();
nkeynes@1034
   266
    vmulist_init();
nkeynes@736
   267
nkeynes@68
   268
    if( aica_program == NULL ) {
nkeynes@1100
   269
        dreamcast_init(use_bootrom);
nkeynes@68
   270
    } else {
nkeynes@700
   271
        dreamcast_configure_aica_only();
nkeynes@700
   272
        mem_load_block( aica_program, 0x00800000, 2048*1024 );
nkeynes@68
   273
    }
nkeynes@562
   274
    mem_set_trace( trace_regions, TRUE );
nkeynes@1
   275
nkeynes@759
   276
    audio_init_driver( audio_driver_name );
nkeynes@736
   277
nkeynes@700
   278
    headless = display_driver_name != NULL && strcasecmp( display_driver_name, "null" ) == 0;
nkeynes@106
   279
    if( headless ) {
nkeynes@700
   280
        display_set_driver( &display_null_driver );
nkeynes@106
   281
    } else {
nkeynes@1015
   282
        gui_init(show_debugger, show_fullscreen);
nkeynes@435
   283
nkeynes@700
   284
        display_driver_t display_driver = get_display_driver_by_name(display_driver_name);
nkeynes@700
   285
        if( display_driver == NULL ) {
nkeynes@700
   286
            ERROR( "Video driver '%s' not found, aborting.", display_driver_name );
nkeynes@700
   287
            exit(2);
nkeynes@700
   288
        } else if( display_set_driver( display_driver ) == FALSE ) {
nkeynes@700
   289
            ERROR( "Video driver '%s' failed to initialize (could not connect to display?)", 
nkeynes@700
   290
                    display_driver->name );
nkeynes@700
   291
            exit(2);
nkeynes@700
   292
        }
nkeynes@87
   293
    }
nkeynes@1015
   294
    
nkeynes@1015
   295
    hotkeys_init();
nkeynes@1077
   296
    serial_init();
nkeynes@106
   297
nkeynes@144
   298
    maple_reattach_all();
nkeynes@180
   299
    INFO( "%s! ready...", APP_NAME );
nkeynes@446
   300
nkeynes@1109
   301
    for( ; optind < argc; optind++ ) {
nkeynes@1108
   302
        ERROR err;
nkeynes@1109
   303
        lxdream_file_type_t type = file_identify(argv[optind], -1, &err);
nkeynes@1109
   304
        if( type == FILE_SAVE_STATE ) {
nkeynes@1109
   305
            if( have_save ) {
nkeynes@1109
   306
                ERROR( "Multiple save states given on command-line, ignoring %s", argv[optind] );
nkeynes@1109
   307
            } else {
nkeynes@1109
   308
                have_save = dreamcast_load_state(argv[optind]);
nkeynes@1109
   309
                if( !have_save )
nkeynes@1109
   310
                    no_start = TRUE;
nkeynes@1109
   311
            }
nkeynes@1109
   312
        } else {
nkeynes@1109
   313
            if( have_disc ) {
nkeynes@1109
   314
                ERROR( "Multiple GD-ROM discs given on command-line, ignoring %s", argv[optind] );
nkeynes@1109
   315
            } else {
nkeynes@1109
   316
                have_disc = gdrom_mount_image(argv[optind], &err);
nkeynes@1116
   317
                if( !have_disc ) {
nkeynes@1116
   318
                    ERROR( err.msg );
nkeynes@1109
   319
                    no_start = TRUE;
nkeynes@1116
   320
                }
nkeynes@1108
   321
            }
nkeynes@1108
   322
        }
nkeynes@1108
   323
    }
nkeynes@1108
   324
nkeynes@1109
   325
    if( exec_name != NULL ) {
nkeynes@1109
   326
        ERROR err;
nkeynes@1109
   327
        if( have_save ) {
nkeynes@1109
   328
            ERROR( "Both a save state and an executable were specified, ignoring %s", exec_name );
nkeynes@1109
   329
        } else {
nkeynes@1109
   330
            have_exec = file_load_exec( exec_name, &err );
nkeynes@1116
   331
            if( !have_exec ) {
nkeynes@1116
   332
                ERROR( err.msg );
nkeynes@1109
   333
                no_start = TRUE;
nkeynes@1116
   334
            }
nkeynes@700
   335
        }
nkeynes@144
   336
    }
nkeynes@144
   337
nkeynes@1109
   338
    if( !no_start && (have_exec || have_disc || have_save) ) {
nkeynes@1109
   339
        start_immediately = TRUE;
nkeynes@1109
   340
    }
nkeynes@1109
   341
nkeynes@464
   342
    if( gdrom_get_current_disc() == NULL ) {
nkeynes@1109
   343
        ERROR err;
nkeynes@1036
   344
        gchar *disc_file = lxdream_get_global_config_path_value( CONFIG_GDROM );
nkeynes@678
   345
        if( disc_file != NULL ) {
nkeynes@1109
   346
            gboolean ok = gdrom_mount_image( disc_file, &err );
nkeynes@1036
   347
            g_free(disc_file);
nkeynes@1109
   348
            if( !ok ) {
nkeynes@1109
   349
                WARN( err.msg );
nkeynes@1109
   350
            }
nkeynes@678
   351
        }
nkeynes@464
   352
    }
nkeynes@464
   353
nkeynes@1125
   354
    sh4_set_core( sh4_core );
nkeynes@379
   355
nkeynes@998
   356
    /* If requested, start the gdb server immediately before we go into the main
nkeynes@998
   357
     * loop.
nkeynes@998
   358
     */
nkeynes@998
   359
    if( sh4_gdb_port != NULL ) {
nkeynes@998
   360
        gdb_init_server( NULL, strtol(sh4_gdb_port,NULL,0), &sh4_cpu_desc, TRUE );
nkeynes@372
   361
    }
nkeynes@998
   362
    if( arm_gdb_port != NULL ) {
nkeynes@998
   363
        gdb_init_server( NULL, strtol(arm_gdb_port,NULL,0), &arm_cpu_desc, TRUE );
nkeynes@77
   364
    }
nkeynes@998
   365
    
nkeynes@689
   366
    if( headless ) {
nkeynes@689
   367
        dreamcast_run();
nkeynes@689
   368
    } else {
nkeynes@681
   369
        gui_main_loop( start_immediately && dreamcast_can_run() );
nkeynes@77
   370
    }
nkeynes@671
   371
    dreamcast_shutdown();
nkeynes@68
   372
    return 0;
nkeynes@1
   373
}
nkeynes@1
   374
.