// license:BSD-3-Clause
// copyright-holders:Angelo Salese
/****************************************************************************
Sealy HW running on VRender0+ SoC
driver by Angelo Salese, based off original crystal.cpp by ElSemi
TODO:
- HY04 protection (controls tile RNG, 8bpp colors, a few program flow bits)
- 8bpp colors are washed, data from flash ROMs is XORed with contents
of NVRAM area 0x1400070b-80f in menghong, might be shared with
HY04 as well.
- EEPROM hookup;
- extract password code when entering test mode in-game (assuming the
0x485 workaround isn't enough);
=============================================================================
Crazy Dou Di Zhu II
Sealy, 2006
PCB Layout
----------
070405-fd-VER1.2
|--------------------------------------|
| PAL 27C322.U36 |
| BATTERY|
| M59PW1282 62256 14.31818MHz |
| W9864G66 |
| |
|J VRENDERZERO+ |
|A W9864G66 |
|M W9864G66 |
|M 8MHz |
|A HY04 0260F8A |
| 28.63636MHz |
| |
| VR1 TLDA1311 |
| TDA1519|
| 18WAY VOL 10WAY |
|--------------------------------------|
Notes:
0260F8A - unknown TQFP44
HY04 - rebadged DIP8 PIC - type unknown *
W9864G66 - Winbond 64MBit DRAM
M59PW1282 - ST Microelectronics 128MBit SOP44 FlashROM.
This is two 64MB SOP44 ROMs in one package
* The pins are:
1 ground
2 nothing
3 data (only active for 1/4 second when the playing cards or "PASS" shows in game next to each player)
4 nothing
5 nothing
6 clock
7 +5V (could be VPP for programming voltage)
8 +5V
=====
Meng Hong Lou (Dream of the Red Chamber)
Sealy, 2004?
Red PCB, very similar to crzyddz2
****************************************************************************/
#include "emu.h"
#include "cpu/se3208/se3208.h"
#include "machine/ds1302.h"
#include "machine/nvram.h"
#include "machine/eepromser.h"
#include "machine/vrender0.h"
#include "machine/timer.h"
#include "emupal.h"
#include <algorithm>
class menghong_state : public driver_device
{
public:
menghong_state(const machine_config &mconfig, device_type type, const char *tag) :
driver_device(mconfig, type, tag),
m_workram(*this, "workram"),
m_flash(*this, "flash"),
m_mainbank(*this, "mainbank"),
m_maincpu(*this, "maincpu"),
m_vr0soc(*this, "vr0soc"),
// m_nvram(*this, "nvram"),
m_ds1302(*this, "rtc"),
m_eeprom(*this, "eeprom"),
m_prot_data(*this, "pic_data")
{ }
void crzyddz2(machine_config &config);
void menghong(machine_config &config);
private:
/* memory pointers */
required_shared_ptr<uint32_t> m_workram;
optional_region_ptr<uint32_t> m_flash;
optional_memory_bank m_mainbank;
/* devices */
required_device<se3208_device> m_maincpu;
required_device<vrender0soc_device> m_vr0soc;
// required_device<nvram_device> m_nvram;
required_device<ds1302_device> m_ds1302;
optional_device<eeprom_serial_93cxx_device> m_eeprom;
required_region_ptr <uint8_t> m_prot_data;
uint32_t m_Bank;
uint32_t m_maxbank;
uint32_t m_FlashCmd;
DECLARE_WRITE32_MEMBER(Banksw_w);
DECLARE_READ32_MEMBER(FlashCmd_r);
DECLARE_WRITE32_MEMBER(FlashCmd_w);
DECLARE_READ32_MEMBER(crzyddz2_key_r);
IRQ_CALLBACK_MEMBER(icallback);
virtual void machine_start() override;
virtual void machine_reset() override;
void menghong_mem(address_map &map);
void crzyddz2_mem(address_map &map);
// PIO
DECLARE_READ32_MEMBER(PIOldat_r);
uint32_t m_PIO;
DECLARE_WRITE32_MEMBER(crzyddz2_PIOldat_w);
DECLARE_READ32_MEMBER(crzyddz2_PIOedat_r);
uint8_t m_crzyddz2_prot;
DECLARE_READ8_MEMBER(menghong_shared_r);
DECLARE_WRITE8_MEMBER(menghong_shared_w);
DECLARE_READ8_MEMBER(crzyddz2_shared_r);
DECLARE_WRITE8_MEMBER(crzyddz2_shared_w);
uint8_t *m_sharedram;
};
IRQ_CALLBACK_MEMBER(menghong_state::icallback)
{
return m_vr0soc->irq_callback();
}
WRITE32_MEMBER(menghong_state::Banksw_w)
{
m_Bank = (data >> 1) & 7;
m_mainbank->set_entry(m_Bank);
}
READ32_MEMBER(menghong_state::FlashCmd_r)
{
if ((m_FlashCmd & 0xff) == 0xff)
{
if (m_Bank < m_maxbank)
{
uint32_t *ptr = (uint32_t*)(m_mainbank->base());
return ptr[0];
}
else
return 0xffffffff;
}
if ((m_FlashCmd & 0xff) == 0x90)
{
if (m_Bank < m_maxbank)
return 0x00180089; //Intel 128MBit
else
return 0xffffffff;
}
return 0;
}
WRITE32_MEMBER(menghong_state::FlashCmd_w)
{
m_FlashCmd = data;
}
// Crazy Dou Di Zhu II
// To do: HY04 (pic?) protection, 93C46 hookup
READ8_MEMBER(menghong_state::menghong_shared_r)
{
return m_sharedram[offset];
}
WRITE8_MEMBER(menghong_state::menghong_shared_w)
{
m_sharedram[offset] = data;
if (offset == 0x2a0)
{
if (data == 0x09)
{
// enables game settings by pressing start on password screen
m_sharedram[0x485] = 0x02;
// start at 0x140071b, up to 0x806, rolls back at 0x70c
// we conveniently use an handcrafted ROM here, created by guessing colors from
// transparencies and shading.
// This will be useful for comparison when the actual PIC data will be extracted.
for (int i=0;i<0x100;i++)
m_sharedram[i+0x70c] = m_prot_data[i];
// MCU also has a part in providing RNG
// hold service1 while selecting makes the user select "a set" (location in NVRAM tbd)
// 0x14005ca player 1 tiles
// 0x14005d9 player 1 discard pond
// 0x14005f9 available tiles
// 0x14005a5 cpu tiles
// 0x14005b4 cpu discard pond
}
}
}
READ8_MEMBER(menghong_state::crzyddz2_shared_r)
{
return m_sharedram[offset];
}
WRITE8_MEMBER(menghong_state::crzyddz2_shared_w)
{
m_sharedram[offset] = data;
// State machine is unconfirmed
if (offset == 0x7e3)
{
switch(data)
{
case 0x00:
m_sharedram[0x650] = 0x00; // prints 93c46 error otherwise
m_sharedram[0x651] = 0x03; // PC=2012188
break;
case 0xbb:
// this actually affects color again, game checksums the NVRAM contents
// at PC=0x2011f9a, expecting a value of 0x7ebe otherwise locks up
// after Sealy logo. Every single value is added to the routine and left
// shifted by 1 (including the two values above)
for(int i=0;i<0x3f;i++)
m_sharedram[i+0x652] = 0xff;
m_sharedram[0x691] = 0x9b;
break;
// additional locking protection is also applied with RNG feature
// PC=0x2036756 tight loops if R1=0
}
}
}
READ32_MEMBER(menghong_state::PIOldat_r)
{
return m_PIO;
}
WRITE32_MEMBER(menghong_state::crzyddz2_PIOldat_w)
{
COMBINE_DATA(&m_PIO);
//uint32_t RST = data & 0x01000000;
//uint32_t CLK = data & 0x02000000;
//uint32_t DAT = data & 0x10000000;
// m_eeprom->cs_write(RST ? 1 : 0);
// m_eeprom->di_write(DAT ? 1 : 0);
// m_eeprom->clk_write(CLK ? 1 : 0);
if (ACCESSING_BITS_8_15)
{
int mux = (m_PIO >> 8) & 0x1f;
if (mux == 0x1f)
{
m_crzyddz2_prot = ((m_PIO >> 8) & 0xc0) ^ 0x40;
logerror("%s: PIO = %08x, prot = %02x\n", machine().describe_context(), m_PIO, m_crzyddz2_prot);
}
}
}
READ32_MEMBER(menghong_state::crzyddz2_PIOedat_r)
{
return 0;//m_eeprom->do_read();
}
READ32_MEMBER(menghong_state::crzyddz2_key_r)
{
static const char *const key_names[] = { "KEY0", "KEY1", "KEY2", "KEY3", "KEY4" };
int mux = (m_PIO >> 8) & 0x1f;
uint8_t data = 0x3f;
for (int i = 0; i < sizeof(key_names)/sizeof(key_names[0]); ++i)
if (!BIT(mux,i))
data = ioport(key_names[i])->read();
/*
crzyddz2 in out
00 40
40 00
c0 80
*/
// menghong Sealy logo pal offset is at 0x3ea7400, relevant code is at 2086034
// m_crzyddz2_prot = (m_PIO >> 8) & 0xc0) ^ 0x40;
m_crzyddz2_prot = (machine().rand() & 0xc0);
return 0xffffff00 | data | m_crzyddz2_prot;
}
void menghong_state::menghong_mem(address_map &map)
{
map(0x00000000, 0x003fffff).rom().nopw();
map(0x01280000, 0x01280003).w(FUNC(menghong_state::Banksw_w));
// map(0x01400000, 0x0140ffff).ram().share("nvram");
map(0x01400000, 0x0140ffff).rw(FUNC(menghong_state::menghong_shared_r), FUNC(menghong_state::menghong_shared_w));
map(0x01500000, 0x01500003).portr("P1_P2");
map(0x01500004, 0x01500007).r(FUNC(menghong_state::crzyddz2_key_r));
map(0x01500008, 0x0150000b).portr("SYSTEM");
map(0x01800000, 0x01ffffff).m(m_vr0soc, FUNC(vrender0soc_device::regs_map));
map(0x01802004, 0x01802007).rw(FUNC(menghong_state::PIOldat_r), FUNC(menghong_state::crzyddz2_PIOldat_w));
map(0x01802008, 0x0180200b).r(FUNC(menghong_state::crzyddz2_PIOedat_r));
map(0x02000000, 0x027fffff).ram().share("workram");
map(0x03000000, 0x04ffffff).m(m_vr0soc, FUNC(vrender0soc_device::audiovideo_map));
map(0x05000000, 0x05ffffff).bankr("mainbank");
map(0x05000000, 0x05000003).rw(FUNC(menghong_state::FlashCmd_r), FUNC(menghong_state::FlashCmd_w));
}
void menghong_state::crzyddz2_mem(address_map &map)
{
menghong_mem(map);
map(0x01400000, 0x0140ffff).rw(FUNC(menghong_state::crzyddz2_shared_r), FUNC(menghong_state::crzyddz2_shared_w));
}
void menghong_state::machine_start()
{
m_sharedram = auto_alloc_array_clear(machine(), uint8_t, 0x10000);
if (m_mainbank)
{
m_maxbank = (m_flash) ? m_flash.bytes() / 0x1000000 : 0;
uint8_t *dummy_region = auto_alloc_array(machine(), uint8_t, 0x1000000);
std::fill_n(&dummy_region[0], 0x1000000, 0xff); // 0xff Filled at Unmapped area
uint8_t *ROM = (m_flash) ? (uint8_t *)&m_flash[0] : dummy_region;
for (int i = 0; i < 8; i++)
{
if ((i < m_maxbank))
m_mainbank->configure_entry(i, ROM + i * 0x1000000);
else
m_mainbank->configure_entry(i, dummy_region);
}
}
save_item(NAME(m_Bank));
save_item(NAME(m_FlashCmd));
save_item(NAME(m_PIO));
}
void menghong_state::machine_reset()
{
m_Bank = 0;
m_mainbank->set_entry(m_Bank);
m_FlashCmd = 0xff;
m_crzyddz2_prot = 0x00;
}
static INPUT_PORTS_START(crzyddz2)
PORT_START("P1_P2") // 1500002 & 1500000
PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) // up
PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) // down (next secret code)
PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) // left (inc secret code)
PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) // right (dec secret code)
PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON1 ) // A
PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON2 ) // B
PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_BUTTON3 ) // C (bet)
PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_BUTTON4 ) // D
PORT_BIT( 0x0000ff00, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x00010000, IP_ACTIVE_LOW, IPT_START1 ) // start (secret code screen)
PORT_BIT( 0x00020000, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_NAME("Operator Mode")
PORT_BIT( 0x00040000, IP_ACTIVE_LOW, IPT_SERVICE ) // .. 1 (secret code screen / service mode)
PORT_BIT( 0x00080000, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_BIT( 0x00100000, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x00200000, IP_ACTIVE_LOW, IPT_SERVICE2 ) // not service mode
PORT_BIT( 0x00400000, IP_ACTIVE_LOW, IPT_SERVICE3 ) PORT_NAME("Clear RAM")
PORT_BIT( 0x00800000, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0xff000000, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_START("SYSTEM")
PORT_BIT( 0x0000ffff, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_DIPNAME( 0x010000, 0x010000, "DSWA" )
PORT_DIPSETTING( 0x010000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x000000, DEF_STR( On ) )
PORT_DIPNAME( 0x020000, 0x020000, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x020000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x000000, DEF_STR( On ) )
PORT_DIPNAME( 0x040000, 0x040000, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x040000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x000000, DEF_STR( On ) )
PORT_DIPNAME( 0x080000, 0x080000, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x080000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x000000, DEF_STR( On ) )
PORT_DIPNAME( 0x100000, 0x100000, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x100000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x000000, DEF_STR( On ) )
PORT_DIPNAME( 0x200000, 0x200000, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x200000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x000000, DEF_STR( On ) )
PORT_DIPNAME( 0x400000, 0x400000, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x400000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x000000, DEF_STR( On ) )
PORT_DIPNAME( 0x800000, 0x800000, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x800000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x000000, DEF_STR( On ) )
PORT_BIT( 0xff000000, IP_ACTIVE_LOW, IPT_UNKNOWN )
// 1500004 (multiplexed by 1802005)
PORT_START("KEY0")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_MAHJONG_A )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_MAHJONG_E )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_MAHJONG_I )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_MAHJONG_M )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_KAN ) // kan
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_MAHJONG_FLIP_FLOP ) // start?
PORT_START("KEY1")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_MAHJONG_B )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_MAHJONG_F )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_MAHJONG_J )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_MAHJONG_N )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_REACH ) // ?
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_MAHJONG_BET ) // ? + C
PORT_START("KEY2")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_MAHJONG_C )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_MAHJONG_G )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_MAHJONG_K )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_MAHJONG_CHI ) // chi
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_SCORE ) // ?
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN ) // nothing
PORT_START("KEY3")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_MAHJONG_D )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_MAHJONG_H )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_MAHJONG_L )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_MAHJONG_PON ) // pon
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNKNOWN ) // nothing
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN ) // nothing
PORT_START("KEY4")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNKNOWN ) // nothing
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_MAHJONG_RON ) // ron
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_MAHJONG_DOUBLE_UP ) // ?
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN ) // nothing
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_MAHJONG_BIG ) // big
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_MAHJONG_SMALL ) // small + D
INPUT_PORTS_END
void menghong_state::menghong(machine_config &config)
{
SE3208(config, m_maincpu, 14318180 * 3); // TODO : different between each PCBs
m_maincpu->set_addrmap(AS_PROGRAM, &menghong_state::menghong_mem);
m_maincpu->set_irq_acknowledge_callback(FUNC(menghong_state::icallback));
// HY04 running at 8 MHz
// NVRAM(config, m_nvram, nvram_device::DEFAULT_ALL_0);
VRENDER0_SOC(config, m_vr0soc, 14318180 * 3);
m_vr0soc->set_host_cpu_tag(m_maincpu);
m_vr0soc->set_external_vclk(28636360); // Assumed from the only available XTal on PCB
DS1302(config, m_ds1302, 32.768_kHz_XTAL);
EEPROM_93C46_16BIT(config, "eeprom");
}
void menghong_state::crzyddz2(machine_config &config)
{
menghong(config);
m_maincpu->set_addrmap(AS_PROGRAM, &menghong_state::crzyddz2_mem);
}
ROM_START( menghong )
ROM_REGION32_LE( 0x1000000, "flash", 0 ) // Flash
ROM_LOAD( "rom.u48", 0x000000, 0x1000000, CRC(e24257c4) SHA1(569d79a61ff6d35100ba5727069363146df9e0b7) )
ROM_REGION( 0x0400000, "maincpu", 0 )
ROM_LOAD( "060511_08-01-18.u49", 0x0000000, 0x0200000, CRC(b0c12107) SHA1(b1753757bbdb7d996df563ac6abdc6b46676704b) ) // 27C160
ROM_RELOAD( 0x0200000, 0x0200000 )
ROM_REGION( 0x4280, "pic", 0 ) // hy04
ROM_LOAD("menghong_hy04", 0x000000, 0x4280, NO_DUMP )
ROM_REGION( 0x0100, "pic_data", ROMREGION_ERASEFF )
ROM_LOAD("hy04_fake_data.bin", 0, 0x100, BAD_DUMP CRC(73cc964b) SHA1(39d223c550e38c97135322e43ccabb70f04964b9) )
ROM_END
ROM_START( crzyddz2 )
ROM_REGION32_LE( 0x1000000, "flash", 0 ) // Flash
ROM_LOAD( "rom.u48", 0x000000, 0x1000000, CRC(0f3a1987) SHA1(6cad943846c79db31226676c7391f32216cfff79) )
ROM_REGION( 0x0400000, "maincpu", ROMREGION_ERASEFF )
ROM_LOAD( "27c322.u49", 0x000000, 0x0400000, CRC(b3177f39) SHA1(2a28bf8045bd2e053d88549b79fbc11f30ef9a32) ) // 1ST AND 2ND HALF IDENTICAL
ROM_REGION( 0x4280, "pic", 0 ) // hy04
ROM_LOAD("hy04", 0x000000, 0x4280, NO_DUMP )
ROM_REGION( 0x0100, "pic_data", ROMREGION_ERASEFF )
ROM_END
GAME( 2004?,menghong, 0, menghong, crzyddz2, menghong_state, empty_init, ROT0, "Sealy", "Meng Hong Lou", MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION )
GAME( 2006, crzyddz2, 0, crzyddz2, crzyddz2, menghong_state, empty_init, ROT0, "Sealy", "Crazy Dou Di Zhu II", MACHINE_NOT_WORKING | MACHINE_UNEMULATED_PROTECTION )