Mercurial > repos > blastem
comparison genesis.c @ 1931:374a5ae694e8 mame_interp
Merge from default
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 18 Apr 2020 11:42:53 -0700 |
parents | 49f65d240299 9fd4bedc1a31 |
children | 2c1c88cd1a3f |
comparison
equal
deleted
inserted
replaced
1843:13abdc98379e | 1931:374a5ae694e8 |
---|---|
16 #include "debug.h" | 16 #include "debug.h" |
17 #include "gdb_remote.h" | 17 #include "gdb_remote.h" |
18 #include "saves.h" | 18 #include "saves.h" |
19 #include "bindings.h" | 19 #include "bindings.h" |
20 #include "jcart.h" | 20 #include "jcart.h" |
21 #include "config.h" | |
21 #define MCLKS_NTSC 53693175 | 22 #define MCLKS_NTSC 53693175 |
22 #define MCLKS_PAL 53203395 | 23 #define MCLKS_PAL 53203395 |
23 | 24 |
24 uint32_t MCLKS_PER_68K; | 25 uint32_t MCLKS_PER_68K; |
25 #define MCLKS_PER_YM 7 | 26 #define MCLKS_PER_YM 7 |
32 //TODO: Figure out the exact value for this | 33 //TODO: Figure out the exact value for this |
33 #define LINES_NTSC 262 | 34 #define LINES_NTSC 262 |
34 #define LINES_PAL 313 | 35 #define LINES_PAL 313 |
35 | 36 |
36 #ifdef IS_LIB | 37 #ifdef IS_LIB |
37 #define MAX_SOUND_CYCLES 1000 | 38 #define MAX_SOUND_CYCLES (MCLKS_PER_YM*NUM_OPERATORS*6*4) |
38 #else | 39 #else |
39 #define MAX_SOUND_CYCLES 100000 | 40 #define MAX_SOUND_CYCLES 100000 |
40 #endif | 41 #endif |
41 | 42 |
42 #ifndef USE_NATIVE | 43 #ifdef NEW_CORE |
43 #define Z80_CYCLE cycles | 44 #define Z80_CYCLE cycles |
44 #define Z80_OPTS opts | 45 #define Z80_OPTS opts |
45 #define z80_handle_code_write(...) | 46 #define z80_handle_code_write(...) |
46 #include "musashi/m68kcpu.h" | 47 #include "musashi/m68kcpu.h" |
47 #else | 48 #else |
197 { | 198 { |
198 genesis_context *gen = (genesis_context *)sys; | 199 genesis_context *gen = (genesis_context *)sys; |
199 deserialize_buffer buffer; | 200 deserialize_buffer buffer; |
200 init_deserialize(&buffer, data, size); | 201 init_deserialize(&buffer, data, size); |
201 genesis_deserialize(&buffer, gen); | 202 genesis_deserialize(&buffer, gen); |
202 #ifdef USE_NATIVE | 203 #ifndef NEW_CORE |
203 //HACK: Fix this once PC/IR is represented in a better way in 68K core | 204 //HACK: Fix this once PC/IR is represented in a better way in 68K core |
204 gen->m68k->resume_pc = get_native_address_trans(gen->m68k, gen->m68k->last_prefetch_address); | 205 gen->m68k->resume_pc = get_native_address_trans(gen->m68k, gen->m68k->last_prefetch_address); |
205 #endif | 206 #endif |
206 } | 207 } |
207 | 208 |
218 } | 219 } |
219 | 220 |
220 static uint16_t get_open_bus_value(system_header *system) | 221 static uint16_t get_open_bus_value(system_header *system) |
221 { | 222 { |
222 genesis_context *genesis = (genesis_context *)system; | 223 genesis_context *genesis = (genesis_context *)system; |
223 #ifdef USE_NATIVE | 224 #ifndef NEW_CORE |
224 return read_dma_value(genesis->m68k->last_prefetch_address/2); | 225 return read_dma_value(genesis->m68k->last_prefetch_address/2); |
225 #else | 226 #else |
226 m68000_base_device *device = (m68000_base_device *)genesis->m68k; | 227 m68000_base_device *device = (m68000_base_device *)genesis->m68k; |
227 return read_dma_value(device->pref_addr/2); | 228 return read_dma_value(device->pref_addr/2); |
228 #endif | 229 #endif |
303 #endif | 304 #endif |
304 | 305 |
305 static void z80_next_int_pulse(z80_context * z_context) | 306 static void z80_next_int_pulse(z80_context * z_context) |
306 { | 307 { |
307 genesis_context * gen = z_context->system; | 308 genesis_context * gen = z_context->system; |
308 #ifndef USE_NATIVE | 309 #ifdef NEW_CORE |
309 z_context->int_cycle = vdp_next_vint_z80(gen->vdp); | 310 z_context->int_cycle = vdp_next_vint_z80(gen->vdp); |
310 z_context->int_end_cycle = z_context->int_cycle + Z80_INT_PULSE_MCLKS; | 311 z_context->int_end_cycle = z_context->int_cycle + Z80_INT_PULSE_MCLKS; |
311 z_context->int_value = 0xFF; | 312 z_context->int_value = 0xFF; |
312 z80_sync_cycle(z_context, z_context->sync_cycle); | 313 z80_sync_cycle(z_context, z_context->sync_cycle); |
313 #else | 314 #else |
319 | 320 |
320 static void sync_z80(z80_context * z_context, uint32_t mclks) | 321 static void sync_z80(z80_context * z_context, uint32_t mclks) |
321 { | 322 { |
322 #ifndef NO_Z80 | 323 #ifndef NO_Z80 |
323 if (z80_enabled) { | 324 if (z80_enabled) { |
324 #ifndef USE_NATIVE | 325 #ifdef NEW_CORE |
325 if (z_context->int_cycle == 0xFFFFFFFFU) { | 326 if (z_context->int_cycle == 0xFFFFFFFFU) { |
326 z80_next_int_pulse(z_context); | 327 z80_next_int_pulse(z_context); |
327 } | 328 } |
328 #endif | 329 #endif |
329 z80_run(z_context, mclks); | 330 z80_run(z_context, mclks); |
371 genesis_context * gen = context->system; | 372 genesis_context * gen = context->system; |
372 vdp_context * v_context = gen->vdp; | 373 vdp_context * v_context = gen->vdp; |
373 z80_context * z_context = gen->z80; | 374 z80_context * z_context = gen->z80; |
374 #ifdef REFRESH_EMULATION | 375 #ifdef REFRESH_EMULATION |
375 if (context->current_cycle != last_sync_cycle) { | 376 if (context->current_cycle != last_sync_cycle) { |
376 //lame estimation of refresh cycle delay | 377 //lame estimation of refresh cycle delay |
377 refresh_counter += context->current_cycle - last_sync_cycle; | 378 refresh_counter += context->current_cycle - last_sync_cycle; |
378 if (!gen->bus_busy) { | 379 if (!gen->bus_busy) { |
379 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); | 380 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); |
380 } | 381 } |
381 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | 382 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); |
382 } | 383 } |
383 #endif | 384 #endif |
384 | 385 |
385 uint32_t mclks = context->current_cycle; | 386 uint32_t mclks = context->current_cycle; |
386 sync_z80(z_context, mclks); | 387 sync_z80(z_context, mclks); |
410 if (gen->mapper_type == MAPPER_JCART) { | 411 if (gen->mapper_type == MAPPER_JCART) { |
411 jcart_adjust_cycles(gen, deduction); | 412 jcart_adjust_cycles(gen, deduction); |
412 } | 413 } |
413 context->current_cycle -= deduction; | 414 context->current_cycle -= deduction; |
414 z80_adjust_cycles(z_context, deduction); | 415 z80_adjust_cycles(z_context, deduction); |
415 gen->ym->current_cycle -= deduction; | 416 ym_adjust_cycles(gen->ym, deduction); |
417 if (gen->ym->vgm) { | |
418 vgm_adjust_cycles(gen->ym->vgm, deduction); | |
419 } | |
416 gen->psg->cycles -= deduction; | 420 gen->psg->cycles -= deduction; |
417 if (gen->ym->write_cycle != CYCLE_NEVER) { | |
418 gen->ym->write_cycle = gen->ym->write_cycle >= deduction ? gen->ym->write_cycle - deduction : 0; | |
419 } | |
420 if (gen->reset_cycle != CYCLE_NEVER) { | 421 if (gen->reset_cycle != CYCLE_NEVER) { |
421 gen->reset_cycle -= deduction; | 422 gen->reset_cycle -= deduction; |
422 } | 423 } |
423 } | 424 } |
424 } | 425 } |
436 adjust_int_cycle(context, v_context); | 437 adjust_int_cycle(context, v_context); |
437 if (gen->reset_cycle < context->target_cycle) { | 438 if (gen->reset_cycle < context->target_cycle) { |
438 context->target_cycle = gen->reset_cycle; | 439 context->target_cycle = gen->reset_cycle; |
439 } | 440 } |
440 if (address) { | 441 if (address) { |
441 #ifdef USE_NATIVE | 442 #ifndef NEW_CORE |
442 if (gen->header.enter_debugger) { | 443 if (gen->header.enter_debugger) { |
443 gen->header.enter_debugger = 0; | 444 gen->header.enter_debugger = 0; |
444 debugger(context, address); | 445 debugger(context, address); |
445 } | 446 } |
447 #endif | |
448 #ifdef NEW_CORE | |
449 if (gen->header.save_state) { | |
450 #else | |
446 if (gen->header.save_state && (z_context->pc || !z_context->native_pc || z_context->reset || !z_context->busreq)) { | 451 if (gen->header.save_state && (z_context->pc || !z_context->native_pc || z_context->reset || !z_context->busreq)) { |
447 #else | |
448 if (gen->header.save_state) { | |
449 #endif | 452 #endif |
450 uint8_t slot = gen->header.save_state - 1; | 453 uint8_t slot = gen->header.save_state - 1; |
451 gen->header.save_state = 0; | 454 gen->header.save_state = 0; |
452 #ifdef USE_NATIVE | 455 #ifndef NEW_CORE |
453 if (z_context->native_pc && !z_context->reset) { | 456 if (z_context->native_pc && !z_context->reset) { |
454 //advance Z80 core to the start of an instruction | 457 //advance Z80 core to the start of an instruction |
455 while (!z_context->pc) | 458 while (!z_context->pc) |
456 { | 459 { |
457 sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80); | 460 sync_z80(z_context, z_context->current_cycle + MCLKS_PER_Z80); |
458 } | 461 } |
459 } | 462 } |
460 #endif | 463 #endif |
461 char *save_path = slot == SERIALIZE_SLOT ? NULL : get_slot_name(&gen->header, slot, use_native_states ? "state" : "gst"); | 464 char *save_path = slot == SERIALIZE_SLOT ? NULL : get_slot_name(&gen->header, slot, use_native_states ? "state" : "gst"); |
462 #ifdef USE_NATIVE | 465 #ifndef NEW_CORE |
463 if (use_native_states || slot == SERIALIZE_SLOT) { | 466 if (use_native_states || slot == SERIALIZE_SLOT) { |
464 #endif | 467 #endif |
465 serialize_buffer state; | 468 serialize_buffer state; |
466 init_serialize(&state); | 469 init_serialize(&state); |
467 genesis_serialize(gen, &state, address); | 470 genesis_serialize(gen, &state, address); |
472 context->should_return = 1; | 475 context->should_return = 1; |
473 } else { | 476 } else { |
474 save_to_file(&state, save_path); | 477 save_to_file(&state, save_path); |
475 free(state.data); | 478 free(state.data); |
476 } | 479 } |
477 #ifdef USE_NATIVE | 480 #ifndef NEW_CORE |
478 } else { | 481 } else { |
479 save_gst(gen, save_path, address); | 482 save_gst(gen, save_path, address); |
480 } | 483 } |
481 #endif | 484 #endif |
482 printf("Saved state to %s\n", save_path); | 485 printf("Saved state to %s\n", save_path); |
499 vdp_port &= 0x1F; | 502 vdp_port &= 0x1F; |
500 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); | 503 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); |
501 #ifdef REFRESH_EMULATION | 504 #ifdef REFRESH_EMULATION |
502 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access | 505 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access |
503 if (context->current_cycle - 4*MCLKS_PER_68K > last_sync_cycle) { | 506 if (context->current_cycle - 4*MCLKS_PER_68K > last_sync_cycle) { |
504 refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle; | 507 refresh_counter += context->current_cycle - 4*MCLKS_PER_68K - last_sync_cycle; |
505 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); | 508 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); |
506 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | 509 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); |
507 last_sync_cycle = context->current_cycle; | 510 last_sync_cycle = context->current_cycle; |
508 } | 511 } |
509 #endif | 512 #endif |
510 sync_components(context, 0); | 513 sync_components(context, 0); |
511 genesis_context * gen = context->system; | 514 genesis_context * gen = context->system; |
512 vdp_context *v_context = gen->vdp; | 515 vdp_context *v_context = gen->vdp; |
646 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); | 649 context->current_cycle += REFRESH_DELAY * MCLKS_PER_68K * (refresh_counter / (MCLKS_PER_68K * REFRESH_INTERVAL)); |
647 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); | 650 refresh_counter = refresh_counter % (MCLKS_PER_68K * REFRESH_INTERVAL); |
648 last_sync_cycle = context->current_cycle; | 651 last_sync_cycle = context->current_cycle; |
649 } | 652 } |
650 #endif | 653 #endif |
651 sync_components(context, 0); | |
652 genesis_context *gen = context->system; | 654 genesis_context *gen = context->system; |
653 vdp_context * v_context = gen->vdp; | 655 vdp_context * v_context = gen->vdp; |
654 uint32_t before_cycle = v_context->cycles; | |
655 if (vdp_port < 0x10) { | 656 if (vdp_port < 0x10) { |
656 if (vdp_port < 4) { | 657 if (vdp_port < 4) { |
658 sync_components(context, 0); | |
659 uint32_t before_cycle = v_context->cycles; | |
657 value = vdp_data_port_read(v_context); | 660 value = vdp_data_port_read(v_context); |
661 if (v_context->cycles != before_cycle) { | |
662 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); | |
663 context->current_cycle = v_context->cycles; | |
664 //Lock the Z80 out of the bus until the VDP access is complete | |
665 genesis_context *gen = context->system; | |
666 gen->bus_busy = 1; | |
667 sync_z80(gen->z80, v_context->cycles); | |
668 gen->bus_busy = 0; | |
669 } | |
658 } else if(vdp_port < 8) { | 670 } else if(vdp_port < 8) { |
671 vdp_run_context(v_context, context->current_cycle); | |
659 value = vdp_control_port_read(v_context); | 672 value = vdp_control_port_read(v_context); |
660 } else { | 673 } else { |
674 vdp_run_context(v_context, context->current_cycle); | |
661 value = vdp_hv_counter_read(v_context); | 675 value = vdp_hv_counter_read(v_context); |
662 //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles); | 676 //printf("HV Counter: %X at cycle %d\n", value, v_context->cycles); |
663 } | 677 } |
664 } else if (vdp_port < 0x18){ | 678 } else if (vdp_port < 0x18){ |
665 fatal_error("Illegal read from PSG port %X\n", vdp_port); | 679 fatal_error("Illegal read from PSG port %X\n", vdp_port); |
666 } else { | 680 } else { |
667 value = vdp_test_port_read(v_context); | 681 value = get_open_bus_value(&gen->header); |
668 } | |
669 if (v_context->cycles != before_cycle) { | |
670 //printf("68K paused for %d (%d) cycles at cycle %d (%d) for read\n", v_context->cycles - context->current_cycle, v_context->cycles - before_cycle, context->current_cycle, before_cycle); | |
671 context->current_cycle = v_context->cycles; | |
672 //Lock the Z80 out of the bus until the VDP access is complete | |
673 genesis_context *gen = context->system; | |
674 gen->bus_busy = 1; | |
675 sync_z80(gen->z80, v_context->cycles); | |
676 gen->bus_busy = 0; | |
677 } | 682 } |
678 #ifdef REFRESH_EMULATION | 683 #ifdef REFRESH_EMULATION |
679 last_sync_cycle -= 4; | 684 last_sync_cycle -= 4; |
680 //refresh may have happened while we were waiting on the VDP, | 685 //refresh may have happened while we were waiting on the VDP, |
681 //so advance refresh_counter but don't add any delays | 686 //so advance refresh_counter but don't add any delays |
766 } else { | 771 } else { |
767 fatal_error("68K write to unhandled Z80 address %X\n", location); | 772 fatal_error("68K write to unhandled Z80 address %X\n", location); |
768 } | 773 } |
769 } | 774 } |
770 } else { | 775 } else { |
771 location &= 0x1FFF; | 776 if (location < 0x10100) { |
772 if (location < 0x100) { | 777 switch(location >> 1 & 0xFF) |
773 switch(location/2) | |
774 { | 778 { |
775 case 0x1: | 779 case 0x1: |
776 io_data_write(gen->io.ports, value, context->current_cycle); | 780 io_data_write(gen->io.ports, value, context->current_cycle); |
777 break; | 781 break; |
778 case 0x2: | 782 case 0x2: |
813 case 0xF: | 817 case 0xF: |
814 gen->io.ports[2].serial_ctrl = value; | 818 gen->io.ports[2].serial_ctrl = value; |
815 break; | 819 break; |
816 } | 820 } |
817 } else { | 821 } else { |
818 if (location == 0x1100) { | 822 uint32_t masked = location & 0xFFF00; |
823 if (masked == 0x11100) { | |
819 if (value & 1) { | 824 if (value & 1) { |
820 dputs("bus requesting Z80"); | 825 dputs("bus requesting Z80"); |
821 if (z80_enabled) { | 826 if (z80_enabled) { |
822 z80_assert_busreq(gen->z80, context->current_cycle); | 827 z80_assert_busreq(gen->z80, context->current_cycle); |
823 } else { | 828 } else { |
838 z80_clear_busreq(gen->z80, context->current_cycle); | 843 z80_clear_busreq(gen->z80, context->current_cycle); |
839 } else { | 844 } else { |
840 gen->z80->busack = 0; | 845 gen->z80->busack = 0; |
841 } | 846 } |
842 } | 847 } |
843 } else if (location == 0x1200) { | 848 } else if (masked == 0x11200) { |
844 sync_z80(gen->z80, context->current_cycle); | 849 sync_z80(gen->z80, context->current_cycle); |
845 if (value & 1) { | 850 if (value & 1) { |
846 if (z80_enabled) { | 851 if (z80_enabled) { |
847 z80_clear_reset(gen->z80, context->current_cycle); | 852 z80_clear_reset(gen->z80, context->current_cycle); |
848 } else { | 853 } else { |
854 } else { | 859 } else { |
855 gen->z80->reset = 1; | 860 gen->z80->reset = 1; |
856 } | 861 } |
857 ym_reset(gen->ym); | 862 ym_reset(gen->ym); |
858 } | 863 } |
864 } else if (masked != 0x11300 && masked != 0x11000) { | |
865 fatal_error("Machine freeze due to unmapped write to address %X\n", location | 0xA00000); | |
859 } | 866 } |
860 } | 867 } |
861 } | 868 } |
862 return context; | 869 return context; |
863 } | 870 } |
889 location &= 0x7FFF; | 896 location &= 0x7FFF; |
890 if (location < 0x4000) { | 897 if (location < 0x4000) { |
891 value = gen->zram[location & 0x1FFF]; | 898 value = gen->zram[location & 0x1FFF]; |
892 } else if (location < 0x6000) { | 899 } else if (location < 0x6000) { |
893 sync_sound(gen, context->current_cycle); | 900 sync_sound(gen, context->current_cycle); |
894 value = ym_read_status(gen->ym); | 901 value = ym_read_status(gen->ym, context->current_cycle, location); |
902 } else if (location < 0x7F00) { | |
903 value = 0xFF; | |
895 } else { | 904 } else { |
905 fatal_error("Machine freeze due to read of Z80 VDP memory window by 68K: %X\n", location | 0xA00000); | |
896 value = 0xFF; | 906 value = 0xFF; |
897 } | 907 } |
898 } else { | 908 } else { |
899 value = 0xFF; | 909 uint16_t word = get_open_bus_value(&gen->header); |
900 } | 910 value = location & 1 ? word : word >> 8; |
901 } else { | 911 } |
902 location &= 0x1FFF; | 912 } else { |
903 if (location < 0x100) { | 913 if (location < 0x10100) { |
904 switch(location/2) | 914 switch(location >> 1 & 0xFF) |
905 { | 915 { |
906 case 0x0: | 916 case 0x0: |
907 //version bits should be 0 for now since we're not emulating TMSS | 917 //version bits should be 0 for now since we're not emulating TMSS |
908 value = gen->version_reg; | 918 value = gen->version_reg; |
909 break; | 919 break; |
951 break; | 961 break; |
952 case 0xF: | 962 case 0xF: |
953 value = gen->io.ports[2].serial_ctrl; | 963 value = gen->io.ports[2].serial_ctrl; |
954 break; | 964 break; |
955 default: | 965 default: |
956 value = 0xFF; | 966 value = get_open_bus_value(&gen->header) >> 8; |
957 } | 967 } |
958 } else { | 968 } else { |
959 if (location == 0x1100) { | 969 uint32_t masked = location & 0xFFF00; |
970 if (masked == 0x11100) { | |
960 value = z80_enabled ? !z80_get_busack(gen->z80, context->current_cycle) : !gen->z80->busack; | 971 value = z80_enabled ? !z80_get_busack(gen->z80, context->current_cycle) : !gen->z80->busack; |
961 value |= (get_open_bus_value(&gen->header) >> 8) & 0xFE; | 972 value |= (get_open_bus_value(&gen->header) >> 8) & 0xFE; |
962 dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d)\n", value, context->current_cycle, gen->z80->reset); | 973 dprintf("Byte read of BUSREQ returned %d @ %d (reset: %d)\n", value, context->current_cycle, gen->z80->reset); |
963 } else if (location == 0x1200) { | 974 } else if (masked == 0x11200) { |
964 value = !gen->z80->reset; | 975 value = !gen->z80->reset; |
976 } else if (masked == 0x11300 || masked == 0x11000) { | |
977 //A11300 is apparently completely unused | |
978 //A11000 is the memory control register which I am assuming is write only | |
979 value = get_open_bus_value(&gen->header) >> 8; | |
965 } else { | 980 } else { |
981 location |= 0xA00000; | |
982 fatal_error("Machine freeze due to read of unmapped IO location %X\n", location); | |
966 value = 0xFF; | 983 value = 0xFF; |
967 printf("Byte read of unknown IO location: %X\n", location); | |
968 } | 984 } |
969 } | 985 } |
970 } | 986 } |
971 return value; | 987 return value; |
972 } | 988 } |
1002 static uint8_t z80_read_ym(uint32_t location, void * vcontext) | 1018 static uint8_t z80_read_ym(uint32_t location, void * vcontext) |
1003 { | 1019 { |
1004 z80_context * context = vcontext; | 1020 z80_context * context = vcontext; |
1005 genesis_context * gen = context->system; | 1021 genesis_context * gen = context->system; |
1006 sync_sound(gen, context->Z80_CYCLE); | 1022 sync_sound(gen, context->Z80_CYCLE); |
1007 return ym_read_status(gen->ym); | 1023 return ym_read_status(gen->ym, context->Z80_CYCLE, location); |
1008 } | 1024 } |
1009 | 1025 |
1010 static uint8_t z80_read_bank(uint32_t location, void * vcontext) | 1026 static uint8_t z80_read_bank(uint32_t location, void * vcontext) |
1011 { | 1027 { |
1012 z80_context * context = vcontext; | 1028 z80_context * context = vcontext; |
1013 genesis_context *gen = context->system; | 1029 genesis_context *gen = context->system; |
1014 | |
1015 if (gen->bus_busy) { | 1030 if (gen->bus_busy) { |
1016 context->Z80_CYCLE = gen->m68k->current_cycle; | 1031 context->Z80_CYCLE = gen->m68k->current_cycle; |
1017 } | 1032 } |
1018 | |
1019 //typical delay from bus arbitration | 1033 //typical delay from bus arbitration |
1020 context->Z80_CYCLE += 3 * MCLKS_PER_Z80; | 1034 context->Z80_CYCLE += 3 * MCLKS_PER_Z80; |
1021 //TODO: add cycle for an access right after a previous one | 1035 //TODO: add cycle for an access right after a previous one |
1022 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high | 1036 //TODO: Below cycle time is an estimate based on the time between 68K !BG goes low and Z80 !MREQ goes high |
1023 // Needs a new logic analyzer capture to get the actual delay on the 68K side | 1037 // Needs a new logic analyzer capture to get the actual delay on the 68K side |
1028 return context->mem_pointers[1][location ^ 1]; | 1042 return context->mem_pointers[1][location ^ 1]; |
1029 } | 1043 } |
1030 uint32_t address = gen->z80_bank_reg << 15 | location; | 1044 uint32_t address = gen->z80_bank_reg << 15 | location; |
1031 if (address >= 0xC00000 && address < 0xE00000) { | 1045 if (address >= 0xC00000 && address < 0xE00000) { |
1032 return z80_vdp_port_read(location & 0xFF, context); | 1046 return z80_vdp_port_read(location & 0xFF, context); |
1047 } else if (address >= 0xA10000 && address <= 0xA10001) { | |
1048 //Apparently version reg can be read through Z80 banked area | |
1049 //TODO: Check rest of IO region addresses | |
1050 return gen->version_reg; | |
1033 } else { | 1051 } else { |
1034 fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area (%X)\n", address, gen->z80_bank_reg << 15); | 1052 fprintf(stderr, "Unhandled read by Z80 from address %X through banked memory area (%X)\n", address, gen->z80_bank_reg << 15); |
1035 } | 1053 } |
1036 return 0; | 1054 return 0; |
1037 } | 1055 } |
1070 | 1088 |
1071 gen->z80_bank_reg = (gen->z80_bank_reg >> 1 | value << 8) & 0x1FF; | 1089 gen->z80_bank_reg = (gen->z80_bank_reg >> 1 | value << 8) & 0x1FF; |
1072 update_z80_bank_pointer(context->system); | 1090 update_z80_bank_pointer(context->system); |
1073 | 1091 |
1074 return context; | 1092 return context; |
1093 } | |
1094 | |
1095 static uint16_t unused_read(uint32_t location, void *vcontext) | |
1096 { | |
1097 m68k_context *context = vcontext; | |
1098 genesis_context *gen = context->system; | |
1099 if ((location >= 0xA13000 && location < 0xA13100) || (location >= 0xA12000 && location < 0xA12100)) { | |
1100 //Only called if the cart/exp doesn't have a more specific handler for this region | |
1101 return get_open_bus_value(&gen->header); | |
1102 } else if (location == 0xA14000 || location == 0xA14002) { | |
1103 if (gen->version_reg & 0xF) { | |
1104 return gen->tmss_lock[location >> 1 & 1]; | |
1105 } else { | |
1106 fatal_error("Machine freeze due to read from TMSS lock when TMSS is not present %X\n", location); | |
1107 return 0xFFFF; | |
1108 } | |
1109 } else if (location == 0xA14100) { | |
1110 if (gen->version_reg & 0xF) { | |
1111 return get_open_bus_value(&gen->header); | |
1112 } else { | |
1113 fatal_error("Machine freeze due to read from TMSS control when TMSS is not present %X\n", location); | |
1114 return 0xFFFF; | |
1115 } | |
1116 } else { | |
1117 fatal_error("Machine freeze due to unmapped read from %X\n", location); | |
1118 return 0xFFFF; | |
1119 } | |
1120 } | |
1121 | |
1122 static uint8_t unused_read_b(uint32_t location, void *vcontext) | |
1123 { | |
1124 uint16_t v = unused_read(location & 0xFFFFFE, vcontext); | |
1125 if (location & 1) { | |
1126 return v; | |
1127 } else { | |
1128 return v >> 8; | |
1129 } | |
1130 } | |
1131 | |
1132 static void *unused_write(uint32_t location, void *vcontext, uint16_t value) | |
1133 { | |
1134 m68k_context *context = vcontext; | |
1135 genesis_context *gen = context->system; | |
1136 uint8_t has_tmss = gen->version_reg & 0xF; | |
1137 if (has_tmss && (location == 0xA14000 || location == 0xA14002)) { | |
1138 gen->tmss_lock[location >> 1 & 1] = value; | |
1139 } else if (has_tmss && location == 0xA14100) { | |
1140 //TODO: implement TMSS control register | |
1141 } else if (location < 0xA12000 || location >= 0xA13100 || (location >= 0xA12100 && location < 0xA13000)) { | |
1142 fatal_error("Machine freeze due to unmapped write to %X\n", location); | |
1143 } | |
1144 return vcontext; | |
1145 } | |
1146 | |
1147 static void *unused_write_b(uint32_t location, void *vcontext, uint8_t value) | |
1148 { | |
1149 m68k_context *context = vcontext; | |
1150 genesis_context *gen = context->system; | |
1151 uint8_t has_tmss = gen->version_reg & 0xF; | |
1152 if (has_tmss && location >= 0xA14000 && location <= 0xA14003) { | |
1153 uint32_t offset = location >> 1 & 1; | |
1154 if (location & 1) { | |
1155 gen->tmss_lock[offset] &= 0xFF00; | |
1156 gen->tmss_lock[offset] |= value; | |
1157 } else { | |
1158 gen->tmss_lock[offset] &= 0xFF; | |
1159 gen->tmss_lock[offset] |= value << 8; | |
1160 } | |
1161 } else if (has_tmss && (location == 0xA14100 || location == 0xA14101)) { | |
1162 //TODO: implement TMSS control register | |
1163 } else if (location < 0xA12000 || location >= 0xA13100 || (location >= 0xA12100 && location < 0xA13000)) { | |
1164 fatal_error("Machine freeze due to unmapped byte write to %X\n", location); | |
1165 } | |
1166 return vcontext; | |
1075 } | 1167 } |
1076 | 1168 |
1077 static void set_speed_percent(system_header * system, uint32_t percent) | 1169 static void set_speed_percent(system_header * system, uint32_t percent) |
1078 { | 1170 { |
1079 genesis_context *context = (genesis_context *)system; | 1171 genesis_context *context = (genesis_context *)system; |
1130 goto done; | 1222 goto done; |
1131 } | 1223 } |
1132 if (load_from_file(&state, statepath)) { | 1224 if (load_from_file(&state, statepath)) { |
1133 genesis_deserialize(&state, gen); | 1225 genesis_deserialize(&state, gen); |
1134 free(state.data); | 1226 free(state.data); |
1135 #ifdef USE_NATIVE | 1227 #ifndef NEW_CORE |
1136 //HACK | 1228 //HACK |
1137 pc = gen->m68k->last_prefetch_address; | 1229 pc = gen->m68k->last_prefetch_address; |
1138 #endif | 1230 #endif |
1139 ret = 1; | 1231 ret = 1; |
1140 } else { | 1232 } else { |
1141 #ifdef USE_NATIVE | 1233 #ifndef NEW_CORE |
1142 strcpy(statepath + strlen(statepath)-strlen("state"), "gst"); | 1234 strcpy(statepath + strlen(statepath)-strlen("state"), "gst"); |
1143 pc = load_gst(gen, statepath); | 1235 pc = load_gst(gen, statepath); |
1144 ret = pc != 0; | 1236 ret = pc != 0; |
1145 #endif | 1237 #endif |
1146 } | 1238 } |
1147 #ifdef USE_NATIVE | 1239 #ifndef NEW_CORE |
1148 if (ret) { | 1240 if (ret) { |
1149 gen->m68k->resume_pc = get_native_address_trans(gen->m68k, pc); | 1241 gen->m68k->resume_pc = get_native_address_trans(gen->m68k, pc); |
1150 } | 1242 } |
1151 #endif | 1243 #endif |
1152 done: | 1244 done: |
1189 deserialize_buffer state; | 1281 deserialize_buffer state; |
1190 uint32_t pc; | 1282 uint32_t pc; |
1191 if (load_from_file(&state, statefile)) { | 1283 if (load_from_file(&state, statefile)) { |
1192 genesis_deserialize(&state, gen); | 1284 genesis_deserialize(&state, gen); |
1193 free(state.data); | 1285 free(state.data); |
1194 #ifdef USE_NATIVE | 1286 #ifndef NEW_CORE |
1195 //HACK | 1287 //HACK |
1196 pc = gen->m68k->last_prefetch_address; | 1288 pc = gen->m68k->last_prefetch_address; |
1197 #endif | 1289 #endif |
1198 } else { | 1290 } else { |
1199 #ifdef USE_NATIVE | 1291 #ifndef NEW_CORE |
1200 pc = load_gst(gen, statefile); | 1292 pc = load_gst(gen, statefile); |
1201 if (!pc) { | 1293 if (!pc) { |
1202 fatal_error("Failed to load save state %s\n", statefile); | 1294 fatal_error("Failed to load save state %s\n", statefile); |
1203 } | 1295 } |
1204 #endif | 1296 #endif |
1205 } | 1297 } |
1206 printf("Loaded %s\n", statefile); | 1298 printf("Loaded %s\n", statefile); |
1207 #ifdef USE_NATIVE | 1299 #ifndef NEW_CORE |
1208 if (gen->header.enter_debugger) { | 1300 if (gen->header.enter_debugger) { |
1209 gen->header.enter_debugger = 0; | 1301 gen->header.enter_debugger = 0; |
1210 insert_breakpoint(gen->m68k, pc, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter); | 1302 insert_breakpoint(gen->m68k, pc, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter); |
1211 } | 1303 } |
1212 #endif | 1304 #endif |
1213 adjust_int_cycle(gen->m68k, gen->vdp); | 1305 adjust_int_cycle(gen->m68k, gen->vdp); |
1214 start_68k_context(gen->m68k, pc); | 1306 start_68k_context(gen->m68k, pc); |
1215 } else { | 1307 } else { |
1216 #ifdef USE_NATIVE | 1308 #ifndef NEW_CORE |
1217 if (gen->header.enter_debugger) { | 1309 if (gen->header.enter_debugger) { |
1218 gen->header.enter_debugger = 0; | 1310 gen->header.enter_debugger = 0; |
1219 uint32_t address = gen->cart[2] << 16 | gen->cart[3]; | 1311 uint32_t address = gen->cart[2] << 16 | gen->cart[3]; |
1220 insert_breakpoint(gen->m68k, address, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter); | 1312 insert_breakpoint(gen->m68k, address, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter); |
1221 } | 1313 } |
1262 FILE * f = fopen(save_filename, "wb"); | 1354 FILE * f = fopen(save_filename, "wb"); |
1263 if (!f) { | 1355 if (!f) { |
1264 fprintf(stderr, "Failed to open %s file %s for writing\n", save_type_name(gen->save_type), save_filename); | 1356 fprintf(stderr, "Failed to open %s file %s for writing\n", save_type_name(gen->save_type), save_filename); |
1265 return; | 1357 return; |
1266 } | 1358 } |
1359 if (gen->save_type == RAM_FLAG_BOTH) { | |
1360 byteswap_rom(gen->save_size, (uint16_t *)gen->save_storage); | |
1361 } | |
1267 fwrite(gen->save_storage, 1, gen->save_size, f); | 1362 fwrite(gen->save_storage, 1, gen->save_size, f); |
1363 if (gen->save_type == RAM_FLAG_BOTH) { | |
1364 byteswap_rom(gen->save_size, (uint16_t *)gen->save_storage); | |
1365 } | |
1268 fclose(f); | 1366 fclose(f); |
1269 printf("Saved %s to %s\n", save_type_name(gen->save_type), save_filename); | 1367 printf("Saved %s to %s\n", save_type_name(gen->save_type), save_filename); |
1270 } | 1368 } |
1271 | 1369 |
1272 static void load_save(system_header *system) | 1370 static void load_save(system_header *system) |
1275 FILE * f = fopen(save_filename, "rb"); | 1373 FILE * f = fopen(save_filename, "rb"); |
1276 if (f) { | 1374 if (f) { |
1277 uint32_t read = fread(gen->save_storage, 1, gen->save_size, f); | 1375 uint32_t read = fread(gen->save_storage, 1, gen->save_size, f); |
1278 fclose(f); | 1376 fclose(f); |
1279 if (read > 0) { | 1377 if (read > 0) { |
1378 if (gen->save_type == RAM_FLAG_BOTH) { | |
1379 byteswap_rom(gen->save_size, (uint16_t *)gen->save_storage); | |
1380 } | |
1280 printf("Loaded %s from %s\n", save_type_name(gen->save_type), save_filename); | 1381 printf("Loaded %s from %s\n", save_type_name(gen->save_type), save_filename); |
1281 } | 1382 } |
1282 } | 1383 } |
1283 } | 1384 } |
1284 | 1385 |
1383 static void config_updated(system_header *system) | 1484 static void config_updated(system_header *system) |
1384 { | 1485 { |
1385 genesis_context *gen = (genesis_context *)system; | 1486 genesis_context *gen = (genesis_context *)system; |
1386 setup_io_devices(config, &system->info, &gen->io); | 1487 setup_io_devices(config, &system->info, &gen->io); |
1387 set_audio_config(gen); | 1488 set_audio_config(gen); |
1489 } | |
1490 | |
1491 static void start_vgm_log(system_header *system, char *filename) | |
1492 { | |
1493 genesis_context *gen = (genesis_context *)system; | |
1494 vgm_writer *vgm = vgm_write_open(filename, gen->version_reg & HZ50 ? 50 : 60, gen->master_clock, gen->m68k->current_cycle); | |
1495 if (vgm) { | |
1496 printf("Started logging VGM to %s\n", filename); | |
1497 sync_sound(gen, vgm->last_cycle); | |
1498 ym_vgm_log(gen->ym, gen->master_clock, vgm); | |
1499 psg_vgm_log(gen->psg, gen->master_clock, vgm); | |
1500 gen->header.vgm_logging = 1; | |
1501 } else { | |
1502 printf("Failed to start logging to %s\n", filename); | |
1503 } | |
1504 } | |
1505 | |
1506 static void stop_vgm_log(system_header *system) | |
1507 { | |
1508 puts("Stopped VGM log"); | |
1509 genesis_context *gen = (genesis_context *)system; | |
1510 vgm_close(gen->ym->vgm); | |
1511 gen->ym->vgm = gen->psg->vgm = NULL; | |
1512 gen->header.vgm_logging = 0; | |
1388 } | 1513 } |
1389 | 1514 |
1390 genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region) | 1515 genesis_context *alloc_init_genesis(rom_info *rom, void *main_rom, void *lock_on, uint32_t system_opts, uint8_t force_region) |
1391 { | 1516 { |
1392 static memmap_chunk z80_map[] = { | 1517 static memmap_chunk z80_map[] = { |
1417 gen->header.keyboard_down = keyboard_down; | 1542 gen->header.keyboard_down = keyboard_down; |
1418 gen->header.keyboard_up = keyboard_up; | 1543 gen->header.keyboard_up = keyboard_up; |
1419 gen->header.config_updated = config_updated; | 1544 gen->header.config_updated = config_updated; |
1420 gen->header.serialize = serialize; | 1545 gen->header.serialize = serialize; |
1421 gen->header.deserialize = deserialize; | 1546 gen->header.deserialize = deserialize; |
1547 gen->header.start_vgm_log = start_vgm_log; | |
1548 gen->header.stop_vgm_log = stop_vgm_log; | |
1422 gen->header.type = SYSTEM_GENESIS; | 1549 gen->header.type = SYSTEM_GENESIS; |
1423 gen->header.info = *rom; | 1550 gen->header.info = *rom; |
1424 set_region(gen, rom, force_region); | 1551 set_region(gen, rom, force_region); |
1425 | 1552 tern_node *model = get_model(config, SYSTEM_GENESIS); |
1426 gen->vdp = init_vdp_context(gen->version_reg & 0x40); | 1553 uint8_t tmss = !strcmp(tern_find_ptr_default(model, "tmss", "off"), "on"); |
1554 if (tmss) { | |
1555 gen->version_reg |= 1; | |
1556 } | |
1557 | |
1558 uint8_t max_vsram = !strcmp(tern_find_ptr_default(model, "vsram", "40"), "64"); | |
1559 gen->vdp = init_vdp_context(gen->version_reg & 0x40, max_vsram); | |
1427 gen->vdp->system = &gen->header; | 1560 gen->vdp->system = &gen->header; |
1428 gen->frame_end = vdp_cycles_to_frame_end(gen->vdp); | 1561 gen->frame_end = vdp_cycles_to_frame_end(gen->vdp); |
1429 char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0", TVAL_PTR).ptrval; | 1562 char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0", TVAL_PTR).ptrval; |
1430 gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL; | 1563 gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL; |
1431 gen->int_latency_prev1 = MCLKS_PER_68K * 32; | 1564 gen->int_latency_prev1 = MCLKS_PER_68K * 32; |
1444 z80_map[0].buffer = gen->zram = calloc(1, Z80_RAM_BYTES); | 1577 z80_map[0].buffer = gen->zram = calloc(1, Z80_RAM_BYTES); |
1445 #ifndef NO_Z80 | 1578 #ifndef NO_Z80 |
1446 z80_options *z_opts = malloc(sizeof(z80_options)); | 1579 z80_options *z_opts = malloc(sizeof(z80_options)); |
1447 init_z80_opts(z_opts, z80_map, 5, NULL, 0, MCLKS_PER_Z80, 0xFFFF); | 1580 init_z80_opts(z_opts, z80_map, 5, NULL, 0, MCLKS_PER_Z80, 0xFFFF); |
1448 gen->z80 = init_z80_context(z_opts); | 1581 gen->z80 = init_z80_context(z_opts); |
1449 #ifdef USE_NATIVE | 1582 #ifndef NEW_CORE |
1450 gen->z80->next_int_pulse = z80_next_int_pulse; | 1583 gen->z80->next_int_pulse = z80_next_int_pulse; |
1451 #endif | 1584 #endif |
1452 z80_assert_reset(gen->z80, 0); | 1585 z80_assert_reset(gen->z80, 0); |
1453 #else | 1586 #else |
1454 gen->z80 = calloc(1, sizeof(z80_context)); | 1587 gen->z80 = calloc(1, sizeof(z80_context)); |
1482 } | 1615 } |
1483 for (int i = 0; i < CRAM_SIZE; i++) | 1616 for (int i = 0; i < CRAM_SIZE; i++) |
1484 { | 1617 { |
1485 write_cram_internal(gen->vdp, i, rand()); | 1618 write_cram_internal(gen->vdp, i, rand()); |
1486 } | 1619 } |
1487 for (int i = 0; i < VSRAM_SIZE; i++) | 1620 for (int i = 0; i < gen->vdp->vsram_size; i++) |
1488 { | 1621 { |
1489 gen->vdp->vsram[i] = rand(); | 1622 gen->vdp->vsram[i] = rand(); |
1490 } | 1623 } |
1491 } | 1624 } |
1492 setup_io_devices(config, rom, &gen->io); | 1625 setup_io_devices(config, rom, &gen->io); |
1519 } | 1652 } |
1520 } | 1653 } |
1521 | 1654 |
1522 m68k_options *opts = malloc(sizeof(m68k_options)); | 1655 m68k_options *opts = malloc(sizeof(m68k_options)); |
1523 init_m68k_opts(opts, rom->map, rom->map_chunks, MCLKS_PER_68K); | 1656 init_m68k_opts(opts, rom->map, rom->map_chunks, MCLKS_PER_68K); |
1524 //TODO: make this configurable | 1657 if (!strcmp(tern_find_ptr_default(model, "tas", "broken"), "broken")) { |
1525 opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY; | 1658 opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY; |
1659 } | |
1526 gen->m68k = init_68k_context(opts, NULL); | 1660 gen->m68k = init_68k_context(opts, NULL); |
1527 gen->m68k->system = gen; | 1661 gen->m68k->system = gen; |
1528 opts->address_log = (system_opts & OPT_ADDRESS_LOG) ? fopen("address.log", "w") : NULL; | 1662 opts->address_log = (system_opts & OPT_ADDRESS_LOG) ? fopen("address.log", "w") : NULL; |
1529 | 1663 |
1530 //This must happen after the 68K context has been allocated | 1664 //This must happen after the 68K context has been allocated |
1554 {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, 0, NULL, | 1688 {0xC00000, 0xE00000, 0x1FFFFF, 0, 0, 0, NULL, |
1555 (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write, | 1689 (read_16_fun)vdp_port_read, (write_16_fun)vdp_port_write, |
1556 (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b}, | 1690 (read_8_fun)vdp_port_read_b, (write_8_fun)vdp_port_write_b}, |
1557 {0xA00000, 0xA12000, 0x1FFFF, 0, 0, 0, NULL, | 1691 {0xA00000, 0xA12000, 0x1FFFF, 0, 0, 0, NULL, |
1558 (read_16_fun)io_read_w, (write_16_fun)io_write_w, | 1692 (read_16_fun)io_read_w, (write_16_fun)io_write_w, |
1559 (read_8_fun)io_read, (write_8_fun)io_write} | 1693 (read_8_fun)io_read, (write_8_fun)io_write}, |
1694 {0x000000, 0xFFFFFF, 0xFFFFFF, 0, 0, 0, NULL, | |
1695 (read_16_fun)unused_read, (write_16_fun)unused_write, | |
1696 (read_8_fun)unused_read_b, (write_8_fun)unused_write_b} | |
1560 }; | 1697 }; |
1561 static tern_node *rom_db; | 1698 static tern_node *rom_db; |
1562 if (!rom_db) { | 1699 if (!rom_db) { |
1563 rom_db = load_rom_db(); | 1700 rom_db = load_rom_db(); |
1564 } | 1701 } |