// license:BSD-3-Clause // copyright-holders:Sandro Ronco /*************************************************************************** ============================================================================ SEGA GOLDEN POKER SERIES "JOKER'S WILD" (REV.B) (c) SEGA MAIN CPU : 68000 Z-80 CRTC : HITACHI HD63484 (24KHz OUTPUT) SOUND : YM3438 14584B.EPR ; MAIN BOARD IC20 EPR-14584B (27C1000 MAIN-ODD) 14585B.EPR ; MAIN BOARD IC22 EPR-14585B (27C1000 MAIN-EVEN) 14586.EPR ; MAIN BOARD IC26 EPR-14586 (27C4096 BG) 14587A.EPR ; SOUND BOARD IC51 EPR-14587A (27C1000 SOUND) ------------------------------------------------------------------ ***************************************************************************/ /* Also seem to be running on the same/similar hardware: * Deuce's Wild (http://topline.royalflush.jp/modules/contents/?%A5%DE%A5%B7%A5%F3%A5%C7%A1%BC%A5%BF%A5%D9%A1%BC%A5%B9%2F%A5%D3%A5%C7%A5%AA%A5%DD%A1%BC%A5%AB%A1%BC%2FSEGA%2FDEUCE%27S_WILD) * Draw Poker (http://topline.royalflush.jp/modules/contents/?%A5%DE%A5%B7%A5%F3%A5%C7%A1%BC%A5%BF%A5%D9%A1%BC%A5%B9%2F%A5%D3%A5%C7%A5%AA%A5%DD%A1%BC%A5%AB%A1%BC%2FSEGA%2FDRAW_POKER) */ #include "emu.h" #include "cpu/m68000/m68000.h" #include "cpu/z80/z80.h" #include "machine/gen_latch.h" #include "machine/nvram.h" #include "machine/315_5296.h" #include "sound/2612intf.h" #include "video/hd63484.h" #include "video/ramdac.h" #include "screen.h" #include "speaker.h" #include "segajw.lh" class segajw_state : public driver_device { public: segajw_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag) , m_maincpu(*this, "maincpu") , m_audiocpu(*this, "audiocpu") , m_soundlatch(*this, "soundlatch") , m_lamps(*this, "lamp%u", 0U) , m_towerlamps(*this, "towerlamp%u", 0U) { } void segajw(machine_config &config); DECLARE_INPUT_CHANGED_MEMBER(coin_drop_start); DECLARE_CUSTOM_INPUT_MEMBER(coin_sensors_r); DECLARE_READ_LINE_MEMBER(hopper_sensors_r); private: DECLARE_READ8_MEMBER(coin_counter_r); DECLARE_WRITE8_MEMBER(coin_counter_w); DECLARE_WRITE8_MEMBER(hopper_w); DECLARE_WRITE8_MEMBER(lamps1_w); DECLARE_WRITE8_MEMBER(lamps2_w); DECLARE_WRITE8_MEMBER(coinlockout_w); // driver_device overrides virtual void machine_start() override; virtual void machine_reset() override; void ramdac_map(address_map &map); void segajw_audiocpu_io_map(address_map &map); void segajw_audiocpu_map(address_map &map); void segajw_hd63484_map(address_map &map); void segajw_map(address_map &map); // devices required_device m_maincpu; required_device m_audiocpu; required_device m_soundlatch; output_finder<16> m_lamps; output_finder<3> m_towerlamps; uint64_t m_coin_start_cycles; uint64_t m_hopper_start_cycles; uint8_t m_coin_counter; }; READ8_MEMBER(segajw_state::coin_counter_r) { return m_coin_counter ^ 0xff; } WRITE8_MEMBER(segajw_state::coin_counter_w) { m_coin_counter = data; } WRITE8_MEMBER(segajw_state::hopper_w) { m_hopper_start_cycles = data & 0x02 ? 0 : m_maincpu->total_cycles(); } WRITE8_MEMBER(segajw_state::lamps1_w) { for (int i = 0; i < 8; i++) m_lamps[i] = BIT(data, i); } WRITE8_MEMBER(segajw_state::lamps2_w) { for (int i = 0; i < 8; i++) m_lamps[8 + i] = BIT(data, i); } WRITE8_MEMBER(segajw_state::coinlockout_w) { machine().bookkeeping().coin_lockout_w(0, data & 1); for (int i = 0; i < 3; i++) m_towerlamps[i] = BIT(data, 3 + i); } INPUT_CHANGED_MEMBER( segajw_state::coin_drop_start ) { if (newval && !m_coin_start_cycles) m_coin_start_cycles = m_maincpu->total_cycles(); } READ_LINE_MEMBER( segajw_state::hopper_sensors_r ) { uint8_t data = 0; // if the hopper is active simulate the coin-out sensor if (m_hopper_start_cycles) { attotime diff = m_maincpu->cycles_to_attotime(m_maincpu->total_cycles() - m_hopper_start_cycles); if (diff > attotime::from_msec(100)) data |= 0x01; if (diff > attotime::from_msec(200)) m_hopper_start_cycles = m_maincpu->total_cycles(); } return data; } CUSTOM_INPUT_MEMBER( segajw_state::coin_sensors_r ) { uint8_t data = 0; // simulates the passage of coins through multiple sensors if (m_coin_start_cycles) { attotime diff = m_maincpu->cycles_to_attotime(m_maincpu->total_cycles() - m_coin_start_cycles); if (diff > attotime::from_msec(20) && diff < attotime::from_msec(100)) data |= 0x01; if (diff > attotime::from_msec(80) && diff < attotime::from_msec(200)) data |= 0x02; if (diff <= attotime::from_msec(100)) data |= 0x04; if (diff > attotime::from_msec(200)) m_coin_start_cycles = 0; } return data; } void segajw_state::segajw_map(address_map &map) { map(0x000000, 0x03ffff).rom(); map(0x080000, 0x080001).rw("hd63484", FUNC(hd63484_device::status16_r), FUNC(hd63484_device::address16_w)); map(0x080002, 0x080003).rw("hd63484", FUNC(hd63484_device::data16_r), FUNC(hd63484_device::data16_w)); map(0x180000, 0x180001).portr("DSW0"); map(0x180005, 0x180005).r("soundlatch2", FUNC(generic_latch_8_device::read)).w(m_soundlatch, FUNC(generic_latch_8_device::write)).umask16(0x00ff); map(0x180008, 0x180009).portr("DSW1"); map(0x18000a, 0x18000b).portr("DSW3"); map(0x18000c, 0x18000d).portr("DSW2"); map(0x1a0000, 0x1a001f).rw("io1a", FUNC(sega_315_5296_device::read), FUNC(sega_315_5296_device::write)).umask16(0x00ff); map(0x1c0000, 0x1c001f).rw("io1c", FUNC(sega_315_5296_device::read), FUNC(sega_315_5296_device::write)).umask16(0x00ff); map(0x280001, 0x280001).w("ramdac", FUNC(ramdac_device::index_w)); map(0x280003, 0x280003).w("ramdac", FUNC(ramdac_device::pal_w)); map(0x280005, 0x280005).w("ramdac", FUNC(ramdac_device::mask_w)); map(0xff0000, 0xffffff).ram().share("nvram"); } void segajw_state::segajw_audiocpu_map(address_map &map) { map(0x0000, 0x7fff).rom(); map(0xe000, 0xffff).ram(); } void segajw_state::segajw_audiocpu_io_map(address_map &map) { map.global_mask(0xff); map(0x80, 0x83).rw("ymsnd", FUNC(ym3438_device::read), FUNC(ym3438_device::write)); map(0xc0, 0xc0).r(m_soundlatch, FUNC(generic_latch_8_device::read)).w("soundlatch2", FUNC(generic_latch_8_device::write)); } void segajw_state::segajw_hd63484_map(address_map &map) { map(0x00000, 0x3ffff).ram(); map(0x80000, 0xbffff).rom().region("gfx1", 0); } static INPUT_PORTS_START( segajw ) PORT_START("IN0") 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_BIT( 0x20, IP_ACTIVE_LOW, IPT_GAMBLE_BET ) PORT_NAME("1 Bet") PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("Max Bet") PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Deal / Draw") PORT_START("IN1") PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Double") PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_GAMBLE_PAYOUT ) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("Change") PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SERVICE ) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Reset") PORT_CODE(KEYCODE_R) PORT_BIT( 0x0d, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_START("IN2") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_GAMBLE_SERVICE ) PORT_NAME("Meter") PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Last Game") PORT_CODE(KEYCODE_T) PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("M-Door") PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("D-Door") PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(segajw_state, hopper_sensors_r) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Hopper Full") PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Hopper Fill") PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_START("IN3") PORT_BIT( 0x07, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(segajw_state, coin_sensors_r) PORT_BIT( 0xf8, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_START("COIN1") // start the coin drop sequence (see coin_sensors_r) PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_COIN1 ) PORT_CHANGED_MEMBER(DEVICE_SELF, segajw_state, coin_drop_start, 0) PORT_START("DSW1") PORT_DIPNAME( 0x0001, 0x0000, "Progressive" ) PORT_DIPLOCATION("SW1:1") PORT_DIPSETTING( 0x0001, "Normal" ) PORT_DIPSETTING( 0x0000, "Progressive" ) PORT_DIPNAME( 0x0002, 0x0000, "Double Down" ) PORT_DIPLOCATION("SW1:2") PORT_DIPSETTING( 0x0002, "With D.D" ) PORT_DIPSETTING( 0x0000, "Without D.D" ) PORT_DIPNAME( 0x0004, 0x0000, "Draw Cards" ) PORT_DIPLOCATION("SW1:3") PORT_DIPSETTING( 0x0004, "Display" ) PORT_DIPSETTING( 0x0000, "No Display" ) PORT_DIPNAME( 0x0008, 0x0000, "Color Change" ) PORT_DIPLOCATION("SW1:4") PORT_DIPSETTING( 0x0008, "Change" ) PORT_DIPSETTING( 0x0000, "No Change" ) PORT_DIPNAME( 0x0010, 0x0000, "Odds Table" ) PORT_DIPLOCATION("SW1:5") PORT_DIPSETTING( 0x0010, "No Display" ) PORT_DIPSETTING( 0x0000, "Display" ) PORT_DIPNAME( 0x0060, 0x0000, "Play Mode" ) PORT_DIPLOCATION("SW1:6,7") PORT_DIPSETTING( 0x0000, "Coin" ) PORT_DIPSETTING( 0x0020, "Coin/Credit" ) // PORT_DIPSETTING( 0x0040, "Coin/Credit" ) PORT_DIPSETTING( 0x0060, "Credit" ) PORT_DIPNAME( 0x0080, 0x0000, "Best Choice" ) PORT_DIPLOCATION("SW1:8") PORT_DIPSETTING( 0x0080, "Display" ) PORT_DIPSETTING( 0x0000, "No Display" ) PORT_START("DSW2") PORT_DIPNAME( 0x0007, 0x0000, "Denomination" ) PORT_DIPLOCATION("SW2:1,2,3") PORT_DIPSETTING( 0x0000, "$25" ) PORT_DIPSETTING( 0x0001, "$5" ) PORT_DIPSETTING( 0x0002, "$1" ) PORT_DIPSETTING( 0x0003, "50c" ) PORT_DIPSETTING( 0x0004, "25c" ) PORT_DIPSETTING( 0x0005, "10c" ) PORT_DIPSETTING( 0x0006, "5c" ) PORT_DIPSETTING( 0x0007, "Medal" ) PORT_DIPNAME( 0x0008, 0x0000, "Max. Pay" ) PORT_DIPLOCATION("SW2:4") PORT_DIPSETTING( 0x0008, "500" ) PORT_DIPSETTING( 0x0000, "1000" ) PORT_DIPNAME( 0x0010, 0x0000, "Max. Credit" ) PORT_DIPLOCATION("SW2:5") PORT_DIPSETTING( 0x0010, "5000" ) PORT_DIPSETTING( 0x0000, "1000" ) PORT_DIPNAME( 0x0020, 0x0000, "$1200" ) PORT_DIPLOCATION("SW2:6") PORT_DIPSETTING( 0x0020, "At. Pay" ) PORT_DIPSETTING( 0x0000, "Credit/At. Pay" ) PORT_DIPNAME( 0x00c0, 0x0000, "Max. Bet" ) PORT_DIPLOCATION("SW2:7,8") PORT_DIPSETTING( 0x0000, "10" ) PORT_DIPSETTING( 0x00c0, "5" ) PORT_DIPSETTING( 0x0040, "3" ) PORT_DIPSETTING( 0x0080, "1" ) PORT_START("DSW3") PORT_DIPNAME( 0x0001, 0x0001, "Meter" ) PORT_DIPLOCATION("SW3:1") PORT_DIPSETTING( 0x0001, "Nevada" ) PORT_DIPSETTING( 0x0000, "New Jersey" ) PORT_DIPNAME( 0x0002, 0x0002, "Card Face" ) PORT_DIPLOCATION("SW3:2") PORT_DIPSETTING( 0x0002, "Changeable" ) PORT_DIPSETTING( 0x0000, "Original" ) PORT_DIPNAME( 0x0004, 0x0004, "Card Back" ) PORT_DIPLOCATION("SW3:3") PORT_DIPSETTING( 0x0004, "Changeable" ) PORT_DIPSETTING( 0x0000, "Original" ) PORT_DIPUNUSED( 0x0008, 0x0008) PORT_DIPLOCATION("SW3:4") PORT_DIPUNUSED( 0x0010, 0x0010) PORT_DIPLOCATION("SW3:5") PORT_DIPUNUSED( 0x0020, 0x0020) PORT_DIPLOCATION("SW3:6") PORT_DIPUNUSED( 0x0040, 0x0040) PORT_DIPLOCATION("SW3:7") PORT_DIPUNUSED( 0x0080, 0x0080) PORT_DIPLOCATION("SW3:8") PORT_START("DSW0") PORT_DIPNAME( 0x0001, 0x0000, "Jumper 1" ) PORT_DIPLOCATION("SW4:1") PORT_DIPSETTING( 0x0001, DEF_STR( Off ) ) PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) PORT_DIPNAME( 0x0002, 0x0000, "Jumper 2" ) PORT_DIPLOCATION("SW4:2") PORT_DIPSETTING( 0x0002, DEF_STR( Off ) ) PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) PORT_DIPNAME( 0x0004, 0x0000, "Jumper 3" ) PORT_DIPLOCATION("SW4:3") PORT_DIPSETTING( 0x0004, DEF_STR( Off ) ) PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) PORT_DIPNAME( 0x0008, 0x0000, "Jumper 4" ) PORT_DIPLOCATION("SW4:4") PORT_DIPSETTING( 0x0008, DEF_STR( Off ) ) PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) PORT_DIPNAME( 0x0010, 0x0000, "Jumper 5" ) PORT_DIPLOCATION("SW4:5") PORT_DIPSETTING( 0x0010, DEF_STR( Off ) ) PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) PORT_DIPNAME( 0x0020, 0x0000, "Jumper 6" ) PORT_DIPLOCATION("SW4:6") PORT_DIPSETTING( 0x0020, DEF_STR( Off ) ) PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) PORT_DIPNAME( 0x0040, 0x0000, "Jumper 7" ) PORT_DIPLOCATION("SW4:7") PORT_DIPSETTING( 0x0040, DEF_STR( Off ) ) PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) PORT_DIPNAME( 0x0080, 0x0000, "Jumper 8" ) PORT_DIPLOCATION("SW4:8") PORT_DIPSETTING( 0x0080, DEF_STR( Off ) ) PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) INPUT_PORTS_END void segajw_state::machine_start() { m_lamps.resolve(); m_towerlamps.resolve(); save_item(NAME(m_coin_start_cycles)); save_item(NAME(m_hopper_start_cycles)); save_item(NAME(m_coin_counter)); } void segajw_state::machine_reset() { m_coin_start_cycles = 0; m_hopper_start_cycles = 0; m_coin_counter = 0xff; } void segajw_state::ramdac_map(address_map &map) { map(0x000, 0x3ff).rw("ramdac", FUNC(ramdac_device::ramdac_pal_r), FUNC(ramdac_device::ramdac_rgb666_w)); } void segajw_state::segajw(machine_config &config) { /* basic machine hardware */ M68000(config, m_maincpu, 8000000); // unknown clock m_maincpu->set_addrmap(AS_PROGRAM, &segajw_state::segajw_map); m_maincpu->set_vblank_int("screen", FUNC(segajw_state::irq4_line_hold)); Z80(config, m_audiocpu, 4000000); // unknown clock m_audiocpu->set_addrmap(AS_PROGRAM, &segajw_state::segajw_audiocpu_map); m_audiocpu->set_addrmap(AS_IO, &segajw_state::segajw_audiocpu_io_map); config.set_maximum_quantum(attotime::from_hz(2000)); NVRAM(config, "nvram", nvram_device::DEFAULT_NONE); sega_315_5296_device &io1a(SEGA_315_5296(config, "io1a", 0)); // unknown clock io1a.out_pa_callback().set(FUNC(segajw_state::coin_counter_w)); io1a.out_pb_callback().set(FUNC(segajw_state::lamps1_w)); io1a.out_pc_callback().set(FUNC(segajw_state::lamps2_w)); io1a.out_pd_callback().set(FUNC(segajw_state::hopper_w)); io1a.in_pf_callback().set(FUNC(segajw_state::coin_counter_r)); sega_315_5296_device &io1c(SEGA_315_5296(config, "io1c", 0)); // unknown clock io1c.in_pa_callback().set_ioport("IN0"); io1c.in_pb_callback().set_ioport("IN1"); io1c.in_pc_callback().set_ioport("IN2"); io1c.in_pd_callback().set_ioport("IN3"); io1c.out_pg_callback().set(FUNC(segajw_state::coinlockout_w)); /* video hardware */ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); screen.set_refresh_hz(60); screen.set_vblank_time(ATTOSECONDS_IN_USEC(0)); screen.set_screen_update("hd63484", FUNC(hd63484_device::update_screen)); screen.set_size(720, 480); screen.set_visarea(0, 720-1, 0, 448-1); screen.set_palette("palette"); PALETTE(config, "palette").set_entries(16); ramdac_device &ramdac(RAMDAC(config, "ramdac", 0, "palette")); ramdac.set_addrmap(0, &segajw_state::ramdac_map); hd63484_device &hd63484(HD63484(config, "hd63484", 8000000)); hd63484.set_addrmap(0, &segajw_state::segajw_hd63484_map); // unknown clock /* sound hardware */ SPEAKER(config, "mono").front_center(); GENERIC_LATCH_8(config, m_soundlatch); m_soundlatch->data_pending_callback().set_inputline(m_audiocpu, INPUT_LINE_NMI); GENERIC_LATCH_8(config, "soundlatch2"); ym3438_device &ymsnd(YM3438(config, "ymsnd", 8000000)); // unknown clock ymsnd.irq_handler().set_inputline("maincpu", 5); ymsnd.add_route(ALL_OUTPUTS, "mono", 0.50); } /*************************************************************************** Game driver(s) ***************************************************************************/ ROM_START( segajw ) ROM_REGION( 0x40000, "maincpu", 0 ) ROM_LOAD16_BYTE( "14584b.epr", 0x00001, 0x20000, CRC(d3a6d63d) SHA1(ce9d4769b7514294a91af1dfd7cd10ee40b3572c) ) ROM_LOAD16_BYTE( "14585b.epr", 0x00000, 0x20000, CRC(556d0a62) SHA1(d2def433a511cbdebbe2cd0c8e51fc8c4ff1ed7b) ) ROM_REGION( 0x20000, "audiocpu", 0 ) ROM_LOAD( "14587a.epr", 0x00000, 0x20000, CRC(66163b6c) SHA1(88e994bcad86c58dc730a93b48226e9296df7667) ) ROM_REGION16_BE( 0x80000, "gfx1", 0 ) ROM_LOAD16_WORD_SWAP( "14586.epr", 0x00000, 0x80000, CRC(daeb0616) SHA1(17a8bb7137ad46a7c3ac07d22cbc4430e76e2f71) ) ROM_END GAMEL( 1991, segajw, 0, segajw, segajw, segajw_state, empty_init, ROT0, "Sega", "Joker's Wild (Rev. B)", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE, layout_segajw )