Added echo emulation to the OkiM6376 sound chip [J. Wallace]

This commit is contained in:
Angelo Salese 2011-06-05 21:53:19 +00:00
parent 7506e9cf13
commit 69ece3433c
4 changed files with 262 additions and 118 deletions

View File

@ -6,7 +6,10 @@
* TODO: * TODO:
* add BEEP tone generator * add BEEP tone generator
* add 2ch handling (for echoing and continuous speech) * add 2ch handling (for echoing and continuous speech)
* * add echo
* Something is definitely not right with the rates and divisions here - the maximum
* oscillation frequency should only be 256KHz, yet this only sounds decent at 3MHz
* add proper NAR handling - this varies with clock rate
**********************************************************************************************/ **********************************************************************************************/
@ -36,10 +39,19 @@ struct _okim6376_state
{ {
#define OKIM6376_VOICES 2 #define OKIM6376_VOICES 2
struct ADPCMVoice voice[OKIM6376_VOICES]; struct ADPCMVoice voice[OKIM6376_VOICES];
INT32 command; INT32 command[OKIM6376_VOICES];
INT32 latch; /* Command data is held before transferring to either channel */
UINT8 *region_base; /* pointer to the base of the region */ UINT8 *region_base; /* pointer to the base of the region */
sound_stream *stream; /* which stream are we playing on? */ sound_stream *stream; /* which stream are we playing on? */
UINT32 master_clock; /* master clock frequency */ UINT32 master_clock; /* master clock frequency */
UINT8 channel;
UINT8 nar; /* Next Address Ready */
UINT8 busy;
UINT8 ch2; /* 2CH pin - enables Channel 2 operation */
UINT8 st; /* STart */
UINT8 st_pulses; /* Keep track of attenuation */
UINT8 ch2_update; /* Pulse shape */
UINT8 st_update;
}; };
/* step size index shift table */ /* step size index shift table */
@ -49,13 +61,13 @@ static const int index_shift[8] = { -1, -1, -1, -1, 2, 4, 6, 8 };
static int diff_lookup[49*16]; static int diff_lookup[49*16];
/* volume lookup table. Upon configuration, the number of ST pulses determine how much /* volume lookup table. Upon configuration, the number of ST pulses determine how much
attenuation to apply to the sound signal. */ attenuation to apply to the sound signal. However, this only applies to the second
static const int volume_table[4] = channel*/
static const int volume_table[3] =
{ {
0x20, // 0 dB 0x20, // 0 dB
0x10, // -6.0 dB 0x10, // -6.0 dB
0x08, // -12.0 dB 0x08, // -12.0 dB
0x04, // -24.0 dB
}; };
/* tables computed? */ /* tables computed? */
@ -279,13 +291,82 @@ static void adpcm_state_save_register(struct ADPCMVoice *voice, device_t *device
static void okim6376_state_save_register(okim6376_state *info, device_t *device) static void okim6376_state_save_register(okim6376_state *info, device_t *device)
{ {
int j; int j;
device->save_item(NAME(info->command));
for (j = 0; j < OKIM6376_VOICES; j++) for (j = 0; j < OKIM6376_VOICES; j++)
{
adpcm_state_save_register(&info->voice[j], device, j); adpcm_state_save_register(&info->voice[j], device, j);
}
device->save_item(NAME(info->command[0]));
device->save_item(NAME(info->command[1]));
} }
static void oki_process(device_t *device, int channel, int command)
{
okim6376_state *info = get_safe_token(device);
/* if a command is pending, process the second half */
if ((command != -1) && (command != 0)) //process silence separately
{
int start;
unsigned char *base/*, *base_end*/;
info->nar = 0;//processing
/* update the stream */
info->stream->update();
/* determine which voice(s) (voice is set by the state of 2CH) */
{
struct ADPCMVoice *voice = &info->voice[channel];
/* determine the start position, max address space is 16Mbit */
base = &info->region_base[info->command[channel] * 4];
//base_end = &info->region_base[(MAX_WORDS+1) * 4];
start = ((base[0] << 16) + (base[1] << 8) + base[2]) & 0x1fffff;
if (start == 0)
{
voice->playing = 0;
}
else
{
/* set up the voice to play this sample */
if (!voice->playing)
{
voice->playing = 1;
voice->base_offset = start;
voice->sample = 0;
voice->count = 0;
/* also reset the ADPCM parameters */
reset_adpcm(voice);
/* FIX: no attenuation for now, handle for channel 2 separately */
voice->volume = volume_table[0];
}
else
{
logerror("OKIM6376:'%s' requested to play sample %02x on non-stopped voice\n",device->tag(),info->command[channel]);
}
}
info->nar = 1;
}
}
/* otherwise, see if this is a silence command */
else
{
info->nar = 0;
/* update the stream, then turn it off */
info->stream->update();
if (command ==0)
{
int i;
for (i = 0; i < OKIM6376_VOICES; i++)
{
struct ADPCMVoice *voice = &info->voice[i];
voice->playing = 0;
}
info->nar = 1;
}
}
}
/********************************************************************************************** /**********************************************************************************************
@ -301,10 +382,17 @@ static DEVICE_START( okim6376 )
compute_tables(); compute_tables();
info->command = -1; info->command[0] = -1;
info->command[1] = -1;
info->latch = 0;
info->region_base = *device->region(); info->region_base = *device->region();
info->master_clock = device->clock(); info->master_clock = device->clock();
info->nar = 1;
info->busy = 1;
info->st = 1;
info->st_update = 0;
info->ch2_update = 0;
info->st_pulses = 0;
/* generate the name and create the stream */ /* generate the name and create the stream */
info->stream = device->machine().sound().stream_alloc(*device, 0, 1, device->clock()/divisor, info, okim6376_update); info->stream = device->machine().sound().stream_alloc(*device, 0, 1, device->clock()/divisor, info, okim6376_update);
@ -319,7 +407,13 @@ static DEVICE_START( okim6376 )
okim6376_state_save_register(info, device); okim6376_state_save_register(info, device);
} }
void okim6376_set_frequency(device_t *device, int frequency)
{
okim6376_state *info = get_safe_token(device);
info->master_clock = frequency;
info->stream->set_sample_rate(info->master_clock / 165);
}
/********************************************************************************************** /**********************************************************************************************
@ -368,6 +462,91 @@ READ8_DEVICE_HANDLER( okim6376_r )
} }
READ_LINE_DEVICE_HANDLER( okim6376_busy_r )
{
okim6376_state *info = get_safe_token(device);
int i,result=1;
for (i = 0; i < OKIM6376_VOICES; i++)
{
struct ADPCMVoice *voice = &info->voice[i];
/* set the bit low if it's playing */
if (voice->playing)
result = 0;
}
return result;
}
READ_LINE_DEVICE_HANDLER( okim6376_nar_r )
{
okim6376_state *info = get_safe_token(device);
return info->nar;
}
WRITE_LINE_DEVICE_HANDLER( okim6376_ch2_w )
{
okim6376_state *info = get_safe_token(device);
if (info->ch2 != state)
{
info->ch2 = state;
info->ch2_update = 1;
}
if((!info->ch2)&&(info->ch2_update))
{
info->channel = 1;
if (info->command[1] != info->latch)
{
info->command[1] = info->latch;
}
}
if((info->ch2)&&(info->ch2_update))
{
info->channel = 0;
oki_process(device, 0, info->command[1]);
}
}
WRITE_LINE_DEVICE_HANDLER( okim6376_st_w )
{
//As in STart, presumably, this triggers everything
okim6376_state *info = get_safe_token(device);
if (info->st != state)
{
info->st = state;
info->st_update = 1;
if ((info->channel == 1) & !info->st)//ST acts as attenuation for Channel 2 when low, and stays at that level until the channel is reset
{
struct ADPCMVoice *voice = &info->voice[info->channel];
{
info->st_pulses ++;
if (info->st_pulses > 3)
{
info->st_pulses = 3; //undocumented behaviour beyond 3 pulses
}
voice->volume = volume_table[info->st_pulses];
}
}
if (info->st && info->st_update)
{
info->command[info->channel] = info->latch;
if (info->channel ==0)
{
oki_process(device, 0, info->command[0]);
}
}
}
}
/********************************************************************************************** /**********************************************************************************************
@ -377,92 +556,12 @@ READ8_DEVICE_HANDLER( okim6376_r )
WRITE8_DEVICE_HANDLER( okim6376_w ) WRITE8_DEVICE_HANDLER( okim6376_w )
{ {
// The data port is purely used to set the latch, everything else is started by an ST pulse
okim6376_state *info = get_safe_token(device); okim6376_state *info = get_safe_token(device);
info->latch = data & 0x7f;
/* if a command is pending, process the second half */ // FIX: maximum adpcm words are 111, there are other 8 commands to generate BEEP tone (0x70 to 0x77),
if (info->command != -1) // and others for internal testing, that manual explicitly says not to use (0x78 to 0x7f)
{
int temp = data >> 4, i, start;
unsigned char *base/*, *base_end*/;
/* FIX: Check if it's possible to start multiple voices at the same time */
if (temp != 0 && temp != 1 && temp != 2)
popmessage("OKI6376 start %x contact MAMEDEV", temp);
/* update the stream */
info->stream->update();
/* determine which voice(s) (voice is set by a 1 bit in the upper 4 bits of the second byte) */
for (i = 0; i < OKIM6376_VOICES; i++, temp >>= 1)
{
if (temp & 1)
{
struct ADPCMVoice *voice = &info->voice[i];
/* determine the start position, max address space is 16Mbit */
base = &info->region_base[info->command * 4];
//base_end = &info->region_base[(MAX_WORDS+1) * 4];
start = ((base[0] << 16) + (base[1] << 8) + base[2]) & 0x1fffff;
if (start == 0)
{
voice->playing = 0;
}
else
{
/* set up the voice to play this sample */
if (!voice->playing)
{
voice->playing = 1;
voice->base_offset = start;
voice->sample = 0;
voice->count = 0;
/* also reset the ADPCM parameters */
reset_adpcm(voice);
/* FIX: no attenuation for now */
voice->volume = volume_table[0];
}
else
{
logerror("OKIM6376:'%s' requested to play sample %02x on non-stopped voice\n",device->tag(),info->command);
}
}
}
}
/* reset the command */
info->command = -1;
}
/* if this is the start of a command, remember the sample number for next time */
else if (data & 0x80)
{
// FIX: maximum adpcm words are 111, there are other 8 commands to generate BEEP tone (0x70 to 0x77),
// and others for internal testing, that manual explicitly says not to use (0x78 to 0x7f)
info->command = data & 0x7f;
}
/* otherwise, see if this is a silence command */
else
{
int temp = data >> 3, i;
/* update the stream, then turn it off */
info->stream->update();
/* determine which voice(s) (voice is set by a 1 bit in bits 3-6 of the command */
for (i = 0; i < OKIM6376_VOICES; i++, temp >>= 1)
{
if (temp & 1)
{
struct ADPCMVoice *voice = &info->voice[i];
voice->playing = 0;
}
}
}
} }
@ -476,18 +575,18 @@ DEVICE_GET_INFO( okim6376 )
switch (state) switch (state)
{ {
/* --- the following bits of info are returned as 64-bit signed integers --- */ /* --- the following bits of info are returned as 64-bit signed integers --- */
case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(okim6376_state); break; case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(okim6376_state); break;
/* --- the following bits of info are returned as pointers to data or functions --- */ /* --- the following bits of info are returned as pointers to data or functions --- */
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( okim6376 ); break; case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( okim6376 ); break;
case DEVINFO_FCT_STOP: /* nothing */ break; case DEVINFO_FCT_STOP: /* nothing */ break;
case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( okim6376 ); break; case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME( okim6376 ); break;
/* --- the following bits of info are returned as NULL-terminated strings --- */ /* --- the following bits of info are returned as NULL-terminated strings --- */
case DEVINFO_STR_NAME: strcpy(info->s, "OKI6376"); break; case DEVINFO_STR_NAME: strcpy(info->s, "OKI6376"); break;
case DEVINFO_STR_FAMILY: strcpy(info->s, "OKI ADPCM"); break; case DEVINFO_STR_FAMILY: strcpy(info->s, "OKI ADPCM"); break;
case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break; case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break; case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright Nicola Salmoria and the MAME Team"); break;
} }
} }

