new WORKING machines (TV Board Games 6-in-1) (#7824)

new WORKING machines
-------
TV Board Games 6-in-1: Silly 6 Pins, Candy Land, Hungry Hungry Hippos, Match 'em, Mixin' Pics, Checkers [Sean Riddle, David Haywood]
TV Board Games 6-in-1: Simon, Battleship, Mouse Trap, Checkers, Link-a-Line, Roll Over [Sean Riddle, David Haywood]
This commit is contained in:
David Haywood 2021-03-02 18:53:31 +00:00 committed by GitHub
parent 323250bbee
commit 2746058dcf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 825 additions and 172 deletions

View File

@ -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",

View File

@ -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<elan_ep3a19asys_device> m_sys;
required_device<elan_eu3a05gpio_device> m_gpio;
required_device<cpu_device> m_maincpu;
required_device<screen_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<uint8_t> m_ram;
required_device<elan_eu3a05_sound_device> m_sound;
required_device<elan_eu3a05vid_device> m_vid;
required_device<address_map_bank_device> m_bank;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_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.

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -259,6 +259,7 @@ ec65.cpp
ec7915.cpp
einstein.cpp
eispc.cpp
elan_ep3a19a.cpp
elan_eu3a05.cpp
elan_eu3a14.cpp
electron.cpp

View File

@ -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;
}

View File

@ -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)