# HG changeset patch # User Michael Pavone # Date 1513187081 28800 # Node ID a763523dadf4ab972ebf193da10e16cdabb2a5b0 # Parent 2564b6ba2e129a3c0930e9eb8fb5d3cde1feb056 Added code for initializing a combined Genesis + Sega CD system when a Sega CD ISO is loaded diff -r 2564b6ba2e12 -r a763523dadf4 genesis.c --- a/genesis.c Tue Dec 12 09:44:33 2017 -0800 +++ b/genesis.c Wed Dec 13 09:44:41 2017 -0800 @@ -4,6 +4,7 @@ BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. */ #include "genesis.h" +#include "segacd.h" #include "blastem.h" #include "nor.h" #include @@ -1086,7 +1087,8 @@ } else { if (gen->header.enter_debugger) { gen->header.enter_debugger = 0; - uint32_t address = gen->cart[2] << 16 | gen->cart[3]; + uint32_t address = read_word(4, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen, gen->m68k) << 16 + | read_word(6, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen, gen->m68k); insert_breakpoint(gen->m68k, address, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter); } m68k_reset(gen->m68k); @@ -1184,7 +1186,7 @@ free(gen); } -genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region) +static genesis_context *shared_init(uint32_t system_opts, rom_info *rom, uint8_t force_region) { static memmap_chunk z80_map[] = { { 0x0000, 0x4000, 0x1FFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL, NULL, NULL, NULL, NULL }, @@ -1193,6 +1195,16 @@ { 0x6000, 0x6100, 0xFFFF, 0, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg}, { 0x7F00, 0x8000, 0x00FF, 0, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} }; + + char *m68k_divider = tern_find_path(config, "clocks\0m68k_divider\0", TVAL_PTR).ptrval; + if (!m68k_divider) { + m68k_divider = "7"; + } + MCLKS_PER_68K = atoi(m68k_divider); + if (!MCLKS_PER_68K) { + MCLKS_PER_68K = 7; + } + genesis_context *gen = calloc(1, sizeof(genesis_context)); gen->header.set_speed_percent = set_speed_percent; gen->header.start_context = start_genesis; @@ -1207,8 +1219,9 @@ gen->header.inc_debug_mode = inc_debug_mode; gen->header.inc_debug_pal = inc_debug_pal; gen->header.type = SYSTEM_GENESIS; + set_region(gen, rom, force_region); - + gen->vdp = malloc(sizeof(vdp_context)); init_vdp_context(gen->vdp, gen->version_reg & 0x40); gen->vdp->system = &gen->header; @@ -1217,7 +1230,7 @@ gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL; gen->int_latency_prev1 = MCLKS_PER_68K * 32; gen->int_latency_prev2 = MCLKS_PER_68K * 16; - + char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0", TVAL_PTR).ptrval; uint32_t lowpass_cutoff = lowpass_cutoff_str ? atoi(lowpass_cutoff_str) : DEFAULT_LOWPASS_CUTOFF; @@ -1241,10 +1254,8 @@ gen->z80->system = gen; gen->z80->mem_pointers[0] = gen->zram; - gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = (uint8_t *)main_rom; - - gen->cart = main_rom; - gen->lock_on = lock_on; + gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = NULL; + gen->work_ram = calloc(2, RAM_WORDS); if (!strcmp("random", tern_find_path_default(config, "system\0ram_init\0", (tern_val){.ptrval = "zero"}, TVAL_PTR).ptrval)) { @@ -1274,8 +1285,19 @@ gen->vdp->vsram[i] = rand(); } } + + return gen; +} + +genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region) +{ + genesis_context *gen = shared_init(system_opts, rom, force_region); + gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = (uint8_t *)main_rom; + + gen->cart = main_rom; + gen->lock_on = lock_on; + setup_io_devices(config, rom, &gen->io); - gen->mapper_type = rom->mapper_type; gen->save_type = rom->save_type; if (gen->save_type != SAVE_NONE) { @@ -1329,23 +1351,22 @@ return gen; } +static memmap_chunk base_map[] = { + {0xE00000, 0x1000000, 0xFFFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL, + NULL, NULL, NULL, NULL}, + {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, 0, NULL, + (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write, + (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b}, + {0xA00000, 0xA12000, 0x1FFFF, 0, 0, 0, NULL, + (read_16_fun)io_read_w, (write_16_fun)io_write_w, + (read_8_fun)io_read, (write_8_fun)io_write} +}; +const size_t base_chunks = sizeof(base_map)/sizeof(*base_map); + genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t ym_opts, uint8_t force_region, rom_info *info_out) { - static memmap_chunk base_map[] = { - {0xE00000, 0x1000000, 0xFFFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL, - NULL, NULL, NULL, NULL}, - {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, 0, NULL, - (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write, - (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b}, - {0xA00000, 0xA12000, 0x1FFFF, 0, 0, 0, NULL, - (read_16_fun)io_read_w, (write_16_fun)io_write_w, - (read_8_fun)io_read, (write_8_fun)io_write} - }; - static tern_node *rom_db; - if (!rom_db) { - rom_db = load_rom_db(); - } - *info_out = configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, sizeof(base_map)/sizeof(base_map[0])); + tern_node *rom_db = get_rom_db(); + *info_out = configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, base_chunks); rom = info_out->rom; rom_size = info_out->rom_size; #ifndef BLASTEM_BIG_ENDIAN @@ -1354,13 +1375,43 @@ byteswap_rom(lock_on_size, lock_on); } #endif - char *m68k_divider = tern_find_path(config, "clocks\0m68k_divider\0", TVAL_PTR).ptrval; - if (!m68k_divider) { - m68k_divider = "7"; - } - MCLKS_PER_68K = atoi(m68k_divider); - if (!MCLKS_PER_68K) { - MCLKS_PER_68K = 7; - } return alloc_init_genesis(info_out, rom, lock_on, ym_opts, force_region); } + +genesis_context *alloc_config_genesis_cdboot(system_media *media, uint32_t system_opts, uint8_t force_region, rom_info *info_out) +{ + segacd_context *cd = alloc_configure_segacd(media, system_opts, force_region, info_out); + genesis_context *gen = shared_init(system_opts, info_out, force_region); + gen->cart = gen->lock_on = NULL; + gen->save_storage = NULL; + gen->save_type = SAVE_NONE; + gen->version_reg &= ~NO_DISK; + + gen->expansion = cd; + setup_io_devices(config, info_out, &gen->io); + + uint32_t cd_chunks; + memmap_chunk *cd_map = segacd_main_cpu_map(gen->expansion, &cd_chunks); + memmap_chunk *map = malloc(sizeof(memmap_chunk) * (cd_chunks + base_chunks)); + memcpy(map, cd_map, sizeof(memmap_chunk) * cd_chunks); + memcpy(map + cd_chunks, base_map, sizeof(memmap_chunk) * base_chunks); + map[cd_chunks].buffer = gen->work_ram; + uint32_t num_chunks = cd_chunks + base_chunks; + + m68k_options *opts = malloc(sizeof(m68k_options)); + init_m68k_opts(opts, map, num_chunks, MCLKS_PER_68K); + //TODO: make this configurable + opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY; + gen->m68k = init_68k_context(opts, NULL); + gen->m68k->system = gen; + opts->address_log = (system_opts & OPT_ADDRESS_LOG) ? fopen("address.log", "w") : NULL; + + //This must happen after the 68K context has been allocated + for (int i = 0; i < num_chunks; i++) + { + if (map[i].flags & MMAP_PTR_IDX) { + gen->m68k->mem_pointers[map[i].ptr_index] = map[i].buffer; + } + } + return gen; +} diff -r 2564b6ba2e12 -r a763523dadf4 genesis.h --- a/genesis.h Tue Dec 12 09:44:33 2017 -0800 +++ b/genesis.h Wed Dec 13 09:44:41 2017 -0800 @@ -63,6 +63,7 @@ uint16_t read_dma_value(uint32_t address); m68k_context * sync_components(m68k_context *context, uint32_t address); genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t system_opts, uint8_t force_region, rom_info *info_out); +genesis_context *alloc_config_genesis_cdboot(system_media *media, uint32_t opts, uint8_t force_region, rom_info *info_out); void genesis_serialize(genesis_context *gen, serialize_buffer *buf, uint32_t m68k_pc); void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen); diff -r 2564b6ba2e12 -r a763523dadf4 romdb.c --- a/romdb.c Tue Dec 12 09:44:33 2017 -0800 +++ b/romdb.c Wed Dec 13 09:44:41 2017 -0800 @@ -33,11 +33,14 @@ return "SRAM"; } -tern_node *load_rom_db() +tern_node *get_rom_db() { - tern_node *db = parse_bundled_config("rom.db"); + static tern_node *db; if (!db) { - fatal_error("Failed to load ROM DB\n"); + db = parse_bundled_config("rom.db"); + if (!db) { + fatal_error("Failed to load ROM DB\n"); + } } return db; } diff -r 2564b6ba2e12 -r a763523dadf4 romdb.h --- a/romdb.h Tue Dec 12 09:44:33 2017 -0800 +++ b/romdb.h Wed Dec 13 09:44:41 2017 -0800 @@ -79,7 +79,7 @@ #define GAME_ID_OFF 0x183 #define GAME_ID_LEN 8 -tern_node *load_rom_db(); +tern_node *get_rom_db(); rom_info configure_rom(tern_node *rom_db, void *vrom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, memmap_chunk const *base_map, uint32_t base_chunks); rom_info configure_rom_heuristics(uint8_t *rom, uint32_t rom_size, memmap_chunk const *base_map, uint32_t base_chunks); uint8_t translate_region_char(uint8_t c); diff -r 2564b6ba2e12 -r a763523dadf4 segacd.c --- a/segacd.c Tue Dec 12 09:44:33 2017 -0800 +++ b/segacd.c Wed Dec 13 09:44:41 2017 -0800 @@ -203,6 +203,7 @@ {0xFF0000, 0xFF7FFF, 0x0000, .read_16 = pcm_read16, .write_16 = pcm_write16, .read_8 = pcm_read8, .write_8 = pcm_write8}, {0xFF8000, 0xFF81FF, 0x0000, .read_16 = sub_gate_read16, .write_16 = sub_gate_write16, .read_8 = sub_gate_read8, .write_8 = sub_gate_write8} }; + memset(info, 0, sizeof(*info)); segacd_context *cd = calloc(sizeof(segacd_context), 1); FILE *f = fopen("cdbios.bin", "rb"); if (!f) { @@ -215,8 +216,12 @@ fatal_error("Failed to read CD firmware"); } cd->rom_mut = malloc(adjusted_size); + byteswap_rom(adjusted_size, cd->rom); memcpy(cd->rom_mut, cd->rom, adjusted_size); - byteswap_rom(firmware_size, cd->rom); + + tern_node *db = get_rom_db(); + *info = configure_rom(db, media->buffer, media->size, media->chain ? media->chain->buffer : NULL, media->chain ? media->chain->size : 0, NULL, 0); + cd->prog_ram = malloc(512*1024); cd->work_ram = malloc(256*1024); cd->pcm_ram = malloc(64*1024); @@ -238,7 +243,7 @@ memmap_chunk *segacd_main_cpu_map(segacd_context *cd, uint32_t *num_chunks) { static memmap_chunk main_cpu_map[] = { - {0x000000, 0x01FFFF, 0x00000, .flags=MMAP_READ}, + {0x000000, 0x01FFFF, 0xFFFFFF, .flags=MMAP_READ}, {0x020000, 0x03FFFF, 0x1FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL, .ptr_index = 0},//TODO: support running main CPU code from here {0x040000, 0x05FFFF, 0x1FFFF, .flags=MMAP_READ}, //first ROM alias //TODO: additional ROM/prog RAM aliases diff -r 2564b6ba2e12 -r a763523dadf4 segacd.h --- a/segacd.h Tue Dec 12 09:44:33 2017 -0800 +++ b/segacd.h Wed Dec 13 09:44:41 2017 -0800 @@ -20,5 +20,6 @@ } segacd_context; segacd_context *alloc_configure_segacd(system_media *media, uint32_t opts, uint8_t force_region, rom_info *info); +memmap_chunk *segacd_main_cpu_map(segacd_context *cd, uint32_t *num_chunks); #endif //SEGACD_H_ diff -r 2564b6ba2e12 -r a763523dadf4 system.c --- a/system.c Tue Dec 12 09:44:33 2017 -0800 +++ b/system.c Wed Dec 13 09:44:41 2017 -0800 @@ -12,7 +12,11 @@ system_type detect_system_type(system_media *media) { if (safe_cmp("SEGA", 0x100, media->buffer, media->size)) { - //TODO: Differentiate between vanilla Genesis and Sega CD/32X games + //TODO: support other bootable identifiers + if (safe_cmp("SEGADISCSYSTEM", 0, media->buffer, media->size)) { + return SYSTEM_SEGACD; + } + //TODO: Differentiate between vanilla Genesis and 32X games return SYSTEM_GENESIS; } if (safe_cmp("TMR SEGA", 0x1FF0, media->buffer, media->size) @@ -60,6 +64,8 @@ { case SYSTEM_GENESIS: return &(alloc_config_genesis(media->buffer, media->size, lock_on, lock_on_size, opts, force_region, info_out))->header; + case SYSTEM_SEGACD: + return &(alloc_config_genesis_cdboot(media, opts, force_region, info_out))->header; #ifndef NO_Z80 case SYSTEM_SMS: return &(alloc_configure_sms(media, opts, force_region, info_out))->header;