Merge pull request #65 from Altheos/gusmax

Add Gravis Ultrasound Max soundcard support
This commit is contained in:
Fred N. van Kempen
2019-01-13 14:40:59 -05:00
committed by GitHub
7 changed files with 2834 additions and 2267 deletions

View File

@@ -0,0 +1,334 @@
/*
* VARCem Virtual ARchaeological Computer EMulator.
* An emulator of (mostly) x86-based PC systems and devices,
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
* spanning the era between 1981 and 1995.
*
* This file is part of the VARCem Project.
*
* Implementation of Cirrus Logic Crystal 423x sound devices.
*
* Version: @(#)snd_cs423x.c 1.0.0 2018/11/27
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
*
* Copyright 2018 Fred N. van Kempen.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the:
*
* Free Software Foundation, Inc.
* 59 Temple Place - Suite 330
* Boston, MA 02111-1307
* USA.
*/
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <wchar.h>
#include <math.h>
#define dbglog sound_card_log
#include "../../emu.h"
#include "../../io.h"
#include "../../device.h"
#include "../../timer.h"
#include "../system/dma.h"
#include "../system/pic.h"
#include "sound.h"
#include "snd_cs423x.h"
#define CS4231 0x80
#define CS4231A 0xa0
#define CS4232 0xa2
#define CS4232A 0xb2
#define CS4236 0x83
#define CS4236B 0x03
static int cs423x_vols[64];
void cs423x_setirq(cs423x_t *cs423x, int irq_ch)
{
cs423x->irq = irq_ch;
}
void cs423x_setdma(cs423x_t *cs423x, int dma_ch)
{
cs423x->dma = dma_ch;
}
uint8_t cs423x_read(uint16_t addr, void *p)
{
cs423x_t *cs423x = (cs423x_t *)p;
uint8_t temp = 0xff;
if (cs423x->initb)
return 0x80;
switch (addr & 3)
{
case 0: /*Index*/
if (cs423x->mode2)
temp = cs423x->index | cs423x->trd | cs423x->mce | cs423x->ia4 | cs423x->initb;
else
temp = cs423x->index | cs423x->trd | cs423x->mce | cs423x->initb;
break;
case 1:
temp = cs423x->regs[cs423x->index];
if (cs423x->index == 0x0b) {
temp ^= 0x20;
cs423x->regs[cs423x->index] = temp;
}
break;
case 2:
temp = cs423x->status;
break;
case 3: // Todo Capture I/O read
break;
}
return temp;
}
void cs423x_write(uint16_t addr, uint8_t val, void *p)
{
cs423x_t *cs423x = (cs423x_t *)p;
double freq;
switch (addr & 3)
{
case 0: /*Index*/
cs423x->index = val & (cs423x->mode2 ? 0x1F : 0x0F);
cs423x->trd = val & 0x20;
cs423x->mce = val & 0x40;
cs423x->ia4 = val & 0x10;
cs423x->initb = val & 0x80;
break;
case 1:
switch (cs423x->index)
{
case 8:
freq = (double)((val & 1) ? 16934400LL : 24576000LL);
switch ((val >> 1) & 7)
{
case 0: freq /= 3072; break;
case 1: freq /= 1536; break;
case 2: freq /= 896; break;
case 3: freq /= 768; break;
case 4: freq /= 448; break;
case 5: freq /= 384; break;
case 6: freq /= 512; break;
case 7: freq /= 2560; break;
}
cs423x->freq = (int64_t)freq;
cs423x->timer_latch = (int64_t)((double)TIMER_USEC * (1000000.0 / (double)cs423x->freq));
break;
case 9:
cs423x->enable = ((val & 0x41) == 0x01);
if (!cs423x->enable)
cs423x->out_l = cs423x->out_r = 0;
break;
case 11:
break;
case 12:
val |= 0x8a;
cs423x->mode2 = (val >> 6) & 1;
break;
case 14:
cs423x->count = cs423x->regs[15] | (val << 8);
break;
case 24:
if (!(val & 0x70))
cs423x->status &= 0xfe;
break;
case 25:
break;
}
cs423x->regs[cs423x->index] = val;
break;
case 2:
cs423x->status &= 0xfe;
break;
case 3: // Todo Playback I/O Write
break;
}
}
void cs423x_speed_changed(cs423x_t *cs423x)
{
cs423x->timer_latch = (int64_t)((double)TIMER_USEC * (1000000.0 / (double)cs423x->freq));
}
void cs423x_update(cs423x_t *cs423x)
{
for (; cs423x->pos < sound_pos_global; cs423x->pos++)
{
cs423x->buffer[cs423x->pos * 2] = cs423x->out_l;
cs423x->buffer[cs423x->pos * 2 + 1] = cs423x->out_r;
}
}
static void cs423x_poll(void *p)
{
cs423x_t *cs423x = (cs423x_t *)p;
if (cs423x->timer_latch)
cs423x->timer_count += cs423x->timer_latch;
else
cs423x->timer_count = TIMER_USEC;
cs423x_update(cs423x);
if (cs423x->enable) {
int32_t temp;
if (!(cs423x->mode2)) {
switch (cs423x->regs[8] & 0x70)
{
case 0x00: /*Mono, 8-bit PCM*/
cs423x->out_l = cs423x->out_r = (dma_channel_read(cs423x->dma) ^ 0x80) * 256;
break;
case 0x10: /*Stereo, 8-bit PCM*/
cs423x->out_l = (dma_channel_read(cs423x->dma) ^ 0x80) * 256;
cs423x->out_r = (dma_channel_read(cs423x->dma) ^ 0x80) * 256;
break;
case 0x40: /*Mono, 16-bit PCM*/
temp = dma_channel_read(cs423x->dma);
cs423x->out_l = cs423x->out_r = (dma_channel_read(cs423x->dma) << 8) | temp;
break;
case 0x50: /*Stereo, 16-bit PCM*/
temp = dma_channel_read(cs423x->dma);
cs423x->out_l = (dma_channel_read(cs423x->dma) << 8) | temp;
temp = dma_channel_read(cs423x->dma);
cs423x->out_r = (dma_channel_read(cs423x->dma) << 8) | temp;
break;
}
}
else {
switch (cs423x->regs[8] & 0xf0)
{
case 0x00: /*Mono, 8-bit PCM*/
cs423x->out_l = cs423x->out_r = (dma_channel_read(cs423x->dma) ^ 0x80) * 256;
break;
case 0x10: /*Stereo, 8-bit PCM*/
cs423x->out_l = (dma_channel_read(cs423x->dma) ^ 0x80) * 256;
cs423x->out_r = (dma_channel_read(cs423x->dma) ^ 0x80) * 256;
break;
case 0x40: /*Mono, 16-bit PCM*/
case 0xc0: /*Mono, 16-bit PCM Big-Endian should not happen on x86*/
temp = dma_channel_read(cs423x->dma);
cs423x->out_l = cs423x->out_r = (dma_channel_read(cs423x->dma) << 8) | temp;
break;
case 0x50: /*Stereo, 16-bit PCM*/
case 0xd0: /*Stereo, 16-bit PCM Big-Endian. Should not happen on x86*/
temp = dma_channel_read(cs423x->dma);
cs423x->out_l = (dma_channel_read(cs423x->dma) << 8) | temp;
temp = dma_channel_read(cs423x->dma);
cs423x->out_r = (dma_channel_read(cs423x->dma) << 8) | temp;
break;
case 0xa0: /*TODO Mono, ADPCM, 4-bit*/
case 0xb0: /*TODO Stereo, ADPCM, 4-bit*/
break;
}
}
if (cs423x->regs[6] & 0x80) // Mute Left-Channel
cs423x->out_l = 0;
else
cs423x->out_l = (cs423x->out_l * cs423x_vols[cs423x->regs[6] & 0x3f]) >> 16;
if (cs423x->regs[7] & 0x80) // Mute Right-Channel
cs423x->out_r = 0;
else
cs423x->out_r = (cs423x->out_r * cs423x_vols[cs423x->regs[7] & 0x3f]) >> 16;
if (cs423x->regs[26] & 0x40) // Mono Output Mute
cs423x->out_l = cs423x->out_r = 0;
if (cs423x->count < 0) {
cs423x->count = cs423x->regs[15] | (cs423x->regs[14] << 8);
if (!(cs423x->status & 0x01)) {
cs423x->status |= 0x01;
if (cs423x->regs[10] & 2)
picint(1 << cs423x->irq);
}
}
cs423x->count--;
}
else {
cs423x->out_l = cs423x->out_r = 0;
}
}
void cs423x_init(cs423x_t *cs423x)
{
int c;
double attenuation;
cs423x->enable = 0;
cs423x->status = 0xcc;
cs423x->index = cs423x->trd = 0;
cs423x->mce = 0x40;
cs423x->initb = 0;
cs423x->mode2 = 0;
cs423x->regs[0] = cs423x->regs[1] = 0;
cs423x->regs[2] = cs423x->regs[3] = 0x88;
cs423x->regs[4] = cs423x->regs[5] = 0x88;
cs423x->regs[6] = cs423x->regs[7] = 0x80;
cs423x->regs[8] = 0;
cs423x->regs[9] = 0x08;
cs423x->regs[10] = cs423x->regs[11] = 0;
cs423x->regs[12] = 0x8a;
cs423x->regs[13] = 0;
cs423x->regs[14] = cs423x->regs[15] = 0;
cs423x->regs[16] = cs423x->regs[17] = 0;
cs423x->regs[18] = cs423x->regs[19] = 0x88;
cs423x->regs[22] = 0x80;
cs423x->regs[24] = 0;
cs423x->regs[25] = CS4231; //CS4231 for GUS MAX
cs423x->regs[26] = 0x80;
cs423x->regs[29] = 0x80;
cs423x->out_l = 0;
cs423x->out_r = 0;
for (c = 0; c < 64; c++) // DAC and Loopback attenuation
{
attenuation = 0.0;
if (c & 0x01) attenuation -= 1.5;
if (c & 0x02) attenuation -= 3.0;
if (c & 0x04) attenuation -= 6.0;
if (c & 0x08) attenuation -= 12.0;
if (c & 0x10) attenuation -= 24.0;
if (c & 0x20) attenuation -= 48.0;
attenuation = pow(10, attenuation / 10);
cs423x_vols[c] = (int)(attenuation * 65536);
}
timer_add(cs423x_poll, &cs423x->timer_count, &cs423x->enable, cs423x);
}

