summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/video/vic6567.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/video/vic6567.c')
-rw-r--r--src/mess/video/vic6567.c2815
1 files changed, 2815 insertions, 0 deletions
diff --git a/src/mess/video/vic6567.c b/src/mess/video/vic6567.c
new file mode 100644
index 00000000000..aeac999dea7
--- /dev/null
+++ b/src/mess/video/vic6567.c
@@ -0,0 +1,2815 @@
+/***************************************************************************
+
+ Video Interface Chip (6567R8 for NTSC system and 6569 for PAL system)
+
+ original emulation by PeT (mess@utanet.at)
+
+ A part of the code (cycle routine and drawing routines) is a modified version of the vic ii emulation used in
+ commodore 64 emulator "frodo" by Christian Bauer
+
+ http://frodo.cebix.net/
+ The rights on the source code remain at the author.
+ It may not - not even in parts - used for commercial purposes without explicit written permission by the author.
+ Permission to use it for non-commercial purposes is hereby granted als long as my copyright notice remains in the program.
+ You are not allowed to use the source to create and distribute a modified version of Frodo.
+
+ 2010-02: converted to be a device and split vic III emulation (which still uses old cycle & drawing routines)
+
+ TODO:
+ - plenty of cleanups
+ - emulate variants of the vic chip
+ - update vic III to use new code for the vic II compatibility
+
+***************************************************************************/
+/* mos videochips
+ vic (6560 NTSC, 6561 PAL)
+ used in commodore vic20
+
+ vic II
+ 6566 NTSC
+ no dram refresh?
+ 6567 NTSC
+ 6569 PAL-B
+ 6572 PAL-N
+ 6573 PAL-M
+ 8562 NTSC
+ 8565 PAL
+ used in commodore c64
+ complete different to vic
+
+ ted
+ 7360/8360 (NTSC-M, PAL-B by same chip ?)
+ 8365 PAL-N
+ 8366 PAL-M
+ used in c16 c116 c232 c264 plus4 c364
+ based on the vic II
+ but no sprites and not register compatible
+ includes timers, input port, sound generators
+ memory interface, dram refresh, clock generation
+
+ vic IIe
+ 8564 NTSC-M
+ 8566 PAL-B
+ 8569 PAL-N
+ used in commodore c128
+ vic II with some additional features
+ 3 programmable output pins k0 k1 k2
+
+ vic III
+ 4567
+ used in commodore c65 prototype
+ vic II compatible (mode only?)
+ several additional features
+ different resolutions, more colors, ...
+ (maybe like in the amiga graphic chip docu)
+
+ vdc
+ 8563
+ 8568 (composite video and composite sync)
+ second graphic chip in c128
+ complete different to above chips
+*/
+
+
+#include "emu.h"
+#include "video/vic6567.h"
+
+typedef struct _vic2_state vic2_state;
+struct _vic2_state
+{
+ vic2_type type;
+
+ screen_device *screen; // screen which sets bitmap properties
+ cpu_device *cpu;
+
+ UINT8 rdy_cycles;
+ UINT8 reg[0x80];
+
+ int on; /* rastering of the screen */
+
+ UINT16 chargenaddr, videoaddr, bitmapaddr;
+
+ bitmap_ind16 *bitmap;
+
+ UINT16 colors[4], spritemulti[4];
+
+ int rasterline;
+ UINT64 cycles_counter;
+ UINT8 cycle;
+ UINT16 raster_x;
+ UINT16 graphic_x;
+
+ /* convert multicolor byte to background/foreground for sprite collision */
+ UINT16 expandx[256];
+ UINT16 expandx_multi[256];
+
+ /* Display */
+ UINT16 dy_start;
+ UINT16 dy_stop;
+
+ /* GFX */
+ UINT8 draw_this_line;
+ UINT8 is_bad_line;
+ UINT8 bad_lines_enabled;
+ UINT8 display_state;
+ UINT8 char_data;
+ UINT8 gfx_data;
+ UINT8 color_data;
+ UINT8 last_char_data;
+ UINT8 matrix_line[40]; // Buffer for video line, read in Bad Lines
+ UINT8 color_line[40]; // Buffer for color line, read in Bad Lines
+ UINT8 vblanking;
+ UINT16 ml_index;
+ UINT8 rc;
+ UINT16 vc;
+ UINT16 vc_base;
+ UINT8 ref_cnt;
+
+ /* Sprites */
+ UINT8 spr_coll_buf[0x400]; // Buffer for sprite-sprite collisions and priorities
+ UINT8 fore_coll_buf[0x400]; // Buffer for foreground-sprite collisions and priorities
+ UINT8 spr_draw_data[8][4]; // Sprite data for drawing
+ UINT8 spr_exp_y;
+ UINT8 spr_dma_on;
+ UINT8 spr_draw;
+ UINT8 spr_disp_on;
+ UINT16 spr_ptr[8];
+ UINT8 spr_data[8][4];
+ UINT16 mc_base[8]; // Sprite data counter bases
+ UINT16 mc[8]; // Sprite data counters
+
+ /* Border */
+ UINT8 border_on;
+ UINT8 ud_border_on;
+ UINT8 border_on_sample[5];
+ UINT8 border_color_sample[0x400 / 8]; // Samples of border color at each "displayed" cycle
+
+ /* Cycles */
+ UINT64 first_ba_cycle;
+ UINT8 device_suspended;
+
+ /* DMA */
+ devcb_resolved_read8 in_dma_read_func;
+ devcb_resolved_read8 in_dma_read_color_func;
+
+ /* IRQ */
+ devcb_resolved_write_line out_interrupt_func;
+
+ /* RDY */
+ devcb_resolved_read8 in_rdy_workaround_func;
+
+ /* lightpen */
+ devcb_resolved_read8 in_lightpen_button_func;
+ devcb_resolved_read8 in_lightpen_x_func;
+ devcb_resolved_read8 in_lightpen_y_func;
+};
+
+
+/*****************************************************************************
+ CONSTANTS
+*****************************************************************************/
+
+#define VERBOSE_LEVEL 0
+#define DBG_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_LEVEL >= N) \
+ { \
+ if( M ) \
+ logerror("%11.6f: %-24s", machine.time().as_double(), (char*) M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+#define ROW25_YSTART 0x33
+#define ROW25_YSTOP 0xfb
+#define ROW24_YSTART 0x37
+#define ROW24_YSTOP 0xf7
+
+#define RASTERLINE_2_C64(a) (a)
+#define C64_2_RASTERLINE(a) (a)
+#define XPOS (VIC2_STARTVISIBLECOLUMNS + (VIC2_VISIBLECOLUMNS - VIC2_HSIZE) / 2)
+#define YPOS (VIC2_STARTVISIBLELINES /* + (VIC2_VISIBLELINES - VIC2_VSIZE) / 2 */)
+#define FIRSTCOLUMN 50
+
+/* 2008-05 FP: lightpen code needs to read input port from c64.c and cbmb.c */
+
+#define LIGHTPEN_BUTTON (vic2->in_lightpen_button_func(0))
+#define LIGHTPEN_X_VALUE (vic2->in_lightpen_x_func(0))
+#define LIGHTPEN_Y_VALUE (vic2->in_lightpen_y_func(0))
+
+/* lightpen delivers values from internal counters; they do not start with the visual area or frame area */
+#define VIC2_MAME_XPOS 0
+#define VIC2_MAME_YPOS 0
+#define VIC6567_X_BEGIN 38
+#define VIC6567_Y_BEGIN -6 /* first 6 lines after retrace not for lightpen! */
+#define VIC6569_X_BEGIN 38
+#define VIC6569_Y_BEGIN -6
+#define VIC2_X_BEGIN ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_X_BEGIN : VIC6567_X_BEGIN)
+#define VIC2_Y_BEGIN ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_Y_BEGIN : VIC6567_Y_BEGIN)
+#define VIC2_X_VALUE ((LIGHTPEN_X_VALUE / 1.3) + 12)
+#define VIC2_Y_VALUE ((LIGHTPEN_Y_VALUE ) + 10)
+
+#define VIC2E_K0_LEVEL (vic2->reg[0x2f] & 0x01)
+#define VIC2E_K1_LEVEL (vic2->reg[0x2f] & 0x02)
+#define VIC2E_K2_LEVEL (vic2->reg[0x2f] & 0x04)
+
+
+/* sprites 0 .. 7 */
+#define SPRITEON(nr) (vic2->reg[0x15] & (1 << nr))
+#define SPRITE_Y_EXPAND(nr) (vic2->reg[0x17] & (1 << nr))
+#define SPRITE_Y_SIZE(nr) (SPRITE_Y_EXPAND(nr) ? 2 * 21 : 21)
+#define SPRITE_X_EXPAND(nr) (vic2->reg[0x1d] & (1 << nr))
+#define SPRITE_X_SIZE(nr) (SPRITE_X_EXPAND(nr) ? 2 * 24 : 24)
+#define SPRITE_X_POS(nr) (vic2->reg[(nr) * 2] | (vic2->reg[0x10] & (1 << (nr)) ? 0x100 : 0))
+#define SPRITE_Y_POS(nr) (vic2->reg[1 + 2 * (nr)])
+#define SPRITE_MULTICOLOR(nr) (vic2->reg[0x1c] & (1 << nr))
+#define SPRITE_PRIORITY(nr) (vic2->reg[0x1b] & (1 << nr))
+#define SPRITE_MULTICOLOR1 (vic2->reg[0x25] & 0x0f)
+#define SPRITE_MULTICOLOR2 (vic2->reg[0x26] & 0x0f)
+#define SPRITE_COLOR(nr) (vic2->reg[0x27+nr] & 0x0f)
+#define SPRITE_ADDR(nr) (vic2->videoaddr | 0x3f8 | nr)
+#define SPRITE_COLL (vic2->reg[0x1e])
+#define SPRITE_BG_COLL (vic2->reg[0x1f])
+
+#define GFXMODE ((vic2->reg[0x11] & 0x60) | (vic2->reg[0x16] & 0x10)) >> 4
+#define SCREENON (vic2->reg[0x11] & 0x10)
+#define VERTICALPOS (vic2->reg[0x11] & 0x07)
+#define HORIZONTALPOS (vic2->reg[0x16] & 0x07)
+#define ECMON (vic2->reg[0x11] & 0x40)
+#define HIRESON (vic2->reg[0x11] & 0x20)
+#define COLUMNS40 (vic2->reg[0x16] & 0x08) /* else 38 Columns */
+
+#define VIDEOADDR ((vic2->reg[0x18] & 0xf0) << (10 - 4))
+#define CHARGENADDR ((vic2->reg[0x18] & 0x0e) << 10)
+#define BITMAPADDR ((data & 0x08) << 10)
+
+#define RASTERLINE (((vic2->reg[0x11] & 0x80) << 1) | vic2->reg[0x12])
+
+#define FRAMECOLOR (vic2->reg[0x20] & 0x0f)
+#define BACKGROUNDCOLOR (vic2->reg[0x21] & 0x0f)
+#define MULTICOLOR1 (vic2->reg[0x22] & 0x0f)
+#define MULTICOLOR2 (vic2->reg[0x23] & 0x0f)
+#define FOREGROUNDCOLOR (vic2->reg[0x24] & 0x0f)
+
+#define VIC2_LINES ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_LINES : VIC6567_LINES)
+#define VIC2_FIRST_DMA_LINE ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_FIRST_DMA_LINE : VIC6567_FIRST_DMA_LINE)
+#define VIC2_LAST_DMA_LINE ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_LAST_DMA_LINE : VIC6567_LAST_DMA_LINE)
+#define VIC2_FIRST_DISP_LINE ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_FIRST_DISP_LINE : VIC6567_FIRST_DISP_LINE)
+#define VIC2_LAST_DISP_LINE ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_LAST_DISP_LINE : VIC6567_LAST_DISP_LINE)
+#define VIC2_RASTER_2_EMU(a) ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_RASTER_2_EMU(a) : VIC6567_RASTER_2_EMU(a))
+#define VIC2_FIRSTCOLUMN ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_FIRSTCOLUMN : VIC6567_FIRSTCOLUMN)
+#define VIC2_X_2_EMU(a) ((vic2->type == VIC6569 || vic2->type == VIC8566) ? VIC6569_X_2_EMU(a) : VIC6567_X_2_EMU(a))
+
+/*****************************************************************************
+ INLINE FUNCTIONS
+*****************************************************************************/
+
+INLINE vic2_state *get_safe_token( device_t *device )
+{
+ assert(device != NULL);
+ assert(device->type() == VIC2);
+
+ return (vic2_state *)downcast<legacy_device_base *>(device)->token();
+}
+
+INLINE const vic2_interface *get_interface( device_t *device )
+{
+ assert(device != NULL);
+ assert((device->type() == VIC2));
+ return (const vic2_interface *) device->static_config();
+}
+
+/*****************************************************************************
+ IMPLEMENTATION
+*****************************************************************************/
+
+static void vic2_set_interrupt( running_machine &machine, int mask, vic2_state *vic2 )
+{
+ if (((vic2->reg[0x19] ^ mask) & vic2->reg[0x1a] & 0xf))
+ {
+ if (!(vic2->reg[0x19] & 0x80))
+ {
+ DBG_LOG(2, "vic2", ("irq start %.2x\n", mask));
+ vic2->reg[0x19] |= 0x80;
+ vic2->out_interrupt_func(1);
+ }
+ }
+ vic2->reg[0x19] |= mask;
+}
+
+static void vic2_clear_interrupt( running_machine &machine, int mask, vic2_state *vic2 )
+{
+ vic2->reg[0x19] &= ~mask;
+ if ((vic2->reg[0x19] & 0x80) && !(vic2->reg[0x19] & vic2->reg[0x1a] & 0xf))
+ {
+ DBG_LOG(2, "vic2", ("irq end %.2x\n", mask));
+ vic2->reg[0x19] &= ~0x80;
+ vic2->out_interrupt_func(0);
+ }
+}
+
+void vic2_lightpen_write( device_t *device, int level )
+{
+ /* calculate current position, write it and raise interrupt */
+}
+
+static TIMER_CALLBACK( vic2_timer_timeout )
+{
+ vic2_state *vic2 = (vic2_state *)ptr;
+ int which = param;
+
+ DBG_LOG(3, "vic2 ", ("timer %d timeout\n", which));
+
+ switch (which)
+ {
+ case 1: /* light pen */
+ /* and diode must recognize light */
+ if (1)
+ {
+ vic2->reg[0x13] = VIC2_X_VALUE;
+ vic2->reg[0x14] = VIC2_Y_VALUE;
+ }
+ vic2_set_interrupt(machine, 8, vic2);
+ break;
+ }
+}
+
+
+// modified VIC II emulation by Christian Bauer starts here...
+
+// Idle access
+INLINE void vic2_idle_access( running_machine &machine, vic2_state *vic2 )
+{
+ vic2->in_dma_read_func(0x3fff);
+}
+
+// Fetch sprite data pointer
+INLINE void vic2_spr_ptr_access( running_machine &machine, vic2_state *vic2, int num )
+{
+ vic2->spr_ptr[num] = vic2->in_dma_read_func(SPRITE_ADDR(num)) << 6;
+}
+
+// Fetch sprite data, increment data counter
+INLINE void vic2_spr_data_access( running_machine &machine, vic2_state *vic2, int num, int bytenum )
+{
+ if (vic2->spr_dma_on & (1 << num))
+ {
+ vic2->spr_data[num][bytenum] = vic2->in_dma_read_func((vic2->mc[num] & 0x3f) | vic2->spr_ptr[num]);
+ vic2->mc[num]++;
+ }
+ else
+ if (bytenum == 1)
+ vic2_idle_access(machine, vic2);
+}
+
+// Turn on display if Bad Line
+INLINE void vic2_display_if_bad_line( vic2_state *vic2 )
+{
+ if (vic2->is_bad_line)
+ vic2->display_state = 1;
+}
+
+// Suspend CPU
+INLINE void vic2_suspend_cpu( running_machine &machine, vic2_state *vic2 )
+{
+ if (vic2->device_suspended == 0)
+ {
+ vic2->first_ba_cycle = vic2->cycles_counter;
+ if (vic2->in_rdy_workaround_func(0) != 7 )
+ {
+// device_suspend(machine.firstcpu, SUSPEND_REASON_SPIN, 0);
+ }
+ vic2->device_suspended = 1;
+ }
+}
+
+// Resume CPU
+INLINE void vic2_resume_cpu( running_machine &machine, vic2_state *vic2 )
+{
+ if (vic2->device_suspended == 1)
+ {
+ // device_resume(machine.firstcpu, SUSPEND_REASON_SPIN);
+ vic2->device_suspended = 0;
+ }
+}
+
+// Refresh access
+INLINE void vic2_refresh_access( running_machine &machine, vic2_state *vic2 )
+{
+ vic2->in_dma_read_func(0x3f00 | vic2->ref_cnt--);
+}
+
+
+INLINE void vic2_fetch_if_bad_line( vic2_state *vic2 )
+{
+ if (vic2->is_bad_line)
+ vic2->display_state = 1;
+}
+
+
+// Turn on display and matrix access and reset RC if Bad Line
+INLINE void vic2_rc_if_bad_line( vic2_state *vic2 )
+{
+ if (vic2->is_bad_line)
+ {
+ vic2->display_state = 1;
+ vic2->rc = 0;
+ }
+}
+
+// Sample border color and increment vic2->graphic_x
+INLINE void vic2_sample_border( vic2_state *vic2 )
+{
+ if (vic2->draw_this_line)
+ {
+ if (vic2->border_on)
+ vic2->border_color_sample[vic2->cycle - 13] = FRAMECOLOR;
+ vic2->graphic_x += 8;
+ }
+}
+
+
+// Turn on sprite DMA if necessary
+INLINE void vic2_check_sprite_dma( vic2_state *vic2 )
+{
+ int i;
+ UINT8 mask = 1;
+
+ for (i = 0; i < 8; i++, mask <<= 1)
+ if (SPRITEON(i) && ((vic2->rasterline & 0xff) == SPRITE_Y_POS(i)))
+ {
+ vic2->spr_dma_on |= mask;
+ vic2->mc_base[i] = 0;
+ if (SPRITE_Y_EXPAND(i))
+ vic2->spr_exp_y &= ~mask;
+ }
+}
+
+// Video matrix access
+INLINE void vic2_matrix_access( running_machine &machine, vic2_state *vic2 )
+{
+// if (vic2->device_suspended == 1)
+ {
+ if (vic2->cycles_counter < vic2->first_ba_cycle)
+ vic2->matrix_line[vic2->ml_index] = vic2->color_line[vic2->ml_index] = 0xff;
+ else
+ {
+ UINT16 adr = (vic2->vc & 0x03ff) | VIDEOADDR;
+ vic2->matrix_line[vic2->ml_index] = vic2->in_dma_read_func(adr); \
+ vic2->color_line[vic2->ml_index] = vic2->in_dma_read_color_func((adr & 0x03ff)); \
+ }
+ }
+}
+
+// Graphics data access
+INLINE void vic2_graphics_access( running_machine &machine, vic2_state *vic2 )
+{
+ if (vic2->display_state == 1)
+ {
+ UINT16 adr;
+ if (HIRESON)
+ adr = ((vic2->vc & 0x03ff) << 3) | vic2->bitmapaddr | vic2->rc;
+ else
+ adr = (vic2->matrix_line[vic2->ml_index] << 3) | vic2->chargenaddr | vic2->rc;
+ if (ECMON)
+ adr &= 0xf9ff;
+ vic2->gfx_data = vic2->in_dma_read_func(adr);
+ vic2->char_data = vic2->matrix_line[vic2->ml_index];
+ vic2->color_data = vic2->color_line[vic2->ml_index];
+ vic2->ml_index++;
+ vic2->vc++;
+ }
+ else
+ {
+ vic2->gfx_data = vic2->in_dma_read_func((ECMON ? 0x39ff : 0x3fff));
+ vic2->char_data = 0;
+ }
+}
+
+INLINE void vic2_draw_background( vic2_state *vic2 )
+{
+ if (vic2->draw_this_line)
+ {
+ UINT8 c;
+
+ switch (GFXMODE)
+ {
+ case 0:
+ case 1:
+ case 3:
+ c = vic2->colors[0];
+ break;
+ case 2:
+ c = vic2->last_char_data & 0x0f;
+ break;
+ case 4:
+ if (vic2->last_char_data & 0x80)
+ if (vic2->last_char_data & 0x40)
+ c = vic2->colors[3];
+ else
+ c = vic2->colors[2];
+ else
+ if (vic2->last_char_data & 0x40)
+ c = vic2->colors[1];
+ else
+ c = vic2->colors[0];
+ break;
+ default:
+ c = 0;
+ break;
+ }
+ vic2->bitmap->plot_box(vic2->graphic_x, VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, c);
+ }
+}
+
+INLINE void vic2_draw_mono( vic2_state *vic2, UINT16 p, UINT8 c0, UINT8 c1 )
+{
+ UINT8 c[2];
+ UINT8 data = vic2->gfx_data;
+
+ c[0] = c0;
+ c[1] = c1;
+
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 7) = c[data & 1];
+ vic2->fore_coll_buf[p + 7] = data & 1; data >>= 1;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 6) = c[data & 1];
+ vic2->fore_coll_buf[p + 6] = data & 1; data >>= 1;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 5) = c[data & 1];
+ vic2->fore_coll_buf[p + 5] = data & 1; data >>= 1;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 4) = c[data & 1];
+ vic2->fore_coll_buf[p + 4] = data & 1; data >>= 1;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 3) = c[data & 1];
+ vic2->fore_coll_buf[p + 3] = data & 1; data >>= 1;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 2) = c[data & 1];
+ vic2->fore_coll_buf[p + 2] = data & 1; data >>= 1;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 1) = c[data & 1];
+ vic2->fore_coll_buf[p + 1] = data & 1; data >>= 1;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 0) = c[data];
+ vic2->fore_coll_buf[p + 0] = data & 1;
+}
+
+INLINE void vic2_draw_multi( vic2_state *vic2, UINT16 p, UINT8 c0, UINT8 c1, UINT8 c2, UINT8 c3 )
+{
+ UINT8 c[4];
+ UINT8 data = vic2->gfx_data;
+
+ c[0] = c0;
+ c[1] = c1;
+ c[2] = c2;
+ c[3] = c3;
+
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 7) = c[data & 3];
+ vic2->fore_coll_buf[p + 7] = data & 2;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 6) = c[data & 3];
+ vic2->fore_coll_buf[p + 6] = data & 2; data >>= 2;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 5) = c[data & 3];
+ vic2->fore_coll_buf[p + 5] = data & 2;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 4) = c[data & 3];
+ vic2->fore_coll_buf[p + 4] = data & 2; data >>= 2;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 3) = c[data & 3];
+ vic2->fore_coll_buf[p + 3] = data & 2;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 2) = c[data & 3];
+ vic2->fore_coll_buf[p + 2] = data & 2; data >>= 2;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 1) = c[data];
+ vic2->fore_coll_buf[p + 1] = data & 2;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 0) = c[data];
+ vic2->fore_coll_buf[p + 0] = data & 2;
+}
+
+// Graphics display (8 pixels)
+static void vic2_draw_graphics( vic2_state *vic2 )
+{
+ if (vic2->draw_this_line == 0)
+ {
+ UINT16 p = vic2->graphic_x + HORIZONTALPOS;
+ vic2->fore_coll_buf[p + 7] = 0;
+ vic2->fore_coll_buf[p + 6] = 0;
+ vic2->fore_coll_buf[p + 5] = 0;
+ vic2->fore_coll_buf[p + 4] = 0;
+ vic2->fore_coll_buf[p + 3] = 0;
+ vic2->fore_coll_buf[p + 2] = 0;
+ vic2->fore_coll_buf[p + 1] = 0;
+ vic2->fore_coll_buf[p + 0] = 0;
+ }
+ else if (vic2->ud_border_on)
+ {
+ UINT16 p = vic2->graphic_x + HORIZONTALPOS;
+ vic2->fore_coll_buf[p + 7] = 0;
+ vic2->fore_coll_buf[p + 6] = 0;
+ vic2->fore_coll_buf[p + 5] = 0;
+ vic2->fore_coll_buf[p + 4] = 0;
+ vic2->fore_coll_buf[p + 3] = 0;
+ vic2->fore_coll_buf[p + 2] = 0;
+ vic2->fore_coll_buf[p + 1] = 0;
+ vic2->fore_coll_buf[p + 0] = 0;
+ vic2_draw_background(vic2);
+ }
+ else
+ {
+ UINT8 tmp_col;
+ UINT16 p = vic2->graphic_x + HORIZONTALPOS;
+ switch (GFXMODE)
+ {
+ case 0:
+ vic2_draw_mono(vic2, p, vic2->colors[0], vic2->color_data & 0x0f);
+ break;
+ case 1:
+ if (vic2->color_data & 0x08)
+ vic2_draw_multi(vic2, p, vic2->colors[0], vic2->colors[1], vic2->colors[2], vic2->color_data & 0x07);
+ else
+ vic2_draw_mono(vic2, p, vic2->colors[0], vic2->color_data & 0x0f);
+ break;
+ case 2:
+ vic2_draw_mono(vic2, p, vic2->char_data & 0x0f, vic2->char_data >> 4);
+ break;
+ case 3:
+ vic2_draw_multi(vic2, p, vic2->colors[0], vic2->char_data >> 4, vic2->char_data & 0x0f, vic2->color_data & 0x0f);
+ break;
+ case 4:
+ if (vic2->char_data & 0x80)
+ if (vic2->char_data & 0x40)
+ tmp_col = vic2->colors[3];
+ else
+ tmp_col = vic2->colors[2];
+ else
+ if (vic2->char_data & 0x40)
+ tmp_col = vic2->colors[1];
+ else
+ tmp_col = vic2->colors[0];
+ vic2_draw_mono(vic2, p, tmp_col, vic2->color_data & 0x0f);
+ break;
+ case 5:
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 7) = 0;
+ vic2->fore_coll_buf[p + 7] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 6) = 0;
+ vic2->fore_coll_buf[p + 6] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 5) = 0;
+ vic2->fore_coll_buf[p + 5] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 4) = 0;
+ vic2->fore_coll_buf[p + 4] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 3) = 0;
+ vic2->fore_coll_buf[p + 3] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 2) = 0;
+ vic2->fore_coll_buf[p + 2] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 1) = 0;
+ vic2->fore_coll_buf[p + 1] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 0) = 0;
+ vic2->fore_coll_buf[p + 0] = 0;
+ break;
+ case 6:
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 7) = 0;
+ vic2->fore_coll_buf[p + 7] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 6) = 0;
+ vic2->fore_coll_buf[p + 6] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 5) = 0;
+ vic2->fore_coll_buf[p + 5] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 4) = 0;
+ vic2->fore_coll_buf[p + 4] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 3) = 0;
+ vic2->fore_coll_buf[p + 3] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 2) = 0;
+ vic2->fore_coll_buf[p + 2] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 1) = 0;
+ vic2->fore_coll_buf[p + 1] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 0) = 0;
+ vic2->fore_coll_buf[p + 0] = 0;
+ break;
+ case 7:
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 7) = 0;
+ vic2->fore_coll_buf[p + 7] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 6) = 0;
+ vic2->fore_coll_buf[p + 6] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 5) = 0;
+ vic2->fore_coll_buf[p + 5] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 4) = 0;
+ vic2->fore_coll_buf[p + 4] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 3) = 0;
+ vic2->fore_coll_buf[p + 3] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 2) = 0;
+ vic2->fore_coll_buf[p + 2] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 1) = 0;
+ vic2->fore_coll_buf[p + 1] = 0;
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + 0) = 0;
+ vic2->fore_coll_buf[p + 0] = 0;
+ break;
+ }
+ }
+}
+
+static void vic2_draw_sprites( running_machine &machine, vic2_state *vic2 )
+{
+ int i;
+ UINT8 snum, sbit;
+ UINT8 spr_coll = 0, gfx_coll = 0;
+ UINT32 plane0_l, plane0_r, plane1_l, plane1_r;
+ UINT32 sdata_l = 0, sdata_r = 0;
+
+ for (i = 0; i < 0x400; i++)
+ vic2->spr_coll_buf[i] = 0;
+
+ for (snum = 0, sbit = 1; snum < 8; snum++, sbit <<= 1)
+ {
+ if ((vic2->spr_draw & sbit) && (SPRITE_X_POS(snum) <= (403 - (VIC2_FIRSTCOLUMN + 1))))
+ {
+ UINT16 p = SPRITE_X_POS(snum) + VIC2_X_2_EMU(0) + 8;
+ UINT8 color = SPRITE_COLOR(snum);
+ UINT32 sdata = (vic2->spr_draw_data[snum][0] << 24) | (vic2->spr_draw_data[snum][1] << 16) | (vic2->spr_draw_data[snum][2] << 8);
+
+ if (SPRITE_X_EXPAND(snum))
+ {
+ if (SPRITE_X_POS(snum) > (403 - 24 - (VIC2_FIRSTCOLUMN + 1)))
+ continue;
+
+ if (SPRITE_MULTICOLOR(snum))
+ {
+ sdata_l = (vic2->expandx_multi[(sdata >> 24) & 0xff] << 16) | vic2->expandx_multi[(sdata >> 16) & 0xff];
+ sdata_r = vic2->expandx_multi[(sdata >> 8) & 0xff] << 16;
+ plane0_l = (sdata_l & 0x55555555) | (sdata_l & 0x55555555) << 1;
+ plane1_l = (sdata_l & 0xaaaaaaaa) | (sdata_l & 0xaaaaaaaa) >> 1;
+ plane0_r = (sdata_r & 0x55555555) | (sdata_r & 0x55555555) << 1;
+ plane1_r = (sdata_r & 0xaaaaaaaa) | (sdata_r & 0xaaaaaaaa) >> 1;
+ for (i = 0; i < 32; i++, plane0_l <<= 1, plane1_l <<= 1)
+ {
+ UINT8 col;
+
+ if (plane1_l & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+ if (plane0_l & 0x80000000)
+ col = vic2->spritemulti[3];
+ else
+ col = color;
+ }
+ else
+ {
+ if (plane0_l & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+ col = vic2->spritemulti[1];
+ }
+ else
+ continue;
+ }
+
+ if (vic2->spr_coll_buf[p + i])
+ spr_coll |= vic2->spr_coll_buf[p + i] | sbit;
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (vic2->fore_coll_buf[p + i] == 0)
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = col;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = col;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+
+ for (; i < 48; i++, plane0_r <<= 1, plane1_r <<= 1)
+ {
+ UINT8 col;
+
+ if(plane1_r & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+
+ if (plane0_r & 0x80000000)
+ col = vic2->spritemulti[3];
+ else
+ col = color;
+ }
+ else
+ {
+ if (plane0_r & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+ col = vic2->spritemulti[1];
+ }
+ else
+ continue;
+ }
+
+ if (vic2->spr_coll_buf[p + i])
+ spr_coll |= vic2->spr_coll_buf[p + i] | sbit;
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (vic2->fore_coll_buf[p + i] == 0)
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = col;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = col;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+ }
+ else
+ {
+ sdata_l = (vic2->expandx[(sdata >> 24) & 0xff] << 16) | vic2->expandx[(sdata >> 16) & 0xff];
+ sdata_r = vic2->expandx[(sdata >> 8) & 0xff] << 16;
+
+ for (i = 0; i < 32; i++, sdata_l <<= 1)
+ if (sdata_l & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+
+ if (vic2->spr_coll_buf[p + i])
+ spr_coll |= vic2->spr_coll_buf[p + i] | sbit;
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (vic2->fore_coll_buf[p + i] == 0)
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = color;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = color;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+
+ for (; i < 48; i++, sdata_r <<= 1)
+ if (sdata_r & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+
+ if (vic2->spr_coll_buf[p + i])
+ spr_coll |= vic2->spr_coll_buf[p + i] | sbit;
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (vic2->fore_coll_buf[p + i] == 0)
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = color;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = color;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (SPRITE_MULTICOLOR(snum))
+ {
+ UINT32 plane0 = (sdata & 0x55555555) | (sdata & 0x55555555) << 1;
+ UINT32 plane1 = (sdata & 0xaaaaaaaa) | (sdata & 0xaaaaaaaa) >> 1;
+
+ for (i = 0; i < 24; i++, plane0 <<= 1, plane1 <<= 1)
+ {
+ UINT8 col;
+
+ if (plane1 & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+
+ if (plane0 & 0x80000000)
+ col = vic2->spritemulti[3];
+ else
+ col = color;
+ }
+ else
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+
+ if (plane0 & 0x80000000)
+ col = vic2->spritemulti[1];
+ else
+ continue;
+ }
+
+ if (vic2->spr_coll_buf[p + i])
+ spr_coll |= vic2->spr_coll_buf[p + i] | sbit;
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (vic2->fore_coll_buf[p + i] == 0)
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = col;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = col;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < 24; i++, sdata <<= 1)
+ {
+ if (sdata & 0x80000000)
+ {
+ if (vic2->fore_coll_buf[p + i])
+ {
+ gfx_coll |= sbit;
+ }
+ if (vic2->spr_coll_buf[p + i])
+ {
+ spr_coll |= vic2->spr_coll_buf[p + i] | sbit;
+ }
+ else
+ {
+ if (SPRITE_PRIORITY(snum))
+ {
+ if (vic2->fore_coll_buf[p + i] == 0)
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = color;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ else
+ {
+ vic2->bitmap->pix16(VIC2_RASTER_2_EMU(vic2->rasterline), p + i) = color;
+ vic2->spr_coll_buf[p + i] = sbit;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (SPRITE_COLL)
+ SPRITE_COLL |= spr_coll;
+ else
+ {
+ SPRITE_COLL = spr_coll;
+ if (SPRITE_COLL)
+ vic2_set_interrupt(machine, 4, vic2);
+ }
+
+ if (SPRITE_BG_COLL)
+ SPRITE_BG_COLL |= gfx_coll;
+ else
+ {
+ SPRITE_BG_COLL = gfx_coll;
+ if (SPRITE_BG_COLL)
+ vic2_set_interrupt(machine, 2, vic2);
+ }
+}
+
+
+static TIMER_CALLBACK( pal_timer_callback )
+{
+ vic2_state *vic2 = (vic2_state *)ptr;
+ int i;
+ UINT8 mask;
+ //static int adjust[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ UINT8 cpu_cycles = vic2->cpu->total_cycles() & 0xff;
+ UINT8 vic_cycles = (vic2->cycles_counter + 1) & 0xff;
+ vic2->cycles_counter++;
+
+// printf("%02x %02x %02x\n",cpu_cycles,vic_cycles,vic2->rdy_cycles);
+#if 0
+if (machine.input().code_pressed(KEYCODE_X))
+{
+if (machine.input().code_pressed_once(KEYCODE_Q)) adjust[1]++;
+if (machine.input().code_pressed_once(KEYCODE_W)) adjust[2]++;
+if (machine.input().code_pressed_once(KEYCODE_E)) adjust[3]++;
+if (machine.input().code_pressed_once(KEYCODE_R)) adjust[4]++;
+if (machine.input().code_pressed_once(KEYCODE_T)) adjust[5]++;
+if (machine.input().code_pressed_once(KEYCODE_Y)) adjust[6]++;
+if (machine.input().code_pressed_once(KEYCODE_U)) adjust[7]++;
+if (machine.input().code_pressed_once(KEYCODE_I)) adjust[8]++;
+if (machine.input().code_pressed_once(KEYCODE_A)) adjust[1]--;
+if (machine.input().code_pressed_once(KEYCODE_S)) adjust[2]--;
+if (machine.input().code_pressed_once(KEYCODE_D)) adjust[3]--;
+if (machine.input().code_pressed_once(KEYCODE_F)) adjust[4]--;
+if (machine.input().code_pressed_once(KEYCODE_G)) adjust[5]--;
+if (machine.input().code_pressed_once(KEYCODE_H)) adjust[6]--;
+if (machine.input().code_pressed_once(KEYCODE_J)) adjust[7]--;
+if (machine.input().code_pressed_once(KEYCODE_K)) adjust[8]--;
+if (machine.input().code_pressed_once(KEYCODE_C)) adjust[0]++;
+if (machine.input().code_pressed_once(KEYCODE_V)) adjust[0]--;
+if (machine.input().code_pressed_once(KEYCODE_Z)) printf("b:%02x 1:%02x 2:%02x 3:%02x 4:%02x 5:%02x 6:%02x 7:%02x 8:%02x\n",
+ adjust[0],adjust[1],adjust[2],adjust[3],adjust[4],adjust[5],adjust[6],adjust[7],adjust[8]);
+}
+#define adjust(x) adjust[x]
+#else
+#define adjust(x) 0
+#endif
+
+ switch(vic2->cycle)
+ {
+
+ // Sprite 3, raster counter, raster IRQ, bad line
+ case 1:
+ if (vic2->rasterline == (VIC2_LINES - 1))
+ {
+ vic2->vblanking = 1;
+
+// if (LIGHTPEN_BUTTON)
+ {
+ /* lightpen timer start */
+ machine.scheduler().timer_set(attotime(0, 0), FUNC(vic2_timer_timeout), 1, vic2);
+ }
+ }
+ else
+ {
+ vic2->rasterline++;
+
+ if (vic2->rasterline == VIC2_FIRST_DMA_LINE)
+ vic2->bad_lines_enabled = SCREENON;
+
+ vic2->is_bad_line = ((vic2->rasterline >= VIC2_FIRST_DMA_LINE) && (vic2->rasterline <= VIC2_LAST_DMA_LINE) &&
+ ((vic2->rasterline & 0x07) == VERTICALPOS) && vic2->bad_lines_enabled);
+
+ vic2->draw_this_line = ((VIC2_RASTER_2_EMU(vic2->rasterline) >= VIC2_RASTER_2_EMU(VIC2_FIRST_DISP_LINE)) &&
+ (VIC2_RASTER_2_EMU(vic2->rasterline ) <= VIC2_RASTER_2_EMU(VIC2_LAST_DISP_LINE)));
+ }
+
+ vic2->border_on_sample[0] = vic2->border_on;
+ vic2_spr_ptr_access(machine, vic2, 3);
+ vic2_spr_data_access(machine, vic2, 3, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x08)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x08) vic2->rdy_cycles += (2 + adjust(1));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 3
+ case 2:
+ if (vic2->vblanking)
+ {
+ // Vertical blank, reset counters
+ vic2->rasterline = vic2->vc_base = 0;
+ vic2->ref_cnt = 0xff;
+ vic2->vblanking = 0;
+
+ // Trigger raster IRQ if IRQ in line 0
+ if (RASTERLINE == 0)
+ {
+ vic2_set_interrupt(machine, 1, vic2);
+ }
+ }
+
+ if (vic2->rasterline == RASTERLINE)
+ {
+ vic2_set_interrupt(machine, 1, vic2);
+ }
+
+ vic2->graphic_x = VIC2_X_2_EMU(0);
+
+ vic2_spr_data_access(machine, vic2, 3, 1);
+ vic2_spr_data_access(machine, vic2, 3, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 4
+ case 3:
+ vic2_spr_ptr_access(machine, vic2, 4);
+ vic2_spr_data_access(machine, vic2, 4, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x10)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x10) vic2->rdy_cycles += (2 + adjust(2));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 4
+ case 4:
+ vic2_spr_data_access(machine, vic2, 4, 1);
+ vic2_spr_data_access(machine, vic2, 4, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 5
+ case 5:
+ vic2_spr_ptr_access(machine, vic2, 5);
+ vic2_spr_data_access(machine, vic2, 5, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x20)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x20) vic2->rdy_cycles += (2 + adjust(3));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 5
+ case 6:
+ vic2_spr_data_access(machine, vic2, 5, 1);
+ vic2_spr_data_access(machine, vic2, 5, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 6
+ case 7:
+ vic2_spr_ptr_access(machine, vic2, 6);
+ vic2_spr_data_access(machine, vic2, 6, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x40)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x40) vic2->rdy_cycles += (2 + adjust(4));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 6
+ case 8:
+ vic2_spr_data_access(machine, vic2, 6, 1);
+ vic2_spr_data_access(machine, vic2, 6, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 7
+ case 9:
+ vic2_spr_ptr_access(machine, vic2, 7);
+ vic2_spr_data_access(machine, vic2, 7, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x80)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x80) vic2->rdy_cycles += (2 + adjust(5));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 7
+ case 10:
+ vic2_spr_data_access(machine, vic2, 7, 1);
+ vic2_spr_data_access(machine, vic2, 7, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Refresh
+ case 11:
+ vic2_refresh_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line
+ case 12:
+ vic2_refresh_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line, raster_x
+ case 13:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_refresh_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ vic2->raster_x = 0xfffc;
+
+ if ((vic2->in_rdy_workaround_func(0) == 0 ) && (vic2->is_bad_line))
+ vic2->rdy_cycles += (43+adjust(0));
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line, RC, VC
+ case 14:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_refresh_access(machine, vic2);
+ vic2_rc_if_bad_line(vic2);
+
+ vic2->vc = vic2->vc_base;
+
+ if ((vic2->in_rdy_workaround_func(0) == 1 ) && (vic2->is_bad_line))
+ vic2->rdy_cycles += (42+adjust(0));
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line, sprite y expansion
+ case 15:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_refresh_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ for (i = 0; i < 8; i++)
+ if (vic2->spr_exp_y & (1 << i))
+ vic2->mc_base[i] += 2;
+
+ vic2->ml_index = 0;
+ vic2_matrix_access(machine, vic2);
+
+ if ((vic2->in_rdy_workaround_func(0) == 2 ) && (vic2->is_bad_line))
+ vic2->rdy_cycles += (41+adjust(0));
+
+ vic2->cycle++;
+ break;
+
+ // Graphics, sprite y expansion, sprite DMA
+ case 16:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ {
+ if (vic2->spr_exp_y & mask)
+ vic2->mc_base[i]++;
+ if ((vic2->mc_base[i] & 0x3f) == 0x3f)
+ vic2->spr_dma_on &= ~mask;
+ }
+
+ vic2_matrix_access(machine, vic2);
+
+ if ((vic2->in_rdy_workaround_func(0) == 3 ) && (vic2->is_bad_line))
+ vic2->rdy_cycles += (40+adjust(0));
+
+ vic2->cycle++;
+ break;
+
+ // Graphics, check border
+ case 17:
+ if (COLUMNS40)
+ {
+ if (vic2->rasterline == vic2->dy_stop)
+ vic2->ud_border_on = 1;
+ else
+ {
+ if (SCREENON)
+ {
+ if (vic2->rasterline == vic2->dy_start)
+ vic2->border_on = vic2->ud_border_on = 0;
+ else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ } else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ }
+ }
+
+ // Second sample of border state
+ vic2->border_on_sample[1] = vic2->border_on;
+
+ vic2_draw_background(vic2);
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+ vic2_matrix_access(machine, vic2);
+
+ if ((vic2->in_rdy_workaround_func(0) == 4 ) && (vic2->is_bad_line))
+ vic2->rdy_cycles += (40+adjust(0));
+
+ vic2->cycle++;
+ break;
+
+ // Check border
+ case 18:
+ if (!COLUMNS40)
+ {
+ if (vic2->rasterline == vic2->dy_stop)
+ vic2->ud_border_on = 1;
+ else
+ {
+ if (SCREENON)
+ {
+ if (vic2->rasterline == vic2->dy_start)
+ vic2->border_on = vic2->ud_border_on = 0;
+ else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ } else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ }
+ }
+
+ // Third sample of border state
+ vic2->border_on_sample[2] = vic2->border_on;
+
+ // Graphics
+
+ 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:
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+ vic2_matrix_access(machine, vic2);
+ vic2->last_char_data = vic2->char_data;
+
+ vic2->cycle++;
+ break;
+
+ // Graphics, sprite y expansion, sprite DMA
+ case 55:
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ // sprite y expansion
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ if (SPRITE_Y_EXPAND (i))
+ vic2->spr_exp_y ^= mask;
+
+ vic2_check_sprite_dma(vic2);
+
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Check border, sprite DMA
+ case 56:
+ if (!COLUMNS40)
+ vic2->border_on = 1;
+
+ // Fourth sample of border state
+ vic2->border_on_sample[3] = vic2->border_on;
+
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_idle_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+ vic2_check_sprite_dma(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Check border, sprites
+ case 57:
+ if (COLUMNS40)
+ vic2->border_on = 1;
+
+ // Fifth sample of border state
+ vic2->border_on_sample[4] = vic2->border_on;
+
+ // Sample spr_disp_on and spr_data for sprite drawing
+ vic2->spr_draw = vic2->spr_disp_on;
+ if (vic2->spr_draw)
+ memcpy(vic2->spr_draw_data, vic2->spr_data, 8 * 4);
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ if ((vic2->spr_disp_on & mask) && !(vic2->spr_dma_on & mask))
+ vic2->spr_disp_on &= ~mask;
+
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_idle_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 0, sprite DMA, MC, RC
+ case 58:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ {
+ vic2->mc[i] = vic2->mc_base[i];
+ if ((vic2->spr_dma_on & mask) && ((vic2->rasterline & 0xff) == SPRITE_Y_POS(i)))
+ vic2->spr_disp_on |= mask;
+ }
+
+ vic2_spr_ptr_access(machine, vic2, 0);
+ vic2_spr_data_access(machine, vic2, 0, 0);
+
+ if (vic2->rc == 7)
+ {
+ vic2->vc_base = vic2->vc;
+ vic2->display_state = 0;
+ }
+
+ if (vic2->is_bad_line || vic2->display_state)
+ {
+ vic2->display_state = 1;
+ vic2->rc = (vic2->rc + 1) & 7;
+ }
+
+ if (vic2->spr_dma_on & 0x01)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x01) vic2->rdy_cycles += (2 + adjust(6));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 0
+ case 59:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_spr_data_access(machine, vic2, 0, 1);
+ vic2_spr_data_access(machine, vic2, 0, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 1, draw
+ case 60:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+
+ if (vic2->draw_this_line)
+ {
+ vic2_draw_sprites(machine, vic2);
+
+ if (vic2->border_on_sample[0])
+ for (i = 0; i < 4; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[i]);
+
+ if (vic2->border_on_sample[1])
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(4 * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[4]);
+
+ if (vic2->border_on_sample[2])
+ for (i = 5; i < 43; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[i]);
+
+ if (vic2->border_on_sample[3])
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(43 * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[43]);
+
+ if (vic2->border_on_sample[4])
+ {
+ for (i = 44; i < 48; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[i]);
+ for (i = 48; i < 51; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[47]);
+ }
+ }
+
+ vic2_spr_ptr_access(machine, vic2, 1);
+ vic2_spr_data_access(machine, vic2, 1, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x02)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x02) vic2->rdy_cycles += (2 + adjust(7));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 1
+ case 61:
+ vic2_spr_data_access(machine, vic2, 1, 1);
+ vic2_spr_data_access(machine, vic2, 1, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 2
+ case 62:
+ vic2_spr_ptr_access(machine, vic2, 2);
+ vic2_spr_data_access(machine, vic2, 2, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x04)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ if (vic2->spr_dma_on & 0x04) vic2->rdy_cycles += (2 + adjust(8));
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 2
+ case 63:
+ vic2_spr_data_access(machine, vic2, 2, 1);
+ vic2_spr_data_access(machine, vic2, 2, 2);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->rasterline == vic2->dy_stop)
+ vic2->ud_border_on = 1;
+ else
+ if (SCREENON && (vic2->rasterline == vic2->dy_start))
+ vic2->ud_border_on = 0;
+
+ // Last cycle
+ vic2->cycle = 1;
+ }
+
+ if ((cpu_cycles == vic_cycles) && (vic2->rdy_cycles > 0))
+ {
+ device_spin_until_time (machine.firstcpu, vic2->cpu->cycles_to_attotime(vic2->rdy_cycles));
+ vic2->rdy_cycles = 0;
+ }
+
+ vic2->raster_x += 8;
+ machine.scheduler().timer_set(vic2->cpu->cycles_to_attotime(1), FUNC(pal_timer_callback), 0, vic2);
+}
+
+static TIMER_CALLBACK( ntsc_timer_callback )
+{
+ vic2_state *vic2 = (vic2_state *)ptr;
+ int i;
+ UINT8 mask;
+ vic2->cycles_counter++;
+
+ switch (vic2->cycle)
+ {
+
+ // Sprite 3, raster counter, raster IRQ, bad line
+ case 1:
+ if (vic2->rasterline == (VIC2_LINES - 1))
+ {
+ vic2->vblanking = 1;
+
+// if (LIGHTPEN_BUTTON)
+ {
+ /* lightpen timer starten */
+ machine.scheduler().timer_set(attotime(0, 0), FUNC(vic2_timer_timeout), 1, vic2);
+ }
+ }
+ else
+ {
+ vic2->rasterline++;
+
+ if (vic2->rasterline == VIC2_FIRST_DMA_LINE)
+ vic2->bad_lines_enabled = SCREENON;
+
+ vic2->is_bad_line = ((vic2->rasterline >= VIC2_FIRST_DMA_LINE) && (vic2->rasterline <= VIC2_LAST_DMA_LINE) &&
+ ((vic2->rasterline & 0x07) == VERTICALPOS) && vic2->bad_lines_enabled);
+
+ vic2->draw_this_line = ((VIC2_RASTER_2_EMU(vic2->rasterline) >= VIC2_RASTER_2_EMU(VIC2_FIRST_DISP_LINE)) &&
+ (VIC2_RASTER_2_EMU(vic2->rasterline ) <= VIC2_RASTER_2_EMU(VIC2_LAST_DISP_LINE)));
+ }
+
+ vic2->border_on_sample[0] = vic2->border_on;
+ vic2_spr_ptr_access(machine, vic2, 3);
+ vic2_spr_data_access(machine, vic2, 3, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x08)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 3
+ case 2:
+ if (vic2->vblanking)
+ {
+ // Vertical blank, reset counters
+ vic2->rasterline = vic2->vc_base = 0;
+ vic2->ref_cnt = 0xff;
+ vic2->vblanking = 0;
+
+ // Trigger raster IRQ if IRQ in line 0
+ if (RASTERLINE == 0)
+ {
+ vic2_set_interrupt(machine, 1, vic2);
+ }
+ }
+
+ if (vic2->rasterline == RASTERLINE)
+ {
+ vic2_set_interrupt(machine, 1, vic2);
+ }
+
+ vic2->graphic_x = VIC2_X_2_EMU(0);
+
+ vic2_spr_data_access(machine, vic2, 3, 1);
+ vic2_spr_data_access(machine, vic2, 3, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 4
+ case 3:
+ vic2_spr_ptr_access(machine, vic2, 4);
+ vic2_spr_data_access(machine, vic2, 4, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x10)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 4
+ case 4:
+ vic2_spr_data_access(machine, vic2, 4, 1);
+ vic2_spr_data_access(machine, vic2, 4, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 5
+ case 5:
+ vic2_spr_ptr_access(machine, vic2, 5);
+ vic2_spr_data_access(machine, vic2, 5, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x20)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 5
+ case 6:
+ vic2_spr_data_access(machine, vic2, 5, 1);
+ vic2_spr_data_access(machine, vic2, 5, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 6
+ case 7:
+ vic2_spr_ptr_access(machine, vic2, 6);
+ vic2_spr_data_access(machine, vic2, 6, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x40)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 6
+ case 8:
+ vic2_spr_data_access(machine, vic2, 6, 1);
+ vic2_spr_data_access(machine, vic2, 6, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 7
+ case 9:
+ vic2_spr_ptr_access(machine, vic2, 7);
+ vic2_spr_data_access(machine, vic2, 7, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x80)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 7
+ case 10:
+ vic2_spr_data_access(machine, vic2, 7, 1);
+ vic2_spr_data_access(machine, vic2, 7, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Refresh
+ case 11:
+ vic2_refresh_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line
+ case 12:
+ vic2_refresh_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line, raster_x
+ case 13:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_refresh_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ vic2->raster_x = 0xfffc;
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line, RC, VC
+ case 14:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_refresh_access(machine, vic2);
+ vic2_rc_if_bad_line(vic2);
+
+ vic2->vc = vic2->vc_base;
+
+ vic2->cycle++;
+ break;
+
+ // Refresh, fetch if bad line, sprite y expansion
+ case 15:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_refresh_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ for (i = 0; i < 8; i++)
+ if (vic2->spr_exp_y & (1 << i))
+ vic2->mc_base[i] += 2;
+
+ if (vic2->is_bad_line)
+ vic2_suspend_cpu(machine, vic2);
+
+ vic2->ml_index = 0;
+ vic2_matrix_access(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Graphics, sprite y expansion, sprite DMA
+ case 16:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ {
+ if (vic2->spr_exp_y & mask)
+ vic2->mc_base[i]++;
+ if ((vic2->mc_base[i] & 0x3f) == 0x3f)
+ vic2->spr_dma_on &= ~mask;
+ }
+
+ vic2_matrix_access(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Graphics, check border
+ case 17:
+ if (COLUMNS40)
+ {
+ if (vic2->rasterline == vic2->dy_stop)
+ vic2->ud_border_on = 1;
+ else
+ {
+ if (SCREENON)
+ {
+ if (vic2->rasterline == vic2->dy_start)
+ vic2->border_on = vic2->ud_border_on = 0;
+ else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ }
+ else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ }
+ }
+
+ // Second sample of border state
+ vic2->border_on_sample[1] = vic2->border_on;
+
+ vic2_draw_background(vic2);
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+ vic2_matrix_access(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Check border
+ case 18:
+ if (!COLUMNS40)
+ {
+ if (vic2->rasterline == vic2->dy_stop)
+ vic2->ud_border_on = 1;
+ else
+ {
+ if (SCREENON)
+ {
+ if (vic2->rasterline == vic2->dy_start)
+ vic2->border_on = vic2->ud_border_on = 0;
+ else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ }
+ else
+ if (vic2->ud_border_on == 0)
+ vic2->border_on = 0;
+ }
+ }
+
+ // Third sample of border state
+ vic2->border_on_sample[2] = vic2->border_on;
+
+ // Graphics
+
+ 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:
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_fetch_if_bad_line(vic2);
+ vic2_matrix_access(machine, vic2);
+ vic2->last_char_data = vic2->char_data;
+
+ vic2->cycle++;
+ break;
+
+ // Graphics, sprite y expansion, sprite DMA
+ case 55:
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_graphics_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ // sprite y expansion
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ if (SPRITE_Y_EXPAND (i))
+ vic2->spr_exp_y ^= mask;
+
+ vic2_check_sprite_dma(vic2);
+
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Check border, sprite DMA
+ case 56:
+ if (!COLUMNS40)
+ vic2->border_on = 1;
+
+ // Fourth sample of border state
+ vic2->border_on_sample[3] = vic2->border_on;
+
+ vic2_draw_graphics(vic2);
+ vic2_sample_border(vic2);
+ vic2_idle_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+ vic2_check_sprite_dma(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Check border, sprites
+ case 57:
+ if (COLUMNS40)
+ vic2->border_on = 1;
+
+ // Fifth sample of border state
+ vic2->border_on_sample[4] = vic2->border_on;
+
+ // Sample spr_disp_on and spr_data for sprite drawing
+ vic2->spr_draw = vic2->spr_disp_on;
+ if (vic2->spr_draw)
+ memcpy(vic2->spr_draw_data, vic2->spr_data, 8 * 4);
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ if ((vic2->spr_disp_on & mask) && !(vic2->spr_dma_on & mask))
+ vic2->spr_disp_on &= ~mask;
+
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_idle_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // for NTSC 6567R8
+ case 58:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_idle_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // for NTSC 6567R8
+ case 59:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_idle_access(machine, vic2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 0, sprite DMA, MC, RC
+ case 60:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+
+ mask = 1;
+ for (i = 0; i < 8; i++, mask <<= 1)
+ {
+ vic2->mc[i] = vic2->mc_base[i];
+ if ((vic2->spr_dma_on & mask) && ((vic2->rasterline & 0xff) == SPRITE_Y_POS(i)))
+ vic2->spr_disp_on |= mask;
+ }
+
+ vic2_spr_ptr_access(machine, vic2, 0);
+ vic2_spr_data_access(machine, vic2, 0, 0);
+
+ if (vic2->rc == 7)
+ {
+ vic2->vc_base = vic2->vc;
+ vic2->display_state = 0;
+ }
+
+ if (vic2->is_bad_line || vic2->display_state)
+ {
+ vic2->display_state = 1;
+ vic2->rc = (vic2->rc + 1) & 7;
+ }
+
+ if (vic2->spr_dma_on & 0x01)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 0
+ case 61:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+ vic2_spr_data_access(machine, vic2, 0, 1);
+ vic2_spr_data_access(machine, vic2, 0, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 1, draw
+ case 62:
+ vic2_draw_background(vic2);
+ vic2_sample_border(vic2);
+
+ if (vic2->draw_this_line)
+ {
+ vic2_draw_sprites(machine, vic2);
+
+ if (vic2->border_on_sample[0])
+ for (i = 0; i < 4; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[i]);
+
+ if (vic2->border_on_sample[1])
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(4 * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[4]);
+
+ if (vic2->border_on_sample[2])
+ for (i = 5; i < 43; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[i]);
+
+ if (vic2->border_on_sample[3])
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(43 * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[43]);
+
+ if (vic2->border_on_sample[4])
+ {
+ for (i = 44; i < 48; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[i]);
+ for (i = 48; i < 53; i++)
+ vic2->bitmap->plot_box(VIC2_X_2_EMU(i * 8), VIC2_RASTER_2_EMU(vic2->rasterline), 8, 1, vic2->border_color_sample[47]);
+ }
+ }
+
+ vic2_spr_ptr_access(machine, vic2, 1);
+ vic2_spr_data_access(machine, vic2, 1, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x02)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 1
+ case 63:
+ vic2_spr_data_access(machine, vic2, 1, 1);
+ vic2_spr_data_access(machine, vic2, 1, 2);
+ vic2_display_if_bad_line(vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 2
+ case 64:
+ vic2_spr_ptr_access(machine, vic2, 2);
+ vic2_spr_data_access(machine, vic2, 2, 0);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->spr_dma_on & 0x04)
+ vic2_suspend_cpu(machine, vic2);
+ else
+ vic2_resume_cpu(machine, vic2);
+
+ vic2->cycle++;
+ break;
+
+ // Sprite 2
+ case 65:
+ vic2_spr_data_access(machine, vic2, 2, 1);
+ vic2_spr_data_access(machine, vic2, 2, 2);
+ vic2_display_if_bad_line(vic2);
+
+ if (vic2->rasterline == vic2->dy_stop)
+ vic2->ud_border_on = 1;
+ else
+ if (SCREENON && (vic2->rasterline == vic2->dy_start))
+ vic2->ud_border_on = 0;
+
+ // Last cycle
+ vic2->cycle = 1;
+ }
+
+ vic2->raster_x += 8;
+ machine.scheduler().timer_set(vic2->cpu->cycles_to_attotime(1), FUNC(ntsc_timer_callback), 0, vic2);
+}
+
+
+/*****************************************************************************
+ I/O HANDLERS
+*****************************************************************************/
+
+void vic2_set_rastering( device_t *device, int onoff )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ vic2->on = onoff;
+}
+
+int vic2e_k0_r( device_t *device )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ return VIC2E_K0_LEVEL;
+}
+
+int vic2e_k1_r( device_t *device )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ return VIC2E_K1_LEVEL;
+}
+
+int vic2e_k2_r( device_t *device )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ return VIC2E_K2_LEVEL;
+}
+
+
+WRITE8_DEVICE_HANDLER( vic2_port_w )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ running_machine &machine = device->machine();
+
+ DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
+ offset &= 0x3f;
+
+ switch (offset)
+ {
+ case 0x01:
+ case 0x03:
+ case 0x05:
+ case 0x07:
+ case 0x09:
+ case 0x0b:
+ case 0x0d:
+ case 0x0f:
+ vic2->reg[offset] = data; /* sprite y positions */
+ break;
+
+ case 0x00:
+ case 0x02:
+ case 0x04:
+ case 0x06:
+ case 0x08:
+ case 0x0a:
+ case 0x0c:
+ case 0x0e:
+ vic2->reg[offset] = data; /* sprite x positions */
+ break;
+
+ case 0x10:
+ vic2->reg[offset] = data; /* sprite x positions */
+ break;
+
+ case 0x17: /* sprite y size */
+ vic2->spr_exp_y |= ~data;
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x1d: /* sprite x size */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x1b: /* sprite background priority */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x1c: /* sprite multicolor mode select */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ /* sprite colors */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x25: /* sprite multicolor */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ vic2->spritemulti[1] = SPRITE_MULTICOLOR1;
+ }
+ break;
+
+ case 0x26: /* sprite multicolor */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ vic2->spritemulti[3] = SPRITE_MULTICOLOR2;
+ }
+ break;
+
+ case 0x19:
+ vic2_clear_interrupt(machine, data & 0x0f, vic2);
+ break;
+
+ case 0x1a: /* irq mask */
+ vic2->reg[offset] = data;
+ vic2_set_interrupt(machine, 0, vic2); // beamrider needs this
+ break;
+
+ case 0x11:
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ if (data & 8)
+ {
+ vic2->dy_start = ROW25_YSTART;
+ vic2->dy_stop = ROW25_YSTOP;
+ }
+ else
+ {
+ vic2->dy_start = ROW24_YSTART;
+ vic2->dy_stop = ROW24_YSTOP;
+ }
+ }
+ break;
+
+ case 0x12:
+ if (data != vic2->reg[offset])
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x16:
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x18:
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ vic2->videoaddr = VIDEOADDR;
+ vic2->chargenaddr = CHARGENADDR;
+ vic2->bitmapaddr = BITMAPADDR;
+ }
+ break;
+
+ case 0x21: /* background color */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ vic2->colors[0] = BACKGROUNDCOLOR;
+ }
+ break;
+
+ case 0x22: /* background color 1 */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ vic2->colors[1] = MULTICOLOR1;
+ }
+ break;
+
+ case 0x23: /* background color 2 */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ vic2->colors[2] = MULTICOLOR2;
+ }
+ break;
+
+ case 0x24: /* background color 3 */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ vic2->colors[3] = FOREGROUNDCOLOR;
+ }
+ break;
+
+ case 0x20: /* framecolor */
+ if (vic2->reg[offset] != data)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x2f:
+ if (vic2->type == VIC8564 || vic2->type == VIC8566)
+ {
+ DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x30:
+ if (vic2->type == VIC8564 || vic2->type == VIC8566)
+ {
+ vic2->reg[offset] = data;
+ }
+ break;
+
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f:
+ vic2->reg[offset] = data;
+ DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
+ break;
+
+ default:
+ vic2->reg[offset] = data;
+ break;
+ }
+}
+
+READ8_DEVICE_HANDLER( vic2_port_r )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ running_machine &machine = device->machine();
+ int val = 0;
+
+ offset &= 0x3f;
+
+ switch (offset)
+ {
+ case 0x11:
+ val = (vic2->reg[offset] & ~0x80) | ((vic2->rasterline & 0x100) >> 1);
+ break;
+
+ case 0x12:
+ val = vic2->rasterline & 0xff;
+ break;
+
+ case 0x16:
+ val = vic2->reg[offset] | 0xc0;
+ break;
+
+ case 0x18:
+ val = vic2->reg[offset] | 0x01;
+ break;
+
+ case 0x19: /* interrupt flag register */
+ /* vic2_clear_interrupt(0xf); */
+ val = vic2->reg[offset] | 0x70;
+ break;
+
+ case 0x1a:
+ val = vic2->reg[offset] | 0xf0;
+ break;
+
+ case 0x1e: /* sprite to sprite collision detect */
+ val = vic2->reg[offset];
+ vic2->reg[offset] = 0;
+ vic2_clear_interrupt(machine, 4, vic2);
+ break;
+
+ case 0x1f: /* sprite to background collision detect */
+ val = vic2->reg[offset];
+ vic2->reg[offset] = 0;
+ vic2_clear_interrupt(machine, 2, vic2);
+ break;
+
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ case 0x23:
+ case 0x24:
+ val = vic2->reg[offset];
+ break;
+
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ case 0x06:
+ case 0x07:
+ case 0x08:
+ case 0x09:
+ case 0x0a:
+ case 0x0b:
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ case 0x0f:
+ case 0x10:
+ case 0x17:
+ case 0x1b:
+ case 0x1c:
+ case 0x1d:
+ case 0x25:
+ case 0x26:
+ case 0x27:
+ case 0x28:
+ case 0x29:
+ case 0x2a:
+ case 0x2b:
+ case 0x2c:
+ case 0x2d:
+ case 0x2e:
+ val = vic2->reg[offset];
+ break;
+
+ case 0x2f:
+ case 0x30:
+ if (vic2->type == VIC8564 || vic2->type == VIC8566)
+ {
+ val = vic2->reg[offset];
+ DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val));
+ }
+ else
+ val = 0xff;
+ break;
+
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ case 0x3a:
+ case 0x3b:
+ case 0x3c:
+ case 0x3d:
+ case 0x3e:
+ case 0x3f: /* not used */
+ // val = vic2->reg[offset]; //
+ val = 0xff;
+ DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val));
+ break;
+
+ default:
+ val = vic2->reg[offset];
+ }
+
+ if ((offset != 0x11) && (offset != 0x12))
+ DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val));
+ return val;
+}
+
+UINT32 vic2_video_update( device_t *device, bitmap_ind16 &bitmap, const rectangle &cliprect )
+{
+ vic2_state *vic2 = get_safe_token(device);
+
+ if (vic2->on)
+ copybitmap(bitmap, *vic2->bitmap, 0, 0, 0, 0, cliprect);
+ return 0;
+}
+
+/*****************************************************************************
+ DEVICE INTERFACE
+*****************************************************************************/
+
+static DEVICE_START( vic2 )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ const vic2_interface *intf = (vic2_interface *)device->static_config();
+ int width, height;
+ int i;
+
+ // resolve callbacks
+ vic2->in_lightpen_x_func.resolve(intf->in_x_cb, *device);
+ vic2->in_lightpen_y_func.resolve(intf->in_y_cb, *device);
+ vic2->in_lightpen_button_func.resolve(intf->in_button_cb, *device);
+ vic2->in_dma_read_func.resolve(intf->in_dma_read_cb, *device);
+ vic2->in_dma_read_color_func.resolve(intf->in_dma_read_color_cb, *device);
+ vic2->out_interrupt_func.resolve(intf->out_irq_cb, *device);
+ vic2->in_rdy_workaround_func.resolve(intf->in_rdy_cb, *device);
+
+ vic2->cpu = device->machine().device<cpu_device>(intf->cpu);
+
+ vic2->screen = device->machine().device<screen_device>(intf->screen);
+ width = vic2->screen->width();
+ height = vic2->screen->height();
+
+ vic2->bitmap = auto_bitmap_ind16_alloc(device->machine(), width, height);
+
+ vic2->type = intf->type;
+
+ // immediately call the timer to handle the first line
+ if (vic2->type == VIC6569 || vic2->type == VIC8566)
+ device->machine().scheduler().timer_set(downcast<cpu_device *>(vic2->cpu)->cycles_to_attotime(0), FUNC(pal_timer_callback), 0, vic2);
+ else
+ device->machine().scheduler().timer_set(downcast<cpu_device *>(vic2->cpu)->cycles_to_attotime(0), FUNC(ntsc_timer_callback), 0, vic2);
+
+ for (i = 0; i < 256; i++)
+ {
+ vic2->expandx[i] = 0;
+ if (i & 1)
+ vic2->expandx[i] |= 3;
+ if (i & 2)
+ vic2->expandx[i] |= 0xc;
+ if (i & 4)
+ vic2->expandx[i] |= 0x30;
+ if (i & 8)
+ vic2->expandx[i] |= 0xc0;
+ if (i & 0x10)
+ vic2->expandx[i] |= 0x300;
+ if (i & 0x20)
+ vic2->expandx[i] |= 0xc00;
+ if (i & 0x40)
+ vic2->expandx[i] |= 0x3000;
+ if (i & 0x80)
+ vic2->expandx[i] |= 0xc000;
+ }
+
+ for (i = 0; i < 256; i++)
+ {
+ vic2->expandx_multi[i] = 0;
+ if (i & 1)
+ vic2->expandx_multi[i] |= 5;
+ if (i & 2)
+ vic2->expandx_multi[i] |= 0xa;
+ if (i & 4)
+ vic2->expandx_multi[i] |= 0x50;
+ if (i & 8)
+ vic2->expandx_multi[i] |= 0xa0;
+ if (i & 0x10)
+ vic2->expandx_multi[i] |= 0x500;
+ if (i & 0x20)
+ vic2->expandx_multi[i] |= 0xa00;
+ if (i & 0x40)
+ vic2->expandx_multi[i] |= 0x5000;
+ if (i & 0x80)
+ vic2->expandx_multi[i] |= 0xa000;
+ }
+
+ device->save_item(NAME(vic2->reg));
+
+ device->save_item(NAME(vic2->on));
+
+ //device->save_item(NAME(vic2->bitmap));
+
+ device->save_item(NAME(vic2->chargenaddr));
+ device->save_item(NAME(vic2->videoaddr));
+ device->save_item(NAME(vic2->bitmapaddr));
+
+ device->save_item(NAME(vic2->colors));
+ device->save_item(NAME(vic2->spritemulti));
+
+ device->save_item(NAME(vic2->rasterline));
+ device->save_item(NAME(vic2->cycles_counter));
+ device->save_item(NAME(vic2->cycle));
+ device->save_item(NAME(vic2->raster_x));
+ device->save_item(NAME(vic2->graphic_x));
+
+ device->save_item(NAME(vic2->dy_start));
+ device->save_item(NAME(vic2->dy_stop));
+
+ device->save_item(NAME(vic2->draw_this_line));
+ device->save_item(NAME(vic2->is_bad_line));
+ device->save_item(NAME(vic2->bad_lines_enabled));
+ device->save_item(NAME(vic2->display_state));
+ device->save_item(NAME(vic2->char_data));
+ device->save_item(NAME(vic2->gfx_data));
+ device->save_item(NAME(vic2->color_data));
+ device->save_item(NAME(vic2->last_char_data));
+ device->save_item(NAME(vic2->matrix_line));
+ device->save_item(NAME(vic2->color_line));
+ device->save_item(NAME(vic2->vblanking));
+ device->save_item(NAME(vic2->ml_index));
+ device->save_item(NAME(vic2->rc));
+ device->save_item(NAME(vic2->vc));
+ device->save_item(NAME(vic2->vc_base));
+ device->save_item(NAME(vic2->ref_cnt));
+
+ device->save_item(NAME(vic2->spr_coll_buf));
+ device->save_item(NAME(vic2->fore_coll_buf));
+ device->save_item(NAME(vic2->spr_exp_y));
+ device->save_item(NAME(vic2->spr_dma_on));
+ device->save_item(NAME(vic2->spr_draw));
+ device->save_item(NAME(vic2->spr_disp_on));
+ device->save_item(NAME(vic2->spr_ptr));
+ device->save_item(NAME(vic2->mc_base));
+ device->save_item(NAME(vic2->mc));
+
+ for (i = 0; i < 8; i++)
+ {
+ device->save_item(NAME(vic2->spr_data[i]), i);
+ device->save_item(NAME(vic2->spr_draw_data[i]), i);
+ }
+
+ device->save_item(NAME(vic2->border_on));
+ device->save_item(NAME(vic2->ud_border_on));
+ device->save_item(NAME(vic2->border_on_sample));
+ device->save_item(NAME(vic2->border_color_sample));
+
+ device->save_item(NAME(vic2->first_ba_cycle));
+ device->save_item(NAME(vic2->device_suspended));
+}
+
+static DEVICE_RESET( vic2 )
+{
+ vic2_state *vic2 = get_safe_token(device);
+ int i, j;
+
+ memset(vic2->reg, 0, ARRAY_LENGTH(vic2->reg));
+
+ for (i = 0; i < ARRAY_LENGTH(vic2->mc); i++)
+ vic2->mc[i] = 63;
+
+ // from 0 to 311 (0 first, PAL) or from 0 to 261 (? first, NTSC 6567R56A) or from 0 to 262 (? first, NTSC 6567R8)
+ vic2->rasterline = 0; // VIC2_LINES - 1;
+
+ vic2->cycles_counter = -1;
+ vic2->cycle = 63;
+
+ vic2->on = 1;
+
+ vic2->dy_start = ROW24_YSTART;
+ vic2->dy_stop = ROW24_YSTOP;
+
+ vic2->draw_this_line = 0;
+ vic2->is_bad_line = 0;
+ vic2->bad_lines_enabled = 0;
+ vic2->display_state = 0;
+ vic2->char_data = 0;
+ vic2->gfx_data = 0;
+ vic2->color_data = 0;
+ vic2->last_char_data = 0;
+ vic2->vblanking = 0;
+ vic2->ml_index = 0;
+ vic2->rc = 0;
+ vic2->vc = 0;
+ vic2->vc_base = 0;
+ vic2->ref_cnt = 0;
+
+ vic2->spr_exp_y = 0;
+ vic2->spr_dma_on = 0;
+ vic2->spr_draw = 0;
+ vic2->spr_disp_on = 0;
+
+
+ vic2->border_on = 0;
+ vic2->ud_border_on = 0;
+
+ vic2->first_ba_cycle = 0;
+ vic2->device_suspended = 0;
+
+ memset(vic2->matrix_line, 0, ARRAY_LENGTH(vic2->matrix_line));
+ memset(vic2->color_line, 0, ARRAY_LENGTH(vic2->color_line));
+
+ memset(vic2->spr_coll_buf, 0, ARRAY_LENGTH(vic2->spr_coll_buf));
+ memset(vic2->fore_coll_buf, 0, ARRAY_LENGTH(vic2->fore_coll_buf));
+ memset(vic2->border_on_sample, 0, ARRAY_LENGTH(vic2->border_on_sample));
+ memset(vic2->border_color_sample, 0, ARRAY_LENGTH(vic2->border_color_sample));
+
+ for (i = 0; i < 8; i++)
+ {
+ vic2->spr_ptr[i] = 0;
+ vic2->mc_base[i] = 0;
+ vic2->mc[i] = 0;
+ for (j = 0; j < 4; j++)
+ {
+ vic2->spr_draw_data[i][j] = 0;
+ vic2->spr_data[i][j] = 0;
+ }
+ }
+
+}
+
+
+/*-------------------------------------------------
+ device definition
+-------------------------------------------------*/
+
+static const char DEVTEMPLATE_SOURCE[] = __FILE__;
+
+#define DEVTEMPLATE_ID(p,s) p##vic2##s
+#define DEVTEMPLATE_FEATURES DT_HAS_START | DT_HAS_RESET
+#define DEVTEMPLATE_NAME "6567 / 6569 VIC II"
+#define DEVTEMPLATE_FAMILY "6567 / 6569 VIC II"
+#include "devtempl.h"
+
+DEFINE_LEGACY_DEVICE(VIC2, vic2);