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