Added PS/1 Audio Card emulation.

This commit is contained in:
SarahW 2016-04-13 21:56:15 +01:00
commit 61d7cf2276
13 changed files with 239 additions and 15 deletions

View file

@ -24,7 +24,7 @@ keyboard.c keyboard_amstrad.c keyboard_at.c keyboard_olim24.c keyboard_pcjr.c ke
linux-time.c lpt.c mcr.c mem.c model.c mouse.c mouse_ps2.c mouse_serial.c neat.c nmi.c nvr.c \
olivetti_m24.c opti.c pc.c pci.c pic.c piix.c pit.c ppi.c ps1.c rom.c serial.c sis496.c sound.c \
sound_ad1848.c sound_adlib.c sound_adlibgold.c sound_cms.c sound_emu8k.c sound_gus.c \
sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_pssj.c sound_sb.c sound_sb_dsp.c sound_sn76489.c \
sound_mpu401_uart.c sound_opl.c sound_pas16.c sound_ps1.c sound_pssj.c sound_sb.c sound_sb_dsp.c sound_sn76489.c \
sound_speaker.c sound_ssi2001.c sound_wss.c sound_ym7128.c soundopenal.c tandy_eeprom.c tandy_rom.c thread-pthread.c \
timer.c um8669f.c um8881f.c vid_ati_eeprom.c vid_ati_mach64.c vid_ati18800.c vid_ati28800.c \
vid_ati68860_ramdac.c vid_cga.c vid_cl5429.c vid_ega.c vid_et4000.c vid_et4000w32.c vid_hercules.c \

View file

@ -10,7 +10,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad
keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o model.o mouse.o mouse_ps2.o \
mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o \
serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \
sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_pssj.o sound_resid.o \
sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \
sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o \
sound_ym7128.o soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \
vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_ega.o vid_et4000.o \

View file

@ -10,7 +10,7 @@ OBJ = 386.o 386_dynarec.o 386_dynarec_ops.o 808x.o acer386sx.o ali1429.o amstrad
keyboard_olim24.o keyboard_pcjr.o keyboard_xt.o lpt.o mcr.o mem.o model.o mouse.o mouse_ps2.o \
mouse_serial.o neat.o nmi.o nvr.o olivetti_m24.o opti.o pc.o pci.o pic.o piix.o pit.o ppi.o ps1.o rom.o \
serial.o sis496.o sound.o sound_ad1848.o sound_adlib.o sound_adlibgold.o sound_cms.o sound_dbopl.o \
sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_pssj.o sound_resid.o \
sound_emu8k.o sound_gus.o sound_mpu401_uart.o sound_opl.o sound_pas16.o sound_ps1.o sound_pssj.o sound_resid.o \
sound_sb.o sound_sb_dsp.o sound_sn76489.o sound_speaker.o sound_ssi2001.o sound_wss.o sound_ym7128.o \
soundopenal.o tandy_eeprom.o tandy_rom.o timer.o um8881f.o um8669f.o vid_ati_eeprom.o vid_ati_mach64.o vid_ati18800.o \
vid_ati28800.o vid_ati68860_ramdac.o vid_cga.o vid_cl5429.o vid_ega.o vid_et4000.o \

View file

@ -1,3 +1,6 @@
#ifndef _CPU_H_
#define _CPU_H_
extern int cpu, cpu_manufacturer;
/*808x class CPUs*/
@ -111,3 +114,5 @@ void cpu_WRMSR();
extern int cpu_use_dynarec;
extern int xt_cpu_multi;
#endif

View file

