From dec6f8fe8d1f35d7a241c3b0a62b7860297aa6eb Mon Sep 17 00:00:00 2001 From: David Haywood <28625134+DavidHaywood@users.noreply.github.com> Date: Tue, 28 Mar 2023 18:35:44 +0100 Subject: tch/topdrive.cpp: Added driver for Proyesel Top Driving. (#11043) new WORKING machine ------------------- Top Driving (Version 1.1) [ClawGrip, Museo del Recreativo, Recreativas.org, David Haywood] --- src/mame/mame.lst | 3 + src/mame/tch/kickgoal.cpp | 6 +- src/mame/tch/topdrive.cpp | 317 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 323 insertions(+), 3 deletions(-) create mode 100644 src/mame/tch/topdrive.cpp diff --git a/src/mame/mame.lst b/src/mame/mame.lst index f127f900d63..55939eee2b0 100755 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -43016,6 +43016,9 @@ rltennisa // (c) 1993 TCH @source:tch/speedspn.cpp speedspn // (c) 1994 +@source:tch/topdrive.cpp +topdrive // (c) 1995 + @source:tch/wheelfir.cpp wheelfir // (c) 199? TCH diff --git a/src/mame/tch/kickgoal.cpp b/src/mame/tch/kickgoal.cpp index 3250b613e8b..d2452d965fb 100644 --- a/src/mame/tch/kickgoal.cpp +++ b/src/mame/tch/kickgoal.cpp @@ -557,7 +557,7 @@ void kickgoal_state::init_actionhw() m_maincpu->space(AS_PROGRAM).install_write_handler(0x800004, 0x800005, write16s_delegate(*this, FUNC(kickgoal_state::actionhw_snd_w))); } -GAME( 1995, kickgoal, 0, kickgoal, kickgoal, kickgoal_state, init_kickgoal, ROT0, "TCH", "Kick Goal (set 1)", MACHINE_SUPPORTS_SAVE ) -GAME( 1995, kickgoala, kickgoal, kickgoal, kickgoal, kickgoal_state, init_kickgoal, ROT0, "TCH", "Kick Goal (set 2)", MACHINE_SUPPORTS_SAVE ) +GAME( 1995, kickgoal, 0, kickgoal, kickgoal, kickgoal_state, init_kickgoal, ROT0, "TCH / Proyesel", "Kick Goal (set 1)", MACHINE_SUPPORTS_SAVE ) +GAME( 1995, kickgoala, kickgoal, kickgoal, kickgoal, kickgoal_state, init_kickgoal, ROT0, "TCH / Proyesel", "Kick Goal (set 2)", MACHINE_SUPPORTS_SAVE ) -GAME( 1995, actionhw, 0, actionhw, kickgoal, kickgoal_state, init_actionhw, ROT0, "TCH", "Action Hollywood", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) +GAME( 1995, actionhw, 0, actionhw, kickgoal, kickgoal_state, init_actionhw, ROT0, "TCH / Proyesel", "Action Hollywood", MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/tch/topdrive.cpp b/src/mame/tch/topdrive.cpp new file mode 100644 index 00000000000..392e2d7b570 --- /dev/null +++ b/src/mame/tch/topdrive.cpp @@ -0,0 +1,317 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +// Top Driving by Proyesel - PRO-4/B PCB +// an alt version of this called Mortal Race has been seen, a logo for it also exists in the ROM. +// https://www.recreativas.org/mortal-race-2435-ecogames-sl "1995 New Dream Games S.L. Palma MCA Spain" + +#include "emu.h" + +#include "cpu/m68000/m68000.h" +#include "machine/eepromser.h" +#include "sound/okim6295.h" + +#include "emupal.h" +#include "screen.h" +#include "speaker.h" +#include "tilemap.h" + +// TODO: +// Wheel support - what is IRQ6 for? wheel? +// Measure clocks, refresh frequency +// Is it worth merging with kickgoal.cpp? + +namespace { + +class topdrive_state : public driver_device +{ +public: + topdrive_state(const machine_config &mconfig, device_type type, const char *tag) : + driver_device(mconfig, type, tag), + m_maincpu(*this, "maincpu"), + m_eeprom(*this, "eeprom") , + m_palette(*this, "palette"), + m_gfxdecode(*this, "gfxdecode"), + m_scrram(*this, "scrram"), + m_spriteram(*this, "spriteram"), + m_bg2_videoram(*this, "bg2_videoram"), + m_bg_videoram(*this, "bg_videoram"), + m_fg_videoram(*this, "fg_videoram") + { } + + void topdrive(machine_config &config) ATTR_COLD; + +protected: + virtual void video_start() override ATTR_COLD; + +private: + required_device m_maincpu; + required_device m_eeprom; + required_device m_palette; + required_device m_gfxdecode; + + required_shared_ptr m_scrram; + required_shared_ptr m_spriteram; + required_shared_ptr m_bg2_videoram; + required_shared_ptr m_bg_videoram; + required_shared_ptr m_fg_videoram; + + // video-related + tilemap_t *m_bg2_tilemap = nullptr; + tilemap_t *m_bg_tilemap = nullptr; + tilemap_t *m_fg_tilemap = nullptr; + + void bg2_videoram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + void bg_videoram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + void fg_videoram_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0); + + void soundbank_w(offs_t offset, uint16_t data, uint16_t mem_mask = ~0) + { + // In theory this would be sample banking (it writes a value of 01 on startup) + // however all samples addresses in header are sequential, and data after + // the last used sample doesn't appear to be sound data anyway. + // Furthermore no other values are ever written here + } + + TILE_GET_INFO_MEMBER(get_bg2_tile_info); + TILE_GET_INFO_MEMBER(get_bg_tile_info); + TILE_GET_INFO_MEMBER(get_fg_tile_info); + + uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + TILEMAP_MAPPER_MEMBER(tilemap_scan_16x16); + + void topdrive_map(address_map &map) ATTR_COLD; + + void draw_sprites(bitmap_ind16 &bitmap,const rectangle &cliprect, int drawpri); +}; + + +TILEMAP_MAPPER_MEMBER(topdrive_state::tilemap_scan_16x16) +{ + /* logical (col,row) -> memory offset */ + return (row & 0xf) | ((col & 0x3f) << 4) | ((row & 0x30) << 6); +} + +void topdrive_state::draw_sprites(bitmap_ind16 &bitmap,const rectangle &cliprect, int drawpri) +{ + for (int offs = 0; offs < m_spriteram.length(); offs += 4) + { + int xpos = m_spriteram[offs + 3]; + int ypos = m_spriteram[offs + 0] & 0x00ff; + u16 const tileno = m_spriteram[offs + 2] & 0x3fff; + bool const pri = (m_spriteram[offs + 1] & 0x0010)>>4; // 0x0020 is NOT flip like kickgoal.cpp, probably another priority bit + u16 const color = m_spriteram[offs + 1] & 0x000f; + + if (m_spriteram[offs + 0] & 0x0100) break; + + if (pri != drawpri) + continue; + + ypos = 0x110 - ypos; + + m_gfxdecode->gfx(0)->transpen(bitmap, cliprect, + tileno, + color + 0x30, + 0,0, + xpos-64+2, ypos-31, 15); + } +} + +void topdrive_state::bg2_videoram_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + COMBINE_DATA(&m_bg2_videoram[offset]); + m_bg2_tilemap->mark_tile_dirty(offset); +} + +TILE_GET_INFO_MEMBER(topdrive_state::get_bg2_tile_info) +{ + int const tileno = m_bg2_videoram[tile_index] & 0x1fff; + int const color = (m_bg2_videoram[tile_index] & 0xe000) >> 13; + tileinfo.set(0, tileno+0x3000, color+0x20, 0); +} + +void topdrive_state::bg_videoram_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + COMBINE_DATA(&m_bg_videoram[offset]); + m_bg_tilemap->mark_tile_dirty(offset); +} + +TILE_GET_INFO_MEMBER(topdrive_state::get_bg_tile_info) +{ + int const tileno = m_bg_videoram[tile_index] & 0x1fff; + int const color = (m_bg_videoram[tile_index] & 0xe000) >> 13; + tileinfo.set(0, tileno+0x6000, color+0x10, 0); +} + +void topdrive_state::fg_videoram_w(offs_t offset, uint16_t data, uint16_t mem_mask) +{ + COMBINE_DATA(&m_fg_videoram[offset]); + m_fg_tilemap->mark_tile_dirty(offset); +} + +TILE_GET_INFO_MEMBER(topdrive_state::get_fg_tile_info) +{ + int const tileno = m_fg_videoram[tile_index] & 0x1fff; + int const color = (m_fg_videoram[tile_index] & 0xe000) >> 13; + tileinfo.set(0, tileno+0x4000, color+0x00, 0); +} + +void topdrive_state::video_start() +{ + m_bg2_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(topdrive_state::get_bg2_tile_info)), tilemap_mapper_delegate(*this, FUNC(topdrive_state::tilemap_scan_16x16)), 16, 16, 32, 16); + m_bg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(topdrive_state::get_bg_tile_info)), tilemap_mapper_delegate(*this, FUNC(topdrive_state::tilemap_scan_16x16)), 16, 16, 32, 16); + m_fg_tilemap = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(topdrive_state::get_fg_tile_info)), tilemap_mapper_delegate(*this, FUNC(topdrive_state::tilemap_scan_16x16)), 16, 16, 32, 16); + + m_bg_tilemap->set_transparent_pen(0xf); + m_fg_tilemap->set_transparent_pen(0xf); +} + +uint32_t topdrive_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +{ + m_fg_tilemap->set_scrollx(0, m_scrram[0]+50); + m_fg_tilemap->set_scrolly(0, m_scrram[1]); + m_bg_tilemap->set_scrollx(0, m_scrram[2]+50); + m_bg_tilemap->set_scrolly(0, m_scrram[3]); + m_bg2_tilemap->set_scrollx(0, m_scrram[4]+50); + m_bg2_tilemap->set_scrolly(0, m_scrram[5]); + + m_bg2_tilemap->draw(screen, bitmap, cliprect, 0, 0); + m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0); + draw_sprites(bitmap, cliprect, 0); + m_fg_tilemap->draw(screen, bitmap, cliprect, 0, 0); + draw_sprites(bitmap, cliprect, 1); + + return 0; +} + +void topdrive_state::topdrive_map(address_map &map) +{ + map(0x000000, 0x0fffff).rom(); + + map(0x800000, 0x800001).portr("P1_P2"); + map(0x800002, 0x800003).portr("SYSTEM"); + // map(0x800006, 0x800007) // accessed in service menu, wheel maybe? + + map(0x900001, 0x900001).lw8(NAME([this] (u8 data) { m_eeprom->cs_write(BIT(data, 0)); })); + map(0x900003, 0x900003).lw8(NAME([this] (u8 data) { m_eeprom->clk_write(BIT(data, 0)); })); + map(0x900005, 0x900005).lw8(NAME([this] (u8 data) { m_eeprom->di_write(BIT(data, 0)); })); + map(0x900007, 0x900007).lr8(NAME([this] () { return u8(m_eeprom->do_read()); })); + + map(0xa00000, 0xa003ff).ram().w(FUNC(topdrive_state::fg_videoram_w)).share(m_fg_videoram); + map(0xa00400, 0xa01fff).ram(); + + map(0xa02000, 0xa03fff).ram(); // buffer for scroll regs? or layer configs? + + map(0xa04000, 0xa043ff).ram().w(FUNC(topdrive_state::bg_videoram_w)).share(m_bg_videoram); + map(0xa04400, 0xa07fff).ram(); + + map(0xa08000, 0xa083ff).ram().w(FUNC(topdrive_state::bg2_videoram_w)).share(m_bg2_videoram); + map(0xa08400, 0xa0bfff).ram(); + + map(0xa0c000, 0xa0c3ff).ram(); // seems to be a buffer for data that gets put at 0xa00000? + map(0xa0c400, 0xa0ffff).ram(); + + map(0xa10000, 0xa1000f).ram().share(m_scrram); + + map(0xb00000, 0xb007ff).ram().share(m_spriteram); + map(0xc00000, 0xc007ff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette"); + map(0xe00003, 0xe00003).rw("oki", FUNC(okim6295_device::read), FUNC(okim6295_device::write)); + map(0xe00004, 0xe00005).w(FUNC(topdrive_state::soundbank_w)); + + map(0xf00000, 0xf2ffff).ram(); + map(0xff0000, 0xffffff).ram(); +} + +static INPUT_PORTS_START( topdrive ) + PORT_START("P1_P2") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1) + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1) + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1) + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1) + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_UNKNOWN ) + + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2) + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2) + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2) + PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2) + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) + + PORT_START("SYSTEM") + PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_UNKNOWN ) + + PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_COIN1 ) + PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_COIN2 ) + PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_SERVICE_NO_TOGGLE( 0x0800, IP_ACTIVE_LOW ) + PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_START1 ) + PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_START2 ) + PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_UNKNOWN ) + PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNKNOWN ) +INPUT_PORTS_END + +static GFXDECODE_START( gfx_topdrive ) + GFXDECODE_ENTRY( "gfx1", 0, gfx_16x16x4_planar, 0x000, 0x40 ) +GFXDECODE_END + + +void topdrive_state::topdrive(machine_config &config) +{ + M68000(config, m_maincpu, XTAL(12'000'000)); + m_maincpu->set_addrmap(AS_PROGRAM, &topdrive_state::topdrive_map); + m_maincpu->set_vblank_int("screen", FUNC(topdrive_state::irq2_line_hold)); // irq6 also looks valid? + + EEPROM_93C46_16BIT(config, m_eeprom); + + GFXDECODE(config, m_gfxdecode, "palette", gfx_topdrive); + + screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER)); + screen.set_refresh_hz(50); // not verified + screen.set_vblank_time(ATTOSECONDS_IN_USEC(2000)); + screen.set_size(64*8, 32*8); + screen.set_visarea(0*8, 48*8-1, 0*8, 30*8-1); + screen.set_screen_update(FUNC(topdrive_state::screen_update)); + screen.set_palette("palette"); + + PALETTE(config, m_palette).set_format(palette_device::xBGR_555, 0x400); + + SPEAKER(config, "mono").front_center(); + + okim6295_device &oki(OKIM6295(config, "oki", XTAL(16'000'000) / 16, okim6295_device::PIN7_HIGH)); // clock frequency & pin 7 not verified + oki.add_route(ALL_OUTPUTS, "mono", 1.00); +} + +ROM_START( topdrive ) + ROM_REGION( 0x100000, "maincpu", 0 ) + ROM_LOAD16_BYTE( "2-27c040.bin", 0x00000, 0x80000, CRC(37798c4e) SHA1(708a64b416bd2104fbc4b72a37bfeae33bbab454) ) + ROM_LOAD16_BYTE( "1-27c040.bin", 0x00001, 0x80000, CRC(e2dc5096) SHA1(82b22e03be225ab7f20eff6314383a9f28d52294) ) + + ROM_REGION( 0x400000, "gfx1", 0 ) + ROM_LOAD( "4-27c040.bin", 0x000000, 0x80000, CRC(a81ca7f7) SHA1(cc2030a9bea90b694adbf222389766945ce9552b) ) + ROM_LOAD( "5-27c040.bin", 0x080000, 0x80000, CRC(a756d2b2) SHA1(59ddef858850b0f6c5865d555d6402c41cc3cb6c) ) + ROM_LOAD( "6-27c040.bin", 0x100000, 0x80000, CRC(90c778a2) SHA1(8122ee085e388bb1f7952edb6a99dffc466f2e2c) ) + ROM_LOAD( "7-27c040.bin", 0x180000, 0x80000, CRC(db219087) SHA1(c79145555678971db29e91a24d69738da7d8f07f) ) + ROM_LOAD( "8-27c040.bin", 0x200000, 0x80000, CRC(0e5f4419) SHA1(4fc8173001e2b412f4a7b0b5160c853436bbb139) ) + ROM_LOAD( "9-27c040.bin", 0x280000, 0x80000, CRC(159a7426) SHA1(6851fbc1fe11ae72a86d35011730d2df641e8fc5) ) + ROM_LOAD( "10-27c040.bin", 0x300000, 0x80000, CRC(54c1617a) SHA1(7bb4faaa54581f080f19f98e78fa9cae899f4c2a) ) + ROM_LOAD( "11-27c040.bin", 0x380000, 0x80000, CRC(6b3c3c73) SHA1(8ac76abdc4676cfcd9dc66a4c7b55010de099133) ) + + ROM_REGION( 0x80000, "oki", 0 ) + ROM_LOAD( "3-27c040.bin", 0x00000, 0x80000, CRC(2894b89b) SHA1(cf884042edd2fc05e04d21ccd36f5183f9a7ec5c) ) +ROM_END + +} // anonymous namespace + +GAME( 1995, topdrive, 0, topdrive, topdrive, topdrive_state, empty_init, ROT0, "Proyesel", "Top Driving (version 1.1)", MACHINE_SUPPORTS_SAVE ) -- cgit v1.2.3