shithub: psxe

ref: 1599df1dd34f5ec106d00ac0da0182c31480d1f7
dir: /frontend/main.c/

View raw version
#include "psx/psx.h"
#include "psx/config.h"

#include "screen.h"
#include "argparse.h"
#include "toml.h"

#include <signal.h>

#undef main

#ifndef OS_INFO
#define OS_INFO unknown
#endif
#ifndef REP_VERSION
#define REP_VERSION latest
#endif
#ifndef REP_COMMIT_HASH
#define REP_COMMIT_HASH latest
#endif

#define STR1(m) #m
#define STR(m) STR1(m)

static const char* g_version_text =
#ifdef _WIN32
    "psxe.exe (" STR(OS_INFO) ") " STR(REP_VERSION) "-" STR(REP_COMMIT_HASH) "\n"
#elif __linux__
    "psxe (" STR(OS_INFO) ") " STR(REP_VERSION) "-" STR(REP_COMMIT_HASH) "\n"
#else
    "psxe (" STR(OS_INFO) ") " STR(REP_VERSION) "-" STR(REP_COMMIT_HASH) "\n"
#endif
    "\nPSXE - A simple, fast and portable Sony PlayStation emulator.\n\n"
    "Copyright (C) 2023 Allkern (Lisandro Alarcon)\n"
    "This is free software; see the source for copying conditions.  There is NO\n"
    "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n";

static const char g_default_settings[] =
    "# Settings file generated by PSXE\n"
    "\n"
    "# Don't change please, reserved for future use\n"
    "psxe_version = \"" STR(REP_VERSION) "\"\n"
    "\n"
    "# BIOS-related settings:\n"
    "[bios]\n"
    "    search_path     = \"bios\"\n"
    "    preferred_model = \"SCPH-1001\"\n"
    "    override_file   = \"\"\n"
    "\n"
    "# Console settings\n"
    "[console]\n"
    "    region          = \"auto\"\n";


static const char* g_models_text =
    "Available console models:\n"
    "\"scph1000\" (SCPH-1000) [NTSC-J]\n"
    "\"scph1001\" (SCPH-1001) [NTSC-U/C]\n"
    "\"scph1002\" (SCPH-1002) [PAL]\n"
    "\"scph3000\" (SCPH-3000) [NTSC-J]\n"
    "\"scph3500\" (SCPH-3500) [NTSC-J]\n"
    "\"scph5000\" (SCPH-5000) [NTSC-U/C]\n"
    "\"scph5501\" (SCPH-5501) [NTSC-U/C]\n"
    "\"scph5500\" (SCPH-5500) [NTSC-J]\n"
    "\"scph5502\" (SCPH-5502) [PAL]\n"
    "\"scph5552\" (SCPH-5552) [PAL]\n"
    "\"scph7000\" (SCPH-7000) [NTSC-J]\n"
    "\"scph7001\" (SCPH-7001) [NTSC-U/C]\n"
    "\"scph7002\" (SCPH-7002) [PAL]\n"
    "\"scph7003\" (SCPH-7003) [NTSC-J]\n"
    "\"scph7501\" (SCPH-7501) [NTSC]\n"
    "\"scph7502\" (SCPH-7502) [PAL]\n"
    "\"scph9002\" (SCPH-9002) [PAL]\n"
    "\"scph100\" (SCPH-100) [NTSC-J]\n"
    "\"scph101\" (SCPH-101) [NTSC-U/C]\n"
    "\"scph102a\" (SCPH-102A) [PAL]\n"
    "\"scph102b\" (SCPH-102B) [PAL]\n"
    "\"scph102c\" (SCPH-102C) [?]\n";

static const char* g_regions_text =
    "Available region options: \"ntsc\", \"pal\", \"auto\"\n";

static const char* g_desc_text =
    "\nPlease report any bugs to <https://github.com/allkern/psxe/issues>\n";

psx_cpu_t* g_cpu;

