// license:GPL-2.0+ // copyright-holders:FelipeSanches, Sandro Ronco // // Wacky Gator // // Driver by Sandro Ronco and // Felipe Correa da Silva Sanches // /* Most of this driver is based on guessing since I do not have access to the actual pcb for this game. Once we get a pcb, please review the correctness of the code in this driver before deleting this comment. TODO: - IRQ and NMI sources are unknown - proper PMM8713 and steppers emulation */ #include "emu.h" #include "cpu/m6809/m6809.h" #include "machine/i8255.h" #include "machine/pit8253.h" #include "machine/ticket.h" #include "machine/timer.h" #include "sound/msm5205.h" #include "sound/ym2413.h" #include "speaker.h" #include "wackygtr.lh" class wackygtr_state : public driver_device { public: wackygtr_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), m_msm(*this, "msm"), m_pit8253_0(*this, "pit8253_0"), m_pit8253_1(*this, "pit8253_1"), m_ticket(*this, "ticket"), m_samples(*this, "oki"), m_alligator(*this, "alligator%u", 0U), m_digit(*this, "digit%u", 0U), m_lamps(*this, "lamp%u", 0U) { } DECLARE_CUSTOM_INPUT_MEMBER(alligators_rear_sensors_r); DECLARE_CUSTOM_INPUT_MEMBER(alligators_front_sensors_r); void wackygtr(machine_config &config); protected: virtual void machine_start() override; virtual void machine_reset() override; DECLARE_WRITE_LINE_MEMBER(adpcm_int); DECLARE_WRITE8_MEMBER(sample_ctrl_w); DECLARE_WRITE8_MEMBER(alligators_ctrl1_w); DECLARE_WRITE8_MEMBER(alligators_ctrl2_w); void set_lamps(int p, uint8_t value); DECLARE_WRITE8_MEMBER(status_lamps_w); template DECLARE_WRITE8_MEMBER(timing_lamps_w) { set_lamps((N + 1) << 3, data); } void set_digits(int p, uint8_t value); template DECLARE_WRITE8_MEMBER(disp_w) { set_digits(N << 1, data); } void pmm8713_ck(int i, int state); template DECLARE_WRITE_LINE_MEMBER(alligator_ck) { pmm8713_ck(N, state); } DECLARE_WRITE8_MEMBER(irq_ack_w) { m_maincpu->set_input_line(M6809_IRQ_LINE, CLEAR_LINE); } DECLARE_WRITE8_MEMBER(firq_ack_w) { m_maincpu->set_input_line(M6809_FIRQ_LINE, CLEAR_LINE); } TIMER_DEVICE_CALLBACK_MEMBER(nmi_timer) { m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero); } void program_map(address_map &map); private: required_device m_maincpu; required_device m_msm; required_device m_pit8253_0; required_device m_pit8253_1; required_device m_ticket; required_memory_region m_samples; output_finder<5> m_alligator; output_finder<8> m_digit; output_finder<32> m_lamps; int m_adpcm_sel; uint16_t m_adpcm_pos; uint8_t m_adpcm_ctrl; uint8_t m_alligators_ctrl; int m_motors_pos[5]; }; WRITE8_MEMBER(wackygtr_state::status_lamps_w) { /* ---x xxxx status lamps --x- ---- game over lamp -x-- ---- coin counter x--- ---- ticket dispenser */ set_lamps(0, data & 0x3f); machine().bookkeeping().coin_counter_w(0, BIT(data, 6)); m_ticket->motor_w(BIT(data, 7)); } WRITE8_MEMBER(wackygtr_state::sample_ctrl_w) { /* --xx xxxx sample index -x-- ---- ??? x--- ---- 5205 reset */ m_adpcm_ctrl = data; m_adpcm_pos = (data & 0x3f) * 0x400; m_adpcm_sel = 0; m_msm->reset_w(BIT(data, 7)); } WRITE8_MEMBER(wackygtr_state::alligators_ctrl1_w) { m_pit8253_0->write_gate0(BIT(data, 0)); m_pit8253_0->write_gate1(BIT(data, 1)); m_pit8253_0->write_gate2(BIT(data, 2)); m_pit8253_1->write_gate1(BIT(data, 3)); m_pit8253_1->write_gate2(BIT(data, 4)); machine().bookkeeping().coin_lockout_w(0, data & 0x40 ? 0 : 1); } WRITE8_MEMBER(wackygtr_state::alligators_ctrl2_w) { /* ---- ---x PMM8713 0 U/D ---- --x- PMM8713 1 U/D ---- -x-- PMM8713 2 U/D ---- x--- PMM8713 3 U/D ---x ---- PMM8713 4 U/D */ m_alligators_ctrl = data & 0x1f; } void wackygtr_state::pmm8713_ck(int i, int state) { if (state) { m_motors_pos[i] += (BIT(m_alligators_ctrl, i) ? +1 : -1); int alligator_state = m_motors_pos[i] / 10; if (alligator_state > 5) alligator_state = 5; if (alligator_state < 0) alligator_state = 0; m_alligator[i] = alligator_state; } } CUSTOM_INPUT_MEMBER(wackygtr_state::alligators_rear_sensors_r) { return ((m_motors_pos[0] < 10) ? 0x01 : 0) | ((m_motors_pos[1] < 10) ? 0x02 : 0) | ((m_motors_pos[2] < 10) ? 0x04 : 0) | ((m_motors_pos[3] < 10) ? 0x08 : 0) | ((m_motors_pos[4] < 10) ? 0x10 : 0) | (m_alligators_ctrl ^ 0x1f); } CUSTOM_INPUT_MEMBER(wackygtr_state::alligators_front_sensors_r) { return ((m_motors_pos[0] < 5 || m_motors_pos[0] > 55) ? 0x01 : 0) | ((m_motors_pos[1] < 5 || m_motors_pos[1] > 55) ? 0x02 : 0) | ((m_motors_pos[2] < 5 || m_motors_pos[2] > 55) ? 0x04 : 0) | ((m_motors_pos[3] < 5 || m_motors_pos[3] > 55) ? 0x08 : 0) | ((m_motors_pos[4] < 5 || m_motors_pos[4] > 55) ? 0x10 : 0); } void wackygtr_state::machine_start() { m_alligator.resolve(); m_digit.resolve(); m_lamps.resolve(); save_item(NAME(m_adpcm_sel)); save_item(NAME(m_adpcm_pos)); save_item(NAME(m_adpcm_ctrl)); save_item(NAME(m_alligators_ctrl)); save_item(NAME(m_motors_pos)); } void wackygtr_state::machine_reset() { m_adpcm_pos = 0; m_adpcm_sel = 0; m_adpcm_ctrl = 0x80; } void wackygtr_state::set_digits(int p, uint8_t value) { static constexpr uint8_t bcd2hex[] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x67, 0, 0, 0, 0, 0, 0 }; // not accurate m_digit[p + 0] = bcd2hex[value & 0x0f]; m_digit[p + 1] = bcd2hex[(value >> 4) & 0x0f]; } void wackygtr_state::set_lamps(int p, uint8_t value) { for (int i=0; i<8; i++) m_lamps[p + i] = BIT(value, i); } static INPUT_PORTS_START( wackygtr ) PORT_START("IN0") PORT_BIT(0x1f, IP_ACTIVE_LOW, IPT_CUSTOM) PORT_CUSTOM_MEMBER(DEVICE_SELF, wackygtr_state, alligators_rear_sensors_r, nullptr) PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_SERVICE) PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_SERVICE1) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_COIN1) PORT_START("IN1") PORT_BIT(0x1f, IP_ACTIVE_LOW, IPT_CUSTOM) PORT_CUSTOM_MEMBER(DEVICE_SELF, wackygtr_state, alligators_front_sensors_r, nullptr) PORT_DIPNAME( 0xe0, 0x00, DEF_STR( Coin_A ) ) PORT_DIPLOCATION("SW:1,2,3") PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ) ) PORT_DIPSETTING( 0x20, DEF_STR( 1C_1C ) ) PORT_DIPSETTING( 0x40, DEF_STR( 1C_1C ) ) PORT_DIPSETTING( 0x60, DEF_STR( 2C_1C ) ) PORT_DIPSETTING( 0x80, DEF_STR( 1C_1C ) ) PORT_DIPSETTING( 0xa0, DEF_STR( 2C_1C ) ) PORT_DIPSETTING( 0xc0, DEF_STR( 1C_1C ) ) PORT_DIPSETTING( 0xe0, DEF_STR( 2C_1C ) ) PORT_START("IN2") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_POKER_HOLD1) PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_POKER_HOLD2) PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_POKER_HOLD3) PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_POKER_HOLD4) PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_POKER_HOLD5) PORT_DIPNAME( 0x20, 0x20, DEF_STR( Test ) ) PORT_DIPLOCATION("SW:4") // For factory Test use ONLY! Do not change PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPSETTING( 0x20, DEF_STR( Off ) ) PORT_DIPNAME( 0x40, 0x00, DEF_STR( Demo_Sounds ) ) PORT_DIPLOCATION("SW:5") PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) PORT_DIPNAME( 0x80, 0x80, DEF_STR( Test ) ) PORT_DIPLOCATION("SW:6") // For factory Test use ONLY! Do not change PORT_DIPSETTING( 0x00, DEF_STR( On ) ) PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) INPUT_PORTS_END WRITE_LINE_MEMBER(wackygtr_state::adpcm_int) { if (!(m_adpcm_ctrl & 0x80)) { uint8_t data = m_samples->base()[m_adpcm_pos & 0xffff]; m_msm->data_w((m_adpcm_sel ? data : (data >> 4)) & 0x0f); m_adpcm_pos += m_adpcm_sel; m_adpcm_sel ^= 1; } } void wackygtr_state::program_map(address_map &map) { map(0x0200, 0x0200).nopr().w(this, FUNC(wackygtr_state::irq_ack_w)); map(0x0400, 0x0400).nopr().w(this, FUNC(wackygtr_state::firq_ack_w)); map(0x0600, 0x0600).w(this, FUNC(wackygtr_state::disp_w<0>)); map(0x0800, 0x0800).w(this, FUNC(wackygtr_state::disp_w<1>)); map(0x0a00, 0x0a00).w(this, FUNC(wackygtr_state::disp_w<2>)); map(0x0c00, 0x0c00).w(this, FUNC(wackygtr_state::disp_w<3>)); map(0x0e00, 0x0e00).w(this, FUNC(wackygtr_state::sample_ctrl_w)); map(0x1000, 0x1001).w("ymsnd", FUNC(ym2413_device::write)); map(0x2000, 0x2003).rw(m_pit8253_0, FUNC(pit8253_device::read), FUNC(pit8253_device::write)); map(0x3000, 0x3003).rw(m_pit8253_1, FUNC(pit8253_device::read), FUNC(pit8253_device::write)); map(0x4000, 0x4003).rw("i8255_0", FUNC(i8255_device::read), FUNC(i8255_device::write)); map(0x5000, 0x5003).rw("i8255_1", FUNC(i8255_device::read), FUNC(i8255_device::write)); map(0x6000, 0x6003).rw("i8255_2", FUNC(i8255_device::read), FUNC(i8255_device::write)); map(0x7000, 0x7fff).ram(); map(0x8000, 0xffff).rom(); } MACHINE_CONFIG_START(wackygtr_state::wackygtr) MCFG_DEVICE_ADD("maincpu", MC6809, XTAL(3'579'545)) // HD68B09P MCFG_DEVICE_PROGRAM_MAP(program_map) MCFG_DEVICE_PERIODIC_INT_DRIVER(wackygtr_state, irq0_line_assert, 50) // FIXME MCFG_TIMER_DRIVER_ADD_PERIODIC("nmi_timer", wackygtr_state, nmi_timer, attotime::from_hz(100)) // FIXME /* Video */ MCFG_DEFAULT_LAYOUT(layout_wackygtr) /* Sound */ SPEAKER(config, "mono").front_center(); MCFG_DEVICE_ADD("msm", MSM5205, XTAL(384'000) ) MCFG_MSM5205_VCLK_CB(WRITELINE(*this, wackygtr_state, adpcm_int)) /* IRQ handler */ MCFG_MSM5205_PRESCALER_SELECTOR(S48_4B) /* 8 KHz, 4 Bits */ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) MCFG_DEVICE_ADD("ymsnd", YM2413, XTAL(3'579'545) ) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) MCFG_DEVICE_ADD("i8255_0", I8255, 0) MCFG_I8255_OUT_PORTA_CB(WRITE8(*this, wackygtr_state, status_lamps_w)) MCFG_I8255_OUT_PORTB_CB(WRITE8(*this, wackygtr_state, alligators_ctrl1_w)) MCFG_I8255_OUT_PORTC_CB(WRITE8(*this, wackygtr_state, alligators_ctrl2_w)) MCFG_DEVICE_ADD("i8255_1", I8255, 0) MCFG_I8255_OUT_PORTA_CB(WRITE8(*this, wackygtr_state, timing_lamps_w<0>)) MCFG_I8255_OUT_PORTB_CB(WRITE8(*this, wackygtr_state, timing_lamps_w<1>)) MCFG_I8255_OUT_PORTC_CB(WRITE8(*this, wackygtr_state, timing_lamps_w<2>)) MCFG_DEVICE_ADD("i8255_2", I8255, 0) MCFG_I8255_IN_PORTA_CB(IOPORT("IN0")) MCFG_I8255_IN_PORTB_CB(IOPORT("IN1")) MCFG_I8255_IN_PORTC_CB(IOPORT("IN2")) MCFG_DEVICE_ADD("pit8253_0", PIT8253, 0) MCFG_PIT8253_CLK0(XTAL(3'579'545)/16) // this is a guess MCFG_PIT8253_OUT0_HANDLER(WRITELINE(*this, wackygtr_state, alligator_ck<0>)) MCFG_PIT8253_CLK1(XTAL(3'579'545)/16) // this is a guess MCFG_PIT8253_OUT1_HANDLER(WRITELINE(*this, wackygtr_state, alligator_ck<1>)) MCFG_PIT8253_CLK2(XTAL(3'579'545)/16) // this is a guess MCFG_PIT8253_OUT2_HANDLER(WRITELINE(*this, wackygtr_state, alligator_ck<2>)) MCFG_DEVICE_ADD("pit8253_1", PIT8253, 0) MCFG_PIT8253_CLK0(XTAL(3'579'545)/16) // this is a guess MCFG_PIT8253_OUT0_HANDLER(INPUTLINE("maincpu", M6809_FIRQ_LINE)) MCFG_PIT8253_CLK1(XTAL(3'579'545)/16) // this is a guess MCFG_PIT8253_OUT1_HANDLER(WRITELINE(*this, wackygtr_state, alligator_ck<3>)) MCFG_PIT8253_CLK2(XTAL(3'579'545)/16) // this is a guess MCFG_PIT8253_OUT2_HANDLER(WRITELINE(*this, wackygtr_state, alligator_ck<4>)) MCFG_TICKET_DISPENSER_ADD("ticket", attotime::from_msec(200), TICKET_MOTOR_ACTIVE_HIGH, TICKET_STATUS_ACTIVE_HIGH) MACHINE_CONFIG_END ROM_START( wackygtr ) ROM_REGION(0x10000, "maincpu", 0) ROM_LOAD("wp3-pr0.4d", 0x8000, 0x8000, CRC(71ca4437) SHA1(c7d948c5593e6053fd0a65601f6c06871f5861f0)) ROM_REGION(0x10000, "oki", 0) ROM_LOAD("wp3-vo0.2h", 0x0000, 0x10000, CRC(91c7986f) SHA1(bc9fa0d41c1caa0f909a349f511d022b7e42c6cd)) ROM_END GAME(1990, wackygtr, 0, wackygtr, wackygtr, wackygtr_state, empty_init, ROT0, "Data East", "Wacky Gator", MACHINE_IS_SKELETON_MECHANICAL | MACHINE_CLICKABLE_ARTWORK)