Sega Pico PCM improvements [ValleyBell]

as the pull request seems to have gone dead I refactored his changes into a new device derived from the 7759 rather than adding the Fifo into the 7759 (due to Aaron saying it doesn't exist there)

it's possible the custom chip that Pico uses has said logic built in somehow as it's not a plain 7759 afaik.
This commit is contained in:
David Haywood 2015-09-08 15:09:43 +01:00
parent c2e597a42d
commit 8abb4014f3
6 changed files with 193 additions and 45 deletions

View File

@ -627,6 +627,8 @@ if (SOUNDS["UPD7759"]~=null) then
files {
MAME_DIR .. "src/emu/sound/upd7759.c",
MAME_DIR .. "src/emu/sound/upd7759.h",
MAME_DIR .. "src/emu/sound/315-5641.c",
MAME_DIR .. "src/emu/sound/315-5641.h",
}
end

70
src/emu/sound/315-5641.c Normal file
View File

@ -0,0 +1,70 @@
/* Sega 315-5641 / D77591 / 9442CA010 */
#include "emu.h"
#include "315-5641.h"
const device_type SEGA_315_5641_PCM = &device_creator<sega_315_5641_pcm_device>;
sega_315_5641_pcm_device::sega_315_5641_pcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: upd7759_device(mconfig, SEGA_315_5641_PCM, "315-5641 PCM", tag, owner, clock, "315-5641_pcm", __FILE__)
{
}
void sega_315_5641_pcm_device::device_start()
{
save_item(NAME(m_fifo_data), 0x40);
save_item(NAME(m_fifo_read));
save_item(NAME(m_fifo_write));
upd7759_device::device_start();
}
void sega_315_5641_pcm_device::advance_state()
{
switch (m_state)
{
case STATE_DROP_DRQ:
if (m_rombase == NULL)
{
// Slave Mode: get data from FIFO buffer
UINT8 fiforead = (m_fifo_read + 1) & 0x3F;
if (fiforead != m_fifo_write)
{
m_fifo_in = m_fifo_data[fiforead];
m_fifo_read = fiforead;
}
}
break;
}
upd775x_device::advance_state();
}
WRITE8_MEMBER( sega_315_5641_pcm_device::port_w )
{
if (m_rombase != NULL)
{
/* update the FIFO value */
m_fifo_in = data;
}
else
{
m_fifo_data[m_fifo_write++] = data;
m_fifo_write &= 0x3F;
}
}
UINT8 sega_315_5641_pcm_device::get_fifo_space()
{
return (m_fifo_read - m_fifo_write) & 0x3F;
}
void sega_315_5641_pcm_device::device_reset()
{
m_fifo_read = 0x3F;
m_fifo_write = 0x00;
upd775x_device::device_reset();
}

30
src/emu/sound/315-5641.h Normal file
View File

@ -0,0 +1,30 @@
/* Sega 315-5641 / D77591 / 9442CA010 */
// this is the PICO sound chip, we are not sure if it's the same as a 7759 or not, it requires FIFO logic
// which the 7759 does _not_ have but it is possible that is handled somewhere else on the PICO hardawre.
#include "upd7759.h"
class sega_315_5641_pcm_device : public upd7759_device
{
public:
sega_315_5641_pcm_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
UINT8 get_fifo_space();
void advance_state();
DECLARE_WRITE8_MEMBER(port_w);
UINT8 m_fifo_data[0x40];
UINT8 m_fifo_read; // last read offset (will read in m_fifo_read+1)
UINT8 m_fifo_write; // write offset
protected:
// device-level overrides
virtual void device_start();
virtual void device_reset();
};
extern const device_type SEGA_315_5641_PCM;

View File

@ -143,23 +143,6 @@
#define FRAC_ONE (1 << FRAC_BITS)
#define FRAC_MASK (FRAC_ONE - 1)
/* chip states */
enum
{
STATE_IDLE,
STATE_DROP_DRQ,
STATE_START,
STATE_FIRST_REQ,
STATE_LAST_SAMPLE,
STATE_DUMMY1,
STATE_ADDR_MSB,
STATE_ADDR_LSB,
STATE_DUMMY2,
STATE_BLOCK_HEADER,
STATE_NIBBLE_COUNT,
STATE_NIBBLE_MSN,
STATE_NIBBLE_LSN
};
upd775x_device::upd775x_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
: device_t(mconfig, type, name, tag, owner, clock, shortname, source),
@ -204,6 +187,14 @@ upd7759_device::upd7759_device(const machine_config &mconfig, const char *tag, d
{
}
upd7759_device::upd7759_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
: upd775x_device(mconfig, type, name, tag, owner, clock, shortname, source),
m_timer(NULL)
{
}
const device_type UPD7756 = &device_creator<upd7756_device>;
upd7756_device::upd7756_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)

View File

@ -5,6 +5,23 @@
#ifndef __UPD7759_H__
#define __UPD7759_H__
/* chip states */
enum
{
STATE_IDLE,
STATE_DROP_DRQ,
STATE_START,
STATE_FIRST_REQ,
STATE_LAST_SAMPLE,
STATE_DUMMY1,
STATE_ADDR_MSB,
STATE_ADDR_LSB,
STATE_DUMMY2,
STATE_BLOCK_HEADER,
STATE_NIBBLE_COUNT,
STATE_NIBBLE_MSN,
STATE_NIBBLE_LSN
};
/* NEC uPD7759/55/56/P56/57/58 ADPCM Speech Processor */
@ -29,7 +46,7 @@ public:
DECLARE_WRITE_LINE_MEMBER( reset_w );
DECLARE_READ_LINE_MEMBER( busy_r );
DECLARE_WRITE8_MEMBER( port_w );
virtual DECLARE_WRITE8_MEMBER( port_w );
void postload();
protected:
@ -86,13 +103,14 @@ protected:
devcb_write_line m_drqcallback;
void update_adpcm(int data);
void advance_state();
virtual void advance_state();
};
class upd7759_device : public upd775x_device
{
public:
upd7759_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
upd7759_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
enum
{

View File

@ -119,7 +119,7 @@ C = MB3514 / 9325 M36
#include "emu.h"
#include "includes/md_cons.h"
#include "sound/upd7759.h"
#include "sound/315-5641.h"
#define PICO_PENX 1
@ -130,14 +130,14 @@ class pico_base_state : public md_cons_state
public:
pico_base_state(const machine_config &mconfig, device_type type, const char *tag)
: md_cons_state(mconfig, type, tag),
m_upd7759(*this, "7759"),
m_sega_315_5641_pcm(*this, "315_5641"),
m_io_page(*this, "PAGE"),
m_io_pad(*this, "PAD"),
m_io_penx(*this, "PENX"),
m_io_peny(*this, "PENY")
{ }
optional_device<upd7759_device> m_upd7759;
optional_device<sega_315_5641_pcm_device> m_sega_315_5641_pcm;
required_ioport m_io_page;
required_ioport m_io_pad;
@ -251,14 +251,18 @@ READ16_MEMBER(pico_base_state::pico_68k_io_read )
case 8: // toy story 2 checks this for 0x3f (is that 'empty'?)
/* Returns free bytes left in the PCM FIFO buffer */
retdata = 0x3f;
retdata = m_sega_315_5641_pcm->get_fifo_space();
break;
case 9:
/*
For reads, if bit 15 is cleared, it means PCM is 'busy' or
something like that, as games sometimes wait for it to become 1.
*/
return (m_upd7759->busy_r()^1) << 15;
// return (m_upd7759->busy_r()^1) << 15;
// The BUSY bit stays 1 as long as some PCM sound is playing.
// SMPS drivers check 800012 [byte] and clear the "prevent music PCM" byte when the READY bit gets set.
// If this is done incorrectly, the voices in Sonic Gameworld (J) are muted by the music's PCM drums.
return m_sega_315_5641_pcm->busy_r() << 15;
case 7:
@ -279,7 +283,7 @@ READ16_MEMBER(pico_base_state::pico_68k_io_read )
WRITE_LINE_MEMBER(pico_base_state::sound_cause_irq)
{
// printf("sound irq\n");
/* upd7759 callback */
/* sega_315_5641_pcm callback */
m_maincpu->set_input_line(3, HOLD_LINE);
}
@ -289,14 +293,44 @@ WRITE16_MEMBER(pico_base_state::pico_68k_io_write )
switch (offset)
{
case 0x12/2: // guess
m_upd7759->reset_w(0);
m_upd7759->start_w(0);
m_upd7759->reset_w(1);
m_upd7759->start_w(1);
case 0x10/2:
if (mem_mask & 0xFF00)
m_sega_315_5641_pcm->port_w(space, 0, (data >> 8) & 0xFF);
if (mem_mask & 0x00FF)
m_sega_315_5641_pcm->port_w(space, 0, (data >> 0) & 0xFF);
break;
case 0x12/2: // guess
// Note about uPD7759 lines:
// reset line: 1 - normal, 1->0 - reset chip, 0 - playback disabled
// start line: 0->1 - start playback
if (mem_mask & 0xFF00)
{
// I assume that:
// value 8000 resets the FIFO? (always used with low reset line)
// value 0800 maps to the uPD7759's reset line (0 = reset, 1 = normal)
// value 4000 maps to the uPD7759's start line (0->1 = start)
m_sega_315_5641_pcm->reset_w((data >> 8) & 0x08);
m_sega_315_5641_pcm->start_w((data >> 8) & 0x40);
if (data & 0x4000)
{
// Somewhere between "Reset Off" and the first sample data,
// we need to send a few commands to make the sample stream work.
// Doing that when rising the "start" line seems to work fine.
m_sega_315_5641_pcm->port_w(space, 0, 0xFF); // "Last Sample" value (must be >= 0x10)
m_sega_315_5641_pcm->port_w(space, 0, 0x00); // Dummy 1
m_sega_315_5641_pcm->port_w(space, 0, 0x00); // Addr MSB
m_sega_315_5641_pcm->port_w(space, 0, 0x00); // Addr LSB
}
}
/*m_sega_315_5641_pcm->reset_w(0);
m_sega_315_5641_pcm->start_w(0);
m_sega_315_5641_pcm->reset_w(1);
m_sega_315_5641_pcm->start_w(1);
if (mem_mask&0x00ff) m_upd7759->port_w(space,0,data&0xff);
if (mem_mask&0xff00) m_upd7759->port_w(space,0,(data>>8)&0xff);
if (mem_mask&0x00ff) m_sega_315_5641_pcm->port_w(space,0,data&0xff);
if (mem_mask&0xff00) m_sega_315_5641_pcm->port_w(space,0,(data>>8)&0xff);*/
break;
}
@ -356,6 +390,7 @@ static MACHINE_CONFIG_START( pico, pico_state )
MCFG_CPU_PROGRAM_MAP(pico_mem)
MCFG_DEVICE_REMOVE("genesis_snd_z80")
MCFG_DEVICE_REMOVE("ymsnd")
MCFG_MACHINE_START_OVERRIDE( pico_state, pico )
MCFG_MACHINE_RESET_OVERRIDE( pico_base_state, ms_megadriv )
@ -363,10 +398,10 @@ static MACHINE_CONFIG_START( pico, pico_state )
MCFG_PICO_CARTRIDGE_ADD("picoslot", pico_cart, NULL)
MCFG_SOFTWARE_LIST_ADD("cart_list","pico")
MCFG_SOUND_ADD("7759", UPD7759, UPD7759_STANDARD_CLOCK)
MCFG_SOUND_ADD("315_5641", SEGA_315_5641_PCM, UPD7759_STANDARD_CLOCK*2)
MCFG_UPD7759_DRQ_CALLBACK(WRITELINE(pico_state,sound_cause_irq))
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.48)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.48)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.16)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.16)
MACHINE_CONFIG_END
static MACHINE_CONFIG_START( picopal, pico_state )
@ -376,6 +411,7 @@ static MACHINE_CONFIG_START( picopal, pico_state )
MCFG_CPU_PROGRAM_MAP(pico_mem)
MCFG_DEVICE_REMOVE("genesis_snd_z80")
MCFG_DEVICE_REMOVE("ymsnd")
MCFG_MACHINE_START_OVERRIDE( pico_state, pico )
MCFG_MACHINE_RESET_OVERRIDE( pico_base_state, ms_megadriv )
@ -383,10 +419,10 @@ static MACHINE_CONFIG_START( picopal, pico_state )
MCFG_PICO_CARTRIDGE_ADD("picoslot", pico_cart, NULL)
MCFG_SOFTWARE_LIST_ADD("cart_list","pico")
MCFG_SOUND_ADD("7759", UPD7759, UPD7759_STANDARD_CLOCK)
MCFG_SOUND_ADD("315_5641", SEGA_315_5641_PCM, UPD7759_STANDARD_CLOCK*2)
MCFG_UPD7759_DRQ_CALLBACK(WRITELINE(pico_state,sound_cause_irq))
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.48)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.48)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.16)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.16)
MACHINE_CONFIG_END
@ -552,10 +588,10 @@ MACHINE_START_MEMBER(copera_state,copera)
m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0xa15000, 0xa150ff, read16_delegate(FUNC(base_md_cart_slot_device::read_a15),(base_md_cart_slot_device*)m_picocart), write16_delegate(FUNC(base_md_cart_slot_device::write_a15),(base_md_cart_slot_device*)m_picocart));
m_maincpu->space(AS_PROGRAM).install_write_handler(0xa14000, 0xa14003, write16_delegate(FUNC(base_md_cart_slot_device::write_tmss_bank),(base_md_cart_slot_device*)m_picocart));
m_upd7759->reset_w(0);
m_upd7759->start_w(0);
m_upd7759->reset_w(1);
m_upd7759->start_w(1);
m_sega_315_5641_pcm->reset_w(0);
m_sega_315_5641_pcm->start_w(0);
m_sega_315_5641_pcm->reset_w(1);
m_sega_315_5641_pcm->start_w(1);
}
@ -566,6 +602,7 @@ static MACHINE_CONFIG_START( copera, copera_state )
MCFG_CPU_PROGRAM_MAP(copera_mem)
MCFG_DEVICE_REMOVE("genesis_snd_z80")
MCFG_DEVICE_REMOVE("ymsnd")
MCFG_MACHINE_START_OVERRIDE( copera_state, copera )
MCFG_MACHINE_RESET_OVERRIDE( pico_base_state, ms_megadriv )
@ -573,10 +610,10 @@ static MACHINE_CONFIG_START( copera, copera_state )
MCFG_COPERA_CARTRIDGE_ADD("coperaslot", copera_cart, NULL)
MCFG_SOFTWARE_LIST_ADD("cart_list","copera")
MCFG_SOUND_ADD("7759", UPD7759, UPD7759_STANDARD_CLOCK)
MCFG_SOUND_ADD("315_5641", SEGA_315_5641_PCM, UPD7759_STANDARD_CLOCK)
MCFG_UPD7759_DRQ_CALLBACK(WRITELINE(copera_state,sound_cause_irq))
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.48)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.48)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.16)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.16)
MACHINE_CONFIG_END