VIA PIPC/AC97: Fixed and enabled software FM mode

This commit is contained in:
RichardG867
2023-03-24 20:53:39 -03:00
parent 4a1d264125
commit 92dd28efc1
2 changed files with 40 additions and 29 deletions

View File

@@ -59,13 +59,15 @@
/* Most revision numbers (PCI-ISA bridge or otherwise) were lifted from PCI device /* Most revision numbers (PCI-ISA bridge or otherwise) were lifted from PCI device
listings on forums, as VIA's datasheets are not very helpful regarding those. */ listings on forums, as VIA's datasheets are not very helpful regarding those. */
#define VIA_PIPC_586A 0x05862500 #define VIA_PIPC_586A 0x05862500
#define VIA_PIPC_586B 0x05864700 #define VIA_PIPC_586B 0x05864700
#define VIA_PIPC_596A 0x05960900 #define VIA_PIPC_596A 0x05960900
#define VIA_PIPC_596B 0x05962300 #define VIA_PIPC_596B 0x05962300
#define VIA_PIPC_686A 0x06861400 #define VIA_PIPC_686A 0x06861400
#define VIA_PIPC_686B 0x06864000 #define VIA_PIPC_686B 0x06864000
#define VIA_PIPC_8231 0x82311000 #define VIA_PIPC_8231 0x82311000
#define VIA_PIPC_FM_EMULATION 1
enum { enum {
TRAP_DRQ = 0, TRAP_DRQ = 0,
@@ -118,7 +120,7 @@ typedef struct _pipc_ {
ide_regs[256], ide_regs[256],
usb_regs[2][256], usb_regs[2][256],
power_regs[256], power_regs[256],
ac97_regs[2][256], fmnmi_regs[4]; ac97_regs[2][256], fmnmi_regs[4], fmnmi_status;
sff8038i_t *bm[2]; sff8038i_t *bm[2];
nvr_t *nvr; nvr_t *nvr;
@@ -760,10 +762,10 @@ pipc_fmnmi_handlers(pipc_t *dev, uint8_t modem)
static uint8_t static uint8_t
pipc_fm_read(uint16_t addr, void *priv) pipc_fm_read(uint16_t addr, void *priv)
{ {
#ifdef VIA_PIPC_FM_EMULATION
uint8_t ret = 0x00;
#else
pipc_t *dev = (pipc_t *) priv; pipc_t *dev = (pipc_t *) priv;
#ifdef VIA_PIPC_FM_EMULATION
uint8_t ret = ((addr & 0x03) == 0x00) ? dev->fmnmi_status : 0x00;
#else
uint8_t ret = dev->sb->opl.read(addr, dev->sb->opl.priv); uint8_t ret = dev->sb->opl.read(addr, dev->sb->opl.priv);
#endif #endif
@@ -788,6 +790,19 @@ pipc_fm_write(uint16_t addr, uint8_t val, void *priv)
} else { } else {
dev->fmnmi_regs[0x01] = val; dev->fmnmi_regs[0x01] = val;
/* TODO: Probe how real hardware handles OPL timers. This assumed implementation
just sets the relevant interrupt flags as soon as a timer is started. */
if (!(addr & 0x02) && (dev->fmnmi_regs[0x02] == 0x04)) {
if (val & 0x80)
dev->fmnmi_status = 0x00;
if ((val & 0x41) == 0x01)
dev->fmnmi_status |= 0x40;
if ((val & 0x22) == 0x02)
dev->fmnmi_status |= 0x20;
if (dev->fmnmi_status & 0x60)
dev->fmnmi_status |= 0x80;
}
/* Fire NMI/SMI if enabled. */ /* Fire NMI/SMI if enabled. */
if (dev->ac97_regs[0][0x48] & 0x01) { if (dev->ac97_regs[0][0x48] & 0x01) {
pipc_log("PIPC: Raising %s\n", (dev->ac97_regs[0][0x48] & 0x04) ? "SMI" : "NMI"); pipc_log("PIPC: Raising %s\n", (dev->ac97_regs[0][0x48] & 0x04) ? "SMI" : "NMI");

View File

@@ -178,6 +178,7 @@ ac97_via_update_codec(ac97_via_t *dev)
/* Update volumes according to codec registers. */ /* Update volumes according to codec registers. */
ac97_codec_getattn(codec, 0x02, &dev->master_vol_l, &dev->master_vol_r); ac97_codec_getattn(codec, 0x02, &dev->master_vol_l, &dev->master_vol_r);
ac97_codec_getattn(codec, 0x18, &dev->sgd[0].vol_l, &dev->sgd[0].vol_r); ac97_codec_getattn(codec, 0x18, &dev->sgd[0].vol_l, &dev->sgd[0].vol_r);
ac97_codec_getattn(codec, 0x18, &dev->sgd[2].vol_l, &dev->sgd[2].vol_r); /* VIAFMTSR sets Master, CD and PCM volumes to 0 dB */
ac97_codec_getattn(codec, 0x12, &dev->cd_vol_l, &dev->cd_vol_r); ac97_codec_getattn(codec, 0x12, &dev->cd_vol_l, &dev->cd_vol_r);
/* Update sample rate according to codec registers and the variable sample rate flag. */ /* Update sample rate according to codec registers and the variable sample rate flag. */
@@ -321,7 +322,7 @@ ac97_via_sgd_write(uint16_t addr, uint8_t val, void *priv)
/* Start at the specified entry pointer. */ /* Start at the specified entry pointer. */
dev->sgd[addr >> 4].sample_ptr = 0; dev->sgd[addr >> 4].sample_ptr = 0;
dev->sgd[addr >> 4].entry_ptr = *((uint32_t *) &dev->sgd_regs[(addr & 0xf0) | 0x4]) & 0xfffffffe; dev->sgd[addr >> 4].entry_ptr = *((uint32_t *) &dev->sgd_regs[(addr & 0xf0) | 0x4]) & 0xfffffffe;
dev->sgd[addr >> 4].restart = 1; dev->sgd[addr >> 4].restart = 2;
/* Start the actual SGD process. */ /* Start the actual SGD process. */
ac97_via_sgd_process(&dev->sgd[addr >> 4]); ac97_via_sgd_process(&dev->sgd[addr >> 4]);
@@ -530,15 +531,14 @@ ac97_via_sgd_process(void *priv)
timer_on_auto(&sgd->dma_timer, 10.0); timer_on_auto(&sgd->dma_timer, 10.0);
/* Process SGD if it's active, and the FIFO has room or is disabled. */ /* Process SGD if it's active, and the FIFO has room or is disabled. */
if ((sgd_status == 0x80) && (sgd->always_run || ((sgd->fifo_end - sgd->fifo_pos) <= (sizeof(sgd->fifo) - 4)))) { if (((sgd_status & 0x84) == 0x80) && (sgd->always_run || ((sgd->fifo_end - sgd->fifo_pos) <= (sizeof(sgd->fifo) - 4)))) {
/* Move on to the next block if no entry is present. */ /* Move on to the next block if no entry is present. */
if (sgd->restart) { if (sgd->restart) {
/* (Re)load entry pointer if required. */
if (sgd->restart & 2)
sgd->entry_ptr = *((uint32_t *) &dev->sgd_regs[sgd->id | 0x4]) & 0xfffffffe; /* TODO: probe real hardware - does "even addr" actually mean dword aligned? */
sgd->restart = 0; sgd->restart = 0;
/* Start at first entry if no pointer is present. */
if (!sgd->entry_ptr)
sgd->entry_ptr = *((uint32_t *) &dev->sgd_regs[sgd->id | 0x4]) & 0xfffffffe;
/* Read entry. */ /* Read entry. */
sgd->sample_ptr = mem_readl_phys(sgd->entry_ptr); sgd->sample_ptr = mem_readl_phys(sgd->entry_ptr);
sgd->entry_ptr += 4; sgd->entry_ptr += 4;
@@ -573,6 +573,9 @@ ac97_via_sgd_process(void *priv)
if (sgd->sample_count <= 0) { if (sgd->sample_count <= 0) {
ac97_via_log("AC97 VIA: Ending SGD %d block", sgd->id >> 4); ac97_via_log("AC97 VIA: Ending SGD %d block", sgd->id >> 4);
/* Move on to the next block on the next run, unless overridden below. */
sgd->restart = 1;
if (sgd->entry_flags & 0x20) { if (sgd->entry_flags & 0x20) {
ac97_via_log(" with STOP"); ac97_via_log(" with STOP");
@@ -583,8 +586,8 @@ ac97_via_sgd_process(void *priv)
if (sgd->entry_flags & 0x40) { if (sgd->entry_flags & 0x40) {
ac97_via_log(" with FLAG"); ac97_via_log(" with FLAG");
/* Raise FLAG and STOP. */ /* Raise FLAG. */
dev->sgd_regs[sgd->id] |= 0x05; dev->sgd_regs[sgd->id] |= 0x01;
#ifdef ENABLE_AC97_VIA_LOG #ifdef ENABLE_AC97_VIA_LOG
if (dev->sgd_regs[sgd->id | 0x2] & 0x01) if (dev->sgd_regs[sgd->id | 0x2] & 0x01)
@@ -610,8 +613,8 @@ ac97_via_sgd_process(void *priv)
/* Un-queue trigger. */ /* Un-queue trigger. */
dev->sgd_regs[sgd->id] &= ~0x08; dev->sgd_regs[sgd->id] &= ~0x08;
/* Go back to the starting block. */ /* Go back to the starting block on the next run. */
sgd->entry_ptr = 0; /* ugly, but Windows XP plays too fast if the pointer is reloaded now */ sgd->restart = 2;
} else { } else {
ac97_via_log(" finish"); ac97_via_log(" finish");
@@ -623,9 +626,6 @@ ac97_via_sgd_process(void *priv)
/* Fire any requested status interrupts. */ /* Fire any requested status interrupts. */
ac97_via_update_irqs(dev); ac97_via_update_irqs(dev);
/* Move on to a new block on the next run. */
sgd->restart = 1;
} }
} }
} }
@@ -749,7 +749,7 @@ ac97_via_speed_changed(void *priv)
freq = (double) SOUND_FREQ; freq = (double) SOUND_FREQ;
dev->sgd[0].timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / freq)); dev->sgd[0].timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / freq));
dev->sgd[2].timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / 24000.0)); dev->sgd[2].timer_latch = (uint64_t) ((double) TIMER_USEC * (1000000.0 / 24000.0)); /* FM operates at a fixed 24 KHz */
} }
static void * static void *
@@ -775,10 +775,6 @@ ac97_via_init(const device_t *info)
if ((i != 0) && (i != 2)) if ((i != 0) && (i != 2))
dev->sgd[i].always_run = 1; dev->sgd[i].always_run = 1;
/* No volume control on FM SGD that I know of. */
if (i == 2)
dev->sgd[i].vol_l = dev->sgd[i].vol_r = 32767;
timer_add(&dev->sgd[i].dma_timer, ac97_via_sgd_process, &dev->sgd[i], 0); timer_add(&dev->sgd[i].dma_timer, ac97_via_sgd_process, &dev->sgd[i], 0);
} }