diff options
Diffstat (limited to 'src/mame/video/seta2.cpp')
-rw-r--r-- | src/mame/video/seta2.cpp | 397 |
1 files changed, 260 insertions, 137 deletions
diff --git a/src/mame/video/seta2.cpp b/src/mame/video/seta2.cpp index 28e098a9226..be5f59e7009 100644 --- a/src/mame/video/seta2.cpp +++ b/src/mame/video/seta2.cpp @@ -17,7 +17,7 @@ Offset: Bits: Value: 0.w f--- ---- ---- ---- Last sprite - -e-- ---- ---- ---- ? + -e-- ---- ---- ---- ? (ignore global offsets, zooming etc. used on frame of map in grdians) --d- ---- ---- ---- Opaque ---c ---- ---- ---- 0 = Each sprite specifies its size, 1 = Use the global size (following words) ---- b--- ---- ---- Shadow @@ -99,7 +99,9 @@ 1c Zoom Y? low bits 1e Zoom Y? high bits * + 24 1->0 in funcube3 and staraudi 26 1->0 during INT0, before writing sprites + (probably creates a custom format sprite list at 0x0000 by processing the list at 0x3000) 30 fedc ba98 7654 321- ---- ---- ---- ---0 Disable video @@ -111,51 +113,131 @@ ***************************************************************************/ +/*************************************************************************** + + NON-BUGS + + grdians : After the fire rowscroll effect in the intro there is a small artifact + left scrolling at the top of the screen when the next image is displayed + See 4:24 in https://www.youtube.com/watch?v=cvHGFEsB_cM + +***************************************************************************/ + WRITE16_MEMBER(seta2_state::vregs_w) { /* 02/04 = horizontal display start/end - mj4simai = 0065/01E5 (0180 visible area) - myangel = 005D/01D5 (0178 visible area) - pzlbowl = 0058/01D8 (0180 visible area) - penbros = 0065/01A5 (0140 visible area) - grdians = 0059/0188 (012f visible area) + mj4simai = 0065/01E5 (0180 visible area) + myangel = 005D/01D5 (0178 visible area) + pzlbowl = 0058/01D8 (0180 visible area) + penbros = 0065/01A5 (0140 visible area) + grdians = 0059/0188 (012f visible area) 06 = horizontal total? - mj4simai = 0204 - myangel = 0200 - pzlbowl = 0204 - penbros = 01c0 - grdians = 019a + mj4simai = 0204 + myangel = 0200 + pzlbowl = 0204 + penbros = 01c0 + grdians = 019a */ uint16_t olddata = m_vregs[offset]; COMBINE_DATA(&m_vregs[offset]); - if ( m_vregs[offset] != olddata ) - logerror("CPU #0 PC %06X: Video Reg %02X <- %04X\n",m_maincpu->pc(),offset*2,data); + if (m_vregs[offset] != olddata) + logerror("CPU #0 PC %06X: Video Reg %02X <- %04X\n", m_maincpu->pc(), offset * 2, data); - switch( offset*2 ) + switch (offset * 2) { + case 0x1a: + logerror("%s: Register 1a write (vertical offset?) %04X (%04x)\n", machine().describe_context(), data, mem_mask); + break; + case 0x1c: // FLIP SCREEN (myangel) <- this is actually zoom - flip_screen_set(data & 1 ); - if (data & ~1) logerror("CPU #0 PC %06X: flip screen unknown bits %04X\n",m_maincpu->pc(),data); + flip_screen_set(data & 1); + if (data & ~1) logerror("CPU #0 PC %06X: flip screen unknown bits %04X\n", m_maincpu->pc(), data); break; case 0x2a: // FLIP X (pzlbowl) - flip_screen_x_set(data & 1 ); - if (data & ~1) logerror("CPU #0 PC %06X: flipx unknown bits %04X\n",m_maincpu->pc(),data); + flip_screen_x_set(data & 1); + if (data & ~1) logerror("CPU #0 PC %06X: flipx unknown bits %04X\n", m_maincpu->pc(), data); break; case 0x2c: // FLIP Y (pzlbowl) - flip_screen_y_set(data & 1 ); - if (data & ~1) logerror("CPU #0 PC %06X: flipy unknown bits %04X\n",m_maincpu->pc(),data); + flip_screen_y_set(data & 1); + if (data & ~1) logerror("CPU #0 PC %06X: flipy unknown bits %04X\n", m_maincpu->pc(), data); break; case 0x30: // BLANK SCREEN (pzlbowl, myangel) - if (data & ~1) logerror("CPU #0 PC %06X: blank unknown bits %04X\n",m_maincpu->pc(),data); + if (data & ~1) logerror("CPU #0 PC %06X: blank unknown bits %04X\n", m_maincpu->pc(), data); + break; + + case 0x24: // funcube3 and staraudi write here instead, why? mirror or different meaning? + case 0x26: // something display list related? buffering control? + if (data) + { + // Buffer sprites by 1 frame + //memcpy(m_buffered_spriteram.get(), m_spriteram, m_spriteram.bytes()); + + /* copy the base spritelist to a private (non-CPU visible buffer) + copy the indexed sprites to 0 in spriteram, adjusting pointers in base sprite list as appropriate + this at least gets the sprite data in the right place for the grdians raster effect to write the + changed scroll values to the correct sprites, but is still nothing more than a guess + */ + int current_sprite_entry = 0; + + for (int i = 0; i < 0x1000 / 2; i += 4) + { + uint16_t num = m_private_spriteram[i + 0] = m_spriteram[(0x3000 / 2) + i + 0]; + m_private_spriteram[i + 1] = m_spriteram[(0x3000 / 2) + i + 1]; + m_private_spriteram[i + 2] = m_spriteram[(0x3000 / 2) + i + 2]; + + int sprite = m_spriteram[(0x3000 / 2) + i + 3]; + m_private_spriteram[i + 3] = ((current_sprite_entry / 4) & 0x7fff) | (sprite & 0x8000); + + int list2addr = (sprite & 0x7fff) * 4; + + num &=0xff; + + for (int j = 0; j <= num; j++) + { + if (current_sprite_entry < 0x3000 / 2) + { + m_spriteram[current_sprite_entry + 0] = m_spriteram[(list2addr + (j * 4) + 0) & 0x1ffff]; + m_spriteram[current_sprite_entry + 1] = m_spriteram[(list2addr + (j * 4) + 1) & 0x1ffff]; + m_spriteram[current_sprite_entry + 2] = m_spriteram[(list2addr + (j * 4) + 2) & 0x1ffff]; + m_spriteram[current_sprite_entry + 3] = m_spriteram[(list2addr + (j * 4) + 3) & 0x1ffff]; + current_sprite_entry += 4; + } + } + + if (m_private_spriteram[i + 0] & 0x8000) // end of list marker, mj4simai must draw the sprite this covers for the company logo, title screen etc. + { + // HACK: however penbros has a dummy sprite entry there which points to 0x0000 as the tile source, and causes garbage with the rearranged format, + // so change it to something that's invalid where we can filter it later. This strongly indicates that the current approach is incorrect however. + if (sprite == 0x00) + { + m_private_spriteram[i + 3] |= 0x4000; + } + + break; + } + } + + } break; case 0x3c: // Raster IRQ related - //logerror("%s: Register 3c write (raster enable?) %04X (%04x)\n",machine().describe_context(),data, mem_mask); + //logerror("%s: Register 3c write (raster enable?) current vpos is %d : %04X (%04x)\n",machine().describe_context(),m_screen->vpos(), data, mem_mask); COMBINE_DATA(&m_rasterenabled); - if (m_rasterenabled & 1) m_raster_timer->adjust(m_screen->time_until_pos((m_rasterposition&0x1ff)+0x80, 0), 0); + + //if (m_rasterenabled & 1) + { + int hpos = 0; + int vpos = m_rasterposition; + + // in the vblank it specifies line 0, the first raster interrupt then specifies line 0 again before the subsequent ones use the real line numbers? + // It seems more likely the the raster IRQ stays asserted for the entire line, thus triggering a second interrupt unless the line number is changed? + if (m_rasterposition == m_screen->vpos()) hpos = m_screen->hpos() + 0x100; + //logerror("setting raster to %d %d\n", vpos, hpos); + m_raster_timer->adjust(m_screen->time_until_pos(vpos, hpos), 0); + } break; case 0x3e: // Raster IRQ related @@ -165,6 +247,11 @@ WRITE16_MEMBER(seta2_state::vregs_w) } } +WRITE16_MEMBER(seta2_state::spriteram_w) +{ + COMBINE_DATA(&m_spriteram[offset]); +} + /*************************************************************************** @@ -249,23 +336,28 @@ inline void seta2_state::get_tile(uint16_t* spriteram, int is_16x16, int x, int void seta2_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect) { // Sprites list + uint16_t *spriteram = m_spriteram; + int global_yoffset = (m_vregs[0x1a/2] & 0x7ff); + if (global_yoffset & 0x400) + global_yoffset -= 0x800; + + global_yoffset += 1; + + uint16_t *s1 = m_private_spriteram; - // When debugging, use m_spriteram here, and run mame -update_in_pause, i.e.: -// uint16_t *buffered_spriteram16 = m_spriteram; - uint16_t *buffered_spriteram16 = m_buffered_spriteram.get(); - uint16_t *s1 = buffered_spriteram16 + 0x3000 / 2; - uint16_t *end = &buffered_spriteram16[m_spriteram.bytes() / 2]; // for ( ; s1 < end; s1+=4 ) - for (; s1 < buffered_spriteram16 + 0x4000 / 2; s1 += 4) // more reasonable (and it cures MAME lockup in e.g. funcube3 boot) + for (; s1 < m_private_spriteram + 0x1000 / 2; s1 += 4) // more reasonable (and it cures MAME lockup in e.g. funcube3 boot) { int num = s1[0]; + int xoffs = s1[1]; int yoffs = s1[2]; int sprite = s1[3]; // Single-sprite address - uint16_t *s2 = &buffered_spriteram16[(sprite & 0x7fff) * 4]; + uint16_t *s2 = &spriteram[(sprite & 0x7fff) * 4]; + uint16_t *end = &spriteram[m_spriteram.bytes() / 2]; // Single-sprite size int global_sizex = xoffs & 0xfc00; @@ -281,136 +373,155 @@ void seta2_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect) // Number of single-sprites num = (num & 0x00ff) + 1; - for (; num > 0; num--, s2 += 4) + // all sprites, except invalid ones should have a pointer <0x3000 in the reformatted list + if ((sprite&0x7fff) < 0x3000 / 2 / 4) { - if (s2 >= end) break; - - if (sprite & 0x8000) + for (; num > 0; num--, s2 += 4) { - // "floating tilemap" sprite - // the 'floating tilemap sprites' are just a window into the tilemap, the position of the sprite does not change the scroll values - - int sx = s2[0]; - int sy = s2[1]; - int scrollx = s2[2]; - int scrolly = s2[3]; - int is_16x16 = (scrollx & 0x8000) >> 15; - int page = (scrollx & 0x7c00) >> 10; - int local_sizex = sx & 0xfc00; - int local_sizey = sy & 0xfc00; - sx &= 0x3ff; - sy &= 0x1ff; - - int width = use_global_size ? global_sizex : local_sizex; - int height = use_global_size ? global_sizey : local_sizey; - - height = ((height & 0xfc00) >> 10) + 1; - width = ((width & 0xfc00) >> 10)/* + 1*/; // reelquak reels - if (!width) - continue; - - scrollx += m_xoffset; - scrollx &= 0x3ff; - scrolly &= 0x1ff; - - rectangle clip; - // sprite clipping region (x) - clip.min_x = (sx + xoffs) & 0x3ff; - clip.min_x = (clip.min_x & 0x1ff) - (clip.min_x & 0x200); - clip.max_x = clip.min_x + width * 0x10 - 1; - - if (clip.min_x > cliprect.max_x) continue; - if (clip.max_x < cliprect.min_x) continue; - if (clip.min_x < cliprect.min_x) clip.min_x = cliprect.min_x; - if (clip.max_x > cliprect.max_x) clip.max_x = cliprect.max_x; - - // sprite clipping region (y) - clip.min_y = ((sy + yoffs) & 0x1ff); - clip.max_y = clip.min_y + height * 0x10 - 1; - - if (clip.min_y > cliprect.max_y) continue; - if (clip.max_y < cliprect.min_y) continue; - if (clip.min_y < cliprect.min_y) clip.min_y = cliprect.min_y; - if (clip.max_y > cliprect.max_y) clip.max_y = cliprect.max_y; - - for (int realline = clip.min_y; realline <= clip.max_y; realline++) - { - int sourceline = (realline - scrolly) & 0x1ff; - - int y = sourceline >> (is_16x16 ? 4 : 3); + if (s2 >= end) break; - for (int x = 0; x < 0x40; x++) + if (sprite & 0x8000) + { + // "floating tilemap" sprite + // the 'floating tilemap sprites' are just a window into the tilemap, the position of the sprite does not change the scroll values + + int sx = s2[0]; + int sy = s2[1]; + int scrollx = s2[2]; + int scrolly = s2[3]; + int is_16x16 = (scrollx & 0x8000) >> 15; + int page = (scrollx & 0x7c00) >> 10; + int local_sizex = sx & 0xfc00; + int local_sizey = sy & 0xfc00; + sx &= 0x3ff; + sy += global_yoffset; + sy &= 0x1ff; + + if (sy & 0x100) + sy -= 0x200; + + int width = use_global_size ? global_sizex : local_sizex; + int height = use_global_size ? global_sizey : local_sizey; + + height = ((height & 0xfc00) >> 10) + 1; + width = ((width & 0xfc00) >> 10)/* + 1*/; // reelquak reels + if (!width) + continue; + + scrollx += m_xoffset; + scrollx &= 0x3ff; + scrolly &= 0x1ff; + + scrolly += global_yoffset; + + rectangle clip; + // sprite clipping region (x) + clip.min_x = (sx + xoffs) & 0x3ff; + clip.min_x = (clip.min_x & 0x1ff) - (clip.min_x & 0x200); + clip.max_x = clip.min_x + width * 0x10 - 1; + + if (clip.min_x > cliprect.max_x) continue; + if (clip.max_x < cliprect.min_x) continue; + if (clip.min_x < cliprect.min_x) clip.min_x = cliprect.min_x; + if (clip.max_x > cliprect.max_x) clip.max_x = cliprect.max_x; + + // sprite clipping region (y) + + int basey = (sy + yoffs) & 0x1ff; + if (basey & 0x100) basey -= 0x200; + + clip.min_y = basey; + clip.max_y = clip.min_y + height * 0x10 - 1; + + if (clip.min_y > cliprect.max_y) continue; + if (clip.max_y < cliprect.min_y) continue; + if (clip.min_y < cliprect.min_y) clip.min_y = cliprect.min_y; + if (clip.max_y > cliprect.max_y) clip.max_y = cliprect.max_y; + + for (int realline = clip.min_y; realline <= clip.max_y; realline++) { - int code, attr, flipx, flipy, color; - get_tile(buffered_spriteram16, is_16x16, x, y ^ 0x1f, page, code, attr, flipx, flipy, color); // yes the tilemap in RAM is flipped?! + int sourceline = (realline - scrolly) & 0x1ff; - int line = is_16x16 ? (sourceline & 0x0f) : (sourceline & 0x07); + int y = sourceline >> (is_16x16 ? 4 : 3); - int ty = (line >> 3) & 1; - line &= 0x7; - for (int tx = 0; tx <= is_16x16; tx++) + for (int x = 0; x < 0x40; x++) { - int dx = sx + (scrollx & 0x3ff) + xoffs + 0x10; - int px = ((dx + x * (8 << is_16x16) + 0x10) & 0x3ff) - 0x10; - int dst_x = (px + (flipx ? is_16x16 - tx : tx) * 8) & 0x3ff; - dst_x = (dst_x & 0x1ff) - (dst_x & 0x200); + int code, attr, flipx, flipy, color; + // tilemap data is NOT buffered? (and yes the tilemap in RAM is flipped?!) + get_tile(spriteram, is_16x16, x, y ^ 0x1f, page, code, attr, flipx, flipy, color); - if ((dst_x >= clip.min_x - 8) && (dst_x <= clip.max_x)) + int line = is_16x16 ? (sourceline & 0x0f) : (sourceline & 0x07); + + int ty = (line >> 3) & 1; + line &= 0x7; + for (int tx = 0; tx <= is_16x16; tx++) { - int realcode = code ^ tx ^ ((flipy ? is_16x16 - ty : ty) << 1); - drawgfx_line(bitmap, clip, which_gfx, m_spritegfx->get_data(m_realtilenumber[realcode]), color << 4, flipx, flipy, dst_x, use_shadow, realline, line, opaque); + int dx = sx + (scrollx & 0x3ff) + xoffs + 0x10; + int px = ((dx + x * (8 << is_16x16) + 0x10) & 0x3ff) - 0x10; + int dst_x = (px + (flipx ? is_16x16 - tx : tx) * 8) & 0x3ff; + dst_x = (dst_x & 0x1ff) - (dst_x & 0x200); + + if ((dst_x >= clip.min_x - 8) && (dst_x <= clip.max_x)) + { + int realcode = code ^ tx ^ ((flipy ? is_16x16 - ty : ty) << 1); + drawgfx_line(bitmap, clip, which_gfx, m_spritegfx->get_data(m_realtilenumber[realcode]), color << 4, flipx, flipy, dst_x, use_shadow, realline, line, opaque); + } } } } } - } - else - { - // "normal" sprite - int sx = s2[0]; - int sy = s2[1]; - int attr = s2[2]; - int code = s2[3] + ((attr & 0x0007) << 16); - int flipx = (attr & 0x0010); - int flipy = (attr & 0x0008); - int color = (attr & 0xffe0) >> 5; + else + { + // "normal" sprite + int sx = s2[0]; + int sy = s2[1]; + int attr = s2[2]; + int code = s2[3] + ((attr & 0x0007) << 16); + int flipx = (attr & 0x0010); + int flipy = (attr & 0x0008); + int color = (attr & 0xffe0) >> 5; - int sizex = use_global_size ? global_sizex : sx; - int sizey = use_global_size ? global_sizey : sy; - sizex = (1 << ((sizex & 0x0c00) >> 10)) - 1; - sizey = (1 << ((sizey & 0x0c00) >> 10)) - 1; + int sizex = use_global_size ? global_sizex : sx; + int sizey = use_global_size ? global_sizey : sy; + sizex = (1 << ((sizex & 0x0c00) >> 10)) - 1; + sizey = (1 << ((sizey & 0x0c00) >> 10)) - 1; - sx += xoffs; - sy += yoffs; + sx += xoffs; + sy += yoffs; - sx = (sx & 0x1ff) - (sx & 0x200); + sx = (sx & 0x1ff) - (sx & 0x200); - sy &= 0x1ff; + sy += global_yoffset; - int basecode = code &= ~((sizex + 1) * (sizey + 1) - 1); // see myangel, myangel2 and grdians + sy &= 0x1ff; - int firstline = sy; - int endline = (sy + (sizey + 1) * 8) - 1; + if (sy & 0x100) + sy -= 0x200; - int realfirstline = firstline; - if (firstline < cliprect.min_y) realfirstline = cliprect.min_y; - if (endline > cliprect.max_y) endline = cliprect.max_y; + int basecode = code &= ~((sizex + 1) * (sizey + 1) - 1); // see myangel, myangel2 and grdians - for (int realline = realfirstline; realline <= endline; realline++) - { - int line = realline - firstline; - int y = (line >> 3); - line &= 0x7; + int firstline = sy; + int endline = (sy + (sizey + 1) * 8) - 1; - for (int x = 0; x <= sizex; x++) + int realfirstline = firstline; + + if (firstline < cliprect.min_y) realfirstline = cliprect.min_y; + if (endline > cliprect.max_y) endline = cliprect.max_y; + + for (int realline = realfirstline; realline <= endline; realline++) { - int realcode = (basecode + (flipy ? sizey - y : y)*(sizex + 1)) + (flipx ? sizex - x : x); - drawgfx_line(bitmap, cliprect, which_gfx, m_spritegfx->get_data(m_realtilenumber[realcode]), color << 4, flipx, flipy, sx + x * 8, use_shadow, realline, line, opaque); + int line = realline - firstline; + int y = (line >> 3); + line &= 0x7; + + for (int x = 0; x <= sizex; x++) + { + int realcode = (basecode + (flipy ? sizey - y : y)*(sizex + 1)) + (flipx ? sizex - x : x); + drawgfx_line(bitmap, cliprect, which_gfx, m_spritegfx->get_data(m_realtilenumber[realcode]), color << 4, flipx, flipy, sx + x * 8, use_shadow, realline, line, opaque); + } } } - - } } if (s1[0] & 0x8000) break; // end of list marker @@ -420,9 +531,19 @@ void seta2_state::draw_sprites(bitmap_ind16 &bitmap, const rectangle &cliprect) TIMER_CALLBACK_MEMBER(seta2_state::raster_timer_done) { - + if (m_tmp68301) + { + if (m_rasterenabled & 1) + { + m_tmp68301->external_interrupt_1(); + logerror("external int (vpos is %d)\n", m_screen->vpos()); + m_screen->update_partial(m_screen->vpos() - 1); + } + } } + + /*************************************************************************** @@ -449,6 +570,8 @@ void seta2_state::video_start() } m_raster_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(seta2_state::raster_timer_done), this)); + + save_item(NAME(m_private_spriteram)); } VIDEO_START_MEMBER(seta2_state,xoffset) @@ -488,8 +611,8 @@ WRITE_LINE_MEMBER(seta2_state::screen_vblank) // rising edge if (state) { - // Buffer sprites by 1 frame - memcpy(m_buffered_spriteram.get(), m_spriteram, m_spriteram.bytes()); + // Buffer sprites by 1 frame, moved to video register 0x26, improves grdians intro there + //memcpy(m_buffered_spriteram.get(), m_spriteram, m_spriteram.bytes()); } } |