From 92dd28efc195655dd24243b62b65446d7f4e52a3 Mon Sep 17 00:00:00 2001 From: RichardG867 Date: Fri, 24 Mar 2023 20:53:39 -0300 Subject: [PATCH] VIA PIPC/AC97: Fixed and enabled software FM mode --- src/chipset/via_pipc.c | 37 ++++++++++++++++++++++++++----------- src/sound/snd_ac97_via.c | 32 ++++++++++++++------------------ 2 files changed, 40 insertions(+), 29 deletions(-) diff --git a/src/chipset/via_pipc.c b/src/chipset/via_pipc.c index 6e59db370..373935eee 100644 --- a/src/chipset/via_pipc.c +++ b/src/chipset/via_pipc.c @@ -59,13 +59,15 @@ /* 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. */ -#define VIA_PIPC_586A 0x05862500 -#define VIA_PIPC_586B 0x05864700 -#define VIA_PIPC_596A 0x05960900 -#define VIA_PIPC_596B 0x05962300 -#define VIA_PIPC_686A 0x06861400 -#define VIA_PIPC_686B 0x06864000 -#define VIA_PIPC_8231 0x82311000 +#define VIA_PIPC_586A 0x05862500 +#define VIA_PIPC_586B 0x05864700 +#define VIA_PIPC_596A 0x05960900 +#define VIA_PIPC_596B 0x05962300 +#define VIA_PIPC_686A 0x06861400 +#define VIA_PIPC_686B 0x06864000 +#define VIA_PIPC_8231 0x82311000 + +#define VIA_PIPC_FM_EMULATION 1 enum { TRAP_DRQ = 0, @@ -118,7 +120,7 @@ typedef struct _pipc_ { ide_regs[256], usb_regs[2][256], power_regs[256], - ac97_regs[2][256], fmnmi_regs[4]; + ac97_regs[2][256], fmnmi_regs[4], fmnmi_status; sff8038i_t *bm[2]; nvr_t *nvr; @@ -760,10 +762,10 @@ pipc_fmnmi_handlers(pipc_t *dev, uint8_t modem) static uint8_t pipc_fm_read(uint16_t addr, void *priv) { -#ifdef VIA_PIPC_FM_EMULATION - uint8_t ret = 0x00; -#else 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); #endif @@ -788,6 +790,19 @@ pipc_fm_write(uint16_t addr, uint8_t val, void *priv) } else { 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. */ if (dev->ac97_regs[0][0x48] & 0x01) { pipc_log("PIPC: Raising %s\n", (dev->ac97_regs[0][0x48] & 0x04) ? "SMI" : "NMI"); diff --git a/src/sound/snd_ac97_via.c b/src/sound/snd_ac97_via.c index 8e611ed44..a630aff82 100644 --- a/src/sound/snd_ac97_via.c +++ b/src/sound/snd_ac97_via.c @@ -178,6 +178,7 @@ ac97_via_update_codec(ac97_via_t *dev) /* Update volumes according to codec registers. */ 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[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); /* 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. */ 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].restart = 1; + dev->sgd[addr >> 4].restart = 2; /* Start the actual SGD process. */ 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); /* 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. */ 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; - /* 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. */ sgd->sample_ptr = mem_readl_phys(sgd->entry_ptr); sgd->entry_ptr += 4; @@ -573,6 +573,9 @@ ac97_via_sgd_process(void *priv) if (sgd->sample_count <= 0) { 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) { ac97_via_log(" with STOP"); @@ -583,8 +586,8 @@ ac97_via_sgd_process(void *priv) if (sgd->entry_flags & 0x40) { ac97_via_log(" with FLAG"); - /* Raise FLAG and STOP. */ - dev->sgd_regs[sgd->id] |= 0x05; + /* Raise FLAG. */ + dev->sgd_regs[sgd->id] |= 0x01; #ifdef ENABLE_AC97_VIA_LOG if (dev->sgd_regs[sgd->id | 0x2] & 0x01) @@ -610,8 +613,8 @@ ac97_via_sgd_process(void *priv) /* Un-queue trigger. */ dev->sgd_regs[sgd->id] &= ~0x08; - /* Go back to the starting block. */ - sgd->entry_ptr = 0; /* ugly, but Windows XP plays too fast if the pointer is reloaded now */ + /* Go back to the starting block on the next run. */ + sgd->restart = 2; } else { ac97_via_log(" finish"); @@ -623,9 +626,6 @@ ac97_via_sgd_process(void *priv) /* Fire any requested status interrupts. */ 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; 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 * @@ -775,10 +775,6 @@ ac97_via_init(const device_t *info) if ((i != 0) && (i != 2)) 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); }