diff --git a/hash/gbcolor.xml b/hash/gbcolor.xml
index 1ebfbf1b9e5..40cf7239fa8 100644
--- a/hash/gbcolor.xml
+++ b/hash/gbcolor.xml
@@ -9993,9 +9993,9 @@ license:CC0
Keitai Denjuu Telefang - Power Version (Japan)
2000
Natsume
-
-
-
+
+
+
@@ -10005,11 +10005,10 @@ license:CC0
-
-
-
-
+
+
+
@@ -10017,17 +10016,47 @@ license:CC0
Keitai Denjuu Telefang - Speed Version (Japan)
2000
Natsume
-
-
-
+
+
+
-
-
+
+
-
+
+
+
+
+
+
+ Pokémon Jade Version
+ 200?
+ bootleg
+
+
+
+
+
+
+
+
+
+
+
+
+ Pokémon Vision Jade
+ 200?
+ bootleg
+
+
+
+
+
+
+
diff --git a/src/devices/bus/gameboy/carts.cpp b/src/devices/bus/gameboy/carts.cpp
index a1341314fc6..e43f62c96dc 100644
--- a/src/devices/bus/gameboy/carts.cpp
+++ b/src/devices/bus/gameboy/carts.cpp
@@ -51,6 +51,7 @@ char const *const GB_HUC1 = "rom_huc1";
char const *const GB_HUC3 = "rom_huc3";
char const *const GB_TAMA5 = "rom_tama5";
char const *const GB_CAMERA = "rom_camera";
+char const *const GB_TFANGBOOT = "rom_tfboot";
char const *const GB_SINTAX = "rom_sintax";
char const *const GB_CHONGWU = "rom_chong";
char const *const GB_LICHENG = "rom_licheng";
@@ -95,6 +96,7 @@ void gameboy_cartridges(device_slot_interface &device)
device.option_add_internal(slotoptions::GB_HUC1, GB_ROM_HUC1);
device.option_add_internal(slotoptions::GB_HUC3, GB_ROM_HUC3);
device.option_add_internal(slotoptions::GB_TAMA5, GB_ROM_TAMA5);
+ device.option_add_internal(slotoptions::GB_TFANGBOOT, GB_ROM_TFANGBOOT);
device.option_add_internal(slotoptions::GB_SINTAX, GB_ROM_SINTAX);
device.option_add_internal(slotoptions::GB_CHONGWU, GB_ROM_CHONGWU);
device.option_add_internal(slotoptions::GB_LICHENG, GB_ROM_LICHENG);
diff --git a/src/devices/bus/gameboy/carts.h b/src/devices/bus/gameboy/carts.h
index ddf1d174665..1a33a4d4a22 100644
--- a/src/devices/bus/gameboy/carts.h
+++ b/src/devices/bus/gameboy/carts.h
@@ -40,6 +40,7 @@ extern char const *const GB_CAMERA;
extern char const *const GB_HUC1;
extern char const *const GB_HUC3;
extern char const *const GB_TAMA5;
+extern char const *const GB_TFANGBOOT;
extern char const *const GB_SINTAX;
extern char const *const GB_CHONGWU;
extern char const *const GB_LICHENG;
diff --git a/src/devices/bus/gameboy/gbslot.cpp b/src/devices/bus/gameboy/gbslot.cpp
index 9cd95a59441..2203e2b94f9 100644
--- a/src/devices/bus/gameboy/gbslot.cpp
+++ b/src/devices/bus/gameboy/gbslot.cpp
@@ -734,6 +734,9 @@ std::optional probe_gbx_footer(std::string_view tag, util::random_
case gbxfile::TYPE_HUC3:
result = slotoptions::GB_HUC3;
break;
+ case gbxfile::TYPE_TFANGBOOT:
+ result = slotoptions::GB_TFANGBOOT;
+ break;
case gbxfile::TYPE_SINTAX:
result = slotoptions::GB_SINTAX;
break;
diff --git a/src/devices/bus/gameboy/gbxfile.h b/src/devices/bus/gameboy/gbxfile.h
index 2be34583ff0..11f0d09bcda 100644
--- a/src/devices/bus/gameboy/gbxfile.h
+++ b/src/devices/bus/gameboy/gbxfile.h
@@ -67,6 +67,7 @@ enum : u32
TYPE_MMM01 = 0x4d4d4d31, // 'MMM1'
TYPE_NEWGBCHK = 0x4e47484b, // 'NGHK'
TYPE_NTNEW = 0x4e544e00, // 'NTN\0'
+ TYPE_TFANGBOOT = 0x504b4a44, // 'PKJD'
TYPE_ROCKET = 0x524f434b, // 'ROCK'
TYPE_PLAIN = 0x524f4d00, // 'ROM\0'
TYPE_SACHEN1 = 0x53414d31, // 'SAM1'
diff --git a/src/devices/bus/gameboy/liebao.cpp b/src/devices/bus/gameboy/liebao.cpp
index f9bd8cafcc1..df261921546 100644
--- a/src/devices/bus/gameboy/liebao.cpp
+++ b/src/devices/bus/gameboy/liebao.cpp
@@ -114,7 +114,7 @@ void liebao_device::device_reset()
void liebao_device::enable_ram(offs_t offset, u8 data)
{
// TODO: how many bits are checked?
- bool const enable = 0x0a == (data & 0x0f);
+ bool const enable(0x0a == (data & 0x0f));
LOG(
"%s: Cartridge RAM %s\n",
machine().describe_context(),
diff --git a/src/devices/bus/gameboy/mbc.h b/src/devices/bus/gameboy/mbc.h
index 9dfedb31232..4cc03952fea 100644
--- a/src/devices/bus/gameboy/mbc.h
+++ b/src/devices/bus/gameboy/mbc.h
@@ -10,7 +10,6 @@
DECLARE_DEVICE_TYPE(GB_ROM_MBC1, device_gb_cart_interface)
DECLARE_DEVICE_TYPE(GB_ROM_MBC5, device_gb_cart_interface)
-DECLARE_DEVICE_TYPE(GB_ROM_MMM01, device_gb_cart_interface)
DECLARE_DEVICE_TYPE(GB_ROM_SINTAX, device_gb_cart_interface)
DECLARE_DEVICE_TYPE(GB_ROM_CHONGWU, device_gb_cart_interface)
DECLARE_DEVICE_TYPE(GB_ROM_LICHENG, device_gb_cart_interface)
diff --git a/src/devices/bus/gameboy/mbc3.cpp b/src/devices/bus/gameboy/mbc3.cpp
index bfead355999..f1971c749e4 100644
--- a/src/devices/bus/gameboy/mbc3.cpp
+++ b/src/devices/bus/gameboy/mbc3.cpp
@@ -47,6 +47,17 @@
-X------ Set to halt real-time clock.
-------X Bit 8 of days.
+ Telefang bootlegs have three additional registers:
+ 0x5 - Low value.
+ 0x6 - High value.
+ 0x7 - Command:
+ 0x11 Decrement low value.
+ 0x12 Decrement high value.
+ 0x41 Add high value to low value.
+ 0x42 Add low value to high value.
+ 0x51 Increment low value.
+ 0x52 Increment high value.
+
TODO:
* How are the static RAM bank outputs set when real-time clock registers
are selected?
@@ -54,6 +65,8 @@
* How do invalid seconds, minutes and hours values roll over?
* Does MBC30 really have eight ROM bank outputs? The one game using it
only uses seven.
+ * Does the bootleg Keitai Denjuu Telefang controller actually include a
+ real-time clock? No oscillator crystal is present.
***************************************************************************/
@@ -100,6 +113,13 @@ protected:
bool install_memory(std::string &message, unsigned highbits, unsigned lowbits) ATTR_COLD;
+protected:
+ u8 const rtc_select() const { return BIT(m_rtc_select, 3); }
+ u8 const rtc_register() const { return m_rtc_select & 0x07; }
+
+ virtual u8 read_rtc(address_space &space);
+ virtual void write_rtc(u8 data);
+
private:
static inline constexpr u8 RTC_MASK[]{ 0x3f, 0x3f, 0x1f, 0xff, 0xc1 };
static inline constexpr u8 RTC_ROLLOVER[]{ 0x3c, 0x3c, 0x18, 0x00, 0x00 };
@@ -110,8 +130,6 @@ private:
void bank_switch_fine(u8 data);
void select_ram_rtc(u8 data);
void latch_rtc(u8 data);
- u8 read_rtc(address_space &space);
- void write_rtc(u8 data);
u8 rtc_increment(unsigned index)
{
@@ -153,6 +171,25 @@ public:
};
+class tfboot_device : public mbc3_device_base
+{
+public:
+ tfboot_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+ virtual image_init_result load(std::string &message) override ATTR_COLD;
+
+protected:
+ virtual void device_start() override ATTR_COLD;
+ virtual void device_reset() override ATTR_COLD;
+
+ virtual u8 read_rtc(address_space &space) override;
+ virtual void write_rtc(u8 data) override;
+
+private:
+ u8 m_protection[2];
+};
+
+
//**************************************************************************
// mbc3_device_base
@@ -546,12 +583,12 @@ void mbc3_device_base::enable_ram_rtc(u8 data)
machine().describe_context());
m_view_ram.disable();
}
- else if (BIT(m_rtc_select, 3))
+ else if (rtc_select())
{
LOG(
"%s: RTC register %u enabled\n",
machine().describe_context(),
- m_rtc_select & 0x07);
+ rtc_register());
m_view_ram.select(1);
}
else
@@ -611,7 +648,7 @@ void mbc3_device_base::latch_rtc(u8 data)
u8 mbc3_device_base::read_rtc(address_space &space)
{
- u8 const reg(m_rtc_select & 0x07);
+ u8 const reg(rtc_register());
if (std::size(m_rtc_regs[1]) > reg)
{
LOG(
@@ -634,7 +671,7 @@ u8 mbc3_device_base::read_rtc(address_space &space)
void mbc3_device_base::write_rtc(u8 data)
{
- u8 const reg(m_rtc_select & 0x07);
+ u8 const reg(rtc_register());
if (std::size(m_rtc_regs[0]) > reg)
{
LOG(
@@ -712,10 +749,107 @@ image_init_result mbc30_device::load(std::string &message)
return image_init_result::PASS;
}
+
+
+//**************************************************************************
+// tfboot_device
+//**************************************************************************
+
+tfboot_device::tfboot_device(
+ machine_config const &mconfig,
+ char const *tag,
+ device_t *owner,
+ u32 clock) :
+ mbc3_device_base(mconfig, GB_ROM_TFANGBOOT, tag, owner, clock),
+ m_protection{ 0U, 0U }
+{
+}
+
+
+image_init_result tfboot_device::load(std::string &message)
+{
+ if (!install_memory(message, 2, 7))
+ return image_init_result::FAIL;
+ else
+ return image_init_result::PASS;
+}
+
+
+void tfboot_device::device_start()
+{
+ mbc3_device_base::device_start();
+
+ save_item(NAME(m_protection));
+}
+
+
+void tfboot_device::device_reset()
+{
+ mbc3_device_base::device_reset();
+
+ m_protection[0] = 0U;
+ m_protection[1] = 0U;
+}
+
+
+u8 tfboot_device::read_rtc(address_space &space)
+{
+ u8 const reg(rtc_register());
+ switch (reg)
+ {
+ case 0x05:
+ case 0x06:
+ return m_protection[BIT(reg, 0)];
+ case 0x07:
+ return 0U;
+ default:
+ return mbc3_device_base::read_rtc(space);
+ }
+}
+
+
+void tfboot_device::write_rtc(u8 data)
+{
+ u8 const reg(rtc_register());
+ switch (reg)
+ {
+ case 0x05:
+ case 0x06:
+ m_protection[BIT(reg, 0)] = data;
+ break;
+ case 0x07:
+ LOG("%s: Protection command 0x%02X\n", machine().describe_context(), data);
+ switch (data)
+ {
+ case 0x11:
+ case 0x12:
+ --m_protection[BIT(data, 0)];
+ break;
+ case 0x41:
+ case 0x42:
+ m_protection[BIT(data, 0)] += m_protection[BIT(~data, 0)];
+ break;
+ case 0x51:
+ case 0x52:
+ ++m_protection[BIT(data, 0)];
+ break;
+ default:
+ logerror(
+ "%s: Unknown protection command 0x%02X\n",
+ machine().describe_context(),
+ data);
+ }
+ break;
+ default:
+ mbc3_device_base::write_rtc(data);
+ }
+}
+
} // anonymous namespace
} // namespace bus::gameboy
-DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_MBC3, device_gb_cart_interface, bus::gameboy::mbc3_device, "gb_rom_mbc3", "Game Boy MBC3 Cartridge")
-DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_MBC30, device_gb_cart_interface, bus::gameboy::mbc30_device, "gb_rom_mbc30", "Game Boy MBC30 Cartridge")
+DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_MBC3, device_gb_cart_interface, bus::gameboy::mbc3_device, "gb_rom_mbc3", "Game Boy MBC3 Cartridge")
+DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_MBC30, device_gb_cart_interface, bus::gameboy::mbc30_device, "gb_rom_mbc30", "Game Boy MBC30 Cartridge")
+DEFINE_DEVICE_TYPE_PRIVATE(GB_ROM_TFANGBOOT, device_gb_cart_interface, bus::gameboy::tfboot_device, "gb_rom_tfboot", "Game Boy Telefang bootleg Cartridge")
diff --git a/src/devices/bus/gameboy/mbc3.h b/src/devices/bus/gameboy/mbc3.h
index e039262fc3d..ffa35d26a36 100644
--- a/src/devices/bus/gameboy/mbc3.h
+++ b/src/devices/bus/gameboy/mbc3.h
@@ -13,7 +13,8 @@
#include "slot.h"
-DECLARE_DEVICE_TYPE(GB_ROM_MBC3, device_gb_cart_interface)
-DECLARE_DEVICE_TYPE(GB_ROM_MBC30, device_gb_cart_interface)
+DECLARE_DEVICE_TYPE(GB_ROM_MBC3, device_gb_cart_interface)
+DECLARE_DEVICE_TYPE(GB_ROM_MBC30, device_gb_cart_interface)
+DECLARE_DEVICE_TYPE(GB_ROM_TFANGBOOT, device_gb_cart_interface)
#endif // MAME_BUS_GAMEBOY_MBC3_H
diff --git a/src/devices/bus/gameboy/ntnew.cpp b/src/devices/bus/gameboy/ntnew.cpp
index 6df635c6ad0..7ea72a2d9f4 100644
--- a/src/devices/bus/gameboy/ntnew.cpp
+++ b/src/devices/bus/gameboy/ntnew.cpp
@@ -125,7 +125,7 @@ void ntnew_device::enable_ram(offs_t offset, u8 data)
}
// TODO: how many bits are checked?
- bool const enable = 0x0a == (data & 0x0f);
+ bool const enable(0x0a == (data & 0x0f));
LOG(
"%s: Cartridge RAM %s\n",
machine().describe_context(),