Add OPL4 and miroSOUND PCM10 emulation

This commit is contained in:
Cacodemon345
2022-11-19 12:34:31 +06:00
parent 18e1cae503
commit 9a5e0af103
9 changed files with 135 additions and 53 deletions

View File

@@ -51,38 +51,38 @@ extern uint8_t rom_read(uint32_t addr, void *p);
extern uint16_t rom_readw(uint32_t addr, void *p);
extern uint32_t rom_readl(uint32_t addr, void *p);
extern FILE *rom_fopen(char *fn, char *mode);
extern FILE *rom_fopen(const char *fn, char *mode);
extern int rom_getfile(char *fn, char *s, int size);
extern int rom_present(char *fn);
extern int rom_load_linear_oddeven(char *fn, uint32_t addr, int sz,
extern int rom_load_linear_oddeven(const char *fn, uint32_t addr, int sz,
int off, uint8_t *ptr);
extern int rom_load_linear(char *fn, uint32_t addr, int sz,
extern int rom_load_linear(const char *fn, uint32_t addr, int sz,
int off, uint8_t *ptr);
extern int rom_load_interleaved(char *fnl, char *fnh, uint32_t addr,
extern int rom_load_interleaved(const char *fnl, const char *fnh, uint32_t addr,
int sz, int off, uint8_t *ptr);
extern uint8_t bios_read(uint32_t addr, void *priv);
extern uint16_t bios_readw(uint32_t addr, void *priv);
extern uint32_t bios_readl(uint32_t addr, void *priv);
extern int bios_load(char *fn1, char *fn2, uint32_t addr, int sz,
extern int bios_load(const char *fn1, const char *fn2, uint32_t addr, int sz,
int off, int flags);
extern int bios_load_linear_combined(char *fn1, char *fn2,
extern int bios_load_linear_combined(const char *fn1, const char *fn2,
int sz, int off);
extern int bios_load_linear_combined2(char *fn1, char *fn2,
char *fn3, char *fn4, char *fn5,
extern int bios_load_linear_combined2(const char *fn1, const char *fn2,
const char *fn3, const char *fn4, const char *fn5,
int sz, int off);
extern int bios_load_linear_combined2_ex(char *fn1, char *fn2,
char *fn3, char *fn4, char *fn5,
extern int bios_load_linear_combined2_ex(const char *fn1, const char *fn2,
const char *fn3, const char *fn4, const char *fn5,
int sz, int off);
extern int rom_init(rom_t *rom, char *fn, uint32_t address, int size,
extern int rom_init(rom_t *rom, const char *fn, uint32_t address, int size,
int mask, int file_offset, uint32_t flags);
extern int rom_init_oddeven(rom_t *rom, char *fn, uint32_t address, int size,
extern int rom_init_oddeven(rom_t *rom, const char *fn, uint32_t address, int size,
int mask, int file_offset, uint32_t flags);
extern int rom_init_interleaved(rom_t *rom, char *fn_low,
char *fn_high, uint32_t address,
extern int rom_init_interleaved(rom_t *rom, const char *fn_low,
const char *fn_high, uint32_t address,
int size, int mask, int file_offset,
uint32_t flags);

View File

@@ -21,6 +21,7 @@ enum fm_type {
FM_YM3812 = 0,
FM_YMF262,
FM_YMF289B,
FM_YMF278B,
FM_MAX
};
@@ -51,6 +52,7 @@ extern const device_t ymf262_nuked_device;
extern const device_t ym3812_ymfm_device;
extern const device_t ymf262_ymfm_device;
extern const device_t ymf289b_ymfm_device;
extern const device_t ymf278b_ymfm_device;
#endif
#endif /*SOUND_OPL_H*/

View File

@@ -81,6 +81,7 @@ extern const device_t adgold_device;
/* Aztech Sound Galaxy 16 */
extern const device_t azt2316a_device;
extern const device_t acermagic_s20_device;
extern const device_t mirosound_pcm10_device;
extern const device_t azt1605_device;
/* Ensoniq AudioPCI */

View File

@@ -87,7 +87,7 @@ rom_add_path(const char *path)
}
FILE *
rom_fopen(char *fn, char *mode)
rom_fopen(const char *fn, char *mode)
{
char temp[1024];
rom_path_t *rom_path;
@@ -205,7 +205,7 @@ rom_readl(uint32_t addr, void *priv)
}
int
rom_load_linear_oddeven(char *fn, uint32_t addr, int sz, int off, uint8_t *ptr)
rom_load_linear_oddeven(const char *fn, uint32_t addr, int sz, int off, uint8_t *ptr)
{
FILE *f = rom_fopen(fn, "rb");
int i;
@@ -241,7 +241,7 @@ rom_load_linear_oddeven(char *fn, uint32_t addr, int sz, int off, uint8_t *ptr)
/* Load a ROM BIOS from its chips, interleaved mode. */
int
rom_load_linear(char *fn, uint32_t addr, int sz, int off, uint8_t *ptr)
rom_load_linear(const char *fn, uint32_t addr, int sz, int off, uint8_t *ptr)
{
FILE *f = rom_fopen(fn, "rb");
@@ -270,7 +270,7 @@ rom_load_linear(char *fn, uint32_t addr, int sz, int off, uint8_t *ptr)
/* Load a ROM BIOS from its chips, linear mode with high bit flipped. */
int
rom_load_linear_inverted(char *fn, uint32_t addr, int sz, int off, uint8_t *ptr)
rom_load_linear_inverted(const char *fn, uint32_t addr, int sz, int off, uint8_t *ptr)
{
FILE *f = rom_fopen(fn, "rb");
@@ -308,7 +308,7 @@ rom_load_linear_inverted(char *fn, uint32_t addr, int sz, int off, uint8_t *ptr)
/* Load a ROM BIOS from its chips, interleaved mode. */
int
rom_load_interleaved(char *fnl, char *fnh, uint32_t addr, int sz, int off, uint8_t *ptr)
rom_load_interleaved(const char *fnl, const char *fnh, uint32_t addr, int sz, int off, uint8_t *ptr)
{
FILE *fl = rom_fopen(fnl, "rb");
FILE *fh = rom_fopen(fnh, "rb");
@@ -478,7 +478,7 @@ bios_add(void)
/* These four are for loading the BIOS. */
int
bios_load(char *fn1, char *fn2, uint32_t addr, int sz, int off, int flags)
bios_load(const char *fn1, const char *fn2, uint32_t addr, int sz, int off, int flags)
{
uint8_t ret = 0;
uint8_t *ptr = NULL;
@@ -525,7 +525,7 @@ bios_load(char *fn1, char *fn2, uint32_t addr, int sz, int off, int flags)
}
int
bios_load_linear_combined(char *fn1, char *fn2, int sz, int off)
bios_load_linear_combined(const char *fn1, const char *fn2, int sz, int off)
{
uint8_t ret = 0;
@@ -536,7 +536,7 @@ bios_load_linear_combined(char *fn1, char *fn2, int sz, int off)
}
int
bios_load_linear_combined2(char *fn1, char *fn2, char *fn3, char *fn4, char *fn5, int sz, int off)
bios_load_linear_combined2(const char *fn1, const char *fn2, const char *fn3, const char *fn4, const char *fn5, int sz, int off)
{
uint8_t ret = 0;
@@ -551,7 +551,7 @@ bios_load_linear_combined2(char *fn1, char *fn2, char *fn3, char *fn4, char *fn5
}
int
bios_load_linear_combined2_ex(char *fn1, char *fn2, char *fn3, char *fn4, char *fn5, int sz, int off)
bios_load_linear_combined2_ex(const char *fn1, const char *fn2, const char *fn3, const char *fn4, const char *fn5, int sz, int off)
{
uint8_t ret = 0;
@@ -566,7 +566,7 @@ bios_load_linear_combined2_ex(char *fn1, char *fn2, char *fn3, char *fn4, char *
}
int
rom_init(rom_t *rom, char *fn, uint32_t addr, int sz, int mask, int off, uint32_t flags)
rom_init(rom_t *rom, const char *fn, uint32_t addr, int sz, int mask, int off, uint32_t flags)
{
rom_log("rom_init(%08X, %s, %08X, %08X, %08X, %08X, %08X)\n", rom, fn, addr, sz, mask, off, flags);
@@ -595,7 +595,7 @@ rom_init(rom_t *rom, char *fn, uint32_t addr, int sz, int mask, int off, uint32_
}
int
rom_init_oddeven(rom_t *rom, char *fn, uint32_t addr, int sz, int mask, int off, uint32_t flags)
rom_init_oddeven(rom_t *rom, const char *fn, uint32_t addr, int sz, int mask, int off, uint32_t flags)
{
rom_log("rom_init(%08X, %08X, %08X, %08X, %08X, %08X, %08X)\n", rom, fn, addr, sz, mask, off, flags);
@@ -624,7 +624,7 @@ rom_init_oddeven(rom_t *rom, char *fn, uint32_t addr, int sz, int mask, int off,
}
int
rom_init_interleaved(rom_t *rom, char *fnl, char *fnh, uint32_t addr, int sz, int mask, int off, uint32_t flags)
rom_init_interleaved(rom_t *rom, const char *fnl, const char *fnh, uint32_t addr, int sz, int mask, int off, uint32_t flags)
{
/* Allocate a buffer for the image. */
rom->rom = malloc(sz);

View File

@@ -64,6 +64,11 @@ fm_driver_get(int chip_id, fm_drv_t *drv)
drv->priv = device_add_inst(&ymf289b_ymfm_device, fm_dev_inst[fm_driver][chip_id]++);
break;
case FM_YMF278B:
*drv = ymfm_drv;
drv->priv = device_add_inst(&ymf278b_ymfm_device, fm_dev_inst[fm_driver][chip_id]++);
break;
default:
return 0;
}

View File

@@ -27,6 +27,8 @@ extern "C" {
#include <86box/device.h>
#include <86box/sound.h>
#include <86box/snd_opl.h>
#include <86box/mem.h>
#include <86box/rom.h>
}
#define RSM_FRAC 10
@@ -62,6 +64,7 @@ public:
virtual void generate_resampled(int32_t *data, uint32_t num_samples) = 0;
virtual int32_t *update() = 0;
virtual uint8_t read(uint16_t addr) = 0;
virtual void set_clock(uint32_t clock) = 0;
protected:
int32_t m_buffer[SOUNDBUFLEN * 2];
@@ -78,6 +81,7 @@ public:
, m_chip(*this)
, m_clock(clock)
, m_samplecnt(0)
, m_samplerate(samplerate)
{
memset(m_samples, 0, sizeof(m_samples));
memset(m_oldsamples, 0, sizeof(m_oldsamples));
@@ -87,6 +91,12 @@ public:
m_subtract[1] = 320.0;
m_type = type;
if (m_type == FM_YMF278B) {
if (rom_load_linear("roms/sound/yamaha/yrw801.rom", 0, 0x200000, 0, m_yrw801) == 0) {
fatal("YRW801 ROM image \"roms/sound/yamaha/yrw801.rom\" not found\n");
}
}
timer_add(&m_timers[0], YMFMChip::timer1, this, 0);
timer_add(&m_timers[1], YMFMChip::timer2, this, 0);
}
@@ -101,7 +111,8 @@ public:
if (tnum > 1)
return;
pc_timer_t *timer = &m_timers[tnum];
m_duration_in_clocks[tnum] = duration_in_clocks;
pc_timer_t *timer = &m_timers[tnum];
if (duration_in_clocks < 0)
timer_stop(timer);
else {
@@ -113,16 +124,26 @@ public:
}
}
virtual void set_clock(uint32_t clock) override
{
m_clock = clock;
m_clock_us = 1000000 / (double) m_clock;
m_rateratio = (m_samplerate << RSM_FRAC) / m_chip.sample_rate(m_clock);
ymfm_set_timer(0, m_duration_in_clocks[0]);
ymfm_set_timer(1, m_duration_in_clocks[1]);
}
virtual void generate(int32_t *data, uint32_t num_samples) override
{
for (uint32_t i = 0; i < num_samples; i++) {
m_chip.generate(&m_output);
if (ChipType::OUTPUTS == 1) {
*data++ = m_output.data[0];
*data++ = m_output.data[0];
*data++ = m_output.data[(m_type == FM_YMF278B) ? 4 : 0];
*data++ = m_output.data[(m_type == FM_YMF278B) ? 4 : 0];
} else {
*data++ = m_output.data[0];
*data++ = m_output.data[1 % ChipType::OUTPUTS];
*data++ = m_output.data[(m_type == FM_YMF278B) ? 4 : 0];
*data++ = m_output.data[(m_type == FM_YMF278B) ? 5 : (1 % ChipType::OUTPUTS)];
}
}
}
@@ -135,11 +156,11 @@ public:
m_oldsamples[1] = m_samples[1];
m_chip.generate(&m_output);
if (ChipType::OUTPUTS == 1) {
m_samples[0] = m_output.data[0];
m_samples[1] = m_output.data[0];
m_samples[0] = m_output.data[(m_type == FM_YMF278B) ? 4 : 0];
m_samples[1] = m_output.data[(m_type == FM_YMF278B) ? 4 : 0];
} else {
m_samples[0] = m_output.data[0];
m_samples[1] = m_output.data[1 % ChipType::OUTPUTS];
m_samples[0] = m_output.data[(m_type == FM_YMF278B) ? 4 : 0];
m_samples[1] = m_output.data[(m_type == FM_YMF278B) ? 5 : (1 % ChipType::OUTPUTS)];
}
m_samplecnt -= m_rateratio;
}
@@ -182,7 +203,7 @@ public:
virtual uint32_t get_special_flags(void) override
{
return ((m_type == FM_YMF262) || (m_type == FM_YMF289B)) ? 0x8000 : 0x0000;
return ((m_type == FM_YMF262) || (m_type == FM_YMF289B) || (m_type == FM_YMF278B)) ? 0x8000 : 0x0000;
}
static void timer1(void *priv)
@@ -197,12 +218,25 @@ public:
drv->m_engine->engine_timer_expired(1);
}
virtual uint8_t ymfm_external_read(ymfm::access_class type, uint32_t address) override
{
if (type == ymfm::access_class::ACCESS_PCM && address < 0x200000) {
return m_yrw801[address];
}
return 0xFF;
}
private:
ChipType m_chip;
uint32_t m_clock;
double m_clock_us, m_subtract[2];
typename ChipType::output_data m_output;
pc_timer_t m_timers[2];
int32_t m_duration_in_clocks[2]; // Needed for clock switches.
uint32_t m_samplerate;
// YRW801-M wavetable ROM.
uint8_t m_yrw801[0x200000];
// Resampling
int32_t m_rateratio;
@@ -237,7 +271,7 @@ ymfm_log(const char *fmt, ...)
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
}
#else
# define ymfm_log(fmt, ...)
@@ -261,6 +295,10 @@ ymfm_drv_init(const device_t *info)
case FM_YMF289B:
fm = (YMFMChipBase *) new YMFMChip<ymfm::ymf289b>(33868800, FM_YMF289B, 48000);
break;
case FM_YMF278B:
fm = (YMFMChipBase *) new YMFMChip<ymfm::ymf278b>(33868800, FM_YMF278B, 48000);
break;
}
fm->set_do_cycles(1);
@@ -282,6 +320,7 @@ ymfm_drv_read(uint16_t port, void *priv)
{
YMFMChipBase *drv = (YMFMChipBase *) priv;
if (port == 0x381) { port += 4; } /* Point to register read port. */
if (drv->flags() & FLAG_CYCLES) {
cycles -= ((int) (isa_timing * 8));
}
@@ -298,6 +337,7 @@ ymfm_drv_write(uint16_t port, uint8_t val, void *priv)
{
YMFMChipBase *drv = (YMFMChipBase *) priv;
ymfm_log("YMFM write port %04x value = %02x\n", port, val);
if (port == 0x380 || port == 0x381) { port += 4; }
drv->write(port, val);
drv->update();
}
@@ -367,6 +407,20 @@ const device_t ymf289b_ymfm_device = {
.config = NULL
};
const device_t ymf278b_ymfm_device = {
.name = "Yamaha YMF278B OPL4 (YMFM)",
.internal_name = "ymf289b_ymfm",
.flags = 0,
.local = FM_YMF278B,
.init = ymfm_drv_init,
.close = ymfm_drv_close,
.reset = NULL,
{ .available = NULL },
.speed_changed = NULL,
.force_redraw = NULL,
.config = NULL
};
const fm_drv_t ymfm_drv {
&ymfm_drv_read,
&ymfm_drv_write,

View File

@@ -6,7 +6,7 @@
*
* This file is part of the 86Box distribution.
*
* OPTi MediaCHIPS 82C929 audio controller emulation.
* OPTi MediaCHIPS 82C929 (also known as OPTi MAD16 Pro) audio controller emulation.
*
*
*
@@ -37,13 +37,15 @@
#include <86box/gameport.h>
#include <86box/snd_ad1848.h>
#include <86box/snd_sb.h>
#include <86box/mem.h>
#include <86box/rom.h>
static int optimc_wss_dma[4] = { 0, 0, 1, 3 };
static int optimc_wss_irq[8] = { 5, 7, 9, 10, 11, 12, 14, 15 }; /* W95 only uses 7-10, others may be wrong */
enum optimc_local_flags {
OPTIMC_CS4231 = 0x100,
OPTIMC_OPL4 = 0x200, /* Unused */
OPTIMC_OPL4 = 0x200,
};
typedef struct optimc_t {
@@ -84,7 +86,8 @@ optimc_wss_write(uint16_t addr, uint8_t val, void *priv)
{
optimc_t *optimc = (optimc_t *) priv;
if (!(optimc->regs[4] & 0x10) && optimc->cur_mode == 0) return;
if (!(optimc->regs[4] & 0x10) && optimc->cur_mode == 0)
return;
optimc->wss_config = val;
ad1848_setdma(&optimc->ad1848, optimc_wss_dma[val & 3]);
ad1848_setirq(&optimc->ad1848, optimc_wss_irq[(val >> 3) & 7]);
@@ -121,8 +124,6 @@ optimc_remove_opl(optimc_t *optimc)
static void
optimc_add_opl(optimc_t *optimc)
{
fm_driver_get(FM_YMF262, &optimc->sb->opl);
/* DSP I/O handler is activated in sb_dsp_setaddr */
io_sethandler(optimc->cur_addr + 0, 0x0004, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv);
io_sethandler(optimc->cur_addr + 8, 0x0002, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv);
@@ -184,8 +185,6 @@ optimc_reg_write(uint16_t addr, uint8_t val, void *p)
}
case 1: /* MC2 */
optimc->regs[1] = val;
if (old != val)
optimc_reload_opl(optimc);
break;
case 2: /* MC3 */
if (val == optimc->type)
@@ -228,8 +227,6 @@ optimc_reg_write(uint16_t addr, uint8_t val, void *p)
break;
case 3: /* MC4 */
optimc->regs[3] = val;
if ((old & 0x8) != (val & 0x8))
optimc_reload_opl(optimc);
break;
case 4: /* MC5 */
optimc->regs[4] = val;
@@ -347,7 +344,7 @@ optimc_init(const device_t *info)
optimc->regs[1] = 0x03;
optimc->regs[2] = 0x00;
optimc->regs[3] = 0x00;
optimc->regs[4] = 0x2F;
optimc->regs[4] = 0x3F;
optimc->regs[5] = 0x83;
optimc->gameport = gameport_add(&gameport_device);
@@ -375,11 +372,14 @@ optimc_init(const device_t *info)
sb_dsp_setdma8(&optimc->sb->dsp, optimc->cur_dma);
sb_ct1345_mixer_reset(optimc->sb);
optimc->fm_type = (info->local & OPTIMC_OPL4) ? FM_YMF289B : FM_YMF262;
optimc->fm_type = (info->local & OPTIMC_OPL4) ? FM_YMF278B : FM_YMF262;
fm_driver_get(optimc->fm_type, &optimc->sb->opl);
io_sethandler(optimc->cur_addr + 0, 0x0004, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv);
io_sethandler(optimc->cur_addr + 8, 0x0002, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv);
io_sethandler(0x0388, 0x0004, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv);
if (optimc->fm_type == FM_YMF278B) {
io_sethandler(0x380, 2, optimc->sb->opl.read, NULL, NULL, optimc->sb->opl.write, NULL, NULL, optimc->sb->opl.priv);
}
io_sethandler(optimc->cur_addr + 4, 0x0002, sb_ct1345_mixer_read, NULL, NULL, sb_ct1345_mixer_write, NULL, NULL, optimc->sb);
@@ -399,7 +399,7 @@ optimc_init(const device_t *info)
static void
optimc_close(void *p)
{
optimc_t* optimc = (optimc_t*)p;
optimc_t *optimc = (optimc_t *) p;
sb_close(optimc->sb);
free(optimc->mpu);
@@ -415,6 +415,12 @@ optimc_speed_changed(void *p)
sb_speed_changed(optimc->sb);
}
static int
mirosound_pcm10_available(void)
{
return rom_present("roms/sound/yamaha/yrw801.rom");
}
static const device_config_t acermagic_s20_config[] = {
// clang-format off
{
@@ -441,12 +447,11 @@ static const device_config_t acermagic_s20_config[] = {
// clang-format on
};
const device_t acermagic_s20_device = {
.name = "AcerMagic S20",
.internal_name = "acermagic_s20",
.flags = DEVICE_ISA | DEVICE_AT,
.local = 0xE3 | 0x100,
.local = 0xE3 | OPTIMC_CS4231,
.init = optimc_init,
.close = optimc_close,
.reset = NULL,
@@ -454,4 +459,18 @@ const device_t acermagic_s20_device = {
.speed_changed = optimc_speed_changed,
.force_redraw = NULL,
.config = acermagic_s20_config
};
const device_t mirosound_pcm10_device = {
.name = "miroSOUND PCM10",
.internal_name = "mirosound_pcm10",
.flags = DEVICE_ISA | DEVICE_AT,
.local = 0xE3 | OPTIMC_OPL4,
.init = optimc_init,
.close = optimc_close,
.reset = NULL,
{ .available = mirosound_pcm10_available },
.speed_changed = optimc_speed_changed,
.force_redraw = NULL,
.config = acermagic_s20_config
};

View File

@@ -110,6 +110,7 @@ static const SOUND_CARD sound_cards[] = {
{ &sound_none_device },
{ &sound_internal_device },
{ &acermagic_s20_device },
{ &mirosound_pcm10_device },
{ &adlib_device },
{ &adgold_device },
{ &azt2316a_device },

View File

@@ -212,8 +212,8 @@ public:
uint32_t result = memory_address();
uint32_t newval = result + 1;
m_regdata[0x05] = newval >> 0;
m_regdata[0x06] = newval >> 8;
m_regdata[0x07] = (newval >> 16) & 0x3f;
m_regdata[0x04] = newval >> 8;
m_regdata[0x03] = (newval >> 16) & 0x3f;
return result;
}