View File

@@ -0,0 +1,73 @@
/*
* VARCem Virtual ARchaeological Computer EMulator.
* An emulator of (mostly) x86-based PC systems and devices,
* using the ISA,EISA,VLB,MCA and PCI system buses, roughly
* spanning the era between 1981 and 1995.
*
* This file is part of the VARCem Project.
*
* Definitions for the Crystal CS423x driver.
*
* Version: @(#)snd_cs423x.h 1.0.0 2018/11/27
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
*
* Copyright 2018 Fred N. van Kempen.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the:
*
* Free Software Foundation, Inc.
* 59 Temple Place - Suite 330
* Boston, MA 02111-1307
* USA.
*/
typedef struct cs423x_t
{
int index;
uint8_t regs[32];
uint8_t status;
int trd;
int mce;
int ia4;
int mode2;
int initb;
int count;
int16_t out_l, out_r;
int64_t enable;
int irq, dma;
int64_t freq;
int64_t timer_count, timer_latch;
int16_t buffer[SOUNDBUFLEN * 2];
int pos;
} cs423x_t;
void cs423x_setirq(cs423x_t *cs423x, int irq);
void cs423x_setdma(cs423x_t *cs423x, int dma);
uint8_t cs423x_read(uint16_t addr, void *p);
void cs423x_write(uint16_t addr, uint8_t val, void *p);
void cs423x_update(cs423x_t *cs423x);
void cs423x_speed_changed(cs423x_t *cs423x);
void cs423x_init(cs423x_t *cs423x);

