This commit is contained in:
OBattler
2025-06-08 19:54:38 +02:00
19 changed files with 1059 additions and 14 deletions

View File

@@ -70,6 +70,7 @@
#include <86box/unittester.h>
#include <86box/novell_cardkey.h>
#include <86box/isamem.h>
#include <86box/isarom.h>
#include <86box/isartc.h>
#include <86box/lpt.h>
#include <86box/serial.h>
@@ -181,6 +182,7 @@ int postcard_enabled = 0; /* (C) enable
int unittester_enabled = 0; /* (C) enable unit tester device */
int gameport_type[GAMEPORT_MAX] = { 0, 0 }; /* (C) enable gameports */
int isamem_type[ISAMEM_MAX] = { 0, 0, 0, 0 }; /* (C) enable ISA mem cards */
int isarom_type[ISAROM_MAX] = { 0, 0, 0, 0 }; /* (C) enable ISA ROM cards */
int isartc_type = 0; /* (C) enable ISA RTC card */
int gfxcard[GFXCARD_MAX] = { 0, 0 }; /* (C) graphics/video card */
int show_second_monitors = 1; /* (C) show non-primary monitors */
@@ -1472,6 +1474,10 @@ pc_reset_hard_init(void)
zip_hard_reset();
/* Reset any ISA ROM cards. */
isarom_reset();
/* Reset any ISA RTC cards. */
isartc_reset();
@@ -1901,4 +1907,4 @@ int FindAccelerator(const char *name) {
}
// No key was found
return -1;
}
}

View File

@@ -46,6 +46,7 @@
#include <86box/ini.h>
#include <86box/config.h>
#include <86box/isamem.h>
#include <86box/isarom.h>
#include <86box/isartc.h>
#include <86box/lpt.h>
#include <86box/serial.h>
@@ -1699,6 +1700,7 @@ load_other_peripherals(void)
if (!novell_keycard_enabled)
ini_section_delete_var(cat, "novell_keycard_enabled");
// ISA RAM Boards
for (uint8_t c = 0; c < ISAMEM_MAX; c++) {
sprintf(temp, "isamem%d_type", c);
@@ -1709,6 +1711,17 @@ load_other_peripherals(void)
ini_section_delete_var(cat, temp);
}
// ISA ROM Boards
for (uint8_t c = 0; c < ISAROM_MAX; c++) {
sprintf(temp, "isarom%d_type", c);
p = ini_section_get_string(cat, temp, "none");
isarom_type[c] = isarom_get_from_internal_name(p);
if (!strcmp(p, "none"))
ini_section_delete_var(cat, temp);
}
p = ini_section_get_string(cat, "isartc_type", "none");
isartc_type = isartc_get_from_internal_name(p);
@@ -1858,6 +1871,8 @@ config_load(void)
cdrom[0].sound_on = 1;
mem_size = 64;
isartc_type = 0;
for (i = 0; i < ISAROM_MAX; i++)
isarom_type[i] = 0;
for (i = 0; i < ISAMEM_MAX; i++)
isamem_type[i] = 0;
@@ -2706,6 +2721,7 @@ save_other_peripherals(void)
else
ini_section_set_int(cat, "novell_keycard_enabled", novell_keycard_enabled);
// ISA RAM Boards
for (uint8_t c = 0; c < ISAMEM_MAX; c++) {
sprintf(temp, "isamem%d_type", c);
if (isamem_type[c] == 0)
@@ -2715,6 +2731,16 @@ save_other_peripherals(void)
isamem_get_internal_name(isamem_type[c]));
}
// ISA ROM Boards
for (uint8_t c = 0; c < ISAROM_MAX; c++) {
sprintf(temp, "isarom%d_type", c);
if (isarom_type[c] == 0)
ini_section_delete_var(cat, temp);
else
ini_section_set_string(cat, temp,
isarom_get_internal_name(isarom_type[c]));
}
if (isartc_type == 0)
ini_section_delete_var(cat, "isartc_type");
else

View File

