SB: finalize IRQ/DMA/options settings

This commit is contained in:
wbcbz7 committed 2026-03-22 00:56:38 +07:00
1 parent f54d9a5840
commit 4bf5631472
11 files changed
+284 -108

No files matched your search

+2 -2
View File
@@ -68,10 +68,10 @@ static const char *modenames[8] = {
#define CMD_MPUFAKE 0x22 // MPU fake all notes off #define CMD_MPUFAKE 0x22 // MPU fake all notes off
#define CMD_OPLWAIT 0x30 // Adlib speed sensitive fix #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_SBTYPE 0x31 // SB type
#define CMD_SBDSPVER 0x31 // SB DSP version
#define CMD_SBIRQ 0x32 // SB IRQ #define CMD_SBIRQ 0x32 // SB IRQ
#define CMD_SBDMA 0x33 // SB DMA #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_MOUSEPORT 0x40 // Mouse Base port
#define CMD_MOUSEPROTO 0x41 // Mouse protocol #define CMD_MOUSEPROTO 0x41 // Mouse protocol
+19
View File
@@ -86,11 +86,30 @@ https://github.com/polpo/picogus/wiki/Compatibility-list
### Sound Blaster/AdLib options ### 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. * `/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. * `/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 * `/oplwait` - wait on OPL2 data write. Can fix speed-sensitive early AdLib
games on fast systems (example: 688 Attack Sub). 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. * `/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 ### MPU-401 options
+171 -38
View File
@@ -107,8 +107,16 @@ static void usage(card_mode_t mode, bool print_all)
if (mode == SB_MODE || print_all) { if (mode == SB_MODE || print_all) {
// "...............................................................................\n" // "...............................................................................\n"
pageprintf("Sound Blaster settings:\n"); pageprintf("Sound Blaster settings:\n");
pageprintf(" /sbport x - set the base port of the Sound Blaster. Default: 220\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(" /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) { if (mode == SB_MODE || mode == ADLIB_MODE || print_all) {
pageprintf("AdLib settings:\n"); pageprintf("AdLib settings:\n");
@@ -176,11 +184,19 @@ static void err_blaster(void)
// "................................................................................\n" // "................................................................................\n"
fprintf(stderr, "ERROR: In SB mode but no BLASTER variable set or is malformed!\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, "The BLASTER environment variable must be set in the following format:\n");
fprintf(stderr, "\tset BLASTER=Axxx Iy Dz T3\n"); fprintf(stderr, "\tset BLASTER=Axxx Iy Dz Hz Tw\n");
fprintf(stderr, "Where xxx = port, y = IRQ, z = DMA. T3 indicates an SB 2.0 compatible card.\n"); fprintf(stderr, "Where xxx = port, y = IRQ, z = DMA. w = SB type:\n");
fprintf(stderr, "Port is set via /sbport xxx option; DMA and IRQ configued via jumper.\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) static void err_pigus(void)
{ {
@@ -247,17 +263,33 @@ static int init_gus(void)
static int init_sb(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"); char* blaster = getenv("BLASTER");
if (blaster == NULL) { if (blaster == NULL) {
err_blaster(); err_blaster();
return 1; return 1;
} }
char blasterTemp[256];
strncpy(blasterTemp, blaster, sizeof(blasterTemp));
// Parse BLASTER // Parse BLASTER
uint16_t port; char* p = strtok(blasterTemp, " ");
int e; uint16_t port = -1, irq = -1, dma8 = -1, dma16 = -1, sbtype = 0;
e = sscanf(blaster, "A%hx I%*hhu D%*hhu T3", &port); while (p != NULL) {
if (e != 1) { 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(); err_blaster();
return 2; return 2;
} }
@@ -268,6 +300,28 @@ static int init_sb(void)
err_blaster(); err_blaster();
return 2; 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; 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); 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); usage(gMode, print_all);
return true; 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; uint8_t value;
@@ -654,7 +708,27 @@ static bool cmdSendBool(const char* arg, const int cmd)
return true; 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")) { if (!stricmp(arg, "TANDY") || !stricmp(arg, "CMS")) {
// Backwards compatibility for old tandy and cms modes // 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; 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); 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) static bool ctrlSendUint16(const char *arg, int cmd, long min, long max, int base)
{ {
char *endptr; char *endptr;
@@ -707,27 +817,27 @@ static bool ctrlSendUint16(const char *arg, int cmd, long min, long max, int bas
return true; 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); 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); 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); 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; char* endptr;
uint8_t val = (uint8_t)strtoul(arg, &endptr, 10); uint8_t val = (uint8_t)strtoul(arg, &endptr, 10);
@@ -753,66 +863,71 @@ static bool cmdSendMousePort(const char *arg, const int cmd)
return true; 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); 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); 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); 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(); wifi_printStatus();
exit(0); 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; wifichg = true;
send_string(cmd, arg, 32); send_string(cmd, arg, 32);
return true; 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; wifichg = true;
send_string(cmd, arg, 63); send_string(cmd, arg, 63);
return true; 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; wifichg = true;
send_string(cmd, "", 1); send_string(cmd, "", 1);
return true; 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); send_string(cmd, arg, 127);
exit(wait_for_cd_load()); 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()); 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); ctrlSendUint8(arg, cmd, 0, 255);
exit(wait_for_cd_load()); 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 tmp_uint8;
uint8_t e = sscanf(arg, "%hhu", &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; 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) if (strlen(arg) > 255)
{ {
@@ -837,7 +952,7 @@ static bool cmdFlashPico(const char* arg, const int cmd)
return true; 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; permanent = true;
return true; return true;
@@ -868,6 +983,11 @@ ParseCommand parseCommands[] = {
{"/gusdma", cmdSendUint8, CMD_GUSDMA, ARG_REQUIRE, "0"}, {"/gusdma", cmdSendUint8, CMD_GUSDMA, ARG_REQUIRE, "0"},
{"/gusport", cmdSendPort, CMD_GUSPORT, ARG_REQUIRE, "240"}, {"/gusport", cmdSendPort, CMD_GUSPORT, ARG_REQUIRE, "240"},
{"/sbport", cmdSendPort, CMD_SBPORT, ARG_REQUIRE, "220"}, {"/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"}, {"/oplport", cmdSendPort, CMD_OPLPORT, ARG_REQUIRE, "388"},
{"/oplwait", cmdSendBool, CMD_OPLWAIT, ARG_REQUIRE, "false"}, {"/oplwait", cmdSendBool, CMD_OPLWAIT, ARG_REQUIRE, "false"},
{"/mpuport", cmdSendPort, CMD_MPUPORT, ARG_REQUIRE, "330"}, {"/mpuport", cmdSendPort, CMD_MPUPORT, ARG_REQUIRE, "330"},
@@ -941,7 +1061,7 @@ int parseCommand(int argc, char* argv[], int* i, ParseCommand commands[])
return retVal; return retVal;
} }
} }
return command->routine(arg, command->cmd); return command->routine(arg, command->cmd, command->cmd2, command->cmd3);
} else { } else {
printf("Invalid command %s. Run pgusinit /? for usage help", argv[idx]); printf("Invalid command %s. Run pgusinit /? for usage help", argv[idx]);
} }
@@ -1006,7 +1126,7 @@ static void printGUSMode()
static void printAdlibMode() static void printAdlibMode()
{ {
printf("Running in AdLib/OPL2 mode on port %x", ctrlGetUint16(CMD_OPLPORT)); 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() static void printUSBMode()
@@ -1023,16 +1143,29 @@ static void printPSGMode()
static void printSBMode() 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()) { if (init_sb()) {
return; 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); uint16_t tmp_uint16 = ctrlGetUint16(CMD_OPLPORT);
if (tmp_uint16) { if (tmp_uint16) {
printf("(AdLib port %x", tmp_uint16); printf("AdLib port %x", tmp_uint16);
printf("%s)\n", ctrlGetUint8(CMD_OPLWAIT) ? ", wait on" : ""); printf("%s\n", ctrlGetUint8(CMD_OPLWAIT) & 1 ? ", wait on" : "");
} else { } else {
printf("(AdLib port disabled)\n"); printf("AdLib port disabled\n");
} }
print_cdemu_status(); print_cdemu_status();
} }
+3 -1
View File
@@ -34,9 +34,11 @@ enum CommandType
typedef struct { typedef struct {
char *name; char *name;
bool (*routine)(const char*, const int); bool (*routine)(const char*, const int, const int, const int);
int cmd; int cmd;
int type; int type;
char *def; char *def;
int cmd2;
int cmd3;
} ParseCommand; } ParseCommand;
+1 -1
View File
@@ -19,7 +19,7 @@ set(PICO_COPY_TO_RAM 1)
include(pico_sdk_import.cmake) include(pico_sdk_import.cmake)
project(picogus project(picogus
VERSION "3.2.1" VERSION "3.2.2"
LANGUAGES C CXX ASM LANGUAGES C CXX ASM
) )
+22 -18
View File
@@ -244,13 +244,10 @@ __force_inline void select_picogus(uint8_t value) {
cur_read_idx = 0; cur_read_idx = 0;
#endif #endif
break; break;
#ifdef SOUND_SB case CMD_SBTYPE:
case CMD_SBDSPVER:
picogus_dataLatch_low = 0;
case CMD_SBIRQ: case CMD_SBIRQ:
case CMD_SBDMA: case CMD_SBDMA:
break; case CMD_SBOPTS:
#endif
case CMD_CDSTATUS: case CMD_CDSTATUS:
case CMD_CDLOAD: case CMD_CDLOAD:
case CMD_CDAUTOADV: 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) case CMD_MOUSESEN: // USB Mouse Sensitivity (8.8 fixedpoint)
mouseSensitivity_low = value; mouseSensitivity_low = value;
break; 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 #endif
break; break;
case CMD_OPLWAIT: // Adlib speed sensitive fix case CMD_OPLWAIT: // Adlib speed sensitive fix
//case CMD_SBOPTS: // ... and SB emulation options settings.SB.oplSpeedSensitive = value;
settings.SB.oplSpeedSensitive = value & 1; // HACK until settings struct resolved
#ifdef SOUND_SB
sbdsp_set_options(value);
#endif
break; break;
case CMD_SBDSPVER:
case CMD_SBTYPE:
settings.SB16.sbType = value;
#ifdef SOUND_SB #ifdef SOUND_SB
sbdsp_set_dsp_version((value << 8) | picogus_dataLatch_low); sbdsp_set_type(value);
#endif #endif
break; break;
case CMD_SBIRQ: case CMD_SBIRQ:
settings.SB16.irq = value;
#ifdef SOUND_SB #ifdef SOUND_SB
sbdsp_set_irq(value); sbdsp_set_irq(value);
#endif #endif
break; break;
case CMD_SBDMA: case CMD_SBDMA:
settings.SB16.dma = value;
#ifdef SOUND_SB #ifdef SOUND_SB
sbdsp_set_dma(value); sbdsp_set_dma(value);
#endif
case CMD_SBOPTS:
settings.SB16.options = value;
#ifdef SOUND_SB
sbdsp_set_options(value);
#endif #endif
break; break;
case CMD_MOUSEPORT: // USB Mouse port (0 - disabled) 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; return settings.Mouse.sensitivity >> 8;
case CMD_NE2KPORT: // NE2000 Base port case CMD_NE2KPORT: // NE2000 Base port
return settings.NE2K.basePort == 0xFFFF ? 0 : (settings.NE2K.basePort >> 8); 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: case CMD_WIFISSID:
break; break;
+32 -19
View File
@@ -13,6 +13,7 @@ Author : Kevin Moonlight <me@yyzkevin.com>
Copyright (C) 2023 Kevin Moonlight Copyright (C) 2023 Kevin Moonlight
Copyright (C) 2024 Ian Scott Copyright (C) 2024 Ian Scott
Copyright (C) 2026 Artem Vasilev
Permission is hereby granted, free of charge, to any person obtaining a copy of 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 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; static dma_inst_t dma_config;
#define DMA_PIO_SM 2 #define DMA_PIO_SM 2
#define DSP_VERSION_MAJOR 4 #define SB_TYPE_SB1 0x1
#define DSP_VERSION_MINOR 5 #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 // Sound Blaster DSP I/O port offsets
#define DSP_RESET 0x6 #define DSP_RESET 0x6
@@ -138,8 +143,8 @@ static dma_inst_t dma_config;
// mixer locking settings // mixer locking settings
#define MIXER_LOCK_NONE 0 // none, all registers writeable #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_BUT_SBP_VOICE 1 // lock all but SBPro Voice (for stereo FX like in Wolf3D)
#define MIXER_LOCK_ALL 15 // lock all registers #define MIXER_LOCK_ALL 2 // lock all registers
static char const copyright_string[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; 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) { 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 // round time constants to 11/22/44 KHz sample rates
switch (tc) { switch (tc) {
case (256 - 62): // 16129 Hz case (256 - 62): // 16129 Hz
@@ -320,11 +325,31 @@ uint16_t sbdsp_sample_rate() {
return 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) { void sbdsp_set_irq(uint8_t irq) {
sbdsp.resources.irq = irq; sbdsp.resources.irq = irq;
int mixer_irq; int mixer_irq;
switch (irq) { switch (irq) {
case 2: mixer_irq = 1; break; case 2:
case 9: mixer_irq = 1; break;
case 7: mixer_irq = 4; break; case 7: mixer_irq = 4; break;
case 10: mixer_irq = 8; break; case 10: mixer_irq = 8; break;
case 5: 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 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); static void sbmixer_reset(void);
void sbdsp_init() { void sbdsp_init() {
puts("Initing ISA DMA PIO..."); puts("Initing ISA DMA PIO...");
SBDSP_DMA_isr_pt = sbdsp_dma_isr; 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; sbdsp.outbox = 0xAA;
dma_config = DMA_multi_init(pio0, DMA_PIO_SM, SBDSP_DMA_isr_pt); 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) { static __force_inline void sbmixer_write(uint8_t value) {
// mixer locking // mixer locking
switch(sbdsp.options.mixer_lock) { switch(sbdsp.options.lockMixer) {
case MIXER_LOCK_ALL_BUT_SBP_VOICE: case MIXER_LOCK_ALL_BUT_SBP_VOICE:
if (sbdsp.mixer_command != MIXER_VOL_VOICE) if (sbdsp.mixer_command != MIXER_VOL_VOICE)
// fallthrough // fallthrough
+4 -27
View File
@@ -84,12 +84,10 @@ typedef struct sbdsp_t {
uint8_t dma; uint8_t dma;
} resources; } resources;
// additional options
union { union {
struct { struct {
uint8_t reserved : 3; // reserved for OPL speed sensitivity fix and future settings uint8_t fixTC : 1;
uint8_t fix_tc : 1; // fix time constant for exact 11/22/44k Hz uint8_t lockMixer : 2;
uint8_t mixer_lock : 4; // mixer lock
}; };
uint8_t b; uint8_t b;
} options; } options;
@@ -140,30 +138,9 @@ static inline uint32_t sbdsp_sample_stereo() {
// ------------------------- // -------------------------
// PicoGUS configuration interface helpers // PicoGUS configuration interface helpers
static inline uint16_t sbdsp_get_dsp_version() { void sbdsp_set_type(uint8_t type);
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_irq(uint8_t irq); void sbdsp_set_irq(uint8_t irq);
void sbdsp_set_dma(uint8_t dma); void sbdsp_set_dma(uint8_t dma);
void sbdsp_set_options(uint8_t options);
static inline uint8_t sbdsp_get_options() {
extern sbdsp_t sbdsp;
return sbdsp.options.b;
}
void sbdsp_set_options(uint8_t opts);
#endif // SBDSP_H #endif // SBDSP_H
+5 -1
View File
@@ -66,7 +66,7 @@ extern cms_buffer_t opl_cmd_buffer;
#include "mouse/sermouse.h" #include "mouse/sermouse.h"
#endif #endif
#ifdef SOUND_MPU #if (defined(SOUND_MPU) || defined(SOUND_SB))
#include "system/flash_settings.h" #include "system/flash_settings.h"
extern Settings settings; extern Settings settings;
#include "mpu401/export.h" #include "mpu401/export.h"
@@ -201,6 +201,10 @@ void play_adlib() {
ad1848_init(); ad1848_init();
#else #else
sbdsp_init(); 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
#endif #endif
init_audio(); init_audio();
+12
View File
@@ -85,6 +85,13 @@ static const Settings defaultSettings = {
.cdVol = 100, .cdVol = 100,
.gusVol = 100, .gusVol = 100,
.psgVol = 80 .psgVol = 80
},
.SB16 = {
.irq = 5,
.dma = 1,
.sbType = 6,
.fixTC = 0,
.lockMixer = 0
} }
}; };
@@ -126,6 +133,11 @@ static const VersionFields versionFieldsTable[] = {
{(const FieldInfo[]){ {(const FieldInfo[]){
FIELD(Volume), FIELD(Volume),
}, 1}, }, 1},
// version 5 - added SB16 settings
{(const FieldInfo[]){
FIELD(SB16),
}, 1},
}; };
// Apply default values only to fields introduced after the given version // Apply default values only to fields introduced after the given version
+13 -1
View File
@@ -25,7 +25,7 @@ extern "C" {
#include <stdbool.h> #include <stdbool.h>
#define SETTINGS_MAGIC 0x70677573 // "pgus" in ascii #define SETTINGS_MAGIC 0x70677573 // "pgus" in ascii
#define SETTINGS_VERSION 4 #define SETTINGS_VERSION 5
// When adding new fields to Settings struct: // When adding new fields to Settings struct:
// 1. Increment SETTINGS_VERSION // 1. Increment SETTINGS_VERSION
@@ -95,6 +95,18 @@ typedef struct Settings {
uint8_t gusVol; uint8_t gusVol;
uint8_t psgVol; uint8_t psgVol;
} Volume; } 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; } Settings;