From fb343966097c68b800011332086c08a909f1f206 Mon Sep 17 00:00:00 2001 From: AJR Date: Sat, 9 Sep 2017 20:39:57 -0400 Subject: quizpun2: Emulate COP402 MCU --- src/mame/drivers/quizpun2.cpp | 265 ++++++++++++------------------------------ 1 file changed, 75 insertions(+), 190 deletions(-) diff --git a/src/mame/drivers/quizpun2.cpp b/src/mame/drivers/quizpun2.cpp index 477466592c2..225fb6bc150 100644 --- a/src/mame/drivers/quizpun2.cpp +++ b/src/mame/drivers/quizpun2.cpp @@ -22,7 +22,7 @@ PCB Layout | U28 6116 Z80 | | U2A 93C46 U111| | 6264 | -| U29 * 8MHz| +| U29 COP 8MHz| | U20 6116 | | 6116 | | U21 U30 | @@ -32,8 +32,8 @@ PCB Layout | YM3014 MAHJONG28 | |---------------------------------------------| Notes: - * - Unknown DIP40 chip. +5V on pin 17, GND on pin 22 - pins 4,3,2 of 93C46 tied to unknown chip on pins 23,24,25 + COP - COP402 or COP404 MCU (DIP40, +5V on pin 17, GND on pin 22). + pins 4,3,2 of 93C46 tied to COP pins 23,24,25 All clocks unknown, PCB not working Possibly Z80's @ 4MHz and YM2203 @ 2MHz PCB marked 'Ducksan Trading Co. Ltd. Made In Korea' @@ -83,6 +83,7 @@ Notes: #include "emu.h" +#include "cpu/cop400/cop400.h" #include "cpu/m6805/m68705.h" #include "cpu/z80/z80.h" @@ -95,19 +96,6 @@ Notes: #include "speaker.h" -// very preliminary quizpun2 protection simulation - -#define VERBOSE_PROTECTION_LOG 0 - -enum prot_state { STATE_IDLE = 0, STATE_ADDR_R, STATE_ROM_R, STATE_EEPROM_R, STATE_EEPROM_W }; -struct prot_t { - prot_state state; - int wait_param; - int param; - int cmd; - int addr; -}; - class quizpun2_state : public driver_device { public: @@ -151,17 +139,13 @@ public: uint32_t screen_update_quizpun2(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); // quizpun2 - void log_protection( address_space &space, const char *warning ); - struct prot_t m_prot; - DECLARE_READ8_MEMBER(quizpun2_protection_r); - DECLARE_WRITE8_MEMBER(quizpun2_protection_w); + DECLARE_WRITE8_MEMBER(cop_d_w); + DECLARE_WRITE8_MEMBER(cop_g_w); + DECLARE_READ8_MEMBER(cop_l_r); + DECLARE_WRITE8_MEMBER(cop_l_w); + DECLARE_READ8_MEMBER(cop_in_r); // quizpun - uint8_t m_port_a, m_port_b; - bool m_quizpun_pending; - bool m_quizpun_written; - bool m_quizpun_repeat; - DECLARE_READ8_MEMBER(quizpun_68705_port_a_r); DECLARE_WRITE8_MEMBER(quizpun_68705_port_a_w); @@ -173,6 +157,12 @@ public: DECLARE_READ8_MEMBER(quizpun_protection_r); DECLARE_WRITE8_MEMBER(quizpun_protection_w); + + uint8_t m_mcu_data_port; + uint8_t m_mcu_control_port; + bool m_mcu_pending; + bool m_mcu_written; + bool m_mcu_repeat; }; /*************************************************************************** @@ -268,150 +258,42 @@ void quizpun2_state::machine_reset() { membank("bank1")->set_entry(0); - // quizpun2 - m_prot.state = STATE_IDLE; - m_prot.wait_param = 0; - m_prot.param = 0; - m_prot.cmd = 0; - m_prot.addr = 0; - // quizpun - m_port_a = m_port_b = 0; - m_quizpun_pending = m_quizpun_written = m_quizpun_repeat = false; + m_mcu_data_port = m_mcu_control_port = 0; + m_mcu_pending = m_mcu_written = m_mcu_repeat = false; } -void quizpun2_state::log_protection( address_space &space, const char *warning ) +WRITE8_MEMBER(quizpun2_state::cop_d_w) { - logerror("%04x: protection - %s (state %x, wait %x, param %02x, cmd %02x, addr %02x)\n", space.device().safe_pc(), warning, - m_prot.state, - m_prot.wait_param, - m_prot.param, - m_prot.cmd, - m_prot.addr - ); + m_eeprom->cs_write(BIT(data, 0)); + // bit 1 used to control second EEPROM??? } -READ8_MEMBER(quizpun2_state::quizpun2_protection_r) +WRITE8_MEMBER(quizpun2_state::cop_g_w) { - struct prot_t &prot = m_prot; - uint8_t ret; - - switch ( prot.state ) + if (BIT(m_mcu_control_port, 0) && !BIT(data, 0)) { - case STATE_ROM_R: // Checksum of MCU addresses 0-ff (0x8e9c^0xffff expected) - if (prot.addr == 0xfe) ret = 0x8e ^ 0xff; - else if (prot.addr == 0xff) ret = 0x9c ^ 0xff; - else ret = 0x00; - break; - - case STATE_ADDR_R: // Address to jump to (big endian!) - switch ( prot.param ) - { - case 0x19: // Print - ret = 0x0b95 >> ((prot.addr & 1) ? 0 : 8); - break; - - case 0x44: // Clear screen? - ret = 0x1bd9 >> ((prot.addr & 1) ? 0 : 8); // needed, but should also clear the screen - break; - - case 0x45: // Backup RAM check - ret = 0x2242 >> ((prot.addr & 1) ? 0 : 8); - break; - - default: - log_protection(space, "unknown address"); - ret = 0x2e59 >> ((prot.addr & 1) ? 0 : 8); // return the address of: XOR A, RET - } - break; - - case STATE_EEPROM_R: // EEPROM read - { - uint8_t *eeprom = memregion("eeprom")->base(); - ret = eeprom[prot.addr]; - break; - } - - default: - log_protection(space, "unknown read"); - ret = 0x00; + m_mcu_pending = false; + m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); } -#if VERBOSE_PROTECTION_LOG - log_protection(space, "info READ"); -#endif - - prot.addr++; - - return ret; + m_mcu_control_port = data; } -WRITE8_MEMBER(quizpun2_state::quizpun2_protection_w) +READ8_MEMBER(quizpun2_state::cop_l_r) { - struct prot_t &prot = m_prot; + return m_mcu_data_port; +} - switch ( prot.state ) - { - case STATE_EEPROM_W: - { - uint8_t *eeprom = memregion("eeprom")->base(); - eeprom[prot.addr] = data; - prot.addr++; - if ((prot.addr % 8) == 0) - prot.state = STATE_IDLE; - break; - } - - default: - if (prot.wait_param) - { - prot.param = data; - prot.wait_param = 0; - - // change state: - - if (prot.cmd & 0x80) - { - if (prot.param == 0x00) - { - prot.state = STATE_ROM_R; - prot.addr = (prot.cmd & 0x7f) * 2; - } - else if (prot.cmd == 0x80) - { - prot.state = STATE_ADDR_R; - prot.addr = 0; - } - else - log_protection(space, "unknown command"); - } - else if (prot.cmd >= 0x00 && prot.cmd <= 0x0f) - { - prot.state = STATE_EEPROM_W; - prot.addr = (prot.cmd & 0x0f) * 8; - } - else if (prot.cmd >= 0x20 && prot.cmd <= 0x2f) - { - prot.state = STATE_EEPROM_R; - prot.addr = (prot.cmd & 0x0f) * 8; - } - else - { - prot.state = STATE_IDLE; - log_protection(space, "unknown command"); - } - } - else - { - prot.cmd = data; - prot.wait_param = 1; - } - break; - } +WRITE8_MEMBER(quizpun2_state::cop_l_w) +{ + if (m_mcu_repeat) + m_mcu_data_port = data; +} -#if VERBOSE_PROTECTION_LOG - log_protection(space, "info WRITE"); -#endif +READ8_MEMBER(quizpun2_state::cop_in_r) +{ + return 8 | (m_mcu_written ? 4 : 2) | (m_mcu_pending ? 0 : 1); } /*************************************************************************** @@ -445,7 +327,7 @@ static ADDRESS_MAP_START( quizpun2_map, AS_PROGRAM, 8, quizpun2_state ) AM_RANGE( 0xe000, 0xffff ) AM_RAM ADDRESS_MAP_END -static ADDRESS_MAP_START( common_io_map, AS_IO, 8, quizpun2_state ) +static ADDRESS_MAP_START( quizpun2_io_map, AS_IO, 8, quizpun2_state ) ADDRESS_MAP_GLOBAL_MASK(0xff) AM_RANGE( 0x40, 0x40 ) AM_WRITE(irq_ack) AM_RANGE( 0x50, 0x50 ) AM_WRITE(soundlatch_w) @@ -454,18 +336,18 @@ static ADDRESS_MAP_START( common_io_map, AS_IO, 8, quizpun2_state ) AM_RANGE( 0x80, 0x80 ) AM_READ_PORT( "DSW" ) AM_RANGE( 0x90, 0x90 ) AM_READ_PORT( "IN0" ) AM_RANGE( 0xa0, 0xa0 ) AM_READ_PORT( "IN1" ) + AM_RANGE( 0xe0, 0xe0 ) AM_READWRITE(quizpun_protection_r, quizpun_protection_w) ADDRESS_MAP_END -static ADDRESS_MAP_START( quizpun2_io_map, AS_IO, 8, quizpun2_state ) - AM_IMPORT_FROM( common_io_map ) - AM_RANGE( 0xe0, 0xe0 ) AM_READWRITE(quizpun2_protection_r, quizpun2_protection_w) +static ADDRESS_MAP_START( quizpun2_cop_map, AS_PROGRAM, 8, quizpun2_state ) + AM_RANGE( 0x000, 0x3ff ) AM_ROM AM_REGION("cop", 0) ADDRESS_MAP_END // quizpun READ8_MEMBER(quizpun2_state::quizpun_protection_r) { -// logerror("%s: port A read %02x\n", machine().describe_context(), m_port_a); +// logerror("%s: port A read %02x\n", machine().describe_context(), m_mcu_data_port); /* Upon reading this port the main cpu is stalled until the mcu provides the value to read @@ -477,39 +359,34 @@ READ8_MEMBER(quizpun2_state::quizpun_protection_r) It also decrements the main cpu PC back to the start of the read instruction. When the mcu un-stalls the Z80, the read happens again, returning the correct mcu-provided value this time */ - if (m_quizpun_repeat) + if (m_mcu_repeat) { - m_quizpun_repeat = false; + m_mcu_repeat = false; } else { - m_quizpun_pending = true; - m_quizpun_written = false; + m_mcu_pending = true; + m_mcu_written = false; m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); m_maincpu->yield(); m_maincpu->set_state_int(Z80_PC, m_maincpu->state_int(Z80_PC) - 2); - m_quizpun_repeat = true; + m_mcu_repeat = true; } - return m_port_a; + return m_mcu_data_port; } WRITE8_MEMBER(quizpun2_state::quizpun_protection_w) { // logerror("%s: port A write %02x\n", machine().describe_context(), data); - m_port_a = data; - m_quizpun_pending = true; - m_quizpun_written = true; + m_mcu_data_port = data; + m_mcu_pending = true; + m_mcu_written = true; m_maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); m_maincpu->yield(); } -static ADDRESS_MAP_START( quizpun_io_map, AS_IO, 8, quizpun2_state ) - AM_IMPORT_FROM( common_io_map ) - AM_RANGE( 0xe0, 0xe0 ) AM_READWRITE(quizpun_protection_r, quizpun_protection_w ) -ADDRESS_MAP_END - /*************************************************************************** Memory Maps - MCU ***************************************************************************/ @@ -518,14 +395,14 @@ ADDRESS_MAP_END READ8_MEMBER(quizpun2_state::quizpun_68705_port_a_r) { -// logerror("%s: port A read %02x\n", machine().describe_context(), m_port_a); - return m_port_a; +// logerror("%s: port A read %02x\n", machine().describe_context(), m_mcu_data_port); + return m_mcu_data_port; } WRITE8_MEMBER(quizpun2_state::quizpun_68705_port_a_w) { // logerror("%s: port A write %02x\n", machine().describe_context(), data); - m_port_a = data; + m_mcu_data_port = data; } // Port B - I/O with main cpu (status) @@ -538,9 +415,9 @@ READ8_MEMBER(quizpun2_state::quizpun_68705_port_b_r) uint8_t const ret = 0xf4 | - ( m_quizpun_pending ? 0 : (1 << 3)) | - ((m_quizpun_pending && m_quizpun_written) ? 0 : (1 << 1)) | - ((m_quizpun_pending && !m_quizpun_written) ? 0 : (1 << 0)); + ( m_mcu_pending ? 0 : (1 << 3)) | + ((m_mcu_pending && m_mcu_written) ? 0 : (1 << 1)) | + ((m_mcu_pending && !m_mcu_written) ? 0 : (1 << 0)); // logerror("%s: port B read %02x\n", machine().describe_context(), ret); return ret; @@ -552,12 +429,12 @@ WRITE8_MEMBER(quizpun2_state::quizpun_68705_port_b_w) // bit 2: 0->1 run main cpu - if (!BIT(m_port_b, 2) && BIT(data, 2)) + if (!BIT(m_mcu_control_port, 2) && BIT(data, 2)) { - m_quizpun_pending = false; + m_mcu_pending = false; m_maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE); } - m_port_b = data; + m_mcu_control_port = data; } // Port C - EEPROM @@ -694,6 +571,18 @@ static MACHINE_CONFIG_START( quizpun2 ) MCFG_CPU_VBLANK_INT_DRIVER("screen", quizpun2_state, irq0_line_hold) // NMI generated by main CPU + MCFG_CPU_ADD("cop", COP402, XTAL_8MHz / 2) + MCFG_CPU_PROGRAM_MAP(quizpun2_cop_map) + MCFG_COP400_CONFIG(COP400_CKI_DIVISOR_16, COP400_CKO_OSCILLATOR_OUTPUT, false) + MCFG_COP400_WRITE_D_CB(WRITE8(quizpun2_state, cop_d_w)) + MCFG_COP400_WRITE_G_CB(WRITE8(quizpun2_state, cop_g_w)) + MCFG_COP400_READ_L_CB(READ8(quizpun2_state, cop_l_r)) + MCFG_COP400_WRITE_L_CB(WRITE8(quizpun2_state, cop_l_w)) + MCFG_COP400_READ_IN_CB(READ8(quizpun2_state, cop_in_r)) + MCFG_COP400_READ_SI_CB(DEVREADLINE("eeprom", eeprom_serial_93cxx_device, do_read)) + MCFG_COP400_WRITE_SO_CB(DEVWRITELINE("eeprom", eeprom_serial_93cxx_device, di_write)) + MCFG_COP400_WRITE_SK_CB(DEVWRITELINE("eeprom", eeprom_serial_93cxx_device, clk_write)) + MCFG_EEPROM_SERIAL_93C46_ADD("eeprom") /* video hardware */ @@ -719,8 +608,7 @@ static MACHINE_CONFIG_START( quizpun2 ) MACHINE_CONFIG_END static MACHINE_CONFIG_DERIVED( quizpun, quizpun2 ) - MCFG_CPU_MODIFY("maincpu") - MCFG_CPU_IO_MAP(quizpun_io_map) + MCFG_DEVICE_REMOVE("cop") MCFG_CPU_ADD("mcu", M68705P5, XTAL_4MHz) // xtal is 4MHz, divided by 4 internally MCFG_M68705_PORTA_R_CB(READ8(quizpun2_state, quizpun_68705_port_a_r)) @@ -746,8 +634,8 @@ ROM_START( quizpun2 ) ROM_REGION( 0x10000, "audiocpu", 0 ) ROM_LOAD( "u22", 0x00000, 0x10000, CRC(f40768b5) SHA1(4410f71850357ec1d10a3a114bb540966e72781b) ) - ROM_REGION( 0x1000, "mcu", 0 ) - ROM_LOAD( "mcu.bin", 0x0000, 0x1000, NO_DUMP ) + ROM_REGION( 0x2000, "cop", 0 ) + ROM_LOAD( "u2a", 0x0000, 0x2000, CRC(13afc2bd) SHA1(0d9c8813525dfc7a844e72d2cf84261db3d10a23) ) // 111xxxxxxxxxx = 0xFF ROM_REGION( 0x40000, "bg", 0 ) // 16x16x8 ROM_LOAD( "u21", 0x00000, 0x10000, CRC(8ac86759) SHA1(2eac9ceee4462ce905aa08ff4f5a6215e0b6672f) ) @@ -769,9 +657,6 @@ ROM_START( quizpun2 ) ROM_REGION16_BE( 0x80, "eeprom", 0 ) // EEPROM (tied to the unknown DIP40) ROM_LOAD( "93c46", 0x00, 0x80, CRC(4d244cc8) SHA1(6593d5b7ac1ebb77fee4648ad1d3d9b59a25fdc8) BAD_DUMP ) // backup ram error - - ROM_REGION( 0x2000, "unknown", 0 ) - ROM_LOAD( "u2a", 0x0000, 0x2000, CRC(13afc2bd) SHA1(0d9c8813525dfc7a844e72d2cf84261db3d10a23) ) // 111xxxxxxxxxx = 0xFF ROM_END ROM_START( quizpun ) @@ -812,4 +697,4 @@ ROM_START( quizpun ) ROM_END GAME( 1988, quizpun, 0, quizpun, quizpun2, quizpun2_state, 0, ROT270, "Space Computer", "Quiz Punch", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) -GAME( 1989, quizpun2, 0, quizpun2, quizpun2, quizpun2_state, 0, ROT270, "Space Computer", "Quiz Punch II", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_UNEMULATED_PROTECTION ) +GAME( 1989, quizpun2, 0, quizpun2, quizpun2, quizpun2_state, 0, ROT270, "Space Computer", "Quiz Punch II", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) -- cgit v1.2.3