@ -90,7 +90,7 @@ void gameport_timer_over(void *p)
// pclog("gameport_timer_over : axis_nr=%i\n", axis->axis_nr);
}
void *gameport_init()
void *gameport_init_common()
{
gameport_t *gameport = malloc(sizeof(gameport_t));
@ -111,11 +111,27 @@ void *gameport_init()
timer_add(gameport_timer_over, &gameport->axis[2].count, &gameport->axis[2].count, &gameport->axis[2]);
timer_add(gameport_timer_over, &gameport->axis[3].count, &gameport->axis[3].count, &gameport->axis[3]);
return gameport;
}
void *gameport_init()
{
gameport_t *gameport = gameport_init_common();
io_sethandler(0x0200, 0x0008, gameport_read, NULL, NULL, gameport_write, NULL, NULL, gameport);
return gameport;
}
void *gameport_201_init()
{
gameport_t *gameport = gameport_init_common();
io_sethandler(0x0201, 0x0001, gameport_read, NULL, NULL, gameport_write, NULL, NULL, gameport);
return gameport;
}
void gameport_close(void *p)
{
gameport_t *gameport = (gameport_t *)p;
@ -134,3 +150,15 @@ device_t gameport_device =
NULL,
NULL
};
device_t gameport_201_device =
{
"Game port (port 201h only)",
0,
gameport_201_init,
gameport_close,
NULL,
NULL,
NULL,
NULL
};

View file

@ -1 +1,2 @@
extern device_t gameport_device;
extern device_t gameport_201_device;

View file

@ -39,6 +39,7 @@
#include "ps1.h"
#include "serial.h"
#include "sis496.h"
#include "sound_ps1.h"
#include "sound_pssj.h"
#include "sound_sn76489.h"
#include "tandy_eeprom.h"
@ -154,7 +155,6 @@ void common_init()
pit_init();
serial1_init(0x3f8, 4);
serial2_init(0x2f8, 3);
device_add(&gameport_device);
}
void xt_init()
@ -166,6 +166,7 @@ void xt_init()
mouse_serial_init();
xtide_init();
nmi_init();
device_add(&gameport_device);
}
void pcjr_init()
@ -196,6 +197,7 @@ void tandy1k_init()
nmi_init();
if (romset != ROM_TANDY)
device_add(&tandy_eeprom_device);
device_add(&gameport_device);
}
void tandy1ksl2_init()
{
@ -209,6 +211,7 @@ void tandy1ksl2_init()
nmi_init();
device_add(&tandy_rom_device);
device_add(&tandy_eeprom_device);
device_add(&gameport_device);
}
void ams_init()
@ -222,6 +225,7 @@ void ams_init()
xtide_init();
nmi_init();
fdc_set_dskchg_activelow();
device_add(&gameport_device);
}
void europc_init()
@ -233,6 +237,7 @@ void europc_init()
mouse_serial_init();
xtide_init();
nmi_init();
device_add(&gameport_device);
}
void olim24_init()
@ -244,6 +249,7 @@ void olim24_init()
olivetti_m24_init();
xtide_init();
nmi_init();
device_add(&gameport_device);
}
void at_init()
@ -259,6 +265,7 @@ void at_init()
mouse_serial_init();
nvr_init();
pic2_init();
device_add(&gameport_device);
}
void deskpro386_init()
@ -282,6 +289,9 @@ void ps1_init()
pic2_init();
ps1mb_init();
fdc_set_dskchg_activelow();
device_add(&ps1_audio_device);
/*PS/1 audio uses ports 200h and 202-207h, so only initialise gameport on 201h*/
device_add(&gameport_201_device);
}
void at_neat_init()

174
src/sound_ps1.c Normal file
View file

