# HG changeset patch # User Michael Pavone # Date 1642281321 28800 # Node ID 3414a4423de1d1803d2b9045f9639ddfb0505497 # Parent 5dacaef602a7a4f802b3a5cf500a0f8ed2de0d4f# Parent 3748a2a8a4b7812b61d3de5050ab806678becb0f Merge from default diff -r 3748a2a8a4b7 -r 3414a4423de1 Makefile --- a/Makefile Sat Jan 01 18:54:46 2022 -0800 +++ b/Makefile Sat Jan 15 13:15:21 2022 -0800 @@ -214,11 +214,11 @@ MAINOBJS=blastem.o system.o genesis.o debug.o gdb_remote.o vdp.o $(RENDEROBJS) io.o romdb.o hash.o menu.o xband.o \ realtec.o i2c.o nor.o sega_mapper.o multi_game.o megawifi.o $(NET) serialize.o $(TERMINAL) $(CONFIGOBJS) gst.o \ - $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) saves.o zip.o bindings.o jcart.o gen_player.o + $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) saves.o zip.o bindings.o jcart.o gen_player.o segacd.o LIBOBJS=libblastem.o system.o genesis.o debug.o gdb_remote.o vdp.o io.o romdb.o hash.o xband.o realtec.o \ i2c.o nor.o sega_mapper.o multi_game.o megawifi.o $(NET) serialize.o $(TERMINAL) $(CONFIGOBJS) gst.o \ - $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) saves.o jcart.o rom.db.o gen_player.o $(LIBZOBJS) + $(M68KOBJS) $(TRANSOBJS) $(AUDIOOBJS) saves.o jcart.o rom.db.o gen_player.o segacd.o $(LIBZOBJS) ifdef NONUKLEAR CFLAGS+= -DDISABLE_NUKLEAR @@ -339,7 +339,7 @@ vos_prog_info : vos_prog_info.o vos_program_module.o $(CC) -o vos_prog_info vos_prog_info.o vos_program_module.o - + m68k.c : m68k.cpu cpu_dsl.py ./cpu_dsl.py -d call $< > $@ diff -r 3748a2a8a4b7 -r 3414a4423de1 blastem.c --- a/blastem.c Sat Jan 01 18:54:46 2022 -0800 +++ b/blastem.c Sat Jan 15 13:15:21 2022 -0800 @@ -91,7 +91,7 @@ size_t readsize = 0; uint16_t *dst, *buf; dst = buf = malloc(filesize); - + size_t read; do { @@ -107,9 +107,9 @@ } } while(read > 0); romclose(f); - + *buffer = buf; - + return readsize; } @@ -132,7 +132,7 @@ return 0; } -uint32_t load_rom_zip(const char *filename, void **dst) +uint32_t load_media_zip(const char *filename, system_media *dst) { static const char *valid_exts[] = {"bin", "md", "gen", "sms", "rom", "smd"}; const uint32_t num_exts = sizeof(valid_exts)/sizeof(*valid_exts); @@ -140,7 +140,7 @@ if (!z) { return 0; } - + for (uint32_t i = 0; i < z->num_entries; i++) { char *ext = path_extension(z->entries[i].name); @@ -151,20 +151,23 @@ { if (!strcasecmp(ext, valid_exts[j])) { size_t out_size = nearest_pow2(z->entries[i].size); - *dst = zip_read(z, i, &out_size); - if (*dst) { - if (is_smd_format(z->entries[i].name, *dst)) { + dst->buffer = zip_read(z, i, &out_size); + if (dst->buffer) { + if (is_smd_format(z->entries[i].name, dst->buffer)) { size_t offset; for (offset = 0; offset + SMD_BLOCK_SIZE + SMD_HEADER_SIZE <= out_size; offset += SMD_BLOCK_SIZE) { uint8_t tmp[SMD_BLOCK_SIZE]; - uint8_t *u8dst = *dst; + uint8_t *u8dst = dst->buffer; memcpy(tmp, u8dst + offset + SMD_HEADER_SIZE, SMD_BLOCK_SIZE); process_smd_block((void *)(u8dst + offset), tmp, SMD_BLOCK_SIZE); } out_size = offset; } - free(ext); + dst->extension = ext; + dst->dir = path_dirname(filename); + dst->name = basename_no_extension(filename); + dst->size = out_size; zip_close(z); return out_size; } @@ -176,13 +179,13 @@ return 0; } -uint32_t load_rom(const char * filename, void **dst, system_type *stype) +uint32_t load_media(const char * filename, system_media *dst, system_type *stype) { uint8_t header[10]; char *ext = path_extension(filename); if (ext && !strcasecmp(ext, "zip")) { free(ext); - return load_rom_zip(filename, dst); + return load_media_zip(filename, dst); } free(ext); ROMFILE f = romopen(filename, "rb"); @@ -192,42 +195,49 @@ if (sizeof(header) != romread(header, 1, sizeof(header), f)) { fatal_error("Error reading from %s\n", filename); } - + + uint32_t ret = 0; if (is_smd_format(filename, header)) { - if (stype) { - *stype = SYSTEM_GENESIS; + if (stype) { + *stype = SYSTEM_GENESIS; + } + ret = load_smd_rom(f, &dst->buffer); } - return load_smd_rom(f, dst); - } - - size_t filesize = 512 * 1024; - size_t readsize = sizeof(header); - - char *buf = malloc(filesize); - memcpy(buf, header, readsize); - - size_t read; - do { - read = romread(buf + readsize, 1, filesize - readsize, f); - if (read > 0) { - readsize += read; - if (readsize == filesize) { - int one_more = romgetc(f); - if (one_more >= 0) { - filesize *= 2; - buf = realloc(buf, filesize); - buf[readsize++] = one_more; - } else { - read = 0; + + if (!ret) { + size_t filesize = 512 * 1024; + size_t readsize = sizeof(header); + + char *buf = malloc(filesize); + memcpy(buf, header, readsize); + + size_t read; + do { + read = romread(buf + readsize, 1, filesize - readsize, f); + if (read > 0) { + readsize += read; + if (readsize == filesize) { + int one_more = romgetc(f); + if (one_more >= 0) { + filesize *= 2; + buf = realloc(buf, filesize); + buf[readsize++] = one_more; + } else { + read = 0; + } } } - } - } while (read > 0); - - *dst = buf; - + } while (read > 0); + dst->buffer = buf; + ret = (uint32_t)readsize; + } + dst->dir = path_dirname(filename); + dst->name = basename_no_extension(filename); + dst->extension = path_extension(filename); + dst->size = ret; + romclose(f); - return readsize; + return ret; } @@ -389,10 +399,7 @@ free(lock_on.dir); free(lock_on.name); free(lock_on.extension); - lock_on.dir = path_dirname(lock_on_path); - lock_on.name = basename_no_extension(lock_on_path); - lock_on.extension = path_extension(lock_on_path); - lock_on.size = load_rom(lock_on_path, &lock_on.buffer, NULL); + load_media(lock_on_path, &lock_on, NULL); } static uint32_t opts = 0; @@ -411,16 +418,14 @@ //start a new arena and save old one in suspended system context current_system->arena = start_new_arena(); } - system_type stype = SYSTEM_UNKNOWN; - if (!(cart.size = load_rom(path, &cart.buffer, &stype))) { - fatal_error("Failed to open %s for reading\n", path); - } free(cart.dir); free(cart.name); free(cart.extension); - cart.dir = path_dirname(path); - cart.name = basename_no_extension(path); - cart.extension = path_extension(path); + system_type stype = SYSTEM_UNKNOWN; + if (!(cart.size = load_media(path, &cart, &stype))) { + fatal_error("Failed to open %s for reading\n", path); + } + if (force_stype != SYSTEM_UNKNOWN) { stype = force_stype; } @@ -572,12 +577,9 @@ if (i >= argc) { fatal_error("-o must be followed by a lock on cartridge filename\n"); } - lock_on.size = load_rom(argv[i], &lock_on.buffer, NULL); - if (!lock_on.size) { + if (!load_media(argv[i], &lock_on, NULL)) { fatal_error("Failed to load lock on cartridge %s\n", argv[i]); } - lock_on.name = basename_no_extension(argv[i]); - lock_on.extension = path_extension(argv[i]); cart.chain = &lock_on; break; } @@ -611,12 +613,9 @@ if (reader_port) { reader_addr = argv[i]; } else { - if (!(cart.size = load_rom(argv[i], &cart.buffer, stype == SYSTEM_UNKNOWN ? &stype : NULL))) { - fatal_error("Failed to open %s for reading\n", argv[i]); - } - cart.dir = path_dirname(argv[i]); - cart.name = basename_no_extension(argv[i]); - cart.extension = path_extension(argv[i]); + if (!load_media(argv[i], &cart, stype == SYSTEM_UNKNOWN ? &stype : NULL)) { + fatal_error("Failed to open %s for reading\n", argv[i]); + } } romfname = argv[i]; loaded = 1; @@ -626,7 +625,7 @@ height = atoi(argv[i]); } } - + int def_width = 0, def_height = 0; char *config_width = tern_find_path(config, "video\0width\0", TVAL_PTR).ptrval; if (config_width) { @@ -657,7 +656,7 @@ render_set_drag_drop_handler(on_drag_drop); } set_bindings(); - + uint8_t menu = !loaded; uint8_t use_nuklear = 0; #ifndef DISABLE_NUKLEAR @@ -670,7 +669,7 @@ romfname = "menu.bin"; } if (is_absolute_path(romfname)) { - if (!(cart.size = load_rom(romfname, &cart.buffer, &stype))) { + if (!(cart.size = load_media(romfname, &cart, &stype))) { fatal_error("Failed to open UI ROM %s for reading", romfname); } } else { @@ -683,12 +682,12 @@ cart.buffer = realloc(cart.buffer, rom_size); cart.size = rom_size; } + cart.dir = path_dirname(romfname); + cart.name = basename_no_extension(romfname); + cart.extension = path_extension(romfname); } //force system detection, value on command line is only for games not the menu stype = detect_system_type(&cart); - cart.dir = path_dirname(romfname); - cart.name = basename_no_extension(romfname); - cart.extension = path_extension(romfname); loaded = 1; } char *state_format = tern_find_path(config, "ui\0state_format\0", TVAL_PTR).ptrval; @@ -705,12 +704,12 @@ if (stype == SYSTEM_UNKNOWN) { fatal_error("Failed to detect system type for %s\n", romfname); } - + current_system = alloc_config_system(stype, &cart, menu ? 0 : opts, force_region); if (!current_system) { fatal_error("Failed to configure emulated machine for %s\n", romfname); } - + setup_saves(&cart, current_system); update_title(current_system->info.name); if (menu) { @@ -719,7 +718,7 @@ game_system = current_system; } } - + #ifndef DISABLE_NUKLEAR if (use_nuklear) { blastem_nuklear_init(!menu); @@ -740,7 +739,7 @@ setup_saves(&cart, current_system); update_title(current_system->info.name); } - + current_system->debugger_type = dtype; current_system->enter_debugger = start_in_debugger && menu == debug_target; current_system->start_context(current_system, menu ? NULL : statefile); diff -r 3748a2a8a4b7 -r 3414a4423de1 genesis.c --- a/genesis.c Sat Jan 01 18:54:46 2022 -0800 +++ b/genesis.c Sat Jan 15 13:15:21 2022 -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 @@ -1410,7 +1411,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); @@ -1747,7 +1749,7 @@ return context; } -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 }, @@ -1756,6 +1758,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; @@ -1831,10 +1843,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->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = NULL; - gen->cart = main_rom; - gen->lock_on = lock_on; 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)) { @@ -1864,9 +1874,20 @@ 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->header.has_keyboard = io_has_keyboard(&gen->io); - gen->mapper_type = rom->mapper_type; gen->save_type = rom->save_type; if (gen->save_type != SAVE_NONE) { @@ -1887,6 +1908,9 @@ gen->mapper_start_index = rom->mapper_start_index; + tern_node *model = get_model(config, SYSTEM_GENESIS); + uint8_t tmss = !strcmp(tern_find_ptr_default(model, "tmss", "off"), "on"); + //This must happen before we generate memory access functions in init_m68k_opts uint8_t next_ptr_index = 0; uint32_t tmss_min_alloc = 16 * 1024; @@ -2055,8 +2079,6 @@ return gen; } -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) -{ static memmap_chunk base_map[] = { {0xE00000, 0x1000000, 0xFFFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL, NULL, NULL, NULL, NULL}, @@ -2070,11 +2092,12 @@ (read_16_fun)unused_read, (write_16_fun)unused_write, (read_8_fun)unused_read_b, (write_8_fun)unused_write_b} }; - static tern_node *rom_db; - if (!rom_db) { - rom_db = load_rom_db(); - } - rom_info info = configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, sizeof(base_map)/sizeof(base_map[0])); +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) +{ + tern_node *rom_db = get_rom_db(); + rom_info info = configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, base_chunks); rom = info.rom; rom_size = info.rom_size; #ifndef BLASTEM_BIG_ENDIAN @@ -2093,3 +2116,44 @@ } return alloc_init_genesis(&info, rom, lock_on, ym_opts, force_region); } + +genesis_context *alloc_config_genesis_cdboot(system_media *media, uint32_t system_opts, uint8_t force_region) +{ + tern_node *rom_db = get_rom_db(); + rom_info info = configure_rom(rom_db, media->buffer, media->size, NULL, 0, base_map, base_chunks); + + segacd_context *cd = alloc_configure_segacd(media, system_opts, force_region, &info); + genesis_context *gen = shared_init(system_opts, &info, 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, &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 3748a2a8a4b7 -r 3414a4423de1 genesis.h --- a/genesis.h Sat Jan 01 18:54:46 2022 -0800 +++ b/genesis.h Sat Jan 15 13:15:21 2022 -0800 @@ -35,6 +35,7 @@ uint16_t *lock_on; uint16_t *work_ram; uint8_t *zram; + void *expansion; void *extra; uint8_t *save_storage; void *mapper_temp; @@ -82,6 +83,7 @@ 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); +genesis_context *alloc_config_genesis_cdboot(system_media *media, uint32_t system_opts, uint8_t force_region); void genesis_serialize(genesis_context *gen, serialize_buffer *buf, uint32_t m68k_pc, uint8_t all); void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen); diff -r 3748a2a8a4b7 -r 3414a4423de1 romdb.c --- a/romdb.c Sat Jan 01 18:54:46 2022 -0800 +++ b/romdb.c Sat Jan 15 13:15:21 2022 -0800 @@ -38,11 +38,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 3748a2a8a4b7 -r 3414a4423de1 romdb.h --- a/romdb.h Sat Jan 01 18:54:46 2022 -0800 +++ b/romdb.h Sat Jan 15 13:15:21 2022 -0800 @@ -84,7 +84,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 3748a2a8a4b7 -r 3414a4423de1 segacd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/segacd.c Sat Jan 15 13:15:21 2022 -0800 @@ -0,0 +1,263 @@ +#include +#include +#include "segacd.h" +#include "genesis.h" +#include "util.h" + +static void *prog_ram_wp_write16(uint32_t address, void *vcontext, uint16_t value) +{ + return vcontext; +} + +static void *prog_ram_wp_write8(uint32_t address, void *vcontext, uint8_t value) +{ + return vcontext; +} + +static uint16_t work_ram_2M_read16(uint32_t address, void *vcontext) +{ + return 0; +} + +static uint8_t work_ram_2M_read8(uint32_t address, void *vcontext) +{ + return 0; +} + +static void *work_ram_2M_write16(uint32_t address, void *vcontext, uint16_t value) +{ + return vcontext; +} + +static void *work_ram_2M_write8(uint32_t address, void *vcontext, uint8_t value) +{ + return vcontext; +} + +static uint16_t work_ram_1M_read16(uint32_t address, void *vcontext) +{ + return 0; +} + +static uint8_t work_ram_1M_read8(uint32_t address, void *vcontext) +{ + return 0; +} + +static void *work_ram_1M_write16(uint32_t address, void *vcontext, uint16_t value) +{ + return vcontext; +} + +static void *work_ram_1M_write8(uint32_t address, void *vcontext, uint8_t value) +{ + return vcontext; +} + +static uint8_t pcm_read8(uint32_t address, void *vcontext) +{ + return 0; +} + +static uint16_t pcm_read16(uint32_t address, void *vcontext) +{ + return 0xFF00 | pcm_read8(address+1, vcontext); +} + +static void *pcm_write8(uint32_t address, void *vcontext, uint8_t value) +{ + return vcontext; +} + +static void *pcm_write16(uint32_t address, void *vcontext, uint16_t value) +{ + return pcm_write8(address+1, vcontext, value); +} + +static uint16_t sub_gate_read16(uint32_t address, void *vcontext) +{ + m68k_context *m68k = vcontext; + segacd_context *cd = m68k->system; + return cd->gate_array[(address & 0x1FF) >> 1]; +} + +static uint8_t sub_gate_read8(uint32_t address, void *vcontext) +{ + m68k_context *m68k = vcontext; + segacd_context *cd = m68k->system; + uint16_t val = cd->gate_array[(address & 0x1FF) >> 1]; + return address & 1 ? val : val >> 8; +} + +static void *sub_gate_write16(uint32_t address, void *vcontext, uint16_t value) +{ + m68k_context *m68k = vcontext; + segacd_context *cd = m68k->system; + uint32_t reg = (address & 0x1FF) >> 1; + switch (reg) + { + case 0x7: + cd->gate_array[reg] &= 0xFF00; + cd->gate_array[reg] |= value & 0xFF; + break; + case 0x10: + case 0x11: + case 0x12: + case 0x13: + case 0x14: + case 0x15: + case 0x16: + case 0x17: + //no effects for these other than saving the value + cd->gate_array[reg] = value; + break; + default: + printf("Unhandled gate array write %X:%X\n", address, value); + } + return vcontext; +} + +static void *sub_gate_write8(uint32_t address, void *vcontext, uint8_t value) +{ + m68k_context *m68k = vcontext; + segacd_context *cd = m68k->system; + uint32_t reg = (address & 0x1FF) >> 1; + uint16_t value16; + if (address & 1) { + value16 = cd->gate_array[reg] & 0xFF00 | value; + } else { + value16 = cd->gate_array[reg] & 0xFF | (value << 8); + } + return sub_gate_write16(address, vcontext, value16); +} + +static uint16_t main_gate_read16(uint32_t address, void *vcontext) +{ + m68k_context *m68k = vcontext; + segacd_context *cd = m68k->system; + return cd->gate_array[(address & 0x1FF) >> 1]; +} + +static uint8_t main_gate_read8(uint32_t address, void *vcontext) +{ + m68k_context *m68k = vcontext; + segacd_context *cd = m68k->system; + uint16_t val = cd->gate_array[(address & 0x1FF) >> 1]; + return address & 1 ? val : val >> 8; +} + +static void *main_gate_write16(uint32_t address, void *vcontext, uint16_t value) +{ + m68k_context *m68k = vcontext; + genesis_context *gen = m68k->system; + segacd_context *cd = gen->expansion; + uint32_t reg = (address & 0x1FF) >> 1; + switch (reg) + { + case 0x7: + cd->gate_array[reg] &= 0xFF; + cd->gate_array[reg] |= value & 0xFF00; + break; + case 0x8: + case 0x9: + case 0xA: + case 0xB: + case 0xC: + case 0xD: + case 0xE: + case 0xF: + //no effects for these other than saving the value + cd->gate_array[reg] = value; + break; + default: + printf("Unhandled gate array write %X:%X\n", address, value); + } + return vcontext; +} + +static void *main_gate_write8(uint32_t address, void *vcontext, uint8_t value) +{ + m68k_context *m68k = vcontext; + genesis_context *gen = m68k->system; + segacd_context *cd = gen->expansion; + uint32_t reg = (address & 0x1FF) >> 1; + uint16_t value16; + if (address & 1) { + value16 = cd->gate_array[reg] & 0xFF00 | value; + } else { + value16 = cd->gate_array[reg] & 0xFF | (value << 8); + } + return main_gate_write16(address, vcontext, value16); +} + +segacd_context *alloc_configure_segacd(system_media *media, uint32_t opts, uint8_t force_region, rom_info *info) +{ + static memmap_chunk sub_cpu_map[] = { + {0x000000, 0x00FEFF, 0x0000, .flags=MMAP_READ | MMAP_CODE, .write_16 = prog_ram_wp_write16, .write_8 = prog_ram_wp_write8}, + {0x00FF00, 0x07FFFF, 0x0000, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE}, + {0x080000, 0x0BFFFF, 0x0000, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 0, + .read_16 = work_ram_2M_read16, .write_16 = work_ram_2M_write16, .read_8 = work_ram_2M_read8, .write_8 = work_ram_2M_write8}, + {0x0C0000, 0x0DFFFF, 0x0000, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 1, + .read_16 = work_ram_1M_read16, .write_16 = work_ram_1M_write16, .read_8 = work_ram_1M_read8, .write_8 = work_ram_1M_write8}, + {0xFE0000, 0xFEFFFF, 0x3FFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_ONLY_ODD}, + {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) { + fatal_error("Failed to open CD firmware for reading"); + } + long firmware_size = file_size(f); + uint32_t adjusted_size = nearest_pow2(firmware_size); + cd->rom = malloc(adjusted_size); + if (firmware_size != fread(cd->rom, 1, firmware_size, f)) { + 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); + + 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); + //TODO: Load state from file + cd->bram = malloc(8*1024); + + sub_cpu_map[0].buffer = sub_cpu_map[1].buffer = cd->prog_ram; + sub_cpu_map[4].buffer = cd->bram; + m68k_options *mopts = malloc(sizeof(m68k_options)); + init_m68k_opts(mopts, sub_cpu_map, sizeof(sub_cpu_map) / sizeof(*sub_cpu_map), 4); + cd->m68k = init_68k_context(mopts, NULL); + cd->m68k->system = cd; + cd->busreq = 1; + cd->busack = 1; + + return cd; +} + +memmap_chunk *segacd_main_cpu_map(segacd_context *cd, uint32_t *num_chunks) +{ + static memmap_chunk main_cpu_map[] = { + {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 + {0x200000, 0x01FFFF, 0x1FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL, .ptr_index = 1}, + {0x220000, 0x03FFFF, 0x1FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL, .ptr_index = 2}, + {0xA12000, 0xA12FFF, 0xFFFFFF, .read_16 = main_gate_read16, .write_16 = main_gate_write16, .read_8 = main_gate_read8, .write_8 = main_gate_write8} + }; + //TODO: support cart boot maps + //TODO: support BRAM cart + main_cpu_map[0].buffer = cd->rom_mut; + main_cpu_map[2].buffer = cd->rom; + main_cpu_map[1].buffer = cd->prog_ram; + main_cpu_map[3].buffer = cd->work_ram; + main_cpu_map[3].buffer = cd->work_ram + 0x10000; + *num_chunks = sizeof(main_cpu_map) / sizeof(*main_cpu_map); + return main_cpu_map; +} diff -r 3748a2a8a4b7 -r 3414a4423de1 segacd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/segacd.h Sat Jan 15 13:15:21 2022 -0800 @@ -0,0 +1,25 @@ +#ifndef SEGACD_H_ +#define SEGACD_H_ +#include +#include "system.h" +#include "m68k_core.h" + +typedef struct { + m68k_context *m68k; + system_media *media; + uint16_t gate_array[0x100]; + uint8_t busreq; + uint8_t busack; + uint8_t reset; + uint16_t *rom; //unaltered ROM, needed for mirrored locations + uint16_t *rom_mut; //ROM with low 16-bit of HINT vector modified by register write + uint16_t *prog_ram; + uint16_t *work_ram; + uint8_t *pcm_ram; + uint8_t *bram; +} 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 3748a2a8a4b7 -r 3414a4423de1 system.c --- a/system.c Sat Jan 01 18:54:46 2022 -0800 +++ b/system.c Sat Jan 15 13:15:21 2022 -0800 @@ -13,7 +13,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) @@ -71,6 +75,8 @@ return &(alloc_config_genesis(media->buffer, media->size, lock_on, lock_on_size, opts, force_region))->header; case SYSTEM_GENESIS_PLAYER: return &(alloc_config_gen_player(media->buffer, media->size))->header; + case SYSTEM_SEGACD: + return &(alloc_config_genesis_cdboot(media, opts, force_region))->header; #ifndef NO_Z80 case SYSTEM_SMS: return &(alloc_configure_sms(media, opts, force_region))->header; diff -r 3748a2a8a4b7 -r 3414a4423de1 system.h --- a/system.h Sat Jan 01 18:54:46 2022 -0800 +++ b/system.h Sat Jan 15 13:15:21 2022 -0800 @@ -10,6 +10,7 @@ SYSTEM_UNKNOWN, SYSTEM_GENESIS, SYSTEM_GENESIS_PLAYER, + SYSTEM_SEGACD, SYSTEM_SMS, SYSTEM_SMS_PLAYER, SYSTEM_JAGUAR, @@ -38,46 +39,51 @@ #include "event_log.h" struct system_header { - system_header *next_context; - system_str_fun start_context; - system_fun resume_context; - system_fun load_save; - system_fun persist_save; - system_u8_fun_r8 load_state; - system_fun request_exit; - system_fun soft_reset; - system_fun free_context; - system_fun_r16 get_open_bus_value; - system_u32_fun set_speed_percent; - system_fun inc_debug_mode; - system_u8_u8_fun gamepad_down; - system_u8_u8_fun gamepad_up; - system_u8_u8_fun mouse_down; - system_u8_u8_fun mouse_up; - system_mabs_fun mouse_motion_absolute; - system_mrel_fun mouse_motion_relative; - system_u8_fun keyboard_down; - system_u8_fun keyboard_up; - system_fun config_updated; + system_header *next_context; + system_str_fun start_context; + system_fun resume_context; + system_fun load_save; + system_fun persist_save; + system_u8_fun_r8 load_state; + system_fun request_exit; + system_fun soft_reset; + system_fun free_context; + system_fun_r16 get_open_bus_value; + system_u32_fun set_speed_percent; + system_fun inc_debug_mode; + system_u8_u8_fun gamepad_down; + system_u8_u8_fun gamepad_up; + system_u8_u8_fun mouse_down; + system_u8_u8_fun mouse_up; + system_mabs_fun mouse_motion_absolute; + system_mrel_fun mouse_motion_relative; + system_u8_fun keyboard_down; + system_u8_fun keyboard_up; + system_fun config_updated; system_ptrszt_fun_rptr8 serialize; system_ptr8_sizet_fun deserialize; system_str_fun start_vgm_log; system_fun stop_vgm_log; - rom_info info; - arena *arena; - char *next_rom; - char *save_dir; - uint8_t enter_debugger; - uint8_t should_exit; - uint8_t save_state; - uint8_t delayed_load_slot; - uint8_t has_keyboard; + rom_info info; + arena *arena; + char *next_rom; + char *save_dir; + uint8_t enter_debugger; + uint8_t should_exit; + uint8_t save_state; + uint8_t delayed_load_slot; + uint8_t has_keyboard; uint8_t vgm_logging; uint8_t force_release; - debugger_type debugger_type; - system_type type; + debugger_type debugger_type; + system_type type; }; +typedef enum { + MEDIA_CART, + MEDIA_CDROM +} media_type; + struct system_media { void *buffer; char *dir; @@ -85,6 +91,7 @@ char *extension; system_media *chain; uint32_t size; + media_type type; }; #define OPT_ADDRESS_LOG (1U << 31U)