From 4bf563147280042f63945a19aef1323df5df4e03 Mon Sep 17 00:00:00 2001 From: wbcbz7 Date: Sun, 22 Mar 2026 00:56:38 +0700 Subject: [PATCH] SB: finalize IRQ/DMA/options settings --- common/picogus.h | 4 +- pgusinit/README.md | 19 ++++ pgusinit/pgusinit.c | 209 ++++++++++++++++++++++++++++++------- pgusinit/pgusinit.h | 4 +- sw/CMakeLists.txt | 2 +- sw/picogus.cpp | 40 +++---- sw/sbdsp/sbdsp.cpp | 51 +++++---- sw/sbdsp/sbdsp.h | 31 +----- sw/sbplay.cpp | 6 +- sw/system/flash_settings.c | 12 +++ sw/system/flash_settings.h | 14 ++- 11 files changed, 284 insertions(+), 108 deletions(-) diff --git a/common/picogus.h b/common/picogus.h index b874baa..8dbdd26 100644 --- a/common/picogus.h +++ b/common/picogus.h @@ -68,10 +68,10 @@ static const char *modenames[8] = { #define CMD_MPUFAKE 0x22 // MPU fake all notes off #define CMD_OPLWAIT 0x30 // Adlib speed sensitive fix -#define CMD_SBOPTS 0x30 // SB options (mixer lock, time constant fix, etc.) - aliased to CMD_OPLWAIT -#define CMD_SBDSPVER 0x31 // SB DSP version +#define CMD_SBTYPE 0x31 // SB type #define CMD_SBIRQ 0x32 // SB IRQ #define CMD_SBDMA 0x33 // SB DMA +#define CMD_SBOPTS 0x34 // SB options (mixer lock, time constant fix, etc.) #define CMD_MOUSEPORT 0x40 // Mouse Base port #define CMD_MOUSEPROTO 0x41 // Mouse protocol diff --git a/pgusinit/README.md b/pgusinit/README.md index cc37e73..7fc941f 100644 --- a/pgusinit/README.md +++ b/pgusinit/README.md @@ -86,11 +86,30 @@ https://github.com/polpo/picogus/wiki/Compatibility-list ### Sound Blaster/AdLib options +Sound Blaster emulation requires the BLASTER variable to be set, in the format: + +`set BLASTER=A220 I5 D1 H1 T6`, where 220 is the PicoGUS's SB emulation port, +5 is the IRQ, 1 is the DMA, 6 is the emulated SB type (see `/sbtype` option) + * `/sbport x` - sets the base port of the Sound Blaster. Defaults to 220. +* `/sbirq x` - sets the IRQ of the Sound Blaster. Must match jumper settings. +* `/sbdma x` - sets the DMA of the Sound Blaster. Must match jumper settings. +* `/sbtype x` - sets the Sound Blaster type: Allowed values are: + 1 - SB 1.x, 2 - SB Pro 1 (dual OPL2), 3 - SB 2.0 + 4 - SB Pro 2 (OPL3), 6 - SB 16 * `/oplport x` - sets the base port of the OPL/AdLib. Defaults to 388. * `/oplwait` - wait on OPL2 data write. Can fix speed-sensitive early AdLib games on fast systems (example: 688 Attack Sub). +* `/sbvol x` - sets the volume of the SB PCM output to x percent. * `/oplvol x` - sets the volume of the OPL2 output to x percent. +* `/sbfixtc 1|0 ` - fix SB time constant for 11/22/44 kHz sample rate. Can fix + PCM audio slightly pitched up or down in pre-SB16 games and applications. + Note than certain programs are already aware of SB time constant inaccuracy + and will sound wrong if this option is enabled. Default = 0 (disabled) +* `/sblockmixer n` - lock writes to SB mixer settings. Choices: + 0 - write lock disabled (default) + 1 - lock all but Voice Volume registers (for panning effects e.g. in Wolf3D) + 2 - lock all registers ### MPU-401 options diff --git a/pgusinit/pgusinit.c b/pgusinit/pgusinit.c index a994728..3522dec 100755 --- a/pgusinit/pgusinit.c +++ b/pgusinit/pgusinit.c @@ -107,8 +107,16 @@ static void usage(card_mode_t mode, bool print_all) if (mode == SB_MODE || print_all) { // "...............................................................................\n" pageprintf("Sound Blaster settings:\n"); - pageprintf(" /sbport x - set the base port of the Sound Blaster. Default: 220\n"); - pageprintf(" /sbvol x - set the Sound Blaster audio volume: 0 - 100%\n"); + pageprintf(" /sbport x - set the base port of the Sound Blaster. Default: 220\n"); + pageprintf(" /sbirq x - set the SB IRQ (must match jumper settings!). Default: 5\n"); + pageprintf(" /sbdma x - set the SB DMA (must match jumper settings!). Default: 1\n"); + pageprintf(" /sbtype x - set the Sound Blaster type. Default: 6 (SB 16)\n"); + pageprintf(" 1 - SB 1.x, 2 - SB Pro 1 (dual OPL2), 3 - SB 2.0,\n"); + pageprintf(" 4 - SB Pro 2 (OPL3), 6 - SB 16\n"); + pageprintf(" /sbvol x - set the Sound Blaster audio volume: 0 - 100%\n"); + pageprintf(" /sbfixtc 1|0 - fix SB time constant to match common rates. Default: 0\n"); + pageprintf(" /sblockmixer n - lock SB mixer settings. Default: 0 (no lock)\n"); + pageprintf(" 0 - no lock, 1 - lock all but Voice Volume, 2 - lock all\n"); } if (mode == SB_MODE || mode == ADLIB_MODE || print_all) { pageprintf("AdLib settings:\n"); @@ -176,11 +184,19 @@ static void err_blaster(void) // "................................................................................\n" fprintf(stderr, "ERROR: In SB mode but no BLASTER variable set or is malformed!\n"); fprintf(stderr, "The BLASTER environment variable must be set in the following format:\n"); - fprintf(stderr, "\tset BLASTER=Axxx Iy Dz T3\n"); - fprintf(stderr, "Where xxx = port, y = IRQ, z = DMA. T3 indicates an SB 2.0 compatible card.\n"); - fprintf(stderr, "Port is set via /sbport xxx option; DMA and IRQ configued via jumper.\n"); + fprintf(stderr, "\tset BLASTER=Axxx Iy Dz Hz Tw\n"); + fprintf(stderr, "Where xxx = port, y = IRQ, z = DMA. w = SB type:\n"); + fprintf(stderr, " 1 - SB 1.x, 2 - SB Pro 1 (dual OPL2), 3 - SB 2.0,\n"); + fprintf(stderr, " 4 - SB Pro 2 (OPL3), 6 - SB 16\n"); + fprintf(stderr, "Port is set via /sbport xxx option; DMA and IRQ configued via jumper then also\n"); + fprintf(stderr, "set via /sbirq y and /sbdma y options.\n"); } +static void err_blaster16_dma_mismatch(void) +{ + // "................................................................................\n" + fprintf(stderr, "ERROR: In SB 16 mode, low (Dx) and high (Hx) DMA in BLASTER variable must match!\n"); +} static void err_pigus(void) { @@ -247,17 +263,33 @@ static int init_gus(void) static int init_sb(void) { + // SB DSP version table + const uint16_t dspver[] = {0, 0x105, 0x300, 0x201, 0x301, 0, 0x405}; + char* blaster = getenv("BLASTER"); if (blaster == NULL) { err_blaster(); return 1; } + char blasterTemp[256]; + strncpy(blasterTemp, blaster, sizeof(blasterTemp)); // Parse BLASTER - uint16_t port; - int e; - e = sscanf(blaster, "A%hx I%*hhu D%*hhu T3", &port); - if (e != 1) { + char* p = strtok(blasterTemp, " "); + uint16_t port = -1, irq = -1, dma8 = -1, dma16 = -1, sbtype = 0; + while (p != NULL) { + switch (*p) { + case 'a': case 'A': port = strtol(p + 1, NULL, 16); break; + case 'i': case 'I': irq = strtol(p + 1, NULL, 10); break; + case 'd': case 'D': dma8 = strtol(p + 1, NULL, 10); break; + case 'h': case 'H': dma16 = strtol(p + 1, NULL, 10); break; + case 't': case 'T': sbtype = strtol(p + 1, NULL, 10); break; + default: break; + } + p = strtok(NULL, " "); + } + + if ((port == -1) || (irq == -1) || (dma8 == -1) || (sbtype > 6) || (dspver[sbtype] == 0) || ((sbtype == 6) && (dma8 != dma16))) { err_blaster(); return 2; } @@ -268,6 +300,28 @@ static int init_sb(void) err_blaster(); return 2; } + + outp(CONTROL_PORT, CMD_SBIRQ); // Select IRQ register + uint8_t tmp_irq = inp(DATA_PORT_HIGH); + if (irq != tmp_irq) { + err_blaster(); + return 2; + } + + outp(CONTROL_PORT, CMD_SBDMA); // Select DMA register + uint8_t tmp_dma = inp(DATA_PORT_HIGH); + if (dma8 != tmp_dma) { + err_blaster(); + return 2; + } + + outp(CONTROL_PORT, CMD_SBTYPE); // Select SB type register + uint8_t tmp_type = inp(DATA_PORT_HIGH); + if (sbtype != tmp_type) { + err_blaster(); + return 2; + } + return 0; } @@ -630,13 +684,13 @@ static void send_string(const uint8_t cmd, const char* str, const int16_t max_le outp(DATA_PORT_HIGH, 0); } -static bool cmdDisplayUsage(const char* arg, const int print_all) +static bool cmdDisplayUsage(const char* arg, const int print_all, const int cmd2, const int cmd3) { usage(gMode, print_all); return true; } -static bool cmdSendBool(const char* arg, const int cmd) +static bool cmdSendBool(const char* arg, const int cmd, const int cmd2, const int cmd3) { uint8_t value; @@ -654,7 +708,27 @@ static bool cmdSendBool(const char* arg, const int cmd) return true; } -static bool cmdSetMode(const char* arg, const int cmd) +static bool cmdSendBoolMasked(const char* arg, const int cmd, const int mask, const int shift) +{ + uint8_t value, oldvalue; + + if (!strcmp(arg, "1") || !stricmp(arg, "true") || !stricmp(arg, "on")) { + value = 1; + } else if (!strcmp(arg, "0") || !stricmp(arg, "false") || !stricmp(arg, "off")) { + value = 0; + } else { + usage(gMode, false); + return false; + } + + outp(CONTROL_PORT, cmd); + oldvalue = inp(DATA_PORT_HIGH); + outp(DATA_PORT_HIGH, (uint8_t)(oldvalue & ~mask) | ((value << shift) & mask)); + return true; +} + + +static bool cmdSetMode(const char* arg, const int cmd, const int cmd2, const int cmd3) { if (!stricmp(arg, "TANDY") || !stricmp(arg, "CMS")) { // Backwards compatibility for old tandy and cms modes @@ -687,11 +761,47 @@ static bool ctrlSendUint8(const char *arg, int cmd, int min, int max) return true; } -static bool cmdSendUint8(const char* arg, const int cmd) +static bool ctrlSendUint8Masked(const char *arg, int cmd, int min, int max, int mask, int shift) { + char* endptr; + uint8_t val = (uint8_t)strtoul(arg, &endptr, 10); + uint8_t oldval = 0; + + if (*endptr != '\0' || val < min || val > max) { + usage(gMode, false); + return false; + } + + outp(CONTROL_PORT, cmd); + oldval = inp(DATA_PORT_HIGH); + outp(DATA_PORT_HIGH, (uint8_t)(oldval & ~mask) | ((val << shift) & mask)); + return true; +} + +static bool cmdSendUint8(const char* arg, const int cmd, const int cmd2, const int cmd3) { return ctrlSendUint8(arg, cmd, 0, 255); } +static bool cmdSendSBType(const char* arg, const int cmd, const int cmd2, const int cmd3) { + char* endptr; + uint8_t val = (uint8_t)strtoul(arg, &endptr, 10); + + if (*endptr != '\0' || val < 1 || val > 6 || val == 5) { + usage(gMode, false); + return false; + } + + outp(CONTROL_PORT, cmd); + outp(DATA_PORT_HIGH, (uint8_t)val); + return true; +} + +static bool cmdSendUint8Masked(const char* arg, const int cmd, const int cmd2, const int cmd3) +{ + // cmd2 - mask, cmd3 - shift + return ctrlSendUint8Masked(arg, cmd, 0, 255, cmd2, cmd3); +} + static bool ctrlSendUint16(const char *arg, int cmd, long min, long max, int base) { char *endptr; @@ -707,27 +817,27 @@ static bool ctrlSendUint16(const char *arg, int cmd, long min, long max, int bas return true; } -static bool cmdSendUint16(const char* arg, const int cmd) +static bool cmdSendUint16(const char* arg, const int cmd, const int cmd2, const int cmd3) { return ctrlSendUint16(arg, cmd, 0, 65535, 10); } -static bool cmdSendPort(const char* arg, const int cmd) +static bool cmdSendPort(const char* arg, const int cmd, const int cmd2, const int cmd3) { return ctrlSendUint16(arg, cmd, 0, 0x3FF, 16); } -static bool cmdDefaults(const char* arg, const int cmd) +static bool cmdDefaults(const char* arg, const int cmd, const int cmd2, const int cmd3) { - return cmdSendUint8(CMD_DEFAULTS, 0xff); + return cmdSendUint8(CMD_DEFAULTS, 0xff, 0, 0); } -static bool cmdSetVol(const char* arg, const int cmd) +static bool cmdSetVol(const char* arg, const int cmd, const int cmd2, const int cmd3) { return ctrlSendUint8(arg, cmd, 0, 100); } -static bool cmdSendMousePort(const char *arg, const int cmd) +static bool cmdSendMousePort(const char *arg, const int cmd, const int cmd2, const int cmd3) { char* endptr; uint8_t val = (uint8_t)strtoul(arg, &endptr, 10); @@ -753,66 +863,71 @@ static bool cmdSendMousePort(const char *arg, const int cmd) return true; } -static bool cmdSendMouseSen(const char* arg, const int cmd) +static bool cmdSendMouseSen(const char* arg, const int cmd, const int cmd2, const int cmd3) { return ctrlSendUint16(arg, cmd, 0, 1024, 10); } -static bool cmdSendMouseProto(const char* arg, const int cmd) +static bool cmdSendMouseProto(const char* arg, const int cmd, const int cmd2, const int cmd3) { return ctrlSendUint8(arg, cmd, 0, 3); } -static bool cmdSendMouseRate(const char* arg, const int cmd) +static bool cmdSendMouseRate(const char* arg, const int cmd, const int cmd2, const int cmd3) { return ctrlSendUint8(arg, cmd, 20, 200); } -static bool cmdWifiStatus(const char* arg, const int cmd) +static bool cmdSendSBLockMixer(const char* arg, const int cmd, const int cmd2, const int cmd3) +{ + return ctrlSendUint8Masked(arg, cmd, 0, 2, (2 << 1), 1); +} + +static bool cmdWifiStatus(const char* arg, const int cmd, const int cmd2, const int cmd3) { wifi_printStatus(); exit(0); } -static bool cmdWifiSSID(const char* arg, const int cmd) +static bool cmdWifiSSID(const char* arg, const int cmd, const int cmd2, const int cmd3) { wifichg = true; send_string(cmd, arg, 32); return true; } -static bool cmdWifiPass(const char* arg, const int cmd) +static bool cmdWifiPass(const char* arg, const int cmd, const int cmd2, const int cmd3) { wifichg = true; send_string(cmd, arg, 63); return true; } -static bool cmdWifiNoPass(const char* arg, const int cmd) +static bool cmdWifiNoPass(const char* arg, const int cmd, const int cmd2, const int cmd3) { wifichg = true; send_string(cmd, "", 1); return true; } -static bool cmdCDLoadName(const char* arg, const int cmd) +static bool cmdCDLoadName(const char* arg, const int cmd, const int cmd2, const int cmd3) { send_string(cmd, arg, 127); exit(wait_for_cd_load()); } -static bool cmdCDList(const char* arg, const int cmd) +static bool cmdCDList(const char* arg, const int cmd, const int cmd2, const int cmd3) { exit(print_cdimage_list()); } -static bool cmdCDLoad(const char* arg, const int cmd) +static bool cmdCDLoad(const char* arg, const int cmd, const int cmd2, const int cmd3) { ctrlSendUint8(arg, cmd, 0, 255); exit(wait_for_cd_load()); } -static bool cmdGUSBuffer(const char* arg, const int cmd) +static bool cmdGUSBuffer(const char* arg, const int cmd, const int cmd2, const int cmd3) { uint8_t tmp_uint8; uint8_t e = sscanf(arg, "%hhu", &tmp_uint8); @@ -826,7 +941,7 @@ static bool cmdGUSBuffer(const char* arg, const int cmd) return true; } -static bool cmdFlashPico(const char* arg, const int cmd) +static bool cmdFlashPico(const char* arg, const int cmd, const int cmd2, const int cmd3) { if (strlen(arg) > 255) { @@ -837,7 +952,7 @@ static bool cmdFlashPico(const char* arg, const int cmd) return true; } -static bool cmdSave(const char* arg, const int cmd) +static bool cmdSave(const char* arg, const int cmd, const int cmd2, const int cmd3) { permanent = true; return true; @@ -868,6 +983,11 @@ ParseCommand parseCommands[] = { {"/gusdma", cmdSendUint8, CMD_GUSDMA, ARG_REQUIRE, "0"}, {"/gusport", cmdSendPort, CMD_GUSPORT, ARG_REQUIRE, "240"}, {"/sbport", cmdSendPort, CMD_SBPORT, ARG_REQUIRE, "220"}, + {"/sbirq", cmdSendUint8, CMD_SBIRQ, ARG_REQUIRE, "5"}, + {"/sbdma", cmdSendUint8, CMD_SBDMA, ARG_REQUIRE, "1"}, + {"/sbtype", cmdSendSBType, CMD_SBTYPE, ARG_REQUIRE, "6"}, + {"/sbfixtc", cmdSendBoolMasked, CMD_SBOPTS, ARG_REQUIRE, "0", (1 << 0), 0}, + {"/sblockmixer", cmdSendSBLockMixer, CMD_SBOPTS, ARG_REQUIRE, "0"}, {"/oplport", cmdSendPort, CMD_OPLPORT, ARG_REQUIRE, "388"}, {"/oplwait", cmdSendBool, CMD_OPLWAIT, ARG_REQUIRE, "false"}, {"/mpuport", cmdSendPort, CMD_MPUPORT, ARG_REQUIRE, "330"}, @@ -941,7 +1061,7 @@ int parseCommand(int argc, char* argv[], int* i, ParseCommand commands[]) return retVal; } } - return command->routine(arg, command->cmd); + return command->routine(arg, command->cmd, command->cmd2, command->cmd3); } else { printf("Invalid command %s. Run pgusinit /? for usage help", argv[idx]); } @@ -1006,7 +1126,7 @@ static void printGUSMode() static void printAdlibMode() { printf("Running in AdLib/OPL2 mode on port %x", ctrlGetUint16(CMD_OPLPORT)); - printf("%s\n", ctrlGetUint8(CMD_OPLWAIT) ? ", wait on" : ""); + printf("%s\n", ctrlGetUint8(CMD_OPLWAIT) & 1 ? ", wait on" : ""); } static void printUSBMode() @@ -1023,16 +1143,29 @@ static void printPSGMode() static void printSBMode() { + static char *strMode[] = {"(invalid)", "1.x", "Pro 1", "2.0", "Pro 2", "(invalid)", "16"}; + static char *strLockMixerMode[] = {"unlocked", "locked except Voice Volume", "locked", "(invalid)"}; + if (init_sb()) { return; } - printf("Running in Sound Blaster 2.0 mode on port %x ", ctrlGetUint16(CMD_SBPORT)); + printf("Running in Sound Blaster %s mode on port %x, IRQ %d, DMA %d\n", + ctrlGetUint8(CMD_SBTYPE) > 6 ? "(invalid)" : strMode[ctrlGetUint8(CMD_SBTYPE)], + ctrlGetUint16(CMD_SBPORT), + ctrlGetUint8(CMD_SBIRQ), + ctrlGetUint8(CMD_SBDMA) + ); + uint8_t tmp_uint8 = ctrlGetUint8(CMD_SBOPTS); + printf("SB Time Constant fix: %s, SB mixer: %s\n", + (tmp_uint8 >> 0) & 1 ? "enabled" : "disabled", + strLockMixerMode[(tmp_uint8 >> 1) & 3] + ); uint16_t tmp_uint16 = ctrlGetUint16(CMD_OPLPORT); if (tmp_uint16) { - printf("(AdLib port %x", tmp_uint16); - printf("%s)\n", ctrlGetUint8(CMD_OPLWAIT) ? ", wait on" : ""); + printf("AdLib port %x", tmp_uint16); + printf("%s\n", ctrlGetUint8(CMD_OPLWAIT) & 1 ? ", wait on" : ""); } else { - printf("(AdLib port disabled)\n"); + printf("AdLib port disabled\n"); } print_cdemu_status(); } diff --git a/pgusinit/pgusinit.h b/pgusinit/pgusinit.h index 7194ed6..010ef9e 100644 --- a/pgusinit/pgusinit.h +++ b/pgusinit/pgusinit.h @@ -34,9 +34,11 @@ enum CommandType typedef struct { char *name; - bool (*routine)(const char*, const int); + bool (*routine)(const char*, const int, const int, const int); int cmd; int type; char *def; + int cmd2; + int cmd3; } ParseCommand; diff --git a/sw/CMakeLists.txt b/sw/CMakeLists.txt index 8e1e86c..26cb192 100644 --- a/sw/CMakeLists.txt +++ b/sw/CMakeLists.txt @@ -19,7 +19,7 @@ set(PICO_COPY_TO_RAM 1) include(pico_sdk_import.cmake) project(picogus - VERSION "3.2.1" + VERSION "3.2.2" LANGUAGES C CXX ASM ) diff --git a/sw/picogus.cpp b/sw/picogus.cpp index 3738974..e9f229f 100644 --- a/sw/picogus.cpp +++ b/sw/picogus.cpp @@ -244,13 +244,10 @@ __force_inline void select_picogus(uint8_t value) { cur_read_idx = 0; #endif break; -#ifdef SOUND_SB - case CMD_SBDSPVER: - picogus_dataLatch_low = 0; + case CMD_SBTYPE: case CMD_SBIRQ: case CMD_SBDMA: - break; -#endif + case CMD_SBOPTS: case CMD_CDSTATUS: case CMD_CDLOAD: case CMD_CDAUTOADV: @@ -296,12 +293,6 @@ __force_inline void write_picogus_low(uint8_t value) { case CMD_MOUSESEN: // USB Mouse Sensitivity (8.8 fixedpoint) mouseSensitivity_low = value; break; -#ifdef SOUND_SB - case CMD_SBDSPVER: - picogus_dataLatch_low = value; - break; -#endif - break; } } @@ -372,25 +363,30 @@ __force_inline void write_picogus_high(uint8_t value) { #endif break; case CMD_OPLWAIT: // Adlib speed sensitive fix - //case CMD_SBOPTS: // ... and SB emulation options - settings.SB.oplSpeedSensitive = value & 1; // HACK until settings struct resolved -#ifdef SOUND_SB - sbdsp_set_options(value); -#endif + settings.SB.oplSpeedSensitive = value; break; - case CMD_SBDSPVER: + + case CMD_SBTYPE: + settings.SB16.sbType = value; #ifdef SOUND_SB - sbdsp_set_dsp_version((value << 8) | picogus_dataLatch_low); + sbdsp_set_type(value); #endif break; case CMD_SBIRQ: + settings.SB16.irq = value; #ifdef SOUND_SB sbdsp_set_irq(value); #endif break; case CMD_SBDMA: + settings.SB16.dma = value; #ifdef SOUND_SB sbdsp_set_dma(value); +#endif + case CMD_SBOPTS: + settings.SB16.options = value; +#ifdef SOUND_SB + sbdsp_set_options(value); #endif break; case CMD_MOUSEPORT: // USB Mouse port (0 - disabled) @@ -606,6 +602,14 @@ __force_inline uint8_t read_picogus_high(void) { return settings.Mouse.sensitivity >> 8; case CMD_NE2KPORT: // NE2000 Base port return settings.NE2K.basePort == 0xFFFF ? 0 : (settings.NE2K.basePort >> 8); + case CMD_SBTYPE: // SB type + return settings.SB16.sbType; + case CMD_SBIRQ: // SB IRQ + return settings.SB16.irq; + case CMD_SBDMA: // SB DMA + return settings.SB16.dma; + case CMD_SBOPTS: // SB Options + return settings.SB16.options; /* case CMD_WIFISSID: break; diff --git a/sw/sbdsp/sbdsp.cpp b/sw/sbdsp/sbdsp.cpp index 6490117..d3ace02 100644 --- a/sw/sbdsp/sbdsp.cpp +++ b/sw/sbdsp/sbdsp.cpp @@ -13,6 +13,7 @@ Author : Kevin Moonlight Copyright (C) 2023 Kevin Moonlight Copyright (C) 2024 Ian Scott +Copyright (C) 2026 Artem Vasilev Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in @@ -49,8 +50,12 @@ static irq_handler_t SBDSP_DMA_isr_pt; static dma_inst_t dma_config; #define DMA_PIO_SM 2 -#define DSP_VERSION_MAJOR 4 -#define DSP_VERSION_MINOR 5 +#define SB_TYPE_SB1 0x1 +#define SB_TYPE_SBPRO1 0x2 +#define SB_TYPE_SB2 0x3 +#define SB_TYPE_SBPRO2 0x4 +#define SB_TYPE_SB2MCV 0x5 +#define SB_TYPE_SB16 0x6 // Sound Blaster DSP I/O port offsets #define DSP_RESET 0x6 @@ -138,8 +143,8 @@ static dma_inst_t dma_config; // mixer locking settings #define MIXER_LOCK_NONE 0 // none, all registers writeable -#define MIXER_LOCK_ALL_BUT_SBP_VOICE 14 // lock all but SBPro Voice (for stereo FX like in Wolf3D) -#define MIXER_LOCK_ALL 15 // lock all registers +#define MIXER_LOCK_ALL_BUT_SBP_VOICE 1 // lock all but SBPro Voice (for stereo FX like in Wolf3D) +#define MIXER_LOCK_ALL 2 // lock all registers static char const copyright_string[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; @@ -222,7 +227,7 @@ uint32_t sbdsp_generate_sample() { } static void sbdsp_handle_time_constant(uint8_t tc) { - if (sbdsp.options.fix_tc) { + if (sbdsp.options.fixTC) { // round time constants to 11/22/44 KHz sample rates switch (tc) { case (256 - 62): // 16129 Hz @@ -320,11 +325,31 @@ uint16_t sbdsp_sample_rate() { return sbdsp.sample_rate; } +void sbdsp_set_options(uint8_t options) { + sbdsp.options.b = options; + // TODO if any to apply +} + +void sbdsp_set_type(uint8_t type) { + if ((type == 0) && (type > SB_TYPE_SB16)) type = SB_TYPE_SB16; + switch (type) { + default: + case SB_TYPE_SB1: sbdsp.dsp_version.major = 1; sbdsp.dsp_version.minor = 5; break; + case SB_TYPE_SB2: + case SB_TYPE_SB2MCV: sbdsp.dsp_version.major = 2; sbdsp.dsp_version.minor = 1; break; + case SB_TYPE_SBPRO1: sbdsp.dsp_version.major = 3; sbdsp.dsp_version.minor = 0; break; + case SB_TYPE_SBPRO2: sbdsp.dsp_version.major = 3; sbdsp.dsp_version.minor = 1; break; + case SB_TYPE_SB16: sbdsp.dsp_version.major = 4; sbdsp.dsp_version.minor = 5; break; + } + return; +} + void sbdsp_set_irq(uint8_t irq) { sbdsp.resources.irq = irq; int mixer_irq; switch (irq) { - case 2: mixer_irq = 1; break; + case 2: + case 9: mixer_irq = 1; break; case 7: mixer_irq = 4; break; case 10: mixer_irq = 8; break; case 5: @@ -338,23 +363,11 @@ void sbdsp_set_dma(uint8_t dma) { mixer_state[MIXER_DMA] = dma < 4 ? (1 << dma) : 0; // 8-bit DMA channel only } -void sbdsp_set_options(uint8_t opts) { - sbdsp.options.b = opts; - // TODO apply them in runtime where applicable -} - static void sbmixer_reset(void); void sbdsp_init() { puts("Initing ISA DMA PIO..."); SBDSP_DMA_isr_pt = sbdsp_dma_isr; - sbdsp.options.mixer_lock = MIXER_LOCK_NONE; - sbdsp.options.fix_tc = 0; - sbdsp.dsp_version.major = DSP_VERSION_MAJOR; - sbdsp.dsp_version.minor = DSP_VERSION_MINOR; - sbdsp_set_irq(5); - sbdsp_set_dma(1); - sbdsp.outbox = 0xAA; dma_config = DMA_multi_init(pio0, DMA_PIO_SM, SBDSP_DMA_isr_pt); @@ -882,7 +895,7 @@ static __force_inline uint8_t sbmixer_read(void) { static __force_inline void sbmixer_write(uint8_t value) { // mixer locking - switch(sbdsp.options.mixer_lock) { + switch(sbdsp.options.lockMixer) { case MIXER_LOCK_ALL_BUT_SBP_VOICE: if (sbdsp.mixer_command != MIXER_VOL_VOICE) // fallthrough diff --git a/sw/sbdsp/sbdsp.h b/sw/sbdsp/sbdsp.h index df3b9ea..9c3fd15 100644 --- a/sw/sbdsp/sbdsp.h +++ b/sw/sbdsp/sbdsp.h @@ -84,12 +84,10 @@ typedef struct sbdsp_t { uint8_t dma; } resources; - // additional options union { struct { - uint8_t reserved : 3; // reserved for OPL speed sensitivity fix and future settings - uint8_t fix_tc : 1; // fix time constant for exact 11/22/44k Hz - uint8_t mixer_lock : 4; // mixer lock + uint8_t fixTC : 1; + uint8_t lockMixer : 2; }; uint8_t b; } options; @@ -140,30 +138,9 @@ static inline uint32_t sbdsp_sample_stereo() { // ------------------------- // PicoGUS configuration interface helpers -static inline uint16_t sbdsp_get_dsp_version() { - extern sbdsp_t sbdsp; - return sbdsp.dsp_version.w; -} -static inline void sbdsp_set_dsp_version(uint16_t dspver) { - extern sbdsp_t sbdsp; - sbdsp.dsp_version.w = dspver; -} - -static inline uint8_t sbdsp_get_irq() { - extern sbdsp_t sbdsp; - return sbdsp.resources.irq; -} -static inline uint8_t sbdsp_get_dma() { - extern sbdsp_t sbdsp; - return sbdsp.resources.dma; -} +void sbdsp_set_type(uint8_t type); void sbdsp_set_irq(uint8_t irq); void sbdsp_set_dma(uint8_t dma); - -static inline uint8_t sbdsp_get_options() { - extern sbdsp_t sbdsp; - return sbdsp.options.b; -} -void sbdsp_set_options(uint8_t opts); +void sbdsp_set_options(uint8_t options); #endif // SBDSP_H diff --git a/sw/sbplay.cpp b/sw/sbplay.cpp index 5895569..fb68697 100644 --- a/sw/sbplay.cpp +++ b/sw/sbplay.cpp @@ -66,7 +66,7 @@ extern cms_buffer_t opl_cmd_buffer; #include "mouse/sermouse.h" #endif -#ifdef SOUND_MPU +#if (defined(SOUND_MPU) || defined(SOUND_SB)) #include "system/flash_settings.h" extern Settings settings; #include "mpu401/export.h" @@ -201,6 +201,10 @@ void play_adlib() { ad1848_init(); #else sbdsp_init(); + sbdsp_set_type(settings.SB16.sbType); + sbdsp_set_irq(settings.SB16.irq); + sbdsp_set_dma(settings.SB16.dma); + sbdsp_set_options(settings.SB16.options); #endif #endif init_audio(); diff --git a/sw/system/flash_settings.c b/sw/system/flash_settings.c index ed95923..bf0c5e0 100644 --- a/sw/system/flash_settings.c +++ b/sw/system/flash_settings.c @@ -85,6 +85,13 @@ static const Settings defaultSettings = { .cdVol = 100, .gusVol = 100, .psgVol = 80 + }, + .SB16 = { + .irq = 5, + .dma = 1, + .sbType = 6, + .fixTC = 0, + .lockMixer = 0 } }; @@ -126,6 +133,11 @@ static const VersionFields versionFieldsTable[] = { {(const FieldInfo[]){ FIELD(Volume), }, 1}, + + // version 5 - added SB16 settings + {(const FieldInfo[]){ + FIELD(SB16), + }, 1}, }; // Apply default values only to fields introduced after the given version diff --git a/sw/system/flash_settings.h b/sw/system/flash_settings.h index 01c8a78..e110287 100644 --- a/sw/system/flash_settings.h +++ b/sw/system/flash_settings.h @@ -25,7 +25,7 @@ extern "C" { #include #define SETTINGS_MAGIC 0x70677573 // "pgus" in ascii -#define SETTINGS_VERSION 4 +#define SETTINGS_VERSION 5 // When adding new fields to Settings struct: // 1. Increment SETTINGS_VERSION @@ -95,6 +95,18 @@ typedef struct Settings { uint8_t gusVol; uint8_t psgVol; } Volume; + struct { + uint8_t irq; + uint8_t dma; + uint8_t sbType; + union { + struct { + uint8_t fixTC : 1; + uint8_t lockMixer : 2; + }; + uint8_t options; + }; + } SB16; // TEMPORARY - may be changed! } Settings;