summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/video/imagetek_i4100.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/video/imagetek_i4100.cpp')
-rw-r--r--src/devices/video/imagetek_i4100.cpp1171
1 files changed, 1171 insertions, 0 deletions
diff --git a/src/devices/video/imagetek_i4100.cpp b/src/devices/video/imagetek_i4100.cpp
new file mode 100644
index 00000000000..7a755d4d7d3
--- /dev/null
+++ b/src/devices/video/imagetek_i4100.cpp
@@ -0,0 +1,1171 @@
+// license:BSD-3-Clause
+// copyright-holders:Luca Elia,David Haywood,Angelo Salese
+/***************************************************************************
+
+ Imagetek I4100 / I4220 / I4300 device files
+
+ device emulation by Angelo Salese, based off from original metro.cpp
+ implementation by Luca Elia & David Haywood
+
+ TODO:
+ - interrupt enable/acknowledge/vector;
+ - soundlatch delegate;
+ - inputs for i4300;
+
+============================================================================
+
+ driver by Luca Elia (l.elia@tin.it)
+
+ [ 3 Scrolling Layers ]
+
+ There is memory for a huge layer, but the actual tilemap
+ is a smaller window (of fixed size) carved from anywhere
+ inside that layer.
+
+ Tile Size: 8 x 8 x 4
+ (later games can switch to 8 x 8 x 8, 16 x 16 x 4/8 at run time)
+
+ Big Layer Size: 2048 x 2048 (8x8 tiles) or 4096 x 4096 (16x16 tiles)
+
+ Tilemap Window Size: 512 x 256 (8x8 tiles) or 1024 x 512 (16x16 tiles)
+
+ The tile codes in memory do not map directly to tiles. They
+ are indexes into a table (with 0x200 entries) that defines
+ a virtual set of tiles for the 3 layers. Each entry in that
+ table adds 16 tiles to the set of available tiles, and decides
+ their color code.
+
+ Tile code with their msbit set are different as they mean:
+ draw a tile filled with a single color (0-fff)
+
+
+ [ 512 Zooming Sprites ]
+
+ The sprites are NOT tile based: the "tile" size can vary from
+ 8 to 64 (independently for width and height) with an 8 pixel
+ granularity. The "tile" address is a multiple of 8x8 pixels.
+
+ Each sprite can be shrinked to ~1/4 or enlarged to ~32x following
+ an exponential curve of sizes (with one zoom value for both width
+ and height)
+
+
+***************************************************************************/
+
+#include "emu.h"
+#include "imagetek_i4100.h"
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// device type definition
+DEFINE_DEVICE_TYPE(I4100, imagetek_i4100_device, "i4100", "Imagetek I4100 052 VDP")
+DEFINE_DEVICE_TYPE(I4220, imagetek_i4220_device, "i4220", "Imagetek I4220 071 VDP")
+DEFINE_DEVICE_TYPE(I4300, imagetek_i4300_device, "i4300", "Imagetek I4300 095 VDP")
+
+DEVICE_ADDRESS_MAP_START( map, 16, imagetek_i4100_device)
+ AM_RANGE(0x00000, 0x1ffff) AM_READWRITE(vram_0_r, vram_0_w) AM_SHARE("vram_0")
+ AM_RANGE(0x20000, 0x3ffff) AM_READWRITE(vram_1_r, vram_1_w) AM_SHARE("vram_1")
+ AM_RANGE(0x40000, 0x5ffff) AM_READWRITE(vram_2_r, vram_2_w) AM_SHARE("vram_2")
+ AM_RANGE(0x60000, 0x6ffff) AM_READ(gfxrom_r)
+ AM_RANGE(0x70000, 0x71fff) AM_READWRITE(scratchram_r, scratchram_w) AM_SHARE("scratchram") // unknown, maybe palette
+ AM_RANGE(0x72000, 0x73fff) AM_DEVREADWRITE("palette", palette_device, read, write) AM_SHARE("palette")
+ AM_RANGE(0x74000, 0x74fff) AM_READWRITE(spriteram_r, spriteram_w) AM_SHARE("spriteram")
+ AM_RANGE(0x75000, 0x75fff) AM_READWRITE(rmw_vram_0_r, rmw_vram_0_w)
+ AM_RANGE(0x76000, 0x76fff) AM_READWRITE(rmw_vram_1_r, rmw_vram_1_w)
+ AM_RANGE(0x77000, 0x77fff) AM_READWRITE(rmw_vram_2_r, rmw_vram_2_w)
+ AM_RANGE(0x78000, 0x787ff) AM_READWRITE(tiletable_r, tiletable_w) AM_SHARE("tiletable")
+ // video registers
+ AM_RANGE(0x78800, 0x78801) AM_READWRITE(sprite_count_r, sprite_count_w)
+ AM_RANGE(0x78802, 0x78803) AM_READWRITE(sprite_priority_r, sprite_priority_w)
+ AM_RANGE(0x78804, 0x78805) AM_READWRITE(sprite_yoffset_r, sprite_yoffset_w)
+ AM_RANGE(0x78806, 0x78807) AM_READWRITE(sprite_xoffset_r, sprite_xoffset_w)
+ AM_RANGE(0x78808, 0x78809) AM_READWRITE(sprite_color_code_r, sprite_color_code_w)
+ AM_RANGE(0x78810, 0x78811) AM_READWRITE(layer_priority_r, layer_priority_w)
+ AM_RANGE(0x78812, 0x78813) AM_READWRITE(background_color_r, background_color_w)
+
+ AM_RANGE(0x78840, 0x7884d) AM_WRITE(blitter_w) AM_SHARE("blitter_regs")
+ AM_RANGE(0x78850, 0x78851) AM_READWRITE(screen_yoffset_r, screen_yoffset_w)
+ AM_RANGE(0x78852, 0x78853) AM_READWRITE(screen_xoffset_r, screen_xoffset_w)
+ AM_RANGE(0x78860, 0x7886b) AM_READWRITE(window_r, window_w) AM_SHARE("windowregs")
+ AM_RANGE(0x78870, 0x7887b) AM_READWRITE(scroll_r, scroll_w) AM_SHARE("scrollregs")
+
+ AM_RANGE(0x78880, 0x78881) AM_WRITE(crtc_vert_w)
+ AM_RANGE(0x78890, 0x78891) AM_WRITE(crtc_horz_w)
+ AM_RANGE(0x788a0, 0x788a1) AM_WRITE(crtc_unlock_w)
+ AM_RANGE(0x788aa, 0x788ab) AM_WRITE(rombank_w)
+ AM_RANGE(0x788ac, 0x788ad) AM_WRITE(screen_ctrl_w)
+ADDRESS_MAP_END
+
+// same as above but with moved video registers (now at 0x797**)
+DEVICE_ADDRESS_MAP_START( v2_map, 16, imagetek_i4220_device)
+ AM_RANGE(0x00000, 0x1ffff) AM_READWRITE(vram_0_r, vram_0_w) AM_SHARE("vram_0")
+ AM_RANGE(0x20000, 0x3ffff) AM_READWRITE(vram_1_r, vram_1_w) AM_SHARE("vram_1")
+ AM_RANGE(0x40000, 0x5ffff) AM_READWRITE(vram_2_r, vram_2_w) AM_SHARE("vram_2")
+ AM_RANGE(0x60000, 0x6ffff) AM_READ(gfxrom_r)
+ AM_RANGE(0x70000, 0x71fff) AM_READWRITE(scratchram_r, scratchram_w) AM_SHARE("scratchram") // unknown, maybe palette
+ AM_RANGE(0x72000, 0x73fff) AM_DEVREADWRITE("palette", palette_device, read, write) AM_SHARE("palette")
+ AM_RANGE(0x74000, 0x74fff) AM_READWRITE(spriteram_r, spriteram_w) AM_SHARE("spriteram")
+ AM_RANGE(0x75000, 0x75fff) AM_READWRITE(rmw_vram_0_r, rmw_vram_0_w)
+ AM_RANGE(0x76000, 0x76fff) AM_READWRITE(rmw_vram_1_r, rmw_vram_1_w)
+ AM_RANGE(0x77000, 0x77fff) AM_READWRITE(rmw_vram_2_r, rmw_vram_2_w)
+ AM_RANGE(0x78000, 0x787ff) AM_READWRITE(tiletable_r, tiletable_w) AM_SHARE("tiletable")
+
+ AM_RANGE(0x78840, 0x7884d) AM_WRITE(blitter_w) AM_SHARE("blitter_regs")
+ AM_RANGE(0x78850, 0x78851) AM_READWRITE(screen_yoffset_r, screen_yoffset_w)
+ AM_RANGE(0x78852, 0x78853) AM_READWRITE(screen_xoffset_r, screen_xoffset_w)
+ AM_RANGE(0x78860, 0x7886b) AM_READWRITE(window_r, window_w) AM_SHARE("windowregs")
+ AM_RANGE(0x78870, 0x7887b) AM_READWRITE(scroll_r, scroll_w) AM_SHARE("scrollregs")
+
+ AM_RANGE(0x78880, 0x78881) AM_WRITE(crtc_vert_w)
+ AM_RANGE(0x78890, 0x78891) AM_WRITE(crtc_horz_w)
+ AM_RANGE(0x788a0, 0x788a1) AM_WRITE(crtc_unlock_w)
+ AM_RANGE(0x788aa, 0x788ab) AM_WRITE(rombank_w)
+ AM_RANGE(0x788ac, 0x788ad) AM_WRITE(screen_ctrl_w)
+
+ // video registers
+ AM_RANGE(0x79700, 0x79701) AM_READWRITE(sprite_count_r, sprite_count_w)
+ AM_RANGE(0x79702, 0x79703) AM_READWRITE(sprite_priority_r, sprite_priority_w)
+ AM_RANGE(0x79704, 0x79705) AM_READWRITE(sprite_yoffset_r, sprite_yoffset_w)
+ AM_RANGE(0x79706, 0x79707) AM_READWRITE(sprite_xoffset_r, sprite_xoffset_w)
+ AM_RANGE(0x79708, 0x79709) AM_READWRITE(sprite_color_code_r, sprite_color_code_w)
+ AM_RANGE(0x79710, 0x79711) AM_READWRITE(layer_priority_r, layer_priority_w)
+ AM_RANGE(0x79712, 0x79713) AM_READWRITE(background_color_r, background_color_w)
+ // repeated here in Puzzlet compatibility mode
+ AM_RANGE(0x78800, 0x78801) AM_READWRITE(sprite_count_r, sprite_count_w)
+ // ... this one breaks Blazing Tornado tho
+// AM_RANGE(0x78802, 0x78803) AM_READWRITE(sprite_priority_r, sprite_priority_w)
+ AM_RANGE(0x78804, 0x78805) AM_READWRITE(sprite_yoffset_r, sprite_yoffset_w)
+ AM_RANGE(0x78806, 0x78807) AM_READWRITE(sprite_xoffset_r, sprite_xoffset_w)
+ AM_RANGE(0x78808, 0x78809) AM_READWRITE(sprite_color_code_r, sprite_color_code_w)
+ AM_RANGE(0x78810, 0x78811) AM_READWRITE(layer_priority_r, layer_priority_w)
+ AM_RANGE(0x78812, 0x78813) AM_READWRITE(background_color_r, background_color_w)
+ADDRESS_MAP_END
+
+// more changes around, namely the screen offsets being reversed here
+DEVICE_ADDRESS_MAP_START( v3_map, 16, imagetek_i4300_device)
+ AM_RANGE(0x00000, 0x1ffff) AM_READWRITE(vram_0_r, vram_0_w) AM_SHARE("vram_0")
+ AM_RANGE(0x20000, 0x3ffff) AM_READWRITE(vram_1_r, vram_1_w) AM_SHARE("vram_1")
+ AM_RANGE(0x40000, 0x5ffff) AM_READWRITE(vram_2_r, vram_2_w) AM_SHARE("vram_2")
+ AM_RANGE(0x60000, 0x6ffff) AM_READ(gfxrom_r)
+ AM_RANGE(0x70000, 0x71fff) AM_READWRITE(scratchram_r, scratchram_w) AM_SHARE("scratchram") // unknown, maybe palette
+ AM_RANGE(0x72000, 0x73fff) AM_DEVREADWRITE("palette", palette_device, read, write) AM_SHARE("palette")
+ AM_RANGE(0x74000, 0x74fff) AM_READWRITE(spriteram_r, spriteram_w) AM_SHARE("spriteram")
+ AM_RANGE(0x75000, 0x75fff) AM_READWRITE(rmw_vram_0_r, rmw_vram_0_w)
+ AM_RANGE(0x76000, 0x76fff) AM_READWRITE(rmw_vram_1_r, rmw_vram_1_w)
+ AM_RANGE(0x77000, 0x77fff) AM_READWRITE(rmw_vram_2_r, rmw_vram_2_w)
+ AM_RANGE(0x78000, 0x787ff) AM_READWRITE(tiletable_r, tiletable_w) AM_SHARE("tiletable")
+ AM_RANGE(0x78808, 0x78809) AM_READWRITE(screen_xoffset_r, screen_xoffset_w)
+ AM_RANGE(0x7880a, 0x7880b) AM_READWRITE(screen_yoffset_r, screen_yoffset_w)
+ AM_RANGE(0x7880e, 0x7880f) AM_WRITE(screen_ctrl_w) // TODO: can be read back here (gakusai)
+
+ AM_RANGE(0x78800, 0x78801) AM_WRITE(crtc_unlock_w)
+ AM_RANGE(0x78802, 0x78803) AM_WRITE(crtc_horz_w)
+ AM_RANGE(0x78804, 0x78805) AM_WRITE(crtc_vert_w)
+
+ AM_RANGE(0x78840, 0x7884d) AM_WRITE(blitter_w) AM_SHARE("blitter_regs")
+ AM_RANGE(0x78850, 0x7885b) AM_READWRITE(scroll_r, scroll_w) AM_SHARE("scrollregs")
+ AM_RANGE(0x78860, 0x7886b) AM_READWRITE(window_r, window_w) AM_SHARE("windowregs")
+ AM_RANGE(0x78870, 0x78871) AM_WRITE(rombank_w)
+
+ // video registers
+ AM_RANGE(0x79700, 0x79701) AM_READWRITE(sprite_count_r, sprite_count_w)
+ AM_RANGE(0x79702, 0x79703) AM_READWRITE(sprite_priority_r, sprite_priority_w)
+ AM_RANGE(0x79704, 0x79705) AM_READWRITE(sprite_yoffset_r, sprite_yoffset_w)
+ AM_RANGE(0x79706, 0x79707) AM_READWRITE(sprite_xoffset_r, sprite_xoffset_w)
+ AM_RANGE(0x79708, 0x79709) AM_READWRITE(sprite_color_code_r, sprite_color_code_w)
+ AM_RANGE(0x79710, 0x79711) AM_READWRITE(layer_priority_r, layer_priority_w)
+ AM_RANGE(0x79712, 0x79713) AM_READWRITE(background_color_r, background_color_w)
+ADDRESS_MAP_END
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// i4100_device - constructor
+//-------------------------------------------------
+
+
+imagetek_i4100_device::imagetek_i4100_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, bool has_ext_tiles)
+ : device_t(mconfig, type, tag, owner, clock)
+ , device_video_interface(mconfig, *this)
+ , m_vram_0(*this, "vram_0")
+ , m_vram_1(*this, "vram_1")
+ , m_vram_2(*this, "vram_2")
+ , m_scratchram(*this, "scratchram")
+ , m_blitter_regs(*this, "blitter_regs")
+ , m_spriteram(*this, "spriteram")
+ , m_tiletable(*this, "tiletable")
+ , m_window(*this, "windowregs")
+ , m_scroll(*this, "scrollregs")
+ , m_palette(*this, "palette")
+ , m_gfxdecode(*this, finder_base::DUMMY_TAG)
+ , m_gfxrom(*this, "^gfx1")
+ , m_blit_irq_cb(*this)
+ , m_support_8bpp( has_ext_tiles )
+ , m_support_16x16( has_ext_tiles )
+{
+ m_tilemap_scrolldx[0] = 0;
+ m_tilemap_scrolldx[1] = 0;
+ m_tilemap_scrolldx[2] = 0;
+}
+
+imagetek_i4100_device::imagetek_i4100_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : imagetek_i4100_device(mconfig, I4100, tag, owner, clock, false)
+{
+}
+
+
+imagetek_i4220_device::imagetek_i4220_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : imagetek_i4100_device(mconfig, I4220, tag, owner, clock, true)
+{
+}
+
+imagetek_i4300_device::imagetek_i4300_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : imagetek_i4100_device(mconfig, I4300, tag, owner, clock, true)
+{
+}
+
+//-------------------------------------------------
+// device_add_mconfig - device-specific machine
+// configuration addiitons
+//-------------------------------------------------
+
+MACHINE_CONFIG_MEMBER(imagetek_i4100_device::device_add_mconfig)
+ MCFG_PALETTE_ADD("palette", 0x1000)
+ MCFG_PALETTE_FORMAT(GGGGGRRRRRBBBBBx)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// static_set_gfxdecode_tag: Set the tag of the
+// gfx decoder
+//-------------------------------------------------
+
+void imagetek_i4100_device::static_set_gfxdecode_tag(device_t &device, const char *tag)
+{
+ downcast<imagetek_i4100_device &>(device).m_gfxdecode.set_tag(tag);
+}
+
+
+void imagetek_i4100_device::static_set_tmap_xoffsets(device_t &device, int x1, int x2, int x3)
+{
+ downcast<imagetek_i4100_device &>(device).m_tilemap_scrolldx[0] = x1;
+ downcast<imagetek_i4100_device &>(device).m_tilemap_scrolldx[1] = x2;
+ downcast<imagetek_i4100_device &>(device).m_tilemap_scrolldx[2] = x3;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void imagetek_i4100_device::expand_gfx1()
+{
+ // TODO: remove from device_reset (otherwise you get broken sprites in i4220+ games because gfx rom isn't yet inited!)
+ if(m_inited_hack == true)
+ return;
+
+ m_inited_hack = true;
+ uint32_t length = m_gfxrom_size * 2;
+
+ m_expanded_gfx1 = std::make_unique<uint8_t[]>(length);
+
+ for (int i = 0; i < length; i += 2)
+ {
+ uint8_t src = m_gfxrom[i / 2];
+
+ m_expanded_gfx1[i + 0] = src & 0xf;
+ m_expanded_gfx1[i + 1] = src >> 4;
+ }
+}
+
+void imagetek_i4100_device::device_start()
+{
+ if(!m_gfxdecode->started())
+ throw device_missing_dependencies();
+
+ m_inited_hack = false;
+ save_item(NAME(m_rombank));
+ save_item(NAME(m_crtc_unlock));
+ save_item(NAME(m_sprite_count));
+ save_item(NAME(m_sprite_priority));
+ save_item(NAME(m_sprite_color_code));
+ save_item(NAME(m_sprite_xoffset));
+ save_item(NAME(m_sprite_yoffset));
+ save_item(NAME(m_screen_xoffset));
+ save_item(NAME(m_screen_yoffset));
+ save_item(NAME(m_layer_priority));
+ save_item(NAME(m_background_color));
+// save_item(NAME(m_window));
+// save_item(NAME(m_scroll));
+ save_item(NAME(m_screen_blank));
+ save_item(NAME(m_screen_flip));
+
+// memory_region *devregion = machine().root_device().memregion(":gfx1");
+// m_gfxrom = devregion->base();
+ if (m_gfxrom == nullptr)
+ fatalerror("Imagetek i4100 %s: \"gfx1\" memory base not found",this->tag());
+
+ m_gfxrom_size = m_gfxrom.bytes();
+
+ m_blit_irq_cb.resolve_safe();
+ m_blit_done_timer = timer_alloc(TIMER_BLIT_END);
+
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void imagetek_i4100_device::device_reset()
+{
+ expand_gfx1();
+}
+
+
+void imagetek_i4100_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_BLIT_END:
+ m_blit_irq_cb(ASSERT_LINE);
+ break;
+ }
+}
+
+//**************************************************************************
+// READ/WRITE HANDLERS
+//**************************************************************************
+
+READ16_MEMBER(imagetek_i4100_device::vram_0_r){ return m_vram_0[offset]; }
+READ16_MEMBER(imagetek_i4100_device::vram_1_r){ return m_vram_1[offset]; }
+READ16_MEMBER(imagetek_i4100_device::vram_2_r){ return m_vram_2[offset]; }
+WRITE16_MEMBER(imagetek_i4100_device::vram_0_w){ COMBINE_DATA(&m_vram_0[offset]); }
+WRITE16_MEMBER(imagetek_i4100_device::vram_1_w){ COMBINE_DATA(&m_vram_1[offset]); }
+WRITE16_MEMBER(imagetek_i4100_device::vram_2_w){ COMBINE_DATA(&m_vram_2[offset]); }
+
+/* This game uses almost only the blitter to write to the tilemaps.
+ The CPU can only access a "window" of 512x256 pixels in the upper
+ left corner of the big tilemap */
+// TODO: Puzzlet, Sankokushi & Lady Killer contradicts with aformentioned description (more like RMW?)
+
+#define RMW_OFFS( _x_ ) ((_x_) & (0x3f)) + (((_x_) & ~(0x3f)) * (0x100 / 0x40))
+
+READ16_MEMBER(imagetek_i4100_device::rmw_vram_0_r){ return m_vram_0[RMW_OFFS(offset)]; }
+READ16_MEMBER(imagetek_i4100_device::rmw_vram_1_r){ return m_vram_1[RMW_OFFS(offset)]; }
+READ16_MEMBER(imagetek_i4100_device::rmw_vram_2_r){ return m_vram_2[RMW_OFFS(offset)]; }
+WRITE16_MEMBER(imagetek_i4100_device::rmw_vram_0_w){ COMBINE_DATA(&m_vram_0[RMW_OFFS(offset)]); }
+WRITE16_MEMBER(imagetek_i4100_device::rmw_vram_1_w){ COMBINE_DATA(&m_vram_1[RMW_OFFS(offset)]); }
+WRITE16_MEMBER(imagetek_i4100_device::rmw_vram_2_w){ COMBINE_DATA(&m_vram_2[RMW_OFFS(offset)]); }
+
+#undef RMW_OFFS
+
+READ16_MEMBER(imagetek_i4100_device::scratchram_r ) { return m_scratchram[offset]; }
+WRITE16_MEMBER(imagetek_i4100_device::scratchram_w ) { COMBINE_DATA(&m_scratchram[offset]); }
+READ16_MEMBER(imagetek_i4100_device::spriteram_r ) { return m_spriteram[offset]; }
+WRITE16_MEMBER(imagetek_i4100_device::spriteram_w ) { COMBINE_DATA(&m_spriteram[offset]); }
+READ16_MEMBER(imagetek_i4100_device::tiletable_r ) { return m_tiletable[offset]; }
+WRITE16_MEMBER(imagetek_i4100_device::tiletable_w ) { COMBINE_DATA(&m_tiletable[offset]); }
+
+// video registers
+/*************************************************************
+ *
+ * 0.w ---- ---- ---- ---- Number Of Sprites To Draw
+ *
+ ************************************************************/
+READ16_MEMBER(imagetek_i4100_device::sprite_count_r) { return m_sprite_count; }
+WRITE16_MEMBER(imagetek_i4100_device::sprite_count_w) { COMBINE_DATA(&m_sprite_count); }
+
+/*************************************************************
+ *
+ * 2.w f--- ---- ---- ---- Disable Sprites Layer Priority
+ * -edc ---- ---- ----
+ * ---- ba-- ---- ---- Sprites Masked Layer
+ * ---- --98 ---- ---- Sprites Priority
+ * ---- ---- 765- ----
+ * ---- ---- ---4 3210 Sprites Masked Number
+ *
+ *************************************************************/
+READ16_MEMBER(imagetek_i4100_device::sprite_priority_r) { return m_sprite_priority; }
+WRITE16_MEMBER(imagetek_i4100_device::sprite_priority_w) { COMBINE_DATA(&m_sprite_priority); }
+
+/*************************************************************
+ *
+ * 4.w ---- ---- ---- ---- Sprites Y Offset
+ * 6.w ---- ---- ---- ---- Sprites X Offset
+ *
+ ************************************************************/
+READ16_MEMBER(imagetek_i4100_device::sprite_xoffset_r) { return m_sprite_xoffset; }
+WRITE16_MEMBER(imagetek_i4100_device::sprite_xoffset_w) { COMBINE_DATA(&m_sprite_xoffset); }
+READ16_MEMBER(imagetek_i4100_device::sprite_yoffset_r) { return m_sprite_yoffset; }
+WRITE16_MEMBER(imagetek_i4100_device::sprite_yoffset_w) { COMBINE_DATA(&m_sprite_yoffset); }
+
+/*************************************************************
+ *
+ * 8.w ---- ---- ---- ---- Sprites Color Codes Start
+ *
+ ************************************************************/
+READ16_MEMBER(imagetek_i4100_device::sprite_color_code_r) { return m_sprite_color_code; }
+WRITE16_MEMBER(imagetek_i4100_device::sprite_color_code_w) { COMBINE_DATA(&m_sprite_color_code); }
+
+/*************************************************************
+ *
+ * 10.w ---- ---- --54 ---- Layer 2 Priority (3 backmost, 0 frontmost)
+ * ---- ---- ---- 32-- Layer 1 Priority
+ * ---- ---- ---- --10 Layer 0 Priority
+ *
+ ************************************************************/
+
+READ16_MEMBER(imagetek_i4100_device::layer_priority_r)
+{
+ return (m_layer_priority[2]<<4) | (m_layer_priority[1]<<2) | m_layer_priority[0];
+}
+
+WRITE16_MEMBER(imagetek_i4100_device::layer_priority_w)
+{
+ m_layer_priority[2] = (data >> 4) & 3;
+ m_layer_priority[1] = (data >> 2) & 3;
+ m_layer_priority[0] = (data >> 0) & 3;
+ if((data >> 6) != 0)
+ logerror("%s warning: layer_priority_w write with %04x %04x\n",this->tag(),data,mem_mask);
+}
+
+/*************************************************************
+ *
+ * 12.w ---- cccc cccc cccc Background Color
+ *
+ ************************************************************/
+
+READ16_MEMBER(imagetek_i4100_device::background_color_r)
+{
+ return m_background_color;
+}
+
+WRITE16_MEMBER(imagetek_i4100_device::background_color_w)
+{
+ COMBINE_DATA(&m_background_color);
+
+ m_background_color &= 0x0fff;
+ if(data & 0xf000)
+ logerror("%s warning: background_color_w write with %04x %04x\n",this->tag(),data,mem_mask);
+}
+
+/***************************************************************************
+ *
+ * 0.w Sprite Y center point
+ * 2.w Sprite X center point
+ *
+ * Appears to apply only for sprites, maybe they applies to tilemaps too under
+ * certain conditions
+ *
+ ***************************************************************************/
+READ16_MEMBER(imagetek_i4100_device::screen_xoffset_r) { return m_screen_xoffset; }
+WRITE16_MEMBER(imagetek_i4100_device::screen_xoffset_w) { COMBINE_DATA(&m_screen_xoffset); }
+READ16_MEMBER(imagetek_i4100_device::screen_yoffset_r) { return m_screen_yoffset; }
+WRITE16_MEMBER(imagetek_i4100_device::screen_yoffset_w) { COMBINE_DATA(&m_screen_yoffset); }
+
+READ16_MEMBER(imagetek_i4100_device::window_r) { return m_window[offset]; }
+WRITE16_MEMBER(imagetek_i4100_device::window_w) { COMBINE_DATA(&m_window[offset]); }
+READ16_MEMBER(imagetek_i4100_device::scroll_r) { return m_scroll[offset]; }
+WRITE16_MEMBER(imagetek_i4100_device::scroll_w) { COMBINE_DATA(&m_scroll[offset]); }
+
+/****************************************************
+ *
+ * Screen Control Register:
+ *
+ * f--- ---- ---- ---- ?
+ * -edc b--- ---- ----
+ * ---- -a98 ---- ---- ? Leds (see gakusai attract)
+ * ---- ---- 765- ---- 16x16 Tiles (Layer 2-1-0)
+ * ---- ---- ---4 32--
+ * ---- ---- ---- --1- Blank Screen
+ * ---- ---- ---- ---0 Flip Screen
+ *
+ ****************************************************/
+WRITE16_MEMBER(imagetek_i4100_device::screen_ctrl_w)
+{
+ m_layer_tile_select[2] = BIT(data,7);
+ m_layer_tile_select[1] = BIT(data,6);
+ m_layer_tile_select[0] = BIT(data,5);
+
+ // TODO: some of these must be externalized
+ m_screen_blank = BIT(data,1);
+ m_screen_flip = BIT(data,0);
+
+ if(data & 0xff1c)
+ logerror("%s warning: screen_ctrl_w write with %04x %04x\n",this->tag(),data,mem_mask);
+
+}
+
+
+/*
+ The main CPU has access to the ROMs that hold the graphics through
+ a banked window of 64k. Those ROMs also usually store the tables for
+ the virtual tiles set. The tile codes to be written to the tilemap
+ memory to render the backgrounds are also stored here, in a format
+ that the blitter can readily use (which is a form of compression)
+*/
+
+READ16_MEMBER(imagetek_i4100_device::gfxrom_r)
+{
+ offset = offset * 2 + 0x10000 * (m_rombank);
+
+ if (offset < m_gfxrom_size)
+ return ((m_gfxrom[offset + 0] << 8) + m_gfxrom[offset + 1]);
+ else
+ return 0xffff;
+}
+
+WRITE16_MEMBER( imagetek_i4100_device::rombank_w )
+{
+ COMBINE_DATA(&m_rombank);
+}
+
+WRITE16_MEMBER( imagetek_i4100_device::crtc_horz_w )
+{
+ if(m_crtc_unlock == true)
+ {
+ //logerror("%s CRTC horizontal %04x %04x\n",this->tag(),data,mem_mask);
+ }
+}
+
+WRITE16_MEMBER( imagetek_i4100_device::crtc_vert_w )
+{
+ if(m_crtc_unlock == true)
+ {
+ //logerror("%s CRTC vertical %04x %04x\n",this->tag(),data,mem_mask);
+ }
+}
+
+WRITE16_MEMBER( imagetek_i4100_device::crtc_unlock_w )
+{
+ m_crtc_unlock = BIT(data,0);
+ if(data & ~1)
+ logerror("%s warning: unlock register write with %04x %04x\n",this->tag(),data,mem_mask);
+}
+
+/***************************************************************************
+
+
+ Blitter
+
+ [ Registers ]
+
+ Offset: Value:
+
+ 0.l Destination Tilemap (1,2,3)
+ 4.l Blitter Data Address (byte offset into the gfx ROMs)
+ 8.l Destination Address << 7 (byte offset into the tilemap)
+
+ The Blitter reads a byte and looks at the most significative
+ bits for the opcode, while the remaining bits define a value
+ (usually how many bytes to write). The opcode byte may be
+ followed by a number of other bytes:
+
+ 76------ Opcode
+ --543210 N
+ (at most N+1 bytes follow)
+
+
+ The blitter is designed to write every other byte (e.g. it
+ writes a byte and skips the next). Hence 2 blits are needed
+ to fill a tilemap (first even, then odd addresses)
+
+ [ Opcodes ]
+
+ 0 Copy the following N+1 bytes. If the whole byte
+ is $00: stop and generate an IRQ
+
+ 1 Fill N+1 bytes with a sequence, starting with
+ the value in the following byte
+
+ 2 Fill N+1 bytes with the value in the following
+ byte
+
+ 3 Skip N+1 bytes. If the whole byte is $C0:
+ skip to the next row of the tilemap (+0x200 bytes)
+ but preserve the column passed at the start of the
+ blit (destination address % 0x200)
+
+
+***************************************************************************/
+
+void imagetek_i4100_device::blt_write( address_space &space, const int tmap, const offs_t offs, const uint16_t data, const uint16_t mask )
+{
+ switch(tmap)
+ {
+ case 1: vram_0_w(space, offs, data, mask); break;
+ case 2: vram_1_w(space, offs, data, mask); break;
+ case 3: vram_2_w(space, offs, data, mask); break;
+ }
+// logerror("%s : Blitter %X] %04X <- %04X & %04X\n", space.machine().describe_context(), tmap, offs, data, mask);
+}
+
+/***************************************************************************
+
+
+ Blitter
+
+ [ Registers ]
+
+ Offset: Value:
+
+ 0.l Destination Tilemap (1,2,3)
+ 4.l Blitter Data Address (byte offset into the gfx ROMs)
+ 8.l Destination Address << 7 (byte offset into the tilemap)
+
+ The Blitter reads a byte and looks at the most significative
+ bits for the opcode, while the remaining bits define a value
+ (usually how many bytes to write). The opcode byte may be
+ followed by a number of other bytes:
+
+ 76------ Opcode
+ --543210 N
+ (at most N+1 bytes follow)
+
+
+ The blitter is designed to write every other byte (e.g. it
+ writes a byte and skips the next). Hence 2 blits are needed
+ to fill a tilemap (first even, then odd addresses)
+
+ [ Opcodes ]
+
+ 0 Copy the following N+1 bytes. If the whole byte
+ is $00: stop and generate an IRQ
+
+ 1 Fill N+1 bytes with a sequence, starting with
+ the value in the following byte
+
+ 2 Fill N+1 bytes with the value in the following
+ byte
+
+ 3 Skip N+1 bytes. If the whole byte is $C0:
+ skip to the next row of the tilemap (+0x200 bytes)
+ but preserve the column passed at the start of the
+ blit (destination address % 0x200)
+
+
+***************************************************************************/
+
+
+// TODO: clean this up
+WRITE16_MEMBER( imagetek_i4100_device::blitter_w )
+{
+ COMBINE_DATA(&m_blitter_regs[offset]);
+
+ if (offset == 0x0c / 2)
+ {
+ //uint8_t *src = memregion("gfx1")->base();
+
+ uint32_t tmap = (m_blitter_regs[0x00 / 2] << 16) + m_blitter_regs[0x02 / 2];
+ uint32_t src_offs = (m_blitter_regs[0x04 / 2] << 16) + m_blitter_regs[0x06 / 2];
+ uint32_t dst_offs = (m_blitter_regs[0x08 / 2] << 16) + m_blitter_regs[0x0a / 2];
+
+ int shift = (dst_offs & 0x80) ? 0 : 8;
+ uint16_t mask = (dst_offs & 0x80) ? 0x00ff : 0xff00;
+
+// logerror("CPU #0 PC %06X : Blitter regs %08X, %08X, %08X\n", space.device().safe_pc(), tmap, src_offs, dst_offs);
+
+ dst_offs >>= 7 + 1;
+ switch (tmap)
+ {
+ case 1:
+ case 2:
+ case 3:
+ break;
+ default:
+ logerror("CPU #0 PC %06X : Blitter unknown destination: %08X\n", space.device().safe_pc(), tmap);
+ return;
+ }
+
+ while (1)
+ {
+ uint16_t b1, b2, count;
+
+ src_offs %= m_gfxrom_size;
+ b1 = m_gfxrom[src_offs];
+// logerror("CPU #0 PC %06X : Blitter opcode %02X at %06X\n", space.device().safe_pc(), b1, src_offs);
+ src_offs++;
+
+ count = ((~b1) & 0x3f) + 1;
+
+ switch ((b1 & 0xc0) >> 6)
+ {
+ case 0:
+ /* Stop and Generate an IRQ. We can't generate it now
+ both because it's unlikely that the blitter is so
+ fast and because some games (e.g. lastfort) need to
+ complete the blitter irq service routine before doing
+ another blit. */
+ if (b1 == 0)
+ {
+ m_blit_done_timer->adjust(attotime::from_usec(500));
+ return;
+ }
+
+ /* Copy */
+ while (count--)
+ {
+ src_offs %= m_gfxrom_size;
+ b2 = m_gfxrom[src_offs] << shift;
+ src_offs++;
+
+ dst_offs &= 0xffff;
+ blt_write(space, tmap, dst_offs, b2, mask);
+ dst_offs = ((dst_offs + 1) & (0x100 - 1)) | (dst_offs & (~(0x100 - 1)));
+ }
+ break;
+
+ case 1:
+ /* Fill with an increasing value */
+ src_offs %= m_gfxrom_size;
+ b2 = m_gfxrom[src_offs];
+ src_offs++;
+
+ while (count--)
+ {
+ dst_offs &= 0xffff;
+ blt_write(space, tmap, dst_offs, b2 << shift, mask);
+ dst_offs = ((dst_offs + 1) & (0x100 - 1)) | (dst_offs & (~(0x100 - 1)));
+ b2++;
+ }
+ break;
+
+ case 2:
+ /* Fill with a fixed value */
+ src_offs %= m_gfxrom_size;
+ b2 = m_gfxrom[src_offs] << shift;
+ src_offs++;
+
+ while (count--)
+ {
+ dst_offs &= 0xffff;
+ blt_write(space, tmap, dst_offs, b2, mask);
+ dst_offs = ((dst_offs + 1) & (0x100 - 1)) | (dst_offs & (~(0x100 - 1)));
+ }
+ break;
+
+ case 3:
+ /* Skip to the next line ?? */
+ if (b1 == 0xc0)
+ {
+ dst_offs += 0x100;
+ dst_offs &= ~(0x100 - 1);
+ dst_offs |= (0x100 - 1) & (m_blitter_regs[0x0a / 2] >> (7 + 1));
+ }
+ else
+ {
+ dst_offs += count;
+ }
+ break;
+
+ default:
+ //logerror("CPU #0 PC %06X : Blitter unknown opcode %02X at %06X\n",space.device().safe_pc(),b1,src_offs-1);
+ return;
+ }
+
+ }
+ }
+}
+
+
+
+/***************************************************************************
+ *
+ * Screen Drawing
+ *
+ ***************************************************************************/
+
+ /***************************************************************************
+
+
+ Sprites Drawing
+
+
+ Offset: Bits: Value:
+
+ 0.w fedc b--- ---- ---- Priority (0 = Max)
+ ---- -a98 7654 3210 X
+
+ 2.w fedc ba-- ---- ---- Zoom (Both X & Y)
+ ---- --98 7654 3210 Y
+
+ 4.w f--- ---- ---- ---- Flip X
+ -e-- ---- ---- ---- Flip Y
+ --dc b--- ---- ---- Size X *
+ ---- -a98 ---- ---- Size Y *
+ ---- ---- 7654 ---- Color
+ ---- ---- ---- 3210 Code High Bits **
+
+ 6.w Code Low Bits **
+
+* 8 pixel increments
+** 8x8 pixel increments
+
+***************************************************************************/
+
+void imagetek_i4100_device::draw_sprites( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect )
+{
+ uint8_t *base_gfx4 = m_expanded_gfx1.get();
+ uint8_t *base_gfx8 = m_gfxrom;
+ uint32_t gfx_size = m_gfxrom_size;
+
+ int max_x = (m_screen_xoffset+1)*2;
+ int max_y = (m_screen_yoffset+1)*2;
+ int m_sprite_xoffs = m_sprite_xoffset - (m_screen_xoffset+1);
+ int m_sprite_yoffs = m_sprite_yoffset - (m_screen_yoffset+1);
+
+ int max_sprites = m_spriteram.bytes() / 8;
+ int sprites = m_sprite_count % max_sprites;
+
+ int color_start = (m_sprite_color_code & 0x0f) << 4;
+
+ int i, j, pri;
+ static const int primask[4] = { 0x0000, 0xff00, 0xff00 | 0xf0f0, 0xff00 | 0xf0f0 | 0xcccc };
+
+ uint16_t *src;
+ int inc;
+
+ if (sprites == 0)
+ return;
+
+ for (i = 0; i < 0x20; i++)
+ {
+ if (!(m_sprite_priority & 0x8000))
+ {
+ src = m_spriteram + (sprites - 1) * (8 / 2);
+ inc = -(8 / 2);
+ } else {
+ src = m_spriteram;
+ inc = (8 / 2);
+ }
+
+ for (j = 0; j < sprites; j++)
+ {
+ int x, y, attr, code, color, flipx, flipy, zoom, curr_pri, width, height;
+
+ // Exponential zoom table extracted from daitoride
+ static const int zoomtable[0x40] =
+ { 0xAAC,0x800,0x668,0x554,0x494,0x400,0x390,0x334,
+ 0x2E8,0x2AC,0x278,0x248,0x224,0x200,0x1E0,0x1C8,
+ 0x1B0,0x198,0x188,0x174,0x164,0x154,0x148,0x13C,
+ 0x130,0x124,0x11C,0x110,0x108,0x100,0x0F8,0x0F0,
+ 0x0EC,0x0E4,0x0DC,0x0D8,0x0D4,0x0CC,0x0C8,0x0C4,
+ 0x0C0,0x0BC,0x0B8,0x0B4,0x0B0,0x0AC,0x0A8,0x0A4,
+ 0x0A0,0x09C,0x098,0x094,0x090,0x08C,0x088,0x080,
+ 0x078,0x070,0x068,0x060,0x058,0x050,0x048,0x040 };
+
+ x = src[0];
+ curr_pri = (x & 0xf800) >> 11;
+
+ if ((curr_pri == 0x1f) || (curr_pri != i))
+ {
+ src += inc;
+ continue;
+ }
+
+ pri = (m_sprite_priority & 0x0300) >> 8;
+
+ if (!(m_sprite_priority & 0x8000))
+ {
+ if (curr_pri > (m_sprite_priority & 0x1f))
+ pri = (m_sprite_priority & 0x0c00) >> 10;
+ }
+
+ y = src[1];
+ attr = src[2];
+ code = src[3];
+
+ flipx = attr & 0x8000;
+ flipy = attr & 0x4000;
+ color = (attr & 0xf0) >> 4;
+
+ zoom = zoomtable[(y & 0xfc00) >> 10] << (16 - 8);
+
+ x = (x & 0x07ff) - m_sprite_xoffs;
+ y = (y & 0x03ff) - m_sprite_yoffs;
+
+ width = (((attr >> 11) & 0x7) + 1) * 8;
+ height = (((attr >> 8) & 0x7) + 1) * 8;
+
+ uint32_t gfxstart = (8 * 8 * 4 / 8) * (((attr & 0x000f) << 16) + code);
+
+ if (m_screen_flip)
+ {
+ flipx = !flipx; x = max_x - x - width;
+ flipy = !flipy; y = max_y - y - height;
+ }
+
+ if (m_support_8bpp == true && color == 0xf) /* 8bpp */
+ {
+ /* Bounds checking */
+ if ((gfxstart + width * height - 1) >= gfx_size)
+ continue;
+
+ gfx_element gfx(m_palette, base_gfx8 + gfxstart, width, height, width, m_palette->entries(), 0, 256);
+
+ gfx.prio_zoom_transpen(bitmap,cliprect,
+ 0,
+ color_start >> 4,
+ flipx, flipy,
+ x, y,
+ zoom, zoom,
+ screen.priority(),primask[pri], 255);
+ }
+ else
+ {
+ /* Bounds checking */
+ if ((gfxstart + width / 2 * height - 1) >= gfx_size)
+ continue;
+
+ gfx_element gfx(m_palette, base_gfx4 + 2 * gfxstart, width, height, width, m_palette->entries(),0, 16);
+
+ gfx.prio_zoom_transpen(bitmap,cliprect,
+ 0,
+ color + color_start,
+ flipx, flipy,
+ x, y,
+ zoom, zoom,
+ screen.priority(),primask[pri], 15);
+ }
+
+ src += inc;
+ }
+ }
+}
+
+
+ inline uint8_t imagetek_i4100_device::get_tile_pix( uint16_t code, uint8_t x, uint8_t y, bool big, uint16_t *pix )
+{
+ int table_index;
+ uint32_t tile;
+
+ // Use code as an index into the tiles set table
+ table_index = ((code & 0x1ff0) >> 4) * 2;
+ tile = (m_tiletable[table_index + 0] << 16) + m_tiletable[table_index + 1];
+
+ if (code & 0x8000) // Special: draw a tile of a single color (i.e. not from the gfx ROMs)
+ {
+ *pix = code & 0x0fff;
+
+ if ((*pix & 0xf) != 0xf)
+ return 1;
+ else
+ return 0;
+ }
+ else if (((tile & 0x00f00000) == 0x00f00000) && (m_support_8bpp == true)) /* draw tile as 8bpp (e.g. balcube bg) */
+ {
+ gfx_element *gfx1 = m_gfxdecode->gfx(big?3:1);
+ uint32_t tile2 = big ? ((tile & 0xfffff) + 8*(code & 0xf)) :
+ ((tile & 0xfffff) + 2*(code & 0xf));
+ const uint8_t* data;
+ uint8_t flipxy = (code & 0x6000) >> 13;
+
+ if (tile2 < gfx1->elements())
+ data = gfx1->get_data(tile2);
+ else
+ {
+ *pix = 0;
+ return 0;
+ }
+
+ switch (flipxy)
+ {
+ default:
+ case 0x0: *pix = data[(y * (big?16:8)) + x]; break;
+ case 0x1: *pix = data[(((big?15:7)-y) * (big?16:8)) + x]; break;
+ case 0x2: *pix = data[(y * (big?16:8)) + ((big?15:7)-x)]; break;
+ case 0x3: *pix = data[(((big?15:7)-y) * (big?16:8)) + ((big?15:7)-x)]; break;
+ }
+
+ *pix |= ((tile & 0x0f000000) >> 24) * 0x100;
+
+ if ((*pix & 0xff) != 0xff)
+ return 1;
+ else
+ return 0;
+ }
+ else
+ {
+ gfx_element *gfx1 = m_gfxdecode->gfx(big?2:0);
+ uint32_t tile2 = big ? ((tile & 0xfffff) + 4*(code & 0xf)) :
+ ((tile & 0xfffff) + (code & 0xf));
+ const uint8_t* data;
+ uint8_t flipxy = (code & 0x6000) >> 13;
+
+ if (tile2 < gfx1->elements())
+ data = gfx1->get_data(tile2);
+ else
+ {
+ *pix = 0;
+ return 0;
+ }
+
+ switch (flipxy)
+ {
+ default:
+ case 0x0: *pix = data[(y * (big?16:8)) + x]; break;
+ case 0x1: *pix = data[(((big?15:7)-y) * (big?16:8)) + x]; break;
+ case 0x2: *pix = data[(y * (big?16:8)) + ((big?15:7)-x)]; break;
+ case 0x3: *pix = data[(((big?15:7)-y) * (big?16:8)) + ((big?15:7)-x)]; break;
+ }
+
+ *pix |= (((tile & 0x0ff00000) >> 20)) * 0x10;
+
+ if ((*pix & 0xf) != 0xf)
+ return 1;
+ else
+ return 0;
+ }
+}
+
+/***************************************************************************
+
+ Tilemaps: Tiles Set & Window
+
+ Each entry in the Tiles Set RAM uses 2 words to specify a starting
+ tile code and a color code. This adds 16 consecutive tiles with
+ that color code to the set of available tiles.
+
+ Offset: Bits: Value:
+
+ 0.w fedc ---- ---- ----
+ ---- ba98 7654 ---- Color Code*
+ ---- ---- ---- 3210 Code High Bits
+
+ 2.w Code Low Bits
+
+* 00-ff, but on later chips supporting it, xf means 256 color tile and palette x
+
+***************************************************************************/
+
+void imagetek_i4100_device::draw_tilemap( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, uint32_t flags, uint32_t pcode,
+ int sx, int sy, int wx, int wy, bool big, uint16_t *tilemapram, int layer )
+{
+ int y;
+
+ bitmap_ind8 &priority_bitmap = m_screen->priority();
+
+ int width = big ? 4096 : 2048;
+ int height = big ? 4096 : 2048;
+
+ int scrwidth = bitmap.width();
+ int scrheight = bitmap.height();
+
+ int windowwidth = width >> 2;
+ int windowheight = height >> 3;
+
+ sx += m_tilemap_scrolldx[layer] * (m_screen_flip ? 1 : -1);
+
+ for (y = 0; y < scrheight; y++)
+ {
+ int scrolly = (sy+y-wy)&(windowheight-1);
+ int x;
+ uint16_t *dst;
+ uint8_t *priority_baseaddr;
+ int srcline = (wy+scrolly)&(height-1);
+ int srctilerow = srcline >> (big ? 4 : 3);
+
+ if (!m_screen_flip)
+ {
+ dst = &bitmap.pix16(y);
+ priority_baseaddr = &priority_bitmap.pix8(y);
+
+ for (x = 0; x < scrwidth; x++)
+ {
+ int scrollx = (sx+x-wx)&(windowwidth-1);
+ int srccol = (wx+scrollx)&(width-1);
+ int srctilecol = srccol >> (big ? 4 : 3);
+ int tileoffs = srctilecol + srctilerow * BIG_NX;
+
+ uint16_t dat = 0;
+
+ uint16_t tile = tilemapram[tileoffs];
+ uint8_t draw = get_tile_pix(tile, big ? (srccol&0xf) : (srccol&0x7), big ? (srcline&0xf) : (srcline&0x7), big, &dat);
+
+ if (draw)
+ {
+ dst[x] = dat;
+ priority_baseaddr[x] = (priority_baseaddr[x] & (pcode >> 8)) | pcode;
+ }
+ }
+ }
+ else // flipped case
+ {
+ dst = &bitmap.pix16(scrheight-y-1);
+ priority_baseaddr = &priority_bitmap.pix8(scrheight-y-1);
+
+ for (x = 0; x < scrwidth; x++)
+ {
+ int scrollx = (sx+x-wx)&(windowwidth-1);
+ int srccol = (wx+scrollx)&(width-1);
+ int srctilecol = srccol >> (big ? 4 : 3);
+ int tileoffs = srctilecol + srctilerow * BIG_NX;
+
+ uint16_t dat = 0;
+
+ uint16_t tile = tilemapram[tileoffs];
+ uint8_t draw = get_tile_pix(tile, big ? (srccol&0xf) : (srccol&0x7), big ? (srcline&0xf) : (srcline&0x7), big, &dat);
+
+ if (draw)
+ {
+ dst[scrwidth-x-1] = dat;
+ priority_baseaddr[scrwidth-x-1] = (priority_baseaddr[scrwidth-x-1] & (pcode >> 8)) | pcode;
+ }
+ }
+ }
+ }
+}
+
+
+void imagetek_i4100_device::draw_layers( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int pri )
+{
+ // Draw all the layers with priority == pri
+ for (int layer = 2; layer >= 0; layer--)
+ {
+ if (pri == m_layer_priority[layer])
+ {
+ // Scroll and Window values
+ uint16_t sy = m_scroll[layer * 2 + 0]; uint16_t sx = m_scroll[layer * 2 + 1];
+ uint16_t wy = m_window[layer * 2 + 0]; uint16_t wx = m_window[layer * 2 + 1];
+
+ uint16_t *tilemapram = nullptr;
+
+ switch (layer)
+ {
+ case 0: tilemapram = m_vram_0; break;
+ case 1: tilemapram = m_vram_1; break;
+ case 2: tilemapram = m_vram_2; break;
+ }
+
+ bool big = (m_support_16x16 && m_layer_tile_select[layer]) == 1;
+
+ draw_tilemap(screen, bitmap, cliprect, 0, 1 << (3 - pri), sx, sy, wx, wy, big, tilemapram, layer);
+ }
+ }
+}
+
+
+uint32_t imagetek_i4100_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ screen.priority().fill(0, cliprect);
+
+ bitmap.fill(m_background_color, cliprect);
+
+ if (m_screen_blank == true)
+ return 0;
+
+ for (int pri = 3; pri >= 0; pri--)
+ draw_layers(screen, bitmap, cliprect, pri);
+
+ draw_sprites(screen, bitmap, cliprect);
+
+ return 0;
+}