1 // license:BSD-3-Clause
2 // copyright-holders:Aaron Giles
3 /*************************************************************************
4 
5     BattleToads
6 
7     driver by Aaron Giles
8 
9 **************************************************************************/
10 
11 #include "emu.h"
12 #include "includes/btoads.h"
13 
14 #include "speaker.h"
15 
16 
17 #define CPU_CLOCK           XTAL(64'000'000)
18 #define VIDEO_CLOCK         XTAL(20'000'000)
19 #define SOUND_CLOCK         XTAL(24'000'000)
20 
21 
22 
23 /*************************************
24  *
25  *  Machine init
26  *
27  *************************************/
28 
machine_start()29 void btoads_state::machine_start()
30 {
31 	m_nvram_data = std::make_unique<uint8_t[]>(0x2000);
32 	subdevice<nvram_device>("nvram")->set_base(m_nvram_data.get(), 0x2000);
33 
34 	save_item(NAME(m_main_to_sound_data));
35 	save_item(NAME(m_main_to_sound_ready));
36 	save_item(NAME(m_sound_to_main_data));
37 	save_item(NAME(m_sound_to_main_ready));
38 	save_item(NAME(m_sound_int_state));
39 	save_pointer(NAME(m_nvram_data), 0x2000);
40 }
41 
42 
43 
44 /*************************************
45  *
46  *  NVRAM
47  *
48  *************************************/
49 
nvram_w(offs_t offset,uint8_t data)50 void btoads_state::nvram_w(offs_t offset, uint8_t data)
51 {
52 	m_nvram_data[offset] = data;
53 }
54 
55 
nvram_r(offs_t offset)56 uint8_t btoads_state::nvram_r(offs_t offset)
57 {
58 	return m_nvram_data[offset];
59 }
60 
61 
62 
63 /*************************************
64  *
65  *  Main -> sound CPU communication
66  *
67  *************************************/
68 
device_timer(emu_timer & timer,device_timer_id id,int param,void * ptr)69 void btoads_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
70 {
71 	switch (id)
72 	{
73 		case TIMER_ID_DELAYED_SOUND:
74 			m_main_to_sound_data = param;
75 			m_main_to_sound_ready = 1;
76 			m_audiocpu->signal_interrupt_trigger();
77 
78 			// use a timer to make long transfers faster
79 			timer_set(attotime::from_usec(50), TIMER_ID_NOP);
80 			break;
81 	}
82 }
83 
84 
main_sound_w(offs_t offset,uint16_t data,uint16_t mem_mask)85 void btoads_state::main_sound_w(offs_t offset, uint16_t data, uint16_t mem_mask)
86 {
87 	if (ACCESSING_BITS_0_7)
88 		synchronize(TIMER_ID_DELAYED_SOUND, data & 0xff);
89 }
90 
91 
main_sound_r()92 uint16_t btoads_state::main_sound_r()
93 {
94 	m_sound_to_main_ready = 0;
95 	return m_sound_to_main_data;
96 }
97 
98 
READ_LINE_MEMBER(btoads_state::main_to_sound_r)99 READ_LINE_MEMBER( btoads_state::main_to_sound_r )
100 {
101 	return m_main_to_sound_ready;
102 }
103 
104 
READ_LINE_MEMBER(btoads_state::sound_to_main_r)105 READ_LINE_MEMBER( btoads_state::sound_to_main_r )
106 {
107 	return m_sound_to_main_ready;
108 }
109 
110 
111 
112 /*************************************
113  *
114  *  Sound -> main CPU communication
115  *
116  *************************************/
117 
sound_data_w(uint8_t data)118 void btoads_state::sound_data_w(uint8_t data)
119 {
120 	m_sound_to_main_data = data;
121 	m_sound_to_main_ready = 1;
122 }
123 
124 
sound_data_r()125 uint8_t btoads_state::sound_data_r()
126 {
127 	m_main_to_sound_ready = 0;
128 	return m_main_to_sound_data;
129 }
130 
131 
sound_ready_to_send_r()132 uint8_t btoads_state::sound_ready_to_send_r()
133 {
134 	return m_sound_to_main_ready ? 0x00 : 0x80;
135 }
136 
137 
sound_data_ready_r()138 uint8_t btoads_state::sound_data_ready_r()
139 {
140 	if (m_audiocpu->pc() == 0xd50 && !m_main_to_sound_ready)
141 		m_audiocpu->spin_until_interrupt();
142 	return m_main_to_sound_ready ? 0x00 : 0x80;
143 }
144 
145 
146 
147 /*************************************
148  *
149  *  Sound CPU interrupt generation
150  *
151  *************************************/
152 
sound_int_state_w(uint8_t data)153 void btoads_state::sound_int_state_w(uint8_t data)
154 {
155 	/* top bit controls BSMT2000 reset */
156 	if (!(m_sound_int_state & 0x80) && (data & 0x80))
157 		m_bsmt->reset();
158 
159 	/* also clears interrupts */
160 	m_audiocpu->set_input_line(0, CLEAR_LINE);
161 	m_sound_int_state = data;
162 }
163 
164 
165 
166 /*************************************
167  *
168  *  Sound CPU BSMT2000 communication
169  *
170  *************************************/
171 
bsmt_ready_r()172 uint8_t btoads_state::bsmt_ready_r()
173 {
174 	return m_bsmt->read_status() << 7;
175 }
176 
177 
bsmt2000_port_w(offs_t offset,uint8_t data)178 void btoads_state::bsmt2000_port_w(offs_t offset, uint8_t data)
179 {
180 	m_bsmt->write_reg(offset >> 8);
181 	m_bsmt->write_data(((offset & 0xff) << 8) | data);
182 }
183 
184 
185 
186 /*************************************
187  *
188  *  Main CPU memory map
189  *
190  *************************************/
191 
main_map(address_map & map)192 void btoads_state::main_map(address_map &map)
193 {
194 	map(0x00000000, 0x003fffff).ram();
195 	map(0x20000000, 0x2000007f).portr("P1");
196 	map(0x20000080, 0x200000ff).portr("P2");
197 	map(0x20000100, 0x2000017f).portr("P3");
198 	map(0x20000180, 0x200001ff).portr("UNK");
199 	map(0x20000200, 0x2000027f).portr("SPECIAL");
200 	map(0x20000280, 0x200002ff).portr("SW1");
201 	map(0x20000000, 0x200000ff).writeonly().share("sprite_scale");
202 	map(0x20000100, 0x2000017f).writeonly().share("sprite_control");
203 	map(0x20000180, 0x200001ff).w(FUNC(btoads_state::display_control_w));
204 	map(0x20000200, 0x2000027f).w(FUNC(btoads_state::scroll0_w));
205 	map(0x20000280, 0x200002ff).w(FUNC(btoads_state::scroll1_w));
206 	map(0x20000300, 0x2000037f).rw(m_tlc34076, FUNC(tlc34076_device::read), FUNC(tlc34076_device::write)).umask32(0x000000ff);
207 	map(0x20000380, 0x200003ff).rw(FUNC(btoads_state::main_sound_r), FUNC(btoads_state::main_sound_w));
208 	map(0x20000400, 0x2000047f).w(FUNC(btoads_state::misc_control_w));
209 	map(0x40000000, 0x4000001f).nopw();    /* watchdog? */
210 	map(0x60000000, 0x6003ffff).rw(FUNC(btoads_state::nvram_r), FUNC(btoads_state::nvram_w)).umask32(0x000000ff);
211 	map(0xa0000000, 0xa03fffff).rw(FUNC(btoads_state::vram_fg_display_r), FUNC(btoads_state::vram_fg_display_w)).share("vram_fg0");
212 	map(0xa4000000, 0xa43fffff).rw(FUNC(btoads_state::vram_fg_draw_r), FUNC(btoads_state::vram_fg_draw_w)).share("vram_fg1");
213 	map(0xa8000000, 0xa87fffff).ram().share("vram_fg_data");
214 	map(0xa8800000, 0xa8ffffff).nopw();
215 	map(0xb0000000, 0xb03fffff).rw(FUNC(btoads_state::vram_bg0_r), FUNC(btoads_state::vram_bg0_w)).share("vram_bg0");
216 	map(0xb4000000, 0xb43fffff).rw(FUNC(btoads_state::vram_bg1_r), FUNC(btoads_state::vram_bg1_w)).share("vram_bg1");
217 	map(0xfc000000, 0xffffffff).rom().region("user1", 0);
218 }
219 
220 
221 
222 /*************************************
223  *
224  *  Sound CPU memory map
225  *
226  *************************************/
227 
sound_map(address_map & map)228 void btoads_state::sound_map(address_map &map)
229 {
230 	map(0x0000, 0x7fff).rom();
231 	map(0x8000, 0xffff).ram();
232 }
233 
sound_io_map(address_map & map)234 void btoads_state::sound_io_map(address_map &map)
235 {
236 	map(0x0000, 0x7fff).w(FUNC(btoads_state::bsmt2000_port_w));
237 	map(0x8000, 0x8000).rw(FUNC(btoads_state::sound_data_r), FUNC(btoads_state::sound_data_w));
238 	map(0x8002, 0x8002).w(FUNC(btoads_state::sound_int_state_w));
239 	map(0x8004, 0x8004).r(FUNC(btoads_state::sound_data_ready_r));
240 	map(0x8005, 0x8005).r(FUNC(btoads_state::sound_ready_to_send_r));
241 	map(0x8006, 0x8006).r(FUNC(btoads_state::bsmt_ready_r));
242 }
243 
244 
245 
246 /*************************************
247  *
248  *  Input ports
249  *
250  *************************************/
251 
252 static INPUT_PORTS_START( btoads )
253 	PORT_START("P1")
254 	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
255 	PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
256 	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
257 	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
258 	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
259 	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
260 	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(2)
261 	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_START1 )
262 	PORT_BIT( 0xffffff00, IP_ACTIVE_LOW, IPT_UNUSED )
263 
264 	PORT_START("P2")
265 	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
266 	PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
267 	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
268 	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
269 	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
270 	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
271 	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_COIN2 ) PORT_IMPULSE(2)
272 	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_START2 )
273 	PORT_BIT( 0xffffff00, IP_ACTIVE_LOW, IPT_UNUSED )
274 
275 	PORT_START("P3")
276 	PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(3)
277 	PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(3)
278 	PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(3)
279 	PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(3)
280 	PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(3)
281 	PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(3)
282 	PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_COIN3 ) PORT_IMPULSE(2)
283 	PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_START3 )
284 	PORT_BIT( 0xffffff00, IP_ACTIVE_LOW, IPT_UNUSED )
285 
286 	PORT_START("UNK")
287 	PORT_BIT( 0xffffffff, IP_ACTIVE_LOW, IPT_UNKNOWN )
288 
289 	PORT_START("SPECIAL")
PORT_READ_LINE_MEMBER(btoads_state,sound_to_main_r)290 	PORT_BIT( 0x00000001, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(btoads_state, sound_to_main_r)
291 	PORT_SERVICE_NO_TOGGLE( 0x0002, IP_ACTIVE_LOW )
292 	PORT_BIT( 0x00000080, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(btoads_state, main_to_sound_r)
293 	PORT_BIT( 0xffffff7c, IP_ACTIVE_LOW, IPT_UNKNOWN )
294 
295 	PORT_START("SW1")
296 	PORT_DIPNAME( 0x0001, 0x0000, DEF_STR( Demo_Sounds )) PORT_DIPLOCATION("SW1:1")
297 	PORT_DIPSETTING(      0x0001, DEF_STR( Off ))
298 	PORT_DIPSETTING(      0x0000, DEF_STR( On ))
299 	PORT_DIPNAME( 0x0002, 0x0000, DEF_STR( Stereo ))      PORT_DIPLOCATION("SW1:2")
300 	PORT_DIPSETTING(      0x0002, DEF_STR( Off ))
301 	PORT_DIPSETTING(      0x0000, DEF_STR( On ))
302 	PORT_DIPNAME( 0x0004, 0x0000, "Common Coin Mech")     PORT_DIPLOCATION("SW1:3")
303 	PORT_DIPSETTING(      0x0004, DEF_STR( Off ))
304 	PORT_DIPSETTING(      0x0000, DEF_STR( On ))
305 	PORT_DIPNAME( 0x0008, 0x0008, "Three Players")        PORT_DIPLOCATION("SW1:4")
306 	PORT_DIPSETTING(      0x0008, DEF_STR( Off ))
307 	PORT_DIPSETTING(      0x0000, DEF_STR( On ))
308 	PORT_DIPNAME( 0x0010, 0x0010, DEF_STR( Free_Play ))   PORT_DIPLOCATION("SW1:5")
309 	PORT_DIPSETTING(      0x0010, DEF_STR( Off ))
310 	PORT_DIPSETTING(      0x0000, DEF_STR( On ))
311 	PORT_DIPNAME( 0x0020, 0x0020, "Blood Free Mode")      PORT_DIPLOCATION("SW1:6")
312 	PORT_DIPSETTING(      0x0020, DEF_STR( Off ))
313 	PORT_DIPSETTING(      0x0000, DEF_STR( On ))
314 	PORT_DIPNAME( 0x0040, 0x0040, "Credit Retention")     PORT_DIPLOCATION("SW1:7")
315 	PORT_DIPSETTING(      0x0040, DEF_STR( Off ))
316 	PORT_DIPSETTING(      0x0000, DEF_STR( On ))
317 	PORT_DIPUNKNOWN_DIPLOC(0x0080, 0x0080, "SW1:8")
318 	PORT_BIT( 0xffffff00, IP_ACTIVE_LOW, IPT_UNUSED )
319 INPUT_PORTS_END
320 
321 
322 /*************************************
323  *
324  *  Machine drivers
325  *
326  *************************************/
327 
328 void btoads_state::btoads(machine_config &config)
329 {
330 	TMS34020(config, m_maincpu, CPU_CLOCK/2);
331 	m_maincpu->set_addrmap(AS_PROGRAM, &btoads_state::main_map);
332 	m_maincpu->set_halt_on_reset(false);
333 	m_maincpu->set_pixel_clock(VIDEO_CLOCK/2);
334 	m_maincpu->set_pixels_per_clock(1);
335 	m_maincpu->set_scanline_rgb32_callback(FUNC(btoads_state::scanline_update));
336 	m_maincpu->set_shiftreg_in_callback(FUNC(btoads_state::to_shiftreg));
337 	m_maincpu->set_shiftreg_out_callback(FUNC(btoads_state::from_shiftreg));
338 
339 	Z80(config, m_audiocpu, SOUND_CLOCK/4);
340 	m_audiocpu->set_addrmap(AS_PROGRAM, &btoads_state::sound_map);
341 	m_audiocpu->set_addrmap(AS_IO, &btoads_state::sound_io_map);
342 	m_audiocpu->set_periodic_int(FUNC(btoads_state::irq0_line_assert), attotime::from_hz(SOUND_CLOCK/4/32768));
343 
344 	NVRAM(config, "nvram", nvram_device::DEFAULT_ALL_1);
345 
346 	/* video hardware */
347 	TLC34076(config, m_tlc34076, tlc34076_device::TLC34076_6_BIT);
348 
349 	SCREEN(config, m_screen, SCREEN_TYPE_RASTER);
350 	m_screen->set_raw(VIDEO_CLOCK/2, 640, 0, 512, 257, 0, 224);
351 	m_screen->set_screen_update("maincpu", FUNC(tms34020_device::tms340x0_rgb32));
352 
353 	/* sound hardware */
354 	SPEAKER(config, "lspeaker").front_left();
355 	SPEAKER(config, "rspeaker").front_right();
356 
357 	BSMT2000(config, m_bsmt, SOUND_CLOCK);
358 	m_bsmt->add_route(0, "lspeaker", 1.0);
359 	m_bsmt->add_route(1, "rspeaker", 1.0);
360 }
361 
362 
363 
364 /*************************************
365  *
366  *  ROM definitions
367  *
368  *************************************/
369 
370 ROM_START( btoads )
371 	ROM_REGION( 0x10000, "audiocpu", 0 )    /* sound program, M27C256B rom */
372 	ROM_LOAD( "bt.u102", 0x0000, 0x8000, CRC(a90b911a) SHA1(6ec25161e68df1c9870d48cc2b1f85cd1a49aba9) )
373 
374 	ROM_REGION32_LE( 0x800000, "user1", 0 ) /* 34020 code, M27C322 roms */
375 	ROM_LOAD32_WORD( "btc0-p0.u120", 0x000000, 0x400000, CRC(0dfd1e35) SHA1(733a0a4235bebd598c600f187ed2628f28cf9bd0) )
376 	ROM_LOAD32_WORD( "btc0-p1.u121", 0x000002, 0x400000, CRC(df7487e1) SHA1(67151b900767bb2653b5261a98c81ff8827222c3) )
377 
378 	ROM_REGION( 0x1000000, "bsmt", 0 )  /* BSMT data, M27C160 rom */
379 	ROM_LOAD( "btc0-s.u109", 0x00000, 0x200000, CRC(d9612ddb) SHA1(f186dfb013e81abf81ba8ac5dc7eb731c1ad82b6) )
380 
381 	ROM_REGION( 0x080a, "plds", 0 )
382 	ROM_LOAD( "u10.bin",  0x0000, 0x0157, CRC(b1144178) SHA1(15fb047adee4125e9fcf04171e0a502655e0a3d8) ) /* GAL20V8A-15LP Located at U10. */
383 	ROM_LOAD( "u11.bin",  0x0000, 0x0157, CRC(7c6beb96) SHA1(2f19d21889dd765b344ad7d257ea7c244baebec2) ) /* GAL20V8A-15LP Located at U11. */
384 	ROM_LOAD( "u57.bin",  0x0000, 0x0157, CRC(be355a56) SHA1(975238bb1ea8fef14458d6f264a82aa77ecf865d) ) /* GAL20V8A-15LP Located at U57. */
385 	ROM_LOAD( "u58.bin",  0x0000, 0x0157, CRC(41ed339c) SHA1(5853c805a902e6d12c979958d878d1cefd6908cc) ) /* GAL20V8A-15LP Located at U58. */
386 	ROM_LOAD( "u90.bin",  0x0000, 0x0157, CRC(a0d0c3f1) SHA1(47464c2ef9fadbba933df27767f377e0c29158aa) ) /* GAL20V8A-15LP Located at U90. */
387 	ROM_LOAD( "u144.bin", 0x0000, 0x0157, CRC(8597017f) SHA1(003d7b5de57e48f831ab211e2783fff338ce2f32) ) /* GAL20V8A-15LP Located at U144. */
388 ROM_END
389 
390 
391 
392 /*************************************
393  *
394  *  Game drivers
395  *
396  *************************************/
397 
398 GAME( 1994, btoads, 0, btoads, btoads, btoads_state, empty_init, ROT0, "Rare / Electronic Arts", "Battletoads", MACHINE_SUPPORTS_SAVE )
399