diff --git a/hash/megadriv.xml b/hash/megadriv.xml
index fe835c0d57da2..69fc784bbe14f 100644
--- a/hash/megadriv.xml
+++ b/hash/megadriv.xml
@@ -31246,30 +31246,6 @@ Notice that these are not working on real hardware due to bugged code with VDP i
-
- Radica: Volume 1 (USA)
- 2004
- Radica Games ~ Sega
-
-
-
-
-
-
-
-
-
- Radica: Street Fighter Pack (Euro)
- 2004
- Radica Games ~ Capcom
-
-
-
-
-
-
-
-
Tom Clown (USA)
1993
@@ -32901,6 +32877,4 @@ This dump is either a bad dump or a wrongly patched one.
-
-
diff --git a/scripts/target/mame/arcade.lua b/scripts/target/mame/arcade.lua
index 891c98089dfa7..9620917c985f7 100644
--- a/scripts/target/mame/arcade.lua
+++ b/scripts/target/mame/arcade.lua
@@ -3182,8 +3182,8 @@ files {
MAME_DIR .. "src/mame/machine/segabb.h",
MAME_DIR .. "src/mame/machine/megadriv.cpp",
MAME_DIR .. "src/mame/includes/megadriv.h",
- MAME_DIR .. "src/mame/drivers/megadrvb.cpp",
- MAME_DIR .. "src/mame/includes/megadrvb.h",
+ MAME_DIR .. "src/mame/drivers/megadriv_acbl.cpp",
+ MAME_DIR .. "src/mame/includes/megadriv_acbl.h",
MAME_DIR .. "src/mame/drivers/megaplay.cpp",
MAME_DIR .. "src/mame/drivers/megatech.cpp",
MAME_DIR .. "src/mame/drivers/calcune.cpp",
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index aaf93bdba8fa7..6bedc7cfbd25c 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -2836,6 +2836,8 @@ files {
MAME_DIR .. "src/mame/machine/gdrom.h",
MAME_DIR .. "src/mame/drivers/megadriv.cpp",
MAME_DIR .. "src/mame/includes/megadriv.h",
+ MAME_DIR .. "src/mame/drivers/megadriv_rad.cpp",
+ MAME_DIR .. "src/mame/includes/megadriv_rad.h",
MAME_DIR .. "src/mame/drivers/segapico.cpp",
MAME_DIR .. "src/mame/drivers/sega_sawatte.cpp",
MAME_DIR .. "src/mame/drivers/segapm.cpp",
@@ -3367,6 +3369,10 @@ files {
MAME_DIR .. "src/mame/drivers/crvision.cpp",
MAME_DIR .. "src/mame/includes/crvision.h",
MAME_DIR .. "src/mame/drivers/geniusiq.cpp",
+ MAME_DIR .. "src/mame/drivers/vtech_unk1.cpp",
+ MAME_DIR .. "src/mame/drivers/vtech_unk2.cpp",
+ MAME_DIR .. "src/mame/drivers/vtech_eu3a12.cpp",
+ MAME_DIR .. "src/mame/drivers/iqunlim.cpp",
MAME_DIR .. "src/mame/drivers/laser3k.cpp",
MAME_DIR .. "src/mame/drivers/lcmate2.cpp",
MAME_DIR .. "src/mame/drivers/pc4.cpp",
@@ -3614,7 +3620,12 @@ files {
MAME_DIR .. "src/mame/drivers/qvt201.cpp",
MAME_DIR .. "src/mame/drivers/qvt6800.cpp",
MAME_DIR .. "src/mame/drivers/rd100.cpp",
- MAME_DIR .. "src/mame/drivers/radicasi.cpp",
+ MAME_DIR .. "src/mame/drivers/rad_eu3a14.cpp",
+ MAME_DIR .. "src/mame/drivers/rad_eu3a05.cpp",
+ MAME_DIR .. "src/mame/audio/rad_eu3a05.cpp",
+ MAME_DIR .. "src/mame/audio/rad_eu3a05.h",
+ MAME_DIR .. "src/mame/machine/rad_eu3a05gpio.cpp",
+ MAME_DIR .. "src/mame/machine/rad_eu3a05gpio.h",
MAME_DIR .. "src/mame/drivers/rvoice.cpp",
MAME_DIR .. "src/mame/drivers/sacstate.cpp",
MAME_DIR .. "src/mame/drivers/sartorius.cpp",
diff --git a/src/emu/xtal.cpp b/src/emu/xtal.cpp
index 2679feaae8090..3ef6b52b8589a 100644
--- a/src/emu/xtal.cpp
+++ b/src/emu/xtal.cpp
@@ -225,7 +225,7 @@ const double XTAL::known_xtals[] = {
21'052'600, /* NEC PC-98xx pixel clock */
21'060'000, /* HP 264x display clock (60 Hz configuration) */
21'254'400, /* TeleVideo 970 132-column display clock */
- 21'281'370, /* Radica Tetris */
+ 21'281'370, /* Radica Tetris (PAL) */
21'300'000,
21'477'272, /* BMC bowling, some Data East 90's games, Vtech Socrates; (6x NTSC subcarrier) */
22'000'000,
diff --git a/src/mame/arcade.flt b/src/mame/arcade.flt
index 2d3e1c54bb976..0a72644156338 100644
--- a/src/mame/arcade.flt
+++ b/src/mame/arcade.flt
@@ -694,7 +694,7 @@ mcr68.cpp
meadows.cpp
meadwttl.cpp
mediagx.cpp
-megadrvb.cpp
+megadriv_acbl.cpp
megaphx.cpp
megaplay.cpp
megasys1.cpp
diff --git a/src/mame/audio/rad_eu3a05.cpp b/src/mame/audio/rad_eu3a05.cpp
new file mode 100644
index 0000000000000..b77e1bdc6a452
--- /dev/null
+++ b/src/mame/audio/rad_eu3a05.cpp
@@ -0,0 +1,266 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+// Format not understood, it is not OKI ADPCM or IMA ADPCM, maybe something more basic?
+
+#include "emu.h"
+#include "rad_eu3a05.h"
+
+DEFINE_DEVICE_TYPE(RADICA6502_SOUND, radica6502_sound_device, "radica6502sound", "Radica 6502 Sound")
+
+radica6502_sound_device::radica6502_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, RADICA6502_SOUND, tag, owner, clock)
+ , device_sound_interface(mconfig, *this)
+ , m_stream(nullptr)
+ , m_space_read_cb(*this)
+{
+}
+
+void radica6502_sound_device::device_start()
+{
+ m_space_read_cb.resolve_safe(0);
+ m_stream = stream_alloc(0, 1, 8000);
+}
+
+void radica6502_sound_device::device_reset()
+{
+ for (int i = 0; i < 6; i++)
+ {
+ m_sound_byte_address[i] = 0;
+ m_sound_byte_len[i] = 0;
+ m_sound_current_nib_pos[i] = 0;
+ }
+
+ m_isstopped = 0x3f;
+}
+
+//-------------------------------------------------
+// sound_stream_update - handle a stream update
+//-------------------------------------------------
+
+void radica6502_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+{
+ // reset the output stream
+ memset(outputs[0], 0, samples * sizeof(*outputs[0]));
+
+ int outpos = 0;
+ // loop while we still have samples to generate
+ while (samples-- != 0)
+ {
+ for (int channel = 0; channel < 6; channel++)
+ {
+ if (!((m_isstopped >> channel) & 1))
+ {
+ //logerror("m_isstopped %02x channel %d is active %08x %06x\n", m_isstopped, channel, m_sound_byte_address[channel], m_sound_current_nib_pos[channel]);
+
+ int readoffset = m_sound_byte_address[channel] + (m_sound_current_nib_pos[channel] / 2);
+
+ int nibble = m_space_read_cb(readoffset);
+
+ nibble = nibble >> ((m_sound_current_nib_pos[channel] & 1) ? 0 : 4);
+ nibble &= 0x0f;
+
+ // it's actually some form of ADPCM? but apparently NOT the OKI ADPCM
+ if (nibble & 0x08)
+ nibble -= 0x10;
+
+ outputs[0][outpos] += nibble * 0x100;
+
+ m_sound_current_nib_pos[channel]++;
+
+ if (m_sound_current_nib_pos[channel] >= m_sound_byte_len[channel] * 2)
+ {
+ m_sound_current_nib_pos[channel] = 0;
+ m_isstopped |= (1 << channel);
+
+ // maybe should generate an interrupt with vector
+ // ffb8, ffbc, ffc0, ffc4, ffc8, or ffcc depending on which channel finished??
+ }
+ }
+ else
+ {
+ //logerror("m_isstopped %02x channel %d is NOT active %08x %06x\n", m_isstopped, channel, m_sound_byte_address[channel], m_sound_current_nib_pos[channel]);
+ }
+ }
+ outpos++;
+ }
+}
+
+
+void radica6502_sound_device::handle_sound_addr_w(int which, int offset, uint8_t data)
+{
+ switch (offset)
+ {
+ case 0x00:
+ m_sound_byte_address[which] = (m_sound_byte_address[which] & 0xffff00) | (data<<0);
+ logerror("%s: sound_0 (%d) write lo address %02x (real address is now %08x)\n", machine().describe_context(), which, data, m_sound_byte_address[which]);
+ break;
+
+ case 0x01:
+ m_sound_byte_address[which] = (m_sound_byte_address[which] & 0xff00ff) | (data<<8);
+ logerror("%s: sound_0 (%d) write md address %02x (real address is now %08x)\n", machine().describe_context(), which, data, m_sound_byte_address[which]);
+ break;
+
+ case 0x02:
+ m_sound_byte_address[which] = (m_sound_byte_address[which] & 0x00ffff) | (data<<16);
+ logerror("%s: sound_0 (%d) write hi address %02x (real address is now %08x)\n", machine().describe_context(), which, data, m_sound_byte_address[which]);
+ break;
+ }
+}
+
+uint8_t radica6502_sound_device::handle_sound_addr_r(int which, int offset)
+{
+ switch (offset)
+ {
+ case 0x00:
+ logerror("%s: sound_0 (%d) read lo address\n", machine().describe_context(), which);
+ return (m_sound_byte_address[which]>>0) & 0xff;
+
+ case 0x01:
+ logerror("%s: sound_0 (%d) read mid address\n", machine().describe_context(), which);
+ return (m_sound_byte_address[which]>>8) & 0xff;
+
+ case 0x02:
+ logerror("%s: sound_0 (%d) read hi address\n", machine().describe_context(), which);
+ return (m_sound_byte_address[which]>>16) & 0xff;
+ }
+
+ return 0x00;
+}
+
+WRITE8_MEMBER(radica6502_sound_device::radicasi_sound_addr_w)
+{
+ m_stream->update();
+ handle_sound_addr_w(offset / 3, offset % 3, data);
+}
+
+READ8_MEMBER(radica6502_sound_device::radicasi_sound_addr_r)
+{
+ m_stream->update();
+ return handle_sound_addr_r(offset / 3, offset % 3);
+}
+
+void radica6502_sound_device::handle_sound_size_w(int which, int offset, uint8_t data)
+{
+ switch (offset)
+ {
+ case 0x00:
+ m_sound_byte_len[which] = (m_sound_byte_len[which] & 0xffff00) | (data<<0);
+ logerror("%s: sound_1 (%d) write lo size %02x (real size is now %08x)\n", machine().describe_context(), which, data, m_sound_byte_len[which]);
+ break;
+
+ case 0x01:
+ m_sound_byte_len[which] = (m_sound_byte_len[which] & 0xff00ff) | (data<<8);
+ logerror("%s: sound_1 (%d) write md size %02x (real size is now %08x)\n", machine().describe_context(), which, data, m_sound_byte_len[which]);
+ break;
+
+ case 0x02:
+ m_sound_byte_len[which] = (m_sound_byte_len[which] & 0x00ffff) | (data<<16);
+ logerror("%s: sound_1 (%d) write hi size %02x (real size is now %08x)\n", machine().describe_context(), which, data, m_sound_byte_len[which]);
+ break;
+ }
+}
+
+uint8_t radica6502_sound_device::handle_sound_size_r(int which, int offset)
+{
+ switch (offset)
+ {
+ case 0x00:
+ logerror("%s: sound_1 (%d) read lo size\n", machine().describe_context(), which);
+ return (m_sound_byte_len[which]>>0) & 0xff;
+
+ case 0x01:
+ logerror("%s: sound_1 (%d) read mid size\n", machine().describe_context(), which);
+ return (m_sound_byte_len[which]>>8) & 0xff;
+
+ case 0x02:
+ logerror("%s: sound_1 (%d) read hi size\n", machine().describe_context(), which);
+ return (m_sound_byte_len[which]>>16) & 0xff;
+ }
+
+ return 0x00;
+}
+
+WRITE8_MEMBER(radica6502_sound_device::radicasi_sound_size_w)
+{
+ m_stream->update();
+ handle_sound_size_w(offset / 3, offset % 3, data);
+}
+
+READ8_MEMBER(radica6502_sound_device::radicasi_sound_size_r)
+{
+ m_stream->update();
+ return handle_sound_size_r(offset / 3, offset % 3);
+}
+
+READ8_MEMBER(radica6502_sound_device::radicasi_sound_trigger_r)
+{
+ m_stream->update();
+
+ logerror("%s: sound read from trigger?\n", machine().describe_context());
+ return m_sound_trigger;
+}
+
+
+WRITE8_MEMBER(radica6502_sound_device::radicasi_sound_trigger_w)
+{
+ m_stream->update();
+
+ logerror("%s: sound write to trigger? %02x\n", machine().describe_context(), data);
+ m_sound_trigger = data;
+
+ for (int i = 0; i < 6; i++)
+ {
+ int bit = (data >> i) & 1;
+
+ if (bit)
+ handle_sound_trigger(i);
+ }
+
+ if (data & 0xc0)
+ logerror(" UNEXPECTED BITS SET");
+}
+
+/* this is read/written with the same individual bits for each channel as the trigger
+ maybe related to interrupts? */
+READ8_MEMBER(radica6502_sound_device::radicasi_sound_unk_r)
+{
+ logerror("%s: radicasi_sound_unk_r\n", machine().describe_context());
+ // don't think this reads back what was written probably a status of something instead?
+ return 0x00; //m_sound_unk;
+}
+
+WRITE8_MEMBER(radica6502_sound_device::radicasi_sound_unk_w)
+{
+ logerror("%s: radicasi_sound_unk_w %02x\n", machine().describe_context(), data);
+
+ for (int i = 0; i < 6; i++)
+ {
+ int bit = (data >> i) & 1;
+
+ if (bit)
+ logerror("(unknown operation on channel %d)\n", i);
+ }
+
+ m_sound_unk = data;
+
+ if (data & 0xc0)
+ logerror(" UNEXPECTED BITS SET");
+}
+
+void radica6502_sound_device::handle_sound_trigger(int which)
+{
+ logerror("Triggering operation on channel (%d) with params %08x %08x\n", which, m_sound_byte_address[which], m_sound_byte_len[which]);
+
+ m_sound_current_nib_pos[which] = 0;
+ m_isstopped &= ~(1 << which);
+}
+
+
+READ8_MEMBER(radica6502_sound_device::radicasi_50a8_r)
+{
+ m_stream->update();
+
+ logerror("%s: radicasi_50a8_r\n", machine().describe_context());
+ return m_isstopped;
+}
diff --git a/src/mame/audio/rad_eu3a05.h b/src/mame/audio/rad_eu3a05.h
new file mode 100644
index 0000000000000..55a98a6e18367
--- /dev/null
+++ b/src/mame/audio/rad_eu3a05.h
@@ -0,0 +1,64 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+#ifndef MAME_AUDIO_RAD_EU3A05_H
+#define MAME_AUDIO_RAD_EU3A05_H
+
+#define MCFG_RADICA6502_SOUND_SPACE_READ_CB(_devcb) \
+ devcb = &radica6502_sound_device::set_space_read_callback(*device, DEVCB_##_devcb);
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> radica6502_sound_device
+
+class radica6502_sound_device : public device_t, public device_sound_interface
+{
+public:
+ radica6502_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ template static devcb_base &set_space_read_callback(device_t &device, Object &&cb) { return downcast(device).m_space_read_cb.set_callback(std::forward