1 /***************************************************************************
2
3 Videa Gridlee hardware
4
5 driver by Aaron Giles
6
7 special thanks to Howard Delman, Roger Hector and Ed Rotberg for
8 allowing distribution of the Gridlee ROMs
9
10 Based on the Bally/Sente SAC system
11
12 Games supported:
13 * Gridlee
14
15 Known bugs:
16 * analog sound hardware is unemulated
17
18 ****************************************************************************
19
20 Memory map
21
22 ****************************************************************************
23
24 ========================================================================
25 CPU #1
26 ========================================================================
27 0000-007F R/W xxxxxxxx Sprite RAM (32 entries x 4 bytes)
28 R/W xxxxxxxx (0: image number)
29 R/W -------- (1: unused?)
30 R/W xxxxxxxx (2: Y position, offset by 17 pixels)
31 R/W xxxxxxxx (3: X position)
32 0080-07FF R/W xxxxxxxx Program RAM
33 0800-7FFF R/W xxxxxxxx Video RAM (256x240 pixels)
34 R/W xxxx---- (left pixel)
35 R/W ----xxxx (right pixel)
36 9000 W -------x Player 1 LED
37 9010 W -------x Player 2 LED
38 9020 W -------x Coin counter
39 9060 W -------x Unknown (written once at startup)
40 9070 W -------x Cocktail flip
41 9200 W --xxxxxx Palette base select
42 9380 W -------- Watchdog reset
43 9500 R ---xxxxx Trackball Y position
44 R ---x---- Sign of delta
45 R ----xxxx Cumulative magnitude
46 9501 R ---xxxxx Trackball X position
47 R ---x---- Sign of delta
48 R ----xxxx Cumulative magnitude
49 9502 R ------x- Fire button 2
50 R -------x Fire button 1
51 9503 R --xx---- Coinage switches
52 R ----x--- 2 player start
53 R -----x-- 1 player start
54 R ------x- Right coin
55 R -------x Left coin
56 9600 R x------- Reset game data switch
57 R -x------ Reset hall of fame switch
58 R --x----- Cocktail/upright switch
59 R ---x---- Free play switch
60 R ----xx-- Lives switches
61 R ------xx Bonus lives switches
62 9700 R x------- VBLANK
63 R -x------ Service advance
64 R --x----- Service switch
65 9820 R xxxxxxxx Random number generator
66 9828-982C W ???????? Unknown
67 9830-983F W ???????? Unknown (sound-related)
68 9C00-9CFF R/W -------- NVRAM
69 A000-FFFF R xxxxxxxx Fixed program ROM
70 ========================================================================
71 Interrupts:
72 NMI not connected
73 IRQ generated by 32L
74 FIRQ generated by ??? (but should be around scanline 92)
75 ========================================================================
76
77 ***************************************************************************/
78
79
80 #include "driver.h"
81 #include "cpu/m6809/m6809.h"
82 #include "vidhrdw/generic.h"
83 #include "gridlee.h"
84 #include <math.h>
85
86
87 /* constants */
88 #define FIRQ_SCANLINE 92
89
90
91 /* local variables */
92 static UINT8 last_analog_input[2];
93 static UINT8 last_analog_output[2];
94
95 /* random number generator states */
96 static UINT8 *poly17 = NULL;
97 static UINT8 *rand17 = NULL;
98
99
100
101 /* local prototypes */
102 static void poly17_init(void);
103
104
105 /*************************************
106 *
107 * Interrupt handling
108 *
109 *************************************/
110
irq_off(int param)111 static void irq_off(int param)
112 {
113 cpu_set_irq_line(0, M6809_IRQ_LINE, CLEAR_LINE);
114 }
115
116
irq_timer(int param)117 static void irq_timer(int param)
118 {
119 /* next interrupt after scanline 256 is scanline 64 */
120 if (param == 256)
121 timer_set(cpu_getscanlinetime(64), 64, irq_timer);
122 else
123 timer_set(cpu_getscanlinetime(param + 64), param + 64, irq_timer);
124
125 /* IRQ starts on scanline 0, 64, 128, etc. */
126 cpu_set_irq_line(0, M6809_IRQ_LINE, ASSERT_LINE);
127
128 /* it will turn off on the next HBLANK */
129 timer_set(cpu_getscanlineperiod() * 0.9, 0, irq_off);
130 }
131
132
firq_off(int param)133 static void firq_off(int param)
134 {
135 cpu_set_irq_line(0, M6809_FIRQ_LINE, CLEAR_LINE);
136 }
137
138
firq_timer(int param)139 static void firq_timer(int param)
140 {
141 /* same time next frame */
142 timer_set(cpu_getscanlinetime(FIRQ_SCANLINE), 0, firq_timer);
143
144 /* IRQ starts on scanline FIRQ_SCANLINE? */
145 cpu_set_irq_line(0, M6809_FIRQ_LINE, ASSERT_LINE);
146
147 /* it will turn off on the next HBLANK */
148 timer_set(cpu_getscanlineperiod() * 0.9, 0, firq_off);
149 }
150
151
MACHINE_INIT(gridlee)152 static MACHINE_INIT( gridlee )
153 {
154 /* start timers to generate interrupts */
155 timer_set(cpu_getscanlinetime(0), 0, irq_timer);
156 timer_set(cpu_getscanlinetime(FIRQ_SCANLINE), 0, firq_timer);
157
158 /* create the polynomial tables */
159 poly17_init();
160 }
161
162
163
164 /*************************************
165 *
166 * ADC handlers
167 *
168 *************************************/
169
READ_HANDLER(analog_port_r)170 static READ_HANDLER( analog_port_r )
171 {
172 int delta, sign, magnitude;
173 UINT8 newval;
174
175 /* first read the new trackball value and compute the signed delta */
176 newval = readinputport(offset + 2 * gridlee_cocktail_flip);
177 delta = (int)newval - (int)last_analog_input[offset];
178
179 /* handle the case where we wrap around from 0x00 to 0xff, or vice versa */
180 if (delta >= 0x80)
181 delta -= 0x100;
182 if (delta <= -0x80)
183 delta += 0x100;
184
185 /* just return the previous value for deltas less than 2, which are ignored */
186 if (delta >= -1 && delta <= 1)
187 return last_analog_output[offset];
188 last_analog_input[offset] = newval;
189
190 /* compute the sign and the magnitude */
191 sign = (delta < 0) ? 0x10 : 0x00;
192 magnitude = (delta < 0) ? -delta : delta;
193
194 /* add the magnitude to the running total */
195 last_analog_output[offset] += magnitude;
196
197 /* or in the sign bit and return that */
198 return (last_analog_output[offset] & 15) | sign;
199 }
200
201
202
203 /*************************************
204 *
205 * MM5837 noise generator
206 *
207 * NOTE: this is stolen straight from
208 * POKEY.c
209 *
210 * NOTE: this is assumed to be the
211 * same as balsente.c
212 *
213 *************************************/
214
215 #define POLY17_BITS 17
216 #define POLY17_SIZE ((1 << POLY17_BITS) - 1)
217 #define POLY17_SHL 7
218 #define POLY17_SHR 10
219 #define POLY17_ADD 0x18000
220
poly17_init(void)221 static void poly17_init(void)
222 {
223 UINT32 i, x = 0;
224 UINT8 *p, *r;
225
226 /* allocate memory */
227 p = poly17 = auto_malloc(2 * (POLY17_SIZE + 1));
228 if (!poly17)
229 return;
230 r = rand17 = poly17 + POLY17_SIZE + 1;
231
232 /* generate the polynomial */
233 for (i = 0; i < POLY17_SIZE; i++)
234 {
235 /* store new values */
236 *p++ = x & 1;
237 *r++ = x >> 3;
238
239 /* calculate next bit */
240 x = ((x << POLY17_SHL) + (x >> POLY17_SHR) + POLY17_ADD) & POLY17_SIZE;
241 }
242 }
243
244
245
246 /*************************************
247 *
248 * Hardware random numbers
249 *
250 *************************************/
251
READ_HANDLER(random_num_r)252 static READ_HANDLER( random_num_r )
253 {
254 unsigned int cc;
255
256 /* CPU runs at 1.25MHz, noise source at 100kHz --> multiply by 12.5 */
257 cc = activecpu_gettotalcycles();
258
259 /* 12.5 = 8 + 4 + 0.5 */
260 cc = (cc << 3) + (cc << 2) + (cc >> 1);
261 return rand17[cc & POLY17_SIZE];
262 }
263
264
265
266 /*************************************
267 *
268 * Misc handlers
269 *
270 *************************************/
271
WRITE_HANDLER(led_0_w)272 static WRITE_HANDLER( led_0_w )
273 {
274 set_led_status(0, data & 1);
275 log_cb(RETRO_LOG_DEBUG, LOGPRE "LED 0 %s\n", (data & 1) ? "on" : "off");
276 }
277
278
WRITE_HANDLER(led_1_w)279 static WRITE_HANDLER( led_1_w )
280 {
281 set_led_status(1, data & 1);
282 log_cb(RETRO_LOG_DEBUG, LOGPRE "LED 1 %s\n", (data & 1) ? "on" : "off");
283 }
284
285
WRITE_HANDLER(gridlee_coin_counter_w)286 static WRITE_HANDLER( gridlee_coin_counter_w )
287 {
288 coin_counter_w(0, data & 1);
289 log_cb(RETRO_LOG_DEBUG, LOGPRE "coin counter %s\n", (data & 1) ? "on" : "off");
290 }
291
292
293
294 /*************************************
295 *
296 * Main CPU memory handlers
297 *
298 *************************************/
299
300 /* CPU 1 read addresses */
MEMORY_READ_START(readmem_cpu1)301 static MEMORY_READ_START( readmem_cpu1 )
302 { 0x0000, 0x7fff, MRA_RAM },
303 { 0x9500, 0x9501, analog_port_r },
304 { 0x9502, 0x9502, input_port_4_r },
305 { 0x9503, 0x9503, input_port_5_r },
306 { 0x9600, 0x9600, input_port_6_r },
307 { 0x9700, 0x9700, input_port_7_r },
308 { 0x9820, 0x9820, random_num_r },
309 { 0x9c00, 0x9cff, MRA_RAM },
310 { 0xa000, 0xffff, MRA_ROM },
311 MEMORY_END
312
313
314 static MEMORY_WRITE_START( writemem_cpu1 )
315 { 0x0000, 0x07ff, MWA_RAM, &spriteram },
316 { 0x0800, 0x7fff, gridlee_videoram_w, &videoram, &videoram_size },
317 { 0x9000, 0x9000, led_0_w },
318 { 0x9010, 0x9010, led_1_w },
319 { 0x9020, 0x9020, gridlee_coin_counter_w },
320 /* { 0x9060, 0x9060, unknown - only written to at startup */
321 { 0x9070, 0x9070, gridlee_cocktail_flip_w },
322 { 0x9200, 0x9200, gridlee_palette_select_w },
323 { 0x9380, 0x9380, watchdog_reset_w },
324 { 0x9700, 0x9700, MWA_NOP },
325 { 0x9828, 0x993f, gridlee_sound_w },
326 { 0x9c00, 0x9cff, MWA_RAM, &generic_nvram, &generic_nvram_size },
327 { 0xa000, 0xffff, MWA_ROM },
328 MEMORY_END
329
330
331
332 /*************************************
333 *
334 * Port definitions
335 *
336 *************************************/
337
338 INPUT_PORTS_START( gridlee )
339 PORT_START /* 9500 (fake) */
340 PORT_ANALOG( 0xff, 0, IPT_TRACKBALL_Y, 20, 8, 0x00, 0xff )
341
342 PORT_START /* 9501 (fake) */
343 PORT_ANALOG( 0xff, 0, IPT_TRACKBALL_X | IPF_REVERSE, 20, 8, 0x00, 0xff )
344
345 PORT_START /* 9500 (fake) */
346 PORT_ANALOG( 0xff, 0, IPT_TRACKBALL_Y | IPF_COCKTAIL, 20, 8, 0x00, 0xff )
347
348 PORT_START /* 9501 (fake) */
349 PORT_ANALOG( 0xff, 0, IPT_TRACKBALL_X | IPF_REVERSE | IPF_COCKTAIL, 20, 8, 0x00, 0xff )
350
351 PORT_START /* 9502 */
352 PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 )
353 PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 | IPF_COCKTAIL )
354 PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_UNKNOWN )
355
356 PORT_START /* 9503 */
357 PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )
358 PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN2 )
359 PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_START1 )
360 PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START2 )
361 PORT_DIPNAME( 0x30, 0x00, DEF_STR( Coinage ))
362 PORT_DIPSETTING( 0x20, DEF_STR( 2C_1C ))
363 PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ))
364 PORT_DIPSETTING( 0x10, DEF_STR( 1C_2C ))
365 PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNKNOWN )
366
367 PORT_START /* 9600 */
368 PORT_DIPNAME( 0x03, 0x01, DEF_STR( Bonus_Life ))
369 PORT_DIPSETTING( 0x00, "8000 points" )
370 PORT_DIPSETTING( 0x01, "10000 points" )
371 PORT_DIPSETTING( 0x02, "12000 points" )
372 PORT_DIPSETTING( 0x03, "14000 points" )
373 PORT_DIPNAME( 0x0c, 0x04, DEF_STR( Lives ))
374 PORT_DIPSETTING( 0x00, "2" )
375 PORT_DIPSETTING( 0x04, "3" )
376 PORT_DIPSETTING( 0x08, "4" )
377 PORT_DIPSETTING( 0x0c, "5" )
378 PORT_DIPNAME( 0x10, 0x00, DEF_STR( Free_Play ))
379 PORT_DIPSETTING( 0x00, DEF_STR( Off ))
380 PORT_DIPSETTING( 0x10, DEF_STR( On ))
381 PORT_DIPNAME( 0x20, 0x00, DEF_STR( Cocktail ))
382 PORT_DIPSETTING( 0x00, DEF_STR( No ))
383 PORT_DIPSETTING( 0x20, DEF_STR( Yes ))
384 PORT_DIPNAME( 0x40, 0x00, "Reset Hall of Fame" )
385 PORT_DIPSETTING( 0x00, DEF_STR( No ))
386 PORT_DIPSETTING( 0x40, DEF_STR( Yes ))
387 PORT_DIPNAME( 0x80, 0x00, "Reset Game Data" )
388 PORT_DIPSETTING( 0x00, DEF_STR( No ))
389 PORT_DIPSETTING( 0x80, DEF_STR( Yes ))
390
391 PORT_START /* 9700 */
392 PORT_BIT( 0x1f, IP_ACTIVE_LOW, IPT_UNKNOWN )
393 PORT_SERVICE( 0x20, IP_ACTIVE_LOW )
394 PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SERVICE1 )
395 PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_VBLANK )
396 INPUT_PORTS_END
397
398
399
400 /*************************************
401 *
402 * Sound definitions
403 *
404 *************************************/
405
406 static struct CustomSound_interface custom_interface =
407 {
408 gridlee_sh_start
409 };
410
411
412 static const char *sample_names[] =
413 {
414 "*gridlee",
415 "bounce1.wav",
416 "bounce2.wav",
417 0 /* end of array */
418 };
419
420 static struct Samplesinterface samples_interface =
421 {
422 8, /* 8 channels */
423 40, /* volume */
424 sample_names
425 };
426
427
428
429 /*************************************
430 *
431 * Machine driver
432 *
433 *************************************/
434
435 static MACHINE_DRIVER_START( gridlee )
436
437 /* basic machine hardware */
438 MDRV_CPU_ADD(M6809, 5000000/4)
439 MDRV_CPU_MEMORY(readmem_cpu1,writemem_cpu1)
440
441 MDRV_FRAMES_PER_SECOND(60)
442 MDRV_VBLANK_DURATION(DEFAULT_REAL_60HZ_VBLANK_DURATION)
443
444 MDRV_MACHINE_INIT(gridlee)
445 MDRV_NVRAM_HANDLER(generic_0fill)
446
447 /* video hardware */
448 MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER | VIDEO_UPDATE_BEFORE_VBLANK)
449 MDRV_SCREEN_SIZE(256, 240)
450 MDRV_VISIBLE_AREA(0, 255, 0, 239)
451 MDRV_PALETTE_LENGTH(2048)
452
453 MDRV_PALETTE_INIT(gridlee)
454 MDRV_VIDEO_START(gridlee)
455 MDRV_VIDEO_UPDATE(gridlee)
456
457 /* sound hardware */
458 MDRV_SOUND_ADD(CUSTOM, custom_interface)
459 MDRV_SOUND_ADD(SAMPLES, samples_interface)
460 MACHINE_DRIVER_END
461
462
463
464 /*************************************
465 *
466 * ROM definitions
467 *
468 *************************************/
469
470 ROM_START( gridlee )
471 ROM_REGION( 0x10000, REGION_CPU1, 0 )
472 ROM_LOAD( "gridfnla.bin", 0xa000, 0x1000, CRC(1c43539e) SHA1(8b4a6f5c2c22bb021937157606d2129e2b01f718) )
473 ROM_LOAD( "gridfnlb.bin", 0xb000, 0x1000, CRC(c48b91b8) SHA1(651210470ddf7c14f16f6c3046a9b8e903824ab8) )
474 ROM_LOAD( "gridfnlc.bin", 0xc000, 0x1000, CRC(6ad436dd) SHA1(f393b63077f249d34a8e85649aea58b27a0425b1) )
475 ROM_LOAD( "gridfnld.bin", 0xd000, 0x1000, CRC(f7188ddb) SHA1(eeb3f7dd8c61689cdd9992280ee1b3b5dc79a54c) )
476 ROM_LOAD( "gridfnle.bin", 0xe000, 0x1000, CRC(d5330bee) SHA1(802bb5705d4cd22d556c1bcbcf730d688ca8e8ab) )
477 ROM_LOAD( "gridfnlf.bin", 0xf000, 0x1000, CRC(695d16a3) SHA1(53d22cbedbedad8c89a964b6a38b7075c43cf03b) )
478
479 ROM_REGION( 0x4000, REGION_GFX1, 0 )
480 ROM_LOAD( "gridpix0.bin", 0x0000, 0x1000, CRC(e6ea15ae) SHA1(2c482e25ea44aafd63ca5533b5a2e2dd8bf89365) )
481 ROM_LOAD( "gridpix1.bin", 0x1000, 0x1000, CRC(d722f459) SHA1(8cad028eefbba387bdd57fb8bb3a855ae314fb32) )
482 ROM_LOAD( "gridpix2.bin", 0x2000, 0x1000, CRC(1e99143c) SHA1(89c2f772cd15f2c37c8167a03dc4c7d1c923e4c3) )
483 ROM_LOAD( "gridpix3.bin", 0x3000, 0x1000, CRC(274342a0) SHA1(818cfd4132183d922ff4585c73f2cd6e4546c75b) )
484
485 ROM_REGION( 0x1800, REGION_PROMS, 0 )
486 ROM_LOAD( "grdrprom.bin", 0x0000, 0x800, CRC(f28f87ed) SHA1(736f38c3ec5455de1266aad348ba708d7201b21a) )
487 ROM_LOAD( "grdgprom.bin", 0x0800, 0x800, CRC(921b0328) SHA1(59d1a3d3a90bd680a75adca5dd1b4682236c673b) )
488 ROM_LOAD( "grdbprom.bin", 0x1000, 0x800, CRC(04350348) SHA1(098fec3073143e0b8746e728d7d321f2a353286f) )
489 ROM_END
490
491
492
493 /*************************************
494 *
495 * Game drivers
496 *
497 *************************************/
498
499 GAMEX( 1983, gridlee, 0, gridlee, gridlee, 0, ROT0, "Videa", "Gridlee", GAME_IMPERFECT_SOUND )
500