// license:BSD-3-Clause // copyright-holders:Ernesto Corvi /******************************************************************* Namco System 1 Video Hardware *******************************************************************/ #include "emu.h" #include "includes/namcos1.h" #include "screen.h" /* video ram map 0000-1fff : scroll playfield (0) : 64*64*2 2000-3fff : scroll playfield (1) : 64*64*2 4000-5fff : scroll playfield (2) : 64*64*2 6000-6fff : scroll playfield (3) : 64*32*2 7000-700f : ? 7010-77ef : fixed playfield (4) : 36*28*2 77f0-77ff : ? 7800-780f : ? 7810-7fef : fixed playfield (5) : 36*28*2 7ff0-7fff : ? */ /* paletteram map (s1ram 0x0000-0x7fff) 0000-17ff : palette page0 : sprite 2000-37ff : palette page1 : playfield 4000-57ff : palette page2 : playfield (shadow) 6000-77ff : palette page3 : work RAM x800-x807 : CUS116 registers (visibility window) so there is just 3x0x2000 RAM, plus the CUS116 internal registers. */ /* spriteram map (s1ram 0x10000-0x10fff) 0000-07ff : work ram 0800-0fef : sprite ram : 0x10 * 127 0ff0-0fff : display control registers 1000-1fff : playfield control registers */ /*************************************************************************** Callbacks for the TileMap code ***************************************************************************/ void namcos1_state::TilemapCB(u16 code, int *tile, int *mask) { code &= 0x3fff; *tile = code; *mask = code; } /*************************************************************************** Start the video hardware emulation. ***************************************************************************/ void namcos1_state::video_start() { int i; /* set table for sprite color == 0x7f */ for (i = 0;i < 15;i++) m_drawmode_table[i] = DRAWMODE_SHADOW; m_drawmode_table[15] = DRAWMODE_NONE; /* all palette entries are not affected by shadow sprites... */ for (i = 0;i < 0x2000;i++) m_c116->shadow_table()[i] = i; /* ... except for tilemap colors */ for (i = 0x0800;i < 0x1000;i++) m_c116->shadow_table()[i] = i + 0x0800; m_copy_sprites = false; save_item(NAME(m_copy_sprites)); } /*************************************************************************** Memory handlers ***************************************************************************/ void namcos1_state::spriteram_w(offs_t offset, u8 data) { /* 0000-07ff work ram */ /* 0800-0fff sprite ram */ m_spriteram[offset] = data; /* a write to this offset tells the sprite chip to buffer the sprite list */ if (offset == 0x0ff2) m_copy_sprites = true; } /*************************************************************************** Display refresh ***************************************************************************/ /* sprite format: 0-3 scratchpad RAM 4-9 CPU writes here, hardware copies from here to 10-15 10 xx------ X size (16, 8, 32, 4) 10 --x----- X flip 10 ---xx--- X offset inside 32x32 tile 10 -----xxx tile bank 11 xxxxxxxx tile number 12 xxxxxxx- color 12 -------x X position MSB 13 xxxxxxxx X position 14 xxx----- priority 14 ---xx--- Y offset inside 32x32 tile 14 -----xx- Y size (16, 8, 32, 4) 14 -------x Y flip 15 xxxxxxxx Y position */ void namcos1_state::draw_sprites(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { u8 *spriteram = m_spriteram + 0x800; const u8 *source = &spriteram[0x800-0x20]; /* the last is NOT a sprite */ const u8 *finish = &spriteram[0]; gfx_element *gfx = m_gfxdecode->gfx(0); const int sprite_xoffs = spriteram[0x07f5] + ((spriteram[0x07f4] & 1) << 8); const int sprite_yoffs = spriteram[0x07f7]; while (source >= finish) { static const int sprite_size[4] = { 16, 8, 32, 4 }; const u8 attr1 = source[10]; const u8 attr2 = source[14]; u32 color = source[12]; int flipx = (attr1 & 0x20) >> 5; int flipy = (attr2 & 0x01); const u16 sizex = sprite_size[(attr1 & 0xc0) >> 6]; const u16 sizey = sprite_size[(attr2 & 0x06) >> 1]; const u16 tx = (attr1 & 0x18) & (~(sizex - 1)); const u16 ty = (attr2 & 0x18) & (~(sizey - 1)); int sx = source[13] + ((color & 0x01) << 8); int sy = -source[15] - sizey; u32 sprite = source[11]; const u32 sprite_bank = attr1 & 7; const int priority = (source[14] & 0xe0) >> 5; const u8 pri_mask = (0xff << (priority + 1)) & 0xff; sprite += sprite_bank * 256; color = color >> 1; sx += sprite_xoffs; sy -= sprite_yoffs; if (flip_screen()) { sx = -sx - sizex; sy = -sy - sizey; flipx ^= 1; flipy ^= 1; } sy++; /* sprites are buffered and delayed by one scanline */ gfx->set_source_clip(tx, sizex, ty, sizey); if (color != 0x7f) gfx->prio_transpen(bitmap,cliprect, sprite, color, flipx,flipy, sx & 0x1ff, ((sy + 16) & 0xff) - 16, screen.priority(), pri_mask, 0xf); else gfx->prio_transtable(bitmap,cliprect, sprite, color, flipx,flipy, sx & 0x1ff, ((sy + 16) & 0xff) - 16, screen.priority(), pri_mask, m_drawmode_table); source -= 0x10; } } u32 namcos1_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect) { int i; rectangle new_clip = cliprect; /* flip screen is embedded in the sprite control registers */ flip_screen_set(m_spriteram[0x0ff6] & 1); /* background color */ bitmap.fill(m_c116->black_pen(), cliprect); /* berabohm uses asymmetrical visibility windows to iris on the character */ i = m_c116->get_reg(0) - 1; // min x if (new_clip.min_x < i) new_clip.min_x = i; i = m_c116->get_reg(1) - 1 - 1; // max x if (new_clip.max_x > i) new_clip.max_x = i; i = m_c116->get_reg(2) - 0x11; // min y if (new_clip.min_y < i) new_clip.min_y = i; i = m_c116->get_reg(3) - 0x11 - 1; // max y if (new_clip.max_y > i) new_clip.max_y = i; if (new_clip.empty()) return 0; m_c123tmap->init_scroll(flip_screen()); screen.priority().fill(0, new_clip); /* bit 0-2 priority */ /* bit 3 disable */ for (int priority = 0; priority < 8; priority++) { m_c123tmap->draw(screen, bitmap, new_clip, priority, priority, 0); } draw_sprites(screen, bitmap, new_clip); return 0; } WRITE_LINE_MEMBER(namcos1_state::screen_vblank) { // rising edge if (state) { if (m_copy_sprites) { u8 *spriteram = m_spriteram + 0x800; for (int i = 0; i < 0x800; i += 16) { for (int j = 10; j < 16; j++) spriteram[i + j] = spriteram[i + j - 6]; } m_copy_sprites = false; } m_maincpu->set_input_line(M6809_IRQ_LINE, ASSERT_LINE); m_subcpu->set_input_line(M6809_IRQ_LINE, ASSERT_LINE); m_audiocpu->set_input_line(M6809_IRQ_LINE, ASSERT_LINE); m_mcu->set_input_line(HD6301_IRQ_LINE, ASSERT_LINE); } }