ST-V sound: SCSP voices from current MAME, Batman Forever RAX board

SCSP (also used by Model 2):
- The slot engine from current MAME: key off goes to the release, the
  envelope tables and the dB curve of the decay, pitch, interpolation,
  the four loop modes, FM from the ring buffer, noise (SSCTL), SBCTL,
  LPSLNK, STWINH/SDIR; 8-bit samples read in big-endian byte order.
- The monitor register 0x408 returns CA, SGC and EG of the slot set in
  MSLC: the sound drivers look there for a free slot, and Winter Heat
  played every voice on slot 0, each one cutting the previous.
- Real timers for timers A, B and C, as in MAME: counting them with the
  generated samples delayed every interrupt until the next stream update.
- Interrupts as in MAME: each source raises its own level until it is
  acknowledged in SCIRE, and an acknowledged expired timer is pending
  again with no new interrupt. Reading MIBUF drops the MIDI interrupt:
  left raised, the sound CPU took it again on an empty FIFO and read
  stale bytes as MIDI data, which broke music commands in Model 2
  (Fighting Vipers, Dead or Alive, Manx TT).
- The DMA used the common registers 0x412 words past them, inside the
  slots: now as in MAME.
- The common registers are 0x400-0x42f only (0x500 is not a mirror),
  the ring buffer at 0x600 can be read and written, the LFO saw wave and
  rate as in MAME.
- ST-V: a 16-bit access of the SH-2 touches only its half of the SCSP
  registers.

Batman Forever: the Acclaim RAX sound board (ADSP-2181), moved from zn.c
to sndhrdw/acclaim_rax.c and shared by NBA Jam Extreme and Batman
Forever, which writes its commands to 0x04800000 as in MAME.

docs/sega-model2.md: the MIDI interrupt of the sound link.

Fixes #2194.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_013Vje3pEtpLHubqCGwCgoQX
This commit is contained in:
VanniandClaude Opus 5.5 committed 2026-11-02 18:47:50 +01:00
1 parent 4930bf5be7
commit 93b073496c
9 files changed
+1048 -912

No files matched your search

