1 // license:BSD-3-Clause
2 // copyright-holders:Mathis Rosenhauer
3 // thanks-to:Eric Smith, Brad Oliver, Bernd Wiebelt, Aaron Giles, Andrew Caldwell
4 /*************************************************************************
5 
6     avgdvg.c: Atari DVG and AVG
7 
8     Some parts of this code are based on the original version by Eric
9     Smith, Brad Oliver, Bernd Wiebelt, Aaron Giles, Andrew Caldwell
10 
11     The schematics and Jed Margolin's article on Vector Generators were
12     very helpful in understanding the hardware.
13 
14 
15 **************************************************************************/
16 
17 #include "emu.h"
18 #include "avgdvg.h"
19 #include "screen.h"
20 
21 /*************************************
22  *
23  *  Macros and defines
24  *
25  *************************************/
26 
27 #define MASTER_CLOCK (12096000)
28 #define VGSLICE      (10000)
29 #define VGVECTOR 0
30 #define VGCLIP 1
31 
32 #define OP0 (m_op & 1)
33 #define OP1 (m_op & 2)
34 #define OP2 (m_op & 4)
35 #define OP3 (m_op & 8)
36 
37 #define ST3 (m_state_latch & 8)
38 
39 
40 /*************************************
41  *
42  *  Flipping
43  *
44  *************************************/
45 
apply_flipping(int * x,int * y)46 void avgdvg_device::apply_flipping(int *x, int *y)
47 {
48 	if (m_flip_x)
49 		*x += (m_xcenter - *x) << 1;
50 	if (m_flip_y)
51 		*y += (m_ycenter - *y) << 1;
52 }
53 
54 
55 /*************************************
56  *
57  *  Vector buffering
58  *
59  *************************************/
60 
vg_flush()61 void avgdvg_device::vg_flush()
62 {
63 	int cx0 = 0, cy0 = 0, cx1 = 0x5000000, cy1 = 0x5000000;
64 	int i = 0;
65 
66 	while (m_vectbuf[i].status == VGCLIP)
67 		i++;
68 	int xs = m_vectbuf[i].x;
69 	int ys = m_vectbuf[i].y;
70 
71 	for (i = 0; i < m_nvect; i++)
72 	{
73 		if (m_vectbuf[i].status == VGVECTOR)
74 		{
75 			int xe = m_vectbuf[i].x;
76 			int ye = m_vectbuf[i].y;
77 			int x0 = xs, y0 = ys, x1 = xe, y1 = ye;
78 
79 			xs = xe;
80 			ys = ye;
81 
82 			if ((x0 < cx0 && x1 < cx0) || (x0 > cx1 && x1 > cx1))
83 				continue;
84 
85 			if (x0 < cx0)
86 			{
87 				y0 += s64(cx0 - x0) * s64(y1 - y0) / (x1 - x0);
88 				x0 = cx0;
89 			}
90 			else if (x0 > cx1)
91 			{
92 				y0 += s64(cx1 - x0) * s64(y1 - y0) / (x1 - x0);
93 				x0 = cx1;
94 			}
95 			if (x1 < cx0)
96 			{
97 				y1 += s64(cx0 - x1) * s64(y1 - y0) / (x1 - x0);
98 				x1 = cx0;
99 			}
100 			else if (x1 > cx1)
101 			{
102 				y1 += s64(cx1 - x1) * s64(y1 - y0) / (x1 - x0);
103 				x1 = cx1;
104 			}
105 
106 			if ((y0 < cy0 && y1 < cy0) || (y0 > cy1 && y1 > cy1))
107 				continue;
108 
109 			if (y0 < cy0)
110 			{
111 				x0 += s64(cy0 - y0) * s64(x1 - x0) / (y1 - y0);
112 				y0 = cy0;
113 			}
114 			else if (y0 > cy1)
115 			{
116 				x0 += s64(cy1 - y0) * s64(x1 - x0) / (y1 - y0);
117 				y0 = cy1;
118 			}
119 			if (y1 < cy0)
120 			{
121 				x1 += s64(cy0 - y1) * s64(x1 - x0) / (y1 - y0);
122 				y1 = cy0;
123 			}
124 			else if (y1 > cy1)
125 			{
126 				x1 += s64(cy1 - y1) * s64(x1 - x0) / (y1 - y0);
127 				y1 = cy1;
128 			}
129 
130 			m_vector->add_point(x0, y0, m_vectbuf[i].color, 0);
131 			m_vector->add_point(x1, y1, m_vectbuf[i].color, m_vectbuf[i].intensity);
132 		}
133 
134 		if (m_vectbuf[i].status == VGCLIP)
135 		{
136 			cx0 = m_vectbuf[i].x;
137 			cy0 = m_vectbuf[i].y;
138 			cx1 = m_vectbuf[i].arg1;
139 			cy1 = m_vectbuf[i].arg2;
140 			if (cx0 > cx1)
141 			{
142 				const int t = cx1;
143 				cx1 = cx0;
144 				cx0 = t;
145 			}
146 			if (cy0 > cx1)
147 			{
148 				const int t = cy1;
149 				cy1 = cy0;
150 				cy0 = t;
151 			}
152 		}
153 	}
154 
155 	m_nvect = 0;
156 }
157 
vg_add_point_buf(int x,int y,rgb_t color,int intensity)158 void avgdvg_device::vg_add_point_buf(int x, int y, rgb_t color, int intensity)
159 {
160 	if (m_nvect < MAXVECT)
161 	{
162 		m_vectbuf[m_nvect].status = VGVECTOR;
163 		m_vectbuf[m_nvect].x = x;
164 		m_vectbuf[m_nvect].y = y;
165 		m_vectbuf[m_nvect].color = color;
166 		m_vectbuf[m_nvect].intensity = intensity;
167 		m_nvect++;
168 	}
169 }
170 
vg_add_clip(int xmin,int ymin,int xmax,int ymax)171 void avgdvg_device::vg_add_clip(int xmin, int ymin, int xmax, int ymax)
172 {
173 	if (m_nvect < MAXVECT)
174 	{
175 		m_vectbuf[m_nvect].status = VGCLIP;
176 		m_vectbuf[m_nvect].x = xmin;
177 		m_vectbuf[m_nvect].y = ymin;
178 		m_vectbuf[m_nvect].arg1 = xmax;
179 		m_vectbuf[m_nvect].arg2 = ymax;
180 		m_nvect++;
181 	}
182 }
183 
184 
185 /*************************************
186  *
187  *  DVG handler functions
188  *
189  *************************************/
190 
update_databus()191 void dvg_device::update_databus() // dvg_data
192 {
193 	/*
194 	 * DVG uses low bit of state for address
195 	 */
196 	m_data = m_vectorram[(m_pc << 1) | (m_state_latch & 1)];
197 }
198 
state_addr()199 u8 dvg_device::state_addr() // dvg_state_addr
200 {
201 	u8 addr = ((((m_state_latch >> 4) ^ 1) & 1) << 7) | (m_state_latch & 0xf);
202 
203 	if (OP3)
204 		addr |= ((m_op & 7) << 4);
205 
206 	return addr;
207 }
208 
handler_0()209 int dvg_device::handler_0() // dvg_dmapush
210 {
211 	if (OP0 == 0)
212 	{
213 		m_sp = (m_sp + 1) & 0xf;
214 		m_stack[m_sp & 3] = m_pc;
215 	}
216 	return 0;
217 }
218 
handler_1()219 int dvg_device::handler_1() // dvg_dmald
220 {
221 	if (OP0)
222 	{
223 		m_pc = m_stack[m_sp & 3];
224 		m_sp = (m_sp - 1) & 0xf;
225 	}
226 	else
227 	{
228 		m_pc = m_dvy;
229 	}
230 
231 	return 0;
232 }
233 
dvg_draw_to(int x,int y,int intensity)234 void dvg_device::dvg_draw_to(int x, int y, int intensity)
235 {
236 	apply_flipping(&x, &y);
237 
238 	if (((x | y) & 0x400) == 0)
239 		vg_add_point_buf((m_xmin + x - 512) << 16,
240 							(m_ymin + 512 - y) << 16,
241 							vector_device::color111(7), intensity << 4);
242 }
243 
handler_2()244 int dvg_device::handler_2() //dvg_gostrobe
245 {
246 	int scale;
247 
248 	if (m_op == 0xf)
249 	{
250 		scale = (m_scale +
251 					(((m_dvy & 0x800) >> 11)
252 					| (((m_dvx & 0x800) ^ 0x800) >> 10)
253 					| ((m_dvx & 0x800)  >> 9))) & 0xf;
254 
255 		m_dvy &= 0xf00;
256 		m_dvx &= 0xf00;
257 	}
258 	else
259 	{
260 		scale = (m_scale + m_op) & 0xf;
261 	}
262 
263 	int fin = 0xfff - (((2 << scale) & 0x7ff) ^ 0xfff);
264 
265 	/* Count up or down */
266 	const int dx = (m_dvx & 0x400) ? -1 : +1;
267 	const int dy = (m_dvy & 0x400) ? -1 : +1;
268 
269 	/* Scale factor for rate multipliers */
270 	const int mx = (m_dvx << 2) & 0xfff;
271 	const int my = (m_dvy << 2) & 0xfff;
272 
273 	const int cycles = 8 * fin;
274 	int c = 0;
275 
276 	while (fin--)
277 	{
278 		/*
279 		 *  The 7497 Bit Rate Multiplier is a 6 bit counter with
280 		 *  clever decoding of output bits to perform the following
281 		 *  operation:
282 		 *
283 		 *  fout = m/64 * fin
284 		 *
285 		 *  where fin is the input frequency, fout is the output
286 		 *  frequency and m is a factor at the input pins. Output
287 		 *  pulses are more or less evenly spaced so we get straight
288 		 *  lines. The DVG has two cascaded 7497s for each coordinate.
289 		 */
290 
291 		int countx = 0;
292 		int county = 0;
293 
294 		for (int bit = 0; bit < 12; bit++)
295 		{
296 			if ((c & ((1 << (bit+1)) - 1)) == ((1 << bit) - 1))
297 			{
298 				if (mx & (1 << (11 - bit)))
299 					countx = 1;
300 
301 				if (my & (1 << (11 - bit)))
302 					county = 1;
303 			}
304 		}
305 
306 		c = (c + 1) & 0xfff;
307 
308 		/*
309 		 *  Since x- and y-counters always hold the correct count
310 		 *  wrt. to each other, we can do clipping exactly like the
311 		 *  hardware does. That is, as soon as any counter's bit 10
312 		 *  changes to high, we finish the vector. If bit 10 changes
313 		 *  from high to low, we start a new vector.
314 		 */
315 
316 		if (countx)
317 		{
318 			/* Is y valid and x entering or leaving the valid range? */
319 			if (((m_ypos & 0x400) == 0)
320 				&& ((m_xpos ^ (m_xpos + dx)) & 0x400))
321 			{
322 				if ((m_xpos + dx) & 0x400)
323 					/* We are leaving the valid range */
324 					dvg_draw_to(m_xpos, m_ypos, m_intensity);
325 				else
326 					/* We are entering the valid range */
327 					dvg_draw_to((m_xpos + dx) & 0xfff, m_ypos, 0);
328 			}
329 			m_xpos = (m_xpos + dx) & 0xfff;
330 		}
331 
332 		if (county)
333 		{
334 			if (((m_xpos & 0x400) == 0)
335 				&& ((m_ypos ^ (m_ypos + dy)) & 0x400))
336 			{
337 				if ((m_xpos & 0x400) == 0)
338 				{
339 					if ((m_ypos + dy) & 0x400)
340 						dvg_draw_to(m_xpos, m_ypos, m_intensity);
341 					else
342 						dvg_draw_to(m_xpos, (m_ypos + dy) & 0xfff, 0);
343 				}
344 			}
345 			m_ypos = (m_ypos + dy) & 0xfff;
346 		}
347 
348 	}
349 
350 	dvg_draw_to(m_xpos, m_ypos, m_intensity);
351 
352 	return cycles;
353 }
354 
handler_3()355 int dvg_device::handler_3() // dvg_haltstrobe
356 {
357 	m_halt = OP0;
358 
359 	if (OP0 == 0)
360 	{
361 		m_xpos = m_dvx & 0xfff;
362 		m_ypos = m_dvy & 0xfff;
363 		dvg_draw_to(m_xpos, m_ypos, 0);
364 	}
365 	return 0;
366 }
367 
handler_7()368 int dvg_device::handler_7() // dvg_latch3
369 {
370 	m_dvx = (m_dvx & 0xff) |  ((m_data & 0xf) << 8);
371 	m_intensity = m_data >> 4;
372 	return 0;
373 }
374 
handler_6()375 int dvg_device::handler_6() // dvg_latch2
376 {
377 	m_dvx &= 0xf00;
378 	if (m_op != 0xf)
379 		m_dvx = (m_dvx & 0xf00) | m_data;
380 
381 	if ((m_op & 0xa) == 0xa)
382 		m_scale = m_intensity;
383 
384 	m_pc++;
385 	return 0;
386 }
387 
handler_5()388 int dvg_device::handler_5() //  dvg_latch1
389 {
390 	m_dvy = (m_dvy & 0xff)
391 		| ((m_data & 0xf) << 8);
392 	m_op = m_data >> 4;
393 
394 	if (m_op == 0xf)
395 	{
396 		m_dvx &= 0xf00;
397 		m_dvy &= 0xf00;
398 	}
399 
400 	return 0;
401 }
402 
handler_4()403 int dvg_device::handler_4() // dvg_latch0
404 {
405 	m_dvy &= 0xf00;
406 	if (m_op == 0xf)
407 		handler_7(); //dvg_latch3
408 	else
409 		m_dvy = (m_dvy & 0xf00) | m_data;
410 
411 	m_pc++;
412 	return 0;
413 }
414 
vggo()415 void dvg_device::vggo() // dvg_vggo
416 {
417 	m_dvy = 0;
418 	m_op = 0;
419 }
420 
vgrst()421 void dvg_device::vgrst() // dvg_vgrst
422 {
423 	m_state_latch = 0;
424 	m_dvy = 0;
425 	m_op = 0;
426 }
427 
428 
429 /********************************************************************
430  *
431  *  AVG handler functions
432  *
433  *  AVG is in many ways different from DVG. The only thing they have
434  *  in common is the state machine approach. There are small
435  *  differences among the AVGs, mostly related to color and vector
436  *  clipping.
437  *
438  *******************************************************************/
439 
state_addr()440 u8 avg_device::state_addr() // avg_state_addr
441 {
442 	return (((m_state_latch >> 4) ^ 1) << 7)
443 		| (m_op << 4)
444 		| (m_state_latch & 0xf);
445 }
446 
447 
update_databus()448 void avg_device::update_databus() // avg_data
449 {
450 	m_data = m_vectorram[m_pc ^ 1];
451 }
452 
vggo()453 void avg_device::vggo() // avg_vggo
454 {
455 	m_pc = 0;
456 	m_sp = 0;
457 }
458 
459 
vgrst()460 void avg_device::vgrst() // avg_vgrst
461 {
462 	m_state_latch = 0;
463 	m_bin_scale = 0;
464 	m_scale = 0;
465 	m_color = 0;
466 }
467 
handler_0()468 int avg_device::handler_0() // avg_latch0
469 {
470 	m_dvy = (m_dvy & 0x1f00) | m_data;
471 	m_pc++;
472 
473 	return 0;
474 }
475 
handler_1()476 int avg_device::handler_1() // avg_latch1
477 {
478 	m_dvy12 = (m_data >> 4) & 1;
479 	m_op = m_data >> 5;
480 
481 	m_int_latch = 0;
482 	m_dvy = (m_dvy12 << 12)
483 		| ((m_data & 0xf) << 8);
484 	m_dvx = 0;
485 	m_pc++;
486 
487 	return 0;
488 }
489 
handler_2()490 int avg_device::handler_2() // avg_latch2
491 {
492 	m_dvx = (m_dvx & 0x1f00) | m_data;
493 	m_pc++;
494 
495 	return 0;
496 }
497 
handler_3()498 int avg_device::handler_3() // avg_latch3
499 {
500 	m_int_latch = m_data >> 4;
501 	m_dvx = ((m_int_latch & 1) << 12)
502 		| ((m_data & 0xf) << 8)
503 		| (m_dvx & 0xff);
504 	m_pc++;
505 
506 	return 0;
507 }
508 
handler_4()509 int avg_device::handler_4() // avg_strobe0
510 {
511 	if (OP0)
512 	{
513 		m_stack[m_sp & 3] = m_pc;
514 	}
515 	else
516 	{
517 		/*
518 		 * Normalization is done to get roughly constant deflection
519 		 * speeds. See Jed's essay why this is important. In addition
520 		 * to the intensity and overall time saving issues it is also
521 		 * needed to avoid accumulation of DAC errors. The X/Y DACs
522 		 * only use bits 3-12. The normalization ensures that the
523 		 * first three bits hold no important information.
524 		 *
525 		 * The circuit doesn't check for dvx=dvy=0. In this case
526 		 * shifting goes on as long as VCTR, SCALE and CNTR are
527 		 * low. We cut off after 16 shifts.
528 		 */
529 		int i = 0;
530 		while ((((m_dvy ^ (m_dvy << 1)) & 0x1000) == 0)
531 				&& (((m_dvx ^ (m_dvx << 1)) & 0x1000) == 0)
532 				&& (i++ < 16))
533 		{
534 			m_dvy = (m_dvy & 0x1000) | ((m_dvy << 1) & 0x1fff);
535 			m_dvx = (m_dvx & 0x1000) | ((m_dvx << 1) & 0x1fff);
536 			m_timer >>= 1;
537 			m_timer |= 0x4000 | (OP1 << 6);
538 		}
539 
540 		if (OP1)
541 			m_timer &= 0xff;
542 	}
543 
544 	return 0;
545 }
546 
547 
avg_common_strobe1()548 int avg_device::avg_common_strobe1()
549 {
550 	if (OP2)
551 	{
552 		if (OP1)
553 			m_sp = (m_sp - 1) & 0xf;
554 		else
555 			m_sp = (m_sp + 1) & 0xf;
556 	}
557 	return 0;
558 }
559 
handler_5()560 int avg_device::handler_5() // avg_strobe1
561 {
562 	if (OP2 == 0)
563 	{
564 		for (int i = m_bin_scale; i > 0; i--)
565 		{
566 			m_timer >>= 1;
567 			m_timer |= 0x4000 | (OP1 << 6);
568 		}
569 		if (OP1)
570 			m_timer &= 0xff;
571 	}
572 
573 	return avg_common_strobe1();
574 }
575 
576 
avg_common_strobe2()577 int avg_device::avg_common_strobe2()
578 {
579 	if (OP2)
580 	{
581 		if (OP0)
582 		{
583 			m_pc = m_dvy << 1;
584 
585 			if (m_dvy == 0)
586 			{
587 				/*
588 				 * Tempest and Quantum keep the AVG in an endless
589 				 * loop. I.e. at one point the AVG jumps to address 0
590 				 * and starts over again. The main CPU updates vector
591 				 * RAM while AVG is running. The hardware takes care
592 				 * that the AVG doesn't read vector RAM while the CPU
593 				 * writes to it. Usually we wait until the AVG stops
594 				 * (halt flag) and then draw all vectors at once. This
595 				 * doesn't work for Tempest and Quantum so we wait for
596 				 * the jump to zero and draw vectors then.
597 				 *
598 				 * Note that this has nothing to do with the real hardware
599 				 * because for a vector monitor it is perfectly okay to
600 				 * have the AVG drawing all the time. In the emulation we
601 				 * somehow have to divide the stream of vectors into
602 				 * 'frames'.
603 				 */
604 
605 				m_vector->clear_list();
606 				vg_flush();
607 			}
608 		}
609 		else
610 		{
611 			m_pc = m_stack[m_sp & 3];
612 		}
613 	}
614 	else
615 	{
616 		if (m_dvy12)
617 		{
618 			m_scale = m_dvy & 0xff;
619 			m_bin_scale = (m_dvy >> 8) & 7;
620 		}
621 	}
622 
623 	return 0;
624 }
625 
handler_6()626 int avg_device::handler_6() // avg_strobe2
627 {
628 	if ((OP2 == 0) && (m_dvy12 == 0))
629 	{
630 		m_color = m_dvy & 0x7;
631 		m_intensity = (m_dvy >> 4) & 0xf;
632 	}
633 
634 	return avg_common_strobe2();
635 }
636 
avg_common_strobe3()637 int avg_device::avg_common_strobe3()
638 {
639 	int cycles = 0;
640 
641 	m_halt = OP0;
642 
643 	if ((m_op & 5) == 0)
644 	{
645 		if (OP1)
646 		{
647 			cycles = 0x100 - (m_timer & 0xff);
648 		}
649 		else
650 		{
651 			cycles = 0x8000 - m_timer;
652 		}
653 		m_timer = 0;
654 
655 		m_xpos += ((((m_dvx >> 3) ^ m_xdac_xor) - 0x200) * cycles * (m_scale ^ 0xff)) >> 4;
656 		m_ypos -= ((((m_dvy >> 3) ^ m_ydac_xor) - 0x200) * cycles * (m_scale ^ 0xff)) >> 4;
657 	}
658 	if (OP2)
659 	{
660 		cycles = 0x8000 - m_timer;
661 		m_timer = 0;
662 		m_xpos = m_xcenter;
663 		m_ypos = m_ycenter;
664 		vg_add_point_buf(m_xpos, m_ypos, 0, 0);
665 	}
666 
667 	return cycles;
668 }
669 
handler_7()670 int avg_device::handler_7() // avg_strobe3
671 {
672 	const int cycles = avg_common_strobe3();
673 
674 	if ((m_op & 5) == 0)
675 	{
676 		vg_add_point_buf(m_xpos, m_ypos, vector_device::color111(m_color),
677 							(((m_int_latch >> 1) == 1)? m_intensity: m_int_latch & 0xe) << 4);
678 	}
679 
680 	return cycles;
681 }
682 
683 /*************************************
684  *
685  *  Tempest handler functions
686  *
687  *************************************/
688 
handler_6()689 int avg_tempest_device::handler_6() // tempest_strobe2
690 {
691 	if ((OP2 == 0) && (m_dvy12 == 0))
692 	{
693 		/* Contrary to previous documentation in MAME,
694 		Tempest does not have the m_enspkl bit. */
695 		if (m_dvy & 0x800)
696 			m_color = m_dvy & 0xf;
697 		else
698 			m_intensity = (m_dvy >> 4) & 0xf;
699 	}
700 
701 	return avg_common_strobe2();
702 }
703 
handler_7()704 int avg_tempest_device::handler_7() // tempest_strobe3
705 {
706 	const int cycles = avg_common_strobe3();
707 
708 	if ((m_op & 5) == 0)
709 	{
710 		const u8 data = m_colorram[m_color];
711 		const u8 bit3 = (~data >> 3) & 1;
712 		const u8 bit2 = (~data >> 2) & 1;
713 		const u8 bit1 = (~data >> 1) & 1;
714 		const u8 bit0 = (~data >> 0) & 1;
715 
716 		const u8 r = bit1 * 0xf3 + bit0 * 0x0c;
717 		const u8 g = bit3 * 0xf3;
718 		const u8 b = bit2 * 0xf3;
719 
720 		int x = m_xpos;
721 		int y = m_ypos;
722 
723 		apply_flipping(&x, &y);
724 
725 		vg_add_point_buf(y - m_ycenter + m_xcenter,
726 							x - m_xcenter + m_ycenter, rgb_t(r, g, b),
727 							(((m_int_latch >> 1) == 1)? m_intensity: m_int_latch & 0xe) << 4);
728 	}
729 
730 	return cycles;
731 }
732 
733 #if 0
734 void avg_tempest_device::vggo() // tempest_vggo
735 {
736 	m_pc = 0;
737 	m_sp = 0;
738 	/*
739 	 * Tempest and Quantum trigger VGGO from time to time even though
740 	 * the VG runs in an endless loop for these games (see
741 	 * avg_common_strobe2). If we don't discard all vectors in the
742 	 * current buffer at this point, the screen starts flickering.
743 	 */
744 	m_nvect = 0;
745 }
746 #endif
747 
748 /*************************************
749 *
750 *  Mhavoc handler functions
751 *
752 *************************************/
753 
handler_1()754 int avg_mhavoc_device::handler_1() //  mhavoc_latch1
755 {
756 	/*
757 	 * Major Havoc just has ymin clipping
758 	 */
759 
760 	if (m_lst == 0)
761 	{
762 		vg_add_clip(0, m_ypos, m_xmax << 16, m_ymax << 16);
763 	}
764 	m_lst = 1;
765 
766 	return avg_device::handler_1(); //avg_latch1()
767 }
768 
handler_6()769 int avg_mhavoc_device::handler_6() // mhavoc_strobe2
770 {
771 	if (OP2 == 0)
772 	{
773 		if (m_dvy12)
774 		{
775 			if (m_dvy & 0x800)
776 				m_lst = 0;
777 		}
778 		else
779 		{
780 			m_color = m_dvy & 0xf;
781 
782 			m_intensity = (m_dvy >> 4) & 0xf;
783 			m_map = (m_dvy >> 8) & 0x3;
784 			if (m_dvy & 0x800)
785 			{
786 				m_enspkl = 1;
787 				m_spkl_shift = ((m_dvy >> 3) & 1)
788 					| ((m_dvy >> 1) & 2)
789 					| ((m_dvy << 1) & 4)
790 					| ((m_dvy << 2) & 8)
791 					| ((machine().rand() & 0x7) << 4);
792 			}
793 			else
794 			{
795 				m_enspkl = 0;
796 			}
797 
798 			/* Major Havoc can do X-flipping by inverting the DAC input */
799 			if (m_dvy & 0x400)
800 				m_xdac_xor = 0x1ff;
801 			else
802 				m_xdac_xor = 0x200;
803 		}
804 	}
805 
806 	return avg_common_strobe2();
807 }
808 
handler_7()809 int avg_mhavoc_device::handler_7()  // mhavoc_strobe3
810 {
811 	m_halt = OP0;
812 	int cycles = 0;
813 
814 	if ((m_op & 5) == 0)
815 	{
816 		if (OP1)
817 		{
818 			cycles = 0x100 - (m_timer & 0xff);
819 		}
820 		else
821 		{
822 			cycles = 0x8000 - m_timer;
823 		}
824 		m_timer = 0;
825 		const int dx = ((((m_dvx >> 3) ^ m_xdac_xor) - 0x200) * (m_scale ^ 0xff));
826 		const int dy = ((((m_dvy >> 3) ^ m_ydac_xor) - 0x200) * (m_scale ^ 0xff));
827 
828 		if (m_enspkl)
829 		{
830 			for (int i = 0; i < cycles / 8; i++)
831 			{
832 				m_xpos += dx / 2;
833 				m_ypos -= dy / 2;
834 				const u8 data = m_colorram[0xf +
835 										(((m_spkl_shift & 1) << 3)
836 										| (m_spkl_shift & 4)
837 										| ((m_spkl_shift & 0x10) >> 3)
838 										| ((m_spkl_shift & 0x40) >> 6))];
839 				const u8 bit3 = (~data >> 3) & 1;
840 				const u8 bit2 = (~data >> 2) & 1;
841 				const u8 bit1 = (~data >> 1) & 1;
842 				const u8 bit0 = (~data >> 0) & 1;
843 				const u8 r = bit3 * 0xcb + bit2 * 0x34;
844 				const u8 g = bit1 * 0xcb;
845 				const u8 b = bit0 * 0xcb;
846 
847 				vg_add_point_buf(m_xpos, m_ypos, rgb_t(r, g, b),
848 									(((m_int_latch >> 1) == 1)? m_intensity: m_int_latch & 0xe) << 4);
849 				m_spkl_shift = (((m_spkl_shift & 0x40) >> 6)
850 									^ ((m_spkl_shift & 0x20) >> 5)
851 									^ 1)
852 					| (m_spkl_shift << 1);
853 
854 				if ((m_spkl_shift & 0x7f) == 0x7f)
855 					m_spkl_shift = 0;
856 			}
857 		}
858 		else
859 		{
860 			m_xpos += (dx * cycles) >> 4;
861 			m_ypos -= (dy * cycles) >> 4;
862 			const u8 data = m_colorram[m_color];
863 
864 			const u8 bit3 = (~data >> 3) & 1;
865 			const u8 bit2 = (~data >> 2) & 1;
866 			const u8 bit1 = (~data >> 1) & 1;
867 			const u8 bit0 = (~data >> 0) & 1;
868 			const u8 r = bit3 * 0xcb + bit2 * 0x34;
869 			const u8 g = bit1 * 0xcb;
870 			const u8 b = bit0 * 0xcb;
871 
872 			vg_add_point_buf(m_xpos, m_ypos, rgb_t(r, g, b),
873 								(((m_int_latch >> 1) == 1)? m_intensity: m_int_latch & 0xe) << 4);
874 		}
875 	}
876 	if (OP2)
877 	{
878 		cycles = 0x8000 - m_timer;
879 		m_timer = 0;
880 		m_xpos = m_xcenter;
881 		m_ypos = m_ycenter;
882 		vg_add_point_buf(m_xpos, m_ypos, 0, 0);
883 	}
884 
885 	return cycles;
886 }
887 
update_databus()888 void avg_mhavoc_device::update_databus() // mhavoc_data
889 {
890 	if (m_pc & 0x2000)
891 	{
892 		m_data = m_bank_region[(m_map << 13) | ((m_pc ^ 1) & 0x1fff)];
893 	}
894 	else
895 	{
896 		m_data = m_vectorram[m_pc ^ 1];
897 	}
898 }
899 
vgrst()900 void avg_mhavoc_device::vgrst() // mhavoc_vgrst
901 {
902 	avg_device::vgrst(); // avg_vgrst
903 	m_enspkl = 0;
904 }
905 
906 
907 /*************************************
908  *
909  *  Starwars handler functions
910  *
911  *************************************/
912 
update_databus()913 void avg_starwars_device::update_databus() // starwars_data
914 {
915 	m_data = m_vectorram[m_pc];
916 }
917 
918 
handler_6()919 int avg_starwars_device::handler_6() // starwars_strobe2
920 {
921 	if ((OP2 == 0) && (m_dvy12 == 0))
922 	{
923 		m_intensity = m_dvy & 0xff;
924 		m_color = (m_dvy >> 8) & 0xf;
925 	}
926 
927 	return avg_common_strobe2();
928 }
929 
handler_7()930 int avg_starwars_device::handler_7() // starwars_strobe3
931 {
932 	const int cycles = avg_common_strobe3();
933 
934 	if ((m_op & 5) == 0)
935 	{
936 		vg_add_point_buf(m_xpos, m_ypos, vector_device::color111(m_color),
937 							((m_int_latch >> 1) * m_intensity) >> 3);
938 	}
939 
940 	return cycles;
941 }
942 
943 /*************************************
944 *
945 *  Quantum handler functions
946 *
947 *************************************/
948 
update_databus()949 void avg_quantum_device::update_databus() // quantum_data
950 {
951 	m_data = ((u16 *)m_vectorram.target())[m_pc >> 1];
952 }
953 
vggo()954 void avg_quantum_device::vggo() // tempest_vggo
955 {
956 	m_pc = 0;
957 	m_sp = 0;
958 	/*
959 	 * Tempest and Quantum trigger VGGO from time to time even though
960 	 * the VG runs in an endless loop for these games (see
961 	 * avg_common_strobe2). If we don't discard all vectors in the
962 	 * current buffer at this point, the screen starts flickering.
963 	 */
964 	m_nvect = 0;
965 }
966 
handler_0()967 int avg_quantum_device::handler_0() // quantum_st2st3
968 {
969 	/* Quantum doesn't decode latch0 or latch2 but ST2 and ST3 are fed
970 	 * into the address controller which increments the PC
971 	 */
972 	m_pc++;
973 	return 0;
974 }
975 
handler_1()976 int avg_quantum_device::handler_1() // quantum_latch1
977 {
978 	m_dvy = m_data & 0x1fff;
979 	m_dvy12 = (m_data >> 12) & 1;
980 	m_op = m_data >> 13;
981 
982 	m_int_latch = 0;
983 	m_dvx = 0;
984 	m_pc++;
985 
986 	return 0;
987 }
988 
handler_2()989 int avg_quantum_device::handler_2() // quantum_st2st3
990 {
991 	/* Quantum doesn't decode latch0 or latch2 but ST2 and ST3 are fed
992 	 * into the address controller which increments the PC
993 	 */
994 	m_pc++;
995 	return 0;
996 }
997 
handler_3()998 int avg_quantum_device::handler_3() // quantum_latch3
999 {
1000 	m_int_latch = m_data >> 12;
1001 	m_dvx = m_data & 0xfff;
1002 	m_pc++;
1003 
1004 	return 0;
1005 }
1006 
1007 
handler_4()1008 int avg_quantum_device::handler_4() // quantum_strobe0
1009 {
1010 	if (OP0)
1011 	{
1012 		m_stack[m_sp & 3] = m_pc;
1013 	}
1014 	else
1015 	{
1016 		/*
1017 		 * Quantum normalizes to 12 bit
1018 		 */
1019 		int i = 0;
1020 		while ((((m_dvy ^ (m_dvy << 1)) & 0x800) == 0)
1021 				&& (((m_dvx ^ (m_dvx << 1)) & 0x800) == 0)
1022 				&& (i++ < 16))
1023 		{
1024 			m_dvy = (m_dvy << 1) & 0xfff;
1025 			m_dvx = (m_dvx << 1) & 0xfff;
1026 			m_timer >>= 1;
1027 			m_timer |= 0x2000 ;
1028 		}
1029 	}
1030 
1031 	return 0;
1032 }
1033 
handler_5()1034 int avg_quantum_device::handler_5() //  quantum_strobe1
1035 {
1036 	if (OP2 == 0)
1037 	{
1038 		for (int i = m_bin_scale; i > 0; i--)
1039 		{
1040 			m_timer >>= 1;
1041 			m_timer |= 0x2000;
1042 		}
1043 	}
1044 
1045 	return avg_common_strobe1();
1046 }
1047 
handler_6()1048 int avg_quantum_device::handler_6() // quantum_strobe2
1049 {
1050 	if ((OP2 == 0) && (m_dvy12 == 0) && (m_dvy & 0x800))
1051 	{
1052 		m_color = m_dvy & 0xf;
1053 		m_intensity = (m_dvy >> 4) & 0xf;
1054 	}
1055 
1056 	return avg_common_strobe2();
1057 }
1058 
handler_7()1059 int avg_quantum_device::handler_7() // quantum_strobe3
1060 {
1061 	int cycles = 0;
1062 
1063 	m_halt = OP0;
1064 
1065 	if ((m_op & 5) == 0)
1066 	{
1067 		const u16 data = ((u16 *)m_colorram.target())[m_color];
1068 		const u8 bit3 = (~data >> 3) & 1;
1069 		const u8 bit2 = (~data >> 2) & 1;
1070 		const u8 bit1 = (~data >> 1) & 1;
1071 		const u8 bit0 = (~data >> 0) & 1;
1072 
1073 		const u8 g = bit1 * 0xaa + bit0 * 0x54;
1074 		const u8 b = bit2 * 0xce;
1075 		const u8 r = bit3 * 0xce;
1076 
1077 		cycles = 0x4000 - m_timer;
1078 		m_timer = 0;
1079 
1080 		m_xpos += (((((m_dvx & 0xfff) >> 2) ^ m_xdac_xor) - 0x200) * cycles * (m_scale ^ 0xff)) >> 4;
1081 		m_ypos -= (((((m_dvy & 0xfff) >> 2) ^ m_ydac_xor) - 0x200) * cycles * (m_scale ^ 0xff)) >> 4;
1082 
1083 		int x = m_xpos;
1084 		int y = m_ypos;
1085 
1086 		apply_flipping(&x, &y);
1087 
1088 		vg_add_point_buf(y - m_ycenter + m_xcenter,
1089 							x - m_xcenter + m_ycenter, rgb_t(r, g, b),
1090 							((m_int_latch == 2)? m_intensity: m_int_latch) << 4);
1091 	}
1092 	if (OP2)
1093 	{
1094 		cycles = 0x4000 - m_timer;
1095 		m_timer = 0;
1096 		m_xpos = m_xcenter;
1097 		m_ypos = m_ycenter;
1098 		vg_add_point_buf(m_xpos, m_ypos, 0, 0);
1099 	}
1100 
1101 	return cycles;
1102 }
1103 
1104 /*************************************
1105 *
1106 *  Bzone handler functions
1107 *
1108 *************************************/
handler_1()1109 int avg_bzone_device::handler_1() // bzone_latch1
1110 {
1111 	/*
1112 	 * Battle Zone has clipping hardware. We need to remember the
1113 	 * position of the beam when the analog switches hst or lst get
1114 	 * turned off.
1115 	 */
1116 
1117 	if (m_hst == 0)
1118 	{
1119 		m_clipx_max = m_xpos;
1120 		m_clipy_min = m_ypos;
1121 	}
1122 
1123 	if (m_lst == 0)
1124 	{
1125 		m_clipx_min = m_xpos;
1126 		m_clipy_max = m_ypos;
1127 	}
1128 
1129 	if (m_lst == 0 || m_hst == 0)
1130 	{
1131 		vg_add_clip(m_clipx_min, m_clipy_min, m_clipx_max, m_clipy_max);
1132 	}
1133 	m_lst = m_hst = 1;
1134 
1135 	return avg_device::handler_1(); // avg_latch1()
1136 }
1137 
1138 
handler_6()1139 int avg_bzone_device::handler_6() // bzone_strobe2
1140 {
1141 	if ((OP2 == 0) && (m_dvy12 == 0))
1142 	{
1143 		m_intensity = (m_dvy >> 4) & 0xf;
1144 
1145 		if (!(m_dvy & 0x400))
1146 		{
1147 			m_lst = m_dvy & 0x200;
1148 			m_hst = m_lst ^ 0x200;
1149 			/*
1150 			 * If izblank is true the zblank signal gets
1151 			 * inverted. This behaviour can't be handled with the
1152 			 * clipping we have right now. Battle Zone doesn't seem to
1153 			 * invert zblank so it's no issue.
1154 			 */
1155 			m_izblank = m_dvy & 0x100;
1156 		}
1157 	}
1158 	return avg_common_strobe2();
1159 }
1160 
1161 
handler_7()1162 int avg_bzone_device::handler_7() // bzone_strobe3
1163 {
1164 	/* Battle Zone is B/W */
1165 	const int cycles = avg_common_strobe3();
1166 
1167 	if ((m_op & 5) == 0)
1168 	{
1169 		vg_add_point_buf(m_xpos, m_ypos, vector_device::color111(7),
1170 							(((m_int_latch >> 1) == 1)? m_intensity: m_int_latch & 0xe) << 4);
1171 	}
1172 
1173 	return cycles;
1174 }
1175 
1176 /*************************************
1177  *
1178  *  Tomcat handler functions
1179  *
1180  *************************************/
1181 
handler_6()1182 int avg_tomcat_device::handler_6() // starwars_strobe2
1183 {
1184 	if ((OP2 == 0) && (m_dvy12 == 0))
1185 	{
1186 		m_intensity = m_dvy & 0xff;
1187 		m_color = (m_dvy >> 8) & 0xf;
1188 	}
1189 
1190 	return avg_common_strobe2();
1191 }
1192 
handler_7()1193 int avg_tomcat_device::handler_7() // starwars_strobe3
1194 {
1195 	const int cycles = avg_common_strobe3();
1196 
1197 	if ((m_op & 5) == 0)
1198 	{
1199 		vg_add_point_buf(m_xpos, m_ypos, vector_device::color111(m_color),
1200 							((m_int_latch >> 1) * m_intensity) >> 3);
1201 	}
1202 
1203 	return cycles;
1204 }
1205 
1206 
1207 /*************************************
1208  *
1209  *  halt functions
1210  *
1211  *************************************/
1212 
vg_set_halt(int dummy)1213 void avgdvg_device::vg_set_halt(int dummy)
1214 {
1215 	m_halt = dummy;
1216 	m_sync_halt = dummy;
1217 }
1218 
TIMER_CALLBACK_MEMBER(avgdvg_device::vg_set_halt_callback)1219 TIMER_CALLBACK_MEMBER(avgdvg_device::vg_set_halt_callback)
1220 {
1221 	vg_set_halt(param);
1222 }
1223 
1224 
1225 /********************************************************************
1226  *
1227  * State Machine
1228  *
1229  * The state machine is a 256x4 bit PROM connected to a latch. The
1230  * address of the next state is generated from the latched previous
1231  * state, an op code and the halt flag. Op codes come from vector
1232  * RAM/ROM. The state machine is clocked with 1.5 MHz. Three bits of
1233  * the state are decoded and used to trigger various parts of the
1234  * hardware.
1235  *
1236  *******************************************************************/
1237 
TIMER_CALLBACK_MEMBER(avgdvg_device::run_state_machine)1238 TIMER_CALLBACK_MEMBER(avgdvg_device::run_state_machine)
1239 {
1240 	int cycles = 0;
1241 
1242 	while (cycles < VGSLICE)
1243 	{
1244 		/* Get next state */
1245 		m_state_latch = (m_state_latch & 0x10)
1246 			| (m_prom[state_addr()] & 0xf);
1247 
1248 		if (ST3)
1249 		{
1250 			/* Read vector RAM/ROM */
1251 			update_databus();
1252 
1253 			/* Decode state and call the corresponding handler */
1254 			switch(m_state_latch & 7) {
1255 				case 0 : cycles += handler_0(); break;
1256 				case 1 : cycles += handler_1(); break;
1257 				case 2 : cycles += handler_2(); break;
1258 				case 3 : cycles += handler_3(); break;
1259 				case 4 : cycles += handler_4(); break;
1260 				case 5 : cycles += handler_5(); break;
1261 				case 6 : cycles += handler_6(); break;
1262 				case 7 : cycles += handler_7(); break;
1263 			}
1264 		}
1265 
1266 		/* If halt flag was set, let CPU catch up before we make halt visible */
1267 		if (m_halt && !(m_state_latch & 0x10))
1268 			m_vg_halt_timer->adjust(attotime::from_hz(MASTER_CLOCK) * cycles, 1);
1269 
1270 		m_state_latch = (m_halt << 4) | (m_state_latch & 0xf);
1271 		cycles += 8;
1272 	}
1273 
1274 	m_vg_run_timer->adjust(attotime::from_hz(MASTER_CLOCK) * cycles);
1275 }
1276 
1277 
1278 /*************************************
1279  *
1280  *  VG halt/vggo
1281  *
1282  ************************************/
1283 
READ_LINE_MEMBER(avgdvg_device::done_r)1284 READ_LINE_MEMBER(avgdvg_device::done_r)
1285 {
1286 	return m_sync_halt ? 1 : 0;
1287 }
1288 
go_w(u8 data)1289 void avgdvg_device::go_w(u8 data)
1290 {
1291 	vggo();
1292 
1293 	if (m_sync_halt && (m_nvect > 10))
1294 	{
1295 		/*
1296 		 * This is a good time to start a new frame. Major Havoc
1297 		 * sometimes sets VGGO after a very short vector list. That's
1298 		 * why we ignore frames with less than 10 vectors.
1299 		 */
1300 		m_vector->clear_list();
1301 	}
1302 	vg_flush();
1303 
1304 	vg_set_halt(0);
1305 	m_vg_run_timer->adjust(attotime::zero);
1306 }
1307 
go_word_w(u16 data)1308 void avgdvg_device::go_word_w(u16 data)
1309 {
1310 	go_w(data);
1311 }
1312 
1313 
1314 /*************************************
1315  *
1316  *  Reset
1317  *
1318  ************************************/
1319 
reset_w(u8 data)1320 void avgdvg_device::reset_w(u8 data)
1321 {
1322 	vgrst();
1323 	vg_set_halt(1);
1324 }
1325 
reset_word_w(u16 data)1326 void avgdvg_device::reset_word_w(u16 data)
1327 {
1328 	reset_w(data);
1329 }
1330 
1331 /*************************************
1332  *
1333  *  Vector generator init
1334  *
1335  ************************************/
1336 
register_state()1337 void avgdvg_device::register_state()
1338 {
1339 	save_item(NAME(m_pc));
1340 	save_item(NAME(m_sp));
1341 	save_item(NAME(m_dvx));
1342 	save_item(NAME(m_dvy));
1343 	save_item(NAME(m_dvy12));
1344 	save_item(NAME(m_timer));
1345 	save_item(NAME(m_stack));
1346 	save_item(NAME(m_data));
1347 	save_item(NAME(m_state_latch));
1348 	save_item(NAME(m_int_latch));
1349 	save_item(NAME(m_scale));
1350 	save_item(NAME(m_bin_scale));
1351 	save_item(NAME(m_intensity));
1352 	save_item(NAME(m_color));
1353 	save_item(NAME(m_enspkl));
1354 	save_item(NAME(m_spkl_shift));
1355 	save_item(NAME(m_map));
1356 	save_item(NAME(m_hst));
1357 	save_item(NAME(m_lst));
1358 	save_item(NAME(m_izblank));
1359 	save_item(NAME(m_op));
1360 	save_item(NAME(m_halt));
1361 	save_item(NAME(m_sync_halt));
1362 	save_item(NAME(m_xdac_xor));
1363 	save_item(NAME(m_ydac_xor));
1364 	save_item(NAME(m_xpos));
1365 	save_item(NAME(m_ypos));
1366 	save_item(NAME(m_clipx_min));
1367 	save_item(NAME(m_clipy_min));
1368 	save_item(NAME(m_clipx_max));
1369 	save_item(NAME(m_clipy_max));
1370 
1371 	save_item(NAME(m_flip_x));
1372 	save_item(NAME(m_flip_y));
1373 }
1374 
device_start()1375 void avg_device::device_start()
1376 {
1377 	if (!m_vector->started())
1378 		throw device_missing_dependencies();
1379 
1380 	const rectangle &visarea = m_vector->screen().visible_area();
1381 
1382 	m_xmin = visarea.min_x;
1383 	m_ymin = visarea.min_y;
1384 	m_xmax = visarea.max_x;
1385 	m_ymax = visarea.max_y;
1386 
1387 	m_xcenter = ((m_xmax - m_xmin) / 2) << 16;
1388 	m_ycenter = ((m_ymax - m_ymin) / 2) << 16;
1389 
1390 	m_flip_x = m_flip_y = false;
1391 
1392 	m_vg_halt_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(avgdvg_device::vg_set_halt_callback),this));
1393 	m_vg_run_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(avgdvg_device::run_state_machine),this));
1394 
1395 	/*
1396 	 * The x and y DACs use 10 bit of the counter values which are in
1397 	 * two's complement representation. The DAC input is xored with
1398 	 * 0x200 to convert the value to unsigned.
1399 	 */
1400 	m_xdac_xor = 0x200;
1401 	m_ydac_xor = 0x200;
1402 
1403 	register_state();
1404 }
1405 
device_start()1406 void dvg_device::device_start()
1407 {
1408 	if (!m_vector->started())
1409 		throw device_missing_dependencies();
1410 
1411 	const rectangle &visarea = m_vector->screen().visible_area();
1412 
1413 	m_xmin = visarea.min_x;
1414 	m_ymin = visarea.min_y;
1415 
1416 	m_xcenter = 512;
1417 	m_ycenter = 512;
1418 
1419 	m_flip_x = m_flip_y = false;
1420 
1421 	m_vg_halt_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(avgdvg_device::vg_set_halt_callback),this));
1422 	m_vg_run_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(avgdvg_device::run_state_machine),this));
1423 
1424 	register_state();
1425 }
1426 
avgdvg_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)1427 avgdvg_device::avgdvg_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
1428 	: device_t(mconfig, type, tag, owner, clock)
1429 	, m_vectorram(*this, "vectorram", 0)
1430 	, m_colorram(*this, "colorram", 0)
1431 	, m_prom(*this, "prom")
1432 	, m_vector(*this, finder_base::DUMMY_TAG)
1433 {
1434 	m_pc = 0;
1435 	m_sp = 0;
1436 	m_dvx = 0;
1437 	m_dvy = 0;
1438 	m_dvy12 = 0;
1439 	m_timer = 0;
1440 	m_stack[0] = 0;
1441 	m_stack[1] = 0;
1442 	m_stack[2] = 0;
1443 	m_stack[3] = 0;
1444 	m_data = 0;
1445 
1446 	m_state_latch = 0;
1447 	m_int_latch = 0;
1448 	m_scale = 0;
1449 	m_bin_scale = 0;
1450 	m_intensity = 0;
1451 	m_color = 0;
1452 	m_enspkl = 0;
1453 	m_spkl_shift = 0;
1454 	m_map = 0;
1455 
1456 	m_hst = 0;
1457 	m_lst = 0;
1458 	m_izblank = 0;
1459 
1460 	m_op = 0;
1461 	m_halt = 0;
1462 	m_sync_halt = 0;
1463 
1464 	m_xdac_xor = 0;
1465 	m_ydac_xor = 0;
1466 
1467 	m_xpos = 0;
1468 	m_ypos = 0;
1469 
1470 	m_clipx_min = 0;
1471 	m_clipy_min = 0;
1472 	m_clipx_max = 0;
1473 	m_clipy_max = 0;
1474 
1475 	m_xmin = 0;
1476 	m_xmax = 0;
1477 	m_ymin = 0;
1478 	m_ymax = 0;
1479 	m_xcenter = 0;
1480 	m_ycenter = 0;
1481 	m_flip_x = false;
1482 	m_flip_y = false;
1483 	m_nvect = 0;
1484 }
1485 
dvg_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1486 dvg_device::dvg_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
1487 	avgdvg_device(mconfig, DVG, tag, owner, clock)
1488 {
1489 }
1490 
avg_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1491 avg_device::avg_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
1492 	avg_device(mconfig, AVG, tag, owner, clock)
1493 {
1494 }
1495 
avg_device(const machine_config & mconfig,device_type type,const char * tag,device_t * owner,uint32_t clock)1496 avg_device::avg_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
1497 	avgdvg_device(mconfig, type, tag, owner, clock)
1498 {
1499 }
1500 
1501 
avg_tempest_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1502 avg_tempest_device::avg_tempest_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
1503 	avg_device(mconfig, AVG_TEMPEST, tag, owner, clock)
1504 {
1505 }
avg_mhavoc_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1506 avg_mhavoc_device::avg_mhavoc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
1507 	avg_device(mconfig, AVG_MHAVOC, tag, owner, clock),
1508 	m_bank_region(*this, DEVICE_SELF)
1509 {
1510 }
1511 
avg_starwars_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1512 avg_starwars_device::avg_starwars_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
1513 	avg_device(mconfig, AVG_STARWARS, tag, owner, clock)
1514 {
1515 }
1516 
avg_quantum_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1517 avg_quantum_device::avg_quantum_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
1518 	avg_device(mconfig, AVG_QUANTUM, tag, owner, clock)
1519 {
1520 }
1521 
avg_bzone_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1522 avg_bzone_device::avg_bzone_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
1523 	avg_device(mconfig, AVG_BZONE, tag, owner, clock)
1524 {
1525 }
1526 
avg_tomcat_device(const machine_config & mconfig,const char * tag,device_t * owner,uint32_t clock)1527 avg_tomcat_device::avg_tomcat_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
1528 	avg_device(mconfig, AVG_TOMCAT, tag, owner, clock)
1529 {
1530 }
1531 
1532 DEFINE_DEVICE_TYPE(DVG,          dvg_device,          "dvg",          "Atari DVG")
1533 DEFINE_DEVICE_TYPE(AVG,          avg_device,          "avg",          "Atari AVG")
1534 DEFINE_DEVICE_TYPE(AVG_TEMPEST,  avg_tempest_device,  "avg_tempest",  "Atari AVG (Tempest)")
1535 DEFINE_DEVICE_TYPE(AVG_MHAVOC,   avg_mhavoc_device,   "avg_mhavoc",   "Atari AVG (Major Havoc)")
1536 DEFINE_DEVICE_TYPE(AVG_STARWARS, avg_starwars_device, "avg_starwars", "Atari AVG (Star Wars)")
1537 DEFINE_DEVICE_TYPE(AVG_QUANTUM,  avg_quantum_device,  "avg_quantum",  "Atari AVG (Quantum)")
1538 DEFINE_DEVICE_TYPE(AVG_BZONE,    avg_bzone_device,    "avg_bzone",    "Atari AVG (Battle Zone)")
1539 DEFINE_DEVICE_TYPE(AVG_TOMCAT,   avg_tomcat_device,   "avg_tomcat",   "Atari AVG (TomCat)")
1540