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