comparison genesis.c @ 1503:a763523dadf4 segacd

Added code for initializing a combined Genesis + Sega CD system when a Sega CD ISO is loaded
author Michael Pavone <pavone@retrodev.com>
date Wed, 13 Dec 2017 09:44:41 -0800
parents f284ad74afe1
children 5dacaef602a7
comparison
equal deleted inserted replaced
1502:2564b6ba2e12 1503:a763523dadf4
2 Copyright 2013-2016 Michael Pavone 2 Copyright 2013-2016 Michael Pavone
3 This file is part of BlastEm. 3 This file is part of BlastEm.
4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text. 4 BlastEm is free software distributed under the terms of the GNU General Public License version 3 or greater. See COPYING for full license text.
5 */ 5 */
6 #include "genesis.h" 6 #include "genesis.h"
7 #include "segacd.h"
7 #include "blastem.h" 8 #include "blastem.h"
8 #include "nor.h" 9 #include "nor.h"
9 #include <stdlib.h> 10 #include <stdlib.h>
10 #include <ctype.h> 11 #include <ctype.h>
11 #include <time.h> 12 #include <time.h>
1084 adjust_int_cycle(gen->m68k, gen->vdp); 1085 adjust_int_cycle(gen->m68k, gen->vdp);
1085 start_68k_context(gen->m68k, pc); 1086 start_68k_context(gen->m68k, pc);
1086 } else { 1087 } else {
1087 if (gen->header.enter_debugger) { 1088 if (gen->header.enter_debugger) {
1088 gen->header.enter_debugger = 0; 1089 gen->header.enter_debugger = 0;
1089 uint32_t address = gen->cart[2] << 16 | gen->cart[3]; 1090 uint32_t address = read_word(4, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen, gen->m68k) << 16
1091 | read_word(6, (void **)gen->m68k->mem_pointers, &gen->m68k->options->gen, gen->m68k);
1090 insert_breakpoint(gen->m68k, address, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter); 1092 insert_breakpoint(gen->m68k, address, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter);
1091 } 1093 }
1092 m68k_reset(gen->m68k); 1094 m68k_reset(gen->m68k);
1093 } 1095 }
1094 handle_reset_requests(gen); 1096 handle_reset_requests(gen);
1182 free(gen->header.save_dir); 1184 free(gen->header.save_dir);
1183 free(gen->lock_on); 1185 free(gen->lock_on);
1184 free(gen); 1186 free(gen);
1185 } 1187 }
1186 1188
1187 genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region) 1189 static genesis_context *shared_init(uint32_t system_opts, rom_info *rom, uint8_t force_region)
1188 { 1190 {
1189 static memmap_chunk z80_map[] = { 1191 static memmap_chunk z80_map[] = {
1190 { 0x0000, 0x4000, 0x1FFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL, NULL, NULL, NULL, NULL }, 1192 { 0x0000, 0x4000, 0x1FFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL, NULL, NULL, NULL, NULL },
1191 { 0x8000, 0x10000, 0x7FFF, 0, 0, 0, NULL, NULL, NULL, z80_read_bank, z80_write_bank}, 1193 { 0x8000, 0x10000, 0x7FFF, 0, 0, 0, NULL, NULL, NULL, z80_read_bank, z80_write_bank},
1192 { 0x4000, 0x6000, 0x0003, 0, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym}, 1194 { 0x4000, 0x6000, 0x0003, 0, 0, 0, NULL, NULL, NULL, z80_read_ym, z80_write_ym},
1193 { 0x6000, 0x6100, 0xFFFF, 0, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg}, 1195 { 0x6000, 0x6100, 0xFFFF, 0, 0, 0, NULL, NULL, NULL, NULL, z80_write_bank_reg},
1194 { 0x7F00, 0x8000, 0x00FF, 0, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write} 1196 { 0x7F00, 0x8000, 0x00FF, 0, 0, 0, NULL, NULL, NULL, z80_vdp_port_read, z80_vdp_port_write}
1195 }; 1197 };
1198
1199 char *m68k_divider = tern_find_path(config, "clocks\0m68k_divider\0", TVAL_PTR).ptrval;
1200 if (!m68k_divider) {
1201 m68k_divider = "7";
1202 }
1203 MCLKS_PER_68K = atoi(m68k_divider);
1204 if (!MCLKS_PER_68K) {
1205 MCLKS_PER_68K = 7;
1206 }
1207
1196 genesis_context *gen = calloc(1, sizeof(genesis_context)); 1208 genesis_context *gen = calloc(1, sizeof(genesis_context));
1197 gen->header.set_speed_percent = set_speed_percent; 1209 gen->header.set_speed_percent = set_speed_percent;
1198 gen->header.start_context = start_genesis; 1210 gen->header.start_context = start_genesis;
1199 gen->header.resume_context = resume_genesis; 1211 gen->header.resume_context = resume_genesis;
1200 gen->header.load_save = load_save; 1212 gen->header.load_save = load_save;
1205 gen->header.get_open_bus_value = get_open_bus_value; 1217 gen->header.get_open_bus_value = get_open_bus_value;
1206 gen->header.request_exit = request_exit; 1218 gen->header.request_exit = request_exit;
1207 gen->header.inc_debug_mode = inc_debug_mode; 1219 gen->header.inc_debug_mode = inc_debug_mode;
1208 gen->header.inc_debug_pal = inc_debug_pal; 1220 gen->header.inc_debug_pal = inc_debug_pal;
1209 gen->header.type = SYSTEM_GENESIS; 1221 gen->header.type = SYSTEM_GENESIS;
1222
1210 set_region(gen, rom, force_region); 1223 set_region(gen, rom, force_region);
1211 1224
1212 gen->vdp = malloc(sizeof(vdp_context)); 1225 gen->vdp = malloc(sizeof(vdp_context));
1213 init_vdp_context(gen->vdp, gen->version_reg & 0x40); 1226 init_vdp_context(gen->vdp, gen->version_reg & 0x40);
1214 gen->vdp->system = &gen->header; 1227 gen->vdp->system = &gen->header;
1215 gen->frame_end = vdp_cycles_to_frame_end(gen->vdp); 1228 gen->frame_end = vdp_cycles_to_frame_end(gen->vdp);
1216 char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0", TVAL_PTR).ptrval; 1229 char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0", TVAL_PTR).ptrval;
1217 gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL; 1230 gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL;
1218 gen->int_latency_prev1 = MCLKS_PER_68K * 32; 1231 gen->int_latency_prev1 = MCLKS_PER_68K * 32;
1219 gen->int_latency_prev2 = MCLKS_PER_68K * 16; 1232 gen->int_latency_prev2 = MCLKS_PER_68K * 16;
1220 1233
1221 char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0", TVAL_PTR).ptrval; 1234 char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0", TVAL_PTR).ptrval;
1222 uint32_t lowpass_cutoff = lowpass_cutoff_str ? atoi(lowpass_cutoff_str) : DEFAULT_LOWPASS_CUTOFF; 1235 uint32_t lowpass_cutoff = lowpass_cutoff_str ? atoi(lowpass_cutoff_str) : DEFAULT_LOWPASS_CUTOFF;
1223 1236
1224 gen->ym = malloc(sizeof(ym2612_context)); 1237 gen->ym = malloc(sizeof(ym2612_context));
1225 ym_init(gen->ym, render_sample_rate(), gen->master_clock, MCLKS_PER_YM, render_audio_buffer(), system_opts, lowpass_cutoff); 1238 ym_init(gen->ym, render_sample_rate(), gen->master_clock, MCLKS_PER_YM, render_audio_buffer(), system_opts, lowpass_cutoff);
1239 gen->z80 = calloc(1, sizeof(z80_context)); 1252 gen->z80 = calloc(1, sizeof(z80_context));
1240 #endif 1253 #endif
1241 1254
1242 gen->z80->system = gen; 1255 gen->z80->system = gen;
1243 gen->z80->mem_pointers[0] = gen->zram; 1256 gen->z80->mem_pointers[0] = gen->zram;
1244 gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = (uint8_t *)main_rom; 1257 gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = NULL;
1245 1258
1246 gen->cart = main_rom;
1247 gen->lock_on = lock_on;
1248 gen->work_ram = calloc(2, RAM_WORDS); 1259 gen->work_ram = calloc(2, RAM_WORDS);
1249 if (!strcmp("random", tern_find_path_default(config, "system\0ram_init\0", (tern_val){.ptrval = "zero"}, TVAL_PTR).ptrval)) 1260 if (!strcmp("random", tern_find_path_default(config, "system\0ram_init\0", (tern_val){.ptrval = "zero"}, TVAL_PTR).ptrval))
1250 { 1261 {
1251 srand(time(NULL)); 1262 srand(time(NULL));
1252 for (int i = 0; i < RAM_WORDS; i++) 1263 for (int i = 0; i < RAM_WORDS; i++)
1272 for (int i = 0; i < VSRAM_SIZE; i++) 1283 for (int i = 0; i < VSRAM_SIZE; i++)
1273 { 1284 {
1274 gen->vdp->vsram[i] = rand(); 1285 gen->vdp->vsram[i] = rand();
1275 } 1286 }
1276 } 1287 }
1288
1289 return gen;
1290 }
1291
1292 genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region)
1293 {
1294 genesis_context *gen = shared_init(system_opts, rom, force_region);
1295 gen->z80->mem_pointers[1] = gen->z80->mem_pointers[2] = (uint8_t *)main_rom;
1296
1297 gen->cart = main_rom;
1298 gen->lock_on = lock_on;
1299
1277 setup_io_devices(config, rom, &gen->io); 1300 setup_io_devices(config, rom, &gen->io);
1278
1279 gen->mapper_type = rom->mapper_type; 1301 gen->mapper_type = rom->mapper_type;
1280 gen->save_type = rom->save_type; 1302 gen->save_type = rom->save_type;
1281 if (gen->save_type != SAVE_NONE) { 1303 if (gen->save_type != SAVE_NONE) {
1282 gen->save_ram_mask = rom->save_mask; 1304 gen->save_ram_mask = rom->save_mask;
1283 gen->save_size = rom->save_size; 1305 gen->save_size = rom->save_size;
1327 } 1349 }
1328 1350
1329 return gen; 1351 return gen;
1330 } 1352 }
1331 1353
1354 static memmap_chunk base_map[] = {
1355 {0xE00000, 0x1000000, 0xFFFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL,
1356 NULL, NULL, NULL, NULL},
1357 {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, 0, NULL,
1358 (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write,
1359 (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b},
1360 {0xA00000, 0xA12000, 0x1FFFF, 0, 0, 0, NULL,
1361 (read_16_fun)io_read_w, (write_16_fun)io_write_w,
1362 (read_8_fun)io_read, (write_8_fun)io_write}
1363 };
1364 const size_t base_chunks = sizeof(base_map)/sizeof(*base_map);
1365
1332 genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t ym_opts, uint8_t force_region, rom_info *info_out) 1366 genesis_context *alloc_config_genesis(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t ym_opts, uint8_t force_region, rom_info *info_out)
1333 { 1367 {
1334 static memmap_chunk base_map[] = { 1368 tern_node *rom_db = get_rom_db();
1335 {0xE00000, 0x1000000, 0xFFFF, 0, 0, MMAP_READ | MMAP_WRITE | MMAP_CODE, NULL, 1369 *info_out = configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, base_chunks);
1336 NULL, NULL, NULL, NULL},
1337 {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, 0, NULL,
1338 (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write,
1339 (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b},
1340 {0xA00000, 0xA12000, 0x1FFFF, 0, 0, 0, NULL,
1341 (read_16_fun)io_read_w, (write_16_fun)io_write_w,
1342 (read_8_fun)io_read, (write_8_fun)io_write}
1343 };
1344 static tern_node *rom_db;
1345 if (!rom_db) {
1346 rom_db = load_rom_db();
1347 }
1348 *info_out = configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, base_map, sizeof(base_map)/sizeof(base_map[0]));
1349 rom = info_out->rom; 1370 rom = info_out->rom;
1350 rom_size = info_out->rom_size; 1371 rom_size = info_out->rom_size;
1351 #ifndef BLASTEM_BIG_ENDIAN 1372 #ifndef BLASTEM_BIG_ENDIAN
1352 byteswap_rom(rom_size, rom); 1373 byteswap_rom(rom_size, rom);
1353 if (lock_on) { 1374 if (lock_on) {
1354 byteswap_rom(lock_on_size, lock_on); 1375 byteswap_rom(lock_on_size, lock_on);
1355 } 1376 }
1356 #endif 1377 #endif
1357 char *m68k_divider = tern_find_path(config, "clocks\0m68k_divider\0", TVAL_PTR).ptrval;
1358 if (!m68k_divider) {
1359 m68k_divider = "7";
1360 }
1361 MCLKS_PER_68K = atoi(m68k_divider);
1362 if (!MCLKS_PER_68K) {
1363 MCLKS_PER_68K = 7;
1364 }
1365 return alloc_init_genesis(info_out, rom, lock_on, ym_opts, force_region); 1378 return alloc_init_genesis(info_out, rom, lock_on, ym_opts, force_region);
1366 } 1379 }
1380
1381 genesis_context *alloc_config_genesis_cdboot(system_media *media, uint32_t system_opts, uint8_t force_region, rom_info *info_out)
1382 {
1383 segacd_context *cd = alloc_configure_segacd(media, system_opts, force_region, info_out);
1384 genesis_context *gen = shared_init(system_opts, info_out, force_region);
1385 gen->cart = gen->lock_on = NULL;
1386 gen->save_storage = NULL;
1387 gen->save_type = SAVE_NONE;
1388 gen->version_reg &= ~NO_DISK;
1389
1390 gen->expansion = cd;
1391 setup_io_devices(config, info_out, &gen->io);
1392
1393 uint32_t cd_chunks;
1394 memmap_chunk *cd_map = segacd_main_cpu_map(gen->expansion, &cd_chunks);
1395 memmap_chunk *map = malloc(sizeof(memmap_chunk) * (cd_chunks + base_chunks));
1396 memcpy(map, cd_map, sizeof(memmap_chunk) * cd_chunks);
1397 memcpy(map + cd_chunks, base_map, sizeof(memmap_chunk) * base_chunks);
1398 map[cd_chunks].buffer = gen->work_ram;
1399 uint32_t num_chunks = cd_chunks + base_chunks;
1400
1401 m68k_options *opts = malloc(sizeof(m68k_options));
1402 init_m68k_opts(opts, map, num_chunks, MCLKS_PER_68K);
1403 //TODO: make this configurable
1404 opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY;
1405 gen->m68k = init_68k_context(opts, NULL);
1406 gen->m68k->system = gen;
1407 opts->address_log = (system_opts & OPT_ADDRESS_LOG) ? fopen("address.log", "w") : NULL;
1408
1409 //This must happen after the 68K context has been allocated
1410 for (int i = 0; i < num_chunks; i++)
1411 {
1412 if (map[i].flags & MMAP_PTR_IDX) {
1413 gen->m68k->mem_pointers[map[i].ptr_index] = map[i].buffer;
1414 }
1415 }
1416 return gen;
1417 }