mame/src/mame/audio/hng64.c
2015-03-12 16:20:35 +00:00

277 lines
9.2 KiB
C

/* Hyper NeoGeo 64 Audio */
// uses a V53A ( == V33A with extra peripherals eg. DMA, Timers, MMU giving virtual 24-bit address space etc.)
/* The uploaded code shows that several different sound program revisions were used
sams64 (#)SNK R&D Center (R) NEO-GEO64 Sound Driver Ver 1.00a. (#)Copyright (C) SNK Corp. 1996-1997 All rights reserved
roadedge (#)SNK R&D Center (R) NEO-GEO64 Sound Driver Ver 1.10. (#)Copyright (C) SNK Corp. 1996-1997 All rights reserved
xrally (#)SNK R&D Center (R) HYPER NEOGEO64 Sound Driver Ver 1.10. (#)Copyright (C) SNK Corp. 1997,1998 All rights reserved
bbust2 (#)SNK R&D Center (R) HYPER NEOGEO64 Sound Driver Ver 1.11. (#)Copyright (C) SNK Corp. 1997,1998 All rights reserved
sams64_2 (#)SNK R&D Center (R) HYPER NEOGEO64 Sound Driver Ver 1.14. (#)Copyright (C) SNK Corp. 1997,1998 All rights reserved
fatfurwa (#)SNK R&D Center (R) HYPER NEOGEO64 Sound Driver Ver 1.14. (#)Copyright (C) SNK Corp. 1997,1998 All rights reserved
buriki (#)SNK R&D Center (R) HYPER NEOGEO64 Sound Driver Ver 1.15. (#)Copyright (C) SNK Corp. 1997,1998 All rights reserved
The earlier revisions appear to have 2 banks of code (there are vectors at the end of the 0x1e0000 block and the 0x1f0000 block)
Those first two revisions also spam the entire range of I/O ports with values several times on startup causing some unexpected
writes to the V53 internal registers. The important ones are reinitialized after this however, I'm guessing this is harmless
on real hardware, as the code flow seems to be correct.
data structures look very similar between all of them
*/
#include "includes/hng64.h"
// save the sound program?
#define DUMP_SOUNDPRG 0
// ----------------------------------------------
// MIPS side
// ----------------------------------------------
// 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
// the program would usually be uploaded (and where all other games upload it) this seems to suggest that the area is unmapped on
// real hardware.
WRITE32_MEMBER(hng64_state::hng64_soundram2_w)
{
}
READ32_MEMBER(hng64_state::hng64_soundram2_r)
{
return 0x0000;
}
WRITE32_MEMBER(hng64_state::hng64_soundram_w)
{
//logerror("hng64_soundram_w %08x: %08x %08x\n", offset, data, mem_mask);
UINT32 mem_mask32 = mem_mask;
UINT32 data32 = data;
/* swap data around.. keep the v55 happy */
data = data32 >> 16;
data = FLIPENDIAN_INT16(data);
mem_mask = mem_mask32 >> 16;
mem_mask = FLIPENDIAN_INT16(mem_mask);
COMBINE_DATA(&m_soundram[offset * 2 + 0]);
data = data32 & 0xffff;
data = FLIPENDIAN_INT16(data);
mem_mask = mem_mask32 & 0xffff;
mem_mask = FLIPENDIAN_INT16(mem_mask);
COMBINE_DATA(&m_soundram[offset * 2 + 1]);
if (DUMP_SOUNDPRG)
{
if (offset==0x7ffff)
{
logerror("dumping sound program in m_soundram\n");
FILE *fp;
char filename[256];
sprintf(filename,"soundram_%s", space.machine().system().name);
fp=fopen(filename, "w+b");
if (fp)
{
fwrite((UINT8*)m_soundram, 0x80000*4, 1, fp);
fclose(fp);
}
}
}
}
READ32_MEMBER(hng64_state::hng64_soundram_r)
{
UINT16 datalo = m_soundram[offset * 2 + 0];
UINT16 datahi = m_soundram[offset * 2 + 1];
return FLIPENDIAN_INT16(datahi) | (FLIPENDIAN_INT16(datalo) << 16);
}
WRITE32_MEMBER( hng64_state::hng64_soundcpu_enable_w )
{
if (mem_mask&0xffff0000)
{
int cmd = data >> 16;
// I guess it's only one of the bits, the commands are inverse of each other
if (cmd==0x55AA)
{
printf("soundcpu ON\n");
m_audiocpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
m_audiocpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
}
else if (cmd==0xAA55)
{
printf("soundcpu OFF\n");
m_audiocpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
m_audiocpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
}
else
{
printf("unknown hng64_soundcpu_enable_w cmd %04x\n", cmd);
}
}
if (mem_mask&0x0000ffff)
{
printf("unknown hng64_soundcpu_enable_w %08x %08x\n", data, mem_mask);
}
}
// ----------------------------------------------
// General
// ----------------------------------------------
void hng64_state::reset_sound()
{
UINT8 *RAM = (UINT8*)m_soundram;
membank("bank1")->set_base(&RAM[0x1f0000]); // allows us to boot
membank("bank2")->set_base(&RAM[0x1f0000]); // seems to be the right default for most games (initial area jumps to a DI here)
m_audiocpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
m_audiocpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
}
// ----------------------------------------------
// V53A side
// ----------------------------------------------
static ADDRESS_MAP_START( hng_sound_map, AS_PROGRAM, 16, hng64_state )
AM_RANGE(0x00000, 0x0ffff) AM_RAMBANK("bank2")
AM_RANGE(0x10000, 0x1ffff) AM_RAM // tmp, roadedge
AM_RANGE(0xf0000, 0xfffff) AM_RAMBANK("bank1")
ADDRESS_MAP_END
WRITE16_MEMBER(hng64_state::hng64_sound_port_0008_w)
{
// printf("hng64_sound_port_0008_w %04x %04x\n", data, mem_mask);
// 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
m_audiocpu->dreq3_w(data&1);
// m_audiocpu->hack_w(1);
}
WRITE16_MEMBER(hng64_state::hng64_sound_select_w)
{
// seems to write values in the format xxyy where yy is 0x00-0x1f and xx is oten 00/01/0a
// there are said to be 32 audio channels, so maybe the lower byte is the channel?
// printf("hng64_sound_select_w")
COMBINE_DATA(&m_audiochannel);
}
WRITE16_MEMBER(hng64_state::hng64_sound_data_02_w)
{
m_audiodat[m_audiochannel].dat[2] = data;
// printf("write port 0x0002 chansel %04x data %04x (%04x%04x%04x)\n", m_audiochannel, data, m_audiodat[m_audiochannel].dat[0], m_audiodat[m_audiochannel].dat[1], m_audiodat[m_audiochannel].dat[2]);
}
WRITE16_MEMBER(hng64_state::hng64_sound_data_04_w)
{
m_audiodat[m_audiochannel].dat[1] = data;
// printf("write port 0x0004 chansel %04x data %04x (%04x%04x%04x)\n", m_audiochannel, data, m_audiodat[m_audiochannel].dat[0], m_audiodat[m_audiochannel].dat[1], m_audiodat[m_audiochannel].dat[2]);
}
WRITE16_MEMBER(hng64_state::hng64_sound_data_06_w)
{
m_audiodat[m_audiochannel].dat[0] = data;
// printf("write port 0x0006 chansel %04x data %04x (%04x%04x%04x)\n", m_audiochannel, data, m_audiodat[m_audiochannel].dat[0], m_audiodat[m_audiochannel].dat[1], m_audiodat[m_audiochannel].dat[2]);
}
// but why not just use the V33/V53 XA mode??
WRITE16_MEMBER(hng64_state::hng64_sound_bank_w)
{
printf("%08x hng64_sound_bank_w? %02x %04x\n", space.device().safe_pc(), offset, data);
// buriki writes 0x3f to 0x200 before jumping to the low addresses..
// where it expects to find data from 0x1f0000
// the 2 early games don't do this.. maybe all banks actuallly default to that region tho?
// the sound code on those games seems buggier anyway.
}
WRITE16_MEMBER(hng64_state::hng64_sound_port_0102_w)
{
printf("hng64_port 0x0102 %04x\n", data);
}
WRITE16_MEMBER(hng64_state::hng64_sound_port_0080_w)
{
printf("hng64_port 0x0080 %04x\n", data);
}
static ADDRESS_MAP_START( hng_sound_io, AS_IO, 16, hng64_state )
AM_RANGE(0x0000, 0x0001) AM_WRITE( hng64_sound_select_w )
AM_RANGE(0x0002, 0x0003) AM_WRITE( hng64_sound_data_02_w )
AM_RANGE(0x0004, 0x0005) AM_WRITE( hng64_sound_data_04_w )
AM_RANGE(0x0006, 0x0007) AM_WRITE( hng64_sound_data_06_w )
AM_RANGE(0x0008, 0x0009) AM_WRITE( hng64_sound_port_0008_w )
// a 8 c used too?
AM_RANGE(0x0080, 0x0081) AM_WRITE( hng64_sound_port_0080_w )
AM_RANGE(0x0102, 0x0103) AM_WRITE( hng64_sound_port_0102_w )
AM_RANGE(0x0200, 0x021f) AM_WRITE( hng64_sound_bank_w ) // ??
ADDRESS_MAP_END
WRITE_LINE_MEMBER(hng64_state::dma_hreq_cb)
{
m_audiocpu->hack_w(1);
}
READ8_MEMBER(hng64_state::dma_memr_cb)
{
return m_audiocpu->space(AS_PROGRAM).read_byte(offset);;
}
WRITE8_MEMBER(hng64_state::dma_iow3_cb)
{
// 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
// this is some kind of buffer for the audio or DSP and eventually will be populated with other values...
// if this comes to life maybe something interesting is happening!
if (data!=0x00) printf("dma_iow3_cb %02x\n", data);
}
WRITE_LINE_MEMBER(hng64_state::tcu_tm0_cb)
{
// this goes high once near startup
printf("tcu_tm0_cb %02x\n", state);
}
WRITE_LINE_MEMBER(hng64_state::tcu_tm1_cb)
{
// these are very active, maybe they feed back into the v53 via one of the IRQ pins? TM2 toggles more rapidly than TM1
// printf("tcu_tm1_cb %02x\n", state);
}
WRITE_LINE_MEMBER(hng64_state::tcu_tm2_cb)
{
// these are very active, maybe they feed back into the v53 via one of the IRQ pins? TM2 toggles more rapidly than TM1
// printf("tcu_tm2_cb %02x\n", state);
}
MACHINE_CONFIG_FRAGMENT( hng64_audio )
MCFG_CPU_ADD("audiocpu", V53A, 16000000) // V53A, 16? mhz!
MCFG_CPU_PROGRAM_MAP(hng_sound_map)
MCFG_CPU_IO_MAP(hng_sound_io)
MCFG_V53_DMAU_OUT_HREQ_CB(WRITELINE(hng64_state, dma_hreq_cb))
MCFG_V53_DMAU_IN_MEMR_CB(READ8(hng64_state, dma_memr_cb))
MCFG_V53_DMAU_OUT_IOW_3_CB(WRITE8(hng64_state,dma_iow3_cb))
MCFG_V53_TCU_OUT0_HANDLER(WRITELINE(hng64_state, tcu_tm0_cb))
MCFG_V53_TCU_OUT1_HANDLER(WRITELINE(hng64_state, tcu_tm1_cb))
MCFG_V53_TCU_OUT2_HANDLER(WRITELINE(hng64_state, tcu_tm2_cb))
MACHINE_CONFIG_END