mirror of
https://github.com/holub/mame
synced 2025-05-25 15:25:33 +03:00
Update SN76489/A to have correct PRNG waveforms (a 0 bit was missing at the beginning, and beginning of SN76489 waveform was all 1s instead of 0s as measured on hardware). Add SN94624 (same as SN76489). [Lord Nightmare, plgDavid (David Viens)]
This commit is contained in:
parent
45dfc2315a
commit
d3a8485a6a
@ -12,9 +12,11 @@
|
|||||||
duty cycle channel.
|
duty cycle channel.
|
||||||
|
|
||||||
Noise emulation for all chips should be accurate:
|
Noise emulation for all chips should be accurate:
|
||||||
SN76489 uses a 15-bit shift register with taps on bits D and E, output on /E
|
SN76489 uses a 15-bit shift register with taps on bits D and E, output on E,
|
||||||
|
XOR function; SN94624 is identical to SN76489.
|
||||||
* It uses a 15-bit ring buffer for periodic noise/arbitrary duty cycle.
|
* It uses a 15-bit ring buffer for periodic noise/arbitrary duty cycle.
|
||||||
SN76489A uses a 16-bit shift register with taps on bits D and F, output on F
|
SN76489A uses a 16-bit shift register with taps on bits D and E, output on F,
|
||||||
|
XNOR function
|
||||||
* It uses a 16-bit ring buffer for periodic noise/arbitrary duty cycle.
|
* It uses a 16-bit ring buffer for periodic noise/arbitrary duty cycle.
|
||||||
SN76494 and SN76496 are PROBABLY identical in operation to the SN76489A
|
SN76494 and SN76496 are PROBABLY identical in operation to the SN76489A
|
||||||
* They have an audio input line which is mixed with the 4 channels of output.
|
* They have an audio input line which is mixed with the 4 channels of output.
|
||||||
@ -37,13 +39,19 @@
|
|||||||
Add READY line readback; cleaned up struct a bit. Cleaned up comments.
|
Add READY line readback; cleaned up struct a bit. Cleaned up comments.
|
||||||
Add more TODOs. Fixed some unsaved savestate related stuff.
|
Add more TODOs. Fixed some unsaved savestate related stuff.
|
||||||
|
|
||||||
|
04/11/2009 : Lord Nightmare
|
||||||
|
Changed the way that the invert works (it now selects between XOR and XNOR
|
||||||
|
for the taps), and added R->OldNoise to simulate the extra 0 that is always
|
||||||
|
output before the noise LFSR contents are after an LFSR reset.
|
||||||
|
This fixes SN76489/A to match chips. Added SN94624.
|
||||||
|
|
||||||
TODO: * Implement a function for setting stereo regs for the game gear.
|
TODO: * Implement a function for setting stereo regs for the game gear.
|
||||||
Requires making the core support both mono and stereo, and have
|
Requires making the core support both mono and stereo, and have
|
||||||
a select register which determines which channels go where.
|
a select register which determines which channels go where.
|
||||||
* Implement the TMS9919 and SN94624, which are earlier versions,
|
* Implement the TMS9919 which is an earlier version, possibly
|
||||||
possibly lacking the /8 clock divider, of the SN76489, and hence
|
lacking the /8 clock divider, of the SN76489, and hence would
|
||||||
would have a max clock of 500Khz and 4 clocks per sample, as
|
have a max clock of 500Khz and 4 clocks per sample, as opposed to
|
||||||
opposed to max of 4Mhz and 32 clocks per sample on the SN76489A
|
max of 4Mhz and 32 clocks per sample on the SN76489A.
|
||||||
* Implement the T6W28; has registers in a weird order, needs writes
|
* Implement the T6W28; has registers in a weird order, needs writes
|
||||||
to be 'sanitized' first. Also is stereo, similar to game gear.
|
to be 'sanitized' first. Also is stereo, similar to game gear.
|
||||||
* Implement the NCR 7496; Is probably 100% compatible with SN76496,
|
* Implement the NCR 7496; Is probably 100% compatible with SN76496,
|
||||||
@ -73,9 +81,10 @@ struct _sn76496_state
|
|||||||
UINT32 RNG; /* noise generator LFSR*/
|
UINT32 RNG; /* noise generator LFSR*/
|
||||||
INT32 FeedbackMask; /* mask for feedback */
|
INT32 FeedbackMask; /* mask for feedback */
|
||||||
INT32 WhitenoiseTaps; /* mask for white noise taps */
|
INT32 WhitenoiseTaps; /* mask for white noise taps */
|
||||||
INT32 WhitenoiseInvert; /* white noise invert flag */
|
INT32 FeedbackInvert; /* feedback invert flag (xor vs xnor) */
|
||||||
INT32 Period[4]; /* Length of 1/2 of waveform */
|
INT32 Period[4]; /* Length of 1/2 of waveform */
|
||||||
INT32 Count[4]; /* Position within the waveform */
|
INT32 Count[4]; /* Position within the waveform */
|
||||||
|
INT32 OldNoise; /* 1 bit output of the PREVIOUS noise output, buffered by the volume amp */
|
||||||
INT32 Output[4]; /* 1-bit output of each channel, pre-volume */
|
INT32 Output[4]; /* 1-bit output of each channel, pre-volume */
|
||||||
INT32 CyclestoREADY;/* number of cycles until the READY line goes active */
|
INT32 CyclestoREADY;/* number of cycles until the READY line goes active */
|
||||||
};
|
};
|
||||||
@ -247,7 +256,7 @@ static STREAM_UPDATE( SN76496Update )
|
|||||||
{
|
{
|
||||||
if (NOISEMODE == 1) /* White Noise Mode */
|
if (NOISEMODE == 1) /* White Noise Mode */
|
||||||
{
|
{
|
||||||
if (((R->RNG & R->WhitenoiseTaps) != R->WhitenoiseTaps) && ((R->RNG & R->WhitenoiseTaps) != 0)) /* crappy xor! */
|
if ((((R->RNG & R->WhitenoiseTaps) != R->WhitenoiseTaps) && ((R->RNG & R->WhitenoiseTaps) != 0)) ^ R->FeedbackInvert ) /* XOR or XNOR */
|
||||||
{
|
{
|
||||||
R->RNG >>= 1;
|
R->RNG >>= 1;
|
||||||
R->RNG |= R->FeedbackMask;
|
R->RNG |= R->FeedbackMask;
|
||||||
@ -256,7 +265,6 @@ static STREAM_UPDATE( SN76496Update )
|
|||||||
{
|
{
|
||||||
R->RNG >>= 1;
|
R->RNG >>= 1;
|
||||||
}
|
}
|
||||||
R->Output[3] = R->WhitenoiseInvert ? !(R->RNG & 1) : R->RNG & 1;
|
|
||||||
}
|
}
|
||||||
else /* Periodic noise mode */
|
else /* Periodic noise mode */
|
||||||
{
|
{
|
||||||
@ -269,8 +277,9 @@ static STREAM_UPDATE( SN76496Update )
|
|||||||
{
|
{
|
||||||
R->RNG >>= 1;
|
R->RNG >>= 1;
|
||||||
}
|
}
|
||||||
R->Output[3] = R->RNG & 1;
|
|
||||||
}
|
}
|
||||||
|
R->Output[3] = R->OldNoise;
|
||||||
|
R->OldNoise = R->RNG & 1;
|
||||||
R->Count[3] += R->Period[3];
|
R->Count[3] += R->Period[3];
|
||||||
if (R->Output[3]) vol[3] += R->Period[3];
|
if (R->Output[3]) vol[3] += R->Period[3];
|
||||||
}
|
}
|
||||||
@ -344,17 +353,19 @@ static int SN76496_init(const device_config *device, sn76496_state *R)
|
|||||||
/* Default is SN76489 non-A */
|
/* Default is SN76489 non-A */
|
||||||
R->FeedbackMask = 0x4000; /* mask for feedback */
|
R->FeedbackMask = 0x4000; /* mask for feedback */
|
||||||
R->WhitenoiseTaps = 0x03; /* mask for white noise taps */
|
R->WhitenoiseTaps = 0x03; /* mask for white noise taps */
|
||||||
R->WhitenoiseInvert = 1; /* white noise invert flag */
|
R->FeedbackInvert = 0; /* feedback invert flag */
|
||||||
R->CyclestoREADY = 1; /* assume ready is not active immediately on init. is this correct?*/
|
R->CyclestoREADY = 1; /* assume ready is not active immediately on init. is this correct?*/
|
||||||
|
|
||||||
R->RNG = R->FeedbackMask;
|
R->RNG = R->FeedbackMask;
|
||||||
R->Output[3] = R->RNG & 1;
|
R->OldNoise = 0;
|
||||||
|
R->Output[3] = R->OldNoise;
|
||||||
|
R->OldNoise = R->RNG & 1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void generic_start(const device_config *device, int feedbackmask, int noisetaps, int noiseinvert)
|
static void generic_start(const device_config *device, int feedbackmask, int noisetaps, int feedbackinvert)
|
||||||
{
|
{
|
||||||
sn76496_state *chip = get_safe_token(device);
|
sn76496_state *chip = get_safe_token(device);
|
||||||
|
|
||||||
@ -364,7 +375,7 @@ static void generic_start(const device_config *device, int feedbackmask, int noi
|
|||||||
|
|
||||||
chip->FeedbackMask = feedbackmask;
|
chip->FeedbackMask = feedbackmask;
|
||||||
chip->WhitenoiseTaps = noisetaps;
|
chip->WhitenoiseTaps = noisetaps;
|
||||||
chip->WhitenoiseInvert = noiseinvert;
|
chip->FeedbackInvert = feedbackinvert;
|
||||||
|
|
||||||
state_save_register_device_item_array(device, 0, chip->VolTable);
|
state_save_register_device_item_array(device, 0, chip->VolTable);
|
||||||
state_save_register_device_item_array(device, 0, chip->Register);
|
state_save_register_device_item_array(device, 0, chip->Register);
|
||||||
@ -373,9 +384,10 @@ static void generic_start(const device_config *device, int feedbackmask, int noi
|
|||||||
state_save_register_device_item(device, 0, chip->RNG);
|
state_save_register_device_item(device, 0, chip->RNG);
|
||||||
state_save_register_device_item(device, 0, chip->FeedbackMask);
|
state_save_register_device_item(device, 0, chip->FeedbackMask);
|
||||||
state_save_register_device_item(device, 0, chip->WhitenoiseTaps);
|
state_save_register_device_item(device, 0, chip->WhitenoiseTaps);
|
||||||
state_save_register_device_item(device, 0, chip->WhitenoiseInvert);
|
state_save_register_device_item(device, 0, chip->FeedbackInvert);
|
||||||
state_save_register_device_item_array(device, 0, chip->Period);
|
state_save_register_device_item_array(device, 0, chip->Period);
|
||||||
state_save_register_device_item_array(device, 0, chip->Count);
|
state_save_register_device_item_array(device, 0, chip->Count);
|
||||||
|
state_save_register_device_item(device, 0, chip->OldNoise);
|
||||||
state_save_register_device_item_array(device, 0, chip->Output);
|
state_save_register_device_item_array(device, 0, chip->Output);
|
||||||
state_save_register_device_item(device, 0, chip->CyclestoREADY);
|
state_save_register_device_item(device, 0, chip->CyclestoREADY);
|
||||||
}
|
}
|
||||||
@ -383,32 +395,37 @@ static void generic_start(const device_config *device, int feedbackmask, int noi
|
|||||||
|
|
||||||
static DEVICE_START( sn76489 )
|
static DEVICE_START( sn76489 )
|
||||||
{
|
{
|
||||||
generic_start(device, 0x4000, 0x03, TRUE);
|
generic_start(device, 0x4000, 0x03, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_START( sn76489a )
|
static DEVICE_START( sn76489a )
|
||||||
{
|
{
|
||||||
generic_start(device, 0x8000, 0x06, FALSE);
|
generic_start(device, 0x8000, 0x06, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_START( sn76494 )
|
static DEVICE_START( sn76494 )
|
||||||
{
|
{
|
||||||
generic_start(device, 0x8000, 0x06, FALSE);
|
generic_start(device, 0x8000, 0x06, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_START( sn76496 )
|
static DEVICE_START( sn76496 )
|
||||||
{
|
{
|
||||||
generic_start(device, 0x8000, 0x06, FALSE);
|
generic_start(device, 0x8000, 0x06, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static DEVICE_START( sn94624 )
|
||||||
|
{
|
||||||
|
generic_start(device, 0x4000, 0x03, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_START( gamegear )
|
static DEVICE_START( gamegear )
|
||||||
{
|
{
|
||||||
generic_start(device, 0x8000, 0x09, FALSE);
|
generic_start(device, 0x8000, 0x09, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DEVICE_START( smsiii )
|
static DEVICE_START( smsiii )
|
||||||
{
|
{
|
||||||
generic_start(device, 0x8000, 0x09, FALSE);
|
generic_start(device, 0x8000, 0x09, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -447,6 +464,16 @@ DEVICE_GET_INFO( sn76489 )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DEVICE_GET_INFO( sn94624 )
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case DEVINFO_FCT_START: info->start = DEVICE_START_NAME( sn94624 ); break;
|
||||||
|
case DEVINFO_STR_NAME: strcpy(info->s, "SN94624"); break;
|
||||||
|
default: DEVICE_GET_INFO_CALL(sn76496); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DEVICE_GET_INFO( sn76489a )
|
DEVICE_GET_INFO( sn76489a )
|
||||||
{
|
{
|
||||||
switch (state)
|
switch (state)
|
||||||
|
@ -10,6 +10,7 @@ DEVICE_GET_INFO( sn76496 );
|
|||||||
DEVICE_GET_INFO( sn76489 );
|
DEVICE_GET_INFO( sn76489 );
|
||||||
DEVICE_GET_INFO( sn76489a );
|
DEVICE_GET_INFO( sn76489a );
|
||||||
DEVICE_GET_INFO( sn76494 );
|
DEVICE_GET_INFO( sn76494 );
|
||||||
|
DEVICE_GET_INFO( sn94624 );
|
||||||
DEVICE_GET_INFO( gamegear );
|
DEVICE_GET_INFO( gamegear );
|
||||||
DEVICE_GET_INFO( smsiii );
|
DEVICE_GET_INFO( smsiii );
|
||||||
|
|
||||||
@ -17,6 +18,7 @@ DEVICE_GET_INFO( smsiii );
|
|||||||
#define SOUND_SN76489 DEVICE_GET_INFO_NAME( sn76489 )
|
#define SOUND_SN76489 DEVICE_GET_INFO_NAME( sn76489 )
|
||||||
#define SOUND_SN76489A DEVICE_GET_INFO_NAME( sn76489a )
|
#define SOUND_SN76489A DEVICE_GET_INFO_NAME( sn76489a )
|
||||||
#define SOUND_SN76494 DEVICE_GET_INFO_NAME( sn76494 )
|
#define SOUND_SN76494 DEVICE_GET_INFO_NAME( sn76494 )
|
||||||
|
#define SOUND_SN94624 DEVICE_GET_INFO_NAME( sn94624 )
|
||||||
#define SOUND_GAMEGEAR DEVICE_GET_INFO_NAME( gamegear )
|
#define SOUND_GAMEGEAR DEVICE_GET_INFO_NAME( gamegear )
|
||||||
#define SOUND_SMSIII DEVICE_GET_INFO_NAME( smsiii )
|
#define SOUND_SMSIII DEVICE_GET_INFO_NAME( smsiii )
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user