@ -0,0 +1,174 @@
#include <stdlib.h>
#include "ibm.h"
#include "device.h"
#include "io.h"
#include "sound.h"
#include "sound_ps1.h"
#include "sound_sn76489.h"
typedef struct ps1_audio_t
{
sn76489_t sn76489;
uint8_t status, ctrl;
int timer_latch, timer_count, timer_enable;
uint8_t fifo[2048];
int fifo_read_idx, fifo_write_idx;
int fifo_threshold;
uint8_t dac_val;
int16_t buffer[SOUNDBUFLEN];
int pos;
} ps1_audio_t;
static void ps1_update_irq_status(ps1_audio_t *ps1)
{
if (((ps1->status & ps1->ctrl) & 0x12) && (ps1->ctrl & 0x01))
picint(1 << 7);
else
picintc(1 << 7);
}
static uint8_t ps1_audio_read(uint16_t port, void *p)
{
ps1_audio_t *ps1 = (ps1_audio_t *)p;
uint8_t temp;
// pclog("ps1_audio_read %04x %04x:%04x\n", port, CS, pc);
switch (port & 7)
{
case 0: /*ADC data*/
ps1->status &= ~0x10;
ps1_update_irq_status(ps1);
return 0;
case 2: /*Status*/
temp = ps1->status;
temp |= (ps1->ctrl & 0x01);
if ((ps1->fifo_write_idx - ps1->fifo_read_idx) >= 2048)
temp |= 0x08; /*FIFO full*/
if (ps1->fifo_read_idx == ps1->fifo_write_idx)
temp |= 0x04; /*FIFO empty*/
// pclog("Return status %02x\n", temp);
return temp;
case 3: /*FIFO timer*/
/*PS/1 technical reference says this should return the current value,
but the PS/1 BIOS and Stunt Island expect it not to change*/
return ps1->timer_latch;
case 4: case 5: case 6: case 7:
return 0;
}
return 0xff;
}
static void ps1_audio_write(uint16_t port, uint8_t val, void *p)
{
ps1_audio_t *ps1 = (ps1_audio_t *)p;
// pclog("ps1_audio_write %04x %02x\n", port, val);
switch (port & 7)
{
case 0: /*DAC output*/
// pclog("DAC write %08x %08x %i\n", ps1->fifo_write_idx, ps1->fifo_read_idx, ps1->fifo_write_idx - ps1->fifo_read_idx);
if ((ps1->fifo_write_idx - ps1->fifo_read_idx) < 2048)
{
ps1->fifo[ps1->fifo_write_idx & 2047] = val;
ps1->fifo_write_idx++;
}
break;
case 2: /*Control*/
ps1->ctrl = val;
if (!(val & 0x02))
ps1->status &= ~0x02;
ps1_update_irq_status(ps1);
break;
case 3: /*Timer reload value*/
ps1->timer_latch = val;
ps1->timer_count = (0xff-val) * TIMER_USEC;
ps1->timer_enable = (val != 0);
break;
case 4: /*Almost empty*/
ps1->fifo_threshold = val * 4;
break;
}
}
static void ps1_audio_update(ps1_audio_t *ps1)
{
for (; ps1->pos < sound_pos_global; ps1->pos++)
ps1->buffer[ps1->pos] = (int8_t)(ps1->dac_val ^ 0x80) * 0x20;
}
static void ps1_audio_callback(void *p)
{
ps1_audio_t *ps1 = (ps1_audio_t *)p;
ps1_audio_update(ps1);
if (ps1->fifo_read_idx != ps1->fifo_write_idx)
{
ps1->dac_val = ps1->fifo[ps1->fifo_read_idx & 2047];
ps1->fifo_read_idx++;
}
// pclog("ps1_callback %08x %08x %08x\n", ps1->fifo_write_idx, ps1->fifo_read_idx, ps1->fifo_threshold);
if ((ps1->fifo_write_idx - ps1->fifo_read_idx) == ps1->fifo_threshold)
{
// pclog("FIFO almost empty\n");
ps1->status |= 0x02; /*FIFO almost empty*/
}
ps1->status |= 0x10; /*ADC data ready*/
ps1_update_irq_status(ps1);
ps1->timer_count += ps1->timer_latch * TIMER_USEC;
}
static void ps1_audio_get_buffer(int16_t *buffer, int len, void *p)
{
ps1_audio_t *ps1 = (ps1_audio_t *)p;
int c;
ps1_audio_update(ps1);
for (c = 0; c < len * 2; c++)
buffer[c] += ps1->buffer[c >> 1];
ps1->pos = 0;
}
static void *ps1_audio_init()
{
ps1_audio_t *ps1 = malloc(sizeof(ps1_audio_t));
memset(ps1, 0, sizeof(ps1_audio_t));
sn76489_init(&ps1->sn76489, 0x0205, 0x0001, SN76496, 4000000);
io_sethandler(0x0200, 0x0001, ps1_audio_read, NULL, NULL, ps1_audio_write, NULL, NULL, ps1);
io_sethandler(0x0202, 0x0006, ps1_audio_read, NULL, NULL, ps1_audio_write, NULL, NULL, ps1);
timer_add(ps1_audio_callback, &ps1->timer_count, &ps1->timer_enable, ps1);
sound_add_handler(ps1_audio_get_buffer, ps1);
return ps1;
}
static void ps1_audio_close(void *p)
{
ps1_audio_t *ps1 = (ps1_audio_t *)p;
free(ps1);
}
device_t ps1_audio_device =
{
"PS/1 Audio Card",
0,
ps1_audio_init,
ps1_audio_close,
NULL,
NULL,
NULL,
NULL
};

