// license:BSD-3-Clause // copyright-holders:Takahiro Nogi, hap /*************************************************************************** Dottori Kun (Head On's mini game) (c)1990 SEGA Driver by Takahiro Nogi (nogi@kt.rim.or.jp) 1999/12/15 - CPU : Z-80 (4MHz) SOUND : (none) 14479.MPR ; PRG (FIRST VER) 14479A.MPR ; PRG (NEW VER) * This game is only for the test of cabinet * BackRaster = WHITE on the FIRST version. * BackRaster = BLACK on the NEW version. * On the NEW version, push COIN-SW as TEST MODE. * 0000-3FFF:ROM 8000-85FF:VRAM(128x96) 8600-87FF:WORK-RAM TODO: - improve video timing more (see http://www.chrismcovell.com/dottorikun.html) ***************************************************************************/ #include "emu.h" #include "cpu/z80/z80.h" #include "machine/timer.h" #include "emupal.h" #include "screen.h" #define MASTER_CLOCK XTAL(4'000'000) class dotrikun_state : public driver_device { public: dotrikun_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), m_screen(*this, "screen"), m_vram(*this, "vram"), m_interrupt_timer(*this, "interrupt"), m_scanline_off_timer(*this, "scanline_off") { } void dotrikun(machine_config &config); protected: required_device m_maincpu; required_device m_screen; required_shared_ptr m_vram; required_device m_interrupt_timer; required_device m_scanline_off_timer; uint8_t m_vram_latch; uint8_t m_color; void vram_w(offs_t offset, uint8_t data); void color_w(uint8_t data); uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); TIMER_DEVICE_CALLBACK_MEMBER(interrupt); TIMER_DEVICE_CALLBACK_MEMBER(scanline_off); TIMER_DEVICE_CALLBACK_MEMBER(scanline_on); virtual void machine_start() override; virtual void machine_reset() override; void dotrikun_map(address_map &map); void io_map(address_map &map); }; TIMER_DEVICE_CALLBACK_MEMBER(dotrikun_state::interrupt) { m_maincpu->pulse_input_line(0, attotime::from_hz(MASTER_CLOCK/128)); } TIMER_DEVICE_CALLBACK_MEMBER(dotrikun_state::scanline_off) { m_maincpu->set_unscaled_clock(MASTER_CLOCK); } TIMER_DEVICE_CALLBACK_MEMBER(dotrikun_state::scanline_on) { // on vram fetch(every 8 pixels during active display), z80 is stalled for 2 clocks if (param < 192) { m_maincpu->set_unscaled_clock(MASTER_CLOCK * 0.75); m_scanline_off_timer->adjust(m_screen->time_until_pos(param, 128)); } // vblank interrupt if (param == 191) m_interrupt_timer->adjust(m_screen->time_until_pos(param, 128+64)); } /************************************* * * Video emulation * *************************************/ void dotrikun_state::vram_w(offs_t offset, uint8_t data) { m_screen->update_now(); m_vram[offset] = data; } void dotrikun_state::color_w(uint8_t data) { // d0-d2: fg palette // d3-d5: bg palette // d6,d7: N/C m_screen->update_now(); m_color = data & 0x3f; } uint32_t dotrikun_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { for (int y = cliprect.min_y; y <= cliprect.max_y; y++) { for (int x = cliprect.min_x; x <= cliprect.max_x; x++) { // vram fetch if ((x & 7) == 0) m_vram_latch = m_vram[x >> 3 | y >> 1 << 4]; bitmap.pix16(y, x) = (m_vram_latch >> (~x & 7) & 1) ? m_color & 7 : m_color >> 3; } } return 0; } /************************************* * * Address maps * *************************************/ void dotrikun_state::dotrikun_map(address_map &map) { map(0x0000, 0x3fff).rom(); map(0x8000, 0x85ff).ram().w(FUNC(dotrikun_state::vram_w)).share("vram"); map(0x8600, 0x87ff).ram(); } void dotrikun_state::io_map(address_map &map) { map.global_mask(0xff); map(0x00, 0x00).mirror(0xff).portr("INPUTS").w(FUNC(dotrikun_state::color_w)); } /************************************* * * Input ports * *************************************/ static INPUT_PORTS_START( dotrikun ) PORT_START("INPUTS") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_START1 ) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_COIN1 ) INPUT_PORTS_END /************************************* * * Machine driver * *************************************/ void dotrikun_state::machine_start() { save_item(NAME(m_vram_latch)); save_item(NAME(m_color)); } void dotrikun_state::machine_reset() { m_vram_latch = 0; m_color = 0; } void dotrikun_state::dotrikun(machine_config &config) { /* basic machine hardware */ Z80(config, m_maincpu, MASTER_CLOCK); m_maincpu->set_addrmap(AS_PROGRAM, &dotrikun_state::dotrikun_map); m_maincpu->set_addrmap(AS_IO, &dotrikun_state::io_map); TIMER(config, "scanline_on").configure_scanline(FUNC(dotrikun_state::scanline_on), "screen", 0, 1); TIMER(config, m_scanline_off_timer).configure_generic(FUNC(dotrikun_state::scanline_off)); TIMER(config, m_interrupt_timer).configure_generic(FUNC(dotrikun_state::interrupt)); /* video hardware */ SCREEN(config, m_screen, SCREEN_TYPE_RASTER); m_screen->set_raw(MASTER_CLOCK, 128+128, 0, 128, 192+64, 0, 192); m_screen->set_physical_aspect(1, 1); // large border area m_screen->set_screen_update(FUNC(dotrikun_state::screen_update)); m_screen->set_video_attributes(VIDEO_ALWAYS_UPDATE); m_screen->set_palette("palette"); PALETTE(config, "palette", palette_device::RGB_3BIT); /* no sound hardware */ } /*************************************************************************** Game driver(s) ***************************************************************************/ ROM_START( dotrikun ) ROM_REGION( 0x10000, "maincpu", 0 ) ROM_LOAD( "14479a.mpr", 0x0000, 0x4000, CRC(b77a50db) SHA1(2a5d812d39f0f58f5c3e1b46f80aca75aa225115) ) ROM_END ROM_START( dotrikun2 ) ROM_REGION( 0x10000, "maincpu", 0 ) ROM_LOAD( "epr-13141.ic2", 0x0000, 0x4000, CRC(a6aa7fa5) SHA1(4dbea33fb3541fdacf2195355751078a33bb30d5) ) ROM_END ROM_START( dotriman ) ROM_REGION( 0x10000, "maincpu", 0 ) ROM_LOAD( "14479a.mpr", 0x0000, 0x4000, CRC(4ba6d2f5) SHA1(db805e9121ecbd41fac4593b58d7f071e7dbc720) ) ROM_END GAME( 1990, dotrikun, 0, dotrikun, dotrikun, dotrikun_state, empty_init, ROT0, "Sega", "Dottori Kun (new version)", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND_HW ) GAME( 1990, dotrikun2, dotrikun, dotrikun, dotrikun, dotrikun_state, empty_init, ROT0, "Sega", "Dottori Kun (old version)", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND_HW ) GAME( 2016, dotriman, dotrikun, dotrikun, dotrikun, dotrikun_state, empty_init, ROT0, "hack (Chris Covell)", "Dottori-Man Jr.", MACHINE_SUPPORTS_SAVE | MACHINE_NO_SOUND_HW )