96 lines
3.4 KiB
C
96 lines
3.4 KiB
C
/* RAC1 Wrapper: runs the decompiled Ratchet & Clank (PAL, SCES_509.16) natively.
|
|
* usage: rac1_wrapper [SCES_509.16 or -] [disc.iso] (the executable is read from the disc by default)
|
|
* Both come from the user's own disc; nothing from them is in this project. */
|
|
#include "uya_runtime.h"
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
/* The disc image: the second argument, RAC1_ISO, or `iso=PATH` in
|
|
* rac1_wrapper.cfg next to the program. */
|
|
static const char *cfg_value(const char *key)
|
|
{
|
|
static char line[4][1024];
|
|
static int k;
|
|
char p[1100];
|
|
snprintf(p, sizeof p, "%s/rac1_wrapper.cfg", plat_exe_dir());
|
|
FILE *f = fopen(p, "r");
|
|
if (!f) return 0;
|
|
char *b = line[k++ & 3];
|
|
size_t kl = strlen(key);
|
|
while (fgets(b, sizeof line[0], f)) {
|
|
b[strcspn(b, "\r\n")] = 0;
|
|
if (!strncmp(b, key, kl) && b[kl] == '=') { fclose(f); return b + kl + 1; }
|
|
}
|
|
fclose(f);
|
|
return 0;
|
|
}
|
|
|
|
static const char *find_iso(int argc, char **argv)
|
|
{
|
|
if (argc > 2) return argv[2];
|
|
if (getenv("RAC1_ISO")) return getenv("RAC1_ISO");
|
|
const char *v = cfg_value("iso");
|
|
if (v) return v;
|
|
uya_log("no disc image: put `iso=C:\\path\\to\\Ratchet & Clank (Europe).iso` in %s/rac1_wrapper.cfg", plat_exe_dir());
|
|
return 0;
|
|
}
|
|
|
|
/* SCES_509.16: read from the disc image itself (`disc:`), unless the first
|
|
* argument or `elf=` in the cfg names a file. */
|
|
static const char *find_elf(int argc, char **argv)
|
|
{
|
|
if (argc > 1 && strcmp(argv[1], "-")) return argv[1];
|
|
const char *v = cfg_value("elf");
|
|
if (v) return v;
|
|
return "disc:SCES_509.16";
|
|
}
|
|
|
|
/* Sections of the executable: everything but code. .vutext is VU microcode
|
|
* (data the game uploads by DMA). */
|
|
static const char *const exe_sections[] = {
|
|
".vutext", "core.data", "core.rdata", "core.bss", "core.lit",
|
|
".lit", ".bss", ".data", "lvl.vtbl", "lvl.camvtbl", "lvl.sndvtbl", 0
|
|
};
|
|
|
|
void rac1_boot(void);
|
|
void rac1_run(void);
|
|
|
|
int uya_main(int argc, char **argv)
|
|
{
|
|
setvbuf(stdout, 0, _IONBF, 0);
|
|
atexit(plat_at_exit);
|
|
uya_log_open();
|
|
uya_log("Project Solana: starting");
|
|
plat_install_trap_handler(); /* first: a crash from here on is logged */
|
|
plat_log_system();
|
|
{ /* renderer=gl|soft in the cfg (UYA_RENDERER overrides it) */
|
|
extern const char *uya_renderer_cfg;
|
|
const char *r = cfg_value("renderer");
|
|
uya_renderer_cfg = r ? strdup(r) : 0;
|
|
}
|
|
const char *elf = find_elf(argc, argv);
|
|
if (plat_map_fixed(PS2_RAM_LO, PS2_RAM_HI - PS2_RAM_LO, 1) ||
|
|
plat_map_fixed(PS2_SPR, PS2_SPR_SIZE, 0) ||
|
|
plat_map_fixed(PS2_EE_REGS, PS2_EE_REGS_SZ, 0) ||
|
|
plat_map_fixed(PS2_VU_MEM, PS2_VU_MEM_SZ, 0) ||
|
|
plat_map_fixed(PS2_GS_PRIV, PS2_GS_PRIV_SZ, 0)) {
|
|
uya_log("the PS2 address space could not be mapped");
|
|
return 1;
|
|
}
|
|
{
|
|
const char *iso = find_iso(argc, argv);
|
|
if (!iso || uya_disc_open(iso) != 0) { uya_log("the disc image could not be opened"); return 1; }
|
|
uya_log("disc image: %s", iso);
|
|
}
|
|
if (uya_load_elf_sections(elf, exe_sections) <= 0) return 1;
|
|
/* code: every byte traps until a trampoline covers it */
|
|
uya_fill_code_traps(0x00112380, 0x0012F580); /* core.text */
|
|
uya_fill_code_traps(0x001E9080, 0x0023E740); /* .text (the game program) */
|
|
uya_install_trampolines();
|
|
atexit(uya_report);
|
|
rac1_boot();
|
|
rac1_run();
|
|
return 0;
|
|
}
|