From a902ee8e0f6848df8ea5e21f7f42ec4a33116898 Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Wed, 29 May 2019 15:24:28 +0200 Subject: Sanity prevailed (nw) There are some bugs, probably linked to the sample counter (I thought it was a frame counter for a start...). But at least the code is not aneurysm-provoking anymore. One thing to do would be to turn the k573dio into a device_mixer_interface to have the connection to the speakers done at the driver device level. Volunteers? --- src/devices/sound/mas3507d.cpp | 112 +++++++++-- src/devices/sound/mas3507d.h | 29 ++- src/devices/sound/samples.cpp | 42 ----- src/devices/sound/samples.h | 20 -- src/mame/drivers/ksys573.cpp | 5 - src/mame/machine/k573dio.cpp | 44 +++-- src/mame/machine/k573dio.h | 9 +- src/mame/machine/k573fpga.cpp | 416 +++++------------------------------------ src/mame/machine/k573fpga.h | 74 +++----- 9 files changed, 216 insertions(+), 535 deletions(-) diff --git a/src/devices/sound/mas3507d.cpp b/src/devices/sound/mas3507d.cpp index 519136cfb4c..cd04e163c6b 100644 --- a/src/devices/sound/mas3507d.cpp +++ b/src/devices/sound/mas3507d.cpp @@ -7,20 +7,31 @@ #include "emu.h" #include "mas3507d.h" +#define MINIMP3_ONLY_MP3 +#define MINIMP3_NO_STDIO +#define MINIMP3_IMPLEMENTATION +#define MAX_FRAME_SYNC_MATCHES 1 +#include "minimp3/minimp3.h" +#include "minimp3/minimp3_ex.h" + // device type definition DEFINE_DEVICE_TYPE(MAS3507D, mas3507d_device, "mas3507d", "MAS 3507D MPEG decoder") mas3507d_device::mas3507d_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, MAS3507D, tag, owner, clock) , device_sound_interface(mconfig, *this) + , cb_sample(*this) , i2c_bus_state(), i2c_bus_address(), i2c_scli(false), i2c_sclo(false), i2c_sdai(false), i2c_sdao(false) , i2c_bus_curbit(0), i2c_bus_curval(0), i2c_subdest(), i2c_command(), i2c_bytecount(0), i2c_io_bank(0), i2c_io_adr(0), i2c_io_count(0), i2c_io_val(0) - , m_samples(nullptr) { } void mas3507d_device::device_start() { + current_rate = 44100; + stream = stream_alloc(0, 2, current_rate); + mp3dec_init(&mp3_dec); + cb_sample.resolve(); } void mas3507d_device::device_reset() @@ -31,6 +42,7 @@ void mas3507d_device::device_reset() i2c_bus_address = UNKNOWN; i2c_bus_curbit = -1; i2c_bus_curval = 0; + total_sample_count = 0; } void mas3507d_device::i2c_scl_w(bool line) @@ -272,11 +284,6 @@ void mas3507d_device::mem_write(int bank, uint32_t adr, uint32_t val) case 0x0032f: logerror("MAS3507D: OutputConfig = %05x\n", val); break; case 0x107f8: logerror("MAS3507D: left->left gain = %05x (%d dB, %f%%)\n", val, gain_to_db(val), gain_to_percentage(val)); - - if (m_samples != nullptr) { - m_samples->set_volume(0, gain_to_percentage(val)); - } - break; case 0x107f9: logerror("MAS3507D: left->right gain = %05x (%d dB, %f%%)\n", val, gain_to_db(val), gain_to_percentage(val)); @@ -286,11 +293,6 @@ void mas3507d_device::mem_write(int bank, uint32_t adr, uint32_t val) break; case 0x107fb: logerror("MAS3507D: right->right gain = %05x (%d dB, %f%%)\n", val, gain_to_db(val), gain_to_percentage(val)); - - if (m_samples != nullptr) { - m_samples->set_volume(1, gain_to_percentage(val)); - } - break; default: logerror("MAS3507D: %d:%04x = %05x\n", bank, adr, val); break; } @@ -317,6 +319,94 @@ void mas3507d_device::run_program(uint32_t adr) } } +void mas3507d_device::fill_buffer() +{ + while(mp3_count < mp3data.size()) { + u16 v = cb_sample(); + mp3data[mp3_count++] = v >> 8; + mp3data[mp3_count++] = v; + } + + int scount = mp3dec_decode_frame(&mp3_dec, mp3data.begin(), mp3_count, samples.begin(), &mp3_info); + + if(!scount) { + int to_drop = mp3_info.frame_bytes; + // At 1MHz, we can transfer around 2082 bytes/video frame. So + // that puts a boundary on how much we're ready to drop + if(to_drop > 2082 || !to_drop) + to_drop = 2082; + std::copy(mp3data.begin() + to_drop, mp3data.end(), mp3data.begin()); + mp3_count -= to_drop; + return; + } + + std::copy(mp3data.begin() + mp3_info.frame_bytes, mp3data.end(), mp3data.begin()); + mp3_count -= mp3_info.frame_bytes; + + if(mp3_info.channels == 1) + sample_count = scount; + else + sample_count = scount; + + if(mp3_info.hz != current_rate) { + current_rate = mp3_info.hz; + stream->set_sample_rate(current_rate); + } +} + +void mas3507d_device::append_buffer(stream_sample_t **outputs, int &pos, int scount) +{ + if(!sample_count) + return; + + int s1 = scount - pos; + if(s1 > sample_count) + s1 = sample_count; + + if(mp3_info.channels == 1) { + for(int i=0; i - -#include "sound/samples.h" - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** +#define MINIMP3_ONLY_MP3 +#define MINIMP3_NO_STDIO +#include "minimp3/minimp3.h" class mas3507d_device : public device_t, public device_sound_interface { @@ -19,12 +15,15 @@ public: // construction/destruction mas3507d_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + auto sample_cb() { return cb_sample.bind(); } + int i2c_scl_r(); int i2c_sda_r(); void i2c_scl_w(bool line); void i2c_sda_w(bool line); - void set_samples(samples_device *sample) { m_samples = sample; } + void reset_sample_count() { total_sample_count = 0; } + u32 get_sample_count() const { return total_sample_count; } protected: virtual void device_start() override; @@ -32,12 +31,23 @@ protected: virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override; private: + devcb_read16 cb_sample; + enum { IDLE, STARTED, NAK, ACK, ACK2 } i2c_bus_state; enum { UNKNOWN, VALIDATED, WRONG } i2c_bus_address; + std::array mp3data; + std::array samples; bool i2c_scli, i2c_sclo, i2c_sdai, i2c_sdao; int i2c_bus_curbit; uint8_t i2c_bus_curval; + int mp3_count, sample_count, current_rate; + u32 total_sample_count; + + mp3dec_t mp3_dec; + mp3dec_frame_info_t mp3_info; + + sound_stream *stream; void i2c_nak(); bool i2c_device_got_address(uint8_t address); @@ -54,7 +64,8 @@ private: void run_program(uint32_t adr); void reg_write(uint32_t adr, uint32_t val); - samples_device *m_samples; + void fill_buffer(); + void append_buffer(stream_sample_t **outputs, int &pos, int samples); }; diff --git a/src/devices/sound/samples.cpp b/src/devices/sound/samples.cpp index 21617148669..40ff619cdce 100644 --- a/src/devices/sound/samples.cpp +++ b/src/devices/sound/samples.cpp @@ -119,27 +119,6 @@ void samples_device::start_raw(uint8_t channel, const int16_t *sampledata, uint3 chan.loop = loop; } -void samples_device::update_raw(uint8_t channel, const int16_t *sampledata, uint32_t samples, uint32_t frequency, bool loop) -{ - assert(channel < m_channels); - - // update the parameters - channel_t &chan = m_channel[channel]; - bool is_update = chan.source != nullptr; - - chan.source = sampledata; - chan.source_length = samples; - chan.basefreq = frequency; - chan.step = (int64_t(chan.basefreq) << FRAC_BITS) / machine().sample_rate(); - chan.loop = loop; - - if (!is_update) { - chan.source_num = -1; - chan.pos = 0; - chan.frac = 0; - } -} - //------------------------------------------------- // set_frequency - set the playback frequency of @@ -342,13 +321,8 @@ void samples_device::device_post_load() void samples_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) { - if (!m_samples_update_cb.isnull()) { - m_samples_update_cb(); - } - // find the channel with this stream for (int channel = 0; channel < m_channels; channel++) - { if (&stream == m_channel[channel].stream) { channel_t &chan = m_channel[channel]; @@ -381,9 +355,7 @@ void samples_device::sound_stream_update(sound_stream &stream, stream_sample_t * if (pos >= sample_length) { if (chan.loop) - { pos %= sample_length; - } else { chan.source = nullptr; @@ -403,7 +375,6 @@ void samples_device::sound_stream_update(sound_stream &stream, stream_sample_t * memset(buffer, 0, samples * sizeof(*buffer)); break; } - } } @@ -667,16 +638,3 @@ bool samples_device::load_samples() } return ok; } - -uint32_t samples_device::get_position(uint8_t channel) -{ - assert(channel < m_channels); - - channel_t &chan = m_channel[channel]; - - if (chan.source == nullptr) { - return 0; - } - - return chan.pos; -} diff --git a/src/devices/sound/samples.h b/src/devices/sound/samples.h index ea50f51ea30..f5f1ca088f0 100644 --- a/src/devices/sound/samples.h +++ b/src/devices/sound/samples.h @@ -26,7 +26,6 @@ DECLARE_DEVICE_TYPE(SAMPLES, samples_device) //************************************************************************** #define SAMPLES_START_CB_MEMBER(_name) void _name() -#define SAMPLES_UPDATE_CB_MEMBER(_name) void _name() // ======================> samples_device @@ -35,7 +34,6 @@ class samples_device : public device_t, { public: typedef device_delegate start_cb_delegate; - typedef device_delegate update_cb_delegate; // construction/destruction samples_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); @@ -55,30 +53,13 @@ public: set_samples_start_callback(start_cb_delegate(callback, name, nullptr, static_cast(nullptr))); } - // update callback helpers - void set_samples_update_callback(update_cb_delegate callback) { - m_samples_update_cb = callback; - m_samples_update_cb.bind_relative_to(*owner()); - } - - template void set_samples_update_callback(const char *devname, void (FunctionClass::*callback)(), const char *name) - { - set_samples_update_callback(update_cb_delegate(callback, name, devname, static_cast(nullptr))); - } - template void set_samples_update_callback(void (FunctionClass::*callback)(), const char *name) - { - set_samples_update_callback(update_cb_delegate(callback, name, nullptr, static_cast(nullptr))); - } - // getters bool playing(uint8_t channel) const; uint32_t base_frequency(uint8_t channel) const; - uint32_t get_position(uint8_t channel); // start/stop helpers void start(uint8_t channel, uint32_t samplenum, bool loop = false); void start_raw(uint8_t channel, const int16_t *sampledata, uint32_t samples, uint32_t frequency, bool loop = false); - void update_raw(uint8_t channel, const int16_t *sampledata, uint32_t samples, uint32_t frequency, bool loop = false); void pause(uint8_t channel, bool pause = true); void stop(uint8_t channel); void stop_all(); @@ -135,7 +116,6 @@ protected: bool load_samples(); start_cb_delegate m_samples_start_cb; // optional callback - start_cb_delegate m_samples_update_cb; // optional callback // internal state std::vector m_channel; diff --git a/src/mame/drivers/ksys573.cpp b/src/mame/drivers/ksys573.cpp index 76a3b7f3cbd..7ac47336dc2 100644 --- a/src/mame/drivers/ksys573.cpp +++ b/src/mame/drivers/ksys573.cpp @@ -2395,7 +2395,6 @@ void ksys573_state::drmn9m(machine_config &config) { k573d(config); subdevice("k573dio")->output_callback().set(FUNC(ksys573_state::drmn_output_callback)); - subdevice("k573dio")->set_mp3_dynamic_base(0x00540000); casszi(config); @@ -2406,7 +2405,6 @@ void ksys573_state::drmn10m(machine_config &config) { k573d(config); subdevice("k573dio")->output_callback().set(FUNC(ksys573_state::drmn_output_callback)); - subdevice("k573dio")->set_mp3_dynamic_base(0x00500000); casszi(config); @@ -2454,13 +2452,11 @@ void ksys573_state::gtfrk10m(machine_config &config) k573d(config); casszi(config); pccard1_32mb(config); - subdevice("k573dio")->set_mp3_dynamic_base(0x00540000); } void ksys573_state::gtfrk10mb(machine_config &config) { gtrfrk7m(config); - subdevice("k573dio")->set_mp3_dynamic_base(0x00540000); KONAMI_573_NETWORK_PCB_UNIT(config, "k573npu", 0); } @@ -2470,7 +2466,6 @@ void ksys573_state::gtfrk11m(machine_config &config) k573d(config); casszi(config); pccard1_32mb(config); - subdevice("k573dio")->set_mp3_dynamic_base(0x00500000); } // Miscellaneous diff --git a/src/mame/machine/k573dio.cpp b/src/mame/machine/k573dio.cpp index 86c92e3c11f..370db9a2089 100644 --- a/src/mame/machine/k573dio.cpp +++ b/src/mame/machine/k573dio.cpp @@ -110,6 +110,7 @@ k573dio_device::k573dio_device(const machine_config &mconfig, const char *tag, d : device_t(mconfig, KONAMI_573_DIGITAL_IO_BOARD, tag, owner, clock), k573fpga(*this, "k573fpga"), digital_id(*this, "digital_id"), + mas3507d(*this, "mpeg"), output_cb(*this), is_ddrsbm_fpga(false) { @@ -119,14 +120,11 @@ void k573dio_device::device_start() { output_cb.resolve_safe(); - ram = std::make_unique(32 * 1024 * 1024); - save_pointer(NAME(ram), 32 * 1024 * 1024 ); + ram = std::make_unique(0x2000000/2); + save_pointer(NAME(ram), 0x2000000/2 ); k573fpga->set_ram(ram.get()); k573fpga->set_ddrsbm_fpga(is_ddrsbm_fpga); - k573fpga->set_mp3_dynamic_base(mp3_dynamic_base); - - device_reset(); } void k573dio_device::device_reset() @@ -149,8 +147,12 @@ const tiny_rom_entry *k573dio_device::device_rom_region() const void k573dio_device::device_add_mconfig(machine_config &config) { - KONAMI_573_DIGITAL_FPGA(config, "k573fpga"); - DS2401(config, "digital_id"); + KONAMI_573_DIGITAL_FPGA(config, k573fpga); + DS2401(config, digital_id); + MAS3507D(config, mas3507d); + mas3507d->sample_cb().set(k573fpga, FUNC(k573fpga_device::get_decrypted)); + mas3507d->add_route(0, ":lspeaker", 1.0); + mas3507d->add_route(1, ":rspeaker", 1.0); } void k573dio_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) @@ -207,13 +209,16 @@ READ16_MEMBER(k573dio_device::a80_r) WRITE16_MEMBER(k573dio_device::mpeg_start_adr_high_w) { logerror("FPGA MPEG start address high %04x\n", data); - k573fpga->set_mp3_start_adr((k573fpga->get_mp3_start_adr() & 0x0000ffff) | (data << 16)); // high + k573fpga->set_mp3_cur_adr((k573fpga->get_mp3_cur_adr() & 0x0000ffff) | (data << 16)); // high } WRITE16_MEMBER(k573dio_device::mpeg_start_adr_low_w) { logerror("FPGA MPEG start address low %04x\n", data); - k573fpga->set_mp3_start_adr((k573fpga->get_mp3_start_adr() & 0xffff0000) | data); // low + k573fpga->set_mp3_cur_adr((k573fpga->get_mp3_cur_adr() & 0xffff0000) | data); // low + if(is_ddrsbm_fpga) + k573fpga->set_crypto_key3(0); + mas3507d->reset_sample_count(); } WRITE16_MEMBER(k573dio_device::mpeg_end_adr_high_w) @@ -230,24 +235,27 @@ WRITE16_MEMBER(k573dio_device::mpeg_end_adr_low_w) READ16_MEMBER(k573dio_device::mpeg_key_1_r) { - return crypto_key1; + return k573fpga->get_crypto_key1(); } WRITE16_MEMBER(k573dio_device::mpeg_key_1_w) { logerror("FPGA MPEG key 1/3 %04x\n", data); k573fpga->set_crypto_key1(data); - crypto_key1 = data; } READ16_MEMBER(k573dio_device::mas_i2c_r) { - return k573fpga->i2c_read(); + int scl = mas3507d->i2c_scl_r() << 13; + int sda = mas3507d->i2c_sda_r() << 12; + + return scl | sda; } WRITE16_MEMBER(k573dio_device::mas_i2c_w) { - k573fpga->i2c_write(data); + mas3507d->i2c_scl_w(data & 0x2000); + mas3507d->i2c_sda_w(data & 0x1000); } READ16_MEMBER(k573dio_device::mpeg_ctrl_r) @@ -274,21 +282,21 @@ WRITE16_MEMBER(k573dio_device::ram_write_adr_low_w) READ16_MEMBER(k573dio_device::ram_r) { - uint16_t res = ram[ram_read_adr >> 1]; + uint16_t res = ram[(ram_read_adr & 0x7fffff) >> 1]; ram_read_adr += 2; return res; } WRITE16_MEMBER(k573dio_device::ram_w) { - ram[ram_adr >> 1] = data; + ram[(ram_adr & 0x1ffffff) >> 1] = data; ram_adr += 2; } WRITE16_MEMBER(k573dio_device::ram_read_adr_high_w) { // read and write address are shared - ram_read_adr = (ram_read_adr & 0x0000ffff) | (data << 16); + ram_read_adr = (ram_read_adr & 0x001fffff) | (data << 16); } WRITE16_MEMBER(k573dio_device::ram_read_adr_low_w) @@ -300,7 +308,7 @@ WRITE16_MEMBER(k573dio_device::ram_read_adr_low_w) READ16_MEMBER(k573dio_device::mp3_playback_high_r) { //logerror("mp3_playback_high_r: %08x (%08x)\n", mp3_playback & 0xffff0000, mp3_playback); - return (k573fpga->get_mp3_playback() & 0xffff0000) >> 16; + return (mas3507d->get_sample_count() & 0xffff0000) >> 16; } WRITE16_MEMBER(k573dio_device::mp3_playback_high_w) @@ -312,7 +320,7 @@ WRITE16_MEMBER(k573dio_device::mp3_playback_high_w) READ16_MEMBER(k573dio_device::mp3_playback_low_r) { //logerror("mp3_playback_low_r: %08x (%08x) %08x %08x\n", mp3_playback & 0x0000ffff, mp3_playback, m_samples->get_position(0), m_samples->get_position(1)); - return k573fpga->get_mp3_playback() & 0x0000ffff; + return mas3507d->get_sample_count() & 0x0000ffff; } WRITE16_MEMBER(k573dio_device::mp3_playback_low_w) diff --git a/src/mame/machine/k573dio.h b/src/mame/machine/k573dio.h index e75618139ed..7f41088c515 100644 --- a/src/mame/machine/k573dio.h +++ b/src/mame/machine/k573dio.h @@ -15,12 +15,8 @@ public: auto output_callback() { return output_cb.bind(); } - required_device k573fpga; - required_device digital_id; - void amap(address_map &map); void set_ddrsbm_fpga(bool flag) { is_ddrsbm_fpga = flag; } - void set_mp3_dynamic_base(uint32_t base) { mp3_dynamic_base = base; } DECLARE_READ16_MEMBER(a00_r); DECLARE_READ16_MEMBER(a02_r); @@ -74,6 +70,9 @@ protected: virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; private: + required_device k573fpga; + required_device digital_id; + required_device mas3507d; devcb_write8 output_cb; std::unique_ptr ram; @@ -83,8 +82,6 @@ private: void output(int offset, uint16_t data); bool is_ddrsbm_fpga; - uint32_t mp3_dynamic_base; - uint16_t crypto_key1; }; DECLARE_DEVICE_TYPE(KONAMI_573_DIGITAL_IO_BOARD, k573dio_device) diff --git a/src/mame/machine/k573fpga.cpp b/src/mame/machine/k573fpga.cpp index eb2197f7c77..4c8dc5b1177 100644 --- a/src/mame/machine/k573fpga.cpp +++ b/src/mame/machine/k573fpga.cpp @@ -5,122 +5,29 @@ #include "k573fpga.h" -// This will delay playback until there are SAMPLES_BUFFER samples in the buffer. -// This fixes some timing issues. Increase value to delay playback. -// The current value was decided by finding a delay that allowed the Konami logo -// to playback on the Drummania 10th Mix loading sequence, but finish just in time -// for the game to send the stop playback command before it looped again. -// TODO: Verify this with real hardware somehow. -#define SAMPLES_BUFFER 1152 * 30 -#define MINIMP3_ONLY_MP3 -#define MINIMP3_NO_STDIO -#define MINIMP3_IMPLEMENTATION -#define MAX_FRAME_SYNC_MATCHES 1 -#include "minimp3/minimp3.h" -#include "minimp3/minimp3_ex.h" - -k573fpga_device::k573fpga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : +k573fpga_device::k573fpga_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) : device_t(mconfig, KONAMI_573_DIGITAL_FPGA, tag, owner, clock), - mas3507d(*this, "mpeg"), - m_samples(*this, "samples"), use_ddrsbm_fpga(false) { } void k573fpga_device::device_start() { - ram_swap = std::make_unique(32 * 1024 * 1024); - save_pointer(NAME(ram_swap), 32 * 1024 * 1024); - - device_reset(); } void k573fpga_device::device_reset() { - mp3_start_adr = 0; + mp3_cur_adr = 0; mp3_end_adr = 0; crypto_key1 = 0; crypto_key2 = 0; crypto_key3 = 0; - mp3_last_adr = 0; - mp3_last_decrypt_adr = 0; - mp3_next_sync = 0; - last_copied_samples = 0; - decrypt_finished = false; - - if (!channel_l_pcm) { - free(channel_l_pcm); - } - - channel_l_pcm = nullptr; - last_buffer_size_channel_l = 0; - - if (!channel_r_pcm) { - free(channel_r_pcm); - } - - channel_r_pcm = nullptr; - last_buffer_size_channel_r = 0; - - memset((void*)ram_swap.get(), 0, 32 * 1024 * 1024 * 2); - memset(&mp3_info, 0, sizeof(mp3_info)); - - mas3507d->set_samples(m_samples); - - last_position_update = 0; - position_diff = 0; -} - -void k573fpga_device::device_add_mconfig(machine_config &config) -{ - MAS3507D(config, "mpeg"); - - /* sound hardware */ - SPEAKER(config, "lspeaker").front_left(); - SPEAKER(config, "rspeaker").front_right(); - SAMPLES(config, m_samples); - m_samples->set_channels(2); - m_samples->set_samples_update_callback(FUNC(k573fpga_device::k573fpga_stream_update)); - m_samples->add_route(0, "lspeaker", 1.0); - m_samples->add_route(1, "rspeaker", 1.0); -} - -uint32_t k573fpga_device::get_mp3_playback() { - if (m_samples->get_position(0) == 0 && decrypt_finished) { - // The game is still requesting position updates after the song has ended. - // This happens in some games like DDR 4th Mix Plus where it uses - // the position in song for actual game engine timings. - // The counter will properly end when the game signals to the FPGA to stop playback. - last_position_update += position_diff; - } else { - if (m_samples->get_position(0) - last_position_update > 0) { - position_diff = m_samples->get_position(0) - last_position_update; - } - - last_position_update = m_samples->get_position(0); - } - - return last_position_update; -} - -uint16_t k573fpga_device::i2c_read() -{ - int scl = mas3507d->i2c_scl_r() << 13; - int sda = mas3507d->i2c_sda_r() << 12; - - return scl | sda; } -void k573fpga_device::i2c_write(uint16_t data) +u16 k573fpga_device::get_mpeg_ctrl() { - mas3507d->i2c_scl_w(data & 0x2000); - mas3507d->i2c_sda_w(data & 0x1000); -} - -uint16_t k573fpga_device::get_mpeg_ctrl() -{ - if (mpeg_ctrl_flag == 0xe000 || m_samples->get_position(0) > 0) { + if ((mpeg_ctrl_flag & 0xe000) == 0xe000) { // This has been tested with real hardware, but this flag is always held 0x1000 when the audio is being played return 0x1000; } @@ -128,50 +35,20 @@ uint16_t k573fpga_device::get_mpeg_ctrl() return 0x0000; } -void k573fpga_device::set_mpeg_ctrl(uint16_t data) +void k573fpga_device::set_mpeg_ctrl(u16 data) { logerror("FPGA MPEG control %c%c%c | %08x %08x\n", data & 0x8000 ? '#' : '.', data & 0x4000 ? '#' : '.', data & 0x2000 ? '#' : '.', - mp3_start_adr, mp3_end_adr); + mp3_cur_adr, mp3_end_adr); mpeg_ctrl_flag = data; - - if (data == 0xa000) { - // Stop playback - m_samples->stop(0); - m_samples->stop(1); - } - - if ((data & 0xa000) == 0xa000) { - // Reset playback state for start and stop events - mp3_next_sync = 0; - mp3_last_adr = mp3_start_adr; - mp3_last_decrypt_adr = mp3_start_adr; - last_copied_samples = 0; - last_buffer_size_channel_l = 0; - last_buffer_size_channel_r = 0; - - last_position_update = 0; - position_diff = 0; - decrypt_finished = false; - - if (channel_l_pcm) { - free(channel_l_pcm); - channel_l_pcm = nullptr; - } - - if (channel_r_pcm) { - free(channel_r_pcm); - channel_r_pcm = nullptr; - } - } } -inline uint16_t k573fpga_device::fpga_decrypt_byte_real(uint16_t v) +u16 k573fpga_device::decrypt_default(u16 v) { - uint16_t m = crypto_key1 ^ crypto_key2; + u16 m = crypto_key1 ^ crypto_key2; v = bitswap<16>( v, @@ -203,20 +80,27 @@ inline uint16_t k573fpga_device::fpga_decrypt_byte_real(uint16_t v) (BIT(m, 0x0) << 0); v ^= bitswap<16>( - (uint16_t)crypto_key3, + (u16)crypto_key3, 7, 0, 6, 1, 5, 2, 4, 3, 3, 4, 2, 5, 1, 6, 0, 7 ); - return (v >> 8) | ((v & 0xff) << 8); + crypto_key1 = (crypto_key1 & 0x8000) | ((crypto_key1 << 1) & 0x7FFE) | ((crypto_key1 >> 14) & 1); + + if(((crypto_key1 >> 15) ^ crypto_key1) & 1) + crypto_key2 = (crypto_key2 << 1) | (crypto_key2 >> 15); + + crypto_key3++; + + return v; } -inline uint16_t k573fpga_device::fpga_decrypt_byte_ddrsbm(uint16_t data, uint32_t crypto_idx) +u16 k573fpga_device::decrypt_ddrsbm(u16 data) { - uint8_t key[16] = {0}; - uint16_t key_state = bitswap<16>( + u8 key[16] = {0}; + u16 key_state = bitswap<16>( crypto_key1, 13, 11, 9, 7, 5, 3, 1, 15, @@ -224,258 +108,46 @@ inline uint16_t k573fpga_device::fpga_decrypt_byte_ddrsbm(uint16_t data, uint32_ 6, 4, 2, 0 ); - for (int i = 0; i < 8; i++) { + for(int i = 0; i < 8; i++) { key[i * 2] = key_state & 0xff; key[i * 2 + 1] = (key_state >> 8) & 0xff; - key_state = (((((key_state >> 8) >> 7) & 1) | (((key_state >> 8) << 1) & 0xff)) << 8) | - (((key_state & 0xff) >> 7) & 1) | (((key_state & 0xff) << 1) & 0xff); + key_state = ((key_state & 0x8080) >> 7) | ((key_state & 0x7f7f) << 1); } - uint16_t output_word = 0; - for (int cur_bit = 0; cur_bit < 8; cur_bit++) { - int even_bit_shift = (cur_bit * 2) & 0xff; - int odd_bit_shift = (cur_bit * 2 + 1) & 0xff; - int is_even_bit_set = (data & (1 << even_bit_shift)) != 0; - int is_odd_bit_set = (data & (1 << odd_bit_shift)) != 0; - int is_key_bit_set = (key[crypto_idx % 16] & (1 << cur_bit)) != 0; - int is_scramble_bit_set = (key[(crypto_idx - 1) % 16] & (1 << cur_bit)) != 0; + u16 output_word = 0; + for(int cur_bit = 0; cur_bit < 8; cur_bit++) { + int even_bit_shift = cur_bit * 2; + int odd_bit_shift = cur_bit * 2 + 1; + bool is_even_bit_set = data & (1 << even_bit_shift); + bool is_odd_bit_set = data & (1 << odd_bit_shift); + bool is_key_bit_set = key[crypto_key3 & 15] & (1 << cur_bit); + bool is_scramble_bit_set = key[(crypto_key3 - 1) & 15] & (1 << cur_bit); - if (is_scramble_bit_set == 1) { - int t = is_even_bit_set; - is_even_bit_set = is_odd_bit_set; - is_odd_bit_set = t; - } + if(is_scramble_bit_set) + std::swap(is_even_bit_set, is_odd_bit_set); - if (((is_even_bit_set ^ is_key_bit_set)) == 1) { + if(is_even_bit_set ^ is_key_bit_set) output_word |= 1 << even_bit_shift; - } - if ((is_odd_bit_set) == 1) { + if(is_odd_bit_set) output_word |= 1 << odd_bit_shift; - } } - return (output_word >> 8) | ((output_word & 0xff) << 8); + crypto_key3++; + + return output_word; } -SAMPLES_UPDATE_CB_MEMBER(k573fpga_device::k573fpga_stream_update) +u16 k573fpga_device::get_decrypted() { - if (mp3_last_adr >= mp3_end_adr) { - mp3_next_sync = 0; - return; - } - - if ((mpeg_ctrl_flag & 0xe000) != 0xe000 || (m_samples->get_position(0) < mp3_next_sync && mp3_next_sync != 0)) { - return; - } - - int new_samples = mp3_info.samples; - int decrypt_buffer_speed = buffer_speed; - - if (mp3_next_sync == 0 && last_copied_samples == 0) { - crypto_key1 = orig_crypto_key1; - crypto_key2 = orig_crypto_key2; - crypto_key3 = orig_crypto_key3; - - mp3_last_decrypt_adr = mp3_start_adr; - - // Cover a large chunk of ID3 or junk at the beginning of a file when decrypting first frame - decrypt_buffer_speed = buffer_speed = 0xe00; - - last_position_update = 0; - position_diff = 0; - decrypt_finished = false; - } - - // Decrypt chunk of data - if (mp3_last_decrypt_adr < mp3_end_adr && mp3_last_adr + decrypt_buffer_speed >= mp3_last_decrypt_adr) { - int32_t cur_idx; + if(mp3_cur_adr >= mp3_end_adr || (mpeg_ctrl_flag & 0xe000) != 0xe000) + return 0; - for (cur_idx = mp3_last_decrypt_adr; cur_idx - mp3_last_decrypt_adr < decrypt_buffer_speed && cur_idx < mp3_end_adr; cur_idx += 2) { - if (use_ddrsbm_fpga) { - ram_swap[cur_idx >> 1] = fpga_decrypt_byte_ddrsbm(ram[cur_idx >> 1], (cur_idx - mp3_start_adr) / 2); - } else { - ram_swap[cur_idx >> 1] = fpga_decrypt_byte_real(ram[cur_idx >> 1]); - } + u16 src = ram[(mp3_cur_adr & 0x1ffffff) >> 1]; + u16 result = use_ddrsbm_fpga ? decrypt_ddrsbm(src) : decrypt_default(src); + mp3_cur_adr += 2; - if (!use_ddrsbm_fpga) { - crypto_key1 = (crypto_key1 & 0x8000) | ((crypto_key1 << 1) & 0x7FFE) | ((crypto_key1 >> 14) & 1); - - if ((((crypto_key1 >> 15) ^ crypto_key1) & 1) != 0) { - crypto_key2 = (crypto_key2 << 1) | (crypto_key2 >> 15); - } - } - - crypto_key3++; - } - - mp3_last_decrypt_adr = cur_idx; - } - - int samples; - int free_format_bytes = 0, frame_size = 0; - int buf_size = decrypt_buffer_speed; - - uint8_t *buf = (uint8_t*)ram_swap.get() + mp3_last_adr; - - // Detect first frame in MP3 data - if (mp3_next_sync == 0 && last_copied_samples == 0) { - buf_size = 0xe00; - - // Everything on the System 573 has a header 0x600 or less from what I've seen, but just ot be sure, check the first 0xe00 bytes - uint32_t first_frame = mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size); - buf += first_frame; - mp3_last_adr += first_frame; - buf_size -= first_frame; - - buffer_speed = hdr_frame_bytes(buf, free_format_bytes) * 2; - } - - if (mp3_last_adr >= mp3_end_adr) { - mp3_next_sync = 0; - return; - } - - if (mp3_next_sync == 0 && last_copied_samples == 0) { - // For the first iteration, we need to set up the MP3 state and such - if (mp3_info.buffer != NULL) { - free(mp3_info.buffer); - } - - memset(&mp3_info, 0, sizeof(mp3_info)); - memset(&mp3_frame_info, 0, sizeof(mp3_frame_info)); - new_samples = 0; - - /* try to make allocation size assumption by first frame */ - mp3dec_init(&mp3_dec); - - samples = mp3dec_decode_frame(&mp3_dec, buf, buf_size, mp3_pcm, &mp3_frame_info); - - if (!samples) { - return; - } - - samples *= mp3_frame_info.channels; - - mp3_allocated = (buf_size / mp3_frame_info.frame_bytes) * samples * sizeof(mp3d_sample_t) + MINIMP3_MAX_SAMPLES_PER_FRAME * sizeof(mp3d_sample_t); - mp3_info.buffer = (mp3d_sample_t*)malloc(mp3_allocated); - - if (!mp3_info.buffer) { - return; - } - - mp3_info.samples = samples; - memcpy(mp3_info.buffer, mp3_pcm, mp3_info.samples * sizeof(mp3d_sample_t)); - - /* save info */ - mp3_info.channels = mp3_frame_info.channels; - mp3_info.hz = mp3_frame_info.hz; - mp3_info.layer = mp3_frame_info.layer; - mp3_last_adr += mp3_frame_info.frame_bytes; - } else { - /* decode rest frames */ - buf_size = decrypt_buffer_speed * 2; - - if (buf < (uint8_t*)ram_swap.get() + mp3_end_adr) { - if (buf + buf_size > (uint8_t*)ram_swap.get() + mp3_end_adr) { - buf_size = ((uint8_t*)ram_swap.get() + mp3_end_adr) - buf; - } - if ((mp3_allocated - mp3_info.samples * sizeof(mp3d_sample_t)) < MINIMP3_MAX_SAMPLES_PER_FRAME * sizeof(mp3d_sample_t)) { - mp3_allocated *= 2; - mp3_info.buffer = (mp3d_sample_t*)realloc(mp3_info.buffer, mp3_allocated); - } - - samples = mp3dec_decode_frame(&mp3_dec, buf, buf_size, mp3_info.buffer + mp3_info.samples, &mp3_frame_info); - - if (!samples) { - mp3_last_decrypt_adr = mp3_start_adr; // Force it to redecrypt everything in case the previous decrypt was too fast to find a full frame - crypto_key1 = orig_crypto_key1; - crypto_key2 = orig_crypto_key2; - crypto_key3 = orig_crypto_key3; - - if (buf + buf_size >= (uint8_t*)ram_swap.get() + mp3_end_adr) { - // Some songs have a weird frame at the very end of the song which can be skipped usually. - mp3_last_adr += buf_size; - } - } else if (mp3_info.hz == mp3_frame_info.hz && mp3_info.layer == mp3_frame_info.layer && mp3_info.channels && mp3_info.channels == mp3_frame_info.channels) { - mp3_last_adr += mp3_frame_info.frame_bytes; - mp3_info.samples += samples * mp3_frame_info.channels; - } - } - } - - new_samples = mp3_info.samples - new_samples; - - if (new_samples > 0) { - size_t buffer_size = 0; - - if (mp3_info.channels == 1) { - buffer_size = mp3_info.samples; - } else { - buffer_size = mp3_info.samples / 2; - } - - if (channel_l_pcm == nullptr) { - last_buffer_size_channel_l = buffer_size * 2; - - if (last_buffer_size_channel_l == 0) { - last_buffer_size_channel_l = 0x1000; - } - - channel_l_pcm = (mp3d_sample_t*)calloc(last_buffer_size_channel_l, sizeof(mp3d_sample_t)); - } else if (buffer_size > last_buffer_size_channel_l) { - // realloc - last_buffer_size_channel_l = buffer_size * 2; - - if (last_buffer_size_channel_l == 0) { - last_buffer_size_channel_l = 0x1000; - } - - channel_l_pcm = (mp3d_sample_t*)realloc(channel_l_pcm, last_buffer_size_channel_l * sizeof(mp3d_sample_t)); - } - - if (channel_r_pcm == nullptr) { - last_buffer_size_channel_r = buffer_size * 2; - - if (last_buffer_size_channel_r == 0) { - last_buffer_size_channel_r = 0x1000; - } - - channel_r_pcm = (mp3d_sample_t*)calloc(last_buffer_size_channel_r, sizeof(mp3d_sample_t)); - } else if (buffer_size > last_buffer_size_channel_r) { - // realloc - last_buffer_size_channel_r = buffer_size * 2; - - if (last_buffer_size_channel_r == 0) { - last_buffer_size_channel_r = 0x1000; - } - - channel_r_pcm = (mp3d_sample_t*)realloc(channel_r_pcm, last_buffer_size_channel_r * sizeof(mp3d_sample_t)); - } - - if (mp3_info.channels == 1) { - memcpy(((int8_t*)channel_l_pcm) + (last_copied_samples * sizeof(mp3d_sample_t)), ((int8_t*)mp3_info.buffer) + (last_copied_samples * sizeof(mp3d_sample_t)), (buffer_size - last_copied_samples) * sizeof(mp3d_sample_t)); - memcpy(((int8_t*)channel_r_pcm) + (last_copied_samples * sizeof(mp3d_sample_t)), ((int8_t*)mp3_info.buffer) + (last_copied_samples * sizeof(mp3d_sample_t)), (buffer_size - last_copied_samples) * sizeof(mp3d_sample_t)); - } else { - for (size_t i = last_copied_samples; i < buffer_size; i++) { - channel_l_pcm[i] = mp3_info.buffer[i * sizeof(mp3d_sample_t)]; - channel_r_pcm[i] = mp3_info.buffer[i * sizeof(mp3d_sample_t) + 1]; - } - } - - last_copied_samples = buffer_size; - - if (last_copied_samples > SAMPLES_BUFFER) { - m_samples->update_raw(0, channel_l_pcm, buffer_size, mp3_info.hz, mp3_start_adr != mp3_dynamic_base); - m_samples->update_raw(1, channel_r_pcm, buffer_size, mp3_info.hz, mp3_start_adr != mp3_dynamic_base); - - mp3_next_sync = buffer_size - (buffer_size / 4); // Grab more data sometime before the current buffer ends. This is arbitrary and kinda hacky, but it worked best between various games in my testing. - } - } - - if (mp3_last_adr >= mp3_end_adr) { - decrypt_finished = true; - } + return result; } DEFINE_DEVICE_TYPE(KONAMI_573_DIGITAL_FPGA, k573fpga_device, "k573fpga", "Konami 573 Digital I/O FPGA") diff --git a/src/mame/machine/k573fpga.h b/src/mame/machine/k573fpga.h index 71b949b4419..807c32b8d5d 100644 --- a/src/mame/machine/k573fpga.h +++ b/src/mame/machine/k573fpga.h @@ -8,82 +8,52 @@ #include "sound/mas3507d.h" #include "machine/ds2401.h" -#include "sound/samples.h" - -#define MINIMP3_ONLY_MP3 -#define MINIMP3_NO_STDIO -#include "minimp3/minimp3.h" -#include "minimp3/minimp3_ex.h" - DECLARE_DEVICE_TYPE(KONAMI_573_DIGITAL_FPGA, k573fpga_device) class k573fpga_device : public device_t { public: - k573fpga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); - - required_device mas3507d; - required_device m_samples; + k573fpga_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); void set_ddrsbm_fpga(bool flag) { use_ddrsbm_fpga = flag; } - void set_ram(uint16_t *v) { ram = v; } + void set_ram(u16 *v) { ram = v; } + u16 get_decrypted(); - void set_crypto_key1(uint16_t v) { orig_crypto_key1 = crypto_key1 = v; } - void set_crypto_key2(uint16_t v) { orig_crypto_key2 = crypto_key2 = v; } - void set_crypto_key3(uint8_t v) { orig_crypto_key3 = crypto_key3 = v; } + void set_crypto_key1(u16 v) { crypto_key1 = v; } + void set_crypto_key2(u16 v) { crypto_key2 = v; } + void set_crypto_key3(u8 v) { crypto_key3 = v; } + u16 get_crypto_key1() const { return crypto_key1; } + u16 get_crypto_key2() const { return crypto_key2; } + u8 get_crypto_key3() const { return crypto_key3; } - uint32_t get_mp3_start_adr() { return mp3_start_adr; } - void set_mp3_start_adr(uint32_t v) { mp3_start_adr = v; } + uint32_t get_mp3_cur_adr() { return mp3_cur_adr; } + void set_mp3_cur_adr(u32 v) { mp3_cur_adr = v; } uint32_t get_mp3_end_adr() { return mp3_end_adr; } - void set_mp3_end_adr(uint32_t v) { mp3_end_adr = v; } - - uint32_t get_mp3_playback(); - - uint16_t i2c_read(); - void i2c_write(uint16_t data); + void set_mp3_end_adr(u32 v) { mp3_end_adr = v; } - uint16_t get_mpeg_ctrl(); - void set_mpeg_ctrl(uint16_t data); + u16 i2c_read(); + void i2c_write(u16 data); - void set_mp3_dynamic_base(uint32_t base) { mp3_dynamic_base = base; } + u16 get_mpeg_ctrl(); + void set_mpeg_ctrl(u16 data); protected: virtual void device_start() override; virtual void device_reset() override; - virtual void device_add_mconfig(machine_config &config) override; private: - uint16_t *ram; - std::unique_ptr ram_swap; + u16 *ram; - uint16_t crypto_key1, crypto_key2, orig_crypto_key1, orig_crypto_key2; - uint8_t crypto_key3, orig_crypto_key3; + u16 crypto_key1, crypto_key2; + u8 crypto_key3; - uint32_t mp3_start_adr, mp3_end_adr, mpeg_ctrl_flag; + u32 mp3_cur_adr, mp3_end_adr, mpeg_ctrl_flag; bool use_ddrsbm_fpga; - uint32_t mp3_last_adr, mp3_next_sync, mp3_last_decrypt_adr; - int16_t *channel_l_pcm, *channel_r_pcm; - size_t last_buffer_size_channel_l, last_buffer_size_channel_r, last_copied_samples; - uint32_t last_position_update, position_diff; - bool decrypt_finished; - - mp3d_sample_t mp3_pcm[MINIMP3_MAX_SAMPLES_PER_FRAME]; - mp3dec_file_info_t mp3_info; - mp3dec_t mp3_dec; - mp3dec_frame_info_t mp3_frame_info; - size_t mp3_allocated; - - uint32_t buffer_speed, mp3_dynamic_base; - - int32_t find_enc_key(); - - uint16_t fpga_decrypt_byte_real(uint16_t data); - uint16_t fpga_decrypt_byte_ddrsbm(uint16_t data, uint32_t crypto_idx); - - SAMPLES_UPDATE_CB_MEMBER(k573fpga_stream_update); + u16 decrypt_default(u16 data); + u16 decrypt_ddrsbm(u16 data); }; #endif // MAME_MACHINE_K573FPGA_H -- cgit v1.2.3