View File

@ -12,4 +12,14 @@ WRITE8_DEVICE_HANDLER( okim6376_w );
DECLARE_LEGACY_SOUND_DEVICE(OKIM6376, okim6376); DECLARE_LEGACY_SOUND_DEVICE(OKIM6376, okim6376);
WRITE_LINE_DEVICE_HANDLER( okim6376_st_w );
WRITE_LINE_DEVICE_HANDLER( okim6376_ch2_w );
READ_LINE_DEVICE_HANDLER( okim6376_busy_r );
READ_LINE_DEVICE_HANDLER( okim6376_nar_r );
DECLARE_LEGACY_SOUND_DEVICE(OKIM6376, okim6376);
void okim6376_set_frequency(device_t *device, int frequency);
#endif /* __OKIM6376_H__ */ #endif /* __OKIM6376_H__ */

View File

@ -26,7 +26,7 @@ Port layout:
0x0000 W Keyboard Lights control port 0x0000 W Keyboard Lights control port
0x0002 W \ Hopper or ticket related 0x0002 W \ Hopper or ticket related
0x0004 W / 0x0004 W /
0x0006 W OKI6395 ADPCM command: need to be latched 0x0006 W OKI6395 (6376?)ADPCM command: need to be latched
0x0010 W Like 0x3c8 in VGA 0x0010 W Like 0x3c8 in VGA
0x0014 W Like 0x3c9 in VGA 0x0014 W Like 0x3c9 in VGA
@ -235,16 +235,26 @@ static WRITE16_HANDLER( tv_vcf_bankselect_w )
} }
static WRITE16_DEVICE_HANDLER( tv_oki6395_w ) static WRITE16_DEVICE_HANDLER( tv_oki6376_w )
{ {
static int okidata; static int okidata;
if (ACCESSING_BITS_0_7 && okidata != data) { if (ACCESSING_BITS_0_7 && okidata != data)
{
okidata = data; okidata = data;
okim6376_w(device, 0, data); okim6376_w(device, 0, data & ~0x80);
okim6376_w(device, 0, (1 << 4)); okim6376_st_w (device, data & 0x80);
} }
} }
static READ16_DEVICE_HANDLER( tv_oki6376_r )
{
if (ACCESSING_BITS_0_7)
{
return okim6376_busy_r(device);
}
return 0xff;
}
static WRITE16_HANDLER( write1_w ) static WRITE16_HANDLER( write1_w )
{ {
/* /*
@ -278,12 +288,12 @@ ADDRESS_MAP_END
static ADDRESS_MAP_START( tv_vcf_io, AS_IO, 16 ) static ADDRESS_MAP_START( tv_vcf_io, AS_IO, 16 )
AM_RANGE(0x0000, 0x0001) AM_WRITE( write1_w ) // lamps AM_RANGE(0x0000, 0x0001) AM_WRITE( write1_w ) // lamps
AM_RANGE(0x0006, 0x0007) AM_DEVWRITE( "oki", tv_oki6395_w ) AM_RANGE(0x0006, 0x0007) AM_DEVWRITE( "oki", tv_oki6376_w )
AM_RANGE(0x0008, 0x0009) AM_READ( read1_r ) AM_RANGE(0x0008, 0x0009) AM_READ( read1_r )
AM_RANGE(0x000a, 0x000b) AM_READ( read2_r ) AM_RANGE(0x000a, 0x000b) AM_READ( read2_r )
AM_RANGE(0x000c, 0x000d) AM_READ( read3_r ) AM_RANGE(0x000c, 0x000d) AM_READ( read3_r )
AM_RANGE(0x0010, 0x0015) AM_WRITE( tv_vcf_paletteram_w ) AM_RANGE(0x0010, 0x0015) AM_WRITE( tv_vcf_paletteram_w )
AM_RANGE(0x0030, 0x0031) AM_WRITE( tv_vcf_bankselect_w ) AM_DEVREAD8( "oki", okim6376_r, 0x00ff ) AM_RANGE(0x0030, 0x0031) AM_WRITE( tv_vcf_bankselect_w ) AM_DEVREAD( "oki", tv_oki6376_r )
ADDRESS_MAP_END ADDRESS_MAP_END
@ -298,15 +308,23 @@ static READ16_HANDLER( tv_ncf_read2_r )
return (input_port_read(space->machine(), "IN1") & 0xbf) | resetpulse; return (input_port_read(space->machine(), "IN1") & 0xbf) | resetpulse;
} }
static WRITE16_DEVICE_HANDLER( tv_ncf_oki6395_w ) static WRITE16_DEVICE_HANDLER( tv_ncf_oki6376_w )
{ {
static int okidata; static int okidata;
if (ACCESSING_BITS_0_7 && okidata != data) { if (ACCESSING_BITS_0_7 && okidata != data) {
okidata = data; okidata = data;
okim6376_w(device, 0, data | 0x80); okim6376_w(device, 0, data );
okim6376_w(device, 0, (1 << 4));
} }
} }
static WRITE16_DEVICE_HANDLER( tv_ncf_oki6376_st_w )
{
if (ACCESSING_BITS_0_7)
{
okim6376_st_w(device, (data & 0x80) );
}
}
static ADDRESS_MAP_START( tv_ncf_map, AS_PROGRAM, 16 ) static ADDRESS_MAP_START( tv_ncf_map, AS_PROGRAM, 16 )
AM_RANGE(0x00000, 0x003ff) AM_RAM /*irq vector area*/ AM_RANGE(0x00000, 0x003ff) AM_RAM /*irq vector area*/
AM_RANGE(0x00400, 0x03fff) AM_RAM AM_SHARE("nvram") AM_RANGE(0x00400, 0x03fff) AM_RAM AM_SHARE("nvram")
@ -317,7 +335,8 @@ ADDRESS_MAP_END
static ADDRESS_MAP_START( tv_ncf_io, AS_IO, 16 ) static ADDRESS_MAP_START( tv_ncf_io, AS_IO, 16 )
AM_RANGE(0x0000, 0x0001) AM_WRITE( write1_w ) // lamps AM_RANGE(0x0000, 0x0001) AM_WRITE( write1_w ) // lamps
AM_RANGE(0x0008, 0x0009) AM_DEVWRITE( "oki", tv_ncf_oki6395_w ) AM_RANGE(0x0008, 0x0009) AM_DEVWRITE( "oki", tv_ncf_oki6376_w )
AM_RANGE(0x000a, 0x000b) AM_DEVWRITE( "oki", tv_ncf_oki6376_st_w )
AM_RANGE(0x000c, 0x000d) AM_READ( read1_r ) AM_RANGE(0x000c, 0x000d) AM_READ( read1_r )
AM_RANGE(0x0010, 0x0011) AM_READ( tv_ncf_read2_r ) AM_RANGE(0x0010, 0x0011) AM_READ( tv_ncf_read2_r )
AM_RANGE(0x0012, 0x0013) AM_READ( read3_r ) AM_RANGE(0x0012, 0x0013) AM_READ( read3_r )
@ -361,7 +380,7 @@ ADDRESS_MAP_END
static ADDRESS_MAP_START( tv_tcf_io, AS_IO, 16 ) static ADDRESS_MAP_START( tv_tcf_io, AS_IO, 16 )
AM_RANGE(0x0000, 0x0001) AM_WRITE( write1_w ) // lamps AM_RANGE(0x0000, 0x0001) AM_WRITE( write1_w ) // lamps
AM_RANGE(0x0006, 0x0007) AM_DEVWRITE( "oki", tv_oki6395_w ) AM_RANGE(0x0006, 0x0007) AM_DEVWRITE( "oki", tv_oki6376_w )
AM_RANGE(0x0008, 0x0009) AM_READ( read1_r ) AM_RANGE(0x0008, 0x0009) AM_READ( read1_r )
AM_RANGE(0x000a, 0x000b) AM_READ( read2_r ) AM_RANGE(0x000a, 0x000b) AM_READ( read2_r )
AM_RANGE(0x0030, 0x0031) AM_READ( read3_r ) AM_WRITE( tv_tcf_bankselect_w ) AM_RANGE(0x0030, 0x0031) AM_READ( read3_r ) AM_WRITE( tv_tcf_bankselect_w )
@ -423,7 +442,7 @@ static ADDRESS_MAP_START( newmcard_io, AS_IO, 16 )
AM_RANGE(0x0000, 0x0001) AM_WRITE( write1_w ) // lamps AM_RANGE(0x0000, 0x0001) AM_WRITE( write1_w ) // lamps
AM_RANGE(0x0002, 0x0003) AM_WRITE( write2_w ) // coin counter & coin lockout AM_RANGE(0x0002, 0x0003) AM_WRITE( write2_w ) // coin counter & coin lockout
AM_RANGE(0x0004, 0x0005) AM_WRITE( newmcard_vblank_w ) AM_RANGE(0x0004, 0x0005) AM_WRITE( newmcard_vblank_w )
AM_RANGE(0x0006, 0x0007) AM_DEVWRITE( "oki", tv_oki6395_w ) AM_RANGE(0x0006, 0x0007) AM_DEVWRITE( "oki", tv_oki6376_w )
AM_RANGE(0x0008, 0x0009) AM_READ( read1_r ) AM_RANGE(0x0008, 0x0009) AM_READ( read1_r )
AM_RANGE(0x000a, 0x000b) AM_READ( read2_r ) AM_RANGE(0x000a, 0x000b) AM_READ( read2_r )
AM_RANGE(0x000c, 0x000d) AM_READ( newmcard_vblank_r ) AM_RANGE(0x000c, 0x000d) AM_READ( newmcard_vblank_r )
@ -491,7 +510,7 @@ static ADDRESS_MAP_START( brasil_io, AS_IO, 16 )
AM_RANGE(0x0030, 0x0031) AM_WRITE( brasil_status_w ) AM_RANGE(0x0030, 0x0031) AM_WRITE( brasil_status_w )
AM_RANGE(0x0000, 0x0001) AM_WRITE( write1_w ) // lamps AM_RANGE(0x0000, 0x0001) AM_WRITE( write1_w ) // lamps
AM_RANGE(0x0002, 0x0003) AM_WRITE( write2_w ) // coin counter & coin lockout AM_RANGE(0x0002, 0x0003) AM_WRITE( write2_w ) // coin counter & coin lockout
AM_RANGE(0x0006, 0x0007) AM_DEVWRITE( "oki", tv_oki6395_w ) AM_RANGE(0x0006, 0x0007) AM_DEVWRITE( "oki", tv_oki6376_w )
AM_RANGE(0x0008, 0x0009) AM_READ( read1_r ) AM_RANGE(0x0008, 0x0009) AM_READ( read1_r )
AM_RANGE(0x000a, 0x000b) AM_READ( read2_r ) AM_RANGE(0x000a, 0x000b) AM_READ( read2_r )
AM_RANGE(0x000e, 0x000f) AM_READ( read3_r ) AM_RANGE(0x000e, 0x000f) AM_READ( read3_r )

View File

@ -4,6 +4,7 @@
This is the core driver, no video specific stuff should go in here. This is the core driver, no video specific stuff should go in here.
This driver holds all the mechanical games. This driver holds all the mechanical games.
05-2011: Add better OKI emulation - clock rate may be wrong but samples sound good now.
04-2011: More accurate gamball code, fixed ROM banking (Project Amber), added BwB CHR simulator (Amber) 04-2011: More accurate gamball code, fixed ROM banking (Project Amber), added BwB CHR simulator (Amber)
This is still a hard coded system, but significantly different to Barcrest's version. This is still a hard coded system, but significantly different to Barcrest's version.
Started adding support for the Crystal Gaming program card, and the link keys for setting parameters. Started adding support for the Crystal Gaming program card, and the link keys for setting parameters.
@ -217,8 +218,9 @@ TODO: - Distinguish door switches using manual
For now, we're ignoring any extra writes to strobes, as the alternative is to assign a timer to *everything* For now, we're ignoring any extra writes to strobes, as the alternative is to assign a timer to *everything*
- Flo's move in Great Escape gives spin alarms - need a different opto setting for reverse spin reels? - Flo's move in Great Escape gives spin alarms - need a different opto setting for reverse spin reels?
- Fix BwB characteriser, need to be able to calculate stabiliser bytes. Anyone fancy reading 6809 source? - Fix BwB characteriser, need to be able to calculate stabiliser bytes. Anyone fancy reading 6809 source?
- Fix MSM6376 - We're triggering 'contact MAMEDEV' since we need all features of the chip, - Fix MSM6376 - We need all features of the chip, including dynamic sample rate adjustment and BEEP.
including dynamic sample rate adjustment and BEEP. - OKI sound chip rate - need to confirm independently (3MHz sounds good, but that could be because
of the old driver - BwB manual claims 64KHz to 128KHz).
***********************************************************************************************************/ ***********************************************************************************************************/
#include "emu.h" #include "emu.h"
#include "machine/6821pia.h" #include "machine/6821pia.h"
@ -374,6 +376,7 @@ public:
int m_pageset; int m_pageset;
int m_hopper; int m_hopper;
int m_reels; int m_reels;
int m_chrdata;
const mpu4_chr_table* m_current_chr_table; const mpu4_chr_table* m_current_chr_table;
const bwb_chr_table* m_bwb_chr_table1; const bwb_chr_table* m_bwb_chr_table1;
//Video //Video
@ -1670,6 +1673,8 @@ static WRITE8_DEVICE_HANDLER( pia_gb_porta_w )
static WRITE8_DEVICE_HANDLER( pia_gb_portb_w ) static WRITE8_DEVICE_HANDLER( pia_gb_portb_w )
{ {
mpu4_state *state = device->machine().driver_data<mpu4_state>(); mpu4_state *state = device->machine().driver_data<mpu4_state>();
device_t *msm6376 = device->machine().device("msm6376");
int changed = state->m_expansion_latch^data; int changed = state->m_expansion_latch^data;
LOG_SS(("%s: GAMEBOARD: PIA Port A Set to %2x\n", device->machine().describe_context(),data)); LOG_SS(("%s: GAMEBOARD: PIA Port A Set to %2x\n", device->machine().describe_context(),data));
@ -1695,18 +1700,29 @@ static WRITE8_DEVICE_HANDLER( pia_gb_portb_w )
} }
} }
} }
okim6376_ch2_w(msm6376,data&0x02);
okim6376_st_w(msm6376,data&0x01);
} }
static READ8_DEVICE_HANDLER( pia_gb_portb_r ) static READ8_DEVICE_HANDLER( pia_gb_portb_r )
{ {
device_t *msm6376 = device->machine().device("msm6376"); device_t *msm6376 = device->machine().device("msm6376");
mpu4_state *state = device->machine().driver_data<mpu4_state>();
LOG_SS(("%s: GAMEBOARD: PIA Read of Port B\n",device->machine().describe_context())); LOG_SS(("%s: GAMEBOARD: PIA Read of Port B\n",device->machine().describe_context()));
int data=0;
// //
// b7, 1 = OKI ready, 0 = OKI busy // b7, 1 = OKI ready, 0 = OKI busy
// b5, vol clock // b5, vol clock
// b4, 1 = Vol down, 0 = Vol up // b4, 1 = Vol down, 0 = Vol up
// //
return okim6376_r(msm6376,0); if ( okim6376_busy_r(msm6376) ) data |= 0x80;
else data &= ~0x80;
if ( okim6376_nar_r(msm6376) ) data |= 0x40;
else data &= ~0x40;
return ( data | state->m_expansion_latch );
} }
static WRITE_LINE_DEVICE_HANDLER( pia_gb_ca2_w ) static WRITE_LINE_DEVICE_HANDLER( pia_gb_ca2_w )
@ -2883,7 +2899,7 @@ static MACHINE_CONFIG_DERIVED( mod4oki, mpu4mod2 )
MCFG_CPU_PROGRAM_MAP(mod4_oki_map) MCFG_CPU_PROGRAM_MAP(mod4_oki_map)
MCFG_DEVICE_REMOVE("ay8913") MCFG_DEVICE_REMOVE("ay8913")
MCFG_SOUND_ADD("msm6376", OKIM6376, 64000) //Dynamic, can also be 85430 at 10.5KHz and 128000 at 16KHz MCFG_SOUND_ADD("msm6376", OKIM6376, 3000000) //Wrong, needs to be 64 KHz, can also be 85430 at 10.5KHz and 128000 at 16KHz
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
MACHINE_CONFIG_END MACHINE_CONFIG_END