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:
OBattler
2024-08-08 18:56:05 +02:00
parent 479ab87f17
commit b172df6498
3 changed files with 50 additions and 25 deletions

View File

@@ -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;

View File

@@ -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:

View File

@@ -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);