mirror of https://github.com/inolen/redream.git
changed region patching to patch each game for all regions vs
patching the flash settings for a particular supported region added post_init callback to device, removing the need for the call to bios_preboot
This commit is contained in:
parent
adcebc3779
commit
7e7aa80c62
|
@ -601,9 +601,11 @@ static void emu_run_frame(struct emu *emu) {
|
|||
void emu_render_frame(struct emu *emu) {
|
||||
prof_counter_add(COUNTER_frames, 1);
|
||||
|
||||
/* check that we're not being called between calls to emu_video_destroyed
|
||||
and emu_video_created */
|
||||
CHECK_NOTNULL(emu->r);
|
||||
if (!dc_running(emu->dc)) {
|
||||
/* not running, just build debug menu */
|
||||
emu_debug_menu(emu);
|
||||
return;
|
||||
}
|
||||
|
||||
int width = r_width(emu->r);
|
||||
int height = r_height(emu->r);
|
||||
|
|
|
@ -1016,7 +1016,7 @@ struct aica *aica_create(struct dreamcast *dc) {
|
|||
aica_init_tables();
|
||||
|
||||
struct aica *aica =
|
||||
dc_create_device(dc, sizeof(struct aica), "aica", &aica_init);
|
||||
dc_create_device(dc, sizeof(struct aica), "aica", &aica_init, NULL);
|
||||
|
||||
/* assign ids */
|
||||
for (int i = 0; i < AICA_NUM_CHANNELS; i++) {
|
||||
|
|
|
@ -238,7 +238,7 @@ void arm7_destroy(struct arm7 *arm) {
|
|||
|
||||
struct arm7 *arm7_create(struct dreamcast *dc) {
|
||||
struct arm7 *arm =
|
||||
dc_create_device(dc, sizeof(struct arm7), "arm", &arm7_init);
|
||||
dc_create_device(dc, sizeof(struct arm7), "arm", &arm7_init, NULL);
|
||||
arm->execute_if = dc_create_execute_interface(&arm7_run, 0);
|
||||
arm->memory_if = dc_create_memory_interface(dc, &arm7_data_map);
|
||||
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
#include "guest/sh4/sh4.h"
|
||||
#include "imgui.h"
|
||||
|
||||
DEFINE_PERSISTENT_OPTION_STRING(region, "auto", "System region");
|
||||
DEFINE_PERSISTENT_OPTION_STRING(region, "usa", "System region");
|
||||
DEFINE_PERSISTENT_OPTION_STRING(language, "english", "System language");
|
||||
DEFINE_PERSISTENT_OPTION_STRING(broadcast, "ntsc", "System broadcast mode");
|
||||
|
||||
/* system settings */
|
||||
static const char *regions[] = {
|
||||
"japan", "usa", "europe", "auto",
|
||||
"japan", "usa", "europe",
|
||||
};
|
||||
|
||||
static const char *languages[] = {
|
||||
|
@ -94,15 +94,6 @@ static void bios_override_settings(struct bios *bios) {
|
|||
}
|
||||
}
|
||||
|
||||
/* if "auto" is specified, select first supported region */
|
||||
if (region == ARRAY_SIZE(regions) - 1) {
|
||||
int supported_regions = DISC_REGION_ALL;
|
||||
if (gdrom_has_disc(gd)) {
|
||||
supported_regions = gdrom_get_regions(gd);
|
||||
}
|
||||
region = ctz32((uint32_t)supported_regions);
|
||||
}
|
||||
|
||||
LOG_INFO("bios_override_settings region=%s lang=%s bcast=%s", regions[region],
|
||||
languages[lang], broadcasts[bcast]);
|
||||
|
||||
|
@ -304,8 +295,31 @@ static int bios_boot(struct bios *bios) {
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int bios_init(struct device *dev) {
|
||||
static int bios_post_init(struct device *dev) {
|
||||
struct bios *bios = (struct bios *)dev;
|
||||
|
||||
bios_validate_flash(bios);
|
||||
|
||||
bios_override_settings(bios);
|
||||
|
||||
/* this code enables a "hybrid" hle mode. in this mode, syscalls are patched
|
||||
to trap into their hle handlers, but the real bios can still be ran to
|
||||
test if bugs exist in the syscall emulation or bootstrap emulation */
|
||||
#if 0
|
||||
/* write out invalid instructions at syscall entry points. note, the boot rom
|
||||
does a bootstrap on startup which copies the boot rom into system ram. due
|
||||
to this, the invalid instructions are written to the original rom, not the
|
||||
system ram (or else, they would be overwritten by the bootstrap process) */
|
||||
struct boot *boot = bios->dc->boot;
|
||||
uint16_t invalid = 0x0;
|
||||
|
||||
boot_write(boot, SYSCALL_FONTROM, &invalid, 2);
|
||||
boot_write(boot, SYSCALL_SYSINFO, &invalid, 2);
|
||||
boot_write(boot, SYSCALL_FLASHROM, &invalid, 2);
|
||||
boot_write(boot, SYSCALL_GDROM, &invalid, 2);
|
||||
/*boot_write(boot, SYSCALL_MENU, &invalid, 2);*/
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -407,38 +421,12 @@ int bios_invalid_instr(struct bios *bios) {
|
|||
return handled;
|
||||
}
|
||||
|
||||
int bios_preboot(struct bios *bios) {
|
||||
bios_validate_flash(bios);
|
||||
|
||||
bios_override_settings(bios);
|
||||
|
||||
/* this code enables a "hybrid" hle mode. in this mode, syscalls are patched
|
||||
to trap into their hle handlers, but the real bios can still be ran to
|
||||
test if bugs exist in the syscall emulation or bootstrap emulation */
|
||||
#if 0
|
||||
/* write out invalid instructions at syscall entry points. note, the boot rom
|
||||
does a bootstrap on startup which copies the boot rom into system ram. due
|
||||
to this, the invalid instructions are written to the original rom, not the
|
||||
system ram (or else, they would be overwritten by the bootstrap process) */
|
||||
struct boot *boot = bios->dc->boot;
|
||||
uint16_t invalid = 0x0;
|
||||
|
||||
boot_write(boot, SYSCALL_FONTROM, &invalid, 2);
|
||||
boot_write(boot, SYSCALL_SYSINFO, &invalid, 2);
|
||||
boot_write(boot, SYSCALL_FLASHROM, &invalid, 2);
|
||||
boot_write(boot, SYSCALL_GDROM, &invalid, 2);
|
||||
/*boot_write(boot, SYSCALL_MENU, &invalid, 2);*/
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void bios_destroy(struct bios *bios) {
|
||||
free(bios);
|
||||
}
|
||||
|
||||
struct bios *bios_create(struct dreamcast *dc) {
|
||||
struct bios *bios =
|
||||
dc_create_device(dc, sizeof(struct bios), "bios", &bios_init);
|
||||
dc_create_device(dc, sizeof(struct bios), "bios", NULL, &bios_post_init);
|
||||
return bios;
|
||||
}
|
||||
|
|
|
@ -18,9 +18,7 @@ struct bios {
|
|||
struct bios *bios_create(struct dreamcast *dc);
|
||||
void bios_destroy(struct bios *bios);
|
||||
|
||||
int bios_preboot(struct bios *bios);
|
||||
int bios_invalid_instr(struct bios *bios);
|
||||
|
||||
void bios_debug_menu(struct bios *bios);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -70,28 +70,28 @@ void dc_suspend(struct dreamcast *dc) {
|
|||
dc->running = 0;
|
||||
}
|
||||
|
||||
int dc_load(struct dreamcast *dc, const char *path) {
|
||||
struct disc *disc = NULL;
|
||||
int dc_running(struct dreamcast *dc) {
|
||||
return dc->running;
|
||||
}
|
||||
|
||||
int dc_load(struct dreamcast *dc, const char *path) {
|
||||
if (path) {
|
||||
LOG_INFO("dc_load path=%s", path);
|
||||
|
||||
struct disc *disc = disc_create(path);
|
||||
|
||||
if (!disc) {
|
||||
LOG_WARNING("dc_load failed");
|
||||
LOG_WARNING("dc_load_game failed");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* boot to bios bootstrap if disc is valid */
|
||||
gdrom_set_disc(dc->gdrom, disc);
|
||||
bios_preboot(dc->bios);
|
||||
sh4_reset(dc->sh4, 0xa0000000);
|
||||
} else {
|
||||
/* boot to main menu of no path specified */
|
||||
bios_preboot(dc->bios);
|
||||
sh4_reset(dc->sh4, 0xa0000000);
|
||||
LOG_INFO("dc_load no path supplied, loading bios");
|
||||
}
|
||||
|
||||
/* boot to bios bootstrap */
|
||||
sh4_reset(dc->sh4, 0xa0000000);
|
||||
dc_resume(dc);
|
||||
|
||||
return 1;
|
||||
|
@ -129,8 +129,15 @@ int dc_init(struct dreamcast *dc) {
|
|||
|
||||
/* initialize each device */
|
||||
list_for_each_entry(dev, &dc->devices, struct device, it) {
|
||||
if (!dev->init(dev)) {
|
||||
LOG_WARNING("dc_init failed to initialize device '%s'", dev->name);
|
||||
if (dev->init && !dev->init(dev)) {
|
||||
LOG_WARNING("dc_init init callback failed for '%s'", dev->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
list_for_each_entry(dev, &dc->devices, struct device, it) {
|
||||
if (dev->post_init && !dev->post_init(dev)) {
|
||||
LOG_WARNING("dc_init post_init callback failed for '%s'", dev->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -200,12 +207,13 @@ struct device *dc_get_device(struct dreamcast *dc, const char *name) {
|
|||
}
|
||||
|
||||
void *dc_create_device(struct dreamcast *dc, size_t size, const char *name,
|
||||
device_init_cb init) {
|
||||
device_init_cb init, device_post_init_cb post_init) {
|
||||
struct device *dev = calloc(1, size);
|
||||
|
||||
dev->dc = dc;
|
||||
dev->name = name;
|
||||
dev->init = init;
|
||||
dev->post_init = post_init;
|
||||
|
||||
list_add(&dc->devices, &dev->it);
|
||||
|
||||
|
|
|
@ -89,12 +89,21 @@ struct memory_interface {
|
|||
* device
|
||||
*/
|
||||
typedef int (*device_init_cb)(struct device *);
|
||||
typedef int (*device_post_init_cb)(struct device *);
|
||||
|
||||
struct device {
|
||||
struct dreamcast *dc;
|
||||
const char *name;
|
||||
|
||||
/* called for each device during dc_init. at this point each device should
|
||||
initialize their own state, but not depend on the state of others */
|
||||
device_init_cb init;
|
||||
|
||||
/* called for each device during dc_init, immediately after each device's
|
||||
init callback has been called. devices should perform initialization
|
||||
that depends on other device's state here */
|
||||
device_post_init_cb post_init;
|
||||
|
||||
/* optional interfaces */
|
||||
struct debug_interface *debug_if;
|
||||
struct execute_interface *execute_if;
|
||||
|
@ -161,7 +170,7 @@ struct dreamcast *dc_create();
|
|||
void dc_destroy(struct dreamcast *dc);
|
||||
|
||||
void *dc_create_device(struct dreamcast *dc, size_t size, const char *name,
|
||||
device_init_cb init);
|
||||
device_init_cb init, device_post_init_cb post_init);
|
||||
struct device *dc_get_device(struct dreamcast *dc, const char *name);
|
||||
void dc_destroy_device(struct device *dev);
|
||||
|
||||
|
@ -183,6 +192,7 @@ void dc_destroy_memory_interface(struct memory_interface *memory);
|
|||
|
||||
int dc_init(struct dreamcast *dc);
|
||||
int dc_load(struct dreamcast *dc, const char *path);
|
||||
int dc_running(struct dreamcast *dc);
|
||||
void dc_suspend(struct dreamcast *dc);
|
||||
void dc_resume(struct dreamcast *dc);
|
||||
void dc_tick(struct dreamcast *dc, int64_t ns);
|
||||
|
|
|
@ -6,6 +6,14 @@
|
|||
#include "guest/gdrom/gdi.h"
|
||||
#include "guest/gdrom/iso.h"
|
||||
|
||||
/* ip.bin layout */
|
||||
#define IP_OFFSET_META 0x0000 /* meta information */
|
||||
#define IP_OFFSET_TOC 0x0100 /* table of contents */
|
||||
#define IP_OFFSET_LICENSE 0x0300 /* license screen code */
|
||||
#define IP_OFFSET_AREAS 0x3700 /* area protection symbols */
|
||||
#define IP_OFFSET_BOOT1 0x3800 /* bootstrap 1 */
|
||||
#define IP_OFFSET_BOOT2 0x6000 /* bootstrap 2 */
|
||||
|
||||
/* meta information found in the ip.bin */
|
||||
struct disc_meta {
|
||||
char hardware_id[16];
|
||||
|
@ -31,6 +39,31 @@ static void disc_get_meta(struct disc *disc, struct disc_meta *meta) {
|
|||
memcpy(meta, tmp, sizeof(*meta));
|
||||
}
|
||||
|
||||
static void disc_patch_regions(struct disc *disc, int fad, uint8_t *data) {
|
||||
/* patch discs to boot in all regions by patching data read from the disk. for
|
||||
a disc to be boot for a region, the region must be enabled in two places:
|
||||
|
||||
1.) in the meta information section of the ip.bin
|
||||
2.) in the area protection symbols section of the ip.bin */
|
||||
if (fad == disc->meta_fad) {
|
||||
/* the area symbols in the meta information contains 8 characters, each of
|
||||
which is either a space, or the first letter of the area if supported */
|
||||
struct disc_meta *meta = (struct disc_meta *)data;
|
||||
strncpy_pad_spaces(meta->area_symbols, "JUE", sizeof(meta->area_symbols));
|
||||
} else if (fad == disc->area_fad) {
|
||||
/* the area protection symbols section contains 8 slots, each of which is
|
||||
either spaces, or the name of the area if supported. note, each slot
|
||||
has a 4-byte code prefix which jumps past it as part of the bootstrap
|
||||
control flow */
|
||||
char *slot0 = (char *)data;
|
||||
char *slot1 = (char *)data + 32;
|
||||
char *slot2 = (char *)data + 64;
|
||||
strncpy_pad_spaces(slot0 + 4, "For JAPAN,TAIWAN,PHILIPINES.", 28);
|
||||
strncpy_pad_spaces(slot1 + 4, "For USA and CANADA.", 28);
|
||||
strncpy_pad_spaces(slot2 + 4, "For EUROPE.", 28);
|
||||
}
|
||||
}
|
||||
|
||||
int disc_read_bytes(struct disc *disc, int fad, int len, uint8_t *dst,
|
||||
int dst_size) {
|
||||
CHECK_LE(len, dst_size);
|
||||
|
@ -69,6 +102,7 @@ int disc_read_sectors(struct disc *disc, int fad, int num_sectors,
|
|||
for (int i = fad; i < endfad; i++) {
|
||||
CHECK_LE(read + track->data_size, dst_size);
|
||||
disc->read_sector(disc, track, i, dst + read);
|
||||
disc_patch_regions(disc, i, dst + read);
|
||||
read += track->data_size;
|
||||
}
|
||||
|
||||
|
@ -205,6 +239,13 @@ struct disc *disc_create(const char *filename) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
/* cache off information about the IP.BIN file location for region patching */
|
||||
struct session *session = disc_get_session(disc, 1);
|
||||
struct track *first_track = disc_get_track(disc, session->first_track);
|
||||
disc->meta_fad = first_track->fad;
|
||||
disc->area_fad = first_track->fad + IP_OFFSET_AREAS / first_track->data_size;
|
||||
disc->area_off = IP_OFFSET_AREAS % first_track->data_size;
|
||||
|
||||
/* extract meta information from the IP.BIN */
|
||||
struct disc_meta meta;
|
||||
disc_get_meta(disc, &meta);
|
||||
|
@ -219,20 +260,6 @@ struct disc *disc_create(const char *filename) {
|
|||
sizeof(meta.device_info) - 5);
|
||||
strncpy_trim_space(disc->bootname, meta.bootname, sizeof(meta.bootname));
|
||||
|
||||
/* the area symbols array contains characters, which are either a space or a
|
||||
specific character corresponding to a particular region the disc is valid
|
||||
for. if the character for a particular region is a space, the disc is not
|
||||
valid for that region */
|
||||
if (meta.area_symbols[0] == 'J') {
|
||||
disc->regions |= DISC_REGION_JAPAN;
|
||||
}
|
||||
if (meta.area_symbols[1] == 'U') {
|
||||
disc->regions |= DISC_REGION_USA;
|
||||
}
|
||||
if (meta.area_symbols[2] == 'E') {
|
||||
disc->regions |= DISC_REGION_EUROPE;
|
||||
}
|
||||
|
||||
/* generate unique id for the disc */
|
||||
snprintf(disc->uid, sizeof(disc->uid), "%s %s %s %s", disc->product_name,
|
||||
disc->product_number, disc->product_version, disc->media_config);
|
||||
|
|
|
@ -44,6 +44,12 @@ struct session {
|
|||
};
|
||||
|
||||
struct disc {
|
||||
/* information about the IP.BIN location on disc, cached to quickly patch
|
||||
region information */
|
||||
int meta_fad;
|
||||
int area_fad;
|
||||
int area_off;
|
||||
|
||||
/* meta information extracted from IP.BIN */
|
||||
char uid[DISC_UID_SIZE];
|
||||
char product_name[DISC_STRING_SIZE];
|
||||
|
@ -51,7 +57,6 @@ struct disc {
|
|||
char product_version[7];
|
||||
char media_config[12];
|
||||
char bootname[17];
|
||||
int regions;
|
||||
|
||||
/* media-specific interface */
|
||||
void (*destroy)(struct disc *);
|
||||
|
|
|
@ -527,12 +527,6 @@ void gdrom_get_bootfile(struct gdrom *gd, int *fad, int *len) {
|
|||
CHECK(res);
|
||||
}
|
||||
|
||||
int gdrom_get_regions(struct gdrom *gd) {
|
||||
CHECK_NOTNULL(gd->disc);
|
||||
|
||||
return gd->disc->regions;
|
||||
}
|
||||
|
||||
void gdrom_get_subcode(struct gdrom *gd, int format, uint8_t *data, int size) {
|
||||
CHECK_NOTNULL(gd->disc);
|
||||
CHECK_GE(size, GD_SPI_SCD_SIZE);
|
||||
|
@ -726,7 +720,7 @@ void gdrom_destroy(struct gdrom *gd) {
|
|||
|
||||
struct gdrom *gdrom_create(struct dreamcast *dc) {
|
||||
struct gdrom *gd =
|
||||
dc_create_device(dc, sizeof(struct gdrom), "gdrom", &gdrom_init);
|
||||
dc_create_device(dc, sizeof(struct gdrom), "gdrom", &gdrom_init, NULL);
|
||||
return gd;
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ void gdrom_get_session(struct gdrom *gd, int session,
|
|||
struct gd_spi_session *ses);
|
||||
void gdrom_get_subcode(struct gdrom *gd, int format, uint8_t *data, int size);
|
||||
|
||||
int gdrom_get_regions(struct gdrom *gd);
|
||||
void gdrom_get_bootfile(struct gdrom *gd, int *fad, int *len);
|
||||
|
||||
int gdrom_find_file(struct gdrom *gd, const char *filename, int *fad, int *len);
|
||||
|
|
|
@ -390,7 +390,7 @@ void holly_destroy(struct holly *hl) {
|
|||
|
||||
struct holly *holly_create(struct dreamcast *dc) {
|
||||
struct holly *hl =
|
||||
dc_create_device(dc, sizeof(struct holly), "holly", &holly_init);
|
||||
dc_create_device(dc, sizeof(struct holly), "holly", &holly_init, NULL);
|
||||
|
||||
/* init registers */
|
||||
#define HOLLY_REG(addr, name, default, type) \
|
||||
|
|
|
@ -139,7 +139,7 @@ void maple_destroy(struct maple *mp) {
|
|||
|
||||
struct maple *maple_create(struct dreamcast *dc) {
|
||||
struct maple *mp =
|
||||
dc_create_device(dc, sizeof(struct maple), "maple", &maple_init);
|
||||
dc_create_device(dc, sizeof(struct maple), "maple", &maple_init, NULL);
|
||||
|
||||
/* register a controller and vmu for all ports by default */
|
||||
for (int i = 0; i < MAPLE_NUM_PORTS; i++) {
|
||||
|
|
|
@ -246,7 +246,8 @@ void pvr_destroy(struct pvr *pvr) {
|
|||
}
|
||||
|
||||
struct pvr *pvr_create(struct dreamcast *dc) {
|
||||
struct pvr *pvr = dc_create_device(dc, sizeof(struct pvr), "pvr", &pvr_init);
|
||||
struct pvr *pvr =
|
||||
dc_create_device(dc, sizeof(struct pvr), "pvr", &pvr_init, NULL);
|
||||
|
||||
return pvr;
|
||||
}
|
||||
|
|
|
@ -832,7 +832,7 @@ void ta_destroy(struct ta *ta) {
|
|||
struct ta *ta_create(struct dreamcast *dc) {
|
||||
ta_init_tables();
|
||||
|
||||
struct ta *ta = dc_create_device(dc, sizeof(struct ta), "ta", &ta_init);
|
||||
struct ta *ta = dc_create_device(dc, sizeof(struct ta), "ta", &ta_init, NULL);
|
||||
|
||||
return ta;
|
||||
}
|
||||
|
|
|
@ -111,7 +111,7 @@ void boot_destroy(struct boot *boot) {
|
|||
|
||||
struct boot *boot_create(struct dreamcast *dc) {
|
||||
struct boot *boot =
|
||||
dc_create_device(dc, sizeof(struct boot), "boot", &boot_init);
|
||||
dc_create_device(dc, sizeof(struct boot), "boot", &boot_init, NULL);
|
||||
return boot;
|
||||
}
|
||||
|
||||
|
|
|
@ -201,7 +201,7 @@ void flash_destroy(struct flash *flash) {
|
|||
|
||||
struct flash *flash_create(struct dreamcast *dc) {
|
||||
struct flash *flash =
|
||||
dc_create_device(dc, sizeof(struct flash), "flash", &flash_init);
|
||||
dc_create_device(dc, sizeof(struct flash), "flash", &flash_init, NULL);
|
||||
|
||||
return flash;
|
||||
}
|
||||
|
|
|
@ -321,7 +321,8 @@ void sh4_destroy(struct sh4 *sh4) {
|
|||
}
|
||||
|
||||
struct sh4 *sh4_create(struct dreamcast *dc) {
|
||||
struct sh4 *sh4 = dc_create_device(dc, sizeof(struct sh4), "sh", &sh4_init);
|
||||
struct sh4 *sh4 =
|
||||
dc_create_device(dc, sizeof(struct sh4), "sh", &sh4_init, NULL);
|
||||
sh4->debug_if = dc_create_debug_interface(
|
||||
&sh4_dbg_num_registers, &sh4_dbg_step, &sh4_dbg_add_breakpoint,
|
||||
&sh4_dbg_remove_breakpoint, &sh4_dbg_read_memory, &sh4_dbg_read_register);
|
||||
|
|
Loading…
Reference in New Issue