void sigint_handler(int sig) {
    log_fatal("r0=%08x at=%08x v0=%08x v1=%08x", g_cpu->r[0] , g_cpu->r[1] , g_cpu->r[2] , g_cpu->r[3] );
    log_fatal("a0=%08x a1=%08x a2=%08x a3=%08x", g_cpu->r[4] , g_cpu->r[5] , g_cpu->r[6] , g_cpu->r[7] );
    log_fatal("t0=%08x t1=%08x t2=%08x t3=%08x", g_cpu->r[8] , g_cpu->r[9] , g_cpu->r[10], g_cpu->r[11]);
    log_fatal("t4=%08x t5=%08x t6=%08x t7=%08x", g_cpu->r[12], g_cpu->r[13], g_cpu->r[14], g_cpu->r[15]);
    log_fatal("s0=%08x s1=%08x s2=%08x s3=%08x", g_cpu->r[16], g_cpu->r[17], g_cpu->r[18], g_cpu->r[19]);
    log_fatal("s4=%08x s5=%08x s6=%08x s7=%08x", g_cpu->r[20], g_cpu->r[21], g_cpu->r[22], g_cpu->r[23]);
    log_fatal("t8=%08x t9=%08x k0=%08x k1=%08x", g_cpu->r[24], g_cpu->r[25], g_cpu->r[26], g_cpu->r[27]);
    log_fatal("gp=%08x sp=%08x fp=%08x ra=%08x", g_cpu->r[28], g_cpu->r[29], g_cpu->r[30], g_cpu->r[31]);
    log_fatal("pc=%08x hi=%08x lo=%08x", g_cpu->pc, g_cpu->hi, g_cpu->lo);

    exit(1);
}

