// license:BSD-3-Clause // copyright-holders:Sandro Ronco /*************************************************************************** Ice Cold Beer mechanical arcade game (c) Taito 1983 ****************************************************************************/ #include "emu.h" #include "cpu/m6809/m6809.h" #include "machine/6821pia.h" #include "machine/i8279.h" #include "sound/ay8910.h" #include "icecold.lh" class icecold_state : public driver_device { public: icecold_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), m_ay8910_0(*this, "ay0"), m_ay8910_1(*this, "ay1"), m_pia1(*this, "pia1") { } DECLARE_INPUT_CHANGED_MEMBER( test_switch_press ); DECLARE_CUSTOM_INPUT_MEMBER( motors_limit_r ); DECLARE_WRITE8_MEMBER( scanlines_w ); DECLARE_WRITE8_MEMBER( digit_w ); DECLARE_READ8_MEMBER( kbd_r ); DECLARE_WRITE8_MEMBER( snd_ctrl_w ); DECLARE_WRITE8_MEMBER( ay_w ); DECLARE_READ8_MEMBER( ay_r ); DECLARE_WRITE8_MEMBER( ay8910_0_b_w ); DECLARE_WRITE8_MEMBER( ay8910_1_a_w ); DECLARE_WRITE8_MEMBER( ay8910_1_b_w ); DECLARE_WRITE8_MEMBER( motors_w ); // driver_device overrides virtual void machine_reset() override; // devices required_device m_maincpu; required_device m_ay8910_0; required_device m_ay8910_1; required_device m_pia1; UINT8 m_digit; // scanlines from i8279 UINT8 m_sound_latch; // sound bus latch UINT8 m_ay_ctrl; // ay controls line UINT8 m_motors_ctrl; // motors control int m_sint; // SINT line int m_motenbl; // /MOTENBL line int m_ball_gate_sw; // ball gate switch // motors positions int m_rmotor; // right motor position (0-100) int m_lmotor; // left motor position (0-100) TIMER_DEVICE_CALLBACK_MEMBER(icecold_sint_timer); TIMER_DEVICE_CALLBACK_MEMBER(icecold_motors_timer); }; static ADDRESS_MAP_START( icecold_map, AS_PROGRAM, 8, icecold_state ) AM_RANGE(0x0000, 0x07ff) AM_RAM AM_RANGE(0x4010, 0x4013) AM_DEVREADWRITE("pia0", pia6821_device, read, write) AM_RANGE(0x4020, 0x4023) AM_DEVREADWRITE("pia1", pia6821_device, read, write) AM_RANGE(0x4040, 0x4043) AM_DEVREADWRITE("pia2", pia6821_device, read, write) // not used AM_RANGE(0x4080, 0x4080) AM_DEVREADWRITE("i8279", i8279_device, data_r, data_w ) AM_RANGE(0x4081, 0x4081) AM_DEVREADWRITE("i8279", i8279_device, status_r, cmd_w) AM_RANGE(0x4100, 0x4100) AM_WRITE(motors_w) AM_RANGE(0xa000, 0xffff) AM_ROM ADDRESS_MAP_END static INPUT_PORTS_START( icecold ) PORT_START("DSW3") PORT_DIPNAME( 0x01, 0x01, "Automatic Attract Mode" ) PORT_DIPLOCATION("SW3:1") PORT_DIPSETTING( 0x00, DEF_STR( Off ) ) PORT_DIPSETTING( 0x01, DEF_STR( On ) ) PORT_DIPNAME( 0x02, 0x00, "Rounds to Complete to Light Star" ) PORT_DIPLOCATION("SW3:2") PORT_DIPSETTING( 0x00, "1 Frame" ) PORT_DIPSETTING( 0x02, "2 Frames" ) PORT_DIPNAME( 0x0c, 0x00, "Automatic Attract Mode Delay" ) PORT_DIPLOCATION("SW3:3,SW3:4") PORT_DIPSETTING( 0x00, "1 Min" ) PORT_DIPSETTING( 0x04, "5 Min" ) PORT_DIPSETTING( 0x08, "10 Min" ) PORT_DIPSETTING( 0x0c, "15 Min" ) PORT_DIPNAME( 0x30, 0x00, "Manual Attract Mode Delay" ) PORT_DIPLOCATION("SW3:5,SW3:6") PORT_DIPSETTING( 0x00, "0 Min" ) PORT_DIPSETTING( 0x10, "2 Min" ) PORT_DIPSETTING( 0x20, "5 Min" ) PORT_DIPSETTING( 0x30, "10 Min" ) PORT_DIPNAME( 0xc0, 0x00, "Difficulty (Prompt Time)" ) PORT_DIPLOCATION("SW3:7,SW3:8") PORT_DIPSETTING( 0x00, "Easy (5, 4, 2, 1)" ) PORT_DIPSETTING( 0x40, "Factory (4, 2, 1, 1)" ) PORT_DIPSETTING( 0x80, "Hard (2, 2, 1, 1)" ) PORT_DIPSETTING( 0xc0, "X-Hard (1, 1, 1, 1)" ) PORT_START("DSW4") PORT_DIPNAME( 0x07, 0x00, "Dispense Option" ) PORT_DIPLOCATION("SW4:1,SW4:2,SW4:3") PORT_DIPSETTING( 0x00, "Disabled" ) PORT_DIPSETTING( 0x01, "2 Tickets after Hole 6, 3 Tickets after Hole 10" ) PORT_DIPSETTING( 0x02, "1 Ticket after Holes 5 - 10" ) PORT_DIPSETTING( 0x03, "No Tickets Dispensed" ) PORT_DIPSETTING( 0x04, "5 Tickets after Hole 5" ) PORT_DIPSETTING( 0x05, "No Tickets Dispensed" ) PORT_DIPSETTING( 0x06, "5 Tickets after Hole 10" ) PORT_DIPSETTING( 0x07, "No Tickets Dispensed" ) PORT_DIPNAME( 0x08, 0x08, DEF_STR( Coin_A ) ) PORT_DIPLOCATION("SW4:4") PORT_DIPSETTING( 0x00, DEF_STR( 2C_1C ) ) PORT_DIPSETTING( 0x08, DEF_STR( 1C_1C ) ) PORT_DIPNAME( 0x30, 0x00, "Score for Extra Ball" ) PORT_DIPLOCATION("SW4:5,SW4:6") PORT_DIPSETTING( 0x00, "No Extra Ball" ) PORT_DIPSETTING( 0x10, "2000" ) PORT_DIPSETTING( 0x20, "4000" ) PORT_DIPSETTING( 0x30, "8000" ) PORT_DIPNAME( 0xc0, 0x00, "Bonus Countdown Speed" ) PORT_DIPLOCATION("SW4:7,SW4:8") PORT_DIPSETTING( 0x00, "Slow" ) PORT_DIPSETTING( 0x40, "Factory" ) PORT_DIPSETTING( 0x80, "Fast" ) PORT_DIPSETTING( 0xc0, "X-Fast" ) PORT_START("TEST") // service switch is directly hard-wired with the NMI line PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_SERVICE) PORT_CHANGED_MEMBER(DEVICE_SELF, icecold_state, test_switch_press, 1) PORT_START("JOY") PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_JOYSTICKRIGHT_DOWN) PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_JOYSTICKLEFT_DOWN) PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_JOYSTICKRIGHT_UP) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_JOYSTICKLEFT_UP) PORT_BIT(0x55, IP_ACTIVE_LOW, IPT_SPECIAL) PORT_CUSTOM_MEMBER(DEVICE_SELF, icecold_state, motors_limit_r, nullptr) PORT_START("X0") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_START1) PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_COIN1) PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Ball Gate") PORT_CODE(KEYCODE_0) PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_TILT1) PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME(DEF_STR( Free_Play )) PORT_CODE(KEYCODE_3) PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Hopper cycle sensor") PORT_CODE(KEYCODE_6) PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Hopper empty") PORT_CODE(KEYCODE_7) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) PORT_START("X1") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Hole 1") PORT_CODE(KEYCODE_1_PAD) PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Hole 2") PORT_CODE(KEYCODE_2_PAD) PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Hole 3") PORT_CODE(KEYCODE_3_PAD) PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Hole 4") PORT_CODE(KEYCODE_4_PAD) PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Hole 5") PORT_CODE(KEYCODE_5_PAD) PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Hole 6") PORT_CODE(KEYCODE_6_PAD) PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Hole 7") PORT_CODE(KEYCODE_7_PAD) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) PORT_START("X2") PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Hole 8") PORT_CODE(KEYCODE_8_PAD) PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Hole 9") PORT_CODE(KEYCODE_9_PAD) PORT_BIT(0x04, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Hole 10") PORT_CODE(KEYCODE_0_PAD) PORT_BIT(0x08, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Ticket feed") PORT_CODE(KEYCODE_8) PORT_BIT(0x10, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Errant Ball") PORT_CODE(KEYCODE_9) PORT_BIT(0x20, IP_ACTIVE_LOW, IPT_UNUSED) PORT_BIT(0x40, IP_ACTIVE_LOW, IPT_UNUSED) PORT_BIT(0x80, IP_ACTIVE_LOW, IPT_UNUSED) INPUT_PORTS_END void icecold_state::machine_reset() { // CH-C is used for generate a 30hz clock m_ay8910_0->set_volume(2, 0); m_rmotor = m_lmotor = 10; m_sint = 0; m_motenbl = 0; m_ball_gate_sw = 1; } CUSTOM_INPUT_MEMBER( icecold_state::motors_limit_r ) { UINT8 data = 0; if (m_rmotor <= 1) data |= 0x01; // right down limit if (m_lmotor <= 1) data |= 0x04; // left down limit if (m_rmotor >= 99) data |= 0x10; // right up limit if (m_lmotor >= 99) data |= 0x40; // left up limit return data; } INPUT_CHANGED_MEMBER( icecold_state::test_switch_press ) { m_maincpu->set_input_line(INPUT_LINE_NMI, newval ? ASSERT_LINE : CLEAR_LINE); } WRITE8_MEMBER( icecold_state::motors_w ) { m_motors_ctrl = data; } WRITE8_MEMBER( icecold_state::scanlines_w ) { m_digit = data; } WRITE8_MEMBER( icecold_state::digit_w ) { output().set_digit_value(m_digit, data & 0x7f); } READ8_MEMBER( icecold_state::kbd_r ) { switch(m_digit) { case 0: // override the ball gate switch return ioport("X0")->read() & ~(m_ball_gate_sw<<2); case 1: return ioport("X1")->read(); case 2: return ioport("X2")->read(); default: return 0xff; } } WRITE8_MEMBER( icecold_state::snd_ctrl_w ) { if (m_ay_ctrl & ~data & 0x04) m_ay8910_0->data_address_w(space, m_ay_ctrl & 0x01, m_sound_latch); if (m_ay_ctrl & ~data & 0x20) m_ay8910_1->data_address_w(space, (m_ay_ctrl>>3) & 0x01, m_sound_latch); m_ay_ctrl = data; } WRITE8_MEMBER( icecold_state::ay_w ) { m_sound_latch = data; } READ8_MEMBER( icecold_state::ay_r ) { if (m_ay_ctrl & 0x02) return m_ay8910_0->data_r(space, 0); if (m_ay_ctrl & 0x10) return m_ay8910_1->data_r(space, 0); return 0; } WRITE8_MEMBER( icecold_state::ay8910_0_b_w ) { output().set_lamp_value(1, BIT(data, 0)); output().set_lamp_value(2, BIT(data, 1)); output().set_lamp_value(3, BIT(data, 2)); output().set_lamp_value(4, BIT(data, 3)); output().set_lamp_value(5, BIT(data, 4)); output().set_value("in_play", BIT(data, 5)); output().set_value("good_game", BIT(data, 6)); m_motenbl = BIT(data, 7); } WRITE8_MEMBER( icecold_state::ay8910_1_a_w ) { output().set_lamp_value(6, BIT(data, 0)); output().set_lamp_value(7, BIT(data, 1)); output().set_lamp_value(8, BIT(data, 2)); output().set_lamp_value(9, BIT(data, 3)); output().set_lamp_value(10, BIT(data, 4)); output().set_value("game_over", BIT(data, 5)); output().set_value("tilt", BIT(data, 6)); // BIT 7 watchdog reset } WRITE8_MEMBER( icecold_state::ay8910_1_b_w ) { if (m_motenbl == 0) { output().set_value("start", BIT(data, 0)); machine().bookkeeping().coin_counter_w(1, BIT(data, 1)); // hopper counter machine().bookkeeping().coin_counter_w(2, BIT(data, 2)); // good game counter machine().bookkeeping().coin_lockout_w(0, BIT(data, 3)); // not used ?? machine().bookkeeping().coin_counter_w(0, BIT(data, 4)); // coin counter // BIT 5 errant ball solenoid // BIT 7 hopper motor } } TIMER_DEVICE_CALLBACK_MEMBER(icecold_state::icecold_sint_timer) { m_sint = !m_sint; m_pia1->ca1_w(m_sint); } TIMER_DEVICE_CALLBACK_MEMBER(icecold_state::icecold_motors_timer) { // /MOTENBL is set high during reset for disable the motors control if (m_motenbl == 0) { int lmotor_dir = ((m_motors_ctrl & 0x0f) == 0x06) ? -1 : ((m_motors_ctrl & 0x0f) == 0x09) ? +1 : 0; int rmotor_dir = ((m_motors_ctrl & 0xf0) == 0x60) ? -1 : ((m_motors_ctrl & 0xf0) == 0x90) ? +1 : 0; // update motors position m_lmotor += lmotor_dir; m_rmotor += rmotor_dir; // if one motor is at the top of the playfield, closes the ball gate switch, to simulate ball movement if (m_lmotor >= 99 || m_rmotor >= 99 ) m_ball_gate_sw = 1; // if the motors are at the bottom of the playfield, opens the ball gate switch for start the game else if (m_lmotor <= 1 && m_rmotor <= 1 ) m_ball_gate_sw = 0; // motors are keep in range 0-100 m_lmotor = MIN(m_lmotor, 100); m_lmotor = MAX(m_lmotor, 0); m_rmotor = MIN(m_rmotor, 100); m_rmotor = MAX(m_rmotor, 0); if (lmotor_dir != 0 || rmotor_dir != 0) { output().set_value("lmotor", m_lmotor); output().set_value("rmotor", m_rmotor); popmessage("Left Motor Right Motor\n%-4s %-4s\n%02d\\100 %02d\\100", (lmotor_dir > 0) ? " up" : ((lmotor_dir < 0) ? "down" : "off"), (rmotor_dir > 0) ? " up" : ((rmotor_dir < 0) ? "down" : "off"), m_lmotor, m_rmotor); } } } static MACHINE_CONFIG_START( icecold, icecold_state ) /* basic machine hardware */ MCFG_CPU_ADD("maincpu", M6809, XTAL_6MHz/4) MCFG_CPU_PROGRAM_MAP(icecold_map) MCFG_DEVICE_ADD( "pia0", PIA6821, 0) MCFG_PIA_READPA_HANDLER(IOPORT("JOY")) MCFG_PIA_READPB_HANDLER(IOPORT("DSW3")) MCFG_PIA_IRQA_HANDLER(DEVWRITELINE("maincpu", m6809_device, irq_line)) MCFG_PIA_IRQB_HANDLER(DEVWRITELINE("maincpu", m6809_device, irq_line)) MCFG_DEVICE_ADD( "pia1", PIA6821, 0) MCFG_PIA_READPA_HANDLER(READ8(icecold_state, ay_r)) MCFG_PIA_WRITEPA_HANDLER(WRITE8(icecold_state, ay_w)) MCFG_PIA_WRITEPB_HANDLER(WRITE8(icecold_state, snd_ctrl_w)) MCFG_PIA_IRQA_HANDLER(DEVWRITELINE("maincpu", m6809_device, firq_line)) MCFG_PIA_IRQB_HANDLER(DEVWRITELINE("maincpu", m6809_device, firq_line)) MCFG_DEVICE_ADD( "pia2", PIA6821, 0) MCFG_PIA_IRQA_HANDLER(DEVWRITELINE("maincpu", m6809_device, irq_line)) MCFG_PIA_IRQB_HANDLER(DEVWRITELINE("maincpu", m6809_device, irq_line)) MCFG_DEVICE_ADD("i8279", I8279, XTAL_6MHz/4) MCFG_I8279_OUT_IRQ_CB(DEVWRITELINE("pia0", pia6821_device, cb1_w)) // irq MCFG_I8279_OUT_SL_CB(WRITE8(icecold_state, scanlines_w)) // scan SL lines MCFG_I8279_OUT_DISP_CB(WRITE8(icecold_state, digit_w)) // display A&B MCFG_I8279_IN_RL_CB(READ8(icecold_state, kbd_r)) // kbd RL lines // 30Hz signal from CH-C of ay0 MCFG_TIMER_DRIVER_ADD_PERIODIC("sint_timer", icecold_state, icecold_sint_timer, attotime::from_hz(30)) // for update motors position MCFG_TIMER_DRIVER_ADD_PERIODIC("motors_timer", icecold_state, icecold_motors_timer, attotime::from_msec(50)) // video hardware MCFG_DEFAULT_LAYOUT(layout_icecold) // sound hardware MCFG_SPEAKER_STANDARD_MONO("mono") MCFG_SOUND_ADD("ay0", AY8910, XTAL_6MHz/4) MCFG_AY8910_PORT_A_READ_CB(IOPORT("DSW4")) MCFG_AY8910_PORT_B_WRITE_CB(WRITE8(icecold_state, ay8910_0_b_w)) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) MCFG_SOUND_ADD("ay1", AY8910, XTAL_6MHz/4) MCFG_AY8910_PORT_A_WRITE_CB(WRITE8(icecold_state, ay8910_1_a_w)) MCFG_AY8910_PORT_B_WRITE_CB(WRITE8(icecold_state, ay8910_1_b_w)) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25) MACHINE_CONFIG_END /*------------------------------------------------------------------- / Ice Cold Beer /-------------------------------------------------------------------*/ ROM_START(icecold) ROM_REGION(0x10000, "maincpu", 0) ROM_LOAD("icb23b.bin", 0xe000, 0x2000, CRC(b5b69d0a) SHA1(86f5444700adebb7b2d9da702b6d5425c8d682e3)) ROM_LOAD("icb24.bin", 0xc000, 0x2000, CRC(2d1e7282) SHA1(6f170e24f71d1504195face5f67176b55c933eef)) ROM_END /*------------------------------------------------------------------- / Zeke's Peak /-------------------------------------------------------------------*/ ROM_START(zekepeak) ROM_REGION(0x10000, "maincpu", 0) ROM_LOAD("zp23.bin", 0xe000, 0x2000, CRC(ef959586) SHA1(7f8a4787b340bfa34180164806b181b5fb4e5cfa)) ROM_LOAD("zp24.bin", 0xc000, 0x2000, CRC(ee90c8f5) SHA1(27a513000e90536e485ccdf43786b415b3c95bd7)) ROM_END GAME(1983, icecold, 0, icecold, icecold, driver_device, 0, ROT0, "Taito", "Ice Cold Beer", MACHINE_NOT_WORKING | MACHINE_MECHANICAL) GAME(1983, zekepeak, icecold, icecold, icecold, driver_device, 0, ROT0, "Taito", "Zeke's Peak", MACHINE_NOT_WORKING | MACHINE_MECHANICAL)