diff options
Diffstat (limited to 'src/mame/video/tc0180vcu.cpp')
-rw-r--r-- | src/mame/video/tc0180vcu.cpp | 390 |
1 files changed, 328 insertions, 62 deletions
diff --git a/src/mame/video/tc0180vcu.cpp b/src/mame/video/tc0180vcu.cpp index 7d8fb28d2e0..c6d2d339787 100644 --- a/src/mame/video/tc0180vcu.cpp +++ b/src/mame/video/tc0180vcu.cpp @@ -1,31 +1,71 @@ // license:BSD-3-Clause // copyright-holders:Nicola Salmoria /* Taito TC0180VCU */ +// Sprite/Framebuffer emulation by Jarek Burczynski (from taito_b.cpp) #include "emu.h" #include "tc0180vcu.h" #include "screen.h" -#define TC0180VCU_RAM_SIZE 0x10000 -#define TC0180VCU_SCROLLRAM_SIZE 0x0800 +//#define TC0180VCU_RAM_SIZE 0x10000 +//#define TC0180VCU_SCROLLRAM_SIZE 0x0800 +const gfx_layout tc0180vcu_device::charlayout = +{ + 8,8, + RGN_FRAC(1,2), + 4, + { 0, 8, RGN_FRAC(1,2), RGN_FRAC(1,2)+8 }, + { STEP8(0,1) }, + { STEP8(0,8*2) }, + 16*8 +}; + +const gfx_layout tc0180vcu_device::tilelayout = +{ + 16,16, + RGN_FRAC(1,2), + 4, + { 0, 8, RGN_FRAC(1,2), RGN_FRAC(1,2)+8 }, + { STEP8(0,1), STEP8(8*8*2,1) }, + { STEP8(0,8*2), STEP8(8*8*2*2,8*2) }, + 64*8 +}; + +GFXDECODE_MEMBER( tc0180vcu_device::gfxinfo ) + GFXDECODE_DEVICE( DEVICE_SELF, 0, charlayout, 0, 256 ) + GFXDECODE_DEVICE( DEVICE_SELF, 0, tilelayout, 0, 256 ) +GFXDECODE_END + +void tc0180vcu_device::tc0180vcu_memrw(address_map &map) +{ + map(0x00000, 0x0ffff).ram().w(FUNC(tc0180vcu_device::word_w)).share("vram"); + map(0x10000, 0x1197f).ram().share("spriteram"); + map(0x11980, 0x137ff).ram(); + map(0x13800, 0x13fff).ram().share("scrollram"); + map(0x18000, 0x1801f).ram().w(FUNC(tc0180vcu_device::ctrl_w)).share("ctrl"); + map(0x40000, 0x7ffff).rw(FUNC(tc0180vcu_device::framebuffer_word_r), FUNC(tc0180vcu_device::framebuffer_word_w)); +} DEFINE_DEVICE_TYPE(TC0180VCU, tc0180vcu_device, "tc0180vcu", "Taito TC0180VCU") -tc0180vcu_device::tc0180vcu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, TC0180VCU, tag, owner, clock), +tc0180vcu_device::tc0180vcu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, TC0180VCU, tag, owner, clock), + device_gfx_interface(mconfig, *this, gfxinfo), device_video_interface(mconfig, *this), - m_ram(nullptr), - //m_scrollram(nullptr), + m_spriteram(*this, "spriteram"), + m_vram(*this, "vram"), + m_scrollram(*this, "scrollram"), + m_ctrl(*this, "ctrl"), //m_bg_rambank(0), //m_fg_rambank(0), //m_tx_rambank(0), m_framebuffer_page(0), m_video_control(0), + m_fb_color_base(0), m_bg_color_base(0), m_fg_color_base(0), m_tx_color_base(0), - m_gfxdecode(*this, finder_base::DUMMY_TAG), m_inth_callback(*this), m_intl_callback(*this), m_intl_timer(nullptr) @@ -50,25 +90,19 @@ void tc0180vcu_device::device_resolve_objects() void tc0180vcu_device::device_start() { - if(!m_gfxdecode->started()) - throw device_missing_dependencies(); - - m_tilemap[0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(tc0180vcu_device::get_bg_tile_info),this), TILEMAP_SCAN_ROWS, 16, 16, 64, 64); - m_tilemap[1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(tc0180vcu_device::get_fg_tile_info),this), TILEMAP_SCAN_ROWS, 16, 16, 64, 64); - m_tilemap[2] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(tc0180vcu_device::get_tx_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 64, 32); + m_tilemap[0] = &machine().tilemap().create(*this, tilemap_get_info_delegate(FUNC(tc0180vcu_device::get_bg_tile_info),this), TILEMAP_SCAN_ROWS, 16, 16, 64, 64); + m_tilemap[1] = &machine().tilemap().create(*this, tilemap_get_info_delegate(FUNC(tc0180vcu_device::get_fg_tile_info),this), TILEMAP_SCAN_ROWS, 16, 16, 64, 64); + m_tilemap[2] = &machine().tilemap().create(*this, tilemap_get_info_delegate(FUNC(tc0180vcu_device::get_tx_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 64, 32); m_tilemap[1]->set_transparent_pen(0); m_tilemap[2]->set_transparent_pen(0); - m_ram = make_unique_clear<uint16_t[]>(TC0180VCU_RAM_SIZE / 2); - m_scrollram = make_unique_clear<uint16_t[]>(TC0180VCU_SCROLLRAM_SIZE / 2); + m_framebuffer[0] = std::make_unique<bitmap_ind16>(512, 256); + m_framebuffer[1] = std::make_unique<bitmap_ind16>(512, 256); screen().register_vblank_callback(vblank_state_delegate(&tc0180vcu_device::vblank_callback, this)); m_intl_timer = timer_alloc(TIMER_INTL); - save_pointer(NAME(m_ram.get()), TC0180VCU_RAM_SIZE / 2); - save_pointer(NAME(m_scrollram.get()), TC0180VCU_SCROLLRAM_SIZE / 2); - save_item(NAME(m_bg_rambank)); save_item(NAME(m_fg_rambank)); save_item(NAME(m_tx_rambank)); @@ -76,7 +110,9 @@ void tc0180vcu_device::device_start() save_item(NAME(m_framebuffer_page)); save_item(NAME(m_video_control)); - save_item(NAME(m_ctrl)); + + save_item(NAME(*m_framebuffer[0])); + save_item(NAME(*m_framebuffer[1])); } //------------------------------------------------- @@ -187,21 +223,6 @@ void tc0180vcu_device::device_timer(emu_timer &timer, device_timer_id id, int pa * */ -READ8_MEMBER( tc0180vcu_device::get_fb_page ) -{ - return m_framebuffer_page; -} - -WRITE8_MEMBER( tc0180vcu_device::set_fb_page ) -{ - m_framebuffer_page = data; -} - -READ8_MEMBER( tc0180vcu_device::get_videoctrl ) -{ - return m_video_control; -} - void tc0180vcu_device::video_control( uint8_t data ) { #if 0 @@ -212,23 +233,18 @@ void tc0180vcu_device::video_control( uint8_t data ) m_video_control = data; if (m_video_control & 0x80) - m_framebuffer_page = (~m_video_control & 0x40) >> 6; + m_framebuffer_page = BIT(~m_video_control, 6); machine().tilemap().set_flip_all((m_video_control & 0x10) ? (TILEMAP_FLIPX | TILEMAP_FLIPY) : 0 ); } -READ16_MEMBER( tc0180vcu_device::ctrl_r ) -{ - return m_ctrl[offset]; -} - WRITE16_MEMBER( tc0180vcu_device::ctrl_w ) { uint16_t oldword = m_ctrl[offset]; COMBINE_DATA (&m_ctrl[offset]); - if (oldword != m_ctrl[offset]) + if (oldword ^ m_ctrl[offset]) { if (ACCESSING_BITS_8_15) { @@ -262,10 +278,29 @@ WRITE16_MEMBER( tc0180vcu_device::ctrl_w ) } } +READ16_MEMBER(tc0180vcu_device::framebuffer_word_r) +{ + int sy = offset >> 8; + int sx = 2 * (offset & 0xff); + + return (m_framebuffer[sy >> 8]->pix16(sy & 0xff, sx + 0) << 8) | m_framebuffer[sy >> 8]->pix16(sy & 0xff, sx + 1); +} + +WRITE16_MEMBER(tc0180vcu_device::framebuffer_word_w) +{ + int sy = offset >> 8; + int sx = 2 * (offset & 0xff); + + if (ACCESSING_BITS_8_15) + m_framebuffer[sy >> 8]->pix16(sy & 0xff, sx + 0) = data >> 8; + if (ACCESSING_BITS_0_7) + m_framebuffer[sy >> 8]->pix16(sy & 0xff, sx + 1) = data & 0xff; +} + TILE_GET_INFO_MEMBER(tc0180vcu_device::get_bg_tile_info) { - int tile = m_ram[tile_index + m_bg_rambank[0]]; - int color = m_ram[tile_index + m_bg_rambank[1]]; + int tile = m_vram[tile_index + m_bg_rambank[0]]; + int color = m_vram[tile_index + m_bg_rambank[1]]; SET_TILE_INFO_MEMBER(1, tile, m_bg_color_base + (color & 0x3f), @@ -274,8 +309,8 @@ TILE_GET_INFO_MEMBER(tc0180vcu_device::get_bg_tile_info) TILE_GET_INFO_MEMBER(tc0180vcu_device::get_fg_tile_info) { - int tile = m_ram[tile_index + m_fg_rambank[0]]; - int color = m_ram[tile_index + m_fg_rambank[1]]; + int tile = m_vram[tile_index + m_fg_rambank[0]]; + int color = m_vram[tile_index + m_fg_rambank[1]]; SET_TILE_INFO_MEMBER(1, tile, m_fg_color_base + (color & 0x3f), @@ -284,7 +319,7 @@ TILE_GET_INFO_MEMBER(tc0180vcu_device::get_fg_tile_info) TILE_GET_INFO_MEMBER(tc0180vcu_device::get_tx_tile_info) { - int tile = m_ram[tile_index + m_tx_rambank]; + int tile = m_vram[tile_index + m_tx_rambank]; SET_TILE_INFO_MEMBER(0, (tile & 0x07ff) | ((m_ctrl[4 + ((tile & 0x800) >> 11)]>>8) << 11), @@ -292,24 +327,9 @@ TILE_GET_INFO_MEMBER(tc0180vcu_device::get_tx_tile_info) 0); } -READ16_MEMBER( tc0180vcu_device::scroll_r ) -{ - return m_scrollram[offset]; -} - -WRITE16_MEMBER( tc0180vcu_device::scroll_w ) -{ - COMBINE_DATA(&m_scrollram[offset]); -} - -READ16_MEMBER( tc0180vcu_device::word_r ) -{ - return m_ram[offset]; -} - WRITE16_MEMBER( tc0180vcu_device::word_w ) { - COMBINE_DATA(&m_ram[offset]); + COMBINE_DATA(&m_vram[offset]); if ((offset & 0x7000) == m_fg_rambank[0] || (offset & 0x7000) == m_fg_rambank[1]) m_tilemap[1]->mark_tile_dirty(offset & 0x0fff); @@ -368,3 +388,249 @@ void tc0180vcu_device::tilemap_draw( screen_device &screen, bitmap_ind16 &bitmap } } } + +void tc0180vcu_device::draw_sprites( bitmap_ind16 &bitmap, const rectangle &cliprect ) +{ +/* Sprite format: (16 bytes per sprite) + offs: bits: + 0000: 0xxxxxxxxxxxxxxx: tile code - 0x0000 to 0x7fff in qzshowby + 0002: 0000000000xxxxxx: color (0x00 - 0x3f) + x000000000000000: flipy + 0x00000000000000: flipx + 00????????000000: unused ? + 0004: xxxxxx0000000000: doesn't matter - some games (eg nastar) fill this with sign bit, some (eg ashura) do not + 000000xxxxxxxxxx: x-coordinate 10 bits signed (all zero for sprites forming up a big sprite, except for the first one) + 0006: xxxxxx0000000000: doesn't matter - same as x + 000000xxxxxxxxxx: y-coordinate 10 bits signed (same as x) + 0008: xxxxxxxx00000000: sprite x-zoom level + 00000000xxxxxxxx: sprite y-zoom level + 0x00 - non scaled = 100% + 0x80 - scaled to 50% + 0xc0 - scaled to 25% + 0xe0 - scaled to 12.5% + 0xff - scaled to zero pixels size (off) + Sprite zoom is used in Ashura Blaster just in the beginning + where you can see a big choplifter and a japanese title. + This japanese title is a scaled sprite. + It is used in Crime City also at the end of the third level (in the garage) + where there are four columns on the sides of the screen + Heaviest usage is in Rambo 3 - almost every sprite in game is scaled + 000a: xxxxxxxx00000000: x-sprites number (big sprite) decremented by one + 00000000xxxxxxxx: y-sprites number (big sprite) decremented by one + 000c - 000f: unused +*/ + + int x, y, xlatch = 0, ylatch = 0, x_no = 0, y_no = 0, x_num = 0, y_num = 0, big_sprite = 0; + int offs, code, color, flipx, flipy; + uint32_t data, zoomx, zoomy, zx, zy, zoomxlatch = 0, zoomylatch = 0; + + for (offs = (0x1980 - 16) / 2; offs >=0; offs -= 8) + { + code = m_spriteram[offs]; + + color = m_spriteram[offs + 1]; + flipx = color & 0x4000; + flipy = color & 0x8000; +#if 0 + /*check the unknown bits*/ + if (color & 0x3fc0) + { + logerror("sprite color (taitob)=%4x ofs=%4x\n", color, offs); + color = machine().rand() & 0x3f; + } +#endif + color = (color & 0x3f) * 16; + + x = m_spriteram[offs + 2] & 0x3ff; + y = m_spriteram[offs + 3] & 0x3ff; + if (x >= 0x200) x -= 0x400; + if (y >= 0x200) y -= 0x400; + + data = m_spriteram[offs + 5]; + if (data) + { + if (!big_sprite) + { + x_num = (data >> 8) & 0xff; + y_num = (data >> 0) & 0xff; + x_no = 0; + y_no = 0; + xlatch = x; + ylatch = y; + data = m_spriteram[offs + 4]; + zoomxlatch = (data >> 8) & 0xff; + zoomylatch = (data >> 0) & 0xff; + big_sprite = 1; + } + } + + data = m_spriteram[offs + 4]; + zoomx = (data >> 8) & 0xff; + zoomy = (data >> 0) & 0xff; + zx = (0x100 - zoomx) / 16; + zy = (0x100 - zoomy) / 16; + + if (big_sprite) + { + zoomx = zoomxlatch; + zoomy = zoomylatch; + + /* Note: like taito_f2.cpp, this zoom implementation is wrong, + chopped up into 16x16 sections instead of one sprite. This + is especially visible in rambo3. */ + + x = xlatch + (x_no * (0xff - zoomx) + 15) / 16; + y = ylatch + (y_no * (0xff - zoomy) + 15) / 16; + zx = xlatch + ((x_no + 1) * (0xff - zoomx) + 15) / 16 - x; + zy = ylatch + ((y_no + 1) * (0xff - zoomy) + 15) / 16 - y; + y_no++; + + if (y_no > y_num) + { + y_no = 0; + x_no++; + + if (x_no > x_num) + big_sprite = 0; + } + } + + if ( zoomx || zoomy ) + { + gfx(1)->zoom_transpen_raw(bitmap,cliprect, + code, + color, + flipx,flipy, + x,y, + (zx << 16) / 16,(zy << 16) / 16,0); + } + else + { + gfx(1)->transpen_raw(bitmap,cliprect, + code, + color, + flipx,flipy, + x,y, + 0); + } + } +} + +void tc0180vcu_device::draw_framebuffer( bitmap_ind16 &bitmap, const rectangle &cliprect, int priority ) +{ + rectangle myclip = cliprect; + int x, y; + +g_profiler.start(PROFILER_USER1); + + priority <<= 4; + + if (m_video_control & 0x08) + { + if (priority) + { + g_profiler.stop(); + return; + } + + if (m_video_control & 0x10) /*flip screen*/ + { + /*popmessage("1. X[%3i;%3i] Y[%3i;%3i]", myclip.min_x, myclip.max_x, myclip.min_y, myclip.max_y);*/ + for (y = myclip.min_y; y <= myclip.max_y; y++) + { + uint16_t *src = &m_framebuffer[m_framebuffer_page]->pix16(y, myclip.min_x); + uint16_t *dst; + + dst = &bitmap.pix16(bitmap.height()-1-y, myclip.max_x); + + for (x = myclip.min_x; x <= myclip.max_x; x++) + { + uint16_t c = *src++; + + if (c != 0) + *dst = m_fb_color_base + c; + + dst--; + } + } + } + else + { + for (y = myclip.min_y; y <= myclip.max_y; y++) + { + uint16_t *src = &m_framebuffer[m_framebuffer_page]->pix16(y, myclip.min_x); + uint16_t *dst = &bitmap.pix16(y, myclip.min_x); + + for (x = myclip.min_x; x <= myclip.max_x; x++) + { + uint16_t c = *src++; + + if (c != 0) + *dst = m_fb_color_base + c; + + dst++; + } + } + } + } + else + { + if (m_video_control & 0x10) /*flip screen*/ + { + /*popmessage("3. X[%3i;%3i] Y[%3i;%3i]", myclip.min_x, myclip.max_x, myclip.min_y, myclip.max_y);*/ + for (y = myclip.min_y ;y <= myclip.max_y; y++) + { + uint16_t *src = &m_framebuffer[m_framebuffer_page]->pix16(y, myclip.min_x); + uint16_t *dst; + + dst = &bitmap.pix16(bitmap.height()-1-y, myclip.max_x); + + for (x = myclip.min_x; x <= myclip.max_x; x++) + { + uint16_t c = *src++; + + if (c != 0 && (c & 0x10) == priority) + *dst = m_fb_color_base + c; + + dst--; + } + } + } + else + { + for (y = myclip.min_y; y <= myclip.max_y; y++) + { + uint16_t *src = &m_framebuffer[m_framebuffer_page]->pix16(y, myclip.min_x); + uint16_t *dst = &bitmap.pix16(y, myclip.min_x); + + for (x = myclip.min_x; x <= myclip.max_x; x++) + { + uint16_t c = *src++; + + if (c != 0 && (c & 0x10) == priority) + *dst = m_fb_color_base + c; + + dst++; + } + } + } + } +g_profiler.stop(); +} + +WRITE_LINE_MEMBER(tc0180vcu_device::screen_vblank) +{ + // rising edge + if (state) + { + if (~m_video_control & 0x01) + m_framebuffer[m_framebuffer_page]->fill(0, screen().visible_area()); + + if (~m_video_control & 0x80) + { + m_framebuffer_page ^= 1; + } + + draw_sprites(*m_framebuffer[m_framebuffer_page], screen().visible_area()); + } +} |