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 }