mirror of
https://github.com/holub/mame
synced 2025-05-07 23:02:33 +03:00
Modernized the sp0250 device. (nw)
This commit is contained in:
parent
a2eb4802b0
commit
dd5917522b
@ -18,7 +18,6 @@
|
||||
|
||||
#include "emu.h"
|
||||
#include "sp0250.h"
|
||||
#include "devlegcy.h"
|
||||
|
||||
/*
|
||||
standard external clock is 3.12MHz
|
||||
@ -33,36 +32,84 @@ should be 312, but 312 = 39*8 so it doesn't look right because a divider by 39 i
|
||||
*/
|
||||
#define CLOCK_DIVIDER (7*6*8)
|
||||
|
||||
struct sp0250_state
|
||||
const device_type SP0250 = &device_creator<sp0250_device>;
|
||||
|
||||
sp0250_device::sp0250_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, SP0250, "SP0250", tag, owner, clock, "sp0250", __FILE__),
|
||||
device_sound_interface(mconfig, *this),
|
||||
m_amp(0),
|
||||
m_pitch(0),
|
||||
m_repeat(0),
|
||||
m_pcount(0),
|
||||
m_rcount(0),
|
||||
m_playing(0),
|
||||
m_RNG(0),
|
||||
m_stream(NULL),
|
||||
m_voiced(0),
|
||||
m_fifo_pos(0)
|
||||
{
|
||||
INT16 amp;
|
||||
UINT8 pitch;
|
||||
UINT8 repeat;
|
||||
int pcount, rcount;
|
||||
int playing;
|
||||
UINT32 RNG;
|
||||
sound_stream * stream;
|
||||
int voiced;
|
||||
UINT8 fifo[15];
|
||||
int fifo_pos;
|
||||
|
||||
device_t *device;
|
||||
void (*drq)(device_t *device, int state);
|
||||
|
||||
struct
|
||||
for (int i = 0; i < 15; i++)
|
||||
{
|
||||
INT16 F, B;
|
||||
INT16 z1, z2;
|
||||
} filter[6];
|
||||
};
|
||||
|
||||
INLINE sp0250_state *get_safe_token(device_t *device)
|
||||
{
|
||||
assert(device != NULL);
|
||||
assert(device->type() == SP0250);
|
||||
return (sp0250_state *)downcast<sp0250_device *>(device)->token();
|
||||
m_fifo[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
m_filter[i].F = 0;
|
||||
m_filter[i].B = 0;
|
||||
m_filter[i].z1 = 0;
|
||||
m_filter[i].z2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_config_complete - perform any
|
||||
// operations now that the configuration is
|
||||
// complete
|
||||
//-------------------------------------------------
|
||||
|
||||
void sp0250_device::device_config_complete()
|
||||
{
|
||||
// inherit a copy of the static data
|
||||
const sp0250_interface *intf = reinterpret_cast<const sp0250_interface *>(static_config());
|
||||
if (intf != NULL)
|
||||
*static_cast<sp0250_interface *>(this) = *intf;
|
||||
|
||||
// or initialize to defaults if none provided
|
||||
else
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void sp0250_device::device_start()
|
||||
{
|
||||
const sp0250_interface *intf = reinterpret_cast<const sp0250_interface *>(static_config());
|
||||
|
||||
m_RNG = 1;
|
||||
m_drq = ( intf!= NULL) ? m_drq_callback : NULL;
|
||||
if (m_drq != NULL)
|
||||
{
|
||||
m_drq(this, ASSERT_LINE);
|
||||
machine().scheduler().timer_pulse(attotime::from_hz(clock()) * CLOCK_DIVIDER, timer_expired_delegate(FUNC(sp0250_device::timer_tick), this));
|
||||
}
|
||||
|
||||
m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / CLOCK_DIVIDER, this);
|
||||
|
||||
save_item(NAME(m_amp));
|
||||
save_item(NAME(m_pitch));
|
||||
save_item(NAME(m_repeat));
|
||||
save_item(NAME(m_pcount));
|
||||
save_item(NAME(m_rcount));
|
||||
save_item(NAME(m_playing));
|
||||
save_item(NAME(m_RNG));
|
||||
save_item(NAME(m_voiced));
|
||||
save_item(NAME(m_fifo));
|
||||
save_item(NAME(m_fifo_pos));
|
||||
}
|
||||
|
||||
static UINT16 sp0250_ga(UINT8 v)
|
||||
{
|
||||
@ -90,180 +137,63 @@ static INT16 sp0250_gc(UINT8 v)
|
||||
return res;
|
||||
}
|
||||
|
||||
static void sp0250_load_values(sp0250_state *sp)
|
||||
void sp0250_device::load_values()
|
||||
{
|
||||
int f;
|
||||
|
||||
|
||||
sp->filter[0].B = sp0250_gc(sp->fifo[ 0]);
|
||||
sp->filter[0].F = sp0250_gc(sp->fifo[ 1]);
|
||||
sp->amp = sp0250_ga(sp->fifo[ 2]);
|
||||
sp->filter[1].B = sp0250_gc(sp->fifo[ 3]);
|
||||
sp->filter[1].F = sp0250_gc(sp->fifo[ 4]);
|
||||
sp->pitch = sp->fifo[ 5];
|
||||
sp->filter[2].B = sp0250_gc(sp->fifo[ 6]);
|
||||
sp->filter[2].F = sp0250_gc(sp->fifo[ 7]);
|
||||
sp->repeat = sp->fifo[ 8] & 0x3f;
|
||||
sp->voiced = sp->fifo[ 8] & 0x40;
|
||||
sp->filter[3].B = sp0250_gc(sp->fifo[ 9]);
|
||||
sp->filter[3].F = sp0250_gc(sp->fifo[10]);
|
||||
sp->filter[4].B = sp0250_gc(sp->fifo[11]);
|
||||
sp->filter[4].F = sp0250_gc(sp->fifo[12]);
|
||||
sp->filter[5].B = sp0250_gc(sp->fifo[13]);
|
||||
sp->filter[5].F = sp0250_gc(sp->fifo[14]);
|
||||
sp->fifo_pos = 0;
|
||||
if (sp->drq != NULL)
|
||||
sp->drq(sp->device, ASSERT_LINE);
|
||||
m_filter[0].B = sp0250_gc(m_fifo[ 0]);
|
||||
m_filter[0].F = sp0250_gc(m_fifo[ 1]);
|
||||
m_amp = sp0250_ga(m_fifo[ 2]);
|
||||
m_filter[1].B = sp0250_gc(m_fifo[ 3]);
|
||||
m_filter[1].F = sp0250_gc(m_fifo[ 4]);
|
||||
m_pitch = m_fifo[ 5];
|
||||
m_filter[2].B = sp0250_gc(m_fifo[ 6]);
|
||||
m_filter[2].F = sp0250_gc(m_fifo[ 7]);
|
||||
m_repeat = m_fifo[ 8] & 0x3f;
|
||||
m_voiced = m_fifo[ 8] & 0x40;
|
||||
m_filter[3].B = sp0250_gc(m_fifo[ 9]);
|
||||
m_filter[3].F = sp0250_gc(m_fifo[10]);
|
||||
m_filter[4].B = sp0250_gc(m_fifo[11]);
|
||||
m_filter[4].F = sp0250_gc(m_fifo[12]);
|
||||
m_filter[5].B = sp0250_gc(m_fifo[13]);
|
||||
m_filter[5].F = sp0250_gc(m_fifo[14]);
|
||||
m_fifo_pos = 0;
|
||||
if (m_drq != NULL)
|
||||
m_drq(this, ASSERT_LINE);
|
||||
|
||||
sp->pcount = 0;
|
||||
sp->rcount = 0;
|
||||
m_pcount = 0;
|
||||
m_rcount = 0;
|
||||
|
||||
for (f = 0; f < 6; f++)
|
||||
sp->filter[f].z1 = sp->filter[f].z2 = 0;
|
||||
m_filter[f].z1 = m_filter[f].z2 = 0;
|
||||
|
||||
sp->playing = 1;
|
||||
m_playing = 1;
|
||||
}
|
||||
|
||||
static TIMER_CALLBACK( sp0250_timer_tick )
|
||||
TIMER_CALLBACK_MEMBER( sp0250_device::timer_tick )
|
||||
{
|
||||
sp0250_state *sp = (sp0250_state *)ptr;
|
||||
sp->stream->update();
|
||||
m_stream->update();
|
||||
}
|
||||
|
||||
static STREAM_UPDATE( sp0250_update )
|
||||
WRITE8_MEMBER( sp0250_device::write )
|
||||
{
|
||||
sp0250_state *sp = (sp0250_state *)param;
|
||||
stream_sample_t *output = outputs[0];
|
||||
int i;
|
||||
for (i = 0; i < samples; i++)
|
||||
m_stream->update();
|
||||
if (m_fifo_pos != 15)
|
||||
{
|
||||
if (sp->playing)
|
||||
{
|
||||
INT16 z0;
|
||||
int f;
|
||||
|
||||
if (sp->voiced)
|
||||
{
|
||||
if(!sp->pcount)
|
||||
z0 = sp->amp;
|
||||
else
|
||||
z0 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Borrowing the ay noise generation LFSR
|
||||
if(sp->RNG & 1)
|
||||
{
|
||||
z0 = sp->amp;
|
||||
sp->RNG ^= 0x24000;
|
||||
}
|
||||
else
|
||||
z0 = -sp->amp;
|
||||
|
||||
sp->RNG >>= 1;
|
||||
}
|
||||
|
||||
for (f = 0; f < 6; f++)
|
||||
{
|
||||
z0 += ((sp->filter[f].z1 * sp->filter[f].F) >> 8)
|
||||
+ ((sp->filter[f].z2 * sp->filter[f].B) >> 9);
|
||||
sp->filter[f].z2 = sp->filter[f].z1;
|
||||
sp->filter[f].z1 = z0;
|
||||
}
|
||||
|
||||
// Physical resolution is only 7 bits, but heh
|
||||
|
||||
// max amplitude is 0x0f80 so we have margin to push up the output
|
||||
output[i] = z0 << 3;
|
||||
|
||||
sp->pcount++;
|
||||
if (sp->pcount >= sp->pitch)
|
||||
{
|
||||
sp->pcount = 0;
|
||||
sp->rcount++;
|
||||
if (sp->rcount >= sp->repeat)
|
||||
sp->playing = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
output[i] = 0;
|
||||
|
||||
if (!sp->playing)
|
||||
{
|
||||
if(sp->fifo_pos == 15)
|
||||
sp0250_load_values(sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static DEVICE_START( sp0250 )
|
||||
{
|
||||
const struct sp0250_interface *intf = (const struct sp0250_interface *)device->static_config();
|
||||
sp0250_state *sp = get_safe_token(device);
|
||||
|
||||
sp->device = device;
|
||||
sp->RNG = 1;
|
||||
sp->drq = (intf != NULL) ? intf->drq_callback : NULL;
|
||||
if (sp->drq != NULL)
|
||||
{
|
||||
sp->drq(sp->device, ASSERT_LINE);
|
||||
device->machine().scheduler().timer_pulse(attotime::from_hz(device->clock()) * CLOCK_DIVIDER, FUNC(sp0250_timer_tick), 0, sp);
|
||||
}
|
||||
|
||||
sp->stream = device->machine().sound().stream_alloc(*device, 0, 1, device->clock() / CLOCK_DIVIDER, sp, sp0250_update);
|
||||
}
|
||||
|
||||
|
||||
WRITE8_DEVICE_HANDLER( sp0250_w )
|
||||
{
|
||||
sp0250_state *sp = get_safe_token(device);
|
||||
sp->stream->update();
|
||||
if (sp->fifo_pos != 15)
|
||||
{
|
||||
sp->fifo[sp->fifo_pos++] = data;
|
||||
if (sp->fifo_pos == 15 && sp->drq != NULL)
|
||||
sp->drq(sp->device, CLEAR_LINE);
|
||||
m_fifo[m_fifo_pos++] = data;
|
||||
if (m_fifo_pos == 15 && m_drq != NULL)
|
||||
m_drq(this, CLEAR_LINE);
|
||||
}
|
||||
else
|
||||
logerror("%s: overflow SP0250 FIFO\n", device->machine().describe_context());
|
||||
logerror("%s: overflow SP0250 FIFO\n", machine().describe_context());
|
||||
}
|
||||
|
||||
|
||||
UINT8 sp0250_drq_r(device_t *device)
|
||||
UINT8 sp0250_device::drq_r()
|
||||
{
|
||||
sp0250_state *sp = get_safe_token(device);
|
||||
sp->stream->update();
|
||||
return (sp->fifo_pos == 15) ? CLEAR_LINE : ASSERT_LINE;
|
||||
}
|
||||
|
||||
|
||||
const device_type SP0250 = &device_creator<sp0250_device>;
|
||||
|
||||
sp0250_device::sp0250_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
||||
: device_t(mconfig, SP0250, "SP0250", tag, owner, clock, "sp0250", __FILE__),
|
||||
device_sound_interface(mconfig, *this)
|
||||
{
|
||||
m_token = global_alloc_clear(sp0250_state);
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_config_complete - perform any
|
||||
// operations now that the configuration is
|
||||
// complete
|
||||
//-------------------------------------------------
|
||||
|
||||
void sp0250_device::device_config_complete()
|
||||
{
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
//-------------------------------------------------
|
||||
|
||||
void sp0250_device::device_start()
|
||||
{
|
||||
DEVICE_START_NAME( sp0250 )(this);
|
||||
m_stream->update();
|
||||
return (m_fifo_pos == 15) ? CLEAR_LINE : ASSERT_LINE;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
@ -272,6 +202,65 @@ void sp0250_device::device_start()
|
||||
|
||||
void sp0250_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 *output = outputs[0];
|
||||
int i;
|
||||
for (i = 0; i < samples; i++)
|
||||
{
|
||||
if (m_playing)
|
||||
{
|
||||
INT16 z0;
|
||||
int f;
|
||||
|
||||
if (m_voiced)
|
||||
{
|
||||
if(!m_pcount)
|
||||
z0 = m_amp;
|
||||
else
|
||||
z0 = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Borrowing the ay noise generation LFSR
|
||||
if(m_RNG & 1)
|
||||
{
|
||||
z0 = m_amp;
|
||||
m_RNG ^= 0x24000;
|
||||
}
|
||||
else
|
||||
z0 = -m_amp;
|
||||
|
||||
m_RNG >>= 1;
|
||||
}
|
||||
|
||||
for (f = 0; f < 6; f++)
|
||||
{
|
||||
z0 += ((m_filter[f].z1 * m_filter[f].F) >> 8)
|
||||
+ ((m_filter[f].z2 * m_filter[f].B) >> 9);
|
||||
m_filter[f].z2 = m_filter[f].z1;
|
||||
m_filter[f].z1 = z0;
|
||||
}
|
||||
|
||||
// Physical resolution is only 7 bits, but heh
|
||||
|
||||
// max amplitude is 0x0f80 so we have margin to push up the output
|
||||
output[i] = z0 << 3;
|
||||
|
||||
m_pcount++;
|
||||
if (m_pcount >= m_pitch)
|
||||
{
|
||||
m_pcount = 0;
|
||||
m_rcount++;
|
||||
if (m_rcount >= m_repeat)
|
||||
m_playing = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
output[i] = 0;
|
||||
|
||||
if (!m_playing)
|
||||
{
|
||||
if(m_fifo_pos == 15)
|
||||
load_values();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,21 +5,21 @@
|
||||
|
||||
|
||||
struct sp0250_interface {
|
||||
void (*drq_callback)(device_t *device, int state);
|
||||
void (*m_drq_callback)(device_t *device, int state);
|
||||
};
|
||||
|
||||
DECLARE_WRITE8_DEVICE_HANDLER( sp0250_w );
|
||||
UINT8 sp0250_drq_r(device_t *device);
|
||||
|
||||
class sp0250_device : public device_t,
|
||||
public device_sound_interface
|
||||
public device_sound_interface,
|
||||
public sp0250_interface
|
||||
{
|
||||
public:
|
||||
sp0250_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
|
||||
~sp0250_device() { global_free(m_token); }
|
||||
~sp0250_device() {}
|
||||
|
||||
// access to legacy token
|
||||
void *token() const { assert(m_token != NULL); return m_token; }
|
||||
DECLARE_WRITE8_MEMBER( write );
|
||||
UINT8 drq_r();
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_config_complete();
|
||||
@ -27,9 +27,29 @@ protected:
|
||||
|
||||
// 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;
|
||||
INT16 m_amp;
|
||||
UINT8 m_pitch;
|
||||
UINT8 m_repeat;
|
||||
int m_pcount, m_rcount;
|
||||
int m_playing;
|
||||
UINT32 m_RNG;
|
||||
sound_stream * m_stream;
|
||||
int m_voiced;
|
||||
UINT8 m_fifo[15];
|
||||
int m_fifo_pos;
|
||||
void (*m_drq)(device_t *device, int state);
|
||||
|
||||
struct
|
||||
{
|
||||
INT16 F, B;
|
||||
INT16 z1, z2;
|
||||
} m_filter[6];
|
||||
|
||||
void load_values();
|
||||
TIMER_CALLBACK_MEMBER( timer_tick );
|
||||
};
|
||||
|
||||
extern const device_type SP0250;
|
||||
|
@ -771,7 +771,7 @@ WRITE8_MEMBER( gottlieb_sound_r2_device::nmi_rate_w )
|
||||
|
||||
CUSTOM_INPUT_MEMBER( gottlieb_sound_r2_device::speech_drq_custom_r )
|
||||
{
|
||||
return sp0250_drq_r(m_sp0250);
|
||||
return m_sp0250->drq_r();
|
||||
}
|
||||
|
||||
|
||||
@ -837,7 +837,7 @@ WRITE8_MEMBER( gottlieb_sound_r2_device::speech_control_w )
|
||||
|
||||
// bit 6 = speech chip DATA PRESENT pin; high then low to make the chip read data
|
||||
if ((previous & 0x40) == 0 && (data & 0x40) != 0)
|
||||
sp0250_w(m_sp0250, space, 0, m_sp0250_latch);
|
||||
m_sp0250->write(space, 0, m_sp0250_latch);
|
||||
|
||||
// bit 7 goes to the speech chip RESET pin
|
||||
if ((previous ^ data) & 0x80)
|
||||
|
@ -340,7 +340,7 @@ ADDRESS_MAP_END
|
||||
|
||||
static ADDRESS_MAP_START( speech_portmap, AS_IO, 8, driver_device )
|
||||
AM_RANGE(0x00, 0xff) AM_DEVREAD_LEGACY("segaspeech", speech_rom_r)
|
||||
AM_RANGE(0x00, 0xff) AM_DEVWRITE_LEGACY("speech", sp0250_w)
|
||||
AM_RANGE(0x00, 0xff) AM_DEVWRITE("speech", sp0250_device, write)
|
||||
AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_DEVREADWRITE_LEGACY("segaspeech", speech_p1_r, speech_p1_w)
|
||||
AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_DEVWRITE_LEGACY("segaspeech", speech_p2_w)
|
||||
AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_DEVREAD_LEGACY("segaspeech", speech_t0_r)
|
||||
|
@ -199,7 +199,6 @@ VBlank duration: 1/VSYNC * (16/256) = 1017.6 us
|
||||
#include "sound/ay8910.h"
|
||||
#include "sound/dac.h"
|
||||
#include "sound/samples.h"
|
||||
#include "sound/sp0250.h"
|
||||
#include "machine/nvram.h"
|
||||
#include "includes/gottlieb.h"
|
||||
|
||||
|
@ -109,7 +109,6 @@
|
||||
#include "sound/dac.h"
|
||||
#include "sound/sn76496.h"
|
||||
#include "sound/samples.h"
|
||||
#include "sound/sp0250.h"
|
||||
#include "audio/segasnd.h"
|
||||
#include "machine/i8255.h"
|
||||
#include "machine/segacrpt.h"
|
||||
|
Loading…
Reference in New Issue
Block a user