internal bool EmulateCycle()
{
byte mask;
int i;
switch (cycle)
{
// Fetch sprite pointer 3, increment raster counter, trigger raster IRQ,
// test for Bad Line, reset BA if sprites 3 and 4 off, read data of sprite 3
case 1:
if (unchecked(raster_y == TOTAL_RASTERS - 1))
// Trigger VBlank in cycle 2
vblanking = true;
else
{
// PMB. Check for overflow
if (raster_y == UInt32.MaxValue)
raster_y = 0;
else
{
// original code
// Increment raster counter
raster_y++;
}
// Trigger raster IRQ if IRQ line reached
if (raster_y == irq_raster)
raster_irq();
// In line $30, the DEN bit controls if Bad Lines can occur
if (raster_y == 0x30)
bad_lines_enabled = (ctrl1 & 0x10) != 0;
// Bad Line condition?
is_bad_line = (raster_y >= FIRST_DMA_LINE && raster_y <= LAST_DMA_LINE && ((raster_y & 7) == y_scroll) && bad_lines_enabled);
// Don't draw all lines, hide some at the top and bottom
draw_this_line = (raster_y >= FIRST_DISP_LINE && raster_y <= LAST_DISP_LINE && !frame_skipped);
}
// First sample of border state
border_on_sample[0] = border_on;
SprPtrAccess(3);
SprDataAccess(3, 0);
DisplayIfBadLine();
if ((spr_dma_on & 0x18) == 0)
_cpu.BALow = false;
break;
// Set BA for sprite 5, read data of sprite 3
case 2:
if (vblanking)
{
// Vertical blank, reset counters
raster_y = vc_base = 0;
ref_cnt = 0xff;
lp_triggered = vblanking = false;
skip_counter--;
frame_skipped = skip_counter == 0;
if (!frame_skipped)
skip_counter = GlobalPrefs.ThePrefs.SkipFrames;
_c64.VBlank(!frame_skipped);
// Get bitmap pointer for next frame. This must be done
// after calling the_c64.VBlank() because the preferences
// and screen configuration may have been changed there
//chunky_line_start = the_display.BitmapBase;
_chunkyLineStartIndex = 0;
xmod = _display.BitmapXMod;
// Trigger raster IRQ if IRQ in line 0
if (irq_raster == 0)
raster_irq();
}
// Our output goes here
//chunky_ptr = chunky_line_start;
_chunkyIndex = _chunkyLineStartIndex;
// Clear foreground mask
//fore_mask_ptr = fore_mask_buf_ptr;
fore_mask_index = fore_mask_buf_index;
Array.Clear(fore_mask_buf, 0, fore_mask_buf.Length);
SprDataAccess(3, 1);
SprDataAccess(3, 2);
DisplayIfBadLine();
if ((spr_dma_on & 0x20) !=0)
SetBALow();
break;
// Fetch sprite pointer 4, reset BA is sprite 4 and 5 off
case 3:
SprPtrAccess(4);
SprDataAccess(4, 0);
DisplayIfBadLine();
if ((spr_dma_on & 0x30) == 0)
_cpu.BALow = false;
break;
// Set BA for sprite 6, read data of sprite 4
case 4:
SprDataAccess(4, 1);
SprDataAccess(4, 2);
DisplayIfBadLine();
if ((spr_dma_on & 0x40) !=0)
SetBALow();
break;
// Fetch sprite pointer 5, reset BA if sprite 5 and 6 off
case 5:
SprPtrAccess(5);
SprDataAccess(5, 0);
DisplayIfBadLine();
if ((spr_dma_on & 0x60) == 0)
_cpu.BALow = false;
break;
// Set BA for sprite 7, read data of sprite 5
case 6:
SprDataAccess(5, 1);
SprDataAccess(5, 2);
DisplayIfBadLine();
if ((spr_dma_on & 0x80) != 0)
SetBALow();
break;
// Fetch sprite pointer 6, reset BA if sprite 6 and 7 off
case 7:
SprPtrAccess(6);
SprDataAccess(6, 0);
DisplayIfBadLine();
if ((spr_dma_on & 0xc0) ==0)
_cpu.BALow = false;
break;
// Read data of sprite 6
case 8:
SprDataAccess(6, 1);
SprDataAccess(6, 2);
DisplayIfBadLine();
break;
// Fetch sprite pointer 7, reset BA if sprite 7 off
case 9:
SprPtrAccess(7);
SprDataAccess(7, 0);
DisplayIfBadLine();
if ((spr_dma_on & 0x80) == 0)
_cpu.BALow = false;
break;
// Read data of sprite 7
case 10:
SprDataAccess(7, 1);
SprDataAccess(7, 2);
DisplayIfBadLine();
break;
// Refresh, reset BA
case 11:
RefreshAccess();
DisplayIfBadLine();
_cpu.BALow = false;
break;
// Refresh, turn on matrix access if Bad Line
case 12:
RefreshAccess();
FetchIfBadLine();
break;
// Refresh, turn on matrix access if Bad Line, reset raster_x, graphics display starts here
case 13:
if (draw_this_line)
{
draw_background();
SampleBorder();
}
RefreshAccess();
FetchIfBadLine();
raster_x = 0xfffc;
break;
// Refresh, VCBASE.VCCOUNT, turn on matrix access and reset RC if Bad Line
case 14:
if (draw_this_line)
{
draw_background();
SampleBorder();
}
RefreshAccess();
RCIfBadLine();
vc = vc_base;
break;
// Refresh and matrix access, increment mc_base by 2 if y expansion flipflop is set
case 15:
if (draw_this_line)
{
draw_background();
SampleBorder();
}
RefreshAccess();
FetchIfBadLine();
for (i = 0; i < 8; i++)
if ((spr_exp_y & (1 << i)) != 0)
mc_base[i] += 2;
ml_index = 0;
matrix_access();
break;
// Graphics and matrix access, increment mc_base by 1 if y expansion flipflop is set
// and check if sprite DMA can be turned off
case 16:
if (draw_this_line)
{
draw_background();
SampleBorder();
}
graphics_access();
FetchIfBadLine();
mask = 1;
for (i = 0; i < 8; i++, mask <<= 1)
{
if ((spr_exp_y & mask) != 0)
mc_base[i]++;
if ((mc_base[i] & 0x3f) == 0x3f)
spr_dma_on &= (byte)~mask;
}
matrix_access();
break;
// Graphics and matrix access, turn off border in 40 column mode, display window starts here
case 17:
if ((ctrl2 & 8) != 0)
{
if (raster_y == dy_stop)
ud_border_on = true;
else
{
if ((ctrl1 & 0x10) != 0)
{
if (raster_y == dy_start)
border_on = ud_border_on = false;
else
if (!ud_border_on)
border_on = false;
}
else
if (!ud_border_on)
border_on = false;
}
}
// Second sample of border state
border_on_sample[1] = border_on;
if (draw_this_line)
draw_background();
draw_graphics();
if (draw_this_line) SampleBorder();
graphics_access();
FetchIfBadLine();
matrix_access();
break;
// Turn off border in 38 column mode
case 18:
if ((ctrl2 & 8) == 0)
{
if (raster_y == dy_stop)
ud_border_on = true;
else
{
if ((ctrl1 & 0x10) != 0)
{
if (raster_y == dy_start)
border_on = ud_border_on = false;
else
if (!ud_border_on)
border_on = false;
}
else
if (!ud_border_on)
border_on = false;
}
}
// Third sample of border state
border_on_sample[2] = border_on;
// Falls through
goto case 19;
// Graphics and matrix access
case 19:
case 20:
case 21:
case 22:
case 23:
case 24:
case 25:
case 26:
case 27:
case 28:
case 29:
case 30:
case 31:
case 32:
case 33:
case 34:
case 35:
case 36:
case 37:
case 38:
case 39:
case 40:
case 41:
case 42:
case 43:
case 44:
case 45:
case 46:
case 47:
case 48:
case 49:
case 50:
case 51:
case 52:
case 53:
case 54: // Gnagna...
draw_graphics();
if (draw_this_line) SampleBorder();
graphics_access();
FetchIfBadLine();
matrix_access();
last_char_data = char_data;
break;
// Last graphics access, turn off matrix access, turn on sprite DMA if Y coordinate is
// right and sprite is enabled, handle sprite y expansion, set BA for sprite 0
case 55:
draw_graphics();
if (draw_this_line) SampleBorder();
graphics_access();
DisplayIfBadLine();
// Invert y expansion flipflop if bit in MYE is set
mask = 1;
for (i = 0; i < 8; i++, mask <<= 1)
if ((mye & mask) != 0)
spr_exp_y ^= mask;
CheckSpriteDMA();
if ((spr_dma_on & 0x01) != 0)
{ // Don't remove these braces!
SetBALow();
}
else
_cpu.BALow = false;
break;
// Turn on border in 38 column mode, turn on sprite DMA if Y coordinate is right and
// sprite is enabled, set BA for sprite 0, display window ends here
case 56:
if ((ctrl2 & 8) == 0)
border_on = true;
// Fourth sample of border state
border_on_sample[3] = border_on;
draw_graphics();
if (draw_this_line) SampleBorder();
IdleAccess();
DisplayIfBadLine();
CheckSpriteDMA();
if ((spr_dma_on & 0x01) != 0)
SetBALow();
break;
// Turn on border in 40 column mode, set BA for sprite 1, paint sprites
case 57:
if ((ctrl2 & 8) != 0)
border_on = true;
// Fifth sample of border state
border_on_sample[4] = border_on;
//// Sample spr_disp_on and spr_data for sprite drawing
//if ((spr_draw = spr_disp_on) != 0)
// memcpy(spr_draw_data_ptr, spr_data_ptr, 8 * 4);
// Sample spr_disp_on and spr_data for sprite drawing
if ((spr_draw = spr_disp_on) != 0)
{
for (int s = 0; s < 8 * 4; s++)
{
//spr_draw_data[spr_draw_data_index + s] = spr_data[spr_data_index + s];
spr_draw_data[s] = spr_data[s];
}
}
// Turn off sprite display if DMA is off
mask = 1;
for (i = 0; i < 8; i++, mask <<= 1)
if ((spr_disp_on & mask) != 0 && (spr_dma_on & mask) == 0)
spr_disp_on &= (byte)~mask;
if (draw_this_line)
{
draw_background();
SampleBorder();
}
IdleAccess();
DisplayIfBadLine();
if ((spr_dma_on & 0x02) != 0)
SetBALow();
break;
// Fetch sprite pointer 0, mc_base.mc, turn on sprite display if necessary,
// turn off display if RC=7, read data of sprite 0
case 58:
if (draw_this_line)
{
draw_background();
SampleBorder();
}
mask = 1;
for (i = 0; i < 8; i++, mask <<= 1)
{
mc[i] = mc_base[i];
if ((spr_dma_on & mask) != 0 && (raster_y & 0xff) == my[i])
spr_disp_on |= mask;
}
SprPtrAccess(0);
SprDataAccess(0, 0);
if (rc == 7)
{
vc_base = vc;
display_state = false;
}
if (is_bad_line || display_state)
{
display_state = true;
rc = (UInt16)((rc + 1) & 7);
}
break;
// Set BA for sprite 2, read data of sprite 0
case 59:
if (draw_this_line)
{
draw_background();
SampleBorder();
}
SprDataAccess(0, 1);
SprDataAccess(0, 2);
DisplayIfBadLine();
if ((spr_dma_on & 0x04) != 0)
SetBALow();
break;
// Fetch sprite pointer 1, reset BA if sprite 1 and 2 off, graphics display ends here
case 60:
if (draw_this_line)
{
draw_background();
SampleBorder();
// Draw sprites
if (spr_draw != 0 && GlobalPrefs.ThePrefs.SpritesOn)
draw_sprites();
// Draw border
if (border_on_sample[0])
for (i = 0; i < 4; i++)
{
_display.SetPixels(_chunkyLineStartIndex + i * 8, 8, border_color_sample[i]);
//byte* p = chunky_line_start + i * 8;
//p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = border_color_sample[i];
}
if (border_on_sample[1])
{
_display.SetPixels(_chunkyLineStartIndex + 4 * 8, 8, border_color_sample[4]);
//byte* p = chunky_line_start + 4 * 8;
//p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = border_color_sample[4];
}
if (border_on_sample[2])
for (i = 5; i < 43; i++)
{
_display.SetPixels(_chunkyLineStartIndex + i * 8, 8, border_color_sample[i]);
//byte* p = chunky_line_start + i * 8;
//p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = border_color_sample[i];
}
if (border_on_sample[3])
{
_display.SetPixels(_chunkyLineStartIndex + 43 * 8, 8, border_color_sample[43]);
//byte* p = chunky_line_start + 43 * 8;
//p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = border_color_sample[43];
}
if (border_on_sample[4])
for (i = 44; i < C64Display.DISPLAY_X / 8; i++)
{
_display.SetPixels(_chunkyLineStartIndex + i * 8, 8, border_color_sample[i]);
//byte* p = chunky_line_start + i * 8;
//p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = border_color_sample[i];
}
#if false
//// Draw border
//if (border_on_sample[0])
// for (i = 0; i < 4; i++)
// {
// byte* p = chunky_line_start + i * 8;
// p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = border_color_sample[i];
// }
//if (border_on_sample[1])
//{
// byte* p = chunky_line_start + 4 * 8;
// p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = border_color_sample[4];
//}
//if (border_on_sample[2])
// for (i = 5; i < 43; i++)
// {
// byte* p = chunky_line_start + i * 8;
// p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = border_color_sample[i];
// }
//if (border_on_sample[3])
//{
// byte* p = chunky_line_start + 43 * 8;
// p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = border_color_sample[43];
//}
//if (border_on_sample[4])
// for (i = 44; i < C64Display.DISPLAY_X / 8; i++)
// {
// byte* p = chunky_line_start + i * 8;
// p[0] = p[1] = p[2] = p[3] = p[4] = p[5] = p[6] = p[7] = border_color_sample[i];
// }
#endif
// Increment pointer in chunky buffer
_chunkyLineStartIndex += xmod;
}
SprPtrAccess(1);
SprDataAccess(1, 0);
DisplayIfBadLine();
if ((spr_dma_on & 0x06) == 0)
_cpu.BALow = false;
break;
// Set BA for sprite 3, read data of sprite 1
case 61:
SprDataAccess(1, 1);
SprDataAccess(1, 2);
DisplayIfBadLine();
if ((spr_dma_on & 0x08) != 0)
SetBALow();
break;
// Read sprite pointer 2, reset BA if sprite 2 and 3 off, read data of sprite 2
case 62:
SprPtrAccess(2);
SprDataAccess(2, 0);
DisplayIfBadLine();
if ((spr_dma_on & 0x0c) == 0)
_cpu.BALow = false;
break;
// Set BA for sprite 4, read data of sprite 2
case 63:
SprDataAccess(2, 1);
SprDataAccess(2, 2);
DisplayIfBadLine();
if (raster_y == dy_stop)
ud_border_on = true;
else
if ((ctrl1 & 0x10) != 0 && raster_y == dy_start)
ud_border_on = false;
if ((spr_dma_on & 0x10) != 0)
SetBALow();
// Last cycle
raster_x += 8;
cycle = 1;
return true;
}
// Next cycle
raster_x += 8;
cycle++;
return false;
}