summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/video/seta2.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/video/seta2.cpp')
-rw-r--r--src/mame/video/seta2.cpp397
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());
}
}