diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/devices/sound/mas3507d.cpp | 76 | ||||
-rw-r--r-- | src/devices/sound/mas3507d.h | 10 | ||||
-rw-r--r-- | src/devices/sound/samples.cpp | 42 | ||||
-rw-r--r-- | src/devices/sound/samples.h | 20 | ||||
-rw-r--r-- | src/mame/drivers/ksys573.cpp | 51 | ||||
-rw-r--r-- | src/mame/machine/k573dio.cpp | 110 | ||||
-rw-r--r-- | src/mame/machine/k573dio.h | 23 | ||||
-rw-r--r-- | src/mame/machine/k573enc.h | 120 | ||||
-rw-r--r-- | src/mame/machine/k573fpga.cpp | 566 | ||||
-rw-r--r-- | src/mame/machine/k573fpga.h | 90 |
10 files changed, 1070 insertions, 38 deletions
diff --git a/src/devices/sound/mas3507d.cpp b/src/devices/sound/mas3507d.cpp index 4b972b46dfc..11c2c79e8b7 100644 --- a/src/devices/sound/mas3507d.cpp +++ b/src/devices/sound/mas3507d.cpp @@ -15,6 +15,7 @@ mas3507d_device::mas3507d_device(const machine_config &mconfig, const char *tag, , device_sound_interface(mconfig, *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) { } @@ -48,6 +49,7 @@ void mas3507d_device::i2c_scl_w(bool line) if(i2c_device_got_address(i2c_bus_curval)) { i2c_bus_state = ACK; i2c_bus_address = VALIDATED; + i2c_bus_curval = 0; } else { i2c_bus_state = NAK; i2c_bus_address = WRONG; @@ -111,7 +113,12 @@ int mas3507d_device::i2c_sda_r() bool mas3507d_device::i2c_device_got_address(uint8_t address) { - i2c_subdest = UNDEFINED; + if (address == 0x3b) { + i2c_subdest = DATA_READ; + } else { + i2c_subdest = UNDEFINED; + } + return (address & 0xfe) == 0x3a; } @@ -120,19 +127,37 @@ void mas3507d_device::i2c_device_got_byte(uint8_t byte) switch(i2c_subdest) { case UNDEFINED: if(byte == 0x68) - i2c_subdest = DATA; + i2c_subdest = DATA_WRITE; else if(byte == 0x69) - i2c_subdest = DATA; + i2c_subdest = DATA_READ; else if(byte == 0x6a) i2c_subdest = CONTROL; else i2c_subdest = BAD; + i2c_bytecount = 0; + i2c_io_val = 0; + break; + case BAD: logerror("MAS I2C: Dropping byte %02x\n", byte); break; - case DATA: + + case DATA_READ: + // Default Read + // This should return the current MPEGFrameCount value when called + + // TODO: Figure out how to use this data exactly (chip docs are a little unclear to me) + i2c_io_val <<= 8; + i2c_io_val |= byte; + i2c_bytecount++; + + logerror("MAS I2C: DATA_READ %d %08x\n", i2c_bytecount, i2c_io_val); + + break; + + case DATA_WRITE: if(!i2c_bytecount) { switch(byte >> 4) { case 0: case 1: @@ -215,6 +240,7 @@ void mas3507d_device::i2c_device_got_byte(uint8_t byte) i2c_bytecount++; break; + case CONTROL: logerror("MAS I2C: Control byte %02x\n", byte); break; @@ -226,14 +252,46 @@ void mas3507d_device::i2c_device_got_stop() logerror("MAS I2C: got stop\n"); } +int gain_to_db(double val) { + return round(20 * log10((0x100000 - val) / 0x80000)); +} + +float gain_to_percentage(int val) { + double db = gain_to_db(val); + + if (db == 0) { + return 0; // Special case for muting it seems + } + + return powf(10.0, (db + 6) / 20.0); +} + void mas3507d_device::mem_write(int bank, uint32_t adr, uint32_t val) { switch(adr | (bank ? 0x10000 : 0)) { case 0x0032f: logerror("MAS3507D: OutputConfig = %05x\n", val); break; - case 0x107f8: logerror("MAS3507D: left->left gain = %05x\n", val); break; - case 0x107f9: logerror("MAS3507D: left->right gain = %05x\n", val); break; - case 0x107fa: logerror("MAS3507D: right->left gain = %05x\n", val); break; - case 0x107fb: logerror("MAS3507D: right->right gain = %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)); + break; + case 0x107fa: + logerror("MAS3507D: right->left gain = %05x (%d dB, %f%%)\n", val, gain_to_db(val), gain_to_percentage(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; } } @@ -261,4 +319,4 @@ void mas3507d_device::run_program(uint32_t adr) void mas3507d_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) { -} +}
\ No newline at end of file diff --git a/src/devices/sound/mas3507d.h b/src/devices/sound/mas3507d.h index f36a4fb2004..a1c852f0eeb 100644 --- a/src/devices/sound/mas3507d.h +++ b/src/devices/sound/mas3507d.h @@ -5,6 +5,9 @@ #pragma once +#include <queue> + +#include "sound/samples.h" //************************************************************************** // TYPE DEFINITIONS @@ -21,6 +24,8 @@ public: void i2c_scl_w(bool line); void i2c_sda_w(bool line); + void set_samples(samples_device *sample) { m_samples = sample; } + protected: virtual void device_start() override; virtual void device_reset() override; @@ -40,15 +45,16 @@ private: void i2c_device_got_stop(); - enum { UNDEFINED, CONTROL, DATA, BAD } i2c_subdest; + enum { UNDEFINED, CONTROL, DATA_READ, DATA_WRITE, BAD } i2c_subdest; enum { CMD_BAD, CMD_RUN, CMD_READ_CTRL, CMD_WRITE_REG, CMD_WRITE_MEM, CMD_READ_REG, CMD_READ_MEM } i2c_command; int i2c_bytecount; uint32_t i2c_io_bank, i2c_io_adr, i2c_io_count, i2c_io_val; - void mem_write(int bank, uint32_t adr, uint32_t val); void run_program(uint32_t adr); void reg_write(uint32_t adr, uint32_t val); + + samples_device *m_samples; }; diff --git a/src/devices/sound/samples.cpp b/src/devices/sound/samples.cpp index 40ff619cdce..21617148669 100644 --- a/src/devices/sound/samples.cpp +++ b/src/devices/sound/samples.cpp @@ -119,6 +119,27 @@ 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 @@ -321,8 +342,13 @@ 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]; @@ -355,7 +381,9 @@ 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; @@ -375,6 +403,7 @@ void samples_device::sound_stream_update(sound_stream &stream, stream_sample_t * memset(buffer, 0, samples * sizeof(*buffer)); break; } + } } @@ -638,3 +667,16 @@ 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 f5f1ca088f0..ea50f51ea30 100644 --- a/src/devices/sound/samples.h +++ b/src/devices/sound/samples.h @@ -26,6 +26,7 @@ DECLARE_DEVICE_TYPE(SAMPLES, samples_device) //************************************************************************** #define SAMPLES_START_CB_MEMBER(_name) void _name() +#define SAMPLES_UPDATE_CB_MEMBER(_name) void _name() // ======================> samples_device @@ -34,6 +35,7 @@ class samples_device : public device_t, { public: typedef device_delegate<void ()> start_cb_delegate; + typedef device_delegate<void ()> update_cb_delegate; // construction/destruction samples_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); @@ -53,13 +55,30 @@ public: set_samples_start_callback(start_cb_delegate(callback, name, nullptr, static_cast<FunctionClass *>(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 <class FunctionClass> 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<FunctionClass *>(nullptr))); + } + template <class FunctionClass> void set_samples_update_callback(void (FunctionClass::*callback)(), const char *name) + { + set_samples_update_callback(update_cb_delegate(callback, name, nullptr, static_cast<FunctionClass *>(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(); @@ -116,6 +135,7 @@ 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<channel_t> m_channel; diff --git a/src/mame/drivers/ksys573.cpp b/src/mame/drivers/ksys573.cpp index 84c7de9e613..f95e6d3a93e 100644 --- a/src/mame/drivers/ksys573.cpp +++ b/src/mame/drivers/ksys573.cpp @@ -413,6 +413,7 @@ public: void hyperbbc(machine_config &config); void pnchmn2(machine_config &config); void ddrsolo(machine_config &config); + void ddrsbm(machine_config &config); void ddr3mp(machine_config &config); void dsftkd(machine_config &config); void dsfdcta(machine_config &config); @@ -431,6 +432,7 @@ public: void gtrfrks(machine_config &config); void gchgchmp(machine_config &config); void ddr5m(machine_config &config); + void ddrmax(machine_config &config); void drmn4m(machine_config &config); void fbaitbc(machine_config &config); void ddr4ms(machine_config &config); @@ -2293,6 +2295,16 @@ void ksys573_state::ddr5m(machine_config &config) casszi(config); } +void ksys573_state::ddrmax(machine_config &config) +{ + k573d(config); + subdevice<k573dio_device>("k573dio")->output_callback().set(FUNC(ksys573_state::ddr_output_callback)); + subdevice<k573dio_device>("k573dio")->set_buffer_speed(0x4000); + + pccard2_32mb(config); + casszi(config); +} + // Dancing Stage void ksys573_state::dsfdcta(machine_config &config) @@ -2334,6 +2346,15 @@ void ksys573_state::ddrsolo(machine_config &config) cassyi(config); } +void ksys573_state::ddrsbm(machine_config &config) +{ + k573d(config); + subdevice<k573dio_device>("k573dio")->output_callback().set(FUNC(ksys573_state::ddrsolo_output_callback)); + subdevice<k573dio_device>("k573dio")->set_fake_fpga(true); + + cassyi(config); +} + void ksys573_state::ddrs2k(machine_config &config) { k573d(config); @@ -2416,6 +2437,8 @@ void ksys573_state::gtrfrk7m(machine_config &config) void ksys573_state::gtfrk10mb(machine_config &config) { gtrfrk7m(config); + subdevice<k573dio_device>("k573dio")->set_mp3_dynamic_base(0x00500000); + KONAMI_573_NETWORK_PCB_UNIT(config, "k573npu", 0); } @@ -4760,6 +4783,25 @@ ROM_START( powyakex ) DISK_IMAGE_READONLY( "802jab02", 0, SHA1(460cc9f0b2514ec1da06b0a1d7b52fe43220d181) ) ROM_END +ROM_START( pcnfrk2m ) + SYS573_BIOS_A + + ROM_REGION( 0x0000224, "cassette:install:eeprom", 0 ) + ROM_LOAD( "ge912ka.u1", 0x000000, 0x000224, BAD_DUMP CRC(b3d5ca9a) SHA1(3dd9034e1a3a78a03bef975186b7ac6b01e3131a) ) + + ROM_REGION( 0x0001014, "cassette:game:eeprom", 0 ) + ROM_LOAD( "gn912ka.u1", 0x000000, 0x001014, BAD_DUMP CRC(c6af0c1a) SHA1(042d23bcfabc2a7fb6d7a038978805968e229395) ) + + ROM_REGION( 0x000008, "cassette:install:id", 0 ) + ROM_LOAD( "ge912ka.u6", 0x000000, 0x000008, BAD_DUMP CRC(af09e43c) SHA1(d8372f2d6e0ae07061b496a2242a63e5bc2e54dc) ) + + ROM_REGION( 0x000008, "cassette:game:id", 0 ) + ROM_LOAD( "gn912ka.u6", 0x000000, 0x000008, BAD_DUMP CRC(ce84419e) SHA1(839e8ee080ecfc79021a06417d930e8b32dfc6a1) ) + + DISK_REGION( "cdrom0" ) + DISK_IMAGE_READONLY( "912kaa02", 0, BAD_DUMP SHA1(176425d4be6809ede0333dd617056c7e8e3aa13a) ) +ROM_END + ROM_START( pcnfrk3m ) SYS573_BIOS_A @@ -4981,7 +5023,7 @@ GAME( 2000, ddr3mk, sys573, ddr3m, ddr, ksys573_state, empty_ini GAME( 2000, ddr3mka, ddr3mk, ddr3m, ddr, ksys573_state, empty_init, ROT0, "Konami", "Dance Dance Revolution 3rd Mix - Ver.Korea (GN887 VER. KAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.3 */ GAME( 1999, ddr3ma, ddr3mk, ddr3m, ddr, ksys573_state, empty_init, ROT0, "Konami", "Dance Dance Revolution 3rd Mix (GN887 VER. AAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.1 */ GAME( 1999, ddr3mj, ddr3mk, ddr3m, ddr, ksys573_state, empty_init, ROT0, "Konami", "Dance Dance Revolution 3rd Mix (GN887 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.0 */ -GAME( 1999, ddrsbm, sys573, ddrsolo, ddrsolo, ksys573_state, empty_init, ROT0, "Konami", "Dance Dance Revolution Solo Bass Mix (GQ894 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) +GAME( 1999, ddrsbm, sys573, ddrsbm, ddrsolo, ksys573_state, empty_init, ROT0, "Konami", "Dance Dance Revolution Solo Bass Mix (GQ894 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) GAME( 1999, ddrs2k, sys573, ddrs2k, ddrsolo, ksys573_state, empty_init, ROT0, "Konami", "Dance Dance Revolution Solo 2000 (GC905 VER. AAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.3 */ GAME( 1999, ddrs2kj, ddrs2k, ddrs2k, ddrsolo, ksys573_state, empty_init, ROT0, "Konami", "Dance Dance Revolution Solo 2000 (GC905 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.2 */ GAME( 1999, hypbbc2p, sys573, hypbbc2p, hypbbc2p, ksys573_state, init_hyperbbc, ROT0, "Konami", "Hyper Bishi Bashi Champ - 2 Player (GX908 1999/08/24 VER. JAA)", MACHINE_IMPERFECT_SOUND ) @@ -4991,6 +5033,7 @@ GAME( 1999, dsfdcta, dsfdct, dsfdcta, ddr, ksys573_state, init_ddr, GAME( 1999, drmn2m, sys573, drmn2m, drmn, ksys573_state, empty_init, ROT0, "Konami", "DrumMania 2nd Mix (GE912 VER. JAB)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.5 */ GAME( 1999, drmn2mpu, drmn2m, drmn2m, drmn, ksys573_state, empty_init, ROT0, "Konami", "DrumMania 2nd Mix Session Power Up Kit (GE912 VER. JAB)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.5 */ GAME( 1999, stepchmp, sys573, salarymc, hyperbbc, ksys573_state, init_salarymc, ROT0, "Konami", "Step Champ (GQ930 VER. JA)", MACHINE_NO_SOUND ) +GAME( 2000, pcnfrk2m, sys573, drmn2m, drmn, ksys573_state, empty_init, ROT0, "Konami", "Percussion Freaks 2nd Mix (GE912 VER. KAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.5 */ GAME( 2000, dncfrks, sys573, dmx, dmx, ksys573_state, empty_init, ROT0, "Konami", "Dance Freaks (G*874 VER. KAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.6 */ GAME( 2000, dmx, dncfrks, dmx, dmx, ksys573_state, empty_init, ROT0, "Konami", "Dance Maniax (G*874 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.6 */ GAME( 2000, gunmania, sys573, gunmania, gunmania, ksys573_state, empty_init, ROT0, "Konami", "GunMania (GL906 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) @@ -5031,8 +5074,8 @@ GAME( 2001, drmn5m, pcnfrk5m, drmn4m, drmn, ksys573_state, empty_ini GAME( 2001, gtrfrk6m, sys573, gtrfrk5m, gtrfrks, ksys573_state, empty_init, ROT0, "Konami", "Guitar Freaks 6th Mix (G*B06 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.9 */ GAME( 2001, drmn6m, sys573, drmn4m, drmn, ksys573_state, empty_init, ROT0, "Konami", "DrumMania 6th Mix (G*B16 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */ GAME( 2001, gtrfrk7m, sys573, gtrfrk7m, gtrfrks, ksys573_state, empty_init, ROT0, "Konami", "Guitar Freaks 7th Mix (G*B17 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */ -GAME( 2001, ddrmax, sys573, ddr5m, ddr, ksys573_state, empty_init, ROT0, "Konami", "DDR Max - Dance Dance Revolution 6th Mix (G*B19 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.9 */ -GAME( 2002, ddrmax2, sys573, ddr5m, ddr, ksys573_state, empty_init, ROT0, "Konami", "DDR Max 2 - Dance Dance Revolution 7th Mix (G*B20 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */ +GAME( 2001, ddrmax, sys573, ddrmax, ddr, ksys573_state, empty_init, ROT0, "Konami", "DDR Max - Dance Dance Revolution 6th Mix (G*B19 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.9 */ +GAME( 2002, ddrmax2, sys573, ddrmax, ddr, ksys573_state, empty_init, ROT0, "Konami", "DDR Max 2 - Dance Dance Revolution 7th Mix (G*B20 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */ GAME( 2002, mrtlbeat, sys573, ddr5m, ddr, ksys573_state, empty_init, ROT0, "Konami", "Martial Beat (G*B47 VER. JBA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.9 */ GAME( 2002, drmn7m, sys573, drmn4m, drmn, ksys573_state, empty_init, ROT0, "Konami", "DrumMania 7th Mix power-up ver. (G*C07 VER. JBA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */ GAME( 2002, drmn7ma, drmn7m, drmn4m, drmn, ksys573_state, empty_init, ROT0, "Konami", "DrumMania 7th Mix (G*C07 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */ @@ -5047,4 +5090,4 @@ GAME( 2003, gtfrk10m, sys573, gtrfrk7m, gtrfrks, ksys573_state, empty_ini GAME( 2003, gtfrk10ma, gtfrk10m, gtrfrk7m, gtrfrks, ksys573_state, empty_init, ROT0, "Konami", "Guitar Freaks 10th Mix (G*D10 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */ GAME( 2003, gtfrk10mb, gtfrk10m, gtfrk10mb, gtrfrks, ksys573_state, empty_init, ROT0, "Konami", "Guitar Freaks 10th Mix eAmusement (G*D10 VER. JBA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */ GAME( 2004, gtfrk11m, sys573, gtrfrk7m, gtrfrks, ksys573_state, empty_init, ROT0, "Konami", "Guitar Freaks 11th Mix (G*D39 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */ -GAME( 2004, drmn10m, sys573, drmn4m, drmn, ksys573_state, empty_init, ROT0, "Konami", "DrumMania 10th Mix (G*D40 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */ +GAME( 2004, drmn10m, sys573, drmn4m, drmn, ksys573_state, empty_init, ROT0, "Konami", "DrumMania 10th Mix (G*D40 VER. JAA)", MACHINE_IMPERFECT_SOUND | MACHINE_NOT_WORKING ) /* BOOT VER 1.95 */ diff --git a/src/mame/machine/k573dio.cpp b/src/mame/machine/k573dio.cpp index 5c274a14602..92935f43650 100644 --- a/src/mame/machine/k573dio.cpp +++ b/src/mame/machine/k573dio.cpp @@ -74,19 +74,25 @@ void k573dio_device::amap(address_map &map) map(0x04, 0x05).r(FUNC(k573dio_device::a04_r)); map(0x06, 0x07).r(FUNC(k573dio_device::a06_r)); map(0x0a, 0x0b).r(FUNC(k573dio_device::a0a_r)); + map(0x10, 0x11).w(FUNC(k573dio_device::a10_w)); map(0x80, 0x81).r(FUNC(k573dio_device::a80_r)); + map(0xa8, 0xa9).r(FUNC(k573dio_device::aa8_r)); + map(0xc4, 0xc5).r(FUNC(k573dio_device::ac4_r)); map(0xa0, 0xa1).w(FUNC(k573dio_device::mpeg_start_adr_high_w)); map(0xa2, 0xa3).w(FUNC(k573dio_device::mpeg_start_adr_low_w)); map(0xa4, 0xa5).w(FUNC(k573dio_device::mpeg_end_adr_high_w)); map(0xa6, 0xa7).w(FUNC(k573dio_device::mpeg_end_adr_low_w)); map(0xa8, 0xa9).w(FUNC(k573dio_device::mpeg_key_1_w)); map(0xac, 0xad).rw(FUNC(k573dio_device::mas_i2c_r), FUNC(k573dio_device::mas_i2c_w)); - map(0xae, 0xaf).w(FUNC(k573dio_device::mpeg_ctrl_w)); + map(0xae, 0xaf).rw(FUNC(k573dio_device::mpeg_ctrl_r), FUNC(k573dio_device::mpeg_ctrl_w)); map(0xb0, 0xb1).w(FUNC(k573dio_device::ram_write_adr_high_w)); map(0xb2, 0xb3).w(FUNC(k573dio_device::ram_write_adr_low_w)); map(0xb4, 0xb5).rw(FUNC(k573dio_device::ram_r), FUNC(k573dio_device::ram_w)); map(0xb6, 0xb7).w(FUNC(k573dio_device::ram_read_adr_high_w)); map(0xb8, 0xb9).w(FUNC(k573dio_device::ram_read_adr_low_w)); + map(0xca, 0xcb).rw(FUNC(k573dio_device::mp3_playback_high_r), FUNC(k573dio_device::mp3_playback_high_w)); + map(0xcc, 0xcd).rw(FUNC(k573dio_device::mp3_playback_low_r), FUNC(k573dio_device::mp3_playback_low_w)); + map(0xce, 0xcf).r(FUNC(k573dio_device::mp3_unk_r)); map(0xe0, 0xe1).w(FUNC(k573dio_device::output_1_w)); map(0xe2, 0xe3).w(FUNC(k573dio_device::output_0_w)); map(0xe4, 0xe5).w(FUNC(k573dio_device::output_3_w)); @@ -103,22 +109,34 @@ void k573dio_device::amap(address_map &map) k573dio_device::k573dio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, KONAMI_573_DIGITAL_IO_BOARD, tag, owner, clock), - mas3507d(*this, "mpeg"), + k573fpga(*this, "k573fpga"), digital_id(*this, "digital_id"), - output_cb(*this) + output_cb(*this), + is_fake_fpga(false), + buffer_speed(0x400) { } void k573dio_device::device_start() { output_cb.resolve_safe(); - ram = std::make_unique<uint16_t[]>(12 * 1024 * 1024 ); - save_pointer(NAME(ram), 12 * 1024 * 1024 ); + + ram = std::make_unique<uint16_t[]>(32 * 1024 * 1024); + save_pointer(NAME(ram), 32 * 1024 * 1024 ); + + k573fpga->set_ram(ram.get()); + k573fpga->set_fake_fpga(is_fake_fpga); + k573fpga->set_buffer_speed(buffer_speed); + k573fpga->set_mp3_dynamic_base(mp3_dynamic_base); + + device_reset(); } void k573dio_device::device_reset() { ram_adr = 0; + ram_read_adr = 0; + memset(output_data, 0, sizeof(output_data)); } @@ -134,8 +152,8 @@ const tiny_rom_entry *k573dio_device::device_rom_region() const void k573dio_device::device_add_mconfig(machine_config &config) { - MAS3507D(config, "mpeg"); - DS2401( config, "digital_id" ); + KONAMI_573_DIGITAL_FPGA(config, "k573fpga"); + DS2401(config, "digital_id"); } void k573dio_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) @@ -172,6 +190,23 @@ READ16_MEMBER(k573dio_device::a0a_r) return 0x0000; } +WRITE16_MEMBER(k573dio_device::a10_w) +{ + logerror("%s: a10_w (%s)\n", tag(), machine().describe_context()); +} + +READ16_MEMBER(k573dio_device::aa8_r) +{ + logerror("%s: aa8_r (%s)\n", tag(), machine().describe_context()); + return 1; +} + +READ16_MEMBER(k573dio_device::ac4_r) +{ + // What is this? + return 0; +} + READ16_MEMBER(k573dio_device::a80_r) { logerror("%s: a80_r (%s)\n", tag(), machine().describe_context()); @@ -181,45 +216,51 @@ 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 } 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 } WRITE16_MEMBER(k573dio_device::mpeg_end_adr_high_w) { logerror("FPGA MPEG end address high %04x\n", data); + k573fpga->set_mp3_end_adr((k573fpga->get_mp3_end_adr() & 0x0000ffff) | (data << 16)); // high } WRITE16_MEMBER(k573dio_device::mpeg_end_adr_low_w) { logerror("FPGA MPEG end address low %04x\n", data); + k573fpga->set_mp3_end_adr((k573fpga->get_mp3_end_adr() & 0xffff0000) | data); // low } WRITE16_MEMBER(k573dio_device::mpeg_key_1_w) { logerror("FPGA MPEG key 1/3 %04x\n", data); + k573fpga->set_crypto_key1(data); } READ16_MEMBER(k573dio_device::mas_i2c_r) { - return (mas3507d->i2c_scl_r() << 13) | (mas3507d->i2c_sda_r() << 12); + return k573fpga->i2c_read(); } WRITE16_MEMBER(k573dio_device::mas_i2c_w) { - mas3507d->i2c_scl_w(data & 0x2000); - mas3507d->i2c_sda_w(data & 0x1000); + k573fpga->i2c_write(data); +} + +READ16_MEMBER(k573dio_device::mpeg_ctrl_r) +{ + return k573fpga->get_mpeg_ctrl(); } WRITE16_MEMBER(k573dio_device::mpeg_ctrl_w) { - logerror("FPGA MPEG control %c%c%c\n", - data & 0x8000 ? '#' : '.', - data & 0x4000 ? '#' : '.', - data & 0x2000 ? '#' : '.'); + k573fpga->set_mpeg_ctrl(data); } WRITE16_MEMBER(k573dio_device::ram_write_adr_high_w) @@ -236,8 +277,8 @@ WRITE16_MEMBER(k573dio_device::ram_write_adr_low_w) READ16_MEMBER(k573dio_device::ram_r) { - uint16_t res = ram[ram_adr >> 1]; - ram_adr += 2; + uint16_t res = ram[ram_read_adr >> 1]; + ram_read_adr += 2; return res; } @@ -250,13 +291,37 @@ WRITE16_MEMBER(k573dio_device::ram_w) WRITE16_MEMBER(k573dio_device::ram_read_adr_high_w) { // read and write address are shared - ram_adr = (ram_adr & 0x0000ffff) | (data << 16); + ram_read_adr = (ram_read_adr & 0x0000ffff) | (data << 16); } WRITE16_MEMBER(k573dio_device::ram_read_adr_low_w) { // read and write address are shared - ram_adr = (ram_adr & 0xffff0000) | data; + ram_read_adr = (ram_read_adr & 0xffff0000) | data; +} + +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; +} + +WRITE16_MEMBER(k573dio_device::mp3_playback_high_w) +{ + //mp3_playback = (mp3_playback & 0x0000ffff) | (data << 16); + //logerror("mp3_playback_low_w: %08x\n", mp3_playback); +} + +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; +} + +WRITE16_MEMBER(k573dio_device::mp3_playback_low_w) +{ + //mp3_playback = (mp3_playback & 0xffff0000) | data; + //logerror("mp3_playback_low_w: %08x\n", mp3_playback & 0x0000ffff); } WRITE16_MEMBER(k573dio_device::output_1_w) @@ -282,11 +347,13 @@ WRITE16_MEMBER(k573dio_device::output_7_w) WRITE16_MEMBER(k573dio_device::mpeg_key_2_w) { logerror("FPGA MPEG key 2/3 %04x\n", data); + k573fpga->set_crypto_key2(data); } WRITE16_MEMBER(k573dio_device::mpeg_key_3_w) { logerror("FPGA MPEG key 3/3 %04x\n", data); + k573fpga->set_crypto_key3(data); } READ16_MEMBER(k573dio_device::digital_id_r) @@ -301,7 +368,7 @@ WRITE16_MEMBER(k573dio_device::digital_id_w) READ16_MEMBER(k573dio_device::fpga_status_r) { - logerror("%s: fpga_status_r (%s)\n", tag(), machine().describe_context()); + //logerror("%s: fpga_status_r (%s)\n", tag(), machine().describe_context()); // fpga/digital board status checks // wants & c000 = 8000 (just after program upload?) @@ -335,6 +402,11 @@ WRITE16_MEMBER(k573dio_device::output_2_w) output(2, data); } +READ16_MEMBER(k573dio_device::mp3_unk_r) +{ + return 0; +} + void k573dio_device::output(int offset, uint16_t data) { data = (data >> 12) & 0x0f; diff --git a/src/mame/machine/k573dio.h b/src/mame/machine/k573dio.h index 80ff4a3dab3..c3e5236f54f 100644 --- a/src/mame/machine/k573dio.h +++ b/src/mame/machine/k573dio.h @@ -5,10 +5,9 @@ #pragma once -#include "sound/mas3507d.h" +#include "machine/k573fpga.h" #include "machine/ds2401.h" - class k573dio_device : public device_t { public: @@ -16,17 +15,24 @@ public: auto output_callback() { return output_cb.bind(); } - required_device<mas3507d_device> mas3507d; + required_device<k573fpga_device> k573fpga; required_device<ds2401_device> digital_id; void amap(address_map &map); + void set_fake_fpga(bool flag) { is_fake_fpga = flag; } + void set_buffer_speed(uint32_t speed) { buffer_speed = speed; } + void set_mp3_dynamic_base(uint32_t base) { mp3_dynamic_base = base; } DECLARE_READ16_MEMBER(a00_r); DECLARE_READ16_MEMBER(a02_r); DECLARE_READ16_MEMBER(a04_r); DECLARE_READ16_MEMBER(a06_r); DECLARE_READ16_MEMBER(a0a_r); + DECLARE_WRITE16_MEMBER(a10_w); DECLARE_READ16_MEMBER(a80_r); + DECLARE_READ16_MEMBER(aa8_r); + DECLARE_READ16_MEMBER(ac4_r); + DECLARE_WRITE16_MEMBER(mpeg_start_adr_high_w); DECLARE_WRITE16_MEMBER(mpeg_start_adr_low_w); DECLARE_WRITE16_MEMBER(mpeg_end_adr_high_w); @@ -34,6 +40,7 @@ public: DECLARE_WRITE16_MEMBER(mpeg_key_1_w); DECLARE_READ16_MEMBER(mas_i2c_r); DECLARE_WRITE16_MEMBER(mas_i2c_w); + DECLARE_READ16_MEMBER(mpeg_ctrl_r); DECLARE_WRITE16_MEMBER(mpeg_ctrl_w); DECLARE_WRITE16_MEMBER(ram_write_adr_high_w); DECLARE_WRITE16_MEMBER(ram_write_adr_low_w); @@ -41,6 +48,10 @@ public: DECLARE_WRITE16_MEMBER(ram_w); DECLARE_WRITE16_MEMBER(ram_read_adr_high_w); DECLARE_WRITE16_MEMBER(ram_read_adr_low_w); + DECLARE_READ16_MEMBER(mp3_playback_high_r); + DECLARE_WRITE16_MEMBER(mp3_playback_high_w); + DECLARE_READ16_MEMBER(mp3_playback_low_r); + DECLARE_WRITE16_MEMBER(mp3_playback_low_w); DECLARE_WRITE16_MEMBER(output_0_w); DECLARE_WRITE16_MEMBER(output_1_w); DECLARE_WRITE16_MEMBER(output_7_w); @@ -54,6 +65,7 @@ public: DECLARE_WRITE16_MEMBER(output_4_w); DECLARE_WRITE16_MEMBER(output_2_w); DECLARE_WRITE16_MEMBER(output_5_w); + DECLARE_READ16_MEMBER(mp3_unk_r); protected: virtual void device_start() override; @@ -66,10 +78,13 @@ private: devcb_write8 output_cb; std::unique_ptr<uint16_t[]> ram; - uint32_t ram_adr; + uint32_t ram_adr, ram_read_adr; uint8_t output_data[8]; void output(int offset, uint16_t data); + + bool is_fake_fpga; + uint32_t buffer_speed, mp3_dynamic_base; }; DECLARE_DEVICE_TYPE(KONAMI_573_DIGITAL_IO_BOARD, k573dio_device) diff --git a/src/mame/machine/k573enc.h b/src/mame/machine/k573enc.h new file mode 100644 index 00000000000..3f115675fb1 --- /dev/null +++ b/src/mame/machine/k573enc.h @@ -0,0 +1,120 @@ +// license:BSD-3-Clause +// copyright-holders:windyfairy +#ifndef MAME_MACHINE_K573ENC_H +#define MAME_MACHINE_K573ENC_H + +#pragma once + +#include <map> + +std::unordered_map<uint16_t, uint32_t> k573enc_lookup({ + { 0x031a, 0 }, + { 0x038e, 1 }, + { 0x0aa7, 2 }, + { 0x0c51, 3 }, + { 0x0e34, 4 }, + { 0x14d9, 5 }, + { 0x154d, 6 }, + { 0x18a0, 7 }, + { 0x18da, 8 }, + { 0x1c67, 9 }, + { 0x20dc, 10 }, + { 0x21d6, 11 }, + { 0x2698, 12 }, + { 0x28b6, 13 }, + { 0x2a5f, 14 }, + { 0x2c7c, 15 }, + { 0x3009, 16 }, + { 0x3395, 17 }, + { 0x3505, 18 }, + { 0x3722, 19 }, + { 0x38cb, 20 }, + { 0x3aaf, 21 }, + { 0x3e3b, 22 }, + { 0x41c8, 23 }, + { 0x4371, 24 }, + { 0x451b, 25 }, + { 0x4555, 26 }, + { 0x46c4, 27 }, + { 0x48e1, 28 }, + { 0x4c6e, 29 }, + { 0x4fc0, 30 }, + { 0x4ffa, 31 }, + { 0x5387, 32 }, + { 0x5530, 33 }, + { 0x56b4, 34 }, + { 0x5714, 35 }, + { 0x5c10, 36 }, + { 0x5c83, 37 }, + { 0x5dcd, 38 }, + { 0x5fd6, 39 }, + { 0x6010, 40 }, + { 0x617f, 41 }, + { 0x6546, 42 }, + { 0x6729, 43 }, + { 0x685f, 44 }, + { 0x6dcf, 45 }, + { 0x6e43, 46 }, + { 0x6fec, 47 }, + { 0x7195, 48 }, + { 0x755c, 49 }, + { 0x78e8, 50 }, + { 0x7c3b, 51 } +}); + +uint8_t k573enc_keys[52][16] = { + { 0x14, 0x26, 0x28, 0x4c, 0x50, 0x98, 0xa0, 0x31, 0x41, 0x62, 0x82, 0xc4, 0x05, 0x89, 0x0a, 0x13 }, + { 0x12, 0x36, 0x24, 0x6c, 0x48, 0xd8, 0x90, 0xb1, 0x21, 0x63, 0x42, 0xc6, 0x84, 0x8d, 0x09, 0x1b }, + { 0x03, 0x7a, 0x06, 0xf4, 0x0c, 0xe9, 0x18, 0xd3, 0x30, 0xa7, 0x60, 0x4f, 0xc0, 0x9e, 0x81, 0x3d }, + { 0x2d, 0x40, 0x5a, 0x80, 0xb4, 0x01, 0x69, 0x02, 0xd2, 0x04, 0xa5, 0x08, 0x4b, 0x10, 0x96, 0x20 }, + { 0x26, 0x68, 0x4c, 0xd0, 0x98, 0xa1, 0x31, 0x43, 0x62, 0x86, 0xc4, 0x0d, 0x89, 0x1a, 0x13, 0x34 }, + { 0x6d, 0x14, 0xda, 0x28, 0xb5, 0x50, 0x6b, 0xa0, 0xd6, 0x41, 0xad, 0x82, 0x5b, 0x05, 0xb6, 0x0a }, + { 0x7b, 0x04, 0xf6, 0x08, 0xed, 0x10, 0xdb, 0x20, 0xb7, 0x40, 0x6f, 0x80, 0xde, 0x01, 0xbd, 0x02 }, + { 0x40, 0x58, 0x80, 0xb0, 0x01, 0x61, 0x02, 0xc2, 0x04, 0x85, 0x08, 0x0b, 0x10, 0x16, 0x20, 0x2c }, + { 0x4c, 0x56, 0x98, 0xac, 0x31, 0x59, 0x62, 0xb2, 0xc4, 0x65, 0x89, 0xca, 0x13, 0x95, 0x26, 0x2b }, + { 0x6b, 0x4a, 0xd6, 0x94, 0xad, 0x29, 0x5b, 0x52, 0xb6, 0xa4, 0x6d, 0x49, 0xda, 0x92, 0xb5, 0x25 }, + { 0x0e, 0x94, 0x1c, 0x29, 0x38, 0x52, 0x70, 0xa4, 0xe0, 0x49, 0xc1, 0x92, 0x83, 0x25, 0x07, 0x4a }, + { 0x1e, 0x92, 0x3c, 0x25, 0x78, 0x4a, 0xf0, 0x94, 0xe1, 0x29, 0xc3, 0x52, 0x87, 0xa4, 0x0f, 0x49 }, + { 0x24, 0xb4, 0x48, 0x69, 0x90, 0xd2, 0x21, 0xa5, 0x42, 0x4b, 0x84, 0x96, 0x09, 0x2d, 0x12, 0x5a }, + { 0x06, 0xda, 0x0c, 0xb5, 0x18, 0x6b, 0x30, 0xd6, 0x60, 0xad, 0xc0, 0x5b, 0x81, 0xb6, 0x03, 0x6d }, + { 0x0f, 0xe6, 0x1e, 0xcd, 0x3c, 0x9b, 0x78, 0x37, 0xf0, 0x6e, 0xe1, 0xdc, 0xc3, 0xb9, 0x87, 0x73 }, + { 0x2e, 0xcc, 0x5c, 0x99, 0xb8, 0x33, 0x71, 0x66, 0xe2, 0xcc, 0xc5, 0x99, 0x8b, 0x33, 0x17, 0x66 }, + { 0x41, 0x84, 0x82, 0x09, 0x05, 0x12, 0x0a, 0x24, 0x14, 0x48, 0x28, 0x90, 0x50, 0x21, 0xa0, 0x42 }, + { 0x57, 0xb0, 0xae, 0x61, 0x5d, 0xc2, 0xba, 0x85, 0x75, 0x0b, 0xea, 0x16, 0xd5, 0x2c, 0xab, 0x58 }, + { 0x73, 0x80, 0xe6, 0x01, 0xcd, 0x02, 0x9b, 0x04, 0x37, 0x08, 0x6e, 0x10, 0xdc, 0x20, 0xb9, 0x40 }, + { 0x70, 0xaa, 0xe0, 0x55, 0xc1, 0xaa, 0x83, 0x55, 0x07, 0xaa, 0x0e, 0x55, 0x1c, 0xaa, 0x38, 0x55 }, + { 0x49, 0xd6, 0x92, 0xad, 0x25, 0x5b, 0x4a, 0xb6, 0x94, 0x6d, 0x29, 0xda, 0x52, 0xb5, 0xa4, 0x6b }, + { 0x43, 0xfe, 0x86, 0xfd, 0x0d, 0xfb, 0x1a, 0xf7, 0x34, 0xef, 0x68, 0xdf, 0xd0, 0xbf, 0xa1, 0x7f }, + { 0x65, 0xee, 0xca, 0xdd, 0x95, 0xbb, 0x2b, 0x77, 0x56, 0xee, 0xac, 0xdd, 0x59, 0xbb, 0xb2, 0x77 }, + { 0x98, 0x14, 0x31, 0x28, 0x62, 0x50, 0xc4, 0xa0, 0x89, 0x41, 0x13, 0x82, 0x26, 0x05, 0x4c, 0x0a }, + { 0x9d, 0x28, 0x3b, 0x50, 0x76, 0xa0, 0xec, 0x41, 0xd9, 0x82, 0xb3, 0x05, 0x67, 0x0a, 0xce, 0x14 }, + { 0xb5, 0x06, 0x6b, 0x0c, 0xd6, 0x18, 0xad, 0x30, 0x5b, 0x60, 0xb6, 0xc0, 0x6d, 0x81, 0xda, 0x03 }, + { 0xbf, 0x00, 0x7f, 0x00, 0xfe, 0x00, 0xfd, 0x00, 0xfb, 0x00, 0xf7, 0x00, 0xef, 0x00, 0xdf, 0x00 }, + { 0xaa, 0x30, 0x55, 0x60, 0xaa, 0xc0, 0x55, 0x81, 0xaa, 0x03, 0x55, 0x06, 0xaa, 0x0c, 0x55, 0x18 }, + { 0x89, 0x58, 0x13, 0xb0, 0x26, 0x61, 0x4c, 0xc2, 0x98, 0x85, 0x31, 0x0b, 0x62, 0x16, 0xc4, 0x2c }, + { 0xaa, 0x4e, 0x55, 0x9c, 0xaa, 0x39, 0x55, 0x72, 0xaa, 0xe4, 0x55, 0xc9, 0xaa, 0x93, 0x55, 0x27 }, + { 0xb8, 0x70, 0x71, 0xe0, 0xe2, 0xc1, 0xc5, 0x83, 0x8b, 0x07, 0x17, 0x0e, 0x2e, 0x1c, 0x5c, 0x38 }, + { 0xbc, 0x7e, 0x79, 0xfc, 0xf2, 0xf9, 0xe5, 0xf3, 0xcb, 0xe7, 0x97, 0xcf, 0x2f, 0x9f, 0x5e, 0x3f }, + { 0xd3, 0x32, 0xa7, 0x64, 0x4f, 0xc8, 0x9e, 0x91, 0x3d, 0x23, 0x7a, 0x46, 0xf4, 0x8c, 0xe9, 0x19 }, + { 0xf4, 0x08, 0xe9, 0x10, 0xd3, 0x20, 0xa7, 0x40, 0x4f, 0x80, 0x9e, 0x01, 0x3d, 0x02, 0x7a, 0x04 }, + { 0xe6, 0x38, 0xcd, 0x70, 0x9b, 0xe0, 0x37, 0xc1, 0x6e, 0x83, 0xdc, 0x07, 0xb9, 0x0e, 0x73, 0x1c }, + { 0xf6, 0x20, 0xed, 0x40, 0xdb, 0x80, 0xb7, 0x01, 0x6f, 0x02, 0xde, 0x04, 0xbd, 0x08, 0x7b, 0x10 }, + { 0xe4, 0x40, 0xc9, 0x80, 0x93, 0x01, 0x27, 0x02, 0x4e, 0x04, 0x9c, 0x08, 0x39, 0x10, 0x72, 0x20 }, + { 0xe1, 0x52, 0xc3, 0xa4, 0x87, 0x49, 0x0f, 0x92, 0x1e, 0x25, 0x3c, 0x4a, 0x78, 0x94, 0xf0, 0x29 }, + { 0xfb, 0x54, 0xf7, 0xa8, 0xef, 0x51, 0xdf, 0xa2, 0xbf, 0x45, 0x7f, 0x8a, 0xfe, 0x15, 0xfd, 0x2a }, + { 0xfe, 0x72, 0xfd, 0xe4, 0xfb, 0xc9, 0xf7, 0x93, 0xef, 0x27, 0xdf, 0x4e, 0xbf, 0x9c, 0x7f, 0x39 }, + { 0x84, 0x80, 0x09, 0x01, 0x12, 0x02, 0x24, 0x04, 0x48, 0x08, 0x90, 0x10, 0x21, 0x20, 0x42, 0x40 }, + { 0x9f, 0x8e, 0x3f, 0x1d, 0x7e, 0x3a, 0xfc, 0x74, 0xf9, 0xe8, 0xf3, 0xd1, 0xe7, 0xa3, 0xcf, 0x47 }, + { 0xba, 0x82, 0x75, 0x05, 0xea, 0x0a, 0xd5, 0x14, 0xab, 0x28, 0x57, 0x50, 0xae, 0xa0, 0x5d, 0x41 }, + { 0xb1, 0xac, 0x63, 0x59, 0xc6, 0xb2, 0x8d, 0x65, 0x1b, 0xca, 0x36, 0x95, 0x6c, 0x2b, 0xd8, 0x56 }, + { 0x8f, 0xc6, 0x1f, 0x8d, 0x3e, 0x1b, 0x7c, 0x36, 0xf8, 0x6c, 0xf1, 0xd8, 0xe3, 0xb1, 0xc7, 0x63 }, + { 0xbb, 0xd6, 0x77, 0xad, 0xee, 0x5b, 0xdd, 0xb6, 0xbb, 0x6d, 0x77, 0xda, 0xee, 0xb5, 0xdd, 0x6b }, + { 0xa9, 0xe2, 0x53, 0xc5, 0xa6, 0x8b, 0x4d, 0x17, 0x9a, 0x2e, 0x35, 0x5c, 0x6a, 0xb8, 0xd4, 0x71 }, + { 0xba, 0xfc, 0x75, 0xf9, 0xea, 0xf3, 0xd5, 0xe7, 0xab, 0xcf, 0x57, 0x9f, 0xae, 0x3f, 0x5d, 0x7e }, + { 0xd7, 0x90, 0xaf, 0x21, 0x5f, 0x42, 0xbe, 0x84, 0x7d, 0x09, 0xfa, 0x12, 0xf5, 0x24, 0xeb, 0x48 }, + { 0xfe, 0x84, 0xfd, 0x09, 0xfb, 0x12, 0xf7, 0x24, 0xef, 0x48, 0xdf, 0x90, 0xbf, 0x21, 0x7f, 0x42 }, + { 0xc8, 0xdc, 0x91, 0xb9, 0x23, 0x73, 0x46, 0xe6, 0x8c, 0xcd, 0x19, 0x9b, 0x32, 0x37, 0x64, 0x6e }, + { 0xe5, 0xce, 0xcb, 0x9d, 0x97, 0x3b, 0x2f, 0x76, 0x5e, 0xec, 0xbc, 0xd9, 0x79, 0xb3, 0xf2, 0x67 } +}; + +#endif // MAME_MACHINE_K573ENC_H diff --git a/src/mame/machine/k573fpga.cpp b/src/mame/machine/k573fpga.cpp new file mode 100644 index 00000000000..0d85813767e --- /dev/null +++ b/src/mame/machine/k573fpga.cpp @@ -0,0 +1,566 @@ +// license:BSD-3-Clause +// copyright-holders:windyfairy +#include "emu.h" +#include "speaker.h" + +#include "k573fpga.h" +#include "k573enc.h" + +// TODO: Check if this is optimal +#define MINIMUM_BUFFER 1 + +// TODO: Is this really needed? Confirm +#define MAX_FRAME_SYNC_MATCHES 1 + +#define MINIMP3_ONLY_MP3 +#define MINIMP3_NO_STDIO +#define MINIMP3_IMPLEMENTATION +#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) : + device_t(mconfig, KONAMI_573_DIGITAL_FPGA, tag, owner, clock), + mas3507d(*this, "mpeg"), + m_samples(*this, "samples"), + use_fake_fpga(false) +{ +} + +void k573fpga_device::device_start() +{ + ram_swap = std::make_unique<uint16_t[]>(32 * 1024 * 1024); + save_pointer(NAME(ram_swap), 32 * 1024 * 1024 ); + + device_reset(); +} + +void k573fpga_device::device_reset() +{ + mp3_start_adr = 0; + mp3_end_adr = 0; + crypto_key1 = 0; + crypto_key2 = 0; + crypto_key3 = 0; + mp3_last_frame = 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, 12 * 1024 * 1024 * 2); + memset(&mp3_info, 0, sizeof(mp3_info)); + + mas3507d->set_samples(m_samples); + + last_position_update = 0; + position_diff = 0; +} + +static const char *const k573fpga_sample_names[] = +{ + "*k573fpga", + "audio", + nullptr +}; + +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_names(k573fpga_sample_names); + 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 (mp3_start_adr == 0) { + 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 { + position_diff = m_samples->get_position(0) - last_position_update; + last_position_update = m_samples->get_position(0); + } + + last_position_update = m_samples->get_position(0); + + return last_position_update; + } + + return 0; +} + +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) +{ + 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 && mp3_decrypt_mode)) { + // This has been tested with real hardware, but this flag is always held 0x1000 when the audio is being played + return mpeg_ctrl_flag | 0x1000; + } + + return mpeg_ctrl_flag; +} + +void k573fpga_device::set_mpeg_ctrl(uint16_t data) +{ + logerror("FPGA MPEG control %c%c%c | %08x %08x\n", + data & 0x8000 ? '#' : '.', + data & 0x4000 ? '#' : '.', + data & 0x2000 ? '#' : '.', + mp3_start_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_last_frame = 0; + 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; + } + } + + if ((data & 0xe000) == 0xe000) { + mp3_decrypt_mode = true; + } else { + mp3_decrypt_mode = false; + } +} + +int32_t k573fpga_device::find_enc_key() +{ + if (k573enc_lookup.find(crypto_key1) == k573enc_lookup.end()) { + return -1; + } + + return k573enc_lookup[crypto_key1]; +} + +inline uint16_t k573fpga_device::fpga_decrypt_byte_real(uint16_t v) +{ + uint16_t m = crypto_key1 ^ crypto_key2; + + v = bitswap<16>( + v, + 15 - BIT(m, 0xF), + 14 + BIT(m, 0xF), + 13 - BIT(m, 0xE), + 12 + BIT(m, 0xE), + 11 - BIT(m, 0xB), + 10 + BIT(m, 0xB), + 9 - BIT(m, 0x9), + 8 + BIT(m, 0x9), + 7 - BIT(m, 0x8), + 6 + BIT(m, 0x8), + 5 - BIT(m, 0x5), + 4 + BIT(m, 0x5), + 3 - BIT(m, 0x3), + 2 + BIT(m, 0x3), + 1 - BIT(m, 0x2), + 0 + BIT(m, 0x2) + ); + + v ^= (BIT(m, 0xD) << 14) ^ + (BIT(m, 0xC) << 12) ^ + (BIT(m, 0xA) << 10) ^ + (BIT(m, 0x7) << 8) ^ + (BIT(m, 0x6) << 6) ^ + (BIT(m, 0x4) << 4) ^ + (BIT(m, 0x1) << 2) ^ + (BIT(m, 0x0) << 0); + + v ^= bitswap<16>( + (uint16_t)crypto_key3, + 7, 0, 6, 1, + 5, 2, 4, 3, + 3, 4, 2, 5, + 1, 6, 0, 7 + ); + + return (v >> 8) | ((v & 0xff) << 8); +} + +inline uint16_t k573fpga_device::fpga_decrypt_byte_fake(uint16_t data, uint32_t crypto_idx) +{ + // Not the real algorithm. Only used for DDR Solo Bass Mix (ddrsbm) + int32_t crypto_enc_idx = find_enc_key(); + + if (crypto_enc_idx == -1) { + return data; + } + + uint8_t *key = k573enc_keys[crypto_enc_idx]; + + 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; + + 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_even_bit_set ^ is_key_bit_set)) == 1) { + output_word |= 1 << even_bit_shift; + } + + if ((is_odd_bit_set) == 1) { + output_word |= 1 << odd_bit_shift; + } + } + + return (output_word >> 8) | ((output_word & 0xff) << 8); +} + +SAMPLES_UPDATE_CB_MEMBER(k573fpga_device::k573fpga_stream_update) +{ + if ((mpeg_ctrl_flag & 0xe000) != 0xe000 || mp3_last_adr >= mp3_end_adr || (m_samples->get_position(0) < mp3_next_sync && mp3_next_sync != 0)) { + return; + } + + int new_samples = 0; + + if (!use_fake_fpga && mp3_start_adr != mp3_dynamic_base) { + // Base addresses are kind of a "hack" and should be dealt with eventually. + // Files that are loaded at he base address are dynamic, meaning the data constantly changes. + // Data will not get loaded outside of the base address region past the boot sequence, however. + // As such, it's possible to decrypt and play the full file if it's not at the designated base address. + // Only 4 games seem to use a base address that is non-0: GF11DM10 (0x00540000) and GF10DM9 (0x00500000). + // This way of doing things seems kind of arbitrary, so it most likely doesn't need to be handled in a + // specific case like this, but this leads to much better performance overall since the data is usually + // small (<1mb). + // Another interesting thing about base addresses is that non-base address files are almost always looped + // in-game, with the exception of the Konami logo sound. Without looping non-base address sounds, things + // like system BGMs and song wheel previews will stop looping. + + crypto_key1 = orig_crypto_key1; + crypto_key2 = orig_crypto_key2; + crypto_key3 = orig_crypto_key3; + + for (int32_t cur_idx = mp3_start_adr; cur_idx < mp3_end_adr; cur_idx += 2) { + if (use_fake_fpga) { + ram_swap[cur_idx >> 1] = fpga_decrypt_byte_fake(ram[cur_idx >> 1], (cur_idx - mp3_start_adr) / 2); + } else { + ram_swap[cur_idx >> 1] = fpga_decrypt_byte_real(ram[cur_idx >> 1]); + } + + if (!use_fake_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++; + } + + // Decrypt entire block of memory + if (mp3_info.buffer != NULL) { + free(mp3_info.buffer); + } + + mp3dec_load_buf(&mp3_dec, ((uint8_t*)ram_swap.get()) + mp3_start_adr, mp3_end_adr - mp3_start_adr, &mp3_info, NULL, NULL); + new_samples = mp3_info.samples; + last_copied_samples = 0; + mp3_last_adr += mp3_end_adr - mp3_start_adr; + } else { + // For base address files, decrypt in a streaming manner. + // By the time the play flag is set, there's usually enough data to decode the first frame or two. + // Some files (specifcially GFDM's audio) has a large 0x600 byte ID3 header, so in order to guarantee that + // the first frame is found, I've found it best to decrypt 0x2000 bytes in the first go and then a smaller + // amount after that for every subsequent update. + + new_samples = mp3_info.samples; + + + int decrypt_buffer = MINIMUM_BUFFER; + int decrypt_buffer_speed = buffer_speed; + + if (mp3_next_sync == 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 = 1; + decrypt_buffer_speed = 0x2000; + + 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 * decrypt_buffer >= mp3_last_decrypt_adr) { + int32_t cur_idx; + + for (cur_idx = mp3_last_decrypt_adr; cur_idx - mp3_last_decrypt_adr < decrypt_buffer_speed * decrypt_buffer && cur_idx < mp3_end_adr; cur_idx += 2) { + if (use_fake_fpga) { + ram_swap[cur_idx >> 1] = fpga_decrypt_byte_fake(ram[cur_idx >> 1], (cur_idx - mp3_start_adr) / 2); + } else { + ram_swap[cur_idx >> 1] = fpga_decrypt_byte_real(ram[cur_idx >> 1]); + } + + if (!use_fake_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 * decrypt_buffer; + + uint8_t *buf = (uint8_t*)ram_swap.get() + mp3_last_adr; + + // Detect first frame in MP3 data + if (mp3_next_sync == 0) { + buf_size = 0x2000; + + // Everything on the System 573 has a header 0x600 or less from what I've seen, but just ot be sure, check the first 0x2000 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; + } + + // Skip x amount of samples previously read (this fixes some weird glitches) + for (int frame_skip = 0; frame_skip < mp3_last_frame && buf < (uint8_t*)ram_swap.get() + mp3_end_adr; frame_skip++) { + mp3d_find_frame(buf, buf_size, &free_format_bytes, &frame_size); + buf += frame_size; + mp3_last_adr += frame_size; + } + + mp3_last_frame = 0; + + if (mp3_next_sync == 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_frame = 0; + + decrypt_buffer = 8; + } + + /* decode rest frames */ + buf_size = decrypt_buffer_speed * 2; + + for (int frame_skip = 0; frame_skip < decrypt_buffer && buf < (uint8_t*)ram_swap.get() + mp3_end_adr; frame_skip++) { + 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 (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; + break; + } + + 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; + break; + } + + if (mp3_info.hz != mp3_frame_info.hz || mp3_info.layer != mp3_frame_info.layer) { + break; + } + + if (mp3_info.channels && mp3_info.channels != mp3_frame_info.channels) { + break; + } + + buf += mp3_frame_info.frame_bytes; + mp3_info.samples += samples * mp3_frame_info.channels; + mp3_last_frame++; + } + + 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; + + 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 / 3); // 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; + } +} + +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 new file mode 100644 index 00000000000..d65c60aa800 --- /dev/null +++ b/src/mame/machine/k573fpga.h @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:windyfairy +#ifndef MAME_MACHINE_K573FPGA_H +#define MAME_MACHINE_K573FPGA_H + +#pragma once + +#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_device> mas3507d; + required_device<samples_device> m_samples; + + void set_fake_fpga(bool flag) { use_fake_fpga = flag; } + + void set_ram(uint16_t *v) { ram = v; } + + 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; } + + 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_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); + + uint16_t get_mpeg_ctrl(); + void set_mpeg_ctrl(uint16_t data); + + void set_buffer_speed(uint32_t speed) { buffer_speed = speed; } + void set_mp3_dynamic_base(uint32_t base) { mp3_dynamic_base = base; } + +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<uint16_t[]> ram_swap; + + uint16_t crypto_key1, crypto_key2, orig_crypto_key1, orig_crypto_key2; + uint8_t crypto_key3, orig_crypto_key3; + + uint32_t mp3_start_adr, mp3_end_adr, mpeg_ctrl_flag; + bool use_fake_fpga; + + uint32_t mp3_last_frame, 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 mp3_decrypt_mode, 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_fake(uint16_t data, uint32_t crypto_idx); + + SAMPLES_UPDATE_CB_MEMBER(k573fpga_stream_update); +}; + +#endif // MAME_MACHINE_K573FPGA_H |