Update tandy sound core to latest (unmerged) mame version. Update tandy sound selection to use the ncr8496 for normal usage and the sn76496 in PCjr mode.
Correct noise algorithm. Ignore writes to certain registers if highest bit is not set for ncr8496 mode. Don't reset the noise producing register on all writes, only when changing the type of noise (ncr8496). Fixes intro sound of KQ2, waves in KQ2 and sound on the title screen of sentinel. Thanks for the help Lord_Nightmare. Imported-from: https://svn.code.sf.net/p/dosbox/code-0/dosbox/trunk@4141
This commit is contained in:
parent
35a46909b5
commit
0463a8b907
3 changed files with 82 additions and 32 deletions
|
@ -46,10 +46,12 @@
|
|||
Noise is an XOR function, and audio output is negated before being output.
|
||||
All the Sega-made PSG chips act as if the frequency was set to 0 if 0 is written
|
||||
to the frequency register.
|
||||
** NCR7496 (as used on the Tandy 1000) is similar to the SN76489 but with a
|
||||
different noise LFSR patttern: taps on bits A and E, output on E
|
||||
** NCR8496 (as used on the Tandy 1000) is similar to the SN76489 but with a
|
||||
different noise LFSR pattern: taps on bits A and E, output on E, XNOR function
|
||||
It uses a 15-bit ring buffer for periodic noise/arbitrary duty cycle.
|
||||
(all this chip's info needs to be verified)
|
||||
Its output is inverted.
|
||||
** PSSJ-3 (as used on the later Tandy 1000 series computers) is the same as the
|
||||
NCR8496 with the exception that its output is not inverted.
|
||||
|
||||
28/03/2005 : Sebastien Chevalier
|
||||
Update th SN76496Write func, according to SN76489 doc found on SMSPower.
|
||||
|
@ -77,7 +79,7 @@
|
|||
16/11/2009 : Lord Nightmare
|
||||
Fix screeching in regulus: When summing together four equal channels, the
|
||||
size of the max amplitude per channel should be 1/4 of the max range, not
|
||||
1/3. Added NCR7496.
|
||||
1/3. Added NCR8496.
|
||||
|
||||
18/11/2009 : Lord Nightmare
|
||||
Modify Init functions to support negating the audio output. The gamegear
|
||||
|
@ -115,11 +117,21 @@
|
|||
ValleyBell. Made Sega PSG chips start up with register 0x3 selected (volume
|
||||
for channel 2) based on hardware tests by Nemesis.
|
||||
|
||||
26/08/2018: Lord Nightmare, Qbix, ValleyBell, NewRisingSun
|
||||
* renamed the NCR8496 to its correct name, based on chip pictures on VGMPF
|
||||
* fixed NCR8496 behavior on write to mirrored registers; unlike any of the
|
||||
other variants, the NCR8496 seems to ignore writes to regs 1,3,5,6,7 if 0x80
|
||||
is not set.
|
||||
***TODO: the above is NOT verified yet!***
|
||||
* fixed NCR8496's noise lfsr behavior so it is only reset if the mode bit in
|
||||
register 6 is changed.
|
||||
* NCR8496's LFSR feedback function is an XNOR, which is now supported
|
||||
* NCR8496's output is inverted (though PSSJ-3's output is not)
|
||||
* add PSSJ-3 support for the later Tandy computers.
|
||||
|
||||
TODO: * Implement the TMS9919 - any difference to sn94624?
|
||||
* Implement the T6W28; has registers in a weird order, needs writes
|
||||
to be 'sanitized' first. Also is stereo, similar to game gear.
|
||||
* Test the NCR7496; Smspower says the whitenoise taps are A and E,
|
||||
but this needs verification on real hardware.
|
||||
* Factor out common code so that the SAA1099 can share some code.
|
||||
|
||||
***************************************************************************/
|
||||
|
@ -141,6 +153,7 @@ sn76496_base_device::sn76496_base_device(
|
|||
bool negate,
|
||||
bool stereo,
|
||||
int clockdivider,
|
||||
bool ncr,
|
||||
bool sega,
|
||||
device_t *owner,
|
||||
uint32_t clock)
|
||||
|
@ -153,58 +166,64 @@ sn76496_base_device::sn76496_base_device(
|
|||
, m_negate(negate)
|
||||
, m_stereo(stereo)
|
||||
, m_clock_divider(clockdivider)
|
||||
, m_ncr_style_psg(ncr)
|
||||
, m_sega_style_psg(sega)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
sn76496_device::sn76496_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: sn76496_base_device(mconfig, SN76496, tag, 0x10000, 0x04, 0x08, false, false, 8, true, owner, clock)
|
||||
: sn76496_base_device(mconfig, SN76496, tag, 0x10000, 0x04, 0x08, false, false, 8, false, true, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
u8106_device::u8106_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: sn76496_base_device(mconfig, U8106, tag, 0x4000, 0x01, 0x02, true, false, 8, true, owner, clock)
|
||||
: sn76496_base_device(mconfig, U8106, tag, 0x4000, 0x01, 0x02, true, false, 8, false, true, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
y2404_device::y2404_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: sn76496_base_device(mconfig, Y2404, tag, 0x10000, 0x04, 0x08, false, false, 8, true, owner, clock)
|
||||
: sn76496_base_device(mconfig, Y2404, tag, 0x10000, 0x04, 0x08, false, false, 8, false, true, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
sn76489_device::sn76489_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: sn76496_base_device(mconfig, SN76489, tag, 0x4000, 0x01, 0x02, true, false, 8, true, owner, clock)
|
||||
: sn76496_base_device(mconfig, SN76489, tag, 0x4000, 0x01, 0x02, true, false, 8, false, true, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
sn76489a_device::sn76489a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: sn76496_base_device(mconfig, SN76489A, tag, 0x10000, 0x04, 0x08, false, false, 8, true, owner, clock)
|
||||
: sn76496_base_device(mconfig, SN76489A, tag, 0x10000, 0x04, 0x08, false, false, 8, false, true, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
sn76494_device::sn76494_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: sn76496_base_device(mconfig, SN76494, tag, 0x10000, 0x04, 0x08, false, false, 1, true, owner, clock)
|
||||
: sn76496_base_device(mconfig, SN76494, tag, 0x10000, 0x04, 0x08, false, false, 1, false, true, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
sn94624_device::sn94624_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: sn76496_base_device(mconfig, SN94624, tag, 0x4000, 0x01, 0x02, true, false, 1, true, owner, clock)
|
||||
: sn76496_base_device(mconfig, SN94624, tag, 0x4000, 0x01, 0x02, true, false, 1, false, true, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
ncr7496_device::ncr7496_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: sn76496_base_device(mconfig, NCR7496, tag, 0x8000, 0x02, 0x20, false, false, 8, true, owner, clock)
|
||||
ncr8496_device::ncr8496_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: sn76496_base_device(mconfig, NCR8496, tag, 0x8000, 0x02, 0x20, true, false, 8, true, true, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
pssj3_device::pssj3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: sn76496_base_device(mconfig, PSSJ3, tag, 0x8000, 0x02, 0x20, false, false, 8, true, true, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
gamegear_device::gamegear_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: sn76496_base_device(mconfig, GAMEGEAR, tag, 0x8000, 0x01, 0x08, true, true, 8, false, owner, clock)
|
||||
: sn76496_base_device(mconfig, GAMEGEAR, tag, 0x8000, 0x01, 0x08, true, true, 8, false, false, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
segapsg_device::segapsg_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: sn76496_base_device(mconfig, SEGAPSG, tag, 0x8000, 0x01, 0x08, true, false, 8, false, owner, clock)
|
||||
: sn76496_base_device(mconfig, SEGAPSG, tag, 0x8000, 0x01, 0x08, true, false, 8, false, false, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -271,6 +290,11 @@ void sn76496_base_device::device_start()
|
|||
//register_for_save_states();
|
||||
}
|
||||
|
||||
void sn76496_base_device::device_clock_changed()
|
||||
{
|
||||
// m_sound->set_sample_rate(clock()/2);
|
||||
}
|
||||
|
||||
WRITE8_MEMBER( sn76496_base_device::stereo_w )
|
||||
{
|
||||
// m_sound->update();
|
||||
|
@ -293,11 +317,13 @@ void sn76496_base_device::write(uint8_t data)
|
|||
{
|
||||
r = (data & 0x70) >> 4;
|
||||
m_last_register = r;
|
||||
if (((m_ncr_style_psg) && (r == 6)) && ((data&0x04) != (m_register[6]&0x04))) m_RNG = m_feedback_mask;
|
||||
m_register[r] = (m_register[r] & 0x3f0) | (data & 0x0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
r = m_last_register;
|
||||
if ((m_ncr_style_psg) && ((r & 1) || (r == 6))) return; // NCR8496 ignores writes to regs 1, 3, 5, 6 and 7 with bit 7 clear
|
||||
}
|
||||
|
||||
c = r >> 1;
|
||||
|
@ -330,7 +356,7 @@ void sn76496_base_device::write(uint8_t data)
|
|||
n = m_register[6];
|
||||
// N/512,N/1024,N/2048,Tone #3 output
|
||||
m_period[3] = ((n&3) == 3)? (m_period[2]<<1) : (1 << (5+(n&3)));
|
||||
m_RNG = m_feedback_mask;
|
||||
if (!(m_ncr_style_psg)) m_RNG = m_feedback_mask;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -365,7 +391,7 @@ void sn76496_base_device::sound_stream_update(sound_stream &stream, stream_sampl
|
|||
{
|
||||
int i;
|
||||
stream_sample_t *lbuffer = outputs[0];
|
||||
stream_sample_t *rbuffer = (m_stereo)? outputs[1] : 0;
|
||||
stream_sample_t *rbuffer = (m_stereo)? outputs[1] : 0;//nullptr;
|
||||
|
||||
int16_t out;
|
||||
int16_t out2 = 0;
|
||||
|
@ -401,7 +427,7 @@ void sn76496_base_device::sound_stream_update(sound_stream &stream, stream_sampl
|
|||
// if noisemode is 1, both taps are enabled
|
||||
// if noisemode is 0, the lower tap, whitenoisetap2, is held at 0
|
||||
// The != was a bit-XOR (^) before
|
||||
if (((m_RNG & m_whitenoise_tap1)!=0) != (((m_RNG & m_whitenoise_tap2)!=0) && in_noise_mode()))
|
||||
if (((m_RNG & m_whitenoise_tap1)!=0) != (((m_RNG & m_whitenoise_tap2)!=(m_ncr_style_psg?m_whitenoise_tap2:0)) && in_noise_mode()))
|
||||
{
|
||||
m_RNG >>= 1;
|
||||
m_RNG |= m_feedback_mask;
|
||||
|
@ -485,7 +511,8 @@ DEFINE_DEVICE_TYPE(SN76489, sn76489_device, "sn76489", "SN76489")
|
|||
DEFINE_DEVICE_TYPE(SN76489A, sn76489a_device, "sn76489a", "SN76489A")
|
||||
DEFINE_DEVICE_TYPE(SN76494, sn76494_device, "sn76494", "SN76494")
|
||||
DEFINE_DEVICE_TYPE(SN94624, sn94624_device, "sn94624", "SN94624")
|
||||
DEFINE_DEVICE_TYPE(NCR7496, ncr7496_device, "ncr7496", "NCR7496")
|
||||
DEFINE_DEVICE_TYPE(NCR8496, ncr8496_device, "ncr8496", "NCR8496")
|
||||
DEFINE_DEVICE_TYPE(PSSJ3, pssj3_device, "pssj3", "PSSJ-3")
|
||||
DEFINE_DEVICE_TYPE(GAMEGEAR, gamegear_device, "gamegear_psg", "Game Gear PSG")
|
||||
DEFINE_DEVICE_TYPE(SEGAPSG, segapsg_device, "segapsg", "Sega VDP PSG")
|
||||
|
||||
|
|
|
@ -13,7 +13,8 @@ DECLARE_DEVICE_TYPE(SN76489, sn76489_device)
|
|||
DECLARE_DEVICE_TYPE(SN76489A, sn76489a_device)
|
||||
DECLARE_DEVICE_TYPE(SN76494, sn76494_device)
|
||||
DECLARE_DEVICE_TYPE(SN94624, sn94624_device)
|
||||
DECLARE_DEVICE_TYPE(NCR7496, ncr7496_device)
|
||||
DECLARE_DEVICE_TYPE(NCR8496, ncr8496_device)
|
||||
DECLARE_DEVICE_TYPE(PSSJ3, pssj3_device)
|
||||
DECLARE_DEVICE_TYPE(GAMEGEAR, gamegear_device)
|
||||
DECLARE_DEVICE_TYPE(SEGAPSG, segapsg_device)
|
||||
|
||||
|
@ -21,22 +22,23 @@ DECLARE_DEVICE_TYPE(SEGAPSG, segapsg_device)
|
|||
|
||||
|
||||
#define MCFG_SN76496_READY_HANDLER(cb) \
|
||||
devcb = &sn76496_base_device::set_ready_handler(*device, (DEVCB_##cb));
|
||||
downcast<sn76496_base_device &>(*device).set_ready_handler((DEVCB_##cb));
|
||||
|
||||
#endif
|
||||
|
||||
class sn76496_base_device : public device_t, public device_sound_interface
|
||||
{
|
||||
public:
|
||||
// static configuration helpers
|
||||
// template <class Object> static devcb_base &set_ready_handler(device_t &device, Object &&cb) { return downcast<sn76496_base_device &>(device).m_ready_handler.set_callback(std::forward<Object>(cb)); }
|
||||
// configuration helpers
|
||||
// template <class Object> devcb_base &set_ready_handler(Object &&cb) { return m_ready_handler.set_callback(std::forward<Object>(cb)); }
|
||||
|
||||
DECLARE_WRITE8_MEMBER( stereo_w );
|
||||
void write(uint8_t data);
|
||||
DECLARE_WRITE8_MEMBER( write );
|
||||
// DECLARE_READ_LINE_MEMBER( ready_r ) { return m_ready_state ? 1 : 0; }
|
||||
// auto ready_cb() { return m_ready_handler.bind(); }
|
||||
|
||||
void convert_samplerate(int32_t target_rate);
|
||||
void convert_samplerate(int32_t target_rate);
|
||||
protected:
|
||||
sn76496_base_device(
|
||||
const machine_config &mconfig,
|
||||
|
@ -48,11 +50,13 @@ protected:
|
|||
bool negate,
|
||||
bool stereo,
|
||||
int clockdivider,
|
||||
bool ncr,
|
||||
bool sega,
|
||||
device_t *owner,
|
||||
uint32_t clock);
|
||||
|
||||
virtual void device_start();
|
||||
virtual void device_clock_changed();
|
||||
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
|
||||
|
||||
private:
|
||||
|
@ -74,7 +78,8 @@ private:
|
|||
const bool m_negate; // output negate flag
|
||||
const bool m_stereo; // whether we're dealing with stereo or not
|
||||
const int32_t m_clock_divider; // clock divider
|
||||
const bool m_sega_style_psg; // flag for if frequency zero acts as if it is one more than max (0x3ff+1) or if it acts like 0; AND if the initial register is pointing to 0x3 instead of 0x0 AND if the volume reg is preloaded with 0xF instead of 0x0
|
||||
const bool m_ncr_style_psg; // flag to ignore writes to regs 1,3,5,6,7 with bit 7 low
|
||||
const bool m_sega_style_psg; // flag to make frequency zero acts as if it is one more than max (0x3ff+1) or if it acts like 0; the initial register is pointing to 0x3 instead of 0x0; the volume reg is preloaded with 0xF instead of 0x0
|
||||
|
||||
int32_t m_vol_table[16]; // volume table (for 4-bit to db conversion)
|
||||
int32_t m_register[8]; // registers
|
||||
|
@ -87,6 +92,7 @@ private:
|
|||
int32_t m_count[4]; // Position within the waveform
|
||||
int32_t m_output[4]; // 1-bit output of each channel, pre-volume
|
||||
int32_t m_cycles_to_ready; // number of cycles until the READY line goes active
|
||||
|
||||
//Modifications for easier sample conversion
|
||||
int32_t sample_rate;
|
||||
//Sample rate conversion
|
||||
|
@ -115,13 +121,21 @@ public:
|
|||
y2404_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
};
|
||||
|
||||
// SN76489 not verified yet. todo: verify;
|
||||
// NCR8496 whitenoise verified, phase verified; verified by ValleyBell & NewRisingSun
|
||||
class sn76489_device : public sn76496_base_device
|
||||
{
|
||||
public:
|
||||
sn76489_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
};
|
||||
|
||||
// PSSJ-3 whitenoise verified, phase verified; verified by ValleyBell & NewRisingSun
|
||||
class pssj3_device : public sn76496_base_device
|
||||
{
|
||||
public:
|
||||
pssj3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
};
|
||||
|
||||
|
||||
// SN76489A: whitenoise verified, phase verified, periodic verified (by plgdavid)
|
||||
class sn76489a_device : public sn76496_base_device
|
||||
{
|
||||
|
@ -143,11 +157,11 @@ public:
|
|||
sn94624_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
};
|
||||
|
||||
// NCR7496 not verified; info from smspower wiki
|
||||
class ncr7496_device : public sn76496_base_device
|
||||
// NCR8496 not verified; info from smspower wiki and vgmpf wiki
|
||||
class ncr8496_device : public sn76496_base_device
|
||||
{
|
||||
public:
|
||||
ncr7496_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
ncr8496_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
};
|
||||
|
||||
// Verified by Justin Kerk
|
||||
|
|
|
@ -63,8 +63,11 @@ static struct {
|
|||
} dac;
|
||||
} tandy;
|
||||
|
||||
static sn76496_device device(machine_config(), 0, 0, SOUND_CLOCK );
|
||||
static sn76496_device device_sn76496(machine_config(), 0, 0, SOUND_CLOCK );
|
||||
static ncr8496_device device_ncr8496(machine_config(), 0, 0, SOUND_CLOCK);
|
||||
|
||||
static sn76496_base_device* activeDevice = &device_ncr8496;
|
||||
#define device (*activeDevice)
|
||||
|
||||
static void SN76496Write(Bitu /*port*/,Bitu data,Bitu /*iolen*/) {
|
||||
tandy.last_write=PIC_Ticks;
|
||||
|
@ -73,6 +76,8 @@ static void SN76496Write(Bitu /*port*/,Bitu data,Bitu /*iolen*/) {
|
|||
tandy.enabled=true;
|
||||
}
|
||||
device.write(data);
|
||||
|
||||
// LOG_MSG("3voice write %X at time %7.3f",data,PIC_FullIndex());
|
||||
}
|
||||
|
||||
static void SN76496Update(Bitu length) {
|
||||
|
@ -271,6 +276,10 @@ public:
|
|||
enable_hw_tandy_dac=false;
|
||||
}
|
||||
|
||||
//Select the correct tandy chip implementation
|
||||
if (machine == MCH_PCJR) activeDevice = &device_sn76496;
|
||||
else activeDevice = &device_ncr8496;
|
||||
|
||||
real_writeb(0x40,0xd4,0x00);
|
||||
if (IS_TANDY_ARCH) {
|
||||
/* enable tandy sound if tandy=true/auto */
|
||||
|
|
Loading…
Add table
Reference in a new issue