View File

@@ -8,7 +8,7 @@
*
* Implementation of the Gravis UltraSound sound device.
*
* Version: @(#)snd_gus.c 1.0.7 2018/10/16
* Version: @(#)snd_gus.c 1.0.8 2018/11/27
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Miran Grca, <mgrca8@gmail.com>
@@ -50,6 +50,10 @@
#include "../system/nmi.h"
#include "../system/pic.h"
#include "sound.h"
#if defined(DEV_BRANCH) && defined(USE_GUSMAX)
#include "snd_cs423x.h"
#include <math.h>
#endif
typedef struct {
@@ -134,12 +138,18 @@ typedef struct {
gp2_addr;
uint8_t usrr;
uint8_t max_ctrl;
#if defined(DEV_BRANCH) && defined(USE_GUSMAX)
cs423x_t cs423x;
#endif
} gus_t;
static const int gus_irqs[8] = {-1, 2, 5, 3, 7, 11, 12, 15};
static const int gus_irqs_midi[8] = {-1, 2, 5, 3, 7, 11, 12, 15};
static const int gus_dmas[8] = {-1, 1, 3, 5, 6, 7, -1, -1};
static const int gus_irqs[8] = { -1, 2, 5, 3, 7, 11, 12, 15 };
static const int gus_irqs_midi[8] = { -1, 2, 5, 3, 7, 11, 12, 15 };
static const int gus_dmas[8] = { -1, 1, 3, 5, 6, 7, -1, -1 };
static const int gusfreqs[] = {
44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400,
28063, 26843, 25725, 24696, 23746, 22866, 22050, 21289,
@@ -213,13 +223,15 @@ midi_update_int_status(gus_t *dev)
if ((dev->midi_ctrl & MIDI_CTRL_TRANSMIT_MASK) == MIDI_CTRL_TRANSMIT && (dev->midi_status & MIDI_INT_TRANSMIT)) {
dev->midi_status |= MIDI_INT_MASTER;
dev->irqstatus |= GUS_INT_MIDI_TRANSMIT;
} else
}
else
dev->irqstatus &= ~GUS_INT_MIDI_TRANSMIT;
if ((dev->midi_ctrl & MIDI_CTRL_RECEIVE) && (dev->midi_status & MIDI_INT_RECEIVE)) {
dev->midi_status |= MIDI_INT_MASTER;
dev->irqstatus |= GUS_INT_MIDI_RECEIVE;
} else
}
else
dev->irqstatus &= ~GUS_INT_MIDI_RECEIVE;
if ((dev->midi_status & MIDI_INT_MASTER) && (dev->irq_midi != -1)) {
@@ -234,6 +246,7 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
gus_t *dev = (gus_t *)priv;
int c, d;
int old;
uint16_t ioport;
if (dev->latch_enable && addr != 0x24b)
dev->latch_enable = 0;
@@ -254,7 +267,8 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
if (dev->midi_loopback) {
dev->midi_status |= MIDI_INT_RECEIVE;
dev->midi_data = val;
} else
}
else
dev->midi_status |= MIDI_INT_TRANSMIT;
break;
@@ -273,29 +287,29 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
break;
case 1: /*Frequency control*/
dev->freq[dev->voice] = (dev->freq[dev->voice]&0xFF00)|val;
dev->freq[dev->voice] = (dev->freq[dev->voice] & 0xFF00) | val;
break;
case 2: /*Start addr high*/
dev->startx[dev->voice] = (dev->startx[dev->voice]&0xF807F)|(val<<7);
dev->start[dev->voice] = (dev->start[dev->voice]&0x1F00FFFF)|(val<<16);
dev->startx[dev->voice] = (dev->startx[dev->voice] & 0xF807F) | (val << 7);
dev->start[dev->voice] = (dev->start[dev->voice] & 0x1F00FFFF) | (val << 16);
break;
case 3: /*Start addr low*/
dev->start[dev->voice] = (dev->start[dev->voice]&0x1FFFFF00)|val;
dev->start[dev->voice] = (dev->start[dev->voice] & 0x1FFFFF00) | val;
break;
case 4: /*End addr high*/
dev->endx[dev->voice] = (dev->endx[dev->voice]&0xF807F)|(val<<7);
dev->end[dev->voice] = (dev->end[dev->voice]&0x1F00FFFF)|(val<<16);
dev->endx[dev->voice] = (dev->endx[dev->voice] & 0xF807F) | (val << 7);
dev->end[dev->voice] = (dev->end[dev->voice] & 0x1F00FFFF) | (val << 16);
break;
case 5: /*End addr low*/
dev->end[dev->voice] = (dev->end[dev->voice]&0x1FFFFF00)|val;
dev->end[dev->voice] = (dev->end[dev->voice] & 0x1FFFFF00) | val;
break;
case 0x6: /*Ramp frequency*/
dev->rfreq[dev->voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6))));
dev->rfreq[dev->voice] = (int)((double)((val & 63) * 512) / (double)(1 << (3 * (val >> 6))));
break;
case 0x9: /*Current volume*/
@@ -303,20 +317,20 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
break;
case 0xA: /*Current addr high*/
dev->cur[dev->voice] = (dev->cur[dev->voice]&0x1F00FFFF)|(val<<16);
dev->curx[dev->voice] = (dev->curx[dev->voice]&0xF807F00)|((val<<7)<<8);
dev->cur[dev->voice] = (dev->cur[dev->voice] & 0x1F00FFFF) | (val << 16);
dev->curx[dev->voice] = (dev->curx[dev->voice] & 0xF807F00) | ((val << 7) << 8);
break;
case 0xB: /*Current addr low*/
dev->cur[dev->voice] = (dev->cur[dev->voice]&0x1FFFFF00)|val;
dev->cur[dev->voice] = (dev->cur[dev->voice] & 0x1FFFFF00) | val;
break;
case 0x42: /*DMA address low*/
dev->dmaaddr = (dev->dmaaddr&0xFF000)|(val<<4);
dev->dmaaddr = (dev->dmaaddr & 0xFF000) | (val << 4);
break;
case 0x43: /*Address low*/
dev->addr = (dev->addr&0xFFF00)|val;
dev->addr = (dev->addr & 0xFFF00) | val;
break;
case 0x45: /*Timer control*/
@@ -328,7 +342,7 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
case 0x345: /*Global high*/
switch (dev->global) {
case 0: /*Voice control*/
if (!(val&1) && dev->ctrl[dev->voice]&1) {
if (!(val & 1) && dev->ctrl[dev->voice] & 1) {
}
dev->ctrl[dev->voice] = val & 0x7f;
@@ -340,31 +354,31 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
break;
case 1: /*Frequency control*/
dev->freq[dev->voice] = (dev->freq[dev->voice]&0xFF)|(val<<8);
dev->freq[dev->voice] = (dev->freq[dev->voice] & 0xFF) | (val << 8);
break;
case 2: /*Start addr high*/
dev->startx[dev->voice] = (dev->startx[dev->voice]&0x07FFF)|(val<<15);
dev->start[dev->voice] = (dev->start[dev->voice]&0x00FFFFFF)|((val&0x1F)<<24);
dev->startx[dev->voice] = (dev->startx[dev->voice] & 0x07FFF) | (val << 15);
dev->start[dev->voice] = (dev->start[dev->voice] & 0x00FFFFFF) | ((val & 0x1F) << 24);
break;
case 3: /*Start addr low*/
dev->startx[dev->voice] = (dev->startx[dev->voice]&0xFFF80)|(val&0x7F);
dev->start[dev->voice] = (dev->start[dev->voice]&0x1FFF00FF)|(val<<8);
dev->startx[dev->voice] = (dev->startx[dev->voice] & 0xFFF80) | (val & 0x7F);
dev->start[dev->voice] = (dev->start[dev->voice] & 0x1FFF00FF) | (val << 8);
break;
case 4: /*End addr high*/
dev->endx[dev->voice] = (dev->endx[dev->voice]&0x07FFF)|(val<<15);
dev->end[dev->voice] = (dev->end[dev->voice]&0x00FFFFFF)|((val&0x1F)<<24);
dev->endx[dev->voice] = (dev->endx[dev->voice] & 0x07FFF) | (val << 15);
dev->end[dev->voice] = (dev->end[dev->voice] & 0x00FFFFFF) | ((val & 0x1F) << 24);
break;
case 5: /*End addr low*/
dev->endx[dev->voice] = (dev->endx[dev->voice]&0xFFF80)|(val&0x7F);
dev->end[dev->voice] = (dev->end[dev->voice]&0x1FFF00FF)|(val<<8);
dev->endx[dev->voice] = (dev->endx[dev->voice] & 0xFFF80) | (val & 0x7F);
dev->end[dev->voice] = (dev->end[dev->voice] & 0x1FFF00FF) | (val << 8);
break;
case 0x6: /*Ramp frequency*/
dev->rfreq[dev->voice] = (int)( (double)((val & 63) * (1 << 10))/(double)(1 << (3 * (val >> 6))));
dev->rfreq[dev->voice] = (int)((double)((val & 63) * (1 << 10)) / (double)(1 << (3 * (val >> 6))));
break;
case 0x7: /*Ramp start*/
@@ -380,13 +394,13 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
break;
case 0xA: /*Current addr high*/
dev->cur[dev->voice] = (dev->cur[dev->voice]&0x00FFFFFF)|((val&0x1F)<<24);
dev->curx[dev->voice] = (dev->curx[dev->voice]&0x07FFF00)|((val<<15)<<8);
dev->cur[dev->voice] = (dev->cur[dev->voice] & 0x00FFFFFF) | ((val & 0x1F) << 24);
dev->curx[dev->voice] = (dev->curx[dev->voice] & 0x07FFF00) | ((val << 15) << 8);
break;
case 0xB: /*Current addr low*/
dev->cur[dev->voice] = (dev->cur[dev->voice]&0x1FFF00FF)|(val<<8);
dev->curx[dev->voice] = (dev->curx[dev->voice]&0xFFF8000)|((val&0x7F)<<8);
dev->cur[dev->voice] = (dev->cur[dev->voice] & 0x1FFF00FF) | (val << 8);
dev->curx[dev->voice] = (dev->curx[dev->voice] & 0xFFF8000) | ((val & 0x7F) << 8);
break;
case 0xC: /*Pan*/
@@ -404,8 +418,8 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
case 0xE:
dev->voices = (val & 63) + 1;
if (dev->voices>32) dev->voices = 32;
if (dev->voices<14) dev->voices = 14;
if (dev->voices > 32) dev->voices = 32;
if (dev->voices < 14) dev->voices = 14;
dev->global = val;
if (dev->voices < 14)
dev->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0));
@@ -414,7 +428,7 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
break;
case 0x41: /*DMA*/
if (val&1 && dev->dma != -1) {
if (val & 1 && dev->dma != -1) {
if (val & 2) {
c = 0;
while (c < 65536) {
@@ -428,7 +442,8 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
dma_result = dma_channel_write(dev->dma, d);
if (dma_result == DMA_NODATA)
break;
} else {
}
else {
d = dev->ram[dev->dmaaddr];
if (val & 0x80)
d ^= 0x80;
@@ -445,7 +460,8 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
dev->dmactrl = val & ~0x40;
if (val & 0x20)
dev->irqnext = 1;
} else {
}
else {
c = 0;
while (c < 65536) {
d = dma_channel_read(dev->dma);
@@ -456,8 +472,9 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
if (val & 0x80)
d ^= 0x8080;
dev->ram[gus_addr] = d & 0xff;
dev->ram[gus_addr +1] = (d >> 8) & 0xff;
} else {
dev->ram[gus_addr + 1] = (d >> 8) & 0xff;
}
else {
if (val & 0x80)
d ^= 0x80;
dev->ram[dev->dmaaddr] = d;
@@ -476,25 +493,25 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
break;
case 0x42: /*DMA address low*/
dev->dmaaddr = (dev->dmaaddr&0xFF0)|(val<<12);
dev->dmaaddr = (dev->dmaaddr & 0xFF0) | (val << 12);
break;
case 0x43: /*Address low*/
dev->addr = (dev->addr&0xF00FF)|(val<<8);
dev->addr = (dev->addr & 0xF00FF) | (val << 8);
break;
case 0x44: /*Address high*/
dev->addr = (dev->addr&0xFFFF)|((val<<16)&0xF0000);
dev->addr = (dev->addr & 0xFFFF) | ((val << 16) & 0xF0000);
break;
case 0x45: /*Timer control*/
if (! (val & 4)) dev->irqstatus &= ~4;
if (! (val & 8)) dev->irqstatus &= ~8;
if (! (val & 0x20)) {
if (!(val & 4)) dev->irqstatus &= ~4;
if (!(val & 8)) dev->irqstatus &= ~8;
if (!(val & 0x20)) {
dev->ad_status &= ~0x18;
nmi = 0;
}
if (! (val & 0x02)) {
if (!(val & 0x02)) {
dev->ad_status &= ~0x01;
nmi = 0;
}
@@ -538,10 +555,12 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
else if (dev->irq != -1)
picint(1 << dev->irq);
}
} else if (!(dev->tctrl & GUS_TIMER_CTRL_AUTO) && dev->adcommand == 4) {
}
else if (!(dev->tctrl & GUS_TIMER_CTRL_AUTO) && dev->adcommand == 4) {
if (val & 0x80) {
dev->ad_status &= ~0x60;
} else {
}
else {
dev->ad_timer_ctrl = val;
if (val & 0x01)
@@ -567,6 +586,9 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
case 0:
if (dev->latch_enable == 1)
dev->dma = gus_dmas[val & 7];
#if defined(DEV_BRANCH) && defined(USE_GUSMAX)
cs423x_setdma(&dev->cs423x, dev->dma);
#endif
if (dev->latch_enable == 2) {
dev->irq = gus_irqs[val & 7];
@@ -575,9 +597,12 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
dev->irq = dev->irq_midi = gus_irqs[(val >> 3) & 7];
else
dev->irq_midi = dev->irq;
} else
}
else
dev->irq_midi = gus_irqs_midi[(val >> 3) & 7];
#if defined(DEV_BRANCH) && defined(USE_GUSMAX)
cs423x_setirq(&dev->cs423x, dev->irq);
#endif
dev->sb_nmi = val & 0x80;
}
dev->latch_enable = 0;
@@ -643,6 +668,22 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
case 0x24f:
dev->reg_ctrl = val;
break;
case 0x346: case 0x746:
if (dev->dma >= 4)
val |= 0x30;
dev->max_ctrl = (val >> 6) & 1;
if (val & 0x40) {
if ((val & 0xF) != ((addr >> 4) & 0xF)) { /* Fix me : why is DOS application attempting to relocate the CODEC ? */
ioport = 0x30c | ((addr >> 4) & 0xf);
io_removehandler(ioport, 4,
cs423x_read, NULL, NULL, cs423x_write, NULL, NULL, &dev->cs423x);
ioport = 0x30c | ((val & 0xf) << 4);
io_sethandler(ioport, 4,
cs423x_read, NULL, NULL, cs423x_write, NULL, NULL, &dev->cs423x);
}
}
break;
}
}
@@ -675,6 +716,9 @@ gus_read(uint16_t addr, void *priv)
break;
case 0x24F:
if (dev->max_ctrl)
val = 0x02;
else
val = 0x00;
break;
@@ -689,23 +733,23 @@ gus_read(uint16_t addr, void *priv)
case 0x344: /*Global low*/
switch (dev->global) {
case 0x82: /*Start addr high*/
val = dev->start[dev->voice]>>16;
val = dev->start[dev->voice] >> 16;
break;
case 0x83: /*Start addr low*/
val = dev->start[dev->voice]&0xFF;
val = dev->start[dev->voice] & 0xFF;
break;
case 0x89: /*Current volume*/
val = dev->rcur[dev->voice]>>6;
val = dev->rcur[dev->voice] >> 6;
break;
case 0x8A: /*Current addr high*/
val = dev->cur[dev->voice]>>16;
val = dev->cur[dev->voice] >> 16;
break;
case 0x8B: /*Current addr low*/
val = dev->cur[dev->voice]&0xFF;
val = dev->cur[dev->voice] & 0xFF;
break;
case 0x8F: /*IRQ status*/
@@ -727,27 +771,27 @@ gus_read(uint16_t addr, void *priv)
case 0x345: /*Global high*/
switch (dev->global) {
case 0x80: /*Voice control*/
val = dev->ctrl[dev->voice]|(dev->waveirqs[dev->voice]?0x80:0);
val = dev->ctrl[dev->voice] | (dev->waveirqs[dev->voice] ? 0x80 : 0);
break;
case 0x82: /*Start addr high*/
val = dev->start[dev->voice]>>24;
val = dev->start[dev->voice] >> 24;
break;
case 0x83: /*Start addr low*/
val = dev->start[dev->voice]>>8;
val = dev->start[dev->voice] >> 8;
break;
case 0x89: /*Current volume*/
val = dev->rcur[dev->voice]>>14;
val = dev->rcur[dev->voice] >> 14;
break;
case 0x8A: /*Current addr high*/
val = dev->cur[dev->voice]>>24;
val = dev->cur[dev->voice] >> 24;
break;
case 0x8B: /*Current addr low*/
val = dev->cur[dev->voice]>>8;
val = dev->cur[dev->voice] >> 8;
break;
case 0x8C: /*Pan*/
@@ -755,18 +799,18 @@ gus_read(uint16_t addr, void *priv)
break;
case 0x8D:
val = dev->rctrl[dev->voice]|(dev->rampirqs[dev->voice]?0x80:0);
val = dev->rctrl[dev->voice] | (dev->rampirqs[dev->voice] ? 0x80 : 0);
break;
case 0x8F: /*IRQ status*/
val = dev->irqstatus2;
dev->rampirqs[dev->irqstatus2&0x1F] = 0;
dev->waveirqs[dev->irqstatus2&0x1F] = 0;
dev->rampirqs[dev->irqstatus2 & 0x1F] = 0;
dev->waveirqs[dev->irqstatus2 & 0x1F] = 0;
poll_irqs(dev);
break;
case 0x41: /*DMA control*/
val = dev->dmactrl|((dev->irqstatus&0x80)?0x40:0);
val = dev->dmactrl | ((dev->irqstatus & 0x80) ? 0x40 : 0);
dev->irqstatus &= ~0x80;
break;
@@ -787,8 +831,11 @@ gus_read(uint16_t addr, void *priv)
}
break;
case 0x346:
val = 0xff;
case 0x346: case 0x746:
if (dev->max_ctrl)
val = 0x0a; /* GUS MAX */
else
val = 0xff; /*Pre 3.7 - no mixer*/
break;
case 0x347: /*DRAM access*/
@@ -800,10 +847,6 @@ gus_read(uint16_t addr, void *priv)
val = 0x00;
break;
case 0x746: /*Revision level*/
val = 0xff; /*Pre 3.7 - no mixer*/
break;
case 0x24b:
switch (dev->reg_ctrl & 0x07) {
case 1:
@@ -964,30 +1007,33 @@ poll_wave(void *priv)
return;
for (d = 0; d < 32; d++) {
if (! (dev->ctrl[d] & 3)) {
if (!(dev->ctrl[d] & 3)) {
if (dev->ctrl[d] & 4) {
addr = dev->cur[d] >> 9;
addr = (addr & 0xC0000) | ((addr << 1) & 0x3FFFE);
if (! (dev->freq[d] >> 10)) { /*Interpolate*/
if (!(dev->freq[d] >> 10)) { /*Interpolate*/
vl = (int16_t)(int8_t)((dev->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80) * (511 - (dev->cur[d] & 511));
vl += (int16_t)(int8_t)((dev->ram[(addr + 3) & 0xFFFFF] ^ 0x80) - 0x80) * (dev->cur[d] & 511);
v = vl >> 9;
} else
}
else
v = (int16_t)(int8_t)((dev->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80);
} else {
if (! (dev->freq[d] >> 10)) { /*Interpolate*/
}
else {
if (!(dev->freq[d] >> 10)) { /*Interpolate*/
vl = ((int8_t)((dev->ram[(dev->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80)) * (511 - (dev->cur[d] & 511));
vl += ((int8_t)((dev->ram[((dev->cur[d] >> 9) + 1) & 0xFFFFF] ^ 0x80) - 0x80)) * (dev->cur[d] & 511);
v = vl >> 9;
} else
}
else
v = (int16_t)(int8_t)((dev->ram[(dev->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80);
}
if ((dev->rcur[d] >> 14) > 4095)
v = (int16_t)((float)v * 24.0 * vol16bit[4095]);
else
v = (int16_t)((float)v * 24.0 * vol16bit[(dev->rcur[d]>>10) & 4095]);
v = (int16_t)((float)v * 24.0 * vol16bit[(dev->rcur[d] >> 10) & 4095]);
dev->out_l += (v * dev->pan_l[d]) / 7;
dev->out_r += (v * dev->pan_r[d]) / 7;
@@ -998,10 +1044,11 @@ poll_wave(void *priv)
int diff = dev->start[d] - dev->cur[d];
if (dev->ctrl[d] & 8) {
if (dev->ctrl[d]&0x10)
dev->ctrl[d]^=0x40;
if (dev->ctrl[d] & 0x10)
dev->ctrl[d] ^= 0x40;
dev->cur[d] = (dev->ctrl[d] & 0x40) ? (dev->end[d] - diff) : (dev->start[d] + diff);
} else if (! (dev->rctrl[d] & 4)) {
}
else if (!(dev->rctrl[d] & 4)) {
dev->ctrl[d] |= 1;
dev->cur[d] = (dev->ctrl[d] & 0x40) ? dev->end[d] : dev->start[d];
}
@@ -1011,17 +1058,19 @@ poll_wave(void *priv)
update_irqs = 1;
}
}
} else {
}
else {
dev->cur[d] += (dev->freq[d] >> 1);
if (dev->cur[d] >= dev->end[d]) {
int diff = dev->cur[d] - dev->end[d];
if (dev->ctrl[d] & 8) {
if (dev->ctrl[d]&0x10)
dev->ctrl[d]^=0x40;
if (dev->ctrl[d] & 0x10)
dev->ctrl[d] ^= 0x40;
dev->cur[d] = (dev->ctrl[d] & 0x40) ? (dev->end[d] - diff) : (dev->start[d] + diff);
} else if (! (dev->rctrl[d] & 4)) {
}
else if (!(dev->rctrl[d] & 4)) {
dev->ctrl[d] |= 1;
dev->cur[d] = (dev->ctrl[d] & 0x40) ? dev->end[d] : dev->start[d];
}
@@ -1034,16 +1083,17 @@ poll_wave(void *priv)
}
}
if (! (dev->rctrl[d] & 3)) {
if (!(dev->rctrl[d] & 3)) {
if (dev->rctrl[d] & 0x40) {
dev->rcur[d] -= dev->rfreq[d];
if (dev->rcur[d] <= dev->rstart[d]) {
int diff = dev->rstart[d] - dev->rcur[d];
if (! (dev->rctrl[d] & 8)) {
if (!(dev->rctrl[d] & 8)) {
dev->rctrl[d] |= 1;
dev->rcur[d] = (dev->rctrl[d] & 0x40) ? dev->rstart[d] : dev->rend[d];
} else {
}
else {
if (dev->rctrl[d] & 0x10)
dev->rctrl[d] ^= 0x40;
dev->rcur[d] = (dev->rctrl[d] & 0x40) ? (dev->rend[d] - diff) : (dev->rstart[d] + diff);
@@ -1054,15 +1104,17 @@ poll_wave(void *priv)
update_irqs = 1;
}
}
} else {
}
else {
dev->rcur[d] += dev->rfreq[d];
if (dev->rcur[d] >= dev->rend[d]) {
int diff = dev->rcur[d] - dev->rend[d];
if (! (dev->rctrl[d] & 8)) {
if (!(dev->rctrl[d] & 8)) {
dev->rctrl[d] |= 1;
dev->rcur[d] = (dev->rctrl[d] & 0x40) ? dev->rstart[d] : dev->rend[d];
} else {
}
else {
if (dev->rctrl[d] & 0x10)
dev->rctrl[d] ^= 0x40;
dev->rcur[d] = (dev->rctrl[d] & 0x40) ? (dev->rend[d] - diff) : (dev->rstart[d] + diff);
@@ -1088,10 +1140,24 @@ get_buffer(int32_t *buffer, int len, void *priv)
gus_t *dev = (gus_t *)priv;
int c;
#if defined(DEV_BRANCH) && defined(USE_GUSMAX)
if (dev->max_ctrl)
cs423x_update(&dev->cs423x);
#endif
gus_update(dev);
for (c = 0; c < len * 2; c++)
for (c = 0; c < len * 2; c++) {
#if defined(DEV_BRANCH) && defined(USE_GUSMAX)
if (dev->max_ctrl)
buffer[c] += (int32_t)(dev->cs423x.buffer[c] / 2);
#endif
buffer[c] += (int32_t)dev->buffer[c & 1][c >> 1];
}
#if defined(DEV_BRANCH) && defined(USE_GUSMAX)
if (dev->max_ctrl)
dev->cs423x.pos = 0;
#endif
dev->pos = 0;
}
@@ -1112,7 +1178,7 @@ gus_init(const device_t *info)
for (c = 0; c < 32; c++) {
dev->ctrl[c] = 1;
dev->rctrl[c] = 1;
dev->rfreq[c] = 63*512;
dev->rfreq[c] = 63 * 512;
}
for (c = 4095; c >= 0; c--) {
@@ -1120,21 +1186,21 @@ gus_init(const device_t *info)
out /= 1.002709201; /* 0.0235 dB Steps */
}
// DEBUG("GUS: top volume %f %f %f %f\n",vol16bit[4095],vol16bit[3800],vol16bit[3000],vol16bit[2048]);
dev->voices=14;
// DEBUG("GUS: top volume %f %f %f %f\n",vol16bit[4095],vol16bit[3800],vol16bit[3000],vol16bit[2048]);
dev->voices = 14;
dev->samp_timer = dev->samp_latch = (int64_t)(TIMER_USEC * (1000000.0 / 44100.0));
dev->t1l = dev->t2l = 0xff;
io_sethandler(0x0240, 16,
gus_read,NULL,NULL, gus_write,NULL,NULL, dev);
gus_read, NULL, NULL, gus_write, NULL, NULL, dev);
io_sethandler(0x0340, 16,
gus_read,NULL,NULL, gus_write,NULL,NULL, dev);
gus_read, NULL, NULL, gus_write, NULL, NULL, dev);
io_sethandler(0x0746, 1,
gus_read,NULL,NULL, gus_write,NULL,NULL, dev);
gus_read, NULL, NULL, gus_write, NULL, NULL, dev);
io_sethandler(0x0388, 2,
gus_read,NULL,NULL, gus_write,NULL,NULL, dev);
gus_read, NULL, NULL, gus_write, NULL, NULL, dev);
timer_add(poll_wave, &dev->samp_timer, TIMER_ALWAYS_ENABLED, dev);
timer_add(poll_timer_1, &dev->timer_1, TIMER_ALWAYS_ENABLED, dev);
@@ -1145,6 +1211,60 @@ gus_init(const device_t *info)
return(dev);
}
#if defined(DEV_BRANCH) && defined(USE_GUSMAX)
static void *
gus_max_init(const device_t *info)
{
int c;
double out = 1.0;
gus_t *dev = (gus_t *)mem_alloc(sizeof(gus_t));
memset(dev, 0x00, sizeof(gus_t));
dev->ram = (uint8_t *)mem_alloc(1 << 20); // Maximum 1 Mb RAM
memset(dev->ram, 0x00, 1 << 20);
for (c = 0;c < 32;c++) {
dev->ctrl[c] = 1;
dev->rctrl[c] = 1;
dev->rfreq[c] = 63 * 512;
}
for (c = 4095;c >= 0;c--) {
vol16bit[c] = out;
out /= 1.002709201;
}
dev->voices = 14;
dev->samp_timer = dev->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0));
dev->t1l = dev->t2l = 0xff;
cs423x_init(&dev->cs423x);
cs423x_setirq(&dev->cs423x, 5); /*Default irq and dma from GUS SDK*/
cs423x_setdma(&dev->cs423x, 3);
io_sethandler(0x0240, 16,
gus_read, NULL, NULL, gus_write, NULL, NULL, dev);
io_sethandler(0x0340, 9,
gus_read, NULL, NULL, gus_write, NULL, NULL, dev);
io_sethandler(0x0746, 1,
gus_read, NULL, NULL, gus_write, NULL, NULL, dev);
io_sethandler(0x0388, 2,
gus_read, NULL, NULL, gus_write, NULL, NULL, dev);
io_sethandler(0x034c, 4,
cs423x_read, NULL, NULL, cs423x_write, NULL, NULL, &dev->cs423x);
timer_add(poll_wave, &dev->samp_timer, TIMER_ALWAYS_ENABLED, dev);
timer_add(poll_timer_1, &dev->timer_1, TIMER_ALWAYS_ENABLED, dev);
timer_add(poll_timer_2, &dev->timer_2, TIMER_ALWAYS_ENABLED, dev);
sound_add_handler(get_buffer, dev);
return(dev);
}
#endif
static void
gus_close(void *priv)
@@ -1166,6 +1286,11 @@ speed_changed(void *priv)
dev->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0));
else
dev->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[dev->voices - 14]));
#if defined(DEV_BRANCH) && defined(USE_GUSMAX)
if (dev->max_ctrl)
cs423x_speed_changed(&dev->cs423x);
#endif
}
@@ -1177,3 +1302,14 @@ const device_t gus_device = {
speed_changed, NULL, NULL,
NULL
};
#if defined(DEV_BRANCH) && defined(USE_GUSMAX)
const device_t gusmax_device = {
"Gravis UltraSound MAX",
DEVICE_ISA,
0,
gus_max_init, gus_close, NULL, NULL,
speed_changed, NULL, NULL,
NULL
};
#endif

View File

@@ -8,7 +8,7 @@
*
* Sound devices support module.
*
* Version: @(#)sound_dev.c 1.0.10 2018/10/20
* Version: @(#)sound_dev.c 1.0.11 2018/11/27
*
* Authors: Fred N. van Kempen, <decwiz@yahoo.com>
* Miran Grca, <mgrca8@gmail.com>
@@ -63,6 +63,9 @@ extern const device_t es1371_device;
extern const device_t sbpci128_device;
extern const device_t cms_device;
extern const device_t gus_device;
#if defined(DEV_BRANCH) && defined(USE_GUSMAX)
extern const device_t gusmax_device;
#endif
#if defined(DEV_BRANCH) && defined(USE_PAS16)
extern const device_t pas16_device;
#endif
@@ -91,6 +94,9 @@ static const struct {
{ "adlibgold", &adgold_device },
{ "cms", &cms_device },
{ "gus", &gus_device },
#if defined(DEV_BRANCH) && defined(USE_GUSMAX)
{ "gusmax", &gusmax_device },
#endif
{ "ssi2001", &ssi2001_device },
{ "sb", &sb_1_device },
{ "sb1.5", &sb_15_device },

View File

@@ -8,7 +8,7 @@
#
# Makefile for Windows systems using the MinGW32 environment.
#
# Version: @(#)Makefile.mingw 1.0.69 2018/11/11
# Version: @(#)Makefile.mingw 1.0.70 2018/11/30
#
# Author: Fred N. van Kempen, <decwiz@yahoo.com>
#
@@ -152,6 +152,9 @@ endif
ifndef HOSTCD
HOSTCD := n
endif
ifndef GUSMAX
GUSMAX := n
endif
# Name of the executable.
@@ -186,6 +189,7 @@ ifeq ($(DEV_BUILD), y)
XL24 := y
WONDER := y
HOSTCD := y
GUSMAX := y
endif
@@ -571,6 +575,10 @@ ifeq ($(DEV_BRANCH), y)
OPTS += -DUSE_HOST_CDROM
endif
ifeq ($(GUSMAX), y)
OPTS += -DUSE_GUSMAX
DEVBROBJ += snd_cs423x.o
endif
endif

View File

@@ -1,4 +1,4 @@
#
#
# VARCem Virtual ARchaeological Computer EMulator.
# An emulator of (mostly) x86-based PC systems and devices,
# using the ISA,EISA,VLB,MCA and PCI system buses, roughly
@@ -8,7 +8,7 @@
#
# Makefile for Windows using Visual Studio 2015.
#
# Version: @(#)Makefile.VC 1.0.55 2018/11/11
# Version: @(#)Makefile.VC 1.0.56 2018/11/30
#
# Author: Fred N. van Kempen, <decwiz@yahoo.com>
#
@@ -153,7 +153,9 @@ endif
ifndef PRINTER
PRINTER := n
endif
ifndef GUSMAX
GUSMAX := n
endif
# Name of the executable.
NETIF := pcap_if
@@ -188,6 +190,7 @@ ifeq ($(DEV_BUILD), y)
WONDER := y
HOSTCD := y
PRINTER := y
GUSMAX := y
endif
@@ -551,6 +554,11 @@ ifeq ($(DEV_BRANCH), y)
OPTS += -DUSE_PRINTER
DEVBROBJ += prt_parallel.obj
endif
ifeq ($(GUSMAX), y)
OPTS += -DUSE_GUSMAX
DEVBROBJ += snd_cs423x.obj
endif
endif

View File

@@ -128,6 +128,7 @@
<ClCompile Include="..\..\..\devices\sound\snd_adlibgold.c" />
<ClCompile Include="..\..\..\devices\sound\snd_audiopci.c" />
<ClCompile Include="..\..\..\devices\sound\snd_cms.c" />
<ClCompile Include="..\..\..\devices\sound\snd_cs423x.c" />
<ClCompile Include="..\..\..\devices\sound\snd_dbopl.cpp" />
<ClCompile Include="..\..\..\devices\sound\snd_emu8k.c" />
<ClCompile Include="..\..\..\devices\sound\snd_gus.c" />
@@ -447,6 +448,7 @@
<ClInclude Include="..\..\..\devices\sound\resid-fp\voice.h" />
<ClInclude Include="..\..\..\devices\sound\resid-fp\wave.h" />
<ClInclude Include="..\..\..\devices\sound\snd_ad1848.h" />
<ClInclude Include="..\..\..\devices\sound\snd_cs423x.h" />
<ClInclude Include="..\..\..\devices\sound\snd_dbopl.h" />
<ClInclude Include="..\..\..\devices\sound\snd_emu8k.h" />
<ClInclude Include="..\..\..\devices\sound\snd_lpt_dac.h" />