Mercurial > repos > blastem
comparison genesis.c @ 2428:65c2e4d990cc
WIP Pico emulation
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Sat, 03 Feb 2024 18:32:41 -0800 |
parents | 767ec72acca7 |
children | da3dc881d3f0 |
comparison
equal
deleted
inserted
replaced
2427:8b948cf23557 | 2428:65c2e4d990cc |
---|---|
57 if (all) { | 57 if (all) { |
58 start_section(buf, SECTION_68000); | 58 start_section(buf, SECTION_68000); |
59 m68k_serialize(gen->m68k, m68k_pc, buf); | 59 m68k_serialize(gen->m68k, m68k_pc, buf); |
60 end_section(buf); | 60 end_section(buf); |
61 | 61 |
62 start_section(buf, SECTION_Z80); | 62 if (gen->header.type == SYSTEM_GENESIS) { |
63 z80_serialize(gen->z80, buf); | 63 start_section(buf, SECTION_Z80); |
64 end_section(buf); | 64 z80_serialize(gen->z80, buf); |
65 end_section(buf); | |
66 } | |
65 } | 67 } |
66 | 68 |
67 start_section(buf, SECTION_VDP); | 69 start_section(buf, SECTION_VDP); |
68 vdp_serialize(gen->vdp, buf); | 70 vdp_serialize(gen->vdp, buf); |
69 end_section(buf); | 71 end_section(buf); |
70 | 72 |
71 start_section(buf, SECTION_YM2612); | 73 if (gen->header.type != SYSTEM_PICO) { |
72 ym_serialize(gen->ym, buf); | 74 start_section(buf, SECTION_YM2612); |
73 end_section(buf); | 75 ym_serialize(gen->ym, buf); |
76 end_section(buf); | |
77 } | |
74 | 78 |
75 start_section(buf, SECTION_PSG); | 79 start_section(buf, SECTION_PSG); |
76 psg_serialize(gen->psg, buf); | 80 psg_serialize(gen->psg, buf); |
77 end_section(buf); | 81 end_section(buf); |
78 | 82 |
84 //I think the refresh logic may technically be part of the VDP, but whatever | 88 //I think the refresh logic may technically be part of the VDP, but whatever |
85 save_int32(buf, gen->last_sync_cycle); | 89 save_int32(buf, gen->last_sync_cycle); |
86 save_int32(buf, gen->refresh_counter); | 90 save_int32(buf, gen->refresh_counter); |
87 end_section(buf); | 91 end_section(buf); |
88 | 92 |
89 start_section(buf, SECTION_SEGA_IO_1); | 93 if (gen->header.type == SYSTEM_GENESIS) { |
90 io_serialize(gen->io.ports, buf); | 94 start_section(buf, SECTION_SEGA_IO_1); |
91 end_section(buf); | 95 io_serialize(gen->io.ports, buf); |
92 | 96 end_section(buf); |
93 start_section(buf, SECTION_SEGA_IO_2); | 97 |
94 io_serialize(gen->io.ports + 1, buf); | 98 start_section(buf, SECTION_SEGA_IO_2); |
95 end_section(buf); | 99 io_serialize(gen->io.ports + 1, buf); |
96 | 100 end_section(buf); |
97 start_section(buf, SECTION_SEGA_IO_EXT); | 101 |
98 io_serialize(gen->io.ports + 2, buf); | 102 start_section(buf, SECTION_SEGA_IO_EXT); |
99 end_section(buf); | 103 io_serialize(gen->io.ports + 2, buf); |
104 end_section(buf); | |
105 } | |
100 | 106 |
101 start_section(buf, SECTION_MAIN_RAM); | 107 start_section(buf, SECTION_MAIN_RAM); |
102 save_int8(buf, RAM_WORDS * 2 / 1024); | 108 save_int8(buf, RAM_WORDS * 2 / 1024); |
103 save_buffer16(buf, gen->work_ram, RAM_WORDS); | 109 save_buffer16(buf, gen->work_ram, RAM_WORDS); |
104 end_section(buf); | 110 end_section(buf); |
105 | 111 |
106 start_section(buf, SECTION_SOUND_RAM); | 112 if (gen->header.type == SYSTEM_GENESIS) { |
107 save_int8(buf, Z80_RAM_BYTES / 1024); | 113 start_section(buf, SECTION_SOUND_RAM); |
108 save_buffer8(buf, gen->zram, Z80_RAM_BYTES); | 114 save_int8(buf, Z80_RAM_BYTES / 1024); |
109 end_section(buf); | 115 save_buffer8(buf, gen->zram, Z80_RAM_BYTES); |
110 | |
111 if (gen->version_reg & 0xF) { | |
112 //only save TMSS info if it's present | |
113 //that will allow a state saved on a model lacking TMSS | |
114 //to be loaded on a model that has it | |
115 start_section(buf, SECTION_TMSS); | |
116 save_int8(buf, gen->tmss); | |
117 save_buffer16(buf, gen->tmss_lock, 2); | |
118 end_section(buf); | 116 end_section(buf); |
117 | |
118 if (gen->version_reg & 0xF) { | |
119 //only save TMSS info if it's present | |
120 //that will allow a state saved on a model lacking TMSS | |
121 //to be loaded on a model that has it | |
122 start_section(buf, SECTION_TMSS); | |
123 save_int8(buf, gen->tmss); | |
124 save_buffer16(buf, gen->tmss_lock, 2); | |
125 end_section(buf); | |
126 } | |
119 } | 127 } |
120 | 128 |
121 cart_serialize(&gen->header, buf); | 129 cart_serialize(&gen->header, buf); |
122 } | 130 } |
123 if (gen->expansion) { | 131 if (gen->expansion) { |
212 static void toggle_tmss_rom(genesis_context *gen); | 220 static void toggle_tmss_rom(genesis_context *gen); |
213 #include "m68k_internal.h" //needed for get_native_address_trans, should be eliminated once handling of PC is cleaned up | 221 #include "m68k_internal.h" //needed for get_native_address_trans, should be eliminated once handling of PC is cleaned up |
214 void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen) | 222 void genesis_deserialize(deserialize_buffer *buf, genesis_context *gen) |
215 { | 223 { |
216 register_section_handler(buf, (section_handler){.fun = m68k_deserialize, .data = gen->m68k}, SECTION_68000); | 224 register_section_handler(buf, (section_handler){.fun = m68k_deserialize, .data = gen->m68k}, SECTION_68000); |
217 register_section_handler(buf, (section_handler){.fun = z80_deserialize, .data = gen->z80}, SECTION_Z80); | |
218 register_section_handler(buf, (section_handler){.fun = vdp_deserialize, .data = gen->vdp}, SECTION_VDP); | 225 register_section_handler(buf, (section_handler){.fun = vdp_deserialize, .data = gen->vdp}, SECTION_VDP); |
219 register_section_handler(buf, (section_handler){.fun = ym_deserialize, .data = gen->ym}, SECTION_YM2612); | |
220 register_section_handler(buf, (section_handler){.fun = psg_deserialize, .data = gen->psg}, SECTION_PSG); | 226 register_section_handler(buf, (section_handler){.fun = psg_deserialize, .data = gen->psg}, SECTION_PSG); |
221 register_section_handler(buf, (section_handler){.fun = bus_arbiter_deserialize, .data = gen}, SECTION_GEN_BUS_ARBITER); | 227 register_section_handler(buf, (section_handler){.fun = bus_arbiter_deserialize, .data = gen}, SECTION_GEN_BUS_ARBITER); |
222 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports}, SECTION_SEGA_IO_1); | |
223 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 1}, SECTION_SEGA_IO_2); | |
224 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 2}, SECTION_SEGA_IO_EXT); | |
225 register_section_handler(buf, (section_handler){.fun = ram_deserialize, .data = gen}, SECTION_MAIN_RAM); | 228 register_section_handler(buf, (section_handler){.fun = ram_deserialize, .data = gen}, SECTION_MAIN_RAM); |
226 register_section_handler(buf, (section_handler){.fun = zram_deserialize, .data = gen}, SECTION_SOUND_RAM); | |
227 register_section_handler(buf, (section_handler){.fun = cart_deserialize, .data = gen}, SECTION_MAPPER); | 229 register_section_handler(buf, (section_handler){.fun = cart_deserialize, .data = gen}, SECTION_MAPPER); |
228 register_section_handler(buf, (section_handler){.fun = tmss_deserialize, .data = gen}, SECTION_TMSS); | 230 if (gen->header.type == SYSTEM_GENESIS) { |
231 register_section_handler(buf, (section_handler){.fun = z80_deserialize, .data = gen->z80}, SECTION_Z80); | |
232 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports}, SECTION_SEGA_IO_1); | |
233 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 1}, SECTION_SEGA_IO_2); | |
234 register_section_handler(buf, (section_handler){.fun = io_deserialize, .data = gen->io.ports + 2}, SECTION_SEGA_IO_EXT); | |
235 register_section_handler(buf, (section_handler){.fun = zram_deserialize, .data = gen}, SECTION_SOUND_RAM); | |
236 register_section_handler(buf, (section_handler){.fun = tmss_deserialize, .data = gen}, SECTION_TMSS); | |
237 } | |
238 if (gen->header.type != SYSTEM_PICO) { | |
239 register_section_handler(buf, (section_handler){.fun = ym_deserialize, .data = gen->ym}, SECTION_YM2612); | |
240 } | |
229 if (gen->expansion) { | 241 if (gen->expansion) { |
230 segacd_context *cd = gen->expansion; | 242 segacd_context *cd = gen->expansion; |
231 segacd_register_section_handlers(cd, buf); | 243 segacd_register_section_handlers(cd, buf); |
232 } | 244 } |
233 uint8_t tmss_old = gen->tmss; | 245 uint8_t tmss_old = gen->tmss; |
234 gen->tmss = 0xFF; | 246 gen->tmss = 0xFF; |
235 while (buf->cur_pos < buf->size) | 247 while (buf->cur_pos < buf->size) |
236 { | 248 { |
237 load_section(buf); | 249 load_section(buf); |
238 } | 250 } |
239 if (gen->version_reg & 0xF) { | 251 if (gen->header.type == SYSTEM_GENESIS && (gen->version_reg & 0xF)) { |
240 if (gen->tmss == 0xFF) { | 252 if (gen->tmss == 0xFF) { |
241 //state lacked a TMSS section, assume that the game ROM is mapped in | 253 //state lacked a TMSS section, assume that the game ROM is mapped in |
242 //and that the VDP is unlocked | 254 //and that the VDP is unlocked |
243 gen->tmss_lock[0] = 0x5345; | 255 gen->tmss_lock[0] = 0x5345; |
244 gen->tmss_lock[1] = 0x4741; | 256 gen->tmss_lock[1] = 0x4741; |
337 context->int_cycle = next_hint; | 349 context->int_cycle = next_hint; |
338 context->int_num = 4; | 350 context->int_num = 4; |
339 | 351 |
340 } | 352 } |
341 } | 353 } |
342 if (mask < 2 && (v_context->regs[REG_MODE_3] & BIT_EINT_EN)) { | 354 if (mask < 2 && (v_context->regs[REG_MODE_3] & BIT_EINT_EN) && gen->header.type == SYSTEM_GENESIS) { |
343 uint32_t next_eint_port0 = io_next_interrupt(gen->io.ports, context->current_cycle); | 355 uint32_t next_eint_port0 = io_next_interrupt(gen->io.ports, context->current_cycle); |
344 uint32_t next_eint_port1 = io_next_interrupt(gen->io.ports + 1, context->current_cycle); | 356 uint32_t next_eint_port1 = io_next_interrupt(gen->io.ports + 1, context->current_cycle); |
345 uint32_t next_eint_port2 = io_next_interrupt(gen->io.ports + 2, context->current_cycle); | 357 uint32_t next_eint_port2 = io_next_interrupt(gen->io.ports + 2, context->current_cycle); |
346 uint32_t next_eint = next_eint_port0 < next_eint_port1 | 358 uint32_t next_eint = next_eint_port0 < next_eint_port1 |
347 ? (next_eint_port0 < next_eint_port2 ? next_eint_port0 : next_eint_port2) | 359 ? (next_eint_port0 < next_eint_port2 ? next_eint_port0 : next_eint_port2) |
667 } | 679 } |
668 } | 680 } |
669 return context; | 681 return context; |
670 } | 682 } |
671 | 683 |
684 static m68k_context* sync_components_pico(m68k_context * context, uint32_t address) | |
685 { | |
686 genesis_context * gen = context->system; | |
687 vdp_context * v_context = gen->vdp; | |
688 if (gen->bus_busy) { | |
689 gen_update_refresh_no_wait(context); | |
690 } else { | |
691 gen_update_refresh(context); | |
692 } | |
693 | |
694 uint32_t mclks = context->current_cycle; | |
695 psg_run(gen->psg, mclks); | |
696 vdp_run_context(v_context, mclks); | |
697 if (mclks >= gen->reset_cycle) { | |
698 gen->reset_requested = 1; | |
699 context->should_return = 1; | |
700 gen->reset_cycle = CYCLE_NEVER; | |
701 } | |
702 if (v_context->frame != gen->last_frame) { | |
703 #ifndef IS_LIB | |
704 if (gen->psg->scope) { | |
705 scope_render(gen->psg->scope); | |
706 } | |
707 #endif | |
708 //printf("reached frame end %d | MCLK Cycles: %d, Target: %d, VDP cycles: %d, vcounter: %d, hslot: %d\n", gen->last_frame, mclks, gen->frame_end, v_context->cycles, v_context->vcounter, v_context->hslot); | |
709 uint32_t elapsed = v_context->frame - gen->last_frame; | |
710 gen->last_frame = v_context->frame; | |
711 event_flush(mclks); | |
712 gen->last_flush_cycle = mclks; | |
713 if (gen->header.enter_debugger_frames) { | |
714 if (elapsed >= gen->header.enter_debugger_frames) { | |
715 gen->header.enter_debugger_frames = 0; | |
716 gen->header.enter_debugger = 1; | |
717 } else { | |
718 gen->header.enter_debugger_frames -= elapsed; | |
719 } | |
720 } | |
721 | |
722 if(exit_after){ | |
723 if (elapsed >= exit_after) { | |
724 exit(0); | |
725 } else { | |
726 exit_after -= elapsed; | |
727 } | |
728 } | |
729 if (context->current_cycle > MAX_NO_ADJUST) { | |
730 uint32_t deduction = mclks - ADJUST_BUFFER; | |
731 vdp_adjust_cycles(v_context, deduction); | |
732 if (gen->mapper_type == MAPPER_JCART) { | |
733 jcart_adjust_cycles(gen, deduction); | |
734 } | |
735 context->current_cycle -= deduction; | |
736 if (gen->psg->vgm) { | |
737 vgm_adjust_cycles(gen->psg->vgm, deduction); | |
738 } | |
739 gen->psg->cycles -= deduction; | |
740 if (gen->reset_cycle != CYCLE_NEVER) { | |
741 gen->reset_cycle -= deduction; | |
742 } | |
743 event_cycle_adjust(mclks, deduction); | |
744 if (gen->expansion) { | |
745 scd_adjust_cycle(gen->expansion, deduction); | |
746 } | |
747 gen->last_flush_cycle -= deduction; | |
748 } | |
749 } else if (mclks - gen->last_flush_cycle > gen->soft_flush_cycles) { | |
750 event_soft_flush(mclks); | |
751 gen->last_flush_cycle = mclks; | |
752 } | |
753 gen->frame_end = vdp_cycles_to_frame_end(v_context); | |
754 context->sync_cycle = gen->frame_end; | |
755 //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot); | |
756 if (!address && (gen->header.enter_debugger || gen->header.save_state)) { | |
757 context->sync_cycle = context->current_cycle + 1; | |
758 } | |
759 adjust_int_cycle(context, v_context); | |
760 if (gen->reset_cycle < context->target_cycle) { | |
761 context->target_cycle = gen->reset_cycle; | |
762 } | |
763 if (address) { | |
764 if (gen->header.enter_debugger || context->wp_hit) { | |
765 if (!context->wp_hit) { | |
766 gen->header.enter_debugger = 0; | |
767 } | |
768 #ifndef IS_LIB | |
769 if (gen->header.debugger_type == DEBUGGER_NATIVE) { | |
770 debugger(context, address); | |
771 } else { | |
772 gdb_debug_enter(context, address); | |
773 } | |
774 #endif | |
775 } | |
776 if (gen->header.save_state) { | |
777 uint8_t slot = gen->header.save_state - 1; | |
778 gen->header.save_state = 0; | |
779 char *save_path = slot >= SERIALIZE_SLOT ? NULL : get_slot_name(&gen->header, slot, use_native_states ? "state" : "gst"); | |
780 if (use_native_states || slot >= SERIALIZE_SLOT) { | |
781 serialize_buffer state; | |
782 init_serialize(&state); | |
783 genesis_serialize(gen, &state, address, slot != EVENTLOG_SLOT); | |
784 if (slot == SERIALIZE_SLOT) { | |
785 gen->serialize_tmp = state.data; | |
786 gen->serialize_size = state.size; | |
787 context->sync_cycle = context->current_cycle; | |
788 context->should_return = 1; | |
789 } else if (slot == EVENTLOG_SLOT) { | |
790 event_state(context->current_cycle, &state); | |
791 } else { | |
792 save_to_file(&state, save_path); | |
793 free(state.data); | |
794 } | |
795 } else { | |
796 save_gst(gen, save_path, address); | |
797 } | |
798 if (slot != SERIALIZE_SLOT) { | |
799 debug_message("Saved state to %s\n", save_path); | |
800 } | |
801 free(save_path); | |
802 } else if(gen->header.save_state) { | |
803 context->sync_cycle = context->current_cycle + 1; | |
804 } | |
805 } | |
806 return context; | |
807 } | |
808 | |
672 static m68k_context *int_ack(m68k_context *context) | 809 static m68k_context *int_ack(m68k_context *context) |
673 { | 810 { |
674 genesis_context * gen = context->system; | 811 genesis_context * gen = context->system; |
675 vdp_context * v_context = gen->vdp; | 812 vdp_context * v_context = gen->vdp; |
676 //printf("acknowledging %d @ %d:%d, vcounter: %d, hslot: %d\n", context->int_ack, context->current_cycle, v_context->cycles, v_context->vcounter, v_context->hslot); | 813 //printf("acknowledging %d @ %d:%d, vcounter: %d, hslot: %d\n", context->int_ack, context->current_cycle, v_context->cycles, v_context->vcounter, v_context->hslot); |
702 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); | 839 //printf("vdp_port write: %X, value: %X, cycle: %d\n", vdp_port, value, context->current_cycle); |
703 | 840 |
704 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access | 841 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access |
705 gen_update_refresh_free_access(context); | 842 gen_update_refresh_free_access(context); |
706 | 843 |
707 sync_components(context, 0); | 844 if (gen->header.type == SYSTEM_PICO) { |
845 sync_components_pico(context, 0); | |
846 } else { | |
847 sync_components(context, 0); | |
848 } | |
708 vdp_context *v_context = gen->vdp; | 849 vdp_context *v_context = gen->vdp; |
709 uint32_t before_cycle = v_context->cycles; | 850 uint32_t before_cycle = v_context->cycles; |
710 uint8_t did_dma = 0; | 851 uint8_t did_dma = 0; |
711 if (vdp_port < 0x10) { | 852 if (vdp_port < 0x10) { |
712 int blocked; | 853 int blocked; |
721 if (m68k_cycle_diff < cycle_diff) { | 862 if (m68k_cycle_diff < cycle_diff) { |
722 m68k_cycle_diff += MCLKS_PER_68K; | 863 m68k_cycle_diff += MCLKS_PER_68K; |
723 } | 864 } |
724 context->current_cycle += m68k_cycle_diff; | 865 context->current_cycle += m68k_cycle_diff; |
725 gen->bus_busy = 1; | 866 gen->bus_busy = 1; |
726 sync_components(context, 0); | 867 if (gen->header.type == SYSTEM_PICO) { |
868 sync_components_pico(context, 0); | |
869 } else { | |
870 sync_components(context, 0); | |
871 } | |
727 gen->bus_busy = 0; | 872 gen->bus_busy = 0; |
728 } | 873 } |
729 } | 874 } |
730 //context->current_cycle = v_context->cycles; | 875 //context->current_cycle = v_context->cycles; |
731 } | 876 } |
744 if (m68k_cycle_diff < cycle_diff) { | 889 if (m68k_cycle_diff < cycle_diff) { |
745 m68k_cycle_diff += MCLKS_PER_68K; | 890 m68k_cycle_diff += MCLKS_PER_68K; |
746 } | 891 } |
747 context->current_cycle += m68k_cycle_diff; | 892 context->current_cycle += m68k_cycle_diff; |
748 gen->bus_busy = 1; | 893 gen->bus_busy = 1; |
749 sync_components(context, 0); | 894 if (gen->header.type == SYSTEM_PICO) { |
895 sync_components_pico(context, 0); | |
896 } else { | |
897 sync_components(context, 0); | |
898 } | |
750 gen->bus_busy = 0; | 899 gen->bus_busy = 0; |
751 } | 900 } |
752 } | 901 } |
753 | 902 |
754 if (blocked < 0) { | 903 if (blocked < 0) { |
771 uint32_t m68k_cycle_diff = (cycle_diff / MCLKS_PER_68K) * MCLKS_PER_68K; | 920 uint32_t m68k_cycle_diff = (cycle_diff / MCLKS_PER_68K) * MCLKS_PER_68K; |
772 if (m68k_cycle_diff < cycle_diff) { | 921 if (m68k_cycle_diff < cycle_diff) { |
773 m68k_cycle_diff += MCLKS_PER_68K; | 922 m68k_cycle_diff += MCLKS_PER_68K; |
774 } | 923 } |
775 context->current_cycle += m68k_cycle_diff; | 924 context->current_cycle += m68k_cycle_diff; |
776 //Lock the Z80 out of the bus until the VDP access is complete | 925 if (gen->header.type == SYSTEM_GENESIS) { |
777 gen->bus_busy = 1; | 926 //Lock the Z80 out of the bus until the VDP access is complete |
778 sync_z80(gen, v_context->cycles); | 927 gen->bus_busy = 1; |
779 gen->bus_busy = 0; | 928 sync_z80(gen, v_context->cycles); |
929 gen->bus_busy = 0; | |
930 } | |
780 } | 931 } |
781 } else if (vdp_port < 0x18) { | 932 } else if (vdp_port < 0x18) { |
782 psg_write(gen->psg, value); | 933 psg_write(gen->psg, value); |
783 } else { | 934 } else { |
784 vdp_test_port_write(gen->vdp, value); | 935 vdp_test_port_write(gen->vdp, value); |
841 uint16_t value; | 992 uint16_t value; |
842 | 993 |
843 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access | 994 //do refresh check here so we can avoid adding a penalty for a refresh that happens during a VDP access |
844 gen_update_refresh_free_access(context); | 995 gen_update_refresh_free_access(context); |
845 | 996 |
846 sync_components(context, 0); | 997 if (gen->header.type == SYSTEM_PICO) { |
998 sync_components_pico(context, 0); | |
999 } else { | |
1000 sync_components(context, 0); | |
1001 } | |
847 vdp_context * v_context = gen->vdp; | 1002 vdp_context * v_context = gen->vdp; |
848 uint32_t before_cycle = context->current_cycle; | 1003 uint32_t before_cycle = context->current_cycle; |
849 if (vdp_port < 0x10) { | 1004 if (vdp_port < 0x10) { |
850 if (vdp_port < 4) { | 1005 if (vdp_port < 4) { |
851 value = vdp_data_port_read(v_context, &context->current_cycle, MCLKS_PER_68K); | 1006 value = vdp_data_port_read(v_context, &context->current_cycle, MCLKS_PER_68K); |
862 } | 1017 } |
863 if (context->current_cycle != before_cycle) { | 1018 if (context->current_cycle != before_cycle) { |
864 //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); | 1019 //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); |
865 //Lock the Z80 out of the bus until the VDP access is complete | 1020 //Lock the Z80 out of the bus until the VDP access is complete |
866 genesis_context *gen = context->system; | 1021 genesis_context *gen = context->system; |
867 gen->bus_busy = 1; | 1022 if (gen->header.type == SYSTEM_GENESIS) { |
868 sync_z80(gen, context->current_cycle); | 1023 gen->bus_busy = 1; |
869 gen->bus_busy = 0; | 1024 sync_z80(gen, context->current_cycle); |
1025 gen->bus_busy = 0; | |
1026 } | |
870 } | 1027 } |
871 | 1028 |
872 //refresh may have happened while we were waiting on the VDP, | 1029 //refresh may have happened while we were waiting on the VDP, |
873 //so advance refresh_counter but don't add any delays | 1030 //so advance refresh_counter but don't add any delays |
874 gen_update_refresh_no_wait(context); | 1031 gen_update_refresh_no_wait(context); |
1070 if (location < 0x10000 || (location & 0x1FFF) >= 0x100) { | 1227 if (location < 0x10000 || (location & 0x1FFF) >= 0x100) { |
1071 return io_write(location, context, value >> 8); | 1228 return io_write(location, context, value >> 8); |
1072 } else { | 1229 } else { |
1073 return io_write(location, context, value); | 1230 return io_write(location, context, value); |
1074 } | 1231 } |
1232 } | |
1233 | |
1234 static void* pico_io_write(uint32_t location, void *vcontext, uint8_t value) | |
1235 { | |
1236 printf("Pico IO write.b %X - %X\n", location, value); | |
1237 return vcontext; | |
1238 } | |
1239 | |
1240 static void* pico_io_write_w(uint32_t location, void *vcontext, uint16_t value) | |
1241 { | |
1242 printf("Pico IO write.w %X - %X\n", location, value); | |
1243 return vcontext; | |
1075 } | 1244 } |
1076 | 1245 |
1077 #define FOREIGN 0x80 | 1246 #define FOREIGN 0x80 |
1078 #define HZ50 0x40 | 1247 #define HZ50 0x40 |
1079 #define USA FOREIGN | 1248 #define USA FOREIGN |
1201 value |= get_open_bus_value(&gen->header) & 0xFF; | 1370 value |= get_open_bus_value(&gen->header) & 0xFF; |
1202 } | 1371 } |
1203 return value; | 1372 return value; |
1204 } | 1373 } |
1205 | 1374 |
1375 static uint8_t pico_io_read(uint32_t location, void *vcontext) | |
1376 { | |
1377 m68k_context *m68k = vcontext; | |
1378 genesis_context *gen = m68k->system; | |
1379 switch(location >> 1 & 0x7F) | |
1380 { | |
1381 case 0: | |
1382 return gen->version_reg; | |
1383 case 1: | |
1384 return gen->pico_button_state; | |
1385 case 2: | |
1386 return gen->pico_pen_x >> 8; | |
1387 case 3: | |
1388 return gen->pico_pen_x; | |
1389 case 4: | |
1390 return gen->pico_pen_y >> 8; | |
1391 case 5: | |
1392 return gen->pico_pen_y; | |
1393 case 6: | |
1394 return gen->pico_page; | |
1395 case 8: | |
1396 printf("uPD7759 data read @ %u\n", m68k->current_cycle); | |
1397 return 0xFF; | |
1398 case 9: | |
1399 printf("uPD7759 contro/status read @ %u\n", m68k->current_cycle); | |
1400 return 0; | |
1401 default: | |
1402 printf("Unknown Pico IO read %X @ %u\n", location, m68k->current_cycle); | |
1403 return 0xFF; | |
1404 } | |
1405 } | |
1406 | |
1407 static uint16_t pico_io_read_w(uint32_t location, void *vcontext) | |
1408 { | |
1409 m68k_context *m68k = vcontext; | |
1410 genesis_context *gen = m68k->system; | |
1411 uint16_t value = pico_io_read(location, vcontext); | |
1412 return value | (value << 8); | |
1413 } | |
1414 | |
1206 static void * z80_write_ym(uint32_t location, void * vcontext, uint8_t value) | 1415 static void * z80_write_ym(uint32_t location, void * vcontext, uint8_t value) |
1207 { | 1416 { |
1208 z80_context * context = vcontext; | 1417 z80_context * context = vcontext; |
1209 genesis_context * gen = context->system; | 1418 genesis_context * gen = context->system; |
1210 sync_sound(gen, context->Z80_CYCLE); | 1419 sync_sound(gen, context->Z80_CYCLE); |
1444 region = translate_region_char(toupper(*def_region)); | 1653 region = translate_region_char(toupper(*def_region)); |
1445 } else { | 1654 } else { |
1446 region = info->regions; | 1655 region = info->regions; |
1447 } | 1656 } |
1448 } | 1657 } |
1449 if (region & REGION_E) { | 1658 uint8_t is_50hz = 0; |
1450 gen->version_reg = NO_DISK | EUR; | 1659 if (gen->header.type == SYSTEM_PICO) { |
1451 } else if (region & REGION_J) { | 1660 if (region & REGION_E) { |
1452 gen->version_reg = NO_DISK | JAP; | 1661 is_50hz = 1; |
1453 } else { | 1662 gen->version_reg = 0x20; |
1454 gen->version_reg = NO_DISK | USA; | 1663 } else if (region & REGION_J) { |
1455 } | 1664 gen->version_reg = 0; |
1456 | 1665 } else { |
1457 if (region & HZ50) { | 1666 gen->version_reg = 0x40; |
1667 } | |
1668 } else { | |
1669 if (region & REGION_E) { | |
1670 gen->version_reg = NO_DISK | EUR; | |
1671 is_50hz = 1; | |
1672 } else if (region & REGION_J) { | |
1673 gen->version_reg = NO_DISK | JAP; | |
1674 } else { | |
1675 gen->version_reg = NO_DISK | USA; | |
1676 } | |
1677 } | |
1678 | |
1679 if (is_50hz) { | |
1458 gen->normal_clock = MCLKS_PAL; | 1680 gen->normal_clock = MCLKS_PAL; |
1681 gen->soft_flush_cycles = MCLKS_LINE * 313 / 3 + 2; | |
1682 } else { | |
1683 gen->normal_clock = MCLKS_NTSC; | |
1459 gen->soft_flush_cycles = MCLKS_LINE * 262 / 3 + 2; | 1684 gen->soft_flush_cycles = MCLKS_LINE * 262 / 3 + 2; |
1460 } else { | |
1461 gen->normal_clock = MCLKS_NTSC; | |
1462 gen->soft_flush_cycles = MCLKS_LINE * 313 / 3 + 2; | |
1463 } | 1685 } |
1464 gen->master_clock = gen->normal_clock; | 1686 gen->master_clock = gen->normal_clock; |
1465 } | 1687 } |
1466 | 1688 |
1467 static uint8_t load_state(system_header *system, uint8_t slot) | 1689 static uint8_t load_state(system_header *system, uint8_t slot) |
1503 while (gen->reset_requested || gen->header.delayed_load_slot) | 1725 while (gen->reset_requested || gen->header.delayed_load_slot) |
1504 { | 1726 { |
1505 if (gen->reset_requested) { | 1727 if (gen->reset_requested) { |
1506 gen->reset_requested = 0; | 1728 gen->reset_requested = 0; |
1507 gen->m68k->should_return = 0; | 1729 gen->m68k->should_return = 0; |
1508 z80_assert_reset(gen->z80, gen->m68k->current_cycle); | 1730 if (gen->header.type == SYSTEM_GENESIS) { |
1509 z80_clear_busreq(gen->z80, gen->m68k->current_cycle); | 1731 z80_assert_reset(gen->z80, gen->m68k->current_cycle); |
1510 ym_reset(gen->ym); | 1732 z80_clear_busreq(gen->z80, gen->m68k->current_cycle); |
1733 } | |
1734 if (gen->header.type != SYSTEM_PICO) { | |
1735 ym_reset(gen->ym); | |
1736 } | |
1511 //Is there any sort of VDP reset? | 1737 //Is there any sort of VDP reset? |
1512 m68k_reset(gen->m68k); | 1738 m68k_reset(gen->m68k); |
1513 } | 1739 } |
1514 if (gen->header.delayed_load_slot) { | 1740 if (gen->header.delayed_load_slot) { |
1515 load_state(&gen->header, gen->header.delayed_load_slot - 1); | 1741 load_state(&gen->header, gen->header.delayed_load_slot - 1); |
1518 } | 1744 } |
1519 } | 1745 } |
1520 if (gen->header.force_release || render_should_release_on_exit()) { | 1746 if (gen->header.force_release || render_should_release_on_exit()) { |
1521 bindings_release_capture(); | 1747 bindings_release_capture(); |
1522 vdp_release_framebuffer(gen->vdp); | 1748 vdp_release_framebuffer(gen->vdp); |
1523 render_pause_source(gen->ym->audio); | 1749 if (gen->header.type != SYSTEM_PICO) { |
1750 render_pause_source(gen->ym->audio); | |
1751 } | |
1524 render_pause_source(gen->psg->audio); | 1752 render_pause_source(gen->psg->audio); |
1525 } | 1753 } |
1526 } | 1754 } |
1527 | 1755 |
1528 static void start_genesis(system_header *system, char *statefile) | 1756 static void start_genesis(system_header *system, char *statefile) |
1570 static void resume_genesis(system_header *system) | 1798 static void resume_genesis(system_header *system) |
1571 { | 1799 { |
1572 genesis_context *gen = (genesis_context *)system; | 1800 genesis_context *gen = (genesis_context *)system; |
1573 if (gen->header.force_release || render_should_release_on_exit()) { | 1801 if (gen->header.force_release || render_should_release_on_exit()) { |
1574 gen->header.force_release = 0; | 1802 gen->header.force_release = 0; |
1575 render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC); | 1803 if (gen->header.type == SYSTEM_PICO) { |
1804 render_set_video_standard((gen->version_reg & 0x60) == 0x20 ? VID_PAL : VID_NTSC); | |
1805 } else { | |
1806 render_set_video_standard((gen->version_reg & HZ50) ? VID_PAL : VID_NTSC); | |
1807 } | |
1576 bindings_reacquire_capture(); | 1808 bindings_reacquire_capture(); |
1577 vdp_reacquire_framebuffer(gen->vdp); | 1809 vdp_reacquire_framebuffer(gen->vdp); |
1578 render_resume_source(gen->ym->audio); | 1810 if (gen->header.type != SYSTEM_PICO) { |
1811 render_resume_source(gen->ym->audio); | |
1812 } | |
1579 render_resume_source(gen->psg->audio); | 1813 render_resume_source(gen->psg->audio); |
1580 } | 1814 } |
1581 resume_68k(gen->m68k); | 1815 resume_68k(gen->m68k); |
1582 handle_reset_requests(gen); | 1816 handle_reset_requests(gen); |
1583 } | 1817 } |
1720 memmap_chunk *map = (memmap_chunk *)gen->m68k->options->gen.memmap; | 1954 memmap_chunk *map = (memmap_chunk *)gen->m68k->options->gen.memmap; |
1721 m68k_options_free(gen->m68k->options); | 1955 m68k_options_free(gen->m68k->options); |
1722 free(gen->cart); | 1956 free(gen->cart); |
1723 free(gen->m68k); | 1957 free(gen->m68k); |
1724 free(gen->work_ram); | 1958 free(gen->work_ram); |
1725 z80_options_free(gen->z80->Z80_OPTS); | 1959 if (gen->header.type == SYSTEM_GENESIS) { |
1726 free(gen->z80); | 1960 z80_options_free(gen->z80->Z80_OPTS); |
1727 free(gen->zram); | 1961 free(gen->z80); |
1728 ym_free(gen->ym); | 1962 free(gen->zram); |
1963 } | |
1964 if (gen->header.type != SYSTEM_PICO) { | |
1965 ym_free(gen->ym); | |
1966 } | |
1729 psg_free(gen->psg); | 1967 psg_free(gen->psg); |
1730 free(gen->header.save_dir); | 1968 free(gen->header.save_dir); |
1731 free_rom_info(&gen->header.info); | 1969 free_rom_info(&gen->header.info); |
1732 free(gen->lock_on); | 1970 free(gen->lock_on); |
1733 if (gen->save_type != SAVE_NONE && gen->mapper_type != MAPPER_SEGA_MED_V2) { | 1971 if (gen->save_type != SAVE_NONE && gen->mapper_type != MAPPER_SEGA_MED_V2) { |
1753 if (gen->mapper_type == MAPPER_JCART) { | 1991 if (gen->mapper_type == MAPPER_JCART) { |
1754 jcart_gamepad_up(gen, gamepad_num, button); | 1992 jcart_gamepad_up(gen, gamepad_num, button); |
1755 } | 1993 } |
1756 } | 1994 } |
1757 | 1995 |
1996 static void gamepad_down_pico(system_header *system, uint8_t gamepad_num, uint8_t button) | |
1997 { | |
1998 genesis_context *gen = (genesis_context *)system; | |
1999 if (gamepad_num != 1) { | |
2000 return; | |
2001 } | |
2002 //TODO: storyware display | |
2003 if (button == BUTTON_C) { | |
2004 gen->pico_page <<= 1; | |
2005 gen->pico_page |= 1; | |
2006 gen->pico_page &= 0x3F; | |
2007 } else if (button == BUTTON_Z) { | |
2008 gen->pico_page >>= 1; | |
2009 } else if (button < BUTTON_B) { | |
2010 gen->pico_button_state &= ~(1 << (button - 1)); | |
2011 } | |
2012 } | |
2013 | |
2014 static void gamepad_up_pico(system_header *system, uint8_t gamepad_num, uint8_t button) | |
2015 { | |
2016 genesis_context *gen = (genesis_context *)system; | |
2017 if (gamepad_num != 1) { | |
2018 return; | |
2019 } | |
2020 if (button < BUTTON_B) { | |
2021 gen->pico_button_state |= 1 << (button - 1); | |
2022 } | |
2023 return; | |
2024 } | |
2025 | |
1758 static void mouse_down(system_header *system, uint8_t mouse_num, uint8_t button) | 2026 static void mouse_down(system_header *system, uint8_t mouse_num, uint8_t button) |
1759 { | 2027 { |
1760 genesis_context *gen = (genesis_context *)system; | 2028 genesis_context *gen = (genesis_context *)system; |
1761 io_mouse_down(&gen->io, mouse_num, button); | 2029 io_mouse_down(&gen->io, mouse_num, button); |
1762 } | 2030 } |
1765 { | 2033 { |
1766 genesis_context *gen = (genesis_context *)system; | 2034 genesis_context *gen = (genesis_context *)system; |
1767 io_mouse_up(&gen->io, mouse_num, button); | 2035 io_mouse_up(&gen->io, mouse_num, button); |
1768 } | 2036 } |
1769 | 2037 |
2038 static void mouse_down_pico(system_header *system, uint8_t mouse_num, uint8_t button) | |
2039 { | |
2040 genesis_context *gen = (genesis_context *)system; | |
2041 if (button == MOUSE_LEFT) { | |
2042 gen->pico_button_state &= ~0x80; | |
2043 } | |
2044 } | |
2045 | |
2046 static void mouse_up_pico(system_header *system, uint8_t mouse_num, uint8_t button) | |
2047 { | |
2048 genesis_context *gen = (genesis_context *)system; | |
2049 if (button == MOUSE_LEFT) { | |
2050 gen->pico_button_state |= 0x80; | |
2051 } | |
2052 } | |
2053 | |
1770 static void mouse_motion_absolute(system_header *system, uint8_t mouse_num, uint16_t x, uint16_t y) | 2054 static void mouse_motion_absolute(system_header *system, uint8_t mouse_num, uint16_t x, uint16_t y) |
1771 { | 2055 { |
1772 genesis_context *gen = (genesis_context *)system; | 2056 genesis_context *gen = (genesis_context *)system; |
1773 io_mouse_motion_absolute(&gen->io, mouse_num, x, y); | 2057 io_mouse_motion_absolute(&gen->io, mouse_num, x, y); |
1774 } | 2058 } |
1777 { | 2061 { |
1778 genesis_context *gen = (genesis_context *)system; | 2062 genesis_context *gen = (genesis_context *)system; |
1779 io_mouse_motion_relative(&gen->io, mouse_num, x, y); | 2063 io_mouse_motion_relative(&gen->io, mouse_num, x, y); |
1780 } | 2064 } |
1781 | 2065 |
2066 static void mouse_motion_absolute_pico(system_header *system, uint8_t mouse_num, uint16_t x, uint16_t y) | |
2067 { | |
2068 genesis_context *gen = (genesis_context *)system; | |
2069 //TODO: scale properly | |
2070 //TODO: limit to mouse motion on emulated storyware/drawing area | |
2071 gen->pico_pen_x = (x >> 1) + 0x3C; | |
2072 gen->pico_pen_y = y + 0x1FC; | |
2073 } | |
2074 | |
2075 static void mouse_motion_relative_pico(system_header *system, uint8_t mouse_num, int32_t x, int32_t y) | |
2076 { | |
2077 genesis_context *gen = (genesis_context *)system; | |
2078 //TODO: scale properly | |
2079 //TODO: limit to mouse motion on emulated storyware/drawing area | |
2080 gen->pico_pen_x += x; | |
2081 gen->pico_pen_y += y; | |
2082 } | |
2083 | |
1782 static void keyboard_down(system_header *system, uint8_t scancode) | 2084 static void keyboard_down(system_header *system, uint8_t scancode) |
1783 { | 2085 { |
1784 genesis_context *gen = (genesis_context *)system; | 2086 genesis_context *gen = (genesis_context *)system; |
1785 io_keyboard_down(&gen->io, scancode); | 2087 io_keyboard_down(&gen->io, scancode); |
1786 } | 2088 } |
1787 | 2089 |
1788 static void keyboard_up(system_header *system, uint8_t scancode) | 2090 static void keyboard_up(system_header *system, uint8_t scancode) |
1789 { | 2091 { |
1790 genesis_context *gen = (genesis_context *)system; | 2092 genesis_context *gen = (genesis_context *)system; |
1791 io_keyboard_up(&gen->io, scancode); | 2093 io_keyboard_up(&gen->io, scancode); |
2094 } | |
2095 | |
2096 static void keyboard_down_pico(system_header *system, uint8_t scancode) | |
2097 { | |
2098 genesis_context *gen = (genesis_context *)system; | |
2099 //TODO: Keyboard Pico emulation | |
2100 } | |
2101 | |
2102 static void keyboard_up_pico(system_header *system, uint8_t scancode) | |
2103 { | |
2104 genesis_context *gen = (genesis_context *)system; | |
2105 //TODO: Keyboard Pico emulation | |
1792 } | 2106 } |
1793 | 2107 |
1794 static void set_audio_config(genesis_context *gen) | 2108 static void set_audio_config(genesis_context *gen) |
1795 { | 2109 { |
1796 char *config_gain; | 2110 char *config_gain; |
1797 config_gain = tern_find_path(config, "audio\0psg_gain\0", TVAL_PTR).ptrval; | 2111 config_gain = tern_find_path(config, "audio\0psg_gain\0", TVAL_PTR).ptrval; |
1798 render_audio_source_gaindb(gen->psg->audio, config_gain ? atof(config_gain) : 0.0f); | 2112 render_audio_source_gaindb(gen->psg->audio, config_gain ? atof(config_gain) : 0.0f); |
1799 config_gain = tern_find_path(config, "audio\0fm_gain\0", TVAL_PTR).ptrval; | 2113 if (gen->header.type != SYSTEM_PICO) { |
1800 render_audio_source_gaindb(gen->ym->audio, config_gain ? atof(config_gain) : 0.0f); | 2114 config_gain = tern_find_path(config, "audio\0fm_gain\0", TVAL_PTR).ptrval; |
1801 | 2115 render_audio_source_gaindb(gen->ym->audio, config_gain ? atof(config_gain) : 0.0f); |
1802 char *config_dac = tern_find_path_default(config, "audio\0fm_dac\0", (tern_val){.ptrval="zero_offset"}, TVAL_PTR).ptrval; | 2116 |
1803 ym_enable_zero_offset(gen->ym, !strcmp(config_dac, "zero_offset")); | 2117 char *config_dac = tern_find_path_default(config, "audio\0fm_dac\0", (tern_val){.ptrval="zero_offset"}, TVAL_PTR).ptrval; |
2118 ym_enable_zero_offset(gen->ym, !strcmp(config_dac, "zero_offset")); | |
2119 } | |
1804 | 2120 |
1805 if (gen->expansion) { | 2121 if (gen->expansion) { |
1806 segacd_context *cd = gen->expansion; | 2122 segacd_context *cd = gen->expansion; |
1807 config_gain = tern_find_path(config, "audio\0rf5c164_gain\0", TVAL_PTR).ptrval; | 2123 config_gain = tern_find_path(config, "audio\0rf5c164_gain\0", TVAL_PTR).ptrval; |
1808 render_audio_source_gaindb(cd->pcm.audio, config_gain ? atof(config_gain) : -6.0f); | 2124 render_audio_source_gaindb(cd->pcm.audio, config_gain ? atof(config_gain) : -6.0f); |
1812 } | 2128 } |
1813 | 2129 |
1814 static void config_updated(system_header *system) | 2130 static void config_updated(system_header *system) |
1815 { | 2131 { |
1816 genesis_context *gen = (genesis_context *)system; | 2132 genesis_context *gen = (genesis_context *)system; |
1817 setup_io_devices(config, &system->info, &gen->io); | 2133 if (gen->header.type == SYSTEM_GENESIS) { |
2134 setup_io_devices(config, &system->info, &gen->io); | |
2135 } | |
1818 set_audio_config(gen); | 2136 set_audio_config(gen); |
1819 //sample rate may have changed | 2137 //sample rate may have changed |
1820 ym_adjust_master_clock(gen->ym, gen->master_clock); | 2138 if (gen->header.type != SYSTEM_PICO) { |
2139 ym_adjust_master_clock(gen->ym, gen->master_clock); | |
2140 } | |
1821 psg_adjust_master_clock(gen->psg, gen->master_clock); | 2141 psg_adjust_master_clock(gen->psg, gen->master_clock); |
1822 if (gen->expansion) { | 2142 if (gen->expansion) { |
1823 segacd_config_updated(gen->expansion); | 2143 segacd_config_updated(gen->expansion); |
1824 } | 2144 } |
1825 } | 2145 } |
1829 genesis_context *gen = (genesis_context *)system; | 2149 genesis_context *gen = (genesis_context *)system; |
1830 vgm_writer *vgm = vgm_write_open(filename, gen->version_reg & HZ50 ? 50 : 60, gen->normal_clock, gen->m68k->current_cycle); | 2150 vgm_writer *vgm = vgm_write_open(filename, gen->version_reg & HZ50 ? 50 : 60, gen->normal_clock, gen->m68k->current_cycle); |
1831 if (vgm) { | 2151 if (vgm) { |
1832 printf("Started logging VGM to %s\n", filename); | 2152 printf("Started logging VGM to %s\n", filename); |
1833 sync_sound(gen, vgm->last_cycle); | 2153 sync_sound(gen, vgm->last_cycle); |
1834 ym_vgm_log(gen->ym, gen->normal_clock, vgm); | 2154 if (gen->header.type != SYSTEM_PICO) { |
2155 ym_vgm_log(gen->ym, gen->normal_clock, vgm); | |
2156 } | |
1835 psg_vgm_log(gen->psg, gen->normal_clock, vgm); | 2157 psg_vgm_log(gen->psg, gen->normal_clock, vgm); |
1836 gen->header.vgm_logging = 1; | 2158 gen->header.vgm_logging = 1; |
1837 } else { | 2159 } else { |
1838 printf("Failed to start logging to %s\n", filename); | 2160 printf("Failed to start logging to %s\n", filename); |
1839 } | 2161 } |
1842 static void stop_vgm_log(system_header *system) | 2164 static void stop_vgm_log(system_header *system) |
1843 { | 2165 { |
1844 puts("Stopped VGM log"); | 2166 puts("Stopped VGM log"); |
1845 genesis_context *gen = (genesis_context *)system; | 2167 genesis_context *gen = (genesis_context *)system; |
1846 vgm_close(gen->ym->vgm); | 2168 vgm_close(gen->ym->vgm); |
1847 gen->ym->vgm = gen->psg->vgm = NULL; | 2169 if (gen->header.type != SYSTEM_PICO) { |
2170 gen->ym->vgm = NULL; | |
2171 } | |
2172 gen->psg->vgm = NULL; | |
1848 gen->header.vgm_logging = 0; | 2173 gen->header.vgm_logging = 0; |
1849 } | 2174 } |
1850 | 2175 |
1851 static void toggle_debug_view(system_header *system, uint8_t debug_view) | 2176 static void toggle_debug_view(system_header *system, uint8_t debug_view) |
1852 { | 2177 { |
1853 #ifndef IS_LIB | 2178 #ifndef IS_LIB |
1854 genesis_context *gen = (genesis_context *)system; | 2179 genesis_context *gen = (genesis_context *)system; |
1855 if (debug_view < DEBUG_OSCILLOSCOPE) { | 2180 if (debug_view < DEBUG_OSCILLOSCOPE) { |
1856 vdp_toggle_debug_view(gen->vdp, debug_view); | 2181 vdp_toggle_debug_view(gen->vdp, debug_view); |
1857 } else if (debug_view == DEBUG_OSCILLOSCOPE) { | 2182 } else if (debug_view == DEBUG_OSCILLOSCOPE) { |
1858 if (gen->ym->scope) { | 2183 if (gen->psg->scope) { |
1859 oscilloscope *scope = gen->ym->scope; | 2184 oscilloscope *scope = gen->psg->scope; |
1860 gen->ym->scope = NULL; | 2185 if (gen->header.type != SYSTEM_PICO) { |
2186 gen->ym->scope = NULL; | |
2187 } | |
1861 gen->psg->scope = NULL; | 2188 gen->psg->scope = NULL; |
1862 if (gen->expansion) { | 2189 if (gen->expansion) { |
1863 segacd_context *cd = gen->expansion; | 2190 segacd_context *cd = gen->expansion; |
1864 cd->pcm.scope = NULL; | 2191 cd->pcm.scope = NULL; |
1865 } | 2192 } |
1866 scope_close(scope); | 2193 scope_close(scope); |
1867 } else { | 2194 } else { |
1868 oscilloscope *scope = create_oscilloscope(); | 2195 oscilloscope *scope = create_oscilloscope(); |
1869 ym_enable_scope(gen->ym, scope, gen->normal_clock); | 2196 if (gen->header.type != SYSTEM_PICO) { |
2197 ym_enable_scope(gen->ym, scope, gen->normal_clock); | |
2198 } | |
1870 psg_enable_scope(gen->psg, scope, gen->normal_clock); | 2199 psg_enable_scope(gen->psg, scope, gen->normal_clock); |
1871 if (gen->expansion) { | 2200 if (gen->expansion) { |
1872 segacd_context *cd = gen->expansion; | 2201 segacd_context *cd = gen->expansion; |
1873 rf5c164_enable_scope(&cd->pcm, scope); | 2202 rf5c164_enable_scope(&cd->pcm, scope); |
1874 } | 2203 } |
2464 gen->header.type = SYSTEM_SEGACD; | 2793 gen->header.type = SYSTEM_SEGACD; |
2465 | 2794 |
2466 set_audio_config(gen); | 2795 set_audio_config(gen); |
2467 return gen; | 2796 return gen; |
2468 } | 2797 } |
2798 | |
2799 static memmap_chunk pico_base_map[] = { | |
2800 {0xE00000, 0x1000000, 0xFFFF, .flags = MMAP_READ | MMAP_WRITE | MMAP_CODE}, | |
2801 {0xC00000, 0xE00000, 0x1FFFFF, .read_16 = (read_16_fun)vdp_port_read, .write_16 =(write_16_fun)vdp_port_write, | |
2802 .read_8 = (read_8_fun)vdp_port_read_b, .write_8 = (write_8_fun)vdp_port_write_b}, | |
2803 {0x800000, 0x900000, 0xFFFFFF, .read_16 = pico_io_read_w, .write_16 = pico_io_write_w, | |
2804 .read_8 = pico_io_read, .write_8 = pico_io_write} | |
2805 }; | |
2806 const size_t pico_base_chunks = sizeof(pico_base_map)/sizeof(*pico_base_map); | |
2807 | |
2808 genesis_context* alloc_config_pico(void *rom, uint32_t rom_size, void *lock_on, uint32_t lock_on_size, uint32_t ym_opts, uint8_t force_region) | |
2809 { | |
2810 tern_node *rom_db = get_rom_db(); | |
2811 rom_info info = configure_rom(rom_db, rom, rom_size, lock_on, lock_on_size, pico_base_map, pico_base_chunks); | |
2812 rom = info.rom; | |
2813 rom_size = info.rom_size; | |
2814 #ifndef BLASTEM_BIG_ENDIAN | |
2815 byteswap_rom(nearest_pow2(rom_size), rom); | |
2816 if (lock_on) { | |
2817 byteswap_rom(nearest_pow2(lock_on_size), lock_on); | |
2818 } | |
2819 #endif | |
2820 char *m68k_divider = tern_find_path(config, "clocks\0m68k_divider\0", TVAL_PTR).ptrval; | |
2821 if (!m68k_divider) { | |
2822 m68k_divider = "7"; | |
2823 } | |
2824 MCLKS_PER_68K = atoi(m68k_divider); | |
2825 if (!MCLKS_PER_68K) { | |
2826 MCLKS_PER_68K = 7; | |
2827 } | |
2828 genesis_context *gen = calloc(1, sizeof(genesis_context)); | |
2829 gen->header.set_speed_percent = set_speed_percent; | |
2830 gen->header.start_context = start_genesis; | |
2831 gen->header.resume_context = resume_genesis; | |
2832 gen->header.load_save = load_save; | |
2833 gen->header.persist_save = persist_save; | |
2834 gen->header.load_state = load_state; | |
2835 gen->header.soft_reset = soft_reset; | |
2836 gen->header.free_context = free_genesis; | |
2837 gen->header.get_open_bus_value = get_open_bus_value; | |
2838 gen->header.request_exit = request_exit; | |
2839 gen->header.inc_debug_mode = inc_debug_mode; | |
2840 gen->header.gamepad_down = gamepad_down_pico; | |
2841 gen->header.gamepad_up = gamepad_up_pico; | |
2842 gen->header.mouse_down = mouse_down_pico; | |
2843 gen->header.mouse_up = mouse_up_pico; | |
2844 gen->header.mouse_motion_absolute = mouse_motion_absolute_pico; | |
2845 gen->header.mouse_motion_relative = mouse_motion_relative_pico; | |
2846 gen->header.keyboard_down = keyboard_down_pico; | |
2847 gen->header.keyboard_up = keyboard_up_pico; | |
2848 gen->header.config_updated = config_updated; | |
2849 gen->header.serialize = serialize; | |
2850 gen->header.deserialize = deserialize; | |
2851 gen->header.start_vgm_log = start_vgm_log; | |
2852 gen->header.stop_vgm_log = stop_vgm_log; | |
2853 gen->header.toggle_debug_view = toggle_debug_view; | |
2854 gen->header.type = SYSTEM_PICO; | |
2855 gen->header.info = info; | |
2856 set_region(gen, rom, force_region); | |
2857 gen->vdp_unlocked = 1; | |
2858 gen->pico_button_state = 0xFF; | |
2859 | |
2860 gen->vdp = init_vdp_context((gen->version_reg & 0x60) == 0x20, 40, VDP_GENESIS); | |
2861 gen->vdp->system = &gen->header; | |
2862 gen->frame_end = vdp_cycles_to_frame_end(gen->vdp); | |
2863 char * config_cycles = tern_find_path(config, "clocks\0max_cycles\0", TVAL_PTR).ptrval; | |
2864 gen->max_cycles = config_cycles ? atoi(config_cycles) : DEFAULT_SYNC_INTERVAL; | |
2865 gen->int_latency_prev1 = MCLKS_PER_68K * 32; | |
2866 gen->int_latency_prev2 = MCLKS_PER_68K * 16; | |
2867 | |
2868 render_set_video_standard((gen->version_reg & 0x60) == 0x20 ? VID_PAL : VID_NTSC); | |
2869 | |
2870 gen->psg = calloc(1, sizeof(psg_context)); | |
2871 psg_init(gen->psg, gen->master_clock, MCLKS_PER_PSG); | |
2872 gen->work_ram = calloc(2, RAM_WORDS); | |
2873 if (!strcmp("random", tern_find_path_default(config, "system\0ram_init\0", (tern_val){.ptrval = "zero"}, TVAL_PTR).ptrval)) | |
2874 { | |
2875 srand(time(NULL)); | |
2876 for (int i = 0; i < RAM_WORDS; i++) | |
2877 { | |
2878 gen->work_ram[i] = rand(); | |
2879 } | |
2880 for (int i = 0; i < VRAM_SIZE; i++) | |
2881 { | |
2882 gen->vdp->vdpmem[i] = rand(); | |
2883 } | |
2884 for (int i = 0; i < SAT_CACHE_SIZE; i++) | |
2885 { | |
2886 gen->vdp->sat_cache[i] = rand(); | |
2887 } | |
2888 for (int i = 0; i < CRAM_SIZE; i++) | |
2889 { | |
2890 write_cram_internal(gen->vdp, i, rand()); | |
2891 } | |
2892 for (int i = 0; i < gen->vdp->vsram_size; i++) | |
2893 { | |
2894 gen->vdp->vsram[i] = rand(); | |
2895 } | |
2896 } | |
2897 gen->cart = rom; | |
2898 gen->lock_on = lock_on; | |
2899 gen->header.has_keyboard = 0; //TODO: Keyboard Pico emulation | |
2900 gen->mapper_type = info.mapper_type; | |
2901 gen->save_type = info.save_type; | |
2902 if (gen->save_type != SAVE_NONE) { | |
2903 gen->save_ram_mask = info.save_mask; | |
2904 gen->save_size = info.save_size; | |
2905 gen->save_storage = info.save_buffer; | |
2906 gen->header.info.save_buffer = info.save_buffer = NULL; | |
2907 gen->eeprom_map = info.eeprom_map; | |
2908 gen->num_eeprom = info.num_eeprom; | |
2909 if (gen->save_type == SAVE_I2C) { | |
2910 eeprom_init(&gen->eeprom, gen->save_storage, gen->save_size); | |
2911 } else if (gen->save_type == SAVE_NOR) { | |
2912 memcpy(&gen->nor, info.nor, sizeof(gen->nor)); | |
2913 //nor_flash_init(&gen->nor, gen->save_storage, gen->save_size, info.save_page_size, info.save_product_id, info.save_bus); | |
2914 } | |
2915 } else { | |
2916 gen->save_storage = NULL; | |
2917 } | |
2918 | |
2919 gen->mapper_start_index = info.mapper_start_index; | |
2920 //This must happen before we generate memory access functions in init_m68k_opts | |
2921 for (int i = 0; i < info.map_chunks; i++) | |
2922 { | |
2923 if (info.map[i].start == 0xE00000) { | |
2924 info.map[i].buffer = gen->work_ram; | |
2925 break; | |
2926 } | |
2927 } | |
2928 | |
2929 memmap_chunk* map = info.map; | |
2930 uint32_t map_chunks = info.map_chunks; | |
2931 info.map = gen->header.info.map = NULL; | |
2932 | |
2933 m68k_options *opts = malloc(sizeof(m68k_options)); | |
2934 init_m68k_opts(opts, map, map_chunks, MCLKS_PER_68K, sync_components_pico, int_ack); | |
2935 //TODO: Pico model selection | |
2936 //if (!strcmp(tern_find_ptr_default(model, "tas", "broken"), "broken")) { | |
2937 opts->gen.flags |= M68K_OPT_BROKEN_READ_MODIFY; | |
2938 //} | |
2939 gen->m68k = init_68k_context(opts, NULL); | |
2940 gen->m68k->system = gen; | |
2941 opts->address_log = (ym_opts & OPT_ADDRESS_LOG) ? fopen("address.log", "w") : NULL; | |
2942 | |
2943 //This must happen after the 68K context has been allocated | |
2944 for (int i = 0; i < map_chunks; i++) | |
2945 { | |
2946 if (map[i].flags & MMAP_PTR_IDX) { | |
2947 gen->m68k->mem_pointers[map[i].ptr_index] = map[i].buffer; | |
2948 } | |
2949 } | |
2950 | |
2951 if (gen->mapper_type == MAPPER_SEGA) { | |
2952 //initialize bank registers | |
2953 for (int i = 1; i < sizeof(gen->bank_regs); i++) | |
2954 { | |
2955 gen->bank_regs[i] = i; | |
2956 } | |
2957 } | |
2958 gen->reset_cycle = CYCLE_NEVER; | |
2959 | |
2960 set_audio_config(gen); | |
2961 bindings_set_mouse_mode(MOUSE_ABSOLUTE); | |
2962 return gen; | |
2963 } |