diff --git a/src/mess/audio/upd1771.c b/src/mess/audio/upd1771.c index 2fdfffabe0d..601e8b78f6f 100644 --- a/src/mess/audio/upd1771.c +++ b/src/mess/audio/upd1771.c @@ -162,13 +162,11 @@ **********************************************************************/ #include "emu.h" -#include "upd1771.h" +#include "audio/upd1771.h" #define LOG 0 -#define MAX_PACKET_SIZE 0x8000 - /* Each of the 8 waveforms have been sampled at 192kHz using period 0xFF, filtered, and each of the 32 levels have been calculated with averages on around 10 samples @@ -189,12 +187,11 @@ const char WAVEFORMS[8][32]={ }; - #define NOISE_SIZE 255 - static unsigned char noise_tbl[]= - { +static unsigned char noise_tbl[]= +{ 0x1c,0x86,0x8a,0x8f,0x98,0xa1,0xad,0xbe,0xd9,0x8a,0x66,0x4d,0x40,0x33,0x2b,0x23, 0x1e,0x8a,0x90,0x97,0xa4,0xae,0xb8,0xd6,0xec,0xe9,0x69,0x4a,0x3e,0x34,0x2d,0x27, 0x24,0x24,0x89,0x8e,0x93,0x9c,0xa5,0xb0,0xc1,0xdd,0x40,0x36,0x30,0x29,0x27,0x24, @@ -211,7 +208,7 @@ const char WAVEFORMS[8][32]={ 0x90,0x9a,0xa4,0xb2,0xc2,0xda,0xff,0x67,0x4c,0x3e,0x33,0x2d,0x25,0x24,0x1f,0x89, 0x8e,0x93,0x9c,0xa5,0xb1,0xc2,0xde,0x85,0x8e,0x98,0xa2,0xb0,0xc0,0xd9,0xfe,0x64, 0x4b,0x3b,0x31,0x2a,0x23,0x22,0x1e,0x88,0x8c,0x91,0x9b,0xa3,0xaf,0xc1,0xdc,0xdc - }; +}; @@ -220,51 +217,86 @@ const char WAVEFORMS[8][32]={ #define STATE_TONE 2 #define STATE_ADPCM 3 -struct upd1771_state + +const device_type UPD1771C = &device_creator; + + +upd1771c_device::upd1771c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, UPD1771C, "NEC uPD1771C 017", tag, owner, clock), + device_sound_interface(mconfig, *this) { - sound_stream *channel; - devcb_resolved_write_line ack_out_func; - emu_timer *timer; - - UINT8 packet[MAX_PACKET_SIZE]; - UINT32 index; - UINT8 expected_bytes; - - UINT8 state;//0:silence, 1 noise, 2 tone - UINT8 pc3; - - //tone - UINT8 t_timbre; //[0; 7] - UINT8 t_offset; //[0; 32] - UINT16 t_period; //[0;255] - UINT8 t_volume; //[0; 31] - UINT8 t_tpos;//timbre pos - UINT16 t_ppos;//period pos - - //noise wavetable LFSR - UINT8 nw_timbre; //[0; 7] - UINT8 nw_volume; //[0; 31] - UINT32 nw_period; - UINT32 nw_tpos; //timbre pos - UINT32 nw_ppos; //period pos - - //noise pulse components - UINT8 n_value[3]; //[0;1] - UINT16 n_volume[3]; //[0; 31] - UINT32 n_period[3]; - UINT32 n_ppos[3]; //period pos -}; - - -INLINE upd1771_state *get_safe_token(device_t *device) -{ - assert(device != NULL); - assert(device->type() == UPD1771C); - return (upd1771_state *)downcast(device)->token(); } -READ8_DEVICE_HANDLER( upd1771_r ) +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void upd1771c_device::device_config_complete() +{ + // inherit a copy of the static data + const upd1771_interface *intf = reinterpret_cast(static_config()); + if (intf != NULL) + *static_cast(this) = *intf; + + // or initialize to defaults if none provided + else + { + memset(&m_ack_callback, 0, sizeof(m_ack_callback)); + } +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void upd1771c_device::device_start() +{ + /* resolve callbacks */ + m_ack_out_func.resolve(m_ack_callback, *this); + + m_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(upd1771c_device::ack_callback),this)); + + m_channel = machine().sound().stream_alloc(*this, 0, 1, clock() / 4, this); + + save_item(NAME(m_packet)); + save_item(NAME(m_index)); + save_item(NAME(m_expected_bytes)); + save_item(NAME(m_state)); + save_item(NAME(m_pc3)); + save_item(NAME(m_t_timbre)); + save_item(NAME(m_t_offset)); + save_item(NAME(m_t_period)); + save_item(NAME(m_t_volume)); + save_item(NAME(m_t_tpos)); + save_item(NAME(m_t_ppos)); + save_item(NAME(m_nw_timbre)); + save_item(NAME(m_nw_volume)); + save_item(NAME(m_nw_period)); + save_item(NAME(m_nw_tpos)); + save_item(NAME(m_nw_ppos)); + save_item(NAME(m_n_value)); + save_item(NAME(m_n_volume)); + save_item(NAME(m_n_period)); + save_item(NAME(m_n_ppos)); +} + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void upd1771c_device::device_reset() +{ + m_index = 0; + m_expected_bytes = 0; + m_pc3 = 0; +} + + + +READ8_MEMBER( upd1771c_device::read ) { return 0x80; // TODO } @@ -331,288 +363,194 @@ Byte8: 0b???VVVVV Low Freq1 volume Byte9: 0b???VVVVV Low Freq2 volume */ -WRITE8_DEVICE_HANDLER( upd1771_w ) +WRITE8_MEMBER( upd1771c_device::write ) { - upd1771_state *state = get_safe_token( device ); - //if (LOG) // logerror( "upd1771_w: received byte 0x%02x\n", data ); - state->ack_out_func(0); + m_ack_out_func(0); - if (state->index < MAX_PACKET_SIZE) - state->packet[state->index++]=data; - else{ - logerror( "upd1771_w: received byte 0x%02x overload!\n", data ); + if (m_index < MAX_PACKET_SIZE) + m_packet[m_index++] = data; + else + { + logerror("upd1771_w: received byte 0x%02x overload!\n", data); return; } - switch(state->packet[0]){ + switch (m_packet[0]) + { case 0: - { - state->state = STATE_SILENCE; - state->index = 0; + m_state = STATE_SILENCE; + m_index = 0; //logerror( "upd1771_w: ----------------silence state reset\n"); - }break; - + break; + case 1: - { - if (state->index == 10){ - state->state = STATE_NOISE; - state->index = 0; - - state->nw_timbre = (state->packet[1] & 0xE0) >> 5; - state->nw_period = ((UINT32)state->packet[2]+1)<<7; - state->nw_volume = state->packet[3] & 0x1f; - + if (m_index == 10) + { + m_state = STATE_NOISE; + m_index = 0; + + m_nw_timbre = (m_packet[1] & 0xe0) >> 5; + m_nw_period = ((UINT32)m_packet[2] + 1) << 7; + m_nw_volume = m_packet[3] & 0x1f; + //very long clocked periods.. used for engine drones - state->n_period[0] = (((UINT32)state->packet[4])+1)<<7; - state->n_period[1] = (((UINT32)state->packet[5])+1)<<7; - state->n_period[2] = (((UINT32)state->packet[6])+1)<<7; - - state->n_volume[0] = state->packet[7]& 0x1f; - state->n_volume[1] = state->packet[8]& 0x1f; - state->n_volume[2] = state->packet[9]& 0x1f; - + m_n_period[0] = (((UINT32)m_packet[4]) + 1) << 7; + m_n_period[1] = (((UINT32)m_packet[5]) + 1) << 7; + m_n_period[2] = (((UINT32)m_packet[6]) + 1) << 7; + + m_n_volume[0] = m_packet[7] & 0x1f; + m_n_volume[1] = m_packet[8] & 0x1f; + m_n_volume[2] = m_packet[9] & 0x1f; + //logerror( "upd1771_w: ----------------noise state reset\n"); } else - state->timer->adjust( attotime::from_ticks( 512, device->clock() ) ); - }break; - + m_timer->adjust(attotime::from_ticks(512, clock())); + break; + case 2: - { - if (state->index == 4){ + if (m_index == 4) + { //logerror( "upd1771_w: ----------------tone state reset\n"); - state->t_timbre = (state->packet[1] & 0xE0) >> 5; - state->t_offset = (state->packet[1] & 0x1F); - state->t_period = state->packet[2]; + m_t_timbre = (m_packet[1] & 0xe0) >> 5; + m_t_offset = (m_packet[1] & 0x1f); + m_t_period = m_packet[2]; //smaller periods dont all equal to 0x20 - if (state->t_period < 0x20) - state->t_period = 0x20; - - state->t_volume = state->packet[3] & 0x1f; - state->state = STATE_TONE; - state->index = 0; + if (m_t_period < 0x20) + m_t_period = 0x20; + + m_t_volume = m_packet[3] & 0x1f; + m_state = STATE_TONE; + m_index = 0; } else - state->timer->adjust( attotime::from_ticks( 512, device->clock() ) ); + m_timer->adjust(attotime::from_ticks(512, clock())); + break; - }break; - - case 0x1F: - { + case 0x1f: //6Khz(ish) DIGI playback - + //end capture - if (state->index >= 2 && state->packet[state->index-2] == 0xFE && - state->packet[state->index-1] == 0x00){ + if (m_index >= 2 && m_packet[m_index - 2] == 0xfe && m_packet[m_index - 1] == 0x00) + { //TODO play capture! - state->index = 0; - state->packet[0]=0; - state->state = STATE_ADPCM; + m_index = 0; + m_packet[0] = 0; + m_state = STATE_ADPCM; } else - state->timer->adjust( attotime::from_ticks( 512, device->clock() ) ); - - }break; + m_timer->adjust(attotime::from_ticks(512, clock())); + break; //garbage: wipe stack default: - state->state = STATE_SILENCE; - state->index = 0; - break; + m_state = STATE_SILENCE; + m_index = 0; + break; } } -WRITE_LINE_DEVICE_HANDLER( upd1771_pcm_w ) +WRITE_LINE_MEMBER( upd1771c_device::pcm_write ) { - upd1771_state *upd1771 = get_safe_token( device ); - //RESET upon HIGH - if (state != upd1771->pc3){ - logerror( "upd1771_pc3 change!: state = %d\n", state ); - upd1771->index = 0; - upd1771->packet[0]=0; + if (state != m_pc3) + { + logerror("upd1771_pc3 change!: state = %d\n", state); + m_index = 0; + m_packet[0] = 0; } - upd1771->pc3 = state; + m_pc3 = state; } -static STREAM_UPDATE( upd1771c_update ) +TIMER_CALLBACK_MEMBER( upd1771c_device::ack_callback ) { - upd1771_state *state = get_safe_token( device ); - stream_sample_t *buffer = outputs[0]; - - switch(state->state){ - case STATE_TONE: - { - //logerror( "upd1771_STATE_TONE samps:%d %d %d %d %d %d\n",(int)samples, - // (int)state->t_timbre,(int)state->t_offset,(int)state->t_volume,(int)state->t_period,(int)state->t_tpos); - - while ( --samples >= 0 ){ - *buffer++ = (WAVEFORMS[state->t_timbre][state->t_tpos])*state->t_volume * 2; - - state->t_ppos++; - if (state->t_ppos >= state->t_period){ - state->t_tpos++; - if (state->t_tpos == 32) - state->t_tpos = state->t_offset; - - state->t_ppos = 0; - } - } - }break; - - case STATE_NOISE: - { - while (--samples >= 0 ){ - *buffer = 0; - - //"wavetable-LFSR" component - int wlfsr_val = ((int)noise_tbl[state->nw_tpos])-127;//data too wide - - state->nw_ppos++; - if (state->nw_ppos >= state->nw_period){ - state->nw_tpos++; - if (state->nw_tpos == NOISE_SIZE) - state->nw_tpos = 0; - state->nw_ppos = 0; - } - - //mix in each of the noise's 3 pulse components - char res[3]; - for (size_t i=0;i<3;++i){ - res[i] = state->n_value[i]* 127; - state->n_ppos[i]++; - if (state->n_ppos[i] >= state->n_period[i]){ - state->n_ppos[i] = 0; - state->n_value[i] = !state->n_value[i]; - } - } - //not quite, but close. - *buffer+= ( - (wlfsr_val*state->nw_volume) | - (res[0]*state->n_volume[0]) | - (res[1]*state->n_volume[1]) | - (res[2]*state->n_volume[2]) - ) ; - - buffer++; - } - }break; - - default: - { - //fill buffer with silence - while (--samples >= 0 ){ - *buffer++ = 0; - } - } - - break; - } - + m_ack_out_func(1); } -static TIMER_CALLBACK( upd1771c_callback ) -{ - device_t *device = (device_t *)ptr; - upd1771_state *state = get_safe_token( device ); - - state->ack_out_func(1); -} - - -static DEVICE_START( upd1771c ) -{ - const upd1771_interface *intf = (const upd1771_interface *)device->static_config(); - upd1771_state *state = get_safe_token( device ); - int sample_rate = device->clock() / 4; - - /* resolve callbacks */ - state->ack_out_func.resolve(intf->ack_callback, *device); - - state->timer = device->machine().scheduler().timer_alloc(FUNC(upd1771c_callback), (void *)device ); - - state->channel = device->machine().sound().stream_alloc( *device, 0, 1, sample_rate, state, upd1771c_update ); - - device->save_item( NAME(state->packet) ); - device->save_item(NAME(state->index) ); - device->save_item(NAME(state->expected_bytes) ); -} - - -static DEVICE_RESET( upd1771c ) -{ - upd1771_state *state = get_safe_token( device ); - - state->index = 0; - state->expected_bytes = 0; - state->pc3 = 0; -} - - -static DEVICE_STOP( upd1771c ) -{ -} - - -const device_type UPD1771C = &device_creator; - -upd1771c_device::upd1771c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : device_t(mconfig, UPD1771C, "NEC uPD1771C 017", tag, owner, clock), - device_sound_interface(mconfig, *this) -{ - m_token = global_alloc_clear(upd1771_state); -} - -//------------------------------------------------- -// device_config_complete - perform any -// operations now that the configuration is -// complete -//------------------------------------------------- - -void upd1771c_device::device_config_complete() -{ -} - -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void upd1771c_device::device_start() -{ - DEVICE_START_NAME( upd1771c )(this); -} - -//------------------------------------------------- -// device_reset - device-specific reset -//------------------------------------------------- - -void upd1771c_device::device_reset() -{ - DEVICE_RESET_NAME( upd1771c )(this); -} - -//------------------------------------------------- -// device_stop - device-specific stop -//------------------------------------------------- - -void upd1771c_device::device_stop() -{ - DEVICE_STOP_NAME( upd1771c )(this); -} - //------------------------------------------------- // sound_stream_update - handle a stream update //------------------------------------------------- void upd1771c_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) { - // should never get here - fatalerror("sound_stream_update called; not applicable to legacy sound devices\n"); + stream_sample_t *buffer = outputs[0]; + + switch (m_state) + { + case STATE_TONE: + //logerror( "upd1771_STATE_TONE samps:%d %d %d %d %d %d\n",(int)samples, + // (int)m_t_timbre,(int)m_t_offset,(int)m_t_volume,(int)m_t_period,(int)m_t_tpos); + + while (--samples >= 0) + { + *buffer++ = (WAVEFORMS[m_t_timbre][m_t_tpos]) * m_t_volume * 2; + + m_t_ppos++; + if (m_t_ppos >= m_t_period) + { + m_t_tpos++; + if (m_t_tpos == 32) + m_t_tpos = m_t_offset; + + m_t_ppos = 0; + } + } + break; + + case STATE_NOISE: + while (--samples >= 0) + { + *buffer = 0; + + //"wavetable-LFSR" component + int wlfsr_val = ((int)noise_tbl[m_nw_tpos]) - 127;//data too wide + + m_nw_ppos++; + if (m_nw_ppos >= m_nw_period) + { + m_nw_tpos++; + if (m_nw_tpos == NOISE_SIZE) + m_nw_tpos = 0; + m_nw_ppos = 0; + } + + //mix in each of the noise's 3 pulse components + char res[3]; + for (int i = 0; i < 3; ++i) + { + res[i] = m_n_value[i] * 127; + m_n_ppos[i]++; + if (m_n_ppos[i] >= m_n_period[i]) + { + m_n_ppos[i] = 0; + m_n_value[i] = !m_n_value[i]; + } + } + //not quite, but close. + *buffer+= ( + (wlfsr_val * m_nw_volume) | + (res[0] * m_n_volume[0]) | + (res[1] * m_n_volume[1]) | + (res[2] * m_n_volume[2]) + ) ; + + buffer++; + } + break; + + default: + //fill buffer with silence + while (--samples >= 0) + { + *buffer++ = 0; + } + break; + } } diff --git a/src/mess/audio/upd1771.h b/src/mess/audio/upd1771.h index 5f04cf522dc..a798bcd9550 100644 --- a/src/mess/audio/upd1771.h +++ b/src/mess/audio/upd1771.h @@ -9,13 +9,15 @@ #include "devcb.h" +#define MAX_PACKET_SIZE 0x8000 + /*************************************************************************** TYPE DEFINITIONS ***************************************************************************/ struct upd1771_interface { - devcb_write_line ack_callback; + devcb_write_line m_ack_callback; }; @@ -24,38 +26,64 @@ struct upd1771_interface ***************************************************************************/ class upd1771c_device : public device_t, - public device_sound_interface + public device_sound_interface, + public upd1771_interface { public: upd1771c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); - ~upd1771c_device() { global_free(m_token); } + ~upd1771c_device() {} - // access to legacy token - void *token() const { assert(m_token != NULL); return m_token; } + DECLARE_READ8_MEMBER( read ); + DECLARE_WRITE8_MEMBER( write ); + WRITE_LINE_MEMBER( pcm_write ); + protected: // device-level overrides virtual void device_config_complete(); virtual void device_start(); - virtual void device_stop(); virtual void device_reset(); // sound stream update overrides virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); + private: // internal state - void *m_token; + sound_stream *m_channel; + devcb_resolved_write_line m_ack_out_func; + emu_timer *m_timer; + + TIMER_CALLBACK_MEMBER(ack_callback); + + UINT8 m_packet[MAX_PACKET_SIZE]; + UINT32 m_index; + UINT8 m_expected_bytes; + + UINT8 m_state;//0:silence, 1 noise, 2 tone + UINT8 m_pc3; + + //tone + UINT8 m_t_timbre; //[0; 7] + UINT8 m_t_offset; //[0; 32] + UINT16 m_t_period; //[0;255] + UINT8 m_t_volume; //[0; 31] + UINT8 m_t_tpos;//timbre pos + UINT16 m_t_ppos;//period pos + + //noise wavetable LFSR + UINT8 m_nw_timbre; //[0; 7] + UINT8 m_nw_volume; //[0; 31] + UINT32 m_nw_period; + UINT32 m_nw_tpos; //timbre pos + UINT32 m_nw_ppos; //period pos + + //noise pulse components + UINT8 m_n_value[3]; //[0;1] + UINT16 m_n_volume[3]; //[0; 31] + UINT32 m_n_period[3]; + UINT32 m_n_ppos[3]; //period pos }; extern const device_type UPD1771C; - -/*************************************************************************** - PROTOTYPES -***************************************************************************/ - -DECLARE_READ8_DEVICE_HANDLER( upd1771_r ); -DECLARE_WRITE8_DEVICE_HANDLER( upd1771_w ); -WRITE_LINE_DEVICE_HANDLER( upd1771_pcm_w ); - #endif /* __UPD1771_H__ */ diff --git a/src/mess/drivers/apc.c b/src/mess/drivers/apc.c index 970ce57263c..e89aa9d4696 100644 --- a/src/mess/drivers/apc.c +++ b/src/mess/drivers/apc.c @@ -488,7 +488,7 @@ static ADDRESS_MAP_START( apc_io, AS_IO, 16, apc_state ) // 0x5a APU data (Arithmetic Processing Unit!) // 0x5b, Power Off // 0x5e APU status/command - AM_RANGE(0x60, 0x61) AM_DEVREADWRITE8_LEGACY("upd1771c", upd1771_r, upd1771_w, 0x00ff ) + AM_RANGE(0x60, 0x61) AM_DEVREADWRITE8("upd1771c", upd1771c_device, read, write, 0x00ff) // AM_RANGE(0x68, 0x6f) i8255 , ODA printer port (A: status (R) B: data (W) C: command (W)) // 0x70, 0x76 AM_DEVREADWRITE8("upd7220_btm", upd7220_device, read, write, 0x00ff) // 0x71, 0x77 IDA Controller diff --git a/src/mess/drivers/scv.c b/src/mess/drivers/scv.c index 5b5e17eba47..abded4e553d 100644 --- a/src/mess/drivers/scv.c +++ b/src/mess/drivers/scv.c @@ -86,7 +86,7 @@ static ADDRESS_MAP_START( scv_mem, AS_PROGRAM, 8, scv_state ) AM_RANGE( 0x2000, 0x3403 ) AM_RAM AM_SHARE("videoram") /* VRAM + 4 registers */ - AM_RANGE( 0x3600, 0x3600 ) AM_DEVWRITE_LEGACY("upd1771c", upd1771_w ) + AM_RANGE( 0x3600, 0x3600 ) AM_DEVWRITE("upd1771c", upd1771c_device, write) AM_RANGE( 0x8000, 0x9fff ) AM_ROMBANK("bank0") AM_RANGE( 0xa000, 0xbfff ) AM_ROMBANK("bank1") @@ -320,7 +320,7 @@ WRITE8_MEMBER( scv_state::scv_portc_w ) m_portc = data; scv_set_banks(); - upd1771_pcm_w( m_upd1771c, m_portc & 0x08 ); + m_upd1771c->pcm_write(m_portc & 0x08); }