1 // license:BSD-3-Clause
2 // copyright-holders:Stefan Jokisch
3 /***************************************************************************
4 
5 Atari Destroyer Driver
6 
7 TODO:
8 - missing language roms means DIP switches related to these do not function
9 
10 ***************************************************************************/
11 
12 #include "emu.h"
13 #include "cpu/m6800/m6800.h"
14 #include "machine/74259.h"
15 #include "machine/timer.h"
16 #include "machine/watchdog.h"
17 #include "emupal.h"
18 #include "screen.h"
19 #include "speaker.h"
20 #include "machine/netlist.h"
21 
22 #include "netlist/nl_setup.h"
23 #include "audio/nl_destroyr.h"
24 
25 #include "destroyr.lh"
26 
27 
28 class destroyr_state : public driver_device
29 {
30 public:
destroyr_state(const machine_config & mconfig,device_type type,const char * tag)31 	destroyr_state(const machine_config &mconfig, device_type type, const char *tag)
32 		: driver_device(mconfig, type, tag)
33 		, m_maincpu(*this, "maincpu")
34 		, m_watchdog(*this, "watchdog")
35 		, m_gfxdecode(*this, "gfxdecode")
36 		, m_screen(*this, "screen")
37 		, m_palette(*this, "palette")
38 		, m_inputs(*this, "IN%u", 0U)
39 		, m_paddle(*this, "PADDLE")
40 		, m_alpha_num_ram(*this, "alpha_nuram")
41 		, m_major_obj_ram(*this, "major_obj_ram")
42 		, m_minor_obj_ram(*this, "minor_obj_ram")
43 		, m_sound_motor_speed(*this, "sound_nl:motor_speed")
44 		, m_sound_noise(*this, "sound_nl:noise")
45 		, m_sound_attract(*this, "sound_nl:attract")
46 		, m_sound_songate(*this, "sound_nl:songate")
47 		, m_sound_launch(*this, "sound_nl:launch")
48 		, m_sound_explo(*this, "sound_nl:explo")
49 		, m_sound_sonlat(*this, "sound_nl:sonlat")
50 		, m_sound_hexplo(*this, "sound_nl:hexplo")
51 		, m_sound_lexplo(*this, "sound_nl:lexplo")
52 	{ }
53 
54 	void destroyr(machine_config &config);
55 
56 private:
57 	virtual void machine_start() override;
58 	virtual void machine_reset() override;
59 	virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
60 
61 	static const device_timer_id TIMER_DIAL = 0;
62 	static const device_timer_id TIMER_FRAME = 1;
63 
64 	void main_map(address_map &map);
65 
66 	void misc_w(uint8_t data);
67 	void cursor_load_w(uint8_t data);
68 	void interrupt_ack_w(uint8_t data);
69 	uint8_t input_r(offs_t offset);
70 	uint8_t scanline_r();
71 
72 	void palette_init(palette_device &palette) const;
73 
74 	uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
75 
76 	TIMER_CALLBACK_MEMBER(dial_callback);
77 	TIMER_CALLBACK_MEMBER(frame_callback);
78 	TIMER_DEVICE_CALLBACK_MEMBER(scanline_irq);
79 
80 	/* devices */
81 	required_device<cpu_device> m_maincpu;
82 	required_device<watchdog_timer_device> m_watchdog;
83 	required_device<gfxdecode_device> m_gfxdecode;
84 	required_device<screen_device> m_screen;
85 	required_device<palette_device> m_palette;
86 	required_ioport_array<3> m_inputs;
87 	required_ioport m_paddle;
88 
89 	/* memory pointers */
90 	required_shared_ptr<uint8_t> m_alpha_num_ram;
91 	required_shared_ptr<uint8_t> m_major_obj_ram;
92 	required_shared_ptr<uint8_t> m_minor_obj_ram;
93 
94 	/* audio triggers */
95 	required_device<netlist_mame_logic_input_device> m_sound_motor_speed;
96 	required_device<netlist_mame_logic_input_device> m_sound_noise;
97 	required_device<netlist_mame_logic_input_device> m_sound_attract;
98 	required_device<netlist_mame_logic_input_device> m_sound_songate;
99 	required_device<netlist_mame_logic_input_device> m_sound_launch;
100 	required_device<netlist_mame_logic_input_device> m_sound_explo;
101 	required_device<netlist_mame_logic_input_device> m_sound_sonlat;
102 	required_device<netlist_mame_logic_input_device> m_sound_hexplo;
103 	required_device<netlist_mame_logic_input_device> m_sound_lexplo;
104 
105 	/* video-related */
106 	int            m_cursor;
107 	int            m_wavemod;
108 
109 	/* misc */
110 	int            m_potmask[2];
111 	int            m_potsense[2];
112 	int            m_attract;
113 	emu_timer      *m_dial_timer;
114 	emu_timer      *m_frame_timer;
115 };
116 
117 
screen_update(screen_device & screen,bitmap_ind16 & bitmap,const rectangle & cliprect)118 uint32_t destroyr_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
119 {
120 	bitmap.fill(0, cliprect);
121 
122 	/* draw major objects */
123 	for (int i = 0; i < 16; i++)
124 	{
125 		int attr = m_major_obj_ram[2 * i + 0] ^ 0xff;
126 		int horz = m_major_obj_ram[2 * i + 1];
127 
128 		int num = attr & 3;
129 		int scan = attr & 4;
130 		int flipx = attr & 8;
131 
132 		if (scan == 0)
133 		{
134 			if (horz >= 192)
135 				horz -= 256;
136 		}
137 		else
138 		{
139 			if (horz < 192)
140 				continue;
141 		}
142 
143 		m_gfxdecode->gfx(2)->transpen(bitmap,cliprect, num, 0, flipx, 0, horz, 16 * i, 0);
144 	}
145 
146 	/* draw alpha numerics */
147 	for (int i = 0; i < 8; i++)
148 	{
149 		for (int j = 0; j < 32; j++)
150 		{
151 			int num = m_alpha_num_ram[32 * i + j];
152 
153 			m_gfxdecode->gfx(0)->transpen(bitmap,cliprect, num, 0, 0, 0, 8 * j, 8 * i, 0);
154 		}
155 	}
156 
157 	/* draw minor objects */
158 	for (int i = 0; i < 2; i++)
159 	{
160 		int num = i << 4 | (m_minor_obj_ram[i + 0] & 0xf);
161 		int horz = 256 - m_minor_obj_ram[i + 2];
162 		int vert = 256 - m_minor_obj_ram[i + 4];
163 
164 		m_gfxdecode->gfx(1)->transpen(bitmap,cliprect, num, 0, 0, 0, horz, vert, 0);
165 	}
166 
167 	/* draw waves */
168 	for (int i = 0; i < 4; i++)
169 	{
170 		m_gfxdecode->gfx(3)->transpen(bitmap,cliprect, m_wavemod ? 1 : 0, 0, 0, 0, 64 * i, 0x4e, 0);
171 	}
172 
173 	/* draw cursor */
174 	for (int i = 0; i < 256; i++)
175 	{
176 		if (i & 4)
177 			bitmap.pix(m_cursor ^ 0xff, i) = 7;
178 	}
179 	return 0;
180 }
181 
182 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)183 void destroyr_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
184 {
185 	switch (id)
186 	{
187 	case TIMER_DIAL:
188 		dial_callback(ptr, param);
189 		break;
190 	case TIMER_FRAME:
191 		frame_callback(ptr, param);
192 		break;
193 	default:
194 		throw emu_fatalerror("Unknown id in destroyr_state::device_timer");
195 	}
196 }
197 
198 
TIMER_CALLBACK_MEMBER(destroyr_state::dial_callback)199 TIMER_CALLBACK_MEMBER(destroyr_state::dial_callback)
200 {
201 	int dial = param;
202 
203 	/* Analog inputs come from the player's depth control potentiometer.
204 	   The voltage is compared to a voltage ramp provided by a discrete
205 	   analog circuit that conditions the VBLANK signal. When the ramp
206 	   voltage exceeds the input voltage an NMI signal is generated. The
207 	   computer then reads the VSYNC data functions to tell where the
208 	   cursor should be located. */
209 
210 	m_potsense[dial] = 1;
211 
212 	if (m_potmask[dial])
213 	{
214 		m_maincpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
215 	}
216 }
217 
218 
TIMER_CALLBACK_MEMBER(destroyr_state::frame_callback)219 TIMER_CALLBACK_MEMBER(destroyr_state::frame_callback)
220 {
221 	m_potsense[0] = 0;
222 	m_potsense[1] = 0;
223 
224 	/* PCB supports two dials, but cab has only got one */
225 	m_dial_timer->adjust(m_screen->time_until_pos(m_paddle->read()));
226 	m_frame_timer->adjust(m_screen->time_until_pos(0));
227 }
228 
229 
TIMER_DEVICE_CALLBACK_MEMBER(destroyr_state::scanline_irq)230 TIMER_DEVICE_CALLBACK_MEMBER(destroyr_state::scanline_irq)
231 {
232 	// 16V clocks LS74 flip-flop with D = 32V and /Q output connected to /IRQ on 6800
233 	m_maincpu->set_input_line(M6800_IRQ_LINE, BIT(param, 5) ? ASSERT_LINE : CLEAR_LINE);
234 }
235 
236 
machine_reset()237 void destroyr_state::machine_reset()
238 {
239 	m_frame_timer->adjust(m_screen->time_until_pos(0));
240 
241 	m_cursor = 0;
242 	m_wavemod = 0;
243 	m_potmask[0] = 0;
244 	m_potmask[1] = 0;
245 	m_potsense[0] = 0;
246 	m_potsense[1] = 0;
247 	m_attract = 0;
248 }
249 
250 
misc_w(uint8_t data)251 void destroyr_state::misc_w(uint8_t data)
252 {
253 	/* bits 0 to 2 connect to the sound circuits */
254 	m_attract = BIT(data, 0);
255 	m_sound_attract->write(m_attract);
256 	m_sound_noise->write(BIT(data, 1));
257 	m_sound_motor_speed->write(BIT(data, 2));
258 	m_potmask[0] = BIT(data, 3);
259 	m_wavemod = BIT(data, 4);
260 	m_potmask[1] = BIT(data, 5);
261 
262 	machine().bookkeeping().coin_lockout_w(0, !m_attract);
263 	machine().bookkeeping().coin_lockout_w(1, !m_attract);
264 }
265 
266 
cursor_load_w(uint8_t data)267 void destroyr_state::cursor_load_w(uint8_t data)
268 {
269 	m_cursor = data;
270 	m_watchdog->watchdog_reset();
271 }
272 
273 
interrupt_ack_w(uint8_t data)274 void destroyr_state::interrupt_ack_w(uint8_t data)
275 {
276 	m_maincpu->set_input_line(M6800_IRQ_LINE, CLEAR_LINE);
277 }
278 
279 
input_r(offs_t offset)280 uint8_t destroyr_state::input_r(offs_t offset)
281 {
282 	if (offset & 1)
283 	{
284 		return m_inputs[1]->read();
285 	}
286 
287 	else
288 	{
289 		uint8_t ret = m_inputs[0]->read();
290 		ret |= (m_potsense[0] && m_potmask[0]) ? (1 << 2) : 0;
291 		ret |= (m_potsense[1] && m_potmask[1]) ? (1 << 3) : 0;
292 		return ret;
293 	}
294 }
295 
296 
scanline_r()297 uint8_t destroyr_state::scanline_r()
298 {
299 	return m_screen->vpos();
300 }
301 
302 
main_map(address_map & map)303 void destroyr_state::main_map(address_map &map)
304 {
305 	map.global_mask(0x7fff);
306 	map(0x0000, 0x00ff).mirror(0xf00).ram();
307 	map(0x1000, 0x1001).mirror(0xffe).r(FUNC(destroyr_state::input_r));
308 	map(0x1000, 0x1007).mirror(0xff0).w("outlatch", FUNC(f9334_device::write_d0));
309 	map(0x1008, 0x1008).mirror(0xff7).w(FUNC(destroyr_state::misc_w));
310 	map(0x2000, 0x2000).mirror(0xfff).portr("IN2");
311 	map(0x3000, 0x30ff).mirror(0xf00).writeonly().share("alpha_nuram");
312 	map(0x4000, 0x401f).mirror(0xfe0).writeonly().share("major_obj_ram");
313 	map(0x5000, 0x5000).mirror(0xff8).w(FUNC(destroyr_state::cursor_load_w));
314 	map(0x5001, 0x5001).mirror(0xff8).w(FUNC(destroyr_state::interrupt_ack_w));
315 	map(0x5002, 0x5007).mirror(0xff8).writeonly().share("minor_obj_ram");
316 	map(0x6000, 0x6000).mirror(0xfff).r(FUNC(destroyr_state::scanline_r));
317 	map(0x7000, 0x7fff).rom();
318 }
319 
320 
321 static INPUT_PORTS_START( destroyr )
322 	PORT_START("IN0")
323 	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED ) /* call 7400 */
324 	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
325 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) /* potsense1 */
326 	PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) /* potsense2 */
327 	PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_START1 )
328 	PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_START2 )
329 	PORT_DIPNAME( 0xc0, 0x80, "Extended Play" ) PORT_DIPLOCATION("SW2:8,7")
330 	PORT_DIPSETTING( 0x40, "1500 points" )
331 	PORT_DIPSETTING( 0x80, "2500 points" )
332 	PORT_DIPSETTING( 0xc0, "3500 points" )
333 	PORT_DIPSETTING( 0x00, "never" )
334 
335 	PORT_START("IN1")
336 	PORT_BIT( 0x01, IP_ACTIVE_LOW,  IPT_TILT )
337 	PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Speed Control") PORT_TOGGLE
338 	PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON1 )
339 	PORT_SERVICE( 0x08, IP_ACTIVE_LOW )
340 	PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_COIN1 )
341 	PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_COIN2 )
342 	PORT_BIT( 0x40, IP_ACTIVE_LOW,  IPT_UNUSED )
343 	PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_VBLANK("screen")
344 
345 	PORT_START("IN2")
346 	PORT_DIPNAME( 0x03, 0x02, DEF_STR( Coinage ) ) PORT_DIPLOCATION("SW:4,3")
347 	PORT_DIPSETTING( 0x03, DEF_STR( 2C_1C ) )
348 	PORT_DIPSETTING( 0x02, DEF_STR( 1C_1C ) )
349 	PORT_DIPSETTING( 0x01, DEF_STR( 1C_2C ) )
350 	PORT_DIPSETTING( 0x00, DEF_STR( Free_Play ) )
351 	PORT_DIPNAME( 0x0c, 0x08, "Play Time" ) PORT_DIPLOCATION("SW:2,1")
352 	PORT_DIPSETTING( 0x00, "50 seconds" )
353 	PORT_DIPSETTING( 0x04, "75 seconds" )
354 	PORT_DIPSETTING( 0x08, "100 seconds" )
355 	PORT_DIPSETTING( 0x0c, "125 seconds" )
356 	PORT_DIPNAME( 0x30, 0x00, DEF_STR( Language ) ) PORT_DIPLOCATION("SW2:5,6")
357 	PORT_DIPSETTING( 0x30, DEF_STR( German ) )
358 	PORT_DIPSETTING( 0x20, DEF_STR( French ) )
359 	PORT_DIPSETTING( 0x10, DEF_STR( Spanish ) )
360 	PORT_DIPSETTING( 0x00, DEF_STR( English ) )
361 	PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED )
362 	PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED )
363 
364 	PORT_START("PADDLE")
365 	PORT_BIT( 0xff, 0x00, IPT_PADDLE_V ) PORT_MINMAX(0,160) PORT_SENSITIVITY(30) PORT_KEYDELTA(10) PORT_CENTERDELTA(0) PORT_REVERSE
366 INPUT_PORTS_END
367 
368 
369 static const gfx_layout destroyr_alpha_num_layout =
370 {
371 	8, 8,     /* width, height */
372 	64,       /* total         */
373 	1,        /* planes        */
374 	{ 0 },    /* plane offsets */
375 	{
376 		0x4, 0x5, 0x6, 0x7, 0xC, 0xD, 0xE, 0xF
377 	},
378 	{
379 		0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70
380 	},
381 	0x80      /* increment */
382 };
383 
384 
385 static const gfx_layout destroyr_minor_object_layout =
386 {
387 	16, 16,   /* width, height */
388 	32,       /* total         */
389 	1,        /* planes        */
390 	{ 0 },    /* plane offsets */
391 	{
392 		0x04, 0x05, 0x06, 0x07, 0x0C, 0x0D, 0x0E, 0x0F,
393 		0x14, 0x15, 0x16, 0x17, 0x1C, 0x1D, 0x1E, 0x1F
394 	},
395 	{
396 		0x000, 0x020, 0x040, 0x060, 0x080, 0x0a0, 0x0c0, 0x0e0,
397 		0x100, 0x120, 0x140, 0x160, 0x180, 0x1a0, 0x1c0, 0x1e0
398 	},
399 	0x200     /* increment */
400 };
401 
402 static const uint32_t destroyr_major_object_layout_xoffset[64] =
403 {
404 	0x00, 0x02, 0x04, 0x06, 0x08, 0x0A, 0x0C, 0x0E,
405 	0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E,
406 	0x20, 0x22, 0x24, 0x26, 0x28, 0x2A, 0x2C, 0x2E,
407 	0x30, 0x32, 0x34, 0x36, 0x38, 0x3A, 0x3C, 0x3E,
408 	0x40, 0x42, 0x44, 0x46, 0x48, 0x4A, 0x4C, 0x4E,
409 	0x50, 0x52, 0x54, 0x56, 0x58, 0x5A, 0x5C, 0x5E,
410 	0x60, 0x62, 0x64, 0x66, 0x68, 0x6A, 0x6C, 0x6E,
411 	0x70, 0x72, 0x74, 0x76, 0x78, 0x7A, 0x7C, 0x7E
412 };
413 
414 static const gfx_layout destroyr_major_object_layout =
415 {
416 	64, 16,   /* width, height */
417 	4,        /* total         */
418 	2,        /* planes        */
419 	{ 1, 0 },  /* plane offsets */
420 	EXTENDED_XOFFS,
421 	{
422 		0x000, 0x080, 0x100, 0x180, 0x200, 0x280, 0x300, 0x380,
423 		0x400, 0x480, 0x500, 0x580, 0x600, 0x680, 0x700, 0x780
424 	},
425 	0x0800,   /* increment */
426 	destroyr_major_object_layout_xoffset,
427 	nullptr
428 };
429 
430 static const uint32_t destroyr_waves_layout_xoffset[64] =
431 {
432 	0x00, 0x01, 0x02, 0x03, 0x08, 0x09, 0x0A, 0x0B,
433 	0x10, 0x11, 0x12, 0x13, 0x18, 0x19, 0x1A, 0x1B,
434 	0x20, 0x21, 0x22, 0x23, 0x28, 0x29, 0x2A, 0x2B,
435 	0x30, 0x31, 0x32, 0x33, 0x38, 0x39, 0x3A, 0x3B,
436 	0x40, 0x41, 0x42, 0x43, 0x48, 0x49, 0x4A, 0x4B,
437 	0x50, 0x51, 0x52, 0x53, 0x58, 0x59, 0x5A, 0x5B,
438 	0x60, 0x61, 0x62, 0x63, 0x68, 0x69, 0x6A, 0x6B,
439 	0x70, 0x71, 0x72, 0x73, 0x78, 0x79, 0x7A, 0x7B
440 };
441 
442 static const gfx_layout destroyr_waves_layout =
443 {
444 	64, 2,    /* width, height */
445 	2,        /* total         */
446 	1,        /* planes        */
447 	{ 0 },
448 	EXTENDED_XOFFS,
449 	{ 0x00, 0x80 },
450 	0x04,     /* increment */
451 	destroyr_waves_layout_xoffset,
452 	nullptr
453 };
454 
455 
456 static GFXDECODE_START( gfx_destroyr )
457 	GFXDECODE_ENTRY( "gfx1", 0, destroyr_alpha_num_layout, 4, 1 )
458 	GFXDECODE_ENTRY( "gfx2", 0, destroyr_minor_object_layout, 4, 1 )
459 	GFXDECODE_ENTRY( "gfx3", 0, destroyr_major_object_layout, 0, 1 )
460 	GFXDECODE_ENTRY( "gfx4", 0, destroyr_waves_layout, 4, 1 )
461 GFXDECODE_END
462 
463 
palette_init(palette_device & palette) const464 void destroyr_state::palette_init(palette_device &palette) const
465 {
466 	palette.set_pen_color(0, rgb_t(0x00, 0x00, 0x00));   // major objects
467 	palette.set_pen_color(1, rgb_t(0x50, 0x50, 0x50));
468 	palette.set_pen_color(2, rgb_t(0xAF, 0xAF, 0xAF));
469 	palette.set_pen_color(3, rgb_t(0xFF ,0xFF, 0xFF));
470 	palette.set_pen_color(4, rgb_t(0x00, 0x00, 0x00));   // alpha numerics, waves, minor objects
471 	palette.set_pen_color(5, rgb_t(0xFF, 0xFF, 0xFF));
472 	palette.set_pen_color(6, rgb_t(0x00, 0x00, 0x00));   // cursor
473 	palette.set_pen_color(7, rgb_t(0x78, 0x78, 0x78));
474 }
475 
476 
machine_start()477 void destroyr_state::machine_start()
478 {
479 	m_dial_timer = timer_alloc(TIMER_DIAL);
480 	m_frame_timer = timer_alloc(TIMER_FRAME);
481 
482 	save_item(NAME(m_cursor));
483 	save_item(NAME(m_wavemod));
484 	save_item(NAME(m_attract));
485 	save_item(NAME(m_potmask));
486 	save_item(NAME(m_potsense));
487 }
488 
destroyr(machine_config & config)489 void destroyr_state::destroyr(machine_config &config)
490 {
491 	/* basic machine hardware */
492 	M6800(config, m_maincpu, 12.096_MHz_XTAL / 16);
493 	m_maincpu->set_addrmap(AS_PROGRAM, &destroyr_state::main_map);
494 
495 	TIMER(config, "scantimer").configure_scanline(FUNC(destroyr_state::scanline_irq), m_screen, 16, 32);
496 
497 	f9334_device &outlatch(F9334(config, "outlatch")); // F8
498 	outlatch.q_out_cb<0>().set_output("led0").invert(); // LED 1
499 	outlatch.q_out_cb<1>().set_output("led1").invert(); // LED 2 (no second LED present on cab)
500 	outlatch.q_out_cb<2>().set(m_sound_songate, FUNC(netlist_mame_logic_input_device::write));
501 	outlatch.q_out_cb<3>().set(m_sound_launch, FUNC(netlist_mame_logic_input_device::write));
502 	outlatch.q_out_cb<4>().set(m_sound_explo, FUNC(netlist_mame_logic_input_device::write));
503 	outlatch.q_out_cb<5>().set(m_sound_sonlat, FUNC(netlist_mame_logic_input_device::write));
504 	outlatch.q_out_cb<6>().set(m_sound_hexplo, FUNC(netlist_mame_logic_input_device::write));
505 	outlatch.q_out_cb<7>().set(m_sound_lexplo, FUNC(netlist_mame_logic_input_device::write));
506 
507 	WATCHDOG_TIMER(config, m_watchdog);
508 
509 	/* video hardware */
510 	SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
511 	m_screen->set_raw(12.096_MHz_XTAL / 2, 384, 0, 256, 263, 0, 240);
512 	m_screen->set_screen_update(FUNC(destroyr_state::screen_update));
513 	m_screen->set_palette(m_palette);
514 
515 	GFXDECODE(config, m_gfxdecode, m_palette, gfx_destroyr);
516 	PALETTE(config, m_palette, FUNC(destroyr_state::palette_init), 8);
517 
518 	/* sound hardware */
519 	SPEAKER(config, "mono").front_center();
520 
521 	NETLIST_SOUND(config, "sound_nl", 48000)
522 		.set_source(NETLIST_NAME(destroyr))
523 		.add_route(ALL_OUTPUTS, "mono", 1.0);
524 
525 	NETLIST_LOGIC_INPUT(config, "sound_nl:motor_speed", "MOTOR_SPEED.IN", 0);
526 	NETLIST_LOGIC_INPUT(config, "sound_nl:noise", "NOISE.IN", 0);
527 	NETLIST_LOGIC_INPUT(config, "sound_nl:attract", "ATTRACT.IN", 0);
528 	NETLIST_LOGIC_INPUT(config, "sound_nl:songate", "SONGATE.IN", 0);
529 	NETLIST_LOGIC_INPUT(config, "sound_nl:launch", "LAUNCH.IN", 0);
530 	NETLIST_LOGIC_INPUT(config, "sound_nl:explo", "EXPLO.IN", 0);
531 	NETLIST_LOGIC_INPUT(config, "sound_nl:sonlat", "SONLAT.IN", 0);
532 	NETLIST_LOGIC_INPUT(config, "sound_nl:hexplo", "HE.IN", 0);
533 	NETLIST_LOGIC_INPUT(config, "sound_nl:lexplo", "LE.IN", 0);
534 
535 	NETLIST_STREAM_OUTPUT(config, "sound_nl:cout0", 0, "OUTPUT").set_mult_offset(1.0, 0.0);
536 }
537 
538 
539 ROM_START( destroyr )
540 	ROM_REGION( 0x8000, "maincpu", 0 )  /* program code */
541 	ROM_LOAD( "030138.rom",0x7000, 0x0800, NO_DUMP ) // optional add-on translation rom
542 	ROM_LOAD( "030146-01.c3", 0x7800, 0x0800, CRC(e560c712) SHA1(0505ab57eee5421b4ff4e87d14505e02b18fd54c) )
543 
544 	ROM_REGION( 0x0400, "gfx1", 0 )     /* alpha numerics */
545 	ROM_LOAD( "030135-01.p4", 0x0000, 0x0400, CRC(184824cf) SHA1(713cfd1d41ef7b1c345ea0038b652c4ba3f08301) )
546 
547 	ROM_REGION( 0x0800, "gfx2", 0 )     /* minor objects */
548 	ROM_LOAD( "030132-01.f4", 0x0000, 0x0400, CRC(e09d3d55) SHA1(b26013397ef2cb32d0416ecb118387b9c2dffa9a) )
549 	ROM_LOAD( "030132-01.k4", 0x0400, 0x0400, CRC(e09d3d55) SHA1(b26013397ef2cb32d0416ecb118387b9c2dffa9a) ) // identical to f4
550 
551 	ROM_REGION( 0x0400, "gfx3", 0 )     /* major objects */
552 	ROM_LOAD_NIB_HIGH( "030134-01.p8", 0x0000, 0x0400, CRC(6259e007) SHA1(049f5f7160305cb4f4b499dd113cb11eea73fc95) )
553 	ROM_LOAD_NIB_LOW ( "030133-01.n8", 0x0000, 0x0400, CRC(108d3e2c) SHA1(8c993369d37c6713670483af78e6d04d38f4b4fc) )
554 
555 	ROM_REGION( 0x0020, "gfx4", 0 )     /* waves */
556 	ROM_LOAD( "030136-01.k2", 0x0000, 0x0020, CRC(532c11b1) SHA1(18ab5369a3f2cfcc9a44f38fa8649524bea5b203) )
557 
558 	ROM_REGION( 0x0100, "syncprom", 0 )    /* used for vsync/vblank signals */
559 	ROM_LOAD( "030131-01.m1", 0x0000, 0x0100, CRC(b8094b4c) SHA1(82dc6799a19984f3b204ee3aeeb007e55afc8be3) )
560 ROM_END
561 
562 ROM_START( destroyr1 )
563 	ROM_REGION( 0x8000, "maincpu", 0 )  /* program code */
564 	ROM_LOAD( "030138.rom",0x7000, 0x0800, NO_DUMP ) // optional add-on translation rom
565 	ROM_LOAD_NIB_HIGH( "030142-01.f3", 0x7800, 0x0400, CRC(9e9a08d3) SHA1(eb31bab1537caf43ab8c3d23a6c9cc2009fcb98e) )
566 	ROM_LOAD_NIB_LOW ( "030141-01.e2", 0x7800, 0x0400, CRC(c924fbce) SHA1(53aa9a3c4c6e90fb94500ddfa6c2ae3076eee2ef) )
567 	ROM_LOAD_NIB_HIGH( "030144-01.j3", 0x7c00, 0x0400, CRC(0c7135c6) SHA1(6a0180353a0a6f34639dadc23179f6323aae8d62) )
568 	ROM_LOAD_NIB_LOW ( "030143-01.h2", 0x7c00, 0x0400, CRC(b946e6f0) SHA1(b906024bb0e03a644fff1d5516637c24916b096e) )
569 
570 	ROM_REGION( 0x0400, "gfx1", 0 )     /* alpha numerics */
571 	ROM_LOAD( "030135-01.p4", 0x0000, 0x0400, CRC(184824cf) SHA1(713cfd1d41ef7b1c345ea0038b652c4ba3f08301) )
572 
573 	ROM_REGION( 0x0800, "gfx2", 0 )     /* minor objects */
574 	ROM_LOAD( "030132-01.f4", 0x0000, 0x0400, CRC(e09d3d55) SHA1(b26013397ef2cb32d0416ecb118387b9c2dffa9a) )
575 	ROM_LOAD( "030132-01.k4", 0x0400, 0x0400, CRC(e09d3d55) SHA1(b26013397ef2cb32d0416ecb118387b9c2dffa9a) ) // identical to f4
576 
577 	ROM_REGION( 0x0400, "gfx3", 0 )     /* major objects */
578 	ROM_LOAD_NIB_HIGH( "030134-01.p8", 0x0000, 0x0400, CRC(6259e007) SHA1(049f5f7160305cb4f4b499dd113cb11eea73fc95) )
579 	ROM_LOAD_NIB_LOW ( "030133-01.n8", 0x0000, 0x0400, CRC(108d3e2c) SHA1(8c993369d37c6713670483af78e6d04d38f4b4fc) )
580 
581 	ROM_REGION( 0x0020, "gfx4", 0 )     /* waves */
582 	ROM_LOAD( "030136-01.k2", 0x0000, 0x0020, CRC(532c11b1) SHA1(18ab5369a3f2cfcc9a44f38fa8649524bea5b203) )
583 
584 	ROM_REGION( 0x0100, "syncprom", 0 )    /* used for vsync/vblank signals */
585 	ROM_LOAD( "030131-01.m1", 0x0000, 0x0100, CRC(b8094b4c) SHA1(82dc6799a19984f3b204ee3aeeb007e55afc8be3) )
586 ROM_END
587 
588 
589 GAMEL( 1977, destroyr,  0,        destroyr, destroyr, destroyr_state, empty_init, ORIENTATION_FLIP_X, "Atari", "Destroyer (version O2)", MACHINE_SUPPORTS_SAVE, layout_destroyr )
590 GAMEL( 1977, destroyr1, destroyr, destroyr, destroyr, destroyr_state, empty_init, ORIENTATION_FLIP_X, "Atari", "Destroyer (version O1)", MACHINE_SUPPORTS_SAVE, layout_destroyr )
591