Merge pull request #6154 from lemondrops/gus

Gravis UltraSound: additions, improvements and fixes
This commit is contained in:
Miran Grča
2025-09-11 19:06:31 +02:00
committed by GitHub
32 changed files with 588 additions and 55 deletions

View File

@@ -32,6 +32,14 @@ enum {
AD1848_TYPE_CS4235 = 6 AD1848_TYPE_CS4235 = 6
}; };
enum {
AD1848_AUX1 = 2,
AD1848_AUX2 = 4,
AD1848_OUT = 6,
AD1848_LINE_IN = 18,
AD1848_MONO = 26
};
typedef struct ad1848_t { typedef struct ad1848_t {
uint8_t type; uint8_t type;
uint8_t index; uint8_t index;
@@ -47,6 +55,7 @@ typedef struct ad1848_t {
int16_t out_l; int16_t out_l;
int16_t out_r; int16_t out_r;
int8_t cd_vol_reg;
double cd_vol_l; double cd_vol_l;
double cd_vol_r; double cd_vol_r;
int fm_vol_l; int fm_vol_l;
@@ -86,8 +95,9 @@ extern void ad1848_write(uint16_t addr, uint8_t val, void *priv);
extern void ad1848_update(ad1848_t *ad1848); extern void ad1848_update(ad1848_t *ad1848);
extern void ad1848_speed_changed(ad1848_t *ad1848); extern void ad1848_speed_changed(ad1848_t *ad1848);
extern void ad1848_set_cd_audio_channel(void *priv, int channel);
extern void ad1848_filter_cd_audio(int channel, double *buffer, void *priv); extern void ad1848_filter_cd_audio(int channel, double *buffer, void *priv);
extern void ad1848_filter_aux2(void* priv, double* out_l, double* out_r); extern void ad1848_filter_channel(void* priv, int channel, double* out_l, double* out_r);
extern void ad1848_init(ad1848_t *ad1848, uint8_t type); extern void ad1848_init(ad1848_t *ad1848, uint8_t type);

View File

@@ -203,9 +203,11 @@ extern const device_t es1373_onboard_device;
extern const device_t ct5880_device; extern const device_t ct5880_device;
extern const device_t ct5880_onboard_device; extern const device_t ct5880_onboard_device;
/* Gravis UltraSound and UltraSound Max */ /* Gravis UltraSound family */
extern const device_t gus_device; extern const device_t gus_device;
extern const device_t gus_v37_device;
extern const device_t gus_max_device; extern const device_t gus_max_device;
extern const device_t gus_ace_device;
/* IBM PS/1 Audio Card */ /* IBM PS/1 Audio Card */
extern const device_t ps1snd_device; extern const device_t ps1snd_device;

View File

@@ -2136,6 +2136,9 @@ msgstr ""
msgid "Enable Game port" msgid "Enable Game port"
msgstr "" msgstr ""
msgid "Enable Adlib ports"
msgstr ""
msgid "SID Model" msgid "SID Model"
msgstr "" msgstr ""

View File

@@ -2136,6 +2136,9 @@ msgstr "Nízký DMA kanál"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Povolit herní port" msgstr "Povolit herní port"
msgid "Enable Adlib ports"
msgstr "Povolit porty Adlib"
msgid "SID Model" msgid "SID Model"
msgstr "Model SID" msgstr "Model SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "Niedrige DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Game-Port einschalten" msgstr "Game-Port einschalten"
msgid "Enable Adlib ports"
msgstr "Adlib-Ports einschalten"
msgid "SID Model" msgid "SID Model"
msgstr "SID-Modell" msgstr "SID-Modell"

View File

@@ -2136,6 +2136,9 @@ msgstr "DMA bajo"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Habilitar puerto de juegos" msgstr "Habilitar puerto de juegos"
msgid "Enable Adlib ports"
msgstr "Habilitar puertos Adlib"
msgid "SID Model" msgid "SID Model"
msgstr "Modelo de SID" msgstr "Modelo de SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "Matala DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Peliportti" msgstr "Peliportti"
msgid "Enable Adlib ports"
msgstr "Adlib-portit"
msgid "SID Model" msgid "SID Model"
msgstr "SID-malli" msgstr "SID-malli"

View File

@@ -2136,6 +2136,9 @@ msgstr "DMA bas"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Activer le port de jeu" msgstr "Activer le port de jeu"
msgid "Enable Adlib ports"
msgstr "Activer les ports Adlib"
msgid "SID Model" msgid "SID Model"
msgstr "Modèle SID" msgstr "Modèle SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "Niski DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Omogoći vrata za igru" msgstr "Omogoći vrata za igru"
msgid "Enable Adlib ports"
msgstr "Omogući Adlib portove"
msgid "SID Model" msgid "SID Model"
msgstr "Model SID-a" msgstr "Model SID-a"

View File

@@ -2136,6 +2136,9 @@ msgstr "DMA basso"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Abilita la porta giochi" msgstr "Abilita la porta giochi"
msgid "Enable Adlib ports"
msgstr "Abilita porte Adlib"
msgid "SID Model" msgid "SID Model"
msgstr "Modello SID" msgstr "Modello SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "低DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "ゲームポートを有効にする" msgstr "ゲームポートを有効にする"
msgid "Enable Adlib ports"
msgstr "Adlibポートを有効にする"
msgid "SID Model" msgid "SID Model"
msgstr "SIDモデル" msgstr "SIDモデル"

View File

@@ -2136,6 +2136,9 @@ msgstr "낮은 DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "게임 포트 사용" msgstr "게임 포트 사용"
msgid "Enable Adlib ports"
msgstr "Adlib 포트 활성화"
msgid "SID Model" msgid "SID Model"
msgstr "SID 모델" msgstr "SID 모델"

View File

@@ -2136,6 +2136,9 @@ msgstr "Lav DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Aktiver spillport" msgstr "Aktiver spillport"
msgid "Enable Adlib ports"
msgstr "Aktiver Adlib-porter"
msgid "SID Model" msgid "SID Model"
msgstr "SID-modell" msgstr "SID-modell"

View File

@@ -2136,6 +2136,9 @@ msgstr "Lage DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Game-poort inschakelen" msgstr "Game-poort inschakelen"
msgid "Enable Adlib ports"
msgstr "Adlib-poorten inschakelen"
msgid "SID Model" msgid "SID Model"
msgstr "SID-model" msgstr "SID-model"

View File

@@ -2136,6 +2136,9 @@ msgstr "Niski poziom DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Włącz port gier" msgstr "Włącz port gier"
msgid "Enable Adlib ports"
msgstr "Włącz porty Adlib"
msgid "SID Model" msgid "SID Model"
msgstr "Model SID" msgstr "Model SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "DMA baixo"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Ativar a porta do jogo" msgstr "Ativar a porta do jogo"
msgid "Enable Adlib ports"
msgstr "Ativar portas Adlib"
msgid "SID Model" msgid "SID Model"
msgstr "Modelo do SID" msgstr "Modelo do SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "DMA baixo"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Ativar a porta de jogos" msgstr "Ativar a porta de jogos"
msgid "Enable Adlib ports"
msgstr "Ativar portas Adlib"
msgid "SID Model" msgid "SID Model"
msgstr "Modelo do SID" msgstr "Modelo do SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "Низкий DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Включить игровой порт" msgstr "Включить игровой порт"
msgid "Enable Adlib ports"
msgstr "Включить порты Adlib"
msgid "SID Model" msgid "SID Model"
msgstr "Модель SID" msgstr "Модель SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "Nízka hodnota DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Povolenie herného portu" msgstr "Povolenie herného portu"
msgid "Enable Adlib ports"
msgstr "Povoliť porty Adlib"
msgid "SID Model" msgid "SID Model"
msgstr "Model SID" msgstr "Model SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "Nizki DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Omogočanje igralnih vrat" msgstr "Omogočanje igralnih vrat"
msgid "Enable Adlib ports"
msgstr "Omogoči vrata Adlib"
msgid "SID Model" msgid "SID Model"
msgstr "Model SID-a" msgstr "Model SID-a"

View File

@@ -2136,6 +2136,9 @@ msgstr "Låg DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Aktivera spelport" msgstr "Aktivera spelport"
msgid "Enable Adlib ports"
msgstr "Aktivera Adlib-portar"
msgid "SID Model" msgid "SID Model"
msgstr "SID-modell" msgstr "SID-modell"

View File

@@ -2136,6 +2136,9 @@ msgstr "Düşük DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Gameport'ı etkinleştir" msgstr "Gameport'ı etkinleştir"
msgid "Enable Adlib ports"
msgstr "Adlib bağlantı noktalarını etkinleştir"
msgid "SID Model" msgid "SID Model"
msgstr "SID Modeli" msgstr "SID Modeli"

View File

@@ -2136,6 +2136,9 @@ msgstr "Низький рівень DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Увімкнути ігровий порт" msgstr "Увімкнути ігровий порт"
msgid "Enable Adlib ports"
msgstr "Увімкнути порти Adlib"
msgid "SID Model" msgid "SID Model"
msgstr "Модель SID" msgstr "Модель SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "DMA thấp"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "Bật cổng trò chơi" msgstr "Bật cổng trò chơi"
msgid "Enable Adlib ports"
msgstr "Bật cổng Adlib"
msgid "SID Model" msgid "SID Model"
msgstr "Mẫu SID" msgstr "Mẫu SID"

View File

@@ -2136,6 +2136,9 @@ msgstr "低 DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "启用游戏端口" msgstr "启用游戏端口"
msgid "Enable Adlib ports"
msgstr "启用 Adlib 端口"
msgid "SID Model" msgid "SID Model"
msgstr "SID 芯片型号" msgstr "SID 芯片型号"

View File

@@ -2136,6 +2136,9 @@ msgstr "低 DMA"
msgid "Enable Game port" msgid "Enable Game port"
msgstr "啟用遊戲埠" msgstr "啟用遊戲埠"
msgid "Enable Adlib ports"
msgstr "啟用 Adlib 連接埠"
msgid "SID Model" msgid "SID Model"
msgstr "SID 型號" msgstr "SID 型號"

View File

@@ -501,16 +501,16 @@ readonly_x:
if (updatefreq) if (updatefreq)
ad1848_updatefreq(ad1848); ad1848_updatefreq(ad1848);
temp = (ad1848->type < AD1848_TYPE_CS4231) ? 2 : ((ad1848->type == AD1848_TYPE_CS4231) ? 18 : 4); if (ad1848->cd_vol_reg > -1) {
if (ad1848->regs[temp] & 0x80) if (ad1848->regs[ad1848->cd_vol_reg] & 0x80)
ad1848->cd_vol_l = 0; ad1848->cd_vol_l = 0;
else else
ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[temp] & 0x1f]; ad1848->cd_vol_l = ad1848_vols_5bits_aux_gain[ad1848->regs[ad1848->cd_vol_reg] & 0x1f];
temp++; if (ad1848->regs[ad1848->cd_vol_reg + 1] & 0x80)
if (ad1848->regs[temp] & 0x80) ad1848->cd_vol_r = 0;
ad1848->cd_vol_r = 0; else
else ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[ad1848->cd_vol_reg + 1] & 0x1f];
ad1848->cd_vol_r = ad1848_vols_5bits_aux_gain[ad1848->regs[temp] & 0x1f]; }
readonly_i: readonly_i:
ad1848_log("AD1848: write(I%d, %02X)\n", ad1848->index, val); ad1848_log("AD1848: write(I%d, %02X)\n", ad1848->index, val);
@@ -746,6 +746,18 @@ ad1848_poll(void *priv)
} }
} }
void
ad1848_set_cd_audio_channel(void *priv, int channel)
{
ad1848_t *ad1848 = (ad1848_t *) priv;
const int max_channel = (ad1848->type >= AD1848_TYPE_CS4231) ? 31 : 15;
if (channel > max_channel)
channel = max_channel;
ad1848->cd_vol_reg = channel;
}
void void
ad1848_filter_cd_audio(int channel, double *buffer, void *priv) ad1848_filter_cd_audio(int channel, double *buffer, void *priv)
{ {
@@ -758,20 +770,24 @@ ad1848_filter_cd_audio(int channel, double *buffer, void *priv)
} }
void void
ad1848_filter_aux2(void *priv, double *out_l, double *out_r) ad1848_filter_channel(void *priv, int channel, double *out_l, double *out_r)
{ {
const ad1848_t *ad1848 = (ad1848_t *) priv; const ad1848_t *ad1848 = (ad1848_t *) priv;
if (ad1848->regs[4] & 0x80) { const int max_channel = (ad1848->type >= AD1848_TYPE_CS4231) ? 31 : 15;
if (channel > max_channel)
channel = max_channel;
if (ad1848->regs[channel] & 0x80) {
*out_l = 0.0; *out_l = 0.0;
} else { } else {
*out_l = ((*out_l) * ad1848_vols_5bits_aux_gain[ad1848->regs[4] & 0x1f]) / 65536.0; *out_l = ((*out_l) * ad1848_vols_5bits_aux_gain[ad1848->regs[channel] & 0x1f]) / 65536.0;
} }
if (ad1848->regs[5] & 0x80) { if (ad1848->regs[channel + 1] & 0x80) {
*out_r = 0.0; *out_r = 0.0;
} else { } else {
*out_r = ((*out_r) * ad1848_vols_5bits_aux_gain[ad1848->regs[5] & 0x1f]) / 65536.0; *out_r = ((*out_r) * ad1848_vols_5bits_aux_gain[ad1848->regs[channel + 1] & 0x1f]) / 65536.0;
} }
} }
@@ -837,6 +853,8 @@ ad1848_init(ad1848_t *ad1848, uint8_t type)
ad1848->out_l = ad1848->out_r = 0; ad1848->out_l = ad1848->out_r = 0;
ad1848->fm_vol_l = ad1848->fm_vol_r = 65536; ad1848->fm_vol_l = ad1848->fm_vol_r = 65536;
ad1848->cd_vol_l = ad1848->cd_vol_r = 65536;
ad1848->cd_vol_reg = -1;
ad1848_updatevolmask(ad1848); ad1848_updatevolmask(ad1848);
if (type >= AD1848_TYPE_CS4235) if (type >= AD1848_TYPE_CS4235)
ad1848->fmt_mask = 0x50; ad1848->fmt_mask = 0x50;