@@ -33,6 +33,7 @@ add_library(dev OBJECT
i2c_gpio.c
ibm_5161.c
isamem.c
isarom.c
isartc.c
isapnp.c
kbc_at.c

643
src/device/isarom.c Normal file
View File

@@ -0,0 +1,643 @@
/*
* 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.
*
* Implementation of ISA ROM card Expansions.
*
* Authors: Jasmine Iwanek, <jriwanek@gmail.com>
*
* Copyright 2025 Jasmine Iwanek.
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/io.h>
#include <86box/device.h>
#include <86box/mem.h>
#include <86box/rom.h>
#include <86box/nvr.h>
#include <86box/isarom.h>
#define ISAROM_CARD 0
#define ISAROM_CARD_DUAL 1
#define ISAROM_CARD_QUAD 2
#ifdef ENABLE_ISAROM_LOG
int isarom_do_log = ENABLE_ISAROM_LOG;
static void
isarom_log(const char *fmt, ...)
{
va_list ap;
if (isarom_do_log) {
va_start(ap, fmt);
pclog_ex(fmt, ap);
va_end(ap);
}
}
#else
# define isarom_log(fmt, ...)
#endif
typedef struct isarom_t {
struct {
rom_t rom;
uint32_t addr;
const char *fn;
uint32_t size;
uint32_t len;
char nvr_path[64];
uint8_t wp;
} socket[4];
uint8_t inst;
uint8_t type;
} isarom_t;
static inline uint8_t
get_limit(uint8_t type)
{
if (type == ISAROM_CARD_DUAL)
return 2;
if (type == ISAROM_CARD_QUAD)
return 4;
return 1;
}
static inline void
isarom_save_nvr(char *path, uint8_t *data, size_t size)
{
if (path[0] == 0x00)
return;
FILE *fp = nvr_fopen(path, "wb");
if (fp) {
fwrite(data, 1, size, fp);
fclose(fp);
}
}
void
isarom_close(void *priv)
{
isarom_t *dev = (isarom_t *) priv;
if (!priv)
return;
for (uint8_t i = 0; i < get_limit(dev->type); i++)
if (dev->socket[i].rom.rom) {
isarom_log("isarom[%u]: saving NVR for socket %u -> %s (%u bytes)\n",
dev->inst, i, dev->socket[i].nvr_path, dev->socket[i].size);
isarom_save_nvr(dev->socket[i].nvr_path, dev->socket[i].rom.rom, dev->socket[i].size);
}
free(dev);
}
static void *
isarom_init(const device_t *info)
{
isarom_t *dev = (isarom_t *) calloc(1, sizeof(isarom_t));
if (!dev)
return NULL;
dev->inst = device_get_instance();
dev->type = (uint8_t) info->local;
isarom_log("isarom[%u]: initializing device (type=%u)\n", dev->inst, dev->type);
for (uint8_t i = 0; i < get_limit(dev->type); i++) {
char key_fn[12];
char key_addr[14];
char key_size[14];
char key_writes[22];
char suffix[4] = "";
if (i > 0)
snprintf(suffix, sizeof(suffix), "%d", i + 1);
snprintf(key_fn, sizeof(key_fn), "bios_fn%s", suffix);
snprintf(key_addr, sizeof(key_addr), "bios_addr%s", suffix);
snprintf(key_size, sizeof(key_size), "bios_size%s", suffix);
snprintf(key_writes, sizeof(key_writes), "rom_writes_enabled%s", suffix);
dev->socket[i].fn = device_get_config_string(key_fn);
dev->socket[i].addr = device_get_config_hex20(key_addr);
dev->socket[i].size = device_get_config_int(key_size);
// Note: 2K is the smallest ROM I've found, but 86box's memory granularity is 4k, the number below is fine
// as we'll end up allocating no less than 4k due to the device config limits.
dev->socket[i].len = (dev->socket[i].size > 2048) ? dev->socket[i].size - 1 : 0;
dev->socket[i].wp = (uint8_t) device_get_config_int(key_writes) ? 1 : 0;
isarom_log("isarom[%u]: socket %u: addr=0x%05X size=%u wp=%u fn=%s\n",
dev->inst, i, dev->socket[i].addr, dev->socket[i].size,
dev->socket[i].wp, dev->socket[i].fn ? dev->socket[i].fn : "(null)");
if (dev->socket[i].addr != 0 && dev->socket[i].fn != NULL) {
rom_init(&dev->socket[i].rom,
dev->socket[i].fn,
dev->socket[i].addr,
dev->socket[i].size,
dev->socket[i].len,
0,
MEM_MAPPING_EXTERNAL);
isarom_log("isarom[%u]: ROM initialized for socket %u\n", dev->inst, i);
if (dev->socket[i].wp) {
mem_mapping_set_write_handler(&dev->socket[i].rom.mapping, rom_write, rom_writew, rom_writel);
snprintf(dev->socket[i].nvr_path, sizeof(dev->socket[i].nvr_path), "isarom_%i_%i.nvr", dev->inst, i + 1);
FILE *fp = nvr_fopen(dev->socket[i].nvr_path, "rb");
if (fp != NULL) {
fread(dev->socket[i].rom.rom, 1, dev->socket[i].size, fp);
fclose(fp);
isarom_log("isarom[%u]: loaded %zu bytes from %s\n", dev->inst, read_bytes, dev->socket[i].nvr_path);
} else
isarom_log("isarom[%u]: NVR not found, skipping load (%s)\n", dev->inst, dev->socket[i].nvr_path);
}
}
}
return dev;
}
#define BIOS_FILE_FILTER "ROM files (*.bin *.rom)|*.bin,*.rom"
#define BIOS_ADDR_SELECTION { \
{ "Disabled", 0x00000 }, \
{ "C000H", 0xc0000 }, \
{ "C200H", 0xc2000 }, \
{ "C400H", 0xc4000 }, \
{ "C600H", 0xc6000 }, \
{ "C800H", 0xc8000 }, \
{ "CA00H", 0xca000 }, \
{ "CC00H", 0xcc000 }, \
{ "CE00H", 0xce000 }, \
{ "D000H", 0xd0000 }, \
{ "D200H", 0xd2000 }, \
{ "D400H", 0xd4000 }, \
{ "D600H", 0xd6000 }, \
{ "D800H", 0xd8000 }, \
{ "DA00H", 0xda000 }, \
{ "DC00H", 0xdc000 }, \
{ "DE00H", 0xde000 }, \
{ "E000H", 0xe0000 }, \
{ "E200H", 0xe2000 }, \
{ "E400H", 0xe4000 }, \
{ "E600H", 0xe6000 }, \
{ "E800H", 0xe8000 }, \
{ "EA00H", 0xea000 }, \
{ "EC00H", 0xec000 }, \
{ "EE00H", 0xee000 }, \
{ "", 0 } \
}
#define BIOS_SIZE_SELECTION { \
{ "4K", 4096 }, \
{ "8K", 8192 }, \
{ "16K", 16384 }, \
{ "32K", 32768 }, \
{ "64K", 65536 }, \
{ "", 0 } \
}
// clang-format off
static const device_config_t isarom_config[] = {
{
.name = "bios_fn",
.description = "BIOS File",
.type = CONFIG_FNAME,
.default_string = NULL,
.default_int = 0,
.file_filter = BIOS_FILE_FILTER,
.spinner = { 0 },
.selection = { },
.bios = { { 0 } }
},
{
.name = "bios_addr",
.description = "BIOS Address",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0x00000,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_ADDR_SELECTION,
.bios = { { 0 } }
},
{
.name = "bios_size",
.description = "BIOS Size:",
.type = CONFIG_INT,
.default_string = NULL,
.default_int = 8192,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_SIZE_SELECTION,
.bios = { { 0 } }
},
{
.name = "rom_writes_enabled",
.description = "Enable BIOS extension ROM Writes",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t isarom_dual_config[] = {
{
.name = "bios_fn",
.description = "BIOS File (ROM #1)",
.type = CONFIG_FNAME,
.default_string = NULL,
.default_int = 0,
.file_filter = BIOS_FILE_FILTER,
.spinner = { 0 },
.selection = { },
.bios = { { 0 } }
},
{
.name = "bios_addr",
.description = "BIOS Address (ROM #1)",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0x00000,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_ADDR_SELECTION,
.bios = { { 0 } }
},
{
.name = "bios_size",
.description = "BIOS Size (ROM #1):",
.type = CONFIG_INT,
.default_string = NULL,
.default_int = 8192,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_SIZE_SELECTION,
.bios = { { 0 } }
},
{
.name = "rom_writes_enabled",
.description = "Enable BIOS extension ROM Writes (ROM #1)",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "bios_fn2",
.description = "BIOS File (ROM #2)",
.type = CONFIG_FNAME,
.default_string = NULL,
.default_int = 0,
.file_filter = BIOS_FILE_FILTER,
.spinner = { 0 },
.selection = { },
.bios = { { 0 } }
},
{
.name = "bios_addr2",
.description = "BIOS Address (ROM #2)",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0x00000,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_ADDR_SELECTION,
.bios = { { 0 } }
},
{
.name = "bios_size2",
.description = "BIOS Size (ROM #2):",
.type = CONFIG_INT,
.default_string = NULL,
.default_int = 8192,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_SIZE_SELECTION,
.bios = { { 0 } }
},
{
.name = "rom_writes_enabled2",
.description = "Enable BIOS extension ROM Writes (ROM #2)",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
static const device_config_t isarom_quad_config[] = {
{
.name = "bios_fn",
.description = "BIOS File (ROM #1)",
.type = CONFIG_FNAME,
.default_string = NULL,
.default_int = 0,
.file_filter = BIOS_FILE_FILTER,
.spinner = { 0 },
.selection = { },
.bios = { { 0 } }
},
{
.name = "bios_addr",
.description = "BIOS Address (ROM #1)",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0x00000,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_ADDR_SELECTION,
.bios = { { 0 } }
},
{
.name = "bios_size",
.description = "BIOS Size (ROM #1):",
.type = CONFIG_INT,
.default_string = NULL,
.default_int = 8192,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_SIZE_SELECTION,
.bios = { { 0 } }
},
{
.name = "rom_writes_enabled",
.description = "Enable BIOS extension ROM Writes (ROM #1)",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "bios_fn2",
.description = "BIOS File (ROM #2)",
.type = CONFIG_FNAME,
.default_string = NULL,
.default_int = 0,
.file_filter = BIOS_FILE_FILTER,
.spinner = { 0 },
.selection = { },
.bios = { { 0 } }
},
{
.name = "bios_addr2",
.description = "BIOS Address (ROM #2)",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0x00000,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_ADDR_SELECTION,
.bios = { { 0 } }
},
{
.name = "bios_size2",
.description = "BIOS Size (ROM #2):",
.type = CONFIG_INT,
.default_string = NULL,
.default_int = 8192,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_SIZE_SELECTION,
.bios = { { 0 } }
},
{
.name = "rom_writes_enabled2",
.description = "Enable BIOS extension ROM Writes (ROM #2)",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "bios_fn3",
.description = "BIOS File (ROM #3)",
.type = CONFIG_FNAME,
.default_string = NULL,
.default_int = 0,
.file_filter = "ROM files (*.bin *.rom)|*.bin,*.rom",
.spinner = { 0 },
.selection = { },
.bios = { { 0 } }
},
{
.name = "bios_addr3",
.description = "BIOS Address (ROM #3)",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0x00000,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_ADDR_SELECTION,
.bios = { { 0 } }
},
{
.name = "bios_size3",
.description = "BIOS Size (ROM #3):",
.type = CONFIG_INT,
.default_string = NULL,
.default_int = 8192,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_SIZE_SELECTION,
.bios = { { 0 } }
},
{
.name = "rom_writes_enabled3",
.description = "Enable BIOS extension ROM Writes (ROM #3)",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{
.name = "bios_fn4",
.description = "BIOS File (ROM #4)",
.type = CONFIG_FNAME,
.default_string = NULL,
.default_int = 0,
.file_filter = BIOS_FILE_FILTER,
.spinner = { 0 },
.selection = { },
.bios = { { 0 } }
},
{
.name = "bios_addr4",
.description = "BIOS Address (ROM #4)",
.type = CONFIG_HEX20,
.default_string = NULL,
.default_int = 0x00000,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_ADDR_SELECTION,
.bios = { { 0 } }
},
{
.name = "bios_size4",
.description = "BIOS Size (ROM #4):",
.type = CONFIG_INT,
.default_string = NULL,
.default_int = 8192,
.file_filter = NULL,
.spinner = { 0 },
.selection = BIOS_SIZE_SELECTION,
.bios = { { 0 } }
},
{
.name = "rom_writes_enabled4",
.description = "Enable BIOS extension ROM Writes (ROM #4)",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
};
// clang-format on
static const device_t isarom_device = {
.name = "Generic ISA ROM Board",
.internal_name = "isarom",
.flags = DEVICE_ISA,
.local = ISAROM_CARD,
.init = isarom_init,
.close = isarom_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = isarom_config
};
static const device_t isarom_dual_device = {
.name = "Generic Dual ISA ROM Board",
.internal_name = "isarom_dual",
.flags = DEVICE_ISA,
.local = ISAROM_CARD_DUAL,
.init = isarom_init,
.close = isarom_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = isarom_dual_config
};
static const device_t isarom_quad_device = {
.name = "Generic Quad ISA ROM Board",
.internal_name = "isarom_quad",
.flags = DEVICE_ISA,
.local = ISAROM_CARD_QUAD,
.init = isarom_init,
.close = isarom_close,
.reset = NULL,
.available = NULL,
.speed_changed = NULL,
.force_redraw = NULL,
.config = isarom_quad_config
};
static const struct {
const device_t *dev;
} boards[] = {
// clang-format off
{ &device_none },
{ &isarom_device },
{ &isarom_dual_device },
{ &isarom_quad_device },
{ NULL }
// clang-format on
};
void
isarom_reset(void)
{
for (uint8_t i = 0; i < ISAROM_MAX; i++) {
if (isarom_type[i] == 0)
continue;
/* Add the device instance to the system. */
device_add_inst(boards[isarom_type[i]].dev, i + 1);
}
}
const char *
isarom_get_name(int board)
{
if (boards[board].dev == NULL)
return NULL;
return (boards[board].dev->name);
}
const char *
isarom_get_internal_name(int board)
{
return device_get_internal_name(boards[board].dev);
}
int
isarom_get_from_internal_name(const char *str)
{
int c = 0;
while (boards[c].dev != NULL) {
if (!strcmp(boards[c].dev->internal_name, str))
return c;
c++;
}
/* Not found. */
return 0;
}
const device_t *
isarom_get_device(int board)
{
/* Add the device instance to the system. */
return boards[board].dev;
}
int
isarom_has_config(int board)
{
if (boards[board].dev == NULL)
return 0;
return (boards[board].dev->config ? 1 : 0);
}

