Amiga: Move audio related registers into Paula device

The device is now independent from the Amiga state class.
This commit is contained in:
Dirk Best 2017-01-29 12:42:26 +01:00
parent f2f55c1568
commit 094ace1fbf
10 changed files with 214 additions and 74 deletions

View File

@ -7,7 +7,6 @@
***************************************************************************/
#include "8364_paula.h"
#include "includes/amiga.h"
//**************************************************************************
@ -36,6 +35,8 @@ const device_type PAULA_8364 = &device_creator<paula_8364_device>;
paula_8364_device::paula_8364_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, PAULA_8364, "8364 Paula", tag, owner, clock, "paula_8364", __FILE__),
device_sound_interface(mconfig, *this),
m_mem_r(*this), m_int_w(*this),
m_dmacon(0), m_adkcon(0),
m_stream(nullptr)
{
}
@ -46,6 +47,10 @@ paula_8364_device::paula_8364_device(const machine_config &mconfig, const char *
void paula_8364_device::device_start()
{
// resolve callbacks
m_mem_r.resolve_safe(0);
m_int_w.resolve_safe();
// initialize channels
for (int i = 0; i < 4; i++)
{
@ -60,46 +65,6 @@ void paula_8364_device::device_start()
m_stream = machine().sound().stream_alloc(*this, 0, 4, clock() / CLOCK_DIVIDER);
}
//*************************************************************************
// IMPLEMENTATION
//**************************************************************************
//-------------------------------------------------
// signal_irq - irq signaling
//-------------------------------------------------
TIMER_CALLBACK_MEMBER( paula_8364_device::signal_irq )
{
amiga_state *state = machine().driver_data<amiga_state>();
state->custom_chip_w(REG_INTREQ, INTENA_SETCLR | (0x80 << param));
}
//-------------------------------------------------
// dma_reload
//-------------------------------------------------
void paula_8364_device::dma_reload(audio_channel *chan)
{
amiga_state *state = machine().driver_data<amiga_state>();
chan->curlocation = CUSTOM_REG_LONG(REG_AUD0LCH + chan->index * 8);
chan->curlength = CUSTOM_REG(REG_AUD0LEN + chan->index * 8);
chan->irq_timer->adjust(attotime::from_hz(15750), chan->index);
LOG(("dma_reload(%d): offs=%05X len=%04X\n", chan->index, chan->curlocation, chan->curlength));
}
//-------------------------------------------------
// data_w - manual mode data writer
//-------------------------------------------------
void paula_8364_device::data_w(int which, uint16_t data)
{
m_channel[which].manualmode = true;
}
//-------------------------------------------------
// update - stream updater
//-------------------------------------------------
@ -109,17 +74,104 @@ void paula_8364_device::update()
m_stream->update();
}
//*************************************************************************
// IMPLEMENTATION
//**************************************************************************
READ16_MEMBER( paula_8364_device::reg_r )
{
switch (offset)
{
case REG_DMACONR:
return m_dmacon;
case REG_ADKCONR:
return m_adkcon;
}
return 0xffff;
}
WRITE16_MEMBER( paula_8364_device::reg_w )
{
if (offset >= 0xa0 && offset <= 0xdf)
m_stream->update();
switch (offset)
{
case REG_DMACON:
m_stream->update();
m_dmacon = (data & 0x8000) ? (m_dmacon | (data & 0x021f)) : (m_dmacon & ~(data & 0x021f)); // only bits 15, 9 and 5 to 0
break;
case REG_ADKCON:
m_stream->update();
m_adkcon = (data & 0x8000) ? (m_adkcon | (data & 0x7fff)) : (m_adkcon & ~(data & 0x7fff));
break;
// to be moved
case REG_AUD0LCL: m_channel[CHAN_0].loc = (m_channel[CHAN_0].loc & 0xffff0000) | ((data & 0xfffe) << 0); break; // 15-bit
case REG_AUD0LCH: m_channel[CHAN_0].loc = (m_channel[CHAN_0].loc & 0x0000ffff) | ((data & 0x001f) << 16); break; // 3-bit on ocs, 5-bit ecs
case REG_AUD1LCL: m_channel[CHAN_1].loc = (m_channel[CHAN_1].loc & 0xffff0000) | ((data & 0xfffe) << 0); break; // 15-bit
case REG_AUD1LCH: m_channel[CHAN_1].loc = (m_channel[CHAN_1].loc & 0x0000ffff) | ((data & 0x001f) << 16); break; // 3-bit on ocs, 5-bit ecs
case REG_AUD2LCL: m_channel[CHAN_2].loc = (m_channel[CHAN_2].loc & 0xffff0000) | ((data & 0xfffe) << 0); break; // 15-bit
case REG_AUD2LCH: m_channel[CHAN_2].loc = (m_channel[CHAN_2].loc & 0x0000ffff) | ((data & 0x001f) << 16); break; // 3-bit on ocs, 5-bit ecs
case REG_AUD3LCL: m_channel[CHAN_3].loc = (m_channel[CHAN_3].loc & 0xffff0000) | ((data & 0xfffe) << 0); break; // 15-bit
case REG_AUD3LCH: m_channel[CHAN_3].loc = (m_channel[CHAN_3].loc & 0x0000ffff) | ((data & 0x001f) << 16); break; // 3-bit on ocs, 5-bit ecs
// audio data
case REG_AUD0LEN: m_channel[CHAN_0].len = data; break;
case REG_AUD0PER: m_channel[CHAN_0].per = data; break;
case REG_AUD0VOL: m_channel[CHAN_0].vol = data; break;
case REG_AUD0DAT: m_channel[CHAN_0].dat = data; m_channel[CHAN_0].manualmode = true; break;
case REG_AUD1LEN: m_channel[CHAN_1].len = data; break;
case REG_AUD1PER: m_channel[CHAN_1].per = data; break;
case REG_AUD1VOL: m_channel[CHAN_1].vol = data; break;
case REG_AUD1DAT: m_channel[CHAN_1].dat = data; m_channel[CHAN_1].manualmode = true; break;
case REG_AUD2LEN: m_channel[CHAN_2].len = data; break;
case REG_AUD2PER: m_channel[CHAN_2].per = data; break;
case REG_AUD2VOL: m_channel[CHAN_2].vol = data; break;
case REG_AUD2DAT: m_channel[CHAN_2].dat = data; m_channel[CHAN_2].manualmode = true; break;
case REG_AUD3LEN: m_channel[CHAN_3].len = data; break;
case REG_AUD3PER: m_channel[CHAN_3].per = data; break;
case REG_AUD3VOL: m_channel[CHAN_3].vol = data; break;
case REG_AUD3DAT: m_channel[CHAN_3].dat = data; m_channel[CHAN_3].manualmode = true; break;
}
}
//-------------------------------------------------
// signal_irq - irq signaling
//-------------------------------------------------
TIMER_CALLBACK_MEMBER( paula_8364_device::signal_irq )
{
m_int_w(0x8000 | (0x80 << param));
}
//-------------------------------------------------
// dma_reload
//-------------------------------------------------
void paula_8364_device::dma_reload(audio_channel *chan)
{
chan->curlocation = chan->loc;
chan->curlength = chan->len;
chan->irq_timer->adjust(attotime::from_hz(15750), chan->index); // clock() / 227
LOG(("dma_reload(%d): offs=%05X len=%04X\n", chan->index, chan->curlocation, chan->curlength));
}
//-------------------------------------------------
// sound_stream_update - handle a stream update
//-------------------------------------------------
void paula_8364_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
amiga_state *state = machine().driver_data<amiga_state>();
int channum, sampoffs = 0;
// if all DMA off, disable all channels
if (!(CUSTOM_REG(REG_DMACON) & 0x0200))
if (BIT(m_dmacon, 9) == 0)
{
m_channel[0].dma_enabled =
m_channel[1].dma_enabled =
@ -138,9 +190,10 @@ void paula_8364_device::sound_stream_update(sound_stream &stream, stream_sample_
for (channum = 0; channum < 4; channum++)
{
audio_channel *chan = &m_channel[channum];
if (!chan->dma_enabled && ((CUSTOM_REG(REG_DMACON) >> channum) & 1))
if (!chan->dma_enabled && ((m_dmacon >> channum) & 1))
dma_reload(chan);
chan->dma_enabled = (CUSTOM_REG(REG_DMACON) >> channum) & 1;
chan->dma_enabled = BIT(m_dmacon, channum);
}
// loop until done
@ -163,9 +216,9 @@ void paula_8364_device::sound_stream_update(sound_stream &stream, stream_sample_
nextper = nextvol = -1;
for (channum = 0; channum < 4; channum++)
{
int volume = (nextvol == -1) ? CUSTOM_REG(REG_AUD0VOL + channum * 8) : nextvol;
int period = (nextper == -1) ? CUSTOM_REG(REG_AUD0PER + channum * 8) : nextper;
audio_channel *chan = &m_channel[channum];
int volume = (nextvol == -1) ? chan->vol : nextvol;
int period = (nextper == -1) ? chan->per : nextper;
stream_sample_t sample;
int i;
@ -174,18 +227,18 @@ void paula_8364_device::sound_stream_update(sound_stream &stream, stream_sample_
volume *= 4;
// are we modulating the period of the next channel?
if ((CUSTOM_REG(REG_ADKCON) >> channum) & 0x10)
if ((m_adkcon >> channum) & 0x10)
{
nextper = CUSTOM_REG(REG_AUD0DAT + channum * 8);
nextper = chan->dat;
nextvol = -1;
sample = 0;
}
// are we modulating the volume of the next channel?
else if ((CUSTOM_REG(REG_ADKCON) >> channum) & 0x01)
else if ((m_adkcon >> channum) & 0x01)
{
nextper = -1;
nextvol = CUSTOM_REG(REG_AUD0DAT + channum * 8);
nextvol = chan->dat;
sample = 0;
}
@ -214,7 +267,8 @@ void paula_8364_device::sound_stream_update(sound_stream &stream, stream_sample_
chan->curlocation++;
if (chan->dma_enabled && !(chan->curlocation & 1))
{
CUSTOM_REG(REG_AUD0DAT + channum * 8) = state->chip_ram_r(chan->curlocation);
chan->dat = m_mem_r(chan->curlocation);
if (chan->curlength != 0)
chan->curlength--;
@ -225,9 +279,9 @@ void paula_8364_device::sound_stream_update(sound_stream &stream, stream_sample_
// latch the next byte of the sample
if (!(chan->curlocation & 1))
chan->latched = CUSTOM_REG(REG_AUD0DAT + channum * 8) >> 8;
chan->latched = chan->dat >> 8;
else
chan->latched = CUSTOM_REG(REG_AUD0DAT + channum * 8) >> 0;
chan->latched = chan->dat >> 0;
// if we're in manual mode, signal an interrupt once we latch the low byte
if (!chan->dma_enabled && chan->manualmode && (chan->curlocation & 1))

View File

@ -45,6 +45,17 @@
#include "emu.h"
//**************************************************************************
// INTERFACE CONFIGURATION MACROS
//**************************************************************************
#define MCFG_PAULA_MEM_READ_CB(_devcb) \
devcb = &paula_8364_device::set_mem_r_callback(*device, DEVCB_##_devcb);
#define MCFG_PAULA_INT_CB(_devcb) \
devcb = &paula_8364_device::set_int_w_callback(*device, DEVCB_##_devcb);
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
@ -57,8 +68,17 @@ public:
paula_8364_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
~paula_8364_device() {}
// configuration
template<class _Object> static devcb_base &set_mem_r_callback(device_t &device, _Object object)
{ return downcast<paula_8364_device &>(device).m_mem_r.set_callback(object); }
template<class _Object> static devcb_base &set_int_w_callback(device_t &device, _Object object)
{ return downcast<paula_8364_device &>(device).m_int_w.set_callback(object); }
DECLARE_READ16_MEMBER(reg_r);
DECLARE_WRITE16_MEMBER(reg_w);
void update();
void data_w(int which, uint16_t data);
protected:
// device-level overrides
@ -68,6 +88,47 @@ protected:
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
private:
enum
{
CHAN_0 = 0,
CHAN_1 = 1,
CHAN_2 = 2,
CHAN_3 = 3
};
enum
{
REG_DMACONR = 0x02/2,
REG_ADKCONR = 0x10/2,
REG_DMACON = 0x96/2,
REG_INTREQ = 0x9c/2,
REG_ADKCON = 0x9e/2,
REG_AUD0LCH = 0xa0/2, // to be moved, not part of paula
REG_AUD0LCL = 0xa2/2, // to be moved, not part of paula
REG_AUD0LEN = 0xa4/2,
REG_AUD0PER = 0xa6/2,
REG_AUD0VOL = 0xa8/2,
REG_AUD0DAT = 0xaa/2,
REG_AUD1LCH = 0xb0/2, // to be moved, not part of paula
REG_AUD1LCL = 0xb2/2, // to be moved, not part of paula
REG_AUD1LEN = 0xb4/2,
REG_AUD1PER = 0xb6/2,
REG_AUD1VOL = 0xb8/2,
REG_AUD1DAT = 0xba/2,
REG_AUD2LCH = 0xc0/2, // to be moved, not part of paula
REG_AUD2LCL = 0xc2/2, // to be moved, not part of paula
REG_AUD2LEN = 0xc4/2,
REG_AUD2PER = 0xc6/2,
REG_AUD2VOL = 0xc8/2,
REG_AUD2DAT = 0xca/2,
REG_AUD3LCH = 0xd0/2, // to be moved, not part of paula
REG_AUD3LCL = 0xd2/2, // to be moved, not part of paula
REG_AUD3LEN = 0xd4/2,
REG_AUD3PER = 0xd6/2,
REG_AUD3VOL = 0xd8/2,
REG_AUD3DAT = 0xda/2
};
static const int CLOCK_DIVIDER = 16;
struct audio_channel
@ -80,11 +141,25 @@ private:
bool dma_enabled;
bool manualmode;
int8_t latched;
// custom chip registers
uint32_t loc; // to be moved, not part of paula
uint16_t len;
uint16_t per;
uint16_t vol;
uint16_t dat;
};
void dma_reload(audio_channel *chan);
// callbacks
devcb_read16 m_mem_r;
devcb_write_line m_int_w;
// internal state
uint16_t m_dmacon;
uint16_t m_adkcon;
audio_channel m_channel[4];
sound_stream *m_stream;

View File

@ -325,6 +325,8 @@ static MACHINE_CONFIG_START( alg_r1, alg_state )
MCFG_SOUND_ROUTE(1, "rspeaker", 0.25)
MCFG_SOUND_ROUTE(2, "rspeaker", 0.25)
MCFG_SOUND_ROUTE(3, "lspeaker", 0.25)
MCFG_PAULA_MEM_READ_CB(READ16(amiga_state, chip_ram_r))
MCFG_PAULA_INT_CB(WRITELINE(amiga_state, paula_int_w))
MCFG_SOUND_MODIFY("laserdisc")
MCFG_SOUND_ROUTE(0, "lspeaker", 1.0)

View File

@ -1334,6 +1334,8 @@ static MACHINE_CONFIG_START( amiga_base, amiga_state )
MCFG_SOUND_ROUTE(1, "rspeaker", 0.50)
MCFG_SOUND_ROUTE(2, "rspeaker", 0.50)
MCFG_SOUND_ROUTE(3, "lspeaker", 0.50)
MCFG_PAULA_MEM_READ_CB(READ16(amiga_state, chip_ram_r))
MCFG_PAULA_INT_CB(WRITELINE(amiga_state, paula_int_w))
// floppy drives
MCFG_DEVICE_ADD("fdc", AMIGA_FDC, amiga_state::CLK_7M_PAL)

View File

@ -317,6 +317,8 @@ static MACHINE_CONFIG_START( arcadia, arcadia_amiga_state )
MCFG_SOUND_ROUTE(1, "rspeaker", 0.50)
MCFG_SOUND_ROUTE(2, "rspeaker", 0.50)
MCFG_SOUND_ROUTE(3, "lspeaker", 0.50)
MCFG_PAULA_MEM_READ_CB(READ16(amiga_state, chip_ram_r))
MCFG_PAULA_INT_CB(WRITELINE(amiga_state, paula_int_w))
/* cia */
MCFG_DEVICE_ADD("cia_0", MOS8520, amiga_state::CLK_E_NTSC)

View File

@ -1054,6 +1054,8 @@ static MACHINE_CONFIG_START( cubo, cubo_state )
MCFG_SOUND_ROUTE(1, "rspeaker", 0.25)
MCFG_SOUND_ROUTE(2, "rspeaker", 0.25)
MCFG_SOUND_ROUTE(3, "lspeaker", 0.25)
MCFG_PAULA_MEM_READ_CB(READ16(amiga_state, chip_ram_r))
MCFG_PAULA_INT_CB(WRITELINE(amiga_state, paula_int_w))
MCFG_SOUND_ADD("cdda", CDDA, 0)
MCFG_SOUND_ROUTE(0, "lspeaker", 0.50)

View File

@ -331,6 +331,8 @@ static MACHINE_CONFIG_START( mquake, mquake_state )
MCFG_SOUND_ROUTE(1, "rspeaker", 0.50)
MCFG_SOUND_ROUTE(2, "rspeaker", 0.50)
MCFG_SOUND_ROUTE(3, "lspeaker", 0.50)
MCFG_PAULA_MEM_READ_CB(READ16(amiga_state, chip_ram_r))
MCFG_PAULA_INT_CB(WRITELINE(amiga_state, paula_int_w))
MCFG_ES5503_ADD("es5503", amiga_state::CLK_7M_NTSC) /* ES5503 is likely mono due to channel strobe used as bank select */
MCFG_ES5503_OUTPUT_CHANNELS(1)

View File

@ -289,6 +289,8 @@ static MACHINE_CONFIG_START( upscope, upscope_state )
MCFG_SOUND_ROUTE(1, "lspeaker", 0.50)
MCFG_SOUND_ROUTE(2, "lspeaker", 0.50)
MCFG_SOUND_ROUTE(3, "rspeaker", 0.50)
MCFG_PAULA_MEM_READ_CB(READ16(amiga_state, chip_ram_r))
MCFG_PAULA_INT_CB(WRITELINE(amiga_state, paula_int_w))
/* cia */
MCFG_DEVICE_ADD("cia_0", MOS8520, amiga_state::CLK_E_NTSC)

View File

@ -336,7 +336,7 @@ public:
m_cia_1(*this, "cia_1"),
m_rs232(*this, "rs232"),
m_centronics(*this, "centronics"),
m_sound(*this, "amiga"),
m_paula(*this, "amiga"),
m_fdc(*this, "fdc"),
m_screen(*this, "screen"),
m_palette(*this, "palette"),
@ -378,12 +378,15 @@ public:
{
return EXPECTED(byteoffs < m_chip_ram.bytes()) ? m_chip_ram.read(byteoffs >> 1) : 0xffff;
}
void chip_ram_w(offs_t byteoffs, uint16_t data)
{
if (EXPECTED(byteoffs < m_chip_ram.bytes()))
m_chip_ram.write(byteoffs >> 1, data);
}
DECLARE_READ16_MEMBER(chip_ram_r) { return chip_ram_r(offset); }
/* sprite states */
uint8_t m_sprite_comparitor_enable_mask;
uint8_t m_sprite_dma_reload_mask;
@ -467,6 +470,8 @@ public:
DECLARE_READ16_MEMBER( custom_chip_r );
DECLARE_WRITE16_MEMBER( custom_chip_w );
DECLARE_WRITE_LINE_MEMBER( paula_int_w );
DECLARE_READ16_MEMBER( rom_mirror_r );
DECLARE_READ32_MEMBER( rom_mirror32_r );
@ -563,7 +568,7 @@ protected:
required_device<mos8520_device> m_cia_1;
optional_device<rs232_port_device> m_rs232;
optional_device<centronics_device> m_centronics;
required_device<paula_8364_device> m_sound;
required_device<paula_8364_device> m_paula;
optional_device<amiga_fdc> m_fdc;
required_device<screen_device> m_screen;
optional_device<palette_device> m_palette;

View File

@ -188,7 +188,7 @@ WRITE_LINE_MEMBER( amiga_state::kbreset_w )
// this is connected to the gary chip, gary then resets the 68k, agnus, paula and the cias
if (!state)
{
m_sound->reset();
m_paula->reset();
machine_reset();
m_maincpu->reset();
}
@ -293,7 +293,7 @@ TIMER_CALLBACK_MEMBER( amiga_state::scanline_callback )
m_cia_1->tod_w((scanline & 1) ^ BIT(CUSTOM_REG(REG_VPOSR), 15));
// force a sound update
m_sound->update();
m_paula->update();
// set timer for next line
scanline = (scanline + 1) % m_screen->height();
@ -373,6 +373,11 @@ TIMER_CALLBACK_MEMBER( amiga_state::amiga_irq_proc )
m_irq_timer->reset();
}
WRITE_LINE_MEMBER( amiga_state::paula_int_w )
{
set_interrupt(INTENA_SETCLR | (0x80 << state));
}
//**************************************************************************
// INPUTS
@ -1267,6 +1272,9 @@ WRITE16_MEMBER( amiga_state::custom_chip_w )
if (LOG_CUSTOM)
logerror("%06X:write to custom %s = %04X\n", space.device().safe_pc(), amiga_custom_names[offset & 0xff], data);
// paula will handle some of those registers
m_paula->reg_w(space, offset, data, mem_mask);
switch (offset)
{
case REG_BLTDDAT: case REG_DMACONR: case REG_VPOSR: case REG_VHPOSR:
@ -1427,8 +1435,6 @@ WRITE16_MEMBER( amiga_state::custom_chip_w )
break;
case REG_DMACON:
m_sound->update();
/* bits BBUSY (14) and BZERO (13) are read-only */
data &= 0x9fff;
data = (data & 0x8000) ? (CUSTOM_REG(offset) | (data & 0x7fff)) : (CUSTOM_REG(offset) & ~(data & 0x7fff));
@ -1480,22 +1486,10 @@ WRITE16_MEMBER( amiga_state::custom_chip_w )
break;
case REG_ADKCON:
m_sound->update();
data = (data & 0x8000) ? (CUSTOM_REG(offset) | (data & 0x7fff)) : (CUSTOM_REG(offset) & ~(data & 0x7fff));
m_fdc->adkcon_set(data);
break;
case REG_AUD0LCL: case REG_AUD0LCH: case REG_AUD0LEN: case REG_AUD0PER: case REG_AUD0VOL:
case REG_AUD1LCL: case REG_AUD1LCH: case REG_AUD1LEN: case REG_AUD1PER: case REG_AUD1VOL:
case REG_AUD2LCL: case REG_AUD2LCH: case REG_AUD2LEN: case REG_AUD2PER: case REG_AUD2VOL:
case REG_AUD3LCL: case REG_AUD3LCH: case REG_AUD3LEN: case REG_AUD3PER: case REG_AUD3VOL:
m_sound->update();
break;
case REG_AUD0DAT: case REG_AUD1DAT: case REG_AUD2DAT: case REG_AUD3DAT:
m_sound->data_w((offset - REG_AUD0DAT) / 8, data);
break;
case REG_BPL1PTH: case REG_BPL2PTH: case REG_BPL3PTH: case REG_BPL4PTH:
case REG_BPL5PTH: case REG_BPL6PTH:
data &= ( m_chip_ram_mask >> 16 );
@ -1575,7 +1569,7 @@ void amiga_state::serial_adjust()
amiga_state *state = this;
uint32_t divisor = (CUSTOM_REG(REG_SERPER) & 0x7fff) + 1;
uint32_t baud = m_sound->clock() / divisor;
uint32_t baud = m_paula->clock() / divisor;
m_serial_timer->adjust(attotime::from_hz(baud) / 2, 0, attotime::from_hz(baud));
}