1 /***************************************************************************
2 
3 	Atari/Kee Ultra Tank hardware
4 
5 	Games supported:
6 		* Ultra Tank
7 
8 	Known issues:
9 		- sound samples needed
10 		- colors are probably correct, but should be verified
11 		- invisible tanks option doesn't work
12 		- coin counters aren't mapped
13 		- hardware collision detection is not emulated. However, the game is fully playable,
14 		  since the game software uses it only as a hint to check for tanks bumping into
15 		  walls/mines.
16 
17 ***************************************************************************/
18 
19 #include "driver.h"
20 #include "vidhrdw/generic.h"
21 
22 static int ultratnk_controls;
23 static UINT8 *mirror_ram;
24 
25 static struct tilemap *bg_tilemap;
26 
27 /*************************************
28  *
29  *	Palette generation
30  *
31  *************************************/
32 
33 static unsigned short colortable_source[] =
34 {
35 	0x02, 0x01,
36 	0x02, 0x00,
37 	0x02, 0x00,
38 	0x02, 0x01
39 };
40 
PALETTE_INIT(ultratnk)41 static PALETTE_INIT( ultratnk )
42 {
43 	palette_set_color(0,0x00,0x00,0x00); /* BLACK */
44 	palette_set_color(1,0xff,0xff,0xff); /* WHITE */
45 	palette_set_color(2,0x80,0x80,0x80); /* LT GREY */
46 	palette_set_color(3,0x55,0x55,0x55); /* DK GREY */
47 	memcpy(colortable,colortable_source,sizeof(colortable_source));
48 }
49 
50 
51 
52 /*************************************
53  *
54  *	Sprite rendering
55  *
56  *************************************/
57 
ultratnk_draw_sprites(struct mame_bitmap * bitmap)58 static void ultratnk_draw_sprites( struct mame_bitmap *bitmap )
59 {
60 	const UINT8 *pMem = memory_region( REGION_CPU1 );
61 
62 	if( (pMem[0x93]&0x80)==0 )
63 	/*	Probably wrong; game description indicates that one or both tanks can
64 		be invisible; in this game mode, tanks are visible when hit, bumping
65 		into a wall, or firing
66 	*/
67 	{
68 		drawgfx( bitmap, Machine->gfx[1], /* tank */
69 			pMem[0x99]>>3,
70 			0,
71 			0,0, /* no flip */
72 			pMem[0x90]-16,pMem[0x98]-16,
73 			&Machine->visible_area,
74 			TRANSPARENCY_PEN, 0 );
75 
76 		drawgfx( bitmap, Machine->gfx[1], /* tank */
77 			pMem[0x9b]>>3,
78 			1,
79 			0,0, /* no flip */
80 			pMem[0x92]-16,pMem[0x9a]-16,
81 			&Machine->visible_area,
82 			TRANSPARENCY_PEN, 0 );
83 	}
84 
85 	drawgfx( bitmap, Machine->gfx[1], /* bullet */
86 		(pMem[0x9f]>>3)|0x20,
87 		0,
88 		0,0, /* no flip */
89 		pMem[0x96]-16,pMem[0x9e]-16,
90 		&Machine->visible_area,
91 		TRANSPARENCY_PEN, 0 );
92 
93 	drawgfx( bitmap, Machine->gfx[1], /* bullet */
94 		(pMem[0x9d]>>3)|0x20,
95 		1,
96 		0,0, /* no flip */
97 		pMem[0x94]-16,pMem[0x9c]-16,
98 		&Machine->visible_area,
99 		TRANSPARENCY_PEN, 0 );
100 }
101 
102 
103 
104 /*************************************
105  *
106  *	Video update
107  *
108  *************************************/
109 
WRITE_HANDLER(ultratnk_videoram_w)110 static WRITE_HANDLER( ultratnk_videoram_w )
111 {
112 	if (videoram[offset] != data)
113 	{
114 		videoram[offset] = data;
115 		tilemap_mark_tile_dirty(bg_tilemap, offset);
116 	}
117 }
118 
get_bg_tile_info(int tile_index)119 static void get_bg_tile_info(int tile_index)
120 {
121 	int attr = videoram[tile_index];
122 	int code = attr & 0x3f;
123 	int color = attr >> 6;
124 
125 	SET_TILE_INFO(0, code, color, 0)
126 }
127 
VIDEO_START(ultratnk)128 VIDEO_START( ultratnk )
129 {
130 	bg_tilemap = tilemap_create(get_bg_tile_info, tilemap_scan_rows,
131 		TILEMAP_OPAQUE, 8, 8, 32, 32);
132 
133 	if ( !bg_tilemap )
134 		return 1;
135 
136 	return 0;
137 }
138 
VIDEO_UPDATE(ultratnk)139 VIDEO_UPDATE( ultratnk )
140 {
141 	tilemap_draw(bitmap, &Machine->visible_area, bg_tilemap, 0, 0);
142 	ultratnk_draw_sprites(bitmap);
143 
144 	/* Weird, but we have to update our sound registers here. */
145 	discrete_sound_w(2, mirror_ram[0x88] % 16);
146 	discrete_sound_w(3, mirror_ram[0x8A] % 16);
147 }
148 
149 /*************************************
150  *
151  *	Control reading
152  *
153  *************************************/
154 
WRITE_HANDLER(da_latch_w)155 static WRITE_HANDLER( da_latch_w )
156 {
157 	int joybits = readinputport(4);
158 	ultratnk_controls = readinputport(3); /* start and fire buttons */
159 
160 	switch( data )
161 	{
162 	case 0x0a:
163 		if( joybits&0x08 ) ultratnk_controls &= ~0x40;
164 		if( joybits&0x04 ) ultratnk_controls &= ~0x04;
165 
166 		if( joybits&0x80 ) ultratnk_controls &= ~0x10;
167 		if( joybits&0x40 ) ultratnk_controls &= ~0x01;
168 		break;
169 
170 	case 0x05:
171 		if( joybits&0x02 ) ultratnk_controls &= ~0x40;
172 		if( joybits&0x01 ) ultratnk_controls &= ~0x04;
173 
174 		if( joybits&0x20 ) ultratnk_controls &= ~0x10;
175 		if( joybits&0x10 ) ultratnk_controls &= ~0x01;
176 		break;
177 	}
178 }
179 
180 
READ_HANDLER(ultratnk_controls_r)181 static READ_HANDLER( ultratnk_controls_r )
182 {
183 	return (ultratnk_controls << offset) & 0x80;
184 }
185 
186 
READ_HANDLER(ultratnk_barrier_r)187 static READ_HANDLER( ultratnk_barrier_r )
188 {
189 	return readinputport(2) & 0x80;
190 }
191 
192 
READ_HANDLER(ultratnk_coin_r)193 static READ_HANDLER( ultratnk_coin_r )
194 {
195 	switch (offset & 0x06)
196 	{
197 		case 0x00: return (readinputport(2) << 3) & 0x80;	/* left coin */
198 		case 0x02: return (readinputport(2) << 4) & 0x80;	/* right coin */
199 		case 0x04: return (readinputport(2) << 1) & 0x80;	/* invisible tanks */
200 		case 0x06: return (readinputport(2) << 2) & 0x80;	/* rebounding shots */
201 	}
202 
203 	return 0;
204 }
205 
206 
READ_HANDLER(ultratnk_tilt_r)207 static READ_HANDLER( ultratnk_tilt_r )
208 {
209 	return (readinputport(2) << 5) & 0x80;	/* tilt */
210 }
211 
212 
READ_HANDLER(ultratnk_dipsw_r)213 static READ_HANDLER( ultratnk_dipsw_r )
214 {
215 	int dipsw = readinputport(0);
216 	switch( offset )
217 	{
218 		case 0x00: return ((dipsw & 0xC0) >> 6); /* language? */
219 		case 0x01: return ((dipsw & 0x30) >> 4); /* credits */
220 		case 0x02: return ((dipsw & 0x0C) >> 2); /* game time */
221 		case 0x03: return ((dipsw & 0x03) >> 0); /* extended time */
222 	}
223 	return 0;
224 }
225 
226 
227 
228 /*************************************
229  *
230  *	Sound handlers
231  *
232  *************************************/
WRITE_HANDLER(ultratnk_fire_w)233 WRITE_HANDLER( ultratnk_fire_w )
234 {
235 	discrete_sound_w(offset/2, offset&1);
236 }
237 
WRITE_HANDLER(ultratnk_attract_w)238 WRITE_HANDLER( ultratnk_attract_w )
239 {
240 	discrete_sound_w(5, (data & 1));
241 }
242 
WRITE_HANDLER(ultratnk_explosion_w)243 WRITE_HANDLER( ultratnk_explosion_w )
244 {
245 	discrete_sound_w(4, data % 16);
246 }
247 
248 
249 
250 /*************************************
251  *
252  *	Interrupt generation
253  *
254  *************************************/
255 
INTERRUPT_GEN(ultratnk_interrupt)256 static INTERRUPT_GEN( ultratnk_interrupt )
257 {
258 	if (readinputport(1) & 0x40 )
259 	{
260 		/* only do NMI interrupt if not in TEST mode */
261 		cpu_set_irq_line(0, IRQ_LINE_NMI, PULSE_LINE);
262 	}
263 }
264 
265 
266 
267 /*************************************
268  *
269  *	Misc memory handlers
270  *
271  *************************************/
272 
READ_HANDLER(ultratnk_collision_r)273 static READ_HANDLER( ultratnk_collision_r )
274 {
275 	/**	Note: hardware collision detection is not emulated.
276 	 *	However, the game is fully playable, since the game software uses it
277 	 *	only as a hint to check for tanks bumping into walls/mines.
278 	 */
279 	switch( offset )
280 	{
281 		case 0x01:	return 0x80;	/* white tank = D7 */
282 		case 0x03:	return 0x80;	/* black tank = D7 */
283 	}
284 	return 0;
285 }
286 
287 
WRITE_HANDLER(ultratnk_leds_w)288 static WRITE_HANDLER( ultratnk_leds_w )
289 {
290 	set_led_status(offset/2,offset&1);
291 }
292 
293 
READ_HANDLER(mirror_r)294 static READ_HANDLER( mirror_r )
295 {
296 	return mirror_ram[offset];
297 }
298 
299 
WRITE_HANDLER(mirror_w)300 static WRITE_HANDLER( mirror_w )
301 {
302 	mirror_ram[offset] = data;
303 }
304 
305 
306 
307 /*************************************
308  *
309  *	Main CPU memory handlers
310  *
311  *************************************/
312 
MEMORY_READ_START(readmem)313 static MEMORY_READ_START( readmem )
314 	{ 0x0000, 0x00ff, MRA_RAM },
315 	{ 0x0100, 0x01ff, mirror_r },
316 	{ 0x0800, 0x0bff, MRA_RAM },
317 	{ 0x0c00, 0x0cff, MRA_RAM },
318 	{ 0x1000, 0x1000, input_port_1_r }, /* self test, vblank */
319 	{ 0x1800, 0x1800, ultratnk_barrier_r }, /* barrier */
320 	{ 0x2000, 0x2007, ultratnk_controls_r },
321 	{ 0x2020, 0x2026, ultratnk_coin_r },
322 	{ 0x2040, 0x2043, ultratnk_collision_r },
323 	{ 0x2046, 0x2046, ultratnk_tilt_r },
324 	{ 0x2060, 0x2063, ultratnk_dipsw_r },
325 	{ 0x2800, 0x2fff, MRA_NOP }, /* diagnostic ROM (see code at B1F3) */
326 	{ 0xb000, 0xbfff, MRA_ROM },
327 	{ 0xf000, 0xffff, MRA_ROM },
328 MEMORY_END
329 
330 
331 static MEMORY_WRITE_START( writemem )
332 	{ 0x0000, 0x00ff, MWA_RAM, &mirror_ram },
333 	{ 0x0100, 0x01ff, mirror_w },
334 	{ 0x0800, 0x0bff, ultratnk_videoram_w, &videoram },
335 	{ 0x0c00, 0x0cff, MWA_RAM }, /* ? */
336 	{ 0x2000, 0x201f, ultratnk_attract_w }, /* attract */
337 	{ 0x2020, 0x203f, MWA_NOP }, /* collision reset 1-4, 2020-21=cr1, 22-23=cr2, 24-25=cr3, 26,27=cr4 */
338 	{ 0x2040, 0x2041, da_latch_w }, /* D/A LATCH */
339 	{ 0x2042, 0x2043, ultratnk_explosion_w }, /* EXPLOSION (sound) */
340 	{ 0x2044, 0x2045, MWA_NOP }, /* TIMER (watchdog) RESET */
341 	{ 0x2066, 0x2067, MWA_NOP }, /* LOCKOUT */
342 	{ 0x2068, 0x206b, ultratnk_leds_w },
343 	{ 0x206c, 0x206f, ultratnk_fire_w }, /* fire 1/2 */
344 	{ 0xb000, 0xbfff, MWA_ROM },
345 	{ 0xf000, 0xffff, MWA_ROM },
346 MEMORY_END
347 
348 
349 
350 /*************************************
351  *
352  *	Port definitions
353  *
354  *************************************/
355 
356 INPUT_PORTS_START( ultratnk )
357 	PORT_START
358 	PORT_DIPNAME( 0x03, 0x01, "Extended Play" )
359 	PORT_DIPSETTING(	0x01, "25 Points" )
360 	PORT_DIPSETTING(	0x02, "50 Points" )
361 	PORT_DIPSETTING(	0x03, "75 Points" )
362 	PORT_DIPSETTING(	0x00, "None" )
363 	PORT_DIPNAME( 0x0c, 0x04, "Game Length" )
364 	PORT_DIPSETTING(	0x00, "60 Seconds" )
365 	PORT_DIPSETTING(	0x04, "90 Seconds" )
366 	PORT_DIPSETTING(	0x08, "120 Seconds" )
367 	PORT_DIPSETTING(	0x0c, "150 Seconds" )
368 	PORT_DIPNAME( 0x30, 0x20, DEF_STR( Coinage ) )
369 	PORT_DIPSETTING(	0x30, DEF_STR( 2C_1C ) )
370 	PORT_DIPSETTING(	0x20, DEF_STR( 1C_1C ) )
371 	PORT_DIPSETTING(	0x10, DEF_STR( 1C_2C ) )
372 	PORT_DIPSETTING(	0x00, DEF_STR( Free_Play ) )
373 	PORT_DIPNAME( 0xc0, 0x00, "Spare" ) /* Language?  Doesn't have any effect. */
374 	PORT_DIPSETTING(	0x00, "A" )
375 	PORT_DIPSETTING(	0x40, "B" )
376 	PORT_DIPSETTING(	0x80, "C" )
377 	PORT_DIPSETTING(	0xc0, "D" )
378 
379 	PORT_START
380 	PORT_SERVICE( 0x40, IP_ACTIVE_LOW )
381 	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_VBLANK )
382 
383 	PORT_START /* input#2 (arbitrarily arranged) */
384 	PORT_BITX(0x80, IP_ACTIVE_HIGH, IPT_SERVICE1 | IPF_TOGGLE, "Option 1", IP_KEY_DEFAULT, IP_JOY_DEFAULT )
385 	PORT_BITX(0x40, IP_ACTIVE_HIGH, IPT_SERVICE2 | IPF_TOGGLE, "Option 2", IP_KEY_DEFAULT, IP_JOY_DEFAULT )
386 	PORT_BITX(0x20, IP_ACTIVE_HIGH, IPT_SERVICE3 | IPF_TOGGLE, "Option 3", IP_KEY_DEFAULT, IP_JOY_DEFAULT )
387 	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_COIN1 )
388 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_COIN2 )
389 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_TILT )
390 
391 	PORT_START /* input#3 */
392 	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START1 )
393 	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SPECIAL ) /* joystick (taken from below) */
394 	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START2 )
395 	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_SPECIAL ) /* joystick (taken from below) */
396 	PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_BUTTON1 | IPF_PLAYER1 )
397 	PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SPECIAL ) /* joystick (taken from below) */
398 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 | IPF_PLAYER2 )
399 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SPECIAL ) /* joystick (taken from below) */
400 
401 	PORT_START /* input#4 - fake */
402 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_DOWN  | IPF_PLAYER1 )
403 	PORT_BIT( 0x0a, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_UP    | IPF_PLAYER1 )	/* note that this sets 2 bits */
404 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_DOWN | IPF_PLAYER1 )
405 	PORT_BIT( 0x05, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_UP   | IPF_PLAYER1 )	/* note that this sets 2 bits */
406 	PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_DOWN  | IPF_PLAYER2 )
407 	PORT_BIT( 0xa0, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_UP    | IPF_PLAYER2 )	/* note that this sets 2 bits */
408 	PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_DOWN | IPF_PLAYER2 )
409 	PORT_BIT( 0x50, IP_ACTIVE_HIGH, IPT_JOYSTICKRIGHT_UP   | IPF_PLAYER2 )	/* note that this sets 2 bits */
410 	PORT_START		/* 5 */
411 	PORT_ADJUSTER( 5, "Motor 1 RPM" )
412 
413 	PORT_START		/* 6 */
414 	PORT_ADJUSTER( 10, "Motor 2 RPM" )
415 INPUT_PORTS_END
416 
417 
418 
419 /*************************************
420  *
421  *	Graphics definitions
422  *
423  *************************************/
424 
425 static struct GfxLayout playfield_layout =
426 {
427 	8,8,
428 	RGN_FRAC(1,2),
429 	1,
430 	{ 0 },
431 	{ 4, 5, 6, 7, 4 + RGN_FRAC(1,2), 5 + RGN_FRAC(1,2), 6 + RGN_FRAC(1,2), 7 + RGN_FRAC(1,2) },
432 	{ 0, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
433 	8*8
434 };
435 
436 
437 static struct GfxLayout motion_layout =
438 {
439 	16,16,
440 	RGN_FRAC(1,4),
441 	1,
442 	{ 0 },
443 	{ 7, 6, 5, 4, 7 + RGN_FRAC(1,4), 6 + RGN_FRAC(1,4), 5 + RGN_FRAC(1,4), 4 + RGN_FRAC(1,4),
444 	  7 + RGN_FRAC(2,4), 6 + RGN_FRAC(2,4), 5 + RGN_FRAC(2,4), 4 + RGN_FRAC(2,4),
445 	  7 + RGN_FRAC(3,4), 6 + RGN_FRAC(3,4), 5 + RGN_FRAC(3,4), 4 + RGN_FRAC(3,4) },
446 	{ 0, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8,
447 	  8*8, 9*8, 10*8, 11*8, 12*8, 13*8, 14*8, 15*8 },
448 	16*8
449 };
450 
451 
452 static struct GfxDecodeInfo gfxdecodeinfo[] =
453 {
454 	{ REGION_GFX1, 0, &playfield_layout, 0, 4 }, 	/* playfield graphics */
455 	{ REGION_GFX2, 0, &motion_layout,    0, 4 }, 	/* motion graphics */
456 	{ -1 }
457 };
458 
459 
460 /************************************************************************/
461 /* ultratnk Sound System Analog emulation                               */
462 /************************************************************************/
463 
464 const struct discrete_lfsr_desc ultratnk_lfsr={
465 	16,			/* Bit Length */
466 	0,			/* Reset Value */
467 	0,			/* Use Bit 0 as XOR input 0 */
468 	14,			/* Use Bit 14 as XOR input 1 */
469 	DISC_LFSR_XNOR,		/* Feedback stage1 is XNOR */
470 	DISC_LFSR_OR,		/* Feedback stage2 is just stage 1 output OR with external feed */
471 	DISC_LFSR_REPLACE,	/* Feedback stage3 replaces the shifted register contents */
472 	0x000001,		/* Everything is shifted into the first bit only */
473 	0,			/* Output is not inverted */
474 	15			/* Output bit */
475 };
476 
477 /* Nodes - Inputs */
478 #define ULTRATNK_MOTORSND1_DATA		NODE_01
479 #define ULTRATNK_MOTORSND2_DATA		NODE_02
480 #define ULTRATNK_FIRESND1_EN		NODE_03
481 #define ULTRATNK_FIRESND2_EN		NODE_04
482 #define ULTRATNK_EXPLOSIONSND_DATA	NODE_05
483 #define ULTRATNK_ATTRACT_EN		NODE_06
484 /* Nodes - Sounds */
485 #define ULTRATNK_MOTORSND1		NODE_10
486 #define ULTRATNK_MOTORSND2		NODE_11
487 #define ULTRATNK_EXPLOSIONSND		NODE_12
488 #define ULTRATNK_FIRESND1		NODE_13
489 #define ULTRATNK_FIRESND2		NODE_14
490 #define ULTRATNK_NOISE			NODE_15
491 #define ULTRATNK_FINAL_MIX		NODE_16
492 
493 static DISCRETE_SOUND_START(ultratnk_sound_interface)
494 	/************************************************/
495 	/* Ultratnk sound system: 5 Sound Sources       */
496 	/*                     Relative Volume          */
497 	/*    1/2) Motor           77.72%               */
498 	/*      2) Explosion      100.00%               */
499 	/*    4/5) Fire            29.89%               */
500 	/* Relative volumes calculated from resitor     */
501 	/* network in combiner circuit                  */
502 	/*                                              */
503 	/*  Discrete sound mapping via:                 */
504 	/*     discrete_sound_w($register,value)        */
505 	/*  $00 - Fire enable Tank 1                    */
506 	/*  $01 - Fire enable Tank 2                    */
507 	/*  $02 - Motorsound frequency Tank 1           */
508 	/*  $03 - Motorsound frequency Tank 2           */
509 	/*  $04 - Explode volume                        */
510 	/*  $05 - Attract                               */
511 	/*                                              */
512 	/************************************************/
513 
514 	/************************************************/
515 	/* Input register mapping for ultratnk           */
516 	/************************************************/
517 	/*                   NODE                    ADDR   MASK   GAIN    OFFSET  INIT */
518 	DISCRETE_INPUT (ULTRATNK_FIRESND1_EN       , 0x00, 0x000f,                  0.0)
519 	DISCRETE_INPUT (ULTRATNK_FIRESND2_EN       , 0x01, 0x000f,                  0.0)
520 	DISCRETE_INPUTX(ULTRATNK_MOTORSND1_DATA    , 0x02, 0x000f, -1.0   , 15.0,   0.0)
521 	DISCRETE_INPUTX(ULTRATNK_MOTORSND2_DATA    , 0x03, 0x000f, -1.0   , 15.0,   0.0)
522 	DISCRETE_INPUTX(ULTRATNK_EXPLOSIONSND_DATA , 0x04, 0x000f, 1000.0/15.0, 0,  0.0)
523 	DISCRETE_INPUT (ULTRATNK_ATTRACT_EN        , 0x05, 0x000f,                  0.0)
524 
525 	/************************************************/
526 	/* Motor sound circuit is based on a 556 VCO    */
527 	/* with the input frequency set by the MotorSND */
528 	/* latch (4 bit). This freqency is then used to */
529 	/* driver a modulo 12 counter, with div6, 4 & 3 */
530 	/* summed as the output of the circuit.         */
531 	/* VCO Output is Sq wave = 27-382Hz             */
532 	/*  F1 freq - (Div6)                            */
533 	/*  F2 freq = (Div4)                            */
534 	/*  F3 freq = (Div3) 33.3% duty, 33.3 deg phase */
535 	/* To generate the frequency we take the freq.  */
536 	/* diff. and /15 to get all the steps between   */
537 	/* 0 - 15.  Then add the low frequency and send */
538 	/* that value to a squarewave generator.        */
539 	/* Also as the frequency changes, it ramps due  */
540 	/* to a 2.2uf capacitor on the R-ladder.        */
541 	/* Note the VCO freq. is controlled by a 250k   */
542 	/* pot.  The freq. used here is for the pot set */
543 	/* to 125k.  The low freq is allways the same.  */
544 	/* This adjusts the high end.                   */
545 	/* 0k = 214Hz.   250k = 4416Hz                  */
546 	/************************************************/
547 	DISCRETE_RCFILTER(NODE_20, 1, ULTRATNK_MOTORSND1_DATA, 123000, 2.2e-6)
548 	DISCRETE_ADJUSTMENT(NODE_21, 1, (214.0-27.0)/12/15, (4416.0-27.0)/12/15, DISC_LOGADJ, 5)
549 	DISCRETE_MULTIPLY(NODE_22, 1, NODE_20, NODE_21)
550 
551 	DISCRETE_MULTADD(NODE_23, 1, NODE_22, 2, 27.0/6)	/* F1 = /12*2 = /6 */
552 	DISCRETE_SQUAREWAVE(NODE_24, 1, NODE_23, (777.2/3), 50.0, 0, 0)
553 	DISCRETE_RCFILTER(NODE_25, 1, NODE_24, 10000, 1e-7)
554 
555 	DISCRETE_MULTADD(NODE_26, 1, NODE_22, 3, 27.0/4)	/* F2 = /12*3 = /4 */
556 	DISCRETE_SQUAREWAVE(NODE_27, 1, NODE_26, (777.2/3), 50.0, 0, 0)
557 	DISCRETE_RCFILTER(NODE_28, 1, NODE_27, 10000, 1e-7)
558 
559 	DISCRETE_MULTADD(NODE_29, 1, NODE_22, 4, 27.0/3)	/* F3 = /12*4 = /3 */
560 	DISCRETE_SQUAREWAVE(NODE_30, 1, NODE_29, (777.2/3), 100.0/3, 0, 360.0/3)
561 	DISCRETE_RCFILTER(NODE_31, 1, NODE_30, 10000, 1e-7)
562 
563 	DISCRETE_ADDER3(ULTRATNK_MOTORSND1, ULTRATNK_ATTRACT_EN, NODE_25, NODE_28, NODE_31)
564 
565 	/************************************************/
566 	/* Tank2 motor sound is basically the same as   */
567 	/* Tank1.  But I shifted the frequencies up for */
568 	/* it to sound different from Tank1.            */
569 	/************************************************/
570 	DISCRETE_RCFILTER(NODE_40, 1, ULTRATNK_MOTORSND2_DATA, 123000, 2.2e-6)
571 	DISCRETE_ADJUSTMENT(NODE_41, 1, (214.0-27.0)/12/15, (4416.0-27.0)/12/15, DISC_LOGADJ, 6)
572 	DISCRETE_MULTIPLY(NODE_42, 1, NODE_40, NODE_41)
573 
574 	DISCRETE_MULTADD(NODE_43, 1, NODE_42, 2, 27.0/6)	/* F1 = /12*2 = /6 */
575 	DISCRETE_SQUAREWAVE(NODE_44, 1, NODE_43, (777.2/3), 50.0, 0, 0)
576 	DISCRETE_RCFILTER(NODE_45, 1, NODE_44, 10000, 1e-7)
577 
578 	DISCRETE_MULTADD(NODE_46, 1, NODE_42, 3, 27.0/4)	/* F2 = /12*3 = /4 */
579 	DISCRETE_SQUAREWAVE(NODE_47, 1, NODE_46, (777.2/3), 50.0, 0, 0)
580 	DISCRETE_RCFILTER(NODE_48, 1, NODE_47, 10000, 1e-7)
581 
582 	DISCRETE_MULTADD(NODE_49, 1, NODE_42, 4, 27.0/3)	/* F3 = /12*4 = /3 */
583 	DISCRETE_SQUAREWAVE(NODE_50, 1, NODE_49, (777.2/3), 100.0/3, 0, 360.0/3)
584 	DISCRETE_RCFILTER(NODE_51, 1, NODE_50, 10000, 1e-7)
585 
586 	DISCRETE_ADDER3(ULTRATNK_MOTORSND2, ULTRATNK_ATTRACT_EN, NODE_45, NODE_48, NODE_51)
587 
588 	/************************************************/
589 	/* Explosion circuit is built around a noise    */
590 	/* generator built from 2 shift registers that  */
591 	/* are clocked by the 2V signal.                */
592 	/* 2V = HSYNC/4                                 */
593 	/*    = 15750/4                                 */
594 	/* Output is binary weighted with 4 bits of     */
595 	/* crash volume.                                */
596 	/************************************************/
597 	DISCRETE_LFSR_NOISE(ULTRATNK_NOISE, ULTRATNK_ATTRACT_EN, ULTRATNK_ATTRACT_EN, 15750.0/4, 1.0, 0, 0, &ultratnk_lfsr)
598 
599 	DISCRETE_MULTIPLY(NODE_60, 1, ULTRATNK_NOISE, ULTRATNK_EXPLOSIONSND_DATA)
600 	DISCRETE_RCFILTER(ULTRATNK_EXPLOSIONSND, 1, NODE_60, 545, 1e-7)
601 
602 	/************************************************/
603 	/* Fire circuits takes the noise output from    */
604 	/* the crash circuit and applies +ve feedback   */
605 	/* to cause oscillation. There is also an RC    */
606 	/* filter on the input to the feedback circuit. */
607 	/* RC is 1K & 10uF                              */
608 	/* Feedback cct is modelled by using the RC out */
609 	/* as the frequency input on a VCO,             */
610 	/* breadboarded freq range as:                  */
611 	/*  0 = 940Hz, 34% duty                         */
612 	/*  1 = 630Hz, 29% duty                         */
613 	/*  the duty variance is so small we ignore it  */
614 	/************************************************/
615 	DISCRETE_INVERT(NODE_70, ULTRATNK_NOISE)
616 	DISCRETE_MULTADD(NODE_71, 1, NODE_70, 940.0-630.0, ((940.0-630.0)/2)+630.0)
617 	DISCRETE_RCFILTER(NODE_72, 1, NODE_71, 1000, 1e-5)
618 	DISCRETE_SQUAREWAVE(NODE_73, 1, NODE_72, 407.8, 31.5, 0, 0.0)
619 	DISCRETE_ONOFF(ULTRATNK_FIRESND1, ULTRATNK_FIRESND1_EN, NODE_73)
620 	DISCRETE_ONOFF(ULTRATNK_FIRESND2, ULTRATNK_FIRESND2_EN, NODE_73)
621 
622 	/************************************************/
623 	/* Combine all 5 sound sources.                 */
624 	/* Add some final gain to get to a good sound   */
625 	/* level.                                       */
626 	/************************************************/
627 	DISCRETE_ADDER3(NODE_90, 1, ULTRATNK_MOTORSND1, ULTRATNK_EXPLOSIONSND, ULTRATNK_FIRESND1)
628 	DISCRETE_ADDER3(NODE_91, 1, NODE_90, ULTRATNK_MOTORSND2, ULTRATNK_FIRESND2)
629 	DISCRETE_GAIN(ULTRATNK_FINAL_MIX, NODE_91, 65534.0/(777.2+777.2+1000.0+298.9+298.9))
630 
631 	DISCRETE_OUTPUT(ULTRATNK_FINAL_MIX, 100)
632 DISCRETE_SOUND_END
633 
634 
635 
636 /*************************************
637  *
638  *	Machine driver
639  *
640  *************************************/
641 
642 static MACHINE_DRIVER_START( ultratnk )
643 
644 	/* basic machine hardware */
645 	MDRV_CPU_ADD(M6502,1500000)
646 	MDRV_CPU_MEMORY(readmem,writemem)
647 	MDRV_CPU_VBLANK_INT(ultratnk_interrupt,4)
648 
649 	MDRV_FRAMES_PER_SECOND(60)
650 	MDRV_VBLANK_DURATION(DEFAULT_REAL_60HZ_VBLANK_DURATION)
651 
652 	/* video hardware */
653 	MDRV_VIDEO_ATTRIBUTES(VIDEO_TYPE_RASTER)
654 	MDRV_SCREEN_SIZE(32*8, 32*8)
655 	MDRV_VISIBLE_AREA(0*8, 32*8-1, 0*8, 28*8-1)
656 	MDRV_GFXDECODE(gfxdecodeinfo)
657 	MDRV_PALETTE_LENGTH(4)
658 	MDRV_COLORTABLE_LENGTH(sizeof(colortable_source)/sizeof(unsigned short))
659 
660 	MDRV_PALETTE_INIT(ultratnk)
661 	MDRV_VIDEO_START(ultratnk)
662 	MDRV_VIDEO_UPDATE(ultratnk)
663 
664 	/* sound hardware */
665 	MDRV_SOUND_ADD_TAG("discrete", DISCRETE, ultratnk_sound_interface)
666 MACHINE_DRIVER_END
667 
668 
669 
670 /*************************************
671  *
672  *	ROM definitions
673  *
674  *************************************/
675 
676 ROM_START( ultratnk )
677 	ROM_REGION( 0x12000, REGION_CPU1, 0 )
678 	ROM_LOAD_NIB_LOW ( "030180.n1",	 0xb000, 0x0800, CRC(b6aa6056) SHA1(6de094017b5d87a238053fac88129d20260f8222) ) /* ROM 3 D0-D3 */
679 	ROM_LOAD_NIB_HIGH( "030181.k1",	 0xb000, 0x0800, CRC(17145c97) SHA1(afe0c9c562c27cd1fba57ea83377b0a4c12496db) ) /* ROM 3 D4-D7 */
680 	ROM_LOAD_NIB_LOW ( "030182.m1",	 0xb800, 0x0800, CRC(034366a2) SHA1(dc289ce4c79e9937977ca8804ce07b4c8e40e969) ) /* ROM 4 D0-D3 */
681 	ROM_RELOAD(                      0xf800, 0x0800 ) /* for 6502 vectors */
682 	ROM_LOAD_NIB_HIGH( "030183.l1",	 0xb800, 0x0800, CRC(be141602) SHA1(17aad9bab9bf6bd22dc3c2214b049bbd68c87380) ) /* ROM 4 D4-D7 */
683 	ROM_RELOAD(                      0xf800, 0x0800 ) /* for 6502 vectors */
684 
685 	ROM_REGION( 0x0400, REGION_GFX1, ROMREGION_DISPOSE )
686 	ROM_LOAD( "30172-01.j6", 0x0000, 0x0200, CRC(1d364b23) SHA1(44c5792ed3f33f40cd8632718b0e82152559ecdf) )
687 	ROM_LOAD( "30173-01.h6", 0x0200, 0x0200, CRC(5c32f331) SHA1(c1d675891490fbc533eaa0da57545398d7325df8) )
688 
689 	ROM_REGION( 0x1000, REGION_GFX2, ROMREGION_DISPOSE )
690 	ROM_LOAD( "30174-01.n6", 0x0000, 0x0400, CRC(d0e20e73) SHA1(0df1ed4a73255032bb809fb4d0a4bf3f151c749d) )
691 	ROM_LOAD( "30175-01.m6", 0x0400, 0x0400, CRC(a47459c9) SHA1(4ca92edc172fbac923ba71731a25546c04ffc7b0) )
692 	ROM_LOAD( "30176-01.l6", 0x0800, 0x0400, CRC(1cc7c2dd) SHA1(7f8aebe8375751183afeae35ea2d241d22ee7a4f) )
693 	ROM_LOAD( "30177-01.k6", 0x0c00, 0x0400, CRC(3a91b09f) SHA1(1e713cb612eb7d78fc4a003e4e60308f62e0b169) )
694 ROM_END
695 
696 
697 
698 /*************************************
699  *
700  *	Game drivers
701  *
702  *************************************/
703 
704 GAME( 1978, ultratnk, 0, ultratnk, ultratnk, 0, 0, "Atari", "Ultra Tank" )
705