1 // license:BSD-3-Clause
2 // copyright-holders:Peter Trauner
3 /***************************************************************************
4 
5     Video Interface Chip (4567)
6 
7     original emulation by PeT (mess@utanet.at)
8 
9     2010-02: converted to be a device and split from vic II
10 
11     TODO:
12       - plenty of cleanups
13       - emulate variants of the vic chip
14       - update vic III to use the new vic6567.c code for the vic II comaptibility
15 
16 ***************************************************************************/
17 
18 #include "emu.h"
19 #include "video/vic4567.h"
20 
21 #include "screen.h"
22 
23 #include <algorithm>
24 
25 
26 /*****************************************************************************
27     CONSTANTS
28 *****************************************************************************/
29 
30 #define VERBOSE_LEVEL 0
31 #define DBG_LOG(N,M,A) \
32 	do { \
33 		if(VERBOSE_LEVEL >= N) \
34 		{ \
35 			if( M ) \
36 				logerror("%11.6f: %-24s", machine().time().as_double(), (char*) M ); \
37 			logerror A; \
38 		} \
39 	} while (0)
40 
41 #define VREFRESHINLINES         28
42 
43 #define VIC2_YPOS               50
44 #define RASTERLINE_2_C64(a)     (a)
45 #define C64_2_RASTERLINE(a)     (a)
46 #define XPOS                (VIC2_STARTVISIBLECOLUMNS + (VIC2_VISIBLECOLUMNS - VIC2_HSIZE) / 2)
47 #define YPOS                (VIC2_STARTVISIBLELINES /* + (VIC2_VISIBLELINES - VIC2_VSIZE) / 2 */)
48 #define FIRSTLINE               10 /* 36 ((VIC2_VISIBLELINES - VIC2_VSIZE)/2) */
49 #define FIRSTCOLUMN         50
50 
51 /* 2008-05 FP: lightpen code needs to read input port from c64.c and cbmb.c */
52 
53 #define LIGHTPEN_BUTTON     (m_lightpen_button_cb(0))
54 #define LIGHTPEN_X_VALUE    (m_lightpen_x_cb(0))
55 #define LIGHTPEN_Y_VALUE    (m_lightpen_y_cb(0))
56 
57 /* lightpen delivers values from internal counters; they do not start with the visual area or frame area */
58 #define VIC2_MAME_XPOS          0
59 #define VIC2_MAME_YPOS          0
60 #define VIC6567_X_BEGIN         38
61 #define VIC6567_Y_BEGIN         -6             /* first 6 lines after retrace not for lightpen! */
62 #define VIC6569_X_BEGIN         38
63 #define VIC6569_Y_BEGIN         -6
64 #define VIC2_X_BEGIN            ((m_type == vic3_type::PAL) ? VIC6569_X_BEGIN : VIC6567_X_BEGIN)
65 #define VIC2_Y_BEGIN            ((m_type == vic3_type::PAL) ? VIC6569_Y_BEGIN : VIC6567_Y_BEGIN)
66 #define VIC2_X_VALUE            ((LIGHTPEN_X_VALUE + VIC2_X_BEGIN + VIC2_MAME_XPOS) / 2)
67 #define VIC2_Y_VALUE            ((LIGHTPEN_Y_VALUE + VIC2_Y_BEGIN + VIC2_MAME_YPOS))
68 
69 #define VIC2E_K0_LEVEL          (m_reg[0x2f] & 0x01)
70 #define VIC2E_K1_LEVEL          (m_reg[0x2f] & 0x02)
71 #define VIC2E_K2_LEVEL          (m_reg[0x2f] & 0x04)
72 
73 /*#define VIC3_P5_LEVEL (m_reg[0x30] & 0x20) */
74 #define VIC3_BITPLANES          (m_reg[0x31] & 0x10)
75 #define VIC3_80COLUMNS          (m_reg[0x31] & 0x80)
76 #define VIC3_LINES              ((m_reg[0x31] & 0x19) == 0x19 ? 400 : 200)
77 #define VIC3_BITPLANES_WIDTH    (m_reg[0x31] & 0x80 ? 640 : 320)
78 
79 /*#define VIC2E_TEST (vic2[0x30] & 2) */
80 #define DOUBLE_CLOCK            (m_reg[0x30] & 0x01)
81 
82 /* sprites 0 .. 7 */
83 #define SPRITEON(nr)            (m_reg[0x15] & (1 << nr))
84 #define SPRITE_Y_EXPAND(nr)     (m_reg[0x17] & (1 << nr))
85 #define SPRITE_Y_SIZE(nr)       (SPRITE_Y_EXPAND(nr) ? 2 * 21 : 21)
86 #define SPRITE_X_EXPAND(nr)     (m_reg[0x1d] & (1 << nr))
87 #define SPRITE_X_SIZE(nr)       (SPRITE_X_EXPAND(nr) ? 2 * 24 : 24)
88 #define SPRITE_X_POS(nr)        ((m_reg[(nr) * 2] | (m_reg[0x10] & (1 <<(nr)) ? 0x100 : 0)) - 24 + XPOS)
89 #define SPRITE_X_POS2(nr)       (m_reg[(nr) * 2] | (m_reg[0x10] & (1 <<(nr)) ? 0x100 : 0))
90 #define SPRITE_Y_POS(nr)        (m_reg[1+2*(nr)] - 50 + YPOS)
91 #define SPRITE_Y_POS2(nr)       (m_reg[1 + 2 *(nr)])
92 #define SPRITE_MULTICOLOR(nr)   (m_reg[0x1c] & (1 << nr))
93 #define SPRITE_PRIORITY(nr)     (m_reg[0x1b] & (1 << nr))
94 #define SPRITE_MULTICOLOR1      (m_reg[0x25] & 0x0f)
95 #define SPRITE_MULTICOLOR2      (m_reg[0x26] & 0x0f)
96 #define SPRITE_COLOR(nr)        (m_reg[0x27+nr] & 0x0f)
97 #define SPRITE_ADDR(nr)         (m_videoaddr | 0x3f8 | nr)
98 #define SPRITE_BG_COLLISION(nr) (m_reg[0x1f] & (1 << nr))
99 #define SPRITE_COLLISION(nr)        (m_reg[0x1e] & (1 << nr))
100 #define SPRITE_SET_BG_COLLISION(nr) (m_reg[0x1f] |= (1 << nr))
101 #define SPRITE_SET_COLLISION(nr)    (m_reg[0x1e] |= (1 << nr))
102 #define SPRITE_COLL         (m_reg[0x1e])
103 #define SPRITE_BG_COLL          (m_reg[0x1f])
104 
105 #define GFXMODE             ((m_reg[0x11] & 0x60) | (m_reg[0x16] & 0x10)) >> 4
106 #define SCREENON                (m_reg[0x11] & 0x10)
107 #define VERTICALPOS         (m_reg[0x11] & 0x07)
108 #define HORIZONTALPOS           (m_reg[0x16] & 0x07)
109 #define ECMON               (m_reg[0x11] & 0x40)
110 #define HIRESON             (m_reg[0x11] & 0x20)
111 #define MULTICOLORON            (m_reg[0x16] & 0x10)
112 #define LINES25             (m_reg[0x11] & 0x08)           /* else 24 Lines */
113 #define LINES               (LINES25 ? 25 : 24)
114 #define YSIZE               (LINES * 8)
115 #define COLUMNS40               (m_reg[0x16] & 0x08)           /* else 38 Columns */
116 #define COLUMNS             (COLUMNS40 ? 40 : 38)
117 #define XSIZE               (COLUMNS * 8)
118 
119 #define VIDEOADDR               ((m_reg[0x18] & 0xf0) << (10 - 4))
120 #define CHARGENADDR         ((m_reg[0x18] & 0x0e) << 10)
121 #define BITMAPADDR          ((data & 0x08) << 10)
122 
123 #define RASTERLINE          (((m_reg[0x11] & 0x80) << 1) | m_reg[0x12])
124 
125 #define FRAMECOLOR          (m_reg[0x20] & 0x0f)
126 #define BACKGROUNDCOLOR         (m_reg[0x21] & 0x0f)
127 #define MULTICOLOR1         (m_reg[0x22] & 0x0f)
128 #define MULTICOLOR2         (m_reg[0x23] & 0x0f)
129 #define FOREGROUNDCOLOR         (m_reg[0x24] & 0x0f)
130 
131 
132 #define VIC2_LINES      (m_type == vic3_type::PAL ? VIC6569_LINES : VIC6567_LINES)
133 #define VIC2_VISIBLELINES   (m_type == vic3_type::PAL ? VIC6569_VISIBLELINES : VIC6567_VISIBLELINES)
134 #define VIC2_VISIBLECOLUMNS (m_type == vic3_type::PAL ? VIC6569_VISIBLECOLUMNS : VIC6567_VISIBLECOLUMNS)
135 #define VIC2_STARTVISIBLELINES ((VIC2_LINES - VIC2_VISIBLELINES)/2)
136 #define VIC2_FIRSTRASTERLINE  (m_type == vic3_type::PAL ? VIC6569_FIRSTRASTERLINE : VIC6567_FIRSTRASTERLINE)
137 #define VIC2_COLUMNS          (m_type == vic3_type::PAL ? VIC6569_COLUMNS : VIC6567_COLUMNS)
138 #define VIC2_STARTVISIBLECOLUMNS ((VIC2_COLUMNS - VIC2_VISIBLECOLUMNS)/2)
139 
140 #define VIC3_BITPLANES_MASK (m_reg[0x32])
141 /* bit 0, 4 not used !?*/
142 /* I think hinibbles contains the banknumbers for interlaced modes */
143 /* if hinibble set then x&1==0 should be in bank1 (0x10000), x&1==1 in bank 0 */
144 #define VIC3_BITPLANE_ADDR_HELPER(x)  ((m_reg[0x33 + x] & 0x0f) << 12)
145 #define VIC3_BITPLANE_ADDR(x) (x & 1 ? VIC3_BITPLANE_ADDR_HELPER(x) + 0x10000 : VIC3_BITPLANE_ADDR_HELPER(x) )
146 #define VIC3_BITPLANE_IADDR_HELPER(x)  ((m_reg[0x33 + x] & 0xf0) << 8)
147 #define VIC3_BITPLANE_IADDR(x) (x & 1 ? VIC3_BITPLANE_IADDR_HELPER(x) + 0x10000 : VIC3_BITPLANE_IADDR_HELPER(x))
148 
149 
150 DEFINE_DEVICE_TYPE(VIC3, vic3_device, "vic3", "CSG 4567 VIC-III")
151 
vic3_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)152 vic3_device::vic3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
153 	: device_t(mconfig, VIC3, tag, owner, clock)
154 	, device_palette_interface(mconfig, *this)
155 	, device_video_interface(mconfig, *this)
156 	, m_type(vic3_type::NTSC)
157 	, m_cpu(*this, finder_base::DUMMY_TAG)
158 	, m_dma_read_cb(*this)
159 	, m_dma_read_color_cb(*this)
160 	, m_interrupt_cb(*this)
161 	, m_port_changed_cb(*this)
162 	, m_lightpen_button_cb(*this)
163 	, m_lightpen_x_cb(*this)
164 	, m_lightpen_y_cb(*this)
165 	, m_c64_mem_r_cb(*this)
166 {
167 }
168 
169 //-------------------------------------------------
170 //  device_start - device-specific startup
171 //-------------------------------------------------
172 
device_start()173 void vic3_device::device_start()
174 {
175 	int width, height;
176 
177 	width = screen().width();
178 	height = screen().height();
179 
180 	m_bitmap = std::make_unique<bitmap_ind16>(width, height);
181 
182 	m_dma_read_cb.resolve_safe(0);
183 	m_dma_read_color_cb.resolve_safe(0);
184 	m_interrupt_cb.resolve_safe();
185 
186 	m_port_changed_cb.resolve();
187 
188 	m_c64_mem_r_cb.resolve_safe(0);
189 
190 	m_lightpen_button_cb.resolve_safe(0);
191 	m_lightpen_x_cb.resolve_safe(0);
192 	m_lightpen_y_cb.resolve_safe(0);
193 
194 	m_screenptr[0] = auto_alloc_array(machine(), uint8_t, 216 * 656 / 8);
195 
196 	for (int i = 1; i < 216; i++)
197 		m_screenptr[i] = m_screenptr[i - 1] + 656 / 8;
198 
199 	for (int i = 0; i < 256; i++)
200 	{
201 		m_foreground[i] = 0;
202 		if ((i & 3) > 1)
203 			m_foreground[i] |= 0x3;
204 		if ((i & 0xc) > 0x4)
205 			m_foreground[i] |= 0xc;
206 		if ((i & 0x30) > 0x10)
207 			m_foreground[i] |= 0x30;
208 		if ((i & 0xc0) > 0x40)
209 			m_foreground[i] |= 0xc0;
210 	}
211 
212 	for (int i = 0; i < 256; i++)
213 	{
214 		m_expandx[i] = 0;
215 		if (i & 1)
216 			m_expandx[i] |= 3;
217 		if (i & 2)
218 			m_expandx[i] |= 0xc;
219 		if (i & 4)
220 			m_expandx[i] |= 0x30;
221 		if (i & 8)
222 			m_expandx[i] |= 0xc0;
223 		if (i & 0x10)
224 			m_expandx[i] |= 0x300;
225 		if (i & 0x20)
226 			m_expandx[i] |= 0xc00;
227 		if (i & 0x40)
228 			m_expandx[i] |= 0x3000;
229 		if (i & 0x80)
230 			m_expandx[i] |= 0xc000;
231 	}
232 
233 	for (int i = 0; i < 256; i++)
234 	{
235 		m_expandx_multi[i] = 0;
236 		if (i & 1)
237 			m_expandx_multi[i] |= 5;
238 		if (i & 2)
239 			m_expandx_multi[i] |= 0xa;
240 		if (i & 4)
241 			m_expandx_multi[i] |= 0x50;
242 		if (i & 8)
243 			m_expandx_multi[i] |= 0xa0;
244 		if (i & 0x10)
245 			m_expandx_multi[i] |= 0x500;
246 		if (i & 0x20)
247 			m_expandx_multi[i] |= 0xa00;
248 		if (i & 0x40)
249 			m_expandx_multi[i] |= 0x5000;
250 		if (i & 0x80)
251 			m_expandx_multi[i] |= 0xa000;
252 	}
253 
254 	save_item(NAME(m_reg));
255 
256 	save_item(NAME(m_on));
257 
258 	//save_item(NAME(m_bitmap));
259 
260 	save_item(NAME(m_lines));
261 
262 	save_item(NAME(m_chargenaddr));
263 	save_item(NAME(m_videoaddr));
264 	save_item(NAME(m_bitmapaddr));
265 
266 	save_item(NAME(m_x_begin));
267 	save_item(NAME(m_x_end));
268 	save_item(NAME(m_y_begin));
269 	save_item(NAME(m_y_end));
270 
271 	save_item(NAME(m_c64_bitmap));
272 	save_item(NAME(m_bitmapmulti));
273 	save_item(NAME(m_mono));
274 	save_item(NAME(m_multi));
275 	save_item(NAME(m_ecmcolor));
276 	save_item(NAME(m_colors));
277 	save_item(NAME(m_spritemulti));
278 
279 	save_item(NAME(m_lastline));
280 	save_item(NAME(m_rasterline));
281 	save_item(NAME(m_interlace));
282 
283 	save_item(NAME(m_columns));
284 	save_item(NAME(m_rows));
285 
286 	save_item(NAME(m_shift));
287 	save_item(NAME(m_foreground));
288 	save_item(NAME(m_multi_collision));
289 
290 	save_item(NAME(m_palette_red));
291 	save_item(NAME(m_palette_green));
292 	save_item(NAME(m_palette_blue));
293 	save_item(NAME(m_palette_dirty));
294 
295 	for (int i = 0; i < 8; i++)
296 	{
297 		save_item(NAME(m_sprites[i].x), i);
298 		save_item(NAME(m_sprites[i].y), i);
299 		save_item(NAME(m_sprites[i].repeat), i);
300 		save_item(NAME(m_sprites[i].line), i);
301 		save_item(NAME(m_sprites[i].paintedline), i);
302 		save_item(NAME(m_sprites[i].bitmap[0]), i);
303 		save_item(NAME(m_sprites[i].bitmap[1]), i);
304 		save_item(NAME(m_sprites[i].bitmap[2]), i);
305 		save_item(NAME(m_sprites[i].bitmap[3]), i);
306 		save_item(NAME(m_sprites[i].bitmap[4]), i);
307 		save_item(NAME(m_sprites[i].bitmap[5]), i);
308 		save_item(NAME(m_sprites[i].bitmap[6]), i);
309 		save_item(NAME(m_sprites[i].bitmap[7]), i);
310 	}
311 }
312 
313 //-------------------------------------------------
314 //  device_reset - device-specific reset
315 //-------------------------------------------------
316 
device_reset()317 void vic3_device::device_reset()
318 {
319 	memset(m_reg, 0, ARRAY_LENGTH(m_reg));
320 
321 	m_on = 1;
322 
323 	m_interlace = 0;
324 	m_columns = 640;
325 	m_rows = 200;
326 	m_lines = VIC2_LINES;
327 
328 	memset(&m_sprites, 0, sizeof(m_sprites));
329 
330 	m_chargenaddr = 0;
331 	m_videoaddr = 0;
332 	m_bitmapaddr = 0;
333 
334 	m_x_begin = 0;
335 	m_x_end = 0;
336 	m_y_begin = 0;
337 	m_y_end = 0;
338 
339 	for (int i = 0; i < 2; i++)
340 	{
341 		m_c64_bitmap[i] = 0;
342 		m_mono[i] = 0;
343 		m_ecmcolor[i] = 0;
344 	}
345 
346 	for (int i = 0; i < 4; i++)
347 	{
348 		m_bitmapmulti[i] = 0;
349 		m_multi[i] = 0;
350 		m_colors[i] = 0;
351 		m_spritemulti[i] = 0;
352 	}
353 
354 	m_lastline = 0;
355 	m_rasterline = 0;
356 
357 	memset(m_shift, 0, ARRAY_LENGTH(m_shift));
358 	memset(m_multi_collision, 0, ARRAY_LENGTH(m_multi_collision));
359 
360 	for (int i = 0; i < 256; i++)
361 	{
362 		m_palette_red[i] = m_palette_green[i] = m_palette_blue[i] = 0;
363 		set_pen_color(i, rgb_t::black());
364 	}
365 
366 	m_palette_dirty = 0;
367 }
368 
369 
370 /*****************************************************************************
371     IMPLEMENTATION
372 *****************************************************************************/
373 
getforeground(int y,int x)374 inline int vic3_device::getforeground( int y, int x )
375 {
376 	return ((m_screenptr[y][x >> 3] << 8) | (m_screenptr[y][(x >> 3) + 1])) >> (8 - (x & 7));
377 }
378 
getforeground16(int y,int x)379 inline int vic3_device::getforeground16( int y, int x )
380 {
381 	return ((m_screenptr[y][x >> 3] << 16) | (m_screenptr[y][(x >> 3) + 1] << 8) | (m_screenptr[y][(x >> 3) + 2])) >> (8 - (x & 7));
382 }
383 
set_interrupt(int mask)384 void vic3_device::set_interrupt( int mask )
385 {
386 	if (((m_reg[0x19] ^ mask) & m_reg[0x1a] & 0xf))
387 	{
388 		if (!(m_reg[0x19] & 0x80))
389 		{
390 			//DBG_LOG(2, "vic2", ("irq start %.2x\n", mask));
391 			m_reg[0x19] |= 0x80;
392 			m_interrupt_cb(1);
393 		}
394 	}
395 	m_reg[0x19] |= mask;
396 }
397 
clear_interrupt(int mask)398 void vic3_device::clear_interrupt( int mask )
399 {
400 	m_reg[0x19] &= ~mask;
401 	if ((m_reg[0x19] & 0x80) && !(m_reg[0x19] & m_reg[0x1a] & 0xf))
402 	{
403 		//DBG_LOG(2, "vic2", ("irq end %.2x\n", mask));
404 		m_reg[0x19] &= ~0x80;
405 		m_interrupt_cb(0);
406 	}
407 }
408 
TIMER_CALLBACK_MEMBER(vic3_device::timer_timeout)409 TIMER_CALLBACK_MEMBER( vic3_device::timer_timeout )
410 {
411 	int which = param;
412 	//DBG_LOG(3, "vic3 ", ("timer %d timeout\n", which));
413 	switch (which)
414 	{
415 	case 1:                        /* light pen */
416 		/* and diode must recognize light */
417 		if (1)
418 		{
419 			m_reg[0x13] = VIC2_X_VALUE;
420 			m_reg[0x14] = VIC2_Y_VALUE;
421 		}
422 		set_interrupt(8);
423 		break;
424 	}
425 }
426 
draw_character(int ybegin,int yend,int ch,int yoff,int xoff,uint16_t * color,int start_x,int end_x)427 void vic3_device::draw_character( int ybegin, int yend, int ch, int yoff, int xoff, uint16_t *color, int start_x, int end_x )
428 {
429 	for (int y = ybegin; y <= yend; y++)
430 	{
431 		int code = m_dma_read_cb(m_chargenaddr + ch * 8 + y);
432 		m_screenptr[y + yoff][xoff >> 3] = code;
433 		if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 0) = color[code >> 7];
434 		if ((xoff + 1 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 1) = color[(code >> 6) & 1];
435 		if ((xoff + 2 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 2) = color[(code >> 5) & 1];
436 		if ((xoff + 3 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 3) = color[(code >> 4) & 1];
437 		if ((xoff + 4 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 4) = color[(code >> 3) & 1];
438 		if ((xoff + 5 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 5) = color[(code >> 2) & 1];
439 		if ((xoff + 6 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 6) = color[(code >> 1) & 1];
440 		if ((xoff + 7 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 7) = color[code & 1];
441 	}
442 }
443 
draw_character_multi(int ybegin,int yend,int ch,int yoff,int xoff,int start_x,int end_x)444 void vic3_device::draw_character_multi( int ybegin, int yend, int ch, int yoff, int xoff, int start_x, int end_x )
445 {
446 	for (int y = ybegin; y <= yend; y++)
447 	{
448 		int code = m_dma_read_cb(m_chargenaddr + ch * 8 + y);
449 		m_screenptr[y + yoff][xoff >> 3] = m_foreground[code];
450 		if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 0) = m_multi[code >> 6];
451 		if ((xoff + 1 > start_x) && (xoff + 1 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 1) = m_multi[code >> 6];
452 		if ((xoff + 2 > start_x) && (xoff + 2 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 2) = m_multi[(code >> 4) & 3];
453 		if ((xoff + 3 > start_x) && (xoff + 3 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 3) = m_multi[(code >> 4) & 3];
454 		if ((xoff + 4 > start_x) && (xoff + 4 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 4) = m_multi[(code >> 2) & 3];
455 		if ((xoff + 5 > start_x) && (xoff + 5 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 5) = m_multi[(code >> 2) & 3];
456 		if ((xoff + 6 > start_x) && (xoff + 6 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 6) = m_multi[code & 3];
457 		if ((xoff + 7 > start_x) && (xoff + 7 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 7) = m_multi[code & 3];
458 	}
459 }
460 
draw_bitmap(int ybegin,int yend,int ch,int yoff,int xoff,int start_x,int end_x)461 void vic3_device::draw_bitmap( int ybegin, int yend, int ch, int yoff, int xoff, int start_x, int end_x )
462 {
463 	for (int y = ybegin; y <= yend; y++)
464 	{
465 		int code = m_dma_read_cb((m_chargenaddr & 0x2000) + ch * 8 + y);
466 		m_screenptr[y + yoff][xoff >> 3] = code;
467 		if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 0) = m_c64_bitmap[code >> 7];
468 		if ((xoff + 1 > start_x) && (xoff + 1 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 1) = m_c64_bitmap[(code >> 6) & 1];
469 		if ((xoff + 2 > start_x) && (xoff + 2 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 2) = m_c64_bitmap[(code >> 5) & 1];
470 		if ((xoff + 3 > start_x) && (xoff + 3 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 3) = m_c64_bitmap[(code >> 4) & 1];
471 		if ((xoff + 4 > start_x) && (xoff + 4 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 4) = m_c64_bitmap[(code >> 3) & 1];
472 		if ((xoff + 5 > start_x) && (xoff + 5 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 5) = m_c64_bitmap[(code >> 2) & 1];
473 		if ((xoff + 6 > start_x) && (xoff + 6 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 6) = m_c64_bitmap[(code >> 1) & 1];
474 		if ((xoff + 7 > start_x) && (xoff + 7 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 7) = m_c64_bitmap[code & 1];
475 	}
476 }
477 
draw_bitmap_multi(int ybegin,int yend,int ch,int yoff,int xoff,int start_x,int end_x)478 void vic3_device::draw_bitmap_multi( int ybegin, int yend, int ch, int yoff, int xoff, int start_x, int end_x )
479 {
480 	for (int y = ybegin; y <= yend; y++)
481 	{
482 		int code = m_dma_read_cb((m_chargenaddr & 0x2000) + ch * 8 + y);
483 		m_screenptr[y + yoff][xoff >> 3] = m_foreground[code];
484 		if ((xoff + 0 > start_x) && (xoff + 0 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 0) = m_bitmapmulti[code >> 6];
485 		if ((xoff + 1 > start_x) && (xoff + 1 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 1) = m_bitmapmulti[code >> 6];
486 		if ((xoff + 2 > start_x) && (xoff + 2 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 2) = m_bitmapmulti[(code >> 4) & 3];
487 		if ((xoff + 3 > start_x) && (xoff + 3 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 3) = m_bitmapmulti[(code >> 4) & 3];
488 		if ((xoff + 4 > start_x) && (xoff + 4 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 4) = m_bitmapmulti[(code >> 2) & 3];
489 		if ((xoff + 5 > start_x) && (xoff + 5 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 5) = m_bitmapmulti[(code >> 2) & 3];
490 		if ((xoff + 6 > start_x) && (xoff + 6 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 6) = m_bitmapmulti[code & 3];
491 		if ((xoff + 7 > start_x) && (xoff + 7 < end_x)) m_bitmap->pix(y + yoff + FIRSTLINE, xoff + 7) = m_bitmapmulti[code & 3];
492 	}
493 }
494 
draw_sprite_code(int y,int xbegin,int code,int color,int start_x,int end_x)495 void vic3_device::draw_sprite_code( int y, int xbegin, int code, int color, int start_x, int end_x )
496 {
497 	if ((y < YPOS) || (y >= (VIC2_STARTVISIBLELINES + VIC2_VISIBLELINES)) || (xbegin <= 1) || (xbegin >= (VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS)))
498 		return;
499 
500 	for (int x = 0, mask = 0x80; x < 8; x++, mask >>= 1)
501 	{
502 		if (code & mask)
503 		{
504 			if ((xbegin + x > start_x) && (xbegin + x < end_x))
505 				m_bitmap->pix(y + FIRSTLINE, xbegin + x) = color;
506 		}
507 	}
508 }
509 
draw_sprite_code_multi(int y,int xbegin,int code,int prior,int start_x,int end_x)510 void vic3_device::draw_sprite_code_multi( int y, int xbegin, int code, int prior, int start_x, int end_x )
511 {
512 	if ((y < YPOS) || (y >= (VIC2_STARTVISIBLELINES + VIC2_VISIBLELINES)) || (xbegin <= 1) || (xbegin >= (VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS)))
513 		return;
514 
515 	for (int x = 0, mask = 0xc0, shift = 6; x < 8; x += 2, mask >>= 2, shift -= 2)
516 	{
517 		if (code & mask)
518 		{
519 			switch ((prior & mask) >> shift)
520 			{
521 			case 1:
522 				if ((xbegin + x + 1 > start_x) && (xbegin + x + 1 < end_x))
523 					m_bitmap->pix(y + FIRSTLINE, xbegin + x + 1) = m_spritemulti[(code >> shift) & 3];
524 				break;
525 			case 2:
526 				if ((xbegin + x > start_x) && (xbegin + x < end_x))
527 					m_bitmap->pix(y + FIRSTLINE, xbegin + x) = m_spritemulti[(code >> shift) & 3];
528 				break;
529 			case 3:
530 				if ((xbegin + x > start_x) && (xbegin + x < end_x))
531 					m_bitmap->pix(y + FIRSTLINE, xbegin + x) = m_spritemulti[(code >> shift) & 3];
532 				if ((xbegin + x + 1> start_x) && (xbegin + x + 1< end_x))
533 					m_bitmap->pix(y + FIRSTLINE, xbegin + x + 1) = m_spritemulti[(code >> shift) & 3];
534 				break;
535 			}
536 		}
537 	}
538 }
539 
sprite_collision(int nr,int y,int x,int mask)540 void vic3_device::sprite_collision( int nr, int y, int x, int mask )
541 {
542 	for (int i = 7; i > nr; i--)
543 	{
544 		if (!SPRITEON(i) || !m_sprites[i].paintedline[y] || (SPRITE_COLLISION(i) && SPRITE_COLLISION(nr)))
545 			continue;
546 
547 		if ((x + 7 < SPRITE_X_POS(i)) || (x >= SPRITE_X_POS(i) + SPRITE_X_SIZE(i)))
548 			continue;
549 
550 		int xdiff = x - SPRITE_X_POS(i);
551 
552 		int value;
553 		if ((x & 7) == (SPRITE_X_POS(i) & 7))
554 			value = m_sprites[i].bitmap[y][xdiff >> 3];
555 		else if (xdiff < 0)
556 			value = m_sprites[i].bitmap[y][0] >> (-xdiff);
557 		else {
558 			uint8_t *vp = m_sprites[i].bitmap[y]+(xdiff >> 3);
559 			value = ((vp[1] | (*vp << 8)) >> (8 - (xdiff & 7) )) & 0xff;
560 		}
561 
562 		if (value & mask)
563 		{
564 			SPRITE_SET_COLLISION(i);
565 			SPRITE_SET_COLLISION(nr);
566 			set_interrupt(4);
567 		}
568 	}
569 }
570 
draw_sprite(int nr,int yoff,int ybegin,int yend,int start_x,int end_x)571 void vic3_device::draw_sprite( int nr, int yoff, int ybegin, int yend, int start_x, int end_x )
572 {
573 	int y, i, addr, xbegin, color, prior, collision;
574 	int value, value3 = 0;
575 
576 	xbegin = SPRITE_X_POS(nr);
577 	addr = m_dma_read_cb(SPRITE_ADDR(nr)) << 6;
578 	color = SPRITE_COLOR(nr);
579 	prior = SPRITE_PRIORITY(nr);
580 	collision = SPRITE_BG_COLLISION(nr);
581 
582 	if (SPRITE_X_EXPAND(nr))
583 	{
584 		for (y = ybegin; y <= yend; y++)
585 		{
586 			m_sprites[nr].paintedline[y] = 1;
587 			for (i = 0; i < 3; i++)
588 			{
589 				value = m_expandx[m_dma_read_cb(addr + m_sprites[nr].line * 3 + i)];
590 				m_sprites[nr].bitmap[y][i * 2] = value >> 8;
591 				m_sprites[nr].bitmap[y][i * 2 + 1] = value & 0xff;
592 				sprite_collision(nr, y, xbegin + i * 16, value >> 8);
593 				sprite_collision(nr, y, xbegin + i * 16 + 8, value & 0xff);
594 				if (prior || !collision)
595 					value3 = getforeground16(yoff + y, xbegin + i * 16 - 7);
596 				if (!collision && (value & value3))
597 				{
598 					collision = 1;
599 					SPRITE_SET_BG_COLLISION(nr);
600 					set_interrupt(2);
601 				}
602 				if (prior)
603 					value &= ~value3;
604 				draw_sprite_code(yoff + y, xbegin + i * 16, value >> 8, color, start_x, end_x);
605 				draw_sprite_code(yoff + y, xbegin + i * 16 + 8, value & 0xff, color, start_x, end_x);
606 			}
607 			m_sprites[nr].bitmap[y][i * 2]=0; //easier sprite collision detection
608 			if (SPRITE_Y_EXPAND(nr))
609 			{
610 				if (m_sprites[nr].repeat)
611 				{
612 					m_sprites[nr].line++;
613 					m_sprites[nr].repeat = 0;
614 				}
615 				else
616 					m_sprites[nr].repeat = 1;
617 			}
618 			else
619 			{
620 				m_sprites[nr].line++;
621 			}
622 		}
623 	}
624 	else
625 	{
626 		for (y = ybegin; y <= yend; y++)
627 		{
628 			m_sprites[nr].paintedline[y] = 1;
629 			for (i = 0; i < 3; i++)
630 			{
631 				value = m_dma_read_cb(addr + m_sprites[nr].line * 3 + i);
632 				m_sprites[nr].bitmap[y][i] = value;
633 				sprite_collision(nr, y, xbegin + i * 8, value);
634 				if (prior || !collision)
635 					value3 = getforeground(yoff + y, xbegin + i * 8 - 7);
636 				if (!collision && (value & value3))
637 				{
638 					collision = 1;
639 					SPRITE_SET_BG_COLLISION(nr);
640 					set_interrupt(2);
641 				}
642 				if (prior)
643 					value &= ~value3;
644 				draw_sprite_code(yoff + y, xbegin + i * 8, value, color, start_x, end_x);
645 			}
646 			m_sprites[nr].bitmap[y][i]=0; //easier sprite collision detection
647 			if (SPRITE_Y_EXPAND(nr))
648 			{
649 				if (m_sprites[nr].repeat)
650 				{
651 					m_sprites[nr].line++;
652 					m_sprites[nr].repeat = 0;
653 				}
654 				else
655 					m_sprites[nr].repeat = 1;
656 			}
657 			else
658 			{
659 				m_sprites[nr].line++;
660 			}
661 		}
662 	}
663 }
664 
draw_sprite_multi(int nr,int yoff,int ybegin,int yend,int start_x,int end_x)665 void vic3_device::draw_sprite_multi( int nr, int yoff, int ybegin, int yend, int start_x, int end_x )
666 {
667 	int y, i, prior, addr, xbegin, collision;
668 	int value, value2, value3 = 0, bg/*, color[2]*/;
669 
670 	xbegin = SPRITE_X_POS(nr);
671 	addr = m_dma_read_cb(SPRITE_ADDR(nr)) << 6;
672 	m_spritemulti[2] = SPRITE_COLOR(nr);
673 	prior = SPRITE_PRIORITY(nr);
674 	collision = SPRITE_BG_COLLISION(nr);
675 	//color[0] = 0;
676 	//color[1] = 1;
677 
678 	if (SPRITE_X_EXPAND(nr))
679 	{
680 		for (y = ybegin; y <= yend; y++)
681 		{
682 			m_sprites[nr].paintedline[y] = 1;
683 			for (i = 0; i < 3; i++)
684 			{
685 				value = m_expandx_multi[bg = m_dma_read_cb(addr + m_sprites[nr].line * 3 + i)];
686 				value2 = m_expandx[m_multi_collision[bg]];
687 				m_sprites[nr].bitmap[y][i * 2] = value2 >> 8;
688 				m_sprites[nr].bitmap[y][i * 2 + 1] = value2 & 0xff;
689 				sprite_collision(nr, y, xbegin + i * 16, value2 >> 8);
690 				sprite_collision(nr, y, xbegin + i * 16 + 8, value2 & 0xff);
691 				if (prior || !collision)
692 				{
693 					value3 = getforeground16(yoff + y, xbegin + i * 16 - 7);
694 				}
695 				if (!collision && (value2 & value3))
696 				{
697 					collision = 1;
698 					SPRITE_SET_BG_COLLISION(nr);
699 					set_interrupt(2);
700 				}
701 				if (prior)
702 				{
703 					draw_sprite_code_multi(yoff + y, xbegin + i * 16, value >> 8, (value3 >> 8) ^ 0xff, start_x, end_x);
704 					draw_sprite_code_multi(yoff + y, xbegin + i * 16 + 8, value & 0xff, (value3 & 0xff) ^ 0xff, start_x, end_x);
705 				}
706 				else
707 				{
708 					draw_sprite_code_multi(yoff + y, xbegin + i * 16, value >> 8, 0xff, start_x, end_x);
709 					draw_sprite_code_multi(yoff + y, xbegin + i * 16 + 8, value & 0xff, 0xff, start_x, end_x);
710 				}
711 			}
712 			m_sprites[nr].bitmap[y][i * 2]=0; //easier sprite collision detection
713 			if (SPRITE_Y_EXPAND(nr))
714 			{
715 				if (m_sprites[nr].repeat)
716 				{
717 					m_sprites[nr].line++;
718 					m_sprites[nr].repeat = 0;
719 				}
720 				else
721 					m_sprites[nr].repeat = 1;
722 			}
723 			else
724 			{
725 				m_sprites[nr].line++;
726 			}
727 		}
728 	}
729 	else
730 	{
731 		for (y = ybegin; y <= yend; y++)
732 		{
733 			m_sprites[nr].paintedline[y] = 1;
734 			for (i = 0; i < 3; i++)
735 			{
736 				value = m_dma_read_cb(addr + m_sprites[nr].line * 3 + i);
737 				m_sprites[nr].bitmap[y][i] = value2 = m_multi_collision[value];
738 				sprite_collision(nr, y, xbegin + i * 8, value2);
739 				if (prior || !collision)
740 				{
741 					value3 = getforeground(yoff + y, xbegin + i * 8 - 7);
742 				}
743 				if (!collision && (value2 & value3))
744 				{
745 					collision = 1;
746 					SPRITE_SET_BG_COLLISION(nr);
747 					set_interrupt(2);
748 				}
749 				if (prior)
750 				{
751 					draw_sprite_code_multi(yoff + y, xbegin + i * 8, value, value3 ^ 0xff, start_x, end_x);
752 				}
753 				else
754 				{
755 					draw_sprite_code_multi(yoff + y, xbegin + i * 8, value, 0xff, start_x, end_x);
756 				}
757 			}
758 			m_sprites[nr].bitmap[y][i] = 0; //easier sprite collision detection
759 			if (SPRITE_Y_EXPAND(nr))
760 			{
761 				if (m_sprites[nr].repeat)
762 				{
763 					m_sprites[nr].line++;
764 					m_sprites[nr].repeat = 0;
765 				}
766 				else
767 					m_sprites[nr].repeat = 1;
768 			}
769 			else
770 			{
771 				m_sprites[nr].line++;
772 			}
773 		}
774 	}
775 }
776 
drawlines(int first,int last,int start_x,int end_x)777 void vic3_device::drawlines( int first, int last, int start_x, int end_x )
778 {
779 	int line, vline, end;
780 	int attr, ch, ecm;
781 	int syend;
782 	int offs, yoff, xoff, ybegin, yend, xbegin, xend;
783 	int x_end2;
784 	int i, j;
785 
786 	if (first == last)
787 		return;
788 	m_lastline = last;
789 
790 	/* top part of display not rastered */
791 	first -= VIC2_YPOS - YPOS;
792 	last -= VIC2_YPOS - YPOS;
793 	if ((first >= last) || (last <= 0))
794 	{
795 		for (i = 0; i < 8; i++)
796 			m_sprites[i].repeat = m_sprites[i].line = 0;
797 		return;
798 	}
799 	if (first < 0)
800 		first = 0;
801 
802 	if (!SCREENON)
803 	{
804 		for (line = first; (line < last) && (line < m_bitmap->height()); line++)
805 		{
806 			std::fill_n(&m_bitmap->pix(line + FIRSTLINE), m_bitmap->width(), 0);
807 		}
808 		return;
809 	}
810 	if (COLUMNS40)
811 		xbegin = XPOS, xend = xbegin + 640;
812 	else
813 		xbegin = XPOS + 7, xend = xbegin + 624;
814 
815 	if (last < m_y_begin)
816 		end = last;
817 	else
818 		end = m_y_begin + YPOS;
819 
820 	for (line = first; line < end; line++)
821 	{
822 		std::fill_n(&m_bitmap->pix(line + FIRSTLINE), m_bitmap->width(), FRAMECOLOR);
823 	}
824 
825 	if (LINES25)
826 	{
827 		vline = line - m_y_begin - YPOS;
828 	}
829 	else
830 	{
831 		vline = line - m_y_begin - YPOS + 8 - VERTICALPOS;
832 	}
833 	if (last < m_y_end + YPOS)
834 		end = last;
835 	else
836 		end = m_y_end + YPOS;
837 	x_end2 = m_x_end * 2;
838 	for (; line < end; vline = (vline + 8) & ~7, line = line + 1 + yend - ybegin)
839 	{
840 		offs = (vline >> 3) * 80;
841 		ybegin = vline & 7;
842 		yoff = line - ybegin;
843 		yend = (yoff + 7 < end) ? 7 : (end - yoff - 1);
844 		/* rendering 39 characters */
845 		/* left and right borders are overwritten later */
846 		m_shift[line] = HORIZONTALPOS;
847 
848 		for (xoff = m_x_begin + XPOS; xoff < x_end2 + XPOS; xoff += 8, offs++)
849 		{
850 			ch = m_dma_read_cb(m_videoaddr + offs);
851 			attr = m_dma_read_color_cb(m_videoaddr + offs);
852 			if (HIRESON)
853 			{
854 				m_bitmapmulti[1] = m_c64_bitmap[1] = ch >> 4;
855 				m_bitmapmulti[2] = m_c64_bitmap[0] = ch & 0xf;
856 				if (MULTICOLORON)
857 				{
858 					m_bitmapmulti[3] = attr;
859 					draw_bitmap_multi(ybegin, yend, offs, yoff, xoff, start_x, end_x);
860 				}
861 				else
862 				{
863 					draw_bitmap(ybegin, yend, offs, yoff, xoff, start_x, end_x);
864 				}
865 			}
866 			else if (ECMON)
867 			{
868 				ecm = ch >> 6;
869 				m_ecmcolor[0] = m_colors[ecm];
870 				m_ecmcolor[1] = attr;
871 				draw_character(ybegin, yend, ch & ~0xC0, yoff, xoff, m_ecmcolor, start_x, end_x);
872 			}
873 			else if (MULTICOLORON && (attr & 8))
874 			{
875 				m_multi[3] = attr & 7;
876 				draw_character_multi(ybegin, yend, ch, yoff, xoff, start_x, end_x);
877 			}
878 			else
879 			{
880 				m_mono[1] = attr;
881 				draw_character(ybegin, yend, ch, yoff, xoff, m_mono, start_x, end_x);
882 			}
883 		}
884 		/* sprite priority, sprite overwrites lowerprior pixels */
885 		for (i = 7; i >= 0; i--)
886 		{
887 			if (m_sprites[i].line || m_sprites[i].repeat)
888 			{
889 				syend = yend;
890 				if (SPRITE_Y_EXPAND(i))
891 				{
892 					if ((21 - m_sprites[i].line) * 2 - m_sprites[i].repeat < yend - ybegin + 1)
893 						syend = ybegin + (21 - m_sprites[i].line) * 2 - m_sprites[i].repeat - 1;
894 				}
895 				else
896 				{
897 					if (m_sprites[i].line + yend - ybegin + 1 > 20)
898 						syend = ybegin + 20 - m_sprites[i].line;
899 				}
900 				if (yoff + syend > YPOS + 200)
901 					syend = YPOS + 200 - yoff - 1;
902 				if (SPRITE_MULTICOLOR(i))
903 					draw_sprite_multi(i, yoff, ybegin, syend, start_x, end_x);
904 				else
905 					draw_sprite(i, yoff, ybegin, syend, start_x, end_x);
906 				if ((syend != yend) || (m_sprites[i].line > 20))
907 				{
908 					m_sprites[i].line = m_sprites[i].repeat = 0;
909 					for (j = syend; j <= yend; j++)
910 						m_sprites[i].paintedline[j] = 0;
911 				}
912 			}
913 			// sprite wrap y at the top of the screen
914 			else if (SPRITEON(i) && (yoff == 1 + yend - ybegin) && (SPRITE_Y_POS(i) < 1 + yend - ybegin))
915 			{
916 				int wrapped = 1 + yend - ybegin - SPRITE_Y_POS(i);
917 				syend = yend;
918 
919 				if (SPRITE_Y_EXPAND(i))
920 				{
921 					if (wrapped & 1) m_sprites[i].repeat = 1;
922 					wrapped >>= 1;
923 					syend = 21 * 2 - 1 - wrapped * 2;
924 					if (syend > (yend - ybegin)) syend = yend - ybegin;
925 				}
926 				else
927 				{
928 					syend = 21 - 1 - wrapped;
929 					if (syend > (yend - ybegin)) syend = yend - ybegin;
930 				}
931 
932 				m_sprites[i].line = wrapped;
933 
934 				if (SPRITE_MULTICOLOR(i))
935 					draw_sprite_multi(i, yoff, 0 , syend, start_x, end_x);
936 				else
937 					draw_sprite(i, yoff, 0 , syend, start_x, end_x);
938 
939 				if ((syend != yend) || (m_sprites[i].line > 20))
940 				{
941 					for (j = syend; j <= yend; j++)
942 						m_sprites[i].paintedline[j] = 0;
943 					m_sprites[i].line = m_sprites[i].repeat = 0;
944 				}
945 			}
946 			else if (SPRITEON(i) && (yoff + ybegin <= SPRITE_Y_POS(i))
947 						&& (yoff + yend >= SPRITE_Y_POS(i)))
948 			{
949 				syend = yend;
950 				if (SPRITE_Y_EXPAND(i))
951 				{
952 					if (21 * 2 < yend - ybegin + 1)
953 						syend = ybegin + 21 * 2 - 1;
954 				}
955 				else
956 				{
957 					if (yend - ybegin + 1 > 21)
958 						syend = ybegin + 21 - 1;
959 				}
960 				if (yoff + syend >= YPOS + 200)
961 					syend = YPOS + 200 - yoff - 1;
962 				for (j = 0; j < SPRITE_Y_POS(i) - yoff; j++)
963 					m_sprites[i].paintedline[j] = 0;
964 				if (SPRITE_MULTICOLOR(i))
965 					draw_sprite_multi(i, yoff, SPRITE_Y_POS(i) - yoff, syend, start_x, end_x);
966 				else
967 					draw_sprite(i, yoff, SPRITE_Y_POS(i) - yoff, syend, start_x, end_x);
968 				if ((syend != yend) || (m_sprites[i].line > 20))
969 				{
970 					for (j = syend; j <= yend; j++)
971 						m_sprites[i].paintedline[j] = 0;
972 					m_sprites[i].line = m_sprites[i].repeat = 0;
973 				}
974 			}
975 			else
976 			{
977 				memset (m_sprites[i].paintedline, 0, sizeof (m_sprites[i].paintedline));
978 			}
979 		}
980 
981 		for (i = ybegin; i <= yend; i++)
982 		{
983 			m_bitmap->plot_box(0, yoff + ybegin + FIRSTLINE, xbegin, yend - ybegin + 1, FRAMECOLOR);
984 			m_bitmap->plot_box(xend, yoff + ybegin + FIRSTLINE, m_bitmap->width() - xend, yend - ybegin + 1, FRAMECOLOR);
985 		}
986 	}
987 	if (last < m_bitmap->height())
988 		end = last;
989 	else
990 		end = m_bitmap->height();
991 
992 	for (; line < end; line++)
993 	{
994 		std::fill_n(&m_bitmap->pix(line + FIRSTLINE), m_bitmap->width(), FRAMECOLOR);
995 	}
996 }
997 
vic2_drawlines(int first,int last,int start_x,int end_x)998 void vic3_device::vic2_drawlines( int first, int last, int start_x, int end_x )
999 {
1000 	if (VIC3_BITPLANES)
1001 		return;
1002 
1003 	/* temporary allowing vic3 displaying 80 columns */
1004 	if (m_reg[0x31] & 0x80)
1005 	{
1006 		drawlines(first, first + 1, start_x, end_x);
1007 		return;
1008 	}
1009 
1010 	/* otherwise, draw VIC II output (currently using the old code, not the new one from vic6567.c) */
1011 
1012 	/* top part of display not rastered */
1013 	first -= VIC2_YPOS - YPOS;
1014 
1015 	int xbegin = VIC2_STARTVISIBLECOLUMNS;
1016 	int xend = xbegin + VIC2_VISIBLECOLUMNS;
1017 	if (!SCREENON)
1018 	{
1019 		xbegin = VIC2_STARTVISIBLECOLUMNS;
1020 		xend = xbegin + VIC2_VISIBLECOLUMNS;
1021 		if ((start_x <= xbegin) && (end_x >= xend))
1022 			m_bitmap->plot_box(xbegin, first + FIRSTLINE, xend - xbegin, 1, FRAMECOLOR);
1023 		if ((start_x > xbegin) && (end_x >= xend))
1024 			m_bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, xend - start_x, 1, FRAMECOLOR);
1025 		if ((start_x <= xbegin) && (end_x < xend))
1026 			m_bitmap->plot_box(xbegin, first + FIRSTLINE, end_x - xbegin , 1, FRAMECOLOR);
1027 		if ((start_x > xbegin) && (end_x < xend))
1028 			m_bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, end_x - start_x, 1, FRAMECOLOR);
1029 		return;
1030 	}
1031 
1032 	if (COLUMNS40)
1033 	{
1034 		xbegin = XPOS;
1035 		xend = xbegin + 320;
1036 	}
1037 	else
1038 	{
1039 		xbegin = XPOS + 7;
1040 		xend = xbegin + 304;
1041 	}
1042 
1043 	int end;
1044 	if (first + 1 < m_y_begin)
1045 		end = first + 1;
1046 	else
1047 		end = m_y_begin + YPOS;
1048 
1049 	int line = first;
1050 	// top border
1051 	if (line < end)
1052 	{
1053 		if ((start_x <= xbegin) && (end_x >= xend))
1054 			m_bitmap->plot_box(xbegin, first + FIRSTLINE, xend - xbegin, 1, FRAMECOLOR);
1055 		if ((start_x > xbegin) && (end_x >= xend))
1056 			m_bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, xend - start_x, 1, FRAMECOLOR);
1057 		if ((start_x <= xbegin) && (end_x < xend))
1058 			m_bitmap->plot_box(xbegin, first + FIRSTLINE, end_x - xbegin , 1, FRAMECOLOR);
1059 		if ((start_x > xbegin) && (end_x < xend))
1060 			m_bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, end_x - start_x, 1, FRAMECOLOR);
1061 		line = end;
1062 	}
1063 
1064 	int vline = line - YPOS + 3 - VERTICALPOS;
1065 
1066 	if (first + 1 < m_y_end + YPOS)
1067 		end = first + 1;
1068 	else
1069 		end = m_y_end + YPOS;
1070 
1071 	if (line < end)
1072 	{
1073 		int offs = (vline >> 3) * 40;
1074 		int ybegin = vline & 7;
1075 		int yoff = line - ybegin;
1076 		int yend = (yoff + 7 < end) ? 7 : (end - yoff - 1);
1077 
1078 		/* rendering 39 characters */
1079 		/* left and right borders are overwritten later */
1080 
1081 		m_shift[line] = HORIZONTALPOS;
1082 		for (int xoff = m_x_begin + XPOS; xoff < m_x_end + XPOS; xoff += 8, offs++)
1083 		{
1084 			int ch = m_dma_read_cb(m_videoaddr + offs);
1085 #if 0
1086 			int attr = m_dma_read_color_cb(m_videoaddr + offs);
1087 #else
1088 			/* temporary until vic3 finished */
1089 			int attr = m_dma_read_color_cb((m_videoaddr + offs)&0x3ff)&0x0f;
1090 #endif
1091 			if (HIRESON)
1092 			{
1093 				m_bitmapmulti[1] = m_c64_bitmap[1] = ch >> 4;
1094 				m_bitmapmulti[2] = m_c64_bitmap[0] = ch & 0xf;
1095 				if (MULTICOLORON)
1096 				{
1097 					m_bitmapmulti[3] = attr;
1098 					draw_bitmap_multi(ybegin, yend, offs, yoff, xoff, start_x, end_x);
1099 				}
1100 				else
1101 				{
1102 					draw_bitmap(ybegin, yend, offs, yoff, xoff, start_x, end_x);
1103 				}
1104 			}
1105 			else if (ECMON)
1106 			{
1107 				int ecm = ch >> 6;
1108 				m_ecmcolor[0] = m_colors[ecm];
1109 				m_ecmcolor[1] = attr;
1110 				draw_character(ybegin, yend, ch & ~0xC0, yoff, xoff, m_ecmcolor, start_x, end_x);
1111 			}
1112 			else if (MULTICOLORON && (attr & 8))
1113 			{
1114 				m_multi[3] = attr & 7;
1115 				draw_character_multi(ybegin, yend, ch, yoff, xoff, start_x, end_x);
1116 			}
1117 			else
1118 			{
1119 				m_mono[1] = attr;
1120 				draw_character(ybegin, yend, ch, yoff, xoff, m_mono, start_x, end_x);
1121 			}
1122 		}
1123 
1124 		/* sprite priority, sprite overwrites lowerprior pixels */
1125 		for (int i = 7; i >= 0; i--)
1126 		{
1127 			if (SPRITEON (i) &&
1128 					(yoff + ybegin >= SPRITE_Y_POS (i)) &&
1129 					(yoff + ybegin - SPRITE_Y_POS (i) < (SPRITE_Y_EXPAND (i)? 21 * 2 : 21 )) &&
1130 					(SPRITE_Y_POS (i) < 0))
1131 			{
1132 				int wrapped = - SPRITE_Y_POS (i) + 6;
1133 
1134 				int syend = yend;
1135 
1136 				if (SPRITE_Y_EXPAND (i))
1137 				{
1138 					if (wrapped & 1) m_sprites[i].repeat = 1;
1139 					wrapped >>= 1;
1140 					syend = 21 * 2 - 1 - wrapped * 2;
1141 					if (syend > (yend - ybegin)) syend = yend - ybegin;
1142 				}
1143 				else
1144 				{
1145 					syend = 21 - 1 - wrapped;
1146 					if (syend > (yend - ybegin)) syend = yend - ybegin;
1147 				}
1148 
1149 				m_sprites[i].line = wrapped;
1150 
1151 				if (SPRITE_MULTICOLOR (i))
1152 					draw_sprite_multi(i, 0, 0 , syend, start_x, end_x);
1153 				else
1154 					draw_sprite(i, 0, 0 , syend, start_x, end_x);
1155 			}
1156 			else if     (SPRITEON (i) &&
1157 					(yoff + ybegin >= SPRITE_Y_POS (i)) &&
1158 					(yoff + ybegin - SPRITE_Y_POS (i) < (SPRITE_Y_EXPAND (i)? 21 * 2 : 21 )) &&
1159 					(SPRITE_Y_POS (i) >= 0))
1160 			{
1161 				int wrapped = yoff + ybegin - SPRITE_Y_POS (i);
1162 
1163 				int syend = yend;
1164 
1165 				if (SPRITE_Y_EXPAND (i))
1166 				{
1167 					if (wrapped & 1) m_sprites[i].repeat = 1;
1168 					wrapped >>= 1;
1169 					syend = 21 * 2 - 1 - wrapped * 2;
1170 					if (syend > (yend - ybegin)) syend = yend - ybegin;
1171 				}
1172 				else
1173 				{
1174 					syend = 21 - 1 - wrapped;
1175 					if (syend > (yend - ybegin)) syend = yend - ybegin;
1176 				}
1177 
1178 				m_sprites[i].line = wrapped;
1179 
1180 				if (SPRITE_MULTICOLOR (i))
1181 					draw_sprite_multi(i, yoff + ybegin, 0, 0, start_x, end_x);
1182 				else
1183 					draw_sprite(i, yoff + ybegin, 0, 0, start_x, end_x);
1184 			}
1185 			else
1186 			{
1187 				memset(m_sprites[i].paintedline, 0, sizeof (m_sprites[i].paintedline));
1188 			}
1189 		}
1190 		line += 1 + yend - ybegin;
1191 	}
1192 
1193 	// left border
1194 	if ((start_x <= VIC2_STARTVISIBLECOLUMNS) && (end_x >= xbegin))
1195 		m_bitmap->plot_box(VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, xbegin - VIC2_STARTVISIBLECOLUMNS, 1, FRAMECOLOR);
1196 	else if ((start_x > VIC2_STARTVISIBLECOLUMNS) && (end_x >= xbegin))
1197 		m_bitmap->plot_box(start_x, first + FIRSTLINE, xbegin - start_x, 1, FRAMECOLOR);
1198 	else if ((start_x <= VIC2_STARTVISIBLECOLUMNS) && (end_x < xbegin))
1199 		m_bitmap->plot_box(VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, end_x, 1, FRAMECOLOR);
1200 	else if ((start_x > VIC2_STARTVISIBLECOLUMNS) && (end_x < xbegin))
1201 		m_bitmap->plot_box(start_x, first + FIRSTLINE, end_x - start_x, 1, FRAMECOLOR);
1202 
1203 	// right border
1204 	if ((start_x <= xend) && (end_x >= VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS))
1205 		m_bitmap->plot_box(xend, first + FIRSTLINE, VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS - xend, 1, FRAMECOLOR);
1206 	else if ((start_x > xend) && (end_x >= VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS))
1207 		m_bitmap->plot_box(start_x, first + FIRSTLINE, VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS - start_x, 1, FRAMECOLOR);
1208 	else if ((start_x <= xend) && (end_x < VIC2_STARTVISIBLECOLUMNS + VIC2_VISIBLECOLUMNS))
1209 		m_bitmap->plot_box(xend, first + FIRSTLINE, end_x - xend, 1, FRAMECOLOR);
1210 	else if ((start_x > VIC2_STARTVISIBLECOLUMNS) && (end_x < xbegin))
1211 		m_bitmap->plot_box(start_x, first + FIRSTLINE, end_x - start_x, 1, FRAMECOLOR);
1212 
1213 	if (first + 1 < m_bitmap->height())
1214 		end = first + 1;
1215 	else
1216 		end = m_bitmap->height();
1217 
1218 	// bottom border
1219 	if (line < end)
1220 	{
1221 		if ((start_x <= xbegin) && (end_x >= xend))
1222 			m_bitmap->plot_box(xbegin, first + FIRSTLINE, xend - xbegin, 1, FRAMECOLOR);
1223 		if ((start_x > xbegin) && (end_x >= xend))
1224 			m_bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, xend - start_x, 1, FRAMECOLOR);
1225 		if ((start_x <= xbegin) && (end_x < xend))
1226 			m_bitmap->plot_box(xbegin, first + FIRSTLINE, end_x - xbegin , 1, FRAMECOLOR);
1227 		if ((start_x > xbegin) && (end_x < xend))
1228 			m_bitmap->plot_box(start_x - VIC2_STARTVISIBLECOLUMNS, first + FIRSTLINE, end_x - start_x, 1, FRAMECOLOR);
1229 		line = end;
1230 	}
1231 }
1232 
1233 /*****************************************************************************
1234     I/O HANDLERS
1235 *****************************************************************************/
1236 
palette_w(offs_t offset,uint8_t data)1237 void vic3_device::palette_w(offs_t offset, uint8_t data)
1238 {
1239 	if (offset < 0x100)
1240 		m_palette_red[offset] = data;
1241 	else if (offset < 0x200)
1242 		m_palette_green[offset & 0xff] = data;
1243 	else
1244 		m_palette_blue[offset & 0xff] = data;
1245 
1246 	m_palette_dirty = 1;
1247 }
1248 
1249 
port_w(offs_t offset,uint8_t data)1250 void vic3_device::port_w(offs_t offset, uint8_t data)
1251 {
1252 	DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
1253 	offset &= 0x7f;
1254 
1255 	/* offsets 0x00 -> 0x2e coincide with VICII */
1256 	switch (offset)
1257 	{
1258 	case 0x01:
1259 	case 0x03:
1260 	case 0x05:
1261 	case 0x07:
1262 	case 0x09:
1263 	case 0x0b:
1264 	case 0x0d:
1265 	case 0x0f:
1266 									/* sprite y positions */
1267 		if (m_reg[offset] != data)
1268 		{
1269 			m_reg[offset] = data;
1270 			m_sprites[offset / 2].y = SPRITE_Y_POS(offset / 2);
1271 		}
1272 		break;
1273 
1274 	case 0x00:
1275 	case 0x02:
1276 	case 0x04:
1277 	case 0x06:
1278 	case 0x08:
1279 	case 0x0a:
1280 	case 0x0c:
1281 	case 0x0e:
1282 									/* sprite x positions */
1283 		if (m_reg[offset] != data)
1284 		{
1285 			m_reg[offset] = data;
1286 			m_sprites[offset / 2].x = SPRITE_X_POS(offset / 2);
1287 		}
1288 		break;
1289 
1290 	case 0x10:                          /* sprite x positions */
1291 		if (m_reg[offset] != data)
1292 		{
1293 			m_reg[offset] = data;
1294 			m_sprites[0].x = SPRITE_X_POS(0);
1295 			m_sprites[1].x = SPRITE_X_POS(1);
1296 			m_sprites[2].x = SPRITE_X_POS(2);
1297 			m_sprites[3].x = SPRITE_X_POS(3);
1298 			m_sprites[4].x = SPRITE_X_POS(4);
1299 			m_sprites[5].x = SPRITE_X_POS(5);
1300 			m_sprites[6].x = SPRITE_X_POS(6);
1301 			m_sprites[7].x = SPRITE_X_POS(7);
1302 		}
1303 		break;
1304 
1305 	case 0x17:                          /* sprite y size */
1306 		if (m_reg[offset] != data)
1307 		{
1308 			m_reg[offset] = data;
1309 		}
1310 		break;
1311 
1312 	case 0x1d:                          /* sprite x size */
1313 		if (m_reg[offset] != data)
1314 		{
1315 			m_reg[offset] = data;
1316 		}
1317 		break;
1318 
1319 	case 0x1b:                          /* sprite background priority */
1320 		if (m_reg[offset] != data)
1321 		{
1322 			m_reg[offset] = data;
1323 		}
1324 		break;
1325 
1326 	case 0x1c:                          /* sprite multicolor mode select */
1327 		if (m_reg[offset] != data)
1328 		{
1329 			m_reg[offset] = data;
1330 		}
1331 		break;
1332 
1333 	case 0x27:
1334 	case 0x28:
1335 	case 0x29:
1336 	case 0x2a:
1337 	case 0x2b:
1338 	case 0x2c:
1339 	case 0x2d:
1340 	case 0x2e:
1341 									/* sprite colors */
1342 		if (m_reg[offset] != data)
1343 		{
1344 			m_reg[offset] = data;
1345 		}
1346 		break;
1347 
1348 	case 0x25:                          /* sprite multicolor */
1349 		if (m_reg[offset] != data)
1350 		{
1351 			m_reg[offset] = data;
1352 			m_spritemulti[1] = SPRITE_MULTICOLOR1;
1353 		}
1354 		break;
1355 
1356 	case 0x26:                          /* sprite multicolor */
1357 		if (m_reg[offset] != data)
1358 		{
1359 			m_reg[offset] = data;
1360 			m_spritemulti[3] = SPRITE_MULTICOLOR2;
1361 		}
1362 		break;
1363 
1364 	case 0x19:
1365 		clear_interrupt(data & 0x0f);
1366 		break;
1367 
1368 	case 0x1a:                          /* irq mask */
1369 		m_reg[offset] = data;
1370 		set_interrupt(0);   // beamrider needs this
1371 		break;
1372 
1373 	case 0x11:
1374 		if (m_reg[offset] != data)
1375 		{
1376 			m_reg[offset] = data;
1377 			if (LINES25)
1378 			{
1379 				m_y_begin = 0;
1380 				m_y_end = m_y_begin + 200;
1381 			}
1382 			else
1383 			{
1384 				m_y_begin = 4;
1385 				m_y_end = m_y_begin + 192;
1386 			}
1387 		}
1388 		break;
1389 
1390 	case 0x12:
1391 		if (data != m_reg[offset])
1392 		{
1393 			m_reg[offset] = data;
1394 		}
1395 		break;
1396 
1397 	case 0x16:
1398 		if (m_reg[offset] != data)
1399 		{
1400 			m_reg[offset] = data;
1401 			m_x_begin = HORIZONTALPOS;
1402 			m_x_end = m_x_begin + 320;
1403 		}
1404 		break;
1405 
1406 	case 0x18:
1407 		if (m_reg[offset] != data)
1408 		{
1409 			m_reg[offset] = data;
1410 			m_videoaddr = VIDEOADDR;
1411 			m_chargenaddr = CHARGENADDR;
1412 			m_bitmapaddr = BITMAPADDR;
1413 		}
1414 		break;
1415 
1416 	case 0x21:                          /* background color */
1417 		if (m_reg[offset] != data)
1418 		{
1419 			m_reg[offset] = data;
1420 			m_mono[0] = m_bitmapmulti[0] = m_multi[0] = m_colors[0] = BACKGROUNDCOLOR;
1421 		}
1422 		break;
1423 
1424 	case 0x22:                          /* background color 1 */
1425 		if (m_reg[offset] != data)
1426 		{
1427 			m_reg[offset] = data;
1428 			m_multi[1] = m_colors[1] = MULTICOLOR1;
1429 		}
1430 		break;
1431 
1432 	case 0x23:                          /* background color 2 */
1433 		if (m_reg[offset] != data)
1434 		{
1435 			m_reg[offset] = data;
1436 			m_multi[2] = m_colors[2] = MULTICOLOR2;
1437 		}
1438 		break;
1439 
1440 	case 0x24:                          /* background color 3 */
1441 		if (m_reg[offset] != data)
1442 		{
1443 			m_reg[offset] = data;
1444 			m_colors[3] = FOREGROUNDCOLOR;
1445 		}
1446 		break;
1447 
1448 	case 0x20:                          /* framecolor */
1449 		if (m_reg[offset] != data)
1450 		{
1451 			m_reg[offset] = data;
1452 		}
1453 		break;
1454 
1455 	case 0x2f:
1456 		DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
1457 		m_reg[offset] = data;
1458 		break;
1459 	case 0x30:
1460 		m_reg[offset] = data;
1461 		if (!m_port_changed_cb.isnull())
1462 		{
1463 			DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
1464 			m_reg[offset] = data;
1465 			m_port_changed_cb((offs_t)0,data);
1466 		}
1467 		break;
1468 	case 0x31:
1469 		m_reg[offset] = data;
1470 		if (data & 0x40)
1471 			m_cpu->set_clock_scale(1.0);
1472 		else
1473 			m_cpu->set_clock_scale(1.0/3.5);
1474 		break;
1475 	case 0x32:
1476 	case 0x33:
1477 	case 0x34:
1478 	case 0x35:
1479 	case 0x36:
1480 	case 0x37:
1481 	case 0x38:
1482 	case 0x39:
1483 	case 0x3a:
1484 	case 0x3b:
1485 	case 0x3c:
1486 	case 0x3d:
1487 	case 0x3e:
1488 	case 0x3f:
1489 		m_reg[offset] = data;
1490 		DBG_LOG(2, "vic write", ("%.2x:%.2x\n", offset, data));
1491 		break;
1492 	case 0x40:
1493 	case 0x41:
1494 	case 0x42:
1495 	case 0x43:
1496 	case 0x44:
1497 	case 0x45:
1498 	case 0x46:
1499 	case 0x47:
1500 		DBG_LOG(2, "vic plane write", ("%.2x:%.2x\n", offset, data));
1501 		break;
1502 	default:
1503 		m_reg[offset] = data;
1504 		break;
1505 	}
1506 }
1507 
port_r(offs_t offset)1508 uint8_t vic3_device::port_r(offs_t offset)
1509 {
1510 	int val = 0;
1511 	offset &= 0x7f;
1512 
1513 	/* offsets 0x00 -> 0x2e coincide with VICII */
1514 	switch (offset)
1515 	{
1516 	case 0x11:
1517 		val = (m_reg[offset] & ~0x80) | ((m_rasterline & 0x100) >> 1);
1518 		break;
1519 
1520 	case 0x12:
1521 		val = m_rasterline & 0xff;
1522 		break;
1523 
1524 	case 0x16:
1525 		val = m_reg[offset] | 0xc0;
1526 		break;
1527 
1528 	case 0x18:
1529 		val = m_reg[offset] | 0x01;
1530 		break;
1531 
1532 	case 0x19:                          /* interrupt flag register */
1533 		/* vic2_clear_interrupt(0xf); */
1534 		val = m_reg[offset] | 0x70;
1535 		break;
1536 
1537 	case 0x1a:
1538 		val = m_reg[offset] | 0xf0;
1539 		break;
1540 
1541 	case 0x1e:                          /* sprite to sprite collision detect */
1542 		val = m_reg[offset];
1543 		m_reg[offset] = 0;
1544 		clear_interrupt(4);
1545 		break;
1546 
1547 	case 0x1f:                          /* sprite to background collision detect */
1548 		val = m_reg[offset];
1549 		m_reg[offset] = 0;
1550 		clear_interrupt(2);
1551 		break;
1552 
1553 	case 0x20:
1554 	case 0x21:
1555 	case 0x22:
1556 	case 0x23:
1557 	case 0x24:
1558 		val = m_reg[offset];
1559 		break;
1560 
1561 	case 0x00:
1562 	case 0x01:
1563 	case 0x02:
1564 	case 0x03:
1565 	case 0x04:
1566 	case 0x05:
1567 	case 0x06:
1568 	case 0x07:
1569 	case 0x08:
1570 	case 0x09:
1571 	case 0x0a:
1572 	case 0x0b:
1573 	case 0x0c:
1574 	case 0x0d:
1575 	case 0x0e:
1576 	case 0x0f:
1577 	case 0x10:
1578 	case 0x17:
1579 	case 0x1b:
1580 	case 0x1c:
1581 	case 0x1d:
1582 	case 0x25:
1583 	case 0x26:
1584 	case 0x27:
1585 	case 0x28:
1586 	case 0x29:
1587 	case 0x2a:
1588 	case 0x2b:
1589 	case 0x2c:
1590 	case 0x2d:
1591 	case 0x2e:
1592 		val = m_reg[offset];
1593 		break;
1594 
1595 	case 0x2f:
1596 	case 0x30:
1597 		val = m_reg[offset];
1598 		DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val));
1599 		break;
1600 	case 0x31:
1601 	case 0x32:
1602 	case 0x33:
1603 	case 0x34:
1604 	case 0x35:
1605 	case 0x36:
1606 	case 0x37:
1607 	case 0x38:
1608 	case 0x39:
1609 	case 0x3a:
1610 	case 0x3b:
1611 	case 0x3c:
1612 	case 0x3d:
1613 	case 0x3e:
1614 	case 0x3f:                         /* not used */
1615 		val = m_reg[offset];
1616 		DBG_LOG(2, "vic read", ("%.2x:%.2x\n", offset, val));
1617 		break;
1618 	case 0x40:
1619 	case 0x41:
1620 	case 0x42:
1621 	case 0x43:
1622 	case 0x44:
1623 	case 0x45:
1624 	case 0x46:
1625 	case 0x47:
1626 		DBG_LOG(2, "vic3 plane read", ("%.2x:%.2x\n", offset, val));
1627 		break;
1628 	default:
1629 		val = m_reg[offset];
1630 	}
1631 	return val;
1632 }
1633 
1634 
1635 #define VIC3_MASK(M)                                                \
1636 	if (M)                                                          \
1637 	{                                                               \
1638 		if (M & 0x01)                                               \
1639 			colors[0] = m_c64_mem_r_cb(VIC3_ADDR(0) + offset);      \
1640 		if (M & 0x02)                                               \
1641 			colors[1] = m_c64_mem_r_cb(VIC3_ADDR(1) + offset) << 1; \
1642 		if (M & 0x04)                                               \
1643 			colors[2] = m_c64_mem_r_cb(VIC3_ADDR(2) + offset) << 2; \
1644 		if (M & 0x08)                                               \
1645 			colors[3] = m_c64_mem_r_cb(VIC3_ADDR(3) + offset) << 3; \
1646 		if (M & 0x10)                                               \
1647 			colors[4] = m_c64_mem_r_cb(VIC3_ADDR(4) + offset) << 4; \
1648 		if (M & 0x20)                                               \
1649 			colors[5] = m_c64_mem_r_cb(VIC3_ADDR(5) + offset) << 5; \
1650 		if (M & 0x40)                                               \
1651 			colors[6] = m_c64_mem_r_cb(VIC3_ADDR(6) + offset) << 6; \
1652 		if (M & 0x80)                                               \
1653 			colors[7] = m_c64_mem_r_cb(VIC3_ADDR(7) + offset) << 7; \
1654 		for (int i = 7; i >= 0; i--)                                \
1655 		{                                                           \
1656 			int p = 0;                                              \
1657 			if (M & 0x01)                                           \
1658 			{                                                       \
1659 				p = colors[0] & 0x01;                               \
1660 				colors[0] >>= 1;                                    \
1661 			}                                                       \
1662 			if (M & 0x02)                                           \
1663 			{                                                       \
1664 				p |= colors[1] & 0x02;                              \
1665 				colors[1] >>= 1;                                    \
1666 			}                                                       \
1667 			if (M & 0x04)                                           \
1668 			{                                                       \
1669 				p |= colors[2] & 0x04;                              \
1670 				colors[2] >>= 1;                                    \
1671 			}                                                       \
1672 			if (M & 0x08)                                           \
1673 			{                                                       \
1674 				p |= colors[3] & 0x08;                              \
1675 				colors[3] >>= 1;                                    \
1676 			}                                                       \
1677 			if (M & 0x10)                                           \
1678 			{                                                       \
1679 				p |= colors[4] & 0x10;                              \
1680 				colors[4] >>= 1;                                    \
1681 			}                                                       \
1682 			if (M & 0x20)                                           \
1683 			{                                                       \
1684 				p |= colors[5] & 0x20;                              \
1685 				colors[5] >>= 1;                                    \
1686 			}                                                       \
1687 			if (M & 0x40)                                           \
1688 			{                                                       \
1689 				p |= colors[6] & 0x40;                              \
1690 				colors[6] >>= 1;                                    \
1691 			}                                                       \
1692 			if (M & 0x80)                                           \
1693 			{                                                       \
1694 				p |= colors[7] & 0x80;                              \
1695 				colors[7] >>= 1;                                    \
1696 			}                                                       \
1697 			m_bitmap->pix(YPOS + y, XPOS + x + i) = p;              \
1698 		}                                                           \
1699 	}
1700 
1701 #define VIC3_ADDR(a) VIC3_BITPLANE_IADDR(a)
interlace_draw_block(int x,int y,int offset)1702 void vic3_device::interlace_draw_block( int x, int y, int offset )
1703 {
1704 	int colors[8] = {0};
1705 
1706 	switch (VIC3_BITPLANES_MASK)
1707 	{
1708 	case 0x05:
1709 		VIC3_MASK(0x05)
1710 		break;
1711 	case 0x07:
1712 		VIC3_MASK(0x07)
1713 		break;
1714 	case 0x0f:
1715 		VIC3_MASK(0x0f)
1716 		break;
1717 	case 0x1f:
1718 		VIC3_MASK(0x1f)
1719 		break;
1720 	case 0x7f:
1721 		VIC3_MASK(0x7f)
1722 		break;
1723 	case 0xff:
1724 		VIC3_MASK(0xff)
1725 		break;
1726 	default:
1727 		if (VIC3_BITPLANES_MASK & 0x01)
1728 			colors[0] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(0) + offset);
1729 
1730 		if (VIC3_BITPLANES_MASK & 0x02)
1731 			colors[1] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(1) + offset) << 1;
1732 
1733 		if (VIC3_BITPLANES_MASK & 0x04)
1734 			colors[2] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(2) + offset) << 2;
1735 
1736 		if (VIC3_BITPLANES_MASK & 0x08)
1737 			colors[3] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(3) + offset) << 3;
1738 
1739 		if (VIC3_BITPLANES_MASK & 0x10)
1740 			colors[4] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(4) + offset) << 4;
1741 
1742 		if (VIC3_BITPLANES_MASK & 0x20)
1743 			colors[5] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(5) + offset) << 5;
1744 
1745 		if (VIC3_BITPLANES_MASK & 0x40)
1746 			colors[6] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(6) + offset) << 6;
1747 
1748 		if (VIC3_BITPLANES_MASK & 0x80)
1749 			colors[7] = m_c64_mem_r_cb(VIC3_BITPLANE_IADDR(7) + offset) << 7;
1750 
1751 		for (int i = 7; i >= 0; i--)
1752 		{
1753 			m_bitmap->pix(YPOS + y, XPOS + x + i) =
1754 					(colors[0] & 0x01) | (colors[1] & 0x02) |
1755 					(colors[2] & 0x04) | (colors[3] & 0x08) |
1756 					(colors[4] & 0x10) | (colors[5] & 0x20) |
1757 					(colors[6] & 0x40) | (colors[7] & 0x80);
1758 			colors[0] >>= 1;
1759 			colors[1] >>= 1;
1760 			colors[2] >>= 1;
1761 			colors[3] >>= 1;
1762 			colors[4] >>= 1;
1763 			colors[5] >>= 1;
1764 			colors[6] >>= 1;
1765 			colors[7] >>= 1;
1766 		}
1767 	}
1768 }
1769 
1770 #undef VIC3_ADDR
1771 #define VIC3_ADDR(a) VIC3_BITPLANE_ADDR(a)
draw_block(int x,int y,int offset)1772 void vic3_device::draw_block( int x, int y, int offset )
1773 {
1774 	int colors[8] = {0};
1775 
1776 	switch (VIC3_BITPLANES_MASK)
1777 	{
1778 	case 5:
1779 		VIC3_MASK(0x05)
1780 		break;
1781 	case 7:
1782 		VIC3_MASK(0x07)
1783 		break;
1784 	case 0xf:
1785 		VIC3_MASK(0x0f)
1786 		break;
1787 	case 0x1f:
1788 		VIC3_MASK(0x1f)
1789 		break;
1790 	case 0x7f:
1791 		VIC3_MASK(0x7f)
1792 		break;
1793 	case 0xff:
1794 		VIC3_MASK(0xff)
1795 		break;
1796 	default:
1797 		if (VIC3_BITPLANES_MASK & 0x01)
1798 			colors[0] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(0) + offset);
1799 
1800 		if (VIC3_BITPLANES_MASK & 0x02)
1801 			colors[1] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(1) + offset) << 1;
1802 
1803 		if (VIC3_BITPLANES_MASK & 0x04)
1804 			colors[2] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(2) + offset) << 2;
1805 
1806 		if (VIC3_BITPLANES_MASK & 0x08)
1807 			colors[3] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(3) + offset) << 3;
1808 
1809 		if (VIC3_BITPLANES_MASK & 0x10)
1810 			colors[4] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(4) + offset) << 4;
1811 
1812 		if (VIC3_BITPLANES_MASK & 0x20)
1813 			colors[5] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(5) + offset) << 5;
1814 
1815 		if (VIC3_BITPLANES_MASK & 0x40)
1816 			colors[6] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(6) + offset) << 6;
1817 
1818 		if (VIC3_BITPLANES_MASK & 0x80)
1819 			colors[7] = m_c64_mem_r_cb(VIC3_BITPLANE_ADDR(7) + offset) << 7;
1820 
1821 		for (int i = 7; i >= 0; i--)
1822 		{
1823 			m_bitmap->pix(YPOS + y, XPOS + x + i) =
1824 					(colors[0] & 0x01) | (colors[1] & 0x02) |
1825 					(colors[2] & 0x04) | (colors[3] & 0x08) |
1826 					(colors[4] & 0x10) | (colors[5] & 0x20) |
1827 					(colors[6] & 0x40) | (colors[7] & 0x80);
1828 			colors[0] >>= 1;
1829 			colors[1] >>= 1;
1830 			colors[2] >>= 1;
1831 			colors[3] >>= 1;
1832 			colors[4] >>= 1;
1833 			colors[5] >>= 1;
1834 			colors[6] >>= 1;
1835 			colors[7] >>= 1;
1836 		}
1837 	}
1838 }
1839 
1840 
draw_bitplanes()1841 void vic3_device::draw_bitplanes()
1842 {
1843 	const rectangle &visarea = screen().visible_area();
1844 
1845 	if (VIC3_LINES == 400)
1846 	{ /* interlaced! */
1847 		for (int y1s = 0, offset = 0; y1s < 400; y1s += 16)
1848 		{
1849 			for (int x = 0; x < VIC3_BITPLANES_WIDTH; x += 8)
1850 			{
1851 				for (int y = y1s; y < y1s + 16; y += 2, offset++)
1852 				{
1853 					if (m_interlace)
1854 						draw_block(x, y, offset);
1855 					else
1856 						interlace_draw_block(x, y + 1, offset);
1857 				}
1858 			}
1859 		}
1860 		m_interlace ^= 1;
1861 	}
1862 	else
1863 	{
1864 		for (int y1s = 0, offset = 0; y1s < 200; y1s += 8)
1865 		{
1866 			for (int x = 0; x < VIC3_BITPLANES_WIDTH; x += 8)
1867 			{
1868 				for (int y = y1s; y < y1s + 8; y++, offset++)
1869 				{
1870 					draw_block(x, y, offset);
1871 				}
1872 			}
1873 		}
1874 	}
1875 
1876 	if (XPOS > 0)
1877 	{
1878 		rectangle vis(0, XPOS - 1, 0, visarea.bottom());
1879 		m_bitmap->fill(FRAMECOLOR, vis);
1880 	}
1881 
1882 	if (XPOS + VIC3_BITPLANES_WIDTH < visarea.right())
1883 	{
1884 		rectangle vis(XPOS + VIC3_BITPLANES_WIDTH, visarea.right(), 0, visarea.bottom());
1885 		m_bitmap->fill(FRAMECOLOR, vis);
1886 	}
1887 
1888 	if (YPOS > 0)
1889 	{
1890 		rectangle vis(0, visarea.right(), 0, YPOS - 1);
1891 		m_bitmap->fill(FRAMECOLOR, vis);
1892 	}
1893 
1894 	if (YPOS + VIC3_LINES < visarea.bottom())
1895 	{
1896 		rectangle vis(0, visarea.right(), YPOS + VIC3_LINES, visarea.bottom());
1897 		m_bitmap->fill(FRAMECOLOR, vis);
1898 	}
1899 }
1900 
raster_interrupt_gen()1901 void vic3_device::raster_interrupt_gen()
1902 {
1903 	int new_columns, new_rows;
1904 	int i;
1905 
1906 	m_rasterline++;
1907 	if (m_rasterline >= m_lines)
1908 	{
1909 		m_rasterline = 0;
1910 		if (m_palette_dirty)
1911 			for (i = 0; i < 256; i++)
1912 				set_pen_color(i, m_palette_red[i] << 4, m_palette_green[i] << 4, m_palette_blue[i] << 4);
1913 
1914 		if (m_palette_dirty)
1915 		{
1916 			m_spritemulti[1] = SPRITE_MULTICOLOR1;
1917 			m_spritemulti[3] = SPRITE_MULTICOLOR2;
1918 			m_mono[0] = m_bitmapmulti[0] = m_multi[0] = m_colors[0] = BACKGROUNDCOLOR;
1919 			m_multi[1] = m_colors[1] = MULTICOLOR1;
1920 			m_multi[2] = m_colors[2] = MULTICOLOR2;
1921 			m_colors[3] = FOREGROUNDCOLOR;
1922 			m_palette_dirty = 0;
1923 		}
1924 
1925 		new_rows = 200;
1926 
1927 		if (VIC3_BITPLANES)
1928 		{
1929 			new_columns = VIC3_BITPLANES_WIDTH;
1930 			if (new_columns < 320)
1931 				new_columns = 320; /*sprites resolution about 320x200 */
1932 			new_rows = VIC3_LINES;
1933 		}
1934 		else if (VIC3_80COLUMNS)
1935 		{
1936 			new_columns = 640;
1937 		}
1938 		else
1939 		{
1940 			new_columns = 320;
1941 		}
1942 		if ((new_columns != m_columns) || (new_rows != m_rows))
1943 		{
1944 			m_rows = new_rows;
1945 			m_columns = new_columns;
1946 			if (m_type == vic3_type::PAL)
1947 				screen().set_visible_area(
1948 									VIC2_STARTVISIBLECOLUMNS + 32,
1949 									VIC2_STARTVISIBLECOLUMNS + 32 + m_columns + 16 - 1,
1950 									VIC2_STARTVISIBLELINES + 34,
1951 									VIC2_STARTVISIBLELINES + 34 + m_rows + 16 - 1);
1952 			else
1953 				screen().set_visible_area(
1954 									VIC2_STARTVISIBLECOLUMNS + 34,
1955 									VIC2_STARTVISIBLECOLUMNS + 34 + m_columns + 16 - 1,
1956 									VIC2_STARTVISIBLELINES + 10,
1957 									VIC2_STARTVISIBLELINES + 10 + m_rows + 16 - 1);
1958 		}
1959 		if (VIC3_BITPLANES)
1960 		{
1961 			draw_bitplanes();
1962 		}
1963 		else
1964 		{
1965 			if (m_type == vic3_type::PAL)
1966 			{
1967 				if (m_on)
1968 					vic2_drawlines(m_lastline, m_lines, VIC2_STARTVISIBLECOLUMNS + 32, VIC2_STARTVISIBLECOLUMNS + 32 + m_columns + 16 - 1);
1969 			}
1970 			else
1971 			{
1972 				if (m_on)
1973 					vic2_drawlines(m_lastline, m_lines, VIC2_STARTVISIBLECOLUMNS + 34, VIC2_STARTVISIBLECOLUMNS + 34 + m_columns + 16 - 1);
1974 			}
1975 		}
1976 
1977 		for (i = 0; i < 8; i++)
1978 			m_sprites[i].repeat = m_sprites[i].line = 0;
1979 
1980 		m_lastline = 0;
1981 
1982 		if (LIGHTPEN_BUTTON)
1983 		{
1984 			/* lightpen timer start */
1985 			machine().scheduler().timer_set(attotime(0, 0), timer_expired_delegate(FUNC(vic3_device::timer_timeout),this), 1);
1986 		}
1987 
1988 	}
1989 
1990 	if (m_rasterline == C64_2_RASTERLINE(RASTERLINE))
1991 	{
1992 		set_interrupt(1);
1993 	}
1994 
1995 	if (m_on)
1996 		if ((m_rasterline >= VIC2_FIRSTRASTERLINE) && (m_rasterline < (VIC2_FIRSTRASTERLINE + VIC2_VISIBLELINES)))
1997 		{
1998 			if (m_type == vic3_type::PAL)
1999 			{
2000 				if (m_on)
2001 					vic2_drawlines(m_rasterline - 1, m_rasterline, VIC2_STARTVISIBLECOLUMNS + 32, VIC2_STARTVISIBLECOLUMNS + 32 + m_columns + 16 - 1);
2002 			}
2003 			else
2004 			{
2005 				if (m_on)
2006 					vic2_drawlines(m_rasterline - 1, m_rasterline, VIC2_STARTVISIBLECOLUMNS + 34, VIC2_STARTVISIBLECOLUMNS + 34 + m_columns + 16 - 1);
2007 			}
2008 		}
2009 }
2010 
video_update(bitmap_ind16 & bitmap,const rectangle & cliprect)2011 uint32_t vic3_device::video_update( bitmap_ind16 &bitmap, const rectangle &cliprect )
2012 {
2013 	copybitmap(bitmap, *m_bitmap, 0, 0, 0, 0, cliprect);
2014 	return 0;
2015 }
2016