summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author David Haywood <28625134+DavidHaywood@users.noreply.github.com>2019-11-04 03:50:48 +0000
committer ajrhacker <ajrhacker@users.noreply.github.com>2019-11-03 22:50:48 -0500
commitd24fc57a95d5d817dc7d04e1df0f266157647199 (patch)
tree55369ca28ec56ea86bd6174a1609c653f6c055db
parent36bfba32f7ca7320d949277b3ecf9b15a5f1ac18 (diff)
Plug & Play / Elan EU3A05 / EU3A14 splitting up, identifying of common features etc. (#5849)
* elan eu3a05 / eu3a14 - identify some common bits (nw) * some elan refactoring baed on current knowledge / standards (nw) * elan refactoring (nw) * elan splitting / refactoring (nw) * validate (nw) * note used areas (nw) * register observations (nw) * another observation (nw) * add the sprite double feature (nw) * rendering tweaks (nw) * rendering improvements for air blaster 3d stages (nw) * refactoring (nw)
-rw-r--r--scripts/target/mame/mess.lua10
-rw-r--r--src/mame/audio/elan_eu3a05.cpp46
-rw-r--r--src/mame/audio/elan_eu3a05.h30
-rw-r--r--src/mame/drivers/elan_eu3a05.cpp1046
-rw-r--r--src/mame/drivers/elan_eu3a14.cpp361
-rw-r--r--src/mame/machine/elan_eu3a05commonsys.cpp307
-rw-r--r--src/mame/machine/elan_eu3a05commonsys.h50
-rw-r--r--src/mame/machine/elan_eu3a05gpio.cpp24
-rw-r--r--src/mame/machine/elan_eu3a05gpio.h10
-rw-r--r--src/mame/machine/elan_eu3a05sys.cpp74
-rw-r--r--src/mame/machine/elan_eu3a05sys.h31
-rw-r--r--src/mame/machine/elan_eu3a14sys.cpp71
-rw-r--r--src/mame/machine/elan_eu3a14sys.h33
-rw-r--r--src/mame/video/elan_eu3a05commonvid.cpp87
-rw-r--r--src/mame/video/elan_eu3a05commonvid.h35
-rw-r--r--src/mame/video/elan_eu3a05vid.cpp596
-rw-r--r--src/mame/video/elan_eu3a05vid.h80
17 files changed, 1656 insertions, 1235 deletions
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index a999bff7ddc..ab0883acec4 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -3695,6 +3695,16 @@ files {
MAME_DIR .. "src/mame/audio/elan_eu3a05.h",
MAME_DIR .. "src/mame/machine/elan_eu3a05gpio.cpp",
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_eu3a05sys.cpp",
+ MAME_DIR .. "src/mame/machine/elan_eu3a05sys.h",
+ MAME_DIR .. "src/mame/machine/elan_eu3a14sys.cpp",
+ MAME_DIR .. "src/mame/machine/elan_eu3a14sys.h",
+ MAME_DIR .. "src/mame/video/elan_eu3a05commonvid.cpp",
+ MAME_DIR .. "src/mame/video/elan_eu3a05commonvid.h",
+ MAME_DIR .. "src/mame/video/elan_eu3a05vid.cpp",
+ MAME_DIR .. "src/mame/video/elan_eu3a05vid.h",
MAME_DIR .. "src/mame/drivers/trkfldch.cpp",
MAME_DIR .. "src/mame/drivers/tvgame.cpp",
MAME_DIR .. "src/mame/drivers/spg110.cpp",
diff --git a/src/mame/audio/elan_eu3a05.cpp b/src/mame/audio/elan_eu3a05.cpp
index 84fbd099fc4..814849e3a43 100644
--- a/src/mame/audio/elan_eu3a05.cpp
+++ b/src/mame/audio/elan_eu3a05.cpp
@@ -6,7 +6,7 @@
#include "emu.h"
#include "elan_eu3a05.h"
-DEFINE_DEVICE_TYPE(RADICA6502_SOUND, radica6502_sound_device, "radica6502sound", "Elan EU3A05 / EU3A14 Sound")
+DEFINE_DEVICE_TYPE(ELAN_EU3A05_SOUND, elan_eu3a05_sound_device, "elan_eu3a05sound", "Elan EU3A05 / EU3A14 Sound")
#define LOG_AUDIO (1U << 0)
@@ -16,21 +16,21 @@ DEFINE_DEVICE_TYPE(RADICA6502_SOUND, radica6502_sound_device, "radica6502sound",
#include "logmacro.h"
-radica6502_sound_device::radica6502_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, RADICA6502_SOUND, tag, owner, clock)
+elan_eu3a05_sound_device::elan_eu3a05_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, ELAN_EU3A05_SOUND, tag, owner, clock)
, device_sound_interface(mconfig, *this)
, m_stream(nullptr)
, m_space_read_cb(*this)
{
}
-void radica6502_sound_device::device_start()
+void elan_eu3a05_sound_device::device_start()
{
m_space_read_cb.resolve_safe(0);
m_stream = stream_alloc(0, 1, 8000);
}
-void radica6502_sound_device::device_reset()
+void elan_eu3a05_sound_device::device_reset()
{
for (int i = 0; i < 6; i++)
{
@@ -46,7 +46,7 @@ void radica6502_sound_device::device_reset()
// sound_stream_update - handle a stream update
//-------------------------------------------------
-void radica6502_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+void elan_eu3a05_sound_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
// reset the output stream
memset(outputs[0], 0, samples * sizeof(*outputs[0]));
@@ -95,7 +95,7 @@ void radica6502_sound_device::sound_stream_update(sound_stream &stream, stream_s
}
-void radica6502_sound_device::handle_sound_addr_w(int which, int offset, uint8_t data)
+void elan_eu3a05_sound_device::handle_sound_addr_w(int which, int offset, uint8_t data)
{
switch (offset)
{
@@ -116,7 +116,7 @@ void radica6502_sound_device::handle_sound_addr_w(int which, int offset, uint8_t
}
}
-uint8_t radica6502_sound_device::handle_sound_addr_r(int which, int offset)
+uint8_t elan_eu3a05_sound_device::handle_sound_addr_r(int which, int offset)
{
switch (offset)
{
@@ -136,19 +136,19 @@ uint8_t radica6502_sound_device::handle_sound_addr_r(int which, int offset)
return 0x00;
}
-WRITE8_MEMBER(radica6502_sound_device::radicasi_sound_addr_w)
+WRITE8_MEMBER(elan_eu3a05_sound_device::elan_eu3a05_sound_addr_w)
{
m_stream->update();
handle_sound_addr_w(offset / 3, offset % 3, data);
}
-READ8_MEMBER(radica6502_sound_device::radicasi_sound_addr_r)
+READ8_MEMBER(elan_eu3a05_sound_device::elan_eu3a05_sound_addr_r)
{
m_stream->update();
return handle_sound_addr_r(offset / 3, offset % 3);
}
-void radica6502_sound_device::handle_sound_size_w(int which, int offset, uint8_t data)
+void elan_eu3a05_sound_device::handle_sound_size_w(int which, int offset, uint8_t data)
{
switch (offset)
{
@@ -169,7 +169,7 @@ void radica6502_sound_device::handle_sound_size_w(int which, int offset, uint8_t
}
}
-uint8_t radica6502_sound_device::handle_sound_size_r(int which, int offset)
+uint8_t elan_eu3a05_sound_device::handle_sound_size_r(int which, int offset)
{
switch (offset)
{
@@ -189,19 +189,19 @@ uint8_t radica6502_sound_device::handle_sound_size_r(int which, int offset)
return 0x00;
}
-WRITE8_MEMBER(radica6502_sound_device::radicasi_sound_size_w)
+WRITE8_MEMBER(elan_eu3a05_sound_device::elan_eu3a05_sound_size_w)
{
m_stream->update();
handle_sound_size_w(offset / 3, offset % 3, data);
}
-READ8_MEMBER(radica6502_sound_device::radicasi_sound_size_r)
+READ8_MEMBER(elan_eu3a05_sound_device::elan_eu3a05_sound_size_r)
{
m_stream->update();
return handle_sound_size_r(offset / 3, offset % 3);
}
-READ8_MEMBER(radica6502_sound_device::radicasi_sound_trigger_r)
+READ8_MEMBER(elan_eu3a05_sound_device::elan_eu3a05_sound_trigger_r)
{
m_stream->update();
@@ -210,7 +210,7 @@ READ8_MEMBER(radica6502_sound_device::radicasi_sound_trigger_r)
}
-WRITE8_MEMBER(radica6502_sound_device::radicasi_sound_trigger_w)
+WRITE8_MEMBER(elan_eu3a05_sound_device::elan_eu3a05_sound_trigger_w)
{
m_stream->update();
@@ -231,16 +231,16 @@ WRITE8_MEMBER(radica6502_sound_device::radicasi_sound_trigger_w)
/* this is read/written with the same individual bits for each channel as the trigger
maybe related to interrupts? */
-READ8_MEMBER(radica6502_sound_device::radicasi_sound_unk_r)
+READ8_MEMBER(elan_eu3a05_sound_device::elan_eu3a05_sound_unk_r)
{
- LOGMASKED( LOG_AUDIO, "%s: radicasi_sound_unk_r\n", machine().describe_context());
+ LOGMASKED( LOG_AUDIO, "%s: elan_eu3a05_sound_unk_r\n", machine().describe_context());
// don't think this reads back what was written probably a status of something instead?
return 0x00; //m_sound_unk;
}
-WRITE8_MEMBER(radica6502_sound_device::radicasi_sound_unk_w)
+WRITE8_MEMBER(elan_eu3a05_sound_device::elan_eu3a05_sound_unk_w)
{
- LOGMASKED( LOG_AUDIO, "%s: radicasi_sound_unk_w %02x\n", machine().describe_context(), data);
+ LOGMASKED( LOG_AUDIO, "%s: elan_eu3a05_sound_unk_w %02x\n", machine().describe_context(), data);
for (int i = 0; i < 6; i++)
{
@@ -256,7 +256,7 @@ WRITE8_MEMBER(radica6502_sound_device::radicasi_sound_unk_w)
LOGMASKED( LOG_AUDIO, " UNEXPECTED BITS SET");
}
-void radica6502_sound_device::handle_sound_trigger(int which)
+void elan_eu3a05_sound_device::handle_sound_trigger(int which)
{
LOGMASKED( LOG_AUDIO, "Triggering operation on channel (%d) with params %08x %08x\n", which, m_sound_byte_address[which], m_sound_byte_len[which]);
@@ -265,10 +265,10 @@ void radica6502_sound_device::handle_sound_trigger(int which)
}
-READ8_MEMBER(radica6502_sound_device::radicasi_50a8_r)
+READ8_MEMBER(elan_eu3a05_sound_device::elan_eu3a05_50a8_r)
{
m_stream->update();
- LOGMASKED( LOG_AUDIO, "%s: radicasi_50a8_r\n", machine().describe_context());
+ LOGMASKED( LOG_AUDIO, "%s: elan_eu3a05_50a8_r\n", machine().describe_context());
return m_isstopped;
}
diff --git a/src/mame/audio/elan_eu3a05.h b/src/mame/audio/elan_eu3a05.h
index 12c7369ec50..e56f8cdc166 100644
--- a/src/mame/audio/elan_eu3a05.h
+++ b/src/mame/audio/elan_eu3a05.h
@@ -1,33 +1,33 @@
// license:BSD-3-Clause
// copyright-holders:David Haywood
-#ifndef MAME_AUDIO_RAD_EU3A05_H
-#define MAME_AUDIO_RAD_EU3A05_H
+#ifndef MAME_AUDIO_ELAN_EU3A05_H
+#define MAME_AUDIO_ELAN_EU3A05_H
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
-// ======================> radica6502_sound_device
+// ======================> elan_eu3a05_sound_device
-class radica6502_sound_device : public device_t, public device_sound_interface
+class elan_eu3a05_sound_device : public device_t, public device_sound_interface
{
public:
- radica6502_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ elan_eu3a05_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto space_read_callback() { return m_space_read_cb.bind(); }
- DECLARE_WRITE8_MEMBER(radicasi_sound_addr_w);
- DECLARE_READ8_MEMBER(radicasi_sound_addr_r);
- DECLARE_WRITE8_MEMBER(radicasi_sound_size_w);
- DECLARE_READ8_MEMBER(radicasi_sound_size_r);
- DECLARE_READ8_MEMBER(radicasi_sound_trigger_r);
- DECLARE_WRITE8_MEMBER(radicasi_sound_trigger_w);
- DECLARE_READ8_MEMBER(radicasi_sound_unk_r);
- DECLARE_WRITE8_MEMBER(radicasi_sound_unk_w);
+ DECLARE_WRITE8_MEMBER(elan_eu3a05_sound_addr_w);
+ DECLARE_READ8_MEMBER(elan_eu3a05_sound_addr_r);
+ DECLARE_WRITE8_MEMBER(elan_eu3a05_sound_size_w);
+ DECLARE_READ8_MEMBER(elan_eu3a05_sound_size_r);
+ DECLARE_READ8_MEMBER(elan_eu3a05_sound_trigger_r);
+ DECLARE_WRITE8_MEMBER(elan_eu3a05_sound_trigger_w);
+ DECLARE_READ8_MEMBER(elan_eu3a05_sound_unk_r);
+ DECLARE_WRITE8_MEMBER(elan_eu3a05_sound_unk_w);
- DECLARE_READ8_MEMBER(radicasi_50a8_r);
+ DECLARE_READ8_MEMBER(elan_eu3a05_50a8_r);
protected:
// device-level overrides
virtual void device_start() override;
@@ -57,6 +57,6 @@ private:
uint8_t handle_sound_size_r(int which, int offset);
};
-DECLARE_DEVICE_TYPE(RADICA6502_SOUND, radica6502_sound_device)
+DECLARE_DEVICE_TYPE(ELAN_EU3A05_SOUND, elan_eu3a05_sound_device)
#endif // MAME_AUDIO_RAD_EU3A05_H
diff --git a/src/mame/drivers/elan_eu3a05.cpp b/src/mame/drivers/elan_eu3a05.cpp
index cd160e8917d..0d1c8a10154 100644
--- a/src/mame/drivers/elan_eu3a05.cpp
+++ b/src/mame/drivers/elan_eu3a05.cpp
@@ -19,144 +19,23 @@
Tetris
Space Invaders
-
- Possible other games on this hardawre
-
- ConnecTV Football (aka ConnecTV International Football)
- - Soccer game, not the same as Play TV Football, or Play TV Soccer
- (it has the same XTAL etc. as this driver at least)
+ ABL Air-Blaster Joystick
---
- The XaviX ones seem to have a XaviX logo on the external packaging while the
- ones for this driver don't seem to have any specific marking.
-
+ XaviX plug and play units almost always have a XaviX logo on the external packaging
+ while the ones for this driver (and SunPlus etc.) don't seem to have any specific
+ markings.
Notes:
- To access internal test on Tetris hold P1 Down + P1 Anticlockwise (Button 2) on boot
- There appears to be a similar mode for Invaders but I don't know if it's accessible
-
-
- RAM 0xa0 and 0xa1 contain the ACD0 and AD1 values and player 2 controls if between
- certain values? probably read via serial??
-
- -----------------------
- Custom Interrupt purposes
- -----------------------
-
- TETRIS
-
- ffb0
- nothing of note?
-
- ffb4
- stuff with 500e, 500c and 500d
-
- ffb8
- stuff with 50a4 / 50a5 / 50a6 and memory address e2
-
- ffbc
- stuff with 50a4 / 50a5 / 50a6 and memory address e2 (similar to above, different bits)
-
- ffc0 - doesn't exist
- ffc4 - doesn't exist
- ffc8 - doesn't exist
- ffd0 - doesn't exist
-
- ffd4
- main irq?
-
- ffd8
- jumps straight to an rti
-
- ffdc
- accesses 501d / 501b
-
- -----------------------
-
- SPACE INVADERS
-
- ffb0
- rti
-
- ffb4
- rti
-
- ffb8
- rti
-
- ffbc
- decreases 301 bit 02
- stuff wit 50a5
-
- ffc0
- decreases 302
- stuff with 50a5 bit 04
-
- ffc4
- decreases 303
- stuff with 50a5 bit 08
-
- ffc8
- decreases 304
- stuff with 50a5 bit 10
-
- ffcc
- uses 307
- stuff with 50a5 bit 20
-
- ffd0
- dead loop
-
- ffd4
- main interrupt
-
- ffd8
- dead loop
+
+ Tetris - RAM 0xa0 and 0xa1 contain the ACD0 and AD1 values and player 2 controls if
+ between certain values? probably read via serial (or ADC abuse?)
- ffdc
- dead loop
-
- ffe0
- dead loop
-
- ffe4
- rti
-
- ffe8
- dead loop
-
- ffec
- dead loop
-
- -----------------------
+ Internal Test Menus:
- AIR BLASTER JOYSTICK
-
- all these 60xx jumps expect bank 00 or 0e or 3a or 7d to be active, so IRQs must be masked
-
- ffb0: jmp to 6000 (ends up jumping to pointer from RAM)
- ffb4: jmp to e08e (stuff with 500c/500d/506e etc.)
- ffb8: jmp to 601c (stub handler) (has function in bank 0e - writes 00 then 01 to 50a5)
- ffbc: jmp to 602a (stub handler)
- ffc0: jmp to 6038 (stub handler)
- ffc4: jmp to 6046 (stub handler)
- ffc8: jmp to 6054 (stub handler)
- ffcc: jmp to 6062 (stub handler)
- ffd0: jmp to 6070 (stub handler)
- ffd4: jmp to 607e (valid code - main IRQ?)
- ffd8: jmp to 608c (stub handler)
- ffdc: jmp to 609a (stub handler)
- ffe0: jmp to 60a8 (stub handler)
- ffe4: jmp to 60b6 (stub handler)
- ffe8: jmp to 60c4 (stub handler)
- ffec: jmp to 60d2 (stub handler)
-
- fff0: 7d
-
- fffa: e0 60 (60e0 vector) (stub handler)
- fffc: 88 e1 (e188 startup vector)
- fffe: 02 e0 (e002 vector)
-
+ Tetris - hold P1 Down + P1 Anticlockwise (Button 2) on boot
+ Space Invaders - hold P1 Down + P1 Button 1 on boot
+ ABL Air-Blaster - none?
----
@@ -195,28 +74,28 @@
#include "machine/bankdev.h"
#include "audio/elan_eu3a05.h"
#include "machine/elan_eu3a05gpio.h"
+#include "machine/elan_eu3a05sys.h"
+#include "video/elan_eu3a05vid.h"
-class radica_eu3a05_state : public driver_device
+class elan_eu3a05_state : public driver_device
{
public:
- radica_eu3a05_state(const machine_config &mconfig, device_type type, const char *tag)
+ elan_eu3a05_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_ram(*this, "ram"),
- m_vram(*this, "vram"),
- m_spriteram(*this, "spriteram"),
- m_palram(*this, "palram"),
- m_unk5007(*this, "unk5007"),
- m_unk5008(*this, "unk5008"),
m_gpio(*this, "gpio"),
+ m_sys(*this, "sys"),
+ m_sound(*this, "eu3a05sound"),
+ m_vid(*this, "vid"),
m_pixram(*this, "pixram"),
m_bank(*this, "bank"),
m_gfxdecode(*this, "gfxdecode"),
m_palette(*this, "palette")
{ }
- void radicasi(machine_config &config);
+ void elan_eu3a05(machine_config &config);
void airblsjs(machine_config& config);
private:
@@ -224,61 +103,21 @@ private:
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
// system
- DECLARE_READ8_MEMBER(radicasi_5003_r);
- DECLARE_READ8_MEMBER(radicasi_pal_ntsc_r);
- DECLARE_READ8_MEMBER(radicasi_rombank_lo_r);
- DECLARE_WRITE8_MEMBER(radicasi_rombank_lo_w);
- DECLARE_WRITE8_MEMBER(radicasi_rombank_hi_w);
-
- // DMA
- DECLARE_WRITE8_MEMBER(radicasi_dmasrc_lo_w);
- DECLARE_WRITE8_MEMBER(radicasi_dmasrc_md_w);
- DECLARE_WRITE8_MEMBER(radicasi_dmasrc_hi_w);
- DECLARE_READ8_MEMBER(radicasi_dmasrc_lo_r);
- DECLARE_READ8_MEMBER(radicasi_dmasrc_md_r);
- DECLARE_READ8_MEMBER(radicasi_dmasrc_hi_r);
- DECLARE_WRITE8_MEMBER(radicasi_dmadst_lo_w);
- DECLARE_WRITE8_MEMBER(radicasi_dmadst_hi_w);
- DECLARE_READ8_MEMBER(radicasi_dmadst_lo_r);
- DECLARE_READ8_MEMBER(radicasi_dmadst_hi_r);
- DECLARE_WRITE8_MEMBER(radicasi_dmasize_lo_w);
- DECLARE_WRITE8_MEMBER(radicasi_dmasize_hi_w);
- DECLARE_READ8_MEMBER(radicasi_dmasize_lo_r);
- DECLARE_READ8_MEMBER(radicasi_dmasize_hi_r);
- DECLARE_READ8_MEMBER(radicasi_dmatrg_r);
- DECLARE_WRITE8_MEMBER(radicasi_dmatrg_w);
-
- // VIDEO
- // tile bases
- DECLARE_WRITE8_MEMBER(radicasi_tile_gfxbase_lo_w);
- DECLARE_WRITE8_MEMBER(radicasi_tile_gfxbase_hi_w);
- DECLARE_READ8_MEMBER(radicasi_tile_gfxbase_lo_r);
- DECLARE_READ8_MEMBER(radicasi_tile_gfxbase_hi_r);
- // sprite tile bases
- DECLARE_WRITE8_MEMBER(radicasi_sprite_gfxbase_lo_w);
- DECLARE_WRITE8_MEMBER(radicasi_sprite_gfxbase_hi_w);
- DECLARE_READ8_MEMBER(radicasi_sprite_gfxbase_lo_r);
- DECLARE_READ8_MEMBER(radicasi_sprite_gfxbase_hi_r);
-
- DECLARE_WRITE8_MEMBER(radicasi_vidctrl_w);
-
- DECLARE_READ8_MEMBER(radicasi_sprite_bg_scroll_r);
- DECLARE_WRITE8_MEMBER(radicasi_sprite_bg_scroll_w);
+ DECLARE_READ8_MEMBER(elan_eu3a05_5003_r);
+ DECLARE_READ8_MEMBER(elan_eu3a05_pal_ntsc_r);
+ DECLARE_WRITE8_MEMBER(elan_eu3a05_500b_unk_w);
// more sound regs?
- DECLARE_READ8_MEMBER(radicasi_50a9_r);
- DECLARE_WRITE8_MEMBER(radicasi_50a9_w);
+ DECLARE_READ8_MEMBER(elan_eu3a05_50a9_r);
+ DECLARE_WRITE8_MEMBER(elan_eu3a05_50a9_w);
INTERRUPT_GEN_MEMBER(interrupt);
- DECLARE_READ8_MEMBER(radicasi_nmi_vector_r);
- DECLARE_READ8_MEMBER(radicasi_irq_vector_r);
-
// for callback
DECLARE_READ8_MEMBER(read_full_space);
- void radicasi_bank_map(address_map &map);
- void radicasi_map(address_map &map);
+ void elan_eu3a05_bank_map(address_map &map);
+ void elan_eu3a05_map(address_map &map);
// driver_device overrides
virtual void machine_start() override;
@@ -289,426 +128,40 @@ private:
required_device<cpu_device> m_maincpu;
required_device<screen_device> m_screen;
required_shared_ptr<uint8_t> m_ram;
- required_shared_ptr<uint8_t> m_vram;
- required_shared_ptr<uint8_t> m_spriteram;
- required_shared_ptr<uint8_t> m_palram;
- required_shared_ptr<uint8_t> m_unk5007;
- required_shared_ptr<uint8_t> m_unk5008;
- required_device<radica6502_gpio_device> m_gpio;
+ required_device<elan_eu3a05gpio_device> m_gpio;
+ required_device<elan_eu3a05sys_device> m_sys;
+ required_device<elan_eu3a05_sound_device> m_sound;
+ required_device<elan_eu3a05vid_device> m_vid;
required_shared_ptr<uint8_t> m_pixram;
required_device<address_map_bank_device> m_bank;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
- uint8_t m_rombank_hi;
- uint8_t m_rombank_lo;
- uint8_t m_vidctrl;
uint8_t m_50a9_data;
-
- uint8_t m_dmasrc_lo_data;
- uint8_t m_dmasrc_md_data;
- uint8_t m_dmasrc_hi_data;
- uint8_t m_dmadst_lo_data;
- uint8_t m_dmadst_hi_data;
- uint8_t m_dmasize_lo_data;
- uint8_t m_dmasize_hi_data;
-
- uint8_t m_tile_gfxbase_lo_data;
- uint8_t m_tile_gfxbase_hi_data;
-
- uint8_t m_sprite_gfxbase_lo_data;
- uint8_t m_sprite_gfxbase_hi_data;
-
- uint8_t m_bg_scroll[2];
-
- int m_custom_irq;
- int m_custom_nmi;
- uint16_t m_custom_irq_vector;
- uint16_t m_custom_nmi_vector;
-
- 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 radica_eu3a05_state::video_start()
+void elan_eu3a05_state::video_start()
{
}
-/* (m_tile_gfxbase_lo_data | (m_tile_gfxbase_hi_data << 8)) * 0x100
- gives you the actual rom address, everything references the 3MByte - 4MByte region, like the banking so
- the system can probably have up to a 4MByte rom, all games we have so far just use the upper 1MByte of
- that space (Tetris seems to rely on mirroring? as it sets all addresses up for the lower 1MB instead)
-*/
-void radica_eu3a05_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+uint32_t elan_eu3a05_state::screen_update(screen_device& screen, bitmap_ind16& bitmap, const rectangle& cliprect)
{
- address_space& fullbankspace = m_bank->space(AS_PROGRAM);
-
- /*
- Sprites
- AA yy xx cc XX YY aa bb
-
- yy = y position
- xx = x position
- XX = texture x start
- YY = texture y start
- aa = same as unk2 on tiles
- bb = sometimes set in invaders
- cc = same as attr on tiles (colour / priority?)
-
- AA = attributes
- e--- fFsS
- e = enable
- S = SizeX
- s = SizeY
- F = FlipX
- f = FlipY (assumed, not seen)
-
- */
-
- for (int i = 0; i < 512; i += 8)
- {
- uint8_t x = m_spriteram[i + 2];
- uint8_t y = m_spriteram[i + 1];
-
- /*
- Space Invaders draws the player base with this specific y value before the start of each life
- and expects it to NOT wrap around. There are no high priority tiles or anything else to hide
- and it doesn't appear on real hardware.
-
- it's possible sprites don't wrap around at all (but then you couldn't have smooth entry at the
- top of the screen - there are no extra y co-ordinate bits. However there would have been easier
- ways to hide this tho as there are a bunch of unseen lines at the bottom of the screen anyway!
-
- needs further investigation.
- */
- if (y==255)
- continue;
-
- uint8_t tex_x = m_spriteram[i + 4];
- uint8_t tex_y = m_spriteram[i + 5];
-
- uint8_t flags = m_spriteram[i + 0];
- uint8_t attr = m_spriteram[i + 3];
- uint8_t unk2 = m_spriteram[i + 6];
-
-
- //int priority = attr & 0x0f;
- int colour = attr & 0xf0;
-
- // ? game select has this set to 0xff, but clearly doesn't want the palette to change!
- // while in Space Invaders this has to be palette for the UFO to be red.
- if (colour & 0x80)
- colour = 0;
-
- int transpen = 0;
-
- /* HACK - how is this calculated
- phoenix and the game select need it like this
- it isn't a simple case of unk2 being transpen either because Qix has some elements set to 0x07
- 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))
- transpen = 0xff;
-
-
- if (!(flags & 0x80))
- continue;
-
- int sizex = 8;
- int sizey = 8;
-
- if (flags & 0x01)
- {
- sizex = 16;
- }
-
- if (flags & 0x02)
- {
- sizey = 16;
- }
-
- int base = (m_sprite_gfxbase_lo_data | (m_sprite_gfxbase_hi_data << 8)) * 0x100;
-
- for (int yy = 0; yy < sizey; yy++)
- {
- uint16_t* row;
-
- if (flags & 0x08) // guess flipy
- {
- row = &bitmap.pix16((y + (sizey - 1 - yy)) & 0xff);
- }
- else
- {
- row = &bitmap.pix16((y + yy) & 0xff);
- }
-
- for (int xx = 0; xx < sizex; xx++)
- {
- int realaddr = base + ((tex_x + xx) & 0xff);
- realaddr += ((tex_y + yy) & 0xff) * 256;
-
- uint8_t pix = fullbankspace.read_byte(realaddr);
-
- if (pix != transpen)
- {
- if (flags & 0x04) // flipx
- {
- row[(x + (sizex - 1 - xx)) & 0xff] = (pix + ((colour & 0x70) << 1)) & 0xff;
- }
- else
- {
- row[(x + xx) & 0xff] = (pix + ((colour & 0x70) << 1)) & 0xff;
- }
- }
- }
- }
- }
-}
-
-double hue2rgb(double p, double q, double t)
-{
- if (t < 0) t += 1;
- if (t > 1) t -= 1;
- if (t < 1 / 6.0f) return p + (q - p) * 6 * t;
- if (t < 1 / 2.0f) return q;
- if (t < 2 / 3.0f) return p + (q - p) * (2 / 3.0f - t) * 6;
- return p;
-}
-
-// a hacky mess for now
-bool radica_eu3a05_state::get_tile_data(int base, int drawpri, int& tile, int &attr, int &unk2)
-{
- tile = m_vram[base * 4] + (m_vram[(base * 4) + 1] << 8);
-
- // these seem to be the basically the same as attr/unk2 in the sprites, which also make
- // very little sense.
- attr = m_vram[(base * 4) + 2];
- unk2 = m_vram[(base * 4) + 3];
-
- /* hack for phoenix title screens.. the have attr set to 0x3f which change the colour bank in ways we don't want
- and also by our interpretation of 0x0f bits sets the tiles to priority over sprites (although in this case
- that might tbe ok, because it looks like the sprites also have that set */
- if (unk2 == 0x07)
- attr = 0;
-
- int priority = attr & 0x0f;
-
- // likely wrong
- if ((drawpri == 0 && priority == 0x0f) || (drawpri == 1 && priority != 0x0f))
- return false;
-
- return true;
-}
-void radica_eu3a05_state::draw_tilemaps(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int drawpri)
-{
- /* this doesn't handle 8x8 4bpp, haven't seen it used
- nor is there support for horizontal scrolling etc.
- for the same reasons
- */
-
- int scroll = (m_bg_scroll[1] << 8) | m_bg_scroll[0];
- address_space& fullbankspace = m_bank->space(AS_PROGRAM);
-
- if (m_vidctrl & 0x40) // 16x16 tiles
- {
- int startrow = (scroll >> 4) & 0x1f;
-
- for (int y = 0; y < 16; y++)
- {
- for (int x = 0; x < 16; x++)
- {
- int realstartrow = (startrow + y);
-
- if (realstartrow >= 28)
- realstartrow -= 28;
-
- int base = (((realstartrow + y) & 0x1f) * 8) + x;
-
- int tile,attr,unk2;
-
- if (!get_tile_data(base, drawpri, tile,attr,unk2))
- continue;
-
- int colour = attr & 0xf0;
-
- if (m_vidctrl & 0x20) // 4bpp mode
- {
- tile = (tile & 0xf) + ((tile & ~0xf) * 16);
- tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5);
- }
- else
- {
- tile = (tile & 0xf) + ((tile & ~0xf) * 16);
- tile <<= 1;
-
- tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5);
- }
-
- for (int i = 0; i < 16; i++)
- {
- int drawline = (y * 16) + i;
- drawline -= scroll & 0xf;
-
- if ((drawline >= 0) && (drawline < 256))
- {
- uint16_t* row = &bitmap.pix16(drawline);
-
- if (m_vidctrl & 0x20) // 4bpp
- {
- for (int xx = 0; xx < 16; xx += 2)
- {
- int realaddr = ((tile + i * 16) << 3) + (xx >> 1);
- uint8_t pix = fullbankspace.read_byte(realaddr);
- row[x * 16 + xx + 0] = ((pix & 0xf0) >> 4) + colour;
- row[x * 16 + xx + 1] = ((pix & 0x0f) >> 0) + colour;
- }
- }
- else // 8bpp
- {
- for (int xx = 0; xx < 16; xx++)
- {
- int realaddr = ((tile + i * 32) << 3) + xx;
- uint8_t pix = fullbankspace.read_byte(realaddr);
- row[x * 16 + xx] = (pix + ((colour & 0x70) << 1)) & 0xff;
- }
- }
-
- }
- }
- }
- }
- }
- else // 8x8 tiles
- {
- // Phoenix scrolling actually skips a pixel, jumping from 0x001 to 0x1bf, scroll 0x000 isn't used, maybe it has other meanings?
-
- int startrow = (scroll >> 3) & 0x3f;
-
- for (int y = 0; y < 32; y++)
- {
- for (int x = 0; x < 32; x++)
- {
- int realstartrow = (startrow + y);
-
- if (realstartrow >= 56)
- realstartrow -= 56;
-
- int base = (((realstartrow) & 0x3f) * 32) + x;
-
- int tile,attr,unk2;
-
- if (!get_tile_data(base, drawpri, tile,attr,unk2))
- continue;
-
- int colour = attr & 0xf0;
-
- tile = (tile & 0x1f) + ((tile & ~0x1f) * 8);
- tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5);
-
- for (int i = 0; i < 8; i++)
- {
- int drawline = (y * 8) + i;
- drawline -= scroll & 0x7;
-
- if ((drawline >= 0) && (drawline < 256))
- {
- uint16_t* row = &bitmap.pix16(drawline);
-
- for (int xx = 0; xx < 8; xx++)
- {
- int realaddr = ((tile + i * 32) << 3) + xx;
- uint8_t pix = fullbankspace.read_byte(realaddr);
- row[x * 8 + xx] = (pix + ((colour & 0x70) << 1)) & 0xff;
- }
- }
- }
- }
- }
- }
-}
-
-uint32_t radica_eu3a05_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
-{
- bitmap.fill(0, cliprect);
-
- // Palette
- int offs = 0;
- for (int index = 0;index < 256; index++)
- {
- uint16_t dat = m_palram[offs++] << 8;
- dat |= m_palram[offs++];
-
- // llll lsss ---h hhhh
- int l_raw = (dat & 0xf800) >> 11;
- int sl_raw = (dat & 0x0700) >> 8;
- int h_raw = (dat & 0x001f) >> 0;
-
- double l = (double)l_raw / 31.0f;
- double s = (double)sl_raw / 7.0f;
- double h = (double)h_raw / 24.0f;
-
- double r, g, b;
-
- if (s == 0) {
- r = g = b = l; // greyscale
- } else {
- double q = l < 0.5f ? l * (1 + s) : l + s - l * s;
- double p = 2 * l - q;
- r = hue2rgb(p, q, h + 1/3.0f);
- g = hue2rgb(p, q, h);
- b = hue2rgb(p, q, h - 1/3.0f);
- }
-
- int r_real = r * 255.0f;
- int g_real = g * 255.0f;
- int b_real = b * 255.0f;
-
- m_palette->set_pen_color(index, r_real, g_real, b_real);
- }
-
-
- draw_tilemaps(screen,bitmap,cliprect,0);
- draw_sprites(screen,bitmap,cliprect);
- draw_tilemaps(screen,bitmap,cliprect,1);
-
- return 0;
+ return m_vid->screen_update(screen, bitmap, cliprect);
}
// System control
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_rombank_hi_w)
-{
- // written with the banking?
- //logerror("%s: radicasi_rombank_hi_w (set ROM bank) %02x\n", machine().describe_context(), data);
- m_rombank_hi = data;
-
- m_bank->set_bank(m_rombank_lo | (m_rombank_hi << 8));
-}
-
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_rombank_lo_w)
-{
- //logerror("%s: radicasi_rombank_lo_w (select ROM bank) %02x\n", machine().describe_context(), data);
- m_rombank_lo = data;
-}
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_rombank_lo_r)
-{
- return m_rombank_lo;
-}
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_pal_ntsc_r)
+READ8_MEMBER(elan_eu3a05_state::elan_eu3a05_pal_ntsc_r)
{
// how best to handle this, we probably need to run the PAL machine at 50hz
// the text under the radica logo differs between regions
- logerror("%s: radicasi_pal_ntsc_r (region + more?)\n", machine().describe_context());
+ logerror("%s: elan_eu3a05_pal_ntsc_r (region + more?)\n", machine().describe_context());
return 0xff; // NTSC
//return 0x00; // PAL
}
-READ8_MEMBER(radica_eu3a05_state::radicasi_5003_r)
+READ8_MEMBER(elan_eu3a05_state::elan_eu3a05_5003_r)
{
/* masked with 0x0f, 0x01 or 0x03 depending on situation..
@@ -720,306 +173,114 @@ READ8_MEMBER(radica_eu3a05_state::radicasi_5003_r)
*/
- logerror("%s: radicasi_5003_r (RNG?)\n", machine().describe_context());
+ logerror("%s: elan_eu3a05_5003_r (RNG?)\n", machine().describe_context());
return machine().rand();
}
-// Video device
-
-// Tile bases
-
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_tile_gfxbase_lo_w)
-{
- //logerror("%s: radicasi_tile_gfxbase_lo_w (select GFX base lower) %02x\n", machine().describe_context(), data);
- m_tile_gfxbase_lo_data = data;
-}
-
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_tile_gfxbase_hi_w)
-{
- //logerror("%s: radicasi_tile_gfxbase_hi_w (select GFX base upper) %02x\n", machine().describe_context(), data);
- m_tile_gfxbase_hi_data = data;
-}
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_tile_gfxbase_lo_r)
-{
- //logerror("%s: radicasi_tile_gfxbase_lo_r (GFX base lower)\n", machine().describe_context());
- return m_tile_gfxbase_lo_data;
-}
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_tile_gfxbase_hi_r)
-{
- //logerror("%s: radicasi_tile_gfxbase_hi_r (GFX base upper)\n", machine().describe_context());
- return m_tile_gfxbase_hi_data;
-}
-
-// Sprite Tile bases
-
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_sprite_gfxbase_lo_w)
-{
- //logerror("%s: radicasi_sprite_gfxbase_lo_w (select Sprite GFX base lower) %02x\n", machine().describe_context(), data);
- m_sprite_gfxbase_lo_data = data;
-}
-
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_sprite_gfxbase_hi_w)
-{
- //logerror("%s: radicasi_sprite_gfxbase_hi_w (select Sprite GFX base upper) %02x\n", machine().describe_context(), data);
- m_sprite_gfxbase_hi_data = data;
-}
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_sprite_gfxbase_lo_r)
-{
- //logerror("%s: radicasi_sprite_gfxbase_lo_r (Sprite GFX base lower)\n", machine().describe_context());
- return m_sprite_gfxbase_lo_data;
-}
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_sprite_gfxbase_hi_r)
-{
- //logerror("%s: radicasi_sprite_gfxbase_hi_r (Sprite GFX base upper)\n", machine().describe_context());
- return m_sprite_gfxbase_hi_data;
-}
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_sprite_bg_scroll_r)
-{
- return m_bg_scroll[offset];
-
-}
-
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_sprite_bg_scroll_w)
-{
- m_bg_scroll[offset] = data;
-}
-
-
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_vidctrl_w)
-{
- logerror("%s: radicasi_vidctrl_w %02x (video control?)\n", machine().describe_context(), data);
- /*
- c3 8bpp 16x16 1100 0011
- e3 4bpp 16x16 1110 0011
- 83 8bpp 8x8 1000 0011
- 02 8bpp 8x8 (phoenix) 0000 0010
- */
- m_vidctrl = data;
-}
-
-// DMA device
-
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_dmasrc_lo_w)
-{
- logerror("%s: radicasi_dmasrc_lo_w (select DMA source low) %02x\n", machine().describe_context(), data);
- m_dmasrc_lo_data = data;
-}
-
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_dmasrc_md_w)
-{
- logerror("%s: radicasi_dmasrc_md_w (select DMA source middle) %02x\n", machine().describe_context(), data);
- m_dmasrc_md_data = data;
-}
-
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_dmasrc_hi_w)
-{
- logerror("%s: radicasi_dmasrc_hi_w (select DMA source upper) %02x\n", machine().describe_context(), data);
- m_dmasrc_hi_data = data;
-}
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_dmasrc_lo_r)
-{
- logerror("%s: radicasi_dmasrc_lo_r (DMA source low)\n", machine().describe_context());
- return m_dmasrc_lo_data;
-}
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_dmasrc_md_r)
-{
- logerror("%s: radicasi_dmasrc_md_r (DMA source middle)\n", machine().describe_context());
- return m_dmasrc_md_data;
-}
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_dmasrc_hi_r)
-{
- logerror("%s: radicasi_dmasrc_hi_r (DMA source upper)\n", machine().describe_context());
- return m_dmasrc_hi_data;
-}
-
-
-
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_dmadst_lo_w)
-{
- logerror("%s: radicasi_dmadst_lo_w (select DMA Dest lower) %02x\n", machine().describe_context(), data);
- m_dmadst_lo_data = data;
-}
-
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_dmadst_hi_w)
-{
- logerror("%s: radicasi_dmadst_hi_w (select DMA Dest upper) %02x\n", machine().describe_context(), data);
- m_dmadst_hi_data = data;
-}
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_dmadst_lo_r)
-{
- logerror("%s: radicasi_dmadst_lo_r (DMA Dest lower)\n", machine().describe_context());
- return m_dmadst_lo_data;
-}
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_dmadst_hi_r)
-{
- logerror("%s: radicasi_dmadst_hi_r (DMA Dest upper)\n", machine().describe_context());
- return m_dmadst_hi_data;
-}
-
-
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_dmasize_lo_w)
-{
- logerror("%s: radicasi_dmasize_lo_w (select DMA Size lower) %02x\n", machine().describe_context(), data);
- m_dmasize_lo_data = data;
-}
-
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_dmasize_hi_w)
-{
- logerror("%s: radicasi_dmasize_hi_w (select DMA Size upper) %02x\n", machine().describe_context(), data);
- m_dmasize_hi_data = data;
-}
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_dmasize_lo_r)
-{
- logerror("%s: radicasi_dmasize_lo_r (DMA Size lower)\n", machine().describe_context());
- return m_dmasize_lo_data;
-}
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_dmasize_hi_r)
-{
- logerror("%s: radicasi_dmasize_hi_r (DMA Size upper)\n", machine().describe_context());
- return m_dmasize_hi_data;
-}
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_dmatrg_r)
-{
- logerror("%s: radicasi_dmatrg_r (DMA operation state?)\n", machine().describe_context());
- return 0x00;//m_dmatrg_data;
-}
-
-
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_dmatrg_w)
-{
- logerror("%s: radicasi_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_maincpu->space(AS_PROGRAM);
-
- if (data)
- {
- int src = (m_dmasrc_lo_data << 0) | (m_dmasrc_md_data << 8) | (m_dmasrc_hi_data << 16);
- uint16_t dest = (m_dmadst_lo_data | (m_dmadst_hi_data << 8));
- uint16_t size = (m_dmasize_lo_data | (m_dmasize_hi_data << 8));
-
- logerror(" Doing DMA %06x to %04x size %04x\n", src, dest, size);
-
- for (int i = 0; i < size; i++)
- {
- uint8_t dat = fullbankspace.read_byte(src + i);
- destspace.write_byte(dest + i, dat);
- }
- }
-}
-
-
-
// probably also sound device, maybe for forcing channels to stop?
-READ8_MEMBER(radica_eu3a05_state::radicasi_50a9_r)
+READ8_MEMBER(elan_eu3a05_state::elan_eu3a05_50a9_r)
{
- logerror("%s: radicasi_50a9_r\n", machine().describe_context());
+ logerror("%s: elan_eu3a05_50a9_r\n", machine().describe_context());
return m_50a9_data;
}
-WRITE8_MEMBER(radica_eu3a05_state::radicasi_50a9_w)
+WRITE8_MEMBER(elan_eu3a05_state::elan_eu3a05_50a9_w)
{
- logerror("%s: radicasi_50a9_w %02x\n", machine().describe_context(), data);
+ logerror("%s: elan_eu3a05_50a9_w %02x\n", machine().describe_context(), data);
m_50a9_data = data;
}
+WRITE8_MEMBER(elan_eu3a05_state::elan_eu3a05_500b_unk_w)
+{
+ // this is the PAL / NTSC flag when read, so what are writes?
+ logerror("%s: elan_eu3a05_500b_unk_w %02x\n", machine().describe_context(), data);
+}
+
// sound callback
-READ8_MEMBER(radica_eu3a05_state::read_full_space)
+READ8_MEMBER(elan_eu3a05_state::read_full_space)
{
address_space& fullbankspace = m_bank->space(AS_PROGRAM);
return fullbankspace.read_byte(offset);
}
-void radica_eu3a05_state::radicasi_map(address_map &map)
+// code at 8bc6 in Air Blaster makes unwanted reads, why, bug in code, flow issue?
+//[:maincpu] ':maincpu' (8BC6): unmapped program memory read from 5972 & FF
+
+
+void elan_eu3a05_state::elan_eu3a05_map(address_map &map)
{
// can the addresses move around?
- map(0x0000, 0x05ff).ram().share("ram");
- map(0x0600, 0x3dff).ram().share("vram");
- map(0x3e00, 0x3fff).ram().share("spriteram");
- map(0x4800, 0x49ff).ram().share("palram");
+ map(0x0000, 0x3fff).ram().share("ram");
+ map(0x4800, 0x49ff).rw(m_vid, FUNC(elan_eu3a05commonvid_device::palette_r), FUNC(elan_eu3a05commonvid_device::palette_w));
// 500x system regs?
- map(0x5003, 0x5003).r(FUNC(radica_eu3a05_state::radicasi_5003_r));
-
- map(0x5007, 0x5007).ram().share("unk5007"); // main NMI?IRQ? mask on 0x02
- map(0x5008, 0x5008).ram().share("unk5008"); // timer IRQ masks or enables?
-
-
- map(0x500b, 0x500b).r(FUNC(radica_eu3a05_state::radicasi_pal_ntsc_r)); // PAL / NTSC flag at least
- map(0x500c, 0x500c).w(FUNC(radica_eu3a05_state::radicasi_rombank_hi_w));
- map(0x500d, 0x500d).rw(FUNC(radica_eu3a05_state::radicasi_rombank_lo_r), FUNC(radica_eu3a05_state::radicasi_rombank_lo_w));
+ map(0x5000, 0x5000).ram();
+ map(0x5001, 0x5001).ram();
+ // 5002
+ map(0x5003, 0x5003).r(FUNC(elan_eu3a05_state::elan_eu3a05_5003_r));
+ map(0x5004, 0x5004).ram();
+ // 5005
+ map(0x5006, 0x5006).ram();
+ map(0x5007, 0x5008).rw(m_sys, FUNC(elan_eu3a05commonsys_device::intmask_r), FUNC(elan_eu3a05commonsys_device::intmask_w));
+ map(0x5009, 0x5009).ram();
+ map(0x500a, 0x500a).ram();
+ map(0x500b, 0x500b).rw(FUNC(elan_eu3a05_state::elan_eu3a05_pal_ntsc_r), FUNC(elan_eu3a05_state::elan_eu3a05_500b_unk_w)); // PAL / NTSC flag at least
+ map(0x500c, 0x500d).rw(m_sys, FUNC(elan_eu3a05commonsys_device::elan_eu3a05_rombank_r), FUNC(elan_eu3a05commonsys_device::elan_eu3a05_rombank_w));
// 501x DMA controller
- map(0x500F, 0x500F).rw(FUNC(radica_eu3a05_state::radicasi_dmasrc_lo_r), FUNC(radica_eu3a05_state::radicasi_dmasrc_lo_w));
- map(0x5010, 0x5010).rw(FUNC(radica_eu3a05_state::radicasi_dmasrc_md_r), FUNC(radica_eu3a05_state::radicasi_dmasrc_md_w));
- map(0x5011, 0x5011).rw(FUNC(radica_eu3a05_state::radicasi_dmasrc_hi_r), FUNC(radica_eu3a05_state::radicasi_dmasrc_hi_w));
-
- map(0x5012, 0x5012).rw(FUNC(radica_eu3a05_state::radicasi_dmadst_lo_r), FUNC(radica_eu3a05_state::radicasi_dmadst_lo_w));
- map(0x5013, 0x5013).rw(FUNC(radica_eu3a05_state::radicasi_dmadst_hi_r), FUNC(radica_eu3a05_state::radicasi_dmadst_hi_w));
-
- map(0x5014, 0x5014).rw(FUNC(radica_eu3a05_state::radicasi_dmasize_lo_r), FUNC(radica_eu3a05_state::radicasi_dmasize_lo_w));
- map(0x5015, 0x5015).rw(FUNC(radica_eu3a05_state::radicasi_dmasize_hi_r), FUNC(radica_eu3a05_state::radicasi_dmasize_hi_w));
-
- map(0x5016, 0x5016).rw(FUNC(radica_eu3a05_state::radicasi_dmatrg_r), FUNC(radica_eu3a05_state::radicasi_dmatrg_w));
+ map(0x500f, 0x5015).rw(m_sys, FUNC(elan_eu3a05sys_device::dma_param_r), FUNC(elan_eu3a05sys_device::dma_param_w));
+ map(0x5016, 0x5016).rw(m_sys, FUNC(elan_eu3a05sys_device::elan_eu3a05_dmatrg_r), FUNC(elan_eu3a05sys_device::elan_eu3a05_dmatrg_w));
// 502x - 503x video regs area?
map(0x5020, 0x5026).ram(); // unknown, space invaders sets these to fixed values, tetris has them as 00
- map(0x5027, 0x5027).w(FUNC(radica_eu3a05_state::radicasi_vidctrl_w));
-
- map(0x5029, 0x5029).rw(FUNC(radica_eu3a05_state::radicasi_tile_gfxbase_lo_r), FUNC(radica_eu3a05_state::radicasi_tile_gfxbase_lo_w)); // tilebase
- map(0x502a, 0x502a).rw(FUNC(radica_eu3a05_state::radicasi_tile_gfxbase_hi_r), FUNC(radica_eu3a05_state::radicasi_tile_gfxbase_hi_w)); // tilebase
-
- map(0x502b, 0x502b).rw(FUNC(radica_eu3a05_state::radicasi_sprite_gfxbase_lo_r), FUNC(radica_eu3a05_state::radicasi_sprite_gfxbase_lo_w)); // tilebase (spr?)
- map(0x502c, 0x502c).rw(FUNC(radica_eu3a05_state::radicasi_sprite_gfxbase_hi_r), FUNC(radica_eu3a05_state::radicasi_sprite_gfxbase_hi_w)); // tilebase (spr?)
-
- map(0x5031, 0x5032).rw(FUNC(radica_eu3a05_state::radicasi_sprite_bg_scroll_r), FUNC(radica_eu3a05_state::radicasi_sprite_bg_scroll_w));
-
+ map(0x5027, 0x5027).rw(m_vid, FUNC(elan_eu3a05vid_device::elan_eu3a05_vidctrl_r), FUNC(elan_eu3a05vid_device::elan_eu3a05_vidctrl_w));
+ map(0x5028, 0x5028).ram();
+ map(0x5029, 0x5029).rw(m_vid, FUNC(elan_eu3a05vid_device::tile_gfxbase_lo_r), FUNC(elan_eu3a05vid_device::tile_gfxbase_lo_w)); // tilebase
+ map(0x502a, 0x502a).rw(m_vid, FUNC(elan_eu3a05vid_device::tile_gfxbase_hi_r), FUNC(elan_eu3a05vid_device::tile_gfxbase_hi_w)); // tilebase
+ map(0x502b, 0x502b).rw(m_vid, FUNC(elan_eu3a05vid_device::sprite_gfxbase_lo_r), FUNC(elan_eu3a05vid_device::sprite_gfxbase_lo_w)); // tilebase (spr?)
+ map(0x502c, 0x502c).rw(m_vid, FUNC(elan_eu3a05vid_device::sprite_gfxbase_hi_r), FUNC(elan_eu3a05vid_device::sprite_gfxbase_hi_w)); // tilebase (spr?)
+ map(0x502d, 0x502d).ram();
+ map(0x502e, 0x502e).rw(m_vid, FUNC(elan_eu3a05vid_device::splitpos_r), FUNC(elan_eu3a05vid_device::splitpos_w)); // split position
+ map(0x502f, 0x502f).ram();
+
+ map(0x5030, 0x5030).ram();
+ map(0x5031, 0x5032).rw(m_vid, FUNC(elan_eu3a05vid_device::tile_scroll_r), FUNC(elan_eu3a05vid_device::tile_scroll_w));
+ map(0x5033, 0x5036).rw(m_vid, FUNC(elan_eu3a05vid_device::tile_xscroll_r), FUNC(elan_eu3a05vid_device::tile_xscroll_w)); // there are 2 scroll values in here, air blaster 3d stages uses split scrolling like huntin'3 on eu3a14
+ // 5037
+ map(0x5038, 0x5038).ram();
// 504x GPIO area?
- map(0x5040, 0x5046).rw("gpio", FUNC(radica6502_gpio_device::gpio_r), FUNC(radica6502_gpio_device::gpio_w));
- map(0x5048, 0x504a).w("gpio", FUNC(radica6502_gpio_device::gpio_unk_w));
+ 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
// 508x sound
- map(0x5080, 0x5091).rw("6ch_sound", FUNC(radica6502_sound_device::radicasi_sound_addr_r), FUNC(radica6502_sound_device::radicasi_sound_addr_w));
- map(0x5092, 0x50a3).rw("6ch_sound", FUNC(radica6502_sound_device::radicasi_sound_size_r), FUNC(radica6502_sound_device::radicasi_sound_size_w));
- map(0x50a4, 0x50a4).rw("6ch_sound", FUNC(radica6502_sound_device::radicasi_sound_unk_r), FUNC(radica6502_sound_device::radicasi_sound_unk_w));
- map(0x50a5, 0x50a5).rw("6ch_sound", FUNC(radica6502_sound_device::radicasi_sound_trigger_r), FUNC(radica6502_sound_device::radicasi_sound_trigger_w));
-
- map(0x50a8, 0x50a8).r("6ch_sound", FUNC(radica6502_sound_device::radicasi_50a8_r)); // possible 'stopped' status of above channels, waits for it to be 0x3f in places
-
- map(0x50a9, 0x50a9).rw(FUNC(radica_eu3a05_state::radicasi_50a9_r), FUNC(radica_eu3a05_state::radicasi_50a9_w));
+ map(0x5080, 0x5091).rw(m_sound, FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_addr_r), FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_addr_w));
+ map(0x5092, 0x50a3).rw(m_sound, FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_size_r), FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_size_w));
+ map(0x50a4, 0x50a4).rw(m_sound, FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_unk_r), FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_unk_w));
+ map(0x50a5, 0x50a5).rw(m_sound, FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_trigger_r), FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_trigger_w));
+ map(0x50a6, 0x50a6).ram();
+ map(0x50a7, 0x50a7).ram();
+ map(0x50a8, 0x50a8).r(m_sound, FUNC(elan_eu3a05_sound_device::elan_eu3a05_50a8_r)); // possible 'stopped' status of above channels, waits for it to be 0x3f in places
+ map(0x50a9, 0x50a9).rw(FUNC(elan_eu3a05_state::elan_eu3a05_50a9_r), FUNC(elan_eu3a05_state::elan_eu3a05_50a9_w));
//map(0x5000, 0x50ff).ram();
map(0x6000, 0xdfff).m(m_bank, FUNC(address_map_bank_device::amap8));
map(0xe000, 0xffff).rom().region("maincpu", 0x3f8000);
// not sure how these work, might be a modified 6502 core instead.
- map(0xfffa, 0xfffb).r(FUNC(radica_eu3a05_state::radicasi_nmi_vector_r));
- map(0xfffe, 0xffff).r(FUNC(radica_eu3a05_state::radicasi_irq_vector_r));
+ map(0xfffa, 0xfffb).r(m_sys, FUNC(elan_eu3a05commonsys_device::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 radica_eu3a05_state::radicasi_bank_map(address_map &map)
+void elan_eu3a05_state::elan_eu3a05_bank_map(address_map &map)
{
map(0x000000, 0xffffff).noprw(); // shut up any logging when video params are invalid
map(0x000000, 0x3fffff).rom().region("maincpu", 0);
@@ -1089,54 +350,13 @@ static INPUT_PORTS_START( airblsjs )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("Missile")
INPUT_PORTS_END
-/* both NMI and IRQ vectors just point to RTI
- there is a table of jumps just before that, those appear to be the real interrupt functions?
- patch the main IRQ to be the one that decreases an address the code is waiting for
- the others look like they might be timer service routines
-*/
-
-READ8_MEMBER(radica_eu3a05_state::radicasi_nmi_vector_r)
-{
- if (m_custom_nmi)
- {
- return m_custom_nmi_vector >> (offset*8);
- }
- else
- {
- uint8_t *rom = memregion("maincpu")->base();
- return rom[0x3f9ffa + offset];
- }
-}
-READ8_MEMBER(radica_eu3a05_state::radicasi_irq_vector_r)
+void elan_eu3a05_state::machine_start()
{
- if (m_custom_irq)
- {
- return m_custom_irq_vector >> (offset*8);
- }
- else
- {
- uint8_t *rom = memregion("maincpu")->base();
- return rom[0x3f9ffe + offset];
- }
}
-void radica_eu3a05_state::machine_start()
-{
- m_custom_irq = 0;
- m_custom_irq_vector = 0x0000;
-
- m_custom_nmi = 0;
- m_custom_nmi_vector = 0x0000;
-
- m_bank->set_bank(0x7f);
-
- save_item(NAME(m_rombank_lo));
- save_item(NAME(m_rombank_hi));
-}
-
-void radica_eu3a05_state::machine_reset()
+void elan_eu3a05_state::machine_reset()
{
/* the 6502 core sets the default stack value to 0x01bd
and Tetris does not initialize it to anything else
@@ -1209,35 +429,18 @@ static const gfx_layout texture_helper_4bpp_layout =
texlayout_yoffset_4bpp
};
-static GFXDECODE_START( gfx_radicasi_fake )
+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(radica_eu3a05_state::interrupt)
-{
- // Air Blaster uses brk in the code, which is problematic for custom IRQs
- // m_custom_irq = 1;
- // m_custom_irq_vector = 0xffd4;
- // m_maincpu->set_input_line(INPUT_LINE_IRQ0,HOLD_LINE);
-
- // 5007 5008
- // ---- --v- ---- -2-0
- //
- // vector = 0xffb0 + 4 * bit position from right
-
- // each bit seems to relate to an IRQ level
- // v = vblank bit (vector 0xffd4)
- // 0 = used for object movement (enemies / bullets) on air blaster chase levels (vector 0xffb0) needs to be frequent, timer? or hbl?
- // 2 = used for ? on air blaster 2d levels (`vector 0xffb8)
- m_custom_nmi = 1;
- m_custom_nmi_vector = 0xffd4;
- if (m_unk5007[0] & 0x02) // seems to be correct otherwise Air Blaster will crash / give random mid-level Game Over messages
- m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
+INTERRUPT_GEN_MEMBER(elan_eu3a05_state::interrupt)
+{
+ m_sys->generate_custom_interrupt(9);
}
@@ -1251,42 +454,53 @@ INTERRUPT_GEN_MEMBER(radica_eu3a05_state::interrupt)
// low clock speed also helps with the badly programmed controls in Tetris
-void radica_eu3a05_state::radicasi(machine_config &config)
+void elan_eu3a05_state::elan_eu3a05(machine_config &config)
{
/* basic machine hardware */
M6502(config, m_maincpu, XTAL(21'281'370)/12); // wrong, this is the PAL clock
- m_maincpu->set_addrmap(AS_PROGRAM, &radica_eu3a05_state::radicasi_map);
- m_maincpu->set_vblank_int("screen", FUNC(radica_eu3a05_state::interrupt));
+ m_maincpu->set_addrmap(AS_PROGRAM, &elan_eu3a05_state::elan_eu3a05_map);
+ m_maincpu->set_vblank_int("screen", FUNC(elan_eu3a05_state::interrupt));
- ADDRESS_MAP_BANK(config, "bank").set_map(&radica_eu3a05_state::radicasi_bank_map).set_options(ENDIANNESS_LITTLE, 8, 24, 0x8000);
+ ADDRESS_MAP_BANK(config, "bank").set_map(&elan_eu3a05_state::elan_eu3a05_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(radica_eu3a05_state::screen_update));
+ m_screen->set_screen_update(FUNC(elan_eu3a05_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_radicasi_fake);
+ GFXDECODE(config, m_gfxdecode, m_palette, gfx_elan_eu3a05_fake);
- RADICA6502_GPIO(config, m_gpio, 0);
+ 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_EU3A05_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);
+
/* sound hardware */
SPEAKER(config, "mono").front_center();
- radica6502_sound_device &sound(RADICA6502_SOUND(config, "6ch_sound", 8000));
- sound.space_read_callback().set(FUNC(radica_eu3a05_state::read_full_space));
- sound.add_route(ALL_OUTPUTS, "mono", 1.0);
+
+ ELAN_EU3A05_SOUND(config, m_sound, 8000);
+ m_sound->space_read_callback().set(FUNC(elan_eu3a05_state::read_full_space));
+ m_sound->add_route(ALL_OUTPUTS, "mono", 1.0);
}
-void radica_eu3a05_state::airblsjs(machine_config& config)
+void elan_eu3a05_state::airblsjs(machine_config& config)
{
- radicasi(config);
+ elan_eu3a05(config);
m_screen->set_refresh_hz(50);
}
@@ -1313,9 +527,9 @@ ROM_START( airblsjs )
ROM_END
-CONS( 2004, rad_sinv, 0, 0, radicasi, rad_sinv, radica_eu3a05_state, empty_init, "Radica (licensed from Taito)", "Space Invaders [Lunar Rescue, Colony 7, Qix, Phoenix] (Radica, Arcade Legends TV Game)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) // "5 Taito games in 1"
+CONS( 2004, rad_sinv, 0, 0, elan_eu3a05, rad_sinv, elan_eu3a05_state, empty_init, "Radica (licensed from Taito)", "Space Invaders [Lunar Rescue, Colony 7, Qix, Phoenix] (Radica, Arcade Legends TV Game)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND ) // "5 Taito games in 1"
-CONS( 2004, rad_tetr, 0, 0, radicasi, rad_tetr, radica_eu3a05_state, empty_init, "Radica (licensed from Elorg / The Tetris Company)", "Tetris (Radica, Arcade Legends TV Game)", MACHINE_NOT_WORKING ) // "5 Tetris games in 1"
+CONS( 2004, rad_tetr, 0, 0, elan_eu3a05, rad_tetr, elan_eu3a05_state, empty_init, "Radica (licensed from Elorg / The Tetris Company)", "Tetris (Radica, Arcade Legends TV Game)", MACHINE_NOT_WORKING ) // "5 Tetris games in 1"
// ROM contains the string "Credit:XiAn Hummer Software Studio(CHINA) Tel:86-29-84270600 Email:HummerSoft@126.com" PCB has datecode of "050423" (23rd April 2005)
-CONS( 2005, airblsjs, 0, 0, airblsjs, airblsjs, radica_eu3a05_state, empty_init, "Advance Bright Ltd", "Air-Blaster Joystick (AB1500, PAL)", MACHINE_NOT_WORKING )
+CONS( 2005, airblsjs, 0, 0, airblsjs, airblsjs, elan_eu3a05_state, empty_init, "Advance Bright Ltd", "Air-Blaster Joystick (AB1500, PAL)", MACHINE_NOT_WORKING )
diff --git a/src/mame/drivers/elan_eu3a14.cpp b/src/mame/drivers/elan_eu3a14.cpp
index bd06fb489b7..f9f8127802d 100644
--- a/src/mame/drivers/elan_eu3a14.cpp
+++ b/src/mame/drivers/elan_eu3a14.cpp
@@ -68,46 +68,21 @@
#include "machine/bankdev.h"
#include "audio/elan_eu3a05.h"
#include "machine/timer.h"
+#include "machine/elan_eu3a14sys.h"
+#include "video/elan_eu3a05commonvid.h"
-/*
-
-TODO: fill these in for other games, this is for Golden Tee Home
-
-ffb0 rti
-ffb4 rti
-ffb8 rti
-ffbc rti
-
-ffc0 rti
-ffc4 rti
-ffc8 rti
-ffcc rti
-
-ffd0 rti
-ffd4 main irq?
-ffd8 rti
-ffdc rti
-
-ffe0 something with 5045 bit 0x08 and 9d in ram (increase or decrease) (ADC interrupt)
-ffe4 something with 5045 bit 0x20 and 9c in ram (increase of decrease) (ADC interrupt)
-
-ffe8 rti
-ffec rti
-
-regular NMI (e3f0 - jump to ($19e2) which seems to point to rti, but could move..)
-regular IRQ (e3f3 - points to rti)
-
-*/
-class radica_eu3a14_state : public driver_device
+class elan_eu3a14_state : public driver_device
{
public:
- radica_eu3a14_state(const machine_config &mconfig, device_type type, const char *tag)
+ elan_eu3a14_state(const machine_config &mconfig, device_type type, const char *tag)
: driver_device(mconfig, type, tag),
m_maincpu(*this, "maincpu"),
+ m_sys(*this, "sys"),
+ m_sound(*this, "eu3a05sound"),
+ m_commonvid(*this, "commonvid"),
m_mainregion(*this, "maincpu"),
- m_palram(*this, "palram"),
m_scrollregs(*this, "scrollregs"),
m_tilecfg(*this, "tilecfg"),
m_rowscrollregs(*this, "rowscrollregs"),
@@ -117,7 +92,6 @@ public:
m_spriteaddr(*this, "spriteaddr"),
m_spritebase(*this, "spritebase"),
m_mainram(*this, "mainram"),
- m_dmaparams(*this, "dmaparams"),
m_bank(*this, "bank"),
m_palette(*this, "palette"),
m_gfxdecode(*this, "gfxdecode"),
@@ -135,8 +109,6 @@ public:
void init_rad_hnt3();
private:
- READ8_MEMBER(irq_vector_r);
-
// screen updates
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
@@ -145,14 +117,8 @@ private:
INTERRUPT_GEN_MEMBER(interrupt);
- DECLARE_READ8_MEMBER(radicasi_pal_ntsc_r);
-
- DECLARE_READ8_MEMBER(dma_trigger_r);
- DECLARE_WRITE8_MEMBER(dma_trigger_w);
+ DECLARE_READ8_MEMBER(elan_eu3a05_pal_ntsc_r);
- DECLARE_READ8_MEMBER(radicasi_rombank_lo_r);
- DECLARE_WRITE8_MEMBER(radicasi_rombank_lo_w);
- DECLARE_WRITE8_MEMBER(radicasi_rombank_hi_w);
DECLARE_WRITE8_MEMBER(porta_dir_w);
DECLARE_WRITE8_MEMBER(portb_dir_w);
@@ -181,11 +147,11 @@ private:
virtual void video_start() override;
- double hue2rgb(double p, double q, double t);
-
required_device<cpu_device> m_maincpu;
+ required_device<elan_eu3a14sys_device> m_sys;
+ required_device<elan_eu3a05_sound_device> m_sound;
+ required_device<elan_eu3a05commonvid_device> m_commonvid;
required_region_ptr<uint8_t> m_mainregion;
- required_shared_ptr<uint8_t> m_palram;
required_shared_ptr<uint8_t> m_scrollregs;
required_shared_ptr<uint8_t> m_tilecfg;
required_shared_ptr<uint8_t> m_rowscrollregs;
@@ -195,15 +161,12 @@ private:
required_shared_ptr<uint8_t> m_spriteaddr;
required_shared_ptr<uint8_t> m_spritebase;
required_shared_ptr<uint8_t> m_mainram;
- required_shared_ptr<uint8_t> m_dmaparams;
required_device<address_map_bank_device> m_bank;
required_device<palette_device> m_palette;
required_device<gfxdecode_device> m_gfxdecode;
required_device<screen_device> m_screen;
required_ioport m_tvtype;
- uint8_t m_rombank_hi;
- uint8_t m_rombank_lo;
int m_tilerambase;
int m_spriterambase;
@@ -211,8 +174,6 @@ private:
uint8_t m_portdir[3];
- void handle_palette(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
-
void draw_background_ramlayer(screen_device& screen, bitmap_ind16& bitmap, const rectangle& cliprect);
int get_xscroll_for_screenypos(int line);
void draw_background_tile(bitmap_ind16 &bitmap, const rectangle &cliprect, int bpp, int tileno, int palette, int priority, int flipx, int flipy, int xpos, int ypos, int transpen, int size, int base, int drawfromram);
@@ -224,61 +185,12 @@ private:
};
-void radica_eu3a14_state::video_start()
+void elan_eu3a14_state::video_start()
{
m_screen->register_screen_bitmap(m_prioritybitmap);
}
-double radica_eu3a14_state::hue2rgb(double p, double q, double t)
-{
- if (t < 0) t += 1;
- if (t > 1) t -= 1;
- if (t < 1 / 6.0f) return p + (q - p) * 6 * t;
- if (t < 1 / 2.0f) return q;
- if (t < 2 / 3.0f) return p + (q - p) * (2 / 3.0f - t) * 6;
- return p;
-}
-
-void radica_eu3a14_state::handle_palette(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
-{
- // Palette
- int offs = 0;
- for (int index = 0; index < 512; index++)
- {
- uint16_t dat = m_palram[offs++] << 8;
- dat |= m_palram[offs++];
-
- // llll lsss ---h hhhh
- int l_raw = (dat & 0xf800) >> 11;
- int sl_raw = (dat & 0x0700) >> 8;
- int h_raw = (dat & 0x001f) >> 0;
-
- double l = (double)l_raw / 31.0f;
- double s = (double)sl_raw / 7.0f;
- double h = (double)h_raw / 24.0f;
-
- double r, g, b;
-
- if (s == 0) {
- r = g = b = l; // greyscale
- }
- else {
- double q = l < 0.5f ? l * (1 + s) : l + s - l * s;
- double p = 2 * l - q;
- r = hue2rgb(p, q, h + 1 / 3.0f);
- g = hue2rgb(p, q, h);
- b = hue2rgb(p, q, h - 1 / 3.0f);
- }
-
- int r_real = r * 255.0f;
- int g_real = g * 255.0f;
- int b_real = b * 255.0f;
-
- m_palette->set_pen_color(index, r_real, g_real, b_real);
- }
-}
-
-void radica_eu3a14_state::draw_background_tile(bitmap_ind16& bitmap, const rectangle& cliprect, int bpp, int tileno, int palette, int priority, int flipx, int flipy, int xpos, int ypos, int transpen, int size, int base, int drawfromram)
+void elan_eu3a14_state::draw_background_tile(bitmap_ind16& bitmap, const rectangle& cliprect, int bpp, int tileno, int palette, int priority, int flipx, int flipy, int xpos, int ypos, int transpen, int size, int base, int drawfromram)
{
int baseaddr = base * 256;
@@ -485,7 +397,7 @@ void radica_eu3a14_state::draw_background_tile(bitmap_ind16& bitmap, const recta
}
}
-int radica_eu3a14_state::get_xscroll_for_screenypos(int ydraw)
+int elan_eu3a14_state::get_xscroll_for_screenypos(int ydraw)
{
if ((ydraw < 0) || (ydraw >= 224))
return 0;
@@ -531,7 +443,7 @@ int radica_eu3a14_state::get_xscroll_for_screenypos(int ydraw)
}
-void radica_eu3a14_state::draw_background_page(screen_device& screen, bitmap_ind16& bitmap, const rectangle& cliprect, int ramstart, int ramend, int xbase, int ybase, int size, int bpp, int base, int pagewidth, int pageheight, int bytespertile, int palettepri, int drawfromram)
+void elan_eu3a14_state::draw_background_page(screen_device& screen, bitmap_ind16& bitmap, const rectangle& cliprect, int ramstart, int ramend, int xbase, int ybase, int size, int bpp, int base, int pagewidth, int pageheight, int bytespertile, int palettepri, int drawfromram)
{
int palette = ((palettepri & 0xf0) >> 4) | ((palettepri & 0x08) << 1);
@@ -584,7 +496,7 @@ void radica_eu3a14_state::draw_background_page(screen_device& screen, bitmap_ind
}
}
-void radica_eu3a14_state::draw_background_ramlayer(screen_device& screen, bitmap_ind16& bitmap, const rectangle& cliprect)
+void elan_eu3a14_state::draw_background_ramlayer(screen_device& screen, bitmap_ind16& bitmap, const rectangle& cliprect)
{
// this register use is questionable
if (m_ramtilecfg[0] & 0x80)
@@ -643,7 +555,7 @@ void radica_eu3a14_state::draw_background_ramlayer(screen_device& screen, bitmap
}
-void radica_eu3a14_state::draw_background(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+void elan_eu3a14_state::draw_background(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
int yscroll = m_scrollregs[2] | (m_scrollregs[3] << 8);
@@ -761,7 +673,7 @@ void radica_eu3a14_state::draw_background(screen_device &screen, bitmap_ind16 &b
}
-void radica_eu3a14_state::draw_sprite_pix(const rectangle& cliprect, uint16_t* dst, uint8_t* pridst, int realx, int priority, uint8_t pix, uint8_t mask, uint8_t shift, int palette)
+void elan_eu3a14_state::draw_sprite_pix(const rectangle& cliprect, uint16_t* dst, uint8_t* pridst, int realx, int priority, uint8_t pix, uint8_t mask, uint8_t shift, int palette)
{
if (realx >= cliprect.min_x && realx <= cliprect.max_x)
{
@@ -776,7 +688,7 @@ void radica_eu3a14_state::draw_sprite_pix(const rectangle& cliprect, uint16_t* d
}
}
-void radica_eu3a14_state::draw_sprite_line(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int offset, int line, int palette, int flipx, int priority, int xpos, int ypos, int bpp)
+void elan_eu3a14_state::draw_sprite_line(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int offset, int line, int palette, int flipx, int priority, int xpos, int ypos, int bpp)
{
offset = offset * 2;
@@ -889,7 +801,7 @@ void radica_eu3a14_state::draw_sprite_line(screen_device &screen, bitmap_ind16 &
}
-void radica_eu3a14_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+void elan_eu3a14_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
// first 4 sprite entries seem to be garbage sprites, so we start at 0x20
// likely we're just interpreting them wrong and they're used for blanking things or clipping?
@@ -983,14 +895,13 @@ void radica_eu3a14_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitm
-uint32_t radica_eu3a14_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+uint32_t elan_eu3a14_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
m_spriterambase = (m_spriteaddr[0] * 0x200) - 0x200;
bitmap.fill(0, cliprect);
m_prioritybitmap.fill(0, cliprect);
- handle_palette(screen, bitmap, cliprect);
draw_background(screen, bitmap, cliprect);
draw_sprites(screen, bitmap, cliprect);
@@ -999,143 +910,90 @@ uint32_t radica_eu3a14_state::screen_update(screen_device &screen, bitmap_ind16
}
// sound callback
-READ8_MEMBER(radica_eu3a14_state::read_full_space)
+READ8_MEMBER(elan_eu3a14_state::read_full_space)
{
address_space& fullbankspace = m_bank->space(AS_PROGRAM);
return fullbankspace.read_byte(offset);
}
-// irq controller seems to be like the Radica Space Invaders
-READ8_MEMBER(radica_eu3a14_state::irq_vector_r)
-{
- if (m_custom_irq)
- {
- return m_custom_irq_vector >> (offset*8);
- }
- else
- {
- uint8_t *rom = memregion("maincpu")->base();
- return rom[0x001ffe + offset];
- }
-}
-
-/*
- code at 0000 maps to e000
- code at 1000 maps to f000
-
- data at 2000
- data at 3000
- data at 4000
- blank 5000
- blank 6000
-
- code at 7000 maps to 3000
- code at 8000 maps to 6000
- 9000 maps to 7000
- a000 maps to 8000
- b000 maps to 9000
- c000 maps to a000
- d000 maps to b000
- e000 maps to c000
-*/
-
-WRITE8_MEMBER(radica_eu3a14_state::radicasi_rombank_hi_w)
-{
- // written with the banking?
- //logerror("%s: radicasi_rombank_hi_w (set ROM bank) %02x\n", machine().describe_context(), data);
- m_rombank_hi = data;
-
- m_bank->set_bank(m_rombank_lo | (m_rombank_hi << 8));
-}
-WRITE8_MEMBER(radica_eu3a14_state::radicasi_rombank_lo_w)
-{
- //logerror("%s: radicasi_rombank_lo_w (select ROM bank) %02x\n", machine().describe_context(), data);
- m_rombank_lo = data;
-}
-
-READ8_MEMBER(radica_eu3a14_state::radicasi_rombank_lo_r)
-{
- return m_rombank_lo;
-}
-
-READ8_MEMBER(radica_eu3a14_state::radicasi_pal_ntsc_r)
+READ8_MEMBER(elan_eu3a14_state::elan_eu3a05_pal_ntsc_r)
{
// how best to handle this, we probably need to run the PAL machine at 50hz
// the text under the radica logo differs between regions
- logerror("%s: radicasi_pal_ntsc_r (region + more?)\n", machine().describe_context());
+ logerror("%s: elan_eu3a05_pal_ntsc_r (region + more?)\n", machine().describe_context());
return m_tvtype->read();
}
-WRITE8_MEMBER(radica_eu3a14_state::porta_dir_w)
+WRITE8_MEMBER(elan_eu3a14_state::porta_dir_w)
{
m_portdir[0] = data;
// update state
}
-WRITE8_MEMBER(radica_eu3a14_state::portb_dir_w)
+WRITE8_MEMBER(elan_eu3a14_state::portb_dir_w)
{
m_portdir[1] = data;
// update state
}
-WRITE8_MEMBER(radica_eu3a14_state::portc_dir_w)
+WRITE8_MEMBER(elan_eu3a14_state::portc_dir_w)
{
m_portdir[2] = data;
// update state
}
-WRITE8_MEMBER(radica_eu3a14_state::porta_dat_w)
+WRITE8_MEMBER(elan_eu3a14_state::porta_dat_w)
{
}
-WRITE8_MEMBER(radica_eu3a14_state::portb_dat_w)
+WRITE8_MEMBER(elan_eu3a14_state::portb_dat_w)
{
}
-WRITE8_MEMBER(radica_eu3a14_state::portc_dat_w)
+WRITE8_MEMBER(elan_eu3a14_state::portc_dat_w)
{
}
-void radica_eu3a14_state::bank_map(address_map &map)
+void elan_eu3a14_state::bank_map(address_map &map)
{
map(0x000000, 0x3fffff).rom().region("maincpu", 0);
}
-void radica_eu3a14_state::radica_eu3a14_map(address_map &map)
+void elan_eu3a14_state::radica_eu3a14_map(address_map &map)
{
map(0x0000, 0x01ff).ram();
map(0x0200, 0x3fff).ram().share("mainram"); // 200-9ff is sprites? a00 - ??? is tilemap?
- map(0x4800, 0x4bff).ram().share("palram");
+ map(0x4800, 0x4bff).rw(m_commonvid, FUNC(elan_eu3a05commonvid_device::palette_r), FUNC(elan_eu3a05commonvid_device::palette_w));
+
+ // 5000 - 501f = SYSTEM AREA
// similar to eu3a05, at least for pal flags and rom banking
// 5001 write
// 5004 write
// 5006 write
- map(0x5007, 0x5007).noprw();
- map(0x5008, 0x5008).nopw(); // startup (read too)
- map(0x5009, 0x5009).r(FUNC(radica_eu3a14_state::radica_5009_unk_r)); // rad_hnt3 polls this on startup
+ map(0x5007, 0x5008).rw(m_sys, FUNC(elan_eu3a05commonsys_device::intmask_r), FUNC(elan_eu3a05commonsys_device::intmask_w));
+ map(0x5009, 0x5009).r(FUNC(elan_eu3a14_state::radica_5009_unk_r)); // rad_hnt3 polls this on startup
map(0x500a, 0x500a).nopw(); // startup
- map(0x500b, 0x500b).r(FUNC(radica_eu3a14_state::radicasi_pal_ntsc_r)).nopw(); // PAL / NTSC flag at least
- map(0x500c, 0x500c).w(FUNC(radica_eu3a14_state::radicasi_rombank_hi_w));
- map(0x500d, 0x500d).rw(FUNC(radica_eu3a14_state::radicasi_rombank_lo_r), FUNC(radica_eu3a14_state::radicasi_rombank_lo_w));
-
+ map(0x500b, 0x500b).r(FUNC(elan_eu3a14_state::elan_eu3a05_pal_ntsc_r)).nopw(); // PAL / NTSC flag at least
+ map(0x500c, 0x500d).rw(m_sys, FUNC(elan_eu3a05commonsys_device::elan_eu3a05_rombank_r), FUNC(elan_eu3a05commonsys_device::elan_eu3a05_rombank_w));
// DMA is similar to, but not the same as eu3a05
- map(0x500f, 0x5017).ram().share("dmaparams");
- map(0x5018, 0x5018).rw(FUNC(radica_eu3a14_state::dma_trigger_r), FUNC(radica_eu3a14_state::dma_trigger_w));
+ map(0x500f, 0x5017).rw(m_sys, FUNC(elan_eu3a14sys_device::dma_param_r), FUNC(elan_eu3a14sys_device::dma_param_w));
+ map(0x5018, 0x5018).rw(m_sys, FUNC(elan_eu3a14sys_device::dma_trigger_r), FUNC(elan_eu3a14sys_device::dma_trigger_w));
// 5019 - 46 on startup (hnt3) 22 (bb3, foot) na (gtg) 09 (rsg)
// 501a - 01 on startup (hnt3) 03 (bb3, foot) na (gtg) 02,01 (rsg)
+
// probably GPIO like eu3a05, although it access 47/48 as unknown instead of 48/49/4a
- map(0x5040, 0x5040).w(FUNC(radica_eu3a14_state::porta_dir_w));
- map(0x5041, 0x5041).portr("IN0").w(FUNC(radica_eu3a14_state::porta_dat_w));
- map(0x5042, 0x5042).w(FUNC(radica_eu3a14_state::portb_dir_w));
- map(0x5043, 0x5043).portr("IN1").w(FUNC(radica_eu3a14_state::portb_dat_w));
- map(0x5044, 0x5044).w(FUNC(radica_eu3a14_state::portc_dir_w));
- map(0x5045, 0x5045).portr("IN2").w(FUNC(radica_eu3a14_state::portc_dat_w));
+ map(0x5040, 0x5040).w(FUNC(elan_eu3a14_state::porta_dir_w));
+ map(0x5041, 0x5041).portr("IN0").w(FUNC(elan_eu3a14_state::porta_dat_w));
+ map(0x5042, 0x5042).w(FUNC(elan_eu3a14_state::portb_dir_w));
+ map(0x5043, 0x5043).portr("IN1").w(FUNC(elan_eu3a14_state::portb_dat_w));
+ map(0x5044, 0x5044).w(FUNC(elan_eu3a14_state::portc_dir_w));
+ map(0x5045, 0x5045).portr("IN2").w(FUNC(elan_eu3a14_state::portc_dat_w));
map(0x5046, 0x5046).nopw();
map(0x5047, 0x5047).nopw();
@@ -1144,13 +1002,13 @@ void radica_eu3a14_state::radica_eu3a14_map(address_map &map)
// 5060 - 506e r/w during startup on foot
// sound appears to be the same as eu3a05
- map(0x5080, 0x5091).rw("6ch_sound", FUNC(radica6502_sound_device::radicasi_sound_addr_r), FUNC(radica6502_sound_device::radicasi_sound_addr_w));
- map(0x5092, 0x50a3).rw("6ch_sound", FUNC(radica6502_sound_device::radicasi_sound_size_r), FUNC(radica6502_sound_device::radicasi_sound_size_w));
- map(0x50a4, 0x50a4).rw("6ch_sound", FUNC(radica6502_sound_device::radicasi_sound_unk_r), FUNC(radica6502_sound_device::radicasi_sound_unk_w)); // read frequently on this
- map(0x50a5, 0x50a5).rw("6ch_sound", FUNC(radica6502_sound_device::radicasi_sound_trigger_r), FUNC(radica6502_sound_device::radicasi_sound_trigger_w));
+ map(0x5080, 0x5091).rw(m_sound, FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_addr_r), FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_addr_w));
+ map(0x5092, 0x50a3).rw(m_sound, FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_size_r), FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_size_w));
+ map(0x50a4, 0x50a4).rw(m_sound, FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_unk_r), FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_unk_w)); // read frequently on this
+ map(0x50a5, 0x50a5).rw(m_sound, FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_trigger_r), FUNC(elan_eu3a05_sound_device::elan_eu3a05_sound_trigger_w));
map(0x50a6, 0x50a6).nopw(); // startup
map(0x50a7, 0x50a7).nopw(); // startup
- map(0x50a8, 0x50a8).r("6ch_sound", FUNC(radica6502_sound_device::radicasi_50a8_r));
+ map(0x50a8, 0x50a8).r(m_sound, FUNC(elan_eu3a05_sound_device::elan_eu3a05_50a8_r));
map(0x50a9, 0x50a9).nopw(); // startup, read foot
// video regs are in the 51xx range
@@ -1204,38 +1062,8 @@ void radica_eu3a14_state::radica_eu3a14_map(address_map &map)
map(0xe000, 0xffff).rom().region("maincpu", 0x0000);
- map(0xfffe, 0xffff).r(FUNC(radica_eu3a14_state::irq_vector_r));
-}
-
-READ8_MEMBER(radica_eu3a14_state::dma_trigger_r)
-{
- logerror("%s: dma_trigger_r\n", machine().describe_context());
- return 0;
-}
-
-WRITE8_MEMBER(radica_eu3a14_state::dma_trigger_w)
-{
- uint32_t dmasrc = (m_dmaparams[2] << 16) | (m_dmaparams[1] << 8) | (m_dmaparams[0] << 0);
- uint32_t dmadst = (m_dmaparams[5] << 16) | (m_dmaparams[4] << 8) | (m_dmaparams[3] << 0);
- uint32_t dmalen = (m_dmaparams[8] << 16) | (m_dmaparams[7] << 8) | (m_dmaparams[6] << 0);
-
- //logerror("%s: dma_trigger_w %02x (src %08x dst %08x size %08x)\n", machine().describe_context(), data, dmasrc, dmadst, dmalen);
-
- address_space& fullbankspace = m_bank->space(AS_PROGRAM);
- address_space& destspace = m_maincpu->space(AS_PROGRAM);
-
- if (data == 0x08)
- {
- for (int i = 0; i < dmalen; i++)
- {
- uint8_t dat = fullbankspace.read_byte(dmasrc + i);
- destspace.write_byte(dmadst + i, dat);
- }
- }
- else
- {
- logerror("UNKNOWN DMA TRIGGER VALUE\n");
- }
+ map(0xfffa, 0xfffb).r(m_sys, FUNC(elan_eu3a05commonsys_device::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
}
@@ -1687,11 +1515,11 @@ static INPUT_PORTS_START( radica_bb3p )
PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED )
INPUT_PORTS_END
-void radica_eu3a14_state::machine_start()
+void elan_eu3a14_state::machine_start()
{
}
-void radica_eu3a14_state::machine_reset()
+void elan_eu3a14_state::machine_reset()
{
// rather be safe
m_maincpu->set_state_int(M6502_S, 0x1ff);
@@ -1706,33 +1534,29 @@ void radica_eu3a14_state::machine_reset()
}
-TIMER_DEVICE_CALLBACK_MEMBER(radica_eu3a14_state::scanline_cb)
+TIMER_DEVICE_CALLBACK_MEMBER(elan_eu3a14_state::scanline_cb)
{
// these interrupts need to occur based on how fast the trackball is
// being moved, the direction is read in a port.
-
int scanline = param;
if (scanline == 20)
{
// vertical trackball
- m_custom_irq_vector = 0xffe0;
- m_maincpu->set_input_line(INPUT_LINE_IRQ0,HOLD_LINE);
+ m_sys->generate_custom_interrupt(12);
}
if (scanline == 40)
{
// horizontal trackball
- m_custom_irq_vector = 0xffe4;
- m_maincpu->set_input_line(INPUT_LINE_IRQ0,HOLD_LINE);
+ m_sys->generate_custom_interrupt(13);
+
}
}
-INTERRUPT_GEN_MEMBER(radica_eu3a14_state::interrupt)
+INTERRUPT_GEN_MEMBER(elan_eu3a14_state::interrupt)
{
- m_custom_irq = 1;
- m_custom_irq_vector = 0xffd4;
- m_maincpu->set_input_line(INPUT_LINE_IRQ0,HOLD_LINE);
+ m_sys->generate_custom_interrupt(9);
}
@@ -1792,14 +1616,18 @@ GFXDECODE_END
-void radica_eu3a14_state::radica_eu3a14(machine_config &config)
+void elan_eu3a14_state::radica_eu3a14(machine_config &config)
{
/* basic machine hardware */
M6502(config, m_maincpu, XTAL(21'477'272)/2); // marked as 21'477'270
- m_maincpu->set_addrmap(AS_PROGRAM, &radica_eu3a14_state::radica_eu3a14_map);
- m_maincpu->set_vblank_int("screen", FUNC(radica_eu3a14_state::interrupt));
+ m_maincpu->set_addrmap(AS_PROGRAM, &elan_eu3a14_state::radica_eu3a14_map);
+ m_maincpu->set_vblank_int("screen", FUNC(elan_eu3a14_state::interrupt));
+
+ ADDRESS_MAP_BANK(config, "bank").set_map(&elan_eu3a14_state::bank_map).set_options(ENDIANNESS_LITTLE, 8, 24, 0x8000);
- ADDRESS_MAP_BANK(config, "bank").set_map(&radica_eu3a14_state::bank_map).set_options(ENDIANNESS_LITTLE, 8, 24, 0x8000);
+ ELAN_EU3A14_SYS(config, m_sys, 0);
+ m_sys->set_cpu("maincpu");
+ m_sys->set_addrbank("bank");
GFXDECODE(config, m_gfxdecode, m_palette, gfx_helper);
@@ -1807,29 +1635,34 @@ void radica_eu3a14_state::radica_eu3a14(machine_config &config)
screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
screen.set_refresh_hz(60);
screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500));
- screen.set_screen_update(FUNC(radica_eu3a14_state::screen_update));
+ screen.set_screen_update(FUNC(elan_eu3a14_state::screen_update));
screen.set_size(32*8, 32*8);
screen.set_visarea(0*8, 32*8-1, 0*8, 28*8-1);
screen.set_palette(m_palette);
PALETTE(config, m_palette).set_entries(512);
+ ELAN_EU3A05_COMMONVID(config, m_commonvid, 0);
+ m_commonvid->set_palette("palette");
+ m_commonvid->set_entries(512);
+
/* sound hardware */
SPEAKER(config, "mono").front_center();
- radica6502_sound_device &sound(RADICA6502_SOUND(config, "6ch_sound", 8000));
- sound.space_read_callback().set(FUNC(radica_eu3a14_state::read_full_space));
- sound.add_route(ALL_OUTPUTS, "mono", 1.0);
+
+ ELAN_EU3A05_SOUND(config, m_sound, 8000);
+ m_sound->space_read_callback().set(FUNC(elan_eu3a14_state::read_full_space));
+ m_sound->add_route(ALL_OUTPUTS, "mono", 1.0);
}
-void radica_eu3a14_state::radica_eu3a14_adc(machine_config &config)
+void elan_eu3a14_state::radica_eu3a14_adc(machine_config &config)
{
radica_eu3a14(config);
- TIMER(config, "scantimer").configure_scanline(FUNC(radica_eu3a14_state::scanline_cb), "screen", 0, 1);
+ TIMER(config, "scantimer").configure_scanline(FUNC(elan_eu3a14_state::scanline_cb), "screen", 0, 1);
}
-void radica_eu3a14_state::radica_eu3a14p(machine_config &config) // TODO, clocks differ too, what are they on PAL?
+void elan_eu3a14_state::radica_eu3a14p(machine_config &config) // TODO, clocks differ too, what are they on PAL?
{
radica_eu3a14(config);
@@ -1837,19 +1670,19 @@ void radica_eu3a14_state::radica_eu3a14p(machine_config &config) // TODO, clocks
}
-void radica_eu3a14_state::init_rad_gtg()
+void elan_eu3a14_state::init_rad_gtg()
{
// must be registers to control this
m_tilerambase = 0x0a00 - 0x200;
}
-void radica_eu3a14_state::init_rad_foot()
+void elan_eu3a14_state::init_rad_foot()
{
// must be registers to control this
m_tilerambase = 0x0200 - 0x200;
}
-void radica_eu3a14_state::init_rad_hnt3()
+void elan_eu3a14_state::init_rad_hnt3()
{
// must be registers to control this
m_tilerambase = 0x0200 - 0x200;
@@ -1907,20 +1740,20 @@ ROM_START( rad_baskp )
ROM_LOAD( "basketball.bin", 0x000000, 0x400000, CRC(7d6ff53c) SHA1(1c75261d55e0107a3b8e8d4c1eb2854750f2d0e8) )
ROM_END
-CONS( 2006, rad_gtg, 0, 0, radica_eu3a14_adc, rad_gtg, radica_eu3a14_state, init_rad_gtg, "Radica / FarSight Studios (licensed from Incredible Technologies)", "Golden Tee Golf: Home Edition", MACHINE_NOT_WORKING )
+CONS( 2006, rad_gtg, 0, 0, radica_eu3a14_adc, rad_gtg, elan_eu3a14_state, init_rad_gtg, "Radica / FarSight Studios (licensed from Incredible Technologies)", "Golden Tee Golf: Home Edition", MACHINE_NOT_WORKING )
-CONS( 2005, rad_rsg, 0, 0, radica_eu3a14, rad_rsg, radica_eu3a14_state, init_rad_gtg, "Radica / FarSight Studios", "Play TV Real Swing Golf", MACHINE_NOT_WORKING )
-// some Connectv branded Real Swing Golf units have a language selection, so there are likely other PAL revisions of this
-CONS( 2005, rad_rsgp, rad_rsg, 0, radica_eu3a14p, rad_rsgp, radica_eu3a14_state, init_rad_gtg, "Radica / FarSight Studios", "Connectv Real Swing Golf", MACHINE_NOT_WORKING )
+CONS( 2005, rad_rsg, 0, 0, radica_eu3a14, rad_rsg, elan_eu3a14_state, init_rad_gtg, "Radica / FarSight Studios", "Play TV Real Swing Golf", MACHINE_NOT_WORKING )
+// some Connectv branded Real Swing Golf units have a language selection (checksum in test mode confirmed as different on said units)
+CONS( 2005, rad_rsgp, rad_rsg, 0, radica_eu3a14p, rad_rsgp, elan_eu3a14_state, init_rad_gtg, "Radica / FarSight Studios", "Connectv Real Swing Golf", MACHINE_NOT_WORKING )
// also has a Connectv Real Soccer logo in the roms, apparently unused, maybe that was to be the US title (without the logo being changed to Play TV) but Play TV Soccer ended up being a different game licensed from Epoch instead.
-CONS( 2006, rad_foot, 0, 0, radica_eu3a14p, radica_foot, radica_eu3a14_state, init_rad_foot, "Radica / Medialink", "Connectv Football", MACHINE_NOT_WORKING )
+CONS( 2006, rad_foot, 0, 0, radica_eu3a14p, radica_foot, elan_eu3a14_state, init_rad_foot, "Radica / Medialink", "Connectv Football", MACHINE_NOT_WORKING )
-CONS( 2005, rad_bb3, 0, 0, radica_eu3a14, radica_bb3, radica_eu3a14_state, init_rad_gtg, "Radica / FarSight Studios", "Play TV Baseball 3", MACHINE_NOT_WORKING )
-CONS( 2005, rad_bb3p, rad_bb3, 0, radica_eu3a14p, radica_bb3p, radica_eu3a14_state, init_rad_gtg, "Radica / FarSight Studios", "Connectv Baseball 3", MACHINE_NOT_WORKING )
+CONS( 2005, rad_bb3, 0, 0, radica_eu3a14, radica_bb3, elan_eu3a14_state, init_rad_gtg, "Radica / FarSight Studios", "Play TV Baseball 3", MACHINE_NOT_WORKING )
+CONS( 2005, rad_bb3p, rad_bb3, 0, radica_eu3a14p, radica_bb3p, elan_eu3a14_state, init_rad_gtg, "Radica / FarSight Studios", "Connectv Baseball 3", MACHINE_NOT_WORKING )
-CONS( 2005, rad_hnt3, 0, 0, radica_eu3a14, radica_hnt3, radica_eu3a14_state, init_rad_hnt3, "Radica / V-Tac Technology Co Ltd.", "Play TV Huntin' 3", MACHINE_NOT_WORKING )
-CONS( 2005, rad_hnt3p,rad_hnt3, 0, radica_eu3a14p, radica_hnt3p, radica_eu3a14_state, init_rad_hnt3, "Radica / V-Tac Technology Co Ltd.", "Connectv Huntin' 3", MACHINE_NOT_WORKING )
+CONS( 2005, rad_hnt3, 0, 0, radica_eu3a14, radica_hnt3, elan_eu3a14_state, init_rad_hnt3, "Radica / V-Tac Technology Co Ltd.", "Play TV Huntin' 3", MACHINE_NOT_WORKING )
+CONS( 2005, rad_hnt3p,rad_hnt3, 0, radica_eu3a14p, radica_hnt3p, elan_eu3a14_state, init_rad_hnt3, "Radica / V-Tac Technology Co Ltd.", "Connectv Huntin' 3", MACHINE_NOT_WORKING )
-CONS( 2005, rad_bask, 0, 0, radica_eu3a14, radica_bask, radica_eu3a14_state, init_rad_gtg, "Radica / FarSight Studios", "Play TV Basketball", MACHINE_NOT_WORKING )
-CONS( 2005, rad_baskp,rad_bask, 0, radica_eu3a14, radica_baskp, radica_eu3a14_state, init_rad_gtg, "Radica / FarSight Studios", "Connectv Basketball", MACHINE_NOT_WORKING )
+CONS( 2005, rad_bask, 0, 0, radica_eu3a14, radica_bask, elan_eu3a14_state, init_rad_gtg, "Radica / FarSight Studios", "Play TV Basketball", MACHINE_NOT_WORKING )
+CONS( 2005, rad_baskp,rad_bask, 0, radica_eu3a14, radica_baskp, elan_eu3a14_state, init_rad_gtg, "Radica / FarSight Studios", "Connectv Basketball", MACHINE_NOT_WORKING )
diff --git a/src/mame/machine/elan_eu3a05commonsys.cpp b/src/mame/machine/elan_eu3a05commonsys.cpp
new file mode 100644
index 00000000000..7b1b5f09e5f
--- /dev/null
+++ b/src/mame/machine/elan_eu3a05commonsys.cpp
@@ -0,0 +1,307 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+#include "emu.h"
+#include "elan_eu3a05commonsys.h"
+
+/*
+ Both the Elan EU3A05 and EU3A14 CPU types implement some kind of custom interrupt handling
+
+ It isn't clear if this is a completely new addition to the CPU, or just an interface / controller
+ sitting on top of the existing NMI or IRQ support in the core providing custom vectors.
+
+ The interrupt handlers are 16 4-byte entries starting at 0xffb0 in memory space
+
+*/
+
+
+/*
+ -----------------------
+ Custom Interrupt purposes
+ -----------------------
+
+ TETRIS (enables 5007 : 0a, 5008: 0f)
+
+ ffb0 (enabled)
+ nothing of note?
+
+ ffb4 (enabled)
+ stuff with 500e, 500c and 500d
+
+ ffb8 (enabled)
+ stuff with 50a4 / 50a5 / 50a6 and memory address e2
+
+ ffbc (enabled)
+ stuff with 50a4 / 50a5 / 50a6 and memory address e2 (similar to above, different bits)
+
+ ffc0 - doesn't exist
+ ffc4 - doesn't exist
+ ffc8 - doesn't exist
+ ffd0 - doesn't exist
+
+ ffd4 (enabled)
+ main irq?
+
+ ffd8
+ jumps straight to an rti
+
+ ffdc (enabled) - probably P2 input related? ADC interrupt?
+ accesses 501d / 501b
+
+ -----------------------
+
+ SPACE INVADERS
+
+ ffb0
+ rti
+
+ ffb4
+ rti
+
+ ffb8 (enabled by phoenix)
+ rti
+
+ ffbc (enabled by phoenix)
+ decreases 301 bit 02
+ stuff with 50a5
+
+ ffc0 (enabled by phoenix)
+ decreases 302
+ stuff with 50a5 bit 04
+
+ ffc4 (enabled by phoenix)
+ decreases 303
+ stuff with 50a5 bit 08
+
+ ffc8 (enabled by phoenix)
+ decreases 304
+ stuff with 50a5 bit 10
+
+ ffcc (enabled by phoenix)
+ uses 307
+ stuff with 50a5 bit 20
+
+ ffd0
+ dead loop
+
+ ffd4 (enabled by all games)
+ main interrupt
+
+ ffd8
+ dead loop
+
+ ffdc
+ dead loop
+
+ ffe0
+ dead loop
+
+ ffe4
+ rti
+
+ ffe8
+ dead loop
+
+ ffec
+ dead loop
+
+ -----------------------
+
+ AIR BLASTER JOYSTICK
+
+ all these 60xx jumps expect bank 00 or 0e or 3a or 7d to be active, so IRQs must be masked
+
+ ffb0: jmp to 6000 (ends up jumping to pointer from RAM)
+ ffb4: jmp to e08e (stuff with 500c/500d/506e etc.)
+ ffb8: jmp to 601c (stub handler) (has function in bank 0e - writes 00 then 01 to 50a5)
+ ffbc: jmp to 602a (stub handler)
+ ffc0: jmp to 6038 (stub handler)
+ ffc4: jmp to 6046 (stub handler)
+ ffc8: jmp to 6054 (stub handler)
+ ffcc: jmp to 6062 (stub handler)
+ ffd0: jmp to 6070 (stub handler)
+ ffd4: jmp to 607e (valid code - main IRQ?)
+ ffd8: jmp to 608c (stub handler)
+ ffdc: jmp to 609a (stub handler)
+ ffe0: jmp to 60a8 (stub handler)
+ ffe4: jmp to 60b6 (stub handler)
+ ffe8: jmp to 60c4 (stub handler)
+ ffec: jmp to 60d2 (stub handler)
+
+ fff0: 7d
+
+ fffa: e0 60 (60e0 vector) (stub handler)
+ fffc: 88 e1 (e188 startup vector)
+ fffe: 02 e0 (e002 vector)
+
+
+ -----------------------
+
+ GOLDEN TEE HOME
+
+ ffb0 rti
+ ffb4 rti
+ ffb8 rti
+ ffbc rti
+
+ ffc0 rti
+ ffc4 rti
+ ffc8 rti
+ ffcc rti
+
+ ffd0 rti
+ ffd4 main irq?
+ ffd8 rti
+ ffdc rti
+
+ ffe0 something with 5045 bit 0x08 and 9d in ram (increase or decrease) (ADC interrupt)
+ ffe4 something with 5045 bit 0x20 and 9c in ram (increase of decrease) (ADC interrupt)
+
+ ffe8 rti
+ ffec rti
+
+ regular NMI (e3f0 - jump to ($19e2) which seems to point to rti, but could move..)
+ regular IRQ (e3f3 - points to rti)
+
+*/
+
+
+DEFINE_DEVICE_TYPE(ELAN_EU3A05_COMMONSYS, elan_eu3a05commonsys_device, "elan_eu3a05commonsys", "Elan EU3A05/EU3A14 Common System")
+
+
+elan_eu3a05commonsys_device::elan_eu3a05commonsys_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ m_cpu(*this, finder_base::DUMMY_TAG),
+ m_bank(*this, finder_base::DUMMY_TAG)
+{
+}
+
+elan_eu3a05commonsys_device::elan_eu3a05commonsys_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ elan_eu3a05commonsys_device(mconfig, ELAN_EU3A05_COMMONSYS, tag, owner, clock)
+{
+}
+
+void elan_eu3a05commonsys_device::device_start()
+{
+ save_item(NAME(m_rombank_lo));
+ save_item(NAME(m_rombank_hi));
+ save_item(NAME(m_intmask));
+ save_item(NAME(m_custom_irq));
+ save_item(NAME(m_custom_nmi));
+ save_item(NAME(m_custom_irq_vector));
+ save_item(NAME(m_custom_nmi_vector));
+}
+
+void elan_eu3a05commonsys_device::device_reset()
+{
+ // all interrupts disabled?
+ m_intmask[0] = 0x00;
+ m_intmask[1] = 0x00;
+
+ m_custom_irq = 0;
+ m_custom_irq_vector = 0x0000;
+
+ m_custom_nmi = 0;
+ m_custom_nmi_vector = 0x0000;
+
+ m_rombank_lo = 0x7f;
+ m_rombank_hi = 0x00;
+ m_bank->set_bank(0x7f);
+
+}
+
+READ8_MEMBER(elan_eu3a05commonsys_device::intmask_r)
+{
+ return m_intmask[offset];
+}
+
+WRITE8_MEMBER(elan_eu3a05commonsys_device::intmask_w)
+{
+ m_intmask[offset] = data;
+}
+
+
+void elan_eu3a05commonsys_device::generate_custom_interrupt(int level)
+{
+ // Air Blaster uses brk in the code, which is problematic for custom IRQs
+ // m_custom_irq = 1;
+ // m_custom_irq_vector = 0xffd4;
+ // m_maincpu->set_input_line(INPUT_LINE_IRQ0,HOLD_LINE);
+
+ // 5007 5008
+ // --ee --v- ssss ss-t
+ // 10 5432 10
+ // vector = 0xffb0 + 4 * bit position from right
+
+ // each bit seems to relate to an IRQ level
+ // v = vbl interrupt bit (vector 0xffd4)
+ // t = used for object movement (enemies / bullets) on air blaster chase levels (vector 0xffb0) needs to be frequent, timer? or hbl?
+ // s = sound channel related? (air blaster enables s1)
+ // e = 'event' interrupts (rad_gtg)
+
+ // vbl irq masking is important for air blaster or it will suffer from random crashes
+
+ uint16_t intmask = (m_intmask[0] << 8) | m_intmask[1];
+
+ if (intmask & (1 << level))
+ {
+ m_custom_nmi = 1;
+ m_custom_nmi_vector = 0xffb0 + level * 4;
+ m_cpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
+ }
+}
+
+READ8_MEMBER(elan_eu3a05commonsys_device::nmi_vector_r)
+{
+ if (m_custom_nmi)
+ {
+ return m_custom_nmi_vector >> (offset*8);
+ }
+ else
+ {
+ fatalerror("NMI without custom vector!");
+ }
+}
+
+// not currently used
+READ8_MEMBER(elan_eu3a05commonsys_device::irq_vector_r)
+{
+ if (m_custom_irq)
+ {
+ return m_custom_irq_vector >> (offset*8);
+ }
+ else
+ {
+ fatalerror("IRQ without custom vector!");
+ }
+}
+
+
+WRITE8_MEMBER(elan_eu3a05commonsys_device::elan_eu3a05_rombank_w)
+{
+ if (offset == 0x00)
+ {
+ // written with the banking?
+ //logerror("%s: elan_eu3a05_rombank_hi_w (set ROM bank) %02x\n", machine().describe_context(), data);
+ m_rombank_hi = data;
+
+ m_bank->set_bank(m_rombank_lo | (m_rombank_hi << 8));
+ }
+ else
+ {
+ //logerror("%s: elan_eu3a05_rombank_lo_w (select ROM bank) %02x\n", machine().describe_context(), data);
+ m_rombank_lo = data;
+ }
+}
+
+READ8_MEMBER(elan_eu3a05commonsys_device::elan_eu3a05_rombank_r)
+{
+ if (offset == 0x00)
+ {
+ return m_rombank_hi;
+ }
+ else
+ {
+ return m_rombank_lo;
+ }
+}
diff --git a/src/mame/machine/elan_eu3a05commonsys.h b/src/mame/machine/elan_eu3a05commonsys.h
new file mode 100644
index 00000000000..ec7f7cd482e
--- /dev/null
+++ b/src/mame/machine/elan_eu3a05commonsys.h
@@ -0,0 +1,50 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+#ifndef MAME_MACHINE_ELAN_EU3A05COMMONSYS_H
+#define MAME_MACHINE_ELAN_EU3A05COMMONSYS_H
+
+#include "cpu/m6502/m6502.h"
+#include "machine/bankdev.h"
+
+class elan_eu3a05commonsys_device : public device_t
+{
+public:
+ elan_eu3a05commonsys_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ elan_eu3a05commonsys_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ template <typename T> void set_cpu(T &&tag) { m_cpu.set_tag(std::forward<T>(tag)); }
+ template <typename T> void set_addrbank(T &&tag) { m_bank.set_tag(std::forward<T>(tag)); }
+
+ void generate_custom_interrupt(int level);
+
+ DECLARE_READ8_MEMBER(intmask_r);
+ DECLARE_WRITE8_MEMBER(intmask_w);
+
+ DECLARE_READ8_MEMBER(nmi_vector_r);
+ DECLARE_READ8_MEMBER(irq_vector_r);
+
+ DECLARE_WRITE8_MEMBER(elan_eu3a05_rombank_w);
+ DECLARE_READ8_MEMBER(elan_eu3a05_rombank_r);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+ required_device<m6502_device> m_cpu;
+ required_device<address_map_bank_device> m_bank;
+ uint8_t m_intmask[2];
+
+ int m_custom_irq;
+ int m_custom_nmi;
+ uint16_t m_custom_irq_vector;
+ uint16_t m_custom_nmi_vector;
+
+ uint8_t m_rombank_hi;
+ uint8_t m_rombank_lo;
+};
+
+DECLARE_DEVICE_TYPE(ELAN_EU3A05_COMMONSYS, elan_eu3a05commonsys_device)
+
+#endif // MAME_MACHINE_ELAN_EU3A05COMMONSYS_H
diff --git a/src/mame/machine/elan_eu3a05gpio.cpp b/src/mame/machine/elan_eu3a05gpio.cpp
index 559db6f83a5..fe24d423dcb 100644
--- a/src/mame/machine/elan_eu3a05gpio.cpp
+++ b/src/mame/machine/elan_eu3a05gpio.cpp
@@ -4,24 +4,24 @@
#include "emu.h"
#include "elan_eu3a05gpio.h"
-DEFINE_DEVICE_TYPE(RADICA6502_GPIO, radica6502_gpio_device, "radica6502gpio", "Elan EU3A05 GPIO")
+DEFINE_DEVICE_TYPE(ELAN_EU3A05_GPIO, elan_eu3a05gpio_device, "elan_eu3a05gpio", "Elan EU3A05 GPIO")
-radica6502_gpio_device::radica6502_gpio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, RADICA6502_GPIO, tag, owner, clock)
+elan_eu3a05gpio_device::elan_eu3a05gpio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, ELAN_EU3A05_GPIO, tag, owner, clock)
, m_space_read0_cb(*this)
, m_space_read1_cb(*this)
, m_space_read2_cb(*this)
{
}
-void radica6502_gpio_device::device_start()
+void elan_eu3a05gpio_device::device_start()
{
m_space_read0_cb.resolve_safe(0xff);
m_space_read1_cb.resolve_safe(0xff);
m_space_read2_cb.resolve_safe(0xff);
}
-void radica6502_gpio_device::device_reset()
+void elan_eu3a05gpio_device::device_reset()
{
for (int i = 0; i < 3; i++)
{
@@ -30,7 +30,7 @@ void radica6502_gpio_device::device_reset()
}
}
-uint8_t radica6502_gpio_device::read_port_data(int which)
+uint8_t elan_eu3a05gpio_device::read_port_data(int which)
{
//todo, actually use the direction registers
switch (which)
@@ -43,12 +43,12 @@ uint8_t radica6502_gpio_device::read_port_data(int which)
return 0xff;
}
-uint8_t radica6502_gpio_device::read_direction(int which)
+uint8_t elan_eu3a05gpio_device::read_direction(int which)
{
return m_ddr[which];
}
-READ8_MEMBER(radica6502_gpio_device::gpio_r)
+READ8_MEMBER(elan_eu3a05gpio_device::gpio_r)
{
int port = offset/2;
@@ -56,19 +56,19 @@ READ8_MEMBER(radica6502_gpio_device::gpio_r)
else return read_port_data(port);
}
-void radica6502_gpio_device::write_port_data(int which, uint8_t data)
+void elan_eu3a05gpio_device::write_port_data(int which, uint8_t data)
{
//todo, actually use the direction registers
logerror("%s: write_port_data (port %d) %02x (direction register %02x)\n", machine().describe_context(), which, data, m_ddr[which]);
}
-void radica6502_gpio_device::write_direction(int which, uint8_t data)
+void elan_eu3a05gpio_device::write_direction(int which, uint8_t data)
{
logerror("%s: write_direction (port %d) %02x\n", machine().describe_context(), which, data);
m_ddr[which] = data;
}
-WRITE8_MEMBER(radica6502_gpio_device::gpio_w)
+WRITE8_MEMBER(elan_eu3a05gpio_device::gpio_w)
{
int port = offset/2;
@@ -76,7 +76,7 @@ WRITE8_MEMBER(radica6502_gpio_device::gpio_w)
else return write_port_data(port, data);
}
-WRITE8_MEMBER(radica6502_gpio_device::gpio_unk_w)
+WRITE8_MEMBER(elan_eu3a05gpio_device::gpio_unk_w)
{
logerror("%s: gpio_unk_w (port %d) %02x (direction register %02x)\n", machine().describe_context(), offset, data, m_ddr[offset]);
}
diff --git a/src/mame/machine/elan_eu3a05gpio.h b/src/mame/machine/elan_eu3a05gpio.h
index a46a654d09d..f06d2eb14b0 100644
--- a/src/mame/machine/elan_eu3a05gpio.h
+++ b/src/mame/machine/elan_eu3a05gpio.h
@@ -1,14 +1,14 @@
// license:BSD-3-Clause
// copyright-holders:David Haywood
-#ifndef MAME_MACHINE_RAD_EU3A05GPIO_H
-#define MAME_MACHINE_RAD_EU3A05GPIO_H
+#ifndef MAME_MACHINE_ELAN_EU3A05GPIO_H
+#define MAME_MACHINE_ELAN_EU3A05GPIO_H
-class radica6502_gpio_device : public device_t
+class elan_eu3a05gpio_device : public device_t
{
public:
- radica6502_gpio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ elan_eu3a05gpio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
auto read_0_callback() { return m_space_read0_cb.bind(); }
auto read_1_callback() { return m_space_read1_cb.bind(); }
@@ -38,6 +38,6 @@ private:
uint8_t m_unk[3];
};
-DECLARE_DEVICE_TYPE(RADICA6502_GPIO, radica6502_gpio_device)
+DECLARE_DEVICE_TYPE(ELAN_EU3A05_GPIO, elan_eu3a05gpio_device)
#endif // MAME_MACHINE_RAD_EU3A05GPIO_H
diff --git a/src/mame/machine/elan_eu3a05sys.cpp b/src/mame/machine/elan_eu3a05sys.cpp
new file mode 100644
index 00000000000..462457010fb
--- /dev/null
+++ b/src/mame/machine/elan_eu3a05sys.cpp
@@ -0,0 +1,74 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+#include "emu.h"
+#include "elan_eu3a05sys.h"
+
+// DMA size and destination are 16-bit here, they're 24-bit on EU3A14
+
+DEFINE_DEVICE_TYPE(ELAN_EU3A05_SYS, elan_eu3a05sys_device, "elan_eu3a05sys", "Elan EU3A05 System")
+
+elan_eu3a05sys_device::elan_eu3a05sys_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ elan_eu3a05commonsys_device(mconfig, ELAN_EU3A05_SYS, tag, owner, clock)
+{
+}
+
+void elan_eu3a05sys_device::device_start()
+{
+ elan_eu3a05commonsys_device::device_start();
+
+ save_item(NAME(m_dmaparams));
+}
+
+void elan_eu3a05sys_device::device_reset()
+{
+ elan_eu3a05commonsys_device::device_reset();
+
+ for (int i = 0; i < 7; i++)
+ m_dmaparams[i] = 0x00;
+}
+
+READ8_MEMBER(elan_eu3a05sys_device::dma_param_r)
+{
+ return m_dmaparams[offset];
+}
+
+WRITE8_MEMBER(elan_eu3a05sys_device::dma_param_w)
+{
+ m_dmaparams[offset] = data;
+}
+
+
+READ8_MEMBER(elan_eu3a05sys_device::elan_eu3a05_dmatrg_r)
+{
+ logerror("%s: elan_eu3a05_dmatrg_r (DMA operation state?)\n", machine().describe_context());
+ return 0x00;//m_dmatrg_data;
+}
+
+
+WRITE8_MEMBER(elan_eu3a05sys_device::elan_eu3a05_dmatrg_w)
+{
+ 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 DMA %06x to %04x size %04x\n", src, dest, size);
+
+ for (int i = 0; i < size; i++)
+ {
+ uint8_t dat = fullbankspace.read_byte(src + i);
+ destspace.write_byte(dest + i, dat);
+ }
+ }
+}
+
+
+
diff --git a/src/mame/machine/elan_eu3a05sys.h b/src/mame/machine/elan_eu3a05sys.h
new file mode 100644
index 00000000000..72e971a7556
--- /dev/null
+++ b/src/mame/machine/elan_eu3a05sys.h
@@ -0,0 +1,31 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+#ifndef MAME_MACHINE_ELAN_EU3A05SYS_H
+#define MAME_MACHINE_ELAN_EU3A05SYS_H
+
+#include "elan_eu3a05commonsys.h"
+
+class elan_eu3a05sys_device : public elan_eu3a05commonsys_device
+{
+public:
+ elan_eu3a05sys_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ DECLARE_READ8_MEMBER(elan_eu3a05_dmatrg_r);
+ DECLARE_WRITE8_MEMBER(elan_eu3a05_dmatrg_w);
+
+ DECLARE_READ8_MEMBER(dma_param_r);
+ DECLARE_WRITE8_MEMBER(dma_param_w);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ uint8_t m_dmaparams[7];
+};
+
+DECLARE_DEVICE_TYPE(ELAN_EU3A05_SYS, elan_eu3a05sys_device)
+
+#endif // MAME_MACHINE_ELAN_EU3A05SYS_H
diff --git a/src/mame/machine/elan_eu3a14sys.cpp b/src/mame/machine/elan_eu3a14sys.cpp
new file mode 100644
index 00000000000..2c9871fc5f1
--- /dev/null
+++ b/src/mame/machine/elan_eu3a14sys.cpp
@@ -0,0 +1,71 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+#include "emu.h"
+#include "elan_eu3a14sys.h"
+
+// DMA size and destination are 24-bit here, they're 16-bit on EU3A05
+
+DEFINE_DEVICE_TYPE(ELAN_EU3A14_SYS, elan_eu3a14sys_device, "elan_eu3a14sys", "Elan EU3A14 System")
+
+elan_eu3a14sys_device::elan_eu3a14sys_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ elan_eu3a05commonsys_device(mconfig, ELAN_EU3A14_SYS, tag, owner, clock)
+{
+}
+
+void elan_eu3a14sys_device::device_start()
+{
+ elan_eu3a05commonsys_device::device_start();
+
+ save_item(NAME(m_dmaparams));
+}
+
+void elan_eu3a14sys_device::device_reset()
+{
+ elan_eu3a05commonsys_device::device_reset();
+
+ for (int i = 0; i < 9; i++)
+ m_dmaparams[i] = 0x00;
+}
+
+
+READ8_MEMBER(elan_eu3a14sys_device::dma_param_r)
+{
+ return m_dmaparams[offset];
+}
+
+WRITE8_MEMBER(elan_eu3a14sys_device::dma_param_w)
+{
+ m_dmaparams[offset] = data;
+}
+
+READ8_MEMBER(elan_eu3a14sys_device::dma_trigger_r)
+{
+ logerror("%s: dma_trigger_r\n", machine().describe_context());
+ return 0;
+}
+
+WRITE8_MEMBER(elan_eu3a14sys_device::dma_trigger_w)
+{
+ uint32_t dmasrc = (m_dmaparams[2] << 16) | (m_dmaparams[1] << 8) | (m_dmaparams[0] << 0);
+ uint32_t dmadst = (m_dmaparams[5] << 16) | (m_dmaparams[4] << 8) | (m_dmaparams[3] << 0);
+ uint32_t dmalen = (m_dmaparams[8] << 16) | (m_dmaparams[7] << 8) | (m_dmaparams[6] << 0);
+
+ //logerror("%s: dma_trigger_w %02x (src %08x dst %08x size %08x)\n", machine().describe_context(), data, dmasrc, dmadst, dmalen);
+
+ address_space& fullbankspace = m_bank->space(AS_PROGRAM);
+ address_space& destspace = m_cpu->space(AS_PROGRAM);
+
+ if (data == 0x08)
+ {
+ for (int i = 0; i < dmalen; i++)
+ {
+ uint8_t dat = fullbankspace.read_byte(dmasrc + i);
+ destspace.write_byte(dmadst + i, dat);
+ }
+ }
+ else
+ {
+ logerror("UNKNOWN DMA TRIGGER VALUE\n");
+ }
+}
diff --git a/src/mame/machine/elan_eu3a14sys.h b/src/mame/machine/elan_eu3a14sys.h
new file mode 100644
index 00000000000..02162af7541
--- /dev/null
+++ b/src/mame/machine/elan_eu3a14sys.h
@@ -0,0 +1,33 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+#ifndef MAME_MACHINE_ELAN_EU3A14SYS_H
+#define MAME_MACHINE_ELAN_EU3A14SYS_H
+
+#include "elan_eu3a05commonsys.h"
+
+class elan_eu3a14sys_device : public elan_eu3a05commonsys_device
+{
+public:
+ elan_eu3a14sys_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ DECLARE_READ8_MEMBER(dma_trigger_r);
+ DECLARE_WRITE8_MEMBER(dma_trigger_w);
+
+ DECLARE_READ8_MEMBER(dma_param_r);
+ DECLARE_WRITE8_MEMBER(dma_param_w);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ uint8_t m_dmaparams[9];
+};
+
+
+
+DECLARE_DEVICE_TYPE(ELAN_EU3A14_SYS, elan_eu3a14sys_device)
+
+#endif // MAME_MACHINE_ELAN_EU3A14SYS_H
diff --git a/src/mame/video/elan_eu3a05commonvid.cpp b/src/mame/video/elan_eu3a05commonvid.cpp
new file mode 100644
index 00000000000..19221f3c463
--- /dev/null
+++ b/src/mame/video/elan_eu3a05commonvid.cpp
@@ -0,0 +1,87 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+#include "emu.h"
+#include "elan_eu3a05commonvid.h"
+
+/*
+ Common video functions shared by Elan EU3A05 and EU3A14 CPU types
+*/
+
+DEFINE_DEVICE_TYPE(ELAN_EU3A05_COMMONVID, elan_eu3a05commonvid_device, "elan_eu3a05commonvid", "Elan EU3A05/EU3A14 Common Video")
+
+elan_eu3a05commonvid_device::elan_eu3a05commonvid_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : elan_eu3a05commonvid_device(mconfig, ELAN_EU3A05_COMMONVID, tag, owner, clock)
+{
+}
+
+elan_eu3a05commonvid_device::elan_eu3a05commonvid_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, type, tag, owner, clock)
+ , m_palette(*this, finder_base::DUMMY_TAG)
+{
+}
+
+
+void elan_eu3a05commonvid_device::device_start()
+{
+}
+
+void elan_eu3a05commonvid_device::device_reset()
+{
+}
+
+double elan_eu3a05commonvid_device::hue2rgb(double p, double q, double t)
+{
+ if (t < 0) t += 1;
+ if (t > 1) t -= 1;
+ if (t < 1 / 6.0f) return p + (q - p) * 6 * t;
+ if (t < 1 / 2.0f) return q;
+ if (t < 2 / 3.0f) return p + (q - p) * (2 / 3.0f - t) * 6;
+ return p;
+}
+
+
+void elan_eu3a05commonvid_device::update_pen(int pen)
+{
+ uint16_t dat = m_palram[(pen*2)] << 8;
+ dat |= m_palram[(pen*2)+1];
+
+ // llll lsss ---h hhhh
+ int l_raw = (dat & 0xf800) >> 11;
+ int sl_raw = (dat & 0x0700) >> 8;
+ int h_raw = (dat & 0x001f) >> 0;
+
+ double l = (double)l_raw / 31.0f;
+ double s = (double)sl_raw / 7.0f;
+ double h = (double)h_raw / 24.0f;
+
+ double r, g, b;
+
+ if (s == 0) {
+ r = g = b = l; // greyscale
+ } else {
+ double q = l < 0.5f ? l * (1 + s) : l + s - l * s;
+ double p = 2 * l - q;
+ r = hue2rgb(p, q, h + 1/3.0f);
+ g = hue2rgb(p, q, h);
+ b = hue2rgb(p, q, h - 1/3.0f);
+ }
+
+ int r_real = r * 255.0f;
+ int g_real = g * 255.0f;
+ int b_real = b * 255.0f;
+
+ m_palette->set_pen_color(pen, r_real, g_real, b_real);
+}
+
+
+READ8_MEMBER(elan_eu3a05commonvid_device::palette_r)
+{
+ return m_palram[offset];
+}
+
+WRITE8_MEMBER(elan_eu3a05commonvid_device::palette_w)
+{
+ m_palram[offset] = data;
+ update_pen(offset/2);
+}
diff --git a/src/mame/video/elan_eu3a05commonvid.h b/src/mame/video/elan_eu3a05commonvid.h
new file mode 100644
index 00000000000..beb7d5bb7d7
--- /dev/null
+++ b/src/mame/video/elan_eu3a05commonvid.h
@@ -0,0 +1,35 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+#ifndef MAME_VIDEO_ELAN_EU3A05COMMONVID_H
+#define MAME_VIDEO_ELAN_EU3A05COMMONVID_H
+
+#include "emupal.h"
+
+class elan_eu3a05commonvid_device : public device_t
+{
+public:
+ elan_eu3a05commonvid_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+ elan_eu3a05commonvid_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
+
+ template <typename T> void set_palette(T &&tag) { m_palette.set_tag(std::forward<T>(tag)); }
+ void set_entries(int entries) { m_palram.resize(entries*2); }
+
+ DECLARE_READ8_MEMBER(palette_r);
+ DECLARE_WRITE8_MEMBER(palette_w);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ required_device<palette_device> m_palette;
+ std::vector<uint8_t> m_palram;
+ void update_pen(int pen);
+ double hue2rgb(double p, double q, double t);
+};
+
+DECLARE_DEVICE_TYPE(ELAN_EU3A05_COMMONVID, elan_eu3a05commonvid_device)
+
+#endif // MAME_VIDEO_ELAN_EU3A05COMMONVID_H
diff --git a/src/mame/video/elan_eu3a05vid.cpp b/src/mame/video/elan_eu3a05vid.cpp
new file mode 100644
index 00000000000..d21d324ebb9
--- /dev/null
+++ b/src/mame/video/elan_eu3a05vid.cpp
@@ -0,0 +1,596 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+#include "emu.h"
+#include "elan_eu3a05vid.h"
+
+DEFINE_DEVICE_TYPE(ELAN_EU3A05_VID, elan_eu3a05vid_device, "elan_eu3a05vid", "Elan EU3A05 Video")
+
+// map(0x0600, 0x3dff).ram().share("vram");
+// map(0x3e00, 0x3fff).ram().share("spriteram");
+
+elan_eu3a05vid_device::elan_eu3a05vid_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : elan_eu3a05commonvid_device(mconfig, ELAN_EU3A05_VID, tag, owner, clock),
+ m_cpu(*this, finder_base::DUMMY_TAG),
+ m_bank(*this, finder_base::DUMMY_TAG)
+{
+}
+
+void elan_eu3a05vid_device::device_start()
+{
+ elan_eu3a05commonvid_device::device_start();
+
+ save_item(NAME(m_vidctrl));
+ save_item(NAME(m_tile_gfxbase_lo_data));
+ save_item(NAME(m_tile_gfxbase_hi_data));
+ save_item(NAME(m_sprite_gfxbase_lo_data));
+ save_item(NAME(m_sprite_gfxbase_hi_data));
+ save_item(NAME(m_tile_scroll));
+ save_item(NAME(m_splitpos));
+}
+
+void elan_eu3a05vid_device::device_reset()
+{
+ elan_eu3a05commonvid_device::device_reset();
+
+ m_vidctrl = 0x00; // need to default to an 8x8 mode for Space Invaders test mode at least
+
+ for (int i=0;i<2;i++)
+ m_tile_scroll[i] = 0x00;
+
+ for (int i=0;i<2;i++)
+ m_tile_xscroll[i] = 0x00;
+
+ m_tile_gfxbase_lo_data = 0x00;
+ m_tile_gfxbase_hi_data = 0x00;
+
+ m_sprite_gfxbase_lo_data = 0x00;
+ m_sprite_gfxbase_hi_data = 0x00;
+
+ m_splitpos = 0x00;
+}
+
+uint8_t elan_eu3a05vid_device::read_spriteram(int offset)
+{
+ address_space& cpuspace = m_cpu->space(AS_PROGRAM);
+ int realoffset = offset+0x3e00;
+ if (realoffset < 0x4000)
+ {
+ return cpuspace.read_byte(realoffset);
+ }
+ else
+ return 0x00;
+}
+
+
+uint8_t elan_eu3a05vid_device::read_vram(int offset)
+{
+ address_space& cpuspace = m_cpu->space(AS_PROGRAM);
+ int realoffset = offset+0x0600;
+ if (realoffset < 0x4000)
+ {
+ return cpuspace.read_byte(realoffset);
+ }
+ else
+ return 0x00;
+}
+
+
+
+/* (m_tile_gfxbase_lo_data | (m_tile_gfxbase_hi_data << 8)) * 0x100
+ gives you the actual rom address, everything references the 3MByte - 4MByte region, like the banking so
+ the system can probably have up to a 4MByte rom, all games we have so far just use the upper 1MByte of
+ 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)
+{
+ address_space& fullbankspace = m_bank->space(AS_PROGRAM);
+
+ /*
+ Sprites
+ FF yy xx AA XX YY aa bb
+
+ yy = y position
+ xx = x position
+ XX = texture x start
+ YY = texture y start
+ aa = same as unk2 on tiles
+ bb = sometimes set in invaders
+ AA = same as attr on tiles (colour / priority?)
+
+ FF = flags ( e-dD fFsS )
+ e = enable
+ D = ZoomX to double size (boss explosions on Air Blaster)
+ d = ZoomY to double size (boss explosions on Air Blaster)
+ S = SizeX
+ s = SizeY
+ F = FlipX
+ f = FlipY (assumed, not seen)
+
+ */
+
+ for (int i = 0; i < 512; i += 8)
+ {
+ uint8_t x = read_spriteram(i + 2);
+ uint8_t y = read_spriteram(i + 1);
+
+ /*
+ Space Invaders draws the player base with this specific y value before the start of each life
+ and expects it to NOT wrap around. There are no high priority tiles or anything else to hide
+ and it doesn't appear on real hardware.
+
+ it's possible sprites don't wrap around at all (but then you couldn't have smooth entry at the
+ top of the screen - there are no extra y co-ordinate bits. However there would have been easier
+ ways to hide this tho as there are a bunch of unseen lines at the bottom of the screen anyway!
+
+ Air Blaster Joystick seems to indicate there is no sprite wrapping - sprites abruptly enter
+ the screen in pieces on real hardware.
+
+ needs further investigation.
+ */
+ if (y==255)
+ continue;
+
+ uint8_t tex_x = read_spriteram(i + 4);
+ uint8_t tex_y = read_spriteram(i + 5);
+
+ uint8_t flags = read_spriteram(i + 0);
+ uint8_t attr = read_spriteram(i + 3);
+ uint8_t unk2 = read_spriteram(i + 6);
+
+ const int doubleX = (flags & 0x10)>>4;
+ const int doubleY = (flags & 0x20)>>5;
+
+ //int priority = attr & 0x0f;
+ int colour = attr & 0xf0;
+
+ // ? game select has this set to 0xff, but clearly doesn't want the palette to change!
+ // while in Space Invaders this has to be palette for the UFO to be red.
+ if (colour & 0x80)
+ colour = 0;
+
+ int transpen = 0;
+
+ /* HACK - how is this calculated
+ phoenix and the game select need it like this
+ it isn't a simple case of unk2 being transpen either because Qix has some elements set to 0x07
+ 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))
+ transpen = 0xff;
+
+
+ if (!(flags & 0x80))
+ continue;
+
+ int sizex = 8;
+ int sizey = 8;
+
+ if (flags & 0x01)
+ {
+ sizex = 16;
+ }
+
+ if (flags & 0x02)
+ {
+ sizey = 16;
+ }
+
+ int base = (m_sprite_gfxbase_lo_data | (m_sprite_gfxbase_hi_data << 8)) * 0x100;
+
+ if (doubleX)
+ sizex = sizex * 2;
+
+ if (doubleY)
+ sizey = sizey * 2;
+
+ for (int yy = 0; yy < sizey; yy++)
+ {
+ uint16_t* row;
+
+ if (flags & 0x08) // guess flipy
+ {
+ row = &bitmap.pix16((y + (sizey - 1 - yy)) & 0xff);
+ }
+ else
+ {
+ row = &bitmap.pix16((y + yy) & 0xff);
+ }
+
+ for (int xx = 0; xx < sizex; xx++)
+ {
+ int realaddr;
+
+ if (!doubleX)
+ realaddr = base + ((tex_x + xx) & 0xff);
+ else
+ realaddr = base + ((tex_x + (xx>>1)) & 0xff);
+
+ if (!doubleY)
+ realaddr += ((tex_y + yy) & 0xff) * 256;
+ else
+ realaddr += ((tex_y + (yy>>1)) & 0xff) * 256;
+
+ uint8_t pix = fullbankspace.read_byte(realaddr);
+
+ if (pix != transpen)
+ {
+ if (flags & 0x04) // flipx
+ {
+ row[(x + (sizex - 1 - xx)) & 0xff] = (pix + ((colour & 0x70) << 1)) & 0xff;
+ }
+ else
+ {
+ row[(x + xx) & 0xff] = (pix + ((colour & 0x70) << 1)) & 0xff;
+ }
+ }
+ }
+ }
+ }
+}
+
+
+// a hacky mess for now
+bool elan_eu3a05vid_device::get_tile_data(int base, int drawpri, int& tile, int &attr, int &unk2)
+{
+ tile = read_vram(base * 4) + (read_vram((base * 4) + 1) << 8);
+
+ // these seem to be the basically the same as attr/unk2 in the sprites, which also make
+ // very little sense.
+ attr = read_vram((base * 4) + 2);
+ unk2 = read_vram((base * 4) + 3);
+
+ /* hack for phoenix title screens.. the have attr set to 0x3f which change the colour bank in ways we don't want
+ and also by our interpretation of 0x0f bits sets the tiles to priority over sprites (although in this case
+ that might tbe ok, because it looks like the sprites also have that set */
+ if (unk2 == 0x07)
+ attr = 0;
+
+ int priority = attr & 0x0f;
+
+ // likely wrong
+ if ((drawpri == 0 && priority == 0x0f) || (drawpri == 1 && priority != 0x0f))
+ return false;
+
+ return true;
+}
+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)
+ */
+
+ int scroll = (m_tile_scroll[1] << 8) | m_tile_scroll[0];
+ address_space& fullbankspace = m_bank->space(AS_PROGRAM);
+
+ // 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
+ {
+ 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;
+ }
+
+ for (int y = 0; y < totalyrow; y++)
+ {
+ for (int x = 0; x < totalxcol * 2; x++)
+ {
+ int realstartrow = (startrow + y);
+
+ int yrows;
+
+ if (m_vidctrl & 0x01)
+ yrows = mapyrowsbase;
+ 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;
+ }
+ }
+ }
+
+ for (int i = 0; i < tileysize; i++)
+ {
+ int drawline = (y * tileysize) + i;
+ drawline -= scroll & (tileysize - 1);
+
+ if ((drawline >= 0) && (drawline < 256))
+ {
+ int scrollx;
+
+ // split can be probably configured in more ways than this
+ if (drawline > m_splitpos)
+ scrollx = get_xscroll(1);
+ else
+ scrollx = get_xscroll(0);
+
+ int base;
+
+ 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;
+
+ if (m_vidctrl & 0x40) // 16x16 tiles
+ {
+ if (m_vidctrl & 0x20) // 4bpp mode
+ {
+ tile = (tile & 0xf) + ((tile & ~0xf) * 16);
+ tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5);
+ }
+ else
+ {
+ tile = (tile & 0xf) + ((tile & ~0xf) * 16);
+ tile <<= 1;
+
+ tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5);
+ }
+ }
+ else
+ {
+ if (m_vidctrl & 0x20) // 4bpp
+ {
+ // TODO
+ tile = 0x0000;//machine().rand() & 0x1ff;
+ }
+ else
+ {
+ tile = (tile & 0x1f) + ((tile & ~0x1f) * 8);
+ tile += ((m_tile_gfxbase_lo_data | m_tile_gfxbase_hi_data << 8) << 5);
+ }
+ }
+
+ uint16_t* row = &bitmap.pix16(drawline);
+
+ if (m_vidctrl & 0x40) // 16x16 tiles
+ {
+ 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 * 16 + xx + 0;
+ drawxpos &= 0x1ff;
+ if ((drawxpos >= 0) && (drawxpos < 256))
+ row[drawxpos] = ((pix & 0xf0) >> 4) + colour;
+
+ drawxpos = x * 16 + xx + 1;
+ 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 * 16 + xx;
+ drawxpos &= 0x1ff;
+ if ((drawxpos >= 0) && (drawxpos < 256))
+ row[drawxpos] = (pix + ((colour & 0x70) << 1)) & 0xff;
+ }
+ }
+ }
+ else // 8x8 tiles
+ {
+ if (m_vidctrl & 0x20) // 4bpp
+ {
+ // TODO
+ }
+ else
+ {
+ for (int xx = 0; xx < tilexsize; xx++)
+ {
+ const int realaddr = ((tile + i * 32) << 3) + xx;
+ const 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;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+uint32_t elan_eu3a05vid_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ bitmap.fill(0, cliprect);
+
+ draw_tilemaps(screen,bitmap,cliprect,0);
+ draw_sprites(screen,bitmap,cliprect);
+ draw_tilemaps(screen,bitmap,cliprect,1);
+
+ return 0;
+}
+
+// Tile bases
+
+WRITE8_MEMBER(elan_eu3a05vid_device::tile_gfxbase_lo_w)
+{
+ //logerror("%s: tile_gfxbase_lo_w (select GFX base lower) %02x\n", machine().describe_context(), data);
+ m_tile_gfxbase_lo_data = data;
+}
+
+WRITE8_MEMBER(elan_eu3a05vid_device::tile_gfxbase_hi_w)
+{
+ //logerror("%s: tile_gfxbase_hi_w (select GFX base upper) %02x\n", machine().describe_context(), data);
+ m_tile_gfxbase_hi_data = data;
+}
+
+READ8_MEMBER(elan_eu3a05vid_device::tile_gfxbase_lo_r)
+{
+ //logerror("%s: tile_gfxbase_lo_r (GFX base lower)\n", machine().describe_context());
+ return m_tile_gfxbase_lo_data;
+}
+
+READ8_MEMBER(elan_eu3a05vid_device::tile_gfxbase_hi_r)
+{
+ //logerror("%s: tile_gfxbase_hi_r (GFX base upper)\n", machine().describe_context());
+ return m_tile_gfxbase_hi_data;
+}
+
+
+
+// Sprite Tile bases
+
+WRITE8_MEMBER(elan_eu3a05vid_device::sprite_gfxbase_lo_w)
+{
+ //logerror("%s: sprite_gfxbase_lo_w (select Sprite GFX base lower) %02x\n", machine().describe_context(), data);
+ m_sprite_gfxbase_lo_data = data;
+}
+
+WRITE8_MEMBER(elan_eu3a05vid_device::sprite_gfxbase_hi_w)
+{
+ //logerror("%s: sprite_gfxbase_hi_w (select Sprite GFX base upper) %02x\n", machine().describe_context(), data);
+ m_sprite_gfxbase_hi_data = data;
+}
+
+READ8_MEMBER(elan_eu3a05vid_device::sprite_gfxbase_lo_r)
+{
+ //logerror("%s: sprite_gfxbase_lo_r (Sprite GFX base lower)\n", machine().describe_context());
+ return m_sprite_gfxbase_lo_data;
+}
+
+READ8_MEMBER(elan_eu3a05vid_device::sprite_gfxbase_hi_r)
+{
+ //logerror("%s: sprite_gfxbase_hi_r (Sprite GFX base upper)\n", machine().describe_context());
+ return m_sprite_gfxbase_hi_data;
+}
+
+
+
+READ8_MEMBER(elan_eu3a05vid_device::tile_scroll_r)
+{
+ return m_tile_scroll[offset];
+}
+
+WRITE8_MEMBER(elan_eu3a05vid_device::tile_scroll_w)
+{
+ m_tile_scroll[offset] = data;
+}
+
+READ8_MEMBER(elan_eu3a05vid_device::tile_xscroll_r)
+{
+ return m_tile_xscroll[offset];
+}
+
+WRITE8_MEMBER(elan_eu3a05vid_device::tile_xscroll_w)
+{
+ m_tile_xscroll[offset] = data;
+}
+
+READ8_MEMBER(elan_eu3a05vid_device::splitpos_r)
+{
+ return m_splitpos;
+}
+
+WRITE8_MEMBER(elan_eu3a05vid_device::splitpos_w)
+{
+ m_splitpos = data;
+}
+
+uint16_t elan_eu3a05vid_device::get_xscroll(int which)
+{
+ switch (which)
+ {
+ case 0x0: return (m_tile_xscroll[1] << 8) | (m_tile_xscroll[0]);
+ case 0x1: return (m_tile_xscroll[3] << 8) | (m_tile_xscroll[2]);
+ }
+
+ return 0x0000;
+}
+
+READ8_MEMBER(elan_eu3a05vid_device::elan_eu3a05_vidctrl_r)
+{
+ return m_vidctrl;
+}
+
+WRITE8_MEMBER(elan_eu3a05vid_device::elan_eu3a05_vidctrl_w)
+{
+ logerror("%s: elan_eu3a05_vidctrl_w %02x (video control?)\n", machine().describe_context(), data);
+ /*
+ c3 8bpp 16x16 1100 0011 abl logo
+ e3 4bpp 16x16 1110 0011
+ 83 8bpp 8x8 1000 0011 air blaster logo
+ 02 8bpp 8x8 (phoenix) 0000 0010 air blaster 2d normal
+ 03 8bpp 8x8 0000 0011 air blaster 2d bosses
+ 00 0000 0000 air blaster 3d stages
+
+ ?tb- --wh
+
+ ? = unknown
+ t = tile size (1 = 16x16, 0 = 8x8)
+ b = bpp (0 = 8bpp, 1 = 4bpp)
+ - = haven't seen used
+ h = tilemap height? (0 = double height)
+ w = tilemap width? (0 = double width)
+
+ space invaders test mode doesn't initialize this
+
+ */
+ m_vidctrl = data;
+} \ No newline at end of file
diff --git a/src/mame/video/elan_eu3a05vid.h b/src/mame/video/elan_eu3a05vid.h
new file mode 100644
index 00000000000..4f4f52ad2f9
--- /dev/null
+++ b/src/mame/video/elan_eu3a05vid.h
@@ -0,0 +1,80 @@
+// license:BSD-3-Clause
+// copyright-holders:David Haywood
+
+#ifndef MAME_VIDEO_ELAN_EU3A05VID_H
+#define MAME_VIDEO_ELAN_EU3A05VID_H
+
+#include "elan_eu3a05commonvid.h"
+#include "cpu/m6502/m6502.h"
+#include "machine/bankdev.h"
+
+class elan_eu3a05vid_device : public elan_eu3a05commonvid_device
+{
+public:
+ elan_eu3a05vid_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
+
+ template <typename T> void set_cpu(T &&tag) { m_cpu.set_tag(std::forward<T>(tag)); }
+ template <typename T> void set_addrbank(T &&tag) { m_bank.set_tag(std::forward<T>(tag)); }
+
+ // VIDEO
+ // tile bases
+ DECLARE_WRITE8_MEMBER(tile_gfxbase_lo_w);
+ DECLARE_WRITE8_MEMBER(tile_gfxbase_hi_w);
+ DECLARE_READ8_MEMBER(tile_gfxbase_lo_r);
+ DECLARE_READ8_MEMBER(tile_gfxbase_hi_r);
+ // sprite tile bases
+ DECLARE_WRITE8_MEMBER(sprite_gfxbase_lo_w);
+ DECLARE_WRITE8_MEMBER(sprite_gfxbase_hi_w);
+ DECLARE_READ8_MEMBER(sprite_gfxbase_lo_r);
+ DECLARE_READ8_MEMBER(sprite_gfxbase_hi_r);
+
+ DECLARE_READ8_MEMBER(elan_eu3a05_vidctrl_r);
+ DECLARE_WRITE8_MEMBER(elan_eu3a05_vidctrl_w);
+
+ DECLARE_READ8_MEMBER(tile_scroll_r);
+ DECLARE_WRITE8_MEMBER(tile_scroll_w);
+
+ DECLARE_READ8_MEMBER(tile_xscroll_r);
+ DECLARE_WRITE8_MEMBER(tile_xscroll_w);
+
+ DECLARE_READ8_MEMBER(splitpos_r);
+ DECLARE_WRITE8_MEMBER(splitpos_w);
+
+ uint16_t get_xscroll(int which);
+
+ uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_start() override;
+ virtual void device_reset() override;
+
+private:
+ required_device<m6502_device> m_cpu;
+ required_device<address_map_bank_device> m_bank;
+
+ uint8_t m_vidctrl;
+
+ uint8_t m_tile_gfxbase_lo_data;
+ uint8_t m_tile_gfxbase_hi_data;
+
+ uint8_t m_sprite_gfxbase_lo_data;
+ uint8_t m_sprite_gfxbase_hi_data;
+
+ uint8_t m_tile_scroll[2];
+ uint8_t m_tile_xscroll[4];
+
+ uint8_t m_splitpos;
+
+ 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);
+
+ uint8_t read_spriteram(int offset);
+ uint8_t read_vram(int offset);
+
+};
+
+DECLARE_DEVICE_TYPE(ELAN_EU3A05_VID, elan_eu3a05vid_device)
+
+#endif // MAME_VIDEO_ELAN_EU3A05VID_H