int main(int argc, const char* argv[]) {
    log_set_level(LOG_INFO);

    int         use_args = 0;
    int         version = 0;
    int         help_model = 0;
    int         help_region = 0;
    const char* settings_path = NULL;
    const char* bios = NULL;
    const char* bios_search = NULL;
    const char* model = NULL;
    const char* exe = NULL;
    const char* region = NULL;
    const char* psxe_version = NULL;

    static const char *const usages[] = {
        "basic [options]",
        NULL,
    };

    struct argparse_option options[] = {
        OPT_BOOLEAN ('h', "help"         , NULL          , "Display this information", argparse_help_cb, 0, 0),
        OPT_BOOLEAN (0  , "help-model"   , &help_model   , "Display available console models", NULL, 0, 0),
        OPT_BOOLEAN (0  , "help-region"  , &help_region  , "Display available region options", NULL, 0, 0),
        OPT_BOOLEAN ('v', "version"      , &version      , "Display version and build information", NULL, 0, 0),
        OPT_BOOLEAN ('a', "use-args"     , &use_args     , "Ignore settings file, use CLI args instead", NULL, 0, 0),
        OPT_STRING  ('S', "settings-file", &settings_path, "Specify settings file path", NULL, 0, 0),
        OPT_GROUP("BIOS options"),
        OPT_BOOLEAN ('b', "bios"         , &bios         , "Use this BIOS file (ignores -B, -M)", NULL, 0, 0),
        OPT_BOOLEAN ('B', "bios-folder"  , &bios_search  , "Specify a BIOS search folder", NULL, 0, 0),
        OPT_GROUP("Console options"),
        OPT_STRING  ('M', "model"        , &model        , "Specify console model (SPCH-XXXX)", NULL, 0, 0),
        OPT_STRING  ('r', "region"       , &region       , "Specify console region"),
        OPT_STRING  ('x', "exe"          , &exe          , "Boot this PS-X EXE file (ignores CDROM image)"),
        OPT_END()
    };

    struct argparse argparse;

    argparse_init(&argparse, options, usages, 0);
    argparse_describe(&argparse, NULL, g_desc_text);

    argc = argparse_parse(&argparse, argc, argv);

    if (help_model) {
        printf("%s\n", g_models_text);

        exit(0);
    }

    if (help_region) {
        printf("%s\n", g_regions_text);

        exit(0);
    }

    if (version) {
        printf("%s\n", g_version_text);

        exit(0);
    }

    if (!use_args) {
        if (!settings_path)
            settings_path = "settings.toml";

        FILE* settings = fopen(settings_path, "rb");

        char error[0x100];

        if (!settings) {
            settings = fopen("settings.toml", "w+b");

            fwrite(g_default_settings, 1, sizeof(g_default_settings) - 1, settings);

            fseek(settings, 0, 0);
        }

        log_info("Parsing settings file...");

        toml_table_t* conf = toml_parse_file(settings, error, sizeof(error));

        if (!conf) {
            log_error("Couldn't parse settings file");

            exit(1);
        }

        toml_datum_t s_version = toml_string_in(conf, "psxe_version");

        if (!s_version.ok) {
            log_error("Settings file lacking version number");

            exit(1);
        }

        toml_table_t* s_bios_table = toml_table_in(conf, "bios");

        if (s_bios_table) {
            toml_datum_t s_bios_search_path = toml_string_in(s_bios_table, "search_path");

            if (s_bios_search_path.ok)
                bios_search = s_bios_search_path.u.s;

            toml_datum_t s_bios_preferred_model = toml_string_in(s_bios_table, "preferred_model");

            if (s_bios_preferred_model.ok)
                model = s_bios_preferred_model.u.s;

            toml_datum_t s_bios_override_file = toml_string_in(s_bios_table, "override_file");

            if (s_bios_override_file.ok)
                bios = s_bios_override_file.u.s;
        }

        toml_table_t* s_console_table = toml_table_in(conf, "console");

        if (s_console_table) {
            toml_datum_t s_console_region = toml_string_in(s_console_table, "region");

            if (s_console_region.ok)
                region = s_console_region.u.s;
        }

        psxe_version = s_version.u.s;

        log_info("Settings file parsed. PSXE version: %s", psxe_version);

        fclose(settings);
    }

    log_set_level(LOG_FATAL);

    signal(SIGINT, sigint_handler);

    psx_t* psx = psx_create();
    psx_init(psx, "SCPH1001.BIN");

    psx_gpu_t* gpu = psx_get_gpu(psx);

    g_cpu = psx_get_cpu(psx);

    psxe_screen_t* screen = psxe_screen_create();
    psxe_screen_init(screen, psx);
    psxe_screen_set_scale(screen, 2);
    psxe_screen_reload(screen);

    psx_gpu_set_event_callback(gpu, GPU_EVENT_DMODE, psxe_gpu_dmode_event_cb);
    psx_gpu_set_udata(gpu, 0, screen);

    if (argv[1]) {
        while (psx->cpu->pc != 0x80030008) {
            psx_update(psx);
        }

        psx_load_exe(psx, argv[1]);
    }

    while (psxe_screen_is_open(screen)) {
        psx_run_frame(psx);

        psxe_screen_update(screen);
    }

    psx_cpu_t* cpu = psx_get_cpu(psx);

    log_fatal("r0=%08x at=%08x v0=%08x v1=%08x", cpu->r[0] , cpu->r[1] , cpu->r[2] , cpu->r[3] );
    log_fatal("a0=%08x a1=%08x a2=%08x a3=%08x", cpu->r[4] , cpu->r[5] , cpu->r[6] , cpu->r[7] );
    log_fatal("t0=%08x t1=%08x t2=%08x t3=%08x", cpu->r[8] , cpu->r[9] , cpu->r[10], cpu->r[11]);
    log_fatal("t4=%08x t5=%08x t6=%08x t7=%08x", cpu->r[12], cpu->r[13], cpu->r[14], cpu->r[15]);
    log_fatal("s0=%08x s1=%08x s2=%08x s3=%08x", cpu->r[16], cpu->r[17], cpu->r[18], cpu->r[19]);
    log_fatal("s4=%08x s5=%08x s6=%08x s7=%08x", cpu->r[20], cpu->r[21], cpu->r[22], cpu->r[23]);
    log_fatal("t8=%08x t9=%08x k0=%08x k1=%08x", cpu->r[24], cpu->r[25], cpu->r[26], cpu->r[27]);
    log_fatal("gp=%08x sp=%08x fp=%08x ra=%08x", cpu->r[28], cpu->r[29], cpu->r[30], cpu->r[31]);
    log_fatal("pc=%08x hi=%08x lo=%08x", cpu->pc, cpu->hi, cpu->lo);

    psx_destroy(psx);
    psxe_screen_destroy(screen);

    return 0;
}