Fix SN76489 behavior and make the Tandy 1000 SX use the NCR sound chip instead (as some revisions of it shipped with that), fixes #4700.
This commit is contained in:
@@ -20,6 +20,9 @@ typedef struct sn76489_t {
|
||||
int freqhi[4];
|
||||
int vol[4];
|
||||
uint32_t shift;
|
||||
uint32_t white_noise_tap_1;
|
||||
uint32_t white_noise_tap_2;
|
||||
uint32_t feedback_mask;
|
||||
uint8_t noise;
|
||||
int lasttone;
|
||||
uint8_t firstdat;
|
||||
|
@@ -1763,7 +1763,7 @@ machine_tandy1k_init(const machine_t *model, int type)
|
||||
tandy_read, NULL, NULL, tandy_write, NULL, NULL, dev);
|
||||
vid_init(dev);
|
||||
device_add_ex(&vid_device, dev);
|
||||
device_add(&sn76489_device);
|
||||
device_add((type == TYPE_TANDY1000SX) ? &ncr8496_device : &sn76489_device);
|
||||
break;
|
||||
|
||||
case TYPE_TANDY1000HX:
|
||||
|
@@ -21,7 +21,15 @@ static float volslog[16] = {
|
||||
7.51785f, 9.46440f, 11.9194f, 15.0000f
|
||||
};
|
||||
|
||||
void
|
||||
static int
|
||||
sn76489_check_tap_2(sn76489_t *sn76489)
|
||||
{
|
||||
int ret = ((sn76489->shift >> sn76489->white_noise_tap_2) & 1);
|
||||
|
||||
return (sn76489->type == SN76496) ? ret : !ret;
|
||||
}
|
||||
|
||||
static void
|
||||
sn76489_update(sn76489_t *sn76489)
|
||||
{
|
||||
for (; sn76489->pos < sound_pos_global; sn76489->pos++) {
|
||||
@@ -42,24 +50,28 @@ sn76489_update(sn76489_t *sn76489)
|
||||
result += (((sn76489->shift & 1) ^ 1) * 127 * volslog[sn76489->vol[0]] * 2);
|
||||
|
||||
sn76489->count[0] -= (512 * sn76489->psgconst);
|
||||
while (sn76489->count[0] < 0 && sn76489->latch[0]) {
|
||||
while ((sn76489->count[0] < 0) && sn76489->latch[0]) {
|
||||
sn76489->count[0] += (sn76489->latch[0] * 4);
|
||||
if (!(sn76489->noise & 4)) {
|
||||
if (sn76489->shift & 1)
|
||||
sn76489->shift |= 0x8000;
|
||||
sn76489->shift >>= 1;
|
||||
if ((sn76489->shift >> sn76489->white_noise_tap_1) & 1) {
|
||||
sn76489->shift >>= 1;
|
||||
sn76489->shift |= sn76489->feedback_mask;
|
||||
} else
|
||||
sn76489->shift >>= 1;
|
||||
} else {
|
||||
if ((sn76489->shift & 1) ^ ((sn76489->shift >> 1) & 1))
|
||||
sn76489->shift |= 0x8000;
|
||||
sn76489->shift >>= 1;
|
||||
if (((sn76489->shift >> sn76489->white_noise_tap_1) & 1) ^ sn76489_check_tap_2(sn76489)) {
|
||||
sn76489->shift >>= 1;
|
||||
sn76489->shift |= sn76489->feedback_mask;
|
||||
} else
|
||||
sn76489->shift >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
sn76489->buffer[sn76489->pos] = result;
|
||||
sn76489->buffer[sn76489->pos] = (sn76489->type == NCR8496) ? -result : result;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
sn76489_get_buffer(int32_t *buffer, int len, void *priv)
|
||||
{
|
||||
sn76489_t *sn76489 = (sn76489_t *) priv;
|
||||
@@ -74,7 +86,7 @@ sn76489_get_buffer(int32_t *buffer, int len, void *priv)
|
||||
sn76489->pos = 0;
|
||||
}
|
||||
|
||||
void
|
||||
static void
|
||||
sn76489_write(UNUSED(uint16_t addr), uint8_t data, void *priv)
|
||||
{
|
||||
sn76489_t *sn76489 = (sn76489_t *) priv;
|
||||
@@ -125,15 +137,13 @@ sn76489_write(UNUSED(uint16_t addr), uint8_t data, void *priv)
|
||||
sn76489->vol[1] = 0xf - data;
|
||||
break;
|
||||
case 0x60:
|
||||
if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496)
|
||||
sn76489->shift = 0x4000;
|
||||
if (((data & 4) != (sn76489->noise & 4)) || (sn76489->type == SN76496))
|
||||
sn76489->shift = sn76489->feedback_mask;
|
||||
sn76489->noise = data & 0xf;
|
||||
if ((data & 3) == 3)
|
||||
sn76489->latch[0] = sn76489->latch[1];
|
||||
else
|
||||
sn76489->latch[0] = 0x400 << (data & 3);
|
||||
if (!sn76489->extra_divide)
|
||||
sn76489->latch[0] &= 0x3ff;
|
||||
if (!sn76489->latch[0])
|
||||
sn76489->latch[0] = (sn76489->extra_divide ? 2048 : 1024) << 6;
|
||||
break;
|
||||
@@ -146,22 +156,24 @@ sn76489_write(UNUSED(uint16_t addr), uint8_t data, void *priv)
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* NCR8496 ignores writes to registers 1, 3, 5, 6 and 7 with bit 7 clear. */
|
||||
if ((sn76489->type != SN76496) && ((sn76489->firstdat & 0x10) || ((sn76489->firstdat & 0x70) == 0x60)))
|
||||
return;
|
||||
|
||||
if ((sn76489->firstdat & 0x70) == 0x60 && (sn76489->type == SN76496)) {
|
||||
if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496)
|
||||
sn76489->shift = 0x4000;
|
||||
if (sn76489->type == SN76496)
|
||||
sn76489->shift = sn76489->feedback_mask;
|
||||
sn76489->noise = data & 0xf;
|
||||
if ((data & 3) == 3)
|
||||
sn76489->latch[0] = sn76489->latch[1];
|
||||
else
|
||||
sn76489->latch[0] = 0x400 << (data & 3);
|
||||
if (!sn76489->latch[0])
|
||||
sn76489->latch[0] = 1024 << 6;
|
||||
sn76489->latch[0] = (sn76489->extra_divide ? 2048 : 1024) << 6;
|
||||
} else if ((sn76489->firstdat & 0x70) != 0x60) {
|
||||
if (sn76489->extra_divide)
|
||||
sn76489->freqhi[sn76489->lasttone] = data & 0x7F;
|
||||
else
|
||||
sn76489->freqhi[sn76489->lasttone] = data & 0x3F;
|
||||
freq = sn76489->freqlo[sn76489->lasttone] | (sn76489->freqhi[sn76489->lasttone] << 4);
|
||||
sn76489->freqhi[sn76489->lasttone] = data & 0x7F;
|
||||
freq = sn76489->freqlo[sn76489->lasttone] |
|
||||
(sn76489->freqhi[sn76489->lasttone] << 4);
|
||||
if (!sn76489->extra_divide)
|
||||
freq &= 0x3ff;
|
||||
if (!freq)
|
||||
@@ -190,6 +202,16 @@ sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type, int fre
|
||||
{
|
||||
sound_add_handler(sn76489_get_buffer, sn76489);
|
||||
|
||||
if (type == SN76496) {
|
||||
sn76489->white_noise_tap_1 = 0;
|
||||
sn76489->white_noise_tap_2 = 1;
|
||||
sn76489->feedback_mask = 0x4000;
|
||||
} else {
|
||||
sn76489->white_noise_tap_1 = 1;
|
||||
sn76489->white_noise_tap_2 = 5;
|
||||
sn76489->feedback_mask = 0x8000;
|
||||
}
|
||||
|
||||
sn76489->latch[0] = sn76489->latch[1] = sn76489->latch[2] = sn76489->latch[3] = 0x3FF << 6;
|
||||
sn76489->vol[0] = 0;
|
||||
sn76489->vol[1] = sn76489->vol[2] = sn76489->vol[3] = 8;
|
||||
@@ -200,7 +222,7 @@ sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type, int fre
|
||||
sn76489->count[2] = (rand() & 0x3FF) << 6;
|
||||
sn76489->count[3] = (rand() & 0x3FF) << 6;
|
||||
sn76489->noise = 3;
|
||||
sn76489->shift = 0x4000;
|
||||
sn76489->shift = sn76489->feedback_mask;
|
||||
sn76489->type = type;
|
||||
sn76489->psgconst = (((double) freq / 64.0) / (double) FREQ_48000);
|
||||
|
||||
|
Reference in New Issue
Block a user