Mercurial > repos > blastem
comparison sms.c @ 1692:5dacaef602a7 segacd
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 05 Jan 2019 00:58:08 -0800 |
parents | 6909c5d0bbb5 |
children | b7ecd0d6a77b 395f684c5379 |
comparison
equal
deleted
inserted
replaced
1504:95b3a1a8b26c | 1692:5dacaef602a7 |
---|---|
4 #include "sms.h" | 4 #include "sms.h" |
5 #include "blastem.h" | 5 #include "blastem.h" |
6 #include "render.h" | 6 #include "render.h" |
7 #include "util.h" | 7 #include "util.h" |
8 #include "debug.h" | 8 #include "debug.h" |
9 #include "saves.h" | |
10 #include "bindings.h" | |
9 | 11 |
10 static void *memory_io_write(uint32_t location, void *vcontext, uint8_t value) | 12 static void *memory_io_write(uint32_t location, void *vcontext, uint8_t value) |
11 { | 13 { |
12 z80_context *z80 = vcontext; | 14 z80_context *z80 = vcontext; |
13 sms_context *sms = z80->system; | 15 sms_context *sms = z80->system; |
290 } | 292 } |
291 } | 293 } |
292 | 294 |
293 static void save_state(sms_context *sms, uint8_t slot) | 295 static void save_state(sms_context *sms, uint8_t slot) |
294 { | 296 { |
295 char *save_path; | 297 char *save_path = get_slot_name(&sms->header, slot, "state"); |
296 if (slot == QUICK_SAVE_SLOT) { | |
297 save_path = save_state_path; | |
298 } else { | |
299 char slotname[] = "slot_0.state"; | |
300 slotname[5] = '0' + slot; | |
301 char const *parts[] = {sms->header.save_dir, PATH_SEP, slotname}; | |
302 save_path = alloc_concat_m(3, parts); | |
303 } | |
304 serialize_buffer state; | 298 serialize_buffer state; |
305 init_serialize(&state); | 299 init_serialize(&state); |
306 sms_serialize(sms, &state); | 300 sms_serialize(sms, &state); |
307 save_to_file(&state, save_path); | 301 save_to_file(&state, save_path); |
308 printf("Saved state to %s\n", save_path); | 302 printf("Saved state to %s\n", save_path); |
303 free(save_path); | |
309 free(state.data); | 304 free(state.data); |
310 } | 305 } |
311 | 306 |
312 static uint8_t load_state_path(sms_context *sms, char *path) | 307 static uint8_t load_state_path(sms_context *sms, char *path) |
313 { | 308 { |
322 } | 317 } |
323 | 318 |
324 static uint8_t load_state(system_header *system, uint8_t slot) | 319 static uint8_t load_state(system_header *system, uint8_t slot) |
325 { | 320 { |
326 sms_context *sms = (sms_context *)system; | 321 sms_context *sms = (sms_context *)system; |
327 char numslotname[] = "slot_0.state"; | 322 char *statepath = get_slot_name(system, slot, "state"); |
328 char *slotname; | 323 uint8_t ret; |
329 if (slot == QUICK_SAVE_SLOT) { | 324 if (!sms->z80->native_pc) { |
330 slotname = "quicksave.state"; | 325 ret = get_modification_time(statepath) != 0; |
331 } else { | 326 if (ret) { |
332 numslotname[5] = '0' + slot; | 327 system->delayed_load_slot = slot + 1; |
333 slotname = numslotname; | 328 } |
334 } | 329 goto done; |
335 char const *parts[] = {sms->header.save_dir, PATH_SEP, slotname}; | 330 |
336 char *statepath = alloc_concat_m(3, parts); | 331 } |
337 uint8_t ret = load_state_path(sms, statepath); | 332 ret = load_state_path(sms, statepath); |
333 done: | |
338 free(statepath); | 334 free(statepath); |
339 return ret; | 335 return ret; |
340 } | 336 } |
341 | 337 |
342 static void run_sms(system_header *system) | 338 static void run_sms(system_header *system) |
343 { | 339 { |
344 render_disable_ym(); | |
345 sms_context *sms = (sms_context *)system; | 340 sms_context *sms = (sms_context *)system; |
346 uint32_t target_cycle = sms->z80->current_cycle + 3420*16; | 341 uint32_t target_cycle = sms->z80->current_cycle + 3420*16; |
347 //TODO: PAL support | 342 //TODO: PAL support |
348 render_set_video_standard(VID_NTSC); | 343 render_set_video_standard(VID_NTSC); |
349 while (!sms->should_return) | 344 while (!sms->should_return) |
350 { | 345 { |
346 if (system->delayed_load_slot) { | |
347 load_state(system, system->delayed_load_slot - 1); | |
348 system->delayed_load_slot = 0; | |
349 | |
350 } | |
351 if (system->enter_debugger && sms->z80->pc) { | 351 if (system->enter_debugger && sms->z80->pc) { |
352 system->enter_debugger = 0; | 352 system->enter_debugger = 0; |
353 zdebugger(sms->z80, sms->z80->pc); | 353 zdebugger(sms->z80, sms->z80->pc); |
354 } | 354 } |
355 if (sms->z80->nmi_start == CYCLE_NEVER) { | 355 if (sms->z80->nmi_start == CYCLE_NEVER) { |
384 vdp_adjust_cycles(sms->vdp, adjust); | 384 vdp_adjust_cycles(sms->vdp, adjust); |
385 sms->psg->cycles -= adjust; | 385 sms->psg->cycles -= adjust; |
386 target_cycle -= adjust; | 386 target_cycle -= adjust; |
387 } | 387 } |
388 } | 388 } |
389 bindings_release_capture(); | |
389 vdp_release_framebuffer(sms->vdp); | 390 vdp_release_framebuffer(sms->vdp); |
391 render_pause_source(sms->psg->audio); | |
390 sms->should_return = 0; | 392 sms->should_return = 0; |
391 render_enable_ym(); | |
392 } | 393 } |
393 | 394 |
394 static void resume_sms(system_header *system) | 395 static void resume_sms(system_header *system) |
395 { | 396 { |
396 sms_context *sms = (sms_context *)system; | 397 sms_context *sms = (sms_context *)system; |
398 bindings_reacquire_capture(); | |
397 vdp_reacquire_framebuffer(sms->vdp); | 399 vdp_reacquire_framebuffer(sms->vdp); |
400 render_resume_source(sms->psg->audio); | |
398 run_sms(system); | 401 run_sms(system); |
399 } | 402 } |
400 | 403 |
401 static void start_sms(system_header *system, char *statefile) | 404 static void start_sms(system_header *system, char *statefile) |
402 { | 405 { |
403 sms_context *sms = (sms_context *)system; | 406 sms_context *sms = (sms_context *)system; |
404 set_keybindings(&sms->io); | |
405 | 407 |
406 z80_assert_reset(sms->z80, 0); | 408 z80_assert_reset(sms->z80, 0); |
407 z80_clear_reset(sms->z80, 128*15); | 409 z80_clear_reset(sms->z80, 128*15); |
408 | 410 |
409 if (statefile) { | 411 if (statefile) { |
447 } | 449 } |
448 | 450 |
449 static void inc_debug_mode(system_header *system) | 451 static void inc_debug_mode(system_header *system) |
450 { | 452 { |
451 sms_context *sms = (sms_context *)system; | 453 sms_context *sms = (sms_context *)system; |
452 sms->vdp->debug++; | 454 vdp_inc_debug_mode(sms->vdp); |
453 if (sms->vdp->debug == 7) { | |
454 sms->vdp->debug = 0; | |
455 } | |
456 } | |
457 | |
458 static void inc_debug_pal(system_header *system) | |
459 { | |
460 sms_context *sms = (sms_context *)system; | |
461 sms->vdp->debug_pal++; | |
462 if (sms->vdp->debug_pal == 4) { | |
463 sms->vdp->debug_pal = 0; | |
464 } | |
465 } | 455 } |
466 | 456 |
467 static void load_save(system_header *system) | 457 static void load_save(system_header *system) |
468 { | 458 { |
469 //TODO: Implement me | 459 //TODO: Implement me |
472 static void persist_save(system_header *system) | 462 static void persist_save(system_header *system) |
473 { | 463 { |
474 //TODO: Implement me | 464 //TODO: Implement me |
475 } | 465 } |
476 | 466 |
477 sms_context *alloc_configure_sms(system_media *media, uint32_t opts, uint8_t force_region, rom_info *info_out) | 467 static void gamepad_down(system_header *system, uint8_t gamepad_num, uint8_t button) |
478 { | 468 { |
479 memset(info_out, 0, sizeof(*info_out)); | 469 sms_context *sms = (sms_context *)system; |
470 if (gamepad_num == GAMEPAD_MAIN_UNIT) { | |
471 if (button == MAIN_UNIT_PAUSE) { | |
472 vdp_pbc_pause(sms->vdp); | |
473 } | |
474 } else { | |
475 io_gamepad_down(&sms->io, gamepad_num, button); | |
476 } | |
477 } | |
478 | |
479 static void gamepad_up(system_header *system, uint8_t gamepad_num, uint8_t button) | |
480 { | |
481 sms_context *sms = (sms_context *)system; | |
482 io_gamepad_up(&sms->io, gamepad_num, button); | |
483 } | |
484 | |
485 static void mouse_down(system_header *system, uint8_t mouse_num, uint8_t button) | |
486 { | |
487 sms_context *sms = (sms_context *)system; | |
488 io_mouse_down(&sms->io, mouse_num, button); | |
489 } | |
490 | |
491 static void mouse_up(system_header *system, uint8_t mouse_num, uint8_t button) | |
492 { | |
493 sms_context *sms = (sms_context *)system; | |
494 io_mouse_up(&sms->io, mouse_num, button); | |
495 } | |
496 | |
497 static void mouse_motion_absolute(system_header *system, uint8_t mouse_num, uint16_t x, uint16_t y) | |
498 { | |
499 sms_context *sms = (sms_context *)system; | |
500 io_mouse_motion_absolute(&sms->io, mouse_num, x, y); | |
501 } | |
502 | |
503 static void mouse_motion_relative(system_header *system, uint8_t mouse_num, int32_t x, int32_t y) | |
504 { | |
505 sms_context *sms = (sms_context *)system; | |
506 io_mouse_motion_relative(&sms->io, mouse_num, x, y); | |
507 } | |
508 | |
509 static void keyboard_down(system_header *system, uint8_t scancode) | |
510 { | |
511 sms_context *sms = (sms_context *)system; | |
512 io_keyboard_down(&sms->io, scancode); | |
513 } | |
514 | |
515 static void keyboard_up(system_header *system, uint8_t scancode) | |
516 { | |
517 sms_context *sms = (sms_context *)system; | |
518 io_keyboard_up(&sms->io, scancode); | |
519 } | |
520 | |
521 static void config_updated(system_header *system) | |
522 { | |
523 sms_context *sms = (sms_context *)system; | |
524 setup_io_devices(config, &system->info, &sms->io); | |
525 } | |
526 | |
527 | |
528 sms_context *alloc_configure_sms(system_media *media, uint32_t opts, uint8_t force_region) | |
529 { | |
480 sms_context *sms = calloc(1, sizeof(sms_context)); | 530 sms_context *sms = calloc(1, sizeof(sms_context)); |
481 uint32_t rom_size = nearest_pow2(media->size); | 531 uint32_t rom_size = nearest_pow2(media->size); |
482 memmap_chunk memory_map[6]; | 532 memmap_chunk memory_map[6]; |
483 if (media->size > 0xC000) { | 533 if (media->size > 0xC000) { |
484 info_out->map_chunks = 6; | 534 sms->header.info.map_chunks = 6; |
485 uint8_t *ram_reg_overlap = sms->ram + sizeof(sms->ram) - 4; | 535 uint8_t *ram_reg_overlap = sms->ram + sizeof(sms->ram) - 4; |
486 memory_map[0] = (memmap_chunk){0x0000, 0x0400, 0xFFFF, 0, 0, MMAP_READ, media->buffer, NULL, NULL, NULL, NULL}; | 536 memory_map[0] = (memmap_chunk){0x0000, 0x0400, 0xFFFF, 0, 0, MMAP_READ, media->buffer, NULL, NULL, NULL, NULL}; |
487 memory_map[1] = (memmap_chunk){0x0400, 0x4000, 0xFFFF, 0, 0, MMAP_READ|MMAP_PTR_IDX|MMAP_CODE, NULL, NULL, NULL, NULL, NULL}; | 537 memory_map[1] = (memmap_chunk){0x0400, 0x4000, 0xFFFF, 0, 0, MMAP_READ|MMAP_PTR_IDX|MMAP_CODE, NULL, NULL, NULL, NULL, NULL}; |
488 memory_map[2] = (memmap_chunk){0x4000, 0x8000, 0x3FFF, 0, 1, MMAP_READ|MMAP_PTR_IDX|MMAP_CODE, NULL, NULL, NULL, NULL, NULL}; | 538 memory_map[2] = (memmap_chunk){0x4000, 0x8000, 0x3FFF, 0, 1, MMAP_READ|MMAP_PTR_IDX|MMAP_CODE, NULL, NULL, NULL, NULL, NULL}; |
489 memory_map[3] = (memmap_chunk){0x8000, 0xC000, 0x3FFF, 0, 2, MMAP_READ|MMAP_PTR_IDX|MMAP_CODE, NULL, NULL, NULL, NULL, cart_ram_write}; | 539 memory_map[3] = (memmap_chunk){0x8000, 0xC000, 0x3FFF, 0, 2, MMAP_READ|MMAP_PTR_IDX|MMAP_CODE, NULL, NULL, NULL, NULL, cart_ram_write}; |
490 memory_map[4] = (memmap_chunk){0xC000, 0xFFFC, sizeof(sms->ram)-1, 0, 0, MMAP_READ|MMAP_WRITE|MMAP_CODE, sms->ram, NULL, NULL, NULL, NULL}; | 540 memory_map[4] = (memmap_chunk){0xC000, 0xFFFC, sizeof(sms->ram)-1, 0, 0, MMAP_READ|MMAP_WRITE|MMAP_CODE, sms->ram, NULL, NULL, NULL, NULL}; |
491 memory_map[5] = (memmap_chunk){0xFFFC, 0x10000, 0x0003, 0, 0, MMAP_READ, ram_reg_overlap, NULL, NULL, NULL, mapper_write}; | 541 memory_map[5] = (memmap_chunk){0xFFFC, 0x10000, 0x0003, 0, 0, MMAP_READ, ram_reg_overlap, NULL, NULL, NULL, mapper_write}; |
492 } else { | 542 } else { |
493 info_out->map_chunks = 2; | 543 sms->header.info.map_chunks = 2; |
494 memory_map[0] = (memmap_chunk){0x0000, 0xC000, rom_size-1, 0, 0, MMAP_READ, media->buffer, NULL, NULL, NULL, NULL}; | 544 memory_map[0] = (memmap_chunk){0x0000, 0xC000, rom_size-1, 0, 0, MMAP_READ, media->buffer, NULL, NULL, NULL, NULL}; |
495 memory_map[1] = (memmap_chunk){0xC000, 0x10000, sizeof(sms->ram)-1, 0, 0, MMAP_READ|MMAP_WRITE|MMAP_CODE, sms->ram, NULL, NULL, NULL, NULL}; | 545 memory_map[1] = (memmap_chunk){0xC000, 0x10000, sizeof(sms->ram)-1, 0, 0, MMAP_READ|MMAP_WRITE|MMAP_CODE, sms->ram, NULL, NULL, NULL, NULL}; |
496 }; | 546 }; |
497 info_out->map = malloc(sizeof(memmap_chunk) * info_out->map_chunks); | 547 sms->header.info.map = malloc(sizeof(memmap_chunk) * sms->header.info.map_chunks); |
498 memcpy(info_out->map, memory_map, sizeof(memmap_chunk) * info_out->map_chunks); | 548 memcpy(sms->header.info.map, memory_map, sizeof(memmap_chunk) * sms->header.info.map_chunks); |
499 z80_options *zopts = malloc(sizeof(z80_options)); | 549 z80_options *zopts = malloc(sizeof(z80_options)); |
500 init_z80_opts(zopts, info_out->map, info_out->map_chunks, io_map, 4, 15, 0xFF); | 550 init_z80_opts(zopts, sms->header.info.map, sms->header.info.map_chunks, io_map, 4, 15, 0xFF); |
501 sms->z80 = init_z80_context(zopts); | 551 sms->z80 = init_z80_context(zopts); |
502 sms->z80->system = sms; | 552 sms->z80->system = sms; |
503 sms->z80->options->gen.debug_cmd_handler = debug_commands; | 553 sms->z80->options->gen.debug_cmd_handler = debug_commands; |
504 | 554 |
505 sms->rom = media->buffer; | 555 sms->rom = media->buffer; |
506 sms->rom_size = rom_size; | 556 sms->rom_size = rom_size; |
507 if (info_out->map_chunks > 2) { | 557 if (sms->header.info.map_chunks > 2) { |
508 sms->z80->mem_pointers[0] = sms->rom; | 558 sms->z80->mem_pointers[0] = sms->rom; |
509 sms->z80->mem_pointers[1] = sms->rom + 0x4000; | 559 sms->z80->mem_pointers[1] = sms->rom + 0x4000; |
510 sms->z80->mem_pointers[2] = sms->rom + 0x8000; | 560 sms->z80->mem_pointers[2] = sms->rom + 0x8000; |
511 sms->bank_regs[1] = 0; | 561 sms->bank_regs[1] = 0; |
512 sms->bank_regs[2] = 0x4000 >> 14; | 562 sms->bank_regs[2] = 0x4000 >> 14; |
513 sms->bank_regs[3] = 0x8000 >> 14; | 563 sms->bank_regs[3] = 0x8000 >> 14; |
514 } | 564 } |
515 | 565 |
516 char * lowpass_cutoff_str = tern_find_path(config, "audio\0lowpass_cutoff\0", TVAL_PTR).ptrval; | |
517 uint32_t lowpass_cutoff = lowpass_cutoff_str ? atoi(lowpass_cutoff_str) : 3390; | |
518 | |
519 //TODO: Detect region and pick master clock based off of that | 566 //TODO: Detect region and pick master clock based off of that |
520 sms->normal_clock = sms->master_clock = 53693175; | 567 sms->normal_clock = sms->master_clock = 53693175; |
521 | 568 |
522 sms->psg = malloc(sizeof(psg_context)); | 569 sms->psg = malloc(sizeof(psg_context)); |
523 psg_init(sms->psg, render_sample_rate(), sms->master_clock, 15*16, render_audio_buffer(), lowpass_cutoff); | 570 psg_init(sms->psg, sms->master_clock, 15*16); |
524 | 571 |
525 sms->vdp = malloc(sizeof(vdp_context)); | 572 sms->vdp = init_vdp_context(0); |
526 init_vdp_context(sms->vdp, 0); | |
527 sms->vdp->system = &sms->header; | 573 sms->vdp->system = &sms->header; |
528 | 574 |
529 info_out->save_type = SAVE_NONE; | 575 sms->header.info.save_type = SAVE_NONE; |
530 info_out->name = strdup(media->name); | 576 sms->header.info.name = strdup(media->name); |
531 | 577 |
532 setup_io_devices(config, info_out, &sms->io); | 578 setup_io_devices(config, &sms->header.info, &sms->io); |
579 sms->header.has_keyboard = io_has_keyboard(&sms->io); | |
533 | 580 |
534 sms->header.set_speed_percent = set_speed_percent; | 581 sms->header.set_speed_percent = set_speed_percent; |
535 sms->header.start_context = start_sms; | 582 sms->header.start_context = start_sms; |
536 sms->header.resume_context = resume_sms; | 583 sms->header.resume_context = resume_sms; |
537 sms->header.load_save = load_save; | 584 sms->header.load_save = load_save; |
540 sms->header.free_context = free_sms; | 587 sms->header.free_context = free_sms; |
541 sms->header.get_open_bus_value = get_open_bus_value; | 588 sms->header.get_open_bus_value = get_open_bus_value; |
542 sms->header.request_exit = request_exit; | 589 sms->header.request_exit = request_exit; |
543 sms->header.soft_reset = soft_reset; | 590 sms->header.soft_reset = soft_reset; |
544 sms->header.inc_debug_mode = inc_debug_mode; | 591 sms->header.inc_debug_mode = inc_debug_mode; |
545 sms->header.inc_debug_pal = inc_debug_pal; | 592 sms->header.gamepad_down = gamepad_down; |
593 sms->header.gamepad_up = gamepad_up; | |
594 sms->header.mouse_down = mouse_down; | |
595 sms->header.mouse_up = mouse_up; | |
596 sms->header.mouse_motion_absolute = mouse_motion_absolute; | |
597 sms->header.mouse_motion_relative = mouse_motion_relative; | |
598 sms->header.keyboard_down = keyboard_down; | |
599 sms->header.keyboard_up = keyboard_up; | |
600 sms->header.config_updated = config_updated; | |
546 sms->header.type = SYSTEM_SMS; | 601 sms->header.type = SYSTEM_SMS; |
547 | 602 |
548 return sms; | 603 return sms; |
549 } | 604 } |