View File

@@ -1211,6 +1211,7 @@ azt_init(const device_t *info)
/* wss part */ /* wss part */
ad1848_init(&azt2316a->ad1848, device_get_config_int("codec")); ad1848_init(&azt2316a->ad1848, device_get_config_int("codec"));
ad1848_set_cd_audio_channel(&azt2316a->ad1848, (device_get_config_int("codec") == AD1848_TYPE_CS4248) ? AD1848_AUX1 : AD1848_LINE_IN);
ad1848_setirq(&azt2316a->ad1848, azt2316a->cur_wss_irq); ad1848_setirq(&azt2316a->ad1848, azt2316a->cur_wss_irq);
ad1848_setdma(&azt2316a->ad1848, azt2316a->cur_wss_dma); ad1848_setdma(&azt2316a->ad1848, azt2316a->cur_wss_dma);

View File

@@ -273,8 +273,10 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv)
} }
switch (dev->regs[3] & 0x0f) { switch (dev->regs[3] & 0x0f) {
case 0: /* WSS Master Control */ case 0: /* WSS Master Control */
if ((dev->type < CRYSTAL_CS4235) && (val & 0x80)) if ((dev->type < CRYSTAL_CS4235) && (val & 0x80)) {
ad1848_init(&dev->ad1848, dev->ad1848_type); ad1848_init(&dev->ad1848, dev->ad1848_type);
ad1848_set_cd_audio_channel(&dev->ad1848, AD1848_AUX2);
}
val = 0x00; val = 0x00;
break; break;
@@ -865,6 +867,7 @@ cs423x_reset(void *priv)
/* Reset WSS codec. */ /* Reset WSS codec. */
ad1848_init(&dev->ad1848, dev->ad1848_type); ad1848_init(&dev->ad1848, dev->ad1848_type);
ad1848_set_cd_audio_channel(&dev->ad1848, AD1848_AUX2);
/* Reset PnP resource data, state and logical devices. */ /* Reset PnP resource data, state and logical devices. */
dev->pnp_enable = 1; dev->pnp_enable = 1;

View File

@@ -13,6 +13,7 @@
#include <86box/io.h> #include <86box/io.h>
#include <86box/midi.h> #include <86box/midi.h>
#include <86box/nmi.h> #include <86box/nmi.h>
#include <86box/gameport.h>
#include <86box/pic.h> #include <86box/pic.h>
#include <86box/sound.h> #include <86box/sound.h>
#include "cpu.h" #include "cpu.h"
@@ -43,10 +44,33 @@ enum {
}; };
enum { enum {
GUS_CLASSIC = 0, GUS_CLASSIC = 0,
GUS_MAX = 1, GUS_CLASSIC_37 = 1,
GUS_MAX = 2,
GUS_ACE = 3
}; };
enum {
GUS_ICS2101_MIC_IN = 0,
GUS_ICS2101_LINE_IN = 1,
GUS_ICS2101_CD_IN = 2,
GUS_ICS2101_GF1_OUT = 3,
GUS_ICS2101_UNUSED = 4,
GUS_ICS2101_MASTER = 5,
GUS_ICS2101_MAX = 6
};
typedef struct ics2101_chan_t {
uint8_t ctrl[2];
double level[2];
uint8_t pan;
} ics2101_chan_t;
typedef struct ics2101_t {
uint8_t addr;
ics2101_chan_t channels[GUS_ICS2101_MAX];
} ics2101_t;
typedef struct gus_t { typedef struct gus_t {
int reset; int reset;
@@ -120,7 +144,9 @@ typedef struct gus_t {
uint8_t sb_ctrl; uint8_t sb_ctrl;
int sb_nmi; int sb_nmi;
uint8_t joy_trim;
uint8_t reg_ctrl; uint8_t reg_ctrl;
uint8_t jumper;
uint8_t ad_status; uint8_t ad_status;
uint8_t ad_data; uint8_t ad_data;
@@ -143,9 +169,13 @@ typedef struct gus_t {
uint8_t usrr; uint8_t usrr;
void *gameport;
uint8_t max_ctrl; uint8_t max_ctrl;
ad1848_t ad1848; ad1848_t ad1848;
ics2101_t ics2101;
} gus_t; } gus_t;
static int gus_gf1_irqs[8] = { -1, 2, 5, 3, 7, 11, 12, 15 }; static int gus_gf1_irqs[8] = { -1, 2, 5, 3, 7, 11, 12, 15 };
@@ -159,6 +189,15 @@ int gusfreqs[] = {
double vol16bit[4096]; double vol16bit[4096];
double ics2101_att[128];
double ics2101_pan[] = { 0.35481, 0.35481, 0.35481, 0.37584, 0.47315, 0.53088, 0.59566, 0.66834,
0.70795,
0.74989, 0.79433, 0.84140, 0.89125, 0.94406, 1.00000, 1.00000, 1.00000 };
void gus_write(uint16_t addr, uint8_t val, void *priv);
uint8_t gus_read(uint16_t addr, void *priv);
void void
gus_update_int_status(gus_t *gus) gus_update_int_status(gus_t *gus)
{ {
@@ -255,6 +294,10 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
uint16_t port; uint16_t port;
uint16_t csioport; uint16_t csioport;
ics2101_t *ics2101 = &gus->ics2101;
uint8_t mixer_ch;
uint8_t mixer_lr;
if ((addr == 0x388) || (addr == 0x389)) if ((addr == 0x388) || (addr == 0x389))
port = addr; port = addr;
else else
@@ -537,6 +580,10 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
gus->t2on = 1; gus->t2on = 1;
break; break;
case 0x4B: /*Joystick trim DAC*/
gus->joy_trim = val;
break;
case 0x4c: /*Reset*/ case 0x4c: /*Reset*/
gus->reset = val; gus->reset = val;
break; break;
@@ -634,9 +681,25 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
gus->gp2_addr = val; gus->gp2_addr = val;
break; break;
case 5: case 5:
gus->usrr = 0; if (gus->type > GUS_CLASSIC)
gus->usrr = 0;
break; break;
case 6: case 6:
if (gus->type > GUS_CLASSIC) {
if (gus->type != GUS_ACE) {
if (!(val & 0x2) && (gus->jumper & 0x2))
io_removehandler(0x0100 + gus->base, 0x0002, gus_read, NULL, NULL, gus_write, NULL, NULL, gus);
else if ((val & 0x2) && !(gus->jumper & 0x2))
io_sethandler(0x0100 + gus->base, 0x0002, gus_read, NULL, NULL, gus_write, NULL, NULL, gus);
if (!(val & 0x4) && (gus->jumper & 0x4))
gameport_remap(gus->gameport, 0x0);
else if ((val & 0x4) && !(gus->jumper & 0x4))
gameport_remap(gus->gameport, 0x201);
}
gus->jumper = val;
}
break; break;
default: default:
@@ -672,11 +735,47 @@ gus_write(uint16_t addr, uint8_t val, void *priv)
gus->sb_2xe = val; gus->sb_2xe = val;
break; break;
case 0x20f: case 0x20f:
gus->reg_ctrl = val; if (gus->type > GUS_CLASSIC)
gus->reg_ctrl = val;
break; break;
case 0x306: case 0x306:
if (gus->type == GUS_CLASSIC_37) {
mixer_ch = (ics2101->addr >> 3) & 0x7; /* current attenuator */
mixer_lr = ics2101->addr & 1; /* left or right channel */
switch (ics2101->addr & 0x6) {
case 0: /* Set control */
ics2101->channels[mixer_ch].ctrl[mixer_lr] = val & 0xF;
if ((mixer_lr == 0) && (val & 0xC)) /* copy to right channel if not normal mode */
ics2101->channels[mixer_ch].ctrl[1] = val & 0xF;
break;
case 2: /* Set attenuator */
switch (ics2101->channels[mixer_ch].ctrl[mixer_lr] & 0xC) {
case 0: /* Normal mode */
ics2101->channels[mixer_ch].level[mixer_lr] = ics2101_att[val & 0x7F];
break;
case 4: /* Stereo mode */
ics2101->channels[mixer_ch].level[0] = ics2101_att[val & 0x7F];
ics2101->channels[mixer_ch].level[1] = ics2101_att[val & 0x7F];
break;
case 8: /* Balance/Pan mode */
ics2101->channels[mixer_ch].level[0] = ics2101_att[val & 0x7F] * ics2101_pan[ics2101->channels[mixer_ch].pan + 1];
ics2101->channels[mixer_ch].level[1] = ics2101_att[val & 0x7F] * ics2101_pan[16 - ics2101->channels[mixer_ch].pan];
break;
}
break;
case 4: /* Set panning */
ics2101->channels[mixer_ch].pan = val & 0xF;
break;
default:
break;
}
break;
}
fallthrough;
case 0x706: case 0x706:
if (gus->type == GUS_MAX) { if (gus->type == GUS_CLASSIC_37) {
gus->ics2101.addr = val & 0x3F;
} else if (gus->type == GUS_MAX) {
if (gus->dma >= 4) if (gus->dma >= 4)
val |= 0x10; val |= 0x10;
if (gus->dma2 >= 4) if (gus->dma2 >= 4)
@@ -746,10 +845,10 @@ gus_read(uint16_t addr, void *priv)
return val; return val;
case 0x20F: case 0x20F:
if (gus->type == GUS_MAX) if (gus->type > GUS_CLASSIC)
val = 0x02; val = gus->jumper;
else else
val = 0x00; val = 0xff;
break; break;
case 0x302: case 0x302:
@@ -842,6 +941,9 @@ gus_read(uint16_t addr, void *priv)
case 0x49: /*Sampling control*/ case 0x49: /*Sampling control*/
return 0; return 0;
case 0x4B: /*Joystick trim DAC*/
return gus->joy_trim;
case 0x00: case 0x00:
case 0x01: case 0x01:
case 0x02: case 0x02:
@@ -867,10 +969,14 @@ gus_read(uint16_t addr, void *priv)
break; break;
case 0x306: case 0x306:
case 0x706: case 0x706:
if (gus->type == GUS_MAX) if (gus->type == GUS_CLASSIC_37)
val = 0x06; /* 3.7x - mixer, no reverse channels bug */
else if (gus->type == GUS_MAX)
val = 0x0a; /* GUS MAX */ val = 0x0a; /* GUS MAX */
else if (gus->type == GUS_ACE)
val = 0x30; /* GUS ACE */
else else
val = 0xff; /*Pre 3.7 - no mixer*/ val = 0xff; /* Pre 3.7 - no mixer */
break; break;
case 0x307: /*DRAM access*/ case 0x307: /*DRAM access*/
@@ -884,22 +990,24 @@ gus_read(uint16_t addr, void *priv)
return 0; return 0;
case 0x20b: case 0x20b:
switch (gus->reg_ctrl & 0x07) { if (gus->type > GUS_CLASSIC) {
case 1: switch (gus->reg_ctrl & 0x07) {
val = gus->gp1; case 1:
break; val = gus->gp1;
case 2: break;
val = gus->gp2; case 2:
break; val = gus->gp2;
case 3: break;
val = gus->gp1_addr; case 3:
break; val = gus->gp1_addr;
case 4: break;
val = gus->gp2_addr; case 4:
break; val = gus->gp2_addr;
break;
default: default:
break; break;
}
} }
break; break;
@@ -911,8 +1019,11 @@ gus_read(uint16_t addr, void *priv)
case 0x20e: case 0x20e:
return gus->sb_2xe; return gus->sb_2xe;
case 0x208:
case 0x388: case 0x388:
if ((gus->type == GUS_ACE) && !device_get_config_int("adlib_ports"))
break;
fallthrough;
case 0x208:
if (gus->tctrl & GUS_TIMER_CTRL_AUTO) if (gus->tctrl & GUS_TIMER_CTRL_AUTO)
val = gus->sb_2xa; val = gus->sb_2xa;
else { else {
@@ -927,10 +1038,12 @@ gus_read(uint16_t addr, void *priv)
#ifdef OLD_NMI_BEHAVIOR #ifdef OLD_NMI_BEHAVIOR
nmi = 0; nmi = 0;
#endif /* OLD_NMI_BEHAVIOR */ #endif /* OLD_NMI_BEHAVIOR */
fallthrough;
case 0x389:
val = gus->ad_data; val = gus->ad_data;
break; break;
case 0x389:
if ((gus->type != GUS_ACE) || device_get_config_int("adlib_ports"))
val = gus->ad_data;
break;
case 0x20A: case 0x20A:
val = gus->adcommand; val = gus->adcommand;
@@ -1164,6 +1277,58 @@ gus_poll_wave(void *priv)
gus_update_int_status(gus); gus_update_int_status(gus);
} }
void
gus_ics2101_filter(void *priv, int channel, double *out_l, double *out_r)
{
ics2101_t *ics2101 = (ics2101_t *) priv;
double temp_l = 0.0;
double temp_r = 0.0;
double master_l = 0.0;
double master_r = 0.0;
uint8_t ctrl_l = ics2101->channels[channel].ctrl[0];
uint8_t ctrl_r = ics2101->channels[channel].ctrl[1];
if (!(ctrl_l & 0xC)) { /* Normal mode */
if (ctrl_l & 1)
temp_l += *out_l * ics2101->channels[channel].level[0];
if (ctrl_l & 2)
temp_r += *out_l * ics2101->channels[channel].level[0];
if (ctrl_r & 1)
temp_l += *out_r * ics2101->channels[channel].level[1];
if (ctrl_r & 2)
temp_r += *out_r * ics2101->channels[channel].level[1];
} else { /* Stereo or Balance/Pan mode */
if (ctrl_l & 2) { /* Mono/Pan */
temp_l = (*out_l + *out_r) * 0.5 * ics2101->channels[channel].level[(ctrl_l & 1)];
temp_r = (*out_r + *out_l) * 0.5 * ics2101->channels[channel].level[!(ctrl_l & 1)];
} else { /* Stereo/Balance */
temp_l = ((ctrl_l & 1) ? *out_l : *out_r) * ics2101->channels[channel].level[(ctrl_l & 1)];
temp_r = ((ctrl_l & 1) ? *out_r : *out_l) * ics2101->channels[channel].level[!(ctrl_l & 1)];
}
}
/* Master */
ctrl_l = ics2101->channels[GUS_ICS2101_MASTER].ctrl[0];
ctrl_r = ics2101->channels[GUS_ICS2101_MASTER].ctrl[1];
if (!(ctrl_l & 0xC)) { /* Normal mode */
if (ctrl_l & 1)
master_l += temp_l * ics2101->channels[GUS_ICS2101_MASTER].level[0];
if (ctrl_l & 2)
master_r += temp_l * ics2101->channels[GUS_ICS2101_MASTER].level[0];
if (ctrl_r & 1)
master_l += temp_r * ics2101->channels[GUS_ICS2101_MASTER].level[1];
if (ctrl_r & 2)
master_r += temp_r * ics2101->channels[GUS_ICS2101_MASTER].level[1];
} else { /* Stereo or Balance mode - no mono/pan for master */
master_l = ((ctrl_l & 1) ? temp_l : temp_r) * ics2101->channels[GUS_ICS2101_MASTER].level[(ctrl_l & 1)];
master_r = ((ctrl_l & 1) ? temp_r : temp_l) * ics2101->channels[GUS_ICS2101_MASTER].level[!(ctrl_l & 1)];
}
*out_l = master_l;
*out_r = master_r;
}
static void static void
gus_get_buffer(int32_t *buffer, int len, void *priv) gus_get_buffer(int32_t *buffer, int len, void *priv)
{ {
@@ -1173,11 +1338,26 @@ gus_get_buffer(int32_t *buffer, int len, void *priv)
ad1848_update(&gus->ad1848); ad1848_update(&gus->ad1848);
gus_update(gus); gus_update(gus);
for (int c = 0; c < len * 2; c += 2) {
for (int c = 0; c < len * 2; c++) { double temp_l = 0.0;
if ((gus->type == GUS_MAX) && (gus->max_ctrl)) double temp_r = 0.0;
buffer[c] += (int32_t) (gus->ad1848.buffer[c] / 2); if ((gus->type == GUS_CLASSIC_37) || (gus->type == GUS_MAX)) {
buffer[c] += (int32_t) gus->buffer[c & 1][c >> 1]; temp_l = (double) gus->buffer[0][c >> 1];
temp_r = (double) gus->buffer[1][c >> 1];
if (gus->type == GUS_MAX) {
if (gus->max_ctrl) {
buffer[c] += (int32_t) (gus->ad1848.buffer[c] / 2);
buffer[c + 1] += (int32_t) (gus->ad1848.buffer[c + 1] / 2);
}
ad1848_filter_channel(&gus->ad1848, AD1848_AUX1, &temp_l, &temp_r);
} else
gus_ics2101_filter(&gus->ics2101, GUS_ICS2101_GF1_OUT, &temp_l, &temp_r);
buffer[c] += (int32_t) temp_l;
buffer[c + 1] += (int32_t) temp_r;
} else {
buffer[c] += (int32_t) gus->buffer[0][c >> 1];
buffer[c + 1] += (int32_t) gus->buffer[1][c >> 1];
}
} }
if ((gus->type == GUS_MAX) && (gus->max_ctrl)) if ((gus->type == GUS_MAX) && (gus->max_ctrl))
@@ -1186,6 +1366,17 @@ gus_get_buffer(int32_t *buffer, int len, void *priv)
gus->pos = 0; gus->pos = 0;
} }
void
gus_filter_cd_audio(int channel, double *buffer, void *priv)
{
const gus_t *gus = (gus_t *) priv;
/* FIXME: No channel remapping possible with the current architecture */
if (gus->ics2101.channels[GUS_ICS2101_CD_IN].ctrl[channel] && gus->ics2101.channels[GUS_ICS2101_MASTER].ctrl[channel])
*buffer *= gus->ics2101.channels[GUS_ICS2101_CD_IN].level[channel] * gus->ics2101.channels[GUS_ICS2101_MASTER].level[channel];
else
*buffer *= 0.0;
}
static void static void
gus_input_msg(void *priv, uint8_t *msg, uint32_t len) gus_input_msg(void *priv, uint8_t *msg, uint32_t len)
{ {
@@ -1292,6 +1483,7 @@ gus_reset(void *priv)
gus->sb_ctrl = 0; gus->sb_ctrl = 0;
gus->sb_nmi = 0; gus->sb_nmi = 0;
gus->joy_trim = 29;
gus->reg_ctrl = 0; gus->reg_ctrl = 0;
gus->ad_status = 0; gus->ad_status = 0;
@@ -1320,6 +1512,13 @@ gus_reset(void *priv)
gus->irq_state = 0; gus->irq_state = 0;
gus->midi_irq_state = 0; gus->midi_irq_state = 0;
for (int i = 0; i < GUS_ICS2101_MAX; i++) {
gus->ics2101.channels[i].level[0] = gus->ics2101.channels[i].level[1] = 1.0;
gus->ics2101.channels[i].ctrl[0] = 1;
gus->ics2101.channels[i].ctrl[1] = 2;
gus->ics2101.channels[i].pan = 7;
}
gus_update_int_status(gus); gus_update_int_status(gus);
} }
@@ -1328,6 +1527,7 @@ gus_init(UNUSED(const device_t *info))
{ {
int c; int c;
double out = 1.0; double out = 1.0;
double gain;
uint8_t gus_ram = device_get_config_int("gus_ram"); uint8_t gus_ram = device_get_config_int("gus_ram");
gus_t *gus = calloc(1, sizeof(gus_t)); gus_t *gus = calloc(1, sizeof(gus_t));
@@ -1355,15 +1555,46 @@ gus_init(UNUSED(const device_t *info))
gus->type = info->local; gus->type = info->local;
gus->jumper = 0x06;
for (int i = 0; i < GUS_ICS2101_MAX; i++) {
gus->ics2101.channels[i].level[0] = gus->ics2101.channels[i].level[1] = 1.0;
gus->ics2101.channels[i].ctrl[0] = 1;
gus->ics2101.channels[i].ctrl[1] = 2;
gus->ics2101.channels[i].pan = 7;
}
gus->base = device_get_config_hex16("base"); gus->base = device_get_config_hex16("base");
io_sethandler(gus->base, 0x0010, gus_read, NULL, NULL, gus_write, NULL, NULL, gus); io_sethandler(gus->base, 0x0010, gus_read, NULL, NULL, gus_write, NULL, NULL, gus);
io_sethandler(0x0100 + gus->base, 0x0010, gus_read, NULL, NULL, gus_write, NULL, NULL, gus); if (gus->type != GUS_ACE)
io_sethandler(0x0100 + gus->base, 0x0002, gus_read, NULL, NULL, gus_write, NULL, NULL, gus);
io_sethandler(0x0102 + gus->base, 0x000e, gus_read, NULL, NULL, gus_write, NULL, NULL, gus);
io_sethandler(0x0506 + gus->base, 0x0001, gus_read, NULL, NULL, gus_write, NULL, NULL, gus); io_sethandler(0x0506 + gus->base, 0x0001, gus_read, NULL, NULL, gus_write, NULL, NULL, gus);
io_sethandler(0x0388, 0x0002, gus_read, NULL, NULL, gus_write, NULL, NULL, gus); io_sethandler(0x0388, 0x0002, gus_read, NULL, NULL, gus_write, NULL, NULL, gus);
if (gus->type == GUS_CLASSIC && device_get_config_int("gameport"))
gus->gameport = gameport_add(&gameport_201_device);
else if (gus->type != GUS_ACE) {
gus->gameport = gameport_add(&gameport_pnp_1io_device);
gameport_remap(gus->gameport, 0x201);
}
if (gus->type == GUS_CLASSIC_37) {
/* Precalculate the attenuation table for ICS2101 */
for (int i = 0; i < 128; i++) {
gain = (127 - i) * -0.5;
if (i < 16)
for (int j = 0; j < (16 - i); j++)
gain += -0.5 - 0.13603 * (j + 1);
ics2101_att[i] = pow(10.0, gain / 20.0);
}
sound_set_cd_audio_filter(gus_filter_cd_audio, gus);
}
if (gus->type == GUS_MAX) { if (gus->type == GUS_MAX) {
ad1848_init(&gus->ad1848, AD1848_TYPE_CS4231); ad1848_init(&gus->ad1848, AD1848_TYPE_CS4231);
ad1848_set_cd_audio_channel(&gus->ad1848, AD1848_AUX2);
ad1848_setirq(&gus->ad1848, 5); ad1848_setirq(&gus->ad1848, 5);
ad1848_setdma(&gus->ad1848, 3); ad1848_setdma(&gus->ad1848, 3);
io_sethandler(0x10C + gus->base, 4, io_sethandler(0x10C + gus->base, 4,
@@ -1376,7 +1607,7 @@ gus_init(UNUSED(const device_t *info))
sound_add_handler(gus_get_buffer, gus); sound_add_handler(gus_get_buffer, gus);
if (device_get_config_int("receive_input")) if ((gus->type != GUS_ACE) && (device_get_config_int("receive_input")))
midi_in_handler(1, gus_input_msg, gus_input_sysex, gus); midi_in_handler(1, gus_input_msg, gus_input_sysex, gus);
return gus; return gus;
@@ -1442,6 +1673,17 @@ static const device_config_t gus_config[] = {
}, },
.bios = { { 0 } } .bios = { { 0 } }
}, },
{
.name = "gameport",
.description = "Enable Game port",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ {
.name = "receive_input", .name = "receive_input",
.description = "Receive MIDI input", .description = "Receive MIDI input",
@@ -1457,6 +1699,160 @@ static const device_config_t gus_config[] = {
// clang-format off // clang-format off
}; };
static const device_config_t gus_v37_config[] = {
// clang-format off
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0x220,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "210H", .value = 0x210 },
{ .description = "220H", .value = 0x220 },
{ .description = "230H", .value = 0x230 },
{ .description = "240H", .value = 0x240 },
{ .description = "250H", .value = 0x250 },
{ .description = "260H", .value = 0x260 },
{ NULL }
},
.bios = { { 0 } }
},
{
.name = "gus_ram",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "256 KB", .value = 0 },
{ .description = "512 KB", .value = 1 },
{ .description = "1 MB", .value = 2 },
{ NULL }
},
.bios = { { 0 } }
},
{
.name = "receive_input",
.description = "Receive MIDI input",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 1,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format off
};
static const device_config_t gus_max_config[] = {
// clang-format off
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0x220,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "210H", .value = 0x210 },
{ .description = "220H", .value = 0x220 },
{ .description = "230H", .value = 0x230 },
{ .description = "240H", .value = 0x240 },
{ .description = "250H", .value = 0x250 },
{ .description = "260H", .value = 0x260 },
{ NULL }
},
.bios = { { 0 } }
},
{
.name = "gus_ram",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 1,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "512 KB", .value = 1 },
{ .description = "1 MB", .value = 2 },
{ NULL }
},
.bios = { { 0 } }
},
{
.name = "receive_input",
.description = "Receive MIDI input",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 1,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format off
};
static const device_config_t gus_ace_config[] = {
// clang-format off
{
.name = "base",
.description = "Address",
.type = CONFIG_HEX16,
.default_string = NULL,
.default_int = 0x260,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "210H", .value = 0x210 },
{ .description = "220H", .value = 0x220 },
{ .description = "230H", .value = 0x230 },
{ .description = "240H", .value = 0x240 },
{ .description = "250H", .value = 0x250 },
{ .description = "260H", .value = 0x260 },
{ NULL }
},
.bios = { { 0 } }
},
{
.name = "gus_ram",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 1,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "512 KB", .value = 1 },
{ .description = "1 MB", .value = 2 },
{ NULL }
},
.bios = { { 0 } }
},
{
.name = "adlib_ports",
.description = "Enable Adlib ports",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format off
};
const device_t gus_device = { const device_t gus_device = {
.name = "Gravis UltraSound", .name = "Gravis UltraSound",
.internal_name = "gus", .internal_name = "gus",
@@ -1471,6 +1867,20 @@ const device_t gus_device = {
.config = gus_config .config = gus_config
}; };
const device_t gus_v37_device = {
.name = "Gravis UltraSound (rev 3.7)",
.internal_name = "gusv37",
.flags = DEVICE_ISA16,
.local = GUS_CLASSIC_37,
.init = gus_init,
.close = gus_close,
.reset = gus_reset,
.available = NULL,
.speed_changed = gus_speed_changed,
.force_redraw = NULL,
.config = gus_v37_config
};
const device_t gus_max_device = { const device_t gus_max_device = {
.name = "Gravis UltraSound MAX", .name = "Gravis UltraSound MAX",
.internal_name = "gusmax", .internal_name = "gusmax",
@@ -1482,5 +1892,19 @@ const device_t gus_max_device = {
.available = NULL, .available = NULL,
.speed_changed = gus_speed_changed, .speed_changed = gus_speed_changed,
.force_redraw = NULL, .force_redraw = NULL,
.config = gus_config .config = gus_max_config
};
const device_t gus_ace_device = {
.name = "Gravis UltraSound ACE",
.internal_name = "gusace",
.flags = DEVICE_ISA16,
.local = GUS_ACE,
.init = gus_init,
.close = gus_close,
.reset = gus_reset,
.available = NULL,
.speed_changed = gus_speed_changed,
.force_redraw = NULL,
.config = gus_ace_config
}; };

View File

@@ -85,7 +85,7 @@ optimc_filter_opl(void *priv, double *out_l, double *out_r)
if (optimc->cur_wss_enabled) { if (optimc->cur_wss_enabled) {
*out_l /= optimc->sb->mixer_sbpro.fm_l; *out_l /= optimc->sb->mixer_sbpro.fm_l;
*out_r /= optimc->sb->mixer_sbpro.fm_r; *out_r /= optimc->sb->mixer_sbpro.fm_r;
ad1848_filter_aux2((void *) &optimc->ad1848, out_l, out_r); ad1848_filter_channel((void *) &optimc->ad1848, AD1848_AUX2, out_l, out_r);
} }
} }
@@ -380,6 +380,7 @@ optimc_init(const device_t *info)
else else
ad1848_init(&optimc->ad1848, AD1848_TYPE_DEFAULT); ad1848_init(&optimc->ad1848, AD1848_TYPE_DEFAULT);
ad1848_set_cd_audio_channel(&optimc->ad1848, (info->local & 0x100) ? AD1848_LINE_IN : AD1848_AUX1);
ad1848_setirq(&optimc->ad1848, optimc->cur_wss_irq); ad1848_setirq(&optimc->ad1848, optimc->cur_wss_irq);
ad1848_setdma(&optimc->ad1848, optimc->cur_wss_dma); ad1848_setdma(&optimc->ad1848, optimc->cur_wss_dma);

View File

@@ -138,7 +138,9 @@ static const SOUND_CARD sound_cards[] = {
{ &cs4235_device }, { &cs4235_device },
{ &cs4236b_device }, { &cs4236b_device },
{ &gus_device }, { &gus_device },
{ &gus_v37_device },
{ &gus_max_device }, { &gus_max_device },
{ &gus_ace_device },
{ &mirosound_pcm10_device }, { &mirosound_pcm10_device },
{ &pas16_device }, { &pas16_device },
{ &pas16d_device }, { &pas16d_device },