diff --git a/src/include/86box/snd_sb.h b/src/include/86box/snd_sb.h index 394b1b249..a5783d010 100644 --- a/src/include/86box/snd_sb.h +++ b/src/include/86box/snd_sb.h @@ -15,7 +15,7 @@ * * Copyright 2008-2018 Sarah Walker. * Copyright 2016-2018 Miran Grca. - * Copyright 2024-2025 Jasmine Iwanek. + * Copyright 2024-2026 Jasmine Iwanek. */ #ifndef SOUND_SND_SB_H #define SOUND_SND_SB_H diff --git a/src/include/86box/snd_sb_dsp.h b/src/include/86box/snd_sb_dsp.h index b73508211..6e4df0eb1 100644 --- a/src/include/86box/snd_sb_dsp.h +++ b/src/include/86box/snd_sb_dsp.h @@ -9,9 +9,9 @@ #define SB_SUBTYPE_CLONE_AZT1605_0X0C 2 /* Aztech Sound Galaxy Nova 16 Extra / Packard Bell Forte 16, DSP 2.1 - SBPRO2 clone */ #define SB_SUBTYPE_CLONE_AZTPR16_0X09 3 /* Aztech Sound Galaxy Pro 16 Extra */ -#define SB_SUBTYPE_ESS_ES688 4 /* ESS Technology ES688 */ -#define SB_SUBTYPE_ESS_ES1688 5 /* ESS Technology ES1688 */ -#define SB_SUBTYPE_MVD201 6 /* Mediavision MVD201, found on the thunderboard and PAS16 */ +#define SB_SUBTYPE_MVD201 4 /* Mediavision MVD201, found on the thunderboard and PAS16 */ +#define SB_SUBTYPE_ESS_ES688 5 /* ESS Technology ES688 */ +#define SB_SUBTYPE_ESS_ES1688 6 /* ESS Technology ES1688 */ /* ESS-related */ #define IS_ESS(dsp) ((dsp)->sb_subtype >= SB_SUBTYPE_ESS_ES688) /* Check for future ESS cards here */ @@ -21,6 +21,9 @@ #define IS_AZTECH(dsp) ((dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT2316A_0X11 || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZT1605_0X0C || (dsp)->sb_subtype == SB_SUBTYPE_CLONE_AZTPR16_0X09) /* check for future AZT cards here */ #define AZTECH_EEPROM_SIZE 36 +/* MediaVision related */ +#define IS_MV201(dsp) ((dsp)->sb_subtype >= SB_SUBTYPE_MVD201) + typedef struct sb_dsp_t { int sb_type; int sb_subtype; /* which clone */ @@ -103,6 +106,7 @@ typedef struct sb_dsp_t { int sbreset; uint8_t sbreaddat; uint8_t sb_command; + uint8_t sb_last_command; uint8_t sb_test; int sb_timei; int sb_timeo; diff --git a/src/include/86box/sound.h b/src/include/86box/sound.h index d83d00a24..b69785353 100644 --- a/src/include/86box/sound.h +++ b/src/include/86box/sound.h @@ -228,6 +228,9 @@ extern const device_t entertainer_device; /* Mindscape Music Board */ extern const device_t mmb_device; +/* MediaVision ThunderBoard */ +extern const device_t thunderboard_device; + /* OPTi 82c93x */ extern const device_t acermagic_s20_device; extern const device_t mirosound_pcm10_device; diff --git a/src/sound/snd_sb.c b/src/sound/snd_sb.c index de9b71f9b..20f8b5694 100644 --- a/src/sound/snd_sb.c +++ b/src/sound/snd_sb.c @@ -15,7 +15,7 @@ * * Copyright 2008-2020 Sarah Walker. * Copyright 2016-2020 Miran Grca. - * Copyright 2024-2025 Jasmine Iwanek. + * Copyright 2024-2026 Jasmine Iwanek. */ #include #include @@ -45,9 +45,10 @@ #include <86box/plat_unused.h> #include <86box/snd_azt2316a.h> -#define SB_1 0 -#define SB_15 1 -#define SB_2 2 +#define SB_1 0 +#define SB_15 1 +#define SB_2 2 +#define THUNDERBOARD 3 #define SB_16_PNP_NOIDE 0 #define SB_16_PNP_IDE 1 @@ -2959,6 +2960,10 @@ sb_init(UNUSED(const device_t *info)) sb->cms_enabled = device_get_config_int("cms"); mixer_addr = device_get_config_int("mixaddr"); break; + case THUNDERBOARD: + model = SB_DSP_200; + sb->cms_enabled = 0; + break; } sb->opl_enabled = device_get_config_int("opl"); @@ -3006,7 +3011,7 @@ sb_init(UNUSED(const device_t *info)) &sb->cms); } - if (mixer_addr > 0x000) { + if (mixer_addr > 0x0000) { sb->mixer_enabled = 1; io_sethandler(mixer_addr + 4, 0x0002, sb_ct1335_mixer_read, NULL, NULL, @@ -3026,6 +3031,58 @@ sb_init(UNUSED(const device_t *info)) return sb; } +void * +thunderboard_init(UNUSED(const device_t *info)) +{ + /* ThunderBoard port mappings, 210h to 260h in 10h steps + 2x6, 2xA, 2xC, 2xE -> DSP chip */ + sb_t *sb = calloc(1, sizeof(sb_t)); + const uint16_t addr = device_get_config_hex16("base"); + + sb->opl_enabled = device_get_config_int("opl"); + if (sb->opl_enabled) + fm_driver_get(FM_YM3812, &sb->opl); + + sb_dsp_set_real_opl(&sb->dsp, 0); + sb_dsp_init(&sb->dsp, SB_DSP_200, SB_SUBTYPE_MVD201, sb); + /* DSP I/O handler is activated in sb_dsp_setaddr */ + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, 1); + + if (device_get_config_int("gameport")) { + sb->gameport = gameport_add(&gameport_device); + sb->gameport_addr = 0x200; + gameport_remap(sb->gameport, sb->gameport_addr); + } + + /* DSP I/O handler is activated in sb_dsp_setaddr */ + if (sb->opl_enabled) { + io_sethandler(addr, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(addr + 8, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + io_sethandler(0x0388, 0x0002, + sb->opl.read, NULL, NULL, + sb->opl.write, NULL, NULL, + sb->opl.priv); + } + + + sb->cms_enabled = 0; + sb->mixer_enabled = 0; + sound_add_handler(sb_get_buffer_sb2, sb); + if (sb->opl_enabled) + music_add_handler(sb_get_music_buffer_sb2, sb); + sound_set_cd_audio_filter(sb2_filter_cd_audio, sb); + + return sb; +} + void * sb_mcv_init(UNUSED(const device_t *info)) { @@ -4288,6 +4345,68 @@ static const device_config_t sb_config[] = { { .name = "", .description = "", .type = CONFIG_END } }; +static const device_config_t thunderboard_config[] = { + { + .name = "base", + .description = "Address", + .type = CONFIG_HEX16, + .default_string = NULL, + .default_int = 0x220, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "0x210", .value = 0x210 }, + { .description = "0x220", .value = 0x220 }, + { .description = "0x230", .value = 0x230 }, + { .description = "0x240", .value = 0x240 }, + { .description = "0x250", .value = 0x250 }, + { .description = "0x260", .value = 0x260 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = 7, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "IRQ 2", .value = 2 }, + { .description = "IRQ 3", .value = 3 }, + { .description = "IRQ 5", .value = 5 }, + { .description = "IRQ 7", .value = 7 }, + { .description = "" } + }, + .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 = "opl", + .description = "Enable OPL", + .type = CONFIG_BINARY, + .default_string = NULL, + .default_int = 1, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +}; + static const device_config_t sb15_config[] = { { .name = "base", @@ -5576,6 +5695,20 @@ static const device_config_t ess_1688_pnp_config[] = { }; // clang-format on +const device_t thunderboard_device = { + .name = "MediaVision ThunderBoard", + .internal_name = "thunderboard", + .flags = DEVICE_ISA, + .local = THUNDERBOARD, + .init = thunderboard_init, + .close = sb_close, + .reset = NULL, + .available = NULL, + .speed_changed = sb_speed_changed, + .force_redraw = NULL, + .config = thunderboard_config +}; + const device_t sb_1_device = { .name = "Sound Blaster v1.0", .internal_name = "sb", diff --git a/src/sound/snd_sb_dsp.c b/src/sound/snd_sb_dsp.c index 275c90576..c0ff417b3 100644 --- a/src/sound/snd_sb_dsp.c +++ b/src/sound/snd_sb_dsp.c @@ -1732,6 +1732,18 @@ sb_exec_command(sb_dsp_t *dsp) sb_add_data(dsp, ~dsp->sb_data[0]); break; case 0xE1: /* Get DSP version */ + if (IS_MV201(dsp)) { + if (dsp->sb_last_command == 0xE1) { + sb_add_data(dsp, 0x01); + sb_add_data(dsp, 0x30); + dsp->sb_last_command = 0x00; + } else { + sb_add_data(dsp, 0x02); + sb_add_data(dsp, 0x00); + dsp->sb_last_command = 0xE1; + } + break; + } if (IS_ESS(dsp)) { /* 0x03 0x01 (Sound Blaster Pro compatibility) confirmed by both the diff --git a/src/sound/sound.c b/src/sound/sound.c index c7aefc746..af2f958a9 100644 --- a/src/sound/sound.c +++ b/src/sound/sound.c @@ -126,6 +126,7 @@ static const SOUND_CARD sound_cards[] = { #ifdef USE_LIBSERIALPORT /*The following devices required LIBSERIALPORT*/ { &opl2board_device }, #endif + { &thunderboard_device }, { &pasplus_device }, { &sb_1_device }, { &sb_15_device },