diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 13fae035ace..a458adbca9e 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -4066,6 +4066,7 @@ files { createMESSProjects(_target, _subtarget, "tvgames") files { + MAME_DIR .. "src/mame/drivers/elan_ep3a19a.cpp", MAME_DIR .. "src/mame/drivers/elan_eu3a14.cpp", MAME_DIR .. "src/mame/drivers/elan_eu3a05.cpp", MAME_DIR .. "src/mame/audio/elan_eu3a05.cpp", @@ -4074,6 +4075,8 @@ files { MAME_DIR .. "src/mame/machine/elan_eu3a05gpio.h", MAME_DIR .. "src/mame/machine/elan_eu3a05commonsys.cpp", MAME_DIR .. "src/mame/machine/elan_eu3a05commonsys.h", + MAME_DIR .. "src/mame/machine/elan_ep3a19asys.cpp", + MAME_DIR .. "src/mame/machine/elan_ep3a19asys.h", MAME_DIR .. "src/mame/machine/elan_eu3a05sys.cpp", MAME_DIR .. "src/mame/machine/elan_eu3a05sys.h", MAME_DIR .. "src/mame/machine/elan_eu3a14sys.cpp", diff --git a/src/mame/drivers/elan_ep3a19a.cpp b/src/mame/drivers/elan_ep3a19a.cpp new file mode 100644 index 00000000000..8235955bd06 --- /dev/null +++ b/src/mame/drivers/elan_ep3a19a.cpp @@ -0,0 +1,372 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + + +#include "emu.h" +#include "cpu/m6502/m6502.h" +//#include "cpu/m6502/m65c02.h" +#include "emupal.h" +#include "screen.h" +#include "speaker.h" +#include "machine/bankdev.h" +#include "audio/elan_eu3a05.h" +#include "machine/elan_eu3a05gpio.h" +#include "machine/elan_ep3a19asys.h" +#include "video/elan_eu3a05vid.h" + +class elan_ep3a19a_state : public driver_device +{ +public: + elan_ep3a19a_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag), + m_sys(*this, "sys"), + m_gpio(*this, "gpio"), + m_maincpu(*this, "maincpu"), + m_screen(*this, "screen"), + m_ram(*this, "ram"), + m_sound(*this, "eu3a05sound"), + m_vid(*this, "vid"), + m_bank(*this, "bank"), + m_gfxdecode(*this, "gfxdecode"), + m_palette(*this, "palette") + { } + + void elan_ep3a19a(machine_config &config); + + void init_tvbg(); + +protected: + // driver_device overrides + virtual void machine_start() override; + virtual void machine_reset() override; + + required_device m_sys; + required_device m_gpio; + + required_device m_maincpu; + required_device m_screen; + +private: + // screen updates + uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + + INTERRUPT_GEN_MEMBER(interrupt); + + // for callback + uint8_t read_full_space(offs_t offset); + + void elan_ep3a19a_bank_map(address_map &map); + void elan_ep3a19a_map(address_map &map); + + virtual void video_start() override; + + required_shared_ptr m_ram; + required_device m_sound; + required_device m_vid; + required_device m_bank; + required_device m_gfxdecode; + required_device m_palette; + + //DECLARE_WRITE_LINE_MEMBER(sound_end0) { m_sys->generate_custom_interrupt(2); } + //DECLARE_WRITE_LINE_MEMBER(sound_end1) { m_sys->generate_custom_interrupt(3); } + //DECLARE_WRITE_LINE_MEMBER(sound_end2) { m_sys->generate_custom_interrupt(4); } + //DECLARE_WRITE_LINE_MEMBER(sound_end3) { m_sys->generate_custom_interrupt(5); } + //DECLARE_WRITE_LINE_MEMBER(sound_end4) { m_sys->generate_custom_interrupt(6); } + //DECLARE_WRITE_LINE_MEMBER(sound_end5) { m_sys->generate_custom_interrupt(7); } + + uint8_t nmi_vector_r(offs_t offset) + { + return 0xffd4 >> (offset * 8); + } + +}; + +void elan_ep3a19a_state::video_start() +{ +} + +uint32_t elan_ep3a19a_state::screen_update(screen_device& screen, bitmap_ind16& bitmap, const rectangle& cliprect) +{ + return m_vid->screen_update(screen, bitmap, cliprect); +} + +// sound callback +uint8_t elan_ep3a19a_state::read_full_space(offs_t offset) +{ + address_space& fullbankspace = m_bank->space(AS_PROGRAM); + return fullbankspace.read_byte(offset); +} + +void elan_ep3a19a_state::elan_ep3a19a_map(address_map &map) +{ + // can the addresses move around? + map(0x0000, 0x3fff).ram().share("ram"); + map(0x4800, 0x49ff).rw(m_vid, FUNC(elan_eu3a05commonvid_device::palette_r), FUNC(elan_eu3a05commonvid_device::palette_w)); + + map(0x5000, 0x5014).m(m_sys, FUNC(elan_ep3a19asys_device::map)); // including DMA controller + map(0x5020, 0x503f).m(m_vid, FUNC(elan_eu3a05vid_device::map)); + + // 504x GPIO area? + map(0x5040, 0x5046).rw(m_gpio, FUNC(elan_eu3a05gpio_device::gpio_r), FUNC(elan_eu3a05gpio_device::gpio_w)); + // 5047 + //map(0x5048, 0x504a).w(m_gpio, FUNC(elan_eu3a05gpio_device::gpio_unk_w)); + + // 506x unknown + //map(0x5060, 0x506d).ram(); // read/written by tetris (ADC?) + + // 508x sound + map(0x5080, 0x50bf).m(m_sound, FUNC(elan_eu3a05_sound_device::map)); + + //map(0x5000, 0x50ff).ram(); + map(0x6000, 0xdfff).m(m_bank, FUNC(address_map_bank_device::amap8)); + + map(0xe000, 0xffff).rom().region("maincpu", 0x0000); + // not sure how these work, might be a modified 6502 core instead. + //map(0xfffa, 0xfffb).r(m_sys, FUNC(elan_eu3a05commonsys_device::nmi_vector_r)); // custom vectors handled with NMI for now + map(0xfffa, 0xfffb).r(FUNC(elan_ep3a19a_state::nmi_vector_r)); // custom vectors handled with NMI for now + + //map(0xfffe, 0xffff).r(m_sys, FUNC(elan_eu3a05commonsys_device::irq_vector_r)); // allow normal IRQ for brk +} + +void elan_ep3a19a_state::elan_ep3a19a_bank_map(address_map &map) +{ + map(0x000000, 0x3fffff).mirror(0xc00000).noprw(); + map(0x000000, 0x3fffff).mirror(0xc00000).rom().region("maincpu", 0); +} + + +static INPUT_PORTS_START( elan_ep3a19a ) + PORT_START("IN0") + PORT_DIPNAME( 0x0001, 0x0001, "IN0" ) + PORT_DIPSETTING( 0x0001, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0002, 0x0002, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0002, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0004, 0x0004, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0004, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0008, 0x0008, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0008, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0010, 0x0010, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0010, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0020, 0x0020, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0020, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0040, 0x0040, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0040, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0080, 0x0080, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0080, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + + PORT_START("IN1") + PORT_DIPNAME( 0x0001, 0x0001, "IN1" ) + PORT_DIPSETTING( 0x0001, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0002, 0x0002, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0002, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0004, 0x0004, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0004, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0008, 0x0008, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0008, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0010, 0x0010, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0010, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0020, 0x0020, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0020, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0040, 0x0040, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0040, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0080, 0x0080, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0080, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + + PORT_START("IN2") + 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_DIPNAME( 0x0020, 0x0020, "IN2" ) + PORT_DIPSETTING( 0x0020, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0040, 0x0040, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0040, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + PORT_DIPNAME( 0x0080, 0x0080, DEF_STR( Unknown ) ) + PORT_DIPSETTING( 0x0080, DEF_STR( Off ) ) + PORT_DIPSETTING( 0x0000, DEF_STR( On ) ) + +INPUT_PORTS_END + + +void elan_ep3a19a_state::machine_start() +{ +} + +void elan_ep3a19a_state::machine_reset() +{ + m_maincpu->set_state_int(M6502_S, 0x1ff); +} + +static const gfx_layout helper_4bpp_8_layout = +{ + 8,1, + RGN_FRAC(1,1), + 4, + { 0,1,2,3 }, + { STEP8(0,4) }, + { 0 }, + 8 * 4 +}; + +static const gfx_layout helper_8bpp_8_layout = +{ + 8,1, + RGN_FRAC(1,1), + 8, + { 0,1,2,3,4,5,6,7 }, + { STEP8(0,8) }, + { 0 }, + 8 * 8 +}; + +// these are fake just to make looking at the texture pages easier +static const uint32_t texlayout_xoffset_8bpp[256] = { STEP256(0,8) }; +static const uint32_t texlayout_yoffset_8bpp[256] = { STEP256(0,256*8) }; +static const gfx_layout texture_helper_8bpp_layout = +{ + 256, 256, + RGN_FRAC(1,1), + 8, + { 0,1,2,3,4,5,6,7 }, + EXTENDED_XOFFS, + EXTENDED_YOFFS, + 256*256*8, + texlayout_xoffset_8bpp, + texlayout_yoffset_8bpp +}; + +static const uint32_t texlayout_xoffset_4bpp[256] = { STEP256(0,4) }; +static const uint32_t texlayout_yoffset_4bpp[256] = { STEP256(0,256*4) }; +static const gfx_layout texture_helper_4bpp_layout = +{ + 256, 256, + RGN_FRAC(1,1), + 4, + { 0,1,2,3 }, + EXTENDED_XOFFS, + EXTENDED_YOFFS, + 256*256*4, + texlayout_xoffset_4bpp, + texlayout_yoffset_4bpp +}; + +static GFXDECODE_START( gfx_elan_eu3a05_fake ) + GFXDECODE_ENTRY( "maincpu", 0, helper_4bpp_8_layout, 0x0, 1 ) + GFXDECODE_ENTRY( "maincpu", 0, texture_helper_4bpp_layout, 0x0, 1 ) + GFXDECODE_ENTRY( "maincpu", 0, helper_8bpp_8_layout, 0x0, 1 ) + GFXDECODE_ENTRY( "maincpu", 0, texture_helper_8bpp_layout, 0x0, 1 ) +GFXDECODE_END + +INTERRUPT_GEN_MEMBER(elan_ep3a19a_state::interrupt) +{ + //m_sys->generate_custom_interrupt(9); + m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero); +} + +void elan_ep3a19a_state::elan_ep3a19a(machine_config &config) +{ + /* basic machine hardware */ + M6502(config, m_maincpu, XTAL(21'477'272)/8); + m_maincpu->set_addrmap(AS_PROGRAM, &elan_ep3a19a_state::elan_ep3a19a_map); + m_maincpu->set_vblank_int("screen", FUNC(elan_ep3a19a_state::interrupt)); + + ADDRESS_MAP_BANK(config, "bank").set_map(&elan_ep3a19a_state::elan_ep3a19a_bank_map).set_options(ENDIANNESS_LITTLE, 8, 24, 0x8000); + + PALETTE(config, m_palette).set_entries(256); + + SCREEN(config, m_screen, SCREEN_TYPE_RASTER); + m_screen->set_refresh_hz(60); + m_screen->set_vblank_time(ATTOSECONDS_IN_USEC(2500)); + m_screen->set_screen_update(FUNC(elan_ep3a19a_state::screen_update)); + m_screen->set_size(32*8, 32*8); + m_screen->set_visarea(0*8, 32*8-1, 0*8, 28*8-1); + m_screen->set_palette(m_palette); + + GFXDECODE(config, m_gfxdecode, m_palette, gfx_elan_eu3a05_fake); + + ELAN_EU3A05_GPIO(config, m_gpio, 0); + m_gpio->read_0_callback().set_ioport("IN0"); + m_gpio->read_1_callback().set_ioport("IN1"); + m_gpio->read_2_callback().set_ioport("IN2"); + + ELAN_EP3A19A_SYS(config, m_sys, 0); + m_sys->set_cpu("maincpu"); + m_sys->set_addrbank("bank"); + + ELAN_EU3A05_VID(config, m_vid, 0); + m_vid->set_cpu("maincpu"); + m_vid->set_addrbank("bank"); + m_vid->set_palette("palette"); + m_vid->set_entries(256); + m_vid->set_is_pvmilfin(); + m_vid->set_use_spritepages(); + m_vid->set_force_transpen_ff(); + m_vid->set_force_basic_scroll(); + + /* sound hardware */ + SPEAKER(config, "mono").front_center(); + + + ELAN_EU3A05_SOUND(config, m_sound, 8000); + m_sound->space_read_callback().set(FUNC(elan_ep3a19a_state::read_full_space)); + m_sound->add_route(ALL_OUTPUTS, "mono", 1.0); + + /* + m_sound->sound_end_cb<0>().set(FUNC(elan_ep3a19a_state::sound_end0)); + m_sound->sound_end_cb<1>().set(FUNC(elan_ep3a19a_state::sound_end1)); + m_sound->sound_end_cb<2>().set(FUNC(elan_ep3a19a_state::sound_end2)); + m_sound->sound_end_cb<3>().set(FUNC(elan_ep3a19a_state::sound_end3)); + m_sound->sound_end_cb<4>().set(FUNC(elan_ep3a19a_state::sound_end4)); + m_sound->sound_end_cb<5>().set(FUNC(elan_ep3a19a_state::sound_end5)); + */ +} + +ROM_START( tvbg6a ) + ROM_REGION( 0x400000, "maincpu", ROMREGION_ERASE00 ) + ROM_LOAD( "candyland_hhh_silly6.bin", 0x00000, 0x200000, CRC(8b16d725) SHA1(06af509d03df0e5a2ca502743797af9f4a5dc6f1) ) + ROM_RELOAD(0x200000,0x200000) +ROM_END + +ROM_START( tvbg6b ) + ROM_REGION( 0x400000, "maincpu", ROMREGION_ERASE00 ) + ROM_LOAD( "bship_simon_mousetrap.bin", 0x00000, 0x200000, CRC(b0627a98) SHA1(6157e26916bb415037a4d122d3075cbfb8e61dcf) ) + ROM_RELOAD(0x200000,0x200000) +ROM_END + +void elan_ep3a19a_state::init_tvbg() +{ + // is this swapping internal to the ep3a19a type ELAN, or external; ROM glob had standard TSOP pinout pads that were used for dumping. + uint8_t* ROM = memregion("maincpu")->base(); + for (int i = 0; i < 0x400000; i++) + { + ROM[i] = bitswap<8>(ROM[i], 6, 5, 7, 0, 2, 3, 1, 4); + } +} + +CONS( 2007, tvbg6a, 0, 0, elan_ep3a19a, elan_ep3a19a, elan_ep3a19a_state, init_tvbg, "NSI International / Mammoth Toys (Licensed by Hasbro)", "TV Board Games 6-in-1: Silly 6 Pins, Candy Land, Hungry Hungry Hippos, Match 'em, Mixin' Pics, Checkers", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) // https://www.youtube.com/watch?v=zajzQo47YYA +CONS( 2007, tvbg6b, 0, 0, elan_ep3a19a, elan_ep3a19a, elan_ep3a19a_state, init_tvbg, "NSI International / Mammoth Toys (Licensed by Hasbro)", "TV Board Games 6-in-1: Simon, Battleship, Mouse Trap, Checkers, Link-a-Line, Roll Over", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) // https://www.youtube.com/watch?v=JbrR67kY8MI + +// TV Board Games 3-in-1: Silly 6 Pins, Hungry Hungry Hippos, Match 'em +// TV Board Games 3-in-1: Simon, Battleship, Checkers https://www.youtube.com/watch?v=Q7nwKJfVavU +// TV Board Games 3-in-1: Boggle, Connect 4, Roll Over https://www.youtube.com/watch?v=SoKKIKSDGhY + +// The back of the Silly 6 Pins 3-in-1 packaging suggests a Monopoly TV Board Game device was planned, but this does not appear to have been released. diff --git a/src/mame/machine/elan_ep3a19asys.cpp b/src/mame/machine/elan_ep3a19asys.cpp new file mode 100644 index 00000000000..dbe6f3f3017 --- /dev/null +++ b/src/mame/machine/elan_ep3a19asys.cpp @@ -0,0 +1,117 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#include "emu.h" +#include "elan_ep3a19asys.h" + +// like EU3A05 but with the DMA at a lower address where the code bank register would usually be, and a single byte for bank register rather than 2 - any other changes? + +DEFINE_DEVICE_TYPE(ELAN_EP3A19A_SYS, elan_ep3a19asys_device, "elan_ep3a19asys", "Elan EP3A19A System") + +elan_ep3a19asys_device::elan_ep3a19asys_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + elan_eu3a05commonsys_device(mconfig, ELAN_EP3A19A_SYS, tag, owner, clock), + device_memory_interface(mconfig, *this), + m_space_config("regs", ENDIANNESS_NATIVE, 8, 5, 0, address_map_constructor(FUNC(elan_ep3a19asys_device::map), this)) +{ +} + +device_memory_interface::space_config_vector elan_ep3a19asys_device::memory_space_config() const +{ + return space_config_vector { + std::make_pair(0, &m_space_config) + }; +} + + +void elan_ep3a19asys_device::rombank_w(offs_t offset, uint8_t data) +{ + m_rombank_lo = data; + m_bank->set_bank(m_rombank_lo); +} + +uint8_t elan_ep3a19asys_device::rombank_r(offs_t offset) +{ + return m_rombank_lo; +} + + +void elan_ep3a19asys_device::map(address_map& map) +{ +// elan_eu3a05commonsys_device::map(map); // 00 - 0e + + map(0x0c, 0x0c).rw(FUNC(elan_ep3a19asys_device::rombank_r), FUNC(elan_ep3a19asys_device::rombank_w)); + + map(0x0d, 0x13).rw(FUNC(elan_ep3a19asys_device::dma_param_r), FUNC(elan_ep3a19asys_device::dma_param_w)); + map(0x14, 0x14).rw(FUNC(elan_ep3a19asys_device::elan_eu3a05_dmatrg_r), FUNC(elan_ep3a19asys_device::elan_eu3a05_dmatrg_w)); +} + +void elan_ep3a19asys_device::device_start() +{ + elan_eu3a05commonsys_device::device_start(); + + save_item(NAME(m_dmaparams)); +} + +void elan_ep3a19asys_device::device_reset() +{ + elan_eu3a05commonsys_device::device_reset(); + + for (int i = 0; i < 7; i++) + m_dmaparams[i] = 0x00; +} + +uint8_t elan_ep3a19asys_device::dma_param_r(offs_t offset) +{ + return m_dmaparams[offset]; +} + +void elan_ep3a19asys_device::dma_param_w(offs_t offset, uint8_t data) +{ + m_dmaparams[offset] = data; +} + + +uint8_t elan_ep3a19asys_device::elan_eu3a05_dmatrg_r() +{ + logerror("%s: elan_eu3a05_dmatrg_r (DMA operation state?)\n", machine().describe_context()); + return 0x00;//m_dmatrg_data; +} + + +void elan_ep3a19asys_device::elan_eu3a05_dmatrg_w(uint8_t data) +{ + logerror("%s: elan_eu3a05_dmatrg_w (trigger DMA operation) %02x\n", machine().describe_context(), data); + //m_dmatrg_data = data; + + address_space& fullbankspace = m_bank->space(AS_PROGRAM); + address_space& destspace = m_cpu->space(AS_PROGRAM); + + if (data) + { + int src = (m_dmaparams[0]) | (m_dmaparams[1] << 8) | (m_dmaparams[2] << 16); + uint16_t dest = m_dmaparams[3] | (m_dmaparams[4] << 8); + uint16_t size = m_dmaparams[5] | (m_dmaparams[6] << 8); + + logerror(" Doing %02x DMA %06x to %04x size %04x\n", data, src, dest, size); + + for (int i = 0; i < size; i++) + { + uint8_t dat = fullbankspace.read_byte(src); + src++; + destspace.write_byte(dest, dat); + dest++; + } + + m_dmaparams[0] = src & 0xff; + m_dmaparams[1] = (src >> 8) & 0xff; + m_dmaparams[2] = (src >> 16) & 0xff; + m_dmaparams[3] = dest & 0xff; + m_dmaparams[4] = (dest >> 8) & 0xff; + + m_dmaparams[5] = 0; + m_dmaparams[6] = 0; + } +} + + + diff --git a/src/mame/machine/elan_ep3a19asys.h b/src/mame/machine/elan_ep3a19asys.h new file mode 100644 index 00000000000..25789370ec2 --- /dev/null +++ b/src/mame/machine/elan_ep3a19asys.h @@ -0,0 +1,38 @@ +// license:BSD-3-Clause +// copyright-holders:David Haywood + +#ifndef MAME_MACHINE_ELAN_EP3A19ASYS_H +#define MAME_MACHINE_ELAN_EP3A19ASYS_H + +#include "elan_eu3a05commonsys.h" + +class elan_ep3a19asys_device : public elan_eu3a05commonsys_device, public device_memory_interface +{ +public: + elan_ep3a19asys_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + uint8_t elan_eu3a05_dmatrg_r(); + void elan_eu3a05_dmatrg_w(uint8_t data); + + uint8_t dma_param_r(offs_t offset); + void dma_param_w(offs_t offset, uint8_t data); + + virtual void map(address_map& map) override; + +protected: + // device-level overrides + virtual void device_start() override; + virtual void device_reset() override; + virtual space_config_vector memory_space_config() const override; + + void rombank_w(offs_t offset, uint8_t data); + uint8_t rombank_r(offs_t offset); + +private: + const address_space_config m_space_config; + uint8_t m_dmaparams[7]; +}; + +DECLARE_DEVICE_TYPE(ELAN_EP3A19A_SYS, elan_ep3a19asys_device) + +#endif // MAME_MACHINE_ELAN_EP3A19ASYS_H diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 198d0f83574..3f2f709294f 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -13105,6 +13105,10 @@ egghunt // (c) 1995 Invi Image einst256 // einstein // +@source:elan_ep3a19a.cpp +tvbg6a +tvbg6b + @source:elan_eu3a14.cpp rad_gtg rad_rsg diff --git a/src/mame/mess.flt b/src/mame/mess.flt index 2a869da53e9..d1c75fa1305 100644 --- a/src/mame/mess.flt +++ b/src/mame/mess.flt @@ -259,6 +259,7 @@ ec65.cpp ec7915.cpp einstein.cpp eispc.cpp +elan_ep3a19a.cpp elan_eu3a05.cpp elan_eu3a14.cpp electron.cpp diff --git a/src/mame/video/elan_eu3a05vid.cpp b/src/mame/video/elan_eu3a05vid.cpp index 5ea11e30bd9..057df0f9937 100644 --- a/src/mame/video/elan_eu3a05vid.cpp +++ b/src/mame/video/elan_eu3a05vid.cpp @@ -17,7 +17,9 @@ elan_eu3a05vid_device::elan_eu3a05vid_device(const machine_config &mconfig, cons m_bytes_per_tile_entry(4), m_vrambase(0x600), m_spritebase(0x3e00), - m_use_spritepages(false) + m_use_spritepages(false), + m_force_transpen_ff(false), + m_force_basic_scroll(false) { } @@ -126,7 +128,7 @@ uint8_t elan_eu3a05vid_device::read_vram(int offset) that space (Tetris seems to rely on mirroring? as it sets all addresses up for the lower 1MB instead) */ -void elan_eu3a05vid_device::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) +void elan_eu3a05vid_device::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, bitmap_ind8 &priority_bitmap, const rectangle &cliprect) { address_space& fullbankspace = m_bank->space(AS_PROGRAM); @@ -139,11 +141,11 @@ void elan_eu3a05vid_device::draw_sprites(screen_device &screen, bitmap_ind16 &bi XX = texture x start YY = texture y start bb = sometimes set in invaders - AA = same as attr on tiles (colour / priority?) + AA = same as attr on tiles (cccc pppp) (c = colour / p = priority?) aa = same as unk2 on tiles? ( --pp ---- ) - p = page + p = page (some hardware types only? or selectable meaning) FF = flags ( e-dD fFsS ) e = enable @@ -156,7 +158,10 @@ void elan_eu3a05vid_device::draw_sprites(screen_device &screen, bitmap_ind16 &bi */ - for (int i = 0; i < 512; i += 8) +// later in list with AA == 0f aa == 07 takes priority over earlier in the list with AA == 0f and aa == 07 +// later in the list with AA == 0e and aa == 17 is under AA == 0f aa == and 07 + + for (int i = 512-8; i >=0; i -= 8) { uint8_t x = read_spriteram(i + 2); uint8_t y = read_spriteram(i + 1); @@ -188,7 +193,8 @@ void elan_eu3a05vid_device::draw_sprites(screen_device &screen, bitmap_ind16 &bi const int doubleX = (flags & 0x10)>>4; const int doubleY = (flags & 0x20)>>5; - //int priority = attr & 0x0f; + int priority = (attr & 0x0f)^0xf; + int colour = attr & 0xf0; // ? game select has this set to 0xff, but clearly doesn't want the palette to change! @@ -204,7 +210,7 @@ void elan_eu3a05vid_device::draw_sprites(screen_device &screen, bitmap_ind16 &bi where the transpen needs to be 0x00 and Space Invaders has it set to 0x04 it could be a global register rather than something in the spritelist? */ - if ((attr == 0xff) && (unk2 == 0xff)) + if (((attr == 0xff) && (unk2 == 0xff)) || m_force_transpen_ff) transpen = 0xff; @@ -242,14 +248,19 @@ void elan_eu3a05vid_device::draw_sprites(screen_device &screen, bitmap_ind16 &bi for (int yy = 0; yy < sizey; yy++) { uint16_t* row; + uint8_t* rowpri; if (flags & 0x08) // guess flipy { - row = &bitmap.pix((y + (sizey - 1 - yy)) & 0xff); + int drawypos = (y + (sizey - 1 - yy)) & 0xff; + row = &bitmap.pix(drawypos); + rowpri = &priority_bitmap.pix(drawypos); } else { - row = &bitmap.pix((y + yy) & 0xff); + int drawypos = (y + yy) & 0xff; + row = &bitmap.pix(drawypos); + rowpri = &priority_bitmap.pix(drawypos); } for (int xx = 0; xx < sizex; xx++) @@ -272,11 +283,23 @@ void elan_eu3a05vid_device::draw_sprites(screen_device &screen, bitmap_ind16 &bi { if (flags & 0x04) // flipx { - row[(x + (sizex - 1 - xx)) & 0xff] = (pix + ((colour & 0x70) << 1)) & 0xff; + int xdrawpos = (x + (sizex - 1 - xx)) & 0xff; + + if (rowpri[xdrawpos] > priority) + { + rowpri[xdrawpos] = priority; + row[xdrawpos] = (pix + ((colour & 0x70) << 1)) & 0xff; + } } else { - row[(x + xx) & 0xff] = (pix + ((colour & 0x70) << 1)) & 0xff; + int xdrawpos = (x + xx) & 0xff; + + if (rowpri[xdrawpos] > priority) + { + rowpri[xdrawpos] = priority; + row[xdrawpos] = (pix + ((colour & 0x70) << 1)) & 0xff; + } } } } @@ -317,183 +340,269 @@ bool elan_eu3a05vid_device::get_tile_data(int base, int drawpri, int& tile, int return true; } + + +void elan_eu3a05vid_device::draw_tilemaps_tileline(int drawpri, int tile, int attr, int unk2, int tilexsize, int i, int xpos, uint16_t* row) +{ + address_space& fullbankspace = m_bank->space(AS_PROGRAM); + int colour = attr & 0xf0; + + /* 'tiles' are organized / extracted from 'texture' lines that form a 'page' the length of the rom + each texture line in 8bpp mode is 256 bytes + each texture line in 4bpp mode is 128 bytes + in 8x8 mode these pages are 32 tiles wide + in 16x16 mode these pages are 16 tiles wide + tiles can start on any line + + it is unclear what the behavior is if the tile starts at the far edge of a line (wrap around on line?) + + this is eu3a05 specific, eu3a14 uses a more traditional approach + */ + + const int tilespersrcline = 256 / tilexsize; + const int tilespersrcline_mask = tilespersrcline - 1; + + tile = (tile & tilespersrcline_mask) + ((tile & ~tilespersrcline_mask) * tilexsize); + + if (!(m_vidctrl & 0x20)) // 8bpp + tile <<= 1; + + if (!(m_vidctrl & 0x40)) // 8*8 tiles + tile >>= 1; + + tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5); + + + if (m_vidctrl & 0x20) // 4bpp + { + for (int xx = 0; xx < tilexsize; xx += 2) + { + int realaddr = ((tile + i * 16) << 3) + (xx >> 1); + uint8_t pix = fullbankspace.read_byte(realaddr); + + int drawxpos; + + drawxpos = xpos + xx + 0; + if ((drawxpos >= 0) && (drawxpos < 256)) + row[drawxpos] = ((pix & 0xf0) >> 4) + colour; + + drawxpos = xpos + xx + 1; + if ((drawxpos >= 0) && (drawxpos < 256)) + row[drawxpos] = ((pix & 0x0f) >> 0) + colour; + } + } + else // 8bpp + { + for (int xx = 0; xx < tilexsize; xx++) + { + int realaddr = ((tile + i * 32) << 3) + xx; + uint8_t pix = fullbankspace.read_byte(realaddr); + + int drawxpos = xpos + xx; + if ((drawxpos >= 0) && (drawxpos < 256)) + row[drawxpos] = (pix + ((colour & 0x70) << 1)) & 0xff; + } + } +} + +uint16_t elan_eu3a05vid_device::get_tilemapindex_from_xy(uint16_t x, uint16_t y) +{ + // for mousetrap and candyland the pages in RAM (16x16 tile mode, 4 pages) are + // top left + // top right + // bottom left + // bottom right + + // for airblaster joystick 3d stagess the pages in RAM (8x8 tile mode, 2 pages) are + // left + // right + + // for airblaster joystick scrolling stages (8x8 tile mode, 2 pages) + // top + // bottom + + uint16_t tilemapsizey; + uint16_t tilemapsizex; + uint16_t pagesizey, pagesizex; + + pagesizey = 14; pagesizex = 16; + + switch (m_vidctrl & 0x03) + { + case 0x00: tilemapsizey = 14 * 2; tilemapsizex = 16 * 2; break; // double height & double width + case 0x02: tilemapsizey = 14 * 2; tilemapsizex = 16; break; // double height + case 0x01: tilemapsizey = 14; tilemapsizex = 16 * 2; break; // double width + case 0x03: tilemapsizey = 14; tilemapsizex = 16; break; // normal + } + + if (!(m_vidctrl & 0x40)) // 16x16 tiles + { + pagesizey <<= 1; + pagesizex <<= 1; + tilemapsizey <<= 1; + tilemapsizex <<= 1; + } + + while (y >= tilemapsizey) + y -= tilemapsizey; + + while (x >= tilemapsizex) + x -= tilemapsizex; + + int index = 0; + int page = 0; + + switch (m_vidctrl & 0x03) + { + case 0x00: // double height & double width + if (y < pagesizey) + { + if (x < pagesizex) + { + page = 0; + } + else + { + page = 1; + } + } + else + { + if (x < pagesizex) + { + page = 2; + } + else + { + page = 3; + } + } + break; + + case 0x02: // double height + if (y < pagesizey) + { + page = 0; + } + else + { + page = 1; + } + break; + + case 0x01: // double width + if (x < pagesizex) + { + page = 0; + } + else + { + page = 1; + } + break; + + case 0x03: + page = 0; + break; + } + + while (y >= pagesizey) + y -= pagesizey; + + while (x >= pagesizex) + x -= pagesizex; + + index = x + y * pagesizex; + index += page * pagesizey * pagesizex; + + return index; +} + void elan_eu3a05vid_device::draw_tilemaps(screen_device& screen, bitmap_ind16& bitmap, const rectangle& cliprect, int drawpri) { /* this doesn't handle 8x8 4bpp (not used by anything yet) */ + //popmessage("%02x: %04x %04x %04x %04x", m_vidctrl, get_scroll(0), get_scroll(1), get_scroll(2), get_scroll(3)); - int scroll = get_scroll(1); - address_space& fullbankspace = m_bank->space(AS_PROGRAM); + int scrolly = get_scroll(1); - // Phoenix scrolling actually skips a pixel, jumping from 0x001 to 0x1bf, scroll 0x000 isn't used, maybe it has other meanings? - - int totalyrow; - int totalxcol; - int mapyrowsbase; - int tileysize; - int tilexsize; - int startrow; - - if (m_vidctrl & 0x40) // 16x16 tiles + for (int screenline = 0; screenline < 224; screenline++) { - totalyrow = 16; - totalxcol = 16; - mapyrowsbase = 14; - tileysize = 16; - tilexsize = 16; - startrow = (scroll >> 4) & 0x1f; - } - else - { - totalyrow = 32; - totalxcol = 32; - mapyrowsbase = 28; - tileysize = 8; - tilexsize = 8; - startrow = (scroll >> 3) & 0x3f; - } + int scrollx; + int coursescrollx; + int finescrollx; + int realline = screenline + scrolly; - for (int y = 0; y < totalyrow; y++) - { - for (int x = 0; x < totalxcol * 2; x++) + // split can be probably configured in more ways than this + // exact enable conditions unclear + // this logic is needed for Air Blaster Joystick + if (screenline < m_splitpos[0]) { - int realstartrow = (startrow + y); + scrollx = get_scroll(0); + } + else if (screenline < m_splitpos[1]) + { + scrollx = get_scroll(2); + } + else + { + scrollx = get_scroll(3); + } - int yrows; + // Candy Land and Mouse Trap in the TV Board Games units don't like the above logic, so force them to just use the + // first scroll register for now, there must be more complex enable conditions for the above + if (m_force_basic_scroll) + scrollx = get_scroll(0); - if (m_vidctrl & 0x01) - yrows = mapyrowsbase; + uint16_t* row = &bitmap.pix(screenline); + + int xtiles; + int xtilesize; + if (m_vidctrl & 0x40) // 16x16 tiles + { + xtiles = 16; // number of tilemap entries per row + xtilesize = 16; // width of tile + coursescrollx = scrollx >> 4; + finescrollx = scrollx & 0xf; + } + else + { + xtiles = 32; + xtilesize = 8; + coursescrollx = scrollx >> 3; + finescrollx = scrollx & 0x7; + } + + for (int xtile = 0; xtile <= xtiles; xtile++) + { + + int realxtile = xtile + coursescrollx; + + int tilemaprow; + int tileline; + + if (m_vidctrl & 0x40) // 16x16 tiles + { + tilemaprow = realline >> 4; + tileline = realline & 0xf; + } else - yrows = mapyrowsbase * 2; - - if (realstartrow >= yrows) - realstartrow -= yrows; - - // in double width & double height mode the page addressing needs adjusting - if (!(m_vidctrl & 0x02)) { - if (!(m_vidctrl & 0x01)) - { - if (realstartrow >= (yrows / 2)) - { - realstartrow += yrows / 2; - } - } + tilemaprow = realline >> 3; + tileline = realline & 0x7; } - for (int i = 0; i < tileysize; i++) - { - int drawline = (y * tileysize) + i; - drawline -= scroll & (tileysize - 1); + int tilemap_entry_index = get_tilemapindex_from_xy(realxtile, tilemaprow); - if ((drawline >= 0) && (drawline < 256)) - { - int scrollx; + int tile, attr, unk2; - // split can be probably configured in more ways than this - // exact enable conditions unclear - if (drawline < m_splitpos[0]) - { - scrollx = get_scroll(0); - } - else if (drawline < m_splitpos[1]) - { - scrollx = get_scroll(2); - } - else - { - scrollx = get_scroll(3); - } + if (!get_tile_data(tilemap_entry_index, drawpri, tile, attr, unk2)) + continue; - int base; + int xpos = xtile * xtilesize - finescrollx; + draw_tilemaps_tileline(drawpri, tile, attr, unk2, xtilesize, tileline, xpos, row); - if (m_vidctrl & 0x40) // 16x16 tiles - { - base = (((realstartrow + y) & 0x3f) * 8) + x; - } - else - { - base = (((realstartrow) & 0x7f) * totalxcol) + (x & (totalxcol - 1)); - } - - if (!(m_vidctrl & 0x02)) - { - if (x & totalxcol) - { - base += totalxcol * mapyrowsbase; - } - } - - int tile, attr, unk2; - - if (!get_tile_data(base, drawpri, tile, attr, unk2)) - continue; - - int colour = attr & 0xf0; - - /* 'tiles' are organized / extracted from 'texture' lines that form a 'page' the length of the rom - each texture line in 8bpp mode is 256 bytes - each texture line in 4bpp mode is 128 bytes - in 8x8 mode these pages are 32 tiles wide - in 16x16 mode these pages are 16 tiles wide - tiles can start on any line - - it is unclear what the behavior is if the tile starts at the far edge of a line (wrap around on line?) - - this is eu3a05 specific, eu3a14 uses a more traditional approach - */ - - const int tilespersrcline = 256 / tilexsize; - const int tilespersrcline_mask = tilespersrcline - 1; - - tile = (tile & tilespersrcline_mask) + ((tile & ~tilespersrcline_mask) * tilexsize); - - if (!(m_vidctrl & 0x20)) // 8bpp - tile <<= 1; - - if (!(m_vidctrl & 0x40)) // 8*8 tiles - tile >>= 1; - - tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5); - - uint16_t *const row = &bitmap.pix(drawline); - - if (m_vidctrl & 0x20) // 4bpp - { - for (int xx = 0; xx < tilexsize; xx += 2) - { - int realaddr = ((tile + i * 16) << 3) + (xx >> 1); - uint8_t pix = fullbankspace.read_byte(realaddr); - - int drawxpos; - - drawxpos = x * tilexsize + xx + 0 - scrollx; - drawxpos &= 0x1ff; - if ((drawxpos >= 0) && (drawxpos < 256)) - row[drawxpos] = ((pix & 0xf0) >> 4) + colour; - - drawxpos = x * tilexsize + xx + 1 - scrollx; - drawxpos &= 0x1ff; - if ((drawxpos >= 0) && (drawxpos < 256)) - row[drawxpos] = ((pix & 0x0f) >> 0) + colour; - } - } - else // 8bpp - { - for (int xx = 0; xx < tilexsize; xx++) - { - int realaddr = ((tile + i * 32) << 3) + xx; - uint8_t pix = fullbankspace.read_byte(realaddr); - - int drawxpos = x * tilexsize + xx - scrollx; - drawxpos &= 0x1ff; - if ((drawxpos >= 0) && (drawxpos < 256)) - row[drawxpos] = (pix + ((colour & 0x70) << 1)) & 0xff; - } - } - } - } } } } @@ -501,10 +610,11 @@ void elan_eu3a05vid_device::draw_tilemaps(screen_device& screen, bitmap_ind16& b uint32_t elan_eu3a05vid_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { bitmap.fill(0, cliprect); + screen.priority().fill(0xff, cliprect); - draw_tilemaps(screen,bitmap,cliprect,0); - draw_sprites(screen,bitmap,cliprect); - draw_tilemaps(screen,bitmap,cliprect,1); + draw_tilemaps(screen,bitmap,cliprect,0); // 'low priority' + draw_sprites(screen,bitmap,screen.priority(),cliprect); + draw_tilemaps(screen,bitmap,cliprect,1); // 'high priority' return 0; } @@ -572,6 +682,7 @@ uint8_t elan_eu3a05vid_device::tile_scroll_r(offs_t offset) void elan_eu3a05vid_device::tile_scroll_w(offs_t offset, uint8_t data) { + //logerror("tile_scroll_w %02x %02x\n", offset, data); m_tile_scroll[offset] = data; } diff --git a/src/mame/video/elan_eu3a05vid.h b/src/mame/video/elan_eu3a05vid.h index 08ccd121cb4..56028158bb6 100644 --- a/src/mame/video/elan_eu3a05vid.h +++ b/src/mame/video/elan_eu3a05vid.h @@ -7,6 +7,7 @@ #include "elan_eu3a05commonvid.h" #include "cpu/m6502/m6502.h" #include "machine/bankdev.h" +#include "screen.h" class elan_eu3a05vid_device : public elan_eu3a05commonvid_device, public device_memory_interface { @@ -23,6 +24,8 @@ public: void set_is_sudoku(); void set_is_pvmilfin(); void set_use_spritepages() { m_use_spritepages = true; }; + void set_force_transpen_ff() { m_force_transpen_ff = true; }; + void set_force_basic_scroll() { m_force_basic_scroll = true; }; protected: // device-level overrides @@ -51,7 +54,9 @@ private: bool get_tile_data(int base, int drawpri, int& tile, int &attr, int &unk2); void draw_tilemaps(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int drawpri); - void draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect); + void draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, bitmap_ind8 &priority_bitmap, const rectangle &cliprect); + void draw_tilemaps_tileline(int drawpri, int tile, int attr, int unk2, int tilexsize, int tileline, int xpos, uint16_t *row); + uint16_t get_tilemapindex_from_xy(uint16_t x, uint16_t y); uint8_t read_spriteram(int offset); uint8_t read_vram(int offset); @@ -84,6 +89,8 @@ private: int m_vrambase; int m_spritebase; bool m_use_spritepages; + bool m_force_transpen_ff; + bool m_force_basic_scroll; }; DECLARE_DEVICE_TYPE(ELAN_EU3A05_VID, elan_eu3a05vid_device)