1 // license:LGPL-2.1+
2 // copyright-holders:David Haywood, Angelo Salese, ElSemi, Andrew Gardner
3 /* Hyper NeoGeo 64 Audio */
4 
5 // uses a V53A ( == V33A with extra peripherals eg. DMA, Timers, MMU giving virtual 24-bit address space etc.)
6 
7 /* The uploaded code shows that several different sound program revisions were used
8 
9 sams64    (#)SNK R&D Center (R) NEO-GEO64 Sound Driver Ver 1.00a.     (#)Copyright (C) SNK Corp. 1996-1997 All rights reserved
10 roadedge  (#)SNK R&D Center (R) NEO-GEO64 Sound Driver Ver 1.10.      (#)Copyright (C) SNK Corp. 1996-1997 All rights reserved
11 xrally    (#)SNK R&D Center (R) HYPER NEOGEO64 Sound Driver Ver 1.10. (#)Copyright (C) SNK Corp. 1997,1998 All rights reserved
12 bbust2    (#)SNK R&D Center (R) HYPER NEOGEO64 Sound Driver Ver 1.11. (#)Copyright (C) SNK Corp. 1997,1998 All rights reserved
13 sams64_2  (#)SNK R&D Center (R) HYPER NEOGEO64 Sound Driver Ver 1.14. (#)Copyright (C) SNK Corp. 1997,1998 All rights reserved
14 fatfurwa  (#)SNK R&D Center (R) HYPER NEOGEO64 Sound Driver Ver 1.14. (#)Copyright (C) SNK Corp. 1997,1998 All rights reserved
15 buriki    (#)SNK R&D Center (R) HYPER NEOGEO64 Sound Driver Ver 1.15. (#)Copyright (C) SNK Corp. 1997,1998 All rights reserved
16 
17 The earlier revisions appear to have 2 banks of code (there are vectors at the end of the 0x1e0000 block and the 0x1f0000 block)
18 
19 If the banking setup is wrong then those first two revisions also spam the entire range of I/O ports with values several times
20 on startup causing some unexpected writes to the V53 internal registers.
21 
22 data structures look very similar between all of them
23 
24 IRQ mask register on the internal interrupt controller is set to 0xd8
25 
26 so levels 0,1,2,5 are unmasked, vectors get set during the sound CPU init code.
27 
28  level 0/1 irq (fatfurwa) starts at 0xd277 (both the same vector)
29  serial comms related, maybe to get commands from main CPU if not done with shared ram?
30 
31  level 2 irq (fatfurwa) 0xdd20
32  simple routine increases counter in RAM, maybe hooked to one / all of the timer irqs
33 
34  level 5 irq: (fatfurwa) starts at 0xc1e1
35  largest irq, does things with ports 100 / 102 / 104 / 106, 10a  (not 108 directly tho)
36 
37  no other irqs (or the NMI) are valid.
38 
39 */
40 
41 
42 #include "emu.h"
43 #include "includes/hng64.h"
44 #include "speaker.h"
45 
46 
47 // save the sound program?
48 #define DUMP_SOUNDPRG  0
49 
50 // ----------------------------------------------
51 // MIPS side
52 // ----------------------------------------------
53 
54 // if you actually map RAM here on the MIPS side then xrally will upload the actual sound program here and blank out the area where
55 // the program would usually be uploaded (and where all other games upload it) this seems to suggest that the area is unmapped on
56 // real hardware.
hng64_soundram2_w(uint32_t data)57 void hng64_state::hng64_soundram2_w(uint32_t data)
58 {
59 }
60 
hng64_soundram2_r()61 uint32_t hng64_state::hng64_soundram2_r()
62 {
63 	return 0x0000;
64 }
65 
66 
hng64_soundram_w(offs_t offset,uint32_t data,uint32_t mem_mask)67 void hng64_state::hng64_soundram_w(offs_t offset, uint32_t data, uint32_t mem_mask)
68 {
69 	//logerror("hng64_soundram_w %08x: %08x %08x\n", offset, data, mem_mask);
70 
71 	uint32_t mem_mask32 = mem_mask;
72 	uint32_t data32 = data;
73 
74 	/* swap data around.. keep the v53 happy */
75 	data = data32 >> 16;
76 	data = swapendian_int16(data);
77 	mem_mask = mem_mask32 >> 16;
78 	mem_mask = swapendian_int16(mem_mask);
79 	COMBINE_DATA(&m_soundram[offset * 2 + 0]);
80 
81 	data = data32 & 0xffff;
82 	data = swapendian_int16(data);
83 	mem_mask = mem_mask32 & 0xffff;
84 	mem_mask = swapendian_int16(mem_mask);
85 	COMBINE_DATA(&m_soundram[offset * 2 + 1]);
86 
87 	if (DUMP_SOUNDPRG)
88 	{
89 		if (offset==0x7ffff)
90 		{
91 			logerror("dumping sound program in m_soundram\n");
92 			FILE *fp;
93 			char filename[256];
94 			sprintf(filename,"soundram_%s", machine().system().name);
95 			fp=fopen(filename, "w+b");
96 			if (fp)
97 			{
98 				fwrite((uint8_t*)m_soundram.get(), 0x80000*4, 1, fp);
99 				fclose(fp);
100 			}
101 		}
102 	}
103 }
104 
105 
hng64_soundram_r(offs_t offset)106 uint32_t hng64_state::hng64_soundram_r(offs_t offset)
107 {
108 	uint16_t datalo = m_soundram[offset * 2 + 0];
109 	uint16_t datahi = m_soundram[offset * 2 + 1];
110 
111 	return swapendian_int16(datahi) | (swapendian_int16(datalo) << 16);
112 }
113 
hng64_soundcpu_enable_w(offs_t offset,uint32_t data,uint32_t mem_mask)114 void hng64_state::hng64_soundcpu_enable_w(offs_t offset, uint32_t data, uint32_t mem_mask)
115 {
116 	if (ACCESSING_BITS_16_31)
117 	{
118 		int cmd = data >> 16;
119 		// I guess it's only one of the bits, the commands are inverse of each other
120 		if (cmd==0x55AA)
121 		{
122 			logerror("soundcpu ON\n");
123 			m_audiocpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
124 			m_audiocpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
125 		}
126 		else if (cmd==0xAA55)
127 		{
128 			logerror("soundcpu OFF\n");
129 			m_audiocpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
130 			m_audiocpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
131 		}
132 		else
133 		{
134 			logerror("unknown hng64_soundcpu_enable_w cmd %04x\n", cmd);
135 		}
136 	}
137 
138 	if (ACCESSING_BITS_0_15)
139 	{
140 		logerror("unknown hng64_soundcpu_enable_w %08x %08x\n", data, mem_mask);
141 	}
142 }
143 
144 // ----------------------------------------------
145 // General
146 // ----------------------------------------------
147 
148 
reset_sound()149 void hng64_state::reset_sound()
150 {
151 	uint8_t *RAM = (uint8_t*)m_soundram.get();
152 	membank("bank0")->set_base(&RAM[0x1f0000]);
153 	membank("bank1")->set_base(&RAM[0x1f0000]);
154 	membank("bank2")->set_base(&RAM[0x1f0000]);
155 	membank("bank3")->set_base(&RAM[0x1f0000]);
156 	membank("bank4")->set_base(&RAM[0x1f0000]);
157 	membank("bank5")->set_base(&RAM[0x1f0000]);
158 	membank("bank6")->set_base(&RAM[0x1f0000]);
159 	membank("bank7")->set_base(&RAM[0x1f0000]);
160 	membank("bank8")->set_base(&RAM[0x1f0000]);
161 	membank("bank9")->set_base(&RAM[0x1f0000]);
162 	membank("banka")->set_base(&RAM[0x1f0000]);
163 	membank("bankb")->set_base(&RAM[0x1f0000]);
164 	membank("bankc")->set_base(&RAM[0x1f0000]);
165 	membank("bankd")->set_base(&RAM[0x1f0000]);
166 	membank("banke")->set_base(&RAM[0x1f0000]);
167 	membank("bankf")->set_base(&RAM[0x1f0000]);
168 
169 	m_audiocpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
170 	m_audiocpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
171 }
172 
173 // ----------------------------------------------
174 // V53A side
175 // ----------------------------------------------
176 
177 
hng_sound_map(address_map & map)178 void hng64_state::hng_sound_map(address_map &map)
179 {
180 	map(0x00000, 0x0ffff).bankrw("bank0");
181 	map(0x10000, 0x1ffff).bankrw("bank1");
182 	map(0x20000, 0x2ffff).bankrw("bank2");
183 	map(0x30000, 0x3ffff).bankrw("bank3");
184 	map(0x40000, 0x4ffff).bankrw("bank4");
185 	map(0x50000, 0x5ffff).bankrw("bank5");
186 	map(0x60000, 0x6ffff).bankrw("bank6");
187 	map(0x70000, 0x7ffff).bankrw("bank7");
188 	map(0x80000, 0x8ffff).bankrw("bank8");
189 	map(0x90000, 0x9ffff).bankrw("bank9");
190 	map(0xa0000, 0xaffff).bankrw("banka");
191 	map(0xb0000, 0xbffff).bankrw("bankb");
192 	map(0xc0000, 0xcffff).bankrw("bankc");
193 	map(0xd0000, 0xdffff).bankrw("bankd");
194 	map(0xe0000, 0xeffff).bankrw("banke");
195 	map(0xf0000, 0xfffff).bankrw("bankf");
196 }
197 
hng64_sound_port_0008_w(offs_t offset,uint16_t data,uint16_t mem_mask)198 void hng64_state::hng64_sound_port_0008_w(offs_t offset, uint16_t data, uint16_t mem_mask)
199 {
200 //  logerror("hng64_sound_port_0008_w %04x %04x\n", data, mem_mask);
201 	// seems to one or more of the DMARQ on the V53, writes here when it expects DMA channel 3 to transfer ~0x20 bytes just after startup
202 
203 	/* TODO: huh? */
204 	m_audiocpu->dreq_w<3>(data&0x1);
205 	m_dsp->l7a1045_sound_w(8/2,data,mem_mask);
206 //  m_audiocpu->hack_w(1);
207 
208 }
209 
210 
hng64_sound_port_0008_r(offs_t offset,uint16_t mem_mask)211 uint16_t hng64_state::hng64_sound_port_0008_r(offs_t offset, uint16_t mem_mask)
212 {
213 	// read in irq5
214 	//logerror("%s: hng64_sound_port_0008_r mask (%04x)\n", machine().describe_context(), mem_mask);
215 	return 0;
216 }
217 
218 
219 
220 // but why not just use the V33/V53 XA mode??
hng64_sound_bank_w(offs_t offset,uint16_t data)221 void hng64_state::hng64_sound_bank_w(offs_t offset, uint16_t data)
222 {
223 	logerror("%s hng64_sound_bank_w? %02x %04x\n", machine().describe_context(), offset, data);
224 	// buriki writes 0x3f to 0x200 before jumping to the low addresses..
225 	// where it expects to find data from 0x1f0000
226 
227 	// the 2 early games don't do this.. maybe all banks actuallly default to that region tho?
228 	// the sound code on those games seems buggier anyway.
229 	uint8_t *RAM = (uint8_t*)m_soundram.get();
230 
231 	int bank = data & 0x1f;
232 
233 	if (offset == 0x0) membank("bank0")->set_base(&RAM[bank*0x10000]);
234 	if (offset == 0x1) membank("bank1")->set_base(&RAM[bank*0x10000]);
235 	if (offset == 0x2) membank("bank2")->set_base(&RAM[bank*0x10000]);
236 	if (offset == 0x3) membank("bank3")->set_base(&RAM[bank*0x10000]);
237 	if (offset == 0x4) membank("bank4")->set_base(&RAM[bank*0x10000]);
238 	if (offset == 0x5) membank("bank5")->set_base(&RAM[bank*0x10000]);
239 	if (offset == 0x6) membank("bank6")->set_base(&RAM[bank*0x10000]);
240 	if (offset == 0x7) membank("bank7")->set_base(&RAM[bank*0x10000]);
241 	if (offset == 0x8) membank("bank8")->set_base(&RAM[bank*0x10000]);
242 	if (offset == 0x9) membank("bank9")->set_base(&RAM[bank*0x10000]);
243 	if (offset == 0xa) membank("banka")->set_base(&RAM[bank*0x10000]);
244 	if (offset == 0xb) membank("bankb")->set_base(&RAM[bank*0x10000]);
245 	if (offset == 0xc) membank("bankc")->set_base(&RAM[bank*0x10000]);
246 	if (offset == 0xd) membank("bankd")->set_base(&RAM[bank*0x10000]);
247 	if (offset == 0xe) membank("banke")->set_base(&RAM[bank*0x10000]);
248 	if (offset == 0xf) membank("bankf")->set_base(&RAM[bank*0x10000]);
249 
250 }
251 
252 
hng64_sound_port_000a_w(offs_t offset,uint16_t data,uint16_t mem_mask)253 void hng64_state::hng64_sound_port_000a_w(offs_t offset, uint16_t data, uint16_t mem_mask)
254 {
255 	logerror("%s: hng64_port hng64_sound_port_000a_w %04x mask (%04x)\n", machine().describe_context(), data, mem_mask);
256 }
257 
hng64_sound_port_000c_w(offs_t offset,uint16_t data,uint16_t mem_mask)258 void hng64_state::hng64_sound_port_000c_w(offs_t offset, uint16_t data, uint16_t mem_mask)
259 {
260 	logerror("%s: hng64_port hng64_sound_port_000c_w %04x mask (%04x)\n", machine().describe_context(), data, mem_mask);
261 }
262 
263 
hng64_sound_port_0080_w(uint16_t data)264 void hng64_state::hng64_sound_port_0080_w(uint16_t data)
265 {
266 	logerror("%s: hng64_port 0x0080 %04x\n", machine().describe_context(), data);
267 }
268 
269 
sound_comms_w(offs_t offset,uint16_t data,uint16_t mem_mask)270 void hng64_state::sound_comms_w(offs_t offset, uint16_t data, uint16_t mem_mask)
271 {
272 	switch(offset*2)
273 	{
274 		case 0x0:
275 			COMBINE_DATA(&sound_latch[0]);
276 			return;
277 		case 0x2:
278 			COMBINE_DATA(&sound_latch[1]);
279 			return;
280 		case 0xa:
281 			/* correct? */
282 			m_audiocpu->set_input_line(5, CLEAR_LINE);
283 			//if(data)
284 			//  printf("IRQ ACK %02x?\n",data);
285 			return;
286 	}
287 
288 	//printf("SOUND W %02x %04x\n",offset*2,data);
289 }
290 
sound_comms_r(offs_t offset)291 uint16_t hng64_state::sound_comms_r(offs_t offset)
292 {
293 	switch(offset*2)
294 	{
295 		case 0x04:
296 			return main_latch[0];
297 		case 0x06:
298 			return main_latch[1];
299 	}
300 	//printf("SOUND R %02x\n",offset*2);
301 
302 	return 0;
303 }
304 
hng_sound_io(address_map & map)305 void hng64_state::hng_sound_io(address_map &map)
306 {
307 	map(0x0000, 0x0007).rw(m_dsp, FUNC(l7a1045_sound_device::l7a1045_sound_r), FUNC(l7a1045_sound_device::l7a1045_sound_w));
308 
309 	map(0x0008, 0x0009).rw(FUNC(hng64_state::hng64_sound_port_0008_r), FUNC(hng64_state::hng64_sound_port_0008_w));
310 	map(0x000a, 0x000b).w(FUNC(hng64_state::hng64_sound_port_000a_w));
311 	map(0x000c, 0x000d).w(FUNC(hng64_state::hng64_sound_port_000c_w));
312 
313 	map(0x0080, 0x0081).w(FUNC(hng64_state::hng64_sound_port_0080_w));
314 
315 	map(0x0100, 0x010f).rw(FUNC(hng64_state::sound_comms_r), FUNC(hng64_state::sound_comms_w));
316 
317 	map(0x0200, 0x021f).w(FUNC(hng64_state::hng64_sound_bank_w)); // ??
318 
319 }
320 
WRITE_LINE_MEMBER(hng64_state::dma_hreq_cb)321 WRITE_LINE_MEMBER(hng64_state::dma_hreq_cb)
322 {
323 	m_audiocpu->hack_w(1);
324 }
325 
dma_memr_cb(offs_t offset)326 uint8_t hng64_state::dma_memr_cb(offs_t offset)
327 {
328 	return m_audiocpu->space(AS_PROGRAM).read_byte(offset);
329 }
330 
dma_iow3_cb(uint8_t data)331 void hng64_state::dma_iow3_cb(uint8_t data)
332 {
333 	// currently it reads a block of 0x20 '0x00' values from a very specific block of RAM where there is a 0x20 space in the data and transfers them repeatedly, I assume
334 	// this is some kind of buffer for the audio or DSP and eventually will be populated with other values...
335 	// if this comes to life maybe something interesting is happening!
336 
337 	if (data!=0x00) logerror("dma_iow3_cb %02x\n", data);
338 }
339 
WRITE_LINE_MEMBER(hng64_state::tcu_tm0_cb)340 WRITE_LINE_MEMBER(hng64_state::tcu_tm0_cb)
341 {
342 	// this goes high once near startup
343 	logerror("tcu_tm0_cb %02x\n", state);
344 }
345 
WRITE_LINE_MEMBER(hng64_state::tcu_tm1_cb)346 WRITE_LINE_MEMBER(hng64_state::tcu_tm1_cb)
347 {
348 	// these are very active, maybe they feed back into the v53 via one of the IRQ pins?  TM2 toggles more rapidly than TM1
349 //  logerror("tcu_tm1_cb %02x\n", state);
350 	//m_audiocpu->set_input_line(5, state? ASSERT_LINE:CLEAR_LINE); // not accurate, just so we have a trigger
351 	/* Almost likely wrong */
352 	m_audiocpu->set_input_line(2, state? ASSERT_LINE :CLEAR_LINE);
353 
354 }
355 
WRITE_LINE_MEMBER(hng64_state::tcu_tm2_cb)356 WRITE_LINE_MEMBER(hng64_state::tcu_tm2_cb)
357 {
358 	// these are very active, maybe they feed back into the v53 via one of the IRQ pins?  TM2 toggles more rapidly than TM1
359 //  logerror("tcu_tm2_cb %02x\n", state);
360 	//m_audiocpu->set_input_line(1, state? ASSERT_LINE :CLEAR_LINE);
361 	//m_audiocpu->set_input_line(2, state? ASSERT_LINE :CLEAR_LINE);
362 
363 
364 	// NOT ACCURATE, just so that all the interrupts get triggered for now.
365 	#if 0
366 	static int i;
367 	if(machine().input().code_pressed_once(KEYCODE_Z))
368 		i++;
369 
370 	if(machine().input().code_pressed_once(KEYCODE_X))
371 		i--;
372 
373 	if(i < 0)
374 		i = 0;
375 	if(i > 7)
376 		i = 7;
377 
378 	//printf("trigger %02x %d\n",i,state);
379 
380 	//if(machine().input().code_pressed_once(KEYCODE_C))
381 	{
382 		m_audiocpu->set_input_line(i, state? ASSERT_LINE :CLEAR_LINE);
383 	}
384 	//i++;
385 	//if (i == 3) i = 0;
386 	#endif
387 }
388 
389 
390 
hng64_audio(machine_config & config)391 void hng64_state::hng64_audio(machine_config &config)
392 {
393 	V53A(config, m_audiocpu, 32000000/2);              // V53A, 16? mhz!
394 	m_audiocpu->set_addrmap(AS_PROGRAM, &hng64_state::hng_sound_map);
395 	m_audiocpu->set_addrmap(AS_IO, &hng64_state::hng_sound_io);
396 	m_audiocpu->out_hreq_cb().set(FUNC(hng64_state::dma_hreq_cb));
397 	m_audiocpu->in_memr_cb().set(FUNC(hng64_state::dma_memr_cb));
398 	m_audiocpu->out_iow_cb<3>().set(FUNC(hng64_state::dma_iow3_cb));
399 
400 	m_audiocpu->out_handler<0>().set(FUNC(hng64_state::tcu_tm0_cb));
401 	m_audiocpu->out_handler<1>().set(FUNC(hng64_state::tcu_tm1_cb));
402 	m_audiocpu->out_handler<2>().set(FUNC(hng64_state::tcu_tm2_cb));
403 
404 	SPEAKER(config, "lspeaker").front_left();
405 	SPEAKER(config, "rspeaker").front_right();
406 
407 	L7A1045(config, m_dsp, 32000000/2); // ??
408 	m_dsp->add_route(0, "lspeaker", 1.0);
409 	m_dsp->add_route(1, "rspeaker", 1.0);
410 }
411