1
src/sound_ps1.h Normal file
View file

@ -0,0 +1 @@
extern device_t ps1_audio_device;

View file

@ -185,7 +185,7 @@ void *pssj_init()
pssj_t *pssj = malloc(sizeof(pssj_t));
memset(pssj, 0, sizeof(pssj_t));
sn76489_init(&pssj->sn76489, 0x00c0, 0x0004, PSSJ);
sn76489_init(&pssj->sn76489, 0x00c0, 0x0004, PSSJ, 3579545);
io_sethandler(0x00C4, 0x0004, pssj_read, NULL, NULL, pssj_write, NULL, NULL, pssj);
timer_add(pssj_callback, &pssj->timer_count, &pssj->enable, pssj);

View file

@ -15,7 +15,7 @@ static float volslog[16]=
7.51785f,9.46440f,11.9194f,15.0000f
};
#define PSGCONST ((3579545.0 / 64.0) / 48000.0)
//#define PSGCONST ((3579545.0 / 64.0) / 48000.0)
void sn76489_update(sn76489_t *sn76489)
{
@ -29,7 +29,7 @@ void sn76489_update(sn76489_t *sn76489)
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 * PSGCONST);
sn76489->count[c] -= (256 * sn76489->psgconst);
while ((int)sn76489->count[c] < 0)
{
sn76489->count[c] += sn76489->latch[c];
@ -38,7 +38,7 @@ void sn76489_update(sn76489_t *sn76489)
}
result += (((sn76489->shift & 1) ^ 1) * 127 * volslog[sn76489->vol[0]] * 2);
sn76489->count[0] -= (512 * PSGCONST);
sn76489->count[0] -= (512 * sn76489->psgconst);
while ((int)sn76489->count[0] < 0 && sn76489->latch[0])
{
sn76489->count[0] += (sn76489->latch[0] * 4);
@ -177,7 +177,7 @@ 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)
void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type, int freq)
{
sound_add_handler(sn76489_get_buffer, sn76489);
@ -193,6 +193,7 @@ void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type)
sn76489->noise = 3;
sn76489->shift = 0x4000;
sn76489->type = type;
sn76489->psgconst = (((double)freq / 64.0) / 48000.0);
sn76489_mute = 0;
@ -204,7 +205,7 @@ void *sn76489_device_init()
sn76489_t *sn76489 = malloc(sizeof(sn76489_t));
memset(sn76489, 0, sizeof(sn76489_t));
sn76489_init(sn76489, 0x00c0, 0x0008, SN76496);
sn76489_init(sn76489, 0x00c0, 0x0008, SN76496, 3579545);
return sn76489;
}
@ -213,7 +214,7 @@ void *ncr8496_device_init()
sn76489_t *sn76489 = malloc(sizeof(sn76489_t));
memset(sn76489, 0, sizeof(sn76489_t));
sn76489_init(sn76489, 0x00c0, 0x0008, NCR8496);
sn76489_init(sn76489, 0x00c0, 0x0008, NCR8496, 3579545);
return sn76489;
}

View file

@ -25,7 +25,9 @@ typedef struct sn76489_t
int16_t buffer[SOUNDBUFLEN];
int pos;
double psgconst;
} sn76489_t;
void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type);
void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type, int freq);
void sn74689_set_extra_divide(sn76489_t *sn76489, int enable);

View file

@ -1,6 +1,8 @@
#ifndef _TIMER_H_
#define _TIMER_H_
#include "cpu.h"
extern int timer_start;
#define timer_start_period(cycles) \