From 00c8a3b165794519f64852b971096793509f5f73 Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Sun, 14 Aug 2016 14:19:02 +0200 Subject: [PATCH] Preliminary VGM player [O. Galibert] Use: ./mame vgmplay -bitb file.vgm/vgz Lots of chips missing, no visualization, no control of anything, no volume control either, and no sound shutdown on end of file. --- scripts/target/mame/mame.lua | 3 + scripts/target/mame/virtual.lua | 73 +++ src/devices/sound/segapcm.cpp | 13 +- src/devices/sound/segapcm.h | 4 +- src/mame/drivers/vgmplay.cpp | 794 ++++++++++++++++++++++++++++++++ src/mame/mame.lst | 4 + src/mame/virtual.flt | 1 + src/mame/virtual.lst | 4 + 8 files changed, 886 insertions(+), 10 deletions(-) create mode 100644 scripts/target/mame/virtual.lua create mode 100644 src/mame/drivers/vgmplay.cpp create mode 100644 src/mame/virtual.flt create mode 100644 src/mame/virtual.lst diff --git a/scripts/target/mame/mame.lua b/scripts/target/mame/mame.lua index b7360486042..d58bfab4595 100644 --- a/scripts/target/mame/mame.lua +++ b/scripts/target/mame/mame.lua @@ -11,13 +11,16 @@ dofile("arcade.lua") dofile("mess.lua") +dofile("virtual.lua") function createProjects_mame_mame(_target, _subtarget) createProjects_mame_arcade(_target, _subtarget) createProjects_mame_mess(_target, _subtarget) + createProjects_mame_virtual(_target, _subtarget) end function linkProjects_mame_mame(_target, _subtarget) linkProjects_mame_arcade(_target, _subtarget) linkProjects_mame_mess(_target, _subtarget) + linkProjects_mame_virtual(_target, _subtarget) end diff --git a/scripts/target/mame/virtual.lua b/scripts/target/mame/virtual.lua new file mode 100644 index 00000000000..5bec4adb607 --- /dev/null +++ b/scripts/target/mame/virtual.lua @@ -0,0 +1,73 @@ +-- license:BSD-3-Clause +-- copyright-holders:MAMEdev Team + +--------------------------------------------------------------------------- +-- +-- virtual.lua +-- +-- Virtual target makefile +-- +--------------------------------------------------------------------------- + +-------------------------------------------------- +-- specify available CPU cores +-------------------------------------------------- + + +-------------------------------------------------- +-- specify available sound cores; some of these are +-- only for MAME and so aren't included +-------------------------------------------------- + + +-------------------------------------------------- +-- specify available video cores +-------------------------------------------------- + + +-------------------------------------------------- +-- specify available machine cores +-------------------------------------------------- + + +-------------------------------------------------- +-- specify available bus cores +-------------------------------------------------- + + +-------------------------------------------------- +-- this is the driver library that +-- comprise the virtual drivers +-------------------------------------------------- +function linkProjects_mame_virtual(_target, _subtarget) + links { + "virtual", + } +end + +function createVirtualProjects(_target, _subtarget, _name) + project (_name) + targetsubdir(_target .."_" .. _subtarget) + kind (LIBTYPE) + uuid (os.uuid("drv-" .. _target .."_" .. _subtarget .. "_" .._name)) + addprojectflags() + precompiledheaders() + + includedirs { + MAME_DIR .. "src/osd", + MAME_DIR .. "src/emu", + MAME_DIR .. "src/devices", + MAME_DIR .. "src/mame", + MAME_DIR .. "src/lib", + MAME_DIR .. "src/lib/util", + MAME_DIR .. "src/lib/netlist", + MAME_DIR .. "3rdparty", + } +end + +function createProjects_mame_virtual(_target, _subtarget) +createVirtualProjects(_target, _subtarget, "virtual") +files { + MAME_DIR .. "src/mame/drivers/vgmplay.cpp", +} +end diff --git a/src/devices/sound/segapcm.cpp b/src/devices/sound/segapcm.cpp index 555ee019b16..d0e7864dd1f 100644 --- a/src/devices/sound/segapcm.cpp +++ b/src/devices/sound/segapcm.cpp @@ -19,7 +19,7 @@ const device_type SEGAPCM = &device_creator; segapcm_device::segapcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : device_t(mconfig, SEGAPCM, "Sega PCM", tag, owner, clock, "segapcm", __FILE__), device_sound_interface(mconfig, *this), - m_rom(*this, DEVICE_SELF), + device_rom_interface(mconfig, *this, 21), m_ram(nullptr), m_bank(0), m_bankshift(0), @@ -35,7 +35,7 @@ segapcm_device::segapcm_device(const machine_config &mconfig, const char *tag, d void segapcm_device::device_start() { - int mask, rom_mask; + int mask; m_ram = std::make_unique(0x800); @@ -46,10 +46,7 @@ void segapcm_device::device_start() if (!mask) mask = BANK_MASK7 >> 16; - for(rom_mask = 1; rom_mask < m_rom.length(); rom_mask *= 2) { }; - rom_mask--; - - m_bankmask = mask & (rom_mask >> m_bankshift); + m_bankmask = mask & (0x1fffff >> m_bankshift); m_stream = stream_alloc(0, 2, clock() / 128); @@ -97,7 +94,7 @@ void segapcm_device::sound_stream_update(sound_stream &stream, stream_sample_t * /* only process active channels */ if (!(regs[0x86]&1)) { - const UINT8 *rom = m_rom + ((regs[0x86] & m_bankmask) << m_bankshift); + int offset = (regs[0x86] & m_bankmask) << m_bankshift; UINT32 addr = (regs[0x85] << 16) | (regs[0x84] << 8) | m_low[ch]; UINT32 loop = (regs[0x05] << 16) | (regs[0x04] << 8); UINT8 end = regs[6] + 1; @@ -120,7 +117,7 @@ void segapcm_device::sound_stream_update(sound_stream &stream, stream_sample_t * } /* fetch the sample */ - v = rom[(addr >> 8) & m_rom.mask()] - 0x80; + v = read_byte(offset + (addr >> 8)) - 0x80; /* apply panning and advance */ outputs[0][i] += v * (regs[2] & 0x7f); diff --git a/src/devices/sound/segapcm.h b/src/devices/sound/segapcm.h index 48474134b46..5861db66940 100644 --- a/src/devices/sound/segapcm.h +++ b/src/devices/sound/segapcm.h @@ -35,7 +35,8 @@ //************************************************************************** class segapcm_device : public device_t, - public device_sound_interface + public device_sound_interface, + public device_rom_interface { public: segapcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); @@ -55,7 +56,6 @@ protected: virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override; private: - required_region_ptr m_rom; std::unique_ptr m_ram; UINT8 m_low[16]; int m_bank; diff --git a/src/mame/drivers/vgmplay.cpp b/src/mame/drivers/vgmplay.cpp new file mode 100644 index 00000000000..4cd78fbac70 --- /dev/null +++ b/src/mame/drivers/vgmplay.cpp @@ -0,0 +1,794 @@ +// license:BSD-3-Clause +// copyright-holders: Olivier Galibert + +// A "virtual" driver to play vgm files +// Use with mame vgmplay -bitb file.vgm + +#include + +#include "emu.h" +#include "debugger.h" +#include "imagedev/bitbngr.h" + +#include "sound/2612intf.h" +#include "sound/ym2151.h" +#include "sound/segapcm.h" + +class vgmplay_device : public cpu_device +{ +public: + enum { + REG_SIZE = 0x00000000, + A_YM2612 = 0x00000010, + A_YM2151 = 0x00000020, + A_SEGAPCM = 0x00001000, + }; + + vgmplay_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + virtual void device_start() override; + virtual void device_reset() override; + + virtual UINT32 execute_min_cycles() const override; + virtual UINT32 execute_max_cycles() const override; + virtual UINT32 execute_input_lines() const override; + virtual void execute_run() override; + virtual void execute_set_input(int inputnum, int state) override; + + virtual const address_space_config *memory_space_config(address_spacenum spacenum = AS_0) const override; + + virtual void state_import(const device_state_entry &entry) override; + virtual void state_export(const device_state_entry &entry) override; + virtual void state_string_export(const device_state_entry &entry, std::string &str) const override; + + virtual UINT32 disasm_min_opcode_bytes() const override; + virtual UINT32 disasm_max_opcode_bytes() const override; + virtual offs_t disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) override; + + READ8_MEMBER(segapcm_rom_r); + +private: + struct rom_block { + offs_t start_address; + offs_t end_address; + std::unique_ptr data; + + rom_block(rom_block &&) = default; + rom_block(offs_t start, offs_t end, UINT8 d[]) { + start_address = start; + end_address = end; + data = d; + } + }; + + enum { RESET, RUN, DONE }; + + address_space_config m_file_config, m_io_config; + address_space *m_file, *m_io; + + int m_icount, m_state; + + UINT32 m_pc; + + std::list m_rom_blocks[0x80]; + UINT32 m_rom_masks[0x80]; + + UINT8 rom_r(UINT8 type, offs_t offset); + UINT32 handle_data_block(UINT32 address); + void blocks_clear(); +}; + +const device_type VGMPLAY = &device_creator; + +class vgmplay_state : public driver_device +{ +public: + vgmplay_state(const machine_config &mconfig, device_type type, const char *tag); + + virtual void machine_start() override; + + READ8_MEMBER(file_r); + READ8_MEMBER(file_size_r); + +private: + std::vector m_file_data; + required_device m_file; + required_device m_ym2612; + required_device m_ym2151; + required_device m_segapcm; + + UINT32 r32(int offset) const; +}; + +vgmplay_device::vgmplay_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : + cpu_device(mconfig, VGMPLAY, "VGM Player engine", tag, owner, clock, "vgmplay", __FILE__), + m_file_config("file", ENDIANNESS_LITTLE, 8, 32), + m_io_config("io", ENDIANNESS_LITTLE, 8, 32) +{ +} + +void vgmplay_device::device_start() +{ + m_icountptr = &m_icount; + m_file = &space(AS_PROGRAM); + m_io = &space(AS_IO); + + save_item(NAME(m_pc)); + + state_add(STATE_GENPC, "GENPC", m_pc).noshow(); + state_add(STATE_GENPCBASE, "GENPCBASE", m_pc).noshow(); +} + +void vgmplay_device::device_reset() +{ + m_pc = 0; + m_state = RESET; + blocks_clear(); +} + +UINT32 vgmplay_device::execute_min_cycles() const +{ + return 0; +} + +UINT32 vgmplay_device::execute_max_cycles() const +{ + return 65536; +} + +UINT32 vgmplay_device::execute_input_lines() const +{ + return 0; +} + +void vgmplay_device::blocks_clear() +{ + for(int i = 0; i < 128; i++) { + m_rom_blocks[i].clear(); + m_rom_masks[i] = 0; + } +} + +UINT32 vgmplay_device::handle_data_block(UINT32 address) +{ + UINT32 size = m_file->read_dword(m_pc+3); + UINT8 type = m_file->read_byte(m_pc+2); + if(type >= 0x80) { + UINT32 rs = m_file->read_dword(m_pc+7); + UINT32 start = m_file->read_dword(m_pc+11); + UINT8 *block = new UINT8[size - 8]; + for(UINT32 i=0; iread_byte(m_pc+15+i); + m_rom_blocks[type - 0x80].emplace_front(start, start+size-9, block); + + UINT32 mask = rs-1; + mask |= mask >> 1; + mask |= mask >> 2; + mask |= mask >> 4; + mask |= mask >> 8; + mask |= mask >> 16; + m_rom_masks[type - 0x80] = mask; + } else + logerror("ignored block size %x type %02x\n", size, type); + return 7+size; +} + +void vgmplay_device::execute_run() +{ + while(m_icount > 0) { + switch(m_state) { + case RESET: { + UINT32 size = m_io->read_dword(REG_SIZE); + if(!size) { + m_pc = 0; + m_state = DONE; + break; + } + UINT32 version = m_file->read_dword(8); + m_pc = version < 0x150 ? 0x40 : 0x34 + m_file->read_dword(0x34); + m_state = RUN; + break; + } + case RUN: { + if(machine().debug_flags & DEBUG_FLAG_ENABLED) + debugger_instruction_hook(this, m_pc); + UINT8 code = m_file->read_byte(m_pc); + switch(code) { + case 0x4f: + logerror("ignored psg 06\n"); + m_pc += 2; + break; + + case 0x50: + logerror("ignored psg\n"); + m_pc += 2; + break; + + case 0x52: + m_io->write_byte(A_YM2612+0, m_file->read_byte(m_pc+1)); + m_io->write_byte(A_YM2612+1, m_file->read_byte(m_pc+2)); + m_pc += 3; + break; + + case 0x53: + m_io->write_byte(A_YM2612+2, m_file->read_byte(m_pc+1)); + m_io->write_byte(A_YM2612+3, m_file->read_byte(m_pc+2)); + m_pc += 3; + break; + + case 0x54: + m_io->write_byte(A_YM2151+0, m_file->read_byte(m_pc+1)); + m_io->write_byte(A_YM2151+1, m_file->read_byte(m_pc+2)); + m_pc += 3; + break; + + case 0x61: { + UINT32 duration = m_file->read_word(m_pc+1); + m_icount -= duration; + m_pc += 3; + break; + } + + case 0x62: + m_icount -= 735; + m_pc++; + break; + + case 0x63: + m_icount -= 882; + m_pc++; + break; + + case 0x66: + m_state = DONE; + break; + + case 0x67: + m_pc += handle_data_block(m_pc); + break; + + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + m_icount -= 1+(code & 0xf); + m_pc += 1; + break; + + case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: + logerror("ignored ym2612 dac from databank\n"); + m_pc += 1; + m_icount -= code & 0xf; + break; + + case 0xc0: + m_io->write_byte(A_SEGAPCM + (m_file->read_word(m_pc+1) & 0x7ff), m_file->read_byte(m_pc+3)); + m_pc += 4; + break; + + case 0xe0: + logerror("ignored ym2612 offset\n"); + m_pc += 5; + break; + + default: + logerror("unhandled code %02x\n", code); + m_state = DONE; + m_icount = 0; + break; + } + break; + } + case DONE: { + static bool done = false; + if(!done) { + logerror("done\n"); + done = true; + } + if(machine().debug_flags & DEBUG_FLAG_ENABLED) + debugger_instruction_hook(this, m_pc); + m_icount = 0; + break; + } + } + } +} + +void vgmplay_device::execute_set_input(int inputnum, int state) +{ +} + +const address_space_config *vgmplay_device::memory_space_config(address_spacenum spacenum) const +{ + switch(spacenum) { + case AS_PROGRAM: return &m_file_config; + case AS_IO: return &m_io_config; + default: return nullptr; + } +} + +void vgmplay_device::state_import(const device_state_entry &entry) +{ +} + +void vgmplay_device::state_export(const device_state_entry &entry) +{ +} + +void vgmplay_device::state_string_export(const device_state_entry &entry, std::string &str) const +{ +} + +UINT32 vgmplay_device::disasm_min_opcode_bytes() const +{ + return 1; +} + +UINT32 vgmplay_device::disasm_max_opcode_bytes() const +{ + return 9; +} + +offs_t vgmplay_device::disasm_disassemble(char *buffer, offs_t pc, const UINT8 *oprom, const UINT8 *opram, UINT32 options) +{ + switch(oprom[0]) { + case 0x4f: + sprintf(buffer, "psg r06 = %02x", oprom[1]); + return 2 | DASMFLAG_SUPPORTED; + + case 0x50: + sprintf(buffer, "psg write %02x", oprom[1]); + return 2 | DASMFLAG_SUPPORTED; + + case 0x51: + sprintf(buffer, "ym2413 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0x52: + sprintf(buffer, "ym2612.0 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0x53: + sprintf(buffer, "ym2612.1 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0x54: + sprintf(buffer, "ym2151 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0x55: + sprintf(buffer, "ym2203 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0x56: + sprintf(buffer, "ym2608.0 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0x57: + sprintf(buffer, "ym2608.1 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0x58: + sprintf(buffer, "ym2610.0 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0x59: + sprintf(buffer, "ym2610.1 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0x5a: + sprintf(buffer, "ym3812 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0x5b: + sprintf(buffer, "ym3526 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0x5c: + sprintf(buffer, "y8950 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0x5d: + sprintf(buffer, "ymz280b r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0x5e: + sprintf(buffer, "ymf262.0 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0x5f: + sprintf(buffer, "ymf262.1 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0x61: { + UINT32 duration = oprom[1] | (oprom[2] << 8); + sprintf(buffer, "wait %d", duration); + return 3 | DASMFLAG_SUPPORTED; + } + + case 0x62: + sprintf(buffer, "wait 735"); + return 1 | DASMFLAG_SUPPORTED; + + case 0x63: + sprintf(buffer, "wait 882"); + return 1 | DASMFLAG_SUPPORTED; + + case 0x66: + sprintf(buffer, "end"); + return 1 | DASMFLAG_SUPPORTED; + + case 0x67: { + static const char *const basic_types[8] = { + "ym2612 pcm", + "rf5c68 pcm", + "rf5c164 pcm", + "pwm pcm", + "okim6258 adpcm", + "huc6280 pcm", + "scsp pcm", + "nes apu dpcm" + }; + + static const char *const rom_types[20] = { + "sega pcm rom", + "ym2608 delta-t rom", + "ym2610 adpcm rom", + "ym2610 delta-t rom", + "ymf278b rom", + "ymf271 rom", + "ymz280b rom", + "ymf278b rom", + "y8950 delta-t rom", + "multipcm rom", + "upd7759 rom", + "okim6295 rom", + "k054539 rom", + "c140 rom", + "k053260 rom", + "qsound rom", + "es5505/es5506 rom", + "x1-010 rom", + "c352 rom", + "ga20 rom" + }; + + static const char *const ram_types[3] = { + "rf5c68 ram", + "rf5c164 ram", + "nes apu ram" + }; + + static const char *const ram2_types[2] = { + "scsp ram", + "es5503 ram" + }; + + UINT8 type = oprom[2]; + UINT32 size = oprom[3] | (oprom[4] << 8) | (oprom[5] << 16) | (oprom[6] << 24); + if(type < 0x8) + sprintf(buffer, "data-block %x, %s", size, basic_types[type]); + else if(type < 0x40) + sprintf(buffer, "data-block %x, %02x", size, type); + else if(type < 0x48) + sprintf(buffer, "data-block %x comp., %s", size, basic_types[type & 0x3f]); + else if(type < 0x7f) + sprintf(buffer, "data-block %x comp., %02x", size, type & 0x3f); + else if(type < 0x80) + sprintf(buffer, "decomp-table %x, %02x/%02x", size, oprom[7], oprom[8]); + else if(type < 0x94) + sprintf(buffer, "data-block %x, %s", size, rom_types[type & 0x7f]); + else if(type < 0xc0) + sprintf(buffer, "data-block %x, rom %02x", size, type); + else if(type < 0x93) + sprintf(buffer, "data-block %x, %s", size, ram_types[type & 0x1f]); + else if(type < 0xe0) + sprintf(buffer, "data-block %x, ram %02x", size, type); + else if(type < 0xe2) + sprintf(buffer, "data-block %x, %s", size, ram2_types[type & 0x1f]); + else + sprintf(buffer, "data-block %x, ram %02x", size, type); + return (7+size) | DASMFLAG_SUPPORTED; + } + + case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: case 0x7c: case 0x7d: case 0x7e: case 0x7f: + sprintf(buffer, "wait %d", 1+(oprom[0] & 0x0f)); + return 1 | DASMFLAG_SUPPORTED; + + case 0x80: + sprintf(buffer, "ym2612.0 r2a = rom++"); + return 1 | DASMFLAG_SUPPORTED; + + case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: case 0x8c: case 0x8d: case 0x8e: case 0x8f: + sprintf(buffer, "ym2612.0 r2a = rom++; wait %d", oprom[0] & 0xf); + return 1 | DASMFLAG_SUPPORTED; + + case 0xa0: + sprintf(buffer, "ay8910 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0xb0: + sprintf(buffer, "rf5c68 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0xb1: + sprintf(buffer, "rf5c68 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0xb2: + sprintf(buffer, "pwm r%x = %03x", oprom[1] >> 4, oprom[2] | ((oprom[1] & 0xf) << 8)); + return 3 | DASMFLAG_SUPPORTED; + + case 0xb3: + sprintf(buffer, "dmg r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0xb4: + sprintf(buffer, "apu r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0xb5: + sprintf(buffer, "multipcm r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0xb6: + sprintf(buffer, "upd7759 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0xb7: + sprintf(buffer, "okim6258 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0xb8: + sprintf(buffer, "huc6280 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0xb9: + sprintf(buffer, "k053260 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0xba: + sprintf(buffer, "pokey r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0xbb: + sprintf(buffer, "rf5c68 r%02x = %02x", oprom[1], oprom[2]); + return 3 | DASMFLAG_SUPPORTED; + + case 0xc0: + sprintf(buffer, "segapcm %04x = %02x", oprom[1] | (oprom[2] << 8), oprom[3]); + return 4 | DASMFLAG_SUPPORTED; + + case 0xc1: + sprintf(buffer, "rf5c68 %04x = %02x", oprom[1] | (oprom[2] << 8), oprom[3]); + return 4 | DASMFLAG_SUPPORTED; + + case 0xc2: + sprintf(buffer, "rf5c163 %04x = %02x", oprom[1] | (oprom[2] << 8), oprom[3]); + return 4 | DASMFLAG_SUPPORTED; + + case 0xc3: + sprintf(buffer, "multipcm c%02x.off = %04x", oprom[1], oprom[2] | (oprom[3] << 8)); + return 4 | DASMFLAG_SUPPORTED; + + case 0xc4: + sprintf(buffer, "qsound %02x = %04x", oprom[3], oprom[2] | (oprom[1] << 8)); + return 4 | DASMFLAG_SUPPORTED; + + case 0xd0: + sprintf(buffer, "ymf278b r%02x.%02x = %02x", oprom[1], oprom[2], oprom[3]); + return 4 | DASMFLAG_SUPPORTED; + + case 0xd1: + sprintf(buffer, "ymf271 r%02x.%02x = %02x", oprom[1], oprom[2], oprom[3]); + return 4 | DASMFLAG_SUPPORTED; + + case 0xd2: + sprintf(buffer, "scc1 r%02x.%02x = %02x", oprom[1], oprom[2], oprom[3]); + return 4 | DASMFLAG_SUPPORTED; + + case 0xd3: + sprintf(buffer, "k054539 r%02x.%02x = %02x", oprom[1], oprom[2], oprom[3]); + return 4 | DASMFLAG_SUPPORTED; + + case 0xd4: + sprintf(buffer, "c140 r%02x.%02x = %02x", oprom[1], oprom[2], oprom[3]); + return 4 | DASMFLAG_SUPPORTED; + + case 0xe0: { + UINT32 off = oprom[1] | (oprom[2] << 8) | (oprom[3] << 16) | (oprom[4] << 24); + sprintf(buffer, "ym2612 offset = %x", off); + return 5 | DASMFLAG_SUPPORTED; + } + + default: + sprintf(buffer, "?? %02x", oprom[0]); + return 1 | DASMFLAG_SUPPORTED; + } +} + +UINT8 vgmplay_device::rom_r(UINT8 type, offs_t offset) +{ + logerror("rom_r %02x, %08x\n", type, offset); + return 0; +} + +READ8_MEMBER(vgmplay_device::segapcm_rom_r) +{ + return rom_r(0x80, offset); +} + +vgmplay_state::vgmplay_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_file(*this, "file"), + m_ym2612(*this, "ym2612"), + m_ym2151(*this, "ym2151"), + m_segapcm(*this, "segapcm") +{ +} + +UINT32 vgmplay_state::r32(int off) const +{ + if(off + 3 < int(m_file_data.size())) + return m_file_data[off] | (m_file_data[off+1] << 8) | (m_file_data[off+2] << 16) | (m_file_data[off+3] << 24); + return 0; +} + +void vgmplay_state::machine_start() +{ + UINT32 size = 0; + if(m_file->exists()) { + size = m_file->length(); + m_file_data.resize(size); + m_file->input(&m_file_data[0], size); + + // Decompress gzip-compressed files (aka vgz) + if(m_file_data[0] == 0x1f && m_file_data[1] == 0x8b) { + std::vector decomp; + int bs = m_file_data.size(); + decomp.resize(2*bs); + z_stream str; + str.zalloc = nullptr; + str.zfree = nullptr; + str.opaque = nullptr; + str.data_type = 0; + str.next_in = &m_file_data[0]; + str.avail_in = m_file_data.size(); + str.total_in = 0; + str.total_out = 0; + int err = inflateInit2(&str, 31); + if(err != Z_OK) { + logerror("gzip header but not a gzip file\n"); + m_file_data.clear(); + return; + } + do { + if(str.total_out >= decomp.size()) + decomp.resize(decomp.size() + bs); + str.next_out = &decomp[str.total_out]; + str.avail_out = decomp.size() - str.total_out; + err = inflate(&str, Z_SYNC_FLUSH); + } while(err == Z_OK); + if(err != Z_STREAM_END) { + logerror("broken gzip file\n"); + m_file_data.clear(); + return; + } + m_file_data.resize(str.total_out); + memcpy(&m_file_data[0], &decomp[0], str.total_out); + } + + if(m_file_data.size() < 0x40 || r32(0) != 0x206d6756) { + logerror("Not a vgm/vgz file\n"); + m_file_data.clear(); + return; + } + + UINT32 version = r32(8); + logerror("File version %x.%02x\n", version >> 8, version & 0xff); + if(r32(0x0c)) + logerror("Warning: file requests an unsupported SN76489\n"); + if(r32(0x10)) + logerror("Warning: file requests an unsupported YM2413\n"); + if(version <= 0x101 && r32(0x0c)) { + m_ym2612->set_unscaled_clock(r32(0x0c)); + m_ym2151->set_unscaled_clock(r32(0x0c)); + } + if(version >= 0x110 && r32(0x2c)) + m_ym2612->set_unscaled_clock(r32(0x2c)); + if(version >= 0x110 && r32(0x30)) + m_ym2151->set_unscaled_clock(r32(0x30)); + if(version >= 0x151 && r32(0x38)) + m_segapcm->set_unscaled_clock(r32(0x38)); + if(version >= 0x151 && r32(0x40)) + logerror("Warning: file requests an unsupported RF5C68\n"); + if(version >= 0x151 && r32(0x44)) + logerror("Warning: file requests an unsupported YM2203\n"); + if(version >= 0x151 && r32(0x48)) + logerror("Warning: file requests an unsupported YM2608\n"); + if(version >= 0x151 && r32(0x4c)) + logerror("Warning: file requests an unsupported %s\n", r32(0x4c) & 0x80000000 ? "YM2610B" : "YM2610"); + if(version >= 0x151 && r32(0x50)) + logerror("Warning: file requests an unsupported YM3812\n"); + if(version >= 0x151 && r32(0x54)) + logerror("Warning: file requests an unsupported YM3526\n"); + if(version >= 0x151 && r32(0x58)) + logerror("Warning: file requests an unsupported Y8950\n"); + if(version >= 0x151 && r32(0x5c)) + logerror("Warning: file requests an unsupported YMF262\n"); + if(version >= 0x151 && r32(0x60)) + logerror("Warning: file requests an unsupported YMF278B\n"); + if(version >= 0x151 && r32(0x64)) + logerror("Warning: file requests an unsupported YMF271\n"); + if(version >= 0x151 && r32(0x68)) + logerror("Warning: file requests an unsupported YMZ280B\n"); + if(version >= 0x151 && r32(0x6c)) + logerror("Warning: file requests an unsupported RF5C164\n"); + if(version >= 0x151 && r32(0x70)) + logerror("Warning: file requests an unsupported PWM\n"); + if(version >= 0x151 && r32(0x74)) + logerror("Warning: file requests an unsupported AY8910\n"); + } +} + +READ8_MEMBER(vgmplay_state::file_r) +{ + if(offset < m_file_data.size()) + return m_file_data[offset]; + return 0; +} + +READ8_MEMBER(vgmplay_state::file_size_r) +{ + UINT32 size = m_file_data.size(); + return size >> (8*offset); +} + +static INPUT_PORTS_START( vgmplay ) +INPUT_PORTS_END + +static ADDRESS_MAP_START( file_map, AS_PROGRAM, 8, vgmplay_state ) + AM_RANGE(0x00000000, 0xffffffff) AM_READ(file_r) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( soundchips_map, AS_IO, 8, vgmplay_state ) + AM_RANGE(vgmplay_device::REG_SIZE, vgmplay_device::REG_SIZE+3) AM_READ(file_size_r) + AM_RANGE(vgmplay_device::A_YM2612, vgmplay_device::A_YM2612+3) AM_DEVREADWRITE("ym2612", ym2612_device, read, write) + AM_RANGE(vgmplay_device::A_YM2151, vgmplay_device::A_YM2151+3) AM_DEVREADWRITE("ym2151", ym2151_device, read, write) + AM_RANGE(vgmplay_device::A_SEGAPCM, vgmplay_device::A_SEGAPCM+0x7ff) AM_DEVREADWRITE("segapcm", segapcm_device, sega_pcm_r, sega_pcm_w) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( segapcm_map, AS_0, 8, vgmplay_state ) + AM_RANGE(0, 0x1fffff) AM_DEVREAD("vgmplay", vgmplay_device, segapcm_rom_r) +ADDRESS_MAP_END + +static MACHINE_CONFIG_START( vgmplay, vgmplay_state ) + MCFG_CPU_ADD("vgmplay", VGMPLAY, 44100) + MCFG_CPU_PROGRAM_MAP( file_map ) + MCFG_CPU_IO_MAP( soundchips_map ) + + MCFG_DEVICE_ADD("file", BITBANGER, 0) + + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + + MCFG_SOUND_ADD("ym2612", YM2612, 7670454) + MCFG_SOUND_ROUTE(0, "lspeaker", 1) + MCFG_SOUND_ROUTE(1, "rspeaker", 1) + + MCFG_SOUND_ADD("ym2151", YM2151, 3579545) + MCFG_SOUND_ROUTE(0, "lspeaker", 1) + MCFG_SOUND_ROUTE(1, "rspeaker", 1) + + MCFG_SOUND_ADD("segapcm", SEGAPCM, 4000000) + MCFG_SEGAPCM_BANK(BANK_512) // Should be configurable for yboard... + MCFG_DEVICE_ADDRESS_MAP(AS_0, segapcm_map) + MCFG_SOUND_ROUTE(0, "lspeaker", 1) + MCFG_SOUND_ROUTE(1, "rspeaker", 1) +MACHINE_CONFIG_END + +ROM_START( vgmplay ) +ROM_END + +CONS( 2016, vgmplay, 0, 0, vgmplay, vgmplay, driver_device, 0, "MAME", "VGM player", 0) + diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 06fcad2cd1f..cb73fd2890f 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -37568,3 +37568,7 @@ ts1500 // Timex Sinclair 1500 zx80 // 1980 Sinclair ZX-80 zx81 // 1981 Sinclair ZX-81 zx97 // + +@source:vgmplay.cpp +vgmplay + diff --git a/src/mame/virtual.flt b/src/mame/virtual.flt new file mode 100644 index 00000000000..8373a776c00 --- /dev/null +++ b/src/mame/virtual.flt @@ -0,0 +1 @@ +vgmplay.cpp diff --git a/src/mame/virtual.lst b/src/mame/virtual.lst new file mode 100644 index 00000000000..27a3e40416c --- /dev/null +++ b/src/mame/virtual.lst @@ -0,0 +1,4 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert +@source:vgmplay.cpp +vgmplay