From b3c19562f6a14673d9b28530da3f0b0326b54b97 Mon Sep 17 00:00:00 2001 From: Aaron Giles Date: Sun, 2 May 2021 10:04:47 -0700 Subject: Ensure all writes to Yamaha FM chips are spaced by 1 cycle. The old FM cores did not really require this spacing and didn't implement the busy flag, so many VGM captures have multiple writes stacked in the same cycle. This won't work with the new cores, so this kludge helps ensure we don't end up with ugly playback on existing files. (#7931) --- src/mame/drivers/vgmplay.cpp | 74 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 8 deletions(-) diff --git a/src/mame/drivers/vgmplay.cpp b/src/mame/drivers/vgmplay.cpp index 3ea1d4f88c9..f1fae2f6905 100644 --- a/src/mame/drivers/vgmplay.cpp +++ b/src/mame/drivers/vgmplay.cpp @@ -399,6 +399,13 @@ private: int m_sega32x_channel_hack; int m_nes_apu_channel_hack[2]; uint8_t m_c6280_channel[2]; + + // newer YM cores require writes to be spaced out in order to play back + // correctly; simulate this by introducing some extra accounting + void space_out_write(uint32_t address); + void decrement_icount(int count); + int m_icount_ahead = 0; + int m_last_write_icount[256] = { 0 }; }; DEFINE_DEVICE_TYPE(VGMPLAY, vgmplay_device, "vgmplay_core", "VGM Player engine") @@ -966,6 +973,34 @@ TIMER_CALLBACK_MEMBER(vgmplay_device::stream_timer_expired) } } +void vgmplay_device::space_out_write(uint32_t address) +{ + // use the top address bits as an index + int index = address >> 24; + uint32_t cycles = uint32_t(total_cycles()); + + // if the last write happened at the current time, steal a cycle + if (m_last_write_icount[index] == cycles) + { + m_icount--; + m_icount_ahead++; + cycles++; + } + m_last_write_icount[index] = cycles; +} + +void vgmplay_device::decrement_icount(int count) +{ + // take back any cycles we stole + if (count >= m_icount_ahead) + { + m_icount -= count - m_icount_ahead; + m_icount_ahead = 0; + } + else + m_icount_ahead -= count; +} + void vgmplay_device::execute_run() { while (m_icount > 0) @@ -1005,7 +1040,7 @@ void vgmplay_device::execute_run() if (m_paused) { machine().sound().system_mute(1); - m_icount = 0; + decrement_icount(m_icount); return; } else @@ -1045,6 +1080,7 @@ void vgmplay_device::execute_run() case 0x51: pulse_act_led(CT_YM2413); + space_out_write(A_YM2413_0); m_io->write_byte(A_YM2413_0 + 0, m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM2413_0 + 1, m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1053,6 +1089,7 @@ void vgmplay_device::execute_run() case 0x52: case 0x53: pulse_act_led(CT_YM2612); + space_out_write(A_YM2612_0); m_io->write_byte(A_YM2612_0 + 0 + ((code & 1) << 1), m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM2612_0 + 1 + ((code & 1) << 1), m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1060,6 +1097,7 @@ void vgmplay_device::execute_run() case 0x54: pulse_act_led(CT_YM2151); + space_out_write(A_YM2151_0); m_io->write_byte(A_YM2151_0 + 0, m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM2151_0 + 1, m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1067,6 +1105,7 @@ void vgmplay_device::execute_run() case 0x55: pulse_act_led(CT_YM2203); + space_out_write(A_YM2203_0); m_io->write_byte(A_YM2203_0 + 0, m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM2203_0 + 1, m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1075,6 +1114,7 @@ void vgmplay_device::execute_run() case 0x56: case 0x57: pulse_act_led(CT_YM2608); + space_out_write(A_YM2608_0); m_io->write_byte(A_YM2608_0 + 0 + ((code & 1) << 1), m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM2608_0 + 1 + ((code & 1) << 1), m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1083,6 +1123,7 @@ void vgmplay_device::execute_run() case 0x58: case 0x59: pulse_act_led(CT_YM2610); + space_out_write(A_YM2610_0); m_io->write_byte(A_YM2610_0 + 0 + ((code & 1) << 1), m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM2610_0 + 1 + ((code & 1) << 1), m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1090,6 +1131,7 @@ void vgmplay_device::execute_run() case 0x5a: pulse_act_led(CT_YM3812); + space_out_write(A_YM3812_0); m_io->write_byte(A_YM3812_0 + 0, m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM3812_0 + 1, m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1097,6 +1139,7 @@ void vgmplay_device::execute_run() case 0x5b: pulse_act_led(CT_YM3526); + space_out_write(A_YM3526_0); m_io->write_byte(A_YM3526_0 + 0, m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM3526_0 + 1, m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1104,6 +1147,7 @@ void vgmplay_device::execute_run() case 0x5c: pulse_act_led(CT_Y8950); + space_out_write(A_Y8950_0); m_io->write_byte(A_Y8950_0 + 0, m_file->read_byte(m_pc + 1)); m_io->write_byte(A_Y8950_0 + 1, m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1119,6 +1163,7 @@ void vgmplay_device::execute_run() case 0x5e: case 0x5f: pulse_act_led(CT_YMF262); + space_out_write(A_YMF262_0); m_io->write_byte(A_YMF262_0 + 0 + ((code & 1) << 1), m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YMF262_0 + 1 + ((code & 1) << 1), m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1127,18 +1172,18 @@ void vgmplay_device::execute_run() case 0x61: { uint32_t duration = m_file->read_word(m_pc + 1); - m_icount -= duration; + decrement_icount(duration); m_pc += 3; break; } case 0x62: - m_icount -= 735; + decrement_icount(735); m_pc++; break; case 0x63: - m_icount -= 882; + decrement_icount(882); m_pc++; break; @@ -1171,7 +1216,7 @@ void vgmplay_device::execute_run() case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: - m_icount -= 1 + (code & 0xf); + decrement_icount(1 + (code & 0xf)); m_pc += 1; break; @@ -1183,12 +1228,13 @@ void vgmplay_device::execute_run() if (m_ym2612_stream_offset >= int(m_data_streams[0].size())) m_ym2612_stream_offset = 0; + space_out_write(A_YM2612_0); m_io->write_byte(A_YM2612_0 + 0, 0x2a); m_io->write_byte(A_YM2612_0 + 1, m_data_streams[0][m_ym2612_stream_offset]); m_ym2612_stream_offset++; } m_pc += 1; - m_icount -= code & 0xf; + decrement_icount(code & 0xf); break; case 0x90: @@ -1394,6 +1440,7 @@ void vgmplay_device::execute_run() case 0xa1: pulse_act_led(CT_YM2413); + space_out_write(A_YM2413_1); m_io->write_byte(A_YM2413_1 + 0, m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM2413_1 + 1, m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1402,6 +1449,7 @@ void vgmplay_device::execute_run() case 0xa2: case 0xa3: pulse_act_led(CT_YM2612); + space_out_write(A_YM2612_1); m_io->write_byte(A_YM2612_1 + 0 + ((code & 1) << 1), m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM2612_1 + 1 + ((code & 1) << 1), m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1409,6 +1457,7 @@ void vgmplay_device::execute_run() case 0xa4: pulse_act_led(CT_YM2151); + space_out_write(A_YM2151_1); m_io->write_byte(A_YM2151_1 + 0, m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM2151_1 + 1, m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1416,6 +1465,7 @@ void vgmplay_device::execute_run() case 0xa5: pulse_act_led(CT_YM2203); + space_out_write(A_YM2203_1); m_io->write_byte(A_YM2203_1 + 0, m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM2203_1 + 1, m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1424,6 +1474,7 @@ void vgmplay_device::execute_run() case 0xa6: case 0xa7: pulse_act_led(CT_YM2608); + space_out_write(A_YM2608_0); m_io->write_byte(A_YM2608_0 + 0 + ((code & 1) << 1), m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM2608_0 + 1 + ((code & 1) << 1), m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1432,6 +1483,7 @@ void vgmplay_device::execute_run() case 0xa8: case 0xa9: pulse_act_led(CT_YM2610); + space_out_write(A_YM2610_0); m_io->write_byte(A_YM2610_0 + 0 + ((code & 1) << 1), m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM2610_0 + 1 + ((code & 1) << 1), m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1439,6 +1491,7 @@ void vgmplay_device::execute_run() case 0xaa: pulse_act_led(CT_YM3812); + space_out_write(A_YM3812_1); m_io->write_byte(A_YM3812_1 + 0, m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM3812_1 + 1, m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1446,6 +1499,7 @@ void vgmplay_device::execute_run() case 0xab: pulse_act_led(CT_YM3526); + space_out_write(A_YM3526_1); m_io->write_byte(A_YM3526_1 + 0, m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YM3526_1 + 1, m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1453,6 +1507,7 @@ void vgmplay_device::execute_run() case 0xac: pulse_act_led(CT_Y8950); + space_out_write(A_Y8950_1); m_io->write_byte(A_Y8950_1 + 0, m_file->read_byte(m_pc + 1)); m_io->write_byte(A_Y8950_1 + 1, m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1468,6 +1523,7 @@ void vgmplay_device::execute_run() case 0xae: case 0xaf: pulse_act_led(CT_YMF262); + space_out_write(A_YMF262_1); m_io->write_byte(A_YMF262_1 + 0 + ((code & 1) << 1), m_file->read_byte(m_pc + 1)); m_io->write_byte(A_YMF262_1 + 1 + ((code & 1) << 1), m_file->read_byte(m_pc + 2)); m_pc += 3; @@ -1810,11 +1866,13 @@ void vgmplay_device::execute_run() uint8_t offset = m_file->read_byte(m_pc + 1); if (offset & 0x80) { + space_out_write(A_YMF278B_1); m_io->write_byte(A_YMF278B_1 + ((offset & 0x7f) << 1) + 0, m_file->read_byte(m_pc + 2)); m_io->write_byte(A_YMF278B_1 + ((offset & 0x7f) << 1) + 1, m_file->read_byte(m_pc + 3)); } else { + space_out_write(A_YMF278B_0); m_io->write_byte(A_YMF278B_0 + ((offset & 0x7f) << 1) + 0, m_file->read_byte(m_pc + 2)); m_io->write_byte(A_YMF278B_0 + ((offset & 0x7f) << 1) + 1, m_file->read_byte(m_pc + 3)); } @@ -1929,7 +1987,7 @@ void vgmplay_device::execute_run() debugger_instruction_hook(m_pc); m_state = DONE; - m_icount = 0; + decrement_icount(m_icount); break; } break; @@ -1937,7 +1995,7 @@ void vgmplay_device::execute_run() case DONE: { machine().sound().system_mute(1); - m_icount = 0; + decrement_icount(m_icount); break; } } -- cgit v1.2.3