Mercurial > repos > blastem
comparison genesis.c @ 2431:61c0bfe10887
Somewhat busted support for Pico ADPCM
author | Michael Pavone <pavone@retrodev.com> |
---|---|
date | Tue, 06 Feb 2024 21:47:11 -0800 |
parents | da3dc881d3f0 |
children | 2907c3312423 |
comparison
equal
deleted
inserted
replaced
2430:fb8d6ebf9d5f | 2431:61c0bfe10887 |
---|---|
679 } | 679 } |
680 } | 680 } |
681 return context; | 681 return context; |
682 } | 682 } |
683 | 683 |
684 static void sync_sound_pico(genesis_context * gen, uint32_t target) | |
685 { | |
686 while (target > gen->psg->cycles && target - gen->psg->cycles > MAX_SOUND_CYCLES) | |
687 { | |
688 uint32_t cur_target = gen->psg->cycles + MAX_SOUND_CYCLES; | |
689 psg_run(gen->psg, cur_target); | |
690 pico_pcm_run(gen->adpcm, cur_target); | |
691 } | |
692 psg_run(gen->psg, target); | |
693 pico_pcm_run(gen->adpcm, target); | |
694 } | |
695 | |
696 static void adjust_int_cycle_pico(m68k_context *context, vdp_context *v_context) | |
697 { | |
698 genesis_context *gen = context->system; | |
699 if (context->sync_cycle - context->current_cycle > gen->max_cycles) { | |
700 context->sync_cycle = context->current_cycle + gen->max_cycles; | |
701 } | |
702 context->int_cycle = CYCLE_NEVER; | |
703 uint8_t mask = context->status & 0x7; | |
704 if (mask < 6) { | |
705 uint32_t next_vint = vdp_next_vint(v_context); | |
706 if (next_vint != CYCLE_NEVER) { | |
707 context->int_cycle = next_vint; | |
708 context->int_num = 6; | |
709 } | |
710 if (mask < 5) { | |
711 uint32_t next_hint = vdp_next_hint(v_context); | |
712 if (next_hint != CYCLE_NEVER) { | |
713 next_hint = next_hint < context->current_cycle ? context->current_cycle : next_hint; | |
714 if (next_hint < context->int_cycle) { | |
715 context->int_cycle = next_hint; | |
716 context->int_num = 5; | |
717 | |
718 } | |
719 } | |
720 if (mask < 3) { | |
721 uint32_t next_pcm_int = pico_pcm_next_int(gen->adpcm); | |
722 if (next_pcm_int != CYCLE_NEVER && next_pcm_int < context->int_cycle) { | |
723 context->int_cycle = next_pcm_int; | |
724 context->int_num = 3; | |
725 } | |
726 if (mask < 2 && (v_context->regs[REG_MODE_3] & BIT_EINT_EN) && gen->header.type == SYSTEM_GENESIS) { | |
727 uint32_t next_eint_port0 = io_next_interrupt(gen->io.ports, context->current_cycle); | |
728 uint32_t next_eint_port1 = io_next_interrupt(gen->io.ports + 1, context->current_cycle); | |
729 uint32_t next_eint_port2 = io_next_interrupt(gen->io.ports + 2, context->current_cycle); | |
730 uint32_t next_eint = next_eint_port0 < next_eint_port1 | |
731 ? (next_eint_port0 < next_eint_port2 ? next_eint_port0 : next_eint_port2) | |
732 : (next_eint_port1 < next_eint_port2 ? next_eint_port1 : next_eint_port2); | |
733 if (next_eint != CYCLE_NEVER) { | |
734 next_eint = next_eint < context->current_cycle ? context->current_cycle : next_eint; | |
735 if (next_eint < context->int_cycle) { | |
736 context->int_cycle = next_eint; | |
737 context->int_num = 2; | |
738 } | |
739 } | |
740 } | |
741 } | |
742 } | |
743 } | |
744 if (context->int_cycle > context->current_cycle && context->int_pending == INT_PENDING_SR_CHANGE) { | |
745 context->int_pending = INT_PENDING_NONE; | |
746 } | |
747 /*if (context->int_cycle != old_int_cycle) { | |
748 printf("int cycle changed to: %d, level: %d @ %d(%d), frame: %d, vcounter: %d, hslot: %d, mask: %d, hint_counter: %d\n", context->int_cycle, context->int_num, v_context->cycles, context->current_cycle, v_context->frame, v_context->vcounter, v_context->hslot, context->status & 0x7, v_context->hint_counter); | |
749 old_int_cycle = context->int_cycle; | |
750 }*/ | |
751 | |
752 if (context->status & M68K_STATUS_TRACE || context->trace_pending) { | |
753 context->target_cycle = context->current_cycle; | |
754 return; | |
755 } | |
756 | |
757 context->target_cycle = context->int_cycle < context->sync_cycle ? context->int_cycle : context->sync_cycle; | |
758 if (context->should_return || gen->header.enter_debugger || context->wp_hit) { | |
759 context->target_cycle = context->current_cycle; | |
760 } else if (context->target_cycle < context->current_cycle) { | |
761 //Changes to SR can result in an interrupt cycle that's in the past | |
762 //This can cause issues with the implementation of STOP though | |
763 context->target_cycle = context->current_cycle; | |
764 } | |
765 if (context->target_cycle == context->int_cycle) { | |
766 //Currently delays from Z80 access and refresh are applied only when we sync | |
767 //this can cause extra latency when it comes to interrupts | |
768 //to prevent this code forces some extra synchronization in the period immediately before an interrupt | |
769 if ((context->target_cycle - context->current_cycle) > gen->int_latency_prev1) { | |
770 context->target_cycle = context->sync_cycle = context->int_cycle - gen->int_latency_prev1; | |
771 } else if ((context->target_cycle - context->current_cycle) > gen->int_latency_prev2) { | |
772 context->target_cycle = context->sync_cycle = context->int_cycle - gen->int_latency_prev2; | |
773 } else { | |
774 context->target_cycle = context->sync_cycle = context->current_cycle; | |
775 } | |
776 | |
777 } | |
778 } | |
779 | |
684 static m68k_context* sync_components_pico(m68k_context * context, uint32_t address) | 780 static m68k_context* sync_components_pico(m68k_context * context, uint32_t address) |
685 { | 781 { |
686 genesis_context * gen = context->system; | 782 genesis_context * gen = context->system; |
687 vdp_context * v_context = gen->vdp; | 783 vdp_context * v_context = gen->vdp; |
688 if (gen->bus_busy) { | 784 if (gen->bus_busy) { |
690 } else { | 786 } else { |
691 gen_update_refresh(context); | 787 gen_update_refresh(context); |
692 } | 788 } |
693 | 789 |
694 uint32_t mclks = context->current_cycle; | 790 uint32_t mclks = context->current_cycle; |
695 psg_run(gen->psg, mclks); | 791 sync_sound_pico(gen, mclks); |
696 vdp_run_context(v_context, mclks); | 792 vdp_run_context(v_context, mclks); |
697 if (mclks >= gen->reset_cycle) { | 793 if (mclks >= gen->reset_cycle) { |
698 gen->reset_requested = 1; | 794 gen->reset_requested = 1; |
699 context->should_return = 1; | 795 context->should_return = 1; |
700 gen->reset_cycle = CYCLE_NEVER; | 796 gen->reset_cycle = CYCLE_NEVER; |
735 context->current_cycle -= deduction; | 831 context->current_cycle -= deduction; |
736 if (gen->psg->vgm) { | 832 if (gen->psg->vgm) { |
737 vgm_adjust_cycles(gen->psg->vgm, deduction); | 833 vgm_adjust_cycles(gen->psg->vgm, deduction); |
738 } | 834 } |
739 gen->psg->cycles -= deduction; | 835 gen->psg->cycles -= deduction; |
836 gen->adpcm->cycle -= deduction; | |
740 if (gen->reset_cycle != CYCLE_NEVER) { | 837 if (gen->reset_cycle != CYCLE_NEVER) { |
741 gen->reset_cycle -= deduction; | 838 gen->reset_cycle -= deduction; |
742 } | 839 } |
743 event_cycle_adjust(mclks, deduction); | 840 event_cycle_adjust(mclks, deduction); |
744 if (gen->expansion) { | 841 if (gen->expansion) { |
754 context->sync_cycle = gen->frame_end; | 851 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); | 852 //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)) { | 853 if (!address && (gen->header.enter_debugger || gen->header.save_state)) { |
757 context->sync_cycle = context->current_cycle + 1; | 854 context->sync_cycle = context->current_cycle + 1; |
758 } | 855 } |
759 adjust_int_cycle(context, v_context); | 856 adjust_int_cycle_pico(context, v_context); |
760 if (gen->reset_cycle < context->target_cycle) { | 857 if (gen->reset_cycle < context->target_cycle) { |
761 context->target_cycle = gen->reset_cycle; | 858 context->target_cycle = gen->reset_cycle; |
762 } | 859 } |
763 if (address) { | 860 if (address) { |
764 if (gen->header.enter_debugger || context->wp_hit) { | 861 if (gen->header.enter_debugger || context->wp_hit) { |
807 } | 904 } |
808 | 905 |
809 static m68k_context *int_ack(m68k_context *context) | 906 static m68k_context *int_ack(m68k_context *context) |
810 { | 907 { |
811 genesis_context * gen = context->system; | 908 genesis_context * gen = context->system; |
812 vdp_context * v_context = gen->vdp; | 909 if (gen->header.type != SYSTEM_PICO || context->int_num > 4 || context->int_num < 3) { |
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); | 910 vdp_context * v_context = gen->vdp; |
814 vdp_run_context(v_context, context->current_cycle); | 911 //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); |
815 vdp_int_ack(v_context); | 912 vdp_run_context(v_context, context->current_cycle); |
913 vdp_int_ack(v_context); | |
914 } | |
816 | 915 |
817 //the Genesis responds to these exclusively with !VPA which means its a slow | 916 //the Genesis responds to these exclusively with !VPA which means its a slow |
818 //6800 operation. documentation says these can take between 10 and 19 cycles. | 917 //6800 operation. documentation says these can take between 10 and 19 cycles. |
819 //actual results measurements seem to suggest it's actually between 9 and 18 | 918 //actual results measurements seem to suggest it's actually between 9 and 18 |
820 //Base 68K core has added 4 cycles for a normal int ack cycle already | 919 //Base 68K core has added 4 cycles for a normal int ack cycle already |
907 } | 1006 } |
908 } | 1007 } |
909 } else { | 1008 } else { |
910 context->sync_cycle = gen->frame_end = vdp_cycles_to_frame_end(v_context); | 1009 context->sync_cycle = gen->frame_end = vdp_cycles_to_frame_end(v_context); |
911 //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot); | 1010 //printf("Set sync cycle to: %d @ %d, vcounter: %d, hslot: %d\n", context->sync_cycle, context->current_cycle, v_context->vcounter, v_context->hslot); |
912 adjust_int_cycle(context, v_context); | 1011 if (gen->header.type == SYSTEM_PICO) { |
1012 adjust_int_cycle_pico(context, v_context); | |
1013 } else { | |
1014 adjust_int_cycle(context, v_context); | |
1015 } | |
913 } | 1016 } |
914 } else { | 1017 } else { |
915 fatal_error("Illegal write to HV Counter port %X\n", vdp_port); | 1018 fatal_error("Illegal write to HV Counter port %X\n", vdp_port); |
916 } | 1019 } |
917 if (v_context->cycles != before_cycle) { | 1020 if (v_context->cycles != before_cycle) { |
1237 return vcontext; | 1340 return vcontext; |
1238 } | 1341 } |
1239 | 1342 |
1240 static void* pico_io_write_w(uint32_t location, void *vcontext, uint16_t value) | 1343 static void* pico_io_write_w(uint32_t location, void *vcontext, uint16_t value) |
1241 { | 1344 { |
1242 printf("Pico IO write.w %X - %X\n", location, value); | 1345 uint32_t port = location & 0xFE; |
1346 m68k_context *context = vcontext; | |
1347 genesis_context *gen = context->system; | |
1348 if (port == 0x10) { | |
1349 sync_sound_pico(gen, context->current_cycle); | |
1350 pico_pcm_data_write(gen->adpcm, value); | |
1351 printf("PICO ADPCM Data: %04X\n", value); | |
1352 if (context->int_num == 3) { | |
1353 adjust_int_cycle_pico(context, gen->vdp); | |
1354 } | |
1355 } else if (port == 0x12) { | |
1356 sync_sound_pico(gen, context->current_cycle); | |
1357 printf("PICO ADPCM Control: %04X\n", value); | |
1358 pico_pcm_ctrl_write(gen->adpcm, value); | |
1359 adjust_int_cycle_pico(context, gen->vdp); | |
1360 } else { | |
1361 return pico_io_write(location, vcontext, value); | |
1362 } | |
1243 return vcontext; | 1363 return vcontext; |
1244 } | 1364 } |
1245 | 1365 |
1246 #define FOREIGN 0x80 | 1366 #define FOREIGN 0x80 |
1247 #define HZ50 0x40 | 1367 #define HZ50 0x40 |
1374 | 1494 |
1375 static uint8_t pico_io_read(uint32_t location, void *vcontext) | 1495 static uint8_t pico_io_read(uint32_t location, void *vcontext) |
1376 { | 1496 { |
1377 m68k_context *m68k = vcontext; | 1497 m68k_context *m68k = vcontext; |
1378 genesis_context *gen = m68k->system; | 1498 genesis_context *gen = m68k->system; |
1499 uint16_t tmp; | |
1379 switch(location >> 1 & 0x7F) | 1500 switch(location >> 1 & 0x7F) |
1380 { | 1501 { |
1381 case 0: | 1502 case 0: |
1382 return gen->version_reg; | 1503 return gen->version_reg; |
1383 case 1: | 1504 case 1: |
1392 return gen->pico_pen_y; | 1513 return gen->pico_pen_y; |
1393 case 6: | 1514 case 6: |
1394 return gen->pico_page; | 1515 return gen->pico_page; |
1395 case 8: | 1516 case 8: |
1396 //printf("uPD7759 data read @ %u\n", m68k->current_cycle); | 1517 //printf("uPD7759 data read @ %u\n", m68k->current_cycle); |
1397 return 0xFF; | 1518 sync_sound_pico(gen, m68k->current_cycle); |
1519 tmp = pico_pcm_data_read(gen->adpcm); | |
1520 return (location & 1) ? tmp >> 8 : tmp; | |
1398 case 9: | 1521 case 9: |
1399 //printf("uPD7759 contro/status read @ %u\n", m68k->current_cycle); | 1522 //printf("uPD7759 contro/status read @ %u\n", m68k->current_cycle); |
1523 sync_sound_pico(gen, m68k->current_cycle); | |
1524 tmp = pico_pcm_ctrl_read(gen->adpcm); | |
1525 return (location & 1) ? tmp >> 8 : tmp; | |
1400 return 0; | 1526 return 0; |
1401 default: | 1527 default: |
1402 printf("Unknown Pico IO read %X @ %u\n", location, m68k->current_cycle); | 1528 printf("Unknown Pico IO read %X @ %u\n", location, m68k->current_cycle); |
1403 return 0xFF; | 1529 return 0xFF; |
1404 } | 1530 } |
1406 | 1532 |
1407 static uint16_t pico_io_read_w(uint32_t location, void *vcontext) | 1533 static uint16_t pico_io_read_w(uint32_t location, void *vcontext) |
1408 { | 1534 { |
1409 m68k_context *m68k = vcontext; | 1535 m68k_context *m68k = vcontext; |
1410 genesis_context *gen = m68k->system; | 1536 genesis_context *gen = m68k->system; |
1537 uint32_t port = location & 0xFE; | |
1538 if (port == 0x10) { | |
1539 sync_sound_pico(gen, m68k->current_cycle); | |
1540 return pico_pcm_data_read(gen->adpcm); | |
1541 } else if (port == 0x12) { | |
1542 sync_sound_pico(gen, m68k->current_cycle); | |
1543 return pico_pcm_ctrl_read(gen->adpcm); | |
1544 } | |
1411 uint16_t value = pico_io_read(location, vcontext); | 1545 uint16_t value = pico_io_read(location, vcontext); |
1412 return value | (value << 8); | 1546 return value | (value << 8); |
1413 } | 1547 } |
1414 | 1548 |
1415 static void * z80_write_ym(uint32_t location, void * vcontext, uint8_t value) | 1549 static void * z80_write_ym(uint32_t location, void * vcontext, uint8_t value) |
1776 gen->header.enter_debugger = 0; | 1910 gen->header.enter_debugger = 0; |
1777 #ifndef IS_LIB | 1911 #ifndef IS_LIB |
1778 insert_breakpoint(gen->m68k, pc, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter); | 1912 insert_breakpoint(gen->m68k, pc, gen->header.debugger_type == DEBUGGER_NATIVE ? debugger : gdb_debug_enter); |
1779 #endif | 1913 #endif |
1780 } | 1914 } |
1781 adjust_int_cycle(gen->m68k, gen->vdp); | 1915 if (gen->header.type == SYSTEM_PICO) { |
1916 adjust_int_cycle_pico(gen->m68k, gen->vdp); | |
1917 } else { | |
1918 adjust_int_cycle(gen->m68k, gen->vdp); | |
1919 } | |
1782 start_68k_context(gen->m68k, pc); | 1920 start_68k_context(gen->m68k, pc); |
1783 } else { | 1921 } else { |
1784 if (gen->header.enter_debugger) { | 1922 if (gen->header.enter_debugger) { |
1785 gen->header.enter_debugger = 0; | 1923 gen->header.enter_debugger = 0; |
1786 #ifndef IS_LIB | 1924 #ifndef IS_LIB |
1959 if (gen->header.type == SYSTEM_GENESIS) { | 2097 if (gen->header.type == SYSTEM_GENESIS) { |
1960 z80_options_free(gen->z80->Z80_OPTS); | 2098 z80_options_free(gen->z80->Z80_OPTS); |
1961 free(gen->z80); | 2099 free(gen->z80); |
1962 free(gen->zram); | 2100 free(gen->zram); |
1963 } | 2101 } |
1964 if (gen->header.type != SYSTEM_PICO) { | 2102 if (gen->header.type == SYSTEM_PICO) { |
2103 pico_pcm_free(gen->adpcm); | |
2104 free(gen->adpcm); | |
2105 } else { | |
1965 ym_free(gen->ym); | 2106 ym_free(gen->ym); |
1966 } | 2107 } |
1967 psg_free(gen->psg); | 2108 psg_free(gen->psg); |
1968 free(gen->header.save_dir); | 2109 free(gen->header.save_dir); |
1969 free_rom_info(&gen->header.info); | 2110 free_rom_info(&gen->header.info); |
2224 if (debug_view < DEBUG_OSCILLOSCOPE) { | 2365 if (debug_view < DEBUG_OSCILLOSCOPE) { |
2225 vdp_toggle_debug_view(gen->vdp, debug_view); | 2366 vdp_toggle_debug_view(gen->vdp, debug_view); |
2226 } else if (debug_view == DEBUG_OSCILLOSCOPE) { | 2367 } else if (debug_view == DEBUG_OSCILLOSCOPE) { |
2227 if (gen->psg->scope) { | 2368 if (gen->psg->scope) { |
2228 oscilloscope *scope = gen->psg->scope; | 2369 oscilloscope *scope = gen->psg->scope; |
2229 if (gen->header.type != SYSTEM_PICO) { | 2370 if (gen->header.type == SYSTEM_PICO) { |
2371 gen->adpcm->scope = NULL; | |
2372 } else { | |
2230 gen->ym->scope = NULL; | 2373 gen->ym->scope = NULL; |
2231 } | 2374 } |
2232 gen->psg->scope = NULL; | 2375 gen->psg->scope = NULL; |
2233 if (gen->expansion) { | 2376 if (gen->expansion) { |
2234 segacd_context *cd = gen->expansion; | 2377 segacd_context *cd = gen->expansion; |
2235 cd->pcm.scope = NULL; | 2378 cd->pcm.scope = NULL; |
2236 } | 2379 } |
2237 scope_close(scope); | 2380 scope_close(scope); |
2238 } else { | 2381 } else { |
2239 oscilloscope *scope = create_oscilloscope(); | 2382 oscilloscope *scope = create_oscilloscope(); |
2240 if (gen->header.type != SYSTEM_PICO) { | 2383 if (gen->header.type == SYSTEM_PICO) { |
2384 pico_pcm_enable_scope(gen->adpcm, scope, gen->normal_clock); | |
2385 } else { | |
2241 ym_enable_scope(gen->ym, scope, gen->normal_clock); | 2386 ym_enable_scope(gen->ym, scope, gen->normal_clock); |
2242 } | 2387 } |
2243 psg_enable_scope(gen->psg, scope, gen->normal_clock); | 2388 psg_enable_scope(gen->psg, scope, gen->normal_clock); |
2244 if (gen->expansion) { | 2389 if (gen->expansion) { |
2245 segacd_context *cd = gen->expansion; | 2390 segacd_context *cd = gen->expansion; |
2911 | 3056 |
2912 render_set_video_standard((gen->version_reg & 0x60) == 0x20 ? VID_PAL : VID_NTSC); | 3057 render_set_video_standard((gen->version_reg & 0x60) == 0x20 ? VID_PAL : VID_NTSC); |
2913 | 3058 |
2914 gen->psg = calloc(1, sizeof(psg_context)); | 3059 gen->psg = calloc(1, sizeof(psg_context)); |
2915 psg_init(gen->psg, gen->master_clock, MCLKS_PER_PSG); | 3060 psg_init(gen->psg, gen->master_clock, MCLKS_PER_PSG); |
3061 | |
3062 gen->adpcm = calloc(1, sizeof(pico_pcm)); | |
3063 pico_pcm_init(gen->adpcm, gen->master_clock, 42); | |
3064 | |
2916 gen->work_ram = calloc(2, RAM_WORDS); | 3065 gen->work_ram = calloc(2, RAM_WORDS); |
2917 if (!strcmp("random", tern_find_path_default(config, "system\0ram_init\0", (tern_val){.ptrval = "zero"}, TVAL_PTR).ptrval)) | 3066 if (!strcmp("random", tern_find_path_default(config, "system\0ram_init\0", (tern_val){.ptrval = "zero"}, TVAL_PTR).ptrval)) |
2918 { | 3067 { |
2919 srand(time(NULL)); | 3068 srand(time(NULL)); |
2920 for (int i = 0; i < RAM_WORDS; i++) | 3069 for (int i = 0; i < RAM_WORDS; i++) |