Changes to device_t struct to accomodate the upcoming PCI IRQ arbitration rewrite; Added device.c/h API to obtain name from the device_t struct; Significant changes to win/win_settings.c to clean up the code a bit and fix bugs; Ported all the CPU and AudioPCI commits from PCem; Added an API call to allow ACPI soft power off to gracefully stop the emulator; Removed the Siemens PCD-2L from the Dev branch because it now works; Removed the Socket 5 HP Vectra from the Dev branch because it now works; Fixed the Compaq Presario and the Micronics Spitfire; Give the IBM PC330 its own list of 486 CPU so it can have DX2's with CPUID 0x470; SMM fixes; Rewrote the SYSENTER, SYSEXIT, SYSCALL, and SYSRET instructions; Changed IDE reset period to match the specification, fixes #929; The keyboard input and output ports are now forced in front of the queue when read, fixes a number of bugs, including the AMI Apollo hanging on soft reset; Added the Intel AN430TX but Dev branched because it does not work; The network code no longer drops packets if the emulated network card has failed to receive them (eg. when the buffer is full); Changes to PCI card adding and renamed some PCI slot types, also added proper AGP bridge slot types; USB UHCI emulation is no longer a stub (still doesn't fully work, but at least Windows XP chk with Debug no longer ASSERT's on it); Fixed NVR on the the SMC FDC37C932QF and APM variants; A number of fixes to Intel 4x0 chipsets, including fixing every register of the 440LX and 440EX; Some ACPI changes.
254 lines
9.0 KiB
C
254 lines
9.0 KiB
C
#include <stdio.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <wchar.h>
|
|
#include <time.h>
|
|
#include <86box/86box.h>
|
|
#include <86box/io.h>
|
|
#include <86box/device.h>
|
|
#include <86box/sound.h>
|
|
#include <86box/snd_sn76489.h>
|
|
|
|
|
|
int sn76489_mute;
|
|
|
|
|
|
static float volslog[16]=
|
|
{
|
|
0.00000f,0.59715f,0.75180f,0.94650f,
|
|
1.19145f,1.50000f,1.88835f,2.37735f,
|
|
2.99295f,3.76785f,4.74345f,5.97165f,
|
|
7.51785f,9.46440f,11.9194f,15.0000f
|
|
};
|
|
|
|
void sn76489_update(sn76489_t *sn76489)
|
|
{
|
|
for (; sn76489->pos < sound_pos_global; sn76489->pos++)
|
|
{
|
|
int c;
|
|
int16_t result = 0;
|
|
|
|
for (c = 1; c < 4; c++)
|
|
{
|
|
if (sn76489->latch[c] > 256) result += (int16_t) (volslog[sn76489->vol[c]] * sn76489->stat[c]);
|
|
else result += (int16_t) (volslog[sn76489->vol[c]] * 127);
|
|
|
|
sn76489->count[c] -= (256 * sn76489->psgconst);
|
|
while ((int)sn76489->count[c] < 0)
|
|
{
|
|
sn76489->count[c] += sn76489->latch[c];
|
|
sn76489->stat[c] = -sn76489->stat[c];
|
|
}
|
|
}
|
|
result += (((sn76489->shift & 1) ^ 1) * 127 * volslog[sn76489->vol[0]] * 2);
|
|
|
|
sn76489->count[0] -= (512 * sn76489->psgconst);
|
|
while ((int)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;
|
|
}
|
|
else
|
|
{
|
|
if ((sn76489->shift & 1) ^ ((sn76489->shift >> 1) & 1))
|
|
sn76489->shift |= 0x8000;
|
|
sn76489->shift >>= 1;
|
|
}
|
|
}
|
|
|
|
sn76489->buffer[sn76489->pos] = result;
|
|
}
|
|
}
|
|
|
|
void sn76489_get_buffer(int32_t *buffer, int len, void *p)
|
|
{
|
|
sn76489_t *sn76489 = (sn76489_t *)p;
|
|
|
|
int c;
|
|
|
|
sn76489_update(sn76489);
|
|
|
|
if (!sn76489_mute)
|
|
{
|
|
for (c = 0; c < len * 2; c++)
|
|
buffer[c] += sn76489->buffer[c >> 1];
|
|
}
|
|
|
|
sn76489->pos = 0;
|
|
}
|
|
|
|
void sn76489_write(uint16_t addr, uint8_t data, void *p)
|
|
{
|
|
sn76489_t *sn76489 = (sn76489_t *)p;
|
|
int freq;
|
|
|
|
sn76489_update(sn76489);
|
|
|
|
if (data & 0x80)
|
|
{
|
|
sn76489->firstdat = data;
|
|
switch (data & 0x70)
|
|
{
|
|
case 0:
|
|
sn76489->freqlo[3] = data & 0xf;
|
|
sn76489->latch[3] = (sn76489->freqlo[3] | (sn76489->freqhi[3] << 4)) << 6;
|
|
if (sn76489->extra_divide)
|
|
sn76489->latch[3] &= 0x3ff;
|
|
if (!sn76489->latch[3])
|
|
sn76489->latch[3] = (sn76489->extra_divide ? 2048 : 1024) << 6;
|
|
sn76489->lasttone = 3;
|
|
break;
|
|
case 0x10:
|
|
data &= 0xf;
|
|
sn76489->vol[3] = 0xf - data;
|
|
break;
|
|
case 0x20:
|
|
sn76489->freqlo[2] = data & 0xf;
|
|
sn76489->latch[2] = (sn76489->freqlo[2] | (sn76489->freqhi[2] << 4)) << 6;
|
|
if (sn76489->extra_divide)
|
|
sn76489->latch[2] &= 0x3ff;
|
|
if (!sn76489->latch[2])
|
|
sn76489->latch[2] = (sn76489->extra_divide ? 2048 : 1024) << 6;
|
|
sn76489->lasttone = 2;
|
|
break;
|
|
case 0x30:
|
|
data &= 0xf;
|
|
sn76489->vol[2] = 0xf - data;
|
|
break;
|
|
case 0x40:
|
|
sn76489->freqlo[1] = data & 0xf;
|
|
sn76489->latch[1] = (sn76489->freqlo[1] | (sn76489->freqhi[1] << 4)) << 6;
|
|
if (sn76489->extra_divide)
|
|
sn76489->latch[1] &= 0x3ff;
|
|
if (!sn76489->latch[1])
|
|
sn76489->latch[1] = (sn76489->extra_divide ? 2048 : 1024) << 6;
|
|
sn76489->lasttone = 1;
|
|
break;
|
|
case 0x50:
|
|
data &= 0xf;
|
|
sn76489->vol[1] = 0xf - data;
|
|
break;
|
|
case 0x60:
|
|
if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496)
|
|
sn76489->shift = 0x4000;
|
|
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;
|
|
case 0x70:
|
|
data &= 0xf;
|
|
sn76489->vol[0] = 0xf - data;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((sn76489->firstdat & 0x70) == 0x60 && (sn76489->type == SN76496))
|
|
{
|
|
if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496)
|
|
sn76489->shift = 0x4000;
|
|
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;
|
|
}
|
|
else if ((sn76489->firstdat & 0x70) != 0x60)
|
|
{
|
|
sn76489->freqhi[sn76489->lasttone] = data & 0x7F;
|
|
freq = sn76489->freqlo[sn76489->lasttone] | (sn76489->freqhi[sn76489->lasttone] << 4);
|
|
if (sn76489->extra_divide)
|
|
freq &= 0x3ff;
|
|
if (!freq)
|
|
freq = sn76489->extra_divide ? 2048 : 1024;
|
|
if ((sn76489->noise & 3) == 3 && sn76489->lasttone == 1)
|
|
sn76489->latch[0] = freq << 6;
|
|
sn76489->latch[sn76489->lasttone] = freq << 6;
|
|
}
|
|
}
|
|
}
|
|
|
|
void sn74689_set_extra_divide(sn76489_t *sn76489, int enable)
|
|
{
|
|
sn76489->extra_divide = enable;
|
|
}
|
|
|
|
void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type, int freq)
|
|
{
|
|
sound_add_handler(sn76489_get_buffer, sn76489);
|
|
|
|
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;
|
|
sn76489->stat[0] = sn76489->stat[1] = sn76489->stat[2] = sn76489->stat[3] = 127;
|
|
srand(time(NULL));
|
|
sn76489->count[0] = 0;
|
|
sn76489->count[1] = (rand()&0x3FF)<<6;
|
|
sn76489->count[2] = (rand()&0x3FF)<<6;
|
|
sn76489->count[3] = (rand()&0x3FF)<<6;
|
|
sn76489->noise = 3;
|
|
sn76489->shift = 0x4000;
|
|
sn76489->type = type;
|
|
sn76489->psgconst = (((double)freq / 64.0) / 48000.0);
|
|
|
|
sn76489_mute = 0;
|
|
|
|
io_sethandler(base, size, NULL, NULL, NULL, sn76489_write, NULL, NULL, sn76489);
|
|
}
|
|
|
|
void *sn76489_device_init(const device_t *info)
|
|
{
|
|
sn76489_t *sn76489 = malloc(sizeof(sn76489_t));
|
|
memset(sn76489, 0, sizeof(sn76489_t));
|
|
|
|
sn76489_init(sn76489, 0x00c0, 0x0008, SN76496, 3579545);
|
|
|
|
return sn76489;
|
|
}
|
|
void *ncr8496_device_init(const device_t *info)
|
|
{
|
|
sn76489_t *sn76489 = malloc(sizeof(sn76489_t));
|
|
memset(sn76489, 0, sizeof(sn76489_t));
|
|
|
|
sn76489_init(sn76489, 0x00c0, 0x0008, NCR8496, 3579545);
|
|
|
|
return sn76489;
|
|
}
|
|
|
|
void sn76489_device_close(void *p)
|
|
{
|
|
sn76489_t *sn76489 = (sn76489_t *)p;
|
|
|
|
free(sn76489);
|
|
}
|
|
|
|
const device_t sn76489_device =
|
|
{
|
|
"TI SN74689 PSG",
|
|
0,
|
|
0,
|
|
sn76489_device_init,
|
|
sn76489_device_close,
|
|
NULL, { NULL }, NULL,
|
|
NULL
|
|
};
|
|
const device_t ncr8496_device =
|
|
{
|
|
"NCR8496 PSG",
|
|
0,
|
|
0,
|
|
ncr8496_device_init,
|
|
sn76489_device_close,
|
|
NULL, { NULL }, NULL,
|
|
NULL
|
|
};
|