comparison blastem.c @ 380:1c8d74f2ab0b

Make the PSG and YM2612 use the master clock internal with an increment based on clock divider so that they stay perflectly in sync. Run both the PSG and YM2612 whenver one of them needs to be run.
author Mike Pavone <pavone@retrodev.com>
date Mon, 03 Jun 2013 21:43:38 -0700
parents d42a8a3e4894
children 1b80b90399da
comparison
equal deleted inserted replaced
379:3218e2f8d685 380:1c8d74f2ab0b
10 #include <string.h> 10 #include <string.h>
11 11
12 #define CARTRIDGE_WORDS 0x200000 12 #define CARTRIDGE_WORDS 0x200000
13 #define RAM_WORDS 32 * 1024 13 #define RAM_WORDS 32 * 1024
14 #define Z80_RAM_BYTES 8 * 1024 14 #define Z80_RAM_BYTES 8 * 1024
15
16 #define MCLKS_NTSC 53693175
17 #define MCLKS_PAL 53203395
18
15 #define MCLKS_PER_68K 7 19 #define MCLKS_PER_68K 7
20 #define MCLKS_PER_YM MCLKS_PER_68K
16 #define MCLKS_PER_Z80 15 21 #define MCLKS_PER_Z80 15
17 #define MCLKS_PER_PSG (MCLKS_PER_Z80*16) 22 #define MCLKS_PER_PSG (MCLKS_PER_Z80*16)
23
18 //TODO: Figure out the exact value for this 24 //TODO: Figure out the exact value for this
19 #define CYCLE_NEVER 0xFFFFFFFF 25 #define CYCLE_NEVER 0xFFFFFFFF
20 #define LINES_NTSC 262 26 #define LINES_NTSC 262
21 #define LINES_PAL 312 27 #define LINES_PAL 312
22 28
185 } 191 }
186 } else { 192 } else {
187 z_context->current_cycle = mclks / MCLKS_PER_Z80; 193 z_context->current_cycle = mclks / MCLKS_PER_Z80;
188 } 194 }
189 } 195 }
196
197 void sync_sound(genesis_context * gen, uint32_t target)
198 {
199 //printf("YM | Cycle: %d, bpos: %d, PSG | Cycle: %d, bpos: %d\n", gen->ym->current_cycle, gen->ym->buffer_pos, gen->psg->cycles, gen->psg->buffer_pos * 2);
200 psg_run(gen->psg, target);
201 ym_run(gen->ym, target);
202
203 //printf("Target: %d, YM bufferpos: %d, PSG bufferpos: %d\n", target, gen->ym->buffer_pos, gen->psg->buffer_pos * 2);
204 }
205
190 uint32_t frame=0; 206 uint32_t frame=0;
191 m68k_context * sync_components(m68k_context * context, uint32_t address) 207 m68k_context * sync_components(m68k_context * context, uint32_t address)
192 { 208 {
193 //TODO: Handle sync targets smaller than a single frame 209 //TODO: Handle sync targets smaller than a single frame
194 genesis_context * gen = context->system; 210 genesis_context * gen = context->system;
195 vdp_context * v_context = gen->vdp; 211 vdp_context * v_context = gen->vdp;
196 z80_context * z_context = gen->z80; 212 z80_context * z_context = gen->z80;
197 uint32_t mclks = context->current_cycle * MCLKS_PER_68K; 213 uint32_t mclks = context->current_cycle * MCLKS_PER_68K;
198 sync_z80(z_context, mclks); 214 sync_z80(z_context, mclks);
199 if (mclks >= mclks_per_frame) { 215 if (mclks >= mclks_per_frame) {
200 ym_run(gen->ym, context->current_cycle); 216 sync_sound(gen, mclks);
201 gen->ym->current_cycle -= mclks_per_frame/MCLKS_PER_68K; 217 gen->ym->current_cycle -= mclks_per_frame;
218 gen->psg->cycles -= mclks_per_frame;
202 if (gen->ym->write_cycle != CYCLE_NEVER) { 219 if (gen->ym->write_cycle != CYCLE_NEVER) {
203 gen->ym->write_cycle = gen->ym->write_cycle >= mclks_per_frame/MCLKS_PER_68K ? gen->ym->write_cycle - mclks_per_frame/MCLKS_PER_68K : 0; 220 gen->ym->write_cycle = gen->ym->write_cycle >= mclks_per_frame/MCLKS_PER_68K ? gen->ym->write_cycle - mclks_per_frame/MCLKS_PER_68K : 0;
204 } 221 }
205 //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks); 222 //printf("reached frame end | 68K Cycles: %d, MCLK Cycles: %d\n", context->current_cycle, mclks);
206 vdp_run_context(v_context, mclks_per_frame); 223 vdp_run_context(v_context, mclks_per_frame);
207 psg_run(gen->psg, mclks/MCLKS_PER_PSG); 224
208 gen->psg->cycles -= mclks_per_frame/MCLKS_PER_PSG;
209 if (!headless) { 225 if (!headless) {
210 break_on_sync |= wait_render_frame(v_context, frame_limit); 226 break_on_sync |= wait_render_frame(v_context, frame_limit);
211 } 227 }
212 frame++; 228 frame++;
213 mclks -= mclks_per_frame; 229 mclks -= mclks_per_frame;
232 vdp_run_context(v_context, mclks); 248 vdp_run_context(v_context, mclks);
233 } 249 }
234 } else { 250 } else {
235 //printf("running VDP for %d cycles\n", mclks - v_context->cycles); 251 //printf("running VDP for %d cycles\n", mclks - v_context->cycles);
236 vdp_run_context(v_context, mclks); 252 vdp_run_context(v_context, mclks);
237 psg_run(gen->psg, mclks/MCLKS_PER_PSG); 253 sync_sound(gen, mclks);
238 } 254 }
239 if (context->int_ack) { 255 if (context->int_ack) {
240 vdp_int_ack(v_context, context->int_ack); 256 vdp_int_ack(v_context, context->int_ack);
241 context->int_ack = 0; 257 context->int_ack = 0;
242 } 258 }
324 if (v_context->cycles != before_cycle) { 340 if (v_context->cycles != before_cycle) {
325 context->current_cycle = v_context->cycles / MCLKS_PER_68K; 341 context->current_cycle = v_context->cycles / MCLKS_PER_68K;
326 } 342 }
327 } else if (vdp_port < 0x18) { 343 } else if (vdp_port < 0x18) {
328 genesis_context * gen = context->system; 344 genesis_context * gen = context->system;
329 psg_run(gen->psg, (context->current_cycle * MCLKS_PER_68K) / MCLKS_PER_PSG); 345 sync_sound(gen, context->current_cycle * MCLKS_PER_68K);
330 psg_write(gen->psg, value); 346 psg_write(gen->psg, value);
331 } else { 347 } else {
332 //TODO: Implement undocumented test register(s) 348 //TODO: Implement undocumented test register(s)
333 } 349 }
334 return context; 350 return context;
356 } else { 372 } else {
357 printf("Illegal write to HV Counter port %X\n", vdp_port); 373 printf("Illegal write to HV Counter port %X\n", vdp_port);
358 exit(1); 374 exit(1);
359 } 375 }
360 } else if (vdp_port < 0x18) { 376 } else if (vdp_port < 0x18) {
361 psg_run(gen->psg, (context->current_cycle * MCLKS_PER_Z80) / MCLKS_PER_PSG); 377 sync_sound(gen, context->current_cycle * MCLKS_PER_Z80);
362 psg_write(gen->psg, value); 378 psg_write(gen->psg, value);
363 } else { 379 } else {
364 //TODO: Implement undocumented test register(s) 380 //TODO: Implement undocumented test register(s)
365 } 381 }
366 return context; 382 return context;
492 location &= 0x7FFF; 508 location &= 0x7FFF;
493 if (location < 0x4000) { 509 if (location < 0x4000) {
494 z80_ram[location & 0x1FFF] = value; 510 z80_ram[location & 0x1FFF] = value;
495 z80_handle_code_write(location & 0x1FFF, gen->z80); 511 z80_handle_code_write(location & 0x1FFF, gen->z80);
496 } else if (location < 0x6000) { 512 } else if (location < 0x6000) {
497 ym_run(gen->ym, context->current_cycle); 513 sync_sound(gen, context->current_cycle * MCLKS_PER_68K);
498 if (location & 1) { 514 if (location & 1) {
499 ym_data_write(gen->ym, value); 515 ym_data_write(gen->ym, value);
500 } else if(location & 2) { 516 } else if(location & 2) {
501 ym_address_write_part2(gen->ym, value); 517 ym_address_write_part2(gen->ym, value);
502 } else { 518 } else {
592 location &= 0x7FFF; 608 location &= 0x7FFF;
593 if (location < 0x4000) { 609 if (location < 0x4000) {
594 z80_ram[location & 0x1FFE] = value >> 8; 610 z80_ram[location & 0x1FFE] = value >> 8;
595 z80_handle_code_write(location & 0x1FFE, gen->z80); 611 z80_handle_code_write(location & 0x1FFE, gen->z80);
596 } else if (location < 0x6000) { 612 } else if (location < 0x6000) {
597 ym_run(gen->ym, context->current_cycle); 613 sync_sound(gen, context->current_cycle * MCLKS_PER_68K);
598 if (location & 1) { 614 if (location & 1) {
599 ym_data_write(gen->ym, value >> 8); 615 ym_data_write(gen->ym, value >> 8);
600 } else if(location & 2) { 616 } else if(location & 2) {
601 ym_address_write_part2(gen->ym, value >> 8); 617 ym_address_write_part2(gen->ym, value >> 8);
602 } else { 618 } else {
698 if (!(busack==Z80_REQ_BUSY || reset)) { 714 if (!(busack==Z80_REQ_BUSY || reset)) {
699 location &= 0x7FFF; 715 location &= 0x7FFF;
700 if (location < 0x4000) { 716 if (location < 0x4000) {
701 value = z80_ram[location & 0x1FFF]; 717 value = z80_ram[location & 0x1FFF];
702 } else if (location < 0x6000) { 718 } else if (location < 0x6000) {
703 ym_run(gen->ym, context->current_cycle); 719 sync_sound(gen, context->current_cycle * MCLKS_PER_68K);
704 value = ym_read_status(gen->ym); 720 value = ym_read_status(gen->ym);
705 } else { 721 } else {
706 value = 0xFF; 722 value = 0xFF;
707 } 723 }
708 } else { 724 } else {
765 if (!(busack==Z80_REQ_BUSY || reset)) { 781 if (!(busack==Z80_REQ_BUSY || reset)) {
766 location &= 0x7FFF; 782 location &= 0x7FFF;
767 if (location < 0x4000) { 783 if (location < 0x4000) {
768 value = z80_ram[location & 0x1FFE]; 784 value = z80_ram[location & 0x1FFE];
769 } else if (location < 0x6000) { 785 } else if (location < 0x6000) {
770 ym_run(gen->ym, context->current_cycle); 786 sync_sound(gen, context->current_cycle * MCLKS_PER_68K);
771 value = ym_read_status(gen->ym); 787 value = ym_read_status(gen->ym);
772 } else { 788 } else {
773 value = 0xFF; 789 value = 0xFF;
774 } 790 }
775 value = value | (value << 8); 791 value = value | (value << 8);
828 } 844 }
829 845
830 z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value) 846 z80_context * z80_write_ym(uint16_t location, z80_context * context, uint8_t value)
831 { 847 {
832 genesis_context * gen = context->system; 848 genesis_context * gen = context->system;
833 ym_run(gen->ym, (context->current_cycle * MCLKS_PER_Z80) / MCLKS_PER_68K); 849 sync_sound(gen, context->current_cycle * MCLKS_PER_Z80);
834 if (location & 1) { 850 if (location & 1) {
835 ym_data_write(gen->ym, value); 851 ym_data_write(gen->ym, value);
836 } else if (location & 2) { 852 } else if (location & 2) {
837 ym_address_write_part2(gen->ym, value); 853 ym_address_write_part2(gen->ym, value);
838 } else { 854 } else {
842 } 858 }
843 859
844 uint8_t z80_read_ym(uint16_t location, z80_context * context) 860 uint8_t z80_read_ym(uint16_t location, z80_context * context)
845 { 861 {
846 genesis_context * gen = context->system; 862 genesis_context * gen = context->system;
847 ym_run(gen->ym, (context->current_cycle * MCLKS_PER_Z80) / MCLKS_PER_68K); 863 sync_sound(gen, context->current_cycle * MCLKS_PER_Z80);
848 return ym_read_status(gen->ym); 864 return ym_read_status(gen->ym);
849 } 865 }
850 866
851 uint16_t read_sram_w(uint32_t address, m68k_context * context) 867 uint16_t read_sram_w(uint32_t address, m68k_context * context)
852 { 868 {
1808 } else if (detect_specific_region('E') || detect_specific_region('A')) { 1824 } else if (detect_specific_region('E') || detect_specific_region('A')) {
1809 version_reg = NO_DISK | EUR; 1825 version_reg = NO_DISK | EUR;
1810 } 1826 }
1811 } 1827 }
1812 1828
1813 #define PSG_CLKS_NTSC (3579545/16)
1814 #define PSG_CLKS_PAL (3546893/16)
1815 #define YM_CLKS_NTSC 7670454
1816 #define YM_CLKS_PAL 7600485
1817
1818 int main(int argc, char ** argv) 1829 int main(int argc, char ** argv)
1819 { 1830 {
1820 if (argc < 2) { 1831 if (argc < 2) {
1821 fputs("Usage: blastem FILENAME\n", stderr); 1832 fputs("Usage: blastem FILENAME\n", stderr);
1822 return 1; 1833 return 1;
1897 vdp_context v_context; 1908 vdp_context v_context;
1898 1909
1899 init_vdp_context(&v_context); 1910 init_vdp_context(&v_context);
1900 1911
1901 ym2612_context y_context; 1912 ym2612_context y_context;
1902 ym_init(&y_context, render_sample_rate(), fps == 60 ? YM_CLKS_NTSC : YM_CLKS_PAL, render_audio_buffer()); 1913 ym_init(&y_context, render_sample_rate(), fps == 60 ? MCLKS_NTSC : MCLKS_PAL, MCLKS_PER_YM, render_audio_buffer());
1903 1914
1904 psg_context p_context; 1915 psg_context p_context;
1905 psg_init(&p_context, render_sample_rate(), fps == 60 ? PSG_CLKS_NTSC : PSG_CLKS_PAL, render_audio_buffer()); 1916 psg_init(&p_context, render_sample_rate(), fps == 60 ? MCLKS_NTSC : MCLKS_PAL, MCLKS_PER_PSG, render_audio_buffer());
1906 1917
1907 z80_context z_context; 1918 z80_context z_context;
1908 x86_z80_options z_opts; 1919 x86_z80_options z_opts;
1909 init_x86_z80_opts(&z_opts); 1920 init_x86_z80_opts(&z_opts);
1910 init_z80_context(&z_context, &z_opts); 1921 init_z80_context(&z_context, &z_opts);