+1 -1
View File
@@ -499,7 +499,7 @@ SOURCES_C += \
$(CORE_DIR)/vidhrdw/mitchell_vidhrdw.c $(CORE_DIR)/drivers/mitchell.c \
$(CORE_DIR)/vidhrdw/cbasebal_vidhrdw.c $(CORE_DIR)/drivers/cbasebal.c \
$(CORE_DIR)/vidhrdw/cps1_vidhrdw.c $(CORE_DIR)/drivers/cps1.c $(CORE_DIR)/drivers/cps2.c $(CORE_DIR)/machine/cps2crypt.c\
$(CORE_DIR)/drivers/zn.c $(CORE_DIR)/sndhrdw/taitozoom.c $(CORE_DIR)/sound/zsg2.c $(CORE_DIR)/cpu/tms57002/tms57002.c \
$(CORE_DIR)/drivers/zn.c $(CORE_DIR)/sndhrdw/acclaim_rax.c $(CORE_DIR)/sndhrdw/taitozoom.c $(CORE_DIR)/sound/zsg2.c $(CORE_DIR)/cpu/tms57002/tms57002.c \
$(CORE_DIR)/drivers/cps3.c $(CORE_DIR)/sndhrdw/cps3_sndhrdw.c \
$(CORE_DIR)/vidhrdw/tms34061_vidhrdw.c \
$(CORE_DIR)/machine/capbowl_machine.c $(CORE_DIR)/vidhrdw/capbowl_vidhrdw.c $(CORE_DIR)/drivers/capbowl.c \
+16
View File
@@ -153,6 +153,22 @@ in ROM, so the interrupt was lost and the main loop waited for the timer
forever (black screen after "STAND ALONE"). With 32 bytes the commands fit
and the game plays.
**The MIDI interrupt.** The sound program reads one byte from the queue per
MIDI interrupt (level 3 on these boards). The interrupt is now dropped when
the program reads the byte, and raised again only while the queue still has
bytes, as in current MAME. Before, it could stay raised on an empty queue:
the sound program then took it again and read a stale byte as part of a
command. This corrupted the music commands of Dead or Alive (61 extra reads
in the attract mode) and Manx TT (189), whose music then played wrong or
stopped. The SCSP timers are now real timers, as in MAME, and each interrupt
source has its own level, which stays raised until the program acknowledges
it.
**How it was checked.** Each sound command the i960 sends is read once, with
no extra reads, in `doa`, `fvipers`, `hotd`, `manxtt`, `rchase2`, `srallyc`
and `vf2`. In Dead or Alive the sound commands and every slot register write
between 15 and 25 s of the attract mode are the same as in MAME 0.264.
## Rail Chase 2: mirrored sample ROMs
Sets: `rchase2`.
+5 -9
View File
@@ -918,17 +918,14 @@ static MEMORY_WRITE16_START( model2_snd_writemem )
{ 0x400000, 0x400001, model2snd_ctrl_w },
MEMORY_END
static int scsp_last_line = 0;
/* the SCSP raises and drops each level on its own (a negative level drops it,
0 means nothing to do here) */
static void scsp_irq( int irq )
{
if( irq )
{
scsp_last_line = irq;
if( irq > 0 )
cpu_set_irq_line( 2, irq, ASSERT_LINE );
}
else
cpu_set_irq_line( 2, scsp_last_line, CLEAR_LINE );
else if( irq < 0 )
cpu_set_irq_line( 2, -irq, CLEAR_LINE );
}
static struct SCSPinterface scsp_interface =
@@ -1881,7 +1878,6 @@ static DRIVER_INIT( model2a )
state_save_register_UINT8( "model2comm", 0, "zfg", &m2comm_zfg, 1 );
state_save_register_UINT8( "model2", 0, "io_analog_channel", &io_analog_channel, 1 );
state_save_register_UINT8( "model2", 0, "lightgun_mux", &m_lightgun_mux, 1 );
state_save_register_int( "model2", 0, "scsp_last_line", &scsp_last_line );
state_save_register_func_postload( model2_postload );
}
+60 -10
View File
@@ -100,6 +100,8 @@ Preliminary Memory map:
#include "machine/sega315_5838.h"
#include "state.h"
#include "includes/stv.h"
#include "cpu/adsp2100/adsp2100.h"
#include "sndhrdw/acclaim_rax.h"
#include <time.h>
#define USE_SLAVE 1
@@ -2955,17 +2957,28 @@ READ32_HANDLER( stv_sh2_soundram_r )
}
/* the SCSP is a 16-bit device: a 16-bit access of the SH-2 touches only its half, as
in MAME. Reading and writing back the other half had side effects: rewriting slot
register 0 processes the key on / key off of all the slots again, and a read of the
other half can take a MIDI byte */
static READ32_HANDLER( stv_scsp_regs_r32 )
{
UINT32 res = 0;
offset <<= 1;
return (SCSP_0_r(offset+1, 0xffff) | (SCSP_0_r(offset, 0xffff)<<16));
if ((mem_mask & 0xffff0000) != 0xffff0000)
res |= SCSP_0_r(offset, mem_mask >> 16) << 16;
if ((mem_mask & 0x0000ffff) != 0x0000ffff)
res |= SCSP_0_r(offset+1, mem_mask & 0xffff);
return res;
}
static WRITE32_HANDLER( stv_scsp_regs_w32 )
{
offset <<= 1;
SCSP_0_w(offset, data>>16, mem_mask >> 16);
SCSP_0_w(offset+1, data, mem_mask);
if ((mem_mask & 0xffff0000) != 0xffff0000)
SCSP_0_w(offset, data>>16, mem_mask >> 16);
if ((mem_mask & 0x0000ffff) != 0x0000ffff)
SCSP_0_w(offset+1, data & 0xffff, mem_mask & 0xffff);
}
/*
@@ -3998,23 +4011,23 @@ struct sh2_config sh2_conf_slave = { 1, stv_opcode_read };
static int scsp_last_line = 0;
/* the SCSP raises and drops each level on its own (a negative level drops it);
0 drops the last raised level, as in current MAME */
static void scsp_irq(int irq)
{
/* don't bother the 68k if it's off*/
if (!en_68k)
{
return;
}
if (irq)
if (irq > 0)
{
scsp_last_line = irq;
cpu_set_irq_line(2, irq, ASSERT_LINE);
}
else if (irq < 0)
cpu_set_irq_line(2, -irq, CLEAR_LINE);
else
{
cpu_set_irq_line(2, scsp_last_line, CLEAR_LINE);
}
}
static struct SCSPinterface scsp_interface =
@@ -4068,6 +4081,26 @@ static MACHINE_DRIVER_START( stv )
MDRV_SOUND_ADD(SCSP, scsp_interface)
MACHINE_DRIVER_END
/* Batman Forever: the Acclaim RAX sound board (an ADSP-2181), as in MAME */
static MACHINE_INIT( batmanfr )
{
machine_init_stv();
acclaim_rax_reset();
minit_boost = sinit_boost = 0;
}
static MACHINE_DRIVER_START( batmanfr )
MDRV_IMPORT_FROM(stv)
MDRV_CPU_ADD_TAG("rax", ADSP2181, RAX_CLOCK)
MDRV_CPU_FLAGS(CPU_AUDIO_CPU)
MDRV_CPU_MEMORY(acclaim_rax_readmem, acclaim_rax_writemem)
MDRV_MACHINE_INIT(batmanfr)
MDRV_SOUND_ADD(CUSTOM, acclaim_rax_custom_interface)
MACHINE_DRIVER_END
#define ROM_LOAD16_WORD_SWAP_BIOS(bios,name,offset,length,hash) \
ROMX_LOAD(name, offset, length, hash, ROM_GROUPWORD | ROM_REVERSE | ROM_BIOS(bios+1)) /* Note '+1' */
@@ -4939,7 +4972,9 @@ ROM_START( batmanfr )
ROM_LOAD16_WORD_SWAP( "gfx5.u15", 0x1800000, 0x0400000, CRC(e201f830) SHA1(5aa22fcc8f2e153d1abc3aa4050c594b3942ee67) )
ROM_LOAD16_WORD_SWAP( "gfx6.u18", 0x1c00000, 0x0400000, CRC(c6b381a3) SHA1(46431f1e47c084a0bf85535d35af27471653b008) )
/* the Acclaim RAX sound board (not emulated): its own region, not over the cart */
ROM_REGION( ADSP2100_SIZE, REGION_CPU4, ROMREGION_ERASE00 ) /* the ADSP-2181 internal RAM */
/* the Acclaim RAX sound board: its own region, not over the cart */
ROM_REGION( 0x1000000, REGION_USER4, 0 )
ROM_LOAD( "350snda1.u52", 0x000000, 0x080000, CRC(9027e7a0) SHA1(678df530838b078964a044ce734776f391654e6c) )
ROM_LOAD( "snd0.u48", 0x400000, 0x200000, CRC(02b1927c) SHA1(08b21d8b31b0f15c59fb5bb7eaf425e6fe04f7b5) )
@@ -5228,6 +5263,21 @@ void stv_draw_crosshairs(struct mame_bitmap *bitmap, const struct rectangle *cli
draw_crosshair(1, bitmap, x, y, clip);
}
/* Batman Forever: the commands to the RAX sound board, in the high word of 0x04800000 */
static WRITE32_HANDLER( batmanfr_sound_comms_w )
{
if (!(mem_mask & 0xffff0000))
acclaim_rax_data_w(data >> 16);
}
static DRIVER_INIT( batmanfr )
{
init_ic13();
install_mem_write32_handler(0, 0x04800000, 0x04800003, batmanfr_sound_comms_w);
install_mem_write32_handler(1, 0x04800000, 0x04800003, batmanfr_sound_comms_w);
acclaim_rax_init(mame_find_cpu_index("rax"), REGION_USER4);
}
static DRIVER_INIT( stvmedal )
{
init_ic13();
@@ -5481,7 +5531,7 @@ GAMEBX( 1995, vfremix, stvbios, stvbios, stv, stv, ic13, ROT0, "Sega",
GAMEBX( 1996, stvbios, 0, stvbios, stv, stv, stv, ROT0, "Sega", "ST-V Bios", NOT_A_DRIVER, &generic_ctrl, NULL )
GAMEBX( 1998, astrass, stvbios, stvbios, stv, stv, astrass, ROT0, "Sunsoft", "Astra SuperStars", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS, &generic_ctrl, NULL )
GAMEBX( 1996, batmanfr, stvbios, stvbios, stv, stv, ic13, ROT0, "Acclaim", "Batman Forever", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS, &generic_ctrl, NULL )
GAMEBX( 1996, batmanfr, stvbios, stvbios, batmanfr, stv, batmanfr, ROT0, "Acclaim", "Batman Forever", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS, &generic_ctrl, NULL )
GAMEBX( 1996, decathlt, stvbios, stvbios, stv, stv, decathlt, ROT0, "Sega", "Decathlete", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS, &generic_ctrl, NULL )
GAMEBX( 1999, ffreveng, stvbios, stvbios, stv, stv, ffreveng, ROT0, "Capcom", "Final Fight Revenge", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS, &generic_ctrl, NULL )
GAMEBX( 1996, findlove, stvbios, stvbios, stv, stv, ic13, ROT0, "Daiki", "Find Love", GAME_IMPERFECT_SOUND | GAME_IMPERFECT_GRAPHICS, &generic_ctrl, NULL )
+8 -503
View File
@@ -155,6 +155,7 @@ Sound: Analog Devices ADSP-2181
#include "machine/intelfsh.h"
#include "machine/ataflash.h"
#include "cpu/adsp2100/adsp2100.h"
#include "sndhrdw/acclaim_rax.h"
static int zn_bank_secsel; /* the game ROM bank follows this register (Raizing) */
static UINT32 tecmo_bank;
@@ -2829,507 +2830,11 @@ MACHINE_DRIVER_END
read the ROM from the bank written in the high half (inverted bit 4),
and the backup RAM is still written there.
RAX sound board (MAME shared/rax.cpp): an ADSP-2181 at 16.67MHz with
8MB of ROM (two banks of 4MB) read by its byte DMA (BDMA), 4 banks of
8K words of external data RAM behind the data memory overlay, and two
DACs fed by SPORT0 in autobuffer mode. The main CPU writes 16-bit
commands to 0x1fbfff80; the ADSP reads them at I/O 3, which clears its
IRQL0.
RAX sound board: sndhrdw/acclaim_rax.c, 8MB of ROM (two banks of 4MB).
The main CPU writes its 16-bit commands to 0x1fbfff80.
***************************************************************************/
/* the ADSP-2181 control registers, data memory 0x3fe0-0x3fff */
enum
{
RAX_IDMA_CONTROL_REG = 0, /* 3fe0 */
RAX_BDMA_INT_ADDR_REG, /* 3fe1 */
RAX_BDMA_EXT_ADDR_REG, /* 3fe2 */
RAX_BDMA_CONTROL_REG, /* 3fe3 */
RAX_BDMA_WORD_COUNT_REG, /* 3fe4 */
RAX_PROG_FLAG_DATA_REG, /* 3fe5 */
RAX_PROG_FLAG_CONTROL_REG, /* 3fe6 */
RAX_S1_AUTOBUF_REG = 15, /* 3fef */
RAX_S1_RFSDIV_REG, /* 3ff0 */
RAX_S1_SCLKDIV_REG, /* 3ff1 */
RAX_S1_CONTROL_REG, /* 3ff2 */
RAX_S0_AUTOBUF_REG, /* 3ff3 */
RAX_S0_RFSDIV_REG, /* 3ff4 */
RAX_S0_SCLKDIV_REG, /* 3ff5 */
RAX_S0_CONTROL_REG, /* 3ff6 */
RAX_S0_MCTXLO_REG, /* 3ff7 */
RAX_S0_MCTXHI_REG, /* 3ff8 */
RAX_S0_MCRXLO_REG, /* 3ff9 */
RAX_S0_MCRXHI_REG, /* 3ffa */
RAX_TIMER_SCALE_REG, /* 3ffb */
RAX_TIMER_COUNT_REG, /* 3ffc */
RAX_TIMER_PERIOD_REG, /* 3ffd */
RAX_WAITSTATES_REG, /* 3ffe */
RAX_SYSCONTROL_REG /* 3fff */
};
#define RAX_CLOCK 16670000
#define RAX_BUFFER_SIZE 0x4000 /* DAC samples per channel */
#define RAX_BUFFER_MASK ( RAX_BUFFER_SIZE - 1 )
static int rax_cpunum;
static UINT8 *rax_rom;
static UINT16 *rax_banked_ram; /* 5 x 8K words: internal, then external 0-3 */
static UINT16 rax_control_regs[ 32 ];
static UINT16 rax_data_in;
static UINT16 rax_data_out;
static UINT8 rax_pf0;
static UINT16 rax_data_bank;
static UINT16 rax_rom_bank;
static UINT32 rax_dmovlay;
static UINT16 rax_size;
static UINT16 rax_incs;
static INT32 rax_ireg;
static UINT16 rax_ireg_base;
static UINT8 rax_dac_enabled[ 2 ];
/* the timers are not saved by the core: their time left is */
static void *rax_reg_timer;
static void *rax_dma_timer;
static double rax_reg_timer_period;
static double rax_reg_timer_left;
static double rax_dma_timer_left;
static UINT32 rax_dma_param;
/* the DACs */
static int rax_stream;
static INT16 *rax_buffer[ 2 ];
static UINT32 rax_buffer_in[ 2 ];
static UINT32 rax_buffer_out[ 2 ];
static UINT32 rax_sample_rate;
static UINT32 rax_sample_step;
static UINT32 rax_sample_position;
static void rax_update_data_ram_bank( void )
{
int n_entry = ( rax_dmovlay == 0 ) ? 0 : 1 + rax_data_bank;
cpu_setbank( 14, rax_banked_ram + n_entry * 0x2000 );
}
/* data memory as the ADSP sees it, outside its context (DMA, DACs) */
static UINT16 *rax_data_ptr( UINT32 n_addr )
{
n_addr &= 0x3fff;
if( n_addr < 0x2000 )
return rax_banked_ram + ( ( rax_dmovlay == 0 ) ? 0 : 1 + rax_data_bank ) * 0x2000 + n_addr;
if( n_addr < 0x3fe0 )
return (UINT16 *)( memory_region( REGION_CPU1 + rax_cpunum ) + ADSP2181_DATA_OFFSET + ( n_addr << 1 ) );
return NULL;
}
static void rax_dma_done( int param )
{
/* update the external address and the page */
rax_control_regs[ RAX_BDMA_WORD_COUNT_REG ] = 0;
rax_control_regs[ RAX_BDMA_EXT_ADDR_REG ] = param & 0x3fff;
rax_control_regs[ RAX_BDMA_CONTROL_REG ] &= ~0xff00;
rax_control_regs[ RAX_BDMA_CONTROL_REG ] |= ( ( param >> 14 ) & 0xff ) << 8;
if( rax_control_regs[ RAX_BDMA_CONTROL_REG ] & 8 )
cpu_set_reset_line( rax_cpunum, PULSE_LINE );
else
cpu_set_irq_line( rax_cpunum, ADSP2181_BDMA, PULSE_LINE );
timer_adjust( rax_dma_timer, TIME_NEVER, 0, 0 );
}
/* the byte DMA: from the ROM to program or data memory, at once; the end
(its interrupt, or the reset of a boot load) after a cycle per word */
static void rax_bdma( UINT32 n_count_reg )
{
const UINT8 *adsp_rom = rax_rom + ( rax_rom_bank & 1 ) * 0x400000;
UINT32 page = ( rax_control_regs[ RAX_BDMA_CONTROL_REG ] >> 8 ) & 0xff;
UINT32 dir = ( rax_control_regs[ RAX_BDMA_CONTROL_REG ] >> 2 ) & 1;
UINT32 type = rax_control_regs[ RAX_BDMA_CONTROL_REG ] & 3;
UINT32 src_addr = ( page << 14 ) | rax_control_regs[ RAX_BDMA_EXT_ADDR_REG ];
UINT32 count = rax_control_regs[ RAX_BDMA_WORD_COUNT_REG ];
if( !dir )
{
while( count )
{
UINT32 n_addr = rax_control_regs[ RAX_BDMA_INT_ADDR_REG ];
if( type == 0 )
{
/* 24-bit words to program memory */
UINT32 n_word = ( adsp_rom[ ( src_addr + 0 ) & 0x3fffff ] << 16 ) |
( adsp_rom[ ( src_addr + 1 ) & 0x3fffff ] << 8 ) | adsp_rom[ ( src_addr + 2 ) & 0x3fffff ];
UINT32 *pgm = (UINT32 *)( memory_region( REGION_CPU1 + rax_cpunum ) + ADSP2181_PGM_OFFSET );
pgm[ n_addr & 0x3fff ] = n_word;
src_addr += 3;
}
else
{
/* 16-bit words, or bytes (MSB or LSB aligned) to data memory */
UINT16 n_word;
UINT16 *p;
if( type == 1 )
{
n_word = ( adsp_rom[ src_addr & 0x3fffff ] << 8 ) | adsp_rom[ ( src_addr + 1 ) & 0x3fffff ];
src_addr += 2;
}
else
{
n_word = adsp_rom[ src_addr & 0x3fffff ] << ( ( type == 2 ) ? 8 : 0 );
src_addr++;
}
p = rax_data_ptr( n_addr );
if( p )
*p = n_word;
}
rax_control_regs[ RAX_BDMA_INT_ADDR_REG ] = ( n_addr + 1 ) & 0x3fff;
count--;
}
}
rax_dma_param = src_addr;
timer_adjust( rax_dma_timer, TIME_IN_HZ( RAX_CLOCK ) * ( n_count_reg & 0x3fff ), rax_dma_param, 0 );
}
static READ16_HANDLER( rax_control_r )
{
if( offset == RAX_PROG_FLAG_DATA_REG )
return rax_pf0;
return rax_control_regs[ offset ];
}
static WRITE16_HANDLER( rax_control_w )
{
rax_control_regs[ offset ] = data;
switch( offset )
{
case RAX_BDMA_INT_ADDR_REG:
rax_control_regs[ offset ] = data & 0x3fff;
break;
case RAX_BDMA_EXT_ADDR_REG:
rax_control_regs[ offset ] = data & 0x3fff;
break;
case RAX_BDMA_CONTROL_REG:
rax_control_regs[ offset ] = data & 0xff0f;
break;
case RAX_BDMA_WORD_COUNT_REG:
rax_control_regs[ offset ] = data & 0x3fff;
rax_bdma( data );
break;
case RAX_S1_AUTOBUF_REG:
/* autobuffer off: the right DAC stops */
if( !( data & 2 ) )
{
stream_update( rax_stream, 0 );
rax_dac_enabled[ 1 ] = 0;
rax_buffer_in[ 1 ] = rax_buffer_out[ 1 ] = 0;
}
break;
case RAX_S0_AUTOBUF_REG:
/* autobuffer off: the left DAC and the transfers stop */
if( !( data & 2 ) )
{
stream_update( rax_stream, 0 );
rax_dac_enabled[ 0 ] = 0;
rax_buffer_in[ 0 ] = rax_buffer_out[ 0 ] = 0;
timer_adjust( rax_reg_timer, TIME_NEVER, 0, 0 );
rax_reg_timer_period = 0;
}
break;
}
}
/* the I/O space: data RAM bank, ROM bank, and the latches */
static UINT16 rax_io_r( UINT32 offset )
{
if( offset == 3 )
{
cpu_set_irq_line( rax_cpunum, ADSP2181_IRQL0, CLEAR_LINE );
return rax_data_in;
}
return 0xffff;
}
static void rax_io_w( UINT32 offset, UINT16 data )
{
switch( offset )
{
case 0:
/* the board has two more RAM sockets, empty */
rax_data_bank = data & 3;
rax_update_data_ram_bank();
break;
case 1:
rax_rom_bank = data;
break;
case 3:
rax_data_out = data;
rax_pf0 = 0;
break;
}
}
static void rax_dmovlay_w( UINT32 data )
{
rax_dmovlay = ( data != 0 );
rax_update_data_ram_bank();
}
/* a quarter of the autobuffer, to the DACs (left, right interleaved) */
static void rax_irq( int param )
{
int reg = cpunum_get_reg( rax_cpunum, ADSP2100_I0 + rax_ireg );
int count = rax_size / ( 4 * ( rax_incs ? rax_incs : 1 ) );
int i;
stream_update( rax_stream, 0 );
for( i = 0; i < ( count & ~1 ); i++ )
{
UINT16 *p = rax_data_ptr( reg );
int n_channel = i & 1;
if( rax_dac_enabled[ n_channel ] )
{
rax_buffer[ n_channel ][ rax_buffer_in[ n_channel ] & RAX_BUFFER_MASK ] = p ? (INT16)*p : 0;
if( rax_buffer_in[ n_channel ] - rax_buffer_out[ n_channel ] < RAX_BUFFER_SIZE - 1 )
rax_buffer_in[ n_channel ]++;
}
reg += rax_incs;
}
/* check for wrapping */
if( reg >= rax_ireg_base + rax_size )
reg = rax_ireg_base;
cpunum_set_reg( rax_cpunum, ADSP2100_I0 + rax_ireg, reg );
}
/* SPORT0 transmit: the autobuffer starts */
static void rax_tx_callback( int port, INT32 data )
{
if( port != 0 )
return;
/* SPORT0 enabled */
if( rax_control_regs[ RAX_SYSCONTROL_REG ] & 0x1000 )
{
/* autobuffer only, which is what this board uses */
if( rax_control_regs[ RAX_S0_AUTOBUF_REG ] & 0x0002 )
{
int mreg, lreg;
UINT16 source;
stream_update( rax_stream, 0 );
rax_ireg = ( rax_control_regs[ RAX_S0_AUTOBUF_REG ] >> 9 ) & 7;
mreg = ( rax_control_regs[ RAX_S0_AUTOBUF_REG ] >> 7 ) & 3;
mreg |= rax_ireg & 0x04; /* msb comes from ireg */
lreg = rax_ireg;
source = cpunum_get_reg( rax_cpunum, ADSP2100_I0 + rax_ireg );
rax_incs = cpunum_get_reg( rax_cpunum, ADSP2100_M0 + mreg );
rax_size = cpunum_get_reg( rax_cpunum, ADSP2100_L0 + lreg );
/* the base value, kept for the wrapping; back one, so that the
first sample is not lost */
source -= rax_incs;
cpunum_set_reg( rax_cpunum, ADSP2100_I0 + rax_ireg, source );
rax_ireg_base = source;
/* a sample every 16 serial clocks; the DACs at that rate */
rax_sample_rate = RAX_CLOCK / ( 16 * ( rax_control_regs[ RAX_S0_SCLKDIV_REG ] + 1 ) );
rax_sample_step = (UINT32)( (double)rax_sample_rate * 65536.0 / (double)Machine->sample_rate );
rax_dac_enabled[ 0 ] = rax_dac_enabled[ 1 ] = 1;
/* a timer every quarter of the buffer (two samples per pair) */
if( rax_incs )
{
rax_reg_timer_period = TIME_IN_HZ( rax_sample_rate ) * rax_size / ( 4 * 2 * rax_incs );
timer_adjust( rax_reg_timer, rax_reg_timer_period, 0, rax_reg_timer_period );
}
return;
}
}
/* anything else: no sound */
stream_update( rax_stream, 0 );
rax_dac_enabled[ 0 ] = rax_dac_enabled[ 1 ] = 0;
rax_buffer_in[ 0 ] = rax_buffer_out[ 0 ] = rax_buffer_in[ 1 ] = rax_buffer_out[ 1 ] = 0;
timer_adjust( rax_reg_timer, TIME_NEVER, 0, 0 );
rax_reg_timer_period = 0;
}
/* both DACs, resampled to the output rate; silence when one runs out */
static void rax_dac_update( int num, INT16 **buffer, int length )
{
UINT32 n_end = rax_sample_position;
int n_channel;
for( n_channel = 0; n_channel < 2; n_channel++ )
{
INT16 *dest = buffer[ n_channel ];
UINT32 current = rax_sample_position;
UINT32 n_used;
int i;
for( i = 0; i < length; i++ )
{
UINT32 n_index = rax_buffer_out[ n_channel ] + ( current >> 16 );
if( !rax_dac_enabled[ n_channel ] || n_index >= rax_buffer_in[ n_channel ] )
break;
dest[ i ] = rax_buffer[ n_channel ][ n_index & RAX_BUFFER_MASK ];
current += rax_sample_step;
}
for( ; i < length; i++ )
dest[ i ] = 0;
/* drop the samples played, keep the fraction */
n_used = current >> 16;
if( n_used > rax_buffer_in[ n_channel ] - rax_buffer_out[ n_channel ] )
n_used = rax_buffer_in[ n_channel ] - rax_buffer_out[ n_channel ];
rax_buffer_out[ n_channel ] += n_used;
if( n_channel == 0 )
n_end = current & 0xffff;
}
rax_sample_position = n_end;
}
static int rax_custom_start( const struct MachineSound *msound )
{
const char *names[] = { "RAX DAC L", "RAX DAC R" };
int vols[] = { MIXER( 100, MIXER_PAN_LEFT ), MIXER( 100, MIXER_PAN_RIGHT ) };
int i;
rax_stream = stream_init_multi( 2, names, vols, Machine->sample_rate, 0, rax_dac_update );
for( i = 0; i < 2; i++ )
{
rax_buffer[ i ] = auto_malloc( RAX_BUFFER_SIZE * sizeof( INT16 ) );
if( !rax_buffer[ i ] )
return 1;
memset( rax_buffer[ i ], 0, RAX_BUFFER_SIZE * sizeof( INT16 ) );
}
state_save_register_INT16( "rax", 0, "buffer_l", rax_buffer[ 0 ], RAX_BUFFER_SIZE );
state_save_register_INT16( "rax", 0, "buffer_r", rax_buffer[ 1 ], RAX_BUFFER_SIZE );
return 0;
}
static struct CustomSound_interface rax_custom_interface =
{
rax_custom_start, 0, 0
};
static MEMORY_READ16_START( rax_readmem )
{ ADSP_DATA_ADDR_RANGE( 0x0000, 0x1fff ), MRA16_BANK14 }, /* internal RAM, or external through DMOVLAY */
{ ADSP_DATA_ADDR_RANGE( 0x2000, 0x3fdf ), MRA16_RAM }, /* internal RAM */
{ ADSP_DATA_ADDR_RANGE( 0x3fe0, 0x3fff ), rax_control_r }, /* control registers */
{ ADSP_PGM_ADDR_RANGE( 0x0000, 0x3fff ), MRA16_RAM }, /* internal program RAM */
MEMORY_END
static MEMORY_WRITE16_START( rax_writemem )
{ ADSP_DATA_ADDR_RANGE( 0x0000, 0x1fff ), MWA16_BANK14 },
{ ADSP_DATA_ADDR_RANGE( 0x2000, 0x3fdf ), MWA16_RAM },
{ ADSP_DATA_ADDR_RANGE( 0x3fe0, 0x3fff ), rax_control_w },
{ ADSP_PGM_ADDR_RANGE( 0x0000, 0x3fff ), MWA16_RAM },
MEMORY_END
static void rax_presave( void )
{
rax_reg_timer_left = timer_timeleft( rax_reg_timer );
rax_dma_timer_left = timer_timeleft( rax_dma_timer );
}
static void rax_postload( void )
{
rax_update_data_ram_bank();
if( rax_reg_timer_period > 0 && rax_reg_timer_left < TIME_NEVER / 2 )
timer_adjust( rax_reg_timer, ( rax_reg_timer_left > 0 ) ? rax_reg_timer_left : 0, 0, rax_reg_timer_period );
else
timer_adjust( rax_reg_timer, TIME_NEVER, 0, 0 );
if( rax_dma_timer_left < TIME_NEVER / 2 )
timer_adjust( rax_dma_timer, ( rax_dma_timer_left > 0 ) ? rax_dma_timer_left : 0, rax_dma_param, 0 );
else
timer_adjust( rax_dma_timer, TIME_NEVER, 0, 0 );
}
static void rax_init( int cpunum )
{
rax_cpunum = cpunum;
rax_rom = memory_region( REGION_SOUND1 );
rax_banked_ram = auto_malloc( 0x2000 * 5 * sizeof( UINT16 ) );
memset( rax_banked_ram, 0, 0x2000 * 5 * sizeof( UINT16 ) );
rax_reg_timer = timer_alloc( rax_irq );
rax_dma_timer = timer_alloc( rax_dma_done );
adsp2181_set_tx_callback( rax_tx_callback );
adsp2181_set_io_callbacks( rax_io_r, rax_io_w );
adsp2181_set_dmovlay_callback( rax_dmovlay_w );
state_save_register_UINT16( "rax", 0, "banked_ram", rax_banked_ram, 0x2000 * 5 );
state_save_register_UINT16( "rax", 0, "control_regs", rax_control_regs, 32 );
state_save_register_UINT16( "rax", 0, "data_in", &rax_data_in, 1 );
state_save_register_UINT16( "rax", 0, "data_out", &rax_data_out, 1 );
state_save_register_UINT8( "rax", 0, "pf0", &rax_pf0, 1 );
state_save_register_UINT16( "rax", 0, "data_bank", &rax_data_bank, 1 );
state_save_register_UINT16( "rax", 0, "rom_bank", &rax_rom_bank, 1 );
state_save_register_UINT32( "rax", 0, "dmovlay", &rax_dmovlay, 1 );
state_save_register_UINT16( "rax", 0, "size", &rax_size, 1 );
state_save_register_UINT16( "rax", 0, "incs", &rax_incs, 1 );
state_save_register_INT32( "rax", 0, "ireg", &rax_ireg, 1 );
state_save_register_UINT16( "rax", 0, "ireg_base", &rax_ireg_base, 1 );
state_save_register_UINT8( "rax", 0, "dac_enabled", rax_dac_enabled, 2 );
state_save_register_double( "rax", 0, "reg_timer_period", &rax_reg_timer_period, 1 );
state_save_register_double( "rax", 0, "reg_timer_left", &rax_reg_timer_left, 1 );
state_save_register_double( "rax", 0, "dma_timer_left", &rax_dma_timer_left, 1 );
state_save_register_UINT32( "rax", 0, "dma_param", &rax_dma_param, 1 );
state_save_register_UINT32( "rax", 0, "buffer_in", rax_buffer_in, 2 );
state_save_register_UINT32( "rax", 0, "buffer_out", rax_buffer_out, 2 );
state_save_register_UINT32( "rax", 0, "sample_rate", &rax_sample_rate, 1 );
state_save_register_UINT32( "rax", 0, "sample_step", &rax_sample_step, 1 );
state_save_register_UINT32( "rax", 0, "sample_position", &rax_sample_position, 1 );
state_save_register_func_presave( rax_presave );
state_save_register_func_postload( rax_postload );
}
static void rax_reset( void )
{
UINT32 *pgm = (UINT32 *)( memory_region( REGION_CPU1 + rax_cpunum ) + ADSP2181_PGM_OFFSET );
int i;
/* the boot: 32 program words (96 bytes) from the ROM, as by BDMA */
for( i = 0; i < 32; i++ )
pgm[ i ] = ( rax_rom[ i * 3 + 0 ] << 16 ) | ( rax_rom[ i * 3 + 1 ] << 8 ) | rax_rom[ i * 3 + 2 ];
rax_pf0 = 1;
rax_rom_bank = 0;
rax_size = 0;
rax_incs = 0;
rax_ireg = 0;
memset( rax_control_regs, 0, sizeof( rax_control_regs ) );
rax_dmovlay = 0;
rax_data_bank = 0;
rax_update_data_ram_bank();
rax_dac_enabled[ 0 ] = rax_dac_enabled[ 1 ] = 0;
rax_buffer_in[ 0 ] = rax_buffer_out[ 0 ] = rax_buffer_in[ 1 ] = rax_buffer_out[ 1 ] = 0;
rax_sample_position = 0;
rax_sample_step = 0x10000;
rax_reg_timer_period = 0;
timer_adjust( rax_reg_timer, TIME_NEVER, 0, 0 );
timer_adjust( rax_dma_timer, TIME_NEVER, 0, 0 );
}
/* from the main CPU: a command, IRQL0 on the ADSP */
static void rax_data_w( UINT16 data )
{
rax_data_in = data;
cpu_set_irq_line( rax_cpunum, ADSP2181_IRQL0, ASSERT_LINE );
cpu_boost_interleave( 0, TIME_IN_USEC( 5 ) );
}
/* the main board side */
static UINT8 *nbajamex_sram; /* 71256 */
@@ -3399,7 +2904,7 @@ static WRITE32_HANDLER( nbajamex_sound_80_w )
{
/* all 16 bits go to the latch of the sound board (see the sound test) */
if( ( mem_mask & 0x0000ffff ) != 0x0000ffff )
rax_data_w( data & 0xffff );
acclaim_rax_data_w( data & 0xffff );
}
static MEMORY_READ32_START( nbajamex_readmem )
@@ -3453,7 +2958,7 @@ static DRIVER_INIT( nbajamex )
znsec_init( 0, memory_region( REGION_USER4 ) ); /* AC01 */
znsec_init( 1, memory_region( REGION_USER5 ) ); /* AC02 */
rax_init( mame_find_cpu_index( "rax" ) );
acclaim_rax_init( mame_find_cpu_index( "rax" ), REGION_SOUND1 );
state_save_register_UINT8( "zn", 0, "nbajamex_sram", nbajamex_sram, 0x8000 );
state_save_register_UINT32( "zn", 0, "nbajamex_rombank", nbajamex_rombank, 2 );
@@ -3468,7 +2973,7 @@ static MACHINE_INIT( nbajamex )
nbajamex_rombank[ 0 ] = nbajamex_rombank[ 1 ] = 0;
nbajamex_bankmap = 0;
nbajamex_update_banks();
rax_reset();
acclaim_rax_reset();
}
/* ZN-1, 2MB VRAM (COH-1000A), SPU and the RAX sound board */
@@ -3479,7 +2984,7 @@ static MACHINE_DRIVER_START( nbajamex )
MDRV_CPU_ADD_TAG( "rax", ADSP2181, RAX_CLOCK )
MDRV_CPU_FLAGS( CPU_AUDIO_CPU )
MDRV_CPU_MEMORY( rax_readmem, rax_writemem )
MDRV_CPU_MEMORY( acclaim_rax_readmem, acclaim_rax_writemem )
MDRV_FRAMES_PER_SECOND( 60 )
MDRV_VBLANK_DURATION( 0 )
@@ -3499,7 +3004,7 @@ static MACHINE_DRIVER_START( nbajamex )
MDRV_SOUND_ATTRIBUTES( SOUND_SUPPORTS_STEREO )
MDRV_SOUND_ADD( PSXSPU, zn_spu_interface )
MDRV_SOUND_ADD( CUSTOM, rax_custom_interface )
MDRV_SOUND_ADD( CUSTOM, acclaim_rax_custom_interface )
MACHINE_DRIVER_END
+511
View File
@@ -0,0 +1,511 @@
/***************************************************************************
Acclaim RAX sound board, as in current MAME (shared/rax.cpp)
An ADSP-2181 at 16.67MHz with its ROM (banks of 4MB) read by the byte DMA
(BDMA), 4 banks of 8K words of external data RAM behind the data memory
overlay, and two DACs fed by SPORT0 in autobuffer mode. The host writes
16-bit commands, which the ADSP reads at I/O 3 (that clears its IRQL0).
Used by NBA Jam Extreme (ZN-1) and Batman Forever (ST-V).
***************************************************************************/
#include "driver.h"
#include "state.h"
#include "cpu/adsp2100/adsp2100.h"
#include "sndhrdw/acclaim_rax.h"
/* the ADSP-2181 control registers, data memory 0x3fe0-0x3fff */
enum
{
RAX_IDMA_CONTROL_REG = 0, /* 3fe0 */
RAX_BDMA_INT_ADDR_REG, /* 3fe1 */
RAX_BDMA_EXT_ADDR_REG, /* 3fe2 */
RAX_BDMA_CONTROL_REG, /* 3fe3 */
RAX_BDMA_WORD_COUNT_REG, /* 3fe4 */
RAX_PROG_FLAG_DATA_REG, /* 3fe5 */
RAX_PROG_FLAG_CONTROL_REG, /* 3fe6 */
RAX_S1_AUTOBUF_REG = 15, /* 3fef */
RAX_S1_RFSDIV_REG, /* 3ff0 */
RAX_S1_SCLKDIV_REG, /* 3ff1 */
RAX_S1_CONTROL_REG, /* 3ff2 */
RAX_S0_AUTOBUF_REG, /* 3ff3 */
RAX_S0_RFSDIV_REG, /* 3ff4 */
RAX_S0_SCLKDIV_REG, /* 3ff5 */
RAX_S0_CONTROL_REG, /* 3ff6 */
RAX_S0_MCTXLO_REG, /* 3ff7 */
RAX_S0_MCTXHI_REG, /* 3ff8 */
RAX_S0_MCRXLO_REG, /* 3ff9 */
RAX_S0_MCRXHI_REG, /* 3ffa */
RAX_TIMER_SCALE_REG, /* 3ffb */
RAX_TIMER_COUNT_REG, /* 3ffc */
RAX_TIMER_PERIOD_REG, /* 3ffd */
RAX_WAITSTATES_REG, /* 3ffe */
RAX_SYSCONTROL_REG /* 3fff */
};
#define RAX_BUFFER_SIZE 0x4000 /* DAC samples per channel */
#define RAX_BUFFER_MASK ( RAX_BUFFER_SIZE - 1 )
static int rax_cpunum;
static UINT8 *rax_rom;
static UINT32 rax_rom_banks; /* the banks of 4MB in the ROM region */
static UINT16 *rax_banked_ram; /* 5 x 8K words: internal, then external 0-3 */
static UINT16 rax_control_regs[ 32 ];
static UINT16 rax_data_in;
static UINT16 rax_data_out;
static UINT8 rax_pf0;
static UINT16 rax_data_bank;
static UINT16 rax_rom_bank;
static UINT32 rax_dmovlay;
static UINT16 rax_size;
static UINT16 rax_incs;
static INT32 rax_ireg;
static UINT16 rax_ireg_base;
static UINT8 rax_dac_enabled[ 2 ];
/* the timers are not saved by the core: their time left is */
static void *rax_reg_timer;
static void *rax_dma_timer;
static double rax_reg_timer_period;
static double rax_reg_timer_left;
static double rax_dma_timer_left;
static UINT32 rax_dma_param;
/* the DACs */
static int rax_stream;
static INT16 *rax_buffer[ 2 ];
static UINT32 rax_buffer_in[ 2 ];
static UINT32 rax_buffer_out[ 2 ];
static UINT32 rax_sample_rate;
static UINT32 rax_sample_step;
static UINT32 rax_sample_position;
static void rax_update_data_ram_bank( void )
{
int n_entry = ( rax_dmovlay == 0 ) ? 0 : 1 + rax_data_bank;
cpu_setbank( 14, rax_banked_ram + n_entry * 0x2000 );
}
/* data memory as the ADSP sees it, outside its context (DMA, DACs) */
static UINT16 *rax_data_ptr( UINT32 n_addr )
{
n_addr &= 0x3fff;
if( n_addr < 0x2000 )
return rax_banked_ram + ( ( rax_dmovlay == 0 ) ? 0 : 1 + rax_data_bank ) * 0x2000 + n_addr;
if( n_addr < 0x3fe0 )
return (UINT16 *)( memory_region( REGION_CPU1 + rax_cpunum ) + ADSP2181_DATA_OFFSET + ( n_addr << 1 ) );
return NULL;
}
static void rax_dma_done( int param )
{
/* update the external address and the page */
rax_control_regs[ RAX_BDMA_WORD_COUNT_REG ] = 0;
rax_control_regs[ RAX_BDMA_EXT_ADDR_REG ] = param & 0x3fff;
rax_control_regs[ RAX_BDMA_CONTROL_REG ] &= ~0xff00;
rax_control_regs[ RAX_BDMA_CONTROL_REG ] |= ( ( param >> 14 ) & 0xff ) << 8;
if( rax_control_regs[ RAX_BDMA_CONTROL_REG ] & 8 )
cpu_set_reset_line( rax_cpunum, PULSE_LINE );
else
cpu_set_irq_line( rax_cpunum, ADSP2181_BDMA, PULSE_LINE );
timer_adjust( rax_dma_timer, TIME_NEVER, 0, 0 );
}
/* the byte DMA: from the ROM to program or data memory, at once; the end
(its interrupt, or the reset of a boot load) after a cycle per word */
static void rax_bdma( UINT32 n_count_reg )
{
const UINT8 *adsp_rom = rax_rom + ( rax_rom_bank % rax_rom_banks ) * 0x400000;
UINT32 page = ( rax_control_regs[ RAX_BDMA_CONTROL_REG ] >> 8 ) & 0xff;
UINT32 dir = ( rax_control_regs[ RAX_BDMA_CONTROL_REG ] >> 2 ) & 1;
UINT32 type = rax_control_regs[ RAX_BDMA_CONTROL_REG ] & 3;
UINT32 src_addr = ( page << 14 ) | rax_control_regs[ RAX_BDMA_EXT_ADDR_REG ];
UINT32 count = rax_control_regs[ RAX_BDMA_WORD_COUNT_REG ];
if( !dir )
{
while( count )
{
UINT32 n_addr = rax_control_regs[ RAX_BDMA_INT_ADDR_REG ];
if( type == 0 )
{
/* 24-bit words to program memory */
UINT32 n_word = ( adsp_rom[ ( src_addr + 0 ) & 0x3fffff ] << 16 ) |
( adsp_rom[ ( src_addr + 1 ) & 0x3fffff ] << 8 ) | adsp_rom[ ( src_addr + 2 ) & 0x3fffff ];
UINT32 *pgm = (UINT32 *)( memory_region( REGION_CPU1 + rax_cpunum ) + ADSP2181_PGM_OFFSET );
pgm[ n_addr & 0x3fff ] = n_word;
src_addr += 3;
}
else
{
/* 16-bit words, or bytes (MSB or LSB aligned) to data memory */
UINT16 n_word;
UINT16 *p;
if( type == 1 )
{
n_word = ( adsp_rom[ src_addr & 0x3fffff ] << 8 ) | adsp_rom[ ( src_addr + 1 ) & 0x3fffff ];
src_addr += 2;
}
else
{
n_word = adsp_rom[ src_addr & 0x3fffff ] << ( ( type == 2 ) ? 8 : 0 );
src_addr++;
}
p = rax_data_ptr( n_addr );
if( p )
*p = n_word;
}
rax_control_regs[ RAX_BDMA_INT_ADDR_REG ] = ( n_addr + 1 ) & 0x3fff;
count--;
}
}
rax_dma_param = src_addr;
timer_adjust( rax_dma_timer, TIME_IN_HZ( RAX_CLOCK ) * ( n_count_reg & 0x3fff ), rax_dma_param, 0 );
}
static READ16_HANDLER( rax_control_r )
{
if( offset == RAX_PROG_FLAG_DATA_REG )
return rax_pf0;
return rax_control_regs[ offset ];
}
static WRITE16_HANDLER( rax_control_w )
{
rax_control_regs[ offset ] = data;
switch( offset )
{
case RAX_BDMA_INT_ADDR_REG:
rax_control_regs[ offset ] = data & 0x3fff;
break;
case RAX_BDMA_EXT_ADDR_REG:
rax_control_regs[ offset ] = data & 0x3fff;
break;
case RAX_BDMA_CONTROL_REG:
rax_control_regs[ offset ] = data & 0xff0f;
break;
case RAX_BDMA_WORD_COUNT_REG:
rax_control_regs[ offset ] = data & 0x3fff;
rax_bdma( data );
break;
case RAX_S1_AUTOBUF_REG:
/* autobuffer off: the right DAC stops */
if( !( data & 2 ) )
{
stream_update( rax_stream, 0 );
rax_dac_enabled[ 1 ] = 0;
rax_buffer_in[ 1 ] = rax_buffer_out[ 1 ] = 0;
}
break;
case RAX_S0_AUTOBUF_REG:
/* autobuffer off: the left DAC and the transfers stop */
if( !( data & 2 ) )
{
stream_update( rax_stream, 0 );
rax_dac_enabled[ 0 ] = 0;
rax_buffer_in[ 0 ] = rax_buffer_out[ 0 ] = 0;
timer_adjust( rax_reg_timer, TIME_NEVER, 0, 0 );
rax_reg_timer_period = 0;
}
break;
}
}
/* the I/O space: data RAM bank, ROM bank, and the latches */
static UINT16 rax_io_r( UINT32 offset )
{
if( offset == 3 )
{
cpu_set_irq_line( rax_cpunum, ADSP2181_IRQL0, CLEAR_LINE );
return rax_data_in;
}
return 0xffff;
}
static void rax_io_w( UINT32 offset, UINT16 data )
{
switch( offset )
{
case 0:
/* the board has two more RAM sockets, empty */
rax_data_bank = data & 3;
rax_update_data_ram_bank();
break;
case 1:
rax_rom_bank = data;
break;
case 3:
rax_data_out = data;
rax_pf0 = 0;
break;
}
}
static void rax_dmovlay_w( UINT32 data )
{
rax_dmovlay = ( data != 0 );
rax_update_data_ram_bank();
}
/* a quarter of the autobuffer, to the DACs (left, right interleaved) */
static void rax_irq( int param )
{
int reg = cpunum_get_reg( rax_cpunum, ADSP2100_I0 + rax_ireg );
int count = rax_size / ( 4 * ( rax_incs ? rax_incs : 1 ) );
int i;
stream_update( rax_stream, 0 );
for( i = 0; i < ( count & ~1 ); i++ )
{
UINT16 *p = rax_data_ptr( reg );
int n_channel = i & 1;
if( rax_dac_enabled[ n_channel ] )
{
rax_buffer[ n_channel ][ rax_buffer_in[ n_channel ] & RAX_BUFFER_MASK ] = p ? (INT16)*p : 0;
if( rax_buffer_in[ n_channel ] - rax_buffer_out[ n_channel ] < RAX_BUFFER_SIZE - 1 )
rax_buffer_in[ n_channel ]++;
}
reg += rax_incs;
}
/* check for wrapping */
if( reg >= rax_ireg_base + rax_size )
reg = rax_ireg_base;
cpunum_set_reg( rax_cpunum, ADSP2100_I0 + rax_ireg, reg );
}
/* SPORT0 transmit: the autobuffer starts */
static void rax_tx_callback( int port, INT32 data )
{
if( port != 0 )
return;
/* SPORT0 enabled */
if( rax_control_regs[ RAX_SYSCONTROL_REG ] & 0x1000 )
{
/* autobuffer only, which is what this board uses */
if( rax_control_regs[ RAX_S0_AUTOBUF_REG ] & 0x0002 )
{
int mreg, lreg;
UINT16 source;
stream_update( rax_stream, 0 );
rax_ireg = ( rax_control_regs[ RAX_S0_AUTOBUF_REG ] >> 9 ) & 7;
mreg = ( rax_control_regs[ RAX_S0_AUTOBUF_REG ] >> 7 ) & 3;
mreg |= rax_ireg & 0x04; /* msb comes from ireg */
lreg = rax_ireg;
source = cpunum_get_reg( rax_cpunum, ADSP2100_I0 + rax_ireg );
rax_incs = cpunum_get_reg( rax_cpunum, ADSP2100_M0 + mreg );
rax_size = cpunum_get_reg( rax_cpunum, ADSP2100_L0 + lreg );
/* the base value, kept for the wrapping; back one, so that the
first sample is not lost */
source -= rax_incs;
cpunum_set_reg( rax_cpunum, ADSP2100_I0 + rax_ireg, source );
rax_ireg_base = source;
/* a sample every 16 serial clocks; the DACs at that rate */
rax_sample_rate = RAX_CLOCK / ( 16 * ( rax_control_regs[ RAX_S0_SCLKDIV_REG ] + 1 ) );
rax_sample_step = (UINT32)( (double)rax_sample_rate * 65536.0 / (double)Machine->sample_rate );
rax_dac_enabled[ 0 ] = rax_dac_enabled[ 1 ] = 1;
/* a timer every quarter of the buffer (two samples per pair) */
if( rax_incs )
{
rax_reg_timer_period = TIME_IN_HZ( rax_sample_rate ) * rax_size / ( 4 * 2 * rax_incs );
timer_adjust( rax_reg_timer, rax_reg_timer_period, 0, rax_reg_timer_period );
}
return;
}
}
/* anything else: no sound */
stream_update( rax_stream, 0 );
rax_dac_enabled[ 0 ] = rax_dac_enabled[ 1 ] = 0;
rax_buffer_in[ 0 ] = rax_buffer_out[ 0 ] = rax_buffer_in[ 1 ] = rax_buffer_out[ 1 ] = 0;
timer_adjust( rax_reg_timer, TIME_NEVER, 0, 0 );
rax_reg_timer_period = 0;
}
/* both DACs, resampled to the output rate; silence when one runs out */
static void rax_dac_update( int num, INT16 **buffer, int length )
{
UINT32 n_end = rax_sample_position;
int n_channel;
for( n_channel = 0; n_channel < 2; n_channel++ )
{
INT16 *dest = buffer[ n_channel ];
UINT32 current = rax_sample_position;
UINT32 n_used;
int i;
for( i = 0; i < length; i++ )
{
UINT32 n_index = rax_buffer_out[ n_channel ] + ( current >> 16 );
if( !rax_dac_enabled[ n_channel ] || n_index >= rax_buffer_in[ n_channel ] )
break;
dest[ i ] = rax_buffer[ n_channel ][ n_index & RAX_BUFFER_MASK ];
current += rax_sample_step;
}
for( ; i < length; i++ )
dest[ i ] = 0;
/* drop the samples played, keep the fraction */
n_used = current >> 16;
if( n_used > rax_buffer_in[ n_channel ] - rax_buffer_out[ n_channel ] )
n_used = rax_buffer_in[ n_channel ] - rax_buffer_out[ n_channel ];
rax_buffer_out[ n_channel ] += n_used;
if( n_channel == 0 )
n_end = current & 0xffff;
}
rax_sample_position = n_end;
}
static int rax_custom_start( const struct MachineSound *msound )
{
const char *names[] = { "RAX DAC L", "RAX DAC R" };
int vols[] = { MIXER( 100, MIXER_PAN_LEFT ), MIXER( 100, MIXER_PAN_RIGHT ) };
int i;
rax_stream = stream_init_multi( 2, names, vols, Machine->sample_rate, 0, rax_dac_update );
for( i = 0; i < 2; i++ )
{
rax_buffer[ i ] = auto_malloc( RAX_BUFFER_SIZE * sizeof( INT16 ) );
if( !rax_buffer[ i ] )
return 1;
memset( rax_buffer[ i ], 0, RAX_BUFFER_SIZE * sizeof( INT16 ) );
}
state_save_register_INT16( "rax", 0, "buffer_l", rax_buffer[ 0 ], RAX_BUFFER_SIZE );
state_save_register_INT16( "rax", 0, "buffer_r", rax_buffer[ 1 ], RAX_BUFFER_SIZE );
return 0;
}
struct CustomSound_interface acclaim_rax_custom_interface =
{
rax_custom_start, 0, 0
};
MEMORY_READ16_START( acclaim_rax_readmem )
{ ADSP_DATA_ADDR_RANGE( 0x0000, 0x1fff ), MRA16_BANK14 }, /* internal RAM, or external through DMOVLAY */
{ ADSP_DATA_ADDR_RANGE( 0x2000, 0x3fdf ), MRA16_RAM }, /* internal RAM */
{ ADSP_DATA_ADDR_RANGE( 0x3fe0, 0x3fff ), rax_control_r }, /* control registers */
{ ADSP_PGM_ADDR_RANGE( 0x0000, 0x3fff ), MRA16_RAM }, /* internal program RAM */
MEMORY_END
MEMORY_WRITE16_START( acclaim_rax_writemem )
{ ADSP_DATA_ADDR_RANGE( 0x0000, 0x1fff ), MWA16_BANK14 },
{ ADSP_DATA_ADDR_RANGE( 0x2000, 0x3fdf ), MWA16_RAM },
{ ADSP_DATA_ADDR_RANGE( 0x3fe0, 0x3fff ), rax_control_w },
{ ADSP_PGM_ADDR_RANGE( 0x0000, 0x3fff ), MWA16_RAM },
MEMORY_END
static void rax_presave( void )
{
rax_reg_timer_left = timer_timeleft( rax_reg_timer );
rax_dma_timer_left = timer_timeleft( rax_dma_timer );
}
static void rax_postload( void )
{
rax_update_data_ram_bank();
if( rax_reg_timer_period > 0 && rax_reg_timer_left < TIME_NEVER / 2 )
timer_adjust( rax_reg_timer, ( rax_reg_timer_left > 0 ) ? rax_reg_timer_left : 0, 0, rax_reg_timer_period );
else
timer_adjust( rax_reg_timer, TIME_NEVER, 0, 0 );
if( rax_dma_timer_left < TIME_NEVER / 2 )
timer_adjust( rax_dma_timer, ( rax_dma_timer_left > 0 ) ? rax_dma_timer_left : 0, rax_dma_param, 0 );
else
timer_adjust( rax_dma_timer, TIME_NEVER, 0, 0 );
}
void acclaim_rax_init( int cpunum, int region )
{
rax_cpunum = cpunum;
rax_rom = memory_region( region );
rax_rom_banks = memory_region_length( region ) / 0x400000;
if( rax_rom_banks < 1 )
rax_rom_banks = 1;
rax_banked_ram = auto_malloc( 0x2000 * 5 * sizeof( UINT16 ) );
memset( rax_banked_ram, 0, 0x2000 * 5 * sizeof( UINT16 ) );
rax_reg_timer = timer_alloc( rax_irq );
rax_dma_timer = timer_alloc( rax_dma_done );
adsp2181_set_tx_callback( rax_tx_callback );
adsp2181_set_io_callbacks( rax_io_r, rax_io_w );
adsp2181_set_dmovlay_callback( rax_dmovlay_w );
state_save_register_UINT16( "rax", 0, "banked_ram", rax_banked_ram, 0x2000 * 5 );
state_save_register_UINT16( "rax", 0, "control_regs", rax_control_regs, 32 );
state_save_register_UINT16( "rax", 0, "data_in", &rax_data_in, 1 );
state_save_register_UINT16( "rax", 0, "data_out", &rax_data_out, 1 );
state_save_register_UINT8( "rax", 0, "pf0", &rax_pf0, 1 );
state_save_register_UINT16( "rax", 0, "data_bank", &rax_data_bank, 1 );
state_save_register_UINT16( "rax", 0, "rom_bank", &rax_rom_bank, 1 );
state_save_register_UINT32( "rax", 0, "dmovlay", &rax_dmovlay, 1 );
state_save_register_UINT16( "rax", 0, "size", &rax_size, 1 );
state_save_register_UINT16( "rax", 0, "incs", &rax_incs, 1 );
state_save_register_INT32( "rax", 0, "ireg", &rax_ireg, 1 );
state_save_register_UINT16( "rax", 0, "ireg_base", &rax_ireg_base, 1 );
state_save_register_UINT8( "rax", 0, "dac_enabled", rax_dac_enabled, 2 );
state_save_register_double( "rax", 0, "reg_timer_period", &rax_reg_timer_period, 1 );
state_save_register_double( "rax", 0, "reg_timer_left", &rax_reg_timer_left, 1 );
state_save_register_double( "rax", 0, "dma_timer_left", &rax_dma_timer_left, 1 );
state_save_register_UINT32( "rax", 0, "dma_param", &rax_dma_param, 1 );
state_save_register_UINT32( "rax", 0, "buffer_in", rax_buffer_in, 2 );
state_save_register_UINT32( "rax", 0, "buffer_out", rax_buffer_out, 2 );
state_save_register_UINT32( "rax", 0, "sample_rate", &rax_sample_rate, 1 );
state_save_register_UINT32( "rax", 0, "sample_step", &rax_sample_step, 1 );
state_save_register_UINT32( "rax", 0, "sample_position", &rax_sample_position, 1 );
state_save_register_func_presave( rax_presave );
state_save_register_func_postload( rax_postload );
}
void acclaim_rax_reset( void )
{
UINT32 *pgm = (UINT32 *)( memory_region( REGION_CPU1 + rax_cpunum ) + ADSP2181_PGM_OFFSET );
int i;
/* the boot: 32 program words (96 bytes) from the ROM, as by BDMA */
for( i = 0; i < 32; i++ )
pgm[ i ] = ( rax_rom[ i * 3 + 0 ] << 16 ) | ( rax_rom[ i * 3 + 1 ] << 8 ) | rax_rom[ i * 3 + 2 ];
rax_pf0 = 1;
rax_rom_bank = 0;
rax_size = 0;
rax_incs = 0;
rax_ireg = 0;
memset( rax_control_regs, 0, sizeof( rax_control_regs ) );
rax_dmovlay = 0;
rax_data_bank = 0;
rax_update_data_ram_bank();
rax_dac_enabled[ 0 ] = rax_dac_enabled[ 1 ] = 0;
rax_buffer_in[ 0 ] = rax_buffer_out[ 0 ] = rax_buffer_in[ 1 ] = rax_buffer_out[ 1 ] = 0;
rax_sample_position = 0;
rax_sample_step = 0x10000;
rax_reg_timer_period = 0;
timer_adjust( rax_reg_timer, TIME_NEVER, 0, 0 );
timer_adjust( rax_dma_timer, TIME_NEVER, 0, 0 );
}
/* from the main CPU: a command, IRQL0 on the ADSP */
void acclaim_rax_data_w( UINT16 data )
{
rax_data_in = data;
cpu_set_irq_line( rax_cpunum, ADSP2181_IRQL0, ASSERT_LINE );
cpu_boost_interleave( 0, TIME_IN_USEC( 5 ) );
}
+21
View File
@@ -0,0 +1,21 @@
/***************************************************************************
Acclaim RAX sound board (sndhrdw/acclaim_rax.c)
***************************************************************************/
#ifndef ACCLAIM_RAX_H
#define ACCLAIM_RAX_H
#define RAX_CLOCK 16670000
/* the ADSP-2181 tagged "rax": its memory map, and the two DACs as a custom sound */
extern const struct Memory_ReadAddress16 acclaim_rax_readmem[];
extern const struct Memory_WriteAddress16 acclaim_rax_writemem[];
extern struct CustomSound_interface acclaim_rax_custom_interface;
void acclaim_rax_init( int cpunum, int region ); /* driver init: the ADSP CPU and its ROM region */
void acclaim_rax_reset( void ); /* machine init */
void acclaim_rax_data_w( UINT16 data ); /* a command from the host */
#endif
+424 -387
View File
File diff suppressed because it is too large. Load diff
+2 -2
View File
@@ -47,7 +47,7 @@ void LFO_Init(void)
if(i<128)
p=i;
else
p=255-i;
p=i-256; /* current MAME */
ALFO_SAW[i]=a;
PLFO_SAW[i]=p;
@@ -130,7 +130,7 @@ static INLINE signed int ALFO_Step(struct _LFO *LFO)
void LFO_ComputeStep(struct _LFO *LFO,data32_t LFOF,data32_t LFOWS,data32_t LFOS,int ALFO)
{
float step=(float) LFOFreq[LFOF]*256.0/(float)Machine->sample_rate;
float step=(float) LFOFreq[LFOF]*256.0/44100.0; /* the SCSP runs at 44100 Hz */
LFO->phase_step=(unsigned int) ((float) (1<<LFO_SHIFT)*step);
if(ALFO)
{