// license:BSD-3-Clause // copyright-holders:Fabio Priuli,Acho A. Tang, R. Belmont /* Konami 007342 ------ The 007342 manages 2 64x32 scrolling tilemaps with 8x8 characters, and optionally generates timing clocks and interrupt signals. It uses 0x2000 bytes of RAM, plus 0x0200 bytes for scrolling, and a variable amount of ROM. It cannot read the ROMs. control registers 000: ------x- INT control ---x---- flip screen (TODO: doesn't work with thehustl) 001: Used for banking in Rock'n'Rage 002: -------x MSB of x scroll 1 ------x- MSB of x scroll 2 ---xxx-- layer 1 row/column scroll control 000 = disabled 010 = unknown (bladestl shootout between periods) 011 = 32 columns (Blades of Steel) 101 = 256 rows (Battlantis, Rock 'n Rage) x------- enable sprite wraparound from bottom to top (see Blades of Steel high score table) 003: x scroll 1 004: y scroll 1 005: x scroll 2 006: y scroll 2 007: not used */ #include "emu.h" #include "k007342.h" #include "konami_helper.h" //#define VERBOSE 1 #include "logmacro.h" DEFINE_DEVICE_TYPE(K007342, k007342_device, "k007342", "K007342 Video Controller") k007342_device::k007342_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, K007342, tag, owner, clock), m_ram(nullptr), m_scroll_ram(nullptr), m_videoram_0(nullptr), m_videoram_1(nullptr), m_colorram_0(nullptr), m_colorram_1(nullptr), //m_tilemap[2]; m_flipscreen(0), m_int_enabled(0), //m_regs[8], //m_scrollx[2], //m_scrolly[2], m_gfxdecode(*this, finder_base::DUMMY_TAG), m_callback(*this), m_gfxnum(0) { } //------------------------------------------------- // device_start - device-specific startup //------------------------------------------------- void k007342_device::device_start() { if(!m_gfxdecode->started()) throw device_missing_dependencies(); // bind the init function m_callback.resolve(); m_tilemap[0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(k007342_device::get_tile_info0)), tilemap_mapper_delegate(*this, FUNC(k007342_device::scan)), 8, 8, 64, 32); m_tilemap[1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(*this, FUNC(k007342_device::get_tile_info1)), tilemap_mapper_delegate(*this, FUNC(k007342_device::scan)), 8, 8, 64, 32); m_ram = make_unique_clear(0x2000); m_scroll_ram = make_unique_clear(0x0200); m_colorram_0 = &m_ram[0x0000]; m_colorram_1 = &m_ram[0x1000]; m_videoram_0 = &m_ram[0x0800]; m_videoram_1 = &m_ram[0x1800]; m_tilemap[0]->set_transparent_pen(0); m_tilemap[1]->set_transparent_pen(0); save_pointer(NAME(m_ram), 0x2000); save_pointer(NAME(m_scroll_ram), 0x0200); save_item(NAME(m_int_enabled)); save_item(NAME(m_flipscreen)); save_item(NAME(m_scrollx)); save_item(NAME(m_scrolly)); save_item(NAME(m_regs)); } //------------------------------------------------- // device_reset - device-specific reset //------------------------------------------------- void k007342_device::device_reset() { int i; m_int_enabled = 0; m_flipscreen = 0; m_scrollx[0] = 0; m_scrollx[1] = 0; m_scrolly[0] = 0; m_scrolly[1] = 0; for (i = 0; i < 8; i++) m_regs[i] = 0; } /***************************************************************************** DEVICE HANDLERS *****************************************************************************/ READ8_MEMBER( k007342_device::read ) { return m_ram[offset]; } WRITE8_MEMBER( k007342_device::write ) { m_ram[offset] = data; if (offset < 0x1000) /* layer 0 */ m_tilemap[0]->mark_tile_dirty(offset & 0x7ff); else /* layer 1 */ m_tilemap[1]->mark_tile_dirty(offset & 0x7ff); } READ8_MEMBER( k007342_device::scroll_r ) { return m_scroll_ram[offset]; } WRITE8_MEMBER( k007342_device::scroll_w ) { m_scroll_ram[offset] = data; } WRITE8_MEMBER( k007342_device::vreg_w ) { switch(offset) { case 0x00: /* bit 1: INT control */ m_int_enabled = data & 0x02; m_flipscreen = data & 0x10; m_tilemap[0]->set_flip(m_flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0); m_tilemap[1]->set_flip(m_flipscreen ? (TILEMAP_FLIPY | TILEMAP_FLIPX) : 0); break; case 0x01: /* used for banking in Rock'n'Rage */ if (data != m_regs[1]) machine().tilemap().mark_all_dirty(); case 0x02: m_scrollx[0] = (m_scrollx[0] & 0xff) | ((data & 0x01) << 8); m_scrollx[1] = (m_scrollx[1] & 0xff) | ((data & 0x02) << 7); break; case 0x03: /* scroll x (register 0) */ m_scrollx[0] = (m_scrollx[0] & 0x100) | data; break; case 0x04: /* scroll y (register 0) */ m_scrolly[0] = data; break; case 0x05: /* scroll x (register 1) */ m_scrollx[1] = (m_scrollx[1] & 0x100) | data; break; case 0x06: /* scroll y (register 1) */ m_scrolly[1] = data; case 0x07: /* unused */ break; } m_regs[offset] = data; } void k007342_device::tilemap_update( ) { int offs; /* update scroll */ switch (m_regs[2] & 0x1c) { case 0x00: case 0x08: /* unknown, blades of steel shootout between periods */ m_tilemap[0]->set_scroll_rows(1); m_tilemap[0]->set_scroll_cols(1); m_tilemap[0]->set_scrollx(0, m_scrollx[0]); m_tilemap[0]->set_scrolly(0, m_scrolly[0]); break; case 0x0c: /* 32 columns */ m_tilemap[0]->set_scroll_rows(1); m_tilemap[0]->set_scroll_cols(512); m_tilemap[0]->set_scrollx(0, m_scrollx[0]); for (offs = 0; offs < 256; offs++) m_tilemap[0]->set_scrolly((offs + m_scrollx[0]) & 0x1ff, m_scroll_ram[2 * (offs / 8)] + 256 * m_scroll_ram[2 * (offs / 8) + 1]); break; case 0x14: /* 256 rows */ m_tilemap[0]->set_scroll_rows(256); m_tilemap[0]->set_scroll_cols(1); m_tilemap[0]->set_scrolly(0, m_scrolly[0]); for (offs = 0; offs < 256; offs++) m_tilemap[0]->set_scrollx((offs + m_scrolly[0]) & 0xff, m_scroll_ram[2 * offs] + 256 * m_scroll_ram[2 * offs + 1]); break; default: // popmessage("unknown scroll ctrl %02x", m_regs[2] & 0x1c); break; } m_tilemap[1]->set_scrollx(0, m_scrollx[1]); m_tilemap[1]->set_scrolly(0, m_scrolly[1]); #if 0 { static int current_layer = 0; if (machine.input().code_pressed_once(KEYCODE_Z)) current_layer = !current_layer; m_tilemap[current_layer]->enable(1); m_tilemap[!current_layer]->enable(0); popmessage("regs:%02x %02x %02x %02x-%02x %02x %02x %02x:%02x", m_regs[0], m_regs[1], m_regs[2], m_regs[3], m_regs[4], m_regs[5], m_regs[6], m_regs[7], current_layer); } #endif } void k007342_device::tilemap_draw( screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect, int num, int flags, uint32_t priority ) { m_tilemap[num]->draw(screen, bitmap, cliprect, flags, priority); } int k007342_device::is_int_enabled( ) { return m_int_enabled; } /*************************************************************************** Callbacks for the TileMap code ***************************************************************************/ /* data format: video RAM xxxxxxxx tile number (bits 0-7) color RAM x------- tiles with priority over the sprites color RAM -x------ depends on external conections color RAM --x----- flip Y color RAM ---x---- flip X color RAM ----xxxx depends on external connections (usually color and banking) */ TILEMAP_MAPPER_MEMBER(k007342_device::scan) { /* logical (col,row) -> memory offset */ return (col & 0x1f) + ((row & 0x1f) << 5) + ((col & 0x20) << 5); } void k007342_device::get_tile_info( tile_data &tileinfo, int tile_index, int layer, uint8_t *cram, uint8_t *vram ) { int color, code, flags; color = cram[tile_index]; code = vram[tile_index]; flags = TILE_FLIPYX((color & 0x30) >> 4); tileinfo.category = (color & 0x80) >> 7; if (!m_callback.isnull()) m_callback(layer, m_regs[1], &code, &color, &flags); SET_TILE_INFO_MEMBER(m_gfxnum, code, color, flags); } TILE_GET_INFO_MEMBER(k007342_device::get_tile_info0) { get_tile_info(tileinfo, tile_index, 0, m_colorram_0, m_videoram_0); } TILE_GET_INFO_MEMBER(k007342_device::get_tile_info1) { get_tile_info(tileinfo, tile_index, 1, m_colorram_1, m_videoram_1); }