/* * 86Box A hypervisor and IBM PC system emulator that specializes in * running old operating systems and software designed for IBM * PC systems and compatibles from 1981 through fairly recent * system designs based on the PCI bus. * * This file is part of the 86Box distribution. * * Emulation of Sergey Kiselev's Monster Floppy Disk Controller. * * * * Authors: Jasmine Iwanek, * Miran Grca, * * Copyright 2022-2024 Jasmine Iwanek. * Copyright 2024 Miran Grca. */ #include #include #include #include #include #include #define HAVE_STDARG_H #include <86box/86box.h> #include <86box/device.h> #include <86box/io.h> #include <86box/mem.h> #include <86box/timer.h> #include <86box/nvr.h> #include <86box/rom.h> #include <86box/machine.h> #include <86box/timer.h> #include <86box/fdd.h> #include <86box/fdc.h> #include <86box/fdc_ext.h> #include <86box/plat_unused.h> #define BIOS_ADDR (uint32_t)(device_get_config_hex20("bios_addr") & 0x000fffff) #define ROM_MONSTER_FDC "roms/floppy/monster-fdc/floppy_bios.bin" typedef struct monster_fdc_t { rom_t bios_rom; fdc_t *fdc_pri; fdc_t *fdc_sec; char nvr_path[64]; } monster_fdc_t; static void rom_write(uint32_t addr, uint8_t val, void *priv) { const rom_t *rom = (rom_t *) priv; #ifdef ROM_TRACE if (rom->mapping.base == ROM_TRACE) rom_log("ROM: read byte from BIOS at %06lX\n", addr); #endif if (addr < rom->mapping.base) return; if (addr >= (rom->mapping.base + rom->sz)) return; rom->rom[(addr - rom->mapping.base) & rom->mask] = val; } static void rom_writew(uint32_t addr, uint16_t val, void *priv) { rom_t *rom = (rom_t *) priv; #ifdef ROM_TRACE if (rom->mapping.base == ROM_TRACE) rom_log("ROM: read word from BIOS at %06lX\n", addr); #endif if (addr < (rom->mapping.base - 1)) return; if (addr >= (rom->mapping.base + rom->sz)) return; *(uint16_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask] = val; } static void rom_writel(uint32_t addr, uint32_t val, void *priv) { rom_t *rom = (rom_t *) priv; #ifdef ROM_TRACE if (rom->mapping.base == ROM_TRACE) rom_log("ROM: read long from BIOS at %06lX\n", addr); #endif if (addr < (rom->mapping.base - 3)) return; if (addr >= (rom->mapping.base + rom->sz)) return; *(uint32_t *) &rom->rom[(addr - rom->mapping.base) & rom->mask] = val; } static void monster_fdc_close(void *priv) { monster_fdc_t *dev = (monster_fdc_t *) priv; if (dev->nvr_path[0] != 0x00) { FILE *fp = nvr_fopen(dev->nvr_path, "wb"); if (fp != NULL) { fwrite(dev->bios_rom.rom, 1, 0x2000, fp); fclose(fp); } } free(dev); } static void * monster_fdc_init(UNUSED(const device_t *info)) { monster_fdc_t *dev; dev = (monster_fdc_t *) calloc(1, sizeof(monster_fdc_t)); #if 0 uint8_t sec_irq = device_get_config_int("sec_irq"); uint8_t sec_dma = device_get_config_int("sec_dma"); #endif if (BIOS_ADDR != 0) rom_init(&dev->bios_rom, ROM_MONSTER_FDC, BIOS_ADDR, 0x2000, 0x1ffff, 0, MEM_MAPPING_EXTERNAL); // Primary FDC dev->fdc_pri = device_add(&fdc_at_device); #if 0 // Secondary FDC uint8_t sec_enabled = device_get_config_int("sec_enabled"); if (sec_enabled) dev->fdc_sec = device_add(&fdc_at_sec_device); fdc_set_irq(dev->fdc_sec, sec_irq); fdc_set_dma_ch(dev->fdc_sec, sec_dma); #endif uint8_t rom_writes_enabled = device_get_config_int("rom_writes_enabled"); if (rom_writes_enabled) { mem_mapping_set_write_handler(&dev->bios_rom.mapping, rom_write, rom_writew, rom_writel); sprintf(dev->nvr_path, "monster_fdc_%i.nvr", device_get_instance()); FILE *fp = nvr_fopen(dev->nvr_path, "rb"); if (fp != NULL) { (void) !fread(dev->bios_rom.rom, 1, 0x2000, fp); fclose(fp); } } return dev; } static int monster_fdc_available(void) { return rom_present(ROM_MONSTER_FDC); } static const device_config_t monster_fdc_config[] = { // clang-format off #if 0 { .name = "sec_enabled", .description = "Enable Secondary Controller", .type = CONFIG_BINARY, .default_string = "", .default_int = 0 }, { .name = "sec_irq", .description = "Secondary Controller IRQ", .type = CONFIG_SELECTION, .default_string = "", .default_int = 6, .file_filter = "", .spinner = { 0 }, .selection = { { .description = "IRQ 2", .value = 2 }, { .description = "IRQ 3", .value = 3 }, { .description = "IRQ 4", .value = 4 }, { .description = "IRQ 5", .value = 5 }, { .description = "IRQ 6", .value = 6 }, { .description = "IRQ 7", .value = 7 }, { .description = "" } } }, { .name = "sec_dma", .description = "Secondary Controller DMA", .type = CONFIG_SELECTION, .default_string = "", .default_int = 2, .file_filter = "", .spinner = { 0 }, .selection = { { .description = "DMA 1", .value = 1 }, { .description = "DMA 2", .value = 2 }, { .description = "DMA 3", .value = 3 }, { .description = "" } } }, #endif { .name = "bios_addr", .description = "BIOS Address", .type = CONFIG_HEX20, .default_string = "", .default_int = 0xc8000, .file_filter = "", .spinner = { 0 }, .selection = { { .description = "Disabled", .value = 0 }, { .description = "C000H", .value = 0xc0000 }, { .description = "C800H", .value = 0xc8000 }, { .description = "D000H", .value = 0xd0000 }, { .description = "D800H", .value = 0xd8000 }, { .description = "E000H", .value = 0xe0000 }, { .description = "E800H", .value = 0xe8000 }, { .description = "" } } }, #if 0 { .name = "bios_size", .description = "BIOS Size:", .type = CONFIG_HEX20, .default_string = "32", .default_int = 0xc8000, .file_filter = "", .spinner = { 0 }, .selection = { { .description = "8K", .value = 8 }, { .description = "32K", .value = 32 }, { .description = "" } } }, #endif { .name = "rom_writes_enabled", .description = "Enable BIOS extension ROM Writes", .type = CONFIG_BINARY, .default_string = "", .default_int = 0 }, { .name = "", .description = "", .type = CONFIG_END } // clang-format on }; const device_t fdc_monster_device = { .name = "Monster FDC Floppy Drive Controller", .internal_name = "monster_fdc", .flags = DEVICE_ISA, .local = 0, .init = monster_fdc_init, .close = monster_fdc_close, .reset = NULL, { .available = monster_fdc_available }, .speed_changed = NULL, .force_redraw = NULL, .config = monster_fdc_config };