# HG changeset patch # User Michael Pavone # Date 1642493030 28800 # Node ID 8ee7ecbf3f21e233afb43adf74c331f4a058fc5c # Parent 3414a4423de1d1803d2b9045f9639ddfb0505497 Implement enough of Sega CD gate array and Sub CPU to pass Sik's Mode 1 test ROM diff -r 3414a4423de1 -r 8ee7ecbf3f21 backend_x86.c --- a/backend_x86.c Sat Jan 15 13:15:21 2022 -0800 +++ b/backend_x86.c Tue Jan 18 00:03:50 2022 -0800 @@ -116,7 +116,7 @@ if (after_inc) { *after_inc = code->cur; } - + if (opts->address_size == SZ_D && opts->address_mask != 0xFFFFFFFF) { and_ir(code, opts->address_mask, adr_reg, SZ_D); } else if (opts->address_size == SZ_W && opts->address_mask != 0xFFFF) { @@ -127,19 +127,31 @@ uint32_t ram_flags_off = opts->ram_flags_off; uint32_t min_address = 0; uint32_t max_address = opts->max_address; + uint8_t need_wide_jcc = 0; for (uint32_t chunk = 0; chunk < num_chunks; chunk++) { + code_info chunk_start = *code; if (memmap[chunk].start > min_address) { cmp_ir(code, memmap[chunk].start, adr_reg, opts->address_size); lb_jcc = code->cur + 1; - jcc(code, CC_C, code->cur + 2); + if (need_wide_jcc) { + jcc(code, CC_C, code->cur + 130); + lb_jcc++; + } else { + jcc(code, CC_C, code->cur + 2); + } } else { min_address = memmap[chunk].end; } if (memmap[chunk].end < max_address) { cmp_ir(code, memmap[chunk].end, adr_reg, opts->address_size); ub_jcc = code->cur + 1; - jcc(code, CC_NC, code->cur + 2); + if (need_wide_jcc) { + jcc(code, CC_NC, code->cur + 130); + ub_jcc++; + } else { + jcc(code, CC_NC, code->cur + 2); + } } else { max_address = memmap[chunk].start; } @@ -312,13 +324,35 @@ } } if (lb_jcc) { - *lb_jcc = code->cur - (lb_jcc+1); + if (need_wide_jcc) { + *((int32_t*)lb_jcc) = code->cur - (lb_jcc+4); + } else if (code->cur - (lb_jcc+1) > 0x7f) { + need_wide_jcc = 1; + chunk--; + *code = chunk_start; + continue; + } else { + *lb_jcc = code->cur - (lb_jcc+1); + } lb_jcc = NULL; } if (ub_jcc) { - *ub_jcc = code->cur - (ub_jcc+1); + if (need_wide_jcc) { + *((int32_t*)ub_jcc) = code->cur - (ub_jcc+4); + } else if (code->cur - (ub_jcc+1) > 0x7f) { + need_wide_jcc = 1; + chunk--; + *code = chunk_start; + continue; + } else { + *ub_jcc = code->cur - (ub_jcc+1); + } + ub_jcc = NULL; } + if (need_wide_jcc) { + need_wide_jcc = 0; + } } if (!is_write) { mov_ir(code, size == SZ_B ? 0xFF : 0xFFFF, opts->scratch1, size); diff -r 3414a4423de1 -r 8ee7ecbf3f21 debug.c --- a/debug.c Sat Jan 15 13:15:21 2022 -0800 +++ b/debug.c Tue Jan 18 00:03:50 2022 -0800 @@ -740,7 +740,7 @@ m68k_disasm(&inst, input_buf); printf("%X: %s\n", address, input_buf); } - + break; case 'n': if (inst.op == M68K_RTS) { @@ -1012,7 +1012,7 @@ init_terminal(); - sync_components(context, 0); + context->options->sync_components(context, 0); genesis_context *gen = context->system; vdp_force_update_framebuffer(gen->vdp); //probably not necessary, but let's play it safe diff -r 3414a4423de1 -r 8ee7ecbf3f21 genesis.c --- a/genesis.c Sat Jan 15 13:15:21 2022 -0800 +++ b/genesis.c Tue Jan 18 00:03:50 2022 -0800 @@ -247,13 +247,22 @@ uint16_t read_dma_value(uint32_t address) { genesis_context *genesis = (genesis_context *)current_system; + address *= 2; //TODO: Figure out what happens when you try to DMA from weird adresses like IO or banked Z80 area if ((address >= 0xA00000 && address < 0xB00000) || (address >= 0xC00000 && address <= 0xE00000)) { return 0; } + if (genesis->expansion) { + segacd_context *cd = genesis->expansion; + uint32_t word_ram = cd->base + 0x200000; + uint32_t word_ram_end = cd->base + 0x240000; + if (address >= word_ram && address < word_ram_end) { + //FIXME: first word should just be garbage + address -= 2; + } + } - //addresses here are word addresses (i.e. bit 0 corresponds to A1), so no need to do multiply by 2 - return read_word(address * 2, (void **)genesis->m68k->mem_pointers, &genesis->m68k->options->gen, genesis->m68k); + return read_word(address, (void **)genesis->m68k->mem_pointers, &genesis->m68k->options->gen, genesis->m68k); } static uint16_t get_open_bus_value(system_header *system) @@ -413,7 +422,7 @@ #define ADJUST_BUFFER (8*MCLKS_LINE*313) #define MAX_NO_ADJUST (UINT_MAX-ADJUST_BUFFER) -m68k_context * sync_components(m68k_context * context, uint32_t address) +static m68k_context *sync_components(m68k_context * context, uint32_t address) { genesis_context * gen = context->system; vdp_context * v_context = gen->vdp; @@ -434,6 +443,9 @@ io_run(gen->io.ports, mclks); io_run(gen->io.ports + 1, mclks); io_run(gen->io.ports + 2, mclks); + if (gen->expansion) { + scd_run(gen->expansion, gen_cycle_to_scd(mclks, gen)); + } if (mclks >= gen->reset_cycle) { gen->reset_requested = 1; context->should_return = 1; @@ -471,6 +483,9 @@ gen->reset_cycle -= deduction; } event_cycle_adjust(mclks, deduction); + if (gen->expansion) { + scd_adjust_cycle(gen->expansion, deduction); + } gen->last_flush_cycle -= deduction; } } else if (mclks - gen->last_flush_cycle > gen->soft_flush_cycles) { @@ -1878,35 +1893,68 @@ return gen; } -genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_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}, + {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}, + {0x000000, 0xFFFFFF, 0xFFFFFF, 0, 0, 0, NULL, + (read_16_fun)unused_read, (write_16_fun)unused_write, + (read_8_fun)unused_read_b, (write_8_fun)unused_write_b} +}; +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) { - genesis_context *gen = shared_init(system_opts, rom, force_region); - gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = (uint8_t *)main_rom; + 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 + byteswap_rom(rom_size, rom); + if (lock_on) { + 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; + } + genesis_context *gen = shared_init(ym_opts, &info, force_region); + gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = rom; - gen->cart = main_rom; + gen->cart = rom; gen->lock_on = lock_on; - setup_io_devices(config, rom, &gen->io); + setup_io_devices(config, &info, &gen->io); gen->header.has_keyboard = io_has_keyboard(&gen->io); - gen->mapper_type = rom->mapper_type; - gen->save_type = rom->save_type; + gen->mapper_type = info.mapper_type; + gen->save_type = info.save_type; if (gen->save_type != SAVE_NONE) { - gen->save_ram_mask = rom->save_mask; - gen->save_size = rom->save_size; - gen->save_storage = rom->save_buffer; - gen->eeprom_map = rom->eeprom_map; - gen->num_eeprom = rom->num_eeprom; + gen->save_ram_mask = info.save_mask; + gen->save_size = info.save_size; + gen->save_storage = info.save_buffer; + gen->eeprom_map = info.eeprom_map; + gen->num_eeprom = info.num_eeprom; if (gen->save_type == SAVE_I2C) { eeprom_init(&gen->eeprom, gen->save_storage, gen->save_size); } else if (gen->save_type == SAVE_NOR) { - memcpy(&gen->nor, rom->nor, sizeof(gen->nor)); - //nor_flash_init(&gen->nor, gen->save_storage, gen->save_size, rom->save_page_size, rom->save_product_id, rom->save_bus); + memcpy(&gen->nor, info.nor, sizeof(gen->nor)); + //nor_flash_init(&gen->nor, gen->save_storage, gen->save_size, info.save_page_size, info.save_product_id, info.save_bus); } } else { gen->save_storage = NULL; } - gen->mapper_start_index = rom->mapper_start_index; + gen->mapper_start_index = info.mapper_start_index; tern_node *model = get_model(config, SYSTEM_GENESIS); uint8_t tmss = !strcmp(tern_find_ptr_default(model, "tmss", "off"), "on"); @@ -1914,19 +1962,19 @@ //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; - for (int i = 0; i < rom->map_chunks; i++) + for (int i = 0; i < info.map_chunks; i++) { - if (rom->map[i].start == 0xE00000) { - rom->map[i].buffer = gen->work_ram; + if (info.map[i].start == 0xE00000) { + info.map[i].buffer = gen->work_ram; if (!tmss) { break; } } - if (rom->map[i].flags & MMAP_PTR_IDX && rom->map[i].ptr_index >= next_ptr_index) { - next_ptr_index = rom->map[i].ptr_index + 1; + if (info.map[i].flags & MMAP_PTR_IDX && info.map[i].ptr_index >= next_ptr_index) { + next_ptr_index = info.map[i].ptr_index + 1; } - if (rom->map[i].start < 0x400000 && rom->map[i].read_16 != unused_read) { - uint32_t highest_offset = (rom->map[i].end & rom->map[i].mask) + 1; + if (info.map[i].start < 0x400000 && info.map[i].read_16 != unused_read) { + uint32_t highest_offset = (info.map[i].end & info.map[i].mask) + 1; if (highest_offset > tmss_min_alloc) { tmss_min_alloc = highest_offset; } @@ -1965,105 +2013,136 @@ } //modify mappings for ROM space to point to the TMSS ROM and fixup flags to allow switching back and forth //WARNING: This code makes some pretty big assumptions about the kinds of map chunks it will encounter - for (int i = 0; i < rom->map_chunks; i++) + for (int i = 0; i < info.map_chunks; i++) { - if (rom->map[i].start < 0x400000 && rom->map[i].read_16 != unused_read) { - if (rom->map[i].flags == MMAP_READ) { + if (info.map[i].start < 0x400000 && info.map[i].read_16 != unused_read) { + if (info.map[i].flags == MMAP_READ) { //Normal ROM - rom->map[i].flags |= MMAP_PTR_IDX | MMAP_CODE; - rom->map[i].ptr_index = next_ptr_index++; - if (rom->map[i].ptr_index >= NUM_MEM_AREAS) { + info.map[i].flags |= MMAP_PTR_IDX | MMAP_CODE; + info.map[i].ptr_index = next_ptr_index++; + if (info.map[i].ptr_index >= NUM_MEM_AREAS) { fatal_error("Too many memmap chunks with MMAP_PTR_IDX after TMSS remap\n"); } - gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; - rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); - } else if (rom->map[i].flags & MMAP_PTR_IDX) { + gen->tmss_pointers[info.map[i].ptr_index] = info.map[i].buffer; + info.map[i].buffer = buffer + (info.map[i].start & ~info.map[i].mask & (tmss_size - 1)); + } else if (info.map[i].flags & MMAP_PTR_IDX) { //Sega mapper page or multi-game mapper - gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; - rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); - if (rom->map[i].write_16) { + gen->tmss_pointers[info.map[i].ptr_index] = info.map[i].buffer; + info.map[i].buffer = buffer + (info.map[i].start & ~info.map[i].mask & (tmss_size - 1)); + if (info.map[i].write_16) { if (!gen->tmss_write_16) { - gen->tmss_write_16 = rom->map[i].write_16; - gen->tmss_write_8 = rom->map[i].write_8; - rom->map[i].write_16 = tmss_rom_write_16; - rom->map[i].write_8 = tmss_rom_write_8; - } else if (gen->tmss_write_16 == rom->map[i].write_16) { - rom->map[i].write_16 = tmss_rom_write_16; - rom->map[i].write_8 = tmss_rom_write_8; + gen->tmss_write_16 = info.map[i].write_16; + gen->tmss_write_8 = info.map[i].write_8; + info.map[i].write_16 = tmss_rom_write_16; + info.map[i].write_8 = tmss_rom_write_8; + } else if (gen->tmss_write_16 == info.map[i].write_16) { + info.map[i].write_16 = tmss_rom_write_16; + info.map[i].write_8 = tmss_rom_write_8; } else { - warning("Chunk starting at %X has a write function, but we've already stored a different one for TMSS remap\n", rom->map[i].start); + warning("Chunk starting at %X has a write function, but we've already stored a different one for TMSS remap\n", info.map[i].start); } } - } else if ((rom->map[i].flags & (MMAP_READ | MMAP_WRITE)) == (MMAP_READ | MMAP_WRITE)) { + } else if ((info.map[i].flags & (MMAP_READ | MMAP_WRITE)) == (MMAP_READ | MMAP_WRITE)) { //RAM or SRAM - rom->map[i].flags |= MMAP_PTR_IDX; - rom->map[i].ptr_index = next_ptr_index++; - gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; - rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); - if (!gen->tmss_write_offset || gen->tmss_write_offset == rom->map[i].start) { - gen->tmss_write_offset = rom->map[i].start; - rom->map[i].flags &= ~MMAP_WRITE; - if (rom->map[i].flags & MMAP_ONLY_ODD) { - rom->map[i].write_16 = tmss_odd_write_16; - rom->map[i].write_8 = tmss_odd_write_8; - } else if (rom->map[i].flags & MMAP_ONLY_EVEN) { - rom->map[i].write_16 = tmss_even_write_16; - rom->map[i].write_8 = tmss_even_write_8; + info.map[i].flags |= MMAP_PTR_IDX; + info.map[i].ptr_index = next_ptr_index++; + gen->tmss_pointers[info.map[i].ptr_index] = info.map[i].buffer; + info.map[i].buffer = buffer + (info.map[i].start & ~info.map[i].mask & (tmss_size - 1)); + if (!gen->tmss_write_offset || gen->tmss_write_offset == info.map[i].start) { + gen->tmss_write_offset = info.map[i].start; + info.map[i].flags &= ~MMAP_WRITE; + if (info.map[i].flags & MMAP_ONLY_ODD) { + info.map[i].write_16 = tmss_odd_write_16; + info.map[i].write_8 = tmss_odd_write_8; + } else if (info.map[i].flags & MMAP_ONLY_EVEN) { + info.map[i].write_16 = tmss_even_write_16; + info.map[i].write_8 = tmss_even_write_8; } else { - rom->map[i].write_16 = tmss_word_write_16; - rom->map[i].write_8 = tmss_word_write_8; + info.map[i].write_16 = tmss_word_write_16; + info.map[i].write_8 = tmss_word_write_8; } } else { - warning("Could not remap writes for chunk starting at %X for TMSS because write_offset is %X\n", rom->map[i].start, gen->tmss_write_offset); + warning("Could not remap writes for chunk starting at %X for TMSS because write_offset is %X\n", info.map[i].start, gen->tmss_write_offset); } - } else if (rom->map[i].flags & MMAP_READ_CODE) { + } else if (info.map[i].flags & MMAP_READ_CODE) { //NOR flash - rom->map[i].flags |= MMAP_PTR_IDX; - rom->map[i].ptr_index = next_ptr_index++; - if (rom->map[i].ptr_index >= NUM_MEM_AREAS) { + info.map[i].flags |= MMAP_PTR_IDX; + info.map[i].ptr_index = next_ptr_index++; + if (info.map[i].ptr_index >= NUM_MEM_AREAS) { fatal_error("Too many memmap chunks with MMAP_PTR_IDX after TMSS remap\n"); } - gen->tmss_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; - rom->map[i].buffer = buffer + (rom->map[i].start & ~rom->map[i].mask & (tmss_size - 1)); + gen->tmss_pointers[info.map[i].ptr_index] = info.map[i].buffer; + info.map[i].buffer = buffer + (info.map[i].start & ~info.map[i].mask & (tmss_size - 1)); if (!gen->tmss_write_16) { - gen->tmss_write_16 = rom->map[i].write_16; - gen->tmss_write_8 = rom->map[i].write_8; - gen->tmss_read_16 = rom->map[i].read_16; - gen->tmss_read_8 = rom->map[i].read_8; - rom->map[i].write_16 = tmss_rom_write_16; - rom->map[i].write_8 = tmss_rom_write_8; - rom->map[i].read_16 = tmss_rom_read_16; - rom->map[i].read_8 = tmss_rom_read_8; - } else if (gen->tmss_write_16 == rom->map[i].write_16) { - rom->map[i].write_16 = tmss_rom_write_16; - rom->map[i].write_8 = tmss_rom_write_8; - rom->map[i].read_16 = tmss_rom_read_16; - rom->map[i].read_8 = tmss_rom_read_8; + gen->tmss_write_16 = info.map[i].write_16; + gen->tmss_write_8 = info.map[i].write_8; + gen->tmss_read_16 = info.map[i].read_16; + gen->tmss_read_8 = info.map[i].read_8; + info.map[i].write_16 = tmss_rom_write_16; + info.map[i].write_8 = tmss_rom_write_8; + info.map[i].read_16 = tmss_rom_read_16; + info.map[i].read_8 = tmss_rom_read_8; + } else if (gen->tmss_write_16 == info.map[i].write_16) { + info.map[i].write_16 = tmss_rom_write_16; + info.map[i].write_8 = tmss_rom_write_8; + info.map[i].read_16 = tmss_rom_read_16; + info.map[i].read_8 = tmss_rom_read_8; } else { - warning("Chunk starting at %X has a write function, but we've already stored a different one for TMSS remap\n", rom->map[i].start); + warning("Chunk starting at %X has a write function, but we've already stored a different one for TMSS remap\n", info.map[i].start); } } else { - warning("Didn't remap chunk starting at %X for TMSS because it has flags %X\n", rom->map[i].start, rom->map[i].flags); + warning("Didn't remap chunk starting at %X for TMSS because it has flags %X\n", info.map[i].start, info.map[i].flags); } } } gen->tmss_buffer = buffer; } + memmap_chunk* map = info.map; + uint32_t map_chunks = info.map_chunks; + if (info.wants_cd) { + segacd_context *cd = alloc_configure_segacd((system_media *)current_media(), 0, force_region, &info); + gen->expansion = cd; + gen->version_reg &= ~NO_DISK; + cd->genesis = gen; + uint32_t cd_chunks; + memmap_chunk *cd_map = segacd_main_cpu_map(gen->expansion, 1, &cd_chunks); + map_chunks = cd_chunks + info.map_chunks; + map = calloc(map_chunks, sizeof(memmap_chunk)); + memcpy(map, info.map, sizeof(memmap_chunk) * (info.map_chunks - 1)); + memcpy(map + info.map_chunks - 1, cd_map, sizeof(memmap_chunk) * cd_chunks); + memcpy(map + map_chunks - 1, info.map + info.map_chunks - 1, sizeof(memmap_chunk)); + free(info.map); + int max_ptr_index = -1; + for (int i = 0; i < info.map_chunks - 1; i++) + { + if (map[i].flags & MMAP_PTR_IDX && map[i].ptr_index > max_ptr_index) { + max_ptr_index = map[i].ptr_index; + } + } + cd->memptr_start_index + max_ptr_index + 1; + for (int i = info.map_chunks - 1; i < map_chunks - 1; i++) + { + if (map[i].flags & MMAP_PTR_IDX) { + map[i].ptr_index += cd->memptr_start_index; + } + } + cd->base = 0x400000; + } m68k_options *opts = malloc(sizeof(m68k_options)); - init_m68k_opts(opts, rom->map, rom->map_chunks, MCLKS_PER_68K); + init_m68k_opts(opts, map, map_chunks, MCLKS_PER_68K, sync_components); if (!strcmp(tern_find_ptr_default(model, "tas", "broken"), "broken")) { 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; + opts->address_log = (ym_opts & OPT_ADDRESS_LOG) ? fopen("address.log", "w") : NULL; //This must happen after the 68K context has been allocated - for (int i = 0; i < rom->map_chunks; i++) + for (int i = 0; i < map_chunks; i++) { - if (rom->map[i].flags & MMAP_PTR_IDX) { - gen->m68k->mem_pointers[rom->map[i].ptr_index] = rom->map[i].buffer; + if (map[i].flags & MMAP_PTR_IDX) { + gen->m68k->mem_pointers[map[i].ptr_index] = map[i].buffer; } } @@ -2079,44 +2158,6 @@ 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}, - {0x000000, 0xFFFFFF, 0xFFFFFF, 0, 0, 0, NULL, - (read_16_fun)unused_read, (write_16_fun)unused_write, - (read_8_fun)unused_read_b, (write_8_fun)unused_write_b} - }; -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 - byteswap_rom(rom_size, rom); - if (lock_on) { - 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, 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(); @@ -2130,10 +2171,12 @@ gen->version_reg &= ~NO_DISK; gen->expansion = cd; + gen->version_reg &= ~NO_DISK; + cd->genesis = gen; 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 *cd_map = segacd_main_cpu_map(gen->expansion, 0, &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); @@ -2141,7 +2184,7 @@ 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); + init_m68k_opts(opts, map, num_chunks, MCLKS_PER_68K, sync_components); //TODO: make this configurable opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY; gen->m68k = init_68k_context(opts, NULL); diff -r 3414a4423de1 -r 8ee7ecbf3f21 genesis.h --- a/genesis.h Sat Jan 15 13:15:21 2022 -0800 +++ b/genesis.h Tue Jan 18 00:03:50 2022 -0800 @@ -81,7 +81,6 @@ #define RAM_WORDS 32 * 1024 #define Z80_RAM_BYTES 8 * 1024 -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); diff -r 3414a4423de1 -r 8ee7ecbf3f21 m68k_core.c --- a/m68k_core.c Sat Jan 15 13:15:21 2022 -0800 +++ b/m68k_core.c Tue Jan 18 00:03:50 2022 -0800 @@ -94,7 +94,7 @@ void m68k_save_result(m68kinst * inst, m68k_options * opts) { if (inst->dst.addr_mode != MODE_REG && inst->dst.addr_mode != MODE_AREG && inst->dst.addr_mode != MODE_UNUSED) { - if (inst->dst.addr_mode == MODE_AREG_PREDEC && + if (inst->dst.addr_mode == MODE_AREG_PREDEC && ((inst->src.addr_mode == MODE_AREG_PREDEC && inst->op != M68K_MOVE) || (inst->op == M68K_NBCD)) ) { areg_to_native(opts, inst->dst.params.regs.pri, opts->gen.scratch2); @@ -489,7 +489,7 @@ } opts->extra_code = opts->gen.code; opts->gen.code = tmp; - + rts(&opts->extra_code); return impl; } @@ -499,7 +499,7 @@ code_info *code = &opts->gen.code; uint8_t early_cycles; uint16_t num_regs = inst->src.addr_mode == MODE_REG ? inst->src.params.immed : inst->dst.params.immed; - { + { //TODO: Move this popcount alg to a utility function uint16_t a = (num_regs & 0b1010101010101010) >> 1; uint16_t b = num_regs & 0b0101010101010101; @@ -549,7 +549,7 @@ m68k_disasm(inst, disasm_buf); fatal_error("%X: %s\naddress mode %d not implemented (movem dst)\n", inst->address, disasm_buf, inst->dst.addr_mode); } - + cycles(&opts->gen, early_cycles); if (num_regs <= 9) { translate_movem_regtomem_reglist(opts, inst); @@ -596,7 +596,7 @@ fatal_error("%X: %s\naddress mode %d not implemented (movem src)\n", inst->address, disasm_buf, inst->src.addr_mode); } cycles(&opts->gen, early_cycles); - + if (num_regs <= 9) { translate_movem_memtoreg_reglist(opts, inst); } else { @@ -625,7 +625,7 @@ static void translate_m68k_rte(m68k_options *opts, m68kinst *inst) { m68k_trap_if_not_supervisor(opts, inst); - + code_info *code = &opts->gen.code; //Read saved SR areg_to_native(opts, 7, opts->gen.scratch1); @@ -646,7 +646,7 @@ code_ptr get_native_address(m68k_options *opts, uint32_t address) { native_map_slot * native_code_map = opts->gen.native_code_map; - + memmap_chunk const *mem_chunk = find_map_chunk(address, &opts->gen, 0, NULL); if (mem_chunk) { //calculate the lowest alias for this address @@ -680,7 +680,7 @@ } else { address &= opts->gen.address_mask; } - + uint32_t chunk = address / NATIVE_CHUNK_SIZE; if (!native_code_map[chunk].base) { return 0; @@ -728,7 +728,7 @@ } else { address &= opts->gen.address_mask; } - + uint32_t chunk = address / NATIVE_CHUNK_SIZE; if (!native_code_map[chunk].base) { native_code_map[chunk].base = native_addr; @@ -830,7 +830,7 @@ warning("Spurious breakpoing at %X\n", address); remove_breakpoint(context, address); } - + return context; } @@ -958,15 +958,15 @@ } code_ptr start = opts->gen.code.cur; check_cycles_int(&opts->gen, inst->address); - + m68k_debug_handler bp; if ((bp = find_breakpoint(context, inst->address))) { m68k_breakpoint_patch(context, inst->address, bp, start); } - + //log_address(&opts->gen, inst->address, "M68K: %X @ %d\n"); if ( - (inst->src.addr_mode > MODE_AREG && inst->src.addr_mode < MODE_IMMEDIATE) + (inst->src.addr_mode > MODE_AREG && inst->src.addr_mode < MODE_IMMEDIATE) || (inst->dst.addr_mode > MODE_AREG && inst->dst.addr_mode < MODE_IMMEDIATE) || (inst->op == M68K_BCC && (inst->src.params.immed & 1)) ) { @@ -1196,7 +1196,7 @@ context->aregs[7] = reset_vec[0] << 16 | reset_vec[1]; uint32_t address = reset_vec[2] << 16 | reset_vec[3]; //interrupt mask may have changed so force a sync - sync_components(context, address); + context->options->sync_components(context, address); start_68k_context(context, address); } diff -r 3414a4423de1 -r 8ee7ecbf3f21 m68k_core.h --- a/m68k_core.h Sat Jan 15 13:15:21 2022 -0800 +++ b/m68k_core.h Tue Jan 18 00:03:50 2022 -0800 @@ -25,6 +25,8 @@ #define M68K_STATUS_TRACE 0x80 typedef void (*start_fun)(uint8_t * addr, void * context); +typedef struct m68k_context m68k_context; +typedef m68k_context *(*sync_fun)(m68k_context * context, uint32_t address); typedef struct { code_ptr impl; @@ -59,6 +61,7 @@ code_ptr set_sr; code_ptr set_ccr; code_ptr bp_stub; + sync_fun sync_components; code_info extra_code; movem_fun *big_movem; uint32_t num_movem; @@ -66,7 +69,6 @@ code_word prologue_start; } m68k_options; -typedef struct m68k_context m68k_context; typedef void (*m68k_debug_handler)(m68k_context *context, uint32_t pc); typedef struct { @@ -106,7 +108,7 @@ void translate_m68k_stream(uint32_t address, m68k_context * context); void start_68k_context(m68k_context * context, uint32_t address); void resume_68k(m68k_context *context); -void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider); +void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider, sync_fun sync_components); m68k_context * init_68k_context(m68k_options * opts, m68k_reset_handler reset_handler); void m68k_reset(m68k_context * context); void m68k_options_free(m68k_options *opts); diff -r 3414a4423de1 -r 8ee7ecbf3f21 m68k_core_x86.c --- a/m68k_core_x86.c Sat Jan 15 13:15:21 2022 -0800 +++ b/m68k_core_x86.c Tue Jan 18 00:03:50 2022 -0800 @@ -422,8 +422,8 @@ } dec_amount = inst->extra.size == OPSIZE_WORD ? 2 : (inst->extra.size == OPSIZE_LONG ? 4 : (op->params.regs.pri == 7 ? 2 :1)); if (!dst || ( - inst->op != M68K_MOVE && inst->op != M68K_MOVEM - && inst->op != M68K_SUBX && inst->op != M68K_ADDX + inst->op != M68K_MOVE && inst->op != M68K_MOVEM + && inst->op != M68K_SUBX && inst->op != M68K_ADDX && inst->op != M68K_ABCD && inst->op != M68K_SBCD )) { cycles(&opts->gen, PREDEC_PENALTY); @@ -817,7 +817,7 @@ void translate_m68k_bcc(m68k_options * opts, m68kinst * inst) { code_info *code = &opts->gen.code; - + int32_t disp = inst->src.params.immed; uint32_t after = inst->address + 2; if (inst->extra.cond == COND_TRUE) { @@ -827,11 +827,11 @@ uint8_t cond = m68k_eval_cond(opts, inst->extra.cond); code_ptr do_branch = code->cur + 1; jcc(code, cond, do_branch); - + cycles(&opts->gen, inst->variant == VAR_BYTE ? 8 : 12); code_ptr done = code->cur + 1; jmp(code, done); - + *do_branch = code->cur - (do_branch + 1); cycles(&opts->gen, 10); code_ptr dest_addr = get_native_address(opts, after + disp); @@ -841,7 +841,7 @@ dest_addr = code->cur + 256; } jmp(code, dest_addr); - + *done = code->cur - (done + 1); } } @@ -1310,7 +1310,7 @@ { code_info *code = &opts->gen.code; uint8_t size = inst->dst.addr_mode == MODE_AREG ? OPSIZE_LONG : inst->extra.size; - + uint32_t numcycles; if ((inst->op == M68K_ADDX || inst->op == M68K_SUBX) && inst->src.addr_mode != MODE_REG) { numcycles = 4; @@ -1322,7 +1322,7 @@ } else if (inst->dst.addr_mode == MODE_REG) { numcycles = inst->src.addr_mode <= MODE_AREG || inst->src.addr_mode == MODE_IMMEDIATE ? 8 : 6; } else if (inst->dst.addr_mode == MODE_AREG) { - numcycles = numcycles = inst->src.addr_mode <= MODE_AREG || inst->src.addr_mode == MODE_IMMEDIATE + numcycles = numcycles = inst->src.addr_mode <= MODE_AREG || inst->src.addr_mode == MODE_IMMEDIATE || inst->extra.size == OPSIZE_WORD ? 8 : 6; } else { numcycles = 4; @@ -1331,11 +1331,11 @@ numcycles = 4; } cycles(&opts->gen, numcycles); - + if (inst->op == M68K_ADDX || inst->op == M68K_SUBX) { flag_to_carry(opts, FLAG_X); } - + if (src_op->mode == MODE_REG_DIRECT) { if (dst_op->mode == MODE_REG_DIRECT) { op_rr(code, inst, src_op->base, dst_op->base, size); @@ -1500,7 +1500,7 @@ //destination is in memory so we need to preserve scratch2 for the write at the end push_r(code, opts->gen.scratch2); } - + //reg to reg takes 6 cycles, mem to mem is 4 cycles + all the operand fetch/writing (including 2 cycle predec penalty for first operand) cycles(&opts->gen, inst->dst.addr_mode != MODE_REG ? BUS : BUS + 2); uint8_t other_reg; @@ -1762,7 +1762,7 @@ force = dividend >> 31; quotient = quotient << 1 | bit; dividend = dividend << 1; - + if (force || dividend >= divisor_shift) { dividend -= divisor_shift; cycles += force ? 4 : 6; @@ -1784,7 +1784,7 @@ if (divisor_shift & 0x80000000) { divisor_shift = 0 - divisor_shift; } - + uint32_t cycles = 12; if (dividend & 0x80000000) { //dvs10 @@ -1805,7 +1805,7 @@ { quotient = quotient << 1 | bit; dividend = dividend << 1; - + if (dividend >= divisor_shift) { dividend -= divisor_shift; cycles += 6; @@ -1824,7 +1824,7 @@ quotient = quotient << 1; } cycles += 4; - + context->flags[FLAG_V] = 0; if (orig_divisor & 0x80000000) { cycles += 16; //was 10 @@ -1894,7 +1894,7 @@ cmp_ir(code, 0, opts->gen.scratch1, SZ_D); code_ptr not_zero = code->cur+1; jcc(code, CC_NZ, not_zero); - + //TODO: Check that opts->trap includes the cycles conumed by the first trap0 microinstruction cycles(&opts->gen, 4); uint32_t isize = 2; @@ -1917,7 +1917,7 @@ mov_ir(code, VECTOR_INT_DIV_ZERO, opts->gen.scratch2, SZ_D); mov_ir(code, inst->address+isize, opts->gen.scratch1, SZ_D); jmp(code, opts->trap); - + *not_zero = code->cur - (not_zero + 1); code_ptr end = NULL; if (inst->op == M68K_DIVU) { @@ -1926,13 +1926,13 @@ cmp_rr(code, opts->gen.scratch1, opts->gen.scratch2, SZ_D); code_ptr not_overflow = code->cur+1; jcc(code, CC_C, not_overflow); - + //overflow seems to always set the N and clear Z update_flags(opts, N1|Z0|V1); cycles(&opts->gen, 10); end = code->cur+1; jmp(code, end); - + *not_overflow = code->cur - (not_overflow + 1); } call(code, opts->gen.save_context); @@ -1941,14 +1941,14 @@ call_args(code, (code_ptr)(inst->op == M68K_DIVU ? divu : divs), 3, opts->gen.scratch2, opts->gen.context_reg, opts->gen.scratch1); pop_r(code, opts->gen.context_reg); mov_rr(code, RAX, opts->gen.scratch1, SZ_D); - + call(code, opts->gen.load_context); - + if (inst->op == M68K_DIVU) { cmp_ir(code, 0, opts->gen.scratch1, SZ_W); update_flags(opts, V0|Z|N); } - + if (dst_op->mode == MODE_REG_DIRECT) { mov_rr(code, opts->gen.scratch1, dst_op->base, SZ_D); } else { @@ -2048,7 +2048,7 @@ call(code, opts->gen.load_context); pop_r(code, opts->gen.scratch1); } - + uint8_t dst_reg; if (dst_op->mode == MODE_REG_DIRECT) { dst_reg = dst_op->base; @@ -2217,11 +2217,11 @@ bt_irdisp(code, BIT_SUPERVISOR, opts->gen.context_reg, offsetof(m68k_context, status), SZ_B); code_ptr in_sup_mode = code->cur + 1; jcc(code, CC_C, code->cur + 2); - + ldi_native(opts, VECTOR_PRIV_VIOLATION, opts->gen.scratch2); ldi_native(opts, inst->address, opts->gen.scratch1); jmp(code, opts->trap); - + *in_sup_mode = code->cur - (in_sup_mode + 1); } @@ -2544,11 +2544,11 @@ m68k_options * opts = context->options; code_info native; native.cur = native_addr ? native_addr : get_native_address(context->options, address); - + if (!native.cur) { return; } - + if (*native.cur != opts->prologue_start) { //instruction has already been patched, probably for retranslation return; @@ -2557,12 +2557,12 @@ native.stack_off = 0; code_ptr start_native = native.cur; mov_ir(&native, address, opts->gen.scratch1, SZ_D); - - + + call(&native, opts->bp_stub); } -void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider) +void init_m68k_opts(m68k_options * opts, memmap_chunk * memmap, uint32_t num_chunks, uint32_t clock_divider, sync_fun sync_components) { memset(opts, 0, sizeof(*opts)); opts->gen.memmap = memmap; @@ -2612,6 +2612,7 @@ opts->gen.limit = RBP; opts->gen.scratch1 = RCX; opts->gen.align_error_mask = 1; + opts->sync_components = sync_components; opts->gen.native_code_map = malloc(sizeof(native_map_slot) * NATIVE_MAP_CHUNKS); @@ -2695,7 +2696,7 @@ push_r(code, opts->gen.scratch1); xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D); - call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1); + call_args_abi(code, (code_ptr)opts->sync_components, 2, opts->gen.context_reg, opts->gen.scratch1); pop_r(code, RSI); //restore saved address from opts->gen.scratch1 push_r(code, RAX); //save context pointer for later call_args(code, (code_ptr)get_native_address_trans, 2, RAX, RSI); @@ -2713,7 +2714,7 @@ push_r(code, opts->gen.scratch2); call(code, opts->gen.save_context); xor_rr(code, opts->gen.scratch1, opts->gen.scratch1, SZ_D); - call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1); + call_args_abi(code, (code_ptr)opts->sync_components, 2, opts->gen.context_reg, opts->gen.scratch1); mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); call(code, opts->gen.load_context); pop_r(code, opts->gen.scratch2); @@ -2722,14 +2723,14 @@ retn(code); opts->gen.handle_code_write = (code_ptr)m68k_handle_code_write; - + check_alloc_code(code, 256); opts->gen.handle_align_error_write = code->cur; code->cur += 256; check_alloc_code(code, 256); opts->gen.handle_align_error_read = code->cur; code->cur += 256; - + opts->read_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_16, NULL); opts->read_8 = gen_mem_fun(&opts->gen, memmap, num_chunks, READ_8, NULL); opts->write_16 = gen_mem_fun(&opts->gen, memmap, num_chunks, WRITE_16, NULL); @@ -2830,7 +2831,7 @@ } } retn(code); - + code_info tmp_code = *code; code->cur = opts->gen.handle_align_error_write; code->last = code->cur + 256; @@ -2893,7 +2894,7 @@ call(code, opts->native_addr_and_sync); cycles(&opts->gen, 18); jmp_r(code, opts->gen.scratch1); - + code->cur = opts->gen.handle_align_error_read; code->last = code->cur + 256; //unwind the stack one functinon call @@ -2955,7 +2956,7 @@ call(code, opts->native_addr_and_sync); cycles(&opts->gen, 18); jmp_r(code, opts->gen.scratch1); - + *code = tmp_code; opts->gen.handle_cycle_limit_int = code->cur; @@ -2974,16 +2975,16 @@ *no_trace = code->cur - (no_trace + 1); //handle interrupts cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D); - code_ptr do_int = code->cur + 2; + code_ptr do_int = code->cur + 2; jcc(code, CC_NC, do_int+512);//force 32-bit displacement //handle component synchronization cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, sync_cycle), opts->gen.cycles, SZ_D); skip_sync = code->cur + 1; jcc(code, CC_C, code->cur + 2); call(code, opts->gen.save_context); - call_args_abi(code, (code_ptr)sync_components, 2, opts->gen.context_reg, opts->gen.scratch1); + call_args_abi(code, (code_ptr)opts->sync_components, 2, opts->gen.context_reg, opts->gen.scratch1); mov_rr(code, RAX, opts->gen.context_reg, SZ_PTR); - jmp(code, opts->gen.load_context); + call(code, opts->gen.load_context); *skip_sync = code->cur - (skip_sync+1); cmp_irdisp(code, 0, opts->gen.context_reg, offsetof(m68k_context, should_return), SZ_B); code_ptr do_ret = code->cur + 1; @@ -3031,9 +3032,9 @@ pop_r(code, opts->gen.scratch2); add_ir(code, 16-sizeof(void *), RSP, SZ_PTR); jmp_r(code, opts->gen.scratch1); - + code->stack_off = tmp_stack_off; - + *((uint32_t *)do_int) = code->cur - (do_int+4); //implement 1 instruction latency cmp_irdisp(code, INT_PENDING_NONE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B); @@ -3048,10 +3049,10 @@ cmp_irdisp(code, INT_PENDING_SR_CHANGE, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B); code_ptr already_int_num = code->cur + 1; jcc(code, CC_NZ, already_int_num); - + mov_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_num), opts->gen.scratch2, SZ_B); mov_rrdisp(code, opts->gen.scratch2, opts->gen.context_reg, offsetof(m68k_context, int_pending), SZ_B); - + *already_int_num = code->cur - (already_int_num + 1); //save PC as stored in scratch1 for later push_r(code, opts->gen.scratch1); @@ -3133,10 +3134,10 @@ add_ir(code, 16-sizeof(void *), RSP, SZ_PTR); jmp_r(code, opts->gen.scratch1); code->stack_off = tmp_stack_off; - + opts->handle_int_latch = code->cur; cmp_rdispr(code, opts->gen.context_reg, offsetof(m68k_context, int_cycle), opts->gen.cycles, SZ_D); - code_ptr do_latch = code->cur + 1; + code_ptr do_latch = code->cur + 1; jcc(code, CC_NC, do_latch); retn(code); *do_latch = code->cur - (do_latch + 1); @@ -3177,7 +3178,7 @@ call(code, opts->native_addr_and_sync); cycles(&opts->gen, 18); jmp_r(code, opts->gen.scratch1); - + opts->retrans_stub = code->cur; call(code, opts->gen.save_context); push_r(code, opts->gen.context_reg); @@ -3186,8 +3187,8 @@ mov_rr(code, RAX, opts->gen.scratch1, SZ_PTR); call(code, opts->gen.load_context); jmp_r(code, opts->gen.scratch1); - - + + check_code_prologue(code); opts->bp_stub = code->cur; @@ -3224,6 +3225,6 @@ add_ir(code, check_int_size - patch_size, opts->gen.scratch1, SZ_PTR); jmp_r(code, opts->gen.scratch1); code->stack_off = tmp_stack_off; - + retranslate_calc(&opts->gen); } diff -r 3414a4423de1 -r 8ee7ecbf3f21 m68k_internal.h --- a/m68k_internal.h Sat Jan 15 13:15:21 2022 -0800 +++ b/m68k_internal.h Tue Jan 18 00:03:50 2022 -0800 @@ -106,8 +106,6 @@ #define PREDEC_PENALTY 2 extern char disasm_buf[1024]; -m68k_context * sync_components(m68k_context * context, uint32_t address); - void m68k_invalid(); void bcd_add(); void bcd_sub(); diff -r 3414a4423de1 -r 8ee7ecbf3f21 romdb.c --- a/romdb.c Sat Jan 15 13:15:21 2022 -0800 +++ b/romdb.c Tue Jan 18 00:03:50 2022 -0800 @@ -475,6 +475,19 @@ info.rom_size = rom_size; add_memmap_header(&info, rom, rom_size, base_map, base_chunks); info.port1_override = info.port2_override = info.ext_override = info.mouse_mode = NULL; + info.wants_cd = 0; + for (uint32_t offset = 0x190; offset < rom_size && offset < 0x1A0; offset++) + { + if (rom[offset] == 'F') { + // probably a codemasters game with a garbage header + break; + } + if (rom[offset] == 'C') { + info.wants_cd = 1; + break; + } + } + return info; } @@ -1055,6 +1068,7 @@ info.port1_override = info.port2_override = info.ext_override = NULL; } info.mouse_mode = tern_find_ptr(entry, "mouse_mode"); + info.wants_cd = !strcmp(tern_find_ptr_default(entry, "wants_cd", "no"), "yes"); return info; } diff -r 3414a4423de1 -r 8ee7ecbf3f21 romdb.h --- a/romdb.h Sat Jan 15 13:15:21 2022 -0800 +++ b/romdb.h Tue Jan 18 00:03:50 2022 -0800 @@ -79,6 +79,7 @@ uint8_t mapper_type; uint8_t regions; uint8_t is_save_lock_on; //Does the save buffer actually belong to a lock-on cart? + uint8_t wants_cd; }; #define GAME_ID_OFF 0x183 diff -r 3414a4423de1 -r 8ee7ecbf3f21 segacd.c --- a/segacd.c Sat Jan 15 13:15:21 2022 -0800 +++ b/segacd.c Tue Jan 18 00:03:50 2022 -0800 @@ -4,52 +4,143 @@ #include "genesis.h" #include "util.h" +#define SCD_MCLKS 50000000 +#define SCD_PERIPH_RESET_CLKS (SCD_MCLKS / 10) +#define TIMER_TICK_CLKS 1536 + +enum { + GA_SUB_CPU_CTRL, + GA_MEM_MODE, + GA_CDC_CTRL, + GA_CDC_REG_DATA, + GA_CDC_HOST_DATA, + GA_CDC_DMA_ADDR, + GA_STOP_WATCH, + GA_COMM_FLAG, + GA_COMM_CMD0, + GA_COMM_CMD1, + GA_COMM_CMD2, + GA_COMM_CMD3, + GA_COMM_CMD4, + GA_COMM_CMD5, + GA_COMM_CMD6, + GA_COMM_CMD7, + GA_COMM_STATUS0, + GA_COMM_STATUS1, + GA_COMM_STATUS2, + GA_COMM_STATUS3, + GA_COMM_STATUS4, + GA_COMM_STATUS5, + GA_COMM_STATUS6, + GA_COMM_STATUS7, + GA_TIMER, + GA_INT_MASK, + GA_CDD_FADER, + GA_CDD_CTRL, + + GA_HINT_VECTOR = GA_CDC_REG_DATA +}; +//GA_SUB_CPU_CTRL +#define BIT_IEN2 0x8000 +#define BIT_IFL2 0x0100 +#define BIT_LEDG 0x0100 +#define BIT_LEDR 0x0080 +#define BIT_SBRQ 0x0002 +#define BIT_SRES 0x0001 +#define BIT_PRES 0x0001 +//GA_MEM_MODE +#define MASK_PROG_BANK 0x00C0 +#define MASK_PRIORITY 0x0018 +#define BIT_MEM_MODE 0x0004 +#define BIT_DMNA 0x0002 +#define BIT_RET 0x0001 +//GA_INT_MASK +#define BIT_MASK_IEN1 0x0002 +#define BIT_MASK_IEN2 0x0004 +#define BIT_MASK_IEN3 0x0008 +#define BIT_MASK_IEN4 0x0010 +#define BIT_MASK_IEN5 0x0020 +#define BIT_MASK_IEN6 0x0040 + static void *prog_ram_wp_write16(uint32_t address, void *vcontext, uint16_t value) { + m68k_context *m68k = vcontext; + segacd_context *cd = m68k->system; + if (!(cd->gate_array[GA_MEM_MODE] & (1 << ((address >> 17) + 8)))) { + cd->prog_ram[address >> 1] = value; + m68k_invalidate_code_range(m68k, address, address + 2); + } return vcontext; } static void *prog_ram_wp_write8(uint32_t address, void *vcontext, uint8_t value) { + m68k_context *m68k = vcontext; + segacd_context *cd = m68k->system; + if (!(cd->gate_array[GA_MEM_MODE] & (1 << ((address >> 17) + 8)))) { + ((uint8_t *)cd->prog_ram)[address ^ 1] = value; + m68k_invalidate_code_range(m68k, address, address + 1); + } return vcontext; } -static uint16_t work_ram_2M_read16(uint32_t address, void *vcontext) +static uint16_t word_ram_2M_read16(uint32_t address, void *vcontext) { return 0; } -static uint8_t work_ram_2M_read8(uint32_t address, void *vcontext) +static uint8_t word_ram_2M_read8(uint32_t address, void *vcontext) { return 0; } -static void *work_ram_2M_write16(uint32_t address, void *vcontext, uint16_t value) +static void *word_ram_2M_write16(uint32_t address, void *vcontext, uint16_t value) +{ + return vcontext; +} + +static void *word_ram_2M_write8(uint32_t address, void *vcontext, uint8_t value) { return vcontext; } -static void *work_ram_2M_write8(uint32_t address, void *vcontext, uint8_t value) +static uint16_t word_ram_1M_read16(uint32_t address, void *vcontext) { - return vcontext; + return 0; } -static uint16_t work_ram_1M_read16(uint32_t address, void *vcontext) +static uint8_t word_ram_1M_read8(uint32_t address, void *vcontext) { return 0; } -static uint8_t work_ram_1M_read8(uint32_t address, void *vcontext) +static void *word_ram_1M_write16(uint32_t address, void *vcontext, uint16_t value) { - return 0; + return vcontext; } -static void *work_ram_1M_write16(uint32_t address, void *vcontext, uint16_t value) +static void *word_ram_1M_write8(uint32_t address, void *vcontext, uint8_t value) { return vcontext; } -static void *work_ram_1M_write8(uint32_t address, void *vcontext, uint8_t value) + +static uint16_t unmapped_prog_read16(uint32_t address, void *vcontext) +{ + return 0xFFFF; +} + +static uint8_t unmapped_prog_read8(uint32_t address, void *vcontext) +{ + return 0xFF; +} + +static void *unmapped_prog_write16(uint32_t address, void *vcontext, uint16_t value) +{ + return vcontext; +} + +static void *unmapped_prog_write8(uint32_t address, void *vcontext, uint8_t value) { return vcontext; } @@ -74,18 +165,108 @@ return pcm_write8(address+1, vcontext, value); } + +static void timers_run(segacd_context *cd, uint32_t cycle) +{ + uint32_t ticks = (cycle - cd->stopwatch_cycle) / TIMER_TICK_CLKS; + cd->stopwatch_cycle += ticks * TIMER_TICK_CLKS; + cd->gate_array[GA_STOP_WATCH] += ticks; + cd->gate_array[GA_STOP_WATCH] &= 0xFFF; + if (!cd->timer_value) { + --ticks; + cd->timer_value = cd->gate_array[GA_TIMER]; + } + if (cd->timer_value) { + while (ticks >= (cd->timer_value + 1)) { + ticks -= cd->timer_value + 1; + cd->timer_value = cd->gate_array[GA_TIMER]; + cd->timer_pending = 1; + } + cd->timer_value -= ticks; + if (!cd->timer_value) { + cd->timer_pending = 1; + } + } +} + +static uint32_t next_timer_int(segacd_context *cd) +{ + if (cd->timer_pending) { + return cd->stopwatch_cycle; + } + if (cd->timer_value) { + return cd->stopwatch_cycle + TIMER_TICK_CLKS * cd->timer_value; + } + if (cd->gate_array[GA_TIMER]) { + return cd->stopwatch_cycle + TIMER_TICK_CLKS * (cd->gate_array[GA_TIMER] + 1); + } + return CYCLE_NEVER; +} + +static void calculate_target_cycle(m68k_context * context) +{ + segacd_context *cd = context->system; + context->int_cycle = CYCLE_NEVER; + uint8_t mask = context->status & 0x7; + if (mask < 3) { + uint32_t next_timer; + if (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN3) { + uint32_t next_timer_cycle = next_timer_int(cd); + if (next_timer_cycle < context->int_cycle) { + context->int_cycle = next_timer_cycle; + context->int_num = 3; + } + } + if (mask < 2) { + if (cd->int2_cycle < context->int_cycle && (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN2)) { + context->int_cycle = cd->int2_cycle; + context->int_num = 2; + } + } + } + if (context->int_cycle > context->current_cycle && context->int_pending == INT_PENDING_SR_CHANGE) { + context->int_pending = INT_PENDING_NONE; + } + if (context->current_cycle >= context->sync_cycle) { + context->should_return = 1; + context->target_cycle = context->current_cycle; + return; + } + if (context->status & M68K_STATUS_TRACE || context->trace_pending) { + context->target_cycle = context->current_cycle; + return; + } + context->target_cycle = context->sync_cycle < context->int_cycle ? context->sync_cycle : context->int_cycle; +} + 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]; + uint32_t reg = address >> 1; + switch (reg) + { + case GA_SUB_CPU_CTRL: { + uint16_t value = cd->gate_array[reg] & 0xFFFE; + if (cd->periph_reset_cycle == CYCLE_NEVER || (m68k->current_cycle - cd->periph_reset_cycle) > SCD_PERIPH_RESET_CLKS) { + value |= BIT_PRES; + } + return value; + } + case GA_MEM_MODE: + return cd->gate_array[reg] & 0xFF1F; + case GA_STOP_WATCH: + case GA_TIMER: + timers_run(cd, m68k->current_cycle); + return cd->gate_array[reg]; + default: + return cd->gate_array[reg]; + } } 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]; + uint16_t val = sub_gate_read16(address, vcontext); return address & 1 ? val : val >> 8; } @@ -93,24 +274,98 @@ { m68k_context *m68k = vcontext; segacd_context *cd = m68k->system; - uint32_t reg = (address & 0x1FF) >> 1; + uint32_t reg = address >> 1; switch (reg) { - case 0x7: + case GA_SUB_CPU_CTRL: + cd->gate_array[reg] &= 0xF0; + cd->gate_array[reg] |= value & (BIT_LEDG|BIT_LEDR); + if (value & BIT_PRES) { + cd->periph_reset_cycle = m68k->current_cycle; + } + break; + case GA_MEM_MODE: { + uint16_t changed = value ^ cd->gate_array[reg]; + genesis_context *gen = cd->genesis; + if (changed & BIT_MEM_MODE) { + //FIXME: ram banks are supposed to be interleaved when in 2M mode + cd->gate_array[reg] &= ~BIT_DMNA; + if (value & BIT_MEM_MODE) { + //switch to 1M mode + gen->m68k->mem_pointers[cd->memptr_start_index + 1] = (value & BIT_RET) ? cd->word_ram + 0x10000 : cd->word_ram; + gen->m68k->mem_pointers[cd->memptr_start_index + 2] = NULL; + m68k->mem_pointers[0] = NULL; + m68k->mem_pointers[1] = (value & BIT_RET) ? cd->word_ram : cd->word_ram + 0x10000; + } else { + //switch to 2M mode + if (value & BIT_RET) { + //Main CPU will have word ram + genesis_context *gen = cd->genesis; + gen->m68k->mem_pointers[cd->memptr_start_index + 1] = cd->word_ram; + gen->m68k->mem_pointers[cd->memptr_start_index + 2] = cd->word_ram + 0x10000; + m68k->mem_pointers[0] = NULL; + m68k->mem_pointers[1] = NULL; + } else { + //sub cpu will have word ram + gen->m68k->mem_pointers[cd->memptr_start_index + 1] = NULL; + gen->m68k->mem_pointers[cd->memptr_start_index + 2] = NULL; + m68k->mem_pointers[0] = cd->word_ram; + m68k->mem_pointers[1] = NULL; + } + } + m68k_invalidate_code_range(gen->m68k, cd->base + 0x200000, cd->base + 0x240000); + m68k_invalidate_code_range(m68k, 0x080000, 0x0E0000); + } else if (changed & BIT_RET) { + cd->gate_array[reg] &= ~BIT_DMNA; + if (value & BIT_MEM_MODE) { + //swapping banks in 1M mode + gen->m68k->mem_pointers[cd->memptr_start_index + 1] = (value & BIT_RET) ? cd->word_ram + 0x10000 : cd->word_ram; + m68k->mem_pointers[1] = (value & BIT_RET) ? cd->word_ram : cd->word_ram + 0x10000; + m68k_invalidate_code_range(gen->m68k, cd->base + 0x200000, cd->base + 0x240000); + m68k_invalidate_code_range(m68k, 0x080000, 0x0E0000); + } else if (value & BIT_RET) { + //giving word ram to main CPU in 2M mode + gen->m68k->mem_pointers[cd->memptr_start_index + 1] = cd->word_ram; + gen->m68k->mem_pointers[cd->memptr_start_index + 2] = cd->word_ram + 0x10000; + m68k->mem_pointers[0] = NULL; + m68k_invalidate_code_range(gen->m68k, cd->base + 0x200000, cd->base + 0x240000); + m68k_invalidate_code_range(m68k, 0x080000, 0x0E0000); + } + } + cd->gate_array[reg] &= 0xFFC2; + cd->gate_array[reg] |= value & (BIT_RET|BIT_MEM_MODE|MASK_PRIORITY); + break; + } + case GA_STOP_WATCH: + //docs say you should only write zero to reset + //unclear what happens when other values are written + timers_run(cd, m68k->current_cycle); + cd->gate_array[reg] = value & 0xFFF; + break; + case GA_COMM_FLAG: 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: + case GA_COMM_STATUS0: + case GA_COMM_STATUS1: + case GA_COMM_STATUS2: + case GA_COMM_STATUS3: + case GA_COMM_STATUS4: + case GA_COMM_STATUS5: + case GA_COMM_STATUS6: + case GA_COMM_STATUS7: //no effects for these other than saving the value cd->gate_array[reg] = value; break; + case GA_TIMER: + timers_run(cd, m68k->current_cycle); + cd->gate_array[reg] = value & 0xFF; + calculate_target_cycle(m68k); + break; + case GA_INT_MASK: + cd->gate_array[reg] = value & (BIT_MASK_IEN6|BIT_MASK_IEN5|BIT_MASK_IEN4|BIT_MASK_IEN3|BIT_MASK_IEN2|BIT_MASK_IEN1); + calculate_target_cycle(m68k); + break; default: printf("Unhandled gate array write %X:%X\n", address, value); } @@ -131,18 +386,111 @@ return sub_gate_write16(address, vcontext, value16); } +static uint8_t can_main_access_prog(segacd_context *cd) +{ + //TODO: use actual busack + return cd->busreq || !cd->reset; +} + +static void scd_peripherals_run(segacd_context *cd, uint32_t cycle) +{ + timers_run(cd, cycle); +} + +static m68k_context *sync_components(m68k_context * context, uint32_t address) +{ + segacd_context *cd = context->system; + scd_peripherals_run(cd, context->current_cycle); + calculate_target_cycle(context); + return context; +} + +void scd_run(segacd_context *cd, uint32_t cycle) +{ + uint8_t m68k_run = !can_main_access_prog(cd); + if (m68k_run) { + cd->m68k->sync_cycle = cycle; + if (cd->need_reset) { + cd->need_reset = 0; + m68k_reset(cd->m68k); + } else { + calculate_target_cycle(cd->m68k); + resume_68k(cd->m68k); + } + } else { + cd->m68k->current_cycle = cycle; + } + scd_peripherals_run(cd, cycle); +} + +uint32_t gen_cycle_to_scd(uint32_t cycle, genesis_context *gen) +{ + return ((uint64_t)cycle) * ((uint64_t)gen->normal_clock) / ((uint64_t)SCD_MCLKS); +} + +void scd_adjust_cycle(segacd_context *cd, uint32_t deduction) +{ + deduction = gen_cycle_to_scd(deduction, cd->genesis); + cd->m68k->current_cycle -= deduction; + cd->stopwatch_cycle -= deduction; + if (deduction >= cd->int2_cycle) { + cd->int2_cycle = 0; + } else if (cd->int2_cycle != CYCLE_NEVER) { + cd->int2_cycle -= deduction; + } + if (deduction >= cd->periph_reset_cycle) { + cd->periph_reset_cycle = CYCLE_NEVER; + } else if (cd->periph_reset_cycle != CYCLE_NEVER) { + cd->periph_reset_cycle -= deduction; + } +} + 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]; + genesis_context *gen = m68k->system; + segacd_context *cd = gen->expansion; + uint32_t scd_cycle = gen_cycle_to_scd(m68k->current_cycle, gen); + scd_run(cd, scd_cycle); + uint32_t offset = (address & 0x1FF) >> 1; + switch (offset) + { + case GA_SUB_CPU_CTRL: { + uint16_t value = 0; + if (cd->gate_array[GA_INT_MASK] & BIT_MASK_IEN2) { + value |= BIT_IEN2; + } + if (cd->int2_cycle != CYCLE_NEVER) { + value |= BIT_IFL2; + } + if (can_main_access_prog(cd)) { + value |= BIT_SBRQ; + } + if (cd->reset) { + value |= BIT_SRES; + } + return value; + } + case GA_MEM_MODE: + //Main CPU can't read priority mode bits + return cd->gate_array[offset] & 0xFFE7; + case GA_HINT_VECTOR: + return cd->rom_mut[0x72/2]; + case GA_CDC_DMA_ADDR: + //TODO: open bus maybe? + return 0xFFFF; + default: + if (offset < GA_TIMER) { + return cd->gate_array[offset]; + } + //TODO: open bus maybe? + return 0xFFFF; + } } 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]; + uint16_t val = main_gate_read16(address & 0xFE, vcontext); return address & 1 ? val : val >> 8; } @@ -151,21 +499,80 @@ m68k_context *m68k = vcontext; genesis_context *gen = m68k->system; segacd_context *cd = gen->expansion; + uint32_t scd_cycle = gen_cycle_to_scd(m68k->current_cycle, gen); + scd_run(cd, scd_cycle); uint32_t reg = (address & 0x1FF) >> 1; switch (reg) { - case 0x7: + case GA_SUB_CPU_CTRL: { + uint8_t old_access = can_main_access_prog(cd); + cd->busreq = value & BIT_SBRQ; + uint8_t old_reset = cd->reset; + cd->reset = value & BIT_SRES; + if (cd->reset && !old_reset) { + cd->need_reset = 1; + } + cd->gate_array[reg] &= 0x7FFF; + cd->gate_array[reg] |= value & 0x8000; + uint8_t new_access = can_main_access_prog(cd); + uint32_t bank = cd->gate_array[GA_MEM_MODE] >> 6 & 0x3; + if (new_access) { + if (!old_access) { + m68k->mem_pointers[cd->memptr_start_index] = cd->prog_ram + bank * 0x10000; + m68k_invalidate_code_range(m68k, cd->base + 0x220000, cd->base + 0x240000); + } + } else if (old_access) { + m68k->mem_pointers[cd->memptr_start_index] = NULL; + m68k_invalidate_code_range(m68k, cd->base + 0x220000, cd->base + 0x240000); + m68k_invalidate_code_range(cd->m68k, bank * 0x20000, (bank + 1) * 0x20000); + } + break; + } + case GA_MEM_MODE: { + uint16_t changed = cd->gate_array[reg] ^ value; + //Main CPU can't write priority mode bits, MODE or RET + cd->gate_array[reg] &= 0x001D; + cd->gate_array[reg] |= value & 0xFFC0; + if ((cd->gate_array[reg] & BIT_MEM_MODE)) { + //1M mode + if (!(value & BIT_DMNA)) { + cd->gate_array[reg] |= BIT_DMNA; + } + } else { + cd->gate_array[reg] |= value & BIT_DMNA; + //2M mode + if (changed & value & BIT_DMNA) { + m68k->mem_pointers[cd->memptr_start_index + 1] = NULL; + m68k->mem_pointers[cd->memptr_start_index + 2] = NULL; + cd->m68k->mem_pointers[0] = cd->word_ram; + + m68k_invalidate_code_range(m68k, cd->base + 0x200000, cd->base + 0x240000); + m68k_invalidate_code_range(cd->m68k, 0x080000, 0x0C0000); + } + } + if (changed & MASK_PROG_BANK) { + uint32_t bank = cd->gate_array[GA_MEM_MODE] >> 6 & 0x3; + m68k->mem_pointers[cd->memptr_start_index] = cd->word_ram + bank * 0x10000; + m68k_invalidate_code_range(m68k, cd->base + 0x220000, cd->base + 0x240000); + } + break; + } + case GA_HINT_VECTOR: + cd->rom_mut[0x72/2] = value; + break; + case GA_COMM_FLAG: + //Main CPU can only write the upper byte; 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: + case GA_COMM_CMD0: + case GA_COMM_CMD1: + case GA_COMM_CMD2: + case GA_COMM_CMD3: + case GA_COMM_CMD4: + case GA_COMM_CMD5: + case GA_COMM_CMD6: + case GA_COMM_CMD7: //no effects for these other than saving the value cd->gate_array[reg] = value; break; @@ -193,17 +600,17 @@ 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} + {0x000000, 0x00FEFF, 0xFFFFFF, .flags=MMAP_READ | MMAP_CODE, .write_16 = prog_ram_wp_write16, .write_8 = prog_ram_wp_write8}, + {0x00FF00, 0x07FFFF, 0xFFFFFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE}, + {0x080000, 0x0BFFFF, 0x03FFFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 0, + .read_16 = word_ram_2M_read16, .write_16 = word_ram_2M_write16, .read_8 = word_ram_2M_read8, .write_8 = word_ram_2M_write8}, + {0x0C0000, 0x0DFFFF, 0x01FFFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_CODE | MMAP_PTR_IDX | MMAP_FUNC_NULL, .ptr_index = 1, + .read_16 = word_ram_1M_read16, .write_16 = word_ram_1M_write16, .read_8 = word_ram_1M_read8, .write_8 = word_ram_1M_write8}, + {0xFE0000, 0xFEFFFF, 0x003FFF, .flags=MMAP_READ | MMAP_WRITE | MMAP_ONLY_ODD}, + {0xFF0000, 0xFF7FFF, 0x003FFF, .read_16 = pcm_read16, .write_16 = pcm_write16, .read_8 = pcm_read8, .write_8 = pcm_write8}, + {0xFF8000, 0xFF81FF, 0x0001FF, .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) { @@ -218,46 +625,67 @@ 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->rom_mut[0x72/2] = 0xFFFF; + + //memset(info, 0, sizeof(*info)); + //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->word_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); + init_m68k_opts(mopts, sub_cpu_map, sizeof(sub_cpu_map) / sizeof(*sub_cpu_map), 4, sync_components); cd->m68k = init_68k_context(mopts, NULL); cd->m68k->system = cd; + cd->int2_cycle = CYCLE_NEVER; cd->busreq = 1; cd->busack = 1; - + cd->need_reset = 1; + cd->reset = 1; //active low, so reset is not active on start + cd->memptr_start_index = 0; + cd->gate_array[1] = 1; + cd->gate_array[0x1B] = 0x100; + return cd; } -memmap_chunk *segacd_main_cpu_map(segacd_context *cd, uint32_t *num_chunks) +memmap_chunk *segacd_main_cpu_map(segacd_context *cd, uint8_t cart_boot, 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 + {0x000000, 0x01FFFF, 0x01FFFF, .flags=MMAP_READ}, + {0x020000, 0x03FFFF, 0x01FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_CODE, .ptr_index = 0, + .read_16 = unmapped_prog_read16, .write_16 = unmapped_prog_write16, .read_8 = unmapped_prog_read8, .write_8 = unmapped_prog_write8}, + {0x040000, 0x05FFFF, 0x01FFFF, .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}, + {0x200000, 0x21FFFF, 0x01FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_CODE, .ptr_index = 1}, + {0x220000, 0x23FFFF, 0x01FFFF, .flags=MMAP_READ|MMAP_WRITE|MMAP_PTR_IDX|MMAP_FUNC_NULL|MMAP_CODE, .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 + for (int i = 0; i < sizeof(main_cpu_map) / sizeof(*main_cpu_map); i++) + { + if (main_cpu_map[i].start < 0x800000) { + if (cart_boot) { + main_cpu_map[i].start |= 0x400000; + main_cpu_map[i].end |= 0x400000; + } else { + main_cpu_map[i].start &= 0x3FFFFF; + main_cpu_map[i].end &= 0x3FFFFF; + } + } + } //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; + main_cpu_map[3].buffer = cd->word_ram; + main_cpu_map[4].buffer = cd->word_ram + 0x10000; *num_chunks = sizeof(main_cpu_map) / sizeof(*main_cpu_map); return main_cpu_map; } diff -r 3414a4423de1 -r 8ee7ecbf3f21 segacd.h --- a/segacd.h Sat Jan 15 13:15:21 2022 -0800 +++ b/segacd.h Tue Jan 18 00:03:50 2022 -0800 @@ -1,25 +1,36 @@ #ifndef SEGACD_H_ #define SEGACD_H_ #include -#include "system.h" -#include "m68k_core.h" +#include "genesis.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; + m68k_context *m68k; + system_media *media; + genesis_context *genesis; + uint16_t gate_array[0x100]; + 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 *word_ram; + uint8_t *pcm_ram; + uint8_t *bram; + uint32_t stopwatch_cycle; + uint32_t int2_cycle; + uint32_t periph_reset_cycle; + uint32_t base; + uint8_t timer_pending; + uint8_t timer_value; + uint8_t busreq; + uint8_t busack; + uint8_t reset; + uint8_t need_reset; + uint8_t memptr_start_index; } 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); +memmap_chunk *segacd_main_cpu_map(segacd_context *cd, uint8_t cart_boot, uint32_t *num_chunks); +uint32_t gen_cycle_to_scd(uint32_t cycle, genesis_context *gen); +void scd_run(segacd_context *cd, uint32_t cycle); +void scd_adjust_cycle(segacd_context *cd, uint32_t deduction); #endif //SEGACD_H_