From 1c7705709dc238fee2facc78ae5cd7ba500a9d7b Mon Sep 17 00:00:00 2001 From: ValleyBell Date: Sat, 1 Jan 2022 05:00:23 +0100 Subject: r8: add PCM cards (#9047) --- hash/r8_card.xml | 64 +++++++++ hash/u110_card.xml | 25 ++++ src/mame/drivers/roland_cm32p.cpp | 28 ++++ src/mame/drivers/roland_r8.cpp | 295 ++++++++++++++++++++++++++++++++++---- 4 files changed, 385 insertions(+), 27 deletions(-) create mode 100644 hash/r8_card.xml diff --git a/hash/r8_card.xml b/hash/r8_card.xml new file mode 100644 index 00000000000..9ac5af3f6e9 --- /dev/null +++ b/hash/r8_card.xml @@ -0,0 +1,64 @@ + + + + + + + SN-R8-01 Contemporary Percussion + 1989 + Roland + + + + + + + + SN-R8-02 Jazz Brush + 1989 + Roland + + + + + + + diff --git a/hash/u110_card.xml b/hash/u110_card.xml index babace4334c..2a197a4e4b4 100644 --- a/hash/u110_card.xml +++ b/hash/u110_card.xml @@ -12,6 +12,31 @@ Undumped cards: -> see https://www.playkeyboardnow.com/Roland_D70_Soundbanks/page63/index.html Release dates were taken from http://www.rolandmuseum.de/z_syn_wc.php + + +address/data line scrambling (same as SN-R8): + + address data +external internal external internal + A0 - - - A0 D0 - - - D2 + A1 - - - A5 D1 - - - D7 + A2 - - - A4 D2 - - - D6 + A3 - - - A6 D3 - - - D4 + A4 - - - A1 D4 - - - D1 + A5 - - - A2 D5 - - - D3 + A6 - - - A3 D6 - - - D0 + A7 - - - A15 D7 - - - D5 + A8 - - - A13 + A9 - - - A10 + A10 - - - A14 + A11 - - - A7 + A12 - - - A12 + A13 - - - A11 + A14 - - - A16 + A15 - - - A9 + A16 - - - A8 + A17 - - - A17 + A18 - - - A18 --> diff --git a/src/mame/drivers/roland_cm32p.cpp b/src/mame/drivers/roland_cm32p.cpp index cefe4efe729..70d74112453 100644 --- a/src/mame/drivers/roland_cm32p.cpp +++ b/src/mame/drivers/roland_cm32p.cpp @@ -117,6 +117,34 @@ Parts: |-----------------------------------------------------------------------| +PCM ROM address/data line scrambling: + + address data +external internal external internal + A0 - - - A0 D0 - - - D2 + A1 - - - A5 D1 - - - D7 + A2 - - - A4 D2 - - - D6 + A3 - - - A6 D3 - - - D4 + A4 - - - A1 D4 - - - D1 + A5 - - - A2 D5 - - - D3 + A6 - - - A3 D6 - - - D0 + A7 - - - A8 D7 - - - D5 + A8 - - - A10 + A9 - - - A13 + A10 - - - A9 + A11 - - - A7 + A12 - - - A11 + A13 - - - A12 + A14 - - - A16 + A15 - - - A14 + A16 - - - A15 + A17 - - - A17 + A18 - - - A18 + +Line scramling of A0..A6 and D0..D7 matches the SN-U110 cards. +For A7..A16 they changed the scrambling. + + PCM ROM Tables -------------- Sample Table (address: 0x00100) diff --git a/src/mame/drivers/roland_r8.cpp b/src/mame/drivers/roland_r8.cpp index 9a04f0464bf..eb20bd49efa 100644 --- a/src/mame/drivers/roland_r8.cpp +++ b/src/mame/drivers/roland_r8.cpp @@ -1,48 +1,234 @@ // license:BSD-3-Clause -// copyright-holders:AJR +// copyright-holders:AJR,Valley Bell /**************************************************************************** Skeleton driver for Roland R-8 drum machine. ****************************************************************************/ +/* +PCM Card Sample Table Format +---------------------------- +Note: 2-byte values are stored in Little Endian. + +General Layout +-------------- +Pos Len Description + 80 01 card ID (00 for SN-R8-01, 01 for SN-R8-02, etc.) + 81 01 number of tones + 82 0E padding (byte 0xFF) + 90 70 tone offsets, 2 bytes per offset, relative to 0x100, each value points to the start of a "tone" definition + 100 500 tone list + 600 200 demo song header? + 800 800 ?? + 1000 2000 demo song data? + 3000 7D000 sample data + +Tone List (address: 0x100) +--------- +Pos Len Description +00 08 tone name +08 01 ?? (always 0x8F) +09 01 ?? +0A 01 frequency (0xE0 == 44100 Hz) +0B 02 ?? +0C 02 sample A bank/flags + sample cards: + Bit 10 (0x0400) = bank (0 = card offsets 0x00000..0x3FFFF, 1 = card offsets 0x40000..0x7FFFF) + R8 internal ROM: + Bit 10 (0x0400) = bank bit 0 (0 = offsets 0x00000..0x3FFFF, 1 = offsets 0x40000..0x7FFFF) + Bit 12 (0x1000) = bank bit 1 (0 = offsets 0x00000..0x7FFFF, 1 = offsets 0x80000..0xFFFFF) + Bits 14-15 (0xC000) - play/loop mode + 0 = normal loop + 1 = no loop? (not used) + 2 = ping-pong 1? (forwards, backwards, forwards, backwards, ...) + 3 = ping-pong 2? (backwards, forwards, backwards, forwards, ...) + -> when this is used, then the start address is usually set to (end address) or (end address+1) +0E 02 sample A start address (high word, i.e. address bits 2..17) +10 02 sample A start address, fraction (2.14 fixed point, i.e. 1 byte = 0x4000) +12 02 sample A loop address (high word) +14 02 sample A end address (high word) +16 02 ?? +18 02 ?? +1A 02 ?? +1C 02 ?? +1E 02 sample B bank and flags? +20 02 sample B start address (high word) +22 02 sample B start address, fraction +24 02 sample B loop address (high word) +26 02 sample B end address (high word) +28 02 ?? +2A 02 ?? +2C 02 ?? +2E 02 ?? +-> 30h bytes per entry + +"sample A" is what is heard. The use for "sample B" is unknown. +The 8 unknwon consecutive bytes (0x16..0x1D and 0x28..0x2F) are probably related to the envelope generation. + + +R8/R8M internal tone list offsets: 0x018C10 +R8/R8M internal tone list data: 0x018CA0 +R8 mkII doesn't seem to store the tone list in the program ROM. + +*/ + #include "emu.h" #include "cpu/upd78k/upd78k2.h" #include "machine/nvram.h" #include "sound/rolandpcm.h" +#include "bus/generic/slot.h" +#include "bus/generic/carts.h" #include "speaker.h" -class roland_r8_state : public driver_device +// PCM card address line scrambling +#define UNSCRAMBLE_ADDR_EXT(_offset) \ + bitswap<19>(_offset,18,17, 8, 9,16,11,12, 7,14,10,13,15, 3, 2, 1, 6, 4, 5, 0) + +#define UNSCRAMBLE_DATA(_data) \ + bitswap<8>(_data,1,2,7,3,5,0,4,6) + +// PCM card offsets in PCM chip memory space +// Right now this is an assumption based on the existing sample tables and wasn't confirmed with the firmware yet. +static const offs_t PCMCARD_SIZE = 0x080000; // 512 KB +static const std::array PCMCARD_OFFSETS = {0x080000, 0x180000, 0x280000}; + +class roland_r8_base_state : public driver_device { public: - roland_r8_state(const machine_config &mconfig, device_type type, const char *tag) + roland_r8_base_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") , m_pcm(*this, "pcm") { } - void r8(machine_config &config); - void r8m(machine_config &config); - void r8mk2(machine_config &config); + void r8_common(machine_config &config); + void init_r8(); -private: +protected: void mk1_map(address_map &map); void mk2_map(address_map &map); + image_init_result pcmrom_load(generic_slot_device* pcmcard, int card_id, device_image_interface &image); + void pcmrom_unload(int card_id); + void descramble_rom_external(u8* dst, const u8* src); + required_device m_maincpu; required_device m_pcm; + //required_device m_ramcard; // TODO }; +class roland_r8_state : public roland_r8_base_state +{ +public: + roland_r8_state(const machine_config &mconfig, device_type type, const char *tag) + : roland_r8_base_state(mconfig, type, tag) + , m_pcmcard(*this, "pcmcard") + { + } -void roland_r8_state::mk1_map(address_map &map) + void r8(machine_config &config); + +private: + DEVICE_IMAGE_LOAD_MEMBER(pcmcard_load) { return pcmrom_load(m_pcmcard, 0, image); } + DEVICE_IMAGE_UNLOAD_MEMBER(pcmcard_unload) { pcmrom_unload(0); } + + required_device m_pcmcard; +}; + +class roland_r8m_state : public roland_r8_base_state +{ +public: + roland_r8m_state(const machine_config &mconfig, device_type type, const char *tag) + : roland_r8_base_state(mconfig, type, tag) + , m_pcmcards(*this, "pcmcard%u", 0U) + { + } + + void r8m(machine_config &config); + +private: + DEVICE_IMAGE_LOAD_MEMBER(pcmcard0_load) { return pcmrom_load(m_pcmcards[0], 0, image); } + DEVICE_IMAGE_UNLOAD_MEMBER(pcmcard0_unload) { pcmrom_unload(0); } + DEVICE_IMAGE_LOAD_MEMBER(pcmcard1_load) { return pcmrom_load(m_pcmcards[1], 1, image); } + DEVICE_IMAGE_UNLOAD_MEMBER(pcmcard1_unload) { pcmrom_unload(1); } + DEVICE_IMAGE_LOAD_MEMBER(pcmcard2_load) { return pcmrom_load(m_pcmcards[2], 2, image); } + DEVICE_IMAGE_UNLOAD_MEMBER(pcmcard2_unload) { pcmrom_unload(2); } + + required_device_array m_pcmcards; +}; + +class roland_r8mk2_state : public roland_r8_base_state +{ +public: + roland_r8mk2_state(const machine_config &mconfig, device_type type, const char *tag) + : roland_r8_base_state(mconfig, type, tag) + , m_pcmcard(*this, "pcmcard") + { + } + + void r8mk2(machine_config &config); + +private: + DEVICE_IMAGE_LOAD_MEMBER(pcmcard_load) { return pcmrom_load(m_pcmcard, 0, image); } + DEVICE_IMAGE_UNLOAD_MEMBER(pcmcard_unload) { pcmrom_unload(0); } + + required_device m_pcmcard; +}; + + +image_init_result roland_r8_base_state::pcmrom_load(generic_slot_device* pcmcard, int card_id, device_image_interface &image) +{ + uint32_t size = pcmcard->common_get_size("rom"); + if (size > PCMCARD_SIZE) + { + image.seterror(image_error::INVALIDIMAGE, "Invalid size: Only up to 512K is supported"); + return image_init_result::FAIL; + } + + pcmcard->rom_alloc(PCMCARD_SIZE, GENERIC_ROM8_WIDTH, ENDIANNESS_LITTLE); + pcmcard->common_load_rom(pcmcard->get_rom_base(), size, "rom"); + u8* base = pcmcard->get_rom_base(); + if (size < PCMCARD_SIZE) + { + uint32_t mirror = (1 << (31 - count_leading_zeros_32(size))); + if (mirror < 0x020000) // due to how address descrambling works, we can currently only do mirroring for 128K pages + mirror = 0x020000; + for (uint32_t ofs = mirror; ofs < PCMCARD_SIZE; ofs += mirror) + memcpy(base + ofs, base, mirror); + } + + offs_t pcm_addr = PCMCARD_OFFSETS[card_id]; + u8* src = static_cast(memregion("pcmorg")->base()); + u8* dst = static_cast(memregion("pcm")->base()); + memcpy(&src[pcm_addr], base, PCMCARD_SIZE); + // descramble PCM card ROM + descramble_rom_external(&dst[pcm_addr], &src[pcm_addr]); + //pcmard_loaded[card_id] = true; + + return image_init_result::PASS; +} + +void roland_r8_base_state::pcmrom_unload(int card_id) +{ + u8* src = static_cast(memregion("pcmorg")->base()); + u8* dst = static_cast(memregion("pcm")->base()); + offs_t pcm_addr = PCMCARD_OFFSETS[card_id]; + memset(&src[pcm_addr], 0xFF, PCMCARD_SIZE); + memset(&dst[pcm_addr], 0xFF, PCMCARD_SIZE); + //pcmard_loaded[card_id] = false; +} + + +void roland_r8_base_state::mk1_map(address_map &map) { map(0x00000, 0x1ffff).rom().region("maincpu", 0); map(0x20000, 0x27fff).ram().share("nvram"); map(0x70000, 0x7001f).rw(m_pcm, FUNC(mb87419_mb87420_device::read), FUNC(mb87419_mb87420_device::write)); } -void roland_r8_state::mk2_map(address_map &map) +void roland_r8_base_state::mk2_map(address_map &map) { map(0x00000, 0x1ffff).rom().region("maincpu", 0); map(0x20000, 0x27fff).ram().share("nvram1"); @@ -55,7 +241,7 @@ static INPUT_PORTS_START(r8) INPUT_PORTS_END -void roland_r8_state::r8(machine_config &config) +void roland_r8_base_state::r8_common(machine_config &config) { UPD78210(config, m_maincpu, 12_MHz_XTAL); m_maincpu->set_addrmap(AS_PROGRAM, &roland_r8_state::mk1_map); @@ -70,23 +256,44 @@ void roland_r8_state::r8(machine_config &config) MB87419_MB87420(config, m_pcm, 33.8688_MHz_XTAL); //m_pcm->int_callback().set_inputline(m_maincpu, upd78k2_device::INTP1_LINE); - m_pcm->set_device_rom_tag("wavedata"); + m_pcm->set_device_rom_tag("pcm"); m_pcm->add_route(0, "lspeaker", 1.0); m_pcm->add_route(1, "rspeaker", 1.0); } -void roland_r8_state::r8m(machine_config &config) +void roland_r8_state::r8(machine_config &config) +{ + r8_common(config); + + GENERIC_CARTSLOT(config, m_pcmcard, generic_romram_plain_slot, "r8_card", "bin"); + m_pcmcard->set_device_load(FUNC(roland_r8_state::pcmcard_load)); + m_pcmcard->set_device_unload(FUNC(roland_r8_state::pcmcard_unload)); + + SOFTWARE_LIST(config, "card_list").set_original("r8_card"); +} + +void roland_r8m_state::r8m(machine_config &config) { - r8(config); + r8_common(config); UPD78213(config.replace(), m_maincpu, 12_MHz_XTAL); - m_maincpu->set_addrmap(AS_PROGRAM, &roland_r8_state::mk1_map); + m_maincpu->set_addrmap(AS_PROGRAM, &roland_r8m_state::mk1_map); + + for (auto& pcmcard : m_pcmcards) + GENERIC_CARTSLOT(config, pcmcard, generic_romram_plain_slot, "r8_card", "bin"); + m_pcmcards[0]->set_device_load(FUNC(roland_r8m_state::pcmcard0_load)); + m_pcmcards[0]->set_device_unload(FUNC(roland_r8m_state::pcmcard0_unload)); + m_pcmcards[1]->set_device_load(FUNC(roland_r8m_state::pcmcard1_load)); + m_pcmcards[1]->set_device_unload(FUNC(roland_r8m_state::pcmcard1_unload)); + m_pcmcards[2]->set_device_load(FUNC(roland_r8m_state::pcmcard2_load)); + m_pcmcards[2]->set_device_unload(FUNC(roland_r8m_state::pcmcard2_unload)); + SOFTWARE_LIST(config, "card_list").set_original("r8_card"); } -void roland_r8_state::r8mk2(machine_config &config) +void roland_r8mk2_state::r8mk2(machine_config &config) { UPD78213(config, m_maincpu, 12_MHz_XTAL); - m_maincpu->set_addrmap(AS_PROGRAM, &roland_r8_state::mk2_map); + m_maincpu->set_addrmap(AS_PROGRAM, &roland_r8mk2_state::mk2_map); NVRAM(config, "nvram1", nvram_device::DEFAULT_ALL_0); // SRM20256LC-10 + battery NVRAM(config, "nvram2", nvram_device::DEFAULT_ALL_0); // SRM20256LC-10 + battery @@ -99,9 +306,37 @@ void roland_r8_state::r8mk2(machine_config &config) MB87419_MB87420(config, m_pcm, 33.8688_MHz_XTAL); //m_pcm->int_callback().set_inputline(m_maincpu, upd78k2_device::INTP1_LINE); - m_pcm->set_device_rom_tag("wavedata"); + m_pcm->set_device_rom_tag("pcm"); m_pcm->add_route(0, "lspeaker", 1.0); m_pcm->add_route(1, "rspeaker", 1.0); + + GENERIC_CARTSLOT(config, m_pcmcard, generic_romram_plain_slot, "r8_card", "bin"); + m_pcmcard->set_device_load(FUNC(roland_r8mk2_state::pcmcard_load)); + m_pcmcard->set_device_unload(FUNC(roland_r8mk2_state::pcmcard_unload)); + SOFTWARE_LIST(config, "card_list").set_original("r8_card"); +} + +void roland_r8_base_state::init_r8() +{ + u8* src = static_cast(memregion("pcmorg")->base()); + u8* dst = static_cast(memregion("pcm")->base()); + + for (offs_t addr = 0; addr < memregion("pcmorg")->bytes(); addr += 0x100000) + { + // TODO: descramble internal ROMs + memcpy(&dst[addr + 0x00000], &src[addr + 0x00000], 0x80000); + // descramble PCM card ROMs + descramble_rom_external(&dst[addr + 0x80000], &src[addr + 0x80000]); + } +} + +void roland_r8_base_state::descramble_rom_external(u8* dst, const u8* src) +{ + for (offs_t srcpos = 0x00; srcpos < PCMCARD_SIZE; srcpos ++) + { + offs_t dstpos = UNSCRAMBLE_ADDR_EXT(srcpos); + dst[dstpos] = UNSCRAMBLE_DATA(src[srcpos]); + } } @@ -109,31 +344,37 @@ ROM_START(r8) ROM_REGION(0x20000, "maincpu", 0) ROM_LOAD("roland r-8_2.02_27c010.bin", 0x00000, 0x20000, CRC(45d0f64f) SHA1(55f0831db74cbdeae20cd7f1ff28af27dafba9b9)) - ROM_REGION(0x100000, "wavedata", ROMREGION_ERASE00) + ROM_REGION(0x200000, "pcmorg", ROMREGION_ERASE00) // ROMs before descrambling ROM_LOAD("r15179929-mn234000rle.ic30", 0x000000, 0x080000, NO_DUMP) - ROM_LOAD("r15179930-mn234000rlf.ic31", 0x080000, 0x080000, NO_DUMP) + // 0x80000..0xFFFFF is reserved for PCM cards, according to the sample list + ROM_LOAD("r15179930-mn234000rlf.ic31", 0x100000, 0x080000, NO_DUMP) + ROM_REGION(0x200000, "pcm", ROMREGION_ERASE00) // ROMs after descrambling ROM_END ROM_START(r8m) ROM_REGION(0x20000, "maincpu", 0) ROM_LOAD("rolandr8mv104.bin", 0x00000, 0x20000, CRC(5e95e2f6) SHA1(b4e1a8f15f72a9db9aa8fd41ee3c3ebd10460587)) - ROM_REGION(0x100000, "wavedata", ROMREGION_ERASE00) // same ROMs as R-8 assumed + ROM_REGION(0x400000, "pcmorg", ROMREGION_ERASE00) // ROMs before descrambling (must be large enough to allow for 3 PCM cards at offsets 0.5M, 1.5M and 2.5M) + // same ROMs as R-8 assumed ROM_LOAD("r15179929-mn234000rle.bin", 0x000000, 0x080000, NO_DUMP) - ROM_LOAD("r15179930-mn234000rlf.bin", 0x080000, 0x080000, NO_DUMP) + // 0x80000..0xFFFFF is reserved for PCM cards, according to the sample list + ROM_LOAD("r15179930-mn234000rlf.bin", 0x100000, 0x080000, NO_DUMP) + ROM_REGION(0x400000, "pcm", ROMREGION_ERASE00) // ROMs after descrambling ROM_END ROM_START(r8mk2) ROM_REGION(0x20000, "maincpu", 0) ROM_LOAD("roland r8 mkii eprom v1.0.3.bin", 0x00000, 0x20000, CRC(128a9a0c) SHA1(94bd8c76efe270754219f2899f31b62fc4f9060d)) - ROM_REGION(0x200000, "wavedata", ROMREGION_ERASE00) + ROM_REGION(0x400000, "pcmorg", ROMREGION_ERASE00) // ROMs before descrambling ROM_LOAD("r15209440-upd27c8001eacz-025.ic30", 0x000000, 0x080000, NO_DUMP) - ROM_LOAD("r15209441-upd27c8001eacz-026.ic31", 0x080000, 0x080000, NO_DUMP) - ROM_LOAD("r15209442-upd27c8001eacz-027.ic82", 0x100000, 0x080000, NO_DUMP) + ROM_LOAD("r15209441-upd27c8001eacz-026.ic31", 0x100000, 0x080000, NO_DUMP) + ROM_LOAD("r15209442-upd27c8001eacz-027.ic82", 0x200000, 0x080000, NO_DUMP) + ROM_REGION(0x400000, "pcm", ROMREGION_ERASE00) // ROMs after descrambling ROM_END -SYST(1989, r8, 0, 0, r8, r8, roland_r8_state, empty_init, "Roland", "R-8 Human Rhythm Composer (v2.02)", MACHINE_IS_SKELETON) -SYST(1990, r8m, r8, 0, r8m, r8, roland_r8_state, empty_init, "Roland", "R-8M Total Percussion Sound Module (v1.04)", MACHINE_IS_SKELETON) -SYST(1992, r8mk2, 0, 0, r8mk2, r8, roland_r8_state, empty_init, "Roland", "R-8 Mk II Human Rhythm Composer (v1.0.3)", MACHINE_IS_SKELETON) +SYST(1989, r8, 0, 0, r8, r8, roland_r8_state, init_r8, "Roland", "R-8 Human Rhythm Composer (v2.02)", MACHINE_IS_SKELETON) +SYST(1990, r8m, r8, 0, r8m, r8, roland_r8m_state, init_r8, "Roland", "R-8M Total Percussion Sound Module (v1.04)", MACHINE_IS_SKELETON) +SYST(1992, r8mk2, 0, 0, r8mk2, r8, roland_r8mk2_state, init_r8, "Roland", "R-8 Mk II Human Rhythm Composer (v1.0.3)", MACHINE_IS_SKELETON) -- cgit v1.2.3