x68k: fix 512 line double scan modes

This commit is contained in:
cracyc 2021-05-28 17:02:41 -05:00
parent 5b2448c084
commit daf27a573e
3 changed files with 78 additions and 85 deletions

View File

@ -203,11 +203,14 @@ void x68k_state::draw_text(bitmap_rgb32 &bitmap, int xscr, int yscr, rectangle r
uint32_t loc; // location in TVRAM
uint32_t colour;
int bit;
int divisor = 1;
if(m_crtc->gfx_double_scan())
divisor = 2;
for(line=rect.min_y;line<=rect.max_y;line++) // per scanline
{
// adjust for scroll registers
loc = (((line - m_crtc->vbegin()) + yscr) & 0x3ff) * 64;
loc = ((((line- m_crtc->vbegin()) / divisor) + yscr) & 0x3ff) * 64;
loc += (xscr / 16) & 0x7f;
loc &= 0xffff;
bit = 15 - (xscr & 0x0f);
@ -241,6 +244,9 @@ bool x68k_state::draw_gfx_scanline( bitmap_ind16 &bitmap, rectangle cliprect, ui
int shift;
bool blend, ret = false;
uint16_t *pal = (uint16_t *)m_gfxpalette->basemem().base();
int divisor = 1;
if(m_crtc->gfx_double_scan())
divisor = 2;
for(int scanline=cliprect.min_y;scanline<=cliprect.max_y;scanline++) // per scanline
{
@ -296,7 +302,7 @@ bool x68k_state::draw_gfx_scanline( bitmap_ind16 &bitmap, rectangle cliprect, ui
case 0x00: // 16 colours
xscr = m_crtc->xscr_gfx(page) & 0x1ff;
yscr = m_crtc->yscr_gfx(page) & 0x1ff;
lineoffset = (((scanline - m_crtc->vbegin()) + yscr) & 0x1ff) * 512;
lineoffset = (((scanline - m_crtc->vbegin() / divisor) + yscr) & 0x1ff) * 512;
loc = xscr & 0x1ff;
shift = 4;
if((m_video.reg[2] & 0x1a00) == 0x1a00)
@ -342,7 +348,7 @@ bool x68k_state::draw_gfx_scanline( bitmap_ind16 &bitmap, rectangle cliprect, ui
{
xscr = m_crtc->xscr_gfx(page) & 0x1ff;
yscr = m_crtc->yscr_gfx(page) & 0x1ff;
lineoffset = (((scanline - m_crtc->vbegin()) + yscr) & 0x1ff) * 512;
lineoffset = (((scanline - m_crtc->vbegin() / divisor) + yscr) & 0x1ff) * 512;
loc = xscr & 0x1ff;
shift = 4;
if((m_video.reg[2] & 0x1a00) == 0x1a00)
@ -387,7 +393,7 @@ bool x68k_state::draw_gfx_scanline( bitmap_ind16 &bitmap, rectangle cliprect, ui
case 0x03: // 65536 colours
xscr = m_crtc->xscr_gfx(0) & 0x1ff;
yscr = m_crtc->yscr_gfx(0) & 0x1ff;
lineoffset = (((scanline - m_crtc->vbegin()) + yscr) & 0x1ff) * 512;
lineoffset = (((scanline - m_crtc->vbegin() / divisor) + yscr) & 0x1ff) * 512;
loc = xscr & 0x1ff;
for(pixel=m_crtc->hbegin();pixel<=m_crtc->hend();pixel++)
{
@ -409,20 +415,25 @@ void x68k_state::draw_gfx(bitmap_rgb32 &bitmap,rectangle cliprect)
{
int priority, scanline, pixel;
bool gfxblend=false;
//rectangle rect;
//int xscr,yscr;
//int gpage;
rectangle gfxrect = cliprect;
int divisor = 1;
if(m_crtc->gfx_double_scan())
{
gfxrect.max_y >>= 1;
gfxrect.min_y >>= 1;
divisor = 2;
}
if(m_crtc->gfx_layer_buffer()) // if graphic layers are set to buffer, then they aren't visible
return;
m_gfxbitmap.fill(0, cliprect);
m_gfxbitmap.fill(0, gfxrect);
if((m_video.reg[2] & 0x1800) == 0x1000)
m_special.fill(0, cliprect);
m_special.fill(0, gfxrect);
for(priority=3;priority>=0;priority--)
{
gfxblend = draw_gfx_scanline(m_gfxbitmap,cliprect,priority);
gfxblend = draw_gfx_scanline(m_gfxbitmap,gfxrect,priority);
}
for(scanline=cliprect.min_y;scanline<=cliprect.max_y;scanline++)
@ -433,13 +444,13 @@ void x68k_state::draw_gfx(bitmap_rgb32 &bitmap,rectangle cliprect)
{
if((m_video.reg[0] & 0x03) == 3)
{
colour = m_gfxbitmap.pix(scanline, pixel);
colour = m_gfxbitmap.pix(scanline / divisor, pixel);
if(colour || (m_video.gfx_pri == 2))
bitmap.pix(scanline, pixel) = GGGGGRRRRRBBBBBI(colour);
}
else if(gfxblend)
{
colour = m_gfxbitmap.pix(scanline, pixel);
colour = m_gfxbitmap.pix(scanline / divisor, pixel);
if(((m_video.reg[2] & 0x1900) == 0x1900) && (m_video.gfx_pri != 2) && (colour & 1))
blend = true;
else
@ -454,7 +465,7 @@ void x68k_state::draw_gfx(bitmap_rgb32 &bitmap,rectangle cliprect)
}
else
{
colour = m_gfxbitmap.pix(scanline, pixel) & 0xff;
colour = m_gfxbitmap.pix(scanline / divisor, pixel) & 0xff;
if(((m_video.reg[2] & 0x1900) == 0x1900) && (m_video.gfx_pri != 2) && (colour & 1))
{
blend = true;
@ -507,6 +518,9 @@ void x68k_state::draw_sprites(bitmap_ind16 &bitmap, int priority, rectangle clip
b1-0, H-Res (0 = 8x8 tilemaps, 1 = 16x16 tilemaps, 2 or 3 = unknown)
*/
int ptr,pri;
int divisor = 1;
if(!(m_video.bg_hvres & 0x0c) && m_crtc->gfx_double_scan())
divisor = 2;
for(ptr=508;ptr>=0;ptr-=4) // stepping through sprites
{
@ -532,7 +546,7 @@ void x68k_state::draw_sprites(bitmap_ind16 &bitmap, int priority, rectangle clip
sx += m_video.bg_hshift;
sx += m_sprite_shift;
m_gfxdecode->gfx(1)->zoom_transpen(bitmap,cliprect,code,colour,xflip,yflip,m_crtc->hbegin()+sx,m_crtc->vbegin()+(sy*m_video.bg_double),0x10000,0x10000*m_video.bg_double,0x00);
m_gfxdecode->gfx(1)->zoom_transpen(bitmap,cliprect,code,colour,xflip,yflip,m_crtc->hbegin()+sx,(m_crtc->vbegin() / divisor)+(sy*m_video.bg_double),0x10000,0x10000*m_video.bg_double,0x00);
}
}
}
@ -544,6 +558,9 @@ void x68k_state::draw_bg(bitmap_ind16 &bitmap, screen_device &screen, int layer,
tilemap_t* x68k_bg0;
tilemap_t* x68k_bg1;
tilemap_t* map;
int divisor = 1;
if(!(m_video.bg_hvres & 0x0c) && m_crtc->gfx_double_scan())
divisor = 2;
if((m_spritereg[0x408] & 0x03) == 0x00) // Sprite/BG H-Res 0=8x8, 1=16x16, 2 or 3 = undefined.
{
@ -562,7 +579,7 @@ void x68k_state::draw_bg(bitmap_ind16 &bitmap, screen_device &screen, int layer,
map = (m_spritereg[0x404] & 0x0006) == 0x02 ? x68k_bg0 : x68k_bg1;
map->set_scrollx(0,(sclx - m_crtc->hbegin() - m_video.bg_hshift) & 0x3ff);
map->set_scrolly(0,(scly - m_crtc->vbegin()) & 0x3ff);
map->set_scrolly(0,(scly - (m_crtc->vbegin() / divisor)) & 0x3ff);
map->draw(screen, bitmap, rect, opaque ? TILEMAP_DRAW_OPAQUE : 0, 0);
}
@ -698,24 +715,33 @@ uint32_t x68k_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
bool clear = false;
if(m_video.reg[2] & 0x0040)
{
rectangle pcgrect = rect;
if(!(m_video.bg_hvres & 0x0c) && m_crtc->gfx_double_scan())
{
pcgrect.max_y >>= 1;
pcgrect.min_y >>= 1;
}
if(m_spritereg[0x404] & 0x0008)
{
clear = true;
draw_bg(m_pcgbitmap, screen, 1, true, rect);
draw_bg(m_pcgbitmap, screen, 1, true, pcgrect);
}
else if(m_spritereg[0x404] & 0x0001)
{
clear = true;
draw_bg(m_pcgbitmap, screen, 0, true, rect);
draw_bg(m_pcgbitmap, screen, 0, true, pcgrect);
}
}
if(clear)
{
int divisor = 1;
if(!(m_video.bg_hvres & 0x0c) && m_crtc->gfx_double_scan())
divisor = 2;
for(scanline=rect.min_y;scanline<=rect.max_y;scanline++)
{
for(pixel=m_crtc->hbegin();pixel<=m_crtc->hend();pixel++)
{
uint8_t colour = m_pcgbitmap.pix(scanline, pixel) & 0xff;
uint8_t colour = m_pcgbitmap.pix(scanline / divisor, pixel) & 0xff;
bitmap.pix(scanline, pixel) = m_pcgpalette->pen(colour);
}
}
@ -732,22 +758,30 @@ uint32_t x68k_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
// Sprite / BG Tiles
if(priority == m_video.sprite_pri /*&& (m_spritereg[0x404] & 0x0200)*/ && (m_video.reg[2] & 0x0040))
{
m_pcgbitmap.fill(0, rect);
draw_sprites(m_pcgbitmap,1,rect);
rectangle pcgrect = rect;
int divisor = 1;
if(!(m_video.bg_hvres & 0x0c) && m_crtc->gfx_double_scan())
{
pcgrect.max_y >>= 1;
pcgrect.min_y >>= 1;
divisor = 2;
}
m_pcgbitmap.fill(0, pcgrect);
draw_sprites(m_pcgbitmap,1,pcgrect);
if(m_spritereg[0x404] & 0x0008)
draw_bg(m_pcgbitmap, screen, 1, false, rect);
draw_bg(m_pcgbitmap, screen, 1, false, pcgrect);
draw_sprites(m_pcgbitmap,2,rect);
draw_sprites(m_pcgbitmap,2,pcgrect);
if(m_spritereg[0x404] & 0x0001)
draw_bg(m_pcgbitmap, screen, 0, false, rect);
draw_bg(m_pcgbitmap, screen, 0, false, pcgrect);
draw_sprites(m_pcgbitmap,3,rect);
draw_sprites(m_pcgbitmap,3,pcgrect);
for(scanline=rect.min_y;scanline<=rect.max_y;scanline++)
{
for(pixel=m_crtc->hbegin();pixel<=m_crtc->hend();pixel++)
{
uint8_t colour = m_pcgbitmap.pix(scanline, pixel) & 0xff;
uint8_t colour = m_pcgbitmap.pix(scanline / divisor, pixel) & 0xff;
if(colour && (m_pcgpalette->pen(colour) & 0xffffff))
bitmap.pix(scanline, pixel) = m_pcgpalette->pen(colour);
}
@ -767,11 +801,14 @@ uint32_t x68k_state::screen_update(screen_device &screen, bitmap_rgb32 &bitmap,
if((m_video.reg[2] & 0x1800) == 0x1000) // special priority
{
uint16_t colour;
int divisor = 1;
if(m_crtc->gfx_double_scan())
divisor = 2;
for(scanline=rect.min_y;scanline<=rect.max_y;scanline++)
{
for(pixel=m_crtc->hbegin();pixel<=m_crtc->hend();pixel++)
{
colour = m_special.pix(scanline, pixel) & 0xff;
colour = m_special.pix(scanline / divisor, pixel) & 0xff;
if(colour)
bitmap.pix(scanline, pixel) = m_gfxpalette->pen(colour & ~1);
}

View File

@ -152,18 +152,14 @@ void x68k_crtc_device::refresh_mode()
{
// Calculate data from register values
m_vmultiple = 1;
if ((m_reg[20] & 0x10) != 0 && (m_reg[20] & 0x0c) == 0)
m_vmultiple = 2; // 31.5kHz + 256 lines = doublescan
if (m_interlace)
m_vmultiple = 0.5f; // 31.5kHz + 1024 lines or 15kHz + 512 lines = interlaced
m_htotal = (m_reg[0] + 1) * 8;
m_vtotal = (m_reg[4] + 1) / m_vmultiple; // default is 567 (568 scanlines)
m_hbegin = (m_reg[2] * 8) + 1;
m_hend = (m_reg[3] * 8);
m_vbegin = (m_reg[6]) / m_vmultiple;
m_hend = m_reg[3] * 8;
m_vbegin = m_reg[6] / m_vmultiple;
m_vend = (m_reg[7] - 1) / m_vmultiple;
if ((m_vmultiple == 2) && !(m_reg[7] & 1)) // otherwise if the raster irq line == vblank line, the raster irq fires too late
m_vend++;
m_hsync_end = (m_reg[1]) * 8;
m_vsync_end = (m_reg[5]) / m_vmultiple;
m_hsyncadjust = m_reg[8];
@ -193,8 +189,8 @@ void x68k_crtc_device::refresh_mode()
unsigned div = (m_reg[20] & 0x03) == 0 ? 4 : 2;
if (BIT(m_reg[20], 4) && !BIT(m_reg[20], 1))
div = BIT(m_reg[20], 0) ? 3 : 6;
if ((m_reg[20] & 0x0c) == 0)
div *= 2;
if (!(m_reg[20] & 0x1f))
div = 8;
attotime refresh = attotime::from_hz((BIT(m_reg[20], 4) ? clock_69m() : clock_39m()) / div) * (scr.max_x * scr.max_y);
LOG("screen().configure(%i,%i,[%i,%i,%i,%i],%f)\n", scr.max_x, scr.max_y, visiblescr.min_x, visiblescr.min_y, visiblescr.max_x, visiblescr.max_y, refresh.as_hz());
screen().configure(scr.max_x, scr.max_y, visiblescr, refresh.as_attoseconds());
@ -211,46 +207,6 @@ TIMER_CALLBACK_MEMBER(x68k_crtc_device::hsync)
if (m_operation & 8)
text_copy((m_reg[22] & 0xff00) >> 8, (m_reg[22] & 0x00ff), (m_reg[21] & 0xf));
if (m_vmultiple == 2) // 256-line (doublescan)
{
if (hstate == 1)
{
if (m_oddscanline)
{
int scan = screen().vpos();
hsync_time = screen().time_until_pos(scan, (m_htotal + m_hend) / 2);
m_scanline_timer->adjust(hsync_time);
if ((scan != 0) && (scan < m_vend))
screen().update_partial(scan - 1);
}
else
{
int scan = screen().vpos();
hsync_time = screen().time_until_pos(scan, m_hend / 2);
m_scanline_timer->adjust(hsync_time);
if ((scan != 0) && (scan < m_vend))
screen().update_partial(scan - 1);
}
}
if (hstate == 0)
{
if (m_oddscanline)
{
int scan = screen().vpos() + 1;
hsync_time = screen().time_until_pos(scan, m_hbegin / 2);
m_scanline_timer->adjust(hsync_time, 1);
m_oddscanline = false;
}
else
{
hsync_time = screen().time_until_pos(screen().vpos(), (m_htotal + m_hbegin) / 2);
m_scanline_timer->adjust(hsync_time, 1);
m_oddscanline = true;
}
}
}
else // 512-line
{
if (hstate == 1)
{
int scan = screen().vpos();
@ -265,7 +221,6 @@ TIMER_CALLBACK_MEMBER(x68k_crtc_device::hsync)
m_scanline_timer->adjust(hsync_time, 1);
}
}
}
TIMER_CALLBACK_MEMBER(x68k_crtc_device::raster_end)
{
@ -390,7 +345,7 @@ void x68k_crtc_device::crtc_w(offs_t offset, u16 data, u16 mem_mask)
attotime irq_time = attotime::zero;
if ((data / m_vmultiple) != screen().vpos())
{
irq_time = screen().time_until_pos((data) / m_vmultiple,2);
irq_time = screen().time_until_pos((data - 1) / m_vmultiple,2);
m_rint_callback(1);
}
m_raster_irq_timer->adjust(irq_time, (data) / m_vmultiple);

View File

@ -39,6 +39,7 @@ public:
u16 yscr_gfx(int page) const { return m_reg[13 + page * 2]; }
u8 vfactor() const { return (m_reg[20] & 0x0c) >> 2; }
bool is_1024x1024() const { return BIT(m_reg[20], 10); }
bool gfx_double_scan() const { return (m_reg[20] & 0x1e) == 0x10; }
bool gfx_layer_buffer() const { return BIT(m_reg[20], 11); }
bool text_layer_buffer() const { return BIT(m_reg[20], 12); }
u16 hbegin() const { return m_hbegin; }