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