Switched the OPL and NukedOPL code to VARCem's reworked (and cleaner) versions.

This commit is contained in:
OBattler
2020-07-19 03:24:45 +02:00
parent 3a4953036f
commit 4f3ae96b63
15 changed files with 1806 additions and 1900 deletions

View File

@@ -1,222 +1,284 @@
/* Copyright holders: Sarah Walker, SA1988
see COPYING for more details
*/
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Interface to the actual OPL emulator.
*
* TODO: Finish re-working this into a device_t, which requires a
* poll-like function for "update" so the sound card can call
* that and get a buffer-full of sample data.
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Miran Grca, <mgrca8@gmail.com>
* TheCollector1995, <mariogplayer@gmail.com>
* Sarah Walker, <tommowalker@tommowalker.co.uk>
*
* Copyright 2017-2020 Fred N. van Kempen.
* Copyright 2016-2019 Miran Grca.
* Copyright 2008-2018 Sarah Walker.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#define dbglog sound_card_log
#include <86box/86box.h>
#include <86box/timer.h>
#include "cpu.h"
#include <86box/io.h>
#include <86box/timer.h>
#include <86box/sound.h>
#include <86box/snd_opl.h>
#include <86box/snd_opl_backend.h>
#include <86box/snd_opl_nuked.h>
/*Interfaces between 86Box and the actual OPL emulator*/
enum {
STATUS_TIMER_1 = 0x40,
STATUS_TIMER_2 = 0x20,
STATUS_TIMER_ALL = 0x80
};
enum {
CTRL_IRQ_RESET = 0x80,
CTRL_TIMER1_MASK = 0x40,
CTRL_TIMER2_MASK = 0x20,
CTRL_TIMER2_CTRL = 0x02,
CTRL_TIMER1_CTRL = 0x01
};
uint8_t
opl2_read(uint16_t a, void *priv)
static void
status_update(opl_t *dev)
{
opl_t *opl = (opl_t *)priv;
sub_cycles((int) (isa_timing * 8));
opl2_update2(opl);
return opl_read(0, a);
if (dev->status & (STATUS_TIMER_1 | STATUS_TIMER_2) & dev->status_mask)
dev->status |= STATUS_TIMER_ALL;
else
dev->status &= ~STATUS_TIMER_ALL;
}
void
opl2_write(uint16_t a, uint8_t v, void *priv)
static void
timer_set(opl_t *dev, int timer, uint64_t period)
{
opl_t *opl = (opl_t *)priv;
opl2_update2(opl);
opl_write(0, a, v);
opl_write(1, a, v);
timer_on_auto(&dev->timers[timer], ((double) period) * 20.0);
}
uint8_t
opl2_l_read(uint16_t a, void *priv)
static void
timer_over(opl_t *dev, int tmr)
{
opl_t *opl = (opl_t *)priv;
if (tmr) {
dev->status |= STATUS_TIMER_2;
timer_set(dev, 1, dev->timer[1] * 16);
} else {
dev->status |= STATUS_TIMER_1;
timer_set(dev, 0, dev->timer[0] * 4);
}
sub_cycles((int)(isa_timing * 8));
opl2_update2(opl);
return opl_read(0, a);
status_update(dev);
}
void
opl2_l_write(uint16_t a, uint8_t v, void *priv)
static void
timer_1(void *priv)
{
opl_t *opl = (opl_t *)priv;
opl_t *dev = (opl_t *)priv;
opl2_update2(opl);
opl_write(0, a, v);
timer_over(dev, 0);
}
uint8_t
opl2_r_read(uint16_t a, void *priv)
static void
timer_2(void *priv)
{
opl_t *opl = (opl_t *)priv;
opl_t *dev = (opl_t *)priv;
sub_cycles((int)(isa_timing * 8));
opl2_update2(opl);
return opl_read(1, a);
timer_over(dev, 1);
}
void
opl2_r_write(uint16_t a, uint8_t v, void *priv)
static uint8_t
opl_read(opl_t *dev, uint16_t port)
{
opl_t *opl = (opl_t *)priv;
if (! (port & 1))
return((dev->status & dev->status_mask) | (dev->is_opl3 ? 0x00 : 0x06));
opl2_update2(opl);
opl_write(1, a, v);
if (dev->is_opl3 && ((port & 0x03) == 0x03))
return(0x00);
return(dev->is_opl3 ? 0x00 : 0xff);
}
uint8_t
opl3_read(uint16_t a, void *priv)
static void
opl_write(opl_t *dev, uint16_t port, uint8_t val)
{
opl_t *opl = (opl_t *)priv;
if (! (port & 1)) {
dev->port = nuked_write_addr(dev->opl, port, val) & 0x01ff;
sub_cycles((int)(isa_timing * 8));
opl3_update2(opl);
if (! dev->is_opl3)
dev->port &= 0x00ff;
return opl_read(0, a);
}
return;
}
nuked_write_reg_buffered(dev->opl, dev->port, val);
void
opl3_write(uint16_t a, uint8_t v, void *priv)
{
opl_t *opl = (opl_t *)priv;
opl3_update2(opl);
opl_write(0, a, v);
}
switch (dev->port) {
case 0x02: // timer 1
dev->timer[0] = 256 - val;
break;
case 0x03: // timer 2
dev->timer[1] = 256 - val;
break;
void
opl2_update2(opl_t *opl)
{
if (opl->pos < sound_pos_global) {
opl2_update(0, &opl->buffer[opl->pos << 1], sound_pos_global - opl->pos);
opl2_update(1, &opl->buffer2[opl->pos << 1], sound_pos_global - opl->pos);
for (; opl->pos < sound_pos_global; opl->pos++) {
opl->buffer[(opl->pos << 1) + 1] = opl->buffer2[(opl->pos << 1) + 1];
opl->buffer[opl->pos << 1] = (opl->buffer[opl->pos << 1] / 2);
opl->buffer[(opl->pos << 1) + 1] = (opl->buffer[(opl->pos << 1) + 1] / 2);
}
case 0x04: // timer control
if (val & CTRL_IRQ_RESET) {
dev->status &= ~(STATUS_TIMER_1 | STATUS_TIMER_2);
status_update(dev);
return;
}
if ((val ^ dev->timer_ctrl) & CTRL_TIMER1_CTRL) {
if (val & CTRL_TIMER1_CTRL)
timer_set(dev, 0, dev->timer[0] * 4);
else
timer_set(dev, 0, 0);
}
if ((val ^ dev->timer_ctrl) & CTRL_TIMER2_CTRL) {
if (val & CTRL_TIMER2_CTRL)
timer_set(dev, 1, dev->timer[1] * 16);
else
timer_set(dev, 1, 0);
}
dev->status_mask = (~val & (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK)) | 0x80;
dev->timer_ctrl = val;
break;
}
}
void
opl3_update2(opl_t *opl)
static void
opl_init(opl_t *dev, int is_opl3)
{
if (opl->pos < sound_pos_global) {
opl3_update(0, &opl->buffer[(opl->pos << 1)], sound_pos_global - opl->pos);
for (; opl->pos < sound_pos_global; opl->pos++) {
opl->buffer[opl->pos << 1] = (opl->buffer[opl->pos << 1] / 2);
opl->buffer[(opl->pos << 1) + 1] = (opl->buffer[(opl->pos << 1) + 1] / 2);
}
memset(dev, 0x00, sizeof(opl_t));
dev->is_opl3 = is_opl3;
/* Create a NukedOPL object. */
dev->opl = nuked_init(48000);
timer_add(&dev->timers[0], timer_1, dev, 0);
timer_add(&dev->timers[1], timer_2, dev, 0);
}
void
opl_close(opl_t *dev)
{
/* Release the NukedOPL object. */
if (dev->opl) {
nuked_close(dev->opl);
dev->opl = NULL;
}
}
void
ym3812_timer_set_0(void *param, int timer, uint64_t period)
uint8_t
opl2_read(uint16_t port, void *priv)
{
opl_t *opl = (opl_t *)param;
opl_t *dev = (opl_t *)priv;
if (period)
timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20);
else
timer_disable(&opl->timers[0][timer]);
cycles -= ISA_CYCLES(8);
opl2_update(dev);
return(opl_read(dev, port));
}
void
ym3812_timer_set_1(void *param, int timer, uint64_t period)
opl2_write(uint16_t port, uint8_t val, void *priv)
{
opl_t *opl = (opl_t *)param;
opl_t *dev = (opl_t *)priv;
if (period)
timer_set_delay_u64(&opl->timers[1][timer], period * TIMER_USEC * 20);
else
timer_disable(&opl->timers[1][timer]);
}
opl2_update(dev);
void
ymf262_timer_set(void *param, int timer, uint64_t period)
{
opl_t *opl = (opl_t *)param;
if (period)
timer_set_delay_u64(&opl->timers[0][timer], period * TIMER_USEC * 20);
else
timer_disable(&opl->timers[0][timer]);
}
static void
opl_timer_callback00(void *p)
{
opl_timer_over(0, 0);
}
static void
opl_timer_callback01(void *p)
{
opl_timer_over(0, 1);
}
static void
opl_timer_callback10(void *p)
{
opl_timer_over(1, 0);
}
static void
opl_timer_callback11(void *p)
{
opl_timer_over(1, 1);
opl_write(dev, port, val);
}
void
opl2_init(opl_t *opl)
opl2_init(opl_t *dev)
{
opl_init(ym3812_timer_set_0, opl, 0, 0);
opl_init(ym3812_timer_set_1, opl, 1, 0);
timer_add(&opl->timers[0][0], opl_timer_callback00, (void *)opl, 0);
timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0);
timer_add(&opl->timers[1][0], opl_timer_callback10, (void *)opl, 0);
timer_add(&opl->timers[1][1], opl_timer_callback11, (void *)opl, 0);
opl_init(dev, 0);
}
void
opl3_init(opl_t *opl)
opl2_update(opl_t *dev)
{
opl_init(ymf262_timer_set, opl, 0, 1);
if (dev->pos >= sound_pos_global)
return;
timer_add(&opl->timers[0][0], opl_timer_callback00, (void *)opl, 0);
timer_add(&opl->timers[0][1], opl_timer_callback01, (void *)opl, 0);
nuked_generate_stream(dev->opl,
&dev->buffer[dev->pos * 2],
sound_pos_global - dev->pos);
for (; dev->pos < sound_pos_global; dev->pos++) {
dev->buffer[dev->pos * 2] /= 2;
dev->buffer[(dev->pos * 2) + 1] = dev->buffer[dev->pos * 2];
}
}
uint8_t
opl3_read(uint16_t port, void *priv)
{
opl_t *dev = (opl_t *)priv;
cycles -= ISA_CYCLES(8);
opl3_update(dev);
return(opl_read(dev, port));
}
void
opl3_write(uint16_t port, uint8_t val, void *priv)
{
opl_t *dev = (opl_t *)priv;
opl3_update(dev);
opl_write(dev, port, val);
}
void
opl3_init(opl_t *dev)
{
opl_init(dev, 1);
}
/* API to sound interface. */
void
opl3_update(opl_t *dev)
{
if (dev->pos >= sound_pos_global)
return;
nuked_generate_stream(dev->opl,
&dev->buffer[dev->pos * 2],
sound_pos_global - dev->pos);
for (; dev->pos < sound_pos_global; dev->pos++) {
dev->buffer[dev->pos * 2] /= 2;
dev->buffer[(dev->pos * 2) + 1] /= 2;
}
}