diff options
author | 2009-11-04 18:21:30 +0000 | |
---|---|---|
committer | 2009-11-04 18:21:30 +0000 | |
commit | d3a8485a6aaa7bed502899fb41815a51501a325d (patch) | |
tree | 54d656822d0b3a474d966e25f11998c6e771f0a0 /src/emu/sound/sn76496.c | |
parent | 45dfc2315a3f80695cc1a32bd8032186b29dc8a2 (diff) |
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)]
Diffstat (limited to 'src/emu/sound/sn76496.c')
-rw-r--r-- | src/emu/sound/sn76496.c | 69 |
1 files changed, 48 insertions, 21 deletions
diff --git a/src/emu/sound/sn76496.c b/src/emu/sound/sn76496.c index 3804edbeef3..52192d17b28 100644 --- a/src/emu/sound/sn76496.c +++ b/src/emu/sound/sn76496.c @@ -12,9 +12,11 @@ duty cycle channel. 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. - 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. 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. @@ -36,14 +38,20 @@ 28/04/2009 : Lord Nightmare Add READY line readback; cleaned up struct a bit. Cleaned up comments. 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. Requires making the core support both mono and stereo, and have a select register which determines which channels go where. - * Implement the TMS9919 and SN94624, which are earlier versions, - possibly lacking the /8 clock divider, of the SN76489, and hence - would have a max clock of 500Khz and 4 clocks per sample, as - opposed to max of 4Mhz and 32 clocks per sample on the SN76489A + * Implement the TMS9919 which is an earlier version, possibly + lacking the /8 clock divider, of the SN76489, and hence would + have a max clock of 500Khz and 4 clocks per sample, as opposed to + max of 4Mhz and 32 clocks per sample on the SN76489A. * Implement the T6W28; has registers in a weird order, needs writes to be 'sanitized' first. Also is stereo, similar to game gear. * Implement the NCR 7496; Is probably 100% compatible with SN76496, @@ -73,9 +81,10 @@ struct _sn76496_state UINT32 RNG; /* noise generator LFSR*/ INT32 FeedbackMask; /* mask for feedback */ 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 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 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 (((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 |= R->FeedbackMask; @@ -256,7 +265,6 @@ static STREAM_UPDATE( SN76496Update ) { R->RNG >>= 1; } - R->Output[3] = R->WhitenoiseInvert ? !(R->RNG & 1) : R->RNG & 1; } else /* Periodic noise mode */ { @@ -269,8 +277,9 @@ static STREAM_UPDATE( SN76496Update ) { 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]; 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 */ R->FeedbackMask = 0x4000; /* mask for feedback */ 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->RNG = R->FeedbackMask; - R->Output[3] = R->RNG & 1; + R->OldNoise = 0; + R->Output[3] = R->OldNoise; + R->OldNoise = R->RNG & 1; 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); @@ -364,7 +375,7 @@ static void generic_start(const device_config *device, int feedbackmask, int noi chip->FeedbackMask = feedbackmask; 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->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->FeedbackMask); 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->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(device, 0, chip->CyclestoREADY); } @@ -383,32 +395,37 @@ static void generic_start(const device_config *device, int feedbackmask, int noi static DEVICE_START( sn76489 ) { - generic_start(device, 0x4000, 0x03, TRUE); + generic_start(device, 0x4000, 0x03, FALSE); } static DEVICE_START( sn76489a ) { - generic_start(device, 0x8000, 0x06, FALSE); + generic_start(device, 0x8000, 0x06, TRUE); } static DEVICE_START( sn76494 ) { - generic_start(device, 0x8000, 0x06, FALSE); + generic_start(device, 0x8000, 0x06, TRUE); } 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 ) { - generic_start(device, 0x8000, 0x09, FALSE); + generic_start(device, 0x8000, 0x09, TRUE); } 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 ) { switch (state) |