View File

@@ -532,8 +532,8 @@ isartc_init(const device_t *info)
switch (dev->board) {
case ISARTC_MM58167: /* Generic MM58167 RTC */
{
int rom_addr = device_get_config_hex20("bios_addr");
if (rom_addr != -1)
uint32_t rom_addr = device_get_config_hex20("bios_addr");
if (rom_addr != 0)
rom_init(&dev->rom, ISARTC_ROM_MM58167_1,
rom_addr, 0x0800, 0x7ff, 0, MEM_MAPPING_EXTERNAL);
@@ -830,7 +830,7 @@ static const device_config_t mm58167_config[] = {
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "Disabled", .value = -1 },
{ .description = "Disabled", .value = 0x00000 },
{ .description = "C800H", .value = 0xc8000 },
{ .description = "CA00H", .value = 0xca000 },
{ .description = "CC00H", .value = 0xcc000 },

View File

@@ -134,6 +134,7 @@ extern int postcard_enabled; /* (C) enable POST card */
extern int unittester_enabled; /* (C) enable unit tester device */
extern int gameport_type[]; /* (C) enable gameports */
extern int isamem_type[]; /* (C) enable ISA mem cards */
extern int isarom_type[]; /* (C) enable ISA ROM cards */
extern int isartc_type; /* (C) enable ISA RTC card */
extern int sound_is_float; /* (C) sound uses FP values */
extern int voodoo_enabled; /* (C) video option */

View File

@@ -122,6 +122,7 @@ typedef struct config_t {
int ide_qua_enabled; /* Quaternary IDE controller enabled */
int bugger_enabled; /* ISA bugger device enabled */
int isa_rtc_type; /* ISA RTC card */
int isa_rom_type[ISAROM_MAX]; /* ISA ROM boards */
int isa_mem_type[ISAMEM_MAX]; /* ISA memory boards */
/* Hard disks category */

View File

@@ -0,0 +1,37 @@
/*
* 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.
*
* Implementation of ISA ROM card Expansions.
*
* Authors: Jasmine Iwanek, <jriwanek@gmail.com>
*
* Copyright 2025 Jasmine Iwanek.
*/
#ifndef EMU_ISAROM_H
#define EMU_ISAROM_H
#define ISAROM_MAX 4 /* max #cards in system */
#ifdef __cplusplus
extern "C" {
#endif
/* Functions. */
extern void isarom_reset(void);
extern const char *isarom_get_name(int t);
extern const char *isarom_get_internal_name(int t);
extern int isarom_get_from_internal_name(const char *str);
extern const device_t *isarom_get_device(int t);
extern int isarom_has_config(int board);
#ifdef __cplusplus
}
#endif
#endif /*EMU_ISAROM_H*/

View File

@@ -39,6 +39,7 @@
#include <86box/video.h>
#include <86box/machine.h>
#include <86box/isamem.h>
#include <86box/isarom.h>
#include <86box/pci.h>
#include <86box/plat_unused.h>
@@ -111,6 +112,11 @@ machine_init_ex(int m)
/* Reset any ISA memory cards. */
isamem_reset();
#if 0
/* Reset any ISA ROM cards. */
isarom_reset();
#endif
/* Reset the fast off stuff. */
cpu_fast_off_reset();

View File

@@ -2053,6 +2053,7 @@ escp_close(void *priv)
free(dev->page);
}
FT_Done_Face(dev->fontface);
free(dev);
}

View File

@@ -2194,4 +2194,13 @@ msgid "Toggle pause"
msgstr "Переключить паузу"
msgid "Toggle mute"
msgstr "Переключить беззвучный режим"
msgstr "Переключить беззвучный режим"
msgid "Text files"
msgstr "Текстовые файлы"
msgid "ROM files"
msgstr "Файлы ПЗУ"
msgid "SoundFont files"
msgstr "Файлы SoundFont"

View File

@@ -31,6 +31,7 @@
#include <QLabel>
#include <QDir>
#include <QSettings>
#include <QStringBuilder>
extern "C" {
#include <86box/86box.h>
@@ -45,6 +46,7 @@ extern "C" {
#include "qt_filefield.hpp"
#include "qt_models_common.hpp"
#include "qt_util.hpp"
#ifdef Q_OS_LINUX
# include <sys/stat.h>
# include <sys/sysmacros.h>
@@ -276,11 +278,25 @@ DeviceConfig::ProcessConfig(void *dc, const void *c, const bool is_dep)
}
case CONFIG_FNAME:
{
auto *fileField = new FileField();
auto *fileField = new FileField(this);
fileField->setObjectName(config->name);
fileField->setFileName(selected);
fileField->setFilter(QString(config->file_filter).left(static_cast<int>(strcspn(config->file_filter,
"|"))));
/* Get the actually used part of the filter */
QString filter = QString(config->file_filter).left(static_cast<int>(strcspn(config->file_filter, "|")));
/* Extract the description and the extension list */
QRegularExpressionMatch match = QRegularExpression("(.+) \\((.+)\\)$").match(filter);
QString description = match.captured(1);
QString extensions = match.captured(2);
QStringList extensionList;
/* Split the extension list up and strip the filename globs */
QRegularExpression re("\\*\\.(.*)");
int i = 0;
while (extensions.section(' ', i, i) != "") {
QString extension = re.match(extensions.section(' ', i, i)).captured(1);
extensionList.append(extension);
i++;
}
fileField->setFilter(tr(description.toUtf8().constData()) % util::DlgFilter(extensionList) % tr("All files") % util::DlgFilter({ "*" }, true));
this->ui->formLayout->addRow(tr(config->description), fileField);
break;
}
@@ -388,6 +404,7 @@ DeviceConfig::ConfigureDevice(const _device_ *device, int instance, Settings *se
}
case CONFIG_MIDI_OUT:
case CONFIG_MIDI_IN:
case CONFIG_INT:
case CONFIG_SELECTION:
{
auto *cbox = dc.findChild<QComboBox *>(config->name);

View File

@@ -24,6 +24,7 @@ extern "C" {
#include <86box/device.h>
#include <86box/machine.h>
#include <86box/isamem.h>
#include <86box/isarom.h>
#include <86box/isartc.h>
#include <86box/unittester.h>
#include <86box/novell_cardkey.h>
@@ -65,6 +66,10 @@ SettingsOtherPeripherals::onCurrentMachineChanged(int machineId)
if (auto *cb = findChild<QComboBox *>(QString("comboBoxIsaMemCard%1").arg(i + 1)))
cb->clear();
for (uint8_t i = 0; i < ISAROM_MAX; ++i)
if (auto *cb = findChild<QComboBox *>(QString("comboBoxIsaRomCard%1").arg(i + 1)))
cb->clear();
int c = 0;
int selectedRow = 0;
@@ -127,6 +132,47 @@ SettingsOtherPeripherals::onCurrentMachineChanged(int machineId)
findChild<QPushButton *>(QString("pushButtonConfigureIsaMemCard%1").arg(i + 1))->setEnabled((isamem_type[i] != 0) &&
isamem_has_config(isamem_type[i]) && machineHasIsa);
}
// ISA ROM Expansion Cards
QComboBox *isarom_cbox[ISAROM_MAX] = { 0 };
QAbstractItemModel *isarom_models[ISAROM_MAX] = { 0 };
int isarom_removeRows_[ISAROM_MAX] = { 0 };
int isarom_selectedRows[ISAROM_MAX] = { 0 };
for (uint8_t i = 0; i < ISAROM_MAX; ++i) {
isarom_cbox[i] = findChild<QComboBox *>(QString("comboBoxIsaRomCard%1").arg(i + 1));
isarom_models[i] = isarom_cbox[i]->model();
isarom_removeRows_[i] = isarom_models[i]->rowCount();
}
c = 0;
while (true) {
const QString name = DeviceConfig::DeviceName(isarom_get_device(c),
isarom_get_internal_name(c), 0);
if (name.isEmpty())
break;
if (device_is_valid(isarom_get_device(c), machineId)) {
for (uint8_t i = 0; i < ISAROM_MAX; ++i) {
int row = Models::AddEntry(isarom_models[i], name, c);
if (c == isarom_type[i])
isarom_selectedRows[i] = row - isarom_removeRows_[i];
}
}
c++;
}
for (uint8_t i = 0; i < ISAROM_MAX; ++i) {
isarom_models[i]->removeRows(0, isarom_removeRows_[i]);
isarom_cbox[i]->setEnabled(isarom_models[i]->rowCount() > 1);
isarom_cbox[i]->setCurrentIndex(-1);
isarom_cbox[i]->setCurrentIndex(isarom_selectedRows[i]);
findChild<QPushButton *>(QString("pushButtonConfigureIsaRomCard%1").arg(i + 1))->setEnabled((isarom_type[i] != 0) &&
isarom_has_config(isarom_type[i]) && machineHasIsa);
}
}
SettingsOtherPeripherals::~SettingsOtherPeripherals()
@@ -149,6 +195,12 @@ SettingsOtherPeripherals::save()
auto *cbox = findChild<QComboBox *>(QString("comboBoxIsaMemCard%1").arg(i + 1));
isamem_type[i] = cbox->currentData().toInt();
}
/* ISA ROM boards. */
for (int i = 0; i < ISAROM_MAX; i++) {
auto *cbox = findChild<QComboBox *>(QString("comboBoxIsaRomCard%1").arg(i + 1));
isarom_type[i] = cbox->currentData().toInt();
}
}
void
@@ -226,6 +278,66 @@ SettingsOtherPeripherals::on_pushButtonConfigureIsaMemCard4_clicked()
DeviceConfig::ConfigureDevice(isamem_get_device(ui->comboBoxIsaMemCard4->currentData().toInt()), 4);
}
void
SettingsOtherPeripherals::on_comboBoxIsaRomCard1_currentIndexChanged(int index)
{
if (index < 0)
return;
ui->pushButtonConfigureIsaRomCard1->setEnabled((index != 0) && isarom_has_config(index) && machine_has_bus(machineId, MACHINE_BUS_ISA));
}
void
SettingsOtherPeripherals::on_pushButtonConfigureIsaRomCard1_clicked()
{
DeviceConfig::ConfigureDevice(isarom_get_device(ui->comboBoxIsaRomCard1->currentData().toInt()), 1);
}
void
SettingsOtherPeripherals::on_comboBoxIsaRomCard2_currentIndexChanged(int index)
{
if (index < 0)
return;
ui->pushButtonConfigureIsaRomCard2->setEnabled((index != 0) && isarom_has_config(index) && machine_has_bus(machineId, MACHINE_BUS_ISA));
}
void
SettingsOtherPeripherals::on_pushButtonConfigureIsaRomCard2_clicked()
{
DeviceConfig::ConfigureDevice(isarom_get_device(ui->comboBoxIsaRomCard2->currentData().toInt()), 2);
}
void
SettingsOtherPeripherals::on_comboBoxIsaRomCard3_currentIndexChanged(int index)
{
if (index < 0)
return;
ui->pushButtonConfigureIsaRomCard3->setEnabled((index != 0) && isarom_has_config(index) && machine_has_bus(machineId, MACHINE_BUS_ISA));
}
void
SettingsOtherPeripherals::on_pushButtonConfigureIsaRomCard3_clicked()
{
DeviceConfig::ConfigureDevice(isarom_get_device(ui->comboBoxIsaRomCard3->currentData().toInt()), 3);
}
void
SettingsOtherPeripherals::on_comboBoxIsaRomCard4_currentIndexChanged(int index)
{
if (index < 0)
return;
ui->pushButtonConfigureIsaRomCard4->setEnabled((index != 0) && isarom_has_config(index) && machine_has_bus(machineId, MACHINE_BUS_ISA));
}
void
SettingsOtherPeripherals::on_pushButtonConfigureIsaRomCard4_clicked()
{
DeviceConfig::ConfigureDevice(isarom_get_device(ui->comboBoxIsaRomCard4->currentData().toInt()), 4);
}
void
SettingsOtherPeripherals::on_checkBoxUnitTester_stateChanged(int arg1)
{

View File

@@ -32,6 +32,15 @@ private slots:
void on_comboBoxIsaMemCard4_currentIndexChanged(int index);
void on_pushButtonConfigureIsaMemCard4_clicked();
void on_comboBoxIsaRomCard1_currentIndexChanged(int index);
void on_pushButtonConfigureIsaRomCard1_clicked();
void on_comboBoxIsaRomCard2_currentIndexChanged(int index);
void on_pushButtonConfigureIsaRomCard2_clicked();
void on_comboBoxIsaRomCard3_currentIndexChanged(int index);
void on_pushButtonConfigureIsaRomCard3_clicked();
void on_comboBoxIsaRomCard4_currentIndexChanged(int index);
void on_pushButtonConfigureIsaRomCard4_clicked();
void on_checkBoxUnitTester_stateChanged(int arg1);
void on_pushButtonConfigureUT_clicked();

View File

@@ -174,6 +174,123 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBoxRom">
<property name="title">
<string>ISA ROM Cards</string>
</property>
<layout class="QGridLayout" name="gridLayoutRom">
<item row="0" column="0">
<widget class="QLabel" name="labelIsaRomCard1">
<property name="text">
<string>Card 1:</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QComboBox" name="comboBoxIsaRomCard1">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maxVisibleItems">
<number>30</number>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="pushButtonConfigureIsaRomCard1">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="labelIsaRomCard2">
<property name="text">
<string>Card 2:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="comboBoxIsaRomCard2">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maxVisibleItems">
<number>30</number>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QPushButton" name="pushButtonConfigureIsaRomCard2">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QLabel" name="labelIsaRomCard3">
<property name="text">
<string>Card 3:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QComboBox" name="comboBoxIsaRomCard3">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maxVisibleItems">
<number>30</number>
</property>
</widget>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="pushButtonConfigureIsaRomCard3">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QLabel" name="labelIsaRomCard4">
<property name="text">
<string>Card 4:</string>
</property>
</widget>
</item>
<item row="3" column="1">
<widget class="QComboBox" name="comboBoxIsaRomCard4">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maxVisibleItems">
<number>30</number>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="pushButtonConfigureIsaRomCard4">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayoutIBPC">
<item>

View File

@@ -92,6 +92,29 @@ DlgFilter(std::initializer_list<QString> extensions, bool last)
return " (" % temp.join(' ') % ")" % (!last ? ";;" : "");
}
QString
DlgFilter(QStringList extensions, bool last)
{
QStringList temp;
for (auto ext : extensions) {
#ifdef Q_OS_UNIX
if (ext == "*") {
temp.append("*");
continue;
}
temp.append("*." % ext.toUpper());
#endif
temp.append("*." % ext);
}
#ifdef Q_OS_UNIX
temp.removeDuplicates();
#endif
return " (" % temp.join(' ') % ")" % (!last ? ";;" : "");
}
QString currentUuid()
{
auto configPath = QFileInfo(cfg_path).dir().canonicalPath();

View File

@@ -11,6 +11,7 @@ namespace util {
static constexpr auto UUID_MIN_LENGTH = 36;
/* Creates extension list for qt filedialog */
QString DlgFilter(std::initializer_list<QString> extensions, bool last = false);
QString DlgFilter(QStringList extensions, bool last = false);
/* Returns screen the widget is on */
QScreen *screenOfWidget(QWidget *widget);
#ifdef Q_OS_WINDOWS

View File

@@ -161,6 +161,7 @@ fluidsynth_init(UNUSED(const device_t *info))
fluid_settings_setnum(data->settings, "synth.sample-rate", 44100);
fluid_settings_setnum(data->settings, "synth.gain", device_get_config_int("output_gain") / 100.0f);
fluid_settings_setint(data->settings, "synth.dynamic-sample-loading", device_get_config_int("dynamic_sample_loading"));
data->synth = new_fluid_synth(data->settings);
@@ -324,7 +325,7 @@ static const device_config_t fluidsynth_config[] = {
.type = CONFIG_FNAME,
.default_string = NULL,
.default_int = 0,
.file_filter = "SF2 Sound Fonts (*.sf2)|*.sf2",
.file_filter = "SoundFont files (*.sf2 *.sf3)|*.sf2,*.sf3",
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
@@ -509,6 +510,17 @@ static const device_config_t fluidsynth_config[] = {
},
.bios = { { 0 } }
},
{
.name = "dynamic_sample_loading",
.description = "Dynamic Sample Loading",
.type = CONFIG_BINARY,
.default_string = NULL,
.default_int = 0,
.file_filter = NULL,
.spinner = { 0 },
.selection = { { 0 } },
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};

View File

@@ -667,7 +667,7 @@ ega_recalctimings(ega_t *ega)
}
if (ega->chipset) {
if (ega->hdisp > 640) {
if (ega->hdisp >= 800) {
ega->dispend <<= 1;
ega->vtotal <<= 1;
ega->split <<= 1;
@@ -881,7 +881,7 @@ ega_poll(void *priv)
ega->stat &= ~8;
ega->vslines++;
if (ega->chipset) {
if (ega->hdisp > 640) {
if (ega->hdisp >= 800) {
if (ega->displine > 2000)
ega->displine = 0;
} else {
@@ -932,7 +932,7 @@ ega_poll(void *priv)
!(ega->real_vc & 1))
ega->vc++;
if (ega->chipset) {
if (ega->hdisp > 640)
if (ega->hdisp >= 800)
ega->vc &= 1023;
else
ega->vc &= 511;
@@ -1641,7 +1641,7 @@ ega_standalone_init(const device_t *info)
}
}
monitor_type = device_get_config_int("monitor_type");
monitor_type = ega->chipset ? 0x09 : device_get_config_int("monitor_type");
ega_init(ega, monitor_type, (monitor_type & 0x0F) == 0x0B);
ega->vram_limit = device_get_config_int("memory") * 1024;
@@ -1841,6 +1841,29 @@ static const device_config_t ega_config[] = {
// clang-format on
};
static const device_config_t atiega800p_config[] = {
// clang-format off
{
.name = "memory",
.description = "Memory size",
.type = CONFIG_SELECTION,
.default_string = NULL,
.default_int = 256,
.file_filter = NULL,
.spinner = { 0 },
.selection = {
{ .description = "32 KB", .value = 32 },
{ .description = "64 KB", .value = 64 },
{ .description = "128 KB", .value = 128 },
{ .description = "256 KB", .value = 256 },
{ .description = "" }
},
.bios = { { 0 } }
},
{ .name = "", .description = "", .type = CONFIG_END }
// clang-format on
};
const device_t ega_device = {
.name = "IBM EGA",
.internal_name = "ega",
@@ -1894,7 +1917,7 @@ const device_t atiega800p_device = {
.available = atiega800p_standalone_available,
.speed_changed = ega_speed_changed,
.force_redraw = NULL,
.config = ega_config
.config = atiega800p_config
};
const device_t iskra_ega_device = {