1 // FB Alpha Aztarac driver module
2 // Based on MAME driver by Mathis Rosenhauer
3
4 #include "burnint.h"
5 #include "m68000_intf.h"
6 #include "z80_intf.h"
7 #include "vector.h"
8 #include "ay8910.h"
9
10 static UINT8 *AllMem;
11 static UINT8 *MemEnd;
12 static UINT8 *AllRam;
13 static UINT8 *RamEnd;
14 static UINT8 *Drv68KROM;
15 static UINT8 *DrvZ80ROM;
16 static UINT8 *Drv68KRAM;
17 static UINT8 *DrvZ80RAM;
18 static UINT8 *DrvVecRAM;
19 static UINT8 *DrvNVRAM;
20
21 static UINT32 *DrvPalette;
22 static UINT8 DrvRecalc;
23
24 static UINT8 *soundlatch;
25 static INT32 sound_irq_timer;
26 static INT32 sound_status;
27
28 static INT32 sound_initialized = 0;
29
30 static INT32 xcenter;
31 static INT32 ycenter;
32
33 static INT32 watchdog;
34
35 static UINT8 DrvJoy1[8];
36 static UINT8 DrvDips[1];
37 static UINT8 DrvInputs[1];
38 static UINT8 DrvReset;
39
40 static INT16 DrvAnalogPort0;
41 static INT16 DrvAnalogPort1;
42
43 static UINT8 xAxis = 0;
44 static UINT8 yAxis = 0;
45 static UINT8 Dial = 0;
46 static UINT8 DialInputs[2];
47
48 #define A(a, b, c, d) {a, b, (UINT8*)(c), d}
49
50 static struct BurnInputInfo AztaracInputList[] = {
51 {"P1 Coin", BIT_DIGITAL, DrvJoy1 + 4, "p1 coin" },
52 {"P1 Start", BIT_DIGITAL, DrvJoy1 + 2, "p1 start" },
53 {"P1 Button 1", BIT_DIGITAL, DrvJoy1 + 1, "p1 fire 1" },
54 {"P1 Button 2", BIT_DIGITAL, DrvJoy1 + 0, "p1 fire 2" },
55
56 A("Left/Right", BIT_ANALOG_REL, &DrvAnalogPort0, "p1 x-axis"),
57 A("Up/Down", BIT_ANALOG_REL, &DrvAnalogPort1, "p1 y-axis"),
58
59 {"Aim Left", BIT_DIGITAL, DialInputs + 0, "p1 fire 3" },
60 {"Aim Right", BIT_DIGITAL, DialInputs + 1, "p1 fire 4" },
61
62 {"Reset", BIT_DIGITAL, &DrvReset, "reset" },
63 {"Service", BIT_DIGITAL, DrvJoy1 + 7, "service" },
64 {"Dip A", BIT_DIPSWITCH, DrvDips + 0, "dip" },
65 };
66
67 STDINPUTINFO(Aztarac)
68
69 #undef A
70
71 static struct BurnDIPInfo AztaracDIPList[] =
72 {
73 {0x0a, 0xf0, 0xff, 0xff, NULL},
74 {0x00, 0xff, 0xff, 0x00, NULL},
75
76 {0 , 0xfe, 0 , 2, "Hires Mode" },
77 {0x00, 0x01, 0x01, 0x00, "No" },
78 {0x00, 0x01, 0x01, 0x01, "Yes" },
79 };
80
STDDIPINFO(Aztarac)81 STDDIPINFO(Aztarac)
82
83 static inline void read_vectorram (INT32 addr, INT32 *x, INT32 *y, INT32 *c)
84 {
85 *c = SekReadWord(0xff8000 + addr);
86 *x = SekReadWord(0xff9000 + addr) & 0x03ff;
87 *y = SekReadWord(0xffa000 + addr) & 0x03ff;
88 if (*x & 0x200) *x |= 0xfffffc00; // signed
89 if (*y & 0x200) *y |= 0xfffffc00; // signed
90 }
91
aztarac_process_vector_list()92 static void aztarac_process_vector_list()
93 {
94 INT32 x, y, c, intensity, xoffset, yoffset, color;
95 INT32 defaddr, objaddr, ndefs;
96
97 vector_reset();
98
99 for (objaddr = 0; objaddr < 0x800; objaddr++)
100 {
101 read_vectorram (objaddr * 2, &xoffset, &yoffset, &c);
102
103 if (c & 0x4000) break;
104
105 if ((c & 0x2000) == 0)
106 {
107 defaddr = (c >> 1) & 0x7ff;
108
109 vector_add_point((xcenter + (xoffset << 16)), (ycenter - (yoffset << 16)), 0, 0);
110
111 read_vectorram (defaddr * 2, &x, &ndefs, &c);
112 ndefs++;
113
114 if (c & 0xff00)
115 {
116 intensity = (c >> 8);
117 color = c & 0x3f;
118
119 while (ndefs--)
120 {
121 defaddr++;
122 read_vectorram (defaddr * 2, &x, &y, &c);
123
124 if ((c & 0xff00) == 0)
125 vector_add_point((xcenter + ((x + xoffset) << 16)), (ycenter - ((y + yoffset) << 16)), 0, 0);
126 else
127 vector_add_point((xcenter + ((x + xoffset) << 16)), (ycenter - ((y + yoffset) << 16)), color, intensity);
128 }
129 }
130 else
131 {
132 while (ndefs--)
133 {
134 defaddr++;
135 read_vectorram (defaddr * 2, &x, &y, &c);
136
137 color = c & 0x3f;
138 vector_add_point((xcenter + ((x + xoffset) << 16)), (ycenter - ((y + yoffset) << 16)), color, c >> 8);
139 }
140 }
141 }
142 }
143 }
144
sync_cpu()145 static inline void sync_cpu()
146 {
147 INT32 cycles = (SekTotalCycles() / 4) - ZetTotalCycles();
148
149 if (cycles > 0) ZetRun(cycles);
150 }
151
aztarac_write_word(UINT32 address,UINT16 data)152 static void __fastcall aztarac_write_word(UINT32 address, UINT16 data)
153 {
154 if ((address & 0xfffff00) == 0x022000) {
155 *((UINT16*)(DrvNVRAM + (address & 0xfe))) = BURN_ENDIAN_SWAP_INT16(data | 0xfff0);
156 return;
157 }
158
159 if (address == 0xffb000) {
160 if (data) aztarac_process_vector_list(); // used once?
161 return;
162 }
163 }
164
aztarac_write_byte(UINT32 address,UINT8 data)165 static void __fastcall aztarac_write_byte(UINT32 address, UINT8 data)
166 {
167 if (address == 0x027009) {
168 sync_cpu();
169 *soundlatch = data;
170 sound_status ^= 0x21;
171
172 if (sound_status & 0x20) ZetSetIRQLine(0, CPU_IRQSTATUS_AUTO);
173
174 return;
175 }
176
177 if (address == 0xffb001) {
178 if (data) aztarac_process_vector_list();
179 return;
180 }
181 }
182
aztarac_read_word(UINT32 address)183 static UINT16 __fastcall aztarac_read_word(UINT32 address)
184 {
185 switch (address)
186 {
187 case 0x027004:
188 return 0xff00 | DrvInputs[0];
189
190 case 0x02700e:
191 watchdog = 0;
192 return 0;
193 }
194
195 return 0;
196 }
197
aztarac_read_byte(UINT32 address)198 static UINT8 __fastcall aztarac_read_byte(UINT32 address)
199 {
200 switch (address)
201 {
202 case 0x027000:
203 return xAxis - 0x0f;
204
205 case 0x027001:
206 return yAxis - 0x0f;
207
208 case 0x027005:
209 return DrvInputs[0]; // inputs
210
211 case 0x027009:
212 sync_cpu();
213 return sound_status & 0x01;
214
215 case 0x02700d:
216 return Dial;
217 }
218
219 return 0;
220 }
221
aztarac_sound_write(UINT16 address,UINT8 data)222 static void __fastcall aztarac_sound_write(UINT16 address, UINT8 data)
223 {
224 switch (address)
225 {
226 case 0x8c00:
227 case 0x8c01:
228 case 0x8c02:
229 case 0x8c03:
230 case 0x8c04:
231 case 0x8c05:
232 case 0x8c06:
233 case 0x8c07:
234 AY8910Write((address & 6) / 2, ~address & 1, data);
235 return;
236
237 case 0x9000:
238 sound_status &= ~0x10;
239 return;
240 }
241 }
242
aztarac_sound_read(UINT16 address)243 static UINT8 __fastcall aztarac_sound_read(UINT16 address)
244 {
245 switch (address)
246 {
247 case 0x8800:
248 sound_status = (sound_status | 0x01) & ~0x20;
249 return *soundlatch;
250
251 case 0x8c00:
252 case 0x8c01:
253 case 0x8c02:
254 case 0x8c03:
255 case 0x8c04:
256 case 0x8c05:
257 case 0x8c06:
258 case 0x8c07:
259 return AY8910Read((address & 6) / 2);
260
261 case 0x9000:
262 return sound_status & ~0x01;
263 }
264
265 return 0;
266 }
267
aztarac_irq_callback(INT32)268 static INT32 __fastcall aztarac_irq_callback(INT32)
269 {
270 return 0x0c;
271 }
272
res_check()273 static INT32 res_check()
274 {
275 if (DrvDips[0] & 1) {
276 INT32 Width, Height;
277 BurnDrvGetVisibleSize(&Width, &Height);
278
279 if (Height != 1080) {
280 vector_rescale((1080*1024/768), 1080);
281 return 1;
282 }
283 } else {
284 INT32 Width, Height;
285 BurnDrvGetVisibleSize(&Width, &Height);
286
287 if (Height != 768) {
288 vector_rescale(1024, 768);
289 return 1;
290 }
291 }
292 return 0;
293 }
294
DrvDoReset(INT32 reset_ram)295 static INT32 DrvDoReset(INT32 reset_ram)
296 {
297 if (reset_ram) {
298 memset (AllRam, 0, RamEnd - AllRam);
299 }
300
301 SekOpen(0);
302 SekReset();
303 SekClose();
304
305 ZetOpen(0);
306 ZetReset();
307 ZetClose();
308
309 AY8910Reset(0);
310 AY8910Reset(1);
311 AY8910Reset(2);
312 AY8910Reset(3);
313
314 sound_status = 0;
315 sound_irq_timer = 0;
316
317 watchdog = 0;
318
319 vector_reset();
320
321 res_check();
322
323 return 0;
324 }
325
MemIndex()326 static INT32 MemIndex()
327 {
328 UINT8 *Next; Next = AllMem;
329
330 Drv68KROM = Next; Next += 0x010000;
331 DrvZ80ROM = Next; Next += 0x002000;
332
333 DrvNVRAM = Next; Next += 0x000400;
334
335 AllRam = Next;
336
337 Drv68KRAM = Next; Next += 0x002000;
338 DrvZ80RAM = Next; Next += 0x000800;
339 DrvVecRAM = Next; Next += 0x003000;
340
341 soundlatch = Next; Next += 0x000004; // 1
342
343 RamEnd = Next;
344
345 DrvPalette = (UINT32*)Next; Next += 0x0040 * 256 * sizeof(UINT32);
346
347 MemEnd = Next;
348
349 return 0;
350 }
351
DrvPaletteInit()352 static void DrvPaletteInit()
353 {
354 for (INT32 i = 0; i < 0x40; i++) // color
355 {
356 for (INT32 j = 0; j < 256; j++) // intensity
357 {
358 INT32 r = (i >> 4) & 3;
359 r = (r << 6) | (r << 4) | (r << 2) | (r << 0);
360
361 INT32 g = (i >> 2) & 3;
362 g = (g << 6) | (g << 4) | (g << 2) | (g << 0);
363
364 INT32 b = (i >> 0) & 3;
365 b = (b << 6) | (b << 4) | (b << 2) | (b << 0);
366
367 r = (r * j) / 255;
368 g = (g * j) / 255;
369 b = (b * j) / 255;
370
371 DrvPalette[i * 256 + j] = (r << 16) | (g << 8) | b;
372 }
373 }
374 }
375
DrvInit()376 static INT32 DrvInit()
377 {
378 BurnSetRefreshRate(40.0);
379
380 AllMem = NULL;
381 MemIndex();
382 INT32 nLen = MemEnd - (UINT8 *)0;
383 if ((AllMem = (UINT8 *)BurnMalloc(nLen)) == NULL) return 1;
384 memset(AllMem, 0, nLen);
385 MemIndex();
386
387 {
388 if (BurnLoadRom(Drv68KROM + 0x00001, 0, 2)) return 1;
389 if (BurnLoadRom(Drv68KROM + 0x00000, 1, 2)) return 1;
390 if (BurnLoadRom(Drv68KROM + 0x02001, 2, 2)) return 1;
391 if (BurnLoadRom(Drv68KROM + 0x02000, 3, 2)) return 1;
392 if (BurnLoadRom(Drv68KROM + 0x04001, 4, 2)) return 1;
393 if (BurnLoadRom(Drv68KROM + 0x04000, 5, 2)) return 1;
394 if (BurnLoadRom(Drv68KROM + 0x06001, 6, 2)) return 1;
395 if (BurnLoadRom(Drv68KROM + 0x06000, 7, 2)) return 1;
396 if (BurnLoadRom(Drv68KROM + 0x08001, 8, 2)) return 1;
397 if (BurnLoadRom(Drv68KROM + 0x08000, 9, 2)) return 1;
398 if (BurnLoadRom(Drv68KROM + 0x0a001, 10, 2)) return 1;
399 if (BurnLoadRom(Drv68KROM + 0x0a000, 11, 2)) return 1;
400
401 if (BurnLoadRom(DrvZ80ROM + 0x00000, 12, 1)) return 1;
402 if (BurnLoadRom(DrvZ80ROM + 0x01000, 13, 1)) return 1;
403 }
404
405 SekInit(0, 0x68000);
406 SekOpen(0);
407 SekSetIrqCallback(aztarac_irq_callback);
408 SekMapMemory(Drv68KROM, 0x000000, 0x00bfff, MAP_ROM);
409 SekMapMemory(DrvNVRAM, 0x022000, 0x0223ff, MAP_ROM);
410 SekMapMemory(DrvVecRAM, 0xff8000, 0xffafff, MAP_RAM);
411 SekMapMemory(Drv68KRAM, 0xffe000, 0xffffff, MAP_RAM);
412 SekSetWriteWordHandler(0, aztarac_write_word);
413 SekSetWriteByteHandler(0, aztarac_write_byte);
414 SekSetReadWordHandler(0, aztarac_read_word);
415 SekSetReadByteHandler(0, aztarac_read_byte);
416 SekClose();
417
418 ZetInit(0);
419 ZetOpen(0);
420 ZetMapMemory(DrvZ80ROM, 0x0000, 0x1fff, MAP_ROM);
421 ZetMapMemory(DrvZ80RAM, 0x8000, 0x87ff, MAP_RAM);
422 ZetSetWriteHandler(aztarac_sound_write);
423 ZetSetReadHandler(aztarac_sound_read);
424 ZetClose();
425
426 AY8910Init(0, 2000000, 0);
427 AY8910Init(1, 2000000, 1);
428 AY8910Init(2, 2000000, 1);
429 AY8910Init(3, 2000000, 1);
430 AY8910SetAllRoutes(0, 0.15, BURN_SND_ROUTE_BOTH);
431 AY8910SetAllRoutes(1, 0.15, BURN_SND_ROUTE_BOTH);
432 AY8910SetAllRoutes(2, 0.15, BURN_SND_ROUTE_BOTH);
433 AY8910SetAllRoutes(3, 0.15, BURN_SND_ROUTE_BOTH);
434
435 DrvPaletteInit();
436
437 vector_init();
438 vector_set_scale(1024, 768);
439
440 xcenter = (1024 / 2) << 16;
441 ycenter = ( 768 / 2) << 16;
442
443 memset (DrvNVRAM, 0xff, 0x100);
444
445 DrvDoReset(1);
446
447 return 0;
448 }
449
DrvExit()450 static INT32 DrvExit()
451 {
452 vector_exit();
453
454 SekExit();
455 ZetExit();
456
457 AY8910Exit(0);
458 AY8910Exit(1);
459 AY8910Exit(2);
460 AY8910Exit(3);
461
462 BurnFree (AllMem);
463
464 sound_initialized = 0;
465
466 return 0;
467 }
468
DrvDraw()469 static INT32 DrvDraw()
470 {
471 if (DrvRecalc) {
472 DrvPaletteInit();
473 DrvRecalc = 0;
474 }
475
476 if (res_check()) return 0; // resolution was changed
477
478 draw_vector(DrvPalette);
479
480 return 0;
481 }
482
DrvFrame()483 static INT32 DrvFrame()
484 {
485 if (DrvReset) {
486 DrvDoReset(1);
487 }
488
489 watchdog++;
490 if (watchdog == 180) { // 3 seconds?
491 DrvDoReset(0);
492 }
493
494 SekNewFrame();
495 ZetNewFrame();
496
497 {
498 DrvInputs[0] = 0xff;
499 for (INT32 i = 0; i < 8; i++) {
500 DrvInputs[0] ^= (DrvJoy1[i] & 1) << i;
501 }
502
503 xAxis = (DrvAnalogPort0 >> 7) + 0x0f;
504 if (xAxis > 0x80) xAxis = 0;
505
506 yAxis = (~DrvAnalogPort1 >> 7) + 0x10;
507 if (yAxis > 0x1d) yAxis = 0x1d;
508
509 if (DialInputs[0]) {
510 Dial += 0x04;
511 } else {
512 if (DialInputs[1]) {
513 Dial -= 0x04;
514 }
515 }
516 }
517
518 INT32 nInterleave = 100;
519 INT32 nCyclesTotal[2] = { 8000000 / 40, 2000000 / 40 };
520 INT32 nCyclesDone[2] = { 0, 0 };
521
522 SekOpen(0);
523 ZetOpen(0);
524
525 for (INT32 i = 0; i < nInterleave; i++, sound_irq_timer++)
526 {
527 nCyclesDone[0] += SekRun(nCyclesTotal[0] / nInterleave);
528 if (i == (nInterleave - 1)) SekSetIRQLine(4, CPU_IRQSTATUS_AUTO);
529
530 //nCyclesDone[1] += ZetRun((SekTotalCycles() / 4) - ZetTotalCycles());
531 sync_cpu();
532
533 if ((sound_irq_timer % 40) == 39) { // every 20000 cycles, 50000 / frame
534 sound_status ^= 0x10;
535 if (sound_status & 0x10) ZetSetIRQLine(0, CPU_IRQSTATUS_AUTO);
536 }
537 }
538
539 SekClose();
540 ZetClose();
541
542 if (pBurnSoundOut) {
543 AY8910Render(pBurnSoundOut, nBurnSoundLen);
544 }
545
546 if (pBurnDraw) {
547 DrvDraw();
548 }
549
550 return 0;
551 }
552
DrvScan(INT32 nAction,INT32 * pnMin)553 static INT32 DrvScan(INT32 nAction, INT32 *pnMin)
554 {
555 struct BurnArea ba;
556
557 if (pnMin != NULL) {
558 *pnMin = 0x029698;
559 }
560
561 if (nAction & ACB_MEMORY_ROM) {
562 ba.Data = Drv68KROM;
563 ba.nLen = 0x000c000;
564 ba.nAddress = 0x0000000;
565 ba.szName = "68K ROM";
566 BurnAcb(&ba);
567
568 ba.Data = DrvZ80ROM;
569 ba.nLen = 0x0002000;
570 ba.nAddress = 0x0000000;
571 ba.szName = "Z80 ROM";
572 BurnAcb(&ba);
573 }
574
575 if (nAction & ACB_MEMORY_RAM) {
576 ba.Data = Drv68KRAM;
577 ba.nLen = 0x0002000;
578 ba.nAddress = 0x0ffe000;
579 ba.szName = "68K RAM";
580 BurnAcb(&ba);
581
582 ba.Data = DrvVecRAM;
583 ba.nLen = 0x0003000;
584 ba.nAddress = 0x0ff8000;
585 ba.szName = "Vector RAM";
586 BurnAcb(&ba);
587
588 ba.Data = DrvZ80RAM;
589 ba.nLen = 0x0000800;
590 ba.nAddress = 0x0000000;
591 ba.szName = "Z80 RAM";
592 BurnAcb(&ba);
593 }
594
595 if (nAction & ACB_NVRAM) {
596 ba.Data = DrvNVRAM;
597 ba.nLen = 0x000100;
598 ba.nAddress = 0x022000;
599 ba.szName = "NV RAM";
600 BurnAcb(&ba);
601 }
602
603 if (nAction & ACB_DRIVER_DATA) {
604 SekScan(nAction);
605 ZetScan(nAction);
606
607 AY8910Scan(nAction, pnMin);
608
609 SCAN_VAR(*soundlatch);
610 SCAN_VAR(sound_irq_timer);
611 SCAN_VAR(sound_status);
612 }
613
614 vector_scan(nAction);
615
616 return 0;
617 }
618
619
620 // Aztarac
621
622 static struct BurnRomInfo aztaracRomDesc[] = {
623 { "6.l8", 0x1000, 0x25f8da18, 1 | BRF_PRG | BRF_ESS }, // 0 68K Code
624 { "0.n8", 0x1000, 0x04e20626, 1 | BRF_PRG | BRF_ESS }, // 1
625 { "7.l7", 0x1000, 0x230e244c, 1 | BRF_PRG | BRF_ESS }, // 2
626 { "1.n7", 0x1000, 0x37b12697, 1 | BRF_PRG | BRF_ESS }, // 3
627 { "8.l6", 0x1000, 0x1293fb9d, 1 | BRF_PRG | BRF_ESS }, // 4
628 { "2.n6", 0x1000, 0x712c206a, 1 | BRF_PRG | BRF_ESS }, // 5
629 { "9.l5", 0x1000, 0x743a6501, 1 | BRF_PRG | BRF_ESS }, // 6
630 { "3.n5", 0x1000, 0xa65cbf99, 1 | BRF_PRG | BRF_ESS }, // 7
631 { "a.l4", 0x1000, 0x9cf1b0a1, 1 | BRF_PRG | BRF_ESS }, // 8
632 { "4.n4", 0x1000, 0x5f0080d5, 1 | BRF_PRG | BRF_ESS }, // 9
633 { "b.l3", 0x1000, 0x8cc7f7fa, 1 | BRF_PRG | BRF_ESS }, // 10
634 { "5.n3", 0x1000, 0x40452376, 1 | BRF_PRG | BRF_ESS }, // 11
635
636 { "c.j4", 0x1000, 0xe897dfcd, 2 | BRF_PRG | BRF_ESS }, // 12 Z80 Code
637 { "d.j3", 0x1000, 0x4016de77, 2 | BRF_PRG | BRF_ESS }, // 13
638
639 /* not hooked up */
640 { "l5.l5", 0x00020, 0x317fb438, 0 | BRF_OPT }, // 14 Proms
641 { "k8.k8", 0x01000, 0x596ad8d9, 0 | BRF_OPT }, // 15
642 { "k9.k9", 0x01000, 0xb8544823, 0 | BRF_OPT }, // 16
643 };
644
645 STD_ROM_PICK(aztarac)
646 STD_ROM_FN(aztarac)
647
648 struct BurnDriver BurnDrvAztarac = {
649 "aztarac", NULL, NULL, NULL, "1983",
650 "Aztarac\0", "Vector graphics", "Centuri", "Miscellaneous",
651 NULL, NULL, NULL, NULL,
652 BDF_GAME_WORKING, 2, HARDWARE_MISC_PRE90S, GBF_SHOOT, 0,
653 NULL, aztaracRomInfo, aztaracRomName, NULL, NULL, NULL, NULL, AztaracInputInfo, AztaracDIPInfo,
654 DrvInit, DrvExit, DrvFrame, DrvDraw, DrvScan, &DrvRecalc, 0x40 * 256,
655 1024, 768, 4, 3
656 };
657