#include #include #include #include #include #include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> #include <86box/gameport.h> #include <86box/io.h> #include <86box/snd_resid.h> #include <86box/sound.h> #include <86box/plat_unused.h> typedef struct ssi2001_t { void *psid; int16_t buffer[SOUNDBUFLEN * 2]; int pos; int gameport_enabled; } ssi2001_t; typedef struct entertainer_t { uint8_t regs; } entertainer_t; static void ssi2001_update(ssi2001_t *ssi2001) { if (ssi2001->pos >= sound_pos_global) return; sid_fillbuf(&ssi2001->buffer[ssi2001->pos], sound_pos_global - ssi2001->pos, ssi2001->psid); ssi2001->pos = sound_pos_global; } static void ssi2001_get_buffer(int32_t *buffer, int len, void *priv) { ssi2001_t *ssi2001 = (ssi2001_t *) priv; ssi2001_update(ssi2001); for (int c = 0; c < len * 2; c++) buffer[c] += ssi2001->buffer[c >> 1] / 2; ssi2001->pos = 0; } static uint8_t ssi2001_read(uint16_t addr, void *priv) { ssi2001_t *ssi2001 = (ssi2001_t *) priv; ssi2001_update(ssi2001); return sid_read(addr, priv); } static void ssi2001_write(uint16_t addr, uint8_t val, void *priv) { ssi2001_t *ssi2001 = (ssi2001_t *) priv; ssi2001_update(ssi2001); sid_write(addr, val, priv); } void * ssi2001_init(UNUSED(const device_t *info)) { ssi2001_t *ssi2001 = malloc(sizeof(ssi2001_t)); memset(ssi2001, 0, sizeof(ssi2001_t)); ssi2001->psid = sid_init(0); sid_reset(ssi2001->psid); uint16_t addr = device_get_config_hex16("base"); ssi2001->gameport_enabled = device_get_config_int("gameport"); io_sethandler(addr, 0x0020, ssi2001_read, NULL, NULL, ssi2001_write, NULL, NULL, ssi2001); if (ssi2001->gameport_enabled) gameport_remap(gameport_add(&gameport_201_device), 0x201); sound_add_handler(ssi2001_get_buffer, ssi2001); return ssi2001; } void ssi2001_close(void *priv) { ssi2001_t *ssi2001 = (ssi2001_t *) priv; sid_close(ssi2001->psid); free(ssi2001); } static uint8_t entertainer_read(uint16_t addr, void *priv) { return 0xa5; } static void entertainer_write(uint16_t addr, uint8_t val, void *priv) { entertainer_t *entertainer = (entertainer_t *) priv; entertainer->regs = val; } void * entertainer_init(UNUSED(const device_t *info)) { ssi2001_t *ssi2001 = malloc(sizeof(ssi2001_t)); entertainer_t *entertainer = malloc(sizeof(entertainer_t)); memset(ssi2001, 0, sizeof(ssi2001_t)); memset(entertainer, 0, sizeof(entertainer_t)); ssi2001->psid = sid_init(0); sid_reset(ssi2001->psid); ssi2001->gameport_enabled = device_get_config_int("gameport"); io_sethandler(0x200, 0x0001, entertainer_read, NULL, NULL, entertainer_write, NULL, NULL, entertainer); io_sethandler(0x280, 0x0020, ssi2001_read, NULL, NULL, ssi2001_write, NULL, NULL, ssi2001); if (ssi2001->gameport_enabled) gameport_remap(gameport_add(&gameport_201_device), 0x201); sound_add_handler(ssi2001_get_buffer, ssi2001); return ssi2001; } void entertainer_close(void *priv) { ssi2001_t *ssi2001 = (ssi2001_t *) priv; sid_close(ssi2001->psid); free(ssi2001); } static const device_config_t ssi2001_config[] = { // clang-format off { .name = "base", .description = "Address", .type = CONFIG_HEX16, .default_string = "", .default_int = 0x280, .file_filter = "", .spinner = { 0 }, .selection = { { .description = "0x280", .value = 0x280 }, { .description = "0x2A0", .value = 0x2A0 }, { .description = "0x2C0", .value = 0x2C0 }, { .description = "0x2E0", .value = 0x2E0 }, { .description = "" } } }, { "gameport", "Enable Game port", CONFIG_BINARY, "", 1 }, { "", "", -1 } // clang-format off }; static const device_config_t entertainer_config[] = { // clang-format off { "gameport", "Enable Game port", CONFIG_BINARY, "", 1 }, { "", "", -1 } // clang-format off }; const device_t ssi2001_device = { .name = "Innovation SSI-2001", .internal_name = "ssi2001", .flags = DEVICE_ISA, .local = 0, .init = ssi2001_init, .close = ssi2001_close, .reset = NULL, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = ssi2001_config }; const device_t entertainer_device = { .name = "The Entertainer", .internal_name = "Entertainer", .flags = DEVICE_ISA, .local = 1, .init = entertainer_init, .close = entertainer_close, .reset = NULL, .available = NULL, .speed_changed = NULL, .force_redraw = NULL